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