LCOV - code coverage report
Current view: top level - source3/utils - net_registry_check.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 401 727 55.2 %
Date: 2024-04-21 15:09:00 Functions: 37 46 80.4 %

          Line data    Source code
       1             : /*
       2             :  * Samba Unix/Linux SMB client library
       3             :  *
       4             :  * Copyright (C) Gregor Beck 2011
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : /**
      21             :  * @brief  Check the registry database.
      22             :  * @author Gregor Beck <gb@sernet.de>
      23             :  * @date   Mar 2011
      24             :  */
      25             : 
      26             : #include "net_registry_check.h"
      27             : 
      28             : #include "includes.h"
      29             : #include "system/filesys.h"
      30             : #include "lib/dbwrap/dbwrap.h"
      31             : #include "lib/dbwrap/dbwrap_open.h"
      32             : #include "lib/dbwrap/dbwrap_rbt.h"
      33             : #include "net.h"
      34             : #include "libcli/security/dom_sid.h"
      35             : #include "libcli/security/secdesc.h"
      36             : #include "cbuf.h"
      37             : #include "srprs.h"
      38             : #include <termios.h>
      39             : #include "util_tdb.h"
      40             : #include "registry/reg_db.h"
      41             : #include "libcli/registry/util_reg.h"
      42             : #include "registry/reg_parse_internal.h"
      43             : #include "interact.h"
      44             : 
      45             : /*
      46             :   check tree:
      47             :   + every key has a subkeylist
      48             :   + every key is referenced by the subkeylist of its parent
      49             :   check path:
      50             :   + starts with valid hive
      51             :   + UTF-8 (option to convert ???)
      52             :   + only uppercase
      53             :   + separator ???
      54             :   check value:
      55             :   + REG_DWORD has size 4
      56             :   + REG_QWORD has size 8
      57             :   + STRINGS are zero terminated UTF-16
      58             : */
      59             : 
      60             : struct regval {
      61             :         char *name;
      62             :         uint32_t type;
      63             :         DATA_BLOB data;
      64             : };
      65             : 
      66             : struct regkey {
      67             :         char *name;
      68             :         char *path;
      69             :         bool has_subkeylist;
      70             :         bool needs_update;
      71             :         struct regkey *parent;
      72             :         size_t nsubkeys;
      73             :         struct regkey **subkeys;
      74             :         size_t nvalues;
      75             :         struct regval **values;
      76             :         struct security_descriptor *sd;
      77             : };
      78             : 
      79             : struct check_ctx {
      80             :         char *fname;
      81             :         struct check_options opt;
      82             : 
      83             :         uint32_t version;
      84             :         char sep;
      85             :         struct db_context *idb;
      86             :         struct db_context *odb;
      87             : 
      88             :         struct regkey *root; /*dummy key to hold all basekeys*/
      89             :         struct db_context *reg;
      90             :         struct db_context *del;
      91             : 
      92             :         bool transaction;
      93             :         char auto_action;
      94             :         char default_action;
      95             : };
      96             : 
      97        3386 : static void* talloc_array_append(void *mem_ctx, void* array[], void *ptr)
      98             : {
      99        3386 :         size_t size = array ? talloc_array_length(array) : 1;
     100        3386 :         void **tmp = talloc_realloc(mem_ctx, array, void*, size + 1);
     101        3386 :         if (tmp == NULL) {
     102           0 :                 talloc_free(array);
     103           0 :                 return NULL;
     104             :         }
     105        3386 :         tmp[size-1] = ptr;
     106        3386 :         tmp[size] = NULL;
     107        3386 :         return tmp;
     108             : }
     109             : 
     110        1894 : static void regkey_add_subkey(struct regkey *key, struct regkey *subkey)
     111             : {
     112        1894 :         key->subkeys = (struct regkey**)
     113        1894 :                 talloc_array_append(key, (void**)key->subkeys, subkey);
     114        1894 :         if (key->subkeys != NULL) {
     115        1894 :                 key->nsubkeys++;
     116             :         }
     117        1894 : }
     118             : 
     119        1492 : static struct regval* regval_copy(TALLOC_CTX *mem_ctx, const struct regval *val)
     120             : {
     121        1492 :         struct regval *ret = talloc_zero(mem_ctx, struct regval);
     122        1492 :         if (ret == NULL) {
     123           0 :                 goto fail;
     124             :         }
     125             : 
     126        1492 :         ret->name = talloc_strdup(ret, val->name);
     127        1492 :         if (ret->name == NULL) {
     128           0 :                 goto fail;
     129             :         }
     130             : 
     131        1492 :         ret->data = data_blob_dup_talloc(ret, val->data);
     132        1492 :         if (ret->data.data == NULL) {
     133           0 :                 goto fail;
     134             :         }
     135             : 
     136        1492 :         ret->type = val->type;
     137             : 
     138        1492 :         return ret;
     139           0 : fail:
     140           0 :         talloc_free(ret);
     141           0 :         return NULL;
     142             : }
     143             : 
     144        1492 : static void regkey_add_regval(struct regkey *key, struct regval *val)
     145             : {
     146        1492 :         key->values = (struct regval**)
     147        1492 :                 talloc_array_append(key, (void**)key->values, val);
     148        1492 :         if (key->values != NULL) {
     149        1492 :                 key->nvalues++;
     150             :         }
     151        1492 : }
     152             : 
     153        5246 : static bool tdb_data_read_uint32(TDB_DATA *buf, uint32_t *result)
     154             : {
     155        5246 :         const size_t len = sizeof(uint32_t);
     156        5246 :         if (buf->dsize >= len) {
     157        5246 :                 *result = IVAL(buf->dptr, 0);
     158        5246 :                 buf->dptr += len;
     159        5246 :                 buf->dsize -= len;
     160        5246 :                 return true;
     161             :         }
     162           0 :         return false;
     163             : }
     164             : 
     165        5498 : static bool tdb_data_read_cstr(TDB_DATA *buf, char **result)
     166             : {
     167        5498 :         const size_t len = strnlen((char*)buf->dptr, buf->dsize) + 1;
     168        5498 :         if (buf->dsize >= len) {
     169        3236 :                 *result = (char*)buf->dptr;
     170        3236 :                 buf->dptr += len;
     171        3236 :                 buf->dsize -= len;
     172        3236 :                 return true;
     173             :         }
     174        2262 :         return false;
     175             : }
     176             : 
     177        1492 : static bool tdb_data_read_blob(TDB_DATA *buf, DATA_BLOB *result)
     178             : {
     179        1492 :         TDB_DATA tmp = *buf;
     180           0 :         uint32_t len;
     181        1492 :         if (!tdb_data_read_uint32(&tmp, &len)) {
     182           0 :                 return false;
     183             :         }
     184        1492 :         if (tmp.dsize >= len) {
     185        1492 :                 *buf = tmp;
     186        1492 :                 result->data   = tmp.dptr;
     187        1492 :                 result->length = len;
     188        1492 :                 buf->dptr += len;
     189        1492 :                 buf->dsize -= len;
     190        1492 :                 return true;
     191             :         }
     192           0 :         return false;
     193             : }
     194             : 
     195        1856 : static bool tdb_data_read_regval(TDB_DATA *buf, struct regval *result)
     196             : {
     197        1856 :         TDB_DATA tmp = *buf;
     198           0 :         struct regval value;
     199        1856 :         if (!tdb_data_read_cstr(&tmp, &value.name)
     200        1492 :             || !tdb_data_read_uint32(&tmp, &value.type)
     201        1492 :             || !tdb_data_read_blob(&tmp, &value.data))
     202             :         {
     203         364 :                 return false;
     204             :         }
     205        1492 :         *buf = tmp;
     206        1492 :         *result = value;
     207        1492 :         return true;
     208             : }
     209             : 
     210        2288 : static bool tdb_data_is_cstr(TDB_DATA d) {
     211        2288 :         if (tdb_data_is_empty(d) || (d.dptr[d.dsize-1] != '\0')) {
     212           0 :                 return false;
     213             :         }
     214        2288 :         return strlen((char *)d.dptr) == d.dsize-1;
     215             : }
     216             : 
     217          10 : static TDB_DATA cbuf_make_tdb_data(cbuf *b)
     218             : {
     219          10 :         return make_tdb_data((void*)cbuf_gets(b, 0), cbuf_getpos(b));
     220             : }
     221             : 
     222        1744 : static void remove_all(char *str, char c)
     223             : {
     224        1744 :         char *out=str;
     225       18430 :         while (*str) {
     226       16686 :                 if (*str != c) {
     227       16686 :                         *out = *str;
     228       16686 :                         out++;
     229             :                 }
     230       16686 :                 str++;
     231             :         }
     232        1744 :         *out = '\0';
     233        1744 : }
     234             : 
     235        1894 : static char* parent_path(const char *path, char sep)
     236             : {
     237        1894 :         const char *p = strrchr(path, sep);
     238        1894 :         return p ? talloc_strndup(talloc_tos(), path, p-path) : NULL;
     239             : }
     240             : 
     241             : /* return the regkey corresponding to path, create if not yet existing */
     242             : static struct regkey*
     243        5900 : check_ctx_lookup_key(struct check_ctx *ctx, const char *path) {
     244        5900 :         struct regkey *ret = NULL;
     245           0 :         NTSTATUS status;
     246        5900 :         TDB_DATA val = tdb_null;
     247             : 
     248        5900 :         if ( path == NULL) {
     249         166 :                 return ctx->root;
     250             :         }
     251             : 
     252        5734 :         status = dbwrap_fetch(ctx->reg, ctx, string_term_tdb_data(path), &val);
     253        5734 :         if (NT_STATUS_IS_OK(status)) {
     254        3840 :                 if (ctx->opt.verbose) {
     255           0 :                         printf("Open: %s\n", path);
     256             :                 }
     257        3840 :                 ret = *(struct regkey**)val.dptr;
     258        1894 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     259             :                 /* not yet existing, create */
     260           0 :                 char *pp;
     261        1894 :                 if (ctx->opt.verbose) {
     262           0 :                         printf("New: %s\n", path);
     263             :                 }
     264        1894 :                 ret = talloc_zero(ctx, struct regkey);
     265        1894 :                 if (ret == NULL) {
     266           0 :                         DEBUG(0, ("Out of memory!\n"));
     267           0 :                         goto done;
     268             :                 }
     269        1894 :                 ret->path = talloc_strdup(ret, path);
     270             : 
     271        1894 :                 pp = parent_path(path, ctx->sep);
     272        1894 :                 ret->parent = check_ctx_lookup_key(ctx, pp);
     273        1894 :                 regkey_add_subkey(ret->parent, ret);
     274        1894 :                 TALLOC_FREE(pp);
     275             : 
     276             :                 /* the dummy root key has no subkeylist so set the name */
     277        1894 :                 if (ret->parent == ctx->root) {
     278         166 :                         ret->name = talloc_strdup(ret, path);
     279             :                 }
     280             : 
     281        1894 :                 dbwrap_store(ctx->reg, string_term_tdb_data(path),
     282             :                              make_tdb_data((void*)&ret, sizeof(ret)), 0);
     283             :         } else {
     284           0 :                 DEBUG(0, ("lookup key: failed to fetch %s: %s\n", path,
     285             :                           nt_errstr(status)));
     286             :         }
     287        5734 : done:
     288        5734 :         talloc_free(val.dptr);
     289        5734 :         return ret;
     290             : }
     291             : 
     292          28 : static struct check_ctx* check_ctx_create(TALLOC_CTX *mem_ctx, const char *db,
     293             :                                           const struct check_options *opt)
     294             : {
     295          28 :         struct check_ctx *ctx = talloc_zero(mem_ctx, struct check_ctx);
     296             : 
     297          28 :         ctx->opt = *opt;
     298          28 :         ctx->reg = db_open_rbt(ctx);
     299          28 :         ctx->del = db_open_rbt(ctx);
     300          28 :         ctx->root = talloc_zero(ctx, struct regkey);
     301          28 :         ctx->fname = talloc_strdup(ctx, db);
     302             : 
     303          28 :         if (opt->automatic && (opt->output == NULL)) {
     304           6 :                 ctx->opt.repair = true;
     305           6 :                 ctx->opt.output = ctx->fname;
     306             :         }
     307             : 
     308          28 :         if (opt->repair) {
     309           0 :                 if (opt->output) {
     310           0 :                         d_fprintf(stderr, "You can not specify --output "
     311             :                                   "with --repair\n");
     312           0 :                         goto fail;
     313             :                 } else {
     314           0 :                         ctx->opt.output = ctx->fname;
     315             :                 }
     316             :         }
     317             : 
     318          28 :         ctx->default_action = 'r';
     319          28 :         return ctx;
     320           0 : fail:
     321           0 :         talloc_free(ctx);
     322           0 :         return NULL;
     323             : }
     324             : 
     325          28 : static bool check_ctx_open_output(struct check_ctx *ctx)
     326             : {
     327          28 :         int oflags = O_RDWR | O_CREAT ;
     328             : 
     329          28 :         if (ctx->opt.output == NULL) {
     330          22 :                 return true;
     331             :         }
     332             : 
     333           6 :         if (!ctx->opt.repair) {
     334           0 :                 if (!ctx->opt.wipe) {
     335           0 :                         oflags |= O_EXCL;
     336             :                 }
     337           0 :                 ctx->opt.wipe = true;
     338             :         }
     339             : 
     340           6 :         ctx->odb = db_open(ctx, ctx->opt.output, 0, TDB_DEFAULT, oflags, 0644,
     341             :                            DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
     342           6 :         if (ctx->odb == NULL) {
     343           0 :                 d_fprintf(stderr,
     344           0 :                           _("Could not open db (%s) for writing: %s\n"),
     345           0 :                           ctx->opt.output, strerror(errno));
     346           0 :                 return false;
     347             :         }
     348           6 :         return true;
     349             : }
     350             : 
     351             : 
     352          28 : static bool check_ctx_open_input(struct check_ctx *ctx) {
     353          28 :         ctx->idb = db_open(ctx, ctx->fname, 0, TDB_DEFAULT, O_RDONLY, 0,
     354             :                            DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
     355          28 :         if (ctx->idb == NULL) {
     356           0 :                 d_fprintf(stderr,
     357           0 :                           _("Could not open db (%s) for reading: %s\n"),
     358           0 :                           ctx->fname, strerror(errno));
     359           0 :                 return false;
     360             :         }
     361          28 :         return true;
     362             : }
     363             : 
     364          28 : static bool check_ctx_transaction_start(struct check_ctx *ctx) {
     365          28 :         if (ctx->odb == NULL) {
     366          22 :                 return true;
     367             :         }
     368           6 :         if (dbwrap_transaction_start(ctx->odb) != 0) {
     369           0 :                 DEBUG(0, ("transaction_start failed\n"));
     370           0 :                 return false;
     371             :         }
     372           6 :         ctx->transaction = true;
     373           6 :         return true;
     374             : }
     375             : 
     376          28 : static void check_ctx_transaction_stop(struct check_ctx *ctx, bool ok) {
     377          28 :         if (!ctx->transaction) {
     378          22 :                 return;
     379             :         }
     380           6 :         if (!ctx->opt.test && ok) {
     381           6 :                 d_printf("Committing changes\n");
     382           6 :                 if (dbwrap_transaction_commit(ctx->odb) != 0) {
     383           0 :                         DEBUG(0, ("transaction_commit failed\n"));
     384             :                 }
     385             :         } else {
     386           0 :                 d_printf("Discarding changes\n");
     387           0 :                 dbwrap_transaction_cancel(ctx->odb);
     388             :         }
     389             : }
     390             : 
     391          26 : static bool read_info(struct check_ctx *ctx, const char *key, TDB_DATA val)
     392             : {
     393          26 :         if (val.dsize==sizeof(uint32_t) && strcmp(key, "version")==0) {
     394          26 :                 uint32_t v = IVAL(val.dptr, 0);
     395          26 :                 printf("INFO: %s = %d\n", key, v);
     396          26 :                 return true;
     397             :         }
     398           0 :         printf("INFO: %s = <invalid>\n", key);
     399           0 :         return false;
     400             : }
     401             : 
     402           0 : static bool is_all_upper(const char *str) {
     403           0 :         bool ret;
     404           0 :         char *tmp = talloc_strdup(talloc_tos(), str);
     405           0 :         if (!strupper_m(tmp)) {
     406           0 :                 talloc_free(tmp);
     407           0 :                 return false;
     408             :         }
     409           0 :         ret = (strcmp(tmp, str) == 0);
     410           0 :         talloc_free(tmp);
     411           0 :         return ret;
     412             : }
     413             : 
     414        1744 : static void move_to_back(struct regkey *key, struct regkey *subkey)
     415             : {
     416           0 :         struct regkey **ptr;
     417           0 :         size_t nidx;
     418             : 
     419        1744 :         DEBUG(5, ("Move to back subkey \"%s\" of \"%s\"\n",
     420             :                   subkey->path, key->path));
     421             : 
     422        2848 :         for (ptr=key->subkeys; *ptr != subkey; ptr++)
     423             :                 ;
     424             : 
     425        1744 :         nidx = ptr + 1 - key->subkeys;
     426        1744 :         memmove(ptr, ptr+1, (key->nsubkeys - nidx) * sizeof(*ptr));
     427             : 
     428        1744 :         key->subkeys[key->nsubkeys-1] = subkey;
     429        1744 : }
     430             : 
     431        1744 : static void set_subkey_name(struct check_ctx *ctx, struct regkey *key,
     432             :                             const char *name, int nlen)
     433             : {
     434        1744 :         char *path = key->path;
     435        1744 :         TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
     436           0 :         char *p;
     437           0 :         struct regkey *subkey;
     438        1744 :         char *nname = talloc_strndup(mem_ctx, name, nlen);
     439        1744 :         remove_all(nname, ctx->sep);
     440             : 
     441        1744 :         if (strncmp(name, nname, nlen) != 0) {
     442             :                 /* XXX interaction: delete/edit */
     443           0 :                 printf("Warning: invalid name: \"%s\" replace with \"%s\"\n",
     444             :                        name, nname);
     445           0 :                 key->needs_update = true;
     446             :         }
     447        1744 :         p = talloc_asprintf_strupper_m(mem_ctx, "%s%c%s",
     448        1744 :                                        path, ctx->sep, nname);
     449        1744 :         subkey = check_ctx_lookup_key(ctx, p);
     450        1744 :         if (subkey->name) {
     451          16 :                 bool do_replace = false;
     452             : 
     453          16 :                 if (strcmp(subkey->name, nname) != 0) {
     454           0 :                         int action;
     455           0 :                         char default_action;
     456             : 
     457           0 :                         if (is_all_upper(nname)) {
     458           0 :                                 default_action = 'o';
     459             :                         } else {
     460           0 :                                 default_action = 'n';
     461             :                         }
     462             : 
     463           0 :                         printf("Conflicting subkey names of [%s]: "
     464             :                                "old: \"%s\", new: \"%s\"\n",
     465             :                                key->path, subkey->name, nname);
     466             : 
     467           0 :                         if (ctx->opt.output == NULL || ctx->opt.automatic) {
     468           0 :                                 action = default_action;
     469             :                         } else {
     470           0 :                                 do {
     471           0 :                                         action = interact_prompt(
     472             :                                                 "choose spelling [o]ld, [n]ew,"
     473             :                                                 "or [e]dit", "one",
     474             :                                                 default_action);
     475           0 :                                         if (action == 'e') {
     476           0 :                                                 printf("Sorry, edit is not yet "
     477             :                                                        "implemented here...\n");
     478             :                                         }
     479           0 :                                 } while (action == 'e');
     480             :                         }
     481             : 
     482           0 :                         if (action == 'n') {
     483           0 :                                 do_replace = true;
     484             :                         }
     485             :                 }
     486             : 
     487          16 :                 if (do_replace) {
     488           0 :                         if (ctx->opt.verbose) {
     489           0 :                                 printf("Replacing name: %s: \"%s\""
     490             :                                        " -> \"%s\"\n", path,
     491             :                                        subkey->name, nname);
     492             :                         }
     493           0 :                         TALLOC_FREE(subkey->name);
     494           0 :                         subkey->name = talloc_steal(subkey, nname);
     495           0 :                         key->needs_update = true;
     496             :                 }
     497             :         } else {
     498        1728 :                 if (ctx->opt.verbose) {
     499           0 :                         printf("Set name: %s: \"%s\"\n", path, nname);
     500             :                 }
     501        1728 :                 subkey->name = talloc_steal(subkey, nname);
     502             :         }
     503             : 
     504        1744 :         move_to_back(key, subkey);
     505        1744 :         TALLOC_FREE(mem_ctx);
     506        1744 : }
     507             : 
     508             : static void
     509        1898 : read_subkeys(struct check_ctx *ctx, const char *path, TDB_DATA val, bool update)
     510             : {
     511        1898 :         uint32_t num_items, found_items = 0;
     512           0 :         char *subkey;
     513        1898 :         struct regkey *key = check_ctx_lookup_key(ctx, path);
     514             : 
     515        1898 :         key->needs_update |= update;
     516             : 
     517             :         /* printf("SUBKEYS: %s\n", path); */
     518        1898 :         if (key->has_subkeylist) {
     519          12 :                 printf("Duplicate subkeylist \"%s\"\n",
     520             :                        path);
     521          12 :                 found_items = key->nsubkeys;
     522             :         }
     523             : 
     524             :         /* exists as defined by regdb_key_exists() */
     525        1898 :         key->has_subkeylist = true;
     526             : 
     527             :         /* name is set if a key is referenced by the */
     528             :         /* subkeylist of its parent. */
     529             : 
     530        1898 :         if (!tdb_data_read_uint32(&val, &num_items) ) {
     531           0 :                 printf("Invalid subkeylist: \"%s\"\n", path);
     532           0 :                 return;
     533             :         }
     534             : 
     535        3642 :         while (tdb_data_read_cstr(&val, &subkey)) {
     536             :                 /* printf(" SUBKEY: %s\n", subkey); */
     537        1744 :                 set_subkey_name(ctx, key, subkey, strlen(subkey));
     538        1744 :                 found_items++;
     539             :         }
     540             : 
     541        1898 :         if (val.dsize != 0) {
     542           0 :                 printf("Subkeylist of \"%s\": trailing: \"%.*s\"\n",
     543           0 :                        path, (int)val.dsize, val.dptr);
     544             :                 /* ask: best effort, delete or edit?*/
     545           0 :                 set_subkey_name(ctx, key, (char*)val.dptr, val.dsize);
     546           0 :                 found_items++;
     547           0 :                 key->needs_update = true;
     548             :         }
     549             : 
     550        1898 :         if (num_items != found_items) {
     551          12 :                 printf("Subkeylist of \"%s\": invalid number of subkeys, "
     552             :                        "expected: %d got: %d\n", path, num_items, found_items);
     553          12 :                 key->needs_update = true;
     554             :         }
     555             : 
     556             : }
     557             : 
     558         364 : static void read_values(struct check_ctx *ctx, const char *path, TDB_DATA val)
     559             : {
     560         364 :         struct regkey *key = check_ctx_lookup_key(ctx, path);
     561           0 :         uint32_t num_items, found_items;
     562           0 :         struct regval value;
     563             : 
     564             :         /* printf("VALUES: %s\n", path); */
     565             : 
     566         364 :         if (!tdb_data_read_uint32(&val, &num_items) ) {
     567           0 :                 printf("Invalid valuelist: \"%s\"\n", path);
     568           0 :                 return;
     569             :         }
     570             : 
     571         364 :         found_items=0;
     572        1856 :         while (tdb_data_read_regval(&val, &value)) {
     573             :                 /* printf(" VAL: %s type: %s(%d) length: %d\n", value.name, */
     574             :                 /*        str_regtype(value.type), value.type, */
     575             :                 /*        (int)value.data.length); */
     576        1492 :                 regkey_add_regval(key, regval_copy(key, &value));
     577        1492 :                 found_items++;
     578             :         }
     579             : 
     580         364 :         if (num_items != found_items) {
     581           0 :                 printf("Valuelist of \"%s\": invalid number of values, "
     582             :                        "expected: %d got: %d\n", path, num_items, found_items);
     583           0 :                 key->needs_update = true;
     584             :         }
     585             : 
     586         364 :         if (val.dsize != 0) {
     587           0 :                 printf("Valuelist of \"%s\": trailing: \"%*s\"\n", path,
     588           0 :                        (int)val.dsize, val.dptr);
     589           0 :                 key->needs_update = true;
     590             :                 /* XXX best effort ??? */
     591             :                 /* ZERO_STRUCT(value); */
     592             :                 /* if (tdb_data_read_cstr(&val, &value.name) */
     593             :                 /*     && tdb_data_read_uint32(&val, &value.type)) */
     594             :                 /* { */
     595             :                 /*      uint32_t len = -1; */
     596             :                 /*      tdb_data_read_uint32(&val, &len); */
     597             :                 /*      ... */
     598             :                 /*      found_items ++; */
     599             :                 /*      regkey_add_regval(key, regval_copy(key, value)); */
     600             :                 /* } */
     601             :         }
     602         364 :         if (found_items == 0) {
     603           0 :                 printf("Valuelist of \"%s\" empty\n", path);
     604           0 :                 key->needs_update = true;
     605             :         }
     606             : }
     607             : 
     608           0 : static bool read_sorted(struct check_ctx *ctx, const char *path, TDB_DATA val)
     609             : {
     610           0 :         if (ctx->version >= 3) {
     611           0 :                 return false;
     612             :         }
     613             : 
     614           0 :         if ((val.dptr == NULL) || (val.dsize<4)) {
     615           0 :                 return false;
     616             :         }
     617             : 
     618             :         /* ToDo: check */
     619             :         /* struct regkey *key = check_ctx_lookup_key(ctx, path); */
     620             :         /* printf("SORTED: %s\n", path); */
     621           0 :         return true;
     622             : }
     623             : 
     624           0 : static bool read_sd(struct check_ctx *ctx, const char *path, TDB_DATA val)
     625             : {
     626           0 :         NTSTATUS status;
     627           0 :         struct regkey *key = check_ctx_lookup_key(ctx, path);
     628             :         /* printf("SD: %s\n", path); */
     629             : 
     630           0 :         status = unmarshall_sec_desc(key, val.dptr, val.dsize, &key->sd);
     631           0 :         if (!NT_STATUS_IS_OK(status)) {
     632           0 :                 DEBUG(0, ("Failed to read SD of %s: %s\n",
     633             :                           path, nt_errstr(status)));
     634             :         }
     635           0 :         return true;
     636             : }
     637             : 
     638        2626 : static bool srprs_path(const char **ptr, const char* prefix, char sep,
     639             :                        const char **ppath)
     640             : {
     641        2626 :         const char *path, *pos = *ptr;
     642        2626 :         if (prefix != NULL) {
     643         364 :                 if (!srprs_str(&pos, prefix, -1) || !srprs_char(&pos, sep) ) {
     644           0 :                         return false;
     645             :                 }
     646             :         }
     647        2626 :         path = pos;
     648        2626 :         if ( !srprs_hive(&pos, NULL) ) {
     649         364 :                 return false;
     650             :         }
     651        2262 :         if ( !srprs_eos(&pos) && !srprs_char(&pos, sep) ) {
     652           0 :                 return false;
     653             :         }
     654        2262 :         *ppath = path;
     655        2262 :         *ptr = strchr(pos, '\0');
     656        2262 :         return true;
     657             : }
     658             : 
     659             : /* Fixme: this doesn't work in the general multibyte char case.
     660             :    see string_replace()
     661             : */
     662        2274 : static bool normalize_path_internal(char* path, char sep) {
     663        2274 :         size_t len = strlen(path);
     664        2274 :         const char *orig = talloc_strndup(talloc_tos(), path, len);
     665        2274 :         char *optr = path, *iptr = path;
     666           0 :         bool changed;
     667             : 
     668        2274 :         while (*iptr == sep ) {
     669           0 :                 iptr++;
     670             :         }
     671      117448 :         while (*iptr) {
     672      115174 :                 *optr = *iptr;
     673      115174 :                 if (*iptr == sep) {
     674       19852 :                         while (*iptr == sep) {
     675        9926 :                                 iptr++;
     676             :                         }
     677        9926 :                         if (*iptr) {
     678        9926 :                                 optr++;
     679             :                         }
     680             :                 } else {
     681      105248 :                         iptr++;
     682      105248 :                         optr++;
     683             :                 }
     684             :         }
     685        2274 :         *optr = '\0';
     686             : 
     687        2274 :         if (!strupper_m(path)) {
     688           0 :                 talloc_free(discard_const(orig));
     689           0 :                 return false;
     690             :         }
     691        2274 :         changed = (strcmp(orig, path) != 0);
     692        2274 :         talloc_free(discard_const(orig));
     693        2274 :         return changed;
     694             : }
     695             : 
     696        2274 : static bool normalize_path(char* path, char sep) {
     697           0 :         static const char* SEPS = "\\/";
     698        2274 :         char* firstsep = strpbrk(path, SEPS);
     699        2274 :         bool wrong_sep = (firstsep && (*firstsep != sep));
     700             : 
     701        2274 :         assert (strchr(SEPS, sep));
     702             : 
     703        2274 :         if (wrong_sep) {
     704           8 :                 string_replace(path, *firstsep, sep);
     705             :         }
     706        2274 :         return normalize_path_internal(path, sep) || wrong_sep;
     707             : }
     708             : 
     709        2288 : static int check_tdb_action(struct db_record *rec, void *check_ctx)
     710             : {
     711        2288 :         struct check_ctx *ctx = (struct check_ctx*)check_ctx;
     712        2288 :         TALLOC_CTX *frame = talloc_stackframe();
     713        2288 :         TDB_DATA val = dbwrap_record_get_value(rec);
     714        2288 :         TDB_DATA rec_key = dbwrap_record_get_key(rec);
     715           0 :         char *key;
     716        2288 :         bool invalid_path = false;
     717           0 :         bool once_more;
     718        2288 :         bool first_iter = true;
     719             : 
     720        2288 :         if (!tdb_data_is_cstr(rec_key)) {
     721           0 :                 printf("Key is not zero terminated: \"%.*s\"\ntry to go on.\n",
     722           0 :                        (int)rec_key.dsize, rec_key.dptr);
     723           0 :                 invalid_path = true;
     724             :         }
     725        2288 :         key = talloc_strndup(frame, (char*)rec_key.dptr, rec_key.dsize);
     726             : 
     727           0 :         do {
     728        2300 :                 const char *path, *pos = key;
     729        2300 :                 once_more = false;
     730             : 
     731        2300 :                 if (srprs_str(&pos, "INFO/", -1)) {
     732          26 :                         if ( read_info(ctx, pos, val) ) {
     733        2288 :                                 break;
     734             :                         }
     735           0 :                         invalid_path = true;
     736             :                         /* ask: mark invalid */
     737        2274 :                 } else if (srprs_str(&pos, "__db_sequence_number__", -1)) {
     738           0 :                         printf("Skip key: \"%.*s\"\n",
     739           0 :                                (int)rec_key.dsize, rec_key.dptr);
     740             :                         /* skip: do nothing + break */
     741           0 :                         break;
     742             : 
     743        2274 :                 } else if (normalize_path(key, ctx->sep)) {
     744          12 :                         printf("Unnormal key: \"%.*s\"\n",
     745          12 :                                (int)rec_key.dsize, rec_key.dptr);
     746          12 :                         printf("Normalize to: \"%s\"\n", key);
     747          12 :                         invalid_path = true;
     748        2262 :                 } else if (srprs_path(&pos, NULL,
     749        2262 :                                       ctx->sep, &path))
     750             :                 {
     751        1898 :                         read_subkeys(ctx, path, val, invalid_path);
     752        1898 :                         break;
     753         364 :                 } else if (srprs_path(&pos, REG_VALUE_PREFIX,
     754         364 :                                       ctx->sep, &path))
     755             :                 {
     756         364 :                         read_values(ctx, path, val);
     757         364 :                         break;
     758           0 :                 } else if (srprs_path(&pos, REG_SECDESC_PREFIX,
     759           0 :                                       ctx->sep, &path))
     760             :                 {
     761           0 :                         read_sd(ctx, path, val);
     762           0 :                         break;
     763           0 :                 } else if (srprs_path(&pos, REG_SORTED_SUBKEYS_PREFIX,
     764           0 :                                       ctx->sep, &path))
     765             :                 {
     766           0 :                         if (!read_sorted(ctx, path, val)) {
     767             :                                 /* delete: mark invalid + break */
     768           0 :                                 printf("Invalid sorted subkeys for: \"%s\"\n", path);
     769           0 :                                 invalid_path = true;
     770           0 :                                 key = NULL;
     771             :                         }
     772           0 :                         break;
     773             :                 } else {
     774           0 :                         printf("Unrecognized key: \"%.*s\"\n",
     775           0 :                                (int)rec_key.dsize, rec_key.dptr);
     776           0 :                         invalid_path = true;
     777             :                 }
     778             : 
     779          12 :                 if (invalid_path) {
     780           0 :                         unsigned char action;
     781          12 :                         if (ctx->opt.output == NULL) {
     782           6 :                                 action = first_iter ? 'r' : 's';
     783           6 :                         } else if (ctx->opt.automatic) {
     784           6 :                                 action = first_iter ? 'r' : 'd';
     785           0 :                         } else if (ctx->auto_action != '\0') {
     786           0 :                                 action = ctx->auto_action;
     787             :                         } else {
     788           0 :                                 action = interact_prompt("[s]kip,[S]kip all,"
     789             :                                                          "[d]elete,[D]elete all"
     790             :                                                          ",[e]dit,[r]etry"
     791             :                                                          , "sder",
     792           0 :                                                          ctx->default_action);
     793             :                         }
     794          12 :                         if (isupper(action)) {
     795           0 :                                 action = tolower(action);
     796           0 :                                 ctx->auto_action = action;
     797             :                         }
     798          12 :                         ctx->default_action = action;
     799          12 :                         switch (action) {
     800           0 :                         case 's': /* skip */
     801           0 :                                 invalid_path = false;
     802           0 :                                 break;
     803           0 :                         case 'd': /* delete */
     804           0 :                                 invalid_path = true;
     805           0 :                                 key = NULL;
     806           0 :                                 break;
     807           0 :                         case 'e': /* edit */ {
     808           0 :                                 char *p = interact_edit(frame, key);
     809           0 :                                 if (p) {
     810           0 :                                         talloc_free(key);
     811           0 :                                         key = p;
     812             :                                 }
     813             :                                 FALL_THROUGH;
     814             :                         }
     815             :                         case 'r': /* retry */
     816          12 :                                 once_more = true;
     817          12 :                                 break;
     818             :                         }
     819             :                 }
     820          12 :                 first_iter = false;
     821          12 :         } while (once_more);
     822             : 
     823        2288 :         if (invalid_path) {
     824          12 :                 dbwrap_store(ctx->del, rec_key, string_term_tdb_data(key), 0);
     825             :         }
     826             : 
     827        2288 :         talloc_free(frame);
     828        2288 :         return 0;
     829             : }
     830             : 
     831          28 : static bool get_version(struct check_ctx *ctx) {
     832           0 :         static const uint32_t curr_version = REGDB_CODE_VERSION;
     833          28 :         uint32_t version = ctx->opt.version ? ctx->opt.version : curr_version;
     834          28 :         uint32_t info_version = 0;
     835           0 :         NTSTATUS status;
     836             : 
     837          28 :         status = dbwrap_fetch_uint32_bystring(ctx->idb, "INFO/version",
     838             :                                               &info_version);
     839          28 :         if (!NT_STATUS_IS_OK(status)) {
     840           2 :                 printf("Warning: no INFO/version found!\n");
     841             :                 /* info_version = guess_version(ctx); */
     842             :         }
     843             : 
     844          28 :         if (ctx->opt.version) {
     845           2 :                 version = ctx->opt.version;
     846          26 :         } else if (ctx->opt.implicit_db) {
     847           6 :                 version = curr_version;
     848             :         } else {
     849          20 :                 version = info_version;
     850             :         }
     851             : 
     852          28 :         if (!version) {
     853           0 :                 printf("Couldn't determine registry format version, "
     854             :                        "specify with --reg-version\n");
     855           0 :                 return false;
     856             :         }
     857             : 
     858             : 
     859          28 :         if ( version != info_version ) {
     860           2 :                 if (ctx->opt.force || !ctx->opt.repair) {
     861           2 :                         printf("Warning: overwrite registry format "
     862             :                                "version %d with %d\n", info_version, version);
     863             :                 } else {
     864           0 :                         printf("Warning: found registry format version %d but "
     865             :                                "expected %d, use --force to proceed.\n", info_version, version);
     866           0 :                         return false;
     867             :                 }
     868             :         }
     869             : 
     870          28 :         ctx->version = version;
     871          28 :         ctx->sep = (version > 1) ? '\\' : '/';
     872             : 
     873          28 :         return true;
     874             : }
     875             : 
     876             : static bool
     877          10 : dbwrap_store_verbose(struct db_context *db, const char *key, TDB_DATA nval)
     878             : {
     879          10 :         TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
     880           0 :         TDB_DATA oval;
     881           0 :         NTSTATUS status;
     882             : 
     883          10 :         status = dbwrap_fetch_bystring(db, mem_ctx, key, &oval);
     884          10 :         if (NT_STATUS_IS_OK(status)) {
     885           6 :                 if (tdb_data_equal(nval, oval)) {
     886           4 :                         goto done;
     887             :                 }
     888           2 :                 printf("store %s:\n  overwrite: %s\n  with:      %s\n", key,
     889             :                        tdb_data_string(mem_ctx, oval),
     890             :                        tdb_data_string(mem_ctx, nval));
     891             : 
     892           4 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     893           4 :                 printf("store %s:\n  write: %s\n", key,
     894             :                        tdb_data_string(mem_ctx, nval));
     895             :         } else {
     896           0 :                 printf ("store %s:\n  failed to fetch old value: %s\n", key,
     897             :                         nt_errstr(status));
     898           0 :                 goto done;
     899             :         }
     900             : 
     901           6 :         status = dbwrap_store_bystring(db, key, nval, 0);
     902           6 :         if (!NT_STATUS_IS_OK(status)) {
     903           0 :                 printf ("store %s failed: %s\n", key, nt_errstr(status));
     904             :         }
     905             : 
     906           6 : done:
     907          10 :         talloc_free(mem_ctx);
     908          10 :         return NT_STATUS_IS_OK(status);
     909             : }
     910             : 
     911             : static bool
     912           6 : dbwrap_store_uint32_verbose(struct db_context *db, const char *key, uint32_t nval)
     913             : {
     914           0 :         uint32_t oval;
     915           0 :         NTSTATUS status;
     916             : 
     917           6 :         status = dbwrap_fetch_uint32_bystring(db, key, &oval);
     918           6 :         if (NT_STATUS_IS_OK(status)) {
     919           6 :                 if (nval == oval) {
     920           6 :                         goto done;
     921             :                 }
     922           0 :                 printf("store %s:\n overwrite: %d\n with:      %d\n", key,
     923             :                        (int)oval, (int)nval);
     924             : 
     925           0 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     926           0 :                 printf("store %s:\n write: %d\n", key, (int)nval);
     927             :         } else {
     928           0 :                 printf ("store %s:\n  failed to fetch old value: %s\n", key,
     929             :                         nt_errstr(status));
     930           0 :                 goto done;
     931             :         }
     932             : 
     933           0 :         status = dbwrap_store_uint32_bystring(db, key, nval);
     934           0 :         if (!NT_STATUS_IS_OK(status)) {
     935           0 :                 printf ("store %s failed: %s\n", key, nt_errstr(status));
     936             :         }
     937             : 
     938           0 : done:
     939           6 :         return NT_STATUS_IS_OK(status);
     940             : }
     941             : 
     942           0 : static int cmp_keynames(char **p1, char **p2)
     943             : {
     944           0 :         return strcasecmp_m(*p1, *p2);
     945             : }
     946             : 
     947             : static bool
     948          10 : write_subkeylist(struct db_context *db, struct regkey *key, char sep)
     949             : {
     950          10 :         cbuf *buf = cbuf_new(talloc_tos());
     951           0 :         size_t i;
     952           0 :         bool ret;
     953             : 
     954          10 :         cbuf_putdw(buf, key->nsubkeys);
     955             : 
     956          40 :         for (i=0; i < key->nsubkeys; i++) {
     957          30 :                 struct regkey *subkey = key->subkeys[i];
     958          30 :                 const char *name = subkey->name;
     959          30 :                 if (name == NULL) {
     960           0 :                         printf("Warning: no explicit name for key %s\n",
     961             :                                subkey->path);
     962           0 :                         name = strrchr_m(subkey->path, sep);
     963           0 :                         assert(name);
     964           0 :                         name ++;
     965             :                 }
     966          30 :                 cbuf_puts(buf, name, -1);
     967          30 :                 cbuf_putc(buf, '\0');
     968             :         }
     969             : 
     970          10 :         ret = dbwrap_store_verbose(db, key->path, cbuf_make_tdb_data(buf));
     971             : 
     972          10 :         talloc_free(buf);
     973          10 :         return ret;
     974             : }
     975             : 
     976           0 : static bool write_sorted(struct db_context *db, struct regkey *key, char sep)
     977             : {
     978           0 :         cbuf *buf = cbuf_new(talloc_tos());
     979           0 :         char *path;
     980           0 :         size_t i;
     981           0 :         bool ret = false;
     982           0 :         char **sorted = talloc_zero_array(buf, char*, key->nsubkeys);
     983           0 :         int offset =  (1 + key->nsubkeys) * sizeof(uint32_t);
     984             : 
     985           0 :         for (i=0; i < key->nsubkeys; i++) {
     986           0 :                 sorted[i] = talloc_strdup_upper(sorted, key->subkeys[i]->name);
     987             :         }
     988           0 :         TYPESAFE_QSORT(sorted, key->nsubkeys, cmp_keynames);
     989             : 
     990           0 :         cbuf_putdw(buf, key->nsubkeys);
     991           0 :         for (i=0; i < key->nsubkeys; i++) {
     992           0 :                 cbuf_putdw(buf, offset);
     993           0 :                 offset += strlen(sorted[i]) + 1;
     994             :         }
     995           0 :         for (i=0; i < key->nsubkeys; i++) {
     996           0 :                 cbuf_puts(buf, sorted[i], -1);
     997           0 :                 cbuf_putc(buf, '\0');
     998             :         }
     999             : 
    1000           0 :         path = talloc_asprintf(buf, "%s%c%s", REG_SORTED_SUBKEYS_PREFIX, sep,
    1001             :                                key->path);
    1002           0 :         if (path == NULL) {
    1003           0 :                 DEBUG(0, ("Out of memory!\n"));
    1004           0 :                 goto done;
    1005             :         }
    1006             : 
    1007           0 :         ret = dbwrap_store_verbose(db, path, cbuf_make_tdb_data(buf));
    1008           0 : done:
    1009           0 :         talloc_free(buf);
    1010           0 :         return ret;
    1011             : }
    1012             : 
    1013           0 : static bool write_values(struct db_context *db, struct regkey *key, char sep)
    1014             : {
    1015           0 :         cbuf *buf = cbuf_new(talloc_tos());
    1016           0 :         char *path;
    1017           0 :         size_t i;
    1018           0 :         bool ret = false;
    1019             : 
    1020           0 :         cbuf_putdw(buf, key->nvalues);
    1021           0 :         for (i=0; i < key->nvalues; i++) {
    1022           0 :                 struct regval *val = key->values[i];
    1023           0 :                 cbuf_puts(buf, val->name, -1);
    1024           0 :                 cbuf_putc(buf, '\0');
    1025           0 :                 cbuf_putdw(buf, val->type);
    1026           0 :                 cbuf_putdw(buf, val->data.length);
    1027           0 :                 cbuf_puts(buf, (void*)val->data.data, val->data.length);
    1028             :         }
    1029             : 
    1030           0 :         path = talloc_asprintf(buf, "%s%c%s", REG_VALUE_PREFIX, sep, key->path);
    1031           0 :         if (path == NULL) {
    1032           0 :                 DEBUG(0, ("Out of memory!\n"));
    1033           0 :                 goto done;
    1034             :         }
    1035             : 
    1036           0 :         ret = dbwrap_store_verbose(db, path, cbuf_make_tdb_data(buf));
    1037           0 : done:
    1038           0 :         talloc_free(buf);
    1039           0 :         return ret;
    1040             : }
    1041             : 
    1042           0 : static bool write_sd(struct db_context *db, struct regkey *key, char sep)
    1043             : {
    1044           0 :         TDB_DATA sd;
    1045           0 :         NTSTATUS status;
    1046           0 :         char *path;
    1047           0 :         bool ret = false;
    1048           0 :         TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
    1049             : 
    1050           0 :         status = marshall_sec_desc(mem_ctx, key->sd, &sd.dptr, &sd.dsize);
    1051           0 :         if (!NT_STATUS_IS_OK(status)) {
    1052           0 :                 printf("marshall sec desc %s failed: %s\n",
    1053             :                        key->path, nt_errstr(status));
    1054           0 :                 goto done;
    1055             :         }
    1056           0 :         path = talloc_asprintf(mem_ctx, "%s%c%s", REG_SECDESC_PREFIX,
    1057             :                                sep, key->path);
    1058           0 :         if (path == NULL) {
    1059           0 :                 DEBUG(0, ("Out of memory!\n"));
    1060           0 :                 goto done;
    1061             :         }
    1062             : 
    1063           0 :         ret = dbwrap_store_verbose(db, path, sd);
    1064           0 : done:
    1065           0 :         talloc_free(mem_ctx);
    1066           0 :         return ret;
    1067             : }
    1068             : 
    1069             : 
    1070           0 : static int check_write_db_action(struct db_record *rec, void *check_ctx)
    1071             : {
    1072           0 :         struct check_ctx *ctx = (struct check_ctx*)check_ctx;
    1073           0 :         TDB_DATA rec_val = dbwrap_record_get_value(rec);
    1074           0 :         struct regkey *key = *(struct regkey**)rec_val.dptr;
    1075           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1076             : 
    1077             :         /* write subkeylist */
    1078           0 :         if ((ctx->version > 2) || (key->nsubkeys > 0) || (key->has_subkeylist)) {
    1079           0 :                 write_subkeylist(ctx->odb, key, ctx->sep);
    1080             :         }
    1081             : 
    1082             :         /* write sorted subkeys */
    1083           0 :         if ((ctx->version < 3) && (key->nsubkeys > 0)) {
    1084           0 :                 write_sorted(ctx->odb, key, ctx->sep);
    1085             :         }
    1086             : 
    1087             :         /* write value list */
    1088           0 :         if (key->nvalues > 0) {
    1089           0 :                 write_values(ctx->odb, key, ctx->sep);
    1090             :         }
    1091             : 
    1092             :         /* write sd */
    1093           0 :         if (key->sd) {
    1094           0 :                 write_sd(ctx->odb, key, ctx->sep);
    1095             :         }
    1096             : 
    1097           0 :         talloc_free(frame);
    1098           0 :         return 0;
    1099             : }
    1100             : 
    1101         450 : static int fix_tree_action(struct db_record *rec, void *check_ctx)
    1102             : {
    1103         450 :         struct check_ctx *ctx = (struct check_ctx*)check_ctx;
    1104         450 :         TDB_DATA rec_key = dbwrap_record_get_key(rec);
    1105         450 :         TDB_DATA rec_val = dbwrap_record_get_value(rec);
    1106         450 :         struct regkey* key = *(struct regkey**)rec_val.dptr;
    1107         450 :         if (ctx->opt.verbose) {
    1108           0 :                 printf("Check Tree: %s\n", key->path);
    1109             :         }
    1110             : 
    1111         450 :         assert (strncmp(key->path, (char*)rec_key.dptr, rec_key.dsize) == 0);
    1112             : 
    1113             :         /* assert(dbwrap_exists(ctx->db, string_term_tdb_data(key->path)) */
    1114             :         /*        == key->exists); */
    1115             : 
    1116         450 :         if (key->needs_update) {
    1117           6 :                 printf("Update key: \"%s\"\n", key->path);
    1118           6 :                 if ((ctx->version > 2) || (key->nsubkeys > 0)) {
    1119           6 :                         write_subkeylist(ctx->odb, key, ctx->sep);
    1120             :                 }
    1121           6 :                 if ((ctx->version <= 2) && (key->nsubkeys > 0)) {
    1122           0 :                         write_sorted(ctx->odb, key, ctx->sep);
    1123             :                 }
    1124           6 :                 if (key->nvalues > 0) {
    1125           0 :                         write_values(ctx->odb, key, ctx->sep);
    1126             :                 }
    1127           6 :                 if (key->sd) {
    1128           0 :                         write_sd(ctx->odb, key, ctx->sep);
    1129             :                 }
    1130         444 :         } else if (!key->has_subkeylist) {
    1131           4 :                 if ((ctx->version > 2) || (key->nsubkeys > 0)) {
    1132           4 :                         printf("Missing subkeylist: %s\n", key->path);
    1133           4 :                         write_subkeylist(ctx->odb, key, ctx->sep);
    1134             :                 }
    1135             :         }
    1136             : 
    1137         450 :         if (key->name == NULL && key->parent->has_subkeylist) {
    1138           0 :                 printf("Key not referenced by the its parents subkeylist: %s\n",
    1139             :                        key->path);
    1140           0 :                 write_subkeylist(ctx->odb, key->parent, ctx->sep);
    1141             :         }
    1142             : 
    1143             : /* XXX check that upcase(name) matches last part of path ??? */
    1144             : 
    1145         450 :         return 0;
    1146             : }
    1147             : 
    1148             : 
    1149             : /* give the same warnings as fix_tree_action */
    1150        1444 : static int check_tree_action(struct db_record *rec, void *check_ctx)
    1151             : {
    1152        1444 :         struct check_ctx *ctx = (struct check_ctx*)check_ctx;
    1153        1444 :         TDB_DATA rec_key = dbwrap_record_get_key(rec);
    1154        1444 :         TDB_DATA rec_val = dbwrap_record_get_value(rec);
    1155        1444 :         struct regkey* key = *(struct regkey**)rec_val.dptr;
    1156        1444 :         if (ctx->opt.verbose) {
    1157           0 :                 printf("Check Tree: %s\n", key->path);
    1158             :         }
    1159             : 
    1160        1444 :         assert (strncmp(key->path, (char*)rec_key.dptr, rec_key.dsize) == 0);
    1161             : 
    1162        1444 :         if (!key->has_subkeylist) {
    1163           4 :                 if ((ctx->version > 2) || (key->nsubkeys > 0)) {
    1164           4 :                         printf("Missing subkeylist: %s\n", key->path);
    1165             :                 }
    1166             :         }
    1167             : 
    1168        1444 :         if (key->name == NULL && key->parent->has_subkeylist) {
    1169           0 :                 printf("Key not referenced by the its parents subkeylist: %s\n",
    1170             :                        key->path);
    1171             :         }
    1172             : 
    1173        1444 :         return 0;
    1174             : }
    1175             : 
    1176           6 : static int delete_invalid_action(struct db_record *rec, void* check_ctx)
    1177             : {
    1178           0 :         NTSTATUS status;
    1179           6 :         struct check_ctx *ctx = (struct check_ctx*)check_ctx;
    1180           6 :         TDB_DATA rec_key = dbwrap_record_get_key(rec);
    1181           6 :         TDB_DATA rec_val = dbwrap_record_get_value(rec);
    1182             : 
    1183             : 
    1184           6 :         printf("Delete key: \"%.*s\"",(int)rec_key.dsize, rec_key.dptr);
    1185           6 :         if (rec_val.dsize > 0) {
    1186           6 :                 printf(" in favour of \"%s\"\n", rec_val.dptr);
    1187             :         } else {
    1188           0 :                 putc('\n', stdout);
    1189             :         }
    1190             : 
    1191           6 :         status = dbwrap_delete(ctx->odb, rec_key);
    1192           6 :         if (!NT_STATUS_IS_OK(status)) {
    1193           0 :                 d_printf("delete key \"%.*s\" failed!\n",
    1194           0 :                          (int)rec_key.dsize, rec_key.dptr);
    1195           0 :                 return -1;
    1196             :         }
    1197           6 :         return 0;
    1198             : }
    1199             : 
    1200          22 : static bool check_ctx_check_tree(struct check_ctx *ctx) {
    1201           0 :         NTSTATUS status;
    1202             : 
    1203          22 :         status = dbwrap_traverse(ctx->reg, check_tree_action, ctx, NULL);
    1204          22 :         if (!NT_STATUS_IS_OK(status)) {
    1205           0 :                 DEBUG(0, ("check traverse failed: %s\n",
    1206             :                           nt_errstr(status)));
    1207           0 :                 return false;
    1208             :         }
    1209          22 :         return true;
    1210             : }
    1211           6 : static bool check_ctx_fix_inplace(struct check_ctx *ctx) {
    1212           0 :         NTSTATUS status;
    1213           6 :         status = dbwrap_traverse(ctx->reg, fix_tree_action, ctx, NULL);
    1214           6 :         if (!NT_STATUS_IS_OK(status)) {
    1215           0 :                 DEBUG(0, ("fix traverse failed: %s\n", nt_errstr(status)));
    1216           0 :                 return false;
    1217             :         }
    1218             : 
    1219           6 :         status = dbwrap_traverse(ctx->del, delete_invalid_action, ctx, NULL);
    1220           6 :         if (!NT_STATUS_IS_OK(status)) {
    1221           0 :                 DEBUG(0, ("delete traverse failed: %s\n", nt_errstr(status)));
    1222           0 :                 return false;
    1223             :         }
    1224             : 
    1225           6 :         if (!dbwrap_store_uint32_verbose(ctx->odb, "INFO/version", ctx->version)) {
    1226           0 :                 DEBUG(0, ("storing version failed: %s\n", nt_errstr(status)));
    1227           0 :                 return false;
    1228             :         }
    1229             : 
    1230           6 :         return true;
    1231             : }
    1232             : 
    1233           0 : static bool check_ctx_write_new_db(struct check_ctx *ctx) {
    1234           0 :         NTSTATUS status;
    1235             : 
    1236           0 :         assert(ctx->odb);
    1237             : 
    1238           0 :         if (ctx->opt.wipe) {
    1239           0 :                 int ret = dbwrap_wipe(ctx->odb);
    1240           0 :                 if (ret != 0) {
    1241           0 :                         DEBUG(0, ("wiping %s failed\n", ctx->opt.output));
    1242           0 :                         return false;
    1243             :                 }
    1244             :         }
    1245             : 
    1246           0 :         status = dbwrap_traverse(ctx->reg, check_write_db_action, ctx, NULL);
    1247           0 :         if (!NT_STATUS_IS_OK(status)) {
    1248           0 :                 DEBUG(0, ("traverse2 failed: %s\n", nt_errstr(status)));
    1249           0 :                 return false;
    1250             :         }
    1251             : 
    1252           0 :         status = dbwrap_store_uint32_bystring(ctx->odb, "INFO/version",
    1253             :                                               ctx->version);
    1254           0 :         if (!NT_STATUS_IS_OK(status)) {
    1255           0 :                 DEBUG(0, ("write version failed: %s\n", nt_errstr(status)));
    1256           0 :                 return false;
    1257             :         }
    1258           0 :         return true;
    1259             : }
    1260             : 
    1261          28 : int net_registry_check_db(const char *name, const struct check_options *opt)
    1262             : {
    1263           0 :         NTSTATUS status;
    1264          28 :         int ret = -1;
    1265          28 :         struct check_ctx *ctx = check_ctx_create(talloc_tos(), name, opt);
    1266          28 :         if (ctx==NULL) {
    1267           0 :                 goto done;
    1268             :         }
    1269             : 
    1270          28 :         d_printf("Check database: %s\n", name);
    1271             : 
    1272             :         /* 1. open output RW */
    1273          28 :         if (!check_ctx_open_output(ctx)) {
    1274           0 :                 goto done;
    1275             :         }
    1276             : 
    1277             :         /* 2. open input RO */
    1278          28 :         if (!check_ctx_open_input(ctx)) {
    1279           0 :                 goto done;
    1280             :         }
    1281             : 
    1282          28 :         if (opt->lock && !check_ctx_transaction_start(ctx)) {
    1283           0 :                 goto done;
    1284             :         }
    1285             : 
    1286          28 :         if (!get_version(ctx)) {
    1287           0 :                 goto done;
    1288             :         }
    1289             : 
    1290          28 :         status = dbwrap_traverse_read(ctx->idb, check_tdb_action, ctx, NULL);
    1291          28 :         if (!NT_STATUS_IS_OK(status)) {
    1292           0 :                 DEBUG(0, ("check traverse failed: %s\n", nt_errstr(status)));
    1293           0 :                 goto done;
    1294             :         }
    1295             : 
    1296          28 :         if (!opt->lock && !check_ctx_transaction_start(ctx)) {
    1297           0 :                 goto done;
    1298             :         }
    1299             : 
    1300          28 :         if (ctx->opt.repair && !ctx->opt.wipe) {
    1301           6 :                 if (!check_ctx_fix_inplace(ctx)) {
    1302           0 :                         goto done;
    1303             :                 }
    1304             :         } else {
    1305          22 :                 if (!check_ctx_check_tree(ctx)) {
    1306           0 :                         goto done;
    1307             :                 }
    1308          22 :                 if (ctx->odb) {
    1309           0 :                         if (!check_ctx_write_new_db(ctx)) {
    1310           0 :                                 goto done;
    1311             :                         }
    1312             :                 }
    1313             :         }
    1314          28 :         ret = 0;
    1315          28 : done:
    1316          28 :         check_ctx_transaction_stop(ctx, ret == 0);
    1317             : 
    1318          28 :         talloc_free(ctx);
    1319          28 :         return ret;
    1320             : }
    1321             : 
    1322             : /*Local Variables:*/
    1323             : /*mode: c*/
    1324             : /*End:*/

Generated by: LCOV version 1.14