From a3e0abad5341b96aa1909082778bd1abb6746c5a Mon Sep 17 00:00:00 2001
From: Yassir Elley <yelley@redhat.com>
Date: Tue, 9 Sep 2014 15:37:05 -0400
Subject: [PATCH] AD-GPO resolve conflicting policy settings correctly

---
 src/providers/ad/ad_gpo.c | 848 ++++++++++++++++++++++++++--------------------
 1 file changed, 474 insertions(+), 374 deletions(-)

diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
index de4d44166b85ccd85ed36bcb11f0596e0020af11..f3a6ebfd53118a95ae866e159f91ea84ae949e46 100644
--- a/src/providers/ad/ad_gpo.c
+++ b/src/providers/ad/ad_gpo.c
@@ -176,9 +176,8 @@ struct tevent_req *ad_gpo_process_cse_send(TALLOC_CTX *mem_ctx,
                                            int cached_gpt_version,
                                            int gpo_timeout_option);
 int ad_gpo_process_cse_recv(struct tevent_req *req,
-                            TALLOC_CTX *mem_ctx,
-                            int *_sysvol_gpt_version,
-                            const char **_policy_filename);
+                            TALLOC_CTX *mem_ctx);
+
 
 /* == ad_gpo_parse_map_options and helpers ==================================*/
 
@@ -1029,6 +1028,238 @@ check_rights(char **privilege_sids,
     return false;
 }
 
