smbd:vfs: fix mis-spellings of hierarchy in comments
[samba.git] / libgpo / gpo_ldap.c
index 16c551ebabc4182fddc0f359ff0d5d43f65fc154..fec00053b4984a29fc0c085811b2817e1e087fb4 100644 (file)
  */
 
 #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
@@ -296,7 +295,7 @@ ADS_STATUS ads_add_gpo_link(ADS_STRUCT *ads,
        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) {
@@ -425,24 +424,30 @@ ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads,
        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");
@@ -451,7 +456,9 @@ ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads,
 
        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);
 }
@@ -484,7 +491,7 @@ ADS_STATUS ads_get_gpo(ADS_STRUCT *ads,
                "ntSecurityDescriptor",
                "versionNumber",
                NULL};
-       uint32_t sd_flags = DACL_SECURITY_INFORMATION;
+       uint32_t sd_flags = SECINFO_DACL;
 
        ZERO_STRUCTP(gpo);
 
@@ -547,18 +554,28 @@ ADS_STATUS ads_get_gpo(ADS_STRUCT *ads,
 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"));
@@ -567,7 +584,7 @@ static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads,
 
                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"));
@@ -579,7 +596,7 @@ static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads,
                        }
                }
 
-               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],
@@ -587,6 +604,13 @@ static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads,
                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;
                }
 
@@ -603,7 +627,8 @@ static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads,
                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]));
@@ -618,16 +643,16 @@ static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads,
 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,
@@ -637,7 +662,7 @@ ADS_STATUS ads_get_sid_token(ADS_STRUCT *ads,
                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,
@@ -669,7 +694,7 @@ ADS_STATUS ads_get_sid_token(ADS_STRUCT *ads,
 
        *token = new_token;
 
-       debug_nt_user_token(DBGC_CLASS, 5, *token);
+       security_token_debug(DBGC_CLASS, 5, *token);
 
        return ADS_ERROR_LDAP(LDAP_SUCCESS);
 }
@@ -685,7 +710,7 @@ static ADS_STATUS add_local_policy_to_gpo_list(TALLOC_CTX *mem_ctx,
 
        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");
@@ -702,17 +727,28 @@ static ADS_STATUS add_local_policy_to_gpo_list(TALLOC_CTX *mem_ctx,
 }
 
 /****************************************************************
- 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;
@@ -720,59 +756,66 @@ ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
        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)) &&
@@ -791,18 +834,13 @@ ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
                        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,
@@ -811,58 +849,101 @@ ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
                                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);
 }