From 94a67f6644279586a70c75aa77e556afa026dcb5 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/db/sysdb.h                 |  29 +-
 src/db/sysdb_gpo.c             | 336 +++++++++++++--
 src/providers/ad/ad_gpo.c      | 902 ++++++++++++++++++-----------------------
 src/tests/cmocka/test_ad_gpo.c |   1 -
 4 files changed, 719 insertions(+), 549 deletions(-)

diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 901b6129b5d84a829637ea0d3e0b05cbe9ac48d9..81b39252c6604fd7c2b604b0b4bc7f00e035252b 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -876,6 +876,8 @@ errno_t sysdb_search_object_by_sid(TALLOC_CTX *mem_ctx,
 
 #define SYSDB_GPO_CONTAINER "cn=gpos,cn=ad,cn=custom"
 
+/* === Functions related to GPO entries === */
+
 #define SYSDB_GPO_OC "gpo"
 #define SYSDB_GPO_FILTER "(objectClass="SYSDB_GPO_OC")"
 #define SYSDB_GPO_GUID_FILTER "(&(objectClass="SYSDB_GPO_OC")("SYSDB_GPO_GUID_ATTR"=%s))"
@@ -908,9 +910,28 @@ errno_t sysdb_gpo_get_gpos(TALLOC_CTX *mem_ctx,
                            struct sss_domain_info *domain,
                            struct ldb_result **_result);
 
-errno_t sysdb_gpo_delete_stale_gpos(TALLOC_CTX *mem_ctx,
-                                    struct sss_domain_info *domain,
-                                    const char **gpo_guid_list,
-                                    int num_gpos);
+/* === Functions related to GPO Result object === */
+
+#define SYSDB_GPO_RESULT_OC "gpo_result"
+#define SYSDB_GPO_RESULT_FILTER "(objectClass="SYSDB_GPO_RESULT_OC")"
+
+#define SYSDB_TMPL_GPO_RESULT_BASE SYSDB_GPO_CONTAINER","SYSDB_DOM_BASE
+#define SYSDB_TMPL_GPO_RESULT "cn=%s,"SYSDB_TMPL_GPO_RESULT_BASE
+
+errno_t sysdb_gpo_get_gpo_result_object(TALLOC_CTX *mem_ctx,
+                                        struct sss_domain_info *domain,
+                                        struct ldb_result **_result);
+
+errno_t sysdb_gpo_delete_gpo_result_object(TALLOC_CTX *mem_ctx,
+                                           struct sss_domain_info *domain);
+
+errno_t sysdb_gpo_store_gpo_result_setting(struct sss_domain_info *domain,
+                                           const char *policy_setting_key,
+                                           const char *policy_setting_value);
+
+errno_t sysdb_gpo_get_gpo_result_setting(TALLOC_CTX *mem_ctx,
+                                         struct sss_domain_info *domain,
+                                         const char *policy_setting_key,
+                                         const char **policy_setting_value);
 
 #endif /* __SYS_DB_H__ */
diff --git a/src/db/sysdb_gpo.c b/src/db/sysdb_gpo.c
index e0b9bb9f0a26ff8defcaf7813588281d11976bfc..ed44e0600a5afc4153da9d9a0f2c607ef94c718b 100644
--- a/src/db/sysdb_gpo.c
+++ b/src/db/sysdb_gpo.c
@@ -37,7 +37,7 @@ sysdb_gpo_dn(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain,
         return NULL;
     }
 
-    DEBUG(SSSDBG_TRACE_FUNC, SYSDB_TMPL_GPO"\n", clean_gpo_guid, domain->name);
+    DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO"\n", clean_gpo_guid, domain->name);
 
     dn = ldb_dn_new_fmt(mem_ctx, domain->sysdb->ldb, SYSDB_TMPL_GPO,
                         clean_gpo_guid, domain->name);
