Support for Windows Registry.
[libguestfs.git] / hivex / 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 <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdint.h>
23 #include <inttypes.h>
24 #include <unistd.h>
25 #include <errno.h>
26
27 #include <libxml/xmlwriter.h>
28
29 #include "hivex.h"
30
31 /* Callback functions. */
32 static int node_start (hive_h *, void *, hive_node_h, const char *name);
33 static int node_end (hive_h *, void *, hive_node_h, const char *name);
34 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);
35 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);
36 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);
37 static int value_dword (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int32_t);
38 static int value_qword (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int64_t);
39 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);
40 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);
41 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);
42
43 static struct hivex_visitor visitor = {
44   .node_start = node_start,
45   .node_end = node_end,
46   .value_string = value_string,
47   .value_multiple_strings = value_multiple_strings,
48   .value_string_invalid_utf16 = value_string_invalid_utf16,
49   .value_dword = value_dword,
50   .value_qword = value_qword,
51   .value_binary = value_binary,
52   .value_none = value_none,
53   .value_other = value_other
54 };
55
56 #define XML_CHECK(proc, args)                                           \
57   do {                                                                  \
58     if ((proc args) == -1) {                                            \
59       fprintf (stderr, "%s: failed to write XML document\n", #proc);    \
60       exit (1);                                                         \
61     }                                                                   \
62   } while (0)
63
64 int
65 main (int argc, char *argv[])
66 {
67   int c;
68   int open_flags = 0;
69   int visit_flags = 0;
70
71   while ((c = getopt (argc, argv, "dk")) != EOF) {
72     switch (c) {
73     case 'd':
74       open_flags |= HIVEX_OPEN_DEBUG;
75       break;
76     case 'k':
77       visit_flags |= HIVEX_VISIT_SKIP_BAD;
78       break;
79     default:
80       fprintf (stderr, "hivexml [-dk] regfile > output.xml\n");
81       exit (1);
82     }
83   }
84
85   if (optind + 1 != argc) {
86     fprintf (stderr, "hivexml: missing name of input file\n");
87     exit (1);
88   }
89
90   hive_h *h = hivex_open (argv[optind], open_flags);
91   if (h == NULL) {
92     perror (argv[optind]);
93     exit (1);
94   }
95
96   /* Note both this macro, and xmlTextWriterStartDocument leak memory.  There
97    * doesn't seem to be any way to recover that memory, but it's not a
98    * large amount.
99    */
100   LIBXML_TEST_VERSION;
101
102   xmlTextWriterPtr writer;
103   writer = xmlNewTextWriterFilename ("/dev/stdout", 0);
104   if (writer == NULL) {
105     fprintf (stderr, "xmlNewTextWriterFilename: failed to create XML writer\n");
106     exit (1);
107   }
108
109   XML_CHECK (xmlTextWriterStartDocument, (writer, NULL, "utf-8", NULL));
110   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "hive"));
111
112   if (hivex_visit (h, &visitor, sizeof visitor, writer, visit_flags) == -1) {
113     perror (argv[optind]);
114     exit (1);
115   }
116
117   if (hivex_close (h) == -1) {
118     perror (argv[optind]);
119     exit (1);
120   }
121
122   XML_CHECK (xmlTextWriterEndElement, (writer));
123   XML_CHECK (xmlTextWriterEndDocument, (writer));
124   xmlFreeTextWriter (writer);
125
126   exit (0);
127 }
128
129 static int
130 node_start (hive_h *h, void *writer_v, hive_node_h node, const char *name)
131 {
132   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
133   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "node"));
134   XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "name", BAD_CAST name));
135   return 0;
136 }
137
138 static int
139 node_end (hive_h *h, void *writer_v, hive_node_h node, const char *name)
140 {
141   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
142   XML_CHECK (xmlTextWriterEndElement, (writer));
143   return 0;
144 }
145
146 static void
147 start_value (xmlTextWriterPtr writer,
148              const char *key, const char *type, const char *encoding)
149 {
150   XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "value"));
151   XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "type", BAD_CAST type));
152   if (encoding)
153     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "encoding", BAD_CAST encoding));
154   if (*key)
155     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "key", BAD_CAST key));
156   else                          /* default key */
157     XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "default", BAD_CAST "1"));
158 }
159
160 static void
161 end_value (xmlTextWriterPtr writer)
162 {
163   XML_CHECK (xmlTextWriterEndElement, (writer));
164 }
165
166 static int
167 value_string (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
168               hive_type t, size_t len, const char *key, const char *str)
169 {
170   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
171   const char *type;
172
173   switch (t) {
174   case hive_t_string: type = "string"; break;
175   case hive_t_expand_string: type = "expand"; break;
176   case hive_t_link: type = "link"; break;
177
178   case hive_t_none:
179   case hive_t_binary:
180   case hive_t_dword:
181   case hive_t_dword_be:
182   case hive_t_multiple_strings:
183   case hive_t_resource_list:
184   case hive_t_full_resource_description:
185   case hive_t_resource_requirements_list:
186   case hive_t_qword:
187     abort ();                   /* internal error - should not happen */
188
189   default:
190     type = "unknown";
191   }
192
193   start_value (writer, key, type, NULL);
194   XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST str));
195   end_value (writer);
196   return 0;
197 }
198
199 static int
200 value_multiple_strings (hive_h *h, void *writer_v, hive_node_h node,
201                         hive_value_h value, hive_type t, size_t len,
202                         const char *key, char **argv)
203 {
204   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
205   start_value (writer, key, "string-list", NULL);
206
207   size_t i;
208   for (i = 0; argv[i] != NULL; ++i) {
209     XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "string"));
210     XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST argv[i]));
211     XML_CHECK (xmlTextWriterEndElement, (writer));
212   }
213
214   end_value (writer);
215   return 0;
216 }
217
218 static int
219 value_string_invalid_utf16 (hive_h *h, void *writer_v, hive_node_h node,
220                             hive_value_h value, hive_type t, size_t len,
221                             const char *key,
222                             const char *str /* original data */)
223 {
224   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
225   const char *type;
226
227   switch (t) {
228   case hive_t_string: type = "bad-string"; break;
229   case hive_t_expand_string: type = "bad-expand"; break;
230   case hive_t_link: type = "bad-link"; break;
231   case hive_t_multiple_strings: type = "bad-string-list"; break;
232
233   case hive_t_none:
234   case hive_t_binary:
235   case hive_t_dword:
236   case hive_t_dword_be:
237   case hive_t_resource_list:
238   case hive_t_full_resource_description:
239   case hive_t_resource_requirements_list:
240   case hive_t_qword:
241     abort ();                   /* internal error - should not happen */
242
243   default:
244     type = "unknown";
245   }
246
247   start_value (writer, key, type, "base64");
248   XML_CHECK (xmlTextWriterWriteBase64, (writer, str, 0, len));
249   end_value (writer);
250
251   return 0;
252 }
253
254 static int
255 value_dword (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
256              hive_type t, size_t len, const char *key, int32_t v)
257 {
258   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
259   start_value (writer, key, "int32", NULL);
260   XML_CHECK (xmlTextWriterWriteFormatString, (writer, "%" PRIi32, v));
261   end_value (writer);
262   return 0;
263 }
264
265 static int
266 value_qword (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
267              hive_type t, size_t len, const char *key, int64_t v)
268 {
269   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
270   start_value (writer, key, "int64", NULL);
271   XML_CHECK (xmlTextWriterWriteFormatString, (writer, "%" PRIi64, v));
272   end_value (writer);
273   return 0;
274 }
275
276 static int
277 value_binary (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
278               hive_type t, size_t len, const char *key, const char *v)
279 {
280   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
281   start_value (writer, key, "binary", "base64");
282   XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
283   end_value (writer);
284   return 0;
285 }
286
287 static int
288 value_none (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
289             hive_type t, size_t len, const char *key, const char *v)
290 {
291   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
292   start_value (writer, key, "none", "base64");
293   if (len > 0) XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
294   end_value (writer);
295   return 0;
296 }
297
298 static int
299 value_other (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
300              hive_type t, size_t len, const char *key, const char *v)
301 {
302   xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
303   const char *type;
304
305   switch (t) {
306   case hive_t_none:
307   case hive_t_binary:
308   case hive_t_dword:
309   case hive_t_dword_be:
310   case hive_t_qword:
311   case hive_t_string:
312   case hive_t_expand_string:
313   case hive_t_link:
314   case hive_t_multiple_strings:
315     abort ();                   /* internal error - should not happen */
316
317   case hive_t_resource_list: type = "resource-list"; break;
318   case hive_t_full_resource_description: type = "resource-description"; break;
319   case hive_t_resource_requirements_list: type = "resource-requirements"; break;
320
321   default:
322     type = "unknown";
323   }
324
325   start_value (writer, key, type, "base64");
326   if (len > 0) XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
327   end_value (writer);
328
329   return 0;
330 }