Add infrastructure for reading/storing Group Policy state and control data in the...
authorGünther Deschner <gd@samba.org>
Fri, 29 Feb 2008 14:46:14 +0000 (15:46 +0100)
committerGünther Deschner <gd@samba.org>
Fri, 29 Feb 2008 14:48:14 +0000 (15:48 +0100)
Guenther
(This used to be commit f673bbd300d972dd7ae2d092b3b1e642ed29cfd2)

source3/Makefile.in
source3/include/gpo.h
source3/include/reg_objects.h
source3/libgpo/gpo_reg.c [new file with mode: 0644]

index c6815e91e60dcd8e4db10b2aaf4725c5e565d296..baa917724da357b5fd0872327abae5a22ed4da0f 100644 (file)
@@ -377,7 +377,8 @@ LIBWBCLIENT_OBJ0 = nsswitch/libwbclient/wbclient.o \
 LIBWBCLIENT_OBJ = $(LIBWBCLIENT_OBJ0) $(WBCOMMON_OBJ) @LIBTALLOC_STATIC@ $(LIBREPLACE_OBJ)
 
 LIBGPO_OBJ0 = libgpo/gpo_ldap.o libgpo/gpo_ini.o libgpo/gpo_util.o \
-             libgpo/gpo_fetch.o libgpo/gpo_filesync.o libgpo/gpo_sec.o
+             libgpo/gpo_fetch.o libgpo/gpo_filesync.o libgpo/gpo_sec.o \
+             libgpo/gpo_reg.o
 LIBGPO_OBJ = $(LIBGPO_OBJ0)
 
 LIBADS_OBJ = libads/ldap.o libads/ldap_printer.o \
index 9b1a672640852bfde7242cf54a361cb4723d511f..d8d9e8e597d925ec30c916ecb4980535682acfd9 100644 (file)
@@ -22,7 +22,8 @@ enum GPO_LINK_TYPE {
        GP_LINK_MACHINE = 1,
        GP_LINK_SITE    = 2,
        GP_LINK_DOMAIN  = 3,
-       GP_LINK_OU      = 4
+       GP_LINK_OU      = 4,
+       GP_LINK_LOCAL   = 5 /* for convenience */
 };
 
 /* GPO_OPTIONS */
