source: trunk/src/common.c @ 159

Last change on this file since 159 was 159, checked in by tim, 14 years ago

began rearranging data parsing. Moved charater set conversion and basic parsing logic into regfi

  • Property svn:keywords set to Id
File size: 9.9 KB
Line 
1/*
2 * This file stores code common to the command line tools.
3 * XXX: This should be converted to a proper library.
4 *
5 * Copyright (C) 2005-2008 Timothy D. Morgan
6 * Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com
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; version 3 of the License.
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 * $Id: common.c 159 2009-12-06 20:09:01Z tim $
22 */
23
24#include <iconv.h>
25iconv_t conv_desc;
26
27const char* key_special_chars = ",\"\\/";
28const char* subfield_special_chars = ",\"\\|";
29const char* common_special_chars = ",\"\\";
30
31#define REGLOOKUP_VERSION "0.11.0"
32
33#define REGLOOKUP_EXIT_OK       0
34#define REGLOOKUP_EXIT_OSERR   71
35#define REGLOOKUP_EXIT_USAGE   64
36#define REGLOOKUP_EXIT_DATAERR 65
37#define REGLOOKUP_EXIT_NOINPUT 66
38
39
40void bailOut(int code, char* message)
41{
42  fprintf(stderr, message);
43  exit(code);
44}
45
46void printMsgs(REGFI_FILE* f)
47{
48  char* msgs = regfi_get_messages(f);
49  if(msgs != NULL)
50  {
51    fprintf(stderr, "%s", msgs);
52    free(msgs);
53  }
54}
55
56void clearMsgs(REGFI_FILE* f)
57{
58  char* msgs = regfi_get_messages(f);
59  if(msgs != NULL)
60    free(msgs);
61}
62
63
64/* Returns a newly malloc()ed string which contains original buffer,
65 * except for non-printable or special characters are quoted in hex
66 * with the syntax '\xQQ' where QQ is the hex ascii value of the quoted
67 * character.  A null terminator is added, since only ascii, not binary,
68 * is returned.
69 */
70static char* quote_buffer(const unsigned char* str, 
71                          unsigned int len, const char* special)
72{
73  unsigned int i, added_len;
74  unsigned int num_written = 0;
75
76  unsigned int buf_len = sizeof(char)*(len+1);
77  char* ret_val = NULL; 
78  char* tmp_buf;
79
80  if(buf_len > 0) 
81    ret_val = malloc(buf_len);
82  if(ret_val == NULL)
83    return NULL;
84
85  for(i=0; i<len; i++)
86  {
87    if(buf_len <= (num_written+5))
88    {
89      /* Expand the buffer by the memory consumption rate seen so far
90       * times the amount of input left to process.  The expansion is bounded
91       * below by a minimum safety increase, and above by the maximum possible
92       * output string length.  This should minimize both the number of
93       * reallocs() and the amount of wasted memory.
94       */
95      added_len = (len-i)*num_written/(i+1);
96      if((buf_len+added_len) > (len*4+1))
97        buf_len = len*4+1;
98      else
99      {
100        if (added_len < 5)
101          buf_len += 5;
102        else
103          buf_len += added_len;
104      }
105
106      tmp_buf = realloc(ret_val, buf_len);
107      if(tmp_buf == NULL)
108      {
109        free(ret_val);
110        return NULL;
111      }
112      ret_val = tmp_buf;
113    }
114   
115    if(str[i] < 32 || str[i] > 126 || strchr(special, str[i]) != NULL)
116    {
117      num_written += snprintf(ret_val + num_written, buf_len - num_written,
118                              "\\x%.2X", str[i]);
119    }
120    else
121      ret_val[num_written++] = str[i];
122  }
123  ret_val[num_written] = '\0';
124
125  return ret_val;
126}
127
128
129/* Returns a newly malloc()ed string which contains original string,
130 * except for non-printable or special characters are quoted in hex
131 * with the syntax '\xQQ' where QQ is the hex ascii value of the quoted
132 * character.
133 */
134static char* quote_string(const char* str, const char* special)
135{
136  unsigned int len;
137
138  if(str == NULL)
139    return NULL;
140
141  len = strlen(str);
142  return quote_buffer((const unsigned char*)str, len, special);
143}
144
145
146/*
147 * Convert from UTF-16LE to ASCII.  Accepts a Unicode buffer, uni, and
148 * it's length, uni_max.  Writes ASCII to the buffer ascii, whose size
149 * is ascii_max.  Writes at most (ascii_max-1) bytes to ascii, and null
150 * terminates the string.  Returns the length of the data written to
151 * ascii.  On error, returns a negative errno code.
152 */
153static int uni_to_ascii(unsigned char* uni, char* ascii, 
154                        uint32 uni_max, uint32 ascii_max)
155{
156  char* inbuf = (char*)uni;
157  char* outbuf = ascii;
158  size_t in_len = (size_t)uni_max;
159  size_t out_len = (size_t)(ascii_max-1);
160  int ret;
161
162  conv_desc = iconv_open("US-ASCII//TRANSLIT", "UTF-16LE");
163
164  ret = iconv(conv_desc, &inbuf, &in_len, &outbuf, &out_len);
165  if(ret == -1)
166  {
167    iconv_close(conv_desc);
168    return -errno;
169  }
170  *outbuf = '\0';
171
172  iconv_close(conv_desc); 
173  return ascii_max-out_len-1;
174}
175
176
177static char* quote_unicode(unsigned char* uni, uint32 length, 
178                           const char* special, char** error_msg)
179{
180  char* ret_val;
181  char* ascii = NULL;
182  char* tmp_err;
183  int ret_err;
184  *error_msg = NULL;
185
186  if(length+1 > 0)
187    ascii = malloc(length+1);
188  if(ascii == NULL)
189  {
190    *error_msg = (char*)malloc(27);
191    if(*error_msg == NULL)
192      return NULL;
193    strcpy(*error_msg, "Memory allocation failure.");
194    return NULL;
195  }
196 
197  ret_err = uni_to_ascii(uni, ascii, length, length+1);
198  if(ret_err < 0)
199  {
200    free(ascii);
201    tmp_err = strerror(-ret_err);
202    *error_msg = (char*)malloc(61+strlen(tmp_err));
203    if(*error_msg == NULL)
204      return NULL;
205
206    sprintf(*error_msg, 
207            "Unicode conversion failed with '%s'. Quoting as binary.", tmp_err);
208    ret_val = quote_buffer(uni, length, special);
209  }
210  else
211  {
212    ret_val = quote_string(ascii, special);
213    free(ascii);
214  }
215 
216  return ret_val;
217}
218
219
220/*
221 * Convert a data value to a string for display.  Returns NULL on error,
222 * and the string to display if there is no error, or a non-fatal
223 * error.  On any error (fatal or non-fatal) occurs, (*error_msg) will
224 * be set to a newly allocated string, containing an error message.  If
225 * a memory allocation failure occurs while generating the error
226 * message, both the return value and (*error_msg) will be NULL.  It
227 * is the responsibility of the caller to free both a non-NULL return
228 * value, and a non-NULL (*error_msg).
229 */
230static char* data_to_ascii(REGFI_DATA* data, char** error_msg)
231{
232  char* ret_val;
233  char* cur_quoted;
234  char* tmp_ptr;
235  char* delim;
236  uint32 ret_val_left, i, tmp_len;
237
238  if(data == NULL || data->size == 0)
239  {
240    *error_msg = (char*)malloc(37);
241    if(*error_msg == NULL)
242      return NULL;
243    strcpy(*error_msg, "Data pointer was NULL or size was 0.");
244    return NULL;
245  }
246  *error_msg = NULL;
247
248
249  if(data->interpreted_size == 0)
250  {
251    *error_msg = (char*)malloc(51);
252    if(*error_msg == NULL)
253      return NULL;
254    strcpy(*error_msg, "Data could not be interpreted, quoting raw buffer.");
255    return quote_buffer(data->raw, data->size, common_special_chars);
256  }
257
258  switch (data->type) 
259  {
260  case REG_SZ:
261    ret_val = quote_string((char*)data->interpreted.string, common_special_chars);
262    if(ret_val == NULL && (*error_msg = (char*)malloc(49)) != NULL)
263        strcpy(*error_msg, "Buffer could not be quoted due to unknown error.");
264
265    return ret_val;
266    break;
267
268   
269  case REG_EXPAND_SZ:
270    ret_val = quote_string((char*)data->interpreted.expand_string, 
271                           common_special_chars);
272    if(ret_val == NULL && (*error_msg = (char*)malloc(49)) != NULL)
273        strcpy(*error_msg, "Buffer could not be quoted due to unknown error.");
274
275    return ret_val;
276    break;
277
278  case REG_LINK:
279    ret_val = quote_string((char*)data->interpreted.link, common_special_chars);
280    if(ret_val == NULL && (*error_msg = (char*)malloc(49)) != NULL)
281        strcpy(*error_msg, "Buffer could not be quoted due to unknown error.");
282
283    return ret_val;
284    break;
285
286  case REG_DWORD:
287    ret_val = malloc(sizeof(char)*(8+2+1));
288    if(ret_val == NULL)
289      return NULL;
290
291    sprintf(ret_val, "0x%.8X", data->interpreted.dword);
292    return ret_val;
293    break;
294
295  case REG_DWORD_BE:
296    ret_val = malloc(sizeof(char)*(8+2+1));
297    if(ret_val == NULL)
298      return NULL;
299
300    sprintf(ret_val, "0x%.8X", data->interpreted.dword_be);
301    return ret_val;
302    break;
303
304  case REG_QWORD:
305    ret_val = malloc(sizeof(char)*(16+2+1));
306    if(ret_val == NULL)
307      return NULL;
308
309    sprintf(ret_val, "0x%.16llX", 
310            (long long unsigned int)data->interpreted.qword);
311    return ret_val;
312    break;
313
314  case REG_MULTI_SZ:
315    ret_val_left = data->interpreted_size*4+1;
316    ret_val = malloc(ret_val_left);
317    if(ret_val == NULL)
318      return NULL;
319
320    tmp_ptr = ret_val;
321    tmp_ptr[0] = '\0';
322    delim = "";
323    for(i=0; data->interpreted.multiple_string[i] != NULL; i++)
324    {
325      cur_quoted = quote_string((char*)data->interpreted.multiple_string[i],
326                                subfield_special_chars);
327      if(cur_quoted != NULL && cur_quoted[0] != '\0')
328      {
329        tmp_len = snprintf(tmp_ptr, ret_val_left, "%s%s",delim, cur_quoted);
330        tmp_ptr += tmp_len;
331        ret_val_left -= tmp_len;
332        free(cur_quoted);
333      }
334      delim = "|";
335    }
336
337    return ret_val;
338    break;
339
340   
341  case REG_NONE:
342    return quote_buffer(data->interpreted.none, data->interpreted_size,
343                        common_special_chars);
344
345    break;
346
347  case REG_RESOURCE_LIST:
348    return quote_buffer(data->interpreted.resource_list, data->interpreted_size,
349                        common_special_chars);
350
351    break;
352
353  case REG_FULL_RESOURCE_DESCRIPTOR:
354    return quote_buffer(data->interpreted.full_resource_descriptor, 
355                        data->interpreted_size, common_special_chars);
356
357    break;
358
359  case REG_RESOURCE_REQUIREMENTS_LIST:
360    return quote_buffer(data->interpreted.resource_requirements_list,
361                        data->interpreted_size, common_special_chars);
362
363    break;
364
365  case REG_BINARY:
366    return quote_buffer(data->interpreted.binary, data->interpreted_size,
367                        common_special_chars);
368
369    break;
370
371  default:
372    /* This shouldn't happen, since the regfi routines won't interpret
373     * unknown types, but just as a safety measure against library changes...
374     */
375    *error_msg = (char*)malloc(65);
376    if(*error_msg == NULL)
377      return NULL;
378    sprintf(*error_msg,
379            "Unrecognized registry data type (0x%.8X); quoting as binary.",
380            data->type);
381    return quote_buffer(data->raw, data->size, common_special_chars);
382  }
383   
384  return NULL;
385}
Note: See TracBrowser for help on using the repository browser.