*/
#include "includes.h"
-#if _SAMBA_BUILD_ == 4
#include "libgpo/gpo.h"
-#include "source4/libgpo/ads_convenience.h"
-#endif
+#include "auth.h"
+#include "../libcli/security/security.h"
/****************************************************************
parse the raw extension string into a GP_EXT structure
const char *gp_link, *gp_link_new;
ADS_MODLIST mods;
- /* although ADS allows to set anything here, we better check here if
+ /* although ADS allows one to set anything here, we better check here if
* the gpo_dn is sane */
if (!strnequal(gpo_dn, "LDAP://CN={", strlen("LDAP://CN={")) != 0) {
ADS_ERROR_HAVE_NO_MEMORY(gpo->ds_path);
if (!ads_pull_uint32(ads, res, "versionNumber", &gpo->version)) {
- return ADS_ERROR(LDAP_NO_MEMORY);
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
}
if (!ads_pull_uint32(ads, res, "flags", &gpo->options)) {
- return ADS_ERROR(LDAP_NO_MEMORY);
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
}
gpo->file_sys_path = ads_pull_string(ads, mem_ctx, res,
"gPCFileSysPath");
- ADS_ERROR_HAVE_NO_MEMORY(gpo->file_sys_path);
+ if (gpo->file_sys_path == NULL) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
gpo->display_name = ads_pull_string(ads, mem_ctx, res,
"displayName");
- ADS_ERROR_HAVE_NO_MEMORY(gpo->display_name);
+ if (gpo->display_name == NULL) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
gpo->name = ads_pull_string(ads, mem_ctx, res,
"name");
- ADS_ERROR_HAVE_NO_MEMORY(gpo->name);
+ if (gpo->name == NULL) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
gpo->machine_extensions = ads_pull_string(ads, mem_ctx, res,
"gPCMachineExtensionNames");
ads_pull_sd(ads, mem_ctx, res, "ntSecurityDescriptor",
&gpo->security_descriptor);
- ADS_ERROR_HAVE_NO_MEMORY(gpo->security_descriptor);
+ if (gpo->security_descriptor == NULL) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
return ADS_ERROR(LDAP_SUCCESS);
}
"ntSecurityDescriptor",
"versionNumber",
NULL};
- uint32_t sd_flags = DACL_SECURITY_INFORMATION;
+ uint32_t sd_flags = SECINFO_DACL;
ZERO_STRUCTP(gpo);
static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads,
TALLOC_CTX *mem_ctx,
struct GROUP_POLICY_OBJECT **gpo_list,
+ struct GROUP_POLICY_OBJECT **forced_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)
+ const struct security_token *token)
{
ADS_STATUS status;
- int i;
-
- for (i = 0; i < gp_link->num_links; i++) {
-
+ uint32_t count;
+
+ /*
+ * Note: DLIST_ADD pushes to the front,
+ * so loop from last to first to get the
+ * order right.
+ */
+ for (count = gp_link->num_links; count > 0; count--) {
+ /* NB. Index into arrays is one less than counter. */
+ uint32_t i = count - 1;
+ struct GROUP_POLICY_OBJECT **target_list = NULL;
struct GROUP_POLICY_OBJECT *new_gpo = NULL;
+ bool is_forced =
+ (gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED) != 0;
if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) {
DEBUG(10,("skipping disabled GPO\n"));
if (only_add_forced_gpos) {
- if (!(gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED)) {
+ if (!is_forced) {
DEBUG(10,("skipping nonenforced GPO link "
"because GPOPTIONS_BLOCK_INHERITANCE "
"has been set\n"));
}
}
- new_gpo = TALLOC_ZERO_P(mem_ctx, struct GROUP_POLICY_OBJECT);
+ new_gpo = talloc_zero(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],
if (!ADS_ERR_OK(status)) {
DEBUG(10,("failed to get gpo: %s\n",
gp_link->link_names[i]));
+ if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
+ (status.err.rc == LDAP_NO_SUCH_ATTRIBUTE)) {
+ DEBUG(10,("skipping empty gpo: %s\n",
+ gp_link->link_names[i]));
+ talloc_free(new_gpo);
+ continue;
+ }
return status;
}
new_gpo->link = link_dn;
new_gpo->link_type = link_type;
- DLIST_ADD(*gpo_list, new_gpo);
+ target_list = is_forced ? forced_gpo_list : gpo_list;
+ DLIST_ADD(*target_list, new_gpo);
DEBUG(10,("add_gplink_to_gplist: added GPLINK #%d %s "
"to GPO list\n", i, gp_link->link_names[i]));
ADS_STATUS ads_get_sid_token(ADS_STRUCT *ads,
TALLOC_CTX *mem_ctx,
const char *dn,
- struct nt_user_token **token)
+ struct security_token **token)
{
ADS_STATUS status;
- DOM_SID object_sid;
- DOM_SID primary_group_sid;
- DOM_SID *ad_token_sids;
+ struct dom_sid object_sid;
+ struct dom_sid primary_group_sid;
+ struct 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;
+ struct dom_sid *token_sids;
+ uint32_t num_token_sids = 0;
+ struct security_token *new_token = NULL;
int i;
status = ads_get_tokensids(ads, mem_ctx, dn,
return status;
}
- token_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, 1);
+ token_sids = talloc_array(mem_ctx, struct dom_sid, 1);
ADS_ERROR_HAVE_NO_MEMORY(token_sids);
status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx,
*token = new_token;
- debug_nt_user_token(DBGC_CLASS, 5, *token);
+ security_token_debug(DBGC_CLASS, 5, *token);
return ADS_ERROR_LDAP(LDAP_SUCCESS);
}
ADS_ERROR_HAVE_NO_MEMORY(gpo_list);
- gpo = TALLOC_ZERO_P(mem_ctx, struct GROUP_POLICY_OBJECT);
+ gpo = talloc_zero(mem_ctx, struct GROUP_POLICY_OBJECT);
ADS_ERROR_HAVE_NO_MEMORY(gpo);
gpo->name = talloc_strdup(mem_ctx, "Local Policy");
}
/****************************************************************
- get the full list of GROUP_POLICY_OBJECTs for a given dn
+ Get the full list of GROUP_POLICY_OBJECTs for a given dn.
****************************************************************/
-ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
+static ADS_STATUS ads_get_gpo_list_internal(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)
+ const struct security_token *token,
+ struct GROUP_POLICY_OBJECT **gpo_list,
+ struct GROUP_POLICY_OBJECT **forced_gpo_list)
{
- /* (L)ocal (S)ite (D)omain (O)rganizational(U)nit */
+ /*
+ * Push GPOs to gpo_list so that the traversal order of the list matches
+ * the order of application:
+ * (L)ocal (S)ite (D)omain (O)rganizational(U)nit
+ * For different domains and OUs: parent-to-child.
+ * Within same level of domains and OUs: Link order.
+ * Since GPOs are pushed to the front of gpo_list, GPOs have to be
+ * pushed in the opposite order of application (OUs first, local last,
+ * child-to-parent).
+ * Forced GPOs are appended in the end since they override all others.
+ */
ADS_STATUS status;
struct GP_LINK gp_link;
bool add_only_forced_gpos = false;
ZERO_STRUCTP(gpo_list);
+ ZERO_STRUCTP(forced_gpo_list);
if (!dn) {
return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
+ if (!ads_set_sasl_wrap_flags(ads, ADS_AUTH_SASL_SIGN)) {
+ return ADS_ERROR(LDAP_INVALID_CREDENTIALS);
+ }
+
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;
- }
+ tmp_dn = dn;
- /* (S)ite */
+ while ((parent_dn = ads_parent_dn(tmp_dn)) &&
+ (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) {
- /* 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;
- }
+ /* (O)rganizational(U)nit */
- DEBUG(10,("ads_get_gpo_list: query SITE: [%s] for GPOs\n",
- site_dn));
+ /* An account can be a member of more OUs */
+ if (strncmp(parent_dn, "OU=", strlen("OU=")) == 0) {
- status = ads_get_gpo_link(ads, mem_ctx, site_dn, &gp_link);
- if (ADS_ERR_OK(status)) {
+ DEBUG(10,("ads_get_gpo_list: query OU: [%s] for GPOs\n",
+ parent_dn));
- if (DEBUGLEVEL >= 100) {
- dump_gplink(ads, mem_ctx, &gp_link);
- }
+ status = ads_get_gpo_link(ads, mem_ctx, parent_dn,
+ &gp_link);
+ if (ADS_ERR_OK(status)) {
- status = add_gplink_to_gpo_list(ads, mem_ctx, gpo_list,
- site_dn, &gp_link,
- GP_LINK_SITE,
+ if (DEBUGLEVEL >= 100) {
+ dump_gplink(&gp_link);
+ }
+
+ status = add_gplink_to_gpo_list(ads,
+ mem_ctx,
+ gpo_list,
+ forced_gpo_list,
+ parent_dn,
+ &gp_link,
+ GP_LINK_OU,
add_only_forced_gpos,
token);
- if (!ADS_ERR_OK(status)) {
- return status;
- }
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
- if (flags & GPO_LIST_FLAG_SITEONLY) {
- return ADS_ERROR(LDAP_SUCCESS);
+ /* block inheritance from now on */
+ if (gp_link.gp_opts &
+ GPOPTIONS_BLOCK_INHERITANCE) {
+ add_only_forced_gpos = true;
+ }
}
-
- /* inheritance can't be blocked at the site level */
}
+
+ tmp_dn = parent_dn;
+
}
+ /* reset dn again */
tmp_dn = dn;
while ((parent_dn = ads_parent_dn(tmp_dn)) &&
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;
+ dump_gplink(&gp_link);
}
status = add_gplink_to_gpo_list(ads,
mem_ctx,
gpo_list,
+ forced_gpo_list,
parent_dn,
&gp_link,
GP_LINK_DOMAIN,
if (!ADS_ERR_OK(status)) {
return status;
}
+
+ /* block inheritance from now on */
+ if (gp_link.gp_opts &
+ GPOPTIONS_BLOCK_INHERITANCE) {
+ add_only_forced_gpos = true;
+ }
}
}
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 */
+ /* (S)ite */
- /* An account can be a member of more OUs */
- if (strncmp(parent_dn, "OU=", strlen("OU=")) == 0) {
+ /* are site GPOs valid for users as well ??? */
+ if (flags & GPO_LIST_FLAG_MACHINE) {
- DEBUG(10,("ads_get_gpo_list: query OU: [%s] for GPOs\n",
- parent_dn));
+ status = ads_site_dn_for_machine(ads, mem_ctx,
+ ads->config.ldap_server_name,
+ &site_dn);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
- status = ads_get_gpo_link(ads, mem_ctx, parent_dn,
- &gp_link);
- if (ADS_ERR_OK(status)) {
+ DEBUG(10,("ads_get_gpo_list: query SITE: [%s] for GPOs\n",
+ site_dn));
- if (DEBUGLEVEL >= 100) {
- dump_gplink(ads, mem_ctx, &gp_link);
- }
+ status = ads_get_gpo_link(ads, mem_ctx, site_dn, &gp_link);
+ if (ADS_ERR_OK(status)) {
- /* block inheritance from now on */
- if (gp_link.gp_opts &
- GPOPTIONS_BLOCK_INHERITANCE) {
- add_only_forced_gpos = true;
- }
+ if (DEBUGLEVEL >= 100) {
+ dump_gplink(&gp_link);
+ }
- status = add_gplink_to_gpo_list(ads,
+ status = add_gplink_to_gpo_list(ads,
mem_ctx,
gpo_list,
- parent_dn,
+ forced_gpo_list,
+ site_dn,
&gp_link,
- GP_LINK_OU,
+ GP_LINK_SITE,
add_only_forced_gpos,
token);
- if (!ADS_ERR_OK(status)) {
- return status;
- }
+ 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 = parent_dn;
+ /* (L)ocal */
+ status = add_local_policy_to_gpo_list(mem_ctx, gpo_list,
+ GP_LINK_LOCAL);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
- };
+ return ADS_ERROR(LDAP_SUCCESS);
+}
+
+/****************************************************************
+ Get the full list of GROUP_POLICY_OBJECTs for a given dn, wrapper
+ around ads_get_gpo_list_internal() that ensures correct ordering.
+****************************************************************/
+
+ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ uint32_t flags,
+ const struct security_token *token,
+ struct GROUP_POLICY_OBJECT **gpo_list)
+{
+ struct GROUP_POLICY_OBJECT *forced_gpo_list = NULL;
+ ADS_STATUS status;
+
+ status = ads_get_gpo_list_internal(ads,
+ mem_ctx,
+ dn,
+ flags,
+ token,
+ gpo_list,
+ &forced_gpo_list);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+ /*
+ * Append |forced_gpo_list| at the end of |gpo_list|,
+ * so that forced GPOs are applied on top of non enforced GPOs.
+ */
+ DLIST_CONCATENATE(*gpo_list, forced_gpo_list);
return ADS_ERROR(LDAP_SUCCESS);
}