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

Generated by: LCOV version 1.14