source: releases/0.10.0/src/common.c@ 286

Last change on this file since 286 was 138, checked in by tim, 16 years ago

extended error message logging to allow for message type filtering

fine tuned message verbosity to more reasonable default levels for reglookup and reglookup-recover

updated related documentation

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