@@ -172,8 +172,7 @@ sysdb_gpo_store_gpo(struct sss_domain_info *domain,
     } else if (ret == EOK && count == 1) {
         /* Update the existing GPO */
 
-        DEBUG(SSSDBG_TRACE_FUNC,
-              "Updating new GPO [%s][%s]\n", domain->name, gpo_guid);
+        DEBUG(SSSDBG_TRACE_ALL, "Updating new GPO [%s][%s]\n", domain->name, gpo_guid);
 
         /* Add the Version */
         lret = ldb_msg_add_empty(update_msg, SYSDB_GPO_VERSION_ATTR,
@@ -254,7 +253,7 @@ sysdb_gpo_get_gpo_by_guid(TALLOC_CTX *mem_ctx,
     tmp_ctx = talloc_new(NULL);
     if (!tmp_ctx) return ENOMEM;
 
-    DEBUG(SSSDBG_TRACE_FUNC, SYSDB_TMPL_GPO_BASE"\n", domain->name);
+    DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO_BASE"\n", domain->name);
 
     base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
                              SYSDB_TMPL_GPO_BASE,
@@ -313,7 +312,7 @@ sysdb_gpo_get_gpos(TALLOC_CTX *mem_ctx,
     tmp_ctx = talloc_new(NULL);
     if (!tmp_ctx) return ENOMEM;
 
-    DEBUG(SSSDBG_TRACE_FUNC, SYSDB_TMPL_GPO_BASE"\n", domain->name);
+    DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO_BASE"\n", domain->name);
 
     base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
                              SYSDB_TMPL_GPO_BASE,
@@ -367,18 +366,292 @@ sysdb_gpo_guid_in_list(const char **gpo_guid_list, int num_gpos, const char *gpo
     return (i < num_gpos) ? true : false;
 }
 
+/* GPO Result */
+
+static struct ldb_dn *
+sysdb_gpo_result_dn(TALLOC_CTX *mem_ctx,
+                    struct sss_domain_info *domain,
+                    const char *result_name)
+{
+    errno_t ret;
+    char *clean_result_name;
+    struct ldb_dn *dn;
+
+    ret = sysdb_dn_sanitize(NULL, result_name, &clean_result_name);
+    if (ret != EOK) {
+        return NULL;
+    }
+
+    DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO_RESULT"\n",
+          clean_result_name, domain->name);
+
+    dn = ldb_dn_new_fmt(mem_ctx, domain->sysdb->ldb, SYSDB_TMPL_GPO_RESULT,
+                        clean_result_name, domain->name);
+    talloc_free(clean_result_name);
+
+    return dn;
+}
+
+errno_t
+sysdb_gpo_store_gpo_result_setting(struct sss_domain_info *domain,
+                                   const char *ini_key,
+                                   const char *ini_value)
+{
+    errno_t ret, sret;
+    int lret;
+    struct ldb_message *update_msg;
+    struct ldb_message **msgs;
+    size_t count;
+    bool in_transaction = false;
+    TALLOC_CTX *tmp_ctx;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+    update_msg = ldb_msg_new(tmp_ctx);
+    if (!update_msg) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    update_msg->dn = sysdb_gpo_result_dn(update_msg, domain, "gpo_result");
+    if (!update_msg->dn) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_transaction_start(domain->sysdb);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
+        goto done;
+    }
+
+    in_transaction = true;
+
+    /* Check for an existing GPO Result object */
+    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, update_msg->dn,
+                             LDB_SCOPE_BASE, NULL, NULL, &count, &msgs);
+
+    if (ret == ENOENT) {
+        /* Create new GPO Result object */
+        DEBUG(SSSDBG_TRACE_FUNC, "Storing setting: key [%s] value [%s]\n",
+              ini_key, ini_value);
+
+        /* Add the objectClass */
+        lret = ldb_msg_add_empty(update_msg, SYSDB_OBJECTCLASS,
+                                 LDB_FLAG_MOD_ADD,
+                                 NULL);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_msg_add_string(update_msg, SYSDB_OBJECTCLASS,
+                                  SYSDB_GPO_RESULT_OC);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        /* Store the policy_setting */
+        lret = ldb_msg_add_empty(update_msg, ini_key,
+                                 LDB_FLAG_MOD_ADD,
+                                 NULL);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_msg_add_string(update_msg, ini_key, ini_value);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_add(domain->sysdb->ldb, update_msg);
+        if (lret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Failed to add GPO Result: [%s]\n",
+                   ldb_strerror(lret));
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+    } else if (ret == EOK && count == 1) {
+        /* Update existing GPO Result object*/
+        DEBUG(SSSDBG_TRACE_FUNC, "Updating setting: key [%s] value [%s]\n",
+              ini_key, ini_value);
+
+        /* Update the policy setting */
+        lret = ldb_msg_add_empty(update_msg, ini_key,
+                                 LDB_FLAG_MOD_REPLACE,
+                                 NULL);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_msg_add_fmt(update_msg, ini_key, "%s", ini_value);
+        if (lret != LDB_SUCCESS) {
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+
+        lret = ldb_modify(domain->sysdb->ldb, update_msg);
+        if (lret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Failed to modify GPO Result: [%s]\n", ldb_strerror(lret));
+            ret = sysdb_error_to_errno(lret);
+            goto done;
+        }
+    } else {
+        ret = EIO;
+        goto done;
+    }
+
+    ret = sysdb_transaction_commit(domain->sysdb);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Could not commit transaction: [%s]\n", strerror(ret));
+        goto done;
+    }
+    in_transaction = false;
+
+done:
+    if (in_transaction) {
+        sret = sysdb_transaction_cancel(domain->sysdb);
+        if (sret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
+        }
+    }
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 errno_t
-sysdb_gpo_delete_stale_gpos(TALLOC_CTX *mem_ctx,
-                            struct sss_domain_info *domain,
-                            const char **gpo_guid_list,
-                            int num_gpos)
+sysdb_gpo_get_gpo_result_setting(TALLOC_CTX *mem_ctx,
+                                 struct sss_domain_info *domain,
+                                 const char *ini_key,
+                                 const char **_ini_value)
+{
+    errno_t ret;
+    int lret;
+    struct ldb_dn *base_dn;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_result *res;
+    const char *ini_value;
+
+    const char *attrs[] = {ini_key};
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+    DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO_RESULT_BASE"\n", domain->name);
+
+    base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
+                             SYSDB_TMPL_GPO_RESULT_BASE,
+                             domain->name);
+    if (!base_dn) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    lret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
+                      LDB_SCOPE_SUBTREE, attrs, SYSDB_GPO_RESULT_FILTER);
+    if (lret) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              "Could not locate GPO Result: [%s]\n",
+              ldb_strerror(lret));
+        ret = sysdb_error_to_errno(lret);
+        goto done;
+    }
+
+    if (res->count == 0) {
+        ret = ENOENT;
+        goto done;
+    }
+
+    ini_value = ldb_msg_find_attr_as_string(res->msgs[0],
+                                            ini_key,
+                                            NULL);
+    DEBUG(SSSDBG_TRACE_FUNC, "key [%s] value [%s]\n", ini_key, ini_value);
+
+    *_ini_value = talloc_strdup(mem_ctx, ini_value);
+    ret = EOK;
+
+done:
+
+    if (ret == ENOENT) {
+        DEBUG(SSSDBG_TRACE_ALL, "No setting for key [%s].\n", ini_key);
+    } else if (ret) {
+        DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+
+errno_t
+sysdb_gpo_get_gpo_result_object(TALLOC_CTX *mem_ctx,
+                                struct sss_domain_info *domain,
+                                struct ldb_result **_result)
+{
+    errno_t ret;
+    int lret;
+    struct ldb_dn *base_dn;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_result *res;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+    DEBUG(SSSDBG_TRACE_ALL, SYSDB_TMPL_GPO_RESULT_BASE"\n", domain->name);
+
+    base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
+                             SYSDB_TMPL_GPO_RESULT_BASE,
+                             domain->name);
+    if (!base_dn) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    lret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
+                      LDB_SCOPE_SUBTREE, NULL, SYSDB_GPO_RESULT_FILTER);
+    if (lret) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              "Could not locate GPO Result object: [%s]\n",
+              ldb_strerror(lret));
+        ret = sysdb_error_to_errno(lret);
+        goto done;
+    }
+
+    if (res->count == 0) {
+        ret = ENOENT;
+        goto done;
+    }
+
+    *_result = talloc_steal(mem_ctx, res);
+    ret = EOK;
+
+done:
+
+    if (ret == ENOENT) {
+        DEBUG(SSSDBG_TRACE_ALL, "No GPO Result object.\n");
+    } else if (ret) {
+        DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret));
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+
+errno_t sysdb_gpo_delete_gpo_result_object(TALLOC_CTX *mem_ctx,
+                                           struct sss_domain_info *domain)
 {
     struct ldb_result *res;
     errno_t ret, sret;
-    int i;
     bool in_transaction = false;
-    const char *cached_gpo_guid;
-    bool stale_gpo_found = false;
 
     ret = sysdb_transaction_start(domain->sysdb);
     if (ret != EOK) {
@@ -388,45 +661,20 @@ sysdb_gpo_delete_stale_gpos(TALLOC_CTX *mem_ctx,
 
     in_transaction = true;
 
-    ret = sysdb_gpo_get_gpos(mem_ctx, domain, &res);
+    ret = sysdb_gpo_get_gpo_result_object(mem_ctx, domain, &res);
     if (ret != EOK && ret != ENOENT) {
         goto done;
     } else if (ret != ENOENT) {
-        for (i = 0; i < res->count; i++) {
-            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;
-            }
+        DEBUG(SSSDBG_TRACE_FUNC, "Deleting GPO Result object\n");
 
-            if (sysdb_gpo_guid_in_list(gpo_guid_list, num_gpos, cached_gpo_guid)) {
-                /* the cached_gpo_guid is still applicable, skip it */
-                continue;
-            } else {
-                stale_gpo_found = true;
-                /* the cached_gpo_guid is no longer applicable, delete it */
-                DEBUG(SSSDBG_TRACE_FUNC, "Deleting stale GPO [gpo_guid:%s]\n",
-                      cached_gpo_guid);
-
-                ret = sysdb_delete_entry(domain->sysdb, res->msgs[i]->dn, true);
-                if (ret != EOK) {
-                    DEBUG(SSSDBG_MINOR_FAILURE,
-                          "Could not delete GPO cache entry [gpo_guid:%s]\n",
-                          cached_gpo_guid);
-                    goto done;
-                }
-            }
+        ret = sysdb_delete_entry(domain->sysdb, res->msgs[0]->dn, true);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Could not delete GPO Result cache entry\n");
+            goto done;
         }
     }
 
-    if (!stale_gpo_found) {
-        DEBUG(SSSDBG_TRACE_FUNC, "No stale GPOs found\n");
-    }
-
     ret = sysdb_transaction_commit(domain->sysdb);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
index de4d44166b85ccd85ed36bcb11f0596e0020af11..98966135bb794d73a4d6bac2ae36d874340e75ad 100644
--- a/src/providers/ad/ad_gpo.c
+++ b/src/providers/ad/ad_gpo.c
@@ -61,11 +61,8 @@
 #define AD_AT_GPOPTIONS "gpOptions"
 #define AD_AT_NT_SEC_DESC "nTSecurityDescriptor"
 #define AD_AT_CN "cn"
-#define AD_AT_DISPLAY_NAME "displayName"
 #define AD_AT_FILE_SYS_PATH "gPCFileSysPath"
-#define AD_AT_VERSION_NUMBER "versionNumber"
 #define AD_AT_MACHINE_EXT_NAMES "gPCMachineExtensionNames"
-#define AD_AT_USER_EXT_NAMES "gPCUserExtensionNames"
 #define AD_AT_FUNC_VERSION "gPCFunctionalityVersion"
 #define AD_AT_FLAGS "flags"
 
@@ -78,9 +75,6 @@
 #define SMB_STANDARD_URI "smb://"
 #define BUFSIZE 65536
 
-#define GPO_VERSION_USER(x) (x >> 16)
-#define GPO_VERSION_MACHINE(x) (x & 0xffff)
-
 #define RIGHTS_SECTION "Privilege Rights"
 #define ALLOW_LOGON_INTERACTIVE "SeInteractiveLogonRight"
 #define DENY_LOGON_INTERACTIVE "SeDenyInteractiveLogonRight"
@@ -91,7 +85,7 @@
 #define ALLOW_LOGON_BATCH "SeBatchLogonRight"
 #define DENY_LOGON_BATCH "SeDenyBatchLogonRight"
 #define ALLOW_LOGON_SERVICE "SeServiceLogonRight"
-#define DENY_LOGON_SERVICE "SeServiceBatchLogonRight"
+#define DENY_LOGON_SERVICE "SeDenyServiceLogonRight"
 
 #define GP_EXT_GUID_SECURITY "{827D319E-6EAC-11D2-A4EA-00C04F79F83A}"
 #define GP_EXT_GUID_SECURITY_SUFFIX "/Machine/Microsoft/Windows NT/SecEdit/GptTmpl.inf"
@@ -122,16 +116,15 @@ struct gp_gpo {
     struct security_descriptor *gpo_sd;
     const char *gpo_dn;
     const char *gpo_guid;
-    const char *gpo_display_name;
     const char *smb_server;
     const char *smb_share;
     const char *smb_path;
-    uint32_t gpc_version;
     const char **gpo_cse_guids;
     int num_gpo_cse_guids;
     int gpo_func_version;
     int gpo_flags;
     bool send_to_child;
+    const char *policy_filename;
 };
 
 enum ace_eval_status {
@@ -164,6 +157,7 @@ int ad_gpo_process_gpo_recv(struct tevent_req *req,
                             TALLOC_CTX *mem_ctx,
                             struct gp_gpo ***candidate_gpos,
                             int *num_candidate_gpos);
+
 struct tevent_req *ad_gpo_process_cse_send(TALLOC_CTX *mem_ctx,
                                            struct tevent_context *ev,
                                            bool send_to_child,
@@ -176,9 +170,7 @@ 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 ==================================*/
 
@@ -200,6 +192,8 @@ struct gpo_map_option_entry {
     enum gpo_map_type gpo_map_type;
     enum ad_basic_opt ad_basic_opt;
     const char **gpo_map_defaults;
+    const char *allow_key;
+    const char *deny_key;
 };
 
 const char *gpo_map_interactive_defaults[] =
@@ -213,17 +207,21 @@ const char *gpo_map_permit_defaults[] = {GPO_SUDO, GPO_SUDO_I, NULL};
 const char *gpo_map_deny_defaults[] = {NULL};
 
 struct gpo_map_option_entry gpo_map_option_entries[] = {
-    {GPO_MAP_INTERACTIVE, AD_GPO_MAP_INTERACTIVE, gpo_map_interactive_defaults},
+    {GPO_MAP_INTERACTIVE, AD_GPO_MAP_INTERACTIVE, gpo_map_interactive_defaults,
+     ALLOW_LOGON_INTERACTIVE, DENY_LOGON_INTERACTIVE},
     {GPO_MAP_REMOTE_INTERACTIVE, AD_GPO_MAP_REMOTE_INTERACTIVE,
-     gpo_map_remote_interactive_defaults},
-    {GPO_MAP_NETWORK, AD_GPO_MAP_NETWORK, gpo_map_network_defaults},
-    {GPO_MAP_BATCH, AD_GPO_MAP_BATCH, gpo_map_batch_defaults},
-    {GPO_MAP_SERVICE, AD_GPO_MAP_SERVICE, gpo_map_service_defaults},
-    {GPO_MAP_PERMIT, AD_GPO_MAP_PERMIT, gpo_map_permit_defaults},
-    {GPO_MAP_DENY, AD_GPO_MAP_DENY, gpo_map_deny_defaults},
+     gpo_map_remote_interactive_defaults,
+     ALLOW_LOGON_REMOTE_INTERACTIVE, DENY_LOGON_REMOTE_INTERACTIVE},
+    {GPO_MAP_NETWORK, AD_GPO_MAP_NETWORK, gpo_map_network_defaults,
+     ALLOW_LOGON_NETWORK, DENY_LOGON_NETWORK},
+    {GPO_MAP_BATCH, AD_GPO_MAP_BATCH, gpo_map_batch_defaults,
+     ALLOW_LOGON_BATCH, DENY_LOGON_BATCH},
+    {GPO_MAP_SERVICE, AD_GPO_MAP_SERVICE, gpo_map_service_defaults,
+     ALLOW_LOGON_SERVICE, DENY_LOGON_SERVICE},
+    {GPO_MAP_PERMIT, AD_GPO_MAP_PERMIT, gpo_map_permit_defaults, NULL, NULL},
+    {GPO_MAP_DENY, AD_GPO_MAP_DENY, gpo_map_deny_defaults, NULL, NULL},
 };
 
-
 const char* gpo_map_type_string(int gpo_map_type)
 {
     switch(gpo_map_type) {
@@ -252,7 +250,6 @@ ad_gpo_service_in_list(char **list, size_t nlist, const char *str)
     return (i < nlist) ? true : false;
 }
 
-
 errno_t
 ad_gpo_parse_map_option_helper(enum gpo_map_type gpo_map_type,
                                hash_key_t key,
@@ -326,7 +323,7 @@ ad_gpo_parse_map_option(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    DEBUG(SSSDBG_TRACE_FUNC, "gpo_map_type: %s\n",
+    DEBUG(SSSDBG_TRACE_ALL, "gpo_map_type: %s\n",
           gpo_map_type_string(gpo_map_type));
 
     if (conf_str) {
@@ -383,7 +380,7 @@ ad_gpo_parse_map_option(TALLOC_CTX *mem_ctx,
             goto done;
         }
 
-        DEBUG(SSSDBG_TRACE_FUNC, "Explicitly added service: %s\n", key.str);
+        DEBUG(SSSDBG_TRACE_ALL, "Explicitly added service: %s\n", key.str);
     }
 
     /* Add defaults to hashtable */
@@ -402,7 +399,7 @@ ad_gpo_parse_map_option(TALLOC_CTX *mem_ctx,
             goto done;
         }
 
-        DEBUG(SSSDBG_TRACE_FUNC, "Default service (not explicitly removed): %s\n",
+        DEBUG(SSSDBG_TRACE_ALL, "Default service (not explicitly removed): %s\n",
               key.str);
     }
 
@@ -442,7 +439,7 @@ ad_gpo_parse_map_options(struct ad_access_ctx *access_ctx)
     gpo_default_right_config =
         dp_opt_get_string(access_ctx->ad_options, AD_GPO_DEFAULT_RIGHT);
 
-    DEBUG(SSSDBG_TRACE_FUNC, "gpo_default_right_config: %s\n",
+    DEBUG(SSSDBG_TRACE_ALL, "gpo_default_right_config: %s\n",
           gpo_default_right_config);
 
     /* if default right not set in config, set them to DENY */
@@ -474,7 +471,7 @@ ad_gpo_parse_map_options(struct ad_access_ctx *access_ctx)
         goto fail;
     }
 
-    DEBUG(SSSDBG_TRACE_FUNC, "gpo_default_right: %d\n", gpo_default_right);
+    DEBUG(SSSDBG_TRACE_ALL, "gpo_default_right: %d\n", gpo_default_right);
     access_ctx->gpo_default_right = gpo_default_right;
 
 fail:
@@ -791,7 +788,6 @@ static errno_t ad_gpo_evaluate_dacl(struct security_acl *dacl,
  * _dacl_filtered_gpos output parameter. The filtering algorithm is
  * defined in [MS-GPOL] 3.2.5.1.6
  */
-
 static errno_t
 ad_gpo_filter_gpos_by_dacl(TALLOC_CTX *mem_ctx,
                            const char *user,
@@ -1002,9 +998,9 @@ ad_gpo_filter_gpos_by_cse_guid(TALLOC_CTX *mem_ctx,
 }
 
 /*
- * This cse-specific function (GP_EXT_GUID_SECURITY) populates the output
- * parameter (found) based on whether the input user_sid or any of the input
- * group_sids appear in the input list of privilege_sids.
+ * This cse-specific function (GP_EXT_GUID_SECURITY) returns a boolean value
+ * based on whether the input user_sid or any of the input group_sids appear
+ * in the input list of privilege_sids.
  */
 static bool
 check_rights(char **privilege_sids,
@@ -1030,8 +1026,156 @@ check_rights(char **privilege_sids,
 }
 
 /*
- * This cse-specific function (GP_EXT_GUID_SECURITY) performs HBAC policy
- * application and determines whether logon access is granted or denied for
+ * This function parses the input ini_config object (which represents
+ * the cse-specific filename), and returns the policy_setting_value
+ * corresponding to the input policy_setting_key.
+ */
+static errno_t
+ad_gpo_extract_policy_setting(TALLOC_CTX *mem_ctx,
+                              struct ini_cfgobj *ini_config,
+                              const char *policy_setting_key,
+                              char **_policy_setting_value)
+{
+    struct value_obj *vobj = NULL;
+    int ret;
+    const char *policy_setting_value;
+
+    ret = ini_get_config_valueobj(RIGHTS_SECTION, policy_setting_key, 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_TRACE_ALL, "section/name not found: [%s][%s]\n",
+              RIGHTS_SECTION, policy_setting_key);
+        ret = ENOENT;
+        goto done;
+    }
+    policy_setting_value = ini_get_string_config_value(vobj, &ret);
+    if (ret != 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "ini_get_string_config_value failed [%d][%s]\n",
+              ret, strerror(ret));
+        goto done;
+    }
+
+    *_policy_setting_value = talloc_strdup(mem_ctx, policy_setting_value);
+
+    ret = EOK;
+
+ done:
+
+    return ret;
+}
+
+/*
+ * This function parses the cse-specific (GP_EXT_GUID_SECURITY) filename,
+ * and stores the allow_key and deny_key of all of the gpo_map_types present
+ * in the file (as part of the GPO Result object in the sysdb cache).
+ */
+static errno_t
+ad_gpo_store_policy_settings(TALLOC_CTX *mem_ctx,
+                             struct sss_domain_info *domain,
+                             const char *filename)
+{
+    struct ini_cfgfile *file_ctx = NULL;
+    struct ini_cfgobj *ini_config = NULL;
+    int ret;
+    int i;
+    char *allow_value = NULL;
+    char *deny_value = NULL;
+    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;
+    }
+
+    for (i = 0; i < GPO_MAP_NUM_OPTS; i++) {
+
+        struct gpo_map_option_entry entry = gpo_map_option_entries[i];
+
+        allow_key = entry.allow_key;
+        if (allow_key != NULL) {
+            DEBUG(SSSDBG_TRACE_ALL, "allow_key = %s\n", allow_key);
+            ret = ad_gpo_extract_policy_setting(tmp_ctx,
+                                                ini_config,
+                                                allow_key,
+                                                &allow_value);
+            if (ret != EOK && ret != ENOENT) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      "ad_gpo_extract_policy_setting failed for %s [%d][%s]\n",
+                      allow_key, ret, strerror(ret));
+                goto done;
+            } else if (ret != ENOENT) {
+                ret = sysdb_gpo_store_gpo_result_setting(domain,
+                                                         allow_key,
+                                                         allow_value);
+            }
+        }
+
+        deny_key = entry.deny_key;
+        if (deny_key != NULL) {
+            DEBUG(SSSDBG_TRACE_ALL, "deny_key = %s\n", deny_key);
+            ret = ad_gpo_extract_policy_setting(tmp_ctx,
+                                                ini_config,
+                                                deny_key,
+                                                &deny_value);
+            if (ret != EOK && ret != ENOENT) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      "ad_gpo_extract_policy_setting failed for %s [%d][%s]\n",
+                      deny_key, ret, strerror(ret));
+                goto done;
+            } else if (ret != ENOENT) {
+                ret = sysdb_gpo_store_gpo_result_setting(domain,
+                                                         deny_key,
+                                                         deny_value);
+            }
+        }
+    }
+
+    ret = EOK;
+
+ 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 the access
+ * check for determining 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.
@@ -1047,7 +1191,7 @@ check_rights(char **privilege_sids,
  *    appear in denied_sids
  *
  * Note that a deployment that is unaware of GPO-based access-control policy
- * settings is unaffected by them (b/c the absence of allowed_sids grants access).
+ * settings is unaffected by them (b/c absence of allowed_sids grants access).
  *
  * Note that if a principal_sid appears in both allowed_sids and denied_sids,
  * the "allowed_sids_condition" is met, but the "denied_sids_condition" is not.
@@ -1072,18 +1216,17 @@ 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, "RESULTANT POLICY:\n");
+    DEBUG(SSSDBG_TRACE_FUNC, "gpo_map_type: %s\n",
+          gpo_map_type_string(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, "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]);
+        DEBUG(SSSDBG_TRACE_FUNC, " denied_sids[%d] = %s\n", j, denied_sids[j]);
     }
 
     ret = ad_gpo_get_sids(mem_ctx, user, domain, &user_sid,
@@ -1103,8 +1246,6 @@ ad_gpo_access_check(TALLOC_CTX *mem_ctx,
               group_sids[j]);
     }
 
-    DEBUG(SSSDBG_TRACE_FUNC, "gpo_map_type: %d\n", gpo_map_type);
-
     if (allowed_size == 0) {
         access_granted = true;
     }  else {
@@ -1112,6 +1253,8 @@ ad_gpo_access_check(TALLOC_CTX *mem_ctx,
                                       group_sids, group_size);
     }
 
+    DEBUG(SSSDBG_TRACE_FUNC, "POLICY DECISION:\n");
+
     DEBUG(SSSDBG_TRACE_FUNC, " access_granted = %d\n", access_granted);
 
     access_denied = check_rights(denied_sids, denied_size, user_sid,
@@ -1171,6 +1314,124 @@ static errno_t gpo_child_init(void)
     return EOK;
 }
 
+/*
+ * This function retrieves the raw policy_setting_value for the input key from
+ * the GPO_Result object in the sysdb cache. It then parses the raw value and
+ * uses the results to populate the output parameters with the sids_list and
+ * the size of the sids_list.
+ */
+errno_t
+parse_policy_setting_value(TALLOC_CTX *mem_ctx,
+                           struct sss_domain_info *domain,
+                           const char *key,
+                           char ***_sids_list,
+                           int *_sids_list_size)
+{
+    int ret;
+    int i;
+    const char *value;
+    int sids_list_size;
+    char **sids_list;
+
+    ret = sysdb_gpo_get_gpo_result_setting(mem_ctx, domain, key, &value);
+
+    if (value == NULL) {
+        DEBUG(SSSDBG_TRACE_FUNC,
+              "No value for key [%s] found in gpo result\n", key);
+        sids_list_size = 0;
+    } else {
+        ret = split_on_separator(mem_ctx, value, ',', true, true,
+                                 &sids_list, &sids_list_size);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "Cannot parse list of sids %s: %d\n", value, ret);
+            ret = EINVAL;
+            goto done;
+        }
+
+        for (i = 0; i < sids_list_size; i++) {
+            /* remove the asterisk prefix found on sids */
+            sids_list[i]++;
+        }
+    }
+
+    *_sids_list = talloc_steal(mem_ctx, sids_list);
+    *_sids_list_size = sids_list_size;
+
+    ret = EOK;
+
+ done:
+    return ret;
+}
+
+/*
+ * 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 retrieves the allow_value and deny_value for the
+ * input gpo_map_type from the GPO Result object in the sysdb cache, parses
+ * the values into allow_sids and deny_sids, and executes the access control
+ * algorithm which compares the allow_sids and deny_sids against the user_sid
+ * and group_sids for the input user.
+ */
+static errno_t
+ad_gpo_perform_hbac_processing(TALLOC_CTX *mem_ctx,
+                               enum gpo_access_control_mode gpo_mode,
+                               enum gpo_map_type gpo_map_type,
+                               const char *user,
+                               struct sss_domain_info *domain)
+{
+    int ret;
+    const char *allow_key = NULL;
+    char **allow_sids;
+    int allow_size ;
+    const char *deny_key = NULL;
+    char **deny_sids;
+    int deny_size;
+
+    allow_key = gpo_map_option_entries[gpo_map_type].allow_key;
+    DEBUG(SSSDBG_TRACE_ALL, "allow_key: %s\n", allow_key);
+    deny_key = gpo_map_option_entries[gpo_map_type].deny_key;
+    DEBUG(SSSDBG_TRACE_ALL, "deny_key: %s\n", deny_key);
+
+    ret = parse_policy_setting_value(mem_ctx, domain, allow_key,
+                                     &allow_sids, &allow_size);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "parse_policy_setting_value failed; allow_size %d: %d\n",
+              allow_size, ret);
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = parse_policy_setting_value(mem_ctx, domain, deny_key,
+                                     &deny_sids, &deny_size);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "parse_policy_setting_value failed; deny_size %d: %d\n",
+              deny_size, ret);
+        ret = EINVAL;
+        goto done;
+    }
+
+    /* perform access check with the final resultant allow_sids and deny_sids */
+    ret = ad_gpo_access_check(mem_ctx, gpo_mode, gpo_map_type, user, domain,
+                              allow_sids, allow_size, deny_sids, deny_size);
+
+    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 {
@@ -1201,13 +1462,6 @@ static void ad_gpo_process_som_done(struct tevent_req *subreq);
 static void ad_gpo_process_gpo_done(struct tevent_req *subreq);
 
 static errno_t ad_gpo_cse_step(struct tevent_req *req);
-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);
 static void ad_gpo_cse_done(struct tevent_req *subreq);
 
 struct tevent_req *
@@ -1361,109 +1615,24 @@ 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;
     errno_t ret;
-    int i;
-
-    ret = sysdb_gpo_get_gpos(mem_ctx, domain, &res);
 
+    ret = ad_gpo_perform_hbac_processing(mem_ctx,
+                                         gpo_mode,
+                                         gpo_map_type,
+                                         user,
+                                         domain);
     if (ret != EOK) {
-        switch (ret) {
-        case ENOENT:
-            DEBUG(SSSDBG_OP_FAILURE, "No GPOs available in cache\n");
-            /* if there are no GPOs available, we allow access by default */
-            ret = EOK;
-            goto done;
-        default:
-            DEBUG(SSSDBG_FATAL_FAILURE,
-                  "Could not read GPOs from cache: [%s]\n",
-                  strerror(ret));
-            goto done;
-        }
-    }
-
-    DEBUG(SSSDBG_TRACE_FUNC, "Retrieving GPOs from cache\n");
-    DEBUG(SSSDBG_TRACE_FUNC, "Found %d GPO(s) in cache\n", res->count);
-
-    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));
-            goto done;
-        }
+        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 +1889,9 @@ 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.
+ * 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)
@@ -1822,21 +1992,19 @@ ad_gpo_process_gpo_done(struct tevent_req *subreq)
           state->num_cse_filtered_gpos);
 
     /*
-     * 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
-     * all stale gpo cache entries (i.e. entries that have a gpo-guid that
-     * doesn't match any of the gpo-guids in the cse_filtered_gpo_guids list)
+     * before we start processing each gpo, we delete the GPO Result object
+     * from the sysdb cache so that any previous policy settings are cleared;
+     * subsequent functions will add the GPO Result object (and populate it
+     * with resultant policy settings) for this policy application
      */
