root/source4/lib/registry/patchfile_preg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. preg_read_utf16
  2. preg_write_utf16
  3. reg_preg_diff_add_key
  4. reg_preg_diff_set_value
  5. reg_preg_diff_del_key
  6. reg_preg_diff_del_value
  7. reg_preg_diff_del_all_values
  8. reg_preg_diff_done
  9. reg_preg_diff_save
  10. reg_preg_diff_load

   1 /*
   2    Unix SMB/CIFS implementation.
   3    Reading Registry.pol PReg registry files
   4 
   5    Copyright (C) Wilco Baan Hofman 2006-2008
   6 
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11 
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16 
  17    You should have received a copy of the GNU General Public License
  18    along with this program; if not, write to the Free Software
  19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 */
  21 
  22 #include "includes.h"
  23 #include "lib/registry/registry.h"
  24 #include "system/filesys.h"
  25 #include "librpc/gen_ndr/winreg.h"
  26 
  27 struct preg_data {
  28         int fd;
  29         TALLOC_CTX *ctx;
  30         struct smb_iconv_convenience *ic;
  31 };
  32 
  33 static WERROR preg_read_utf16(struct smb_iconv_convenience *ic, int fd, char *c)
     /* [<][>][^][v][top][bottom][index][help] */
  34 {
  35         uint16_t v;
  36 
  37         if (read(fd, &v, 2) < 2) {
  38                 return WERR_GENERAL_FAILURE;
  39         }
  40         push_codepoint(ic, c, v);
  41         return WERR_OK;
  42 }
  43 static WERROR preg_write_utf16(struct smb_iconv_convenience *ic, int fd, const char *string)
     /* [<][>][^][v][top][bottom][index][help] */
  44 {
  45         codepoint_t v;
  46         uint16_t i;
  47         size_t size;
  48 
  49         for (i = 0; i < strlen(string); i+=size) {
  50                 v = next_codepoint_convenience(ic, &string[i], &size);
  51                 if (write(fd, &v, 2) < 2) {
  52                         return WERR_GENERAL_FAILURE;
  53                 }
  54         }
  55         return WERR_OK;
  56 }
  57 /* PReg does not support adding keys. */
  58 static WERROR reg_preg_diff_add_key(void *_data, const char *key_name)
     /* [<][>][^][v][top][bottom][index][help] */
  59 {
  60         return WERR_OK;
  61 }
  62 
  63 static WERROR reg_preg_diff_set_value(void *_data, const char *key_name,
     /* [<][>][^][v][top][bottom][index][help] */
  64                                       const char *value_name,
  65                                       uint32_t value_type, DATA_BLOB value_data)
  66 {
  67         struct preg_data *data = (struct preg_data *)_data;
  68         uint32_t buf;
  69         
  70         preg_write_utf16(data->ic, data->fd, "[");
  71         preg_write_utf16(data->ic, data->fd, key_name);
  72         preg_write_utf16(data->ic, data->fd, ";");
  73         preg_write_utf16(data->ic, data->fd, value_name);
  74         preg_write_utf16(data->ic, data->fd, ";");
  75         SIVAL(&buf, 0, value_type);
  76         write(data->fd, &buf, sizeof(uint32_t));
  77         preg_write_utf16(data->ic, data->fd, ";");
  78         SIVAL(&buf, 0, value_data.length);
  79         write(data->fd, &buf, sizeof(uint32_t));
  80         preg_write_utf16(data->ic, data->fd, ";");
  81         write(data->fd, value_data.data, value_data.length);
  82         preg_write_utf16(data->ic, data->fd, "]");
  83         
  84         return WERR_OK;
  85 }
  86 
  87 static WERROR reg_preg_diff_del_key(void *_data, const char *key_name)
     /* [<][>][^][v][top][bottom][index][help] */
  88 {
  89         struct preg_data *data = (struct preg_data *)_data;
  90         char *parent_name;
  91         DATA_BLOB blob;
  92 
  93         parent_name = talloc_strndup(data->ctx, key_name, strrchr(key_name, '\\')-key_name);
  94         blob.data = (uint8_t *)talloc_strndup(data->ctx, key_name+(strrchr(key_name, '\\')-key_name)+1,
  95                         strlen(key_name)-(strrchr(key_name, '\\')-key_name));
  96         blob.length = strlen((char *)blob.data)+1;
  97         
  98 
  99         /* FIXME: These values should be accumulated to be written at done(). */
 100         return reg_preg_diff_set_value(data, parent_name, "**DeleteKeys", REG_SZ, blob);
 101 }
 102 
 103 static WERROR reg_preg_diff_del_value(void *_data, const char *key_name,
     /* [<][>][^][v][top][bottom][index][help] */
 104                                       const char *value_name)
 105 {
 106         struct preg_data *data = (struct preg_data *)_data;
 107         char *val;
 108         DATA_BLOB blob;
 109 
 110         val = talloc_asprintf(data->ctx, "**Del.%s", value_name);
 111 
 112         blob.data = (uint8_t *)talloc(data->ctx, uint32_t);
 113         *(uint32_t *)blob.data = 0;
 114         blob.length = 4;
 115         return reg_preg_diff_set_value(data, key_name, val, REG_DWORD, blob);
 116 }
 117 
 118 static WERROR reg_preg_diff_del_all_values(void *_data, const char *key_name)
     /* [<][>][^][v][top][bottom][index][help] */
 119 {
 120         struct preg_data *data = (struct preg_data *)_data;
 121         DATA_BLOB blob;
 122 
 123         blob.data = (uint8_t *)talloc(data->ctx, uint32_t);
 124         *(uint32_t *)blob.data = 0;     
 125         blob.length = 4;
 126 
 127         return reg_preg_diff_set_value(data, key_name, "**DelVals.", REG_DWORD, blob);
 128 }
 129 
 130 static WERROR reg_preg_diff_done(void *_data)
     /* [<][>][^][v][top][bottom][index][help] */
 131 {
 132         struct preg_data *data = (struct preg_data *)_data;
 133         
 134         close(data->fd);
 135         talloc_free(data);
 136         return WERR_OK;
 137 }
 138 
 139 /**
 140  * Save registry diff
 141  */
 142 _PUBLIC_ WERROR reg_preg_diff_save(TALLOC_CTX *ctx, const char *filename,
     /* [<][>][^][v][top][bottom][index][help] */
 143                                    struct smb_iconv_convenience *ic,
 144                                    struct reg_diff_callbacks **callbacks,
 145                                    void **callback_data)
 146 {
 147         struct preg_data *data;
 148         struct {
 149                 char hdr[4];
 150                 uint32_t version;
 151         } preg_header;
 152 
 153 
 154         data = talloc_zero(ctx, struct preg_data);
 155         *callback_data = data;
 156 
 157         if (filename) {
 158                 data->fd = open(filename, O_CREAT|O_WRONLY, 0755);
 159                 if (data->fd < 0) {
 160                         DEBUG(0, ("Unable to open %s\n", filename));
 161                         return WERR_BADFILE;
 162                 }
 163         } else {
 164                 data->fd = STDOUT_FILENO;
 165         }
 166 
 167         strncpy(preg_header.hdr, "PReg", 4);
 168         SIVAL(&preg_header, 4, 1);
 169         write(data->fd, (uint8_t *)&preg_header,8);
 170 
 171         data->ctx = ctx;
 172         data->ic = ic;
 173 
 174         *callbacks = talloc(ctx, struct reg_diff_callbacks);
 175 
 176         (*callbacks)->add_key = reg_preg_diff_add_key;
 177         (*callbacks)->del_key = reg_preg_diff_del_key;
 178         (*callbacks)->set_value = reg_preg_diff_set_value;
 179         (*callbacks)->del_value = reg_preg_diff_del_value;
 180         (*callbacks)->del_all_values = reg_preg_diff_del_all_values;
 181         (*callbacks)->done = reg_preg_diff_done;
 182 
 183         return WERR_OK;
 184 }
 185 /**
 186  * Load diff file
 187  */
 188 _PUBLIC_ WERROR reg_preg_diff_load(int fd,
     /* [<][>][^][v][top][bottom][index][help] */
 189                                    struct smb_iconv_convenience *iconv_convenience, 
 190                                    const struct reg_diff_callbacks *callbacks,
 191                                    void *callback_data)
 192 {
 193         struct {
 194                 char hdr[4];
 195                 uint32_t version;
 196         } preg_header;
 197         char *buf;
 198         size_t buf_size = 1024;
 199         char *buf_ptr;
 200         TALLOC_CTX *mem_ctx = talloc_init("reg_preg_diff_load");
 201         WERROR ret = WERR_OK;
 202         DATA_BLOB data = {NULL, 0};
 203         char *key = NULL;
 204         char *value_name = NULL;
 205 
 206         buf = talloc_array(mem_ctx, char, buf_size);
 207         buf_ptr = buf;
 208 
 209         /* Read first 8 bytes (the header) */
 210         if (read(fd, &preg_header, 8) != 8) {
 211                 DEBUG(0, ("Could not read PReg file: %s\n",
 212                                 strerror(errno)));
 213                 ret = WERR_GENERAL_FAILURE;
 214                 goto cleanup;
 215         }
 216         preg_header.version = IVAL(&preg_header.version, 0);
 217 
 218         if (strncmp(preg_header.hdr, "PReg", 4) != 0) {
 219                 DEBUG(0, ("This file is not a valid preg registry file\n"));
 220                 ret = WERR_GENERAL_FAILURE;
 221                 goto cleanup;
 222         }
 223         if (preg_header.version > 1) {
 224                 DEBUG(0, ("Warning: file format version is higher than expected.\n"));
 225         }
 226 
 227         /* Read the entries */
 228         while(1) {
 229                 uint32_t value_type, length;
 230 
 231                 if (!W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr))) {
 232                         break;
 233                 }
 234                 if (*buf_ptr != '[') {
 235                         DEBUG(0, ("Error in PReg file.\n"));
 236                         ret = WERR_GENERAL_FAILURE;
 237                         goto cleanup;
 238                 }
 239 
 240                 /* Get the path */
 241                 buf_ptr = buf;
 242                 while (W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
 243                        *buf_ptr != ';' && buf_ptr-buf < buf_size) {
 244                         buf_ptr++;
 245                 }
 246                 buf[buf_ptr-buf] = '\0';
 247                 key = talloc_strdup(mem_ctx, buf);
 248 
 249                 /* Get the name */
 250                 buf_ptr = buf;
 251                 while (W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
 252                        *buf_ptr != ';' && buf_ptr-buf < buf_size) {
 253                         buf_ptr++;
 254                 }
 255                 buf[buf_ptr-buf] = '\0';
 256                 value_name = talloc_strdup(mem_ctx, buf);
 257 
 258                 /* Get the type */
 259                 if (read(fd, &value_type, 4) < 4) {
 260                         DEBUG(0, ("Error while reading PReg\n"));
 261                         ret = WERR_GENERAL_FAILURE;
 262                         goto cleanup;
 263                 }
 264                 value_type = IVAL(&value_type, 0);
 265 
 266                 /* Read past delimiter */
 267                 buf_ptr = buf;
 268                 if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
 269                     *buf_ptr == ';') && buf_ptr-buf < buf_size) {
 270                         DEBUG(0, ("Error in PReg file.\n"));
 271                         ret = WERR_GENERAL_FAILURE;
 272                         goto cleanup;
 273                 }
 274                 /* Get data length */
 275                 if (read(fd, &length, 4) < 4) {
 276                         DEBUG(0, ("Error while reading PReg\n"));
 277                         ret = WERR_GENERAL_FAILURE;
 278                         goto cleanup;
 279                 }
 280                 /* Read past delimiter */
 281                 buf_ptr = buf;
 282                 if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
 283                     *buf_ptr == ';') && buf_ptr-buf < buf_size) {
 284                         DEBUG(0, ("Error in PReg file.\n"));
 285                         ret = WERR_GENERAL_FAILURE;
 286                         goto cleanup;
 287                 }
 288                 /* Get the data */
 289                 buf_ptr = buf;
 290                 if (length < buf_size &&
 291                     read(fd, buf_ptr, length) != length) {
 292                         DEBUG(0, ("Error while reading PReg\n"));
 293                         ret = WERR_GENERAL_FAILURE;
 294                         goto cleanup;
 295                 }
 296                 data = data_blob_talloc(mem_ctx, buf, length);
 297 
 298                 /* Check if delimiter is in place (whine if it isn't) */
 299                 buf_ptr = buf;
 300                 if (!(W_ERROR_IS_OK(preg_read_utf16(iconv_convenience, fd, buf_ptr)) &&
 301                     *buf_ptr == ']') && buf_ptr-buf < buf_size) {
 302                         DEBUG(0, ("Warning: Missing ']' in PReg file, expected ']', got '%c' 0x%x.\n",
 303                                 *buf_ptr, *buf_ptr));
 304                 }
 305 
 306                 if (strcasecmp(value_name, "**DelVals") == 0) {
 307                         callbacks->del_all_values(callback_data, key);
 308                 } else if (strncasecmp(value_name, "**Del.",6) == 0) {
 309                         char *p = value_name+6;
 310 
 311                         callbacks->del_value(callback_data, key, p);
 312                 } else  if (strcasecmp(value_name, "**DeleteValues") == 0) {
 313                         char *p, *q;
 314 
 315                         p = (char *) data.data;
 316 
 317                         while ((q = strchr_m(p, ';'))) {
 318                                 *q = '\0';
 319                                 q++;
 320 
 321                                 callbacks->del_value(callback_data, key, p);
 322 
 323                                 p = q;
 324                         }
 325                         callbacks->del_value(callback_data, key, p);
 326                 } else if (strcasecmp(value_name, "**DeleteKeys") == 0) {
 327                         char *p, *q, *full_key;
 328 
 329                         p = (char *) data.data;
 330 
 331                         while ((q = strchr_m(p, ';'))) {
 332                                 *q = '\0';
 333                                 q++;
 334 
 335                                 full_key = talloc_asprintf(mem_ctx, "%s\\%s",
 336                                                            key, p);
 337                                 callbacks->del_key(callback_data, full_key);
 338                                 talloc_free(full_key);
 339 
 340                                 p = q;
 341                         }
 342                         full_key = talloc_asprintf(mem_ctx, "%s\\%s", key, p);
 343                         callbacks->del_key(callback_data, full_key);
 344                         talloc_free(full_key);
 345                 } else {
 346                         callbacks->add_key(callback_data, key);
 347                         callbacks->set_value(callback_data, key, value_name,
 348                                              value_type, data);
 349                 }
 350         }
 351 cleanup:
 352         close(fd);
 353         talloc_free(data.data);
 354         talloc_free(key);
 355         talloc_free(value_name);
 356         talloc_free(buf);
 357         return ret;
 358 }

/* [<][>][^][v][top][bottom][index][help] */