+
+static void dump_policy_file(enum gpo_map_type gpo_map_type,
+                                char **allowed_sids,
+                                int allowed_size,
+                                char **denied_sids,
+                                int denied_size)
+{
+    int j;
+
+    DEBUG(SSSDBG_TRACE_FUNC, "POLICY FILE:\n");
+    DEBUG(SSSDBG_TRACE_FUNC, "gpo_map_type: %d\n", gpo_map_type);
+    DEBUG(SSSDBG_TRACE_FUNC, "allowed_size = %d\n", allowed_size);
+    for (j= 0; j < allowed_size; j++) {
+        DEBUG(SSSDBG_TRACE_FUNC, "allowed_sids[%d] = %s\n", j,
+              allowed_sids[j]);
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, "denied_size = %d\n", denied_size);
+    for (j= 0; j < denied_size; j++) {
+        DEBUG(SSSDBG_TRACE_FUNC, " denied_sids[%d] = %s\n", j,
+              denied_sids[j]);
+    }
+}
+
+/*
+ * This function uses the input ini_config object to parse the logon right value
+ * associated with the input name. This value is a list of sids, and is used
+ * to populate the output parameters.
+ */
+static errno_t
+parse_logon_right_with_libini(TALLOC_CTX *mem_ctx,
+                              struct ini_cfgobj *ini_config,
+                              const char *name,
+                              int *_size,
+                              char ***_sids)
+{
+    int ret = 0;
+    struct value_obj *vobj = NULL;
+    char **ini_sids = NULL;
+    char *ini_sid = NULL;
+    int num_ini_sids = 0;
+    char **sids = NULL;
+    int i;
+    TALLOC_CTX *tmp_ctx = NULL;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ini_get_config_valueobj(RIGHTS_SECTION, name, ini_config,
+                                  INI_GET_FIRST_VALUE, &vobj);
+    if (ret != 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "ini_get_config_valueobj failed [%d][%s]\n", ret, strerror(ret));
+        goto done;
+    }
+    if (vobj == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "section/name not found: [%s][%s]\n",
+              RIGHTS_SECTION, name);
+        ret = EOK;
+        goto done;
+    }
+    ini_sids = ini_get_string_config_array(vobj, NULL, &num_ini_sids, &ret);
+
+    if (ret != 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "ini_get_string_config_array failed [%d][%s]\n",
+              ret, strerror(ret));
+        goto done;
+    }
+
+    sids = talloc_array(tmp_ctx, char *, num_ini_sids + 1);
+    if (sids == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    for (i = 0; i < num_ini_sids; i++) {
+        ini_sid = ini_sids[i];
+
+        /* remove the asterisk prefix found on sids in the .inf policy file */
+        if (ini_sid[0] == '*') {
+            ini_sid++;
+        }
+        sids[i] = talloc_strdup(sids, ini_sid);
+        if (sids[i] == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+    sids[i] = NULL;
+
+    *_size = num_ini_sids;
+    *_sids = talloc_steal(mem_ctx, sids);
+
+    ret = EOK;
+
+ done:
+
+    ini_free_string_config_array(ini_sids);
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+/*
+ * This function parses the cse-specific (GP_EXT_GUID_SECURITY) input data_buf,
+ * and uses the results to populate the output parameters with the list of
+ * allowed_sids and denied_sids. If the allowed_sids input or denied_sids input
+ * has been set to NULL by the caller, then this function will not return the
+ * allowed_sids or denied_sids, respectively, from the filename.
+ */
+static errno_t
+ad_gpo_parse_policy_file(TALLOC_CTX *mem_ctx,
+                         const char *filename,
+                         enum gpo_map_type gpo_map_type,
+                         char ***allowed_sids,
+                         int *allowed_size,
+                         char ***denied_sids,
+                         int *denied_size)
+{
+    struct ini_cfgfile *file_ctx = NULL;
+    struct ini_cfgobj *ini_config = NULL;
+    int ret;
+    char **allow_sids = NULL;
+    char **deny_sids = NULL;
+    int allow_size = 0;
+    int deny_size = 0;
+    const char *allow_key = NULL;
+    const char *deny_key = NULL;
+    TALLOC_CTX *tmp_ctx = NULL;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = ini_config_create(&ini_config);
+    if (ret != 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "ini_config_create failed [%d][%s]\n", ret, strerror(ret));
+        goto done;
+    }
+
+    ret = ini_config_file_open(filename, 0, &file_ctx);
+    if (ret != 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "ini_config_file_open failed [%d][%s]\n", ret, strerror(ret));
+        goto done;
+    }
+
+    ret = ini_config_parse(file_ctx, INI_STOP_ON_NONE, 0, 0, ini_config);
+    if (ret != 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "ini_config_parse failed [%d][%s]\n", ret, strerror(ret));
+        goto done;
+    }
+
+    switch (gpo_map_type) {
+    case GPO_MAP_INTERACTIVE:
+        allow_key = ALLOW_LOGON_INTERACTIVE;
+        deny_key = DENY_LOGON_INTERACTIVE;
+        break;
+    case GPO_MAP_REMOTE_INTERACTIVE:
+        allow_key = ALLOW_LOGON_REMOTE_INTERACTIVE;
+        deny_key = DENY_LOGON_REMOTE_INTERACTIVE;
+        break;
+    case GPO_MAP_NETWORK:
+        allow_key = ALLOW_LOGON_NETWORK;
+        deny_key = DENY_LOGON_NETWORK;
+        break;
+    case GPO_MAP_BATCH:
+        allow_key = ALLOW_LOGON_BATCH;
+        deny_key = DENY_LOGON_BATCH;
+        break;
+    case GPO_MAP_SERVICE:
+        allow_key = ALLOW_LOGON_SERVICE;
+        deny_key = DENY_LOGON_SERVICE;
+        break;
+    default:
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (allowed_sids != NULL) {
+        ret = parse_logon_right_with_libini(tmp_ctx,
+                                            ini_config,
+                                            allow_key,
+                                            &allow_size,
+                                            &allow_sids);
+        if (ret != 0) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "parse_logon_right_with_libini failed for %s [%d][%s]\n",
+                  allow_key, ret, strerror(ret));
+            goto done;
+        }
+
+        *allowed_sids = talloc_steal(mem_ctx, allow_sids);
+        *allowed_size = allow_size;
+    }
+
+    if (denied_sids != NULL) {
+        ret = parse_logon_right_with_libini(tmp_ctx,
+                                            ini_config,
+                                            deny_key,
+                                            &deny_size,
+                                            &deny_sids);
+        if (ret != 0) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "parse_logon_right_with_libini failed for %s [%d][%s]\n",
+                  deny_key, ret, strerror(ret));
+            goto done;
+        }
+
+        *denied_sids = talloc_steal(mem_ctx, deny_sids);
+        *denied_size = deny_size;
+    }
+
+ done:
+
+    if (ret != EOK) {
+      DEBUG(SSSDBG_CRIT_FAILURE, "Error encountered: %d.\n", ret);
+    }
+
+    ini_config_file_destroy(file_ctx);
+    ini_config_destroy(ini_config);
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 /*
  * This cse-specific function (GP_EXT_GUID_SECURITY) performs HBAC policy
  * application and determines whether logon access is granted or denied for
@@ -1072,19 +1303,8 @@ ad_gpo_access_check(TALLOC_CTX *mem_ctx,
     int ret;
     int j;
 
-    DEBUG(SSSDBG_TRACE_FUNC, "POLICY FILE:\n");
-    DEBUG(SSSDBG_TRACE_FUNC, "gpo_map_type: %d\n", gpo_map_type);
-    DEBUG(SSSDBG_TRACE_FUNC, "allowed_size = %d\n", allowed_size);
-    for (j= 0; j < allowed_size; j++) {
-        DEBUG(SSSDBG_TRACE_FUNC, "allowed_sids[%d] = %s\n", j,
-              allowed_sids[j]);
-    }
-
-    DEBUG(SSSDBG_TRACE_FUNC, "denied_size = %d\n", denied_size);
-    for (j= 0; j < denied_size; j++) {
-        DEBUG(SSSDBG_TRACE_FUNC, " denied_sids[%d] = %s\n", j,
-              denied_sids[j]);
-    }
+    dump_policy_file(gpo_map_type, allowed_sids, allowed_size,
+                     denied_sids, denied_size);
 
     ret = ad_gpo_get_sids(mem_ctx, user, domain, &user_sid,
                           &group_sids, &group_size);
@@ -1171,6 +1391,149 @@ static errno_t gpo_child_init(void)
     return EOK;
 }
 
+/*
+ * This cse-specific function (GP_EXT_GUID_SECURITY) performs HBAC policy
+ * processing and determines whether logon access is granted or denied for
+ * the {user,domain} tuple specified in the inputs. This function returns EOK
+ * to indicate that access is granted. Any other return value indicates that
+ * access is denied.
+ *
+ * Internally, this function parses each of the input policy_filenames
+ * (extracting the allowed_sids and denied_sids for the input gpo_map_type), and
+ * determines the gpo_index of the last policy_filename which contains an allow
+ * policy setting (allowed_gpo_index), as well as the gpo_index of the last
+ * policy_filename which contains a deny policy setting (denied_gpo_index).
+ *
+ * Since the policy_filenames are in priority order (with the highest priority
+ * appearing last), this function is essentially implementing the
+ * "last policy wins" mechanism. Note that this conflict resolution mechanism
+ * ("last policy wins") applies per policy setting. In other words, if more
+ * than one policy_filename contains the SeInteractiveLogonRight, then the
+ * last policy_filename "overwrites" all previous settings of that key.
+ * Similarly, if more than one policy_filename contains the
+ * SeDenyInteractiveLogonRight, then the last policy_filename "overwrites" all
+ * previous settings of that key.
+ */
+static errno_t ad_gpo_perform_hbac_processing(TALLOC_CTX *mem_ctx,
+                                              int num_cse_filtered_gpos,
+                                              const char **policy_filenames,
+                                              enum gpo_access_control_mode gpo_mode,
+                                              enum gpo_map_type gpo_map_type,
+                                              const char *user,
+                                              struct sss_domain_info *domain)
+{
+    int i;
+    int ret;
+    char **allowed_sids_temp;
+    int allowed_size_temp;
+    char **denied_sids_temp;
+    int denied_size_temp;
+    char **allowed_sids_result;
+    int allowed_size_result;
+    int allowed_gpo_index = -1;
+    char **denied_sids_result;
+    int denied_size_result;
+    int denied_gpo_index = -1;
+
+    /*
+     * for the given gpo_map_type, we parse each policy file, in priority order;
+     * we initialize the allowed_gpo_index and denied_gpo_index with -1;
+     * we keep track of the last gpo_index which has an allow policy setting;
+     * we keep track of the last gpo_index which has a deny policy setting;
+     */
+
+    for (i = 0; i < num_cse_filtered_gpos; i++) {
+
+        ret = ad_gpo_parse_policy_file(mem_ctx,
+                                       policy_filenames[i],
+                                       gpo_map_type,
+                                       &allowed_sids_temp,
+                                       &allowed_size_temp,
+                                       &denied_sids_temp,
+                                       &denied_size_temp);
+
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Cannot parse policy file: [%s][%d][%s]\n",
+                  policy_filenames[i], ret, strerror(ret));
+            goto done;
+        }
+
+        if (allowed_size_temp != 0) {
+            allowed_gpo_index = i;
+        }
+
+        if (denied_size_temp != 0) {
+            denied_gpo_index = i;
+        }
+
+        DEBUG(SSSDBG_TRACE_FUNC, "allowed_gpo_index: %d\n", allowed_gpo_index);
+        DEBUG(SSSDBG_TRACE_FUNC, "denied_gpo_index: %d\n", denied_gpo_index);
+        dump_policy_file(gpo_map_type, allowed_sids_temp, allowed_size_temp,
+                         denied_sids_temp, denied_size_temp);
+    }
+
+    /*
+     * if either gpo_index is -1, we set the corresponding size_result to 0;
+     * otherwise, we return the allowed and denied sids from the most
+     * recent gpo to have those settings (i.e. last gpo wins, since it has
+     * highest priority)
+     */
+    if (allowed_gpo_index != -1) {
+        ret = ad_gpo_parse_policy_file(mem_ctx,
+                                       policy_filenames[allowed_gpo_index],
+                                       gpo_map_type,
+                                       &allowed_sids_result,
+                                       &allowed_size_result,
+                                       NULL,
+                                       0);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Cannot parse policy file: [%s][%d][%s]\n",
+                  policy_filenames[allowed_gpo_index], ret, strerror(ret));
+            goto done;
+        }
+    } else {
+        /* none of the policy files contained an allow key for the gpo map type */
+        allowed_size_result = 0;
+    }
+
+    if (denied_gpo_index != -1) {
+        ret = ad_gpo_parse_policy_file(mem_ctx,
+                                       policy_filenames[denied_gpo_index],
+                                       gpo_map_type,
+                                       NULL,
+                                       0,
+                                       &denied_sids_result,
+                                       &denied_size_result);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Cannot parse policy file: [%s][%d][%s]\n",
+                  policy_filenames[denied_gpo_index], ret, strerror(ret));
+            goto done;
+        }
+    } else {
+        /* none of the policy files contained a deny key for the gpo map type */
+        denied_size_result = 0;
+    }
+
+    /* perform the access check with the resultant allowed_sids and denied_sids */
+    ret = ad_gpo_access_check
+        (mem_ctx, gpo_mode, gpo_map_type, user,
+         domain, allowed_sids_result, allowed_size_result,
+         denied_sids_result, denied_size_result);
+
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "GPO access check failed: [%d](%s)\n",
+              ret, strerror(ret));
+        goto done;
+    }
+
+ done:
+    return ret;
+}
+
 /* == ad_gpo_access_send/recv implementation ================================*/
 
 struct ad_gpo_access_state {
@@ -1193,6 +1556,7 @@ struct ad_gpo_access_state {
     struct gp_gpo **cse_filtered_gpos;
     int num_cse_filtered_gpos;
     int cse_gpo_index;
+    const char **policy_filenames;
 };
 
 static void ad_gpo_connect_done(struct tevent_req *subreq);
@@ -1361,78 +1725,18 @@ immediately:
 }
 
 static errno_t
