LCOV - code coverage report
Current view: top level - source4/lib/registry - patchfile_dotreg.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 116 206 56.3 %
Date: 2021-09-23 10:06:22 Functions: 7 10 70.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Reading .REG files
       4             : 
       5             :    Copyright (C) Jelmer Vernooij 2004-2007
       6             :    Copyright (C) Wilco Baan Hofman 2006-2010
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program; if not, write to the Free Software
      20             :    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
      21             : */
      22             : 
      23             : /* FIXME:
      24             :  * - Newer .REG files, created by Windows XP and above use unicode UCS-2
      25             :  * - @="" constructions should write value with empty name.
      26             : */
      27             : 
      28             : #include "includes.h"
      29             : #include "lib/registry/registry.h"
      30             : #include "system/filesys.h"
      31             : 
      32             : /**
      33             :  * @file
      34             :  * @brief Registry patch files
      35             :  */
      36             : 
      37             : #define HEADER_STRING "REGEDIT4"
      38             : 
      39             : struct dotreg_data {
      40             :         int fd;
      41             : };
      42             : 
      43             : /* 
      44             :  * This is basically a copy of data_blob_hex_string_upper, but with comma's 
      45             :  * between the bytes in hex.
      46             :  */
      47           0 : static char *dotreg_data_blob_hex_string(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
      48             : {
      49             :         size_t i;
      50             :         char *hex_string;
      51             : 
      52           0 :         hex_string = talloc_array(mem_ctx, char, (blob->length*3)+1);
      53           0 :         if (!hex_string) {
      54           0 :                 return NULL;
      55             :         }
      56             : 
      57           0 :         for (i = 0; i < blob->length; i++)
      58           0 :                 slprintf(&hex_string[i*3], 4, "%02X,", blob->data[i]);
      59             : 
      60             :         /* Remove last comma and NULL-terminate the string */
      61           0 :         hex_string[(blob->length*3)-1] = '\0';
      62           0 :         return hex_string;
      63             : }
      64             : 
      65             : /* 
      66             :  * This is basically a copy of reg_val_data_string, except that this function
      67             :  * has no 0x for dwords, everything else is regarded as binary, and binary 
      68             :  * strings are represented with bytes comma-separated.
      69             :  */
      70           1 : static char *reg_val_dotreg_string(TALLOC_CTX *mem_ctx, uint32_t type,
      71             :                                    const DATA_BLOB data)
      72             : {
      73           1 :         size_t converted_size = 0;
      74           1 :         char *ret = NULL;
      75             : 
      76           1 :         if (data.length == 0)
      77           0 :                 return talloc_strdup(mem_ctx, "");
      78             : 
      79           1 :         switch (type) {
      80           0 :                 case REG_EXPAND_SZ:
      81             :                 case REG_SZ:
      82           0 :                         convert_string_talloc(mem_ctx,
      83           0 :                                               CH_UTF16, CH_UNIX, data.data, data.length,
      84             :                                               (void **)&ret, &converted_size);
      85           0 :                         break;
      86           1 :                 case REG_DWORD:
      87             :                 case REG_DWORD_BIG_ENDIAN:
      88           1 :                         SMB_ASSERT(data.length == sizeof(uint32_t));
      89           1 :                         ret = talloc_asprintf(mem_ctx, "%08x",
      90           1 :                                               IVAL(data.data, 0));
      91           1 :                         break;
      92           0 :                 default: /* default means treat as binary */
      93             :                 case REG_BINARY:
      94           0 :                         ret = dotreg_data_blob_hex_string(mem_ctx, &data);
      95           0 :                         break;
      96             :         }
      97             : 
      98           1 :         return ret;
      99             : }
     100             : 
     101           6 : static WERROR reg_dotreg_diff_add_key(void *_data, const char *key_name)
     102             : {
     103           6 :         struct dotreg_data *data = (struct dotreg_data *)_data;
     104             : 
     105           6 :         fdprintf(data->fd, "\n[%s]\n", key_name);
     106             : 
     107           6 :         return WERR_OK;
     108             : }
     109             : 
     110           2 : static WERROR reg_dotreg_diff_del_key(void *_data, const char *key_name)
     111             : {
     112           2 :         struct dotreg_data *data = (struct dotreg_data *)_data;
     113             : 
     114           2 :         fdprintf(data->fd, "\n[-%s]\n", key_name);
     115             : 
     116           2 :         return WERR_OK;
     117             : }
     118             : 
     119           1 : static WERROR reg_dotreg_diff_set_value(void *_data, const char *path,
     120             :                                         const char *value_name,
     121             :                                         uint32_t value_type, DATA_BLOB value)
     122             : {
     123           1 :         struct dotreg_data *data = (struct dotreg_data *)_data;
     124           1 :         char *data_string = reg_val_dotreg_string(NULL, 
     125             :                                                 value_type, value);
     126             :         char *data_incl_type;
     127             : 
     128           1 :         W_ERROR_HAVE_NO_MEMORY(data_string);
     129             : 
     130           1 :         switch (value_type) {
     131           0 :                 case REG_SZ:
     132           0 :                         data_incl_type = talloc_asprintf(data_string, "\"%s\"", 
     133             :                                         data_string);
     134           0 :                         break;
     135           1 :                 case REG_DWORD:
     136           1 :                         data_incl_type = talloc_asprintf(data_string, 
     137             :                                         "dword:%s", data_string);
     138           1 :                         break;
     139           0 :                 case REG_BINARY:
     140           0 :                         data_incl_type = talloc_asprintf(data_string, "hex:%s",
     141             :                                         data_string);
     142           0 :                         break;
     143           0 :                 default:
     144           0 :                         data_incl_type = talloc_asprintf(data_string, "hex(%x):%s", 
     145             :                                         value_type, data_string);
     146           0 :                         break;
     147             :         }
     148             : 
     149           1 :         if (value_name[0] == '\0') {
     150           0 :                 fdprintf(data->fd, "@=%s\n", data_incl_type);
     151             :         } else {
     152           1 :                 fdprintf(data->fd, "\"%s\"=%s\n",
     153             :                          value_name, data_incl_type);
     154             :         }
     155             : 
     156           1 :         talloc_free(data_string);
     157             : 
     158           1 :         return WERR_OK;
     159             : }
     160             : 
     161           0 : static WERROR reg_dotreg_diff_del_value(void *_data, const char *path,
     162             :                                         const char *value_name)
     163             : {
     164           0 :         struct dotreg_data *data = (struct dotreg_data *)_data;
     165             : 
     166           0 :         fdprintf(data->fd, "\"%s\"=-\n", value_name);
     167             : 
     168           0 :         return WERR_OK;
     169             : }
     170             : 
     171           1 : static WERROR reg_dotreg_diff_done(void *_data)
     172             : {
     173           1 :         struct dotreg_data *data = (struct dotreg_data *)_data;
     174             : 
     175           1 :         close(data->fd);
     176           1 :         talloc_free(data);
     177             : 
     178           1 :         return WERR_OK;
     179             : }
     180             : 
     181           0 : static WERROR reg_dotreg_diff_del_all_values(void *callback_data,
     182             :                                              const char *key_name)
     183             : {
     184           0 :         return WERR_NOT_SUPPORTED;
     185             : }
     186             : 
     187             : /**
     188             :  * Save registry diff
     189             :  */
     190           1 : _PUBLIC_ WERROR reg_dotreg_diff_save(TALLOC_CTX *ctx, const char *filename,
     191             :                                      struct reg_diff_callbacks **callbacks,
     192             :                                      void **callback_data)
     193             : {
     194             :         struct dotreg_data *data;
     195             : 
     196           1 :         data = talloc_zero(ctx, struct dotreg_data);
     197           1 :         *callback_data = data;
     198             : 
     199           1 :         if (filename) {
     200           1 :                 data->fd = open(filename, O_CREAT|O_WRONLY, 0755);
     201           1 :                 if (data->fd < 0) {
     202           0 :                         DEBUG(0, ("Unable to open %s\n", filename));
     203           0 :                         return WERR_FILE_NOT_FOUND;
     204             :                 }
     205             :         } else {
     206           0 :                 data->fd = STDOUT_FILENO;
     207             :         }
     208             : 
     209           1 :         fdprintf(data->fd, "%s\n\n", HEADER_STRING);
     210             : 
     211           1 :         *callbacks = talloc(ctx, struct reg_diff_callbacks);
     212             : 
     213           1 :         (*callbacks)->add_key = reg_dotreg_diff_add_key;
     214           1 :         (*callbacks)->del_key = reg_dotreg_diff_del_key;
     215           1 :         (*callbacks)->set_value = reg_dotreg_diff_set_value;
     216           1 :         (*callbacks)->del_value = reg_dotreg_diff_del_value;
     217           1 :         (*callbacks)->del_all_values = reg_dotreg_diff_del_all_values;
     218           1 :         (*callbacks)->done = reg_dotreg_diff_done;
     219             : 
     220           1 :         return WERR_OK;
     221             : }
     222             : 
     223             : /**
     224             :  * Load diff file
     225             :  */
     226         194 : _PUBLIC_ WERROR reg_dotreg_diff_load(int fd,
     227             :                                      const struct reg_diff_callbacks *callbacks,
     228             :                                      void *callback_data)
     229             : {
     230             :         char *line, *p, *q;
     231         194 :         char *curkey = NULL;
     232         194 :         TALLOC_CTX *mem_ctx = talloc_init("reg_dotreg_diff_load");
     233             :         WERROR error;
     234             :         uint32_t value_type;
     235             :         DATA_BLOB data;
     236             :         bool result;
     237         194 :         char *type_str = NULL;
     238         194 :         char *data_str = NULL;
     239         194 :         char *value = NULL;
     240         194 :         bool continue_next_line = 0;
     241             : 
     242         194 :         line = afdgets(fd, mem_ctx, 0);
     243         194 :         if (!line) {
     244           0 :                 DEBUG(0, ("Can't read from file.\n"));
     245           0 :                 talloc_free(mem_ctx);
     246           0 :                 close(fd);
     247           0 :                 return WERR_GEN_FAILURE;
     248             :         }
     249             : 
     250        8844 :         while ((line = afdgets(fd, mem_ctx, 0))) {
     251             :                 /* Remove '\r' if it's a Windows text file */
     252        8510 :                 if (strlen(line) && line[strlen(line)-1] == '\r') {
     253           0 :                         line[strlen(line)-1] = '\0';
     254             :                 }
     255             : 
     256             :                 /* Ignore comments and empty lines */
     257        8510 :                 if (strlen(line) == 0 || line[0] == ';') {
     258        4062 :                         talloc_free(line);
     259             : 
     260        4062 :                         if (curkey) {
     261        3865 :                                 talloc_free(curkey);
     262             :                         }
     263        4062 :                         curkey = NULL;
     264        4062 :                         continue;
     265             :                 }
     266             : 
     267             :                 /* Start of key */
     268        4448 :                 if (line[0] == '[') {
     269        3868 :                         if (line[strlen(line)-1] != ']') {
     270           0 :                                 DEBUG(0, ("Missing ']' on line: %s\n", line));
     271           0 :                                 talloc_free(line);
     272           0 :                                 continue;
     273             :                         }
     274             : 
     275             :                         /* Deleting key */
     276        3868 :                         if (line[1] == '-') {
     277           2 :                                 curkey = talloc_strndup(line, line+2, strlen(line)-3);
     278           2 :                                 W_ERROR_HAVE_NO_MEMORY(curkey);
     279             : 
     280           2 :                                 error = callbacks->del_key(callback_data,
     281             :                                                            curkey);
     282             : 
     283           2 :                                 if (!W_ERROR_IS_OK(error)) {
     284           0 :                                         DEBUG(0,("Error deleting key %s\n",
     285             :                                                 curkey));
     286           0 :                                         talloc_free(mem_ctx);
     287           0 :                                         return error;
     288             :                                 }
     289             : 
     290           2 :                                 talloc_free(line);
     291           2 :                                 curkey = NULL;
     292           2 :                                 continue;
     293             :                         }
     294        3866 :                         curkey = talloc_strndup(mem_ctx, line+1, strlen(line)-2);
     295        3866 :                         W_ERROR_HAVE_NO_MEMORY(curkey);
     296             : 
     297        3866 :                         error = callbacks->add_key(callback_data, curkey);
     298        3866 :                         if (!W_ERROR_IS_OK(error)) {
     299           0 :                                 DEBUG(0,("Error adding key %s\n", curkey));
     300           0 :                                 talloc_free(mem_ctx);
     301           0 :                                 return error;
     302             :                         }
     303             : 
     304        3866 :                         talloc_free(line);
     305        3866 :                         continue;
     306             :                 }
     307             : 
     308             :                 /* Deleting/Changing value */
     309         580 :                 if (continue_next_line) {
     310           0 :                         continue_next_line = 0;
     311             : 
     312             :                         /* Continued data start with two whitespaces */
     313           0 :                         if (line[0] != ' ' || line[1] != ' ') {
     314           0 :                                 DEBUG(0, ("Malformed line: %s\n", line));
     315           0 :                                 talloc_free(line);
     316           0 :                                 continue;
     317             :                         }
     318           0 :                         p = line + 2;
     319             : 
     320             :                         /* Continue again if line ends with a backslash */
     321           0 :                         if (line[strlen(line)-1] == '\\') {
     322           0 :                                 line[strlen(line)-1] = '\0';
     323           0 :                                 continue_next_line = 1;
     324           0 :                                 data_str = talloc_strdup_append(data_str, p);
     325           0 :                                 talloc_free(line);
     326           0 :                                 continue;
     327             :                         }
     328           0 :                         data_str = talloc_strdup_append(data_str, p);
     329             :                 } else {
     330         580 :                         p = strchr_m(line, '=');
     331         580 :                         if (p == NULL) {
     332           0 :                                 DEBUG(0, ("Malformed line: %s\n", line));
     333           0 :                                 talloc_free(line);
     334           0 :                                 continue;
     335             :                         }
     336             : 
     337         580 :                         *p = '\0'; p++;
     338             : 
     339             : 
     340         580 :                         if (curkey == NULL) {
     341           0 :                                 DEBUG(0, ("Value change without key\n"));
     342           0 :                                 talloc_free(line);
     343           0 :                                 continue;
     344             :                         }
     345             : 
     346             :                         /* Values should be double-quoted */
     347         580 :                         if (line[0] != '"') {
     348           0 :                                 DEBUG(0, ("Malformed line\n"));
     349           0 :                                 talloc_free(line);
     350           0 :                                 continue;
     351             :                         }
     352             : 
     353             :                         /* Chop of the quotes and store as value */
     354         580 :                         value = talloc_strndup(mem_ctx, line+1,strlen(line)-2);
     355             : 
     356             :                         /* Delete value */
     357         580 :                         if (p[0] == '-') {
     358           0 :                                 error = callbacks->del_value(callback_data,
     359             :                                                      curkey, value);
     360             : 
     361             :                                 /* Ignore if key does not exist (WERR_FILE_NOT_FOUND)
     362             :                                  * Consistent with Windows behaviour */
     363           0 :                                 if (!W_ERROR_IS_OK(error) &&
     364           0 :                                     !W_ERROR_EQUAL(error, WERR_FILE_NOT_FOUND)) {
     365           0 :                                         DEBUG(0, ("Error deleting value %s in key %s\n",
     366             :                                                 value, curkey));
     367           0 :                                         talloc_free(mem_ctx);
     368           0 :                                         return error;
     369             :                                 }
     370             : 
     371           0 :                                 talloc_free(line);
     372           0 :                                 talloc_free(value);
     373           0 :                                 continue;
     374             :                         }
     375             : 
     376             :                         /* Do not look for colons in strings */
     377         580 :                         if (p[0] == '"') {
     378         386 :                                 q = NULL;
     379         386 :                                 data_str = talloc_strndup(mem_ctx, p+1,strlen(p)-2);
     380             :                         } else {
     381             :                                 /* Split the value type from the data */
     382         194 :                                 q = strchr_m(p, ':');
     383         194 :                                 if (q) {
     384         194 :                                         *q = '\0';
     385         194 :                                         q++;
     386         194 :                                         type_str = talloc_strdup(mem_ctx, p);
     387         194 :                                         data_str = talloc_strdup(mem_ctx, q);
     388             :                                 } else {
     389           0 :                                         data_str = talloc_strdup(mem_ctx, p);
     390             :                                 }
     391             :                         }
     392             : 
     393             :                         /* Backslash before the CRLF means continue on next line */
     394         580 :                         if (data_str[strlen(data_str)-1] == '\\') {
     395           0 :                                 data_str[strlen(data_str)-1] = '\0';
     396           0 :                                 talloc_free(line);
     397           0 :                                 continue_next_line = 1;
     398           0 :                                 continue;
     399             :                         }
     400             :                 }
     401         580 :                 DEBUG(9, ("About to write %s with type %s, length %ld: %s\n", value, type_str, (long) strlen(data_str), data_str));
     402         580 :                 result = reg_string_to_val(value,
     403             :                                   type_str?type_str:"REG_SZ", data_str,
     404             :                                   &value_type, &data);
     405         580 :                 if (!result) {
     406           0 :                         DEBUG(0, ("Error converting string to value for line:\n%s\n",
     407             :                                         line));
     408           0 :                         return WERR_GEN_FAILURE;
     409             :                 }
     410             : 
     411         580 :                 error = callbacks->set_value(callback_data, curkey, value,
     412             :                                              value_type, data);
     413         580 :                 if (!W_ERROR_IS_OK(error)) {
     414           0 :                         DEBUG(0, ("Error setting value for %s in %s\n",
     415             :                                 value, curkey));
     416           0 :                         talloc_free(mem_ctx);
     417           0 :                         return error;
     418             :                 }
     419             : 
     420             :                 /* Clean up buffers */
     421         580 :                 if (type_str != NULL) {
     422         194 :                         talloc_free(type_str);
     423         194 :                         type_str = NULL;
     424             :                 }
     425         580 :                 talloc_free(data_str);
     426         580 :                 talloc_free(value);
     427         580 :                 talloc_free(line);
     428             :         }
     429             : 
     430         194 :         close(fd);
     431             : 
     432         194 :         talloc_free(mem_ctx);
     433             : 
     434         194 :         return WERR_OK;
     435             : }

Generated by: LCOV version 1.13