hivexml: Add correct casts to xmlTextWriter* function call params.
[hivex.git] / xml / hivexml.c
1 /* hivexml - Convert Windows Registry "hive" to XML file.
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdint.h>
25 #include <inttypes.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <time.h>
29 #include <locale.h>
30
31 #ifdef HAVE_LIBINTL_H
32 #include <libintl.h>
33 #endif
34
35 #include <libxml/xmlwriter.h>
36
37 #include "hivex.h"
38
39 #ifdef HAVE_GETTEXT
40 #include "gettext.h"
41 #define _(str) dgettext(PACKAGE, (str))
42 //#define N_(str) dgettext(PACKAGE, (str))
43 #else
44 #define _(str) str
45 //#define N_(str) str
46 #endif
47
48 static char *filetime_to_8601 (int64_t windows_ticks);
49
50 /* Callback functions. */
51 static int node_start (hive_h *, void *, hive_node_h, const char *name);
52 static int node_end (hive_h *, void *, hive_node_h, const char *name);
53 static int value_string (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
54 static int value_multiple_strings (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, char **argv);
55 static int value_string_invalid_utf16 (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
56 static int value_dword (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int32_t);
57 static int value_qword (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int64_t);
58 static int value_binary (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
59 static int value_none (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
60 static int value_other (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
61
62 static struct hivex_visitor visitor = {
63   .node_start = node_start,
64   .node_end = node_end,
65   .value_string = value_string,
66   .value_multiple_strings = value_multiple_strings,
67   .value_string_invalid_utf16 = value_string_invalid_utf16,
68   .value_dword = value_dword,
69   .value_qword = value_qword,
70   .value_binary = value_binary,
71   .value_none = value_none,
72   .value_other = value_other
73 };
74
75 #define XML_CHECK(proc, args)                                           \
76   do {                                                                  \
77     if ((proc args) == -1) {                                            \
78       fprintf (stderr, _("%s: failed to write XML document\n"), #proc); \
79       exit (EXIT_FAILURE);                                              \
80     }                                                                   \
81   } while (0)
82
83 int
84 main (int argc, char *argv[])
85 {
86   setlocale (LC_ALL, "");
87 #ifdef HAVE_BINDTEXTDOMAIN
88   bindtextdomain (PACKAGE, LOCALEBASEDIR);
89   textdomain (PACKAGE);
90 #endif
91
92   int c;
93   int open_flags = 0;
94   int visit_flags = 0;
95
96   while ((c = getopt (argc, argv, "dk")) != EOF) {
97     switch (c) {
98     case 'd':
99       open_flags |= HIVEX_OPEN_DEBUG;
100       break;
101     case 'k':
102       visit_flags |= HIVEX_VISIT_SKIP_BAD;
103       break;
104     default:
105       fprintf (stderr, "hivexml [-dk] regfile > output.xml\n");
106       exit (EXIT_FAILURE);
107     }
108   }
109
110   if (optind + 1 != argc) {
111     fprintf (stderr, _("hivexml: missing name of input file\n"));
112     exit (EXIT_FAILURE);
113   }
114
115   hive_h *h = hivex_open (argv[optind], open_flags);
116   if (h == NULL) {
117     perror (argv[optind]);
118     exit (EXIT_FAILURE);
119   }
120
121   /* Note both this macro, and xmlTextWriterStartDocument leak memory.  There
122    * doesn't seem to be any way to recover that memory, but it's not a
123    * large amount.
124    */
125   LIBXML_TEST_VERSION;
126
127   xmlTextWriterPtr writer;
128   writer = xmlNewTextWriterFilename ("/dev/stdout", 0);
129   if (writer == NULL) {
130     fprintf (stderr, _("xmlNewTextWriterFilename: failed to create XML writer\n"));
131     exit (EXIT_FAILURE);
132   }
133
134   XML_CHECK (xmlTextWriterStartDocument, (writer, NULL, "utf-8", NULL));
135   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "hive"));
136
137   int64_t hive_mtime = hivex_last_modified (h);
138   if (hive_mtime >= 0) {
139     char *timebuf = filetime_to_8601 (hive_mtime);
140     if (timebuf) {
141       XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "mtime"));
142       XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST timebuf));
143       XML_CHECK (xmlTextWriterEndElement, (writer));
144       free (timebuf);
145     }
146   }
147
148   if (hivex_visit (h, &visitor, sizeof visitor, writer, visit_flags) == -1) {
149     perror (argv[optind]);
150     exit (EXIT_FAILURE);
151   }
152
153   if (hivex_close (h) == -1) {
154     perror (argv[optind]);
155     exit (EXIT_FAILURE);
156   }
157
158   XML_CHECK (xmlTextWriterEndElement, (writer));
159   XML_CHECK (xmlTextWriterEndDocument, (writer));
160   xmlFreeTextWriter (writer);
161
162   exit (EXIT_SUCCESS);
163 }
164
165 /* Convert Windows filetime to ISO 8601 format.
166  * http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux/6161842#6161842
167  *
168  * Source for time_t->char* conversion: Fiwalk version 0.6.14's
169  * fiwalk.cpp.
170  *
171  * The caller should free the returned buffer.
172  */
173
174 #define WINDOWS_TICK 10000000LL
175 #define SEC_TO_UNIX_EPOCH 11644473600LL
176 #define TIMESTAMP_BUF_LEN 32
177
178 static char *
179 filetime_to_8601 (int64_t windows_ticks)
180 {
181   char *ret;
182   time_t t;
183   struct tm *tm;
184
185   t = windows_ticks / WINDOWS_TICK - SEC_TO_UNIX_EPOCH;
186   tm = gmtime (&t);
187   if (tm == NULL)
188     return NULL;
189
190   ret = malloc (TIMESTAMP_BUF_LEN);
191   if (ret == NULL) {
192     perror ("malloc");
193     exit (EXIT_FAILURE);
194   }
195
196   if (strftime (ret, TIMESTAMP_BUF_LEN, "%FT%TZ", tm) == 0) {
197     perror ("strftime");
198     exit (EXIT_FAILURE);
199   }
200
201   return ret;
202 }
203
204 static int
205 node_start (hive_h *h, void *writer_v, hive_node_h node, const char *name)
206 {
207   int64_t last_modified;
208   char *timebuf;
209   int ret = 0;
210
211   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
212   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "node"));
213   XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "name", BAD_CAST name));
214
215   if (node == hivex_root (h)) {
216     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "root", BAD_CAST "1"));
217   }
218
219   last_modified = hivex_node_timestamp (h, node);
220   if (last_modified >= 0) {
221     timebuf = filetime_to_8601 (last_modified);
222     if (timebuf) {
223       XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "mtime"));
224       XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST timebuf));
225       XML_CHECK (xmlTextWriterEndElement, (writer));
226       free (timebuf);
227     }
228   }
229
230   return 0;
231 }
232
233 static int
234 node_end (hive_h *h, void *writer_v, hive_node_h node, const char *name)
235 {
236   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
237   XML_CHECK (xmlTextWriterEndElement, (writer));
238   return 0;
239 }
240
241 static void
242 start_value (xmlTextWriterPtr writer,
243              const char *key, const char *type, const char *encoding)
244 {
245   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "value"));
246   XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "type", BAD_CAST type));
247   if (encoding)
248     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "encoding", BAD_CAST encoding));
249   if (*key)
250     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "key", BAD_CAST key));
251   else                          /* default key */
252     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "default", BAD_CAST "1"));
253 }
254
255 static void
256 end_value (xmlTextWriterPtr writer)
257 {
258   XML_CHECK (xmlTextWriterEndElement, (writer));
259 }
260
261 static int
262 value_string (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
263               hive_type t, size_t len, const char *key, const char *str)
264 {
265   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
266   const char *type;
267
268   switch (t) {
269   case hive_t_string: type = "string"; break;
270   case hive_t_expand_string: type = "expand"; break;
271   case hive_t_link: type = "link"; break;
272
273   case hive_t_none:
274   case hive_t_binary:
275   case hive_t_dword:
276   case hive_t_dword_be:
277   case hive_t_multiple_strings:
278   case hive_t_resource_list:
279   case hive_t_full_resource_description:
280   case hive_t_resource_requirements_list:
281   case hive_t_qword:
282     abort ();                   /* internal error - should not happen */
283
284   default:
285     type = "unknown";
286   }
287
288   start_value (writer, key, type, NULL);
289   XML_CHECK (xmlTextWriterStartAttribute, (writer, BAD_CAST "value"));
290   XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST str));
291   XML_CHECK (xmlTextWriterEndAttribute, (writer));
292   end_value (writer);
293   return 0;
294 }
295
296 static int
297 value_multiple_strings (hive_h *h, void *writer_v, hive_node_h node,
298                         hive_value_h value, hive_type t, size_t len,
299                         const char *key, char **argv)
300 {
301   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
302   start_value (writer, key, "string-list", NULL);
303
304   size_t i;
305   for (i = 0; argv[i] != NULL; ++i) {
306     XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "string"));
307     XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST argv[i]));
308     XML_CHECK (xmlTextWriterEndElement, (writer));
309   }
310
311   end_value (writer);
312   return 0;
313 }
314
315 static int
316 value_string_invalid_utf16 (hive_h *h, void *writer_v, hive_node_h node,
317                             hive_value_h value, hive_type t, size_t len,
318                             const char *key,
319                             const char *str /* original data */)
320 {
321   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
322   const char *type;
323
324   switch (t) {
325   case hive_t_string: type = "bad-string"; break;
326   case hive_t_expand_string: type = "bad-expand"; break;
327   case hive_t_link: type = "bad-link"; break;
328   case hive_t_multiple_strings: type = "bad-string-list"; break;
329
330   case hive_t_none:
331   case hive_t_binary:
332   case hive_t_dword:
333   case hive_t_dword_be:
334   case hive_t_resource_list:
335   case hive_t_full_resource_description:
336   case hive_t_resource_requirements_list:
337   case hive_t_qword:
338     abort ();                   /* internal error - should not happen */
339
340   default:
341     type = "unknown";
342   }
343
344   start_value (writer, key, type, "base64");
345   XML_CHECK (xmlTextWriterStartAttribute, (writer, BAD_CAST "value"));
346   XML_CHECK (xmlTextWriterWriteBase64, (writer, str, 0, len));
347   XML_CHECK (xmlTextWriterEndAttribute, (writer));
348   end_value (writer);
349
350   return 0;
351 }
352
353 static int
354 value_dword (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
355              hive_type t, size_t len, const char *key, int32_t v)
356 {
357   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
358   start_value (writer, key, "int32", NULL);
359   XML_CHECK (xmlTextWriterWriteFormatAttribute, (writer, BAD_CAST "value", "%" PRIi32, v));
360   end_value (writer);
361   return 0;
362 }
363
364 static int
365 value_qword (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
366              hive_type t, size_t len, const char *key, int64_t v)
367 {
368   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
369   start_value (writer, key, "int64", NULL);
370   XML_CHECK (xmlTextWriterWriteFormatAttribute, (writer, BAD_CAST "value", "%" PRIi64, v));
371   end_value (writer);
372   return 0;
373 }
374
375 static int
376 value_binary (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
377               hive_type t, size_t len, const char *key, const char *v)
378 {
379   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
380   start_value (writer, key, "binary", "base64");
381   XML_CHECK (xmlTextWriterStartAttribute, (writer, BAD_CAST "value"));
382   XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
383   XML_CHECK (xmlTextWriterEndAttribute, (writer));
384   end_value (writer);
385   return 0;
386 }
387
388 static int
389 value_none (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
390             hive_type t, size_t len, const char *key, const char *v)
391 {
392   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
393   start_value (writer, key, "none", "base64");
394   if (len > 0) {
395     XML_CHECK (xmlTextWriterStartAttribute, (writer, BAD_CAST "value"));
396     XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
397     XML_CHECK (xmlTextWriterEndAttribute, (writer));
398   }
399   end_value (writer);
400   return 0;
401 }
402
403 static int
404 value_other (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
405              hive_type t, size_t len, const char *key, const char *v)
406 {
407   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
408   const char *type;
409
410   switch (t) {
411   case hive_t_none:
412   case hive_t_binary:
413   case hive_t_dword:
414   case hive_t_dword_be:
415   case hive_t_qword:
416   case hive_t_string:
417   case hive_t_expand_string:
418   case hive_t_link:
419   case hive_t_multiple_strings:
420     abort ();                   /* internal error - should not happen */
421
422   case hive_t_resource_list: type = "resource-list"; break;
423   case hive_t_full_resource_description: type = "resource-description"; break;
424   case hive_t_resource_requirements_list: type = "resource-requirements"; break;
425
426   default:
427     type = "unknown";
428   }
429
430   start_value (writer, key, type, "base64");
431   if (len > 0) {
432     XML_CHECK (xmlTextWriterStartAttribute, (writer, BAD_CAST "value"));
433     XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
434     XML_CHECK (xmlTextWriterEndAttribute, (writer));
435   }
436   end_value (writer);
437
438   return 0;
439 }