diff options
Diffstat (limited to '')
-rw-r--r-- | source4/lib/registry/patchfile_dotreg.c | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/source4/lib/registry/patchfile_dotreg.c b/source4/lib/registry/patchfile_dotreg.c new file mode 100644 index 0000000..5fb342b --- /dev/null +++ b/source4/lib/registry/patchfile_dotreg.c @@ -0,0 +1,435 @@ +/* + Unix SMB/CIFS implementation. + Reading .REG files + + Copyright (C) Jelmer Vernooij 2004-2007 + Copyright (C) Wilco Baan Hofman 2006-2010 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* FIXME: + * - Newer .REG files, created by Windows XP and above use unicode UCS-2 + * - @="" constructions should write value with empty name. +*/ + +#include "includes.h" +#include "lib/registry/registry.h" +#include "system/filesys.h" + +/** + * @file + * @brief Registry patch files + */ + +#define HEADER_STRING "REGEDIT4" + +struct dotreg_data { + int fd; +}; + +/* + * This is basically a copy of data_blob_hex_string_upper, but with comma's + * between the bytes in hex. + */ +static char *dotreg_data_blob_hex_string(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob) +{ + size_t i; + char *hex_string; + + hex_string = talloc_array(mem_ctx, char, (blob->length*3)+1); + if (!hex_string) { + return NULL; + } + + for (i = 0; i < blob->length; i++) + slprintf(&hex_string[i*3], 4, "%02X,", blob->data[i]); + + /* Remove last comma and NULL-terminate the string */ + hex_string[(blob->length*3)-1] = '\0'; + return hex_string; +} + +/* + * This is basically a copy of reg_val_data_string, except that this function + * has no 0x for dwords, everything else is regarded as binary, and binary + * strings are represented with bytes comma-separated. + */ +static char *reg_val_dotreg_string(TALLOC_CTX *mem_ctx, uint32_t type, + const DATA_BLOB data) +{ + size_t converted_size = 0; + char *ret = NULL; + + if (data.length == 0) + return talloc_strdup(mem_ctx, ""); + + switch (type) { + case REG_EXPAND_SZ: + case REG_SZ: + convert_string_talloc(mem_ctx, + CH_UTF16, CH_UNIX, data.data, data.length, + (void **)&ret, &converted_size); + break; + case REG_DWORD: + case REG_DWORD_BIG_ENDIAN: + SMB_ASSERT(data.length == sizeof(uint32_t)); + ret = talloc_asprintf(mem_ctx, "%08x", + IVAL(data.data, 0)); + break; + default: /* default means treat as binary */ + case REG_BINARY: + ret = dotreg_data_blob_hex_string(mem_ctx, &data); + break; + } + + return ret; +} + +static WERROR reg_dotreg_diff_add_key(void *_data, const char *key_name) +{ + struct dotreg_data *data = (struct dotreg_data *)_data; + + fdprintf(data->fd, "\n[%s]\n", key_name); + + return WERR_OK; +} + +static WERROR reg_dotreg_diff_del_key(void *_data, const char *key_name) +{ + struct dotreg_data *data = (struct dotreg_data *)_data; + + fdprintf(data->fd, "\n[-%s]\n", key_name); + + return WERR_OK; +} + +static WERROR reg_dotreg_diff_set_value(void *_data, const char *path, + const char *value_name, + uint32_t value_type, DATA_BLOB value) +{ + struct dotreg_data *data = (struct dotreg_data *)_data; + char *data_string = reg_val_dotreg_string(NULL, + value_type, value); + char *data_incl_type; + + W_ERROR_HAVE_NO_MEMORY(data_string); + + switch (value_type) { + case REG_SZ: + data_incl_type = talloc_asprintf(data_string, "\"%s\"", + data_string); + break; + case REG_DWORD: + data_incl_type = talloc_asprintf(data_string, + "dword:%s", data_string); + break; + case REG_BINARY: + data_incl_type = talloc_asprintf(data_string, "hex:%s", + data_string); + break; + default: + data_incl_type = talloc_asprintf(data_string, "hex(%x):%s", + value_type, data_string); + break; + } + + if (value_name[0] == '\0') { + fdprintf(data->fd, "@=%s\n", data_incl_type); + } else { + fdprintf(data->fd, "\"%s\"=%s\n", + value_name, data_incl_type); + } + + talloc_free(data_string); + + return WERR_OK; +} + +static WERROR reg_dotreg_diff_del_value(void *_data, const char *path, + const char *value_name) +{ + struct dotreg_data *data = (struct dotreg_data *)_data; + + fdprintf(data->fd, "\"%s\"=-\n", value_name); + + return WERR_OK; +} + +static WERROR reg_dotreg_diff_done(void *_data) +{ + struct dotreg_data *data = (struct dotreg_data *)_data; + + close(data->fd); + talloc_free(data); + + return WERR_OK; +} + +static WERROR reg_dotreg_diff_del_all_values(void *callback_data, + const char *key_name) +{ + return WERR_NOT_SUPPORTED; +} + +/** + * Save registry diff + */ +_PUBLIC_ WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename, + struct reg_diff_callbacks **callbacks, + void **callback_data) +{ + struct dotreg_data *data; + + data = talloc_zero(ctx, struct dotreg_data); + *callback_data = data; + + if (filename) { + data->fd = open(filename, O_CREAT|O_WRONLY, 0755); + if (data->fd < 0) { + DEBUG(0, ("Unable to open %s\n", filename)); + return WERR_FILE_NOT_FOUND; + } + } else { + data->fd = STDOUT_FILENO; + } + + fdprintf(data->fd, "%s\n\n", HEADER_STRING); + + *callbacks = talloc(ctx, struct reg_diff_callbacks); + + (*callbacks)->add_key = reg_dotreg_diff_add_key; + (*callbacks)->del_key = reg_dotreg_diff_del_key; + (*callbacks)->set_value = reg_dotreg_diff_set_value; + (*callbacks)->del_value = reg_dotreg_diff_del_value; + (*callbacks)->del_all_values = reg_dotreg_diff_del_all_values; + (*callbacks)->done = reg_dotreg_diff_done; + + return WERR_OK; +} + +/** + * Load diff file + */ +_PUBLIC_ WERROR reg_dotreg_diff_load(int fd, + const struct reg_diff_callbacks *callbacks, + void *callback_data) +{ + char *line, *p, *q; + char *curkey = NULL; + TALLOC_CTX *mem_ctx = talloc_init("reg_dotreg_diff_load"); + WERROR error; + uint32_t value_type; + DATA_BLOB data; + bool result; + char *type_str = NULL; + char *data_str = NULL; + char *value = NULL; + bool continue_next_line = 0; + + line = afdgets(fd, mem_ctx, 0); + if (!line) { + DEBUG(0, ("Can't read from file.\n")); + talloc_free(mem_ctx); + close(fd); + return WERR_GEN_FAILURE; + } + + while ((line = afdgets(fd, mem_ctx, 0))) { + /* Remove '\r' if it's a Windows text file */ + if (strlen(line) && line[strlen(line)-1] == '\r') { + line[strlen(line)-1] = '\0'; + } + + /* Ignore comments and empty lines */ + if (strlen(line) == 0 || line[0] == ';') { + talloc_free(line); + + if (curkey) { + talloc_free(curkey); + } + curkey = NULL; + continue; + } + + /* Start of key */ + if (line[0] == '[') { + if (line[strlen(line)-1] != ']') { + DEBUG(0, ("Missing ']' on line: %s\n", line)); + talloc_free(line); + continue; + } + + /* Deleting key */ + if (line[1] == '-') { + curkey = talloc_strndup(line, line+2, strlen(line)-3); + W_ERROR_HAVE_NO_MEMORY(curkey); + + error = callbacks->del_key(callback_data, + curkey); + + if (!W_ERROR_IS_OK(error)) { + DEBUG(0,("Error deleting key %s\n", + curkey)); + talloc_free(mem_ctx); + return error; + } + + talloc_free(line); + curkey = NULL; + continue; + } + curkey = talloc_strndup(mem_ctx, line+1, strlen(line)-2); + W_ERROR_HAVE_NO_MEMORY(curkey); + + error = callbacks->add_key(callback_data, curkey); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0,("Error adding key %s\n", curkey)); + talloc_free(mem_ctx); + return error; + } + + talloc_free(line); + continue; + } + + /* Deleting/Changing value */ + if (continue_next_line) { + continue_next_line = 0; + + /* Continued data start with two whitespaces */ + if (line[0] != ' ' || line[1] != ' ') { + DEBUG(0, ("Malformed line: %s\n", line)); + talloc_free(line); + continue; + } + p = line + 2; + + /* Continue again if line ends with a backslash */ + if (line[strlen(line)-1] == '\\') { + line[strlen(line)-1] = '\0'; + continue_next_line = 1; + data_str = talloc_strdup_append(data_str, p); + talloc_free(line); + continue; + } + data_str = talloc_strdup_append(data_str, p); + } else { + p = strchr_m(line, '='); + if (p == NULL) { + DEBUG(0, ("Malformed line: %s\n", line)); + talloc_free(line); + continue; + } + + *p = '\0'; p++; + + + if (curkey == NULL) { + DEBUG(0, ("Value change without key\n")); + talloc_free(line); + continue; + } + + /* Values should be double-quoted */ + if (line[0] != '"') { + DEBUG(0, ("Malformed line\n")); + talloc_free(line); + continue; + } + + /* Chop of the quotes and store as value */ + value = talloc_strndup(mem_ctx, line+1,strlen(line)-2); + + /* Delete value */ + if (p[0] == '-') { + error = callbacks->del_value(callback_data, + curkey, value); + + /* Ignore if key does not exist (WERR_FILE_NOT_FOUND) + * Consistent with Windows behaviour */ + if (!W_ERROR_IS_OK(error) && + !W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) { + DEBUG(0, ("Error deleting value %s in key %s\n", + value, curkey)); + talloc_free(mem_ctx); + return error; + } + + talloc_free(line); + talloc_free(value); + continue; + } + + /* Do not look for colons in strings */ + if (p[0] == '"') { + q = NULL; + data_str = talloc_strndup(mem_ctx, p+1,strlen(p)-2); + } else { + /* Split the value type from the data */ + q = strchr_m(p, ':'); + if (q) { + *q = '\0'; + q++; + type_str = talloc_strdup(mem_ctx, p); + data_str = talloc_strdup(mem_ctx, q); + } else { + data_str = talloc_strdup(mem_ctx, p); + } + } + + /* Backslash before the CRLF means continue on next line */ + if (data_str[strlen(data_str)-1] == '\\') { + data_str[strlen(data_str)-1] = '\0'; + talloc_free(line); + continue_next_line = 1; + continue; + } + } + DEBUG(9, ("About to write %s with type %s, length %ld: %s\n", value, type_str, (long) strlen(data_str), data_str)); + result = reg_string_to_val(value, + type_str?type_str:"REG_SZ", data_str, + &value_type, &data); + if (!result) { + DEBUG(0, ("Error converting string to value for line:\n%s\n", + line)); + return WERR_GEN_FAILURE; + } + + error = callbacks->set_value(callback_data, curkey, value, + value_type, data); + if (!W_ERROR_IS_OK(error)) { + DEBUG(0, ("Error setting value for %s in %s\n", + value, curkey)); + talloc_free(mem_ctx); + return error; + } + + /* Clean up buffers */ + if (type_str != NULL) { + talloc_free(type_str); + type_str = NULL; + } + talloc_free(data_str); + talloc_free(value); + talloc_free(line); + } + + close(fd); + + talloc_free(mem_ctx); + + return WERR_OK; +} |