8cdb8fac5912a5f1bfb9c6c6bf4d6b8550b7efa0
[samba.git] / source3 / utils / net_registry_check.c
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 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
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
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
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
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
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
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
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
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
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
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
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*
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
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
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);
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
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);
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
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
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("Commiting 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
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
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
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
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
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
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
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
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
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 */
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
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
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                         case 'r': /* retry */
815                                 once_more = true;
816                                 break;
817                         }
818                 }
819                 first_iter = false;
820         } while (once_more);
821
822         if (invalid_path) {
823                 dbwrap_store(ctx->del, rec_key, string_term_tdb_data(key), 0);
824         }
825
826         talloc_free(frame);
827         return 0;
828 }
829
830 static bool get_version(struct check_ctx *ctx) {
831         static const uint32_t curr_version = REGDB_CODE_VERSION;
832         uint32_t version = ctx->opt.version ? ctx->opt.version : curr_version;
833         uint32_t info_version = 0;
834         NTSTATUS status;
835
836         status = dbwrap_fetch_uint32_bystring(ctx->idb, "INFO/version",
837                                               &info_version);
838         if (!NT_STATUS_IS_OK(status)) {
839                 printf("Warning: no INFO/version found!\n");
840                 /* info_version = guess_version(ctx); */
841         }
842
843         if (ctx->opt.version) {
844                 version = ctx->opt.version;
845         } else if (ctx->opt.implicit_db) {
846                 version = curr_version;
847         } else {
848                 version = info_version;
849         }
850
851         if (!version) {
852                 printf("Couldn't determine registry format version, "
853                        "specify with --reg-version\n");
854                 return false;
855         }
856
857
858         if ( version != info_version ) {
859                 if (ctx->opt.force || !ctx->opt.repair) {
860                         printf("Warning: overwrite registry format "
861                                "version %d with %d\n", info_version, version);
862                 } else {
863                         printf("Warning: found registry format version %d but "
864                                "expected %d, use --force to proceed.\n", info_version, version);
865                         return false;
866                 }
867         }
868
869         ctx->version = version;
870         ctx->sep = (version > 1) ? '\\' : '/';
871
872         return true;
873 }
874
875 static bool
876 dbwrap_store_verbose(struct db_context *db, const char *key, TDB_DATA nval)
877 {
878         TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
879         TDB_DATA oval;
880         NTSTATUS status;
881
882         status = dbwrap_fetch_bystring(db, mem_ctx, key, &oval);
883         if (NT_STATUS_IS_OK(status)) {
884                 if (tdb_data_equal(nval, oval)) {
885                         goto done;
886                 }
887                 printf("store %s:\n  overwrite: %s\n  with:      %s\n", key,
888                        tdb_data_string(mem_ctx, oval),
889                        tdb_data_string(mem_ctx, nval));
890
891         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
892                 printf("store %s:\n  write: %s\n", key,
893                        tdb_data_string(mem_ctx, nval));
894         } else {
895                 printf ("store %s:\n  failed to fetch old value: %s\n", key,
896                         nt_errstr(status));
897                 goto done;
898         }
899
900         status = dbwrap_store_bystring(db, key, nval, 0);
901         if (!NT_STATUS_IS_OK(status)) {
902                 printf ("store %s failed: %s\n", key, nt_errstr(status));
903         }
904
905 done:
906         talloc_free(mem_ctx);
907         return NT_STATUS_IS_OK(status);
908 }
909
910 static bool
911 dbwrap_store_uint32_verbose(struct db_context *db, const char *key, uint32_t nval)
912 {
913         uint32_t oval;
914         NTSTATUS status;
915
916         status = dbwrap_fetch_uint32_bystring(db, key, &oval);
917         if (NT_STATUS_IS_OK(status)) {
918                 if (nval == oval) {
919                         goto done;
920                 }
921                 printf("store %s:\n overwrite: %d\n with:      %d\n", key,
922                        (int)oval, (int)nval);
923
924         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
925                 printf("store %s:\n write: %d\n", key, (int)nval);
926         } else {
927                 printf ("store %s:\n  failed to fetch old value: %s\n", key,
928                         nt_errstr(status));
929                 goto done;
930         }
931
932         status = dbwrap_store_uint32_bystring(db, key, nval);
933         if (!NT_STATUS_IS_OK(status)) {
934                 printf ("store %s failed: %s\n", key, nt_errstr(status));
935         }
936
937 done:
938         return NT_STATUS_IS_OK(status);
939 }
940
941 static int cmp_keynames(char **p1, char **p2)
942 {
943         return strcasecmp_m(*p1, *p2);
944 }
945
946 static bool
947 write_subkeylist(struct db_context *db, struct regkey *key, char sep)
948 {
949         cbuf *buf = cbuf_new(talloc_tos());
950         int i;
951         bool ret;
952
953         cbuf_putdw(buf, key->nsubkeys);
954
955         for (i=0; i < key->nsubkeys; i++) {
956                 struct regkey *subkey = key->subkeys[i];
957                 const char *name = subkey->name;
958                 if (name == NULL) {
959                         printf("Warning: no explicite name for key %s\n",
960                                subkey->path);
961                         name = strrchr_m(subkey->path, sep);
962                         assert(name);
963                         name ++;
964                 }
965                 cbuf_puts(buf, name, -1);
966                 cbuf_putc(buf, '\0');
967         }
968
969         ret = dbwrap_store_verbose(db, key->path, cbuf_make_tdb_data(buf));
970
971         talloc_free(buf);
972         return ret;
973 }
974
975 static bool write_sorted(struct db_context *db, struct regkey *key, char sep)
976 {
977         cbuf *buf = cbuf_new(talloc_tos());
978         char *path;
979         int i;
980         bool ret = false;
981         char **sorted = talloc_zero_array(buf, char*, key->nsubkeys);
982         int offset =  (1 + key->nsubkeys) * sizeof(uint32_t);
983
984         for (i=0; i < key->nsubkeys; i++) {
985                 sorted[i] = talloc_strdup_upper(sorted, key->subkeys[i]->name);
986         }
987         TYPESAFE_QSORT(sorted, key->nsubkeys, cmp_keynames);
988
989         cbuf_putdw(buf, key->nsubkeys);
990         for (i=0; i < key->nsubkeys; i++) {
991                 cbuf_putdw(buf, offset);
992                 offset += strlen(sorted[i]) + 1;
993         }
994         for (i=0; i < key->nsubkeys; i++) {
995                 cbuf_puts(buf, sorted[i], -1);
996                 cbuf_putc(buf, '\0');
997         }
998
999         path = talloc_asprintf(buf, "%s%c%s", REG_SORTED_SUBKEYS_PREFIX, sep,
1000                                key->path);
1001         if (path == NULL) {
1002                 DEBUG(0, ("Out of memory!\n"));
1003                 goto done;
1004         }
1005
1006         ret = dbwrap_store_verbose(db, path, cbuf_make_tdb_data(buf));
1007 done:
1008         talloc_free(buf);
1009         return ret;
1010 }
1011
1012 static bool write_values(struct db_context *db, struct regkey *key, char sep)
1013 {
1014         cbuf *buf = cbuf_new(talloc_tos());
1015         char *path;
1016         int i;
1017         bool ret = false;
1018
1019         cbuf_putdw(buf, key->nvalues);
1020         for (i=0; i < key->nvalues; i++) {
1021                 struct regval *val = key->values[i];
1022                 cbuf_puts(buf, val->name, -1);
1023                 cbuf_putc(buf, '\0');
1024                 cbuf_putdw(buf, val->type);
1025                 cbuf_putdw(buf, val->data.length);
1026                 cbuf_puts(buf, (void*)val->data.data, val->data.length);
1027         }
1028
1029         path = talloc_asprintf(buf, "%s%c%s", REG_VALUE_PREFIX, sep, key->path);
1030         if (path == NULL) {
1031                 DEBUG(0, ("Out of memory!\n"));
1032                 goto done;
1033         }
1034
1035         ret = dbwrap_store_verbose(db, path, cbuf_make_tdb_data(buf));
1036 done:
1037         talloc_free(buf);
1038         return ret;
1039 }
1040
1041 static bool write_sd(struct db_context *db, struct regkey *key, char sep)
1042 {
1043         TDB_DATA sd;
1044         NTSTATUS status;
1045         char *path;
1046         bool ret = false;
1047         TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
1048
1049         status = marshall_sec_desc(mem_ctx, key->sd, &sd.dptr, &sd.dsize);
1050         if (!NT_STATUS_IS_OK(status)) {
1051                 printf("marshall sec desc %s failed: %s\n",
1052                        key->path, nt_errstr(status));
1053                 goto done;
1054         }
1055         path = talloc_asprintf(mem_ctx, "%s%c%s", REG_SECDESC_PREFIX,
1056                                sep, key->path);
1057         if (path == NULL) {
1058                 DEBUG(0, ("Out of memory!\n"));
1059                 goto done;
1060         }
1061
1062         ret = dbwrap_store_verbose(db, path, sd);
1063 done:
1064         talloc_free(mem_ctx);
1065         return ret;
1066 }
1067
1068
1069 static int check_write_db_action(struct db_record *rec, void *check_ctx)
1070 {
1071         struct check_ctx *ctx = (struct check_ctx*)check_ctx;
1072         TDB_DATA rec_val = dbwrap_record_get_value(rec);
1073         struct regkey *key = *(struct regkey**)rec_val.dptr;
1074         TALLOC_CTX *frame = talloc_stackframe();
1075
1076         /* write subkeylist */
1077         if ((ctx->version > 2) || (key->nsubkeys > 0) || (key->has_subkeylist)) {
1078                 write_subkeylist(ctx->odb, key, ctx->sep);
1079         }
1080
1081         /* write sorted subkeys */
1082         if ((ctx->version < 3) && (key->nsubkeys > 0)) {
1083                 write_sorted(ctx->odb, key, ctx->sep);
1084         }
1085
1086         /* write value list */
1087         if (key->nvalues > 0) {
1088                 write_values(ctx->odb, key, ctx->sep);
1089         }
1090
1091         /* write sd */
1092         if (key->sd) {
1093                 write_sd(ctx->odb, key, ctx->sep);
1094         }
1095
1096         talloc_free(frame);
1097         return 0;
1098 }
1099
1100 static int fix_tree_action(struct db_record *rec, void *check_ctx)
1101 {
1102         struct check_ctx *ctx = (struct check_ctx*)check_ctx;
1103         TDB_DATA rec_key = dbwrap_record_get_key(rec);
1104         TDB_DATA rec_val = dbwrap_record_get_value(rec);
1105         struct regkey* key = *(struct regkey**)rec_val.dptr;
1106         if (ctx->opt.verbose) {
1107                 printf("Check Tree: %s\n", key->path);
1108         }
1109
1110         assert (strncmp(key->path, (char*)rec_key.dptr, rec_key.dsize) == 0);
1111
1112         /* assert(dbwrap_exists(ctx->db, string_term_tdb_data(key->path)) */
1113         /*        == key->exists); */
1114
1115         if (key->needs_update) {
1116                 printf("Update key: \"%s\"\n", key->path);
1117                 if ((ctx->version > 2) || (key->nsubkeys > 0)) {
1118                         write_subkeylist(ctx->odb, key, ctx->sep);
1119                 }
1120                 if ((ctx->version <= 2) && (key->nsubkeys > 0)) {
1121                         write_sorted(ctx->odb, key, ctx->sep);
1122                 }
1123                 if (key->nvalues > 0) {
1124                         write_values(ctx->odb, key, ctx->sep);
1125                 }
1126                 if (key->sd) {
1127                         write_sd(ctx->odb, key, ctx->sep);
1128                 }
1129         } else if (!key->has_subkeylist) {
1130                 if ((ctx->version > 2) || (key->nsubkeys > 0)) {
1131                         printf("Missing subkeylist: %s\n", key->path);
1132                         write_subkeylist(ctx->odb, key, ctx->sep);
1133                 }
1134         }
1135
1136         if (key->name == NULL && key->parent->has_subkeylist) {
1137                 printf("Key not referenced by the its parents subkeylist: %s\n",
1138                        key->path);
1139                 write_subkeylist(ctx->odb, key->parent, ctx->sep);
1140         }
1141
1142 /* XXX check that upcase(name) matches last part of path ??? */
1143
1144         return 0;
1145 }
1146
1147
1148 /* give the same warnings as fix_tree_action */
1149 static int check_tree_action(struct db_record *rec, void *check_ctx)
1150 {
1151         struct check_ctx *ctx = (struct check_ctx*)check_ctx;
1152         TDB_DATA rec_key = dbwrap_record_get_key(rec);
1153         TDB_DATA rec_val = dbwrap_record_get_value(rec);
1154         struct regkey* key = *(struct regkey**)rec_val.dptr;
1155         if (ctx->opt.verbose) {
1156                 printf("Check Tree: %s\n", key->path);
1157         }
1158
1159         assert (strncmp(key->path, (char*)rec_key.dptr, rec_key.dsize) == 0);
1160
1161         if (!key->has_subkeylist) {
1162                 if ((ctx->version > 2) || (key->nsubkeys > 0)) {
1163                         printf("Missing subkeylist: %s\n", key->path);
1164                 }
1165         }
1166
1167         if (key->name == NULL && key->parent->has_subkeylist) {
1168                 printf("Key not referenced by the its parents subkeylist: %s\n",
1169                        key->path);
1170         }
1171
1172         return 0;
1173 }
1174
1175 static int delete_invalid_action(struct db_record *rec, void* check_ctx)
1176 {
1177         NTSTATUS status;
1178         struct check_ctx *ctx = (struct check_ctx*)check_ctx;
1179         TDB_DATA rec_key = dbwrap_record_get_key(rec);
1180         TDB_DATA rec_val = dbwrap_record_get_value(rec);
1181
1182
1183         printf("Delete key: \"%.*s\"",(int)rec_key.dsize, rec_key.dptr);
1184         if (rec_val.dsize > 0) {
1185                 printf(" in favour of \"%s\"\n", rec_val.dptr);
1186         } else {
1187                 putc('\n', stdout);
1188         }
1189
1190         status = dbwrap_delete(ctx->odb, rec_key);
1191         if (!NT_STATUS_IS_OK(status)) {
1192                 d_printf("delete key \"%.*s\" failed!\n",
1193                          (int)rec_key.dsize, rec_key.dptr);
1194                 return -1;
1195         }
1196         return 0;
1197 }
1198
1199 static bool check_ctx_check_tree(struct check_ctx *ctx) {
1200         NTSTATUS status;
1201
1202         status = dbwrap_traverse(ctx->reg, check_tree_action, ctx, NULL);
1203         if (!NT_STATUS_IS_OK(status)) {
1204                 DEBUG(0, ("check traverse failed: %s\n",
1205                           nt_errstr(status)));
1206                 return false;
1207         }
1208         return true;
1209 }
1210 static bool check_ctx_fix_inplace(struct check_ctx *ctx) {
1211         NTSTATUS status;
1212         status = dbwrap_traverse(ctx->reg, fix_tree_action, ctx, NULL);
1213         if (!NT_STATUS_IS_OK(status)) {
1214                 DEBUG(0, ("fix traverse failed: %s\n", nt_errstr(status)));
1215                 return false;
1216         }
1217
1218         status = dbwrap_traverse(ctx->del, delete_invalid_action, ctx, NULL);
1219         if (!NT_STATUS_IS_OK(status)) {
1220                 DEBUG(0, ("delete traverse failed: %s\n", nt_errstr(status)));
1221                 return false;
1222         }
1223
1224         if (!dbwrap_store_uint32_verbose(ctx->odb, "INFO/version", ctx->version)) {
1225                 DEBUG(0, ("storing version failed: %s\n", nt_errstr(status)));
1226                 return false;
1227         }
1228
1229         return true;
1230 }
1231
1232 static bool check_ctx_write_new_db(struct check_ctx *ctx) {
1233         NTSTATUS status;
1234
1235         assert(ctx->odb);
1236
1237         if (ctx->opt.wipe) {
1238                 int ret = dbwrap_wipe(ctx->odb);
1239                 if (ret != 0) {
1240                         DEBUG(0, ("wiping %s failed\n", ctx->opt.output));
1241                         return false;
1242                 }
1243         }
1244
1245         status = dbwrap_traverse(ctx->reg, check_write_db_action, ctx, NULL);
1246         if (!NT_STATUS_IS_OK(status)) {
1247                 DEBUG(0, ("traverse2 failed: %s\n", nt_errstr(status)));
1248                 return false;
1249         }
1250
1251         status = dbwrap_store_uint32_bystring(ctx->odb, "INFO/version",
1252                                               ctx->version);
1253         if (!NT_STATUS_IS_OK(status)) {
1254                 DEBUG(0, ("write version failed: %s\n", nt_errstr(status)));
1255                 return false;
1256         }
1257         return true;
1258 }
1259
1260 int net_registry_check_db(const char *name, const struct check_options *opt)
1261 {
1262         NTSTATUS status;
1263         int ret = -1;
1264         struct check_ctx *ctx = check_ctx_create(talloc_tos(), name, opt);
1265         if (ctx==NULL) {
1266                 goto done;
1267         }
1268
1269         d_printf("Check database: %s\n", name);
1270
1271         /* 1. open output RW */
1272         if (!check_ctx_open_output(ctx)) {
1273                 goto done;
1274         }
1275
1276         /* 2. open input RO */
1277         if (!check_ctx_open_input(ctx)) {
1278                 goto done;
1279         }
1280
1281         if (opt->lock && !check_ctx_transaction_start(ctx)) {
1282                 goto done;
1283         }
1284
1285         if (!get_version(ctx)) {
1286                 goto done;
1287         }
1288
1289         status = dbwrap_traverse_read(ctx->idb, check_tdb_action, ctx, NULL);
1290         if (!NT_STATUS_IS_OK(status)) {
1291                 DEBUG(0, ("check traverse failed: %s\n", nt_errstr(status)));
1292                 goto done;
1293         }
1294
1295         if (!opt->lock && !check_ctx_transaction_start(ctx)) {
1296                 goto done;
1297         }
1298
1299         if (ctx->opt.repair && !ctx->opt.wipe) {
1300                 if (!check_ctx_fix_inplace(ctx)) {
1301                         goto done;
1302                 }
1303         } else {
1304                 if (!check_ctx_check_tree(ctx)) {
1305                         goto done;
1306                 }
1307                 if (ctx->odb) {
1308                         if (!check_ctx_write_new_db(ctx)) {
1309                                 goto done;
1310                         }
1311                 }
1312         }
1313         ret = 0;
1314 done:
1315         check_ctx_transaction_stop(ctx, ret == 0);
1316
1317         talloc_free(ctx);
1318         return ret;
1319 }
1320
1321 /*Local Variables:*/
1322 /*mode: c*/
1323 /*End:*/