registry: rename tdb_refcount to regdb_refcount after change to dbwrap.
[kai/samba-autobuild/.git] / source3 / registry / reg_backend_db.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  Virtual Windows Registry Layer
4  *  Copyright (C) Gerald Carter                     2002-2005
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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* Implementation of internal registry database functions. */
21
22 #include "includes.h"
23
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_REGISTRY
26
27 static struct db_context *regdb = NULL;
28 static int regdb_refcount;
29
30 /* List the deepest path into the registry.  All part components will be created.*/
31
32 /* If you want to have a part of the path controlled by the tdb and part by
33    a virtual registry db (e.g. printing), then you have to list the deepest path.
34    For example,"HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Print" 
35    allows the reg_db backend to handle everything up to 
36    "HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion" and then we'll hook 
37    the reg_printing backend onto the last component of the path (see 
38    KEY_PRINTING_2K in include/rpc_reg.h)   --jerry */
39
40 static const char *builtin_registry_paths[] = {
41         KEY_PRINTING_2K,
42         KEY_PRINTING_PORTS,
43         KEY_PRINTING,
44         KEY_SHARES,
45         KEY_EVENTLOG,
46         KEY_SMBCONF,
47         KEY_PERFLIB,
48         KEY_PERFLIB_009,
49         "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors",
50         KEY_PROD_OPTIONS,
51         "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\DefaultUserConfiguration",
52         KEY_TCPIP_PARAMS,
53         KEY_NETLOGON_PARAMS,
54         KEY_HKU,
55         KEY_HKCR,
56         KEY_HKPD,
57         KEY_HKPT,
58          NULL };
59
60 struct builtin_regkey_value {
61         const char *path;
62         const char *valuename;
63         uint32 type;
64         union {
65                 const char *string;
66                 uint32 dw_value;
67         } data;
68 };
69
70 static struct builtin_regkey_value builtin_registry_values[] = {
71         { KEY_PRINTING_PORTS,
72                 SAMBA_PRINTER_PORT_NAME, REG_SZ, { "" } },
73         { KEY_PRINTING_2K,
74                 "DefaultSpoolDirectory", REG_SZ, { "C:\\Windows\\System32\\Spool\\Printers" } },
75         { KEY_EVENTLOG,
76                 "DisplayName", REG_SZ, { "Event Log" } }, 
77         { KEY_EVENTLOG,
78                 "ErrorControl", REG_DWORD, { (char*)0x00000001 } },
79         { NULL, NULL, 0, { NULL } }
80 };
81
82 /***********************************************************************
83  Open the registry data in the tdb
84  ***********************************************************************/
85
86 static bool init_registry_data( void )
87 {
88         char *path = NULL;
89         char *base = NULL;
90         char *remaining = NULL;
91         TALLOC_CTX *frame = NULL;
92         char *keyname;
93         char *subkeyname;
94         REGSUBKEY_CTR *subkeys;
95         REGVAL_CTR *values;
96         int i;
97         const char *p, *p2;
98         UNISTR2 data;
99
100         /*
101          * There are potentially quite a few store operations which are all
102          * indiviually wrapped in tdb transactions. Wrapping them in a single
103          * transaction gives just a single transaction_commit() to actually do
104          * its fsync()s. See tdb/common/transaction.c for info about nested
105          * transaction behaviour.
106          */
107
108         if ( regdb->transaction_start( regdb ) == -1 ) {
109                 DEBUG(0, ("init_registry_data: tdb_transaction_start "
110                           "failed\n"));
111                 return false;
112         }
113
114         /* loop over all of the predefined paths and add each component */
115
116         for ( i=0; builtin_registry_paths[i] != NULL; i++ ) {
117
118                 frame = talloc_stackframe();
119
120                 DEBUG(6,("init_registry_data: Adding [%s]\n", builtin_registry_paths[i]));
121
122                 path = talloc_strdup(talloc_tos(), builtin_registry_paths[i]);
123                 base = talloc_strdup(talloc_tos(), "");
124                 if (!path || !base) {
125                         goto fail;
126                 }
127                 p = path;
128
129                 while (next_token_talloc(talloc_tos(), &p, &keyname, "\\")) {
130
131                         /* build up the registry path from the components */
132
133                         if (*base) {
134                                 base = talloc_asprintf(talloc_tos(), "%s\\", base);
135                                 if (!base) {
136                                         goto fail;
137                                 }
138                         }
139                         base = talloc_asprintf_append(base, "%s", keyname);
140                         if (!base) {
141                                 goto fail;
142                         }
143
144                         /* get the immediate subkeyname (if we have one ) */
145
146                         subkeyname = talloc_strdup(talloc_tos(), "");
147                         if (!subkeyname) {
148                                 goto fail;
149                         }
150                         if (*p) {
151                                 remaining = talloc_strdup(talloc_tos(), p);
152                                 if (!remaining) {
153                                         goto fail;
154                                 }
155                                 p2 = remaining;
156
157                                 if (!next_token_talloc(talloc_tos(), &p2,
158                                                         &subkeyname, "\\")) {
159                                         subkeyname = talloc_strdup(talloc_tos(),p2);
160                                         if (!subkeyname) {
161                                                 goto fail;
162                                         }
163                                 }
164                         }
165
166                         DEBUG(10,("init_registry_data: Storing key [%s] with subkey [%s]\n",
167                                 base, *subkeyname ? subkeyname : "NULL"));
168
169                         /* we don't really care if the lookup succeeds or not since
170                            we are about to update the record.  We just want any
171                            subkeys already present */
172
173                         if ( !(subkeys = TALLOC_ZERO_P(talloc_tos(), REGSUBKEY_CTR )) ) {
174                                 DEBUG(0,("talloc() failure!\n"));
175                                 goto fail;
176                         }
177
178                         regdb_fetch_keys(base, subkeys);
179                         if (*subkeyname) {
180                                 regsubkey_ctr_addkey( subkeys, subkeyname);
181                         }
182                         if (!regdb_store_keys( base, subkeys)) {
183                                 goto fail;
184                         }
185                 }
186
187                 TALLOC_FREE(frame);
188         }
189
190         /* loop over all of the predefined values and add each component */
191
192         for (i=0; builtin_registry_values[i].path != NULL; i++) {
193
194                 if (!(values = TALLOC_ZERO_P(talloc_tos(), REGVAL_CTR))) {
195                         goto fail;
196                 }
197
198                 regdb_fetch_values( builtin_registry_values[i].path, values);
199
200                 /* preserve existing values across restarts.  Only add new ones */
201
202                 if (!regval_ctr_key_exists(values, builtin_registry_values[i].valuename)) {
203                         switch(builtin_registry_values[i].type) {
204                         case REG_DWORD:
205                                 regval_ctr_addvalue( values,
206                                                      builtin_registry_values[i].valuename,
207                                                      REG_DWORD,
208                                                      (char*)&builtin_registry_values[i].data.dw_value,
209                                                      sizeof(uint32) );
210                                 break;
211
212                         case REG_SZ:
213                                 init_unistr2( &data, builtin_registry_values[i].data.string, UNI_STR_TERMINATE);
214                                 regval_ctr_addvalue( values,
215                                                      builtin_registry_values[i].valuename,
216                                                      REG_SZ,
217                                                      (char*)data.buffer,
218                                                      data.uni_str_len*sizeof(uint16) );
219                                 break;
220
221                         default:
222                                 DEBUG(0,("init_registry_data: invalid value type in builtin_registry_values [%d]\n",
223                                         builtin_registry_values[i].type));
224                         }
225                         regdb_store_values( builtin_registry_values[i].path, values );
226                 }
227                 TALLOC_FREE( values );
228         }
229
230         TALLOC_FREE(frame);
231
232         if (regdb->transaction_commit(regdb) == -1) {
233                 DEBUG(0, ("init_registry_data: Could not commit "
234                           "transaction\n"));
235                 return false;
236         }
237
238         return true;
239
240  fail:
241
242         TALLOC_FREE(frame);
243
244         if (regdb->transaction_cancel(regdb) == -1) {
245                 smb_panic("init_registry_data: tdb_transaction_cancel "
246                           "failed\n");
247         }
248
249         return false;
250 }
251
252 /***********************************************************************
253  Open the registry database
254  ***********************************************************************/
255  
256 bool regdb_init( void )
257 {
258         const char *vstring = "INFO/version";
259         uint32 vers_id;
260
261         if ( regdb ) {
262                 DEBUG(10,("regdb_init: incrementing refcount (%d)\n", regdb_refcount));
263                 regdb_refcount++;
264                 return true;
265         }
266
267         if ( !(regdb = db_open(NULL, state_path("registry.tdb"), 0, REG_TDB_FLAGS, O_RDWR, 0600)) )
268         {
269                 regdb = db_open(NULL, state_path("registry.tdb"), 0, REG_TDB_FLAGS, O_RDWR|O_CREAT, 0600);
270                 if ( !regdb ) {
271                         DEBUG(0,("regdb_init: Failed to open registry %s (%s)\n",
272                                 state_path("registry.tdb"), strerror(errno) ));
273                         return false;
274                 }
275                 
276                 DEBUG(10,("regdb_init: Successfully created registry tdb\n"));
277         }
278
279         regdb_refcount = 1;
280
281         vers_id = dbwrap_fetch_int32(regdb, vstring);
282
283         if ( vers_id != REGVER_V1 ) {
284                 /* any upgrade code here if needed */
285                 DEBUG(10, ("regdb_init: got INFO/version = %d != %d\n",
286                            vers_id, REGVER_V1));
287         }
288
289         /* always setup the necessary keys and values */
290
291         if ( !init_registry_data() ) {
292                 DEBUG(0,("regdb_init: Failed to initialize data in registry!\n"));
293                 return false;
294         }
295
296         return true;
297 }
298
299 /***********************************************************************
300  Open the registry.  Must already have been initialized by regdb_init()
301  ***********************************************************************/
302
303 WERROR regdb_open( void )
304 {
305         WERROR result = WERR_OK;
306
307         if ( regdb ) {
308                 DEBUG(10,("regdb_open: incrementing refcount (%d)\n", regdb_refcount));
309                 regdb_refcount++;
310                 return WERR_OK;
311         }
312         
313         become_root();
314
315         regdb = db_open(NULL, state_path("registry.tdb"), 0, REG_TDB_FLAGS, O_RDWR, 0600);
316         if ( !regdb ) {
317                 result = ntstatus_to_werror( map_nt_error_from_unix( errno ) );
318                 DEBUG(0,("regdb_open: Failed to open %s! (%s)\n", 
319                         state_path("registry.tdb"), strerror(errno) ));
320         }
321
322         unbecome_root();
323
324         regdb_refcount = 1;
325         DEBUG(10,("regdb_open: refcount reset (%d)\n", regdb_refcount));
326
327         return result;
328 }
329
330 /***********************************************************************
331  ***********************************************************************/
332
333 int regdb_close( void )
334 {
335         if (regdb_refcount == 0) {
336                 return 0;
337         }
338
339         regdb_refcount--;
340
341         DEBUG(10,("regdb_close: decrementing refcount (%d)\n", regdb_refcount));
342
343         if ( regdb_refcount > 0 )
344                 return 0;
345
346         SMB_ASSERT( regdb_refcount >= 0 );
347
348         TALLOC_FREE(regdb);
349         return 0;
350 }
351
352 /***********************************************************************
353  return the tdb sequence number of the registry tdb.
354  this is an indicator for the content of the registry
355  having changed. it will change upon regdb_init, too, though.
356  ***********************************************************************/
357 int regdb_get_seqnum(void)
358 {
359         return regdb->get_seqnum(regdb);
360 }
361
362 /***********************************************************************
363  Add subkey strings to the registry tdb under a defined key
364  fmt is the same format as tdb_pack except this function only supports
365  fstrings
366  ***********************************************************************/
367
368 static bool regdb_store_keys_internal(const char *key, REGSUBKEY_CTR *ctr)
369 {
370         TDB_DATA dbuf;
371         uint8 *buffer = NULL;
372         int i = 0;
373         uint32 len, buflen;
374         bool ret = true;
375         uint32 num_subkeys = regsubkey_ctr_numkeys(ctr);
376         char *keyname = NULL;
377         TALLOC_CTX *ctx = talloc_tos();
378         NTSTATUS status;
379
380         if (!key) {
381                 return false;
382         }
383
384         keyname = talloc_strdup(ctx, key);
385         if (!keyname) {
386                 return false;
387         }
388         keyname = normalize_reg_path(ctx, keyname);
389
390         /* allocate some initial memory */
391
392         if (!(buffer = (uint8 *)SMB_MALLOC(1024))) {
393                 return false;
394         }
395         buflen = 1024;
396         len = 0;
397
398         /* store the number of subkeys */
399
400         len += tdb_pack(buffer+len, buflen-len, "d", num_subkeys );
401
402         /* pack all the strings */
403
404         for (i=0; i<num_subkeys; i++) {
405                 len += tdb_pack( buffer+len, buflen-len, "f", regsubkey_ctr_specific_key(ctr, i) );
406                 if ( len > buflen ) {
407                         /* allocate some extra space */
408                         if ((buffer = (uint8 *)SMB_REALLOC( buffer, len*2 )) == NULL) {
409                                 DEBUG(0,("regdb_store_keys: Failed to realloc memory of size [%d]\n", len*2));
410                                 ret = false;
411                                 goto done;
412                         }
413                         buflen = len*2;
414
415                         len = tdb_pack( buffer+len, buflen-len, "f", regsubkey_ctr_specific_key(ctr, i) );
416                 }
417         }
418
419         /* finally write out the data */
420
421         dbuf.dptr = buffer;
422         dbuf.dsize = len;
423         status = dbwrap_store_bystring(regdb, keyname, dbuf, TDB_REPLACE);
424         if (!NT_STATUS_IS_OK(status)) {
425                 ret = false;
426                 goto done;
427         }
428
429 done:
430         SAFE_FREE( buffer );
431         return ret;
432 }
433
434 /***********************************************************************
435  Store the new subkey record and create any child key records that
436  do not currently exist
437  ***********************************************************************/
438
439 bool regdb_store_keys(const char *key, REGSUBKEY_CTR *ctr)
440 {
441         int num_subkeys, i;
442         char *path = NULL;
443         REGSUBKEY_CTR *subkeys = NULL, *old_subkeys = NULL;
444         char *oldkeyname = NULL;
445         TALLOC_CTX *ctx = talloc_tos();
446         NTSTATUS status;
447
448         /*
449          * fetch a list of the old subkeys so we can determine if anything has
450          * changed
451          */
452
453         if (!(old_subkeys = TALLOC_ZERO_P(ctr, REGSUBKEY_CTR))) {
454                 DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
455                 return false;
456         }
457
458         regdb_fetch_keys(key, old_subkeys);
459
460         if ((ctr->num_subkeys && old_subkeys->num_subkeys) &&
461             (ctr->num_subkeys == old_subkeys->num_subkeys)) {
462
463                 for (i = 0; i<ctr->num_subkeys; i++) {
464                         if (strcmp(ctr->subkeys[i],
465                                    old_subkeys->subkeys[i]) != 0) {
466                                 break;
467                         }
468                 }
469                 if (i == ctr->num_subkeys) {
470                         /*
471                          * Nothing changed, no point to even start a tdb
472                          * transaction
473                          */
474                         TALLOC_FREE(old_subkeys);
475                         return true;
476                 }
477         }
478
479         if (regdb->transaction_start(regdb) == -1) {
480                 DEBUG(0, ("regdb_store_keys: transaction_start failed\n"));
481                 return false;
482         }
483
484         /*
485          * Re-fetch the old keys inside the transaction
486          */
487
488         TALLOC_FREE(old_subkeys);
489
490         if (!(old_subkeys = TALLOC_ZERO_P(ctr, REGSUBKEY_CTR))) {
491                 DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
492                 goto fail;
493         }
494
495         regdb_fetch_keys(key, old_subkeys);
496
497         /* store the subkey list for the parent */
498
499         if (!regdb_store_keys_internal(key, ctr) ) {
500                 DEBUG(0,("regdb_store_keys: Failed to store new subkey list "
501                          "for parent [%s]\n", key));
502                 goto fail;
503         }
504
505         /* now delete removed keys */
506
507         num_subkeys = regsubkey_ctr_numkeys(old_subkeys);
508         for (i=0; i<num_subkeys; i++) {
509                 oldkeyname = regsubkey_ctr_specific_key(old_subkeys, i);
510
511                 if (regsubkey_ctr_key_exists(ctr, oldkeyname)) {
512                         /*
513                          * It's still around, don't delete
514                          */
515
516                         continue;
517                 }
518
519                 path = talloc_asprintf(ctx, "%s/%s", key, oldkeyname);
520                 if (!path) {
521                         goto fail;
522                 }
523                 path = normalize_reg_path(ctx, path);
524                 if (!path) {
525                         goto fail;
526                 }
527                 status = dbwrap_delete_bystring(regdb, path);
528                 if (!NT_STATUS_IS_OK(status)) {
529                         DEBUG(1, ("Deleting %s failed\n", path));
530                         goto fail;
531                 }
532
533                 TALLOC_FREE(path);
534                 path = talloc_asprintf(ctx, "%s/%s/%s",
535                                 REG_VALUE_PREFIX,
536                                 key,
537                                 oldkeyname );
538                 if (!path) {
539                         goto fail;
540                 }
541                 path = normalize_reg_path(ctx, path);
542                 if (!path) {
543                         goto fail;
544                 }
545
546                 /*
547                  * Ignore errors here, we might have no values around
548                  */
549                 dbwrap_delete_bystring(regdb, path);
550                 TALLOC_FREE(path);
551         }
552
553         TALLOC_FREE(old_subkeys);
554
555         /* now create records for any subkeys that don't already exist */
556
557         num_subkeys = regsubkey_ctr_numkeys(ctr);
558
559         if (num_subkeys == 0) {
560                 if (!(subkeys = TALLOC_ZERO_P(ctr, REGSUBKEY_CTR)) ) {
561                         DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
562                         goto fail;
563                 }
564
565                 if (!regdb_store_keys_internal(key, subkeys)) {
566                         DEBUG(0,("regdb_store_keys: Failed to store "
567                                  "new record for key [%s]\n", key));
568                         goto fail;
569                 }
570                 TALLOC_FREE(subkeys);
571
572         }
573
574         for (i=0; i<num_subkeys; i++) {
575                 path = talloc_asprintf(ctx, "%s/%s",
576                                         key,
577                                         regsubkey_ctr_specific_key(ctr, i));
578                 if (!path) {
579                         goto fail;
580                 }
581                 if (!(subkeys = TALLOC_ZERO_P(ctr, REGSUBKEY_CTR)) ) {
582                         DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
583                         goto fail;
584                 }
585
586                 if (regdb_fetch_keys( path, subkeys ) == -1) {
587                         /* create a record with 0 subkeys */
588                         if (!regdb_store_keys_internal(path, subkeys)) {
589                                 DEBUG(0,("regdb_store_keys: Failed to store "
590                                          "new record for key [%s]\n", path));
591                                 goto fail;
592                         }
593                 }
594
595                 TALLOC_FREE(subkeys);
596                 TALLOC_FREE(path);
597         }
598
599         if (regdb->transaction_commit(regdb) == -1) {
600                 DEBUG(0, ("regdb_store_keys: Could not commit transaction\n"));
601                 return false;
602         }
603
604         return true;
605
606  fail:
607         TALLOC_FREE(old_subkeys);
608         TALLOC_FREE(subkeys);
609
610         if (regdb->transaction_cancel(regdb) == -1) {
611                 smb_panic("regdb_store_keys: transaction_cancel failed\n");
612         }
613
614         return false;
615 }
616
617
618 /***********************************************************************
619  Retrieve an array of strings containing subkeys.  Memory should be
620  released by the caller.
621  ***********************************************************************/
622
623 int regdb_fetch_keys(const char *key, REGSUBKEY_CTR *ctr)
624 {
625         char *path = NULL;
626         uint32 num_items;
627         uint8 *buf;
628         uint32 buflen, len;
629         int i;
630         fstring subkeyname;
631         int ret = -1;
632         TALLOC_CTX *frame = talloc_stackframe();
633         struct db_record *rec;
634
635         DEBUG(11,("regdb_fetch_keys: Enter key => [%s]\n", key ? key : "NULL"));
636
637         path = talloc_strdup(talloc_tos(), key);
638         if (!path) {
639                 goto fail;
640         }
641
642         /* convert to key format */
643         path = talloc_string_sub(talloc_tos(), path, "\\", "/");
644         if (!path) {
645                 goto fail;
646         }
647         strupper_m(path);
648
649         rec = regdb->fetch_locked(regdb, frame, string_term_tdb_data(path));
650         if (rec == NULL) {
651                 return 0;
652         }
653
654         ctr->seqnum = regdb_get_seqnum();
655
656         buf = rec->value.dptr;
657         buflen = rec->value.dsize;
658
659         if ( !buf ) {
660                 DEBUG(5,("regdb_fetch_keys: tdb lookup failed to locate key [%s]\n", key));
661                 goto fail;
662         }
663
664         len = tdb_unpack( buf, buflen, "d", &num_items);
665
666         for (i=0; i<num_items; i++) {
667                 len += tdb_unpack(buf+len, buflen-len, "f", subkeyname);
668                 regsubkey_ctr_addkey(ctr, subkeyname);
669         }
670
671         DEBUG(11,("regdb_fetch_keys: Exit [%d] items\n", num_items));
672
673         ret = num_items;
674  fail:
675         TALLOC_FREE(frame);
676         return ret;
677 }
678
679 /****************************************************************************
680  Unpack a list of registry values frem the TDB
681  ***************************************************************************/
682
683 static int regdb_unpack_values(REGVAL_CTR *values, uint8 *buf, int buflen)
684 {
685         int             len = 0;
686         uint32          type;
687         fstring valuename;
688         uint32          size;
689         uint8           *data_p;
690         uint32          num_values = 0;
691         int             i;
692
693         /* loop and unpack the rest of the registry values */
694
695         len += tdb_unpack(buf+len, buflen-len, "d", &num_values);
696
697         for ( i=0; i<num_values; i++ ) {
698                 /* unpack the next regval */
699
700                 type = REG_NONE;
701                 size = 0;
702                 data_p = NULL;
703                 valuename[0] = '\0';
704                 len += tdb_unpack(buf+len, buflen-len, "fdB",
705                                   valuename,
706                                   &type,
707                                   &size,
708                                   &data_p);
709
710                 /* add the new value. Paranoid protective code -- make sure data_p is valid */
711
712                 if (*valuename && size && data_p) {
713                         regval_ctr_addvalue(values, valuename, type,
714                                         (const char *)data_p, size);
715                 }
716                 SAFE_FREE(data_p); /* 'B' option to tdb_unpack does a malloc() */
717
718                 DEBUG(8,("specific: [%s], len: %d\n", valuename, size));
719         }
720
721         return len;
722 }
723
724 /****************************************************************************
725  Pack all values in all printer keys
726  ***************************************************************************/
727
728 static int regdb_pack_values(REGVAL_CTR *values, uint8 *buf, int buflen)
729 {
730         int             len = 0;
731         int             i;
732         REGISTRY_VALUE  *val;
733         int             num_values;
734
735         if ( !values )
736                 return 0;
737
738         num_values = regval_ctr_numvals( values );
739
740         /* pack the number of values first */
741
742         len += tdb_pack( buf+len, buflen-len, "d", num_values );
743
744         /* loop over all values */
745
746         for ( i=0; i<num_values; i++ ) {
747                 val = regval_ctr_specific_value( values, i );
748                 len += tdb_pack(buf+len, buflen-len, "fdB",
749                                 regval_name(val),
750                                 regval_type(val),
751                                 regval_size(val),
752                                 regval_data_p(val) );
753         }
754
755         return len;
756 }
757
758 /***********************************************************************
759  Retrieve an array of strings containing subkeys.  Memory should be
760  released by the caller.
761  ***********************************************************************/
762
763 int regdb_fetch_values( const char* key, REGVAL_CTR *values )
764 {
765         char *keystr = NULL;
766         TALLOC_CTX *ctx = talloc_stackframe();
767         struct db_record *rec;
768         int ret = 0;
769
770         DEBUG(10,("regdb_fetch_values: Looking for value of key [%s] \n", key));
771
772         keystr = talloc_asprintf(ctx, "%s/%s", REG_VALUE_PREFIX, key);
773         if (!keystr) {
774                 return 0;
775         }
776         keystr = normalize_reg_path(ctx, keystr);
777         if (!keystr) {
778                 goto done;
779         }
780
781         rec = regdb->fetch_locked(regdb, ctx, string_term_tdb_data(keystr));
782         if (rec == NULL) {
783                 goto done;
784         }
785
786         values->seqnum = regdb_get_seqnum();
787
788         if (!rec->value.dptr) {
789                 /* all keys have zero values by default */
790                 goto done;
791         }
792
793         regdb_unpack_values(values, rec->value.dptr, rec->value.dsize);
794         ret = regval_ctr_numvals(values);
795
796 done:
797         TALLOC_FREE(ctx);
798         return ret;
799 }
800
801 bool regdb_store_values( const char *key, REGVAL_CTR *values )
802 {
803         TDB_DATA old_data, data;
804         char *keystr = NULL;
805         TALLOC_CTX *ctx = talloc_tos();
806         int len, ret;
807
808         DEBUG(10,("regdb_store_values: Looking for value of key [%s] \n", key));
809
810         ZERO_STRUCT(data);
811
812         len = regdb_pack_values(values, data.dptr, data.dsize);
813         if (len <= 0) {
814                 DEBUG(0,("regdb_store_values: unable to pack values. len <= 0\n"));
815                 return false;
816         }
817
818         data.dptr = SMB_MALLOC_ARRAY( uint8, len );
819         data.dsize = len;
820
821         len = regdb_pack_values(values, data.dptr, data.dsize);
822
823         SMB_ASSERT( len == data.dsize );
824
825         keystr = talloc_asprintf(ctx, "%s/%s", REG_VALUE_PREFIX, key );
826         if (!keystr) {
827                 SAFE_FREE(data.dptr);
828                 return false;
829         }
830         keystr = normalize_reg_path(ctx, keystr);
831         if (!keystr) {
832                 SAFE_FREE(data.dptr);
833                 return false;
834         }
835
836         old_data = dbwrap_fetch_bystring(regdb, ctx, keystr);
837
838         if ((old_data.dptr != NULL)
839             && (old_data.dsize == data.dsize)
840             && (memcmp(old_data.dptr, data.dptr, data.dsize) == 0)) {
841                 TALLOC_FREE(old_data.dptr);
842                 SAFE_FREE(data.dptr);
843                 return true;
844         }
845
846         ret = dbwrap_trans_store(regdb, string_term_tdb_data(keystr), data,
847                                  TDB_REPLACE);
848
849         TALLOC_FREE( old_data.dptr );
850         SAFE_FREE( data.dptr );
851
852         return ret != -1 ;
853 }
854
855 static WERROR regdb_get_secdesc(TALLOC_CTX *mem_ctx, const char *key,
856                                 struct security_descriptor **psecdesc)
857 {
858         char *tdbkey;
859         TDB_DATA data;
860         NTSTATUS status;
861         TALLOC_CTX *tmp_ctx = talloc_stackframe();
862
863         DEBUG(10, ("regdb_get_secdesc: Getting secdesc of key [%s]\n", key));
864
865         if (asprintf(&tdbkey, "%s/%s", REG_SECDESC_PREFIX, key) == -1) {
866                 return WERR_NOMEM;
867         }
868         normalize_dbkey(tdbkey);
869
870         data = dbwrap_fetch_bystring(regdb, tmp_ctx, tdbkey);
871         SAFE_FREE(tdbkey);
872
873         if (data.dptr == NULL) {
874                 return WERR_BADFILE;
875         }
876
877         status = unmarshall_sec_desc(mem_ctx, (uint8 *)data.dptr, data.dsize,
878                                      psecdesc);
879
880         TALLOC_FREE(tmp_ctx);
881
882         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
883                 return WERR_NOMEM;
884         }
885
886         if (!NT_STATUS_IS_OK(status)) {
887                 return WERR_REG_CORRUPT;
888         }
889
890         return WERR_OK;
891 }
892
893 static WERROR regdb_set_secdesc(const char *key,
894                                 struct security_descriptor *secdesc)
895 {
896         prs_struct ps;
897         TALLOC_CTX *mem_ctx;
898         char *tdbkey;
899         WERROR err = WERR_NOMEM;
900         TDB_DATA tdbdata;
901
902         if (!(mem_ctx = talloc_init("regdb_set_secdesc"))) {
903                 return WERR_NOMEM;
904         }
905
906         ZERO_STRUCT(ps);
907
908         if (!(tdbkey = talloc_asprintf(mem_ctx, "%s/%s", REG_SECDESC_PREFIX,
909                                        key))) {
910                 goto done;
911         }
912         normalize_dbkey(tdbkey);
913
914         if (secdesc == NULL) {
915                 /* assuming a delete */
916                 int tdb_ret;
917
918                 tdb_ret = dbwrap_trans_delete(regdb,
919                                               string_term_tdb_data(tdbkey));
920                 if (tdb_ret == -1) {
921                         err = ntstatus_to_werror(map_nt_error_from_unix(errno));
922                 } else {
923                         err = WERR_OK;
924                 }
925
926                 goto done;
927         }
928
929         err = ntstatus_to_werror(marshall_sec_desc(mem_ctx, secdesc,
930                                                    &tdbdata.dptr,
931                                                    &tdbdata.dsize));
932         if (!W_ERROR_IS_OK(err)) {
933                 goto done;
934         }
935
936         if (dbwrap_trans_store(regdb, string_term_tdb_data(tdbkey),
937                                tdbdata, 0) == -1) {
938                 err = ntstatus_to_werror(map_nt_error_from_unix(errno));
939                 goto done;
940         }
941
942  done:
943         prs_mem_free(&ps);
944         TALLOC_FREE(mem_ctx);
945         return err;
946 }
947
948 bool regdb_subkeys_need_update(REGSUBKEY_CTR *subkeys)
949 {
950         return (regdb_get_seqnum() != subkeys->seqnum);
951 }
952
953 bool regdb_values_need_update(REGVAL_CTR *values)
954 {
955         return (regdb_get_seqnum() != values->seqnum);
956 }
957
958 /* 
959  * Table of function pointers for default access
960  */
961  
962 REGISTRY_OPS regdb_ops = {
963         regdb_fetch_keys,
964         regdb_fetch_values,
965         regdb_store_keys,
966         regdb_store_values,
967         NULL,
968         regdb_get_secdesc,
969         regdb_set_secdesc,
970         regdb_subkeys_need_update,
971         regdb_values_need_update
972 };