@@ -33,6 +34,17 @@ enum GPO_LINK_TYPE {
 #define GPO_LIST_FLAG_MACHINE  0x00000001
 #define GPO_LIST_FLAG_SITEONLY 0x00000002
 
+/* following flags from http://support.microsoft.com/kb/312164/EN-US/ */
+#define GPO_INFO_FLAG_MACHINE                  0x00000001
+#define GPO_INFO_FLAG_BACKGROUND               0x00000010
+#define GPO_INFO_FLAG_SLOWLINK                 0x00000020
+#define GPO_INFO_FLAG_VERBOSE                  0x00000040
+#define GPO_INFO_FLAG_NOCHANGES                        0x00000080
+#define GPO_INFO_FLAG_LINKTRANSITION           0x00000100
+#define GPO_INFO_FLAG_LOGRSOP_TRANSITION       0x00000200
+#define GPO_INFO_FLAG_FORCED_REFRESH           0x00000400
+#define GPO_INFO_FLAG_SAFEMODE_BOOT            0x00000800
+
 #define GPO_VERSION_USER(x) (x >> 16)
 #define GPO_VERSION_MACHINE(x) (x & 0xffff)
 
@@ -88,10 +100,56 @@ struct GP_EXT {
        char **extensions_guid;
        char **snapins;
        char **snapins_guid;
+       struct GP_EXT *next, *prev;
 };
 
 #define GPO_CACHE_DIR "gpo_cache"
 #define GPT_INI "GPT.INI"
+#define GPO_REFRESH_INTERVAL 60*90
+
+#define GPO_REG_STATE_MACHINE "State\\Machine"
+
+enum gp_reg_action {
+       GP_REG_ACTION_NONE = 0,
+       GP_REG_ACTION_ADD_VALUE = 1,
+       GP_REG_ACTION_ADD_KEY = 2,
+       GP_REG_ACTION_DEL_VALUES = 3,
+       GP_REG_ACTION_DEL_VALUE = 4,
+       GP_REG_ACTION_DEL_ALL_VALUES = 5,
+       GP_REG_ACTION_DEL_KEYS = 6,
+       GP_REG_ACTION_SEC_KEY_SET = 7,
+       GP_REG_ACTION_SEC_KEY_RESET = 8
+};
+
+struct gp_registry_entry {
+       enum gp_reg_action action;
+       const char *key;
+       const char *value;
+       struct registry_value *data;
+};
+
+struct gp_registry_value {
+       const char *value;
+       struct registry_value *data;
+};
+
+struct gp_registry_entry2 {
+       enum gp_reg_action action;
+       const char *key;
+       size_t num_values;
+       struct gp_registry_value **values;
+};
+
+struct gp_registry_entries {
+       size_t num_entries;
+       struct gp_registry_entry **entries;
+};
+
+struct gp_registry_context {
+       const struct nt_user_token *token;
+       const char *path;
+       struct registry_key *curr_key;
+};
 
 #define GP_EXT_GUID_SECURITY "827D319E-6EAC-11D2-A4EA-00C04F79F83A"
 #define GP_EXT_GUID_REGISTRY "35378EAC-683F-11D2-A89A-00C04FBBCFA2"
index 3df701f61cced8fc79fe60fe062b1a45f721108c..1d0d0d4996f476aa98f02ddc8d7588e5b3cc84d9 100644 (file)
@@ -105,9 +105,16 @@ typedef struct {
 #define KEY_CURRENT_VERSION    "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
 #define KEY_PERFLIB            "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"
 #define KEY_PERFLIB_009                "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"
+#define KEY_GROUP_POLICY       "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Group Policy"
+#define KEY_WINLOGON           "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"
 #define KEY_SMBCONF            "HKLM\\SOFTWARE\\Samba\\smbconf"
+#define KEY_SAMBA_GROUP_POLICY "HKLM\\SOFTWARE\\Samba\\Group Policy"
 #define KEY_TREE_ROOT          ""
 
+#define KEY_GP_MACHINE_POLICY          "HKLM\\Software\\Policies"
+#define KEY_GP_MACHINE_WIN_POLICY      "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies"
+#define KEY_GP_USER_POLICY             "HKCU\\Software\\Policies"
+#define KEY_GP_USER_WIN_POLICY         "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies"
 /*
  * Registry key types
  *     Most keys are going to be GENERIC -- may need a better name?
diff --git a/source3/libgpo/gpo_reg.c b/source3/libgpo/gpo_reg.c
new file mode 100644 (file)
index 0000000..2a27a7e
--- /dev/null
@@ -0,0 +1,1058 @@
+/*
+ *  Unix SMB/CIFS implementation.
+ *  Group Policy Object Support
+ *  Copyright (C) Guenther Deschner 2007-2008
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+
+extern REGISTRY_OPS regdb_ops;
+
+static int gp_reg_fetch_keys(const char *key, REGSUBKEY_CTR *subkey_ctr)
+{
+       return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+static bool gp_reg_store_keys(const char *key, REGSUBKEY_CTR *subkeys)
+{
+       return regdb_ops.store_subkeys(key, subkeys);
+}
+
+static int gp_reg_fetch_values(const char *key, REGVAL_CTR *val)
+{
+       return regdb_ops.fetch_values(key, val);
+}
+
+static bool gp_reg_store_values(const char *key, REGVAL_CTR *val)
+{
+       return regdb_ops.store_values(key, val);
+}
+
+static WERROR gp_reg_get_secdesc(TALLOC_CTX *mem_ctx, const char *key,
+                                struct security_descriptor **psecdesc)
+{
+       return regdb_ops.get_secdesc(mem_ctx, key, psecdesc);
+}
+
+static WERROR gp_reg_set_secdesc(const char *key,
+                                struct security_descriptor *secdesc)
+{
+       return regdb_ops.set_secdesc(key, secdesc);
+}
+
+/****************************************************************
+****************************************************************/
+
+static REGISTRY_OPS gp_reg_ops = {
+       .fetch_subkeys          = gp_reg_fetch_keys,
+       .fetch_values           = gp_reg_fetch_values,
+       .store_subkeys          = gp_reg_store_keys,
+       .store_values           = gp_reg_store_values,
+/*     .reg_access_check       = gp_reg_reg_access_check, */
+       .get_secdesc            = gp_reg_get_secdesc,
+       .set_secdesc            = gp_reg_set_secdesc
+};
+
+/****************************************************************
+****************************************************************/
+
+struct nt_user_token *registry_create_system_token(TALLOC_CTX *mem_ctx)
+{
+       struct nt_user_token *token = NULL;
+
+       token = TALLOC_ZERO_P(mem_ctx, struct nt_user_token);
+       if (!token) {
+               DEBUG(1,("talloc failed\n"));
+               return NULL;
+       }
+
+       token->privileges = se_priv_all;
+
+       if (!NT_STATUS_IS_OK(add_sid_to_array(token, &global_sid_System,
+                        &token->user_sids, &token->num_sids))) {
+               DEBUG(1,("Error adding nt-authority system sid to token\n"));
+               return NULL;
+       }
+
+       return token;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_init_reg_ctx(TALLOC_CTX *mem_ctx,
+                      const char *initial_path,
+                      uint32_t desired_access,
+                      const struct nt_user_token *token,
+                      struct gp_registry_context **reg_ctx)
+{
+       struct gp_registry_context *tmp_ctx;
+       static REGISTRY_HOOK gp_reg_hook;
+       WERROR werr;
+
+       if (!reg_ctx) {
+               return WERR_INVALID_PARAM;
+       }
+
+       if (!regdb_init()) {
+               return WERR_CAN_NOT_COMPLETE;
+       }
+
+       gp_reg_hook.keyname = initial_path; /* KEY_SAMBA_GROUP_POLICY */
+       gp_reg_hook.ops = &gp_reg_ops;
+
+       /* not sure about the cache hook */
+       reghook_cache_init();
+
+       if (!reghook_cache_add(&gp_reg_hook)) {
+               return WERR_CAN_NOT_COMPLETE;
+       }
+
+       tmp_ctx = TALLOC_ZERO_P(mem_ctx, struct gp_registry_context);
+       W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
+
+       if (token) {
+               tmp_ctx->token = token;
+       } else {
+               tmp_ctx->token = registry_create_system_token(mem_ctx);
+       }
+       if (!tmp_ctx->token) {
+               TALLOC_FREE(tmp_ctx);
+               return WERR_NOMEM;
+       }
+
+       if (initial_path) {
+               tmp_ctx->path = talloc_strdup(mem_ctx, initial_path);
+               if (!tmp_ctx->path) {
+                       TALLOC_FREE(tmp_ctx);
+                       return WERR_NOMEM;
+               }
+
+               werr = reg_open_path(mem_ctx, tmp_ctx->path, desired_access,
+                                    tmp_ctx->token, &tmp_ctx->curr_key);
+               if (!W_ERROR_IS_OK(werr)) {
+                       TALLOC_FREE(tmp_ctx);
+                       return werr;
+               }
+       }
+
+       *reg_ctx = tmp_ctx;
+
+       return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+void gp_free_reg_ctx(struct gp_registry_context *reg_ctx)
+{
+       TALLOC_FREE(reg_ctx);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_store_reg_subkey(TALLOC_CTX *mem_ctx,
+                          const char *subkeyname,
+                          struct registry_key *curr_key,
+                          struct registry_key **new_key)
+{
+       enum winreg_CreateAction action = REG_ACTION_NONE;
+       WERROR werr;
+
+       werr = reg_createkey(mem_ctx, curr_key, subkeyname,
+                            REG_KEY_WRITE, new_key, &action);
+       if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) {
+               return WERR_OK;
+       }
+
+       return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_read_reg_subkey(TALLOC_CTX *mem_ctx,
+                         struct gp_registry_context *reg_ctx,
+                         const char *subkeyname,
+                         struct registry_key **key)
+{
+       const char *tmp = NULL;
+
+       if (!reg_ctx || !subkeyname || !key) {
+               return WERR_INVALID_PARAM;
+       }
+
+       tmp = talloc_asprintf(mem_ctx, "%s\\%s", reg_ctx->path, subkeyname);
+       W_ERROR_HAVE_NO_MEMORY(tmp);
+
+       return reg_open_path(mem_ctx, tmp, REG_KEY_READ,
+                            reg_ctx->token, key);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_store_reg_val_sz(TALLOC_CTX *mem_ctx,
+                          struct registry_key *key,
+                          const char *val_name,
+                          const char *val)
+{
+       struct registry_value reg_val;
+       ZERO_STRUCT(reg_val);
+
+       /* FIXME: hack */
+       val = val ? val : " ";
+
+       reg_val.type = REG_SZ;
+       reg_val.v.sz.len = strlen(val);
+       reg_val.v.sz.str = talloc_strdup(mem_ctx, val);
+       W_ERROR_HAVE_NO_MEMORY(reg_val.v.sz.str);
+
+       return reg_setvalue(key, val_name, &reg_val);
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_store_reg_val_dword(TALLOC_CTX *mem_ctx,
+                                    struct registry_key *key,
+                                    const char *val_name,
+                                    uint32_t val)
+{
+       struct registry_value reg_val;
+       ZERO_STRUCT(reg_val);
+
+       reg_val.type = REG_DWORD;
+       reg_val.v.dword = val;
+
+       return reg_setvalue(key, val_name, &reg_val);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_read_reg_val_sz(TALLOC_CTX *mem_ctx,
+                         struct registry_key *key,
+                         const char *val_name,
+                         const char **val)
+{
+       WERROR werr;
+       struct registry_value *reg_val = NULL;
+
+       werr = reg_queryvalue(mem_ctx, key, val_name, &reg_val);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       if (reg_val->type != REG_SZ) {
+               return WERR_INVALID_DATATYPE;
+       }
+
+       *val = talloc_strdup(mem_ctx, reg_val->v.sz.str);
+       W_ERROR_HAVE_NO_MEMORY(*val);
+
+       return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_read_reg_val_dword(TALLOC_CTX *mem_ctx,
+                                   struct registry_key *key,
+                                   const char *val_name,
+                                   uint32_t *val)
+{
+       WERROR werr;
+       struct registry_value *reg_val = NULL;
+
+       werr = reg_queryvalue(mem_ctx, key, val_name, &reg_val);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       if (reg_val->type != REG_DWORD) {
+               return WERR_INVALID_DATATYPE;
+       }
+
+       *val = reg_val->v.dword;
+
+       return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_store_reg_gpovals(TALLOC_CTX *mem_ctx,
+                                  struct registry_key *key,
+                                  struct GROUP_POLICY_OBJECT *gpo)
+{
+       WERROR werr;
+
+       if (!key || !gpo) {
+               return WERR_INVALID_PARAM;
+       }
+
+       werr = gp_store_reg_val_dword(mem_ctx, key, "Version",
+                                     gpo->version);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_store_reg_val_dword(mem_ctx, key, "WQLFilterPass",
+                                     true); /* fake */
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_store_reg_val_dword(mem_ctx, key, "AccessDenied",
+                                     false); /* fake */
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_store_reg_val_dword(mem_ctx, key, "GPO-Disabled",
+                                     (gpo->options & GPO_FLAG_DISABLE));
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_store_reg_val_dword(mem_ctx, key, "Options",
+                                     gpo->options);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_store_reg_val_sz(mem_ctx, key, "GPOID",
+                                  gpo->name);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_store_reg_val_sz(mem_ctx, key, "SOM",
+                                  gpo->link);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_store_reg_val_sz(mem_ctx, key, "DisplayName",
+                                  gpo->display_name);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_store_reg_val_sz(mem_ctx, key, "WQL-Id",
+                                  NULL);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static const char *gp_reg_groupmembership_path(TALLOC_CTX *mem_ctx,
+                                              const DOM_SID *sid,
+                                              uint32_t flags)
+{
+       if (flags & GPO_LIST_FLAG_MACHINE) {
+               return "GroupMembership";
+       }
+
+       return talloc_asprintf(mem_ctx, "%s\\%s", sid_string_tos(sid),
+                              "GroupMembership");
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_reg_del_groupmembership(TALLOC_CTX *mem_ctx,
+                                        struct registry_key *key,
+                                        const struct nt_user_token *token,
+                                        uint32_t flags)
+{
+       const char *path = NULL;
+
+       path = gp_reg_groupmembership_path(mem_ctx, &token->user_sids[0],
+                                          flags);
+       W_ERROR_HAVE_NO_MEMORY(path);
+
+       return reg_deletekey_recursive(mem_ctx, key, path);
+
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_reg_store_groupmembership(TALLOC_CTX *mem_ctx,
+                                          struct gp_registry_context *reg_ctx,
+                                          const struct nt_user_token *token,
+                                          uint32_t flags)
+{
+       struct registry_key *key = NULL;
+       WERROR werr;
+       int i = 0;
+       const char *valname = NULL;
+       const char *path = NULL;
+       const char *val = NULL;
+       int count = 0;
+
+       path = gp_reg_groupmembership_path(mem_ctx, &token->user_sids[0],
+                                          flags);
+       W_ERROR_HAVE_NO_MEMORY(path);
+
+       gp_reg_del_groupmembership(mem_ctx, reg_ctx->curr_key, token, flags);
+
+       werr = gp_store_reg_subkey(mem_ctx, path,
+                                  reg_ctx->curr_key, &key);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       for (i=0; i<token->num_sids; i++) {
+
+               valname = talloc_asprintf(mem_ctx, "Group%d", count++);
+               W_ERROR_HAVE_NO_MEMORY(valname);
+
+               val = sid_string_talloc(mem_ctx, &token->user_sids[i]);
+               W_ERROR_HAVE_NO_MEMORY(val);
+               werr = gp_store_reg_val_sz(mem_ctx, key, valname, val);
+               W_ERROR_NOT_OK_RETURN(werr);
+       }
+
+       werr = gp_store_reg_val_dword(mem_ctx, key, "Count", count);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+#if 0
+/* not used yet */
+static WERROR gp_reg_read_groupmembership(TALLOC_CTX *mem_ctx,
+                                         struct gp_registry_context *reg_ctx,
+                                         const DOM_SID *object_sid,
+                                         struct nt_user_token **token,
+                                         uint32_t flags)
+{
+       struct registry_key *key = NULL;
+       WERROR werr;
+       int i = 0;
+       const char *valname = NULL;
+       const char *val = NULL;
+       const char *path = NULL;
+       uint32_t count = 0;
+       int num_token_sids = 0;
+       struct nt_user_token *tmp_token = NULL;
+
+       tmp_token = TALLOC_ZERO_P(mem_ctx, struct nt_user_token);
+       W_ERROR_HAVE_NO_MEMORY(tmp_token);
+
+       path = gp_reg_groupmembership_path(mem_ctx, object_sid, flags);
+       W_ERROR_HAVE_NO_MEMORY(path);
+
+       werr = gp_read_reg_subkey(mem_ctx, reg_ctx, path, &key);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_read_reg_val_dword(mem_ctx, key, "Count", &count);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       for (i=0; i<count; i++) {
+
+               valname = talloc_asprintf(mem_ctx, "Group%d", i);
+               W_ERROR_HAVE_NO_MEMORY(valname);
+
+               werr = gp_read_reg_val_sz(mem_ctx, key, valname, &val);
+               W_ERROR_NOT_OK_RETURN(werr);
+
+               if (!string_to_sid(&tmp_token->user_sids[num_token_sids++],
+                                  val)) {
+                       return WERR_INSUFFICIENT_BUFFER;
+               }
+       }
+
+       tmp_token->num_sids = num_token_sids;
+
+       *token = tmp_token;
+
+       return WERR_OK;
+}
+#endif
+/****************************************************************
+****************************************************************/
+
+static const char *gp_req_state_path(TALLOC_CTX *mem_ctx,
+                                    const DOM_SID *sid,
+                                    uint32_t flags)
+{
+       if (flags & GPO_LIST_FLAG_MACHINE) {
+               return GPO_REG_STATE_MACHINE;
+       }
+
+       return talloc_asprintf(mem_ctx, "%s\\%s", "State", sid_string_tos(sid));
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_del_reg_state(TALLOC_CTX *mem_ctx,
+                              struct registry_key *key,
+                              const char *path)
+{
+       return reg_deletesubkeys_recursive(mem_ctx, key, path);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_reg_state_store(TALLOC_CTX *mem_ctx,
+                         uint32_t flags,
+                         const char *dn,
+                         const struct nt_user_token *token,
+                         struct GROUP_POLICY_OBJECT *gpo_list)
+{
+       struct gp_registry_context *reg_ctx = NULL;
+       WERROR werr = WERR_GENERAL_FAILURE;
+       const char *subkeyname = NULL;
+       struct GROUP_POLICY_OBJECT *gpo;
+       int count = 0;
+       struct registry_key *key;
+
+       werr = gp_init_reg_ctx(mem_ctx, KEY_GROUP_POLICY, REG_KEY_WRITE,
+                              token, &reg_ctx);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_secure_key(mem_ctx, flags, KEY_GROUP_POLICY,
+                            &token->user_sids[0]);
+       if (!W_ERROR_IS_OK(werr)) {
+               DEBUG(0,("failed to secure key: %s\n", dos_errstr(werr)));
+               goto done;
+       }
+
+       werr = gp_reg_store_groupmembership(mem_ctx, reg_ctx, token, flags);
+       if (!W_ERROR_IS_OK(werr)) {
+               DEBUG(0,("failed to store group membership: %s\n", dos_errstr(werr)));
+               goto done;
+       }
+
+       subkeyname = gp_req_state_path(mem_ctx, &token->user_sids[0], flags);
+       if (!subkeyname) {
+               werr = WERR_NOMEM;
+               goto done;
+       }
+
+       werr = gp_del_reg_state(mem_ctx, reg_ctx->curr_key, subkeyname);
+       if (!W_ERROR_IS_OK(werr)) {
+               DEBUG(0,("failed to delete old state: %s\n", dos_errstr(werr)));
+               /* goto done; */
+       }
+
+       werr = gp_store_reg_subkey(mem_ctx, subkeyname,
+                                  reg_ctx->curr_key, &reg_ctx->curr_key);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
+       }
+
+       werr = gp_store_reg_val_sz(mem_ctx, reg_ctx->curr_key,
+                                  "Distinguished-Name", dn);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
+       }
+
+       /* store link list */
+
+       werr = gp_store_reg_subkey(mem_ctx, "GPLink-List",
+                                  reg_ctx->curr_key, &key);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
+       }
+
+       /* store gpo list */
+
+       werr = gp_store_reg_subkey(mem_ctx, "GPO-List",
+                                  reg_ctx->curr_key, &reg_ctx->curr_key);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
+       }
+
+       for (gpo = gpo_list; gpo; gpo = gpo->next) {
+
+               subkeyname = talloc_asprintf(mem_ctx, "%d", count++);
+               if (!subkeyname) {
+                       werr = WERR_NOMEM;
+                       goto done;
+               }
+
+               werr = gp_store_reg_subkey(mem_ctx, subkeyname,
+                                          reg_ctx->curr_key, &key);
+               if (!W_ERROR_IS_OK(werr)) {
+                       goto done;
+               }
+
+               werr = gp_store_reg_gpovals(mem_ctx, key, gpo);
+               if (!W_ERROR_IS_OK(werr)) {
+                       DEBUG(0,("gp_reg_state_store: "
+                               "gpo_store_reg_gpovals failed for %s: %s\n",
+                               gpo->display_name, dos_errstr(werr)));
+                       goto done;
+               }
+       }
+ done:
+       gp_free_reg_ctx(reg_ctx);
+       return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_read_reg_gpovals(TALLOC_CTX *mem_ctx,
+                                 struct registry_key *key,
+                                 struct GROUP_POLICY_OBJECT *gpo)
+{
+       WERROR werr;
+
+       if (!key || !gpo) {
+               return WERR_INVALID_PARAM;
+       }
+
+       werr = gp_read_reg_val_dword(mem_ctx, key, "Version",
+                                    &gpo->version);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_read_reg_val_dword(mem_ctx, key, "Options",
+                                    &gpo->options);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_read_reg_val_sz(mem_ctx, key, "GPOID",
+                                 &gpo->name);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_read_reg_val_sz(mem_ctx, key, "SOM",
+                                 &gpo->link);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       werr = gp_read_reg_val_sz(mem_ctx, key, "DisplayName",
+                                 &gpo->display_name);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_read_reg_gpo(TALLOC_CTX *mem_ctx,
+                             struct registry_key *key,
+                             struct GROUP_POLICY_OBJECT **gpo_ret)
+{
+       struct GROUP_POLICY_OBJECT *gpo = NULL;
+       WERROR werr;
+
+       if (!gpo_ret || !key) {
+               return WERR_INVALID_PARAM;
+       }
+
+       gpo = TALLOC_ZERO_P(mem_ctx, struct GROUP_POLICY_OBJECT);
+       W_ERROR_HAVE_NO_MEMORY(gpo);
+
+       werr = gp_read_reg_gpovals(mem_ctx, key, gpo);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       *gpo_ret = gpo;
+
+       return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_reg_state_read(TALLOC_CTX *mem_ctx,
+                        uint32_t flags,
+                        const DOM_SID *sid,
+                        struct GROUP_POLICY_OBJECT **gpo_list)
+{
+       struct gp_registry_context *reg_ctx = NULL;
+       WERROR werr = WERR_GENERAL_FAILURE;
+       const char *subkeyname = NULL;
+       struct GROUP_POLICY_OBJECT *gpo = NULL;
+       int count = 0;
+       struct registry_key *key = NULL;
+       const char *path = NULL;
+       const char *gp_state_path = NULL;
+
+       if (!gpo_list) {
+               return WERR_INVALID_PARAM;
+       }
+
+       ZERO_STRUCTP(gpo_list);
+
+       gp_state_path = gp_req_state_path(mem_ctx, sid, flags);
+       if (!gp_state_path) {
+               werr = WERR_NOMEM;
+               goto done;
+       }
+
+       path = talloc_asprintf(mem_ctx, "%s\\%s\\%s",
+                              KEY_GROUP_POLICY,
+                              gp_state_path,
+                              "GPO-List");
+       if (!path) {
+               werr = WERR_NOMEM;
+               goto done;
+       }
+
+       werr = gp_init_reg_ctx(mem_ctx, path, REG_KEY_READ, NULL, &reg_ctx);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
+       }
+
+       while (1) {
+
+               subkeyname = talloc_asprintf(mem_ctx, "%d", count++);
+               if (!subkeyname) {
+                       werr = WERR_NOMEM;
+                       goto done;
+               }
+
+               werr = gp_read_reg_subkey(mem_ctx, reg_ctx, subkeyname, &key);
+               if (W_ERROR_EQUAL(werr, WERR_BADFILE)) {
+                       werr = WERR_OK;
+                       break;
+               }
+               if (!W_ERROR_IS_OK(werr)) {
+                       DEBUG(0,("gp_reg_state_read: "
+                               "gp_read_reg_subkey gave: %s\n",
+                               dos_errstr(werr)));
+                       goto done;
+               }
+
+               werr = gp_read_reg_gpo(mem_ctx, key, &gpo);
+               if (!W_ERROR_IS_OK(werr)) {
+                       goto done;
+               }
+
+               DLIST_ADD(*gpo_list, gpo);
+       }
+
+ done:
+       gp_free_reg_ctx(reg_ctx);
+       return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_reg_generate_sd(TALLOC_CTX *mem_ctx,
+                                const DOM_SID *sid,
+                                struct security_descriptor **sd,
+                                size_t *sd_size)
+{
+       SEC_ACE ace[6];
+       SEC_ACCESS mask;
+
+       SEC_ACL *acl = NULL;
+
+       uint8_t inherit_flags;
+
+       init_sec_access(&mask, REG_KEY_ALL);
+       init_sec_ace(&ace[0],
+                    &global_sid_System,
+                    SEC_ACE_TYPE_ACCESS_ALLOWED,
+                    mask, 0);
+
+       init_sec_access(&mask, REG_KEY_ALL);
+       init_sec_ace(&ace[1],
+                    &global_sid_Builtin_Administrators,
+                    SEC_ACE_TYPE_ACCESS_ALLOWED,
+                    mask, 0);
+
+       init_sec_access(&mask, REG_KEY_READ);
+       init_sec_ace(&ace[2],
+                    sid ? sid : &global_sid_Authenticated_Users,
+                    SEC_ACE_TYPE_ACCESS_ALLOWED,
+                    mask, 0);
+
+       inherit_flags = SEC_ACE_FLAG_OBJECT_INHERIT |
+                       SEC_ACE_FLAG_CONTAINER_INHERIT |
+                       SEC_ACE_FLAG_INHERIT_ONLY;
+
+       init_sec_access(&mask, REG_KEY_ALL);
+       init_sec_ace(&ace[3],
+                    &global_sid_System,
+                    SEC_ACE_TYPE_ACCESS_ALLOWED,
+                    mask, inherit_flags);
+
+       init_sec_access(&mask, REG_KEY_ALL);
+       init_sec_ace(&ace[4],
+                    &global_sid_Builtin_Administrators,
+                    SEC_ACE_TYPE_ACCESS_ALLOWED,
+                    mask, inherit_flags);
+
+       init_sec_access(&mask, REG_KEY_READ);
+       init_sec_ace(&ace[5],
+                    sid ? sid : &global_sid_Authenticated_Users,
+                    SEC_ACE_TYPE_ACCESS_ALLOWED,
+                    mask, inherit_flags);
+
+       acl = make_sec_acl(mem_ctx, NT4_ACL_REVISION, 6, ace);
+       W_ERROR_HAVE_NO_MEMORY(acl);
+
+       *sd = make_sec_desc(mem_ctx, SEC_DESC_REVISION,
+                           SEC_DESC_SELF_RELATIVE |
+                           SEC_DESC_DACL_AUTO_INHERITED | /* really ? */
+                           SEC_DESC_DACL_AUTO_INHERIT_REQ, /* really ? */
+                           NULL, NULL, NULL,
+                           acl, sd_size);
+       W_ERROR_HAVE_NO_MEMORY(*sd);
+
+       return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_secure_key(TALLOC_CTX *mem_ctx,
+                    uint32_t flags,
+                    const char *key,
+                    const DOM_SID *sid)
+{
+       struct security_descriptor *sd = NULL;
+       size_t sd_size = 0;
+       const DOM_SID *sd_sid = NULL;
+       WERROR werr;
+
+       if (!(flags & GPO_LIST_FLAG_MACHINE)) {
+               sd_sid = sid;
+       }
+
+       werr = gp_reg_generate_sd(mem_ctx, sd_sid, &sd, &sd_size);
+       W_ERROR_NOT_OK_RETURN(werr);
+
+       return gp_reg_set_secdesc(key, sd);
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_reg_val(int lvl, const char *direction,
+                 const char *key, const char *subkey,
+                 struct registry_value *val)
+{
+       int i = 0;
+       const char *type_str = NULL;
+
+       if (!val) {
+               DEBUG(lvl,("no val!\n"));
+               return;
+       }
+
+       type_str = reg_type_lookup(val->type);
+
+       DEBUG(lvl,("\tdump_reg_val: %s '%s' '%s' %s: ",
+               direction, key, subkey, type_str));
+
+       switch (val->type) {
+               case REG_DWORD:
+                       DEBUG(lvl,("%d\n", (int)val->v.dword));
+                       break;
+               case REG_QWORD:
+                       DEBUG(lvl,("%d\n", (int)val->v.qword));
+                       break;
+               case REG_SZ:
+                       DEBUG(lvl,("%s (length: %d)\n",
+                                  val->v.sz.str,
+                                  (int)val->v.sz.len));
+                       break;
+               case REG_MULTI_SZ:
+                       DEBUG(lvl,("(num_strings: %d)\n",
+                                  val->v.multi_sz.num_strings));
+                       for (i=0; i < val->v.multi_sz.num_strings; i++) {
+                               DEBUGADD(lvl,("\t%s\n",
+                                       val->v.multi_sz.strings[i]));
+                       }
+                       break;
+               case REG_NONE:
+                       DEBUG(lvl,("\n"));
+                       break;
+               case REG_BINARY:
+                       dump_data(lvl, val->v.binary.data,
+                                 val->v.binary.length);
+                       break;
+               default:
+                       DEBUG(lvl,("unsupported type: %d\n", val->type));
+                       break;
+       }
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_reg_entry(uint32_t flags,
+                   const char *dir,
+                   struct gp_registry_entry *entry)
+{
+       if (!(flags & GPO_INFO_FLAG_VERBOSE))
+               return;
+
+       dump_reg_val(1, dir,
+                    entry->key,
+                    entry->value,
+                    entry->data);
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_reg_entries(uint32_t flags,
+                     const char *dir,
+                     struct gp_registry_entry *entries,
+                     size_t num_entries)
+{
+       size_t i;
+
+       if (!(flags & GPO_INFO_FLAG_VERBOSE))
+               return;
+
+       for (i=0; i < num_entries; i++) {
+               dump_reg_entry(flags, dir, &entries[i]);
+       }
+}
+
+/****************************************************************
+****************************************************************/
+
+bool add_gp_registry_entry_to_array(TALLOC_CTX *mem_ctx,
+                                   struct gp_registry_entry *entry,
+                                   struct gp_registry_entry **entries,
+                                   size_t *num)
+{
+       *entries = TALLOC_REALLOC_ARRAY(mem_ctx, *entries,
+                                       struct gp_registry_entry,
+                                       (*num)+1);
+
+       if (*entries == NULL) {
+               *num = 0;
+               return false;
+       }
+
+       (*entries)[*num].action = entry->action;
+       (*entries)[*num].key = entry->key;
+       (*entries)[*num].value = entry->value;
+       (*entries)[*num].data = entry->data;
+
+       *num += 1;
+       return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static const char *gp_reg_action_str(enum gp_reg_action action)
+{
+       switch (action) {
+               case GP_REG_ACTION_NONE:
+                       return "GP_REG_ACTION_NONE";
+               case GP_REG_ACTION_ADD_VALUE:
+                       return "GP_REG_ACTION_ADD_VALUE";
+               case GP_REG_ACTION_ADD_KEY:
+                       return "GP_REG_ACTION_ADD_KEY";
+               case GP_REG_ACTION_DEL_VALUES:
+                       return "GP_REG_ACTION_DEL_VALUES";
+               case GP_REG_ACTION_DEL_VALUE:
+                       return "GP_REG_ACTION_DEL_VALUE";
+               case GP_REG_ACTION_DEL_ALL_VALUES:
+                       return "GP_REG_ACTION_DEL_ALL_VALUES";
+               case GP_REG_ACTION_DEL_KEYS:
+                       return "GP_REG_ACTION_DEL_KEYS";
+               case GP_REG_ACTION_SEC_KEY_SET:
+                       return "GP_REG_ACTION_SEC_KEY_SET";
+               case GP_REG_ACTION_SEC_KEY_RESET:
+                       return "GP_REG_ACTION_SEC_KEY_RESET";
+               default:
+                       return "unknown";
+       }
+};
+
+/****************************************************************
+****************************************************************/
+
+WERROR reg_apply_registry_entry(TALLOC_CTX *mem_ctx,
+                               struct registry_key *root_key,
+                               struct gp_registry_context *reg_ctx,
+                               struct gp_registry_entry *entry,
+                               const struct nt_user_token *token,
+                               uint32_t flags)
+{
+       WERROR werr;
+       struct registry_key *key = NULL;
+
+       if (flags & GPO_INFO_FLAG_VERBOSE) {
+               printf("about to store key:    [%s]\n", entry->key);
+               printf("               value:  [%s]\n", entry->value);
+               printf("               data:   [%s]\n", reg_type_lookup(entry->data->type));
+               printf("               action: [%s]\n", gp_reg_action_str(entry->action));
+       }
+
+       werr = gp_store_reg_subkey(mem_ctx, entry->key,
+                                  root_key, &key);
+                                  /* reg_ctx->curr_key, &key); */
+       if (!W_ERROR_IS_OK(werr)) {
+               DEBUG(0,("gp_store_reg_subkey failed: %s\n", dos_errstr(werr)));
+               return werr;
+       }
+
+       switch (entry->action) {
+               case GP_REG_ACTION_NONE:
+               case GP_REG_ACTION_ADD_KEY:
+                       return WERR_OK;
+
+               case GP_REG_ACTION_SEC_KEY_SET:
+                       werr = gp_secure_key(mem_ctx, flags,
+                                            entry->key,
+                                            &token->user_sids[0]);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               DEBUG(0,("reg_apply_registry_entry: "
+                                       "gp_secure_key failed: %s\n",
+                                       dos_errstr(werr)));
+                               return werr;
+                       }
+                       break;
+               case GP_REG_ACTION_ADD_VALUE:
+                       werr = reg_setvalue(key, entry->value, entry->data);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               DEBUG(0,("reg_apply_registry_entry: "
+                                       "reg_setvalue failed: %s\n",
+                                       dos_errstr(werr)));
+                               dump_reg_entry(flags, "STORE", entry);
+                               return werr;
+                       }
+                       break;
+               case GP_REG_ACTION_DEL_VALUE:
+                       werr = reg_deletevalue(key, entry->value);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               DEBUG(0,("reg_apply_registry_entry: "
+                                       "reg_deletevalue failed: %s\n",
+                                       dos_errstr(werr)));
+                               dump_reg_entry(flags, "STORE", entry);
+                               return werr;
+                       }
+                       break;
+               case GP_REG_ACTION_DEL_ALL_VALUES:
+                       werr = reg_deleteallvalues(key);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               DEBUG(0,("reg_apply_registry_entry: "
+                                       "reg_deleteallvalues failed: %s\n",
+                                       dos_errstr(werr)));
+                               dump_reg_entry(flags, "STORE", entry);
+                               return werr;
+                       }
+                       break;
+               case GP_REG_ACTION_DEL_VALUES:
+               case GP_REG_ACTION_DEL_KEYS:
+               case GP_REG_ACTION_SEC_KEY_RESET:
+                       DEBUG(0,("reg_apply_registry_entry: "
+                               "not yet supported: %s (%d)\n",
+                               gp_reg_action_str(entry->action),
+                               entry->action));
+                       return WERR_NOT_SUPPORTED;
+               default:
+                       DEBUG(0,("invalid action: %d\n", entry->action));
+                       return WERR_INVALID_PARAM;
+       }
+
+       return werr;
+}
+