-process_offline_gpo(TALLOC_CTX *mem_ctx,
-                    const char *user,
-                    enum gpo_access_control_mode gpo_mode,
-                    struct sss_domain_info *domain,
-                    struct ldb_message *gpo_cache_entry,
-                    enum gpo_map_type gpo_map_type)
-{
-    const char *policy_filename = NULL;
-    const char *cached_gpo_guid;
-    char **allowed_sids;
-    int allowed_size;
-    char **denied_sids;
-    int denied_size;
-    int ret;
-
-    cached_gpo_guid = ldb_msg_find_attr_as_string(gpo_cache_entry,
-                                                  SYSDB_GPO_GUID_ATTR, NULL);
-
-    if (cached_gpo_guid == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "No gpo_guid attribute found in gpo cache entry\n");
-        ret = EFAULT;
-        goto done;
-    }
-
-    policy_filename = talloc_asprintf(mem_ctx,
-                                      GPO_CACHE_PATH"/%s/Policies/%s%s",
-                                      domain->name,
-                                      cached_gpo_guid,
-                                      GP_EXT_GUID_SECURITY_SUFFIX);
-
-    if (policy_filename == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    DEBUG(SSSDBG_TRACE_FUNC, "policy_filename:%s\n", policy_filename);
-
-    ret = ad_gpo_parse_policy_file(mem_ctx,
-                                   policy_filename,
-                                   gpo_map_type,
-                                   &allowed_sids,
-                                   &allowed_size,
-                                   &denied_sids,
-                                   &denied_size);
-
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Cannot parse policy file: [%s][%d][%s]\n",
-              policy_filename, ret, strerror(ret));
-        goto done;
-    }
-
-    ret = ad_gpo_access_check
-        (mem_ctx, gpo_mode, gpo_map_type, user, domain,
-         allowed_sids, allowed_size, denied_sids, denied_size);
-
- done:
-    return ret;
-}
-
-static errno_t
 process_offline_gpos(TALLOC_CTX *mem_ctx,
                      const char *user,
                      enum gpo_access_control_mode gpo_mode,
                      struct sss_domain_info *domain,
                      enum gpo_map_type gpo_map_type)
