mirror of
https://github.com/samba-team/samba.git
synced 2024-12-27 03:21:53 +03:00
67e0eaa1d0
Guenther Signed-off-by: Günther Deschner <gd@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org>
1041 lines
26 KiB
C
1041 lines
26 KiB
C
/*
|
|
* 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"
|
|
#include "../libgpo/gpo.h"
|
|
#include "libgpo/gpo_proto.h"
|
|
#include "registry.h"
|
|
#include "registry/reg_api.h"
|
|
#include "registry/reg_backend_db.h"
|
|
#include "registry/reg_api_util.h"
|
|
#include "registry/reg_init_basic.h"
|
|
#include "../libcli/security/security.h"
|
|
#include "../libcli/registry/util_reg.h"
|
|
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
struct security_token *registry_create_system_token(TALLOC_CTX *mem_ctx)
|
|
{
|
|
struct security_token *token = NULL;
|
|
|
|
token = talloc_zero(mem_ctx, struct security_token);
|
|
if (!token) {
|
|
DEBUG(1,("talloc failed\n"));
|
|
return NULL;
|
|
}
|
|
|
|
token->privilege_mask = SE_ALL_PRIVS;
|
|
|
|
if (!NT_STATUS_IS_OK(add_sid_to_array(token, &global_sid_System,
|
|
&token->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 security_token *token,
|
|
struct gp_registry_context **reg_ctx)
|
|
{
|
|
struct gp_registry_context *tmp_ctx;
|
|
WERROR werr;
|
|
|
|
if (!reg_ctx) {
|
|
return WERR_INVALID_PARAM;
|
|
}
|
|
|
|
werr = registry_init_basic();
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
return werr;
|
|
}
|
|
|
|
tmp_ctx = talloc_zero(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;
|
|
}
|
|
|
|
werr = regdb_open();
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
return werr;
|
|
}
|
|
|
|
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;
|
|
|
|
reg_val.type = REG_SZ;
|
|
if (!push_reg_sz(mem_ctx, ®_val.data, val)) {
|
|
return WERR_NOMEM;
|
|
}
|
|
|
|
return reg_setvalue(key, val_name, ®_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;
|
|
|
|
reg_val.type = REG_DWORD;
|
|
reg_val.data = data_blob_talloc(mem_ctx, NULL, 4);
|
|
SIVAL(reg_val.data.data, 0, val);
|
|
|
|
return reg_setvalue(key, val_name, ®_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, ®_val);
|
|
W_ERROR_NOT_OK_RETURN(werr);
|
|
|
|
if (reg_val->type != REG_SZ) {
|
|
return WERR_INVALID_DATATYPE;
|
|
}
|
|
|
|
if (!pull_reg_sz(mem_ctx, ®_val->data, val)) {
|
|
return WERR_NOMEM;
|
|
}
|
|
|
|
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, ®_val);
|
|
W_ERROR_NOT_OK_RETURN(werr);
|
|
|
|
if (reg_val->type != REG_DWORD) {
|
|
return WERR_INVALID_DATATYPE;
|
|
}
|
|
|
|
if (reg_val->data.length < 4) {
|
|
return WERR_INSUFFICIENT_BUFFER;
|
|
}
|
|
*val = IVAL(reg_val->data.data, 0);
|
|
|
|
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 ? 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",
|
|
"");
|
|
W_ERROR_NOT_OK_RETURN(werr);
|
|
|
|
return werr;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
static const char *gp_reg_groupmembership_path(TALLOC_CTX *mem_ctx,
|
|
const struct 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 security_token *token,
|
|
uint32_t flags)
|
|
{
|
|
const char *path = NULL;
|
|
|
|
path = gp_reg_groupmembership_path(mem_ctx, &token->sids[0],
|
|
flags);
|
|
W_ERROR_HAVE_NO_MEMORY(path);
|
|
|
|
return reg_deletekey_recursive(key, path);
|
|
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
static WERROR gp_reg_store_groupmembership(TALLOC_CTX *mem_ctx,
|
|
struct gp_registry_context *reg_ctx,
|
|
const struct security_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->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->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 struct dom_sid *object_sid,
|
|
struct security_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 security_token *tmp_token = NULL;
|
|
|
|
tmp_token = talloc_zero(mem_ctx, struct security_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->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 struct 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(key, path);
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR gp_reg_state_store(TALLOC_CTX *mem_ctx,
|
|
uint32_t flags,
|
|
const char *dn,
|
|
const struct security_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, ®_ctx);
|
|
W_ERROR_NOT_OK_RETURN(werr);
|
|
|
|
werr = gp_secure_key(mem_ctx, flags, reg_ctx->curr_key,
|
|
&token->sids[0]);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
DEBUG(0,("failed to secure key: %s\n", win_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", win_errstr(werr)));
|
|
goto done;
|
|
}
|
|
|
|
subkeyname = gp_req_state_path(mem_ctx, &token->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", win_errstr(werr)));
|
|
/* goto done; */
|
|
}
|
|
|
|
werr = gp_store_reg_subkey(mem_ctx, subkeyname,
|
|
reg_ctx->curr_key, ®_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, ®_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: "
|
|
"gp_store_reg_gpovals failed for %s: %s\n",
|
|
gpo->display_name, win_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(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 struct 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, ®_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",
|
|
win_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 struct dom_sid *sid,
|
|
struct security_descriptor **sd,
|
|
size_t *sd_size)
|
|
{
|
|
struct security_ace ace[6];
|
|
uint32_t mask;
|
|
|
|
struct security_acl *theacl = NULL;
|
|
|
|
uint8_t inherit_flags;
|
|
|
|
mask = REG_KEY_ALL;
|
|
init_sec_ace(&ace[0],
|
|
&global_sid_System,
|
|
SEC_ACE_TYPE_ACCESS_ALLOWED,
|
|
mask, 0);
|
|
|
|
mask = REG_KEY_ALL;
|
|
init_sec_ace(&ace[1],
|
|
&global_sid_Builtin_Administrators,
|
|
SEC_ACE_TYPE_ACCESS_ALLOWED,
|
|
mask, 0);
|
|
|
|
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;
|
|
|
|
mask = REG_KEY_ALL;
|
|
init_sec_ace(&ace[3],
|
|
&global_sid_System,
|
|
SEC_ACE_TYPE_ACCESS_ALLOWED,
|
|
mask, inherit_flags);
|
|
|
|
mask = REG_KEY_ALL;
|
|
init_sec_ace(&ace[4],
|
|
&global_sid_Builtin_Administrators,
|
|
SEC_ACE_TYPE_ACCESS_ALLOWED,
|
|
mask, inherit_flags);
|
|
|
|
mask = REG_KEY_READ;
|
|
init_sec_ace(&ace[5],
|
|
sid ? sid : &global_sid_Authenticated_Users,
|
|
SEC_ACE_TYPE_ACCESS_ALLOWED,
|
|
mask, inherit_flags);
|
|
|
|
theacl = make_sec_acl(mem_ctx, NT4_ACL_REVISION, 6, ace);
|
|
W_ERROR_HAVE_NO_MEMORY(theacl);
|
|
|
|
*sd = make_sec_desc(mem_ctx, SD_REVISION,
|
|
SEC_DESC_SELF_RELATIVE |
|
|
SEC_DESC_DACL_AUTO_INHERITED | /* really ? */
|
|
SEC_DESC_DACL_AUTO_INHERIT_REQ, /* really ? */
|
|
NULL, NULL, NULL,
|
|
theacl, sd_size);
|
|
W_ERROR_HAVE_NO_MEMORY(*sd);
|
|
|
|
return WERR_OK;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR gp_secure_key(TALLOC_CTX *mem_ctx,
|
|
uint32_t flags,
|
|
struct registry_key *key,
|
|
const struct dom_sid *sid)
|
|
{
|
|
struct security_descriptor *sd = NULL;
|
|
size_t sd_size = 0;
|
|
const struct 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 reg_setkeysecurity(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 = str_regtype(val->type);
|
|
|
|
DEBUG(lvl,("\tdump_reg_val:\t%s '%s'\n\t\t\t'%s' %s: ",
|
|
direction, key, subkey, type_str));
|
|
|
|
switch (val->type) {
|
|
case REG_DWORD: {
|
|
uint32_t v;
|
|
if (val->data.length < 4) {
|
|
break;
|
|
}
|
|
v = IVAL(val->data.data, 0);
|
|
DEBUG(lvl,("%d (0x%08x)\n",
|
|
(int)v, v));
|
|
break;
|
|
}
|
|
case REG_QWORD: {
|
|
uint64_t v;
|
|
if (val->data.length < 8) {
|
|
break;
|
|
}
|
|
v = BVAL(val->data.data, 0);
|
|
DEBUG(lvl,("%d (0x%016llx)\n",
|
|
(int)v,
|
|
(unsigned long long)v));
|
|
break;
|
|
}
|
|
case REG_SZ: {
|
|
const char *s;
|
|
if (!pull_reg_sz(talloc_tos(), &val->data, &s)) {
|
|
break;
|
|
}
|
|
DEBUG(lvl,("%s (length: %d)\n",
|
|
s, (int)strlen_m(s)));
|
|
break;
|
|
}
|
|
case REG_MULTI_SZ: {
|
|
const char **a;
|
|
if (!pull_reg_multi_sz(talloc_tos(), &val->data, &a)) {
|
|
break;
|
|
}
|
|
for (i=0; a[i] != NULL; i++) {
|
|
;;
|
|
}
|
|
DEBUG(lvl,("(num_strings: %d)\n", i));
|
|
for (i=0; a[i] != NULL; i++) {
|
|
DEBUGADD(lvl,("\t%s\n", a[i]));
|
|
}
|
|
break;
|
|
}
|
|
case REG_NONE:
|
|
DEBUG(lvl,("\n"));
|
|
break;
|
|
case REG_BINARY:
|
|
dump_data(lvl, val->data.data,
|
|
val->data.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(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 security_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", str_regtype(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", win_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,
|
|
key,
|
|
&token->sids[0]);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
DEBUG(0,("reg_apply_registry_entry: "
|
|
"gp_secure_key failed: %s\n",
|
|
win_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",
|
|
win_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",
|
|
win_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",
|
|
win_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;
|
|
}
|
|
|