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