s4:registry:regdiff: use existing talloc context for the event context
[sfrench/samba-autobuild/.git] / source4 / lib / registry / util.c
index 7da53d381d59ad51d9b168832b63839c321e488b..1197adba7f15fdad160d2e4669419063f48cd99a 100644 (file)
@@ -2,6 +2,7 @@
    Unix SMB/CIFS implementation.
    Transparent registry backend handling
    Copyright (C) Jelmer Vernooij                       2003-2007.
+   Copyright (C) Wilco Baan Hofman                     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
 #include "includes.h"
 #include "lib/registry/registry.h"
 #include "librpc/gen_ndr/winreg.h"
+#include "lib/util/data_blob.h"
 
-/**
- * @file
- * @brief Registry utility functions
- */
-
-static const struct {
-       uint32_t id;
-       const char *name;
-} reg_value_types[] = {
-       { REG_NONE, "REG_NONE" },
-       { REG_SZ, "REG_SZ" },
-       { REG_EXPAND_SZ, "REG_EXPAND_SZ" },
-       { REG_BINARY, "REG_BINARY" },
-       { REG_DWORD, "REG_DWORD" },
-       { REG_DWORD_BIG_ENDIAN, "REG_DWORD_BIG_ENDIAN" },
-       { REG_LINK, "REG_LINK" },
-       { REG_MULTI_SZ, "REG_MULTI_SZ" },
-       { REG_RESOURCE_LIST, "REG_RESOURCE_LIST" },
-       { REG_FULL_RESOURCE_DESCRIPTOR, "REG_FULL_RESOURCE_DESCRIPTOR" },
-       { REG_RESOURCE_REQUIREMENTS_LIST, "REG_RESOURCE_REQUIREMENTS_LIST" },
-       { REG_QWORD, "REG_QWORD" },
-
-       { 0, NULL }
-};
-
-/** Return string description of registry value type */
-_PUBLIC_ const char *str_regtype(int type)
-{
-       unsigned int i;
-       for (i = 0; reg_value_types[i].name; i++) {
-               if (reg_value_types[i].id == type)
-                       return reg_value_types[i].name;
-       }
-
-       return "Unknown";
-}
-
-_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, 
-                                  struct smb_iconv_convenience *iconv_convenience,
-                                  uint32_t type,
+_PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx, uint32_t type,
                                   const DATA_BLOB data)
 {
+       size_t converted_size = 0;
        char *ret = NULL;
 
        if (data.length == 0)
@@ -71,25 +35,25 @@ _PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx,
        switch (type) {
                case REG_EXPAND_SZ:
                case REG_SZ:
-                       convert_string_talloc_convenience(mem_ctx,
-                                                         iconv_convenience,
-                                                         CH_UTF16, CH_UNIX,
-                                                         data.data,
-                                                         data.length,
-                                                         (void **)&ret,
-                                                         NULL, false);
+                       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, "0x%8.8x",
+                                             IVAL(data.data, 0));
+                       break;
+               case REG_QWORD:
+                       SMB_ASSERT(data.length == sizeof(uint64_t));
+                       ret = talloc_asprintf(mem_ctx, "0x%16.16llx",
+                                             (long long)BVAL(data.data, 0));
                        break;
                case REG_BINARY:
                        ret = data_blob_hex_string_upper(mem_ctx, &data);
                        break;
-               case REG_DWORD:
-                       if (IVAL(data.data, 0) == 0) {
-                               ret = talloc_strdup(mem_ctx, "0");
-                       } else {
-                               ret = talloc_asprintf(mem_ctx, "0x%x",
-                                                     IVAL(data.data, 0));
-                       }
-                       break;
                case REG_NONE:
                        /* "NULL" is the right return value */
                        break;
@@ -106,33 +70,87 @@ _PUBLIC_ char *reg_val_data_string(TALLOC_CTX *mem_ctx,
 }
 
 /** Generate a string that describes a registry value */
-_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx, 
-                                  struct smb_iconv_convenience *iconv_convenience, 
+_PUBLIC_ char *reg_val_description(TALLOC_CTX *mem_ctx,
                                   const char *name,
                                   uint32_t data_type,
                                   const DATA_BLOB data)
 {
        return talloc_asprintf(mem_ctx, "%s = %s : %s", name?name:"<No Name>",
                               str_regtype(data_type),
-                              reg_val_data_string(mem_ctx, iconv_convenience, data_type, data));
+                              reg_val_data_string(mem_ctx, data_type, data));
 }
 
