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