source: trunk/src/common.c @ 134

Last change on this file since 134 was 134, checked in by tim, 15 years ago

rewrote winsec library, stripping out Samba dependencies

eliminated remaining Samba prs functions

added support for 'li' subkey list records

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