/* 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 <http://www.gnu.org/licenses/>. */ #include "includes.h" #include "registry.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_delete_recursive(const char *name) { DIR *d; struct dirent *e; WERROR werr; d = opendir(name); if (d == NULL) { DEBUG(3,("Unable to open '%s': %s\n", name, strerror(errno))); return WERR_BADFILE; } while((e = readdir(d))) { char *path; struct stat stbuf; if (ISDOT(e->d_name) || ISDOTDOT(e->d_name)) continue; path = talloc_asprintf(name, "%s/%s", name, e->d_name); if (!path) return WERR_NOMEM; stat(path, &stbuf); if (!S_ISDIR(stbuf.st_mode)) { if (unlink(path) < 0) { talloc_free(path); closedir(d); return WERR_GENERAL_FAILURE; } } else { werr = reg_dir_delete_recursive(path); if (!W_ERROR_IS_OK(werr)) { talloc_free(path); closedir(d); return werr; } } talloc_free(path); } closedir(d); if (rmdir(name) == 0) return WERR_OK; else if (errno == ENOENT) return WERR_BADFILE; else 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; ret = reg_dir_delete_recursive(child); 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, uint32_t *max_subkeynamelen, uint32_t *max_valnamelen, uint32_t *max_valbufsize) { 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; if (max_subkeynamelen != NULL) *max_subkeynamelen = 0; if (max_valnamelen != NULL) *max_valnamelen = 0; if (max_valbufsize != NULL) *max_valbufsize = 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)) { if (num_subkeys != NULL) (*num_subkeys)++; if (max_subkeynamelen != NULL) *max_subkeynamelen = MAX(*max_subkeynamelen, strlen(e->d_name)); } if (!S_ISDIR(st.st_mode)) { if (num_values != NULL) (*num_values)++; if (max_valnamelen != NULL) *max_valnamelen = MAX(*max_valnamelen, strlen(e->d_name)); if (max_valbufsize != NULL) *max_valbufsize = MAX(*max_valbufsize, st.st_size); } 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, 0, mem_ctx); talloc_free(path); if (contents == NULL) return WERR_BADFILE; 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, 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_BADFILE; 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, };