registry: use normalize_reg_path() in regdb_fetch_keys()
[kai/samba.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         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         TALLOC_CTX *frame = talloc_stackframe();
732         TDB_DATA value;
733
734         DEBUG(11,("regdb_fetch_keys: Enter key => [%s]\n", key ? key : "NULL"));
735
736         path = talloc_strdup(frame, key);
737         if (!path) {
738                 goto fail;
739         }
740
741         /* convert to key format */
742         path = normalize_reg_path(frame, path);
743         if (!path) {
744                 goto fail;
745         }
746
747         ctr->seqnum = regdb_get_seqnum();
748
749         value = dbwrap_fetch_bystring(regdb, frame, path);
750
751         buf = value.dptr;
752         buflen = value.dsize;
753
754         if ( !buf ) {
755                 DEBUG(5,("regdb_fetch_keys: tdb lookup failed to locate key [%s]\n", key));
756                 goto fail;
757         }
758
759         len = tdb_unpack( buf, buflen, "d", &num_items);
760
761         for (i=0; i<num_items; i++) {
762                 len += tdb_unpack(buf+len, buflen-len, "f", subkeyname);
763                 werr = regsubkey_ctr_addkey(ctr, subkeyname);
764                 if (!W_ERROR_IS_OK(werr)) {
765                         DEBUG(5, ("regdb_fetch_keys: regsubkey_ctr_addkey "
766                                   "failed: %s\n", dos_errstr(werr)));
767                         goto fail;
768                 }
769         }
770
771         DEBUG(11,("regdb_fetch_keys: Exit [%d] items\n", num_items));
772
773         ret = num_items;
774  fail:
775         TALLOC_FREE(frame);
776         return ret;
777 }
778
779 /****************************************************************************
780  Unpack a list of registry values frem the TDB
781  ***************************************************************************/
782
783 static int regdb_unpack_values(REGVAL_CTR *values, uint8 *buf, int buflen)
784 {
785         int             len = 0;
786         uint32          type;
787         fstring valuename;
788         uint32          size;
789         uint8           *data_p;
790         uint32          num_values = 0;
791         int             i;
792
793         /* loop and unpack the rest of the registry values */
794
795         len += tdb_unpack(buf+len, buflen-len, "d", &num_values);
796
797         for ( i=0; i<num_values; i++ ) {
798                 /* unpack the next regval */
799
800                 type = REG_NONE;
801                 size = 0;
802                 data_p = NULL;
803                 valuename[0] = '\0';
804                 len += tdb_unpack(buf+len, buflen-len, "fdB",
805                                   valuename,
806                                   &type,
807                                   &size,
808                                   &data_p);
809
810                 /* add the new value. Paranoid protective code -- make sure data_p is valid */
811
812                 if (*valuename && size && data_p) {
813                         regval_ctr_addvalue(values, valuename, type,
814                                         (const char *)data_p, size);
815                 }
816                 SAFE_FREE(data_p); /* 'B' option to tdb_unpack does a malloc() */
817
818                 DEBUG(8,("specific: [%s], len: %d\n", valuename, size));
819         }
820
821         return len;
822 }
823
824 /****************************************************************************
825  Pack all values in all printer keys
826  ***************************************************************************/
827
828 static int regdb_pack_values(REGVAL_CTR *values, uint8 *buf, int buflen)
829 {
830         int             len = 0;
831         int             i;
832         REGISTRY_VALUE  *val;
833         int             num_values;
834
835         if ( !values )
836                 return 0;
837
838         num_values = regval_ctr_numvals( values );
839
840         /* pack the number of values first */
841
842         len += tdb_pack( buf+len, buflen-len, "d", num_values );
843
844         /* loop over all values */
845
846         for ( i=0; i<num_values; i++ ) {
847                 val = regval_ctr_specific_value( values, i );
848                 len += tdb_pack(buf+len, buflen-len, "fdB",
849                                 regval_name(val),
850                                 regval_type(val),
851                                 regval_size(val),
852                                 regval_data_p(val) );
853         }
854
855         return len;
856 }
857
858 /***********************************************************************
859  Retrieve an array of strings containing subkeys.  Memory should be
860  released by the caller.
861  ***********************************************************************/
862
863 int regdb_fetch_values( const char* key, REGVAL_CTR *values )
864 {
865         char *keystr = NULL;
866         TALLOC_CTX *ctx = talloc_stackframe();
867         int ret = 0;
868         TDB_DATA value;
869
870         DEBUG(10,("regdb_fetch_values: Looking for value of key [%s] \n", key));
871
872         keystr = talloc_asprintf(ctx, "%s/%s", REG_VALUE_PREFIX, key);
873         if (!keystr) {
874                 return 0;
875         }
876         keystr = normalize_reg_path(ctx, keystr);
877         if (!keystr) {
878                 goto done;
879         }
880
881         values->seqnum = regdb_get_seqnum();
882
883         value = dbwrap_fetch_bystring(regdb, ctx, keystr);
884
885         if (!value.dptr) {
886                 /* all keys have zero values by default */
887                 goto done;
888         }
889
890         regdb_unpack_values(values, value.dptr, value.dsize);
891         ret = regval_ctr_numvals(values);
892
893 done:
894         TALLOC_FREE(ctx);
895         return ret;
896 }
897
898 bool regdb_store_values( const char *key, REGVAL_CTR *values )
899 {
900         TDB_DATA old_data, data;
901         char *keystr = NULL;
902         TALLOC_CTX *ctx = talloc_stackframe();
903         int len;
904         NTSTATUS status;
905         bool result = false;
906
907         DEBUG(10,("regdb_store_values: Looking for value of key [%s] \n", key));
908
909         ZERO_STRUCT(data);
910
911         len = regdb_pack_values(values, data.dptr, data.dsize);
912         if (len <= 0) {
913                 DEBUG(0,("regdb_store_values: unable to pack values. len <= 0\n"));
914                 goto done;
915         }
916
917         data.dptr = TALLOC_ARRAY(ctx, uint8, len);
918         data.dsize = len;
919
920         len = regdb_pack_values(values, data.dptr, data.dsize);
921
922         SMB_ASSERT( len == data.dsize );
923
924         keystr = talloc_asprintf(ctx, "%s/%s", REG_VALUE_PREFIX, key );
925         if (!keystr) {
926                 goto done;
927         }
928         keystr = normalize_reg_path(ctx, keystr);
929         if (!keystr) {
930                 goto done;
931         }
932
933         old_data = dbwrap_fetch_bystring(regdb, ctx, keystr);
934
935         if ((old_data.dptr != NULL)
936             && (old_data.dsize == data.dsize)
937             && (memcmp(old_data.dptr, data.dptr, data.dsize) == 0))
938         {
939                 result = true;
940                 goto done;
941         }
942
943         status = dbwrap_trans_store(regdb, string_term_tdb_data(keystr), data,
944                                     TDB_REPLACE);
945
946         result = NT_STATUS_IS_OK(status);
947
948 done:
949         TALLOC_FREE(ctx);
950         return result;
951 }
952
953 static WERROR regdb_get_secdesc(TALLOC_CTX *mem_ctx, const char *key,
954                                 struct security_descriptor **psecdesc)
955 {
956         char *tdbkey;
957         TDB_DATA data;
958         NTSTATUS status;
959         TALLOC_CTX *tmp_ctx = talloc_stackframe();
960         WERROR err = WERR_OK;
961
962         DEBUG(10, ("regdb_get_secdesc: Getting secdesc of key [%s]\n", key));
963
964         tdbkey = talloc_asprintf(tmp_ctx, "%s/%s", REG_SECDESC_PREFIX, key);
965         if (tdbkey == NULL) {
966                 err = WERR_NOMEM;
967                 goto done;
968         }
969         normalize_dbkey(tdbkey);
970
971         data = dbwrap_fetch_bystring(regdb, tmp_ctx, tdbkey);
972         if (data.dptr == NULL) {
973                 err = WERR_BADFILE;
974                 goto done;
975         }
976
977         status = unmarshall_sec_desc(mem_ctx, (uint8 *)data.dptr, data.dsize,
978                                      psecdesc);
979
980         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
981                 err = WERR_NOMEM;
982         } else if (!NT_STATUS_IS_OK(status)) {
983                 err = WERR_REG_CORRUPT;
984         }
985
986 done:
987         TALLOC_FREE(tmp_ctx);
988         return err;
989 }
990
991 static WERROR regdb_set_secdesc(const char *key,
992                                 struct security_descriptor *secdesc)
993 {
994         TALLOC_CTX *mem_ctx = talloc_stackframe();
995         char *tdbkey;
996         NTSTATUS status;
997         WERROR err = WERR_NOMEM;
998         TDB_DATA tdbdata;
999
1000         tdbkey = talloc_asprintf(mem_ctx, "%s/%s", REG_SECDESC_PREFIX, key);
1001         if (tdbkey == NULL) {
1002                 goto done;
1003         }
1004         normalize_dbkey(tdbkey);
1005
1006         if (secdesc == NULL) {
1007                 /* assuming a delete */
1008                 status = dbwrap_trans_delete(regdb,
1009                                              string_term_tdb_data(tdbkey));
1010                 if (NT_STATUS_IS_OK(status)) {
1011                         err = WERR_OK;
1012                 } else {
1013                         err = ntstatus_to_werror(status);
1014                 }
1015                 goto done;
1016         }
1017
1018         err = ntstatus_to_werror(marshall_sec_desc(mem_ctx, secdesc,
1019                                                    &tdbdata.dptr,
1020                                                    &tdbdata.dsize));
1021         if (!W_ERROR_IS_OK(err)) {
1022                 goto done;
1023         }
1024
1025         status = dbwrap_trans_store(regdb, string_term_tdb_data(tdbkey),
1026                                     tdbdata, 0);
1027         if (!NT_STATUS_IS_OK(status)) {
1028                 err = ntstatus_to_werror(status);
1029                 goto done;
1030         }
1031
1032  done:
1033         TALLOC_FREE(mem_ctx);
1034         return err;
1035 }
1036
1037 bool regdb_subkeys_need_update(REGSUBKEY_CTR *subkeys)
1038 {
1039         return (regdb_get_seqnum() != subkeys->seqnum);
1040 }
1041
1042 bool regdb_values_need_update(REGVAL_CTR *values)
1043 {
1044         return (regdb_get_seqnum() != values->seqnum);
1045 }
1046
1047 /* 
1048  * Table of function pointers for default access
1049  */
1050  
1051 REGISTRY_OPS regdb_ops = {
1052         .fetch_subkeys = regdb_fetch_keys,
1053         .fetch_values = regdb_fetch_values,
1054         .store_subkeys = regdb_store_keys,
1055         .store_values = regdb_store_values,
1056         .get_secdesc = regdb_get_secdesc,
1057         .set_secdesc = regdb_set_secdesc,
1058         .subkeys_need_update = regdb_subkeys_need_update,
1059         .values_need_update = regdb_values_need_update
1060 };