r665: merge over the new build system from my tmp branch
[ira/wip.git] / source4 / lib / registry / common / reg_interface.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Transparent registry backend handling
4    Copyright (C) Jelmer Vernooij                        2003-2004.
5
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.
10
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.
15
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.
19 */
20
21 #include "includes.h"
22 #include "lib/registry/common/registry.h"
23
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_REGISTRY
26
27 /* List of available backends */
28 static struct reg_init_function_entry *backends = NULL;
29
30 static struct reg_init_function_entry *reg_find_backend_entry(const char *name);
31
32 /* Register new backend */
33 NTSTATUS registry_register(void *_function)  
34 {
35         struct registry_ops *functions = _function;
36         struct reg_init_function_entry *entry = backends;
37
38         if (!functions || !functions->name) {
39                 return NT_STATUS_INVALID_PARAMETER;
40         }
41
42         DEBUG(5,("Attempting to register registry backend %s\n", functions->name));
43
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;
48         }
49
50         entry = malloc(sizeof(struct reg_init_function_entry));
51         entry->functions = functions;
52
53         DLIST_ADD(backends, entry);
54         DEBUG(5,("Successfully added registry backend '%s'\n", functions->name));
55         return NT_STATUS_OK;
56 }
57
58 /* Find a backend in the list of available backends */
59 static struct reg_init_function_entry *reg_find_backend_entry(const char *name)
60 {
61         struct reg_init_function_entry *entry = backends;
62
63         while(entry) {
64                 if (strcmp(entry->functions->name, name)==0) return entry;
65                 entry = entry->next;
66         }
67
68         return NULL;
69 }
70
71 /* Open a registry file/host/etc */
72 WERROR reg_open(const char *backend, const char *location, const char *credentials, REG_HANDLE **h)
73 {
74         struct reg_init_function_entry *entry;
75         static BOOL reg_first_init = True;
76         TALLOC_CTX *mem_ctx;
77         REG_HANDLE *ret;
78         NTSTATUS status;
79         WERROR werr;
80
81         if(reg_first_init) {
82                 status = register_subsystem("registry", registry_register);
83                 if (!NT_STATUS_IS_OK(status)) 
84                         return WERR_GENERAL_FAILURE;
85
86                 static_init_registry;
87                 reg_first_init = False;
88         }
89
90         entry = reg_find_backend_entry(backend);
91         
92         if (!entry) {
93                 DEBUG(0, ("No such registry backend '%s' loaded!\n", backend));
94                 return WERR_GENERAL_FAILURE;
95         }
96         
97         mem_ctx = talloc_init(backend);
98         ret = talloc(mem_ctx, sizeof(REG_HANDLE));
99         ZERO_STRUCTP(ret);      
100         ret->location = location?talloc_strdup(mem_ctx, location):NULL;
101         ret->credentials = credentials?talloc_strdup(mem_ctx, credentials):NULL;
102         ret->functions = entry->functions;
103         ret->backend_data = NULL;
104         ret->mem_ctx = mem_ctx;
105         *h = ret;
106
107         if(!entry->functions->open_registry) {
108                 return WERR_OK;
109         }
110         
111         werr = entry->functions->open_registry(ret, location, credentials);
112
113         if(W_ERROR_IS_OK(werr)) 
114                 return WERR_OK;
115
116         talloc_destroy(mem_ctx);
117         return werr;
118 }
119
120 /* Open a key 
121  * First tries to use the open_key function from the backend
122  * then falls back to get_subkey_by_name and later get_subkey_by_index 
123  */
124 WERROR reg_open_key(REG_KEY *parent, const char *name, REG_KEY **result)
125 {
126         char *fullname;
127         WERROR error;
128         TALLOC_CTX *mem_ctx;
129
130         if(!parent) {
131                 DEBUG(0, ("Invalid parent key specified"));
132                 return WERR_INVALID_PARAM;
133         }
134
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), 
139                          *curbegin = orig, 
140                          *curend = strchr(orig, '\\');
141                 REG_KEY *curkey = parent;
142
143                 while(curbegin && *curbegin) {
144                         if(curend)*curend = '\0';
145                         error = reg_key_get_subkey_by_name(curkey, curbegin, result);
146                         if(!W_ERROR_IS_OK(error)) {
147                                 SAFE_FREE(orig);
148                                 return error;
149                         }
150                         if(!curend) break;
151                         curbegin = curend + 1;
152                         curend = strchr(curbegin, '\\');
153                 }
154                 SAFE_FREE(orig);
155                 
156                 *result = curkey;
157                 return WERR_OK;
158         }
159
160         mem_ctx = talloc_init("mem_ctx");
161
162         fullname = talloc_asprintf(mem_ctx, "%s%s%s", parent->path, parent->path[strlen(parent->path)-1] == '\\'?"":"\\", name);
163
164         if(!parent->handle->functions->open_key) {
165                 DEBUG(0, ("Registry backend doesn't have get_subkey_by_name nor open_key!\n"));
166                 return WERR_NOT_SUPPORTED;
167         }
168
169         error = parent->handle->functions->open_key(parent->handle, fullname, result);
170
171         if(!W_ERROR_IS_OK(error)) {
172                 talloc_destroy(mem_ctx);
173                 return error;
174         }
175                 
176         (*result)->handle = parent->handle;
177         (*result)->path = fullname;
178         talloc_steal(mem_ctx, (*result)->mem_ctx, fullname);
179
180         talloc_destroy(mem_ctx);
181
182         return WERR_OK;
183 }
184
185 WERROR reg_key_get_value_by_index(REG_KEY *key, int idx, REG_VAL **val)
186 {
187         if(!key) return WERR_INVALID_PARAM;
188
189         if(key->handle->functions->get_value_by_index) {
190                 WERROR status = key->handle->functions->get_value_by_index(key, idx, val);
191                 if(!W_ERROR_IS_OK(status)) 
192                         return status;
193
194         } else if(key->handle->functions->fetch_values) {
195                 if(!key->cache_values)
196                         key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
197                 
198                 if(idx < key->cache_values_count && idx >= 0) {
199                         *val = reg_val_dup(key->cache_values[idx]);
200                 } else {
201                         return WERR_NO_MORE_ITEMS;
202                 }
203         } else {
204                 return WERR_NOT_SUPPORTED;
205         }
206         
207         (*val)->parent = key;
208         (*val)->handle = key->handle;
209         return WERR_OK;
210 }
211
212 WERROR reg_key_num_subkeys(REG_KEY *key, int *count)
213 {
214         if(!key) return WERR_INVALID_PARAM;
215         
216         if(key->handle->functions->num_subkeys) {
217                 return key->handle->functions->num_subkeys(key, count);
218         }
219
220         if(key->handle->functions->fetch_subkeys) {
221                 if(!key->cache_subkeys) 
222                         key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
223
224                 *count = key->cache_subkeys_count;
225                 return WERR_OK;
226         }
227
228         if(key->handle->functions->get_subkey_by_index) {
229                 int i;
230                 WERROR error;
231                 REG_KEY *dest;
232                 for(i = 0; W_ERROR_IS_OK(error = key->handle->functions->get_subkey_by_index(key, i, &dest)); i++) {
233                         reg_key_free(dest);
234                 }
235
236                 *count = i;
237                 if(W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) return WERR_OK;
238                 return error;
239         }
240
241         return WERR_NOT_SUPPORTED;
242 }
243
244 WERROR reg_key_num_values(REG_KEY *key, int *count)
245 {
246         
247         if(!key) return WERR_INVALID_PARAM;
248         
249         if(!key->handle->functions->num_values) {
250                 if(!key->handle->functions->fetch_values) {
251                         DEBUG(1, ("Backend '%s' doesn't support enumerating values\n", key->handle->functions->name));
252                         return WERR_NOT_SUPPORTED;
253                 }
254                 
255                 if(!key->cache_values) 
256                         key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
257
258                 *count = key->cache_values_count;
259                 return WERR_OK;
260         }
261
262         
263         return key->handle->functions->num_values(key, count);
264 }
265
266 WERROR reg_key_get_subkey_by_index(REG_KEY *key, int idx, REG_KEY **subkey)
267 {
268         if(!key) return WERR_INVALID_PARAM;
269
270         if(key->handle->functions->get_subkey_by_index) {
271                 WERROR status = key->handle->functions->get_subkey_by_index(key, idx, subkey);
272                 if(!NT_STATUS_IS_OK(status)) return status;
273         } else if(key->handle->functions->fetch_subkeys) {
274                 if(!key->cache_subkeys) 
275                         key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
276
277                 if(idx < key->cache_subkeys_count) {
278                         *subkey = reg_key_dup(key->cache_subkeys[idx]);
279                 } else {
280                         return WERR_NO_MORE_ITEMS;
281                 }
282         } else {
283                 return WERR_NOT_SUPPORTED;
284         }
285
286         (*subkey)->path = talloc_asprintf((*subkey)->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", (*subkey)->name);
287         (*subkey)->handle = key->handle;
288
289
290         return WERR_OK;;
291 }
292
293 WERROR reg_key_get_subkey_by_name(REG_KEY *key, const char *name, REG_KEY **subkey)
294 {
295         int i;
296         WERROR error = WERR_OK;
297
298         if(!key) return WERR_INVALID_PARAM;
299
300         if(key->handle->functions->get_subkey_by_name) {
301                 error = key->handle->functions->get_subkey_by_name(key,name,subkey);
302         } else if(key->handle->functions->get_subkey_by_index || key->handle->functions->fetch_subkeys) {
303                 for(i = 0; W_ERROR_IS_OK(error); i++) {
304                         error = reg_key_get_subkey_by_index(key, i, subkey);
305                         if(W_ERROR_IS_OK(error) && !strcmp((*subkey)->name, name)) {
306                                 return error;
307                         }
308                         reg_key_free(*subkey);
309                 }
310         } else {
311                 return WERR_NOT_SUPPORTED;
312         }
313
314         if(!W_ERROR_IS_OK(error)) return error;
315
316         (*subkey)->path = talloc_asprintf((*subkey)->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", (*subkey)->name);
317         (*subkey)->handle = key->handle;
318
319         return WERR_OK; 
320 }
321
322 WERROR reg_key_get_value_by_name(REG_KEY *key, const char *name, REG_VAL **val)
323 {
324         int i;
325         WERROR error = WERR_OK;
326
327         if(!key) return WERR_INVALID_PARAM;
328
329         if(key->handle->functions->get_value_by_name) {
330                 error = key->handle->functions->get_value_by_name(key,name, val);
331         } else {
332                 for(i = 0; W_ERROR_IS_OK(error); i++) {
333                         error = reg_key_get_value_by_index(key, i, val);
334                         if(W_ERROR_IS_OK(error) && StrCaseCmp((*val)->name, name)) {
335                                 break;
336                         }
337                         reg_val_free(*val);
338                 }
339         }
340
341         if(!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
342                 return error;
343         
344         (*val)->parent = key;
345         (*val)->handle = key->handle;
346         
347         return WERR_OK;
348 }
349
350 WERROR reg_key_del(REG_KEY *key)
351 {
352         WERROR error;
353         if(!key) return WERR_INVALID_PARAM;
354         
355         
356         if(!key->handle->functions->del_key)
357                 return WERR_NOT_SUPPORTED;
358         
359         error = key->handle->functions->del_key(key);
360         if(!W_ERROR_IS_OK(error)) return error;
361
362         /* Invalidate cache */
363         key->cache_subkeys = NULL;
364         key->cache_subkeys_count = 0;
365         return WERR_OK;
366 }
367
368 WERROR reg_sync(REG_KEY *h, const char *location)
369 {
370         if(!h->handle->functions->sync_key)
371                 return WERR_OK;
372
373         return h->handle->functions->sync_key(h, location);
374 }
375
376 WERROR reg_key_del_recursive(REG_KEY *key)
377 {
378         WERROR error = WERR_OK;
379         int i;
380         
381         /* Delete all values for specified key */
382         for(i = 0; W_ERROR_IS_OK(error); i++) {
383                 REG_VAL *val;
384                 error = reg_key_get_value_by_index(key, i, &val);
385                 if(!W_ERROR_IS_OK(error) && !W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS)) 
386                         return error;
387
388                 if(W_ERROR_IS_OK(error)) {
389                         error = reg_val_del(val);
390                         if(!W_ERROR_IS_OK(error)) return error;
391                 }
392         }
393
394         error = WERR_OK;
395
396         /* Delete all keys below this one */
397         for(i = 0; W_ERROR_IS_OK(error); i++) {
398                 REG_KEY *subkey;
399
400                 error = reg_key_get_subkey_by_index(key, i, &subkey);
401                 if(!W_ERROR_IS_OK(error)) return error;
402
403                 error = reg_key_del_recursive(subkey);
404                 if(!W_ERROR_IS_OK(error)) return error;
405         }
406
407         return reg_key_del(key);
408 }
409
410 WERROR reg_val_del(REG_VAL *val)
411 {
412         WERROR error;
413         if (!val) return WERR_INVALID_PARAM;
414
415         if (!val->handle->functions->del_value) {
416                 DEBUG(1, ("Backend '%s' doesn't support method del_value\n", val->handle->functions->name));
417                 return WERR_NOT_SUPPORTED;
418         }
419         
420         error = val->handle->functions->del_value(val);
421
422         if(!W_ERROR_IS_OK(error)) return error;
423
424         val->parent->cache_values = NULL;
425         val->parent->cache_values_count = 0;
426
427         return WERR_OK;
428 }
429
430 WERROR reg_key_add_name_recursive(REG_KEY *parent, const char *path)
431 {
432         REG_KEY *cur, *prevcur = parent;
433         WERROR error;
434         /* FIXME: we should never write to a 'const char *' !!! --metze */
435         char *begin = (char *)path, *end;
436
437         while(1) { 
438                 end = strchr(begin, '\\');
439                 if(end) *end = '\0';
440                 
441                 error = reg_key_get_subkey_by_name(prevcur, begin, &cur);
442
443                 /* Key is not there, add it */
444                 if(W_ERROR_EQUAL(error, WERR_DEST_NOT_FOUND)) {
445                         error = reg_key_add_name(prevcur, begin, 0, NULL, &cur);
446                         if(!W_ERROR_IS_OK(error)) return error;
447                 }
448
449                 if(!W_ERROR_IS_OK(error)) {
450                         if(end) *end = '\\';
451                         return error;
452                 }
453                 
454                 if(!end) break;
455                 *end = '\\';
456                 begin = end+1;
457                 prevcur = cur;
458         }
459         return WERR_OK;
460 }
461
462 WERROR reg_key_add_name(REG_KEY *parent, const char *name, uint32 access_mask, SEC_DESC *desc, REG_KEY **newkey)
463 {
464         WERROR error;
465         
466         if (!parent) return WERR_INVALID_PARAM;
467         
468         if (!parent->handle->functions->add_key) {
469                 DEBUG(1, ("Backend '%s' doesn't support method add_key\n", parent->handle->functions->name));
470                 return WERR_NOT_SUPPORTED;
471         }
472
473         error = parent->handle->functions->add_key(parent, name, access_mask, desc, newkey);
474
475         if(!W_ERROR_IS_OK(error)) return error;
476         
477         (*newkey)->handle = parent->handle;
478         (*newkey)->backend_data = talloc_asprintf((*newkey)->mem_ctx, "%s\\%s", reg_key_get_path(parent), name);
479
480         parent->cache_subkeys = NULL;
481         parent->cache_subkeys_count = 0;
482         return WERR_OK;
483 }
484
485 WERROR reg_val_update(REG_VAL *val, int type, void *data, int len)
486 {
487         WERROR error;
488         
489         /* A 'real' update function has preference */
490         if (val->handle->functions->update_value) 
491                 return val->handle->functions->update_value(val, type, data, len);
492
493         /* Otherwise, just remove and add again */
494         if (val->handle->functions->add_value && 
495                 val->handle->functions->del_value) {
496                 REG_VAL *new;
497                 if(!W_ERROR_IS_OK(error = val->handle->functions->del_value(val))) 
498                         return error;
499                 
500                 error = val->handle->functions->add_value(val->parent, val->name, type, data, len);
501                 if(!W_ERROR_IS_OK(error)) return error;
502                 memcpy(val, new, sizeof(REG_VAL));
503                 val->parent->cache_values = NULL;
504                 val->parent->cache_values_count = 0;
505                 return WERR_OK;
506         }
507                 
508         DEBUG(1, ("Backend '%s' doesn't support method update_value\n", val->handle->functions->name));
509         return WERR_NOT_SUPPORTED;
510 }
511
512 void reg_free(REG_HANDLE *h)
513 {
514         if(!h->functions->close_registry) return;
515
516         h->functions->close_registry(h);
517 }
518
519 WERROR reg_get_root(REG_HANDLE *h, REG_KEY **key) 
520 {
521         WERROR ret;
522         if(h->functions->open_root_key) {
523                 ret = h->functions->open_root_key(h, key);
524         } else if(h->functions->open_key) {
525                 ret = h->functions->open_key(h, "\\", key);
526         } else {
527                 DEBUG(0, ("Backend '%s' has neither open_root_key nor open_key method implemented\n", h->functions->name));
528                 ret = WERR_NOT_SUPPORTED;
529         }
530
531         if(W_ERROR_IS_OK(ret)) {
532                 (*key)->handle = h;
533                 (*key)->path = talloc_strdup((*key)->mem_ctx, "\\");
534         }
535
536         return ret;
537 }
538
539 WERROR reg_key_add_value(REG_KEY *key, const char *name, int type, void *value, size_t vallen)
540 {
541         WERROR ret = WERR_OK;
542         if(!key->handle->functions->add_value)
543                 return WERR_NOT_SUPPORTED;
544
545         ret = key->handle->functions->add_value(key, name, type, value, vallen);
546
547         if(!W_ERROR_IS_OK(ret)) return ret;
548
549         /* Invalidate the cache */
550         key->cache_values = NULL;
551         key->cache_values_count = 0;
552         return ret;
553 }
554
555 WERROR reg_save(REG_HANDLE *h, const char *location)
556 {
557         /* FIXME */     
558         return WERR_NOT_SUPPORTED;
559 }
560
561 WERROR reg_key_get_parent(REG_KEY *key, REG_KEY **parent)
562 {
563         char *parent_name;
564         char *last;
565         REG_KEY *root;
566         WERROR error;
567
568         error = reg_get_root(key->handle, &root);
569         if(!W_ERROR_IS_OK(error)) return error;
570
571         parent_name = strdup(reg_key_get_path(key));
572         last = strrchr(parent_name, '\\');
573
574         if(!last) {
575                 SAFE_FREE(parent_name);
576                 return WERR_FOOBAR;
577         }
578         *last = '\0';
579
580         error = reg_open_key(root, parent_name, parent);
581         SAFE_FREE(parent_name);
582         return error;
583 }