LCOV - code coverage report
Current view: top level - source3/registry - reg_backend_db.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 503 922 54.6 %
Date: 2024-06-13 04:01:37 Functions: 43 59 72.9 %

          Line data    Source code
       1             : /* 
       2             :  *  Unix SMB/CIFS implementation.
       3             :  *  Virtual Windows Registry Layer
       4             :  *  Copyright (C) Gerald Carter                     2002-2005
       5             :  *  Copyright (C) Michael Adam                      2007-2011
       6             :  *  Copyright (C) Gregor Beck                       2011
       7             :  *
       8             :  *  This program is free software; you can redistribute it and/or modify
       9             :  *  it under the terms of the GNU General Public License as published by
      10             :  *  the Free Software Foundation; either version 3 of the License, or
      11             :  *  (at your option) any later version.
      12             :  *  
      13             :  *  This program is distributed in the hope that it will be useful,
      14             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  *  GNU General Public License for more details.
      17             :  *  
      18             :  *  You should have received a copy of the GNU General Public License
      19             :  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
      20             :  */
      21             : 
      22             : /* Implementation of internal registry database functions. */
      23             : 
      24             : #include "includes.h"
      25             : #include "system/filesys.h"
      26             : #include "registry.h"
      27             : #include "reg_db.h"
      28             : #include "reg_util_internal.h"
      29             : #include "reg_parse_internal.h"
      30             : #include "reg_backend_db.h"
      31             : #include "reg_objects.h"
      32             : #include "nt_printing.h"
      33             : #include "util_tdb.h"
      34             : #include "dbwrap/dbwrap.h"
      35             : #include "dbwrap/dbwrap_open.h"
      36             : #include "../libcli/security/secdesc.h"
      37             : 
      38             : #undef DBGC_CLASS
      39             : #define DBGC_CLASS DBGC_REGISTRY
      40             : 
      41             : #define REGDB_VERSION_KEYNAME "INFO/version"
      42             : 
      43             : static struct db_context *regdb = NULL;
      44             : static int regdb_refcount;
      45             : 
      46             : static bool regdb_key_exists(struct db_context *db, const char *key);
      47             : static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key,
      48             :                                         struct regsubkey_ctr *ctr);
      49             : static bool regdb_store_keys_internal(struct db_context *db, const char *key,
      50             :                                       struct regsubkey_ctr *ctr);
      51             : static int regdb_fetch_values_internal(struct db_context *db, const char* key,
      52             :                                        struct regval_ctr *values);
      53             : static NTSTATUS regdb_store_values_internal(struct db_context *db, const char *key,
      54             :                                             struct regval_ctr *values);
      55             : static WERROR regdb_store_subkey_list(struct db_context *db, const char *parent,
      56             :                                       const char *key);
      57             : 
      58             : static WERROR regdb_create_basekey(struct db_context *db, const char *key);
      59             : static WERROR regdb_create_subkey_internal(struct db_context *db,
      60             :                                            const char *key,
      61             :                                            const char *subkey);
      62             : 
      63             : 
      64             : struct regdb_trans_ctx {
      65             :         NTSTATUS (*action)(struct db_context *, void *);
      66             :         void *private_data;
      67             : };
      68             : 
      69        4315 : static NTSTATUS regdb_trans_do_action(struct db_context *db, void *private_data)
      70             : {
      71             :         NTSTATUS status;
      72             :         int32_t version_id;
      73        4315 :         struct regdb_trans_ctx *ctx = (struct regdb_trans_ctx *)private_data;
      74             : 
      75        4315 :         status = dbwrap_fetch_int32_bystring(db, REGDB_VERSION_KEYNAME,
      76             :                                              &version_id);
      77             : 
      78        4315 :         if (!NT_STATUS_IS_OK(status)) {
      79           0 :                 DEBUG(0, ("ERROR: could not fetch registry db version: %s. "
      80             :                           "Denying access.\n", nt_errstr(status)));
      81           0 :                 return NT_STATUS_ACCESS_DENIED;
      82             :         }
      83             : 
      84        4315 :         if (version_id != REGDB_CODE_VERSION) {
      85           0 :                 DEBUG(0, ("ERROR: changed registry version %d found while "
      86             :                           "trying to write to the registry. Version %d "
      87             :                           "expected.  Denying access.\n",
      88             :                           version_id, REGDB_CODE_VERSION));
      89           0 :                 return NT_STATUS_ACCESS_DENIED;
      90             :         }
      91             : 
      92        4315 :         status = ctx->action(db,  ctx->private_data);
      93        4315 :         return status;
      94             : }
      95             : 
      96        4315 : static WERROR regdb_trans_do(struct db_context *db,
      97             :                              NTSTATUS (*action)(struct db_context *, void *),
      98             :                              void *private_data)
      99             : {
     100             :         NTSTATUS status;
     101             :         struct regdb_trans_ctx ctx;
     102             : 
     103             : 
     104        4315 :         ctx.action = action;
     105        4315 :         ctx.private_data = private_data;
     106             : 
     107        4315 :         status = dbwrap_trans_do(db, regdb_trans_do_action, &ctx);
     108             : 
     109        4315 :         return ntstatus_to_werror(status);
     110             : }
     111             : 
     112             : /* List the deepest path into the registry.  All part components will be created.*/
     113             : 
     114             : /* If you want to have a part of the path controlled by the tdb and part by
     115             :    a virtual registry db (e.g. printing), then you have to list the deepest path.
     116             :    For example,"HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Print" 
     117             :    allows the reg_db backend to handle everything up to 
     118             :    "HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion" and then we'll hook 
     119             :    the reg_printing backend onto the last component of the path (see 
     120             :    KEY_PRINTING_2K in include/rpc_reg.h)   --jerry */
     121             : 
     122             : static const char *builtin_registry_paths[] = {
     123             :         KEY_PRINTING_2K,
     124             :         KEY_PCC,
     125             :         KEY_PRINTING_PORTS,
     126             :         KEY_PRINTING,
     127             :         KEY_PRINTING "\\Forms",
     128             :         KEY_PRINTING "\\Printers",
     129             :         KEY_PRINTING "\\Environments\\Windows NT x86\\Print Processors\\winprint",
     130             :         KEY_PRINTING "\\Environments\\Windows x64\\Print Processors\\winprint",
     131             :         KEY_SHARES,
     132             :         KEY_EVENTLOG,
     133             :         KEY_SMBCONF,
     134             :         KEY_PERFLIB,
     135             :         KEY_PERFLIB_009,
     136             :         KEY_GROUP_POLICY,
     137             :         KEY_SAMBA_GROUP_POLICY,
     138             :         KEY_GP_MACHINE_POLICY,
     139             :         KEY_GP_MACHINE_WIN_POLICY,
     140             :         KEY_HKCU,
     141             :         KEY_GP_USER_POLICY,
     142             :         KEY_GP_USER_WIN_POLICY,
     143             :         "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions",
     144             :         "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors",
     145             :         KEY_PROD_OPTIONS,
     146             :         "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\DefaultUserConfiguration",
     147             :         KEY_TCPIP_PARAMS,
     148             :         KEY_NETLOGON_PARAMS,
     149             :         KEY_HKU,
     150             :         KEY_HKCR,
     151             :         KEY_HKPD,
     152             :         KEY_HKPT,
     153             :          NULL };
     154             : 
     155             : struct builtin_regkey_value {
     156             :         const char *path;
     157             :         const char *valuename;
     158             :         uint32_t type;
     159             :         union {
     160             :                 const char *string;
     161             :                 uint32_t dw_value;
     162             :         } data;
     163             : };
     164             : 
     165             : static struct builtin_regkey_value builtin_registry_values[] = {
     166             :         { KEY_PRINTING_PORTS,
     167             :                 SAMBA_PRINTER_PORT_NAME, REG_SZ, { "" } },
     168             :         { KEY_PRINTING_2K,
     169             :                 "DefaultSpoolDirectory", REG_SZ, { "C:\\Windows\\System32\\Spool\\Printers" } },
     170             :         { KEY_EVENTLOG,
     171             :                 "DisplayName", REG_SZ, { "Event Log" } },
     172             :         { KEY_EVENTLOG,
     173             :                 "ErrorControl", REG_DWORD, { (char*)0x00000001 } },
     174             :         { NULL, NULL, 0, { NULL } }
     175             : };
     176             : 
     177        5776 : static WERROR create_key_recursive(struct db_context *db,
     178             :                                    char *path,
     179             :                                    const char *subkey)
     180             : {
     181             :         WERROR werr;
     182             :         char *p;
     183             : 
     184        5776 :         if (subkey == NULL) {
     185           0 :                 return WERR_INVALID_PARAMETER;
     186             :         }
     187             : 
     188        5776 :         if (path == NULL) {
     189        1140 :                 return regdb_create_basekey(db, subkey);
     190             :         }
     191             : 
     192        4636 :         p = strrchr_m(path, '\\');
     193             : 
     194        4636 :         if (p == NULL) {
     195         950 :                 werr = create_key_recursive(db, NULL, path);
     196             :         } else {
     197        3686 :                 *p = '\0';
     198        3686 :                 werr = create_key_recursive(db, path, p+1);
     199        3686 :                 *p = '\\';
     200             :         }
     201             : 
     202        4636 :         if (!W_ERROR_IS_OK(werr)) {
     203           0 :                 goto done;
     204             :         }
     205             : 
     206        4636 :         werr = regdb_create_subkey_internal(db, path, subkey);
     207             : 
     208        4636 : done:
     209        4636 :         return werr;
     210             : }
     211             : 
     212             : /**
     213             :  * Initialize a key in the registry:
     214             :  * create each component key of the specified path.
     215             :  */
     216        1140 : static WERROR init_registry_key_internal(struct db_context *db,
     217             :                                          const char *add_path)
     218             : {
     219             :         char *subkey, *key;
     220             :         WERROR werr;
     221        1140 :         TALLOC_CTX *frame = talloc_stackframe();
     222             : 
     223        1140 :         if (add_path == NULL) {
     224           0 :                 werr = WERR_INVALID_PARAMETER;
     225           0 :                 goto done;
     226             :         }
     227             : 
     228        1140 :         key = talloc_strdup(frame, add_path);
     229             : 
     230        1140 :         subkey = strrchr_m(key, '\\');
     231        1140 :         if (subkey == NULL) {
     232         190 :                 subkey = key;
     233         190 :                 key = NULL;
     234             :         } else {
     235         950 :                 *subkey = '\0';
     236         950 :                 subkey++;
     237             :         }
     238             : 
     239        1140 :         werr = create_key_recursive(db, key, subkey);
     240             : 
     241        1140 : done:
     242        1140 :         talloc_free(frame);
     243        1140 :         return werr;
     244             : }
     245             : 
     246             : struct init_registry_key_context {
     247             :         const char *add_path;
     248             : };
     249             : 
     250           0 : static NTSTATUS init_registry_key_action(struct db_context *db,
     251             :                                          void *private_data)
     252             : {
     253           0 :         struct init_registry_key_context *init_ctx =
     254             :                 (struct init_registry_key_context *)private_data;
     255             : 
     256           0 :         return werror_to_ntstatus(init_registry_key_internal(
     257             :                                         db, init_ctx->add_path));
     258             : }
     259             : 
     260             : /**
     261             :  * Initialize a key in the registry:
     262             :  * create each component key of the specified path,
     263             :  * wrapped in one db transaction.
     264             :  */
     265         100 : WERROR init_registry_key(const char *add_path)
     266             : {
     267             :         struct init_registry_key_context init_ctx;
     268             : 
     269         100 :         if (regdb_key_exists(regdb, add_path)) {
     270         100 :                 return WERR_OK;
     271             :         }
     272             : 
     273           0 :         init_ctx.add_path = add_path;
     274             : 
     275           0 :         return regdb_trans_do(regdb,
     276             :                               init_registry_key_action,
     277             :                               &init_ctx);
     278             : }
     279             : 
     280             : /***********************************************************************
     281             :  Open the registry data in the tdb
     282             :  ***********************************************************************/
     283             : 
     284         152 : static void regdb_ctr_add_value(struct regval_ctr *ctr,
     285             :                                 struct builtin_regkey_value *value)
     286             : {
     287         152 :         switch(value->type) {
     288          38 :         case REG_DWORD:
     289          38 :                 regval_ctr_addvalue(ctr, value->valuename, REG_DWORD,
     290          38 :                                     (uint8_t *)&value->data.dw_value,
     291             :                                     sizeof(uint32_t));
     292          38 :                 break;
     293             : 
     294         114 :         case REG_SZ:
     295         114 :                 regval_ctr_addvalue_sz(ctr, value->valuename,
     296             :                                        value->data.string);
     297         114 :                 break;
     298             : 
     299           0 :         default:
     300           0 :                 DEBUG(0, ("regdb_ctr_add_value: invalid value type in "
     301             :                           "registry values [%d]\n", value->type));
     302             :         }
     303         152 : }
     304             : 
     305          38 : static NTSTATUS init_registry_data_action(struct db_context *db,
     306             :                                           void *private_data)
     307             : {
     308             :         NTSTATUS status;
     309          38 :         TALLOC_CTX *frame = talloc_stackframe();
     310             :         struct regval_ctr *values;
     311             :         int i;
     312             : 
     313             :         /* loop over all of the predefined paths and add each component */
     314             : 
     315        1178 :         for (i=0; builtin_registry_paths[i] != NULL; i++) {
     316        1140 :                 if (regdb_key_exists(db, builtin_registry_paths[i])) {
     317           0 :                         continue;
     318             :                 }
     319        1140 :                 status = werror_to_ntstatus(init_registry_key_internal(db,
     320             :                                                   builtin_registry_paths[i]));
     321        1140 :                 if (!NT_STATUS_IS_OK(status)) {
     322           0 :                         goto done;
     323             :                 }
     324             :         }
     325             : 
     326             :         /* loop over all of the predefined values and add each component */
     327             : 
     328         380 :         for (i=0; builtin_registry_values[i].path != NULL; i++) {
     329             :                 WERROR werr;
     330             : 
     331         152 :                 werr = regval_ctr_init(frame, &values);
     332         152 :                 if (!W_ERROR_IS_OK(werr)) {
     333           0 :                         status = werror_to_ntstatus(werr);
     334           0 :                         goto done;
     335             :                 }
     336             : 
     337         152 :                 regdb_fetch_values_internal(db,
     338             :                                             builtin_registry_values[i].path,
     339             :                                             values);
     340             : 
     341             :                 /* preserve existing values across restarts. Only add new ones */
     342             : 
     343         152 :                 if (!regval_ctr_value_exists(values,
     344             :                                         builtin_registry_values[i].valuename))
     345             :                 {
     346         152 :                         regdb_ctr_add_value(values,
     347             :                                             &builtin_registry_values[i]);
     348         152 :                         status = regdb_store_values_internal(db,
     349             :                                         builtin_registry_values[i].path,
     350             :                                         values);
     351         152 :                         if (!NT_STATUS_IS_OK(status)) {
     352           0 :                                 goto done;
     353             :                         }
     354             :                 }
     355         152 :                 TALLOC_FREE(values);
     356             :         }
     357             : 
     358          38 :         status = NT_STATUS_OK;
     359             : 
     360          38 : done:
     361             : 
     362          38 :         TALLOC_FREE(frame);
     363          38 :         return status;
     364             : }
     365             : 
     366         166 : WERROR init_registry_data(void)
     367             : {
     368             :         WERROR werr;
     369         166 :         TALLOC_CTX *frame = talloc_stackframe();
     370             :         struct regval_ctr *values;
     371             :         int i;
     372             : 
     373             :         /*
     374             :          * First, check for the existence of the needed keys and values.
     375             :          * If all do already exist, we can save the writes.
     376             :          */
     377        4006 :         for (i=0; builtin_registry_paths[i] != NULL; i++) {
     378        3878 :                 if (!regdb_key_exists(regdb, builtin_registry_paths[i])) {
     379          38 :                         goto do_init;
     380             :                 }
     381             :         }
     382             : 
     383         640 :         for (i=0; builtin_registry_values[i].path != NULL; i++) {
     384         512 :                 werr = regval_ctr_init(frame, &values);
     385         512 :                 W_ERROR_NOT_OK_GOTO_DONE(werr);
     386             : 
     387         512 :                 regdb_fetch_values_internal(regdb,
     388             :                                             builtin_registry_values[i].path,
     389             :                                             values);
     390         512 :                 if (!regval_ctr_value_exists(values,
     391             :                                         builtin_registry_values[i].valuename))
     392             :                 {
     393           0 :                         TALLOC_FREE(values);
     394           0 :                         goto do_init;
     395             :                 }
     396             : 
     397         512 :                 TALLOC_FREE(values);
     398             :         }
     399             : 
     400         128 :         werr = WERR_OK;
     401         128 :         goto done;
     402             : 
     403          38 : do_init:
     404             : 
     405             :         /*
     406             :          * There are potentially quite a few store operations which are all
     407             :          * indiviually wrapped in tdb transactions. Wrapping them in a single
     408             :          * transaction gives just a single transaction_commit() to actually do
     409             :          * its fsync()s. See tdb/common/transaction.c for info about nested
     410             :          * transaction behaviour.
     411             :          */
     412             : 
     413          38 :         werr = regdb_trans_do(regdb,
     414             :                               init_registry_data_action,
     415             :                               NULL);
     416             : 
     417         166 : done:
     418         166 :         TALLOC_FREE(frame);
     419         166 :         return werr;
     420             : }
     421             : 
     422           0 : static int regdb_normalize_keynames_fn(struct db_record *rec,
     423             :                                        void *private_data)
     424             : {
     425           0 :         TALLOC_CTX *mem_ctx = talloc_tos();
     426             :         const char *keyname;
     427             :         NTSTATUS status;
     428             :         TDB_DATA key;
     429             :         TDB_DATA value;
     430           0 :         struct db_context *db = (struct db_context *)private_data;
     431             : 
     432           0 :         key = dbwrap_record_get_key(rec);
     433           0 :         if (key.dptr == NULL || key.dsize == 0) {
     434           0 :                 return 0;
     435             :         }
     436             : 
     437           0 :         value = dbwrap_record_get_value(rec);
     438             : 
     439           0 :         if (db == NULL) {
     440           0 :                 DEBUG(0, ("regdb_normalize_keynames_fn: ERROR: "
     441             :                           "NULL db context handed in via private_data\n"));
     442           0 :                 return 1;
     443             :         }
     444             : 
     445           0 :         if (strncmp((const char *)key.dptr, REGDB_VERSION_KEYNAME,
     446             :             strlen(REGDB_VERSION_KEYNAME)) == 0)
     447             :         {
     448           0 :                 return 0;
     449             :         }
     450             : 
     451           0 :         keyname = strchr((const char *)key.dptr, '/');
     452           0 :         if (keyname) {
     453           0 :                 keyname = talloc_string_sub(mem_ctx,
     454           0 :                                             (const char *)key.dptr,
     455             :                                             "/",
     456             :                                             "\\");
     457             : 
     458           0 :                 DEBUG(2, ("regdb_normalize_keynames_fn: Convert %s to %s\n",
     459             :                           (const char *)key.dptr,
     460             :                           keyname));
     461             : 
     462             :                 /* Delete the original record and store the normalized key */
     463           0 :                 status = dbwrap_record_delete(rec);
     464           0 :                 if (!NT_STATUS_IS_OK(status)) {
     465           0 :                         DEBUG(0,("regdb_normalize_keynames_fn: "
     466             :                                  "tdb_delete for [%s] failed!\n",
     467             :                                  (const char *)key.dptr));
     468           0 :                         return 1;
     469             :                 }
     470             : 
     471           0 :                 status = dbwrap_store_bystring(db, keyname, value, TDB_REPLACE);
     472           0 :                 if (!NT_STATUS_IS_OK(status)) {
     473           0 :                         DEBUG(0,("regdb_normalize_keynames_fn: "
     474             :                                  "failed to store new record for [%s]!\n",
     475             :                                  keyname));
     476           0 :                         return 1;
     477             :                 }
     478             :         }
     479             : 
     480           0 :         return 0;
     481             : }
     482             : 
     483          38 : static WERROR regdb_store_regdb_version(struct db_context *db, uint32_t version)
     484             : {
     485             :         NTSTATUS status;
     486          38 :         if (db == NULL) {
     487           0 :                 return WERR_CAN_NOT_COMPLETE;
     488             :         }
     489             : 
     490          38 :         status = dbwrap_trans_store_int32_bystring(db, REGDB_VERSION_KEYNAME,
     491             :                                                    version);
     492          38 :         if (!NT_STATUS_IS_OK(status)) {
     493           0 :                 DEBUG(1, ("regdb_store_regdb_version: error storing %s = %d: %s\n",
     494             :                           REGDB_VERSION_KEYNAME, version, nt_errstr(status)));
     495           0 :                 return ntstatus_to_werror(status);
     496             :         } else {
     497          38 :                 DEBUG(10, ("regdb_store_regdb_version: stored %s = %d\n",
     498             :                           REGDB_VERSION_KEYNAME, version));
     499          38 :                 return WERR_OK;
     500             :         }
     501             : }
     502             : 
     503           0 : static WERROR regdb_upgrade_v1_to_v2(struct db_context *db)
     504             : {
     505             :         TALLOC_CTX *mem_ctx;
     506             :         NTSTATUS status;
     507             :         WERROR werr;
     508             : 
     509           0 :         mem_ctx = talloc_stackframe();
     510             : 
     511           0 :         status = dbwrap_traverse(db, regdb_normalize_keynames_fn, db, NULL);
     512           0 :         if (!NT_STATUS_IS_OK(status)) {
     513           0 :                 werr = WERR_REGISTRY_IO_FAILED;
     514           0 :                 goto done;
     515             :         }
     516             : 
     517           0 :         werr = regdb_store_regdb_version(db, REGDB_VERSION_V2);
     518             : 
     519           0 : done:
     520           0 :         talloc_free(mem_ctx);
     521           0 :         return werr;
     522             : }
     523             : 
     524           0 : static bool tdb_data_read_uint32(TDB_DATA *buf, uint32_t *result)
     525             : {
     526           0 :         const size_t len = sizeof(uint32_t);
     527           0 :         if (buf->dsize >= len) {
     528           0 :                 *result = IVAL(buf->dptr, 0);
     529           0 :                 buf->dptr += len;
     530           0 :                 buf->dsize -= len;
     531           0 :                 return true;
     532             :         }
     533           0 :         return false;
     534             : }
     535             : 
     536           0 : static bool tdb_data_read_cstr(TDB_DATA *buf, char **result)
     537             : {
     538           0 :         const size_t len = strnlen((char*)buf->dptr, buf->dsize) + 1;
     539           0 :         if (buf->dsize >= len) {
     540           0 :                 *result = (char*)buf->dptr;
     541           0 :                 buf->dptr += len;
     542           0 :                 buf->dsize -= len;
     543           0 :                 return true;
     544             :         }
     545           0 :         return false;
     546             : }
     547             : 
     548           0 : static bool tdb_data_is_cstr(TDB_DATA d) {
     549           0 :         if (tdb_data_is_empty(d) || (d.dptr[d.dsize-1] != '\0')) {
     550           0 :                 return false;
     551             :         }
     552           0 :         return strlen((char *)d.dptr) == (d.dsize-1);
     553             : }
     554             : 
     555           0 : static bool upgrade_v2_to_v3_check_subkeylist(struct db_context *db,
     556             :                                               const char *key,
     557             :                                               const char *subkey)
     558             : {
     559             :         static uint32_t zero = 0;
     560             :         static TDB_DATA empty_subkey_list = {
     561             :                 .dptr = (unsigned char*)&zero,
     562             :                 .dsize = sizeof(uint32_t),
     563             :         };
     564           0 :         bool success = false;
     565           0 :         char *path = talloc_asprintf(talloc_tos(), "%s\\%s", key, subkey);
     566           0 :         if (!strupper_m(path)) {
     567           0 :                 goto done;
     568             :         }
     569             : 
     570           0 :         if (!dbwrap_exists(db, string_term_tdb_data(path))) {
     571             :                 NTSTATUS status;
     572             : 
     573           0 :                 DEBUG(10, ("regdb_upgrade_v2_to_v3: writing subkey list [%s]\n",
     574             :                            path));
     575             : 
     576           0 :                 status = dbwrap_store_bystring(db, path, empty_subkey_list,
     577             :                                                TDB_INSERT);
     578           0 :                 if (!NT_STATUS_IS_OK(status)) {
     579           0 :                         DEBUG(0, ("regdb_upgrade_v2_to_v3: writing subkey list "
     580             :                                   "[%s] failed\n", path));
     581           0 :                         goto done;
     582             :                 }
     583             :         }
     584           0 :         success = true;
     585           0 : done:
     586           0 :         talloc_free(path);
     587           0 :         return success;
     588             : }
     589             : 
     590           0 : static bool upgrade_v2_to_v3_check_parent(struct db_context *db,
     591             :                                           const char *key)
     592             : {
     593           0 :         const char *sep = strrchr_m(key, '\\');
     594           0 :         if (sep != NULL) {
     595           0 :                 char *pkey = talloc_strndup(talloc_tos(), key, sep-key);
     596           0 :                 if (!dbwrap_exists(db, string_term_tdb_data(pkey))) {
     597           0 :                         DEBUG(0, ("regdb_upgrade_v2_to_v3: missing subkey list "
     598             :                                   "[%s]\nrun \"net registry check\"\n", pkey));
     599             :                 }
     600           0 :                 talloc_free(pkey);
     601             :         }
     602           0 :         return true;
     603             : }
     604             : 
     605             : 
     606             : #define IS_EQUAL(d,s) (((d).dsize == strlen(s)+1) &&    \
     607             :                        (strcmp((char*)(d).dptr, (s)) == 0))
     608             : #define STARTS_WITH(d,s) (((d).dsize > strlen(s)) &&                 \
     609             :                           (strncmp((char*)(d).dptr, (s), strlen(s)) == 0))
     610             : #define SSTR(d) (int)(d).dsize , (char*)(d).dptr
     611             : 
     612             : 
     613           0 : static int regdb_upgrade_v2_to_v3_fn(struct db_record *rec, void *private_data)
     614             : {
     615           0 :         struct db_context *db = (struct db_context *)private_data;
     616           0 :         TDB_DATA key = dbwrap_record_get_key(rec);
     617           0 :         TDB_DATA val = dbwrap_record_get_value(rec);
     618             : 
     619           0 :         if (tdb_data_is_empty(key)) {
     620           0 :                 return 0;
     621             :         }
     622             : 
     623           0 :         if (db == NULL) {
     624           0 :                 DEBUG(0, ("regdb_upgrade_v2_to_v3_fn: ERROR: "
     625             :                           "NULL db context handed in via private_data\n"));
     626           0 :                 return 1;
     627             :         }
     628             : 
     629           0 :         if (IS_EQUAL(key, REGDB_VERSION_KEYNAME) ||
     630           0 :             STARTS_WITH(key, REG_VALUE_PREFIX) ||
     631           0 :             STARTS_WITH(key, REG_SECDESC_PREFIX))
     632             :         {
     633           0 :                 DEBUG(10, ("regdb_upgrade_v2_to_v3: skipping [%.*s]\n",
     634             :                            SSTR(key)));
     635           0 :                 return 0;
     636             :         }
     637             : 
     638           0 :         if (STARTS_WITH(key, REG_SORTED_SUBKEYS_PREFIX)) {
     639             :                 NTSTATUS status;
     640             :                 /* Delete the deprecated sorted subkeys cache. */
     641             : 
     642           0 :                 DEBUG(10, ("regdb_upgrade_v2_to_v3: deleting [%.*s]\n",
     643             :                            SSTR(key)));
     644             : 
     645           0 :                 status = dbwrap_record_delete(rec);
     646           0 :                 if (!NT_STATUS_IS_OK(status)) {
     647           0 :                         DEBUG(0, ("regdb_upgrade_v2_to_v3: deleting [%.*s] "
     648             :                                   "failed!\n", SSTR(key)));
     649           0 :                         return 1;
     650             :                 }
     651             : 
     652           0 :                 return 0;
     653             :         }
     654             : 
     655           0 :         if ( tdb_data_is_cstr(key) &&
     656           0 :              hive_info((char*)key.dptr) != NULL )
     657           0 :         {
     658             :                 /*
     659             :                  * Found a regular subkey list record.
     660             :                  * Walk the list and create the list record for those
     661             :                  * subkeys that don't already have one.
     662             :                  */
     663           0 :                 TDB_DATA pos = val;
     664           0 :                 char *subkey, *path = (char*)key.dptr;
     665           0 :                 uint32_t num_items, found_items = 0;
     666             : 
     667             : 
     668           0 :                 DEBUG(10, ("regdb_upgrade_v2_to_v3: scanning subkeylist of "
     669             :                            "[%s]\n", path));
     670             : 
     671           0 :                 if (!tdb_data_read_uint32(&pos, &num_items)) {
     672             :                         /* invalid or empty - skip */
     673           0 :                         return 0;
     674             :                 }
     675             : 
     676           0 :                 while (tdb_data_read_cstr(&pos, &subkey)) {
     677           0 :                         found_items++;
     678             : 
     679           0 :                         if (!upgrade_v2_to_v3_check_subkeylist(db, path, subkey))
     680             :                         {
     681           0 :                                 return 1;
     682             :                         }
     683             : 
     684           0 :                         if (!upgrade_v2_to_v3_check_parent(db, path)) {
     685           0 :                                 return 1;
     686             :                         }
     687             :                 }
     688           0 :                 if (found_items != num_items) {
     689           0 :                         DEBUG(0, ("regdb_upgrade_v2_to_v3: inconsistent subkey "
     690             :                                   "list [%s]\nrun \"net registry check\"\n",
     691             :                                   path));
     692             :                 }
     693             :         } else {
     694           0 :                 DEBUG(10, ("regdb_upgrade_v2_to_v3: skipping invalid [%.*s]\n"
     695             :                            "run \"net registry check\"\n", SSTR(key)));
     696             :         }
     697             : 
     698           0 :         return 0;
     699             : }
     700             : 
     701           0 : static WERROR regdb_upgrade_v2_to_v3(struct db_context *db)
     702             : {
     703             :         NTSTATUS status;
     704             :         WERROR werr;
     705             : 
     706           0 :         status = dbwrap_traverse(db, regdb_upgrade_v2_to_v3_fn, db, NULL);
     707           0 :         if (!NT_STATUS_IS_OK(status)) {
     708           0 :                 werr = WERR_REGISTRY_IO_FAILED;
     709           0 :                 goto done;
     710             :         }
     711             : 
     712           0 :         werr = regdb_store_regdb_version(db, REGDB_VERSION_V3);
     713             : 
     714           0 : done:
     715           0 :         return werr;
     716             : }
     717             : 
     718             : /***********************************************************************
     719             :  Open the registry database
     720             :  ***********************************************************************/
     721             : 
     722         166 : WERROR regdb_init(void)
     723             : {
     724             :         int32_t vers_id;
     725             :         WERROR werr;
     726             :         NTSTATUS status;
     727             :         char *db_path;
     728             : 
     729         166 :         if (regdb) {
     730          15 :                 DEBUG(10, ("regdb_init: incrementing refcount (%d->%d)\n",
     731             :                            regdb_refcount, regdb_refcount+1));
     732          15 :                 regdb_refcount++;
     733          15 :                 return WERR_OK;
     734             :         }
     735             : 
     736             :         /*
     737             :          * Clustered Samba can only work as root because we need messaging to
     738             :          * talk to ctdb which only works as root.
     739             :          */
     740         151 :         if (!uid_wrapper_enabled() && lp_clustering() && geteuid() != 0) {
     741           0 :                 DBG_ERR("Cluster mode requires running as root.\n");
     742           0 :                 return WERR_ACCESS_DENIED;
     743             :         }
     744             : 
     745         151 :         db_path = state_path(talloc_tos(), "registry.tdb");
     746         151 :         if (db_path == NULL) {
     747           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     748             :         }
     749             : 
     750         151 :         regdb = db_open(NULL, db_path, 0,
     751             :                         REG_TDB_FLAGS, O_RDWR, 0600,
     752             :                         DBWRAP_LOCK_ORDER_1, REG_DBWRAP_FLAGS);
     753         151 :         if (!regdb) {
     754          38 :                 regdb = db_open(NULL, db_path, 0,
     755             :                                 REG_TDB_FLAGS, O_RDWR|O_CREAT, 0600,
     756             :                                 DBWRAP_LOCK_ORDER_1, REG_DBWRAP_FLAGS);
     757          38 :                 if (!regdb) {
     758           0 :                         werr = ntstatus_to_werror(map_nt_error_from_unix(errno));
     759           0 :                         DEBUG(1,("regdb_init: Failed to open registry %s (%s)\n",
     760             :                                 db_path, strerror(errno) ));
     761           0 :                         TALLOC_FREE(db_path);
     762           0 :                         return werr;
     763             :                 }
     764             : 
     765          38 :                 werr = regdb_store_regdb_version(regdb, REGDB_CODE_VERSION);
     766          38 :                 if (!W_ERROR_IS_OK(werr)) {
     767           0 :                         DEBUG(1, ("regdb_init: Failed to store version: %s\n",
     768             :                                   win_errstr(werr)));
     769           0 :                         TALLOC_FREE(db_path);
     770           0 :                         return werr;
     771             :                 }
     772             : 
     773          38 :                 DEBUG(10,("regdb_init: Successfully created registry tdb\n"));
     774             :         }
     775         151 :         TALLOC_FREE(db_path);
     776             : 
     777         151 :         regdb_refcount = 1;
     778         151 :         DEBUG(10, ("regdb_init: registry db openend. refcount reset (%d)\n",
     779             :                    regdb_refcount));
     780             : 
     781         151 :         status = dbwrap_fetch_int32_bystring(regdb, REGDB_VERSION_KEYNAME,
     782             :                                              &vers_id);
     783         151 :         if (!NT_STATUS_IS_OK(status)) {
     784           0 :                 DBG_DEBUG("Reading registry version failed: %s, "
     785             :                           "initializing to version %d\n",
     786             :                           nt_errstr(status), REGDB_VERSION_V1);
     787             : 
     788             :                 /*
     789             :                  * There was a regdb format version prior to version 1
     790             :                  * which did not store a INFO/version key. The format
     791             :                  * of this version was identical to version 1 except for
     792             :                  * the lack of the sorted subkey cache records.
     793             :                  * Since these are disposable, we can safely assume version
     794             :                  * 1 if no INFO/version key is found and run the db through
     795             :                  * the whole chain of upgrade. If the database was not
     796             :                  * initialized, this does not harm. If it was the unversioned
     797             :                  * version ("0"), then it do the right thing with the records.
     798             :                  */
     799           0 :                 werr = regdb_store_regdb_version(regdb, REGDB_VERSION_V1);
     800           0 :                 if (!W_ERROR_IS_OK(werr)) {
     801           0 :                         return werr;
     802             :                 }
     803           0 :                 vers_id = REGDB_VERSION_V1;
     804             :         }
     805             : 
     806         151 :         if (vers_id == REGDB_CODE_VERSION) {
     807         151 :                 return WERR_OK;
     808             :         }
     809             : 
     810           0 :         if (vers_id > REGDB_CODE_VERSION || vers_id == 0) {
     811           0 :                 DEBUG(0, ("regdb_init: unknown registry version %d "
     812             :                           "(code version = %d), refusing initialization\n",
     813             :                           vers_id, REGDB_CODE_VERSION));
     814           0 :                 return WERR_CAN_NOT_COMPLETE;
     815             :         }
     816             : 
     817           0 :         if (dbwrap_transaction_start(regdb) != 0) {
     818           0 :                 return WERR_REGISTRY_IO_FAILED;
     819             :         }
     820             : 
     821           0 :         if (vers_id == REGDB_VERSION_V1) {
     822           0 :                 DEBUG(10, ("regdb_init: upgrading registry from version %d "
     823             :                            "to %d\n", REGDB_VERSION_V1, REGDB_VERSION_V2));
     824             : 
     825           0 :                 werr = regdb_upgrade_v1_to_v2(regdb);
     826           0 :                 if (!W_ERROR_IS_OK(werr)) {
     827           0 :                         dbwrap_transaction_cancel(regdb);
     828           0 :                         return werr;
     829             :                 }
     830             : 
     831           0 :                 vers_id = REGDB_VERSION_V2;
     832             :         }
     833             : 
     834           0 :         if (vers_id == REGDB_VERSION_V2) {
     835           0 :                 DEBUG(10, ("regdb_init: upgrading registry from version %d "
     836             :                            "to %d\n", REGDB_VERSION_V2, REGDB_VERSION_V3));
     837             : 
     838           0 :                 werr = regdb_upgrade_v2_to_v3(regdb);
     839           0 :                 if (!W_ERROR_IS_OK(werr)) {
     840           0 :                         dbwrap_transaction_cancel(regdb);
     841           0 :                         return werr;
     842             :                 }
     843             : 
     844           0 :                 vers_id = REGDB_VERSION_V3;
     845             :         }
     846             : 
     847             :         /* future upgrade code should go here */
     848             : 
     849           0 :         if (dbwrap_transaction_commit(regdb) != 0) {
     850           0 :                 return WERR_REGISTRY_IO_FAILED;
     851             :         }
     852             : 
     853           0 :         return WERR_OK;
     854             : }
     855             : 
     856             : /***********************************************************************
     857             :  Open the registry.  Must already have been initialized by regdb_init()
     858             :  ***********************************************************************/
     859             : 
     860      190762 : WERROR regdb_open( void )
     861             : {
     862             :         WERROR result;
     863      190762 :         char *db_path = NULL;
     864             :         int saved_errno;
     865             : 
     866      190762 :         if ( regdb ) {
     867      190653 :                 DEBUG(10, ("regdb_open: incrementing refcount (%d->%d)\n",
     868             :                            regdb_refcount, regdb_refcount+1));
     869      190653 :                 regdb_refcount++;
     870      190653 :                 result = WERR_OK;
     871      190653 :                 goto done;
     872             :         }
     873             : 
     874         109 :         db_path = state_path(talloc_tos(), "registry.tdb");
     875         109 :         if (db_path == NULL) {
     876           0 :                 result = WERR_NOT_ENOUGH_MEMORY;
     877           0 :                 goto done;
     878             :         }
     879             : 
     880         109 :         become_root();
     881             : 
     882         109 :         regdb = db_open(NULL, db_path, 0,
     883             :                         REG_TDB_FLAGS, O_RDWR, 0600,
     884             :                         DBWRAP_LOCK_ORDER_1, REG_DBWRAP_FLAGS);
     885         109 :         saved_errno = errno;
     886         109 :         unbecome_root();
     887         109 :         if ( !regdb ) {
     888           0 :                 result = ntstatus_to_werror(map_nt_error_from_unix(saved_errno));
     889           0 :                 DEBUG(0,("regdb_open: Failed to open %s! (%s)\n",
     890             :                          db_path, strerror(saved_errno)));
     891           0 :                 goto done;
     892             :         }
     893             : 
     894         109 :         regdb_refcount = 1;
     895         109 :         DEBUG(10, ("regdb_open: registry db opened. refcount reset (%d)\n",
     896             :                    regdb_refcount));
     897             : 
     898         109 :         result = WERR_OK;
     899      190762 : done:
     900      190762 :         TALLOC_FREE(db_path);
     901      190762 :         return result;
     902             : }
     903             : 
     904             : /***********************************************************************
     905             :  ***********************************************************************/
     906             : 
     907      190742 : int regdb_close( void )
     908             : {
     909      190742 :         if (regdb_refcount == 0) {
     910           0 :                 return 0;
     911             :         }
     912             : 
     913      190742 :         regdb_refcount--;
     914             : 
     915      190742 :         DEBUG(10, ("regdb_close: decrementing refcount (%d->%d)\n",
     916             :                    regdb_refcount+1, regdb_refcount));
     917             : 
     918      190742 :         if ( regdb_refcount > 0 )
     919      190575 :                 return 0;
     920             : 
     921         167 :         SMB_ASSERT( regdb_refcount >= 0 );
     922             : 
     923         167 :         TALLOC_FREE(regdb);
     924         167 :         return 0;
     925             : }
     926             : 
     927        2741 : WERROR regdb_transaction_start(void)
     928             : {
     929        2741 :         return (dbwrap_transaction_start(regdb) == 0) ?
     930        2741 :                 WERR_OK : WERR_REGISTRY_IO_FAILED;
     931             : }
     932             : 
     933        2741 : WERROR regdb_transaction_commit(void)
     934             : {
     935        2741 :         return (dbwrap_transaction_commit(regdb) == 0) ?
     936        2741 :                 WERR_OK : WERR_REGISTRY_IO_FAILED;
     937             : }
     938             : 
     939           0 : WERROR regdb_transaction_cancel(void)
     940             : {
     941           0 :         return (dbwrap_transaction_cancel(regdb) == 0) ?
     942           0 :                 WERR_OK : WERR_REGISTRY_IO_FAILED;
     943             : }
     944             : 
     945             : /***********************************************************************
     946             :  return the tdb sequence number of the registry tdb.
     947             :  this is an indicator for the content of the registry
     948             :  having changed. it will change upon regdb_init, too, though.
     949             :  ***********************************************************************/
     950        1676 : int regdb_get_seqnum(void)
     951             : {
     952        1676 :         return dbwrap_get_seqnum(regdb);
     953             : }
     954             : 
     955             : 
     956         255 : static WERROR regdb_delete_key_with_prefix(struct db_context *db,
     957             :                                            const char *keyname,
     958             :                                            const char *prefix)
     959             : {
     960             :         char *path;
     961         255 :         WERROR werr = WERR_NOT_ENOUGH_MEMORY;
     962         255 :         TALLOC_CTX *mem_ctx = talloc_stackframe();
     963             : 
     964         255 :         if (keyname == NULL) {
     965           0 :                 werr = WERR_INVALID_PARAMETER;
     966           0 :                 goto done;
     967             :         }
     968             : 
     969         255 :         if (prefix == NULL) {
     970          67 :                 path = discard_const_p(char, keyname);
     971             :         } else {
     972         188 :                 path = talloc_asprintf(mem_ctx, "%s\\%s", prefix, keyname);
     973         188 :                 if (path == NULL) {
     974           0 :                         goto done;
     975             :                 }
     976             :         }
     977             : 
     978         255 :         path = normalize_reg_path(mem_ctx, path);
     979         255 :         if (path == NULL) {
     980           0 :                 goto done;
     981             :         }
     982             : 
     983         255 :         werr = ntstatus_to_werror(dbwrap_purge_bystring(db, path));
     984             : 
     985         255 : done:
     986         255 :         talloc_free(mem_ctx);
     987         255 :         return werr;
     988             : }
     989             : 
     990             : 
     991         121 : static WERROR regdb_delete_values(struct db_context *db, const char *keyname)
     992             : {
     993         121 :         return regdb_delete_key_with_prefix(db, keyname, REG_VALUE_PREFIX);
     994             : }
     995             : 
     996          67 : static WERROR regdb_delete_secdesc(struct db_context *db, const char *keyname)
     997             : {
     998          67 :         return regdb_delete_key_with_prefix(db, keyname, REG_SECDESC_PREFIX);
     999             : }
    1000             : 
    1001          67 : static WERROR regdb_delete_subkeylist(struct db_context *db, const char *keyname)
    1002             : {
    1003          67 :         return regdb_delete_key_with_prefix(db, keyname, NULL);
    1004             : }
    1005             : 
    1006             : 
    1007          67 : static WERROR regdb_delete_key_lists(struct db_context *db, const char *keyname)
    1008             : {
    1009             :         WERROR werr;
    1010             : 
    1011          67 :         werr = regdb_delete_values(db, keyname);
    1012          67 :         if (!W_ERROR_IS_OK(werr)) {
    1013           0 :                 DEBUG(1, (__location__ " Deleting %s\\%s failed: %s\n",
    1014             :                           REG_VALUE_PREFIX, keyname, win_errstr(werr)));
    1015           0 :                 goto done;
    1016             :         }
    1017             : 
    1018          67 :         werr = regdb_delete_secdesc(db, keyname);
    1019          67 :         if (!W_ERROR_IS_OK(werr)) {
    1020           0 :                 DEBUG(1, (__location__ " Deleting %s\\%s failed: %s\n",
    1021             :                           REG_SECDESC_PREFIX, keyname, win_errstr(werr)));
    1022           0 :                 goto done;
    1023             :         }
    1024             : 
    1025          67 :         werr = regdb_delete_subkeylist(db, keyname);
    1026          67 :         if (!W_ERROR_IS_OK(werr)) {
    1027           0 :                 DEBUG(1, (__location__ " Deleting %s failed: %s\n",
    1028             :                           keyname, win_errstr(werr)));
    1029           0 :                 goto done;
    1030             :         }
    1031             : 
    1032         134 : done:
    1033          67 :         return werr;
    1034             : }
    1035             : 
    1036             : /***********************************************************************
    1037             :  Add subkey strings to the registry tdb under a defined key
    1038             :  fmt is the same format as tdb_pack except this function only supports
    1039             :  fstrings
    1040             :  ***********************************************************************/
    1041             : 
    1042        4671 : static WERROR regdb_store_keys_internal2(struct db_context *db,
    1043             :                                          const char *key,
    1044             :                                          struct regsubkey_ctr *ctr)
    1045             : {
    1046             :         TDB_DATA dbuf;
    1047        4671 :         uint8_t *buffer = NULL;
    1048        4671 :         uint32_t i = 0;
    1049             :         uint32_t len, buflen;
    1050        4671 :         uint32_t num_subkeys = regsubkey_ctr_numkeys(ctr);
    1051        4671 :         char *keyname = NULL;
    1052        4671 :         TALLOC_CTX *ctx = talloc_stackframe();
    1053             :         WERROR werr;
    1054             : 
    1055        4671 :         if (!key) {
    1056           0 :                 werr = WERR_INVALID_PARAMETER;
    1057           0 :                 goto done;
    1058             :         }
    1059             : 
    1060        4671 :         keyname = talloc_strdup(ctx, key);
    1061        4671 :         if (!keyname) {
    1062           0 :                 werr = WERR_NOT_ENOUGH_MEMORY;
    1063           0 :                 goto done;
    1064             :         }
    1065             : 
    1066        4671 :         keyname = normalize_reg_path(ctx, keyname);
    1067        4671 :         if (!keyname) {
    1068           0 :                 werr = WERR_NOT_ENOUGH_MEMORY;
    1069           0 :                 goto done;
    1070             :         }
    1071             : 
    1072             :         /* allocate some initial memory */
    1073             : 
    1074        4671 :         buffer = (uint8_t *)SMB_MALLOC(1024);
    1075        4671 :         if (buffer == NULL) {
    1076           0 :                 werr = WERR_NOT_ENOUGH_MEMORY;
    1077           0 :                 goto done;
    1078             :         }
    1079        4671 :         buflen = 1024;
    1080        4671 :         len = 0;
    1081             : 
    1082             :         /* store the number of subkeys */
    1083             : 
    1084        4671 :         len += tdb_pack(buffer+len, buflen-len, "d", num_subkeys);
    1085             : 
    1086             :         /* pack all the strings */
    1087             : 
    1088        8495 :         for (i=0; i<num_subkeys; i++) {
    1089             :                 size_t thistime;
    1090             : 
    1091        3824 :                 thistime = tdb_pack(buffer+len, buflen-len, "f",
    1092             :                                     regsubkey_ctr_specific_key(ctr, i));
    1093        3824 :                 if (len+thistime > buflen) {
    1094             :                         size_t thistime2;
    1095             :                         /*
    1096             :                          * tdb_pack hasn't done anything because of the short
    1097             :                          * buffer, allocate extra space.
    1098             :                          */
    1099           0 :                         buffer = SMB_REALLOC_ARRAY(buffer, uint8_t,
    1100             :                                                    (len+thistime)*2);
    1101           0 :                         if(buffer == NULL) {
    1102           0 :                                 DEBUG(0, ("regdb_store_keys: Failed to realloc "
    1103             :                                           "memory of size [%u]\n",
    1104             :                                           (unsigned int)(len+thistime)*2));
    1105           0 :                                 werr = WERR_NOT_ENOUGH_MEMORY;
    1106           0 :                                 goto done;
    1107             :                         }
    1108           0 :                         buflen = (len+thistime)*2;
    1109           0 :                         thistime2 = tdb_pack(
    1110           0 :                                 buffer+len, buflen-len, "f",
    1111             :                                 regsubkey_ctr_specific_key(ctr, i));
    1112           0 :                         if (thistime2 != thistime) {
    1113           0 :                                 DEBUG(0, ("tdb_pack failed\n"));
    1114           0 :                                 werr = WERR_CAN_NOT_COMPLETE;
    1115           0 :                                 goto done;
    1116             :                         }
    1117             :                 }
    1118        3824 :                 len += thistime;
    1119             :         }
    1120             : 
    1121             :         /* finally write out the data */
    1122             : 
    1123        4671 :         dbuf.dptr = buffer;
    1124        4671 :         dbuf.dsize = len;
    1125        4671 :         werr = ntstatus_to_werror(dbwrap_store_bystring(db, keyname, dbuf,
    1126             :                                                         TDB_REPLACE));
    1127             : 
    1128        4671 : done:
    1129        4671 :         TALLOC_FREE(ctx);
    1130        4671 :         SAFE_FREE(buffer);
    1131        4671 :         return werr;
    1132             : }
    1133             : 
    1134             : /**
    1135             :  * Utility function to store a new empty list of
    1136             :  * subkeys of given key specified as parent and subkey name
    1137             :  * (thereby creating the key).
    1138             :  * If the parent keyname is NULL, then the "subkey" is
    1139             :  * interpreted as a base key.
    1140             :  * If the subkey list does already exist, it is not modified.
    1141             :  *
    1142             :  * Must be called from within a transaction.
    1143             :  */
    1144        3328 : static WERROR regdb_store_subkey_list(struct db_context *db, const char *parent,
    1145             :                                       const char *key)
    1146             : {
    1147             :         WERROR werr;
    1148        3328 :         char *path = NULL;
    1149        3328 :         struct regsubkey_ctr *subkeys = NULL;
    1150        3328 :         TALLOC_CTX *frame = talloc_stackframe();
    1151             : 
    1152        3328 :         if (parent == NULL) {
    1153        1140 :                 path = talloc_strdup(frame, key);
    1154             :         } else {
    1155        2188 :                 path = talloc_asprintf(frame, "%s\\%s", parent, key);
    1156             :         }
    1157        3328 :         if (!path) {
    1158           0 :                 werr = WERR_NOT_ENOUGH_MEMORY;
    1159           0 :                 goto done;
    1160             :         }
    1161             : 
    1162        3328 :         werr = regsubkey_ctr_init(frame, &subkeys);
    1163        3328 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1164             : 
    1165        3328 :         werr = regdb_fetch_keys_internal(db, path, subkeys);
    1166        3328 :         if (W_ERROR_IS_OK(werr)) {
    1167             :                 /* subkey list exists already - don't modify */
    1168         912 :                 goto done;
    1169             :         }
    1170             : 
    1171        2416 :         werr = regsubkey_ctr_reinit(subkeys);
    1172        2416 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1173             : 
    1174             :         /* create a record with 0 subkeys */
    1175        2416 :         werr = regdb_store_keys_internal2(db, path, subkeys);
    1176        2416 :         if (!W_ERROR_IS_OK(werr)) {
    1177           0 :                 DEBUG(0, ("regdb_store_keys: Failed to store new record for "
    1178             :                           "key [%s]: %s\n", path, win_errstr(werr)));
    1179           0 :                 goto done;
    1180             :         }
    1181             : 
    1182        5667 : done:
    1183        3328 :         talloc_free(frame);
    1184        3328 :         return werr;
    1185             : }
    1186             : 
    1187             : /***********************************************************************
    1188             :  Store the new subkey record and create any child key records that
    1189             :  do not currently exist
    1190             :  ***********************************************************************/
    1191             : 
    1192             : struct regdb_store_keys_context {
    1193             :         const char *key;
    1194             :         struct regsubkey_ctr *ctr;
    1195             : };
    1196             : 
    1197           0 : static NTSTATUS regdb_store_keys_action(struct db_context *db,
    1198             :                                         void *private_data)
    1199             : {
    1200             :         struct regdb_store_keys_context *store_ctx;
    1201             :         WERROR werr;
    1202             :         int num_subkeys, i;
    1203           0 :         char *path = NULL;
    1204           0 :         struct regsubkey_ctr *old_subkeys = NULL;
    1205           0 :         char *oldkeyname = NULL;
    1206           0 :         TALLOC_CTX *mem_ctx = talloc_stackframe();
    1207             : 
    1208           0 :         store_ctx = (struct regdb_store_keys_context *)private_data;
    1209             : 
    1210             :         /*
    1211             :          * Re-fetch the old keys inside the transaction
    1212             :          */
    1213             : 
    1214           0 :         werr = regsubkey_ctr_init(mem_ctx, &old_subkeys);
    1215           0 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1216             : 
    1217           0 :         werr = regdb_fetch_keys_internal(db, store_ctx->key, old_subkeys);
    1218           0 :         if (!W_ERROR_IS_OK(werr) &&
    1219           0 :             !W_ERROR_EQUAL(werr, WERR_NOT_FOUND))
    1220             :         {
    1221           0 :                 goto done;
    1222             :         }
    1223             : 
    1224             :         /*
    1225             :          * Make the store operation as safe as possible without transactions:
    1226             :          *
    1227             :          * (1) For each subkey removed from ctr compared with old_subkeys:
    1228             :          *
    1229             :          *     (a) First delete the value db entry.
    1230             :          *
    1231             :          *     (b) Next delete the secdesc db record.
    1232             :          *
    1233             :          *     (c) Then delete the subkey list entry.
    1234             :          *
    1235             :          * (2) Now write the list of subkeys of the parent key,
    1236             :          *     deleting removed entries and adding new ones.
    1237             :          *
    1238             :          * (3) Finally create the subkey list entries for the added keys.
    1239             :          *
    1240             :          * This way if we crash half-way in between deleting the subkeys
    1241             :          * and storing the parent's list of subkeys, no old data can pop up
    1242             :          * out of the blue when re-adding keys later on.
    1243             :          */
    1244             : 
    1245             :         /* (1) delete removed keys' lists (values/secdesc/subkeys) */
    1246             : 
    1247           0 :         num_subkeys = regsubkey_ctr_numkeys(old_subkeys);
    1248           0 :         for (i=0; i<num_subkeys; i++) {
    1249           0 :                 oldkeyname = regsubkey_ctr_specific_key(old_subkeys, i);
    1250             : 
    1251           0 :                 if (regsubkey_ctr_key_exists(store_ctx->ctr, oldkeyname)) {
    1252             :                         /*
    1253             :                          * It's still around, don't delete
    1254             :                          */
    1255           0 :                         continue;
    1256             :                 }
    1257             : 
    1258           0 :                 path = talloc_asprintf(mem_ctx, "%s\\%s", store_ctx->key,
    1259             :                                        oldkeyname);
    1260           0 :                 if (!path) {
    1261           0 :                         werr = WERR_NOT_ENOUGH_MEMORY;
    1262           0 :                         goto done;
    1263             :                 }
    1264             : 
    1265           0 :                 werr = regdb_delete_key_lists(db, path);
    1266           0 :                 W_ERROR_NOT_OK_GOTO_DONE(werr);
    1267             : 
    1268           0 :                 TALLOC_FREE(path);
    1269             :         }
    1270             : 
    1271           0 :         TALLOC_FREE(old_subkeys);
    1272             : 
    1273             :         /* (2) store the subkey list for the parent */
    1274             : 
    1275           0 :         werr = regdb_store_keys_internal2(db, store_ctx->key, store_ctx->ctr);
    1276           0 :         if (!W_ERROR_IS_OK(werr)) {
    1277           0 :                 DEBUG(0,("regdb_store_keys: Failed to store new subkey list "
    1278             :                          "for parent [%s]: %s\n", store_ctx->key,
    1279             :                          win_errstr(werr)));
    1280           0 :                 goto done;
    1281             :         }
    1282             : 
    1283             :         /* (3) now create records for any subkeys that don't already exist */
    1284             : 
    1285           0 :         num_subkeys = regsubkey_ctr_numkeys(store_ctx->ctr);
    1286             : 
    1287           0 :         for (i=0; i<num_subkeys; i++) {
    1288             :                 const char *subkey;
    1289             : 
    1290           0 :                 subkey = regsubkey_ctr_specific_key(store_ctx->ctr, i);
    1291             : 
    1292           0 :                 werr = regdb_store_subkey_list(db, store_ctx->key, subkey);
    1293           0 :                 W_ERROR_NOT_OK_GOTO_DONE(werr);
    1294             :         }
    1295             : 
    1296             :         /*
    1297             :          * Update the seqnum in the container to possibly
    1298             :          * prevent next read from going to disk
    1299             :          */
    1300           0 :         werr = regsubkey_ctr_set_seqnum(store_ctx->ctr, dbwrap_get_seqnum(db));
    1301             : 
    1302           0 : done:
    1303           0 :         talloc_free(mem_ctx);
    1304           0 :         return werror_to_ntstatus(werr);
    1305             : }
    1306             : 
    1307           0 : static bool regdb_store_keys_internal(struct db_context *db, const char *key,
    1308             :                                       struct regsubkey_ctr *ctr)
    1309             : {
    1310             :         int num_subkeys, old_num_subkeys, i;
    1311           0 :         struct regsubkey_ctr *old_subkeys = NULL;
    1312           0 :         TALLOC_CTX *ctx = talloc_stackframe();
    1313             :         WERROR werr;
    1314           0 :         bool ret = false;
    1315             :         struct regdb_store_keys_context store_ctx;
    1316             : 
    1317           0 :         if (!regdb_key_exists(db, key)) {
    1318           0 :                 goto done;
    1319             :         }
    1320             : 
    1321             :         /*
    1322             :          * fetch a list of the old subkeys so we can determine if anything has
    1323             :          * changed
    1324             :          */
    1325             : 
    1326           0 :         werr = regsubkey_ctr_init(ctx, &old_subkeys);
    1327           0 :         if (!W_ERROR_IS_OK(werr)) {
    1328           0 :                 DEBUG(0,("regdb_store_keys: talloc() failure!\n"));
    1329           0 :                 goto done;
    1330             :         }
    1331             : 
    1332           0 :         werr = regdb_fetch_keys_internal(db, key, old_subkeys);
    1333           0 :         if (!W_ERROR_IS_OK(werr) &&
    1334           0 :             !W_ERROR_EQUAL(werr, WERR_NOT_FOUND))
    1335             :         {
    1336           0 :                 goto done;
    1337             :         }
    1338             : 
    1339           0 :         num_subkeys = regsubkey_ctr_numkeys(ctr);
    1340           0 :         old_num_subkeys = regsubkey_ctr_numkeys(old_subkeys);
    1341           0 :         if ((num_subkeys && old_num_subkeys) &&
    1342             :             (num_subkeys == old_num_subkeys)) {
    1343             : 
    1344           0 :                 for (i = 0; i < num_subkeys; i++) {
    1345           0 :                         if (strcmp(regsubkey_ctr_specific_key(ctr, i),
    1346           0 :                                    regsubkey_ctr_specific_key(old_subkeys, i))
    1347             :                             != 0)
    1348             :                         {
    1349           0 :                                 break;
    1350             :                         }
    1351             :                 }
    1352           0 :                 if (i == num_subkeys) {
    1353             :                         /*
    1354             :                          * Nothing changed, no point to even start a tdb
    1355             :                          * transaction
    1356             :                          */
    1357             : 
    1358           0 :                         ret = true;
    1359           0 :                         goto done;
    1360             :                 }
    1361             :         }
    1362             : 
    1363           0 :         TALLOC_FREE(old_subkeys);
    1364             : 
    1365           0 :         store_ctx.key = key;
    1366           0 :         store_ctx.ctr = ctr;
    1367             : 
    1368           0 :         werr = regdb_trans_do(db,
    1369             :                               regdb_store_keys_action,
    1370             :                               &store_ctx);
    1371             : 
    1372           0 :         ret = W_ERROR_IS_OK(werr);
    1373             : 
    1374           0 : done:
    1375           0 :         TALLOC_FREE(ctx);
    1376             : 
    1377           0 :         return ret;
    1378             : }
    1379             : 
    1380           0 : static bool regdb_store_keys(const char *key, struct regsubkey_ctr *ctr)
    1381             : {
    1382           0 :         return regdb_store_keys_internal(regdb, key, ctr);
    1383             : }
    1384             : 
    1385             : /**
    1386             :  * create a subkey of a given key
    1387             :  */
    1388             : 
    1389             : struct regdb_create_subkey_context {
    1390             :         const char *key;
    1391             :         const char *subkey;
    1392             : };
    1393             : 
    1394        2188 : static NTSTATUS regdb_create_subkey_action(struct db_context *db,
    1395             :                                            void *private_data)
    1396             : {
    1397             :         WERROR werr;
    1398             :         struct regdb_create_subkey_context *create_ctx;
    1399             :         struct regsubkey_ctr *subkeys;
    1400        2188 :         TALLOC_CTX *mem_ctx = talloc_stackframe();
    1401             : 
    1402        2188 :         create_ctx = (struct regdb_create_subkey_context *)private_data;
    1403             : 
    1404        2188 :         werr = regsubkey_ctr_init(mem_ctx, &subkeys);
    1405        2188 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1406             : 
    1407        2188 :         werr = regdb_fetch_keys_internal(db, create_ctx->key, subkeys);
    1408        2188 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1409             : 
    1410        2188 :         werr = regsubkey_ctr_addkey(subkeys, create_ctx->subkey);
    1411        2188 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1412             : 
    1413        2188 :         werr = regdb_store_keys_internal2(db, create_ctx->key, subkeys);
    1414        2188 :         if (!W_ERROR_IS_OK(werr)) {
    1415           0 :                 DEBUG(0, (__location__ " failed to store new subkey list for "
    1416             :                          "parent key %s: %s\n", create_ctx->key,
    1417             :                          win_errstr(werr)));
    1418             :         }
    1419             : 
    1420        2188 :         werr = regdb_store_subkey_list(db, create_ctx->key, create_ctx->subkey);
    1421             : 
    1422        2188 : done:
    1423        2188 :         talloc_free(mem_ctx);
    1424        2188 :         return werror_to_ntstatus(werr);
    1425             : }
    1426             : 
    1427        4886 : static WERROR regdb_create_subkey_internal(struct db_context *db,
    1428             :                                            const char *key,
    1429             :                                            const char *subkey)
    1430             : {
    1431             :         WERROR werr;
    1432             :         struct regsubkey_ctr *subkeys;
    1433        4886 :         TALLOC_CTX *mem_ctx = talloc_stackframe();
    1434             :         struct regdb_create_subkey_context create_ctx;
    1435             : 
    1436        4886 :         if (!regdb_key_exists(db, key)) {
    1437           0 :                 werr = WERR_NOT_FOUND;
    1438           0 :                 goto done;
    1439             :         }
    1440             : 
    1441        4886 :         werr = regsubkey_ctr_init(mem_ctx, &subkeys);
    1442        4886 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1443             : 
    1444        4886 :         werr = regdb_fetch_keys_internal(db, key, subkeys);
    1445        4886 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1446             : 
    1447        4886 :         if (regsubkey_ctr_key_exists(subkeys, subkey)) {
    1448             :                 char *newkey;
    1449             : 
    1450        2698 :                 newkey = talloc_asprintf(mem_ctx, "%s\\%s", key, subkey);
    1451        2698 :                 if (newkey == NULL) {
    1452           0 :                         werr = WERR_NOT_ENOUGH_MEMORY;
    1453           0 :                         goto done;
    1454             :                 }
    1455             : 
    1456        2698 :                 if (regdb_key_exists(db, newkey)) {
    1457        2698 :                         werr = WERR_OK;
    1458        2698 :                         goto done;
    1459             :                 }
    1460             :         }
    1461             : 
    1462        2188 :         talloc_free(subkeys);
    1463             : 
    1464        2188 :         create_ctx.key = key;
    1465        2188 :         create_ctx.subkey = subkey;
    1466             : 
    1467        2188 :         werr = regdb_trans_do(db,
    1468             :                               regdb_create_subkey_action,
    1469             :                               &create_ctx);
    1470             : 
    1471        4886 : done:
    1472        4886 :         talloc_free(mem_ctx);
    1473        4886 :         return werr;
    1474             : }
    1475             : 
    1476         250 : static WERROR regdb_create_subkey(const char *key, const char *subkey)
    1477             : {
    1478         250 :         return regdb_create_subkey_internal(regdb, key, subkey);
    1479             : }
    1480             : 
    1481             : /**
    1482             :  * create a base key
    1483             :  */
    1484             : 
    1485             : struct regdb_create_basekey_context {
    1486             :         const char *key;
    1487             : };
    1488             : 
    1489        1140 : static NTSTATUS regdb_create_basekey_action(struct db_context *db,
    1490             :                                             void *private_data)
    1491             : {
    1492             :         WERROR werr;
    1493             :         struct regdb_create_basekey_context *create_ctx;
    1494             : 
    1495        1140 :         create_ctx = (struct regdb_create_basekey_context *)private_data;
    1496             : 
    1497        1140 :         werr = regdb_store_subkey_list(db, NULL, create_ctx->key);
    1498             : 
    1499        1140 :         return werror_to_ntstatus(werr);
    1500             : }
    1501             : 
    1502        1140 : static WERROR regdb_create_basekey(struct db_context *db, const char *key)
    1503             : {
    1504             :         WERROR werr;
    1505             :         struct regdb_create_subkey_context create_ctx;
    1506             : 
    1507        1140 :         create_ctx.key = key;
    1508             : 
    1509        1140 :         werr = regdb_trans_do(db,
    1510             :                               regdb_create_basekey_action,
    1511             :                               &create_ctx);
    1512             : 
    1513        1140 :         return werr;
    1514             : }
    1515             : 
    1516             : /**
    1517             :  * create a subkey of a given key
    1518             :  */
    1519             : 
    1520             : struct regdb_delete_subkey_context {
    1521             :         const char *key;
    1522             :         const char *subkey;
    1523             :         const char *path;
    1524             :         bool lazy;
    1525             : };
    1526             : 
    1527          67 : static NTSTATUS regdb_delete_subkey_action(struct db_context *db,
    1528             :                                            void *private_data)
    1529             : {
    1530             :         WERROR werr;
    1531             :         struct regdb_delete_subkey_context *delete_ctx;
    1532             :         struct regsubkey_ctr *subkeys;
    1533          67 :         TALLOC_CTX *mem_ctx = talloc_stackframe();
    1534             : 
    1535          67 :         delete_ctx = (struct regdb_delete_subkey_context *)private_data;
    1536             : 
    1537          67 :         werr = regdb_delete_key_lists(db, delete_ctx->path);
    1538          67 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1539             : 
    1540          67 :         if (delete_ctx->lazy) {
    1541           0 :                 goto done;
    1542             :         }
    1543             : 
    1544          67 :         werr = regsubkey_ctr_init(mem_ctx, &subkeys);
    1545          67 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1546             : 
    1547          67 :         werr = regdb_fetch_keys_internal(db, delete_ctx->key, subkeys);
    1548          67 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1549             : 
    1550          67 :         werr = regsubkey_ctr_delkey(subkeys, delete_ctx->subkey);
    1551          67 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1552             : 
    1553          67 :         werr = regdb_store_keys_internal2(db, delete_ctx->key, subkeys);
    1554          67 :         if (!W_ERROR_IS_OK(werr)) {
    1555           0 :                 DEBUG(0, (__location__ " failed to store new subkey_list for "
    1556             :                          "parent key %s: %s\n", delete_ctx->key,
    1557             :                          win_errstr(werr)));
    1558             :         }
    1559             : 
    1560         134 : done:
    1561          67 :         talloc_free(mem_ctx);
    1562          67 :         return werror_to_ntstatus(werr);
    1563             : }
    1564             : 
    1565          67 : static WERROR regdb_delete_subkey(const char *key, const char *subkey, bool lazy)
    1566             : {
    1567             :         WERROR werr;
    1568             :         char *path;
    1569             :         struct regdb_delete_subkey_context delete_ctx;
    1570          67 :         TALLOC_CTX *mem_ctx = talloc_stackframe();
    1571             : 
    1572          67 :         if (!regdb_key_exists(regdb, key)) {
    1573           0 :                 werr = WERR_NOT_FOUND;
    1574           0 :                 goto done;
    1575             :         }
    1576             : 
    1577          67 :         path = talloc_asprintf(mem_ctx, "%s\\%s", key, subkey);
    1578          67 :         if (path == NULL) {
    1579           0 :                 werr = WERR_NOT_ENOUGH_MEMORY;
    1580           0 :                 goto done;
    1581             :         }
    1582             : 
    1583          67 :         if (!regdb_key_exists(regdb, path)) {
    1584           0 :                 werr = WERR_OK;
    1585           0 :                 goto done;
    1586             :         }
    1587             : 
    1588          67 :         delete_ctx.key = key;
    1589          67 :         delete_ctx.subkey = subkey;
    1590          67 :         delete_ctx.path = path;
    1591          67 :         delete_ctx.lazy = lazy;
    1592             : 
    1593          67 :         werr = regdb_trans_do(regdb,
    1594             :                               regdb_delete_subkey_action,
    1595             :                               &delete_ctx);
    1596             : 
    1597          67 : done:
    1598          67 :         talloc_free(mem_ctx);
    1599          67 :         return werr;
    1600             : }
    1601             : 
    1602      227912 : static TDB_DATA regdb_fetch_key_internal(struct db_context *db,
    1603             :                                          TALLOC_CTX *mem_ctx, const char *key)
    1604             : {
    1605      227912 :         char *path = NULL;
    1606             :         TDB_DATA data;
    1607             :         NTSTATUS status;
    1608             : 
    1609      227912 :         path = normalize_reg_path(mem_ctx, key);
    1610      227912 :         if (!path) {
    1611           0 :                 return make_tdb_data(NULL, 0);
    1612             :         }
    1613             : 
    1614      227912 :         status = dbwrap_fetch_bystring(db, mem_ctx, path, &data);
    1615      227912 :         if (!NT_STATUS_IS_OK(status)) {
    1616      191971 :                 data = tdb_null;
    1617             :         }
    1618             : 
    1619      227912 :         TALLOC_FREE(path);
    1620      227912 :         return data;
    1621             : }
    1622             : 
    1623             : 
    1624             : /**
    1625             :  * Check for the existence of a key.
    1626             :  *
    1627             :  * Existence of a key is authoritatively defined by
    1628             :  * the existence of the record that contains the list
    1629             :  * of its subkeys.
    1630             :  *
    1631             :  * Return false, if the record does not match the correct
    1632             :  * structure of an initial 4-byte counter and then a
    1633             :  * list of the corresponding number of zero-terminated
    1634             :  * strings.
    1635             :  */
    1636      216166 : static bool regdb_key_exists(struct db_context *db, const char *key)
    1637             : {
    1638      216166 :         TALLOC_CTX *mem_ctx = talloc_stackframe();
    1639             :         TDB_DATA value;
    1640      216166 :         bool ret = false;
    1641             :         char *path;
    1642             :         uint32_t buflen;
    1643             :         const char *buf;
    1644             :         uint32_t num_items, i;
    1645             :         int32_t len;
    1646             : 
    1647      216166 :         if (key == NULL) {
    1648           0 :                 goto done;
    1649             :         }
    1650             : 
    1651      216166 :         path = normalize_reg_path(mem_ctx, key);
    1652      216166 :         if (path == NULL) {
    1653           0 :                 DEBUG(0, ("out of memory! (talloc failed)\n"));
    1654           0 :                 goto done;
    1655             :         }
    1656             : 
    1657      216166 :         if (*path == '\0') {
    1658           0 :                 goto done;
    1659             :         }
    1660             : 
    1661      216166 :         value = regdb_fetch_key_internal(db, mem_ctx, path);
    1662      216166 :         if (value.dptr == NULL) {
    1663      191614 :                 goto done;
    1664             :         }
    1665             : 
    1666       24552 :         if (value.dsize == 0) {
    1667           0 :                 DEBUG(10, ("regdb_key_exists: subkeylist-record for key "
    1668             :                           "[%s] is empty: Could be a deleted record in a "
    1669             :                           "clustered (ctdb) environment?\n",
    1670             :                           path));
    1671           0 :                 goto done;
    1672             :         }
    1673             : 
    1674       24552 :         len = tdb_unpack(value.dptr, value.dsize, "d", &num_items);
    1675       24552 :         if (len == (int32_t)-1) {
    1676           0 :                 DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record for key "
    1677             :                           "[%s] is invalid: Could not parse initial 4-byte "
    1678             :                           "counter. record data length is %u.\n",
    1679             :                           path, (unsigned int)value.dsize));
    1680           0 :                 goto done;
    1681             :         }
    1682             : 
    1683             :         /*
    1684             :          * Note: the tdb_unpack check above implies that len <= value.dsize
    1685             :          */
    1686       24552 :         buflen = value.dsize - len;
    1687       24552 :         buf = (const char *)value.dptr + len;
    1688             : 
    1689       50091 :         for (i = 0; i < num_items; i++) {
    1690       25539 :                 if (buflen == 0) {
    1691           0 :                         break;
    1692             :                 }
    1693       25539 :                 len = strnlen(buf, buflen) + 1;
    1694       25539 :                 if (buflen < len) {
    1695           0 :                         DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record "
    1696             :                                   "for key [%s] is corrupt: %u items expected, "
    1697             :                                   "item number %u is not zero terminated.\n",
    1698             :                                   path, num_items, i+1));
    1699           0 :                         goto done;
    1700             :                 }
    1701             : 
    1702       25539 :                 buf += len;
    1703       25539 :                 buflen -= len;
    1704             :         }
    1705             : 
    1706       24552 :         if (buflen > 0) {
    1707           0 :                 DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record for key "
    1708             :                           "[%s] is corrupt: %u items expected and found, but "
    1709             :                           "the record contains additional %u bytes\n",
    1710             :                           path, num_items, buflen));
    1711           0 :                 goto done;
    1712             :         }
    1713             : 
    1714       24552 :         if (i < num_items) {
    1715           0 :                 DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record for key "
    1716             :                           "[%s] is corrupt: %u items expected, but only %u "
    1717             :                           "items found.\n",
    1718             :                           path, num_items, i+1));
    1719           0 :                 goto done;
    1720             :         }
    1721             : 
    1722       24552 :         ret = true;
    1723             : 
    1724      216166 : done:
    1725      216166 :         TALLOC_FREE(mem_ctx);
    1726      216166 :         return ret;
    1727             : }
    1728             : 
    1729             : 
    1730             : /***********************************************************************
    1731             :  Retrieve an array of strings containing subkeys.  Memory should be
    1732             :  released by the caller.
    1733             :  ***********************************************************************/
    1734             : 
    1735      201158 : static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key,
    1736             :                                         struct regsubkey_ctr *ctr)
    1737             : {
    1738             :         WERROR werr;
    1739             :         uint32_t num_items;
    1740             :         uint8_t *buf;
    1741             :         uint32_t buflen, len;
    1742             :         uint32_t i;
    1743             :         fstring subkeyname;
    1744      201158 :         TALLOC_CTX *frame = talloc_stackframe();
    1745             :         TDB_DATA value;
    1746             :         int seqnum[2], count;
    1747             : 
    1748      201158 :         DEBUG(11,("regdb_fetch_keys: Enter key => [%s]\n", key ? key : "NULL"));
    1749             : 
    1750      201158 :         if (!regdb_key_exists(db, key)) {
    1751      190436 :                 DEBUG(10, ("key [%s] not found\n", key));
    1752      190436 :                 werr = WERR_NOT_FOUND;
    1753      190436 :                 goto done;
    1754             :         }
    1755             : 
    1756       10722 :         werr = regsubkey_ctr_reinit(ctr);
    1757       10722 :         W_ERROR_NOT_OK_GOTO_DONE(werr);
    1758             : 
    1759       10722 :         count = 0;
    1760       10722 :         ZERO_STRUCT(value);
    1761       10722 :         seqnum[0] = dbwrap_get_seqnum(db);
    1762             : 
    1763             :         do {
    1764       10722 :                 count++;
    1765       10722 :                 TALLOC_FREE(value.dptr);
    1766       10722 :                 value = regdb_fetch_key_internal(db, frame, key);
    1767       10722 :                 seqnum[count % 2] = dbwrap_get_seqnum(db);
    1768             : 
    1769       10722 :         } while (seqnum[0] != seqnum[1]);
    1770             : 
    1771       10722 :         if (count > 1) {
    1772           0 :                 DEBUG(5, ("regdb_fetch_keys_internal: it took %d attempts to "
    1773             :                           "fetch key '%s' with constant seqnum\n",
    1774             :                           count, key));
    1775             :         }
    1776             : 
    1777       10722 :         werr = regsubkey_ctr_set_seqnum(ctr, seqnum[0]);
    1778       10722 :         if (!W_ERROR_IS_OK(werr)) {
    1779           0 :                 goto done;
    1780             :         }
    1781             : 
    1782       10722 :         if (value.dsize == 0 || value.dptr == NULL) {
    1783           0 :                 DEBUG(10, ("regdb_fetch_keys: no subkeys found for key [%s]\n",
    1784             :                            key));
    1785           0 :                 goto done;
    1786             :         }
    1787             : 
    1788       10722 :         buf = value.dptr;
    1789       10722 :         buflen = value.dsize;
    1790       10722 :         len = tdb_unpack( buf, buflen, "d", &num_items);
    1791       10722 :         if (len == (uint32_t)-1) {
    1792           0 :                 werr = WERR_NOT_FOUND;
    1793           0 :                 goto done;
    1794             :         }
    1795             : 
    1796       24782 :         for (i=0; i<num_items; i++) {
    1797             :                 int this_len;
    1798             : 
    1799       14060 :                 this_len = tdb_unpack(buf+len, buflen-len, "f", subkeyname);
    1800       14060 :                 if (this_len == -1) {
    1801           0 :                         DBG_WARNING("Invalid registry data, "
    1802             :                                     "tdb_unpack failed\n");
    1803           0 :                         werr = WERR_INTERNAL_DB_CORRUPTION;
    1804           0 :                         goto done;
    1805             :                 }
    1806       14060 :                 len += this_len;
    1807       14060 :                 if (len < this_len) {
    1808           0 :                         DBG_WARNING("Invalid registry data, "
    1809             :                                     "integer overflow\n");
    1810           0 :                         werr = WERR_INTERNAL_DB_CORRUPTION;
    1811           0 :                         goto done;
    1812             :                 }
    1813             : 
    1814       14060 :                 werr = regsubkey_ctr_addkey(ctr, subkeyname);
    1815       14060 :                 if (!W_ERROR_IS_OK(werr)) {
    1816           0 :                         DEBUG(5, ("regdb_fetch_keys: regsubkey_ctr_addkey "
    1817             :                                   "failed: %s\n", win_errstr(werr)));
    1818           0 :                         num_items = 0;
    1819           0 :                         goto done;
    1820             :                 }
    1821             :         }
    1822             : 
    1823       10722 :         DEBUG(11,("regdb_fetch_keys: Exit [%d] items\n", num_items));
    1824             : 
    1825      201158 : done:
    1826      201158 :         TALLOC_FREE(frame);
    1827      201158 :         return werr;
    1828             : }
    1829             : 
    1830      190689 : static int regdb_fetch_keys(const char *key, struct regsubkey_ctr *ctr)
    1831             : {
    1832             :         WERROR werr;
    1833             : 
    1834      190689 :         werr = regdb_fetch_keys_internal(regdb, key, ctr);
    1835      190689 :         if (!W_ERROR_IS_OK(werr)) {
    1836      188020 :                 return -1;
    1837             :         }
    1838             : 
    1839        2669 :         return regsubkey_ctr_numkeys(ctr);
    1840             : }
    1841             : 
    1842             : /****************************************************************************
    1843             :  Unpack a list of registry values frem the TDB
    1844             :  ***************************************************************************/
    1845             : 
    1846         667 : static int regdb_unpack_values(struct regval_ctr *values,
    1847             :                                uint8_t *buf,
    1848             :                                size_t buflen)
    1849             : {
    1850             :         int this_len;
    1851         667 :         size_t          len = 0;
    1852             :         uint32_t        type;
    1853             :         fstring valuename;
    1854             :         uint32_t        size;
    1855             :         uint8_t         *data_p;
    1856         667 :         uint32_t        num_values = 0;
    1857             :         uint32_t        i;
    1858             : 
    1859             :         /* loop and unpack the rest of the registry values */
    1860             : 
    1861         667 :         this_len = tdb_unpack(buf, buflen, "d", &num_values);
    1862         667 :         if (this_len == -1) {
    1863           0 :                 DBG_WARNING("Invalid registry data, "
    1864             :                             "tdb_unpack failed\n");
    1865           0 :                 return -1;
    1866             :         }
    1867         667 :         len = this_len;
    1868             : 
    1869        1888 :         for ( i=0; i<num_values; i++ ) {
    1870             :                 /* unpack the next regval */
    1871             : 
    1872        1221 :                 type = REG_NONE;
    1873        1221 :                 size = 0;
    1874        1221 :                 data_p = NULL;
    1875        1221 :                 valuename[0] = '\0';
    1876        1221 :                 this_len = tdb_unpack(buf+len, buflen-len, "fdB",
    1877             :                                       valuename,
    1878             :                                       &type,
    1879             :                                       &size,
    1880             :                                       &data_p);
    1881        1221 :                 if (this_len == -1) {
    1882           0 :                         DBG_WARNING("Invalid registry data, "
    1883             :                                     "tdb_unpack failed\n");
    1884           0 :                         return -1;
    1885             :                 }
    1886        1221 :                 len += this_len;
    1887        1221 :                 if (len < (size_t)this_len) {
    1888           0 :                         DBG_WARNING("Invalid registry data, "
    1889             :                                     "integer overflow\n");
    1890           0 :                         return -1;
    1891             :                 }
    1892             : 
    1893        1221 :                 regval_ctr_addvalue(values, valuename, type,
    1894             :                                 (uint8_t *)data_p, size);
    1895        1221 :                 SAFE_FREE(data_p); /* 'B' option to tdb_unpack does a malloc() */
    1896             : 
    1897        1221 :                 DEBUG(10, ("regdb_unpack_values: value[%d]: name[%s] len[%d]\n",
    1898             :                            i, valuename, size));
    1899             :         }
    1900             : 
    1901         667 :         return len;
    1902             : }
    1903             : 
    1904             : /****************************************************************************
    1905             :  Pack all values in all printer keys
    1906             :  ***************************************************************************/
    1907             : 
    1908        1960 : static int regdb_pack_values(struct regval_ctr *values, uint8_t *buf, int buflen)
    1909             : {
    1910        1960 :         int             len = 0;
    1911             :         int             i;
    1912             :         struct regval_blob      *val;
    1913             :         int             num_values;
    1914             : 
    1915        1960 :         if ( !values )
    1916           0 :                 return 0;
    1917             : 
    1918        1960 :         num_values = regval_ctr_numvals( values );
    1919             : 
    1920             :         /* pack the number of values first */
    1921             : 
    1922        1960 :         len += tdb_pack( buf+len, buflen-len, "d", num_values );
    1923             : 
    1924             :         /* loop over all values */
    1925             : 
    1926        7586 :         for ( i=0; i<num_values; i++ ) {
    1927        5626 :                 val = regval_ctr_specific_value( values, i );
    1928        5626 :                 len += tdb_pack(buf+len, buflen-len, "fdB",
    1929             :                                 regval_name(val),
    1930             :                                 regval_type(val),
    1931             :                                 regval_size(val),
    1932             :                                 regval_data_p(val) );
    1933             :         }
    1934             : 
    1935        1960 :         return len;
    1936             : }
    1937             : 
    1938             : /***********************************************************************
    1939             :  Retrieve an array of strings containing subkeys.  Memory should be
    1940             :  released by the caller.
    1941             :  ***********************************************************************/
    1942             : 
    1943        1024 : static int regdb_fetch_values_internal(struct db_context *db, const char* key,
    1944             :                                        struct regval_ctr *values)
    1945             : {
    1946        1024 :         char *keystr = NULL;
    1947        1024 :         TALLOC_CTX *ctx = talloc_stackframe();
    1948        1024 :         int ret = 0;
    1949             :         TDB_DATA value;
    1950             :         WERROR werr;
    1951             :         int seqnum[2], count;
    1952             : 
    1953        1024 :         DEBUG(10,("regdb_fetch_values: Looking for values of key [%s]\n", key));
    1954             : 
    1955        1024 :         if (!regdb_key_exists(db, key)) {
    1956           0 :                 DEBUG(10, ("regb_fetch_values: key [%s] does not exist\n",
    1957             :                            key));
    1958           0 :                 ret = -1;
    1959           0 :                 goto done;
    1960             :         }
    1961             : 
    1962        1024 :         keystr = talloc_asprintf(ctx, "%s\\%s", REG_VALUE_PREFIX, key);
    1963        1024 :         if (!keystr) {
    1964           0 :                 goto done;
    1965             :         }
    1966             : 
    1967        1024 :         ZERO_STRUCT(value);
    1968        1024 :         count = 0;
    1969        1024 :         seqnum[0] = dbwrap_get_seqnum(db);
    1970             : 
    1971             :         do {
    1972        1024 :                 count++;
    1973        1024 :                 TALLOC_FREE(value.dptr);
    1974        1024 :                 value = regdb_fetch_key_internal(db, ctx, keystr);
    1975        1024 :                 seqnum[count % 2] = dbwrap_get_seqnum(db);
    1976        1024 :         } while (seqnum[0] != seqnum[1]);
    1977             : 
    1978        1024 :         if (count > 1) {
    1979           0 :                 DEBUG(5, ("regdb_fetch_values_internal: it took %d attempts "
    1980             :                           "to fetch key '%s' with constant seqnum\n",
    1981             :                           count, key));
    1982             :         }
    1983             : 
    1984        1024 :         werr = regval_ctr_set_seqnum(values, seqnum[0]);
    1985        1024 :         if (!W_ERROR_IS_OK(werr)) {
    1986           0 :                 goto done;
    1987             :         }
    1988             : 
    1989        1024 :         if (!value.dptr) {
    1990             :                 /* all keys have zero values by default */
    1991         357 :                 goto done;
    1992             :         }
    1993             : 
    1994         667 :         ret = regdb_unpack_values(values, value.dptr, value.dsize);
    1995         667 :         if (ret == -1) {
    1996           0 :                 DBG_WARNING("regdb_unpack_values failed\n");
    1997             :         }
    1998             : 
    1999         667 :         ret = regval_ctr_numvals(values);
    2000             : 
    2001        1024 : done:
    2002        1024 :         TALLOC_FREE(ctx);
    2003        1024 :         return ret;
    2004             : }
    2005             : 
    2006         360 : static int regdb_fetch_values(const char* key, struct regval_ctr *values)
    2007             : {
    2008         360 :         return regdb_fetch_values_internal(regdb, key, values);
    2009             : }
    2010             : 
    2011        1034 : static NTSTATUS regdb_store_values_internal(struct db_context *db,
    2012             :                                             const char *key,
    2013             :                                             struct regval_ctr *values)
    2014             : {
    2015             :         TDB_DATA old_data, data;
    2016        1034 :         char *keystr = NULL;
    2017        1034 :         TALLOC_CTX *ctx = talloc_stackframe();
    2018             :         int len;
    2019             :         NTSTATUS status;
    2020             :         WERROR werr;
    2021             : 
    2022        1034 :         DEBUG(10,("regdb_store_values: Looking for values of key [%s]\n", key));
    2023             : 
    2024        1034 :         if (!regdb_key_exists(db, key)) {
    2025           0 :                 status = NT_STATUS_NOT_FOUND;
    2026           0 :                 goto done;
    2027             :         }
    2028             : 
    2029        1034 :         if (regval_ctr_numvals(values) == 0) {
    2030          54 :                 werr = regdb_delete_values(db, key);
    2031          54 :                 if (!W_ERROR_IS_OK(werr)) {
    2032           0 :                         status = werror_to_ntstatus(werr);
    2033           0 :                         goto done;
    2034             :                 }
    2035             : 
    2036             :                 /*
    2037             :                  * update the seqnum in the cache to prevent the next read
    2038             :                  * from going to disk
    2039             :                  */
    2040          54 :                 werr = regval_ctr_set_seqnum(values, dbwrap_get_seqnum(db));
    2041          54 :                 status = werror_to_ntstatus(werr);
    2042          54 :                 goto done;
    2043             :         }
    2044             : 
    2045         980 :         ZERO_STRUCT(data);
    2046             : 
    2047         980 :         len = regdb_pack_values(values, data.dptr, data.dsize);
    2048         980 :         if (len <= 0) {
    2049           0 :                 DEBUG(0,("regdb_store_values: unable to pack values. len <= 0\n"));
    2050           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    2051           0 :                 goto done;
    2052             :         }
    2053             : 
    2054         980 :         data.dptr = talloc_array(ctx, uint8_t, len);
    2055         980 :         data.dsize = len;
    2056             : 
    2057         980 :         len = regdb_pack_values(values, data.dptr, data.dsize);
    2058             : 
    2059         980 :         SMB_ASSERT( len == data.dsize );
    2060             : 
    2061         980 :         keystr = talloc_asprintf(ctx, "%s\\%s", REG_VALUE_PREFIX, key );
    2062         980 :         if (!keystr) {
    2063           0 :                 status = NT_STATUS_NO_MEMORY;
    2064           0 :                 goto done;
    2065             :         }
    2066         980 :         keystr = normalize_reg_path(ctx, keystr);
    2067         980 :         if (!keystr) {
    2068           0 :                 status = NT_STATUS_NO_MEMORY;
    2069           0 :                 goto done;
    2070             :         }
    2071             : 
    2072         980 :         status = dbwrap_fetch_bystring(db, ctx, keystr, &old_data);
    2073             : 
    2074         980 :         if (NT_STATUS_IS_OK(status)
    2075         611 :             && (old_data.dptr != NULL)
    2076         611 :             && (old_data.dsize == data.dsize)
    2077           0 :             && (memcmp(old_data.dptr, data.dptr, data.dsize) == 0))
    2078             :         {
    2079           0 :                 status = NT_STATUS_OK;
    2080           0 :                 goto done;
    2081             :         }
    2082             : 
    2083         980 :         status = dbwrap_trans_store_bystring(db, keystr, data, TDB_REPLACE);
    2084         980 :         if (!NT_STATUS_IS_OK(status)) {
    2085           0 :                 DEBUG(0, ("regdb_store_values_internal: error storing: %s\n", nt_errstr(status)));
    2086           0 :                 goto done;
    2087             :         }
    2088             : 
    2089             :         /*
    2090             :          * update the seqnum in the cache to prevent the next read
    2091             :          * from going to disk
    2092             :          */
    2093         980 :         werr = regval_ctr_set_seqnum(values, dbwrap_get_seqnum(db));
    2094         980 :         status = werror_to_ntstatus(werr);
    2095             : 
    2096        1034 : done:
    2097        1034 :         TALLOC_FREE(ctx);
    2098        1034 :         return status;
    2099             : }
    2100             : 
    2101             : struct regdb_store_values_ctx {
    2102             :         const char *key;
    2103             :         struct regval_ctr *values;
    2104             : };
    2105             : 
    2106         882 : static NTSTATUS regdb_store_values_action(struct db_context *db,
    2107             :                                           void *private_data)
    2108             : {
    2109             :         NTSTATUS status;
    2110         882 :         struct regdb_store_values_ctx *ctx =
    2111             :                 (struct regdb_store_values_ctx *)private_data;
    2112             : 
    2113         882 :         status = regdb_store_values_internal(db, ctx->key, ctx->values);
    2114             : 
    2115         882 :         return status;
    2116             : }
    2117             : 
    2118         882 : static bool regdb_store_values(const char *key, struct regval_ctr *values)
    2119             : {
    2120             :         WERROR werr;
    2121             :         struct regdb_store_values_ctx ctx;
    2122             : 
    2123         882 :         ctx.key = key;
    2124         882 :         ctx.values = values;
    2125             : 
    2126         882 :         werr = regdb_trans_do(regdb, regdb_store_values_action, &ctx);
    2127             : 
    2128         882 :         return W_ERROR_IS_OK(werr);
    2129             : }
    2130             : 
    2131         114 : static WERROR regdb_get_secdesc(TALLOC_CTX *mem_ctx, const char *key,
    2132             :                                 struct security_descriptor **psecdesc)
    2133             : {
    2134             :         char *tdbkey;
    2135             :         TDB_DATA data;
    2136             :         NTSTATUS status;
    2137         114 :         TALLOC_CTX *tmp_ctx = talloc_stackframe();
    2138         114 :         WERROR err = WERR_OK;
    2139             : 
    2140         114 :         DEBUG(10, ("regdb_get_secdesc: Getting secdesc of key [%s]\n", key));
    2141             : 
    2142         114 :         if (!regdb_key_exists(regdb, key)) {
    2143           0 :                 err = WERR_FILE_NOT_FOUND;
    2144           0 :                 goto done;
    2145             :         }
    2146             : 
    2147         114 :         tdbkey = talloc_asprintf(tmp_ctx, "%s\\%s", REG_SECDESC_PREFIX, key);
    2148         114 :         if (tdbkey == NULL) {
    2149           0 :                 err = WERR_NOT_ENOUGH_MEMORY;
    2150           0 :                 goto done;
    2151             :         }
    2152             : 
    2153         114 :         tdbkey = normalize_reg_path(tmp_ctx, tdbkey);
    2154         114 :         if (tdbkey == NULL) {
    2155           0 :                 err = WERR_NOT_ENOUGH_MEMORY;
    2156           0 :                 goto done;
    2157             :         }
    2158             : 
    2159         114 :         status = dbwrap_fetch_bystring(regdb, tmp_ctx, tdbkey, &data);
    2160         114 :         if (!NT_STATUS_IS_OK(status)) {
    2161         114 :                 err = WERR_FILE_NOT_FOUND;
    2162         114 :                 goto done;
    2163             :         }
    2164             : 
    2165           0 :         status = unmarshall_sec_desc(mem_ctx, (uint8_t *)data.dptr, data.dsize,
    2166             :                                      psecdesc);
    2167             : 
    2168           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
    2169           0 :                 err = WERR_NOT_ENOUGH_MEMORY;
    2170           0 :         } else if (!NT_STATUS_IS_OK(status)) {
    2171           0 :                 err = WERR_REGISTRY_CORRUPT;
    2172             :         }
    2173             : 
    2174         114 : done:
    2175         114 :         TALLOC_FREE(tmp_ctx);
    2176         114 :         return err;
    2177             : }
    2178             : 
    2179             : struct regdb_set_secdesc_ctx {
    2180             :         const char *key;
    2181             :         struct security_descriptor *secdesc;
    2182             : };
    2183             : 
    2184           0 : static NTSTATUS regdb_set_secdesc_action(struct db_context *db,
    2185             :                                          void *private_data)
    2186             : {
    2187             :         char *tdbkey;
    2188             :         NTSTATUS status;
    2189             :         TDB_DATA tdbdata;
    2190           0 :         struct regdb_set_secdesc_ctx *ctx =
    2191             :                 (struct regdb_set_secdesc_ctx *)private_data;
    2192           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2193             : 
    2194           0 :         tdbkey = talloc_asprintf(frame, "%s\\%s", REG_SECDESC_PREFIX, ctx->key);
    2195           0 :         if (tdbkey == NULL) {
    2196           0 :                 status = NT_STATUS_NO_MEMORY;
    2197           0 :                 goto done;
    2198             :         }
    2199             : 
    2200           0 :         tdbkey = normalize_reg_path(frame, tdbkey);
    2201           0 :         if (tdbkey == NULL) {
    2202           0 :                 status = NT_STATUS_NO_MEMORY;
    2203           0 :                 goto done;
    2204             :         }
    2205             : 
    2206           0 :         if (ctx->secdesc == NULL) {
    2207             :                 /* assuming a delete */
    2208           0 :                 status = dbwrap_delete_bystring(db, tdbkey);
    2209           0 :                 goto done;
    2210             :         }
    2211             : 
    2212           0 :         status = marshall_sec_desc(frame, ctx->secdesc, &tdbdata.dptr,
    2213             :                                    &tdbdata.dsize);
    2214           0 :         if (!NT_STATUS_IS_OK(status)) {
    2215           0 :                 goto done;
    2216             :         }
    2217             : 
    2218           0 :         status = dbwrap_store_bystring(db, tdbkey, tdbdata, 0);
    2219             : 
    2220           0 : done:
    2221           0 :         TALLOC_FREE(frame);
    2222           0 :         return status;
    2223             : }
    2224             : 
    2225           0 : static WERROR regdb_set_secdesc(const char *key,
    2226             :                                 struct security_descriptor *secdesc)
    2227             : {
    2228             :         WERROR err;
    2229             :         struct regdb_set_secdesc_ctx ctx;
    2230             : 
    2231           0 :         if (!regdb_key_exists(regdb, key)) {
    2232           0 :                 err = WERR_FILE_NOT_FOUND;
    2233           0 :                 goto done;
    2234             :         }
    2235             : 
    2236           0 :         ctx.key = key;
    2237           0 :         ctx.secdesc = secdesc;
    2238             : 
    2239           0 :         err = regdb_trans_do(regdb, regdb_set_secdesc_action, &ctx);
    2240             : 
    2241           0 : done:
    2242           0 :         return err;
    2243             : }
    2244             : 
    2245         366 : static bool regdb_subkeys_need_update(struct regsubkey_ctr *subkeys)
    2246             : {
    2247         366 :         return (regdb_get_seqnum() != regsubkey_ctr_get_seqnum(subkeys));
    2248             : }
    2249             : 
    2250        1252 : static bool regdb_values_need_update(struct regval_ctr *values)
    2251             : {
    2252        1252 :         return (regdb_get_seqnum() != regval_ctr_get_seqnum(values));
    2253             : }
    2254             : 
    2255             : /*
    2256             :  * Table of function pointers for default access
    2257             :  */
    2258             : 
    2259             : struct registry_ops regdb_ops = {
    2260             :         .fetch_subkeys = regdb_fetch_keys,
    2261             :         .fetch_values = regdb_fetch_values,
    2262             :         .store_subkeys = regdb_store_keys,
    2263             :         .store_values = regdb_store_values,
    2264             :         .create_subkey = regdb_create_subkey,
    2265             :         .delete_subkey = regdb_delete_subkey,
    2266             :         .get_secdesc = regdb_get_secdesc,
    2267             :         .set_secdesc = regdb_set_secdesc,
    2268             :         .subkeys_need_update = regdb_subkeys_need_update,
    2269             :         .values_need_update = regdb_values_need_update
    2270             : };

Generated by: LCOV version 1.13