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