b6b38e9b62cc71002b0f9320e05bfe6f12a1813b
[ira/wip.git] / source4 / lib / registry / common / reg_interface.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Transparent registry backend handling
4    Copyright (C) Jelmer Vernooij                        2003-2004.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "lib/registry/common/registry.h"
23
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_REGISTRY
26
27 /* List of available backends */
28 static struct reg_init_function_entry *backends = NULL;
29
30 static struct reg_init_function_entry *reg_find_backend_entry(const char *name);
31
32 /* Register new backend */
33 NTSTATUS registry_register(void *_function)  
34 {
35         REG_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 REG_HANDLE *reg_open(const char *backend, const char *location, BOOL try_full_load)
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
79         if(reg_first_init) {
80                 if (!NT_STATUS_IS_OK(register_subsystem("registry", registry_register))) {
81                         return False;
82                 }
83
84                 static_init_reg;
85                 reg_first_init = False;
86         }
87
88         entry = reg_find_backend_entry(backend);
89         
90         if (!entry) {
91                 DEBUG(0, ("No such registry backend '%s' loaded!\n", backend));
92                 return NULL;
93         }
94         
95         mem_ctx = talloc_init(backend);
96         ret = talloc(mem_ctx, sizeof(REG_HANDLE));
97         ZERO_STRUCTP(ret);      
98         ret->location = location?talloc_strdup(mem_ctx, location):NULL;
99         ret->functions = entry->functions;
100         ret->backend_data = NULL;
101         ret->mem_ctx = mem_ctx;
102
103         if(!entry->functions->open_registry) {
104                 return ret;
105         }
106         
107         if(entry->functions->open_registry(ret, location, try_full_load))
108                 return ret;
109
110         talloc_destroy(mem_ctx);
111         return NULL;
112 }
113
114 /* Open a key 
115  * First tries to use the open_key function from the backend
116  * then falls back to get_subkey_by_name and later get_subkey_by_index 
117  */
118 REG_KEY *reg_open_key(REG_KEY *parent, const char *name)
119 {
120         char *fullname;
121         REG_KEY *ret = NULL;
122         TALLOC_CTX *mem_ctx;
123
124         if(!parent) {
125                 DEBUG(0, ("Invalid parent key specified"));
126                 return NULL;
127         }
128
129         if(!parent->handle->functions->open_key && 
130            (parent->handle->functions->get_subkey_by_name || 
131            parent->handle->functions->get_subkey_by_index)) {
132                 char *orig = strdup(name), 
133                          *curbegin = orig, 
134                          *curend = strchr(orig, '\\');
135                 REG_KEY *curkey = parent;
136
137                 while(curbegin && *curbegin) {
138                         if(curend)*curend = '\0';
139                         curkey = reg_key_get_subkey_by_name(curkey, curbegin);
140                         if(!curkey) {
141                                 SAFE_FREE(orig);
142                                 return NULL;
143                         }
144                         if(!curend) break;
145                         curbegin = curend + 1;
146                         curend = strchr(curbegin, '\\');
147                 }
148                 SAFE_FREE(orig);
149                 
150                 return curkey;
151         }
152
153         mem_ctx = talloc_init("mem_ctx");
154
155         fullname = talloc_asprintf(mem_ctx, "%s%s%s", parent->path, parent->path[strlen(parent->path)-1] == '\\'?"":"\\", name);
156
157
158         if(!parent->handle->functions->open_key) {
159                 DEBUG(0, ("Registry backend doesn't have get_subkey_by_name nor open_key!\n"));
160                 return NULL;
161         }
162
163         ret = parent->handle->functions->open_key(parent->handle, fullname);
164
165         if(ret) {
166                 ret->handle = parent->handle;
167                 ret->path = fullname;
168                 talloc_steal(mem_ctx, ret->mem_ctx, fullname);
169         }
170
171         talloc_destroy(mem_ctx);
172
173         return ret;
174 }
175
176 REG_VAL *reg_key_get_value_by_index(REG_KEY *key, int idx)
177 {
178         REG_VAL *ret;
179
180         if(!key) return NULL;
181
182         if(!key->handle->functions->get_value_by_index) {
183                 if(!key->cache_values)
184                         key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
185                 
186                 if(idx < key->cache_values_count && idx >= 0) {
187                         ret = reg_val_dup(key->cache_values[idx]);
188                 } else {
189                         return NULL;
190                 }
191         } else {
192                 ret = key->handle->functions->get_value_by_index(key, idx);
193         }
194         
195         if(ret) {
196                 ret->parent = key;
197                 ret->handle = key->handle;
198         }
199
200         return ret;
201 }
202
203 int reg_key_num_subkeys(REG_KEY *key)
204 {
205         if(!key) return 0;
206         
207         if(!key->handle->functions->num_subkeys) {
208                 if(!key->cache_subkeys) 
209                         key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
210
211                 return key->cache_subkeys_count;
212         }
213
214         return key->handle->functions->num_subkeys(key);
215 }
216
217 int reg_key_num_values(REG_KEY *key)
218 {
219         
220         if(!key) return 0;
221         
222         if(!key->handle->functions->num_values) {
223                 if(!key->handle->functions->fetch_values) {
224                         DEBUG(1, ("Backend '%s' doesn't support enumerating values\n", key->handle->functions->name));
225                         return 0;
226                 }
227                 
228                 if(!key->cache_values) 
229                         key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
230
231                 return key->cache_values_count;
232         }
233
234         
235         return key->handle->functions->num_values(key);
236 }
237
238 REG_KEY *reg_key_get_subkey_by_index(REG_KEY *key, int idx)
239 {
240         REG_KEY *ret = NULL;
241
242         if(!key) return NULL;
243
244         if(!key->handle->functions->get_subkey_by_index) {
245                 if(!key->cache_subkeys) 
246                         key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
247
248                 if(idx < key->cache_subkeys_count) {
249                         ret = reg_key_dup(key->cache_subkeys[idx]);
250                 } else {
251                         /* No such key ! */
252                         return NULL;
253                 }
254         } else {
255                 ret = key->handle->functions->get_subkey_by_index(key, idx);
256         }
257
258         if(ret && !ret->path) {
259                 ret->path = talloc_asprintf(ret->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name);
260                 ret->handle = key->handle;
261         }
262
263         return ret;
264 }
265
266 REG_KEY *reg_key_get_subkey_by_name(REG_KEY *key, const char *name)
267 {
268         int i, max;
269         REG_KEY *ret = NULL;
270
271         if(!key) return NULL;
272
273         if(key->handle->functions->get_subkey_by_name) {
274                 ret = key->handle->functions->get_subkey_by_name(key,name);
275         } else {
276                 max = reg_key_num_subkeys(key);
277                 for(i = 0; i < max; i++) {
278                         REG_KEY *v = reg_key_get_subkey_by_index(key, i);
279                         if(v && !strcmp(v->name, name)) {
280                                 ret = v;
281                                 break;
282                         }
283                         reg_key_free(v);
284                 }
285         }
286
287         if(ret && !ret->path) {
288                 ret->path = talloc_asprintf(ret->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name);
289                 ret->handle = key->handle;
290         }
291                 
292         return ret; 
293 }
294
295 REG_VAL *reg_key_get_value_by_name(REG_KEY *key, const char *name)
296 {
297         int i, max;
298         REG_VAL *ret = NULL;
299
300         if(!key) return NULL;
301
302         if(key->handle->functions->get_value_by_name) {
303                 ret = key->handle->functions->get_value_by_name(key,name);
304         } else {
305                 max = reg_key_num_values(key);
306                 for(i = 0; i < max; i++) {
307                         REG_VAL *v = reg_key_get_value_by_index(key, i);
308                         if(v && StrCaseCmp(v->name, name)) {
309                                 ret = v;
310                                 break;
311                         }
312                         reg_val_free(v);
313                 }
314         }
315         
316         if(ret) {
317                 ret->parent = key;
318                 ret->handle = key->handle;
319         }
320         
321         return ret;
322 }
323
324 BOOL reg_key_del(REG_KEY *key)
325 {
326         if(key->handle->functions->del_key) {
327                 if(key->handle->functions->del_key(key)) {
328                         /* Invalidate cache */
329                         key->cache_subkeys = NULL;
330                         key->cache_subkeys_count = 0;
331                         return True;
332                 }
333         }
334
335         return False;
336 }
337
338 BOOL reg_sync(REG_HANDLE *h, const char *location)
339 {
340         if(!h->functions->sync)
341                 return True;
342
343         return h->functions->sync(h, location);
344 }
345
346 BOOL reg_key_del_recursive(REG_KEY *key)
347 {
348         BOOL succeed = True;
349         int i;
350         
351         /* Delete all values for specified key */
352         for(i = 0; i < reg_key_num_values(key); i++) {
353                 if(!reg_val_del(reg_key_get_value_by_index(key, i)))
354                         succeed = False;
355         }
356
357         /* Delete all keys below this one */
358         for(i = 0; i < reg_key_num_subkeys(key); i++) {
359                 if(!reg_key_del_recursive(reg_key_get_subkey_by_index(key, i)))
360                         succeed = False;
361         }
362
363         if(succeed)reg_key_del(key);
364
365         return succeed;
366 }
367
368 BOOL reg_val_del(REG_VAL *val)
369 {
370         if (!val->handle->functions->del_value) {
371                 DEBUG(1, ("Backend '%s' doesn't support method del_value\n", val->handle->functions->name));
372                 return False;
373         }
374         
375         if(val->handle->functions->del_value(val)) {
376                 val->parent->cache_values = NULL;
377                 val->parent->cache_values_count = 0;
378                 return True;
379         } 
380         return False;
381 }
382
383 BOOL reg_key_add_name_recursive(REG_KEY *parent, const char *path)
384 {
385         REG_KEY *cur, *prevcur = parent;
386         char *begin = (char *)path, *end;
387
388         while(1) { 
389                 end = strchr(begin, '\\');
390                 if(end) *end = '\0';
391                 cur = reg_key_get_subkey_by_name(prevcur, begin);
392                 if(!cur) {
393                         if(!reg_key_add_name(prevcur, begin)) { printf("foo\n"); return False; }
394                         cur = reg_key_get_subkey_by_name(prevcur, begin);
395                         if(!cur) {
396                                 DEBUG(0, ("Can't find key after adding it : %s\n", begin));
397                                 return False;
398                         }
399                 }
400                 
401                 if(!end) break;
402                 *end = '\\';
403                 begin = end+1;
404                 prevcur = cur;
405         }
406         return True;
407 }
408
409 BOOL reg_key_add_name(REG_KEY *parent, const char *name)
410 {
411         if (!parent) return False;
412         
413         if (!parent->handle->functions->add_key) {
414                 DEBUG(1, ("Backend '%s' doesn't support method add_key\n", parent->handle->functions->name));
415                 return False;
416         }
417
418         if(parent->handle->functions->add_key(parent, name)) {
419                 parent->cache_subkeys = NULL;
420                 parent->cache_subkeys_count = 0;
421                 return True;
422         } 
423         return False;
424 }
425
426 BOOL reg_val_update(REG_VAL *val, int type, void *data, int len)
427 {
428         /* A 'real' update function has preference */
429         if (val->handle->functions->update_value) 
430                 return val->handle->functions->update_value(val, type, data, len);
431
432         /* Otherwise, just remove and add again */
433         if (val->handle->functions->add_value && 
434                 val->handle->functions->del_value) {
435                 REG_VAL *new;
436                 if(!val->handle->functions->del_value(val)) 
437                         return False;
438                 
439                 new = val->handle->functions->add_value(val->parent, val->name, type, data, len);
440                 memcpy(val, new, sizeof(REG_VAL));
441                 val->parent->cache_values = NULL;
442                 val->parent->cache_values_count = 0;
443                 return True;
444         }
445                 
446         DEBUG(1, ("Backend '%s' doesn't support method update_value\n", val->handle->functions->name));
447         return False;
448 }
449
450 void reg_free(REG_HANDLE *h)
451 {
452         if(!h->functions->close_registry) return;
453
454         h->functions->close_registry(h);
455 }
456
457 REG_KEY *reg_get_root(REG_HANDLE *h) 
458 {
459         REG_KEY *ret = NULL;
460         if(h->functions->open_root_key) {
461                 ret = h->functions->open_root_key(h);
462         } else if(h->functions->open_key) {
463                 ret = h->functions->open_key(h, "\\");
464         } else {
465                 DEBUG(0, ("Backend '%s' has neither open_root_key nor open_key method implemented\n", h->functions->name));
466         }
467
468         if(ret) {
469                 ret->handle = h;
470                 ret->path = talloc_strdup(ret->mem_ctx, "\\");
471         }
472
473         return ret;
474 }
475
476 REG_VAL *reg_key_add_value(REG_KEY *key, const char *name, int type, void *value, size_t vallen)
477 {
478         REG_VAL *ret;
479         if(!key->handle->functions->add_value)
480                 return NULL;
481
482         ret = key->handle->functions->add_value(key, name, type, value, vallen);
483         ret->parent = key;
484         ret->handle = key->handle;
485
486         /* Invalidate the cache */
487         key->cache_values = NULL;
488         key->cache_values_count = 0;
489         return ret;
490 }