r20: Add the registry library. Still needs a lot of work,
[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
59 /* Find a backend in the list of available backends */
60 static struct reg_init_function_entry *reg_find_backend_entry(const char *name)
61 {
62         struct reg_init_function_entry *entry = backends;
63
64         while(entry) {
65                 if (strcmp(entry->functions->name, name)==0) return entry;
66                 entry = entry->next;
67         }
68
69         return NULL;
70 }
71
72 /* Open a registry file/host/etc */
73 REG_HANDLE *reg_open(const char *backend, const char *location, BOOL try_full_load)
74 {
75         struct reg_init_function_entry *entry;
76         static BOOL reg_first_init = True;
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         ret = malloc(sizeof(REG_HANDLE));
96         ZERO_STRUCTP(ret);      
97         ret->location = location?strdup(location):NULL;
98         ret->functions = entry->functions;
99         ret->backend_data = NULL;
100
101         if(!entry->functions->open_registry) {
102                 return ret;
103         }
104         
105         if(entry->functions->open_registry(ret, location, try_full_load))
106                 return ret;
107
108         SAFE_FREE(ret);
109         return NULL;
110 }
111
112 /* Open a key */
113 REG_KEY *reg_open_key(REG_KEY *parent, const char *name)
114 {
115         char *fullname;
116         REG_KEY *ret = NULL;
117
118         if(!parent) {
119                 DEBUG(0, ("Invalid parent key specified"));
120                 return NULL;
121         }
122
123         if(!parent->handle->functions->open_key && 
124            (parent->handle->functions->get_subkey_by_name || 
125            parent->handle->functions->get_subkey_by_index)) {
126                 char *orig = strdup(name), 
127                          *curbegin = orig, 
128                          *curend = strchr(orig, '\\');
129                 REG_KEY *curkey = parent;
130
131                 while(curbegin && *curbegin) {
132                         if(curend)*curend = '\0';
133                         curkey = reg_key_get_subkey_by_name(curkey, curbegin);
134                         if(!curkey) return NULL;
135                         if(!curend) break;
136                         curbegin = curend + 1;
137                         curend = strchr(curbegin, '\\');
138                 }
139                 
140                 return curkey;
141         }
142
143         asprintf(&fullname, "%s%s%s", parent->path, parent->path[strlen(parent->path)-1] == '\\'?"":"\\", name);
144
145         if(!parent->handle->functions->open_key) {
146                 DEBUG(0, ("Registry backend doesn't have get_subkey_by_name nor open_key!\n"));
147                 return NULL;
148         }
149
150         ret = parent->handle->functions->open_key(parent->handle, fullname);
151
152         if(ret) {
153                 ret->handle = parent->handle;
154                 ret->path = fullname;
155         } else
156                 SAFE_FREE(fullname);
157
158         return ret;
159 }
160
161 REG_VAL *reg_key_get_value_by_index(REG_KEY *key, int idx)
162 {
163         REG_VAL *ret;
164
165         if(!key) return NULL;
166
167         if(!key->handle->functions->get_value_by_index) {
168                 if(!key->cache_values)
169                         key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
170                 
171                 if(idx < key->cache_values_count && idx >= 0) {
172                         ret = reg_val_dup(key->cache_values[idx]);
173                 } else {
174                         return NULL;
175                 }
176         } else {
177                 ret = key->handle->functions->get_value_by_index(key, idx);
178         }
179         
180         if(ret) {
181                 ret->parent = key;
182                 ret->handle = key->handle;
183         }
184
185         return ret;
186 }
187
188 int reg_key_num_subkeys(REG_KEY *key)
189 {
190         if(!key->handle->functions->num_subkeys) {
191                 if(!key->cache_subkeys) 
192                         key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
193
194                 return key->cache_subkeys_count;
195         }
196
197         return key->handle->functions->num_subkeys(key);
198 }
199
200 int reg_key_num_values(REG_KEY *key)
201 {
202         
203         if(!key) return 0;
204         
205         if(!key->handle->functions->num_values) {
206                 if(!key->handle->functions->fetch_values) {
207                         DEBUG(1, ("Backend '%s' doesn't support enumerating values\n", key->handle->functions->name));
208                         return 0;
209                 }
210                 
211                 if(!key->cache_values) 
212                         key->handle->functions->fetch_values(key, &key->cache_values_count, &key->cache_values);
213
214                 return key->cache_values_count;
215         }
216
217         
218         return key->handle->functions->num_values(key);
219 }
220
221 REG_KEY *reg_key_get_subkey_by_index(REG_KEY *key, int idx)
222 {
223         REG_KEY *ret = NULL;
224
225         if(!key) return NULL;
226
227         if(!key->handle->functions->get_subkey_by_index) {
228                 if(!key->cache_subkeys) 
229                         key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
230
231                 if(idx < key->cache_subkeys_count) {
232                         ret = reg_key_dup(key->cache_subkeys[idx]);
233                 } else {
234                         /* No such key ! */
235                         return NULL;
236                 }
237         } else {
238                 ret = key->handle->functions->get_subkey_by_index(key, idx);
239         }
240
241         if(ret && !ret->path) {
242                 asprintf(&ret->path, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name);
243                 ret->handle = key->handle;
244         }
245
246         return ret;
247 }
248
249 REG_KEY *reg_key_get_subkey_by_name(REG_KEY *key, const char *name)
250 {
251         int i, max;
252         REG_KEY *ret = NULL;
253
254         if(!key) return NULL;
255
256         if(key->handle->functions->get_subkey_by_name) {
257                 ret = key->handle->functions->get_subkey_by_name(key,name);
258         } else {
259                 max = reg_key_num_subkeys(key);
260                 for(i = 0; i < max; i++) {
261                         REG_KEY *v = reg_key_get_subkey_by_index(key, i);
262                         if(v && !strcmp(v->name, name)) {
263                                 ret = v;
264                                 break;
265                         }
266                         reg_key_free(v);
267                 }
268         }
269
270         if(ret && !ret->path) {
271                 asprintf(&ret->path, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", ret->name);
272                 ret->handle = key->handle;
273         }
274                 
275         return ret; 
276 }
277
278 REG_VAL *reg_key_get_value_by_name(REG_KEY *key, const char *name)
279 {
280         int i, max;
281         REG_VAL *ret = NULL;
282
283         if(!key) return NULL;
284
285         if(key->handle->functions->get_value_by_name) {
286                 ret = key->handle->functions->get_value_by_name(key,name);
287         } else {
288                 max = reg_key_num_values(key);
289                 for(i = 0; i < max; i++) {
290                         REG_VAL *v = reg_key_get_value_by_index(key, i);
291                         if(v && StrCaseCmp(v->name, name)) {
292                                 ret = v;
293                                 break;
294                         }
295                         reg_val_free(v);
296                 }
297         }
298         
299         if(ret) {
300                 ret->parent = key;
301                 ret->handle = key->handle;
302         }
303         
304         return ret;
305 }
306
307 BOOL reg_key_del(REG_KEY *key)
308 {
309         if(key->handle->functions->del_key)
310                 return key->handle->functions->del_key(key);
311
312         return False;
313 }
314
315 BOOL reg_sync(REG_HANDLE *h, const char *location)
316 {
317         if(!h->functions->sync)
318                 return True;
319
320         return h->functions->sync(h, location);
321 }
322
323 BOOL reg_key_del_recursive(REG_KEY *key)
324 {
325         BOOL succeed = True;
326         int i;
327         
328         /* Delete all values for specified key */
329         for(i = 0; i < reg_key_num_values(key); i++) {
330                 if(!reg_val_del(reg_key_get_value_by_index(key, i)))
331                         succeed = False;
332         }
333
334         /* Delete all keys below this one */
335         for(i = 0; i < reg_key_num_subkeys(key); i++) {
336                 if(!reg_key_del_recursive(reg_key_get_subkey_by_index(key, i)))
337                         succeed = False;
338         }
339
340         if(succeed)reg_key_del(key);
341
342         return succeed;
343 }
344
345 BOOL reg_val_del(REG_VAL *val)
346 {
347         if (!val->handle->functions->del_value) {
348                 DEBUG(1, ("Backend '%s' doesn't support method del_value\n", val->handle->functions->name));
349                 return False;
350         }
351         
352         return val->handle->functions->del_value(val);
353 }
354
355 BOOL reg_key_add_name(REG_KEY *parent, const char *name)
356 {
357         if (!parent->handle->functions->add_key) {
358                 DEBUG(1, ("Backend '%s' doesn't support method add_key\n", parent->handle->functions->name));
359                 return False;
360         }
361
362         return parent->handle->functions->add_key(parent, name);
363 }
364
365 BOOL reg_val_update(REG_VAL *val, int type, void *data, int len)
366 {
367         /* A 'real' update function has preference */
368         if (val->handle->functions->update_value) 
369                 return val->handle->functions->update_value(val, type, data, len);
370
371         /* Otherwise, just remove and add again */
372         if (val->handle->functions->add_value && 
373                 val->handle->functions->del_value) {
374                 REG_VAL *new;
375                 if(!val->handle->functions->del_value(val)) 
376                         return False;
377                 
378                 new = val->handle->functions->add_value(val->parent, val->name, type, data, len);
379                 memcpy(val, new, sizeof(REG_VAL));
380                 return True;
381         }
382                 
383         DEBUG(1, ("Backend '%s' doesn't support method update_value\n", val->handle->functions->name));
384         return False;
385 }
386
387 void reg_free(REG_HANDLE *h)
388 {
389         if(!h->functions->close_registry) return;
390
391         h->functions->close_registry(h);
392 }
393
394 REG_KEY *reg_get_root(REG_HANDLE *h) 
395 {
396         REG_KEY *ret = NULL;
397         if(h->functions->open_root_key) {
398                 ret = h->functions->open_root_key(h);
399         } else if(h->functions->open_key) {
400                 ret = h->functions->open_key(h, "\\");
401         } else {
402                 DEBUG(0, ("Backend '%s' has neither open_root_key nor open_key method implemented\n", h->functions->name));
403         }
404
405         if(ret) {
406                 ret->handle = h;
407                 ret->path = strdup("\\");
408         }
409
410         return ret;
411 }
412
413 REG_VAL *reg_key_add_value(REG_KEY *key, const char *name, int type, void *value, size_t vallen)
414 {
415         REG_VAL *ret;
416         if(!key->handle->functions->add_value)
417                 return NULL;
418
419         ret = key->handle->functions->add_value(key, name, type, value, vallen);
420         ret->parent = key;
421         ret->handle = key->handle;
422         return ret;
423 }