s4-registry: fixed byte order assumptions
[ira/wip.git] / source4 / lib / registry / patchfile_preg.c
index 8f02a0b5e382fec672f03dbc6e1a3062e7aeb9f5..d7b4bc3730819c1c142dedc1ee086b01d5567e8b 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/CIFS implementation.
    Reading Registry.pol PReg registry files
 
-   Copyright (C) Wilco Baan Hofman 2006
+   Copyright (C) Wilco Baan Hofman 2006-2008
 
    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 "lib/registry/patchfile.h"
 #include "system/filesys.h"
-#include "param/param.h"
+#include "librpc/gen_ndr/winreg.h"
 
 struct preg_data {
        int fd;
+       TALLOC_CTX *ctx;
 };
 
-static WERROR preg_read_utf16(struct smb_iconv_convenience *ic, int fd, char *c)
+static WERROR preg_read_utf16(int fd, char *c)
 {
        uint16_t v;
 
        if (read(fd, &v, 2) < 2) {
                return WERR_GENERAL_FAILURE;
        }
-       push_codepoint(ic, c, v);
+       push_codepoint(c, v);
        return WERR_OK;
 }
-
-/* FIXME These functions need to be implemented */
-static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
+static WERROR preg_write_utf16(int fd, const char *string)
 {
+       codepoint_t v;
+       uint16_t i;
+       size_t size;
+
+       for (i = 0; i < strlen(string); i+=size) {
+               v = next_codepoint(&string[i], &size);
+               if (write(fd, &v, 2) < 2) {
+                       return WERR_GENERAL_FAILURE;
+               }
+       }
        return WERR_OK;
 }
-
-static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
+/* PReg does not support adding keys. */
+static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
 {
        return WERR_OK;
 }
@@ -55,24 +63,73 @@ static WERROR reg_preg_diff_set_value(void *_data, const char *key_name,
                                      const char *value_name,
                                      uint32_t value_type, DATA_BLOB value_data)
 {
+       struct preg_data *data = (struct preg_data *)_data;
+       uint32_t buf;
+       
+       preg_write_utf16(data->fd, "[");
+       preg_write_utf16(data->fd, key_name);
+       preg_write_utf16(data->fd, ";");
+       preg_write_utf16(data->fd, value_name);
+       preg_write_utf16(data->fd, ";");
+       SIVAL(&buf, 0, value_type);
+       write(data->fd, &buf, sizeof(uint32_t));
+       preg_write_utf16(data->fd, ";");
+       SIVAL(&buf, 0, value_data.length);
+       write(data->fd, &buf, sizeof(uint32_t));
+       preg_write_utf16(data->fd, ";");
+       write(data->fd, value_data.data, value_data.length);
+       preg_write_utf16(data->fd, "]");
+       
        return WERR_OK;
 }
 