-_PUBLIC_ bool reg_string_to_val(TALLOC_CTX *mem_ctx, 
-                               struct smb_iconv_convenience *iconv_convenience,
-                               const char *type_str,
-                               const char *data_str, uint32_t *type,
-                               DATA_BLOB *data)
+/*
+ * This implements reading hex bytes that include comma's.
+ * It was previously handled by strhex_to_data_blob, but that did not cover
+ * the format used by windows.
+ */
+static DATA_BLOB reg_strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *str)
 {
-       unsigned int i;
-       *type = -1;
+       DATA_BLOB ret;
+       const char *HEXCHARS = "0123456789ABCDEF";
+       size_t i, j;
+       char *hi, *lo;
+
+       ret = data_blob_talloc_zero(mem_ctx, (strlen(str)+(strlen(str) % 3))/3);
+       j = 0;
+       for (i = 0; i < strlen(str); i++) {
+               hi = strchr(HEXCHARS, toupper(str[i]));
+               if (hi == NULL)
+                       continue;
+
+               i++;
+               lo = strchr(HEXCHARS, toupper(str[i]));
+               if (lo == NULL)
+                       break;
 
-       /* Find the correct type */
-       for (i = 0; reg_value_types[i].name; i++) {
-               if (!strcmp(reg_value_types[i].name, type_str)) {
-                       *type = reg_value_types[i].id;
+               ret.data[j] = PTR_DIFF(hi, HEXCHARS) << 4;
+               ret.data[j] += PTR_DIFF(lo, HEXCHARS);
+               j++;
+
+               if (j > ret.length) {
+                       DEBUG(0, ("Trouble converting hex string to bin\n"));
                        break;
                }
        }
+       return ret;
+}
+
+
+_PUBLIC_ bool reg_string_to_val(TALLOC_CTX *mem_ctx, const char *type_str,
+                               const char *data_str, uint32_t *type, DATA_BLOB *data)
+{
+       char *tmp_type_str, *p, *q;
+       int result;
+
+       *type = regtype_by_string(type_str);
+
+       if (*type == -1) {
+               /* Normal windows format is hex, hex(type int as string),
+                  dword or just a string. */
+               if (strncmp(type_str, "hex(", 4) == 0) {
+                       /* there is a hex string with the value type between
+                          the braces */
+                       tmp_type_str = talloc_strdup(mem_ctx, type_str);
+                       q = p = tmp_type_str + strlen("hex(");
+
+                       /* Go to the closing brace or end of the string */
+                       while (*q != ')' && *q != '\0') q++;
+                       *q = '\0';
+
+                       /* Convert hex string to int, store it in type */
+                       result = sscanf(p, "%x", type);
+                       if (!result) {
+                               DEBUG(0, ("Could not convert hex to int\n"));
+                               return false;
+                       }
+                       talloc_free(tmp_type_str);
+               } else if (strcmp(type_str, "hex") == 0) {
+                       *type = REG_BINARY;
+               } else if (strcmp(type_str, "dword") == 0) {
+                       *type = REG_DWORD;
+               }
+       }
 
        if (*type == -1)
                return false;
@@ -141,30 +159,35 @@ _PUBLIC_ bool reg_string_to_val(TALLOC_CTX *mem_ctx,
 
        switch (*type) {
                case REG_SZ:
-               case REG_EXPAND_SZ:
-                       convert_string_talloc_convenience(mem_ctx,
-                                                         iconv_convenience,
-                                                         CH_UNIX, CH_UTF16,
-                                                         data_str,
-                                                         strlen(data_str)+1,
-                                                         (void **)&data->data,
-                                                         &data->length, false);
+                       return convert_string_talloc(mem_ctx,
+                                                    CH_UNIX, CH_UTF16,
+                                                    data_str, strlen(data_str)+1,
+                                                    (void **)&data->data,
+                                                    &data->length);
                        break;
+               case REG_MULTI_SZ:
+               case REG_EXPAND_SZ:
                case REG_BINARY:
-                       *data = strhex_to_data_blob(mem_ctx, data_str);
+                       *data = reg_strhex_to_data_blob(mem_ctx, data_str);
                        break;
-               case REG_DWORD: {
-                       uint32_t tmp = strtol(data_str, NULL, 0);
-                       *data = data_blob_talloc(mem_ctx, NULL, 4);
+               case REG_DWORD:
+               case REG_DWORD_BIG_ENDIAN: {
+                       uint32_t tmp = strtol(data_str, NULL, 16);
+                       *data = data_blob_talloc(mem_ctx, NULL, sizeof(uint32_t));
+                       if (data->data == NULL) return false;
                        SIVAL(data->data, 0, tmp);
                        }
                        break;
+               case REG_QWORD: {
+                       uint64_t tmp = strtoll(data_str, NULL, 16);
+                       *data = data_blob_talloc(mem_ctx, NULL, sizeof(uint64_t));
+                       if (data->data == NULL) return false;
+                       SBVAL(data->data, 0, tmp);
+                       }
+                       break;
                case REG_NONE:
                        ZERO_STRUCTP(data);
                        break;
-               case REG_MULTI_SZ:
-                       /* FIXME: We don't support this yet */
-                       return false;
                default:
                        /* FIXME */
                        /* Other datatypes aren't supported -> return no success */
@@ -188,6 +211,7 @@ WERROR reg_open_key_abs(TALLOC_CTX *mem_ctx, struct registry_context *handle,
                predeflength = strlen(name);
 
        predefname = talloc_strndup(mem_ctx, name, predeflength);
+       W_ERROR_HAVE_NO_MEMORY(predefname);
        error = reg_get_predefined_key_by_name(handle, predefname, &predef);
        talloc_free(predefname);
 
@@ -216,13 +240,15 @@ static WERROR get_abs_parent(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
        }
 
        parent_name = talloc_strndup(mem_ctx, path, strrchr(path, '\\')-path);
-
+       W_ERROR_HAVE_NO_MEMORY(parent_name);
        error = reg_open_key_abs(mem_ctx, ctx, parent_name, parent);
+       talloc_free(parent_name);
        if (!W_ERROR_IS_OK(error)) {
                return error;
        }
 
        *name = talloc_strdup(mem_ctx, strrchr(path, '\\')+1);
+       W_ERROR_HAVE_NO_MEMORY(*name);
 
        return WERR_OK;
 }
@@ -240,7 +266,7 @@ WERROR reg_key_del_abs(struct registry_context *ctx, const char *path)
 
        error = get_abs_parent(mem_ctx, ctx, path, &parent, &n);
        if (W_ERROR_IS_OK(error)) {
-               error = reg_key_del(parent, n);
+               error = reg_key_del(mem_ctx, parent, n);
        }
 
        talloc_free(mem_ctx);
@@ -257,6 +283,8 @@ WERROR reg_key_add_abs(TALLOC_CTX *mem_ctx, struct registry_context *ctx,
        const char *n;
        WERROR error;
 
+       *result = NULL;
+
        if (!strchr(path, '\\')) {
                return WERR_ALREADY_EXISTS;
        }