-    ret = sysdb_gpo_delete_stale_gpos(state, state->domain,
-                                      cse_filtered_gpo_guids,
-                                      state->num_cse_filtered_gpos);
+    ret = sysdb_gpo_delete_gpo_result_object(state, state->domain);
     if (ret != EOK) {
         switch (ret) {
         case ENOENT:
-            DEBUG(SSSDBG_OP_FAILURE, "No GPOs available in cache\n");
+            DEBUG(SSSDBG_OP_FAILURE, "No GPO Result available in cache\n");
         default:
             DEBUG(SSSDBG_FATAL_FAILURE,
-                  "Could not delete stale GPOs from cache: [%s]\n",
+                  "Could not delete GPO Result from cache: [%s]\n",
                   strerror(ret));
             goto done;
         }
@@ -1870,7 +2038,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 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 +2054,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);
 
+    cse_filtered_gpo->policy_filename =
+        talloc_asprintf(state,
+                        GPO_CACHE_PATH"%s%s",
+                        cse_filtered_gpo->smb_path,
+                        GP_EXT_GUID_SECURITY_SUFFIX);
+    if (cse_filtered_gpo->policy_filename == 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 +2123,12 @@ 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 settings for all applicable GPOs have been
+ * stored as part of the GPO Result object in the sysdb cache. Once all
+ * GPOs have been processed, this functions performs HBAC processing by
+ * comparing the resultant policy setting values in the GPO Result object
+ * with the user_sid/group_sids of interest.
  */
 static void
 ad_gpo_cse_done(struct tevent_req *subreq)
@@ -1960,12 +2136,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 +2147,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 +2157,32 @@ 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;
-    }
+    /*
+     * now that the policy file for this gpo have been downloaded to the
+     * GPO CACHE, we store all of the supported keys present in the file
+     * (as part of the GPO Result object in the sysdb cache).
+     */
+    ret = ad_gpo_store_policy_settings(state, state->domain,
+                                       cse_filtered_gpo->policy_filename);
 
     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->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) {
@@ -2212,7 +2378,7 @@ ad_gpo_populate_gplink_list(TALLOC_CTX *mem_ctx,
         return EINVAL;
     }
 
-    DEBUG(SSSDBG_TRACE_ALL, "som_dn: %s\n", som_dn);
+    DEBUG(SSSDBG_TRACE_FUNC, "som_dn: %s\n", som_dn);
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
         ret = ENOMEM;
@@ -2227,7 +2393,7 @@ ad_gpo_populate_gplink_list(TALLOC_CTX *mem_ctx,
     }
 
     if (gplink_count == 0) {
-        ret = EINVAL;
+        ret = EOK;
         goto done;
     }
 
@@ -3235,8 +3401,7 @@ immediately:
 static errno_t
 ad_gpo_get_gpo_attrs_step(struct tevent_req *req)
 {
-    const char *attrs[] = {AD_AT_NT_SEC_DESC, AD_AT_CN, AD_AT_DISPLAY_NAME,
-                           AD_AT_FILE_SYS_PATH, AD_AT_VERSION_NUMBER,
+    const char *attrs[] = {AD_AT_NT_SEC_DESC, AD_AT_CN, AD_AT_FILE_SYS_PATH,
                            AD_AT_MACHINE_EXT_NAMES, AD_AT_FUNC_VERSION,
                            AD_AT_FLAGS, NULL};
     struct tevent_req *subreq;
@@ -3275,7 +3440,6 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
     struct sysdb_attrs **results;
     struct ldb_message_element *el = NULL;
     const char *gpo_guid = NULL;
-    const char *gpo_display_name = NULL;
     const char *raw_file_sys_path = NULL;
     char *file_sys_path = NULL;
     uint8_t *raw_machine_ext_names = NULL;
@@ -3328,25 +3492,6 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
     DEBUG(SSSDBG_TRACE_ALL, "populating attrs for gpo_guid: %s\n",
           gp_gpo->gpo_guid);
 
-    /* retrieve AD_AT_DISPLAY_NAME */
-    ret = sysdb_attrs_get_string(results[0], AD_AT_DISPLAY_NAME,
-                                 &gpo_display_name);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              "sysdb_attrs_get_string failed: [%d](%s)\n",
-              ret, sss_strerror(ret));
-        goto done;
-    }
-
-    gp_gpo->gpo_display_name = talloc_steal(gp_gpo, gpo_display_name);
-    if (gp_gpo->gpo_display_name == NULL) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    DEBUG(SSSDBG_TRACE_ALL, "gpo_display_name: %s\n",
-                            gp_gpo->gpo_display_name);
-
     /* retrieve AD_AT_FILE_SYS_PATH */
     ret = sysdb_attrs_get_string(results[0],
                                  AD_AT_FILE_SYS_PATH,
@@ -3375,43 +3520,6 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
     DEBUG(SSSDBG_TRACE_ALL, "smb_share: %s\n", gp_gpo->smb_share);
     DEBUG(SSSDBG_TRACE_ALL, "smb_path: %s\n", gp_gpo->smb_path);
 
-    /* retrieve AD_AT_VERSION_NUMBER */
-    ret = sysdb_attrs_get_uint32_t(results[0], AD_AT_VERSION_NUMBER,
-                                   &gp_gpo->gpc_version);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              "sysdb_attrs_get_uint32_t failed: [%d](%s)\n",
-              ret, sss_strerror(ret));
-        goto done;
-    }
-
-    DEBUG(SSSDBG_TRACE_ALL, "gpc_version: %d\n", gp_gpo->gpc_version);
-
-    /* retrieve AD_AT_MACHINE_EXT_NAMES */
-    ret = sysdb_attrs_get_el(results[0], AD_AT_MACHINE_EXT_NAMES, &el);
-    if (ret != EOK && ret != ENOENT) {
-        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
-        goto done;
-    }
-    if ((ret == ENOENT) || (el->num_values == 0)) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              "machine_ext_names not found or has no value\n");
-        ret = ENOENT;
-        goto done;
-    }
-
-    raw_machine_ext_names = el[0].values[0].data;
-
-    ret = ad_gpo_parse_machine_ext_names(gp_gpo,
-                                         (char *)raw_machine_ext_names,
-                                         &gp_gpo->gpo_cse_guids,
-                                         &gp_gpo->num_gpo_cse_guids);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              "ad_gpo_parse_machine_ext_names() failed\n");
-        goto done;
-    }
-
     /* retrieve AD_AT_FUNC_VERSION */
     ret = sysdb_attrs_get_int32_t(results[0], AD_AT_FUNC_VERSION,
                                   &gp_gpo->gpo_func_version);
