From c441b7dda8507b22a94146be0df77e54e623645a Mon Sep 17 00:00:00 2001 From: Wilco Baan Hofman Date: Sun, 1 Mar 2009 14:06:36 +0100 Subject: Add ads convenience functions to samba 4. Move gpo_ldap.c to root libgpo. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Günther Deschner --- libgpo/gpo_ldap.c | 869 +++++++++++++++++++++++++++++++++++++++ libgpo/gpo_util.c | 2 +- source3/libgpo/gpo_ldap.c | 866 -------------------------------------- source4/libgpo/ads_convenience.c | 248 +++++++++++ source4/libgpo/ads_convenience.h | 61 +++ 5 files changed, 1179 insertions(+), 867 deletions(-) create mode 100644 libgpo/gpo_ldap.c delete mode 100644 source3/libgpo/gpo_ldap.c create mode 100644 source4/libgpo/ads_convenience.c create mode 100644 source4/libgpo/ads_convenience.h diff --git a/libgpo/gpo_ldap.c b/libgpo/gpo_ldap.c new file mode 100644 index 0000000000..788d6887a3 --- /dev/null +++ b/libgpo/gpo_ldap.c @@ -0,0 +1,869 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Object Support + * Copyright (C) Guenther Deschner 2005,2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "includes.h" +#if _SAMBA_BUILD_ == 4 +#include "source4/libgpo/ads_convenience.h" +#endif + +/**************************************************************** + parse the raw extension string into a GP_EXT structure +****************************************************************/ + +bool ads_parse_gp_ext(TALLOC_CTX *mem_ctx, + const char *extension_raw, + struct GP_EXT **gp_ext) +{ + bool ret = false; + struct GP_EXT *ext = NULL; + char **ext_list = NULL; + char **ext_strings = NULL; + int i; + + if (!extension_raw) { + goto parse_error; + } + + DEBUG(20,("ads_parse_gp_ext: %s\n", extension_raw)); + + ext = TALLOC_ZERO_P(mem_ctx, struct GP_EXT); + if (!ext) { + goto parse_error; + } + + ext_list = str_list_make_v3(mem_ctx, extension_raw, "]"); + if (!ext_list) { + goto parse_error; + } + + for (i = 0; ext_list[i] != NULL; i++) { + /* no op */ + } + + ext->num_exts = i; + + if (ext->num_exts) { + ext->extensions = TALLOC_ZERO_ARRAY(mem_ctx, char *, + ext->num_exts); + ext->extensions_guid = TALLOC_ZERO_ARRAY(mem_ctx, char *, + ext->num_exts); + ext->snapins = TALLOC_ZERO_ARRAY(mem_ctx, char *, + ext->num_exts); + ext->snapins_guid = TALLOC_ZERO_ARRAY(mem_ctx, char *, + ext->num_exts); + } + + ext->gp_extension = talloc_strdup(mem_ctx, extension_raw); + + if (!ext->extensions || !ext->extensions_guid || + !ext->snapins || !ext->snapins_guid || + !ext->gp_extension) { + goto parse_error; + } + + for (i = 0; ext_list[i] != NULL; i++) { + + int k; + char *p, *q; + + DEBUGADD(10,("extension #%d\n", i)); + + p = ext_list[i]; + + if (p[0] == '[') { + p++; + } + + ext_strings = str_list_make_v3(mem_ctx, p, "}"); + if (ext_strings == NULL) { + goto parse_error; + } + + for (k = 0; ext_strings[k] != NULL; k++) { + /* no op */ + } + + q = ext_strings[0]; + + if (q[0] == '{') { + q++; + } + + ext->extensions[i] = talloc_strdup(mem_ctx, + cse_gpo_guid_string_to_name(q)); + ext->extensions_guid[i] = talloc_strdup(mem_ctx, q); + + /* we might have no name for the guid */ + if (ext->extensions_guid[i] == NULL) { + goto parse_error; + } + + for (k = 1; ext_strings[k] != NULL; k++) { + + char *m = ext_strings[k]; + + if (m[0] == '{') { + m++; + } + + /* FIXME: theoretically there could be more than one + * snapin per extension */ + ext->snapins[i] = talloc_strdup(mem_ctx, + cse_snapin_gpo_guid_string_to_name(m)); + ext->snapins_guid[i] = talloc_strdup(mem_ctx, m); + + /* we might have no name for the guid */ + if (ext->snapins_guid[i] == NULL) { + goto parse_error; + } + } + } + + *gp_ext = ext; + + ret = true; + + parse_error: + TALLOC_FREE(ext_list); + TALLOC_FREE(ext_strings); + + return ret; +} + +#ifdef HAVE_LDAP + +/**************************************************************** + parse the raw link string into a GP_LINK structure +****************************************************************/ + +static ADS_STATUS gpo_parse_gplink(TALLOC_CTX *mem_ctx, + const char *gp_link_raw, + uint32_t options, + struct GP_LINK *gp_link) +{ + ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + char **link_list; + int i; + + ZERO_STRUCTP(gp_link); + + DEBUG(10,("gpo_parse_gplink: gPLink: %s\n", gp_link_raw)); + + link_list = str_list_make_v3(mem_ctx, gp_link_raw, "]"); + if (!link_list) { + goto parse_error; + } + + for (i = 0; link_list[i] != NULL; i++) { + /* no op */ + } + + gp_link->gp_opts = options; + gp_link->num_links = i; + + if (gp_link->num_links) { + gp_link->link_names = TALLOC_ZERO_ARRAY(mem_ctx, char *, + gp_link->num_links); + gp_link->link_opts = TALLOC_ZERO_ARRAY(mem_ctx, uint32_t, + gp_link->num_links); + } + + gp_link->gp_link = talloc_strdup(mem_ctx, gp_link_raw); + + if (!gp_link->link_names || !gp_link->link_opts || !gp_link->gp_link) { + goto parse_error; + } + + for (i = 0; link_list[i] != NULL; i++) { + + char *p, *q; + + DEBUGADD(10,("gpo_parse_gplink: processing link #%d\n", i)); + + q = link_list[i]; + if (q[0] == '[') { + q++; + }; + + p = strchr(q, ';'); + + if (p == NULL) { + goto parse_error; + } + + gp_link->link_names[i] = talloc_strdup(mem_ctx, q); + if (gp_link->link_names[i] == NULL) { + goto parse_error; + } + gp_link->link_names[i][PTR_DIFF(p, q)] = 0; + + gp_link->link_opts[i] = atoi(p + 1); + + DEBUGADD(10,("gpo_parse_gplink: link: %s\n", + gp_link->link_names[i])); + DEBUGADD(10,("gpo_parse_gplink: opt: %d\n", + gp_link->link_opts[i])); + + } + + status = ADS_SUCCESS; + + parse_error: + TALLOC_FREE(link_list); + + return status; +} + +/**************************************************************** + helper call to get a GP_LINK structure from a linkdn +****************************************************************/ + +ADS_STATUS ads_get_gpo_link(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *link_dn, + struct GP_LINK *gp_link_struct) +{ + ADS_STATUS status; + const char *attrs[] = {"gPLink", "gPOptions", NULL}; + LDAPMessage *res = NULL; + const char *gp_link; + uint32_t gp_options; + + ZERO_STRUCTP(gp_link_struct); + + status = ads_search_dn(ads, &res, link_dn, attrs); + if (!ADS_ERR_OK(status)) { + DEBUG(10,("ads_get_gpo_link: search failed with %s\n", + ads_errstr(status))); + return status; + } + + if (ads_count_replies(ads, res) != 1) { + DEBUG(10,("ads_get_gpo_link: no result\n")); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink"); + if (gp_link == NULL) { + DEBUG(10,("ads_get_gpo_link: no 'gPLink' attribute found\n")); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE); + } + + /* perfectly legal to have no options */ + if (!ads_pull_uint32(ads, res, "gPOptions", &gp_options)) { + DEBUG(10,("ads_get_gpo_link: " + "no 'gPOptions' attribute found\n")); + gp_options = 0; + } + + ads_msgfree(ads, res); + + return gpo_parse_gplink(mem_ctx, gp_link, gp_options, gp_link_struct); +} + +/**************************************************************** + helper call to add a gp link +****************************************************************/ + +ADS_STATUS ads_add_gpo_link(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *link_dn, + const char *gpo_dn, + uint32_t gpo_opt) +{ + ADS_STATUS status; + const char *attrs[] = {"gPLink", NULL}; + LDAPMessage *res = NULL; + const char *gp_link, *gp_link_new; + ADS_MODLIST mods; + + /* although ADS allows to set anything here, we better check here if + * the gpo_dn is sane */ + + if (!strnequal(gpo_dn, "LDAP://CN={", strlen("LDAP://CN={")) != 0) { + return ADS_ERROR(LDAP_INVALID_DN_SYNTAX); + } + + status = ads_search_dn(ads, &res, link_dn, attrs); + if (!ADS_ERR_OK(status)) { + DEBUG(10,("ads_add_gpo_link: search failed with %s\n", + ads_errstr(status))); + return status; + } + + if (ads_count_replies(ads, res) != 1) { + DEBUG(10,("ads_add_gpo_link: no result\n")); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink"); + if (gp_link == NULL) { + gp_link_new = talloc_asprintf(mem_ctx, "[%s;%d]", + gpo_dn, gpo_opt); + } else { + gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]", + gp_link, gpo_dn, gpo_opt); + } + + ads_msgfree(ads, res); + ADS_ERROR_HAVE_NO_MEMORY(gp_link_new); + + mods = ads_init_mods(mem_ctx); + ADS_ERROR_HAVE_NO_MEMORY(mods); + + status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new); + if (!ADS_ERR_OK(status)) { + return status; + } + + return ads_gen_mod(ads, link_dn, mods); +} + +/**************************************************************** + helper call to delete add a gp link +****************************************************************/ + +/* untested & broken */ +ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *link_dn, + const char *gpo_dn) +{ + ADS_STATUS status; + const char *attrs[] = {"gPLink", NULL}; + LDAPMessage *res = NULL; + const char *gp_link, *gp_link_new = NULL; + ADS_MODLIST mods; + + /* check for a sane gpo_dn */ + if (gpo_dn[0] != '[') { + DEBUG(10,("ads_delete_gpo_link: first char not: [\n")); + return ADS_ERROR(LDAP_INVALID_DN_SYNTAX); + } + + if (gpo_dn[strlen(gpo_dn)] != ']') { + DEBUG(10,("ads_delete_gpo_link: last char not: ]\n")); + return ADS_ERROR(LDAP_INVALID_DN_SYNTAX); + } + + status = ads_search_dn(ads, &res, link_dn, attrs); + if (!ADS_ERR_OK(status)) { + DEBUG(10,("ads_delete_gpo_link: search failed with %s\n", + ads_errstr(status))); + return status; + } + + if (ads_count_replies(ads, res) != 1) { + DEBUG(10,("ads_delete_gpo_link: no result\n")); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink"); + if (gp_link == NULL) { + return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE); + } + + /* find link to delete */ + /* gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]", gp_link, + gpo_dn, gpo_opt); */ + + ads_msgfree(ads, res); + ADS_ERROR_HAVE_NO_MEMORY(gp_link_new); + + mods = ads_init_mods(mem_ctx); + ADS_ERROR_HAVE_NO_MEMORY(mods); + + status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new); + if (!ADS_ERR_OK(status)) { + return status; + } + + return ads_gen_mod(ads, link_dn, mods); +} + +/**************************************************************** + parse a GROUP_POLICY_OBJECT structure from an LDAPMessage result +****************************************************************/ + + ADS_STATUS ads_parse_gpo(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + LDAPMessage *res, + const char *gpo_dn, + struct GROUP_POLICY_OBJECT *gpo) +{ + ZERO_STRUCTP(gpo); + + ADS_ERROR_HAVE_NO_MEMORY(res); + + if (gpo_dn) { + gpo->ds_path = talloc_strdup(mem_ctx, gpo_dn); + } else { + gpo->ds_path = ads_get_dn(ads, mem_ctx, res); + } + + ADS_ERROR_HAVE_NO_MEMORY(gpo->ds_path); + + if (!ads_pull_uint32(ads, res, "versionNumber", &gpo->version)) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + if (!ads_pull_uint32(ads, res, "flags", &gpo->options)) { + return ADS_ERROR(LDAP_NO_MEMORY); + } + + gpo->file_sys_path = ads_pull_string(ads, mem_ctx, res, + "gPCFileSysPath"); + ADS_ERROR_HAVE_NO_MEMORY(gpo->file_sys_path); + + gpo->display_name = ads_pull_string(ads, mem_ctx, res, + "displayName"); + ADS_ERROR_HAVE_NO_MEMORY(gpo->display_name); + + gpo->name = ads_pull_string(ads, mem_ctx, res, + "name"); + ADS_ERROR_HAVE_NO_MEMORY(gpo->name); + + gpo->machine_extensions = ads_pull_string(ads, mem_ctx, res, + "gPCMachineExtensionNames"); + gpo->user_extensions = ads_pull_string(ads, mem_ctx, res, + "gPCUserExtensionNames"); + + ads_pull_sd(ads, mem_ctx, res, "ntSecurityDescriptor", + &gpo->security_descriptor); + ADS_ERROR_HAVE_NO_MEMORY(gpo->security_descriptor); + + return ADS_ERROR(LDAP_SUCCESS); +} + +/**************************************************************** + get a GROUP_POLICY_OBJECT structure based on different input parameters +****************************************************************/ + +ADS_STATUS ads_get_gpo(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *gpo_dn, + const char *display_name, + const char *guid_name, + struct GROUP_POLICY_OBJECT *gpo) +{ + ADS_STATUS status; + LDAPMessage *res = NULL; + char *dn; + const char *filter; + const char *attrs[] = { + "cn", + "displayName", + "flags", + "gPCFileSysPath", + "gPCFunctionalityVersion", + "gPCMachineExtensionNames", + "gPCUserExtensionNames", + "gPCWQLFilter", + "name", + "ntSecurityDescriptor", + "versionNumber", + NULL}; + uint32_t sd_flags = DACL_SECURITY_INFORMATION; + + ZERO_STRUCTP(gpo); + + if (!gpo_dn && !display_name && !guid_name) { + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + if (gpo_dn) { + + if (strnequal(gpo_dn, "LDAP://", strlen("LDAP://")) != 0) { + gpo_dn = gpo_dn + strlen("LDAP://"); + } + + status = ads_search_retry_dn_sd_flags(ads, &res, + sd_flags, + gpo_dn, attrs); + + } else if (display_name || guid_name) { + + filter = talloc_asprintf(mem_ctx, + "(&(objectclass=groupPolicyContainer)(%s=%s))", + display_name ? "displayName" : "name", + display_name ? display_name : guid_name); + ADS_ERROR_HAVE_NO_MEMORY(filter); + + status = ads_do_search_all_sd_flags(ads, ads->config.bind_path, + LDAP_SCOPE_SUBTREE, filter, + attrs, sd_flags, &res); + } + + if (!ADS_ERR_OK(status)) { + DEBUG(10,("ads_get_gpo: search failed with %s\n", + ads_errstr(status))); + return status; + } + + if (ads_count_replies(ads, res) != 1) { + DEBUG(10,("ads_get_gpo: no result\n")); + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + } + + dn = ads_get_dn(ads, mem_ctx, res); + if (dn == NULL) { + ads_msgfree(ads, res); + return ADS_ERROR(LDAP_NO_MEMORY); + } + + status = ads_parse_gpo(ads, mem_ctx, res, dn, gpo); + ads_msgfree(ads, res); + TALLOC_FREE(dn); + + return status; +} + +/**************************************************************** + add a gplink to the GROUP_POLICY_OBJECT linked list +****************************************************************/ + +static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + struct GROUP_POLICY_OBJECT **gpo_list, + const char *link_dn, + struct GP_LINK *gp_link, + enum GPO_LINK_TYPE link_type, + bool only_add_forced_gpos, + const struct nt_user_token *token) +{ + ADS_STATUS status; + int i; + + for (i = 0; i < gp_link->num_links; i++) { + + struct GROUP_POLICY_OBJECT *new_gpo = NULL; + + if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) { + DEBUG(10,("skipping disabled GPO\n")); + continue; + } + + if (only_add_forced_gpos) { + + if (!(gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED)) { + DEBUG(10,("skipping nonenforced GPO link " + "because GPOPTIONS_BLOCK_INHERITANCE " + "has been set\n")); + continue; + } else { + DEBUG(10,("adding enforced GPO link although " + "the GPOPTIONS_BLOCK_INHERITANCE " + "has been set\n")); + } + } + + new_gpo = TALLOC_ZERO_P(mem_ctx, struct GROUP_POLICY_OBJECT); + ADS_ERROR_HAVE_NO_MEMORY(new_gpo); + + status = ads_get_gpo(ads, mem_ctx, gp_link->link_names[i], + NULL, NULL, new_gpo); + if (!ADS_ERR_OK(status)) { + DEBUG(10,("failed to get gpo: %s\n", + gp_link->link_names[i])); + return status; + } + + status = ADS_ERROR_NT(gpo_apply_security_filtering(new_gpo, + token)); + if (!ADS_ERR_OK(status)) { + DEBUG(10,("skipping GPO \"%s\" as object " + "has no access to it\n", + new_gpo->display_name)); + TALLOC_FREE(new_gpo); + continue; + } + + new_gpo->link = link_dn; + new_gpo->link_type = link_type; + + DLIST_ADD(*gpo_list, new_gpo); + + DEBUG(10,("add_gplink_to_gplist: added GPLINK #%d %s " + "to GPO list\n", i, gp_link->link_names[i])); + } + + return ADS_ERROR(LDAP_SUCCESS); +} + +/**************************************************************** +****************************************************************/ + +ADS_STATUS ads_get_sid_token(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *dn, + struct nt_user_token **token) +{ + ADS_STATUS status; + DOM_SID object_sid; + DOM_SID primary_group_sid; + DOM_SID *ad_token_sids; + size_t num_ad_token_sids = 0; + DOM_SID *token_sids; + size_t num_token_sids = 0; + struct nt_user_token *new_token = NULL; + int i; + + status = ads_get_tokensids(ads, mem_ctx, dn, + &object_sid, &primary_group_sid, + &ad_token_sids, &num_ad_token_sids); + if (!ADS_ERR_OK(status)) { + return status; + } + + token_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, 1); + ADS_ERROR_HAVE_NO_MEMORY(token_sids); + + status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx, + &primary_group_sid, + &token_sids, + &num_token_sids)); + if (!ADS_ERR_OK(status)) { + return status; + } + + for (i = 0; i < num_ad_token_sids; i++) { + + if (sid_check_is_in_builtin(&ad_token_sids[i])) { + continue; + } + + status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx, + &ad_token_sids[i], + &token_sids, + &num_token_sids)); + if (!ADS_ERR_OK(status)) { + return status; + } + } + + new_token = create_local_nt_token(mem_ctx, &object_sid, false, + num_token_sids, token_sids); + ADS_ERROR_HAVE_NO_MEMORY(new_token); + + *token = new_token; + + debug_nt_user_token(DBGC_CLASS, 5, *token); + + return ADS_ERROR_LDAP(LDAP_SUCCESS); +} + +/**************************************************************** +****************************************************************/ + +static ADS_STATUS add_local_policy_to_gpo_list(TALLOC_CTX *mem_ctx, + struct GROUP_POLICY_OBJECT **gpo_list, + enum GPO_LINK_TYPE link_type) +{ + struct GROUP_POLICY_OBJECT *gpo = NULL; + + ADS_ERROR_HAVE_NO_MEMORY(gpo_list); + + gpo = TALLOC_ZERO_P(mem_ctx, struct GROUP_POLICY_OBJECT); + ADS_ERROR_HAVE_NO_MEMORY(gpo); + + gpo->name = talloc_strdup(mem_ctx, "Local Policy"); + ADS_ERROR_HAVE_NO_MEMORY(gpo->name); + + gpo->display_name = talloc_strdup(mem_ctx, "Local Policy"); + ADS_ERROR_HAVE_NO_MEMORY(gpo->display_name); + + gpo->link_type = link_type; + + DLIST_ADD(*gpo_list, gpo); + + return ADS_ERROR_NT(NT_STATUS_OK); +} + +/**************************************************************** + get the full list of GROUP_POLICY_OBJECTs for a given dn +****************************************************************/ + +ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads, + TALLOC_CTX *mem_ctx, + const char *dn, + uint32_t flags, + const struct nt_user_token *token, + struct GROUP_POLICY_OBJECT **gpo_list) +{ + /* (L)ocal (S)ite (D)omain (O)rganizational(U)nit */ + + ADS_STATUS status; + struct GP_LINK gp_link; + const char *parent_dn, *site_dn, *tmp_dn; + bool add_only_forced_gpos = false; + + ZERO_STRUCTP(gpo_list); + + if (!dn) { + return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER); + } + + DEBUG(10,("ads_get_gpo_list: getting GPO list for [%s]\n", dn)); + + /* (L)ocal */ + status = add_local_policy_to_gpo_list(mem_ctx, gpo_list, + GP_LINK_LOCAL); + if (!ADS_ERR_OK(status)) { + return status; + } + + /* (S)ite */ + + /* are site GPOs valid for users as well ??? */ + if (flags & GPO_LIST_FLAG_MACHINE) { + + status = ads_site_dn_for_machine(ads, mem_ctx, + ads->config.ldap_server_name, + &site_dn); + if (!ADS_ERR_OK(status)) { + return status; + } + + DEBUG(10,("ads_get_gpo_list: query SITE: [%s] for GPOs\n", + site_dn)); + + status = ads_get_gpo_link(ads, mem_ctx, site_dn, &gp_link); + if (ADS_ERR_OK(status)) { + + if (DEBUGLEVEL >= 100) { + dump_gplink(ads, mem_ctx, &gp_link); + } + + status = add_gplink_to_gpo_list(ads, mem_ctx, gpo_list, + site_dn, &gp_link, + GP_LINK_SITE, + add_only_forced_gpos, + token); + if (!ADS_ERR_OK(status)) { + return status; + } + + if (flags & GPO_LIST_FLAG_SITEONLY) { + return ADS_ERROR(LDAP_SUCCESS); + } + + /* inheritance can't be blocked at the site level */ + } + } + + tmp_dn = dn; + + while ((parent_dn = ads_parent_dn(tmp_dn)) && + (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) { + + /* (D)omain */ + + /* An account can just be a member of one domain */ + if (strncmp(parent_dn, "DC=", strlen("DC=")) == 0) { + + DEBUG(10,("ads_get_gpo_list: query DC: [%s] for GPOs\n", + parent_dn)); + + status = ads_get_gpo_link(ads, mem_ctx, parent_dn, + &gp_link); + if (ADS_ERR_OK(status)) { + + if (DEBUGLEVEL >= 100) { + dump_gplink(ads, mem_ctx, &gp_link); + } + + /* block inheritance from now on */ + if (gp_link.gp_opts & + GPOPTIONS_BLOCK_INHERITANCE) { + add_only_forced_gpos = true; + } + + status = add_gplink_to_gpo_list(ads, + mem_ctx, + gpo_list, + parent_dn, + &gp_link, + GP_LINK_DOMAIN, + add_only_forced_gpos, + token); + if (!ADS_ERR_OK(status)) { + return status; + } + } + } + + tmp_dn = parent_dn; + } + + /* reset dn again */ + tmp_dn = dn; + + while ((parent_dn = ads_parent_dn(tmp_dn)) && + (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) { + + + /* (O)rganizational(U)nit */ + + /* An account can be a member of more OUs */ + if (strncmp(parent_dn, "OU=", strlen("OU=")) == 0) { + + DEBUG(10,("ads_get_gpo_list: query OU: [%s] for GPOs\n", + parent_dn)); + + status = ads_get_gpo_link(ads, mem_ctx, parent_dn, + &gp_link); + if (ADS_ERR_OK(status)) { + + if (DEBUGLEVEL >= 100) { + dump_gplink(ads, mem_ctx, &gp_link); + } + + /* block inheritance from now on */ + if (gp_link.gp_opts & + GPOPTIONS_BLOCK_INHERITANCE) { + add_only_forced_gpos = true; + } + + status = add_gplink_to_gpo_list(ads, + mem_ctx, + gpo_list, + parent_dn, + &gp_link, + GP_LINK_OU, + add_only_forced_gpos, + token); + if (!ADS_ERR_OK(status)) { + return status; + } + } + } + + tmp_dn = parent_dn; + + }; + + return ADS_ERROR(LDAP_SUCCESS); +} + +#endif /* HAVE_LDAP */ diff --git a/libgpo/gpo_util.c b/libgpo/gpo_util.c index 505400be8c..d5e3f24c8d 100644 --- a/libgpo/gpo_util.c +++ b/libgpo/gpo_util.c @@ -315,7 +315,7 @@ void dump_gpo(ADS_STRUCT *ads, DEBUGADD(lvl,("security descriptor:\n")); - ads_disp_sd(ads, mem_ctx, gpo->security_descriptor); + NDR_PRINT_DEBUG(security_descriptor, gpo->security_descriptor); } /**************************************************************** diff --git a/source3/libgpo/gpo_ldap.c b/source3/libgpo/gpo_ldap.c deleted file mode 100644 index 716b8729c3..0000000000 --- a/source3/libgpo/gpo_ldap.c +++ /dev/null @@ -1,866 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Group Policy Object Support - * Copyright (C) Guenther Deschner 2005,2007 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include "includes.h" - -/**************************************************************** - parse the raw extension string into a GP_EXT structure -****************************************************************/ - -bool ads_parse_gp_ext(TALLOC_CTX *mem_ctx, - const char *extension_raw, - struct GP_EXT **gp_ext) -{ - bool ret = false; - struct GP_EXT *ext = NULL; - char **ext_list = NULL; - char **ext_strings = NULL; - int i; - - if (!extension_raw) { - goto parse_error; - } - - DEBUG(20,("ads_parse_gp_ext: %s\n", extension_raw)); - - ext = TALLOC_ZERO_P(mem_ctx, struct GP_EXT); - if (!ext) { - goto parse_error; - } - - ext_list = str_list_make_v3(mem_ctx, extension_raw, "]"); - if (!ext_list) { - goto parse_error; - } - - for (i = 0; ext_list[i] != NULL; i++) { - /* no op */ - } - - ext->num_exts = i; - - if (ext->num_exts) { - ext->extensions = TALLOC_ZERO_ARRAY(mem_ctx, char *, - ext->num_exts); - ext->extensions_guid = TALLOC_ZERO_ARRAY(mem_ctx, char *, - ext->num_exts); - ext->snapins = TALLOC_ZERO_ARRAY(mem_ctx, char *, - ext->num_exts); - ext->snapins_guid = TALLOC_ZERO_ARRAY(mem_ctx, char *, - ext->num_exts); - } - - ext->gp_extension = talloc_strdup(mem_ctx, extension_raw); - - if (!ext->extensions || !ext->extensions_guid || - !ext->snapins || !ext->snapins_guid || - !ext->gp_extension) { - goto parse_error; - } - - for (i = 0; ext_list[i] != NULL; i++) { - - int k; - char *p, *q; - - DEBUGADD(10,("extension #%d\n", i)); - - p = ext_list[i]; - - if (p[0] == '[') { - p++; - } - - ext_strings = str_list_make_v3(mem_ctx, p, "}"); - if (ext_strings == NULL) { - goto parse_error; - } - - for (k = 0; ext_strings[k] != NULL; k++) { - /* no op */ - } - - q = ext_strings[0]; - - if (q[0] == '{') { - q++; - } - - ext->extensions[i] = talloc_strdup(mem_ctx, - cse_gpo_guid_string_to_name(q)); - ext->extensions_guid[i] = talloc_strdup(mem_ctx, q); - - /* we might have no name for the guid */ - if (ext->extensions_guid[i] == NULL) { - goto parse_error; - } - - for (k = 1; ext_strings[k] != NULL; k++) { - - char *m = ext_strings[k]; - - if (m[0] == '{') { - m++; - } - - /* FIXME: theoretically there could be more than one - * snapin per extension */ - ext->snapins[i] = talloc_strdup(mem_ctx, - cse_snapin_gpo_guid_string_to_name(m)); - ext->snapins_guid[i] = talloc_strdup(mem_ctx, m); - - /* we might have no name for the guid */ - if (ext->snapins_guid[i] == NULL) { - goto parse_error; - } - } - } - - *gp_ext = ext; - - ret = true; - - parse_error: - TALLOC_FREE(ext_list); - TALLOC_FREE(ext_strings); - - return ret; -} - -#ifdef HAVE_LDAP - -/**************************************************************** - parse the raw link string into a GP_LINK structure -****************************************************************/ - -static ADS_STATUS gpo_parse_gplink(TALLOC_CTX *mem_ctx, - const char *gp_link_raw, - uint32_t options, - struct GP_LINK *gp_link) -{ - ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); - char **link_list; - int i; - - ZERO_STRUCTP(gp_link); - - DEBUG(10,("gpo_parse_gplink: gPLink: %s\n", gp_link_raw)); - - link_list = str_list_make_v3(mem_ctx, gp_link_raw, "]"); - if (!link_list) { - goto parse_error; - } - - for (i = 0; link_list[i] != NULL; i++) { - /* no op */ - } - - gp_link->gp_opts = options; - gp_link->num_links = i; - - if (gp_link->num_links) { - gp_link->link_names = TALLOC_ZERO_ARRAY(mem_ctx, char *, - gp_link->num_links); - gp_link->link_opts = TALLOC_ZERO_ARRAY(mem_ctx, uint32_t, - gp_link->num_links); - } - - gp_link->gp_link = talloc_strdup(mem_ctx, gp_link_raw); - - if (!gp_link->link_names || !gp_link->link_opts || !gp_link->gp_link) { - goto parse_error; - } - - for (i = 0; link_list[i] != NULL; i++) { - - char *p, *q; - - DEBUGADD(10,("gpo_parse_gplink: processing link #%d\n", i)); - - q = link_list[i]; - if (q[0] == '[') { - q++; - }; - - p = strchr(q, ';'); - - if (p == NULL) { - goto parse_error; - } - - gp_link->link_names[i] = talloc_strdup(mem_ctx, q); - if (gp_link->link_names[i] == NULL) { - goto parse_error; - } - gp_link->link_names[i][PTR_DIFF(p, q)] = 0; - - gp_link->link_opts[i] = atoi(p + 1); - - DEBUGADD(10,("gpo_parse_gplink: link: %s\n", - gp_link->link_names[i])); - DEBUGADD(10,("gpo_parse_gplink: opt: %d\n", - gp_link->link_opts[i])); - - } - - status = ADS_SUCCESS; - - parse_error: - TALLOC_FREE(link_list); - - return status; -} - -/**************************************************************** - helper call to get a GP_LINK structure from a linkdn -****************************************************************/ - -ADS_STATUS ads_get_gpo_link(ADS_STRUCT *ads, - TALLOC_CTX *mem_ctx, - const char *link_dn, - struct GP_LINK *gp_link_struct) -{ - ADS_STATUS status; - const char *attrs[] = {"gPLink", "gPOptions", NULL}; - LDAPMessage *res = NULL; - const char *gp_link; - uint32_t gp_options; - - ZERO_STRUCTP(gp_link_struct); - - status = ads_search_dn(ads, &res, link_dn, attrs); - if (!ADS_ERR_OK(status)) { - DEBUG(10,("ads_get_gpo_link: search failed with %s\n", - ads_errstr(status))); - return status; - } - - if (ads_count_replies(ads, res) != 1) { - DEBUG(10,("ads_get_gpo_link: no result\n")); - ads_msgfree(ads, res); - return ADS_ERROR(LDAP_NO_SUCH_OBJECT); - } - - gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink"); - if (gp_link == NULL) { - DEBUG(10,("ads_get_gpo_link: no 'gPLink' attribute found\n")); - ads_msgfree(ads, res); - return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE); - } - - /* perfectly legal to have no options */ - if (!ads_pull_uint32(ads, res, "gPOptions", &gp_options)) { - DEBUG(10,("ads_get_gpo_link: " - "no 'gPOptions' attribute found\n")); - gp_options = 0; - } - - ads_msgfree(ads, res); - - return gpo_parse_gplink(mem_ctx, gp_link, gp_options, gp_link_struct); -} - -/**************************************************************** - helper call to add a gp link -****************************************************************/ - -ADS_STATUS ads_add_gpo_link(ADS_STRUCT *ads, - TALLOC_CTX *mem_ctx, - const char *link_dn, - const char *gpo_dn, - uint32_t gpo_opt) -{ - ADS_STATUS status; - const char *attrs[] = {"gPLink", NULL}; - LDAPMessage *res = NULL; - const char *gp_link, *gp_link_new; - ADS_MODLIST mods; - - /* although ADS allows to set anything here, we better check here if - * the gpo_dn is sane */ - - if (!strnequal(gpo_dn, "LDAP://CN={", strlen("LDAP://CN={")) != 0) { - return ADS_ERROR(LDAP_INVALID_DN_SYNTAX); - } - - status = ads_search_dn(ads, &res, link_dn, attrs); - if (!ADS_ERR_OK(status)) { - DEBUG(10,("ads_add_gpo_link: search failed with %s\n", - ads_errstr(status))); - return status; - } - - if (ads_count_replies(ads, res) != 1) { - DEBUG(10,("ads_add_gpo_link: no result\n")); - ads_msgfree(ads, res); - return ADS_ERROR(LDAP_NO_SUCH_OBJECT); - } - - gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink"); - if (gp_link == NULL) { - gp_link_new = talloc_asprintf(mem_ctx, "[%s;%d]", - gpo_dn, gpo_opt); - } else { - gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]", - gp_link, gpo_dn, gpo_opt); - } - - ads_msgfree(ads, res); - ADS_ERROR_HAVE_NO_MEMORY(gp_link_new); - - mods = ads_init_mods(mem_ctx); - ADS_ERROR_HAVE_NO_MEMORY(mods); - - status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new); - if (!ADS_ERR_OK(status)) { - return status; - } - - return ads_gen_mod(ads, link_dn, mods); -} - -/**************************************************************** - helper call to delete add a gp link -****************************************************************/ - -/* untested & broken */ -ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads, - TALLOC_CTX *mem_ctx, - const char *link_dn, - const char *gpo_dn) -{ - ADS_STATUS status; - const char *attrs[] = {"gPLink", NULL}; - LDAPMessage *res = NULL; - const char *gp_link, *gp_link_new = NULL; - ADS_MODLIST mods; - - /* check for a sane gpo_dn */ - if (gpo_dn[0] != '[') { - DEBUG(10,("ads_delete_gpo_link: first char not: [\n")); - return ADS_ERROR(LDAP_INVALID_DN_SYNTAX); - } - - if (gpo_dn[strlen(gpo_dn)] != ']') { - DEBUG(10,("ads_delete_gpo_link: last char not: ]\n")); - return ADS_ERROR(LDAP_INVALID_DN_SYNTAX); - } - - status = ads_search_dn(ads, &res, link_dn, attrs); - if (!ADS_ERR_OK(status)) { - DEBUG(10,("ads_delete_gpo_link: search failed with %s\n", - ads_errstr(status))); - return status; - } - - if (ads_count_replies(ads, res) != 1) { - DEBUG(10,("ads_delete_gpo_link: no result\n")); - ads_msgfree(ads, res); - return ADS_ERROR(LDAP_NO_SUCH_OBJECT); - } - - gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink"); - if (gp_link == NULL) { - return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE); - } - - /* find link to delete */ - /* gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]", gp_link, - gpo_dn, gpo_opt); */ - - ads_msgfree(ads, res); - ADS_ERROR_HAVE_NO_MEMORY(gp_link_new); - - mods = ads_init_mods(mem_ctx); - ADS_ERROR_HAVE_NO_MEMORY(mods); - - status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new); - if (!ADS_ERR_OK(status)) { - return status; - } - - return ads_gen_mod(ads, link_dn, mods); -} - -/**************************************************************** - parse a GROUP_POLICY_OBJECT structure from an LDAPMessage result -****************************************************************/ - - ADS_STATUS ads_parse_gpo(ADS_STRUCT *ads, - TALLOC_CTX *mem_ctx, - LDAPMessage *res, - const char *gpo_dn, - struct GROUP_POLICY_OBJECT *gpo) -{ - ZERO_STRUCTP(gpo); - - ADS_ERROR_HAVE_NO_MEMORY(res); - - if (gpo_dn) { - gpo->ds_path = talloc_strdup(mem_ctx, gpo_dn); - } else { - gpo->ds_path = ads_get_dn(ads, mem_ctx, res); - } - - ADS_ERROR_HAVE_NO_MEMORY(gpo->ds_path); - - if (!ads_pull_uint32(ads, res, "versionNumber", &gpo->version)) { - return ADS_ERROR(LDAP_NO_MEMORY); - } - - if (!ads_pull_uint32(ads, res, "flags", &gpo->options)) { - return ADS_ERROR(LDAP_NO_MEMORY); - } - - gpo->file_sys_path = ads_pull_string(ads, mem_ctx, res, - "gPCFileSysPath"); - ADS_ERROR_HAVE_NO_MEMORY(gpo->file_sys_path); - - gpo->display_name = ads_pull_string(ads, mem_ctx, res, - "displayName"); - ADS_ERROR_HAVE_NO_MEMORY(gpo->display_name); - - gpo->name = ads_pull_string(ads, mem_ctx, res, - "name"); - ADS_ERROR_HAVE_NO_MEMORY(gpo->name); - - gpo->machine_extensions = ads_pull_string(ads, mem_ctx, res, - "gPCMachineExtensionNames"); - gpo->user_extensions = ads_pull_string(ads, mem_ctx, res, - "gPCUserExtensionNames"); - - ads_pull_sd(ads, mem_ctx, res, "ntSecurityDescriptor", - &gpo->security_descriptor); - ADS_ERROR_HAVE_NO_MEMORY(gpo->security_descriptor); - - return ADS_ERROR(LDAP_SUCCESS); -} - -/**************************************************************** - get a GROUP_POLICY_OBJECT structure based on different input parameters -****************************************************************/ - -ADS_STATUS ads_get_gpo(ADS_STRUCT *ads, - TALLOC_CTX *mem_ctx, - const char *gpo_dn, - const char *display_name, - const char *guid_name, - struct GROUP_POLICY_OBJECT *gpo) -{ - ADS_STATUS status; - LDAPMessage *res = NULL; - char *dn; - const char *filter; - const char *attrs[] = { - "cn", - "displayName", - "flags", - "gPCFileSysPath", - "gPCFunctionalityVersion", - "gPCMachineExtensionNames", - "gPCUserExtensionNames", - "gPCWQLFilter", - "name", - "ntSecurityDescriptor", - "versionNumber", - NULL}; - uint32_t sd_flags = DACL_SECURITY_INFORMATION; - - ZERO_STRUCTP(gpo); - - if (!gpo_dn && !display_name && !guid_name) { - return ADS_ERROR(LDAP_NO_SUCH_OBJECT); - } - - if (gpo_dn) { - - if (strnequal(gpo_dn, "LDAP://", strlen("LDAP://")) != 0) { - gpo_dn = gpo_dn + strlen("LDAP://"); - } - - status = ads_search_retry_dn_sd_flags(ads, &res, - sd_flags, - gpo_dn, attrs); - - } else if (display_name || guid_name) { - - filter = talloc_asprintf(mem_ctx, - "(&(objectclass=groupPolicyContainer)(%s=%s))", - display_name ? "displayName" : "name", - display_name ? display_name : guid_name); - ADS_ERROR_HAVE_NO_MEMORY(filter); - - status = ads_do_search_all_sd_flags(ads, ads->config.bind_path, - LDAP_SCOPE_SUBTREE, filter, - attrs, sd_flags, &res); - } - - if (!ADS_ERR_OK(status)) { - DEBUG(10,("ads_get_gpo: search failed with %s\n", - ads_errstr(status))); - return status; - } - - if (ads_count_replies(ads, res) != 1) { - DEBUG(10,("ads_get_gpo: no result\n")); - ads_msgfree(ads, res); - return ADS_ERROR(LDAP_NO_SUCH_OBJECT); - } - - dn = ads_get_dn(ads, mem_ctx, res); - if (dn == NULL) { - ads_msgfree(ads, res); - return ADS_ERROR(LDAP_NO_MEMORY); - } - - status = ads_parse_gpo(ads, mem_ctx, res, dn, gpo); - ads_msgfree(ads, res); - TALLOC_FREE(dn); - - return status; -} - -/**************************************************************** - add a gplink to the GROUP_POLICY_OBJECT linked list -****************************************************************/ - -static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads, - TALLOC_CTX *mem_ctx, - struct GROUP_POLICY_OBJECT **gpo_list, - const char *link_dn, - struct GP_LINK *gp_link, - enum GPO_LINK_TYPE link_type, - bool only_add_forced_gpos, - const struct nt_user_token *token) -{ - ADS_STATUS status; - int i; - - for (i = 0; i < gp_link->num_links; i++) { - - struct GROUP_POLICY_OBJECT *new_gpo = NULL; - - if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) { - DEBUG(10,("skipping disabled GPO\n")); - continue; - } - - if (only_add_forced_gpos) { - - if (!(gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED)) { - DEBUG(10,("skipping nonenforced GPO link " - "because GPOPTIONS_BLOCK_INHERITANCE " - "has been set\n")); - continue; - } else { - DEBUG(10,("adding enforced GPO link although " - "the GPOPTIONS_BLOCK_INHERITANCE " - "has been set\n")); - } - } - - new_gpo = TALLOC_ZERO_P(mem_ctx, struct GROUP_POLICY_OBJECT); - ADS_ERROR_HAVE_NO_MEMORY(new_gpo); - - status = ads_get_gpo(ads, mem_ctx, gp_link->link_names[i], - NULL, NULL, new_gpo); - if (!ADS_ERR_OK(status)) { - DEBUG(10,("failed to get gpo: %s\n", - gp_link->link_names[i])); - return status; - } - - status = ADS_ERROR_NT(gpo_apply_security_filtering(new_gpo, - token)); - if (!ADS_ERR_OK(status)) { - DEBUG(10,("skipping GPO \"%s\" as object " - "has no access to it\n", - new_gpo->display_name)); - TALLOC_FREE(new_gpo); - continue; - } - - new_gpo->link = link_dn; - new_gpo->link_type = link_type; - - DLIST_ADD(*gpo_list, new_gpo); - - DEBUG(10,("add_gplink_to_gplist: added GPLINK #%d %s " - "to GPO list\n", i, gp_link->link_names[i])); - } - - return ADS_ERROR(LDAP_SUCCESS); -} - -/**************************************************************** -****************************************************************/ - -ADS_STATUS ads_get_sid_token(ADS_STRUCT *ads, - TALLOC_CTX *mem_ctx, - const char *dn, - struct nt_user_token **token) -{ - ADS_STATUS status; - DOM_SID object_sid; - DOM_SID primary_group_sid; - DOM_SID *ad_token_sids; - size_t num_ad_token_sids = 0; - DOM_SID *token_sids; - size_t num_token_sids = 0; - struct nt_user_token *new_token = NULL; - int i; - - status = ads_get_tokensids(ads, mem_ctx, dn, - &object_sid, &primary_group_sid, - &ad_token_sids, &num_ad_token_sids); - if (!ADS_ERR_OK(status)) { - return status; - } - - token_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, 1); - ADS_ERROR_HAVE_NO_MEMORY(token_sids); - - status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx, - &primary_group_sid, - &token_sids, - &num_token_sids)); - if (!ADS_ERR_OK(status)) { - return status; - } - - for (i = 0; i < num_ad_token_sids; i++) { - - if (sid_check_is_in_builtin(&ad_token_sids[i])) { - continue; - } - - status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx, - &ad_token_sids[i], - &token_sids, - &num_token_sids)); - if (!ADS_ERR_OK(status)) { - return status; - } - } - - new_token = create_local_nt_token(mem_ctx, &object_sid, false, - num_token_sids, token_sids); - ADS_ERROR_HAVE_NO_MEMORY(new_token); - - *token = new_token; - - debug_nt_user_token(DBGC_CLASS, 5, *token); - - return ADS_ERROR_LDAP(LDAP_SUCCESS); -} - -/**************************************************************** -****************************************************************/ - -static ADS_STATUS add_local_policy_to_gpo_list(TALLOC_CTX *mem_ctx, - struct GROUP_POLICY_OBJECT **gpo_list, - enum GPO_LINK_TYPE link_type) -{ - struct GROUP_POLICY_OBJECT *gpo = NULL; - - ADS_ERROR_HAVE_NO_MEMORY(gpo_list); - - gpo = TALLOC_ZERO_P(mem_ctx, struct GROUP_POLICY_OBJECT); - ADS_ERROR_HAVE_NO_MEMORY(gpo); - - gpo->name = talloc_strdup(mem_ctx, "Local Policy"); - ADS_ERROR_HAVE_NO_MEMORY(gpo->name); - - gpo->display_name = talloc_strdup(mem_ctx, "Local Policy"); - ADS_ERROR_HAVE_NO_MEMORY(gpo->display_name); - - gpo->link_type = link_type; - - DLIST_ADD(*gpo_list, gpo); - - return ADS_ERROR_NT(NT_STATUS_OK); -} - -/**************************************************************** - get the full list of GROUP_POLICY_OBJECTs for a given dn -****************************************************************/ - -ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads, - TALLOC_CTX *mem_ctx, - const char *dn, - uint32_t flags, - const struct nt_user_token *token, - struct GROUP_POLICY_OBJECT **gpo_list) -{ - /* (L)ocal (S)ite (D)omain (O)rganizational(U)nit */ - - ADS_STATUS status; - struct GP_LINK gp_link; - const char *parent_dn, *site_dn, *tmp_dn; - bool add_only_forced_gpos = false; - - ZERO_STRUCTP(gpo_list); - - if (!dn) { - return ADS_ERROR(LDAP_PARAM_ERROR); - } - - DEBUG(10,("ads_get_gpo_list: getting GPO list for [%s]\n", dn)); - - /* (L)ocal */ - status = add_local_policy_to_gpo_list(mem_ctx, gpo_list, - GP_LINK_LOCAL); - if (!ADS_ERR_OK(status)) { - return status; - } - - /* (S)ite */ - - /* are site GPOs valid for users as well ??? */ - if (flags & GPO_LIST_FLAG_MACHINE) { - - status = ads_site_dn_for_machine(ads, mem_ctx, - ads->config.ldap_server_name, - &site_dn); - if (!ADS_ERR_OK(status)) { - return status; - } - - DEBUG(10,("ads_get_gpo_list: query SITE: [%s] for GPOs\n", - site_dn)); - - status = ads_get_gpo_link(ads, mem_ctx, site_dn, &gp_link); - if (ADS_ERR_OK(status)) { - - if (DEBUGLEVEL >= 100) { - dump_gplink(ads, mem_ctx, &gp_link); - } - - status = add_gplink_to_gpo_list(ads, mem_ctx, gpo_list, - site_dn, &gp_link, - GP_LINK_SITE, - add_only_forced_gpos, - token); - if (!ADS_ERR_OK(status)) { - return status; - } - - if (flags & GPO_LIST_FLAG_SITEONLY) { - return ADS_ERROR(LDAP_SUCCESS); - } - - /* inheritance can't be blocked at the site level */ - } - } - - tmp_dn = dn; - - while ((parent_dn = ads_parent_dn(tmp_dn)) && - (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) { - - /* (D)omain */ - - /* An account can just be a member of one domain */ - if (strncmp(parent_dn, "DC=", strlen("DC=")) == 0) { - - DEBUG(10,("ads_get_gpo_list: query DC: [%s] for GPOs\n", - parent_dn)); - - status = ads_get_gpo_link(ads, mem_ctx, parent_dn, - &gp_link); - if (ADS_ERR_OK(status)) { - - if (DEBUGLEVEL >= 100) { - dump_gplink(ads, mem_ctx, &gp_link); - } - - /* block inheritance from now on */ - if (gp_link.gp_opts & - GPOPTIONS_BLOCK_INHERITANCE) { - add_only_forced_gpos = true; - } - - status = add_gplink_to_gpo_list(ads, - mem_ctx, - gpo_list, - parent_dn, - &gp_link, - GP_LINK_DOMAIN, - add_only_forced_gpos, - token); - if (!ADS_ERR_OK(status)) { - return status; - } - } - } - - tmp_dn = parent_dn; - } - - /* reset dn again */ - tmp_dn = dn; - - while ((parent_dn = ads_parent_dn(tmp_dn)) && - (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) { - - - /* (O)rganizational(U)nit */ - - /* An account can be a member of more OUs */ - if (strncmp(parent_dn, "OU=", strlen("OU=")) == 0) { - - DEBUG(10,("ads_get_gpo_list: query OU: [%s] for GPOs\n", - parent_dn)); - - status = ads_get_gpo_link(ads, mem_ctx, parent_dn, - &gp_link); - if (ADS_ERR_OK(status)) { - - if (DEBUGLEVEL >= 100) { - dump_gplink(ads, mem_ctx, &gp_link); - } - - /* block inheritance from now on */ - if (gp_link.gp_opts & - GPOPTIONS_BLOCK_INHERITANCE) { - add_only_forced_gpos = true; - } - - status = add_gplink_to_gpo_list(ads, - mem_ctx, - gpo_list, - parent_dn, - &gp_link, - GP_LINK_OU, - add_only_forced_gpos, - token); - if (!ADS_ERR_OK(status)) { - return status; - } - } - } - - tmp_dn = parent_dn; - - }; - - return ADS_ERROR(LDAP_SUCCESS); -} - -#endif /* HAVE_LDAP */ diff --git a/source4/libgpo/ads_convenience.c b/source4/libgpo/ads_convenience.c new file mode 100644 index 0000000000..1c64197b3d --- /dev/null +++ b/source4/libgpo/ads_convenience.c @@ -0,0 +1,248 @@ +/* + Samba CIFS implementation + ADS convenience functions for GPO + + Copyright (C) 2001 Andrew Tridgell (from samba3 ads.c) + Copyright (C) 2001 Remus Koos (from samba3 ads.c) + Copyright (C) 2001 Andrew Bartlett (from samba3 ads.c) + Copyright (C) 2008 Jelmer Vernooij, jelmer@samba.org + Copyright (C) 2008 Wilco Baan Hofman, wilco@baanhofman.nl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "libnet/libnet.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "libgpo/source/ads_convenience.h" + +WERROR ads_startup (struct libnet_context *netctx, ADS_STRUCT **ads) +{ + *ads = talloc(netctx, ADS_STRUCT); + *ads->netctx = netctx; + + ads_connect(*ads); + + return WERR_OK; +} + +ADS_STATUS ads_connect(ADS_STRUCT *ads) +{ + struct libnet_lookup_DCs *io; + char *url; + + io = talloc_zero(ads, struct libnet_lookup_DCs); + + /* We are looking for the PDC of the active domain. */ + io->in.name_type = NBT_NAME_PDC; + io->in.domain_name = lp_workgroup(ads->netctx->lp_ctx); + libnet_lookupDCs(ads->netctx, ads, io); + + url = talloc_asprintf(ads, "ldap://%s", io->out.dcs[0]); + ads->ldbctx = ldb_wrap_connect(ads, ads->netctx->event_ctx, ads->netctx->lp_ctx, + url, NULL, ads->netctx->cred, 0, NULL); + if (ads->ldbctx == NULL) { + return ADS_STATUS_NT(NT_STATUS_UNSUCCESSFUL); + } + + return ADS_STATUS_NT(NT_STATUS_OK); +} + +ADS_STATUS ads_search_dn(ADS_STRUCT *ads, LDAPMessage **res, + const char *dn, const char **attrs) +{ + ADS_STATUS status; + + status.err_state = ldb_search(ads->ldbctx, ads, res, + ldb_dn_new(ads, ads->ldbctx, dn), + LDB_SCOPE_BASE, + attrs, + "(objectclass=*)"); + + status.error_type = ENUM_ADS_ERROR_LDAP; + return status; +} + +const char * ads_get_dn(ADS_STRUCT *ads, LDAPMessage *res) +{ + return ldb_dn_get_linearized(res->msgs[0]->dn); +} + +bool ads_pull_sd(ADS_STRUCT *ads, TALLOC_CTX *ctx, LDAPMessage *res, const char *field, struct security_descriptor **sd) +{ + struct ldb_val *val; + struct ndr_err_code ndr_err; + + val = ldb_msg_find_ldb_val(res->msgs[0], field); + + *sd = talloc(ctx, struct security_descriptor); + if (*sd == NULL) { + return -1; + } + /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */ + ndr_err = ndr_pull_struct_blob(val, *sd, NULL, *sd, + (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(*sd); + return -1; + } + return 0; +} + +ADS_STATUS ads_search_retry_dn_sd_flags(ADS_STRUCT *ads, LDAPMessage **res, uint32_t sd_flags, + const char *dn, const char **attrs) +{ + return ads_search_sd_flags(ads, dn, LDB_SCOPE_BASE, "(objectclass=*)", attrs, sd_flags, res); +} + +static ADS_STATUS ads_do_search_all_sd_flags (ADS_STRUCT *ads, const char *dn, int scope, + const char *filter, const char **attrs, + uint32_t sd_flags, LDAPMessage **res) +{ + int count = 3; + int rv; + struct ldb_request *req; + struct ldb_control **controls; + struct ldb_parse_tree *tree; + + controls = talloc_zero_array(ads, struct ldb_control *, 2); + controls[0] = talloc(ads, struct ldb_control); + controls[0]->oid = LDB_CONTROL_SD_FLAGS_OID; + controls[0]->data = &sd_flags; + controls[0]->critical = 1; + + tree = ldb_parse_tree(ads, filter); + + rv = ldb_build_search_req_ex(&req, ads->ldbctx, ads, res, dn, scope, tree, attrs, controls, + res, ldb_search_default_callback, NULL); + if (rv != LDB_SUCCESS) { + talloc_free(*res); + talloc_free(req); + talloc_free(tree); + return ADS_STATUS(irv); + } + rv = ldb_request(ads->ldbctx, req); + if (rv == LDB_SUCCESS) { + rv = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(req); + talloc_free(tree); + return ADS_STATUS(rv); + +} + +const char * ads_pull_string(ADS_STRUCT *ads, TALLOC_CTX *ctx, LDAPMessage *res, const char *field) +{ + return ldb_msg_find_attr_as_string(res->msgs[0], field, NULL); +} + +bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *res, const char *field, uint32_t *ret) +{ + if (ldb_msg_find_element(res->msgs[0], field) == NULL) { + return false; + } + *ret = ldb_msg_find_attr_as_uint(res->msgs[0], field, 0); + return true; +} + + +int ads_count_replies(ADS_STRUCT *ads, LDAPMessage *res) +{ + return res->count; +} + +ADS_STATUS ads_msgfree(ADS_STRUCT *ads, LDAPMessage *res) +{ + talloc_free(res); +} + +/* + do a rough conversion between ads error codes and NT status codes + we'll need to fill this in more +*/ +NTSTATUS ads_ntstatus(ADS_STATUS status) +{ + switch (status.error_type) { + case ENUM_ADS_ERROR_NT: + return status.err.nt_status; + case ENUM_ADS_ERROR_SYSTEM: + return map_nt_error_from_unix(status.err.rc); + case ENUM_ADS_ERROR_LDAP: + if (status.err.rc == LDB_SUCCESS) { + return NT_STATUS_OK; + } + return NT_STATUS_UNSUCCESSFUL; + default: + break; + } + + if (ADS_ERR_OK(status)) { + return NT_STATUS_OK; + } + return NT_STATUS_UNSUCCESSFUL; +} + +/* + return a string for an error from an ads routine +*/ +const char *ads_errstr(ADS_STATUS status) +{ + switch (status.error_type) { + case ENUM_ADS_ERROR_SYSTEM: + return strerror(status.err.rc); + case ENUM_ADS_ERROR_LDAP: + return msg; + case ENUM_ADS_ERROR_NT: + return get_friendly_nt_error_msg(ads_ntstatus(status)); + default: + return "Unknown ADS error type!? (not compiled in?)"; + } +} + +ADS_STATUS ads_build_ldap_error(int ldb_error) +{ + ADS_STATUS ret; + ret.err.rc = ldb_error; + ret.error_type = ENUM_ADS_ERROR_LDAP; + return ret; +} + +ADS_STATUS ads_build_nt_error(NTSTATUS nt_status) +{ + ADS_STATUS ret; + ret.err.nt_status = nt_status; + ret.error_type = ENUM_ADS_ERROR_NT; + return ret; +} + +/* + FIXME + Stub write functions, these do not do anything, though they should. -- Wilco +*/ + +ADS_MODLIST ads_init_mods(TALLOC_CTX *ctx) +{ + return NULL; +} + +ADS_STATUS ads_mod_str(TALLOC_CTX *ctx, ADS_MODLIST *mods, const char *name, const char *val) +{ + return ADS_ERROR_NT(NT_STATUS_NOT_IMPLEMENTED); +} + +ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods) +{ + return ADS_ERROR_NT(NT_STATUS_NOT_IMPLEMENTED); +} diff --git a/source4/libgpo/ads_convenience.h b/source4/libgpo/ads_convenience.h new file mode 100644 index 0000000000..13bd54b588 --- /dev/null +++ b/source4/libgpo/ads_convenience.h @@ -0,0 +1,61 @@ +/* + Samba CIFS implementation + ADS convenience functions for GPO + + Copyright (C) 2008 Jelmer Vernooij, jelmer@samba.org + Copyright (C) 2008 Wilco Baan Hofman, wilco@baanhofman.nl + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __ADS_CONVENIENCE_H__ +#define __ADS_CONVENIENCE_H__ + +#define ADS_ERR_OK(status) ((status.error_type == ENUM_ADS_ERROR_NT) ? NT_STATUS_IS_OK(status.err.nt_status):(status.err.rc == 0)) +#define ADS_ERROR(rc) ads_build_ldap_error(rc) +#define ADS_ERROR_NT(rc) ads_build_nt_error(rc) +#define ADS_ERROR_HAVE_NO_MEMORY(x) do { \ + if (!(x)) {\ + return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);\ + }\ +} while (0) + +#define LDAP_SCOPE_BASE LDB_SCOPE_BASE +#define LDAP_SCOPE_SUBTREE LDB_SCOPE_SUBTREE +#define LDAP_SCOPE_ONELEVEL LDB_SCOPE_ONELEVEL + + + + +typedef struct { + struct libnet_context *netctx; + struct ldb_context *ldbctx; +} ADS_STRUCT; + +typedef struct ldb_result LDAPMessage; +typedef struct void ** ADS_MODLIST; + +/* there are 3 possible types of errors the ads subsystem can produce */ +enum ads_error_type { ENUM_ADS_ERROR_LDAP, ENUM_ADS_ERROR_SYSTEM, ENUM_ADS_ERROR_NT}; + +typedef struct { + enum ads_error_type error_type; + union err_state{ + int rc; + NTSTATUS nt_status; + } err; + int minor_status; +} ADS_STATUS; + +#endif -- cgit