+static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
+{
+       struct preg_data *data = (struct preg_data *)_data;
+       char *parent_name;
+       DATA_BLOB blob;
+
+       parent_name = talloc_strndup(data->ctx, key_name, strrchr(key_name, '\\')-key_name);
+       blob.data = (uint8_t *)talloc_strndup(data->ctx, key_name+(strrchr(key_name, '\\')-key_name)+1,
+                       strlen(key_name)-(strrchr(key_name, '\\')-key_name));
+       blob.length = strlen((char *)blob.data)+1;
+       
+
+       /* FIXME: These values should be accumulated to be written at done(). */
+       return reg_preg_diff_set_value(data, parent_name, "**DeleteKeys", REG_SZ, blob);
+}
+
 static WERROR reg_preg_diff_del_value(void *_data, const char *key_name,
                                      const char *value_name)
 {
-       return WERR_OK;
+       struct preg_data *data = (struct preg_data *)_data;
+       char *val;
+       DATA_BLOB blob;
+
+       val = talloc_asprintf(data->ctx, "**Del.%s", value_name);
+
+       blob.data = (uint8_t *)talloc(data->ctx, uint32_t);
+       SIVAL(blob.data, 0, 0);
+       blob.length = 4;
+       return reg_preg_diff_set_value(data, key_name, val, REG_DWORD, blob);
 }
 
 static WERROR reg_preg_diff_del_all_values(void *_data, const char *key_name)
 {
-       return WERR_OK;
+       struct preg_data *data = (struct preg_data *)_data;
+       DATA_BLOB blob;
+
+       blob.data = (uint8_t *)talloc(data->ctx, uint32_t);
+       SIVAL(blob.data, 0, 0);
+       blob.length = 4;
+
+       return reg_preg_diff_set_value(data, key_name, "**DelVals.", REG_DWORD, blob);
 }
 
 static WERROR reg_preg_diff_done(void *_data)
 {
        struct preg_data *data = (struct preg_data *)_data;
-
+       
        close(data->fd);
        talloc_free(data);
        return WERR_OK;
@@ -82,6 +139,7 @@ static WERROR reg_preg_diff_done(void *_data)
  * Save registry diff
  */
 _PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename,
+                                  struct smb_iconv_convenience *ic,
                                   struct reg_diff_callbacks **callbacks,
                                   void **callback_data)
 {
@@ -96,18 +154,21 @@ _PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename,
        *callback_data = data;
 
        if (filename) {
-               data->fd = open(filename, O_CREAT, 0755);
-               if (data->fd == -1) {
+               data->fd = open(filename, O_CREAT|O_WRONLY, 0755);
+               if (data->fd < 0) {
                        DEBUG(0, ("Unable to open %s\n", filename));
                        return WERR_BADFILE;
                }
        } else {
                data->fd = STDOUT_FILENO;
        }
-       snprintf(preg_header.hdr, 4, "PReg");
+
+       strncpy(preg_header.hdr, "PReg", 4);
        SIVAL(&preg_header, 4, 1);
        write(data->fd, (uint8_t *)&preg_header,8);
 
+       data->ctx = ctx;
+
        *callbacks = talloc(ctx, struct reg_diff_callbacks);
 
        (*callbacks)->add_key = reg_preg_diff_add_key;
@@ -150,6 +211,8 @@ _PUBLIC_ WERROR reg_preg_diff_load(int fd,
                ret = WERR_GENERAL_FAILURE;
                goto cleanup;
        }
+       preg_header.version = IVAL(&preg_header.version, 0);
+
        if (strncmp(preg_header.hdr, "PReg", 4) != 0) {
                DEBUG(0, ("This file is not a valid preg registry file\n"));
                ret = WERR_GENERAL_FAILURE;
@@ -163,7 +226,7 @@ _PUBLIC_ WERROR reg_preg_diff_load(int fd,
        while(1) {
                uint32_t value_type, length;
 
-               if (!W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr))) {
+               if (!W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr))) {
                        break;
                }
                if (*buf_ptr != '[') {
@@ -174,18 +237,20 @@ _PUBLIC_ WERROR reg_preg_diff_load(int fd,
 
                /* Get the path */
                buf_ptr = buf;
-               while (W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
+               while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
                       *buf_ptr != ';' && buf_ptr-buf < buf_size) {
                        buf_ptr++;
                }
-               key = talloc_asprintf(mem_ctx, "\\%s", buf);
+               buf[buf_ptr-buf] = '\0';
+               key = talloc_strdup(mem_ctx, buf);
 
                /* Get the name */
                buf_ptr = buf;
-               while (W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
+               while (W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
                       *buf_ptr != ';' && buf_ptr-buf < buf_size) {
                        buf_ptr++;
                }
+               buf[buf_ptr-buf] = '\0';
                value_name = talloc_strdup(mem_ctx, buf);
 
                /* Get the type */
@@ -194,9 +259,11 @@ _PUBLIC_ WERROR reg_preg_diff_load(int fd,
                        ret = WERR_GENERAL_FAILURE;
                        goto cleanup;
                }
+               value_type = IVAL(&value_type, 0);
+
                /* Read past delimiter */
                buf_ptr = buf;
-               if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
+               if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
                    *buf_ptr == ';') && buf_ptr-buf < buf_size) {
                        DEBUG(0, ("Error in PReg file.\n"));
                        ret = WERR_GENERAL_FAILURE;
@@ -210,7 +277,7 @@ _PUBLIC_ WERROR reg_preg_diff_load(int fd,
                }
                /* Read past delimiter */
                buf_ptr = buf;
-               if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
+               if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
                    *buf_ptr == ';') && buf_ptr-buf < buf_size) {
                        DEBUG(0, ("Error in PReg file.\n"));
                        ret = WERR_GENERAL_FAILURE;
@@ -228,7 +295,7 @@ _PUBLIC_ WERROR reg_preg_diff_load(int fd,
 
                /* Check if delimiter is in place (whine if it isn't) */
                buf_ptr = buf;
-               if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
+               if (!(W_ERROR_IS_OK(preg_read_utf16(fd, buf_ptr)) &&
                    *buf_ptr == ']') && buf_ptr-buf < buf_size) {
                        DEBUG(0, ("Warning: Missing ']' in PReg file, expected ']', got '%c' 0x%x.\n",
                                *buf_ptr, *buf_ptr));