+
 {
     struct ldb_result *res;
-    struct ldb_message *gpo_cache_entry;
+    const char *cached_gpo_guid;
     errno_t ret;
     int i;
+    const char **policy_filenames;
 
     ret = sysdb_gpo_get_gpos(mem_ctx, domain, &res);
 
@@ -1454,16 +1758,46 @@ process_offline_gpos(TALLOC_CTX *mem_ctx,
     DEBUG(SSSDBG_TRACE_FUNC, "Retrieving GPOs from cache\n");
     DEBUG(SSSDBG_TRACE_FUNC, "Found %d GPO(s) in cache\n", res->count);
 
+    /* we create and populate an array of policy filenames */
+    policy_filenames = talloc_array(mem_ctx, const char *, res->count);
+    if (policy_filenames == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
     for (i = 0; i < res->count; i++){
-        gpo_cache_entry = res->msgs[i];
-        ret = process_offline_gpo(mem_ctx, user, gpo_mode, domain,
-                                  gpo_cache_entry, gpo_map_type);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_OP_FAILURE,
-                  "process_offline_gpo failed [%d](%s)\n",
-                  ret, sss_strerror(ret));
+        cached_gpo_guid = ldb_msg_find_attr_as_string(res->msgs[i],
+                                                  SYSDB_GPO_GUID_ATTR, NULL);
+        if (cached_gpo_guid == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "No gpo_guid attribute found in gpo cache entry\n");
+            ret = EFAULT;
             goto done;
         }
+
+        policy_filenames[i] = talloc_asprintf(mem_ctx,
+                                              GPO_CACHE_PATH"/%s/Policies/%s%s",
+                                              domain->name,
+                                              cached_gpo_guid,
+                                              GP_EXT_GUID_SECURITY_SUFFIX);
+        if (policy_filenames[i] == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+    }
+
+    ret = ad_gpo_perform_hbac_processing(mem_ctx,
+                                         res->count,
+                                         policy_filenames,
+                                         gpo_mode,
+                                         gpo_map_type,
+                                         user,
+                                         domain);
+
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "HBAC processing failed: [%d](%s}\n",
+              ret, sss_strerror(ret));
+        goto done;
     }
 
     /* we have successfully processed all offline gpos */
