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