@@ -3457,7 +3565,37 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
         goto done;
     }
 
-    state->gpo_index++;
+    /* retrieve AD_AT_MACHINE_EXT_NAMES */
+    ret = sysdb_attrs_get_el(results[0], AD_AT_MACHINE_EXT_NAMES, &el);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
+        goto done;
+    }
+
+    if ((ret == ENOENT) || (el->num_values == 0)) {
+        /*
+         * if gpo has no machine_ext_names (which is perfectly valid: it could
+         * have only user_ext_names, for example), we continue to next gpo
+         */
+        DEBUG(SSSDBG_TRACE_ALL,
+              "machine_ext_names attribute not found or has no value\n");
+        state->gpo_index++;
+    } else {
+        raw_machine_ext_names = el[0].values[0].data;
+
+        ret = ad_gpo_parse_machine_ext_names(gp_gpo,
+                                             (char *)raw_machine_ext_names,
+                                             &gp_gpo->gpo_cse_guids,
+                                             &gp_gpo->num_gpo_cse_guids);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "ad_gpo_parse_machine_ext_names() failed\n");
+            goto done;
+        }
+
+        state->gpo_index++;
+    }
+
     ret = ad_gpo_get_gpo_attrs_step(req);
 
  done:
@@ -3550,207 +3688,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 +3723,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 +3771,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 +3802,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 +3931,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 +3947,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;
 }
 
diff --git a/src/tests/cmocka/test_ad_gpo.c b/src/tests/cmocka/test_ad_gpo.c
index e6319118e3c94e3a5c9c7e06f7025f2cd4ec9037..4753c95d32651ab13a107a945769a5fbc8e38b7d 100644
--- a/src/tests/cmocka/test_ad_gpo.c
+++ b/src/tests/cmocka/test_ad_gpo.c
@@ -256,7 +256,6 @@ void test_populate_gplink_list_malformed(void **state)
     };
 
     test_populate_gplink_list(NULL, false, &expected);
-    test_populate_gplink_list("[malformed", false, &expected);
     test_populate_gplink_list("[malformed]", false, &expected);
     /* the GPLinkOptions value (after semicolon) must be between 0 and 3 */
     test_populate_gplink_list("[gpo_dn; 4]", false, &expected);
-- 
1.8.5.3