@@ -1720,8 +2054,13 @@ ad_gpo_process_som_done(struct tevent_req *subreq)
  * reduces it to a list of cse_filtered_gpos, based on whether each GPO's list
  * of cse_guids includes the "SecuritySettings" CSE GUID (used for HBAC).
  *
- * This function then sends each cse_filtered_gpo to the CSE processing engine
- * for policy application, which currently consists of HBAC functionality.
+ * This function then removes any stale gpo cache entries (i.e. entries that
+ * have a gpo-guid that doesn't match any of the gpo-guids in the cse_guids list)
+ * to prevent "tattooing".
+ *
+ * Ultimately, this function then sends each cse_filtered_gpo to the gpo_child,
+ * which retrieves the GPT.INI and policy files (as needed). Once all files
+ * have been downloaded, the ad_gpo_cse_done function performs HBAC processing.
  */
 static void
 ad_gpo_process_gpo_done(struct tevent_req *subreq)
@@ -1821,6 +2160,14 @@ ad_gpo_process_gpo_done(struct tevent_req *subreq)
     DEBUG(SSSDBG_TRACE_FUNC, "num_cse_filtered_gpos: %d\n",
           state->num_cse_filtered_gpos);
 
+    /* we create and populate an array of policy filenames */
+    state->policy_filenames =
+        talloc_array(state, const char *, state->num_cse_filtered_gpos);
+    if (state->policy_filenames == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
     /*
      * we now have the array of applicable gpos in hand; however, since we
      * may have cached a larger set of gpo-guids previously, we delete
@@ -1870,7 +2217,7 @@ ad_gpo_cse_step(struct tevent_req *req)
     struct gp_gpo *cse_filtered_gpo =
         state->cse_filtered_gpos[state->cse_gpo_index];
 
-    /* cse_filtered_gpo is NULL only after all GPOs have been processed */
+    /* cse_filtered_gpo is NULL only after all GPO policy files have been downloaded */
     if (cse_filtered_gpo == NULL) return EOK;
 
     DEBUG(SSSDBG_TRACE_FUNC, "cse filtered_gpos[%d]->gpo_guid is %s\n",
@@ -1886,6 +2233,15 @@ ad_gpo_cse_step(struct tevent_req *req)
     DEBUG(SSSDBG_TRACE_FUNC, "smb_path: %s\n", cse_filtered_gpo->smb_path);
     DEBUG(SSSDBG_TRACE_FUNC, "gpo_guid: %s\n", cse_filtered_gpo->gpo_guid);
 
+    state->policy_filenames[state->cse_gpo_index] =
+        talloc_asprintf(state->policy_filenames,
+                        GPO_CACHE_PATH"%s%s",
+                        cse_filtered_gpo->smb_path,
+                        GP_EXT_GUID_SECURITY_SUFFIX);
+    if (state->policy_filenames[state->cse_gpo_index] == NULL) {
+        return ENOMEM;
+    }
+
     /* retrieve gpo cache entry; set cached_gpt_version to -1 if unavailable */
     DEBUG(SSSDBG_TRACE_FUNC, "retrieving GPO from cache [%s]\n",
           cse_filtered_gpo->gpo_guid);
@@ -1946,13 +2302,9 @@ ad_gpo_cse_step(struct tevent_req *req)
 }
 
 /*
- * This cse-specific function (GP_EXT_GUID_SECURITY) retrieves a list of
- * allowed_sids and denied_sids, and uses them to determine whether logon
- * access is granted or denied for the state's {user, domain} tuple.
- *
- * If it is determined that the current cse_filtered_gpo grants access, then
- * we process the next cse_filtered_gpo in the list. At any time, if access is
- * denied, we return immediately with an error.
+ * This cse-specific function (GP_EXT_GUID_SECURITY) increments the
+ * cse_gpo_index until the policy files for all applicable GPOs have been
+ * downloaded. Once that happens, this functions performs HBAC processing.
  */
 static void
 ad_gpo_cse_done(struct tevent_req *subreq)
@@ -1960,12 +2312,6 @@ ad_gpo_cse_done(struct tevent_req *subreq)
     struct tevent_req *req;
     struct ad_gpo_access_state *state;
     int ret;
-    int sysvol_gpt_version;
-    const char *policy_filename = NULL;
-    char **allowed_sids;
-    int allowed_size;
-    char **denied_sids;
-    int denied_size;
 
     req = tevent_req_callback_data(subreq, struct tevent_req);
     state = tevent_req_data(req, struct ad_gpo_access_state);
@@ -1977,8 +2323,7 @@ ad_gpo_cse_done(struct tevent_req *subreq)
 
     DEBUG(SSSDBG_TRACE_FUNC, "gpo_guid: %s\n", gpo_guid);
 
-    ret = ad_gpo_process_cse_recv(subreq, state, &sysvol_gpt_version,
-                                  &policy_filename);
+    ret = ad_gpo_process_cse_recv(subreq, state);
 
     talloc_zfree(subreq);
 
@@ -1988,35 +2333,26 @@ ad_gpo_cse_done(struct tevent_req *subreq)
         goto done;
     }
 
-    ret = ad_gpo_parse_policy_file(state,
-                                   policy_filename,
-                                   state->gpo_map_type,
-                                   &allowed_sids,
-                                   &allowed_size,
-                                   &denied_sids,
-                                   &denied_size);
-
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Cannot parse policy file: [%s][%d][%s]\n",
-              policy_filename, ret, strerror(ret));
-        goto done;
-    }
-
-    ret = ad_gpo_access_check
-        (state, state->gpo_mode, state->gpo_map_type, state->user,
-         state->domain, allowed_sids, allowed_size, denied_sids, denied_size);
-
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              "GPO access check failed: [%d](%s)\n",
-              ret, strerror(ret));
-        goto done;
-    }
-
     state->cse_gpo_index++;
     ret = ad_gpo_cse_step(req);
 
