root/source4/lib/registry/patchfile.c

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

DEFINITIONS

This source file includes following definitions.
  1. reg_generate_diff_key
  2. reg_generate_diff
  3. reg_diff_load
  4. reg_diff_apply_add_key
  5. reg_diff_apply_del_key
  6. reg_diff_apply_set_value
  7. reg_diff_apply_del_value
  8. reg_diff_apply_del_all_values
  9. reg_diff_apply

   1 /*
   2    Unix SMB/CIFS implementation.
   3    Reading registry patch files
   4 
   5    Copyright (C) Jelmer Vernooij 2004-2007
   6    Copyright (C) Wilco Baan Hofman 2006
   7    Copyright (C) Matthias Dieter Wallnöfer 2008
   8 
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 3 of the License, or
  12    (at your option) any later version.
  13 
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18 
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 #include "includes.h"
  24 #include "lib/registry/registry.h"
  25 #include "system/filesys.h"
  26 
  27 
  28 _PUBLIC_ WERROR reg_preg_diff_load(int fd,
  29                                    struct smb_iconv_convenience *iconv_convenience, 
  30                                    const struct reg_diff_callbacks *callbacks,
  31                                    void *callback_data);
  32 
  33 _PUBLIC_ WERROR reg_dotreg_diff_load(int fd,
  34                                      struct smb_iconv_convenience *iconv_convenience,
  35                                      const struct reg_diff_callbacks *callbacks,
  36                                      void *callback_data);
  37 
  38 /*
  39  * Generate difference between two keys
  40  */
  41 WERROR reg_generate_diff_key(struct registry_key *oldkey,
     /* [<][>][^][v][top][bottom][index][help] */
  42                              struct registry_key *newkey,
  43                              const char *path,
  44                              const struct reg_diff_callbacks *callbacks,
  45                              void *callback_data)
  46 {
  47         int i;
  48         struct registry_key *t1 = NULL, *t2 = NULL;
  49         char *tmppath;
  50         const char *keyname1;
  51         WERROR error, error1, error2;
  52         TALLOC_CTX *mem_ctx = talloc_init("writediff");
  53         uint32_t old_num_subkeys, old_num_values,
  54                          new_num_subkeys, new_num_values;
  55 
  56         if (oldkey != NULL) {
  57                 error = reg_key_get_info(mem_ctx, oldkey, NULL,
  58                                          &old_num_subkeys, &old_num_values,
  59                                          NULL, NULL, NULL, NULL);
  60                 if (!W_ERROR_IS_OK(error)) {
  61                         DEBUG(0, ("Error occurred while getting key info: %s\n",
  62                                 win_errstr(error)));
  63                         talloc_free(mem_ctx);
  64                         return error;
  65                 }
  66         } else {
  67                 old_num_subkeys = 0;
  68                 old_num_values = 0;
  69         }
  70 
  71         /* Subkeys that were changed or deleted */
  72         for (i = 0; i < old_num_subkeys; i++) {
  73                 error1 = reg_key_get_subkey_by_index(mem_ctx, oldkey, i,
  74                                                      &keyname1, NULL, NULL);
  75                 if (!W_ERROR_IS_OK(error1)) {
  76                         DEBUG(0, ("Error occurred while getting subkey by index: %s\n",
  77                                 win_errstr(error1)));
  78                         continue;
  79                 }
  80 
  81                 if (newkey != NULL) {
  82                         error2 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
  83                 } else {
  84                         error2 = WERR_BADFILE;
  85                         t2 = NULL;
  86                 }
  87 
  88                 if (!W_ERROR_IS_OK(error2) && !W_ERROR_EQUAL(error2, WERR_BADFILE)) {
  89                         DEBUG(0, ("Error occured while getting subkey by name: %s\n",
  90                                 win_errstr(error2)));
  91                         talloc_free(mem_ctx);
  92                         return error2;
  93                 }
  94 
  95                 /* if "error2" is going to be "WERR_BADFILE", then newkey */
  96                 /* didn't have such a subkey and therefore add a del diff */
  97                 tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
  98                 if (!W_ERROR_IS_OK(error2))
  99                         callbacks->del_key(callback_data, tmppath);
 100 
 101                 /* perform here also the recursive invocation */
 102                 error1 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
 103                 if (!W_ERROR_IS_OK(error1)) {
 104                         DEBUG(0, ("Error occured while getting subkey by name: %s\n",
 105                         win_errstr(error1)));
 106                         talloc_free(mem_ctx);
 107                         return error1;
 108                 }
 109                 reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
 110 
 111                 talloc_free(tmppath);
 112         }
 113 
 114         if (newkey != NULL) {
 115                 error = reg_key_get_info(mem_ctx, newkey, NULL,
 116                                          &new_num_subkeys, &new_num_values,
 117                                          NULL, NULL, NULL, NULL);
 118                 if (!W_ERROR_IS_OK(error)) {
 119                         DEBUG(0, ("Error occurred while getting key info: %s\n",
 120                                 win_errstr(error)));
 121                         talloc_free(mem_ctx);
 122                         return error;
 123                 }
 124         } else {
 125                 new_num_subkeys = 0;
 126                 new_num_values = 0;
 127         }
 128 
 129         /* Subkeys that were added */
 130         for(i = 0; i < new_num_subkeys; i++) {
 131                 error1 = reg_key_get_subkey_by_index(mem_ctx, newkey, i,
 132                                                      &keyname1, NULL, NULL);
 133                 if (!W_ERROR_IS_OK(error1)) {
 134                         DEBUG(0, ("Error occurred while getting subkey by index: %s\n",
 135                                 win_errstr(error1)));
 136                         talloc_free(mem_ctx);
 137                         return error1;
 138                 }
 139 
 140                 if (oldkey != NULL) {
 141                         error2 = reg_open_key(mem_ctx, oldkey, keyname1, &t1);
 142 
 143                         if (W_ERROR_IS_OK(error2))
 144                                 continue;
 145                 } else {
 146                         error2 = WERR_BADFILE;  
 147                         t1 = NULL;
 148                 }
 149 
 150                 if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
 151                         DEBUG(0, ("Error occurred while getting subkey by name: %s\n",
 152                                 win_errstr(error2)));
 153                         talloc_free(mem_ctx);
 154                         return error2;
 155                 }
 156 
 157                 /* oldkey didn't have such a subkey, add add diff */
 158                 tmppath = talloc_asprintf(mem_ctx, "%s\\%s", path, keyname1);
 159                 callbacks->add_key(callback_data, tmppath);
 160 
 161                 /* perform here also the recursive invocation */
 162                 error1 = reg_open_key(mem_ctx, newkey, keyname1, &t2);
 163                 if (!W_ERROR_IS_OK(error1)) {
 164                         DEBUG(0, ("Error occured while getting subkey by name: %s\n",
 165                         win_errstr(error1)));
 166                         talloc_free(mem_ctx);
 167                         return error1;
 168                 }
 169                 reg_generate_diff_key(t1, t2, tmppath, callbacks, callback_data);
 170 
 171                 talloc_free(tmppath);
 172         }
 173 
 174         /* Values that were added or changed */
 175         for(i = 0; i < new_num_values; i++) {
 176                 const char *name;
 177                 uint32_t type1, type2;
 178                 DATA_BLOB contents1, contents2;
 179 
 180                 error1 = reg_key_get_value_by_index(mem_ctx, newkey, i,
 181                                                     &name, &type1, &contents1);
 182                 if (!W_ERROR_IS_OK(error1)) {
 183                         DEBUG(0, ("Unable to get value by index: %s\n",
 184                                 win_errstr(error1)));
 185                         talloc_free(mem_ctx);
 186                         return error1;
 187                 }
 188 
 189                 if (oldkey != NULL) {
 190                         error2 = reg_key_get_value_by_name(mem_ctx, oldkey,
 191                                                            name, &type2,
 192                                                            &contents2);
 193                 } else
 194                         error2 = WERR_BADFILE;
 195 
 196                 if (!W_ERROR_IS_OK(error2)
 197                         && !W_ERROR_EQUAL(error2, WERR_BADFILE)) {
 198                         DEBUG(0, ("Error occurred while getting value by name: %s\n",
 199                                 win_errstr(error2)));
 200                         talloc_free(mem_ctx);
 201                         return error2;
 202                 }
 203 
 204                 if (W_ERROR_IS_OK(error2)
 205                         && (data_blob_cmp(&contents1, &contents2) == 0)
 206                         && (type1 == type2))
 207                         continue;
 208 
 209                 callbacks->set_value(callback_data, path, name,
 210                                      type1, contents1);
 211         }
 212 
 213         /* Values that were deleted */
 214         for (i = 0; i < old_num_values; i++) {
 215                 const char *name;
 216                 uint32_t type;
 217                 DATA_BLOB contents;
 218 
 219                 error1 = reg_key_get_value_by_index(mem_ctx, oldkey, i, &name,
 220                                                     &type, &contents);
 221                 if (!W_ERROR_IS_OK(error1)) {
 222                         DEBUG(0, ("Unable to get value by index: %s\n",
 223                                 win_errstr(error1)));
 224                         talloc_free(mem_ctx);
 225                         return error1;
 226                 }
 227 
 228                 if (newkey != NULL)
 229                         error2 = reg_key_get_value_by_name(mem_ctx, newkey,
 230                                  name, &type, &contents);
 231                 else
 232                         error2 = WERR_BADFILE;
 233 
 234                 if (W_ERROR_IS_OK(error2))
 235                         continue;
 236 
 237                 if (!W_ERROR_EQUAL(error2, WERR_BADFILE)) {
 238                         DEBUG(0, ("Error occurred while getting value by name: %s\n",
 239                                 win_errstr(error2)));
 240                         talloc_free(mem_ctx);
 241                         return error2;
 242                 }
 243 
 244                 callbacks->del_value(callback_data, path, name);
 245         }
 246 
 247         talloc_free(mem_ctx);
 248         return WERR_OK;
 249 }
 250 
 251 /**
 252  * Generate diff between two registry contexts
 253  */
 254 _PUBLIC_ WERROR reg_generate_diff(struct registry_context *ctx1,
     /* [<][>][^][v][top][bottom][index][help] */
 255                                   struct registry_context *ctx2,
 256                                   const struct reg_diff_callbacks *callbacks,
 257                                   void *callback_data)
 258 {
 259         int i;
 260         WERROR error;
 261 
 262         for (i = 0; reg_predefined_keys[i].name; i++) {
 263                 struct registry_key *r1 = NULL, *r2 = NULL;
 264 
 265                 error = reg_get_predefined_key(ctx1,
 266                         reg_predefined_keys[i].handle, &r1);
 267                 if (!W_ERROR_IS_OK(error) &&
 268                     !W_ERROR_EQUAL(error, WERR_BADFILE)) {
 269                         DEBUG(0, ("Unable to open hive %s for backend 1\n",
 270                                 reg_predefined_keys[i].name));
 271                         continue;
 272                 }
 273 
 274                 error = reg_get_predefined_key(ctx2,
 275                         reg_predefined_keys[i].handle, &r2);
 276                 if (!W_ERROR_IS_OK(error) &&
 277                     !W_ERROR_EQUAL(error, WERR_BADFILE)) {
 278                         DEBUG(0, ("Unable to open hive %s for backend 2\n",
 279                                 reg_predefined_keys[i].name));
 280                         continue;
 281                 }
 282 
 283                 error = reg_generate_diff_key(r1, r2,
 284                         reg_predefined_keys[i].name, callbacks,
 285                         callback_data);
 286                 if (!W_ERROR_IS_OK(error)) {
 287                         DEBUG(0, ("Unable to determine diff: %s\n",
 288                                 win_errstr(error)));
 289                         return error;
 290                 }
 291         }
 292         if (callbacks->done != NULL) {
 293                 callbacks->done(callback_data);
 294         }
 295         return WERR_OK;
 296 }
 297 
 298 /**
 299  * Load diff file
 300  */
 301 _PUBLIC_ WERROR reg_diff_load(const char *filename,
     /* [<][>][^][v][top][bottom][index][help] */
 302                               struct smb_iconv_convenience *iconv_convenience,
 303                               const struct reg_diff_callbacks *callbacks,
 304                               void *callback_data)
 305 {
 306         int fd;
 307         char hdr[4];
 308 
 309         fd = open(filename, O_RDONLY, 0);
 310         if (fd == -1) {
 311                 DEBUG(0, ("Error opening registry patch file `%s'\n",
 312                         filename));
 313                 return WERR_GENERAL_FAILURE;
 314         }
 315 
 316         if (read(fd, &hdr, 4) != 4) {
 317                 DEBUG(0, ("Error reading registry patch file `%s'\n",
 318                         filename));
 319                 return WERR_GENERAL_FAILURE;
 320         }
 321 
 322         /* Reset position in file */
 323         lseek(fd, 0, SEEK_SET);
 324 #if 0 /* These backends are not supported yet. */
 325         if (strncmp(hdr, "CREG", 4) == 0) {
 326                 /* Must be a W9x CREG Config.pol file */
 327                 return reg_creg_diff_load(diff, fd);
 328         } else if (strncmp(hdr, "regf", 4) == 0) {
 329                 /* Must be a REGF NTConfig.pol file */
 330                 return reg_regf_diff_load(diff, fd);
 331         } else
 332 #endif
 333         if (strncmp(hdr, "PReg", 4) == 0) {
 334                 /* Must be a GPO Registry.pol file */
 335                 return reg_preg_diff_load(fd, iconv_convenience, callbacks, callback_data);
 336         } else {
 337                 /* Must be a normal .REG file */
 338                 return reg_dotreg_diff_load(fd, iconv_convenience, callbacks, callback_data);
 339         }
 340 }
 341 
 342 /**
 343  * The reg_diff_apply functions
 344  */
 345 static WERROR reg_diff_apply_add_key(void *_ctx, const char *key_name)
     /* [<][>][^][v][top][bottom][index][help] */
 346 {
 347         struct registry_context *ctx = (struct registry_context *)_ctx;
 348         struct registry_key *tmp;
 349         char *buf, *buf_ptr;
 350         WERROR error;
 351 
 352         /* Recursively create the path */
 353         buf = talloc_strdup(ctx, key_name);
 354         buf_ptr = buf;
 355 
 356         while (*buf_ptr++ != '\0' ) {
 357                 if (*buf_ptr == '\\') {
 358                         *buf_ptr = '\0';
 359                         error = reg_key_add_abs(ctx, ctx, buf, 0, NULL, &tmp);
 360 
 361                         if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
 362                                     !W_ERROR_IS_OK(error)) {
 363                                 DEBUG(0, ("Error adding new key '%s': %s\n",
 364                                         key_name, win_errstr(error)));
 365                                 return error;
 366                         }
 367                         *buf_ptr++ = '\\';
 368                 }
 369         }
 370 
 371         /* Add the key */
 372         error = reg_key_add_abs(ctx, ctx, key_name, 0, NULL, &tmp);
 373 
 374         if (!W_ERROR_EQUAL(error, WERR_ALREADY_EXISTS) &&
 375                     !W_ERROR_IS_OK(error)) {
 376                 DEBUG(0, ("Error adding new key '%s': %s\n",
 377                         key_name, win_errstr(error)));
 378                 return error;
 379         }
 380         return WERR_OK;
 381 }
 382 
 383 static WERROR reg_diff_apply_del_key(void *_ctx, const char *key_name)
     /* [<][>][^][v][top][bottom][index][help] */
 384 {
 385         struct registry_context *ctx = (struct registry_context *)_ctx;
 386 
 387         /* We can't proof here for success, because a common superkey could */
 388         /* have been deleted before the subkey's (diff order). This removed */
 389         /* therefore all childs recursively and the "WERR_BADFILE" result is */
 390         /* expected. */
 391 
 392         reg_key_del_abs(ctx, key_name);
 393 
 394         return WERR_OK;
 395 }
 396 
 397 static WERROR reg_diff_apply_set_value(void *_ctx, const char *path,
     /* [<][>][^][v][top][bottom][index][help] */
 398                                        const char *value_name,
 399                                        uint32_t value_type, DATA_BLOB value)
 400 {
 401         struct registry_context *ctx = (struct registry_context *)_ctx;
 402         struct registry_key *tmp;
 403         WERROR error;
 404 
 405         /* Open key */
 406         error = reg_open_key_abs(ctx, ctx, path, &tmp);
 407 
 408         if (W_ERROR_EQUAL(error, WERR_BADFILE)) {
 409                 DEBUG(0, ("Error opening key '%s'\n", path));
 410                 return error;
 411         }
 412 
 413         /* Set value */
 414         error = reg_val_set(tmp, value_name,
 415                                  value_type, value);
 416         if (!W_ERROR_IS_OK(error)) {
 417                 DEBUG(0, ("Error setting value '%s'\n", value_name));
 418                 return error;
 419         }
 420 
 421         return WERR_OK;
 422 }
 423 
 424 static WERROR reg_diff_apply_del_value(void *_ctx, const char *key_name,
     /* [<][>][^][v][top][bottom][index][help] */
 425                                        const char *value_name)
 426 {
 427         struct registry_context *ctx = (struct registry_context *)_ctx;
 428         struct registry_key *tmp;
 429         WERROR error;
 430 
 431         /* Open key */
 432         error = reg_open_key_abs(ctx, ctx, key_name, &tmp);
 433 
 434         if (!W_ERROR_IS_OK(error)) {
 435                 DEBUG(0, ("Error opening key '%s'\n", key_name));
 436                 return error;
 437         }
 438 
 439         error = reg_del_value(tmp, value_name);
 440         if (!W_ERROR_IS_OK(error)) {
 441                 DEBUG(0, ("Error deleting value '%s'\n", value_name));
 442                 return error;
 443         }
 444 
 445 
 446         return WERR_OK;
 447 }
 448 
 449 static WERROR reg_diff_apply_del_all_values(void *_ctx, const char *key_name)
     /* [<][>][^][v][top][bottom][index][help] */
 450 {
 451         struct registry_context *ctx = (struct registry_context *)_ctx;
 452         struct registry_key *key;
 453         WERROR error;
 454         const char* value_name;
 455 
 456         error = reg_open_key_abs(ctx, ctx, key_name, &key);
 457 
 458         if (!W_ERROR_IS_OK(error)) {
 459                 DEBUG(0, ("Error opening key '%s'\n", key_name));
 460                 return error;
 461         }
 462 
 463         W_ERROR_NOT_OK_RETURN(reg_key_get_info(ctx, key, NULL,
 464                                NULL, NULL, NULL, NULL, NULL, NULL));
 465 
 466         while (W_ERROR_IS_OK(reg_key_get_value_by_index(
 467                         ctx, key, 0, &value_name, NULL, NULL))) {
 468                 error = reg_del_value(key, value_name);
 469                 if (!W_ERROR_IS_OK(error)) {
 470                         DEBUG(0, ("Error deleting value '%s'\n", value_name));
 471                         return error;
 472                 }
 473         }
 474 
 475         return WERR_OK;
 476 }
 477 
 478 /**
 479  * Apply diff to a registry context
 480  */
 481 _PUBLIC_ WERROR reg_diff_apply(struct registry_context *ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 482                                                            struct smb_iconv_convenience *iconv_convenience, 
 483                                                            const char *filename)
 484 {
 485         struct reg_diff_callbacks callbacks;
 486 
 487         callbacks.add_key = reg_diff_apply_add_key;
 488         callbacks.del_key = reg_diff_apply_del_key;
 489         callbacks.set_value = reg_diff_apply_set_value;
 490         callbacks.del_value = reg_diff_apply_del_value;
 491         callbacks.del_all_values = reg_diff_apply_del_all_values;
 492         callbacks.done = NULL;
 493 
 494         return reg_diff_load(filename, iconv_convenience,
 495                              &callbacks, ctx);
 496 }

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