2 * Samba Unix/Linux SMB client library
4 * Copyright (C) Gregor Beck 2011
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.
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.
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/>.
21 * @brief Check the registry database.
22 * @author Gregor Beck <gb@sernet.de>
26 #include "net_registry_check.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"
34 #include "libcli/security/dom_sid.h"
35 #include "libcli/security/secdesc.h"
40 #include "registry/reg_db.h"
41 #include "libcli/registry/util_reg.h"
42 #include "registry/reg_parse_internal.h"
47 + every key has a subkeylist
48 + every key is referenced by the subkeylist of its parent
50 + starts with valid hive
51 + UTF-8 (option to convert ???)
55 + REG_DWORD has size 4
56 + REG_QWORD has size 8
57 + STRINGS are zero terminated UTF-16
71 struct regkey *parent;
73 struct regkey **subkeys;
75 struct regval **values;
76 struct security_descriptor *sd;
81 struct check_options opt;
85 struct db_context *idb;
86 struct db_context *odb;
88 struct regkey *root; /*dummy key to hold all basekeys*/
89 struct db_context *reg;
90 struct db_context *del;
97 static void* talloc_array_append(void *mem_ctx, void* array[], void *ptr)
99 size_t size = array ? talloc_array_length(array) : 1;
100 void **tmp = talloc_realloc(mem_ctx, array, void*, size + 1);
110 static void regkey_add_subkey(struct regkey *key, struct regkey *subkey)
112 key->subkeys = (struct regkey**)
113 talloc_array_append(key, (void**)key->subkeys, subkey);
114 if (key->subkeys != NULL) {
119 static struct regval* regval_copy(TALLOC_CTX *mem_ctx, const struct regval *val)
121 struct regval *ret = talloc_zero(mem_ctx, struct regval);
126 ret->name = talloc_strdup(ret, val->name);
127 if (ret->name == NULL) {
131 ret->data = data_blob_dup_talloc(ret, val->data);
132 if (ret->data.data == NULL) {
136 ret->type = val->type;
144 static void regkey_add_regval(struct regkey *key, struct regval *val)
146 key->values = (struct regval**)
147 talloc_array_append(key, (void**)key->values, val);
148 if (key->values != NULL) {
153 static bool tdb_data_read_uint32(TDB_DATA *buf, uint32_t *result)
155 const size_t len = sizeof(uint32_t);
156 if (buf->dsize >= len) {
157 *result = IVAL(buf->dptr, 0);
165 static bool tdb_data_read_cstr(TDB_DATA *buf, char **result)
167 const size_t len = strnlen((char*)buf->dptr, buf->dsize) + 1;
168 if (buf->dsize >= len) {
169 *result = (char*)buf->dptr;
177 static bool tdb_data_read_blob(TDB_DATA *buf, DATA_BLOB *result)
181 if (!tdb_data_read_uint32(&tmp, &len)) {
184 if (tmp.dsize >= len) {
186 result->data = tmp.dptr;
187 result->length = len;
195 static bool tdb_data_read_regval(TDB_DATA *buf, struct regval *result)
199 if (!tdb_data_read_cstr(&tmp, &value.name)
200 || !tdb_data_read_uint32(&tmp, &value.type)
201 || !tdb_data_read_blob(&tmp, &value.data))
210 static bool tdb_data_is_empty(TDB_DATA d) {
211 return (d.dptr == NULL) || (d.dsize == 0);
214 static bool tdb_data_is_cstr(TDB_DATA d) {
215 if (tdb_data_is_empty(d) || (d.dptr[d.dsize-1] != '\0')) {
218 return rawmemchr(d.dptr, '\0') == &d.dptr[d.dsize-1];
221 static char* tdb_data_print(TALLOC_CTX *mem_ctx, TDB_DATA d)
223 if (!tdb_data_is_empty(d)) {
225 cbuf *ost = cbuf_new(mem_ctx);
226 int len = cbuf_print_quoted(ost, (const char*)d.dptr, d.dsize);
228 cbuf_swapptr(ost, &ret, 0);
229 talloc_steal(mem_ctx, ret);
234 return talloc_strdup(mem_ctx, "<NULL>");
238 static TDB_DATA cbuf_make_tdb_data(cbuf *b)
240 return make_tdb_data((void*)cbuf_gets(b, 0), cbuf_getpos(b));
243 static void remove_all(char *str, char c)
256 static void remove_runs(char *str, char c)
274 static char* parent_path(const char *path, char sep)
276 const char *p = strrchr(path, sep);
277 return p ? talloc_strndup(talloc_tos(), path, p-path) : NULL;
280 /* return the regkey corresponding to path, create if not yet existing */
281 static struct regkey*
282 check_ctx_lookup_key(struct check_ctx *ctx, const char *path) {
283 struct regkey *ret = NULL;
291 status = dbwrap_fetch(ctx->reg, ctx, string_term_tdb_data(path), &val);
292 if (!NT_STATUS_IS_OK(status)) {
295 if (val.dptr != NULL) {
296 if (ctx->opt.verbose) {
297 printf("Open: %s\n", path);
299 ret = *(struct regkey**)val.dptr;
301 /* not yet existing, create */
303 if (ctx->opt.verbose) {
304 printf("New: %s\n", path);
306 ret = talloc_zero(ctx, struct regkey);
308 DEBUG(0, ("Out of memory!\n"));
311 ret->path = talloc_strdup(ret, path);
313 pp = parent_path(path, ctx->sep);
314 ret->parent = check_ctx_lookup_key(ctx, pp);
315 regkey_add_subkey(ret->parent, ret);
318 /* the dummy root key has no subkeylist so set the name */
319 if (ret->parent == ctx->root) {
320 ret->name = talloc_strdup(ret, path);
323 dbwrap_store(ctx->reg, string_term_tdb_data(path),
324 make_tdb_data((void*)&ret, sizeof(ret)), 0);
327 talloc_free(val.dptr);
331 static struct check_ctx* check_ctx_create(TALLOC_CTX *mem_ctx, const char *db,
332 const struct check_options *opt)
334 struct check_ctx *ctx = talloc_zero(mem_ctx, struct check_ctx);
337 ctx->reg = db_open_rbt(ctx);
338 ctx->del = db_open_rbt(ctx);
339 ctx->root = talloc_zero(ctx, struct regkey);
340 ctx->fname = talloc_strdup(ctx, db);
342 if (opt->automatic && (opt->output == NULL)) {
343 ctx->opt.repair = true;
344 ctx->opt.output = ctx->fname;
349 d_fprintf(stderr, "You can not specify --output "
353 ctx->opt.output = ctx->fname;
357 ctx->default_action = opt->automatic ? 'd' : 'r';
364 static bool check_ctx_open_output(struct check_ctx *ctx)
366 int oflags = O_RDWR | O_CREAT ;
368 if (ctx->opt.output == NULL) {
372 if (!ctx->opt.repair) {
373 if (!ctx->opt.wipe) {
376 ctx->opt.wipe = true;
379 ctx->odb = db_open(ctx, ctx->opt.output, 0, TDB_DEFAULT, oflags, 0644);
380 if (ctx->odb == NULL) {
382 _("Could not open db (%s) for writing: %s\n"),
383 ctx->opt.output, strerror(errno));
390 static bool check_ctx_open_input(struct check_ctx *ctx) {
391 ctx->idb = db_open(ctx, ctx->fname, 0, TDB_DEFAULT, O_RDONLY, 0);
392 if (ctx->idb == NULL) {
394 _("Could not open db (%s) for reading: %s\n"),
395 ctx->fname, strerror(errno));
401 static bool check_ctx_transaction_start(struct check_ctx *ctx) {
402 if (ctx->odb == NULL) {
405 if (dbwrap_transaction_start(ctx->odb) != 0) {
406 DEBUG(0, ("transaction_start failed\n"));
409 ctx->transaction = true;
413 static void check_ctx_transaction_stop(struct check_ctx *ctx, bool ok) {
414 if (!ctx->transaction) {
417 if (!ctx->opt.test && ok) {
418 d_printf("Commiting changes\n");
419 if (dbwrap_transaction_commit(ctx->odb) != 0) {
420 DEBUG(0, ("transaction_commit failed\n"));
423 d_printf("Discarding changes\n");
424 dbwrap_transaction_cancel(ctx->odb);
428 static bool read_info(struct check_ctx *ctx, const char *key, TDB_DATA val)
430 if (val.dsize==sizeof(uint32_t) && strcmp(key, "version")==0) {
431 uint32_t v = IVAL(val.dptr, 0);
432 printf("INFO: %s = %d\n", key, v);
435 printf("INFO: %s = <invalid>\n", key);
439 static bool is_all_upper(const char *str) {
441 char *tmp = talloc_strdup(talloc_tos(), str);
443 ret = (strcmp(tmp, str) == 0);
448 static void move_to_back(struct regkey *key, struct regkey *subkey)
453 DEBUG(5, ("Move to back subkey \"%s\" of \"%s\"\n",
454 subkey->path, key->path));
456 for (ptr=key->subkeys; *ptr != subkey; ptr++)
459 nidx = ptr + 1 - key->subkeys;
460 memmove(ptr, ptr+1, (key->nsubkeys - nidx) * sizeof(*ptr));
462 key->subkeys[key->nsubkeys-1] = subkey;
465 static void set_subkey_name(struct check_ctx *ctx, struct regkey *key,
466 const char *name, int nlen)
468 char *path = key->path;
469 TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
471 struct regkey *subkey;
472 char *nname = talloc_strndup(mem_ctx, name, nlen);
473 remove_all(nname, ctx->sep);
475 if (strncmp(name, nname, nlen) != 0) {
476 /* XXX interaction: delete/edit */
477 printf("Warning: invalid name: \"%s\" replace with \"%s\"\n",
479 key->needs_update = true;
481 p = talloc_asprintf_strupper_m(mem_ctx, "%s%c%s",
482 path, ctx->sep, nname);
483 subkey = check_ctx_lookup_key(ctx, p);
485 bool do_replace = false;
487 if (strcmp(subkey->name, nname) != 0) {
491 if (is_all_upper(nname)) {
492 default_action = 'o';
494 default_action = 'n';
497 printf("Conflicting subkey names of [%s]: "
498 "old: \"%s\", new: \"%s\"\n",
499 key->path, subkey->name, nname);
501 if (ctx->opt.output == NULL || ctx->opt.automatic) {
502 action = default_action;
505 action = interact_prompt(
506 "choose spelling [o]ld, [n]ew,"
510 printf("Sorry, edit is not yet "
511 "implemented here...\n");
513 } while (action == 'e');
522 if (ctx->opt.verbose) {
523 printf("Replacing name: %s: \"%s\""
524 " -> \"%s\"\n", path,
525 subkey->name, nname);
527 TALLOC_FREE(subkey->name);
528 subkey->name = talloc_steal(subkey, nname);
529 key->needs_update = true;
532 if (ctx->opt.verbose) {
533 printf("Set name: %s: \"%s\"\n", path, nname);
535 subkey->name = talloc_steal(subkey, nname);
538 move_to_back(key, subkey);
539 TALLOC_FREE(mem_ctx);
543 read_subkeys(struct check_ctx *ctx, const char *path, TDB_DATA val, bool update)
545 uint32_t num_items, found_items = 0;
547 struct regkey *key = check_ctx_lookup_key(ctx, path);
549 key->needs_update |= update;
551 /* printf("SUBKEYS: %s\n", path); */
552 if (key->has_subkeylist) {
553 printf("Duplicate subkeylist \"%s\"\n",
555 found_items = key->nsubkeys;
558 /* exists as defined by regdb_key_exists() */
559 key->has_subkeylist = true;
561 /* name is set if a key is referenced by the */
562 /* subkeylist of its parent. */
564 if (!tdb_data_read_uint32(&val, &num_items) ) {
565 printf("Invalid subkeylist: \"%s\"\n", path);
569 while (tdb_data_read_cstr(&val, &subkey)) {
570 /* printf(" SUBKEY: %s\n", subkey); */
571 set_subkey_name(ctx, key, subkey, strlen(subkey));
575 if (val.dsize != 0) {
576 printf("Subkeylist of \"%s\": trailing: \"%.*s\"\n",
577 path, (int)val.dsize, val.dptr);
578 /* ask: best effort, delete or edit?*/
579 set_subkey_name(ctx, key, (char*)val.dptr, val.dsize);
581 key->needs_update = true;
584 if (num_items != found_items) {
585 printf("Subkeylist of \"%s\": invalid number of subkeys, "
586 "expected: %d got: %d\n", path, num_items, found_items);
587 key->needs_update = true;
592 static void read_values(struct check_ctx *ctx, const char *path, TDB_DATA val)
594 struct regkey *key = check_ctx_lookup_key(ctx, path);
595 uint32_t num_items, found_items;
598 /* printf("VALUES: %s\n", path); */
600 if (!tdb_data_read_uint32(&val, &num_items) ) {
601 printf("Invalid valuelist: \"%s\"\n", path);
606 while (tdb_data_read_regval(&val, &value)) {
607 /* printf(" VAL: %s type: %s(%d) length: %d\n", value.name, */
608 /* str_regtype(value.type), value.type, */
609 /* (int)value.data.length); */
610 regkey_add_regval(key, regval_copy(key, &value));
614 if (num_items != found_items) {
615 printf("Valuelist of \"%s\": invalid number of values, "
616 "expected: %d got: %d\n", path, num_items, found_items);
617 key->needs_update = true;
620 if (val.dsize != 0) {
621 printf("Valuelist of \"%s\": trailing: \"%*s\"\n", path,
622 (int)val.dsize, val.dptr);
623 key->needs_update = true;
624 /* XXX best effort ??? */
625 /* ZERO_STRUCT(value); */
626 /* if (tdb_data_read_cstr(&val, &value.name) */
627 /* && tdb_data_read_uint32(&val, &value.type)) */
629 /* uint32_t len = -1; */
630 /* tdb_data_read_uint32(&val, &len); */
632 /* found_items ++; */
633 /* regkey_add_regval(key, regval_copy(key, value)); */
636 if (found_items == 0) {
637 printf("Valuelist of \"%s\" empty\n", path);
638 key->needs_update = true;
642 static bool read_sorted(struct check_ctx *ctx, const char *path, TDB_DATA val)
644 if (ctx->version >= 3) {
648 if ((val.dptr == NULL) || (val.dsize<4)) {
653 /* struct regkey *key = check_ctx_lookup_key(ctx, path); */
654 /* printf("SORTED: %s\n", path); */
658 static bool read_sd(struct check_ctx *ctx, const char *path, TDB_DATA val)
661 struct regkey *key = check_ctx_lookup_key(ctx, path);
662 /* printf("SD: %s\n", path); */
664 status = unmarshall_sec_desc(key, val.dptr, val.dsize, &key->sd);
665 if (!NT_STATUS_IS_OK(status)) {
666 DEBUG(0, ("Failed to read SD of %s: %s\n",
667 path, nt_errstr(status)));
672 static bool srprs_path(const char **ptr, const char* prefix, char sep,
675 const char *path, *pos = *ptr;
676 if (prefix != NULL) {
677 if (!srprs_str(&pos, prefix, -1) || !srprs_char(&pos, sep) ) {
682 if ( !srprs_hive(&pos, NULL) ) {
685 if ( !srprs_eos(&pos) && !srprs_char(&pos, sep) ) {
689 *ptr = rawmemchr(pos, '\0');
693 /* Fixme: this dosn't work in the general multibyte char case.
696 static bool normalize_path_internal(char* path, char sep) {
697 size_t len = strlen(path);
698 const char *orig = talloc_strndup(talloc_tos(), path, len);
699 char *optr = path, *iptr = path;
702 while (*iptr == sep ) {
708 while (*iptr == sep) {
722 changed = (strcmp(orig, path) != 0);
723 talloc_free(discard_const(orig));
727 static bool normalize_path(char* path, char sep) {
728 static const char* SEPS = "\\/";
729 char* firstsep = strpbrk(path, SEPS);
731 assert (strchr(SEPS, sep));
733 if (firstsep && (*firstsep != sep)) {
734 string_replace(path, *firstsep, sep);
736 return normalize_path_internal(path, sep);
739 static int check_tdb_action(struct db_record *rec, void *check_ctx)
741 struct check_ctx *ctx = (struct check_ctx*)check_ctx;
742 TALLOC_CTX *frame = talloc_stackframe();
743 TDB_DATA val = dbwrap_record_get_value(rec);
744 TDB_DATA rec_key = dbwrap_record_get_key(rec);
746 bool invalid_path = false;
749 if (!tdb_data_is_cstr(rec_key)) {
750 printf("Key is not zero terminated: \"%.*s\"\ntry to go on.\n",
751 (int)rec_key.dsize, rec_key.dptr);
754 key = talloc_strndup(frame, (char*)rec_key.dptr, rec_key.dsize);
757 const char *path, *pos = key;
760 if (srprs_str(&pos, "INFO/", -1)) {
761 if ( read_info(ctx, pos, val) ) {
765 /* ask: mark invalid */
766 } else if (srprs_str(&pos, "__db_sequence_number__", -1)) {
767 printf("Skip key: \"%.*s\"\n",
768 (int)rec_key.dsize, rec_key.dptr);
769 /* skip: do nothing + break */
772 } else if (normalize_path(key, ctx->sep)) {
773 printf("Unnormal key: \"%.*s\"\n",
774 (int)rec_key.dsize, rec_key.dptr);
775 printf("Normalize to: \"%s\"\n", key);
777 } else if (srprs_path(&pos, NULL,
780 read_subkeys(ctx, path, val, invalid_path);
782 } else if (srprs_path(&pos, REG_VALUE_PREFIX,
785 read_values(ctx, path, val);
787 } else if (srprs_path(&pos, REG_SECDESC_PREFIX,
790 read_sd(ctx, path, val);
792 } else if (srprs_path(&pos, REG_SORTED_SUBKEYS_PREFIX,
795 if (!read_sorted(ctx, path, val)) {
796 /* delete: mark invalid + break */
797 printf("Invalid sorted subkeys for: \"%s\"\n", path);
803 printf("Unrecognized key: \"%.*s\"\n",
804 (int)rec_key.dsize, rec_key.dptr);
810 if (ctx->opt.output == NULL) {
812 } else if (ctx->opt.automatic) {
813 action = (ctx->default_action == 'r') ? 'd' : 'r';
814 } else if (ctx->auto_action != '\0') {
815 action = ctx->auto_action;
817 action = interact_prompt("[s]kip,[S]kip all,"
818 "[d]elete,[D]elete all"
821 ctx->default_action);
823 if (isupper(action)) {
824 action = tolower(action);
825 ctx->auto_action = action;
827 ctx->default_action = action;
830 invalid_path = false;
832 case 'd': /* delete */
836 case 'e': /* edit */ {
837 char *p = interact_edit(frame, key);
843 case 'r': /* retry */
851 dbwrap_store(ctx->del, rec_key, string_term_tdb_data(key), 0);
858 static bool get_version(struct check_ctx *ctx) {
859 static const uint32_t curr_version = REGDB_CODE_VERSION;
860 uint32_t version = ctx->opt.version ? ctx->opt.version : curr_version;
861 uint32_t info_version = 0;
864 status = dbwrap_fetch_uint32(ctx->idb, "INFO/version", &info_version);
865 if (!NT_STATUS_IS_OK(status)) {
866 printf("Warning: no INFO/version found!\n");
867 /* info_version = guess_version(ctx); */
870 if (ctx->opt.version) {
871 version = ctx->opt.version;
872 } else if (ctx->opt.implicit_db) {
873 version = curr_version;
875 version = info_version;
879 printf("Couldn't determine registry format version, "
880 "specify with --version\n");
885 if ( version != info_version ) {
886 if (ctx->opt.force || !ctx->opt.repair) {
887 printf("Warning: overwrite registry format "
888 "version %d with %d\n", info_version, version);
890 printf("Warning: found registry format version %d but "
891 "expected %d\n", info_version, version);
896 ctx->version = version;
897 ctx->sep = (version > 1) ? '\\' : '/';
903 dbwrap_store_verbose(struct db_context *db, const char *key, TDB_DATA nval)
905 TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
909 status = dbwrap_fetch_bystring(db, mem_ctx, key, &oval);
910 if (!NT_STATUS_IS_OK(status)) {
911 printf ("store %s failed to fetch old value: %s\n", key,
916 if (!tdb_data_is_empty(oval) && !tdb_data_equal(nval, oval)) {
920 key, tdb_data_print(mem_ctx, oval),
921 tdb_data_print(mem_ctx, nval));
924 status = dbwrap_store_bystring(db, key, nval, 0);
925 if (!NT_STATUS_IS_OK(status)) {
926 printf ("store %s failed: %s\n", key, nt_errstr(status));
930 talloc_free(mem_ctx);
931 return NT_STATUS_IS_OK(status);
935 static int cmp_keynames(char **p1, char **p2)
937 return strcasecmp_m(*p1, *p2);
941 write_subkeylist(struct db_context *db, struct regkey *key, char sep)
943 cbuf *buf = cbuf_new(talloc_tos());
947 cbuf_putdw(buf, key->nsubkeys);
949 for (i=0; i < key->nsubkeys; i++) {
950 struct regkey *subkey = key->subkeys[i];
951 const char *name = subkey->name;
953 printf("Warning: no explicite name for key %s\n",
955 name = strrchr_m(subkey->path, sep);
959 cbuf_puts(buf, name, -1);
960 cbuf_putc(buf, '\0');
963 ret = dbwrap_store_verbose(db, key->path, cbuf_make_tdb_data(buf));
969 static bool write_sorted(struct db_context *db, struct regkey *key, char sep)
971 cbuf *buf = cbuf_new(talloc_tos());
975 char **sorted = talloc_zero_array(buf, char*, key->nsubkeys);
976 int offset = (1 + key->nsubkeys) * sizeof(uint32_t);
978 for (i=0; i < key->nsubkeys; i++) {
979 sorted[i] = talloc_strdup_upper(sorted, key->subkeys[i]->name);
981 TYPESAFE_QSORT(sorted, key->nsubkeys, cmp_keynames);
983 cbuf_putdw(buf, key->nsubkeys);
984 for (i=0; i < key->nsubkeys; i++) {
985 cbuf_putdw(buf, offset);
986 offset += strlen(sorted[i]) + 1;
988 for (i=0; i < key->nsubkeys; i++) {
989 cbuf_puts(buf, sorted[i], -1);
990 cbuf_putc(buf, '\0');
993 path = talloc_asprintf(buf, "%s%c%s", REG_SORTED_SUBKEYS_PREFIX, sep,
996 DEBUG(0, ("Out of memory!\n"));
1000 ret = dbwrap_store_verbose(db, path, cbuf_make_tdb_data(buf));
1006 static bool write_values(struct db_context *db, struct regkey *key, char sep)
1008 cbuf *buf = cbuf_new(talloc_tos());
1013 cbuf_putdw(buf, key->nvalues);
1014 for (i=0; i < key->nvalues; i++) {
1015 struct regval *val = key->values[i];
1016 cbuf_puts(buf, val->name, -1);
1017 cbuf_putc(buf, '\0');
1018 cbuf_putdw(buf, val->type);
1019 cbuf_putdw(buf, val->data.length);
1020 cbuf_puts(buf, (void*)val->data.data, val->data.length);
1023 path = talloc_asprintf(buf, "%s%c%s", REG_VALUE_PREFIX, sep, key->path);
1025 DEBUG(0, ("Out of memory!\n"));
1029 ret = dbwrap_store_verbose(db, path, cbuf_make_tdb_data(buf));
1035 static bool write_sd(struct db_context *db, struct regkey *key, char sep)
1041 TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
1043 status = marshall_sec_desc(mem_ctx, key->sd, &sd.dptr, &sd.dsize);
1044 if (!NT_STATUS_IS_OK(status)) {
1045 printf("marshall sec desc %s failed: %s\n",
1046 key->path, nt_errstr(status));
1049 path = talloc_asprintf(mem_ctx, "%s%c%s", REG_SECDESC_PREFIX,
1052 DEBUG(0, ("Out of memory!\n"));
1056 ret = dbwrap_store_verbose(db, path, sd);
1058 talloc_free(mem_ctx);
1063 static int check_write_db_action(struct db_record *rec, void *check_ctx)
1065 struct check_ctx *ctx = (struct check_ctx*)check_ctx;
1066 TDB_DATA rec_val = dbwrap_record_get_value(rec);
1067 struct regkey *key = *(struct regkey**)rec_val.dptr;
1068 TALLOC_CTX *frame = talloc_stackframe();
1070 /* write subkeylist */
1071 if ((ctx->version > 2) || (key->nsubkeys > 0) || (key->has_subkeylist)) {
1072 write_subkeylist(ctx->odb, key, ctx->sep);
1075 /* write sorted subkeys */
1076 if ((ctx->version < 3) && (key->nsubkeys > 0)) {
1077 write_sorted(ctx->odb, key, ctx->sep);
1080 /* write value list */
1081 if (key->nvalues > 0) {
1082 write_values(ctx->odb, key, ctx->sep);
1087 write_sd(ctx->odb, key, ctx->sep);
1094 static int fix_tree_action(struct db_record *rec, void *check_ctx)
1096 struct check_ctx *ctx = (struct check_ctx*)check_ctx;
1097 TDB_DATA rec_key = dbwrap_record_get_key(rec);
1098 TDB_DATA rec_val = dbwrap_record_get_value(rec);
1099 struct regkey* key = *(struct regkey**)rec_val.dptr;
1100 if (ctx->opt.verbose) {
1101 printf("Check Tree: %s\n", key->path);
1104 assert (strncmp(key->path, (char*)rec_key.dptr, rec_key.dsize) == 0);
1106 /* assert(dbwrap_exists(ctx->db, string_term_tdb_data(key->path)) */
1107 /* == key->exists); */
1109 if (key->needs_update) {
1110 printf("Update key: \"%s\"\n", key->path);
1111 if ((ctx->version > 2) || (key->nsubkeys > 0)) {
1112 write_subkeylist(ctx->odb, key, ctx->sep);
1114 if ((ctx->version <= 2) && (key->nsubkeys > 0)) {
1115 write_sorted(ctx->odb, key, ctx->sep);
1117 if (key->nvalues > 0) {
1118 write_values(ctx->odb, key, ctx->sep);
1121 write_sd(ctx->odb, key, ctx->sep);
1123 } else if (!key->has_subkeylist) {
1124 if ((ctx->version > 2) || (key->nsubkeys > 0)) {
1125 printf("Missing subkeylist: %s\n", key->path);
1126 write_subkeylist(ctx->odb, key, ctx->sep);
1130 if (key->name == NULL && key->parent->has_subkeylist) {
1131 printf("Key not referenced by the its parents subkeylist: %s\n",
1133 write_subkeylist(ctx->odb, key->parent, ctx->sep);
1136 /* XXX check that upcase(name) matches last part of path ??? */
1142 /* give the same warnings as fix_tree_action */
1143 static int check_tree_action(struct db_record *rec, void *check_ctx)
1145 struct check_ctx *ctx = (struct check_ctx*)check_ctx;
1146 TDB_DATA rec_key = dbwrap_record_get_key(rec);
1147 TDB_DATA rec_val = dbwrap_record_get_value(rec);
1148 struct regkey* key = *(struct regkey**)rec_val.dptr;
1149 if (ctx->opt.verbose) {
1150 printf("Check Tree: %s\n", key->path);
1153 assert (strncmp(key->path, (char*)rec_key.dptr, rec_key.dsize) == 0);
1155 if (!key->has_subkeylist) {
1156 if ((ctx->version > 2) || (key->nsubkeys > 0)) {
1157 printf("Missing subkeylist: %s\n", key->path);
1161 if (key->name == NULL && key->parent->has_subkeylist) {
1162 printf("Key not referenced by the its parents subkeylist: %s\n",
1169 static int delete_invalid_action(struct db_record *rec, void* check_ctx)
1172 struct check_ctx *ctx = (struct check_ctx*)check_ctx;
1173 TDB_DATA rec_key = dbwrap_record_get_key(rec);
1174 TDB_DATA rec_val = dbwrap_record_get_value(rec);
1177 printf("Delete key: \"%.*s\"",(int)rec_key.dsize, rec_key.dptr);
1178 if (rec_val.dsize > 0) {
1179 printf(" in favour of \"%s\"\n", rec_val.dptr);
1184 status = dbwrap_delete(ctx->odb, rec_key);
1185 if (!NT_STATUS_IS_OK(status)) {
1186 d_printf("delete key \"%.*s\" failed!\n",
1187 (int)rec_key.dsize, rec_key.dptr);
1193 static bool check_ctx_check_tree(struct check_ctx *ctx) {
1196 status = dbwrap_traverse(ctx->reg, check_tree_action, ctx, NULL);
1197 if (!NT_STATUS_IS_OK(status)) {
1198 DEBUG(0, ("check traverse failed: %s\n",
1199 nt_errstr(status)));
1204 static bool check_ctx_fix_inplace(struct check_ctx *ctx) {
1206 status = dbwrap_traverse(ctx->reg, fix_tree_action, ctx, NULL);
1207 if (!NT_STATUS_IS_OK(status)) {
1208 DEBUG(0, ("fix traverse failed: %s\n",
1209 nt_errstr(status)));
1213 status = dbwrap_traverse(ctx->del, delete_invalid_action, ctx, NULL);
1214 if (!NT_STATUS_IS_OK(status)) {
1215 DEBUG(0, ("delete traverse failed: %s\n",
1216 nt_errstr(status)));
1222 static bool check_ctx_write_new_db(struct check_ctx *ctx) {
1227 if (ctx->opt.wipe) {
1228 int ret = dbwrap_wipe(ctx->odb);
1230 DEBUG(0, ("wiping %s failed\n",
1236 status = dbwrap_traverse(ctx->reg, check_write_db_action, ctx, NULL);
1237 if (!NT_STATUS_IS_OK(status)) {
1238 DEBUG(0, ("traverse2 failed: %s\n", nt_errstr(status)));
1242 status = dbwrap_store_uint32(ctx->odb,
1243 "INFO/version", ctx->version);
1244 if (!NT_STATUS_IS_OK(status)) {
1245 DEBUG(0, ("write version failed: %s\n", nt_errstr(status)));
1251 int net_registry_check_db(const char *name, const struct check_options *opt)
1255 struct check_ctx *ctx = check_ctx_create(talloc_tos(), name, opt);
1260 d_printf("Check database: %s\n", name);
1262 /* 1. open output RW */
1263 if (!check_ctx_open_output(ctx)) {
1267 /* 2. open input RO */
1268 if (!check_ctx_open_input(ctx)) {
1272 if (opt->lock && !check_ctx_transaction_start(ctx)) {
1276 if (!get_version(ctx)) {
1280 status = dbwrap_traverse_read(ctx->idb, check_tdb_action, ctx, NULL);
1281 if (!NT_STATUS_IS_OK(status)) {
1282 DEBUG(0, ("check traverse failed: %s\n", nt_errstr(status)));
1286 if (!opt->lock && !check_ctx_transaction_start(ctx)) {
1290 if (ctx->opt.repair && !ctx->opt.wipe) {
1291 if (!check_ctx_fix_inplace(ctx)) {
1295 if (!check_ctx_check_tree(ctx)) {
1299 if (!check_ctx_write_new_db(ctx)) {
1306 check_ctx_transaction_stop(ctx, ret == 0);
1312 /*Local Variables:*/