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/dir.c | 333 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 source4/lib/registry/dir.c (limited to 'source4/lib/registry/dir.c') diff --git a/source4/lib/registry/dir.c b/source4/lib/registry/dir.c new file mode 100644 index 0000000000..146c5197fd --- /dev/null +++ b/source4/lib/registry/dir.c @@ -0,0 +1,333 @@ +/* + Unix SMB/CIFS implementation. + Registry interface + Copyright (C) Jelmer Vernooij 2004-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 "hive.h" +#include "system/dir.h" +#include "system/filesys.h" + +struct dir_key { + struct hive_key key; + const char *path; +}; + +static struct hive_operations reg_backend_dir; + +static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx, + const struct hive_key *parent, + const char *name, const char *classname, + struct security_descriptor *desc, + struct hive_key **result) +{ + struct dir_key *dk = talloc_get_type(parent, struct dir_key); + char *path; + int ret; + + path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name); + ret = mkdir(path, 0700); + if (ret == 0) { + struct dir_key *key = talloc(mem_ctx, struct dir_key); + key->key.ops = ®_backend_dir; + key->path = talloc_steal(key, path); + *result = (struct hive_key *)key; + return WERR_OK; + } + + if (errno == EEXIST) + return WERR_ALREADY_EXISTS; + printf("FAILED %s BECAUSE: %s\n", path, strerror(errno)); + return WERR_GENERAL_FAILURE; +} + +static WERROR reg_dir_del_key(const struct hive_key *k, const char *name) +{ + struct dir_key *dk = talloc_get_type(k, struct dir_key); + char *child = talloc_asprintf(NULL, "%s/%s", dk->path, name); + WERROR ret; + + if (rmdir(child) == 0) + ret = WERR_OK; + else if (errno == ENOENT) + ret = WERR_NOT_FOUND; + else + ret = WERR_GENERAL_FAILURE; + + talloc_free(child); + + return ret; +} + +static WERROR reg_dir_open_key(TALLOC_CTX *mem_ctx, + const struct hive_key *parent, + const char *name, struct hive_key **subkey) +{ + DIR *d; + char *fullpath; + const struct dir_key *p = talloc_get_type(parent, struct dir_key); + struct dir_key *ret; + + if (name == NULL) { + DEBUG(0, ("NULL pointer passed as directory name!")); + return WERR_INVALID_PARAM; + } + + fullpath = talloc_asprintf(mem_ctx, "%s/%s", p->path, name); + + d = opendir(fullpath); + if (d == NULL) { + DEBUG(3,("Unable to open '%s': %s\n", fullpath, strerror(errno))); + return WERR_BADFILE; + } + closedir(d); + ret = talloc(mem_ctx, struct dir_key); + ret->key.ops = ®_backend_dir; + ret->path = talloc_steal(ret, fullpath); + *subkey = (struct hive_key *)ret; + return WERR_OK; +} + +static WERROR reg_dir_key_by_index(TALLOC_CTX *mem_ctx, + const struct hive_key *k, uint32_t idx, + const char **name, + const char **classname, + NTTIME *last_mod_time) +{ + struct dirent *e; + const struct dir_key *dk = talloc_get_type(k, struct dir_key); + int i = 0; + DIR *d; + + d = opendir(dk->path); + + if (d == NULL) + return WERR_INVALID_PARAM; + + while((e = readdir(d))) { + if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) { + struct stat stbuf; + char *thispath; + + /* Check if file is a directory */ + asprintf(&thispath, "%s/%s", dk->path, e->d_name); + stat(thispath, &stbuf); + + if (!S_ISDIR(stbuf.st_mode)) { + SAFE_FREE(thispath); + continue; + } + + if (i == idx) { + struct stat st; + *name = talloc_strdup(mem_ctx, e->d_name); + *classname = NULL; + stat(thispath, &st); + unix_to_nt_time(last_mod_time, st.st_mtime); + SAFE_FREE(thispath); + closedir(d); + return WERR_OK; + } + i++; + + SAFE_FREE(thispath); + } + } + + closedir(d); + + return WERR_NO_MORE_ITEMS; +} + +WERROR reg_open_directory(TALLOC_CTX *parent_ctx, + const char *location, struct hive_key **key) +{ + struct dir_key *dk; + + if (location == NULL) + return WERR_INVALID_PARAM; + + dk = talloc(parent_ctx, struct dir_key); + dk->key.ops = ®_backend_dir; + dk->path = talloc_strdup(dk, location); + *key = (struct hive_key *)dk; + return WERR_OK; +} + +WERROR reg_create_directory(TALLOC_CTX *parent_ctx, + const char *location, struct hive_key **key) +{ + if (mkdir(location, 0700) != 0) { + *key = NULL; + return WERR_GENERAL_FAILURE; + } + + return reg_open_directory(parent_ctx, location, key); +} + +static WERROR reg_dir_get_info(TALLOC_CTX *ctx, const struct hive_key *key, + const char **classname, + uint32_t *num_subkeys, + uint32_t *num_values, + NTTIME *lastmod) +{ + DIR *d; + const struct dir_key *dk = talloc_get_type(key, struct dir_key); + struct dirent *e; + struct stat st; + + SMB_ASSERT(key != NULL); + + if (classname != NULL) + *classname = NULL; + + d = opendir(dk->path); + if (d == NULL) + return WERR_INVALID_PARAM; + + if (num_subkeys != NULL) + *num_subkeys = 0; + + if (num_values != NULL) + *num_values = 0; + + while((e = readdir(d))) { + if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) { + char *path = talloc_asprintf(ctx, "%s/%s", dk->path, e->d_name); + + if (stat(path, &st) < 0) { + DEBUG(0, ("Error statting %s: %s\n", path, strerror(errno))); + continue; + } + + if (S_ISDIR(st.st_mode) && num_subkeys != NULL) + (*num_subkeys)++; + + if (!S_ISDIR(st.st_mode) && num_values != NULL) + (*num_values)++; + + talloc_free(path); + } + } + + closedir(d); + + if (lastmod != NULL) + *lastmod = 0; + return WERR_OK; +} + +static WERROR reg_dir_set_value (struct hive_key *key, const char *name, + uint32_t type, const DATA_BLOB data) +{ + const struct dir_key *dk = talloc_get_type(key, struct dir_key); + char *path = talloc_asprintf(dk, "%s/%s", dk->path, name); + + if (!file_save(path, data.data, data.length)) + return WERR_GENERAL_FAILURE; + + /* FIXME: Type */ + + return WERR_OK; +} + +static WERROR reg_dir_get_value (TALLOC_CTX *mem_ctx, + struct hive_key *key, const char *name, + uint32_t *type, DATA_BLOB *data) +{ + const struct dir_key *dk = talloc_get_type(key, struct dir_key); + char *path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name); + size_t size; + char *contents; + + contents = file_load(path, &size, mem_ctx); + talloc_free(path); + if (contents == NULL) + return WERR_NOT_FOUND; + + if (type != NULL) + *type = 4; /* FIXME */ + + data->data = (uint8_t *)contents; + data->length = size; + + return WERR_OK; +} + +static WERROR reg_dir_enum_value (TALLOC_CTX *mem_ctx, + const struct hive_key *key, int idx, + const char **name, + uint32_t *type, DATA_BLOB *data) +{ + const struct dir_key *dk = talloc_get_type(key, struct dir_key); + DIR *d; + struct dirent *e; + int i; + + d = opendir(dk->path); + if (d == NULL) { + DEBUG(3,("Unable to open '%s': %s\n", dk->path, strerror(errno))); + return WERR_BADFILE; + } + + i = 0; + while((e = readdir(d))) { + if (ISDOT(e->d_name) || ISDOTDOT(e->d_name)) + continue; + + if (i == idx) { + if (name != NULL) + *name = talloc_strdup(mem_ctx, e->d_name); + W_ERROR_NOT_OK_RETURN(reg_dir_get_value(mem_ctx, key, *name, type, data)); + return WERR_OK; + } + + i++; + } + closedir(d); + + return WERR_NO_MORE_ITEMS; +} + + +static WERROR reg_dir_del_value (struct hive_key *key, const char *name) +{ + const struct dir_key *dk = talloc_get_type(key, struct dir_key); + char *path = talloc_asprintf(key, "%s/%s", dk->path, name); + if (unlink(path) < 0) { + talloc_free(path); + if (errno == ENOENT) + return WERR_NOT_FOUND; + return WERR_GENERAL_FAILURE; + } + talloc_free(path); + + return WERR_OK; +} + +static struct hive_operations reg_backend_dir = { + .name = "dir", + .get_key_by_name = reg_dir_open_key, + .get_key_info = reg_dir_get_info, + .add_key = reg_dir_add_key, + .del_key = reg_dir_del_key, + .enum_key = reg_dir_key_by_index, + .set_value = reg_dir_set_value, + .get_value_by_name = reg_dir_get_value, + .enum_value = reg_dir_enum_value, + .delete_value = reg_dir_del_value, +}; -- cgit