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