+    if (ret == EOK) {
+        /* ret is EOK only after all GPO policy files have been downloaded */
+        ret = ad_gpo_perform_hbac_processing(state,
+                                             state->num_cse_filtered_gpos,
+                                             state->policy_filenames,
+                                             state->gpo_mode,
+                                             state->gpo_map_type,
+                                             state->user,
+                                             state->domain);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "HBAC processing failed: [%d](%s}\n",
+                  ret, sss_strerror(ret));
+            goto done;
+        }
+
+    }
+
  done:
 
     if (ret == EOK) {
@@ -3550,207 +3886,6 @@ create_cse_send_buffer(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
-/*
- * This function uses the input ini_config object to parse the logon right value
- * associated with the input name. This value is a list of sids, and is used
- * to populate the output parameters.
- */
-static errno_t
-parse_logon_right_with_libini(TALLOC_CTX *mem_ctx,
-                              struct ini_cfgobj *ini_config,
-                              const char *name,
-                              int *_size,
-                              char ***_sids)
-{
-    int ret = 0;
-    struct value_obj *vobj = NULL;
-    char **ini_sids = NULL;
-    char *ini_sid = NULL;
-    int num_ini_sids = 0;
-    char **sids = NULL;
-    int i;
-    TALLOC_CTX *tmp_ctx = NULL;
-
-    tmp_ctx = talloc_new(NULL);
-    if (tmp_ctx == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    ret = ini_get_config_valueobj(RIGHTS_SECTION, name, ini_config,
-                                  INI_GET_FIRST_VALUE, &vobj);
-    if (ret != 0) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "ini_get_config_valueobj failed [%d][%s]\n", ret, strerror(ret));
-        goto done;
-    }
-    if (vobj == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "section/name not found: [%s][%s]\n",
-              RIGHTS_SECTION, name);
-        ret = EOK;
-        goto done;
-    }
-    ini_sids = ini_get_string_config_array(vobj, NULL, &num_ini_sids, &ret);
-
-    if (ret != 0) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "ini_get_string_config_array failed [%d][%s]\n",
-              ret, strerror(ret));
-        goto done;
-    }
-
-    sids = talloc_array(tmp_ctx, char *, num_ini_sids + 1);
-    if (sids == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    for (i = 0; i < num_ini_sids; i++) {
-        ini_sid = ini_sids[i];
-
-        /* remove the asterisk prefix found on sids in the .inf policy file */
-        if (ini_sid[0] == '*') {
-            ini_sid++;
-        }
-        sids[i] = talloc_strdup(sids, ini_sid);
-        if (sids[i] == NULL) {
-            ret = ENOMEM;
-            goto done;
-        }
-    }
-    sids[i] = NULL;
-
-    *_size = num_ini_sids;
-    *_sids = talloc_steal(mem_ctx, sids);
-
-    ret = EOK;
-
- done:
-
-    ini_free_string_config_array(ini_sids);
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-/*
- * This function parses the cse-specific (GP_EXT_GUID_SECURITY) input data_buf,
- * and uses the results to populate the output parameters with the list of
- * allowed_sids and denied_sids
- */
-static errno_t
-ad_gpo_parse_policy_file(TALLOC_CTX *mem_ctx,
-                         const char *filename,
-                         enum gpo_map_type gpo_map_type,
-                         char ***allowed_sids,
-                         int *allowed_size,
-                         char ***denied_sids,
-                         int *denied_size)
-{
-    struct ini_cfgfile *file_ctx = NULL;
-    struct ini_cfgobj *ini_config = NULL;
-    int ret;
-    char **allow_sids = NULL;
-    char **deny_sids = NULL;
-    int allow_size = 0;
-    int deny_size = 0;
-    const char *allow_key = NULL;
-    const char *deny_key = NULL;
-    TALLOC_CTX *tmp_ctx = NULL;
-
-    tmp_ctx = talloc_new(NULL);
-    if (tmp_ctx == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    ret = ini_config_create(&ini_config);
-    if (ret != 0) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "ini_config_create failed [%d][%s]\n", ret, strerror(ret));
-        goto done;
-    }
-
-    ret = ini_config_file_open(filename, 0, &file_ctx);
-    if (ret != 0) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "ini_config_file_open failed [%d][%s]\n", ret, strerror(ret));
-        goto done;
-    }
-
-    ret = ini_config_parse(file_ctx, INI_STOP_ON_NONE, 0, 0, ini_config);
-    if (ret != 0) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "ini_config_parse failed [%d][%s]\n", ret, strerror(ret));
-        goto done;
-    }
-
-    switch (gpo_map_type) {
-    case GPO_MAP_INTERACTIVE:
-        allow_key = ALLOW_LOGON_INTERACTIVE;
-        deny_key = DENY_LOGON_INTERACTIVE;
-        break;
-    case GPO_MAP_REMOTE_INTERACTIVE:
-        allow_key = ALLOW_LOGON_REMOTE_INTERACTIVE;
-        deny_key = DENY_LOGON_REMOTE_INTERACTIVE;
-        break;
-    case GPO_MAP_NETWORK:
-        allow_key = ALLOW_LOGON_NETWORK;
-        deny_key = DENY_LOGON_NETWORK;
-        break;
-    case GPO_MAP_BATCH:
-        allow_key = ALLOW_LOGON_BATCH;
-        deny_key = DENY_LOGON_BATCH;
-        break;
-    case GPO_MAP_SERVICE:
-        allow_key = ALLOW_LOGON_SERVICE;
-        deny_key = DENY_LOGON_SERVICE;
-        break;
-    default:
-        ret = EINVAL;
-        goto done;
-    }
-
-    ret = parse_logon_right_with_libini(tmp_ctx,
-                                        ini_config,
-                                        allow_key,
-                                        &allow_size,
-                                        &allow_sids);
-    if (ret != 0) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "parse_logon_right_with_libini failed for %s [%d][%s]\n",
-              allow_key, ret, strerror(ret));
-        goto done;
-    }
-
-    ret = parse_logon_right_with_libini(tmp_ctx,
-                                        ini_config,
-                                        deny_key,
-                                        &deny_size,
-                                        &deny_sids);
-    if (ret != 0) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "parse_logon_right_with_libini failed for %s [%d][%s]\n",
-              deny_key, ret, strerror(ret));
-        goto done;
-    }
-
-    *allowed_sids = talloc_steal(mem_ctx, allow_sids);
-    *allowed_size = allow_size;
-    *denied_sids = talloc_steal(mem_ctx, deny_sids);
-    *denied_size = deny_size;
-
- done:
-
-    if (ret != EOK) {
-      DEBUG(SSSDBG_CRIT_FAILURE, "Error encountered: %d.\n", ret);
-    }
-
-    ini_config_file_destroy(file_ctx);
-    ini_config_destroy(ini_config);
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
 static errno_t
 ad_gpo_parse_gpo_child_response(TALLOC_CTX *mem_ctx,
                                 uint8_t *buf,
@@ -3786,8 +3921,6 @@ struct ad_gpo_process_cse_state {
     const char *gpo_guid;
     const char *smb_path;
     const char *smb_cse_suffix;
-    int sysvol_gpt_version;
-    const char *policy_filename;
     pid_t child_pid;
     uint8_t *buf;
     ssize_t len;
@@ -3836,9 +3969,11 @@ static void gpo_cse_step(struct tevent_req *subreq);
 static void gpo_cse_done(struct tevent_req *subreq);
 
 /*
- * This cse-specific function (GP_EXT_GUID_SECURITY) retrieves the data
- * referenced by the input smb_uri, and uses the parsed results to populate the
- * state's list of allowed_sids and denied_sids.
+ * This cse-specific function (GP_EXT_GUID_SECURITY) sends the input smb uri
+ * components and cached_gpt_version to the gpo child, which, in turn,
+ * will download the GPT.INI file and policy files (as needed) and store
+ * them in the GPO_CACHE directory. Note that if the send_to_child input is
+ * false, this function simply completes the request.
  */
 struct tevent_req *
 ad_gpo_process_cse_send(TALLOC_CTX *mem_ctx,
@@ -3865,25 +4000,11 @@ ad_gpo_process_cse_send(TALLOC_CTX *mem_ctx,
         return NULL;
     }
 
-    state->sysvol_gpt_version = -1;
-
     if (!send_to_child) {
         /*
-         * if we don't need to talk to child (b/c cache timeout is valid),
-         * we simply set the policy_filename and complete the request
+         * if we don't need to talk to child (b/c cache timeout is still valid),
+         * we simply complete the request
          */
-        state->policy_filename =
-            talloc_asprintf(state,
-                            GPO_CACHE_PATH"/%s/Policies/%s%s",
-                            domain->name,
-                            gpo_guid,
-                            GP_EXT_GUID_SECURITY_SUFFIX);
-        if (state->policy_filename == NULL) {
-            ret = ENOMEM;
-            goto immediately;
-        }
-
-        DEBUG(SSSDBG_TRACE_FUNC, "policy_filename:%s\n", state->policy_filename);
         ret = EOK;
         goto immediately;
     }
@@ -4008,17 +4129,6 @@ static void gpo_cse_done(struct tevent_req *subreq)
         tevent_req_error(req, child_result);
     }
 
-    state->sysvol_gpt_version = sysvol_gpt_version;
-    state->policy_filename = talloc_asprintf(state,
-                                             GPO_CACHE_PATH"%s%s",
-                                             state->smb_path,
-                                             state->smb_cse_suffix);
-    if (state->policy_filename == NULL) {
-        tevent_req_error(req, ENOMEM);
-    }
-
-    DEBUG(SSSDBG_TRACE_FUNC, "policy_filename:%s\n", state->policy_filename);
-
     now = time(NULL);
     DEBUG(SSSDBG_TRACE_FUNC, "sysvol_gpt_version: %d\n", sysvol_gpt_version);
     ret = sysdb_gpo_store_gpo(state->domain, state->gpo_guid, sysvol_gpt_version,
@@ -4035,19 +4145,9 @@ static void gpo_cse_done(struct tevent_req *subreq)
 }
 
 int ad_gpo_process_cse_recv(struct tevent_req *req,
-                            TALLOC_CTX *mem_ctx,
-                            int *_sysvol_gpt_version,
-                            const char **_policy_filename)
+                            TALLOC_CTX *mem_ctx)
 {
-    struct ad_gpo_process_cse_state *state;
-
-    state = tevent_req_data(req, struct ad_gpo_process_cse_state);
-
     TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    *_sysvol_gpt_version = state->sysvol_gpt_version;
-    *_policy_filename = talloc_steal(mem_ctx, state->policy_filename);
-
     return EOK;
 }
 
-- 
1.8.5.3

