2 Unix SMB/CIFS implementation.
3 Transparent registry backend handling
4 Copyright (C) Jelmer Vernooij 2003-2004.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "lib/registry/common/registry.h"
25 #define DBGC_CLASS DBGC_REGISTRY
27 /* List of available backends */
28 static struct reg_init_function_entry *backends = NULL;
30 static struct reg_init_function_entry *reg_find_backend_entry(const char *name);
32 /* Register new backend */
33 NTSTATUS registry_register(void *_function)
35 struct registry_ops *functions = _function;
36 struct reg_init_function_entry *entry = backends;
38 if (!functions || !functions->name) {
39 return NT_STATUS_INVALID_PARAMETER;
42 DEBUG(5,("Attempting to register registry backend %s\n", functions->name));
44 /* Check for duplicates */
45 if (reg_find_backend_entry(functions->name)) {
46 DEBUG(0,("There already is a registry backend registered with the name %s!\n", functions->name));
47 return NT_STATUS_OBJECT_NAME_COLLISION;
50 entry = malloc(sizeof(struct reg_init_function_entry));
51 entry->functions = functions;
53 DLIST_ADD(backends, entry);
54 DEBUG(5,("Successfully added registry backend '%s'\n", functions->name));
58 /* Find a backend in the list of available backends */
59 static struct reg_init_function_entry *reg_find_backend_entry(const char *name)
61 struct reg_init_function_entry *entry = backends;
64 if (strcmp(entry->functions->name, name)==0) return entry;
71 /* Open a registry file/host/etc */
72 WERROR reg_open(const char *backend, const char *location, const char *credentials, REG_HANDLE **h)
74 struct reg_init_function_entry *entry;
75 static BOOL reg_first_init = True;
82 status = register_subsystem("registry", registry_register);
83 if (!NT_STATUS_IS_OK(status))
84 return WERR_GENERAL_FAILURE;
87 reg_first_init = False;
90 entry = reg_find_backend_entry(backend);
93 DEBUG(0, ("No such registry backend '%s' loaded!\n", backend));
94 return WERR_GENERAL_FAILURE;
97 mem_ctx = talloc_init(backend);
98 ret = talloc(mem_ctx, sizeof(REG_HANDLE));
100 ret->location = location?talloc_strdup(mem_ctx, location):NULL;
101 ret->functions = entry->functions;
102 ret->backend_data = NULL;
103 ret->mem_ctx = mem_ctx;
106 if(!entry->functions->open_registry) {
110 werr = entry->functions->open_registry(ret, location, credentials);
112 if(W_ERROR_IS_OK(werr))
115 talloc_destroy(mem_ctx);
120 * First tries to use the open_key function from the backend
121 * then falls back to get_subkey_by_name and later get_subkey_by_index
123 WERROR reg_open_key(REG_KEY *parent, const char *name, REG_KEY **result)
131 DEBUG(0, ("Invalid parent key specified"));
132 return WERR_INVALID_PARAM;
135 if(!parent->handle->functions->open_key &&
136 (parent->handle->functions->get_subkey_by_name ||
137 parent->handle->functions->get_subkey_by_index)) {
138 char *orig = strdup(name),
140 *curend = strchr(orig, '\\');
141 REG_KEY *curkey = parent;
143 while(curbegin && *curbegin) {
144 if(curend)*curend = '\0';
145 status = reg_key_get_subkey_by_name(curkey, curbegin, result);
146 if(!NT_STATUS_IS_OK(status)) {
151 curbegin = curend + 1;
152 curend = strchr(curbegin, '\\');
160 mem_ctx = talloc_init("mem_ctx");
162 fullname = talloc_asprintf(mem_ctx, "%s%s%s", parent->path, parent->path[strlen(parent->path)-1] == '\\'?"":"\\", name);
165 if(!parent->handle->functions->open_key) {
166 DEBUG(0, ("Registry backend doesn't have get_subkey_by_name nor open_key!\n"));
167 return WERR_NOT_SUPPORTED;
170 status = parent->handle->functions->open_key(parent->handle, fullname, result);
172 if(!NT_STATUS_IS_OK(status)) {
173 talloc_destroy(mem_ctx);
177 ret->handle = parent->handle;
178 ret->path = fullname;
179 talloc_steal(mem_ctx, ret->mem_ctx, fullname);
181 talloc_destroy(mem_ctx);
188 WERROR reg_key_get_value_by_index(REG_KEY *key, int idx, REG_VAL **val)
190 if(!key) return WERR_INVALID_PARAM;
192 if(!key->handle->functions->get_value_by_index) {
193 if(!key->cache_values)
194 key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
196 if(idx < key->cache_values_count && idx >= 0) {
197 *val = reg_val_dup(key->cache_values[idx]);
199 return WERR_NO_MORE_ITEMS;
202 WERROR status = key->handle->functions->get_value_by_index(key, idx, val);
203 if(!W_ERROR_IS_OK(status))
207 (*val)->parent = key;
208 (*val)->handle = key->handle;
212 WERROR reg_key_num_subkeys(REG_KEY *key, int *count)
214 if(!key) return WERR_INVALID_PARAM;
216 if(!key->handle->functions->num_subkeys) {
217 if(!key->cache_subkeys)
218 key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
220 *count = key->cache_subkeys_count;
224 return key->handle->functions->num_subkeys(key, count);
227 WERROR reg_key_num_values(REG_KEY *key, int *count)
230 if(!key) return WERR_INVALID_PARAM;
232 if(!key->handle->functions->num_values) {
233 if(!key->handle->functions->fetch_values) {
234 DEBUG(1, ("Backend '%s' doesn't support enumerating values\n", key->handle->functions->name));
235 return WERR_NOT_SUPPORTED;
238 if(!key->cache_values)
239 key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
241 *count = key->cache_values_count;
246 return key->handle->functions->num_values(key, count);
249 WERROR reg_key_get_subkey_by_index(REG_KEY *key, int idx, REG_KEY **subkey)
251 if(!key) return WERR_INVALID_PARAM;
253 if(!key->handle->functions->get_subkey_by_index) {
254 if(!key->cache_subkeys)
255 key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
257 if(idx < key->cache_subkeys_count) {
258 *subkey = reg_key_dup(key->cache_subkeys[idx]);
260 return WERR_NO_MORE_ITEMS;
263 WERROR status = key->handle->functions->get_subkey_by_index(key, idx, subkey);
264 if(!NT_STATUS_IS_OK(status)) return status;
267 (*subkey)->path = talloc_asprintf((*subkey)->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", (*subkey)->name);
268 (*subkey)->handle = key->handle;
274 WERROR reg_key_get_subkey_by_name(REG_KEY *key, const char *name, REG_KEY **subkey)
278 WERROR error = WERR_OK;
280 if(!key) return WERR_INVALID_PARAM;
282 if(key->handle->functions->get_subkey_by_name) {
283 error = key->handle->functions->get_subkey_by_name(key,name,subkey);
285 for(i = 0; W_ERROR_IS_OK(error); i++) {
286 error = reg_key_get_subkey_by_index(key, i, subkey);
287 if(W_ERROR_IS_OK(error) && !strcmp((*subkey)->name, name)) {
290 reg_key_free(*subkey);
295 if(!W_ERROR_IS_OK(error) && W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
298 ret->path = talloc_asprintf(ret->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name);
299 ret->handle = key->handle;
306 WERROR reg_key_get_value_by_name(REG_KEY *key, const char *name, REG_VAL **val)
310 WERROR error = WERR_OK;
312 if(!key) return WERR_INVALID_PARAM;
314 if(key->handle->functions->get_value_by_name) {
315 error = key->handle->functions->get_value_by_name(key,name, val);
317 for(i = 0; W_ERROR_IS_OK(error); i++) {
318 error = reg_key_get_value_by_index(key, i, val);
319 if(W_ERROR_IS_OK(error) && StrCaseCmp((*val)->name, name)) {
326 if(!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
329 (*val)->parent = key;
330 (*val)->handle = key->handle;
335 WERROR reg_key_del(REG_KEY *key)
338 if(!key) return WERR_INVALID_PARAM;
341 if(!key->handle->functions->del_key)
342 return WERR_NOT_SUPPORTED;
344 error = key->handle->functions->del_key(key);
345 if(!W_ERROR_IS_OK(error)) return error;
347 /* Invalidate cache */
348 key->cache_subkeys = NULL;
349 key->cache_subkeys_count = 0;
353 WERROR reg_sync(REG_KEY *h, const char *location)
355 if(!h->handle->functions->sync_key)
358 return h->handle->functions->sync_key(h, location);
361 WERROR reg_key_del_recursive(REG_KEY *key)
364 WERROR error = WERR_OK;
367 /* Delete all values for specified key */
368 for(i = 0; W_ERROR_IS_OK(error); i++) {
370 error = reg_key_get_value_by_index(key, i, &val);
371 if(!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
374 if(W_ERROR_IS_OK(error)) {
375 error = reg_val_del(val);
376 if(!W_ERROR_IS_OK(error)) return error;
382 /* Delete all keys below this one */
383 for(i = 0; W_ERROR_IS_OK(error); i++) {
386 error = reg_key_get_subkey_by_index(key, i, &subkey);
387 if(!W_ERROR_IS_OK(error)) return error;
389 error = reg_key_del_recursive(subkey);
390 if(!W_ERROR_IS_OK(error)) return error;
393 return reg_key_del(key);
396 WERROR reg_val_del(REG_VAL *val)
399 if (!val) return WERR_INVALID_PARAM;
401 if (!val->handle->functions->del_value) {
402 DEBUG(1, ("Backend '%s' doesn't support method del_value\n", val->handle->functions->name));
403 return WERR_NOT_SUPPORTED;
406 error = val->handle->functions->del_value(val);
408 if(!W_ERROR_IS_OK(error)) return error;
410 val->parent->cache_values = NULL;
411 val->parent->cache_values_count = 0;
416 WERROR reg_key_add_name_recursive(REG_KEY *parent, const char *path)
418 REG_KEY *cur, *prevcur = parent;
420 char *begin = (char *)path, *end;
423 end = strchr(begin, '\\');
426 error = reg_key_get_subkey_by_name(prevcur, begin, &cur);
428 /* Key is not there, add it */
429 if(W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
430 error = reg_key_add_name(prevcur, begin, 0, NULL, &cur);
431 if(!W_ERROR_IS_OK(error)) return error;
434 if(!W_ERROR_IS_OK(error)) {
447 WERROR reg_key_add_name(REG_KEY *parent, const char *name, uint32 access_mask, SEC_DESC *desc, REG_KEY **newkey)
451 if (!parent) return WERR_INVALID_PARAM;
453 if (!parent->handle->functions->add_key) {
454 DEBUG(1, ("Backend '%s' doesn't support method add_key\n", parent->handle->functions->name));
455 return WERR_NOT_SUPPORTED;
458 error = parent->handle->functions->add_key(parent, name, access_mask, desc, newkey);
460 if(!W_ERROR_IS_OK(error)) return error;
462 (*newkey)->handle = parent->handle;
463 (*newkey)->backend_data = talloc_asprintf((*newkey)->mem_ctx, "%s\\%s", reg_key_get_path(parent), name);
465 parent->cache_subkeys = NULL;
466 parent->cache_subkeys_count = 0;
470 WERROR reg_val_update(REG_VAL *val, int type, void *data, int len)
474 /* A 'real' update function has preference */
475 if (val->handle->functions->update_value)
476 return val->handle->functions->update_value(val, type, data, len);
478 /* Otherwise, just remove and add again */
479 if (val->handle->functions->add_value &&
480 val->handle->functions->del_value) {
482 if(!W_ERROR_IS_OK(error = val->handle->functions->del_value(val)))
485 error = val->handle->functions->add_value(val->parent, val->name, type, data, len);
486 if(!W_ERROR_IS_OK(error)) return error;
487 memcpy(val, new, sizeof(REG_VAL));
488 val->parent->cache_values = NULL;
489 val->parent->cache_values_count = 0;
493 DEBUG(1, ("Backend '%s' doesn't support method update_value\n", val->handle->functions->name));
494 return WERR_NOT_SUPPORTED;
497 void reg_free(REG_HANDLE *h)
499 if(!h->functions->close_registry) return;
501 h->functions->close_registry(h);
504 WERROR reg_get_root(REG_HANDLE *h, REG_KEY **key)
507 if(h->functions->open_root_key) {
508 ret = h->functions->open_root_key(h, key);
509 } else if(h->functions->open_key) {
510 ret = h->functions->open_key(h, "\\", key);
512 DEBUG(0, ("Backend '%s' has neither open_root_key nor open_key method implemented\n", h->functions->name));
513 ret = WERR_NOT_SUPPORTED;
516 if(W_ERROR_IS_OK(ret)) {
518 (*key)->path = talloc_strdup((*key)->mem_ctx, "\\");
524 WERROR reg_key_add_value(REG_KEY *key, const char *name, int type, void *value, size_t vallen)
526 WERROR ret = WERR_OK;
527 if(!key->handle->functions->add_value)
528 return WERR_NOT_SUPPORTED;
530 ret = key->handle->functions->add_value(key, name, type, value, vallen);
532 if(!W_ERROR_IS_OK(ret)) return ret;
534 /* Invalidate the cache */
535 key->cache_values = NULL;
536 key->cache_values_count = 0;
540 WERROR reg_save(REG_HANDLE *h, const char *location)
543 return WERR_NOT_SUPPORTED;