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_cstr(TDB_DATA d
) {
211 if (tdb_data_is_empty(d
) || (d
.dptr
[d
.dsize
-1] != '\0')) {
214 return strchr((char *)d
.dptr
, '\0') == (char *)&d
.dptr
[d
.dsize
-1];
217 static char* tdb_data_print(TALLOC_CTX
*mem_ctx
, TDB_DATA d
)
219 if (!tdb_data_is_empty(d
)) {
221 cbuf
*ost
= cbuf_new(mem_ctx
);
222 int len
= cbuf_print_quoted(ost
, (const char*)d
.dptr
, d
.dsize
);
224 cbuf_swapptr(ost
, &ret
, 0);
225 talloc_steal(mem_ctx
, ret
);
230 return talloc_strdup(mem_ctx
, "<NULL>");
234 static TDB_DATA
cbuf_make_tdb_data(cbuf
*b
)
236 return make_tdb_data((void*)cbuf_gets(b
, 0), cbuf_getpos(b
));
239 static void remove_all(char *str
, char c
)
252 static char* parent_path(const char *path
, char sep
)
254 const char *p
= strrchr(path
, sep
);
255 return p
? talloc_strndup(talloc_tos(), path
, p
-path
) : NULL
;
258 /* return the regkey corresponding to path, create if not yet existing */
259 static struct regkey
*
260 check_ctx_lookup_key(struct check_ctx
*ctx
, const char *path
) {
261 struct regkey
*ret
= NULL
;
263 TDB_DATA val
= tdb_null
;
269 status
= dbwrap_fetch(ctx
->reg
, ctx
, string_term_tdb_data(path
), &val
);
270 if (NT_STATUS_IS_OK(status
)) {
271 if (ctx
->opt
.verbose
) {
272 printf("Open: %s\n", path
);
274 ret
= *(struct regkey
**)val
.dptr
;
275 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
276 /* not yet existing, create */
278 if (ctx
->opt
.verbose
) {
279 printf("New: %s\n", path
);
281 ret
= talloc_zero(ctx
, struct regkey
);
283 DEBUG(0, ("Out of memory!\n"));
286 ret
->path
= talloc_strdup(ret
, path
);
288 pp
= parent_path(path
, ctx
->sep
);
289 ret
->parent
= check_ctx_lookup_key(ctx
, pp
);
290 regkey_add_subkey(ret
->parent
, ret
);
293 /* the dummy root key has no subkeylist so set the name */
294 if (ret
->parent
== ctx
->root
) {
295 ret
->name
= talloc_strdup(ret
, path
);
298 dbwrap_store(ctx
->reg
, string_term_tdb_data(path
),
299 make_tdb_data((void*)&ret
, sizeof(ret
)), 0);
301 DEBUG(0, ("lookup key: failed to fetch %s: %s\n", path
,
305 talloc_free(val
.dptr
);
309 static struct check_ctx
* check_ctx_create(TALLOC_CTX
*mem_ctx
, const char *db
,
310 const struct check_options
*opt
)
312 struct check_ctx
*ctx
= talloc_zero(mem_ctx
, struct check_ctx
);
315 ctx
->reg
= db_open_rbt(ctx
);
316 ctx
->del
= db_open_rbt(ctx
);
317 ctx
->root
= talloc_zero(ctx
, struct regkey
);
318 ctx
->fname
= talloc_strdup(ctx
, db
);
320 if (opt
->automatic
&& (opt
->output
== NULL
)) {
321 ctx
->opt
.repair
= true;
322 ctx
->opt
.output
= ctx
->fname
;
327 d_fprintf(stderr
, "You can not specify --output "
331 ctx
->opt
.output
= ctx
->fname
;
335 ctx
->default_action
= 'r';
342 static bool check_ctx_open_output(struct check_ctx
*ctx
)
344 int oflags
= O_RDWR
| O_CREAT
;
346 if (ctx
->opt
.output
== NULL
) {
350 if (!ctx
->opt
.repair
) {
351 if (!ctx
->opt
.wipe
) {
354 ctx
->opt
.wipe
= true;
357 ctx
->odb
= db_open(ctx
, ctx
->opt
.output
, 0, TDB_DEFAULT
, oflags
, 0644,
358 DBWRAP_LOCK_ORDER_1
);
359 if (ctx
->odb
== NULL
) {
361 _("Could not open db (%s) for writing: %s\n"),
362 ctx
->opt
.output
, strerror(errno
));
369 static bool check_ctx_open_input(struct check_ctx
*ctx
) {
370 ctx
->idb
= db_open(ctx
, ctx
->fname
, 0, TDB_DEFAULT
, O_RDONLY
, 0,
371 DBWRAP_LOCK_ORDER_1
);
372 if (ctx
->idb
== NULL
) {
374 _("Could not open db (%s) for reading: %s\n"),
375 ctx
->fname
, strerror(errno
));
381 static bool check_ctx_transaction_start(struct check_ctx
*ctx
) {
382 if (ctx
->odb
== NULL
) {
385 if (dbwrap_transaction_start(ctx
->odb
) != 0) {
386 DEBUG(0, ("transaction_start failed\n"));
389 ctx
->transaction
= true;
393 static void check_ctx_transaction_stop(struct check_ctx
*ctx
, bool ok
) {
394 if (!ctx
->transaction
) {
397 if (!ctx
->opt
.test
&& ok
) {
398 d_printf("Commiting changes\n");
399 if (dbwrap_transaction_commit(ctx
->odb
) != 0) {
400 DEBUG(0, ("transaction_commit failed\n"));
403 d_printf("Discarding changes\n");
404 dbwrap_transaction_cancel(ctx
->odb
);
408 static bool read_info(struct check_ctx
*ctx
, const char *key
, TDB_DATA val
)
410 if (val
.dsize
==sizeof(uint32_t) && strcmp(key
, "version")==0) {
411 uint32_t v
= IVAL(val
.dptr
, 0);
412 printf("INFO: %s = %d\n", key
, v
);
415 printf("INFO: %s = <invalid>\n", key
);
419 static bool is_all_upper(const char *str
) {
421 char *tmp
= talloc_strdup(talloc_tos(), str
);
423 ret
= (strcmp(tmp
, str
) == 0);
428 static void move_to_back(struct regkey
*key
, struct regkey
*subkey
)
433 DEBUG(5, ("Move to back subkey \"%s\" of \"%s\"\n",
434 subkey
->path
, key
->path
));
436 for (ptr
=key
->subkeys
; *ptr
!= subkey
; ptr
++)
439 nidx
= ptr
+ 1 - key
->subkeys
;
440 memmove(ptr
, ptr
+1, (key
->nsubkeys
- nidx
) * sizeof(*ptr
));
442 key
->subkeys
[key
->nsubkeys
-1] = subkey
;
445 static void set_subkey_name(struct check_ctx
*ctx
, struct regkey
*key
,
446 const char *name
, int nlen
)
448 char *path
= key
->path
;
449 TALLOC_CTX
*mem_ctx
= talloc_new(talloc_tos());
451 struct regkey
*subkey
;
452 char *nname
= talloc_strndup(mem_ctx
, name
, nlen
);
453 remove_all(nname
, ctx
->sep
);
455 if (strncmp(name
, nname
, nlen
) != 0) {
456 /* XXX interaction: delete/edit */
457 printf("Warning: invalid name: \"%s\" replace with \"%s\"\n",
459 key
->needs_update
= true;
461 p
= talloc_asprintf_strupper_m(mem_ctx
, "%s%c%s",
462 path
, ctx
->sep
, nname
);
463 subkey
= check_ctx_lookup_key(ctx
, p
);
465 bool do_replace
= false;
467 if (strcmp(subkey
->name
, nname
) != 0) {
471 if (is_all_upper(nname
)) {
472 default_action
= 'o';
474 default_action
= 'n';
477 printf("Conflicting subkey names of [%s]: "
478 "old: \"%s\", new: \"%s\"\n",
479 key
->path
, subkey
->name
, nname
);
481 if (ctx
->opt
.output
== NULL
|| ctx
->opt
.automatic
) {
482 action
= default_action
;
485 action
= interact_prompt(
486 "choose spelling [o]ld, [n]ew,"
490 printf("Sorry, edit is not yet "
491 "implemented here...\n");
493 } while (action
== 'e');
502 if (ctx
->opt
.verbose
) {
503 printf("Replacing name: %s: \"%s\""
504 " -> \"%s\"\n", path
,
505 subkey
->name
, nname
);
507 TALLOC_FREE(subkey
->name
);
508 subkey
->name
= talloc_steal(subkey
, nname
);
509 key
->needs_update
= true;
512 if (ctx
->opt
.verbose
) {
513 printf("Set name: %s: \"%s\"\n", path
, nname
);
515 subkey
->name
= talloc_steal(subkey
, nname
);
518 move_to_back(key
, subkey
);
519 TALLOC_FREE(mem_ctx
);
523 read_subkeys(struct check_ctx
*ctx
, const char *path
, TDB_DATA val
, bool update
)
525 uint32_t num_items
, found_items
= 0;
527 struct regkey
*key
= check_ctx_lookup_key(ctx
, path
);
529 key
->needs_update
|= update
;
531 /* printf("SUBKEYS: %s\n", path); */
532 if (key
->has_subkeylist
) {
533 printf("Duplicate subkeylist \"%s\"\n",
535 found_items
= key
->nsubkeys
;
538 /* exists as defined by regdb_key_exists() */
539 key
->has_subkeylist
= true;
541 /* name is set if a key is referenced by the */
542 /* subkeylist of its parent. */
544 if (!tdb_data_read_uint32(&val
, &num_items
) ) {
545 printf("Invalid subkeylist: \"%s\"\n", path
);
549 while (tdb_data_read_cstr(&val
, &subkey
)) {
550 /* printf(" SUBKEY: %s\n", subkey); */
551 set_subkey_name(ctx
, key
, subkey
, strlen(subkey
));
555 if (val
.dsize
!= 0) {
556 printf("Subkeylist of \"%s\": trailing: \"%.*s\"\n",
557 path
, (int)val
.dsize
, val
.dptr
);
558 /* ask: best effort, delete or edit?*/
559 set_subkey_name(ctx
, key
, (char*)val
.dptr
, val
.dsize
);
561 key
->needs_update
= true;
564 if (num_items
!= found_items
) {
565 printf("Subkeylist of \"%s\": invalid number of subkeys, "
566 "expected: %d got: %d\n", path
, num_items
, found_items
);
567 key
->needs_update
= true;
572 static void read_values(struct check_ctx
*ctx
, const char *path
, TDB_DATA val
)
574 struct regkey
*key
= check_ctx_lookup_key(ctx
, path
);
575 uint32_t num_items
, found_items
;
578 /* printf("VALUES: %s\n", path); */
580 if (!tdb_data_read_uint32(&val
, &num_items
) ) {
581 printf("Invalid valuelist: \"%s\"\n", path
);
586 while (tdb_data_read_regval(&val
, &value
)) {
587 /* printf(" VAL: %s type: %s(%d) length: %d\n", value.name, */
588 /* str_regtype(value.type), value.type, */
589 /* (int)value.data.length); */
590 regkey_add_regval(key
, regval_copy(key
, &value
));
594 if (num_items
!= found_items
) {
595 printf("Valuelist of \"%s\": invalid number of values, "
596 "expected: %d got: %d\n", path
, num_items
, found_items
);
597 key
->needs_update
= true;
600 if (val
.dsize
!= 0) {
601 printf("Valuelist of \"%s\": trailing: \"%*s\"\n", path
,
602 (int)val
.dsize
, val
.dptr
);
603 key
->needs_update
= true;
604 /* XXX best effort ??? */
605 /* ZERO_STRUCT(value); */
606 /* if (tdb_data_read_cstr(&val, &value.name) */
607 /* && tdb_data_read_uint32(&val, &value.type)) */
609 /* uint32_t len = -1; */
610 /* tdb_data_read_uint32(&val, &len); */
612 /* found_items ++; */
613 /* regkey_add_regval(key, regval_copy(key, value)); */
616 if (found_items
== 0) {
617 printf("Valuelist of \"%s\" empty\n", path
);
618 key
->needs_update
= true;
622 static bool read_sorted(struct check_ctx
*ctx
, const char *path
, TDB_DATA val
)
624 if (ctx
->version
>= 3) {
628 if ((val
.dptr
== NULL
) || (val
.dsize
<4)) {
633 /* struct regkey *key = check_ctx_lookup_key(ctx, path); */
634 /* printf("SORTED: %s\n", path); */
638 static bool read_sd(struct check_ctx
*ctx
, const char *path
, TDB_DATA val
)
641 struct regkey
*key
= check_ctx_lookup_key(ctx
, path
);
642 /* printf("SD: %s\n", path); */
644 status
= unmarshall_sec_desc(key
, val
.dptr
, val
.dsize
, &key
->sd
);
645 if (!NT_STATUS_IS_OK(status
)) {
646 DEBUG(0, ("Failed to read SD of %s: %s\n",
647 path
, nt_errstr(status
)));
652 static bool srprs_path(const char **ptr
, const char* prefix
, char sep
,
655 const char *path
, *pos
= *ptr
;
656 if (prefix
!= NULL
) {
657 if (!srprs_str(&pos
, prefix
, -1) || !srprs_char(&pos
, sep
) ) {
662 if ( !srprs_hive(&pos
, NULL
) ) {
665 if ( !srprs_eos(&pos
) && !srprs_char(&pos
, sep
) ) {
669 *ptr
= strchr(pos
, '\0');
673 /* Fixme: this dosn't work in the general multibyte char case.
676 static bool normalize_path_internal(char* path
, char sep
) {
677 size_t len
= strlen(path
);
678 const char *orig
= talloc_strndup(talloc_tos(), path
, len
);
679 char *optr
= path
, *iptr
= path
;
682 while (*iptr
== sep
) {
688 while (*iptr
== sep
) {
702 changed
= (strcmp(orig
, path
) != 0);
703 talloc_free(discard_const(orig
));
707 static bool normalize_path(char* path
, char sep
) {
708 static const char* SEPS
= "\\/";
709 char* firstsep
= strpbrk(path
, SEPS
);
710 bool wrong_sep
= (firstsep
&& (*firstsep
!= sep
));
712 assert (strchr(SEPS
, sep
));
715 string_replace(path
, *firstsep
, sep
);
717 return normalize_path_internal(path
, sep
) || wrong_sep
;
720 static int check_tdb_action(struct db_record
*rec
, void *check_ctx
)
722 struct check_ctx
*ctx
= (struct check_ctx
*)check_ctx
;
723 TALLOC_CTX
*frame
= talloc_stackframe();
724 TDB_DATA val
= dbwrap_record_get_value(rec
);
725 TDB_DATA rec_key
= dbwrap_record_get_key(rec
);
727 bool invalid_path
= false;
729 bool first_iter
= true;
731 if (!tdb_data_is_cstr(rec_key
)) {
732 printf("Key is not zero terminated: \"%.*s\"\ntry to go on.\n",
733 (int)rec_key
.dsize
, rec_key
.dptr
);
736 key
= talloc_strndup(frame
, (char*)rec_key
.dptr
, rec_key
.dsize
);
739 const char *path
, *pos
= key
;
742 if (srprs_str(&pos
, "INFO/", -1)) {
743 if ( read_info(ctx
, pos
, val
) ) {
747 /* ask: mark invalid */
748 } else if (srprs_str(&pos
, "__db_sequence_number__", -1)) {
749 printf("Skip key: \"%.*s\"\n",
750 (int)rec_key
.dsize
, rec_key
.dptr
);
751 /* skip: do nothing + break */
754 } else if (normalize_path(key
, ctx
->sep
)) {
755 printf("Unnormal key: \"%.*s\"\n",
756 (int)rec_key
.dsize
, rec_key
.dptr
);
757 printf("Normalize to: \"%s\"\n", key
);
759 } else if (srprs_path(&pos
, NULL
,
762 read_subkeys(ctx
, path
, val
, invalid_path
);
764 } else if (srprs_path(&pos
, REG_VALUE_PREFIX
,
767 read_values(ctx
, path
, val
);
769 } else if (srprs_path(&pos
, REG_SECDESC_PREFIX
,
772 read_sd(ctx
, path
, val
);
774 } else if (srprs_path(&pos
, REG_SORTED_SUBKEYS_PREFIX
,
777 if (!read_sorted(ctx
, path
, val
)) {
778 /* delete: mark invalid + break */
779 printf("Invalid sorted subkeys for: \"%s\"\n", path
);
785 printf("Unrecognized key: \"%.*s\"\n",
786 (int)rec_key
.dsize
, rec_key
.dptr
);
791 unsigned char action
;
792 if (ctx
->opt
.output
== NULL
) {
793 action
= first_iter
? 'r' : 's';
794 } else if (ctx
->opt
.automatic
) {
795 action
= first_iter
? 'r' : 'd';
796 } else if (ctx
->auto_action
!= '\0') {
797 action
= ctx
->auto_action
;
799 action
= interact_prompt("[s]kip,[S]kip all,"
800 "[d]elete,[D]elete all"
803 ctx
->default_action
);
805 if (isupper(action
)) {
806 action
= tolower(action
);
807 ctx
->auto_action
= action
;
809 ctx
->default_action
= action
;
812 invalid_path
= false;
814 case 'd': /* delete */
818 case 'e': /* edit */ {
819 char *p
= interact_edit(frame
, key
);
825 case 'r': /* retry */
834 dbwrap_store(ctx
->del
, rec_key
, string_term_tdb_data(key
), 0);
841 static bool get_version(struct check_ctx
*ctx
) {
842 static const uint32_t curr_version
= REGDB_CODE_VERSION
;
843 uint32_t version
= ctx
->opt
.version
? ctx
->opt
.version
: curr_version
;
844 uint32_t info_version
= 0;
847 status
= dbwrap_fetch_uint32(ctx
->idb
, "INFO/version", &info_version
);
848 if (!NT_STATUS_IS_OK(status
)) {
849 printf("Warning: no INFO/version found!\n");
850 /* info_version = guess_version(ctx); */
853 if (ctx
->opt
.version
) {
854 version
= ctx
->opt
.version
;
855 } else if (ctx
->opt
.implicit_db
) {
856 version
= curr_version
;
858 version
= info_version
;
862 printf("Couldn't determine registry format version, "
863 "specify with --reg-version\n");
868 if ( version
!= info_version
) {
869 if (ctx
->opt
.force
|| !ctx
->opt
.repair
) {
870 printf("Warning: overwrite registry format "
871 "version %d with %d\n", info_version
, version
);
873 printf("Warning: found registry format version %d but "
874 "expected %d, use --force to proceed.\n", info_version
, version
);
879 ctx
->version
= version
;
880 ctx
->sep
= (version
> 1) ? '\\' : '/';
886 dbwrap_store_verbose(struct db_context
*db
, const char *key
, TDB_DATA nval
)
888 TALLOC_CTX
*mem_ctx
= talloc_new(talloc_tos());
892 status
= dbwrap_fetch_bystring(db
, mem_ctx
, key
, &oval
);
893 if (NT_STATUS_IS_OK(status
)) {
894 if (tdb_data_equal(nval
, oval
)) {
897 printf("store %s:\n overwrite: %s\n with: %s\n", key
,
898 tdb_data_print(mem_ctx
, oval
),
899 tdb_data_print(mem_ctx
, nval
));
901 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
902 printf("store %s:\n write: %s\n", key
,
903 tdb_data_print(mem_ctx
, nval
));
905 printf ("store %s:\n failed to fetch old value: %s\n", key
,
910 status
= dbwrap_store_bystring(db
, key
, nval
, 0);
911 if (!NT_STATUS_IS_OK(status
)) {
912 printf ("store %s failed: %s\n", key
, nt_errstr(status
));
916 talloc_free(mem_ctx
);
917 return NT_STATUS_IS_OK(status
);
921 dbwrap_store_uint32_verbose(struct db_context
*db
, const char *key
, uint32_t nval
)
926 status
= dbwrap_fetch_uint32(db
, key
, &oval
);
927 if (NT_STATUS_IS_OK(status
)) {
931 printf("store %s:\n overwrite: %d\n with: %d\n", key
,
932 (int)oval
, (int)nval
);
934 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
935 printf("store %s:\n write: %d\n", key
, (int)nval
);
937 printf ("store %s:\n failed to fetch old value: %s\n", key
,
942 status
= dbwrap_store_uint32(db
, key
, nval
);
943 if (!NT_STATUS_IS_OK(status
)) {
944 printf ("store %s failed: %s\n", key
, nt_errstr(status
));
948 return NT_STATUS_IS_OK(status
);
951 static int cmp_keynames(char **p1
, char **p2
)
953 return strcasecmp_m(*p1
, *p2
);
957 write_subkeylist(struct db_context
*db
, struct regkey
*key
, char sep
)
959 cbuf
*buf
= cbuf_new(talloc_tos());
963 cbuf_putdw(buf
, key
->nsubkeys
);
965 for (i
=0; i
< key
->nsubkeys
; i
++) {
966 struct regkey
*subkey
= key
->subkeys
[i
];
967 const char *name
= subkey
->name
;
969 printf("Warning: no explicite name for key %s\n",
971 name
= strrchr_m(subkey
->path
, sep
);
975 cbuf_puts(buf
, name
, -1);
976 cbuf_putc(buf
, '\0');
979 ret
= dbwrap_store_verbose(db
, key
->path
, cbuf_make_tdb_data(buf
));
985 static bool write_sorted(struct db_context
*db
, struct regkey
*key
, char sep
)
987 cbuf
*buf
= cbuf_new(talloc_tos());
991 char **sorted
= talloc_zero_array(buf
, char*, key
->nsubkeys
);
992 int offset
= (1 + key
->nsubkeys
) * sizeof(uint32_t);
994 for (i
=0; i
< key
->nsubkeys
; i
++) {
995 sorted
[i
] = talloc_strdup_upper(sorted
, key
->subkeys
[i
]->name
);
997 TYPESAFE_QSORT(sorted
, key
->nsubkeys
, cmp_keynames
);
999 cbuf_putdw(buf
, key
->nsubkeys
);
1000 for (i
=0; i
< key
->nsubkeys
; i
++) {
1001 cbuf_putdw(buf
, offset
);
1002 offset
+= strlen(sorted
[i
]) + 1;
1004 for (i
=0; i
< key
->nsubkeys
; i
++) {
1005 cbuf_puts(buf
, sorted
[i
], -1);
1006 cbuf_putc(buf
, '\0');
1009 path
= talloc_asprintf(buf
, "%s%c%s", REG_SORTED_SUBKEYS_PREFIX
, sep
,
1012 DEBUG(0, ("Out of memory!\n"));
1016 ret
= dbwrap_store_verbose(db
, path
, cbuf_make_tdb_data(buf
));
1022 static bool write_values(struct db_context
*db
, struct regkey
*key
, char sep
)
1024 cbuf
*buf
= cbuf_new(talloc_tos());
1029 cbuf_putdw(buf
, key
->nvalues
);
1030 for (i
=0; i
< key
->nvalues
; i
++) {
1031 struct regval
*val
= key
->values
[i
];
1032 cbuf_puts(buf
, val
->name
, -1);
1033 cbuf_putc(buf
, '\0');
1034 cbuf_putdw(buf
, val
->type
);
1035 cbuf_putdw(buf
, val
->data
.length
);
1036 cbuf_puts(buf
, (void*)val
->data
.data
, val
->data
.length
);
1039 path
= talloc_asprintf(buf
, "%s%c%s", REG_VALUE_PREFIX
, sep
, key
->path
);
1041 DEBUG(0, ("Out of memory!\n"));
1045 ret
= dbwrap_store_verbose(db
, path
, cbuf_make_tdb_data(buf
));
1051 static bool write_sd(struct db_context
*db
, struct regkey
*key
, char sep
)
1057 TALLOC_CTX
*mem_ctx
= talloc_new(talloc_tos());
1059 status
= marshall_sec_desc(mem_ctx
, key
->sd
, &sd
.dptr
, &sd
.dsize
);
1060 if (!NT_STATUS_IS_OK(status
)) {
1061 printf("marshall sec desc %s failed: %s\n",
1062 key
->path
, nt_errstr(status
));
1065 path
= talloc_asprintf(mem_ctx
, "%s%c%s", REG_SECDESC_PREFIX
,
1068 DEBUG(0, ("Out of memory!\n"));
1072 ret
= dbwrap_store_verbose(db
, path
, sd
);
1074 talloc_free(mem_ctx
);
1079 static int check_write_db_action(struct db_record
*rec
, void *check_ctx
)
1081 struct check_ctx
*ctx
= (struct check_ctx
*)check_ctx
;
1082 TDB_DATA rec_val
= dbwrap_record_get_value(rec
);
1083 struct regkey
*key
= *(struct regkey
**)rec_val
.dptr
;
1084 TALLOC_CTX
*frame
= talloc_stackframe();
1086 /* write subkeylist */
1087 if ((ctx
->version
> 2) || (key
->nsubkeys
> 0) || (key
->has_subkeylist
)) {
1088 write_subkeylist(ctx
->odb
, key
, ctx
->sep
);
1091 /* write sorted subkeys */
1092 if ((ctx
->version
< 3) && (key
->nsubkeys
> 0)) {
1093 write_sorted(ctx
->odb
, key
, ctx
->sep
);
1096 /* write value list */
1097 if (key
->nvalues
> 0) {
1098 write_values(ctx
->odb
, key
, ctx
->sep
);
1103 write_sd(ctx
->odb
, key
, ctx
->sep
);
1110 static int fix_tree_action(struct db_record
*rec
, void *check_ctx
)
1112 struct check_ctx
*ctx
= (struct check_ctx
*)check_ctx
;
1113 TDB_DATA rec_key
= dbwrap_record_get_key(rec
);
1114 TDB_DATA rec_val
= dbwrap_record_get_value(rec
);
1115 struct regkey
* key
= *(struct regkey
**)rec_val
.dptr
;
1116 if (ctx
->opt
.verbose
) {
1117 printf("Check Tree: %s\n", key
->path
);
1120 assert (strncmp(key
->path
, (char*)rec_key
.dptr
, rec_key
.dsize
) == 0);
1122 /* assert(dbwrap_exists(ctx->db, string_term_tdb_data(key->path)) */
1123 /* == key->exists); */
1125 if (key
->needs_update
) {
1126 printf("Update key: \"%s\"\n", key
->path
);
1127 if ((ctx
->version
> 2) || (key
->nsubkeys
> 0)) {
1128 write_subkeylist(ctx
->odb
, key
, ctx
->sep
);
1130 if ((ctx
->version
<= 2) && (key
->nsubkeys
> 0)) {
1131 write_sorted(ctx
->odb
, key
, ctx
->sep
);
1133 if (key
->nvalues
> 0) {
1134 write_values(ctx
->odb
, key
, ctx
->sep
);
1137 write_sd(ctx
->odb
, key
, ctx
->sep
);
1139 } else if (!key
->has_subkeylist
) {
1140 if ((ctx
->version
> 2) || (key
->nsubkeys
> 0)) {
1141 printf("Missing subkeylist: %s\n", key
->path
);
1142 write_subkeylist(ctx
->odb
, key
, ctx
->sep
);
1146 if (key
->name
== NULL
&& key
->parent
->has_subkeylist
) {
1147 printf("Key not referenced by the its parents subkeylist: %s\n",
1149 write_subkeylist(ctx
->odb
, key
->parent
, ctx
->sep
);
1152 /* XXX check that upcase(name) matches last part of path ??? */
1158 /* give the same warnings as fix_tree_action */
1159 static int check_tree_action(struct db_record
*rec
, void *check_ctx
)
1161 struct check_ctx
*ctx
= (struct check_ctx
*)check_ctx
;
1162 TDB_DATA rec_key
= dbwrap_record_get_key(rec
);
1163 TDB_DATA rec_val
= dbwrap_record_get_value(rec
);
1164 struct regkey
* key
= *(struct regkey
**)rec_val
.dptr
;
1165 if (ctx
->opt
.verbose
) {
1166 printf("Check Tree: %s\n", key
->path
);
1169 assert (strncmp(key
->path
, (char*)rec_key
.dptr
, rec_key
.dsize
) == 0);
1171 if (!key
->has_subkeylist
) {
1172 if ((ctx
->version
> 2) || (key
->nsubkeys
> 0)) {
1173 printf("Missing subkeylist: %s\n", key
->path
);
1177 if (key
->name
== NULL
&& key
->parent
->has_subkeylist
) {
1178 printf("Key not referenced by the its parents subkeylist: %s\n",
1185 static int delete_invalid_action(struct db_record
*rec
, void* check_ctx
)
1188 struct check_ctx
*ctx
= (struct check_ctx
*)check_ctx
;
1189 TDB_DATA rec_key
= dbwrap_record_get_key(rec
);
1190 TDB_DATA rec_val
= dbwrap_record_get_value(rec
);
1193 printf("Delete key: \"%.*s\"",(int)rec_key
.dsize
, rec_key
.dptr
);
1194 if (rec_val
.dsize
> 0) {
1195 printf(" in favour of \"%s\"\n", rec_val
.dptr
);
1200 status
= dbwrap_delete(ctx
->odb
, rec_key
);
1201 if (!NT_STATUS_IS_OK(status
)) {
1202 d_printf("delete key \"%.*s\" failed!\n",
1203 (int)rec_key
.dsize
, rec_key
.dptr
);
1209 static bool check_ctx_check_tree(struct check_ctx
*ctx
) {
1212 status
= dbwrap_traverse(ctx
->reg
, check_tree_action
, ctx
, NULL
);
1213 if (!NT_STATUS_IS_OK(status
)) {
1214 DEBUG(0, ("check traverse failed: %s\n",
1215 nt_errstr(status
)));
1220 static bool check_ctx_fix_inplace(struct check_ctx
*ctx
) {
1222 status
= dbwrap_traverse(ctx
->reg
, fix_tree_action
, ctx
, NULL
);
1223 if (!NT_STATUS_IS_OK(status
)) {
1224 DEBUG(0, ("fix traverse failed: %s\n", nt_errstr(status
)));
1228 status
= dbwrap_traverse(ctx
->del
, delete_invalid_action
, ctx
, NULL
);
1229 if (!NT_STATUS_IS_OK(status
)) {
1230 DEBUG(0, ("delete traverse failed: %s\n", nt_errstr(status
)));
1234 if (!dbwrap_store_uint32_verbose(ctx
->odb
, "INFO/version", ctx
->version
)) {
1235 DEBUG(0, ("storing version failed: %s\n", nt_errstr(status
)));
1242 static bool check_ctx_write_new_db(struct check_ctx
*ctx
) {
1247 if (ctx
->opt
.wipe
) {
1248 int ret
= dbwrap_wipe(ctx
->odb
);
1250 DEBUG(0, ("wiping %s failed\n", ctx
->opt
.output
));
1255 status
= dbwrap_traverse(ctx
->reg
, check_write_db_action
, ctx
, NULL
);
1256 if (!NT_STATUS_IS_OK(status
)) {
1257 DEBUG(0, ("traverse2 failed: %s\n", nt_errstr(status
)));
1261 status
= dbwrap_store_uint32(ctx
->odb
,
1262 "INFO/version", ctx
->version
);
1263 if (!NT_STATUS_IS_OK(status
)) {
1264 DEBUG(0, ("write version failed: %s\n", nt_errstr(status
)));
1270 int net_registry_check_db(const char *name
, const struct check_options
*opt
)
1274 struct check_ctx
*ctx
= check_ctx_create(talloc_tos(), name
, opt
);
1279 d_printf("Check database: %s\n", name
);
1281 /* 1. open output RW */
1282 if (!check_ctx_open_output(ctx
)) {
1286 /* 2. open input RO */
1287 if (!check_ctx_open_input(ctx
)) {
1291 if (opt
->lock
&& !check_ctx_transaction_start(ctx
)) {
1295 if (!get_version(ctx
)) {
1299 status
= dbwrap_traverse_read(ctx
->idb
, check_tdb_action
, ctx
, NULL
);
1300 if (!NT_STATUS_IS_OK(status
)) {
1301 DEBUG(0, ("check traverse failed: %s\n", nt_errstr(status
)));
1305 if (!opt
->lock
&& !check_ctx_transaction_start(ctx
)) {
1309 if (ctx
->opt
.repair
&& !ctx
->opt
.wipe
) {
1310 if (!check_ctx_fix_inplace(ctx
)) {
1314 if (!check_ctx_check_tree(ctx
)) {
1318 if (!check_ctx_write_new_db(ctx
)) {
1325 check_ctx_transaction_stop(ctx
, ret
== 0);
1331 /*Local Variables:*/