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