From b409d4120f9ae451f93a2322267c0f346531d9f3 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 26 Aug 2007 15:16:40 +0000 Subject: r24667: Finally merge the registry improvements that Wilco Baan Hofman and I have been working on for at least half a year now. Contains the following improvements: * proper layering (finally!) for the registry library. Distinction is now made between 'real' backends (local, remote, wine, etc) and the low-level hive backends (regf, creg, ldb, ...) that are only used by the local registry backend * tests for all important hive and registry operations * re-enable RPC-WINREG tests (still needs more work though, as some return values aren't checked yet) * write support for REGF files * dir backend now supports setting/reading values, creating keys * support for storing security descriptors * remove CREG backend as it was incomplete, didn't match the data model and wasn't used at all anyway * support for parsing ADM files as used by the policy editor (see lib/policy) * support for parsing PREG files (format used by .POL files) * new streaming interface for registry diffs (improves speed and memory usage for regdiff/regpatch significantly) ... and fixes a large number of bugs in the registry code (This used to be commit 7a1eec6358bc863dfc671c542b7185d3e39d7b5a) --- source4/lib/registry/util.c | 242 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 source4/lib/registry/util.c (limited to 'source4/lib/registry/util.c') diff --git a/source4/lib/registry/util.c b/source4/lib/registry/util.c new file mode 100644 index 0000000000..47716f89cf --- /dev/null +++ b/source4/lib/registry/util.c @@ -0,0 +1,242 @@ +/* + Unix SMB/CIFS implementation. + Transparent registry backend handling + Copyright (C) Jelmer Vernooij 2003-2007. + + 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 . +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "librpc/gen_ndr/winreg.h" + +/** + * @file + * @brief Registry utility functions + */ + +static const struct { + uint32_t id; + const char *name; +} reg_value_types[] = { + { REG_SZ, "REG_SZ" }, + { REG_DWORD, "REG_DWORD" }, + { REG_BINARY, "REG_BINARY" }, + { REG_EXPAND_SZ, "REG_EXPAND_SZ" }, + { REG_NONE, "REG_NONE" }, + { 0, NULL } +}; + +/** Return string description of registry value type */ +_PUBLIC_ const char *str_regtype(int type) +{ + int i; + for (i = 0; reg_value_types[i].name; i++) { + if (reg_value_types[i].id == type) + return reg_value_types[i].name; + } + + return "Unknown"; +} + +_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type, + const DATA_BLOB data) +{ + char *ret = NULL; + + if (data.length == 0) + return talloc_strdup(mem_ctx, ""); + + switch (type) { + case REG_EXPAND_SZ: + case REG_SZ: + convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, data.data, data.length, + (void **)&ret); + return ret; + + case REG_BINARY: + ret = data_blob_hex_string(mem_ctx, &data); + return ret; + + case REG_DWORD: + if (*(int *)data.data == 0) + return talloc_strdup(mem_ctx, "0"); + + return talloc_asprintf(mem_ctx, "0x%x", *(int *)data.data); + + case REG_MULTI_SZ: + /* FIXME */ + break; + + default: + break; + } + + return ret; +} + +/** Generate a string that describes a registry value */ +_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, const char *name, + uint32_t data_type, + const DATA_BLOB data) +{ + return talloc_asprintf(mem_ctx, "%s = %s : %s", name?name:"", + str_regtype(data_type), + reg_val_data_string(mem_ctx, data_type, data)); +} + +_PUBLIC_ BOOL reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str, const char *data_str, uint32_t *type, DATA_BLOB *data) +{ + int i; + *type = -1; + + /* Find the correct type */ + for (i = 0; reg_value_types[i].name; i++) { + if (!strcmp(reg_value_types[i].name, type_str)) { + *type = reg_value_types[i].id; + break; + } + } + + if (*type == -1) + return False; + + /* Convert data appropriately */ + + switch (*type) + { + case REG_SZ: + case REG_EXPAND_SZ: + data->length = convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16, data_str, strlen(data_str), (void **)&data->data); + break; + + case REG_DWORD: { + uint32_t tmp = strtol(data_str, NULL, 0); + *data = data_blob_talloc(mem_ctx, &tmp, 4); + } + break; + + case REG_NONE: + ZERO_STRUCTP(data); + break; + + case REG_BINARY: + *data = strhex_to_data_blob(data_str); + talloc_steal(mem_ctx, data->data); + break; + + default: + /* FIXME */ + return False; + } + return True; +} + +/** Open a key by name (including the predefined key name!) */ +WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle, const char *name, struct registry_key **result) +{ + struct registry_key *predef; + WERROR error; + int predeflength; + char *predefname; + + if (strchr(name, '\\') != NULL) + predeflength = strchr(name, '\\')-name; + else + predeflength = strlen(name); + + predefname = talloc_strndup(mem_ctx, name, predeflength); + error = reg_get_predefined_key_by_name(handle, predefname, &predef); + talloc_free(predefname); + + if (!W_ERROR_IS_OK(error)) { + return error; + } + + if (strchr(name, '\\')) { + return reg_open_key(mem_ctx, predef, strchr(name, '\\')+1, result); + } else { + *result = predef; + return WERR_OK; + } +} + +static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx, + const char *path, struct registry_key **parent, + const char **name) +{ + char *parent_name; + WERROR error; + + if (strchr(path, '\\') == NULL) { + return WERR_FOOBAR; + } + + parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-path); + + error = reg_open_key_abs(mem_ctx, ctx, parent_name, parent); + if (!W_ERROR_IS_OK(error)) { + return error; + } + + *name = talloc_strdup(mem_ctx, strrchr(path, '\\')+1); + + return WERR_OK; +} + +WERROR reg_key_del_abs(struct registry_context *ctx, const char *path) +{ + struct registry_key *parent; + const char *n; + TALLOC_CTX *mem_ctx = talloc_init("reg_key_del_abs"); + WERROR error; + + if (!strchr(path, '\\')) { + return WERR_FOOBAR; + } + + error = get_abs_parent(mem_ctx, ctx, path, &parent, &n); + if (W_ERROR_IS_OK(error)) { + error = reg_key_del(parent, n); + } + + talloc_free(mem_ctx); + + return error; +} + +WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx, + const char *path, uint32_t access_mask, + struct security_descriptor *sec_desc, + struct registry_key **result) +{ + struct registry_key *parent; + const char *n; + WERROR error; + + if (!strchr(path, '\\')) { + return WERR_ALREADY_EXISTS; + } + + error = get_abs_parent(mem_ctx, ctx, path, &parent, &n); + if (!W_ERROR_IS_OK(error)) { + DEBUG(2, ("Opening parent of %s failed with %s\n", path, + win_errstr(error))); + return error; + } + + error = reg_key_add_name(mem_ctx, parent, n, NULL, sec_desc, result); + + return error; +} -- cgit