diff options
Diffstat (limited to 'source3/utils/net_registry.c')
-rw-r--r-- | source3/utils/net_registry.c | 199 |
1 files changed, 194 insertions, 5 deletions
diff --git a/source3/utils/net_registry.c b/source3/utils/net_registry.c index b466e7e7b7..8a65e0db51 100644 --- a/source3/utils/net_registry.c +++ b/source3/utils/net_registry.c @@ -30,6 +30,7 @@ #include "registry/reg_backend_db.h" #include "registry/reg_import.h" #include "registry/reg_format.h" +#include "registry/reg_api_util.h" #include <assert.h> #include "../libcli/security/display_sec.h" #include "../libcli/security/sddl.h" @@ -1029,6 +1030,192 @@ static WERROR import_delete_val (struct import_ctx* ctx, struct registry_key* pa return werr; } +struct precheck_ctx { + TALLOC_CTX *mem_ctx; + bool failed; +}; + +static WERROR precheck_create_key(struct precheck_ctx *ctx, + struct registry_key *parent, + const char *name, void **pkey, bool *existing) +{ + WERROR werr; + TALLOC_CTX *frame = talloc_stackframe(); + struct registry_key *key = NULL; + + if (parent == NULL) { + char *subkeyname = NULL; + werr = open_hive(frame, name, REG_KEY_READ, + &parent, &subkeyname); + if (!W_ERROR_IS_OK(werr)) { + d_printf("Precheck: open_hive of [%s] failed: %s\n", + name, win_errstr(werr)); + goto done; + } + name = subkeyname; + } + + werr = reg_openkey(frame, parent, name, 0, &key); + if (!W_ERROR_IS_OK(werr)) { + d_printf("Precheck: openkey [%s] failed: %s\n", + name, win_errstr(werr)); + goto done; + } + + if (existing != NULL) { + *existing = true; + } + + if (pkey != NULL) { + *pkey = talloc_steal(ctx->mem_ctx, key); + } + +done: + talloc_free(frame); + ctx->failed = !W_ERROR_IS_OK(werr); + return werr; +} + +static WERROR precheck_close_key(struct precheck_ctx *ctx, + struct registry_key *key) +{ + talloc_free(key); + return WERR_OK; +} + +static WERROR precheck_delete_key(struct precheck_ctx *ctx, + struct registry_key *parent, const char *name) +{ + WERROR werr; + TALLOC_CTX *frame = talloc_stackframe(); + struct registry_key *key; + + if (parent == NULL) { + char *subkeyname = NULL; + werr = open_hive(frame, name, REG_KEY_READ, + &parent, &subkeyname); + if (!W_ERROR_IS_OK(werr)) { + d_printf("Precheck: open_hive of [%s] failed: %s\n", + name, win_errstr(werr)); + goto done; + } + name = subkeyname; + } + + werr = reg_openkey(ctx->mem_ctx, parent, name, 0, &key); + if (W_ERROR_IS_OK(werr)) { + d_printf("Precheck: key [%s\\%s] should not exist\n", + parent->key->name, name); + werr = WERR_FILE_EXISTS; + } else if (W_ERROR_EQUAL(werr, WERR_BADFILE)) { + werr = WERR_OK; + } else { + d_printf("Precheck: openkey [%s\\%s] failed: %s\n", + parent->key->name, name, win_errstr(werr)); + } + +done: + talloc_free(frame); + ctx->failed = !W_ERROR_IS_OK(werr); + return werr; +} + +static WERROR precheck_create_val(struct precheck_ctx *ctx, + struct registry_key *parent, + const char *name, + const struct registry_value *value) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct registry_value *old; + WERROR werr; + + SMB_ASSERT(parent); + + werr = reg_queryvalue(frame, parent, name, &old); + if (!W_ERROR_IS_OK(werr)) { + d_printf("Precheck: queryvalue \"%s\" of [%s] failed: %s\n", + name, parent->key->name, win_errstr(werr)); + goto done; + } + if (registry_value_cmp(value, old) != 0) { + d_printf("Precheck: unexpected value \"%s\" of key [%s]\n", + name, parent->key->name); + ctx->failed = true; + } +done: + talloc_free(frame); + return werr; +} + +static WERROR precheck_delete_val(struct precheck_ctx *ctx, + struct registry_key *parent, + const char *name) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct registry_value *old; + WERROR werr; + + SMB_ASSERT(parent); + + werr = reg_queryvalue(frame, parent, name, &old); + if (W_ERROR_IS_OK(werr)) { + d_printf("Precheck: value \"%s\" of key [%s] should not exist\n", + name, parent->key->name); + werr = WERR_FILE_EXISTS; + } else if (W_ERROR_EQUAL(werr, WERR_BADFILE)) { + werr = WERR_OK; + } else { + printf("Precheck: queryvalue \"%s\" of key [%s] failed: %s\n", + name, parent->key->name, win_errstr(werr)); + } + + talloc_free(frame); + ctx->failed = !W_ERROR_IS_OK(werr); + return werr; +} + +static bool import_precheck(const char *fname, const char *parse_options) +{ + TALLOC_CTX *mem_ctx = talloc_tos(); + struct precheck_ctx precheck_ctx = { + .mem_ctx = mem_ctx, + .failed = false, + }; + struct reg_import_callback precheck_callback = { + .openkey = NULL, + .closekey = (reg_import_callback_closekey_t)&precheck_close_key, + .createkey = (reg_import_callback_createkey_t)&precheck_create_key, + .deletekey = (reg_import_callback_deletekey_t)&precheck_delete_key, + .deleteval = (reg_import_callback_deleteval_t)&precheck_delete_val, + .setval = { + .registry_value = (reg_import_callback_setval_registry_value_t) + &precheck_create_val, + }, + .setval_type = REGISTRY_VALUE, + .data = &precheck_ctx + }; + struct reg_parse_callback *parse_callback; + int ret; + + if (!fname) { + return true; + } + + parse_callback = reg_import_adapter(mem_ctx, precheck_callback); + if (parse_callback == NULL) { + d_printf("talloc failed\n"); + return false; + } + + ret = reg_parse_file(fname, parse_callback, parse_options); + + if (ret < 0 || precheck_ctx.failed) { + d_printf("Precheck failed\n"); + return false; + } + return true; +} + static int net_registry_import(struct net_context *c, int argc, const char **argv) @@ -1050,7 +1237,7 @@ static int net_registry_import(struct net_context *c, int argc, .setval_type = REGISTRY_VALUE, .data = &import_ctx }; - + const char *parse_options = (argc > 1) ? argv[1] : NULL; int ret = -1; WERROR werr; @@ -1076,12 +1263,14 @@ static int net_registry_import(struct net_context *c, int argc, goto done; } - ret = reg_parse_file(argv[0], - reg_import_adapter(frame, import_callback), - (argc > 1) ? argv[1] : NULL); + if (import_precheck(c->opt_precheck, parse_options)) { + ret = reg_parse_file(argv[0], + reg_import_adapter(frame, import_callback), + parse_options); + } if (ret < 0) { - d_printf("reg_parse_file failed: transaction canceled\n"); + d_printf("Transaction canceled!\n"); regdb_transaction_cancel(); } else { werr = regdb_transaction_commit(); |