fd4929316d1436a9cc34d29c48128786b5205ac3
[libguestfs.git] / hivex / hivexget.c
1 /* hivexget - Get single subkeys or values from a hive.
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 <errno.h>
27
28 #include "hivex.h"
29
30 #ifdef HAVE_GETTEXT
31 #include "gettext.h"
32 #define _(str) dgettext(PACKAGE, (str))
33 //#define N_(str) dgettext(PACKAGE, (str))
34 #else
35 #define _(str) str
36 //#define N_(str) str
37 #endif
38
39 enum { EXIT_NOT_FOUND = 2 };
40
41 int
42 main (int argc, char *argv[])
43 {
44   setlocale (LC_ALL, "");
45   bindtextdomain (PACKAGE, LOCALEBASEDIR);
46   textdomain (PACKAGE);
47
48   if (argc < 3 || argc > 4) {
49     fprintf (stderr, _("hivexget regfile path [key]\n"));
50     exit (EXIT_FAILURE);
51   }
52
53   char *file = argv[1];
54   char *path = argv[2];
55   char *key = argv[3];          /* could be NULL */
56
57   if (path[0] != '\\') {
58     fprintf (stderr, _("hivexget: path must start with a \\ character\n"));
59     exit (EXIT_FAILURE);
60   }
61   if (path[1] == '\\') {
62   doubled:
63     fprintf (stderr, _("hivexget: %s: \\ characters in path are doubled - are you escaping the path parameter correctly?\n"), path);
64     exit (EXIT_FAILURE);
65   }
66
67   hive_h *h = hivex_open (file, 0);
68   if (h == NULL) {
69   error:
70     perror (file);
71     exit (EXIT_FAILURE);
72   }
73
74   /* Navigate to the desired node. */
75   hive_node_h node = hivex_root (h);
76   if (!node)
77     goto error;
78
79   char *p = path+1, *pnext;
80   size_t len;
81   while (*p) {
82     len = strcspn (p, "\\");
83
84     if (len == 0)
85       goto doubled;
86
87     if (p[len] == '\\') {
88       p[len] = '\0';
89       pnext = p + len + 1;
90     } else
91       pnext = p + len;
92
93     errno = 0;
94     node = hivex_node_get_child (h, node, p);
95     if (node == 0) {
96       if (errno)
97         goto error;
98       /* else node not found */
99       fprintf (stderr, _("hivexget: %s: %s: path element not found\n"),
100                path, p);
101       exit (EXIT_NOT_FOUND);
102     }
103
104     p = pnext;
105   }
106
107   /* Get the desired key, or print all keys. */
108   if (key) {
109     hive_value_h value;
110
111     errno = 0;
112     if (key[0] == '@' && key[1] == '\0') /* default key written as "@" */
113       value = hivex_node_get_value (h, node, "");
114     else
115       value = hivex_node_get_value (h, node, key);
116
117     if (value == 0) {
118       if (errno)
119         goto error;
120       /* else key not found */
121       fprintf (stderr, _("hivexget: %s: key not found\n"), key);
122       exit (EXIT_NOT_FOUND);
123     }
124
125     /* Print the value. */
126     hive_type t;
127     size_t len;
128     if (hivex_value_type (h, value, &t, &len) == -1)
129       goto error;
130
131     switch (t) {
132     case hive_t_string:
133     case hive_t_expand_string:
134     case hive_t_link: {
135       char *str = hivex_value_string (h, value);
136       if (!str)
137         goto error;
138
139       puts (str); /* note: this adds a single \n character */
140       free (str);
141       break;
142     }
143
144     case hive_t_dword:
145     case hive_t_dword_be: {
146       int32_t j = hivex_value_dword (h, value);
147       printf ("%" PRIi32 "\n", j);
148       break;
149     }
150
151     case hive_t_qword: {
152       int64_t j = hivex_value_qword (h, value);
153       printf ("%" PRIi64 "\n", j);
154       break;
155     }
156
157     case hive_t_multiple_strings: {
158       char **strs = hivex_value_multiple_strings (h, value);
159       if (!strs)
160         goto error;
161       size_t j;
162       for (j = 0; strs[j] != NULL; ++j) {
163         puts (strs[j]);
164         free (strs[j]);
165       }
166       free (strs);
167       break;
168     }
169
170     case hive_t_none:
171     case hive_t_binary:
172     case hive_t_resource_list:
173     case hive_t_full_resource_description:
174     case hive_t_resource_requirements_list:
175     default: {
176       char *data = hivex_value_value (h, value, &t, &len);
177       if (!data)
178         goto error;
179
180       if (fwrite (data, 1, len, stdout) != len)
181         goto error;
182
183       free (data);
184       break;
185     }
186     } /* switch */
187   } else {
188     /* No key specified, so print all keys in this node.  We do this
189      * in a format which looks like the output of regedit, although
190      * this isn't a particularly useful format.
191      */
192     hive_value_h *values;
193
194     values = hivex_node_values (h, node);
195     if (values == NULL)
196       goto error;
197
198     size_t i;
199     for (i = 0; values[i] != 0; ++i) {
200       char *key = hivex_value_key (h, values[i]);
201       if (!key) goto error;
202
203       if (*key) {
204         putchar ('"');
205         size_t j;
206         for (j = 0; key[j] != 0; ++j) {
207           if (key[j] == '"' || key[j] == '\\')
208             putchar ('\\');
209           putchar (key[j]);
210         }
211         putchar ('"');
212       } else
213         printf ("\"@\"");       /* default key in regedit files */
214       putchar ('=');
215       free (key);
216
217       hive_type t;
218       size_t len;
219       if (hivex_value_type (h, values[i], &t, &len) == -1)
220         goto error;
221
222       switch (t) {
223       case hive_t_string:
224       case hive_t_expand_string:
225       case hive_t_link: {
226         char *str = hivex_value_string (h, values[i]);
227         if (!str)
228           goto error;
229
230         if (t != hive_t_string)
231           printf ("str(%d):", t);
232         putchar ('"');
233         size_t j;
234         for (j = 0; str[j] != 0; ++j) {
235           if (str[j] == '"' || str[j] == '\\')
236             putchar ('\\');
237           putchar (str[j]);
238         }
239         putchar ('"');
240         free (str);
241         break;
242       }
243
244       case hive_t_dword:
245       case hive_t_dword_be: {
246         int32_t j = hivex_value_dword (h, values[i]);
247         printf ("dword:%08" PRIx32 "\"", j);
248         break;
249       }
250
251       case hive_t_qword: /* sic */
252       case hive_t_none:
253       case hive_t_binary:
254       case hive_t_multiple_strings:
255       case hive_t_resource_list:
256       case hive_t_full_resource_description:
257       case hive_t_resource_requirements_list:
258       default: {
259         char *data = hivex_value_value (h, values[i], &t, &len);
260         if (!data)
261           goto error;
262
263         printf ("hex(%d):", t);
264         size_t j;
265         for (j = 0; j < len; ++j) {
266           if (j > 0)
267             putchar (',');
268           printf ("%02x", data[j]);
269         }
270         break;
271       }
272       } /* switch */
273
274       putchar ('\n');
275     } /* for */
276
277     free (values);
278   }
279
280   if (hivex_close (h) == -1)
281     goto error;
282
283   exit (EXIT_SUCCESS);
284 }