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