maint: remove trailing blanks
[hivex.git] / perl / lib / Win / Hivex / Regedit.pm
1 # Win::Hivex::Regedit
2 # Copyright (C) 2009-2011 Red Hat Inc.
3 # Derived from code by Petter Nordahl-Hagen under a compatible license:
4 #   Copyright (c) 1997-2007 Petter Nordahl-Hagen.
5 # Derived from code by Markus Stephany under a compatible license:
6 #   Copyright (c)2000-2004, Markus Stephany.
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 =pod
23
24 =head1 NAME
25
26 Win::Hivex::Regedit - Helper for reading and writing regedit format files
27
28 =head1 SYNOPSIS
29
30  use Win::Hivex;
31  use Win::Hivex::Regedit qw(reg_import reg_export);
32
33  $h = Win::Hivex->open ('SOFTWARE', write => 1);
34
35  open FILE, "updates.reg";
36  reg_import (\*FILE, $h);
37  $h->commit (undef);
38
39  reg_export ($h, "\\Microsoft\\Windows NT\\CurrentVersion", \*OUTFILE,
40     prefix => "HKEY_LOCAL_MACHINE\\SOFTWARE");
41
42 =head1 DESCRIPTION
43
44 Win::Hivex::Regedit is a helper library for reading and writing the
45 Windows regedit (or C<.REG>) file format.  This is the textual format
46 that is commonly used on Windows for distributing groups of Windows
47 Registry changes, and this format is read and written by the
48 proprietary C<reg.exe> and C<regedit.exe> programs supplied with
49 Windows.  It is I<not> the same as the binary "hive" format which the
50 hivex library itself can read and write.  Note that the regedit format
51 is not well-specified, and hence deviations can occur between what the
52 Windows program can read/write and what we can read/write.  (Please
53 file bugs for any deviations found).
54
55 Win::Hivex::Regedit is the low-level Perl library.  There is also a
56 command line tool for combining hive files and reg files
57 (L<hivexregedit(1)>).  If you have a Windows virtual machine that you need
58 to merge regedit-format changes into, use the high-level
59 L<virt-win-reg(1)> tool (part of libguestfs tools).
60
61 =head2 FUNCTIONS
62
63 =cut
64
65 package Win::Hivex::Regedit;
66
67 use strict;
68 use warnings;
69
70 use Carp qw(croak confess);
71 use Encode qw(encode decode);
72
73 require Exporter;
74
75 use vars qw(@EXPORT_OK @ISA);
76
77 @ISA = qw(Exporter);
78 @EXPORT_OK = qw(reg_import reg_export);
79
80 =head2 reg_import
81
82  reg_import ($fh, ($h|$map), [encoding => "UTF-16LE"]);
83
84 This function imports the registry keys from file handle C<$fh> either
85 into the hive C<$h> or via a map function.
86
87 The hive handle C<$h> must have been opened for writing, ie.
88 using the C<write =E<gt> 1> flag to C<Win::Hivex-E<gt>open>.
89
90 In the binary hive file, the first part of the key name (eg.
91 C<HKEY_LOCAL_MACHINE\SOFTWARE>) is not stored.  You just have to know
92 (somehow) that this maps to the C<SOFTWARE> hive.  Therefore if you
93 are given a file containing a mixture of keys that have to be added to
94 different hives, you have to have a way to map these to the hive
95 handles.  This is outside the scope of the hivex library, but if the
96 second argument is a CODEREF (ie. reference to a function) then this
97 C<$map> function is called on each key name:
98
99  map ($keyname)
100  ==> ($h, $keyname)
101
102 As shown, the function should return a pair, hive handle, and the true
103 key name (with the prefix stripped off).  For example:
104
105  sub map {
106    if ($_[0] =~ /^HKEY_LOCAL_MACHINE\\SOFTWARE(.*)/i) {
107      return ($software_h, $1);
108    } else ...
109  }
110
111 C<encoding> is the encoding used by default for strings.  If not
112 specified, this defaults to C<"UTF-16LE">, however we highly advise
113 you to specify it.  See L</ENCODING STRINGS> below.
114
115 As with the regedit program, we merge the new registry keys with
116 existing ones, and new node values with old ones.  You can use the
117 C<-> (minus) character to delete individual keys and values.  This is
118 explained in detail in the Wikipedia page on the Windows Registry.
119
120 Remember you need to call C<$h-E<gt>commit (undef)> on the hivex
121 handle before any changes are written to the hive file.  See
122 L<hivex(3)/WRITING TO HIVE FILES>.
123
124 =cut
125
126 sub reg_import
127 {
128     local $_;
129     my $fh = shift;
130     my $hmap = shift;
131     my %params = @_;
132
133     my $encoding = $params{encoding} || "utf-16le";
134
135     my $state = "outer";
136     my $newnode;
137     my @newvalues;
138     my @delvalues;
139     my $lineno = 0;
140
141     while (<$fh>) {
142         # Join continuation lines.  This is recipe 8.1 from the Perl
143         # Cookbook.  Note we allow spaces after the final \ because
144         # this is fairly common in pasted regedit files.
145         $lineno++;
146         chomp;
147         if (s/\\\s*$//) {
148             $_ .= <$fh>;
149             redo unless eof ($fh);
150         }
151
152         #print STDERR "reg_import: parsing <<<$_>>>\n";
153
154         if ($state eq "outer") {
155             # Ignore blank lines, headers.
156             next if /^\s*$/;
157
158             # .* is needed before Windows Registry Editor Version.. in
159             # order to eat a possible Unicode BOM which regedit writes
160             # there.
161             next if /^.*Windows Registry Editor Version.*/;
162             next if /^REGEDIT/;
163
164             # Ignore comments.
165             next if /^\s*;/;
166
167             # Expect to see [...] or -[...]
168             # to merge or delete a node respectively.
169             if (/^\[(.*)\]\s*$/) {
170                 $state = "inner";
171                 $newnode = $1;
172                 @newvalues = ();
173                 @delvalues = ();
174             } elsif (/^-\[(.*)\]\s*$/) {
175                 _delete_node ($hmap, \%params, $1);
176                 $state = "outer";
177             } else {
178                 croak (_unexpected ($_, $lineno));
179             }
180         } elsif ($state eq "inner") {
181             if (/^(".*)=-\s*$/) { # delete value
182                 my $key = _parse_quoted_string ($_);
183                 croak (_parse_error ($_, $lineno)) unless defined $key;
184                 push @delvalues, $key;
185             } elsif (/^@=-\s*$/) { # delete default key
186                 push @delvalues, "";
187             } elsif (/^".*"=/) { # ordinary value
188                 my $value = _parse_key_value ($_, $encoding);
189                 croak (_parse_error ($_, $lineno)) unless defined $value;
190                 push @newvalues, $value;
191             } elsif (/^@=(.*)/) { # default key
192                 my $value = _parse_value ("", $1, $encoding);
193                 croak (_parse_error ($_, $lineno)) unless defined $value;
194                 push @newvalues, $value;
195             } elsif (/^\s*$/) { # blank line after values
196                 _merge_node ($hmap, \%params, $newnode, \@newvalues, \@delvalues);
197                 $state = "outer";
198             } else {
199                 croak (_unexpected ($_, $lineno));
200             }
201         }
202     } # while
203
204     # Still got a node left over to merge?
205     if ($state eq "inner") {
206         _merge_node ($hmap, \%params, $newnode, \@newvalues, \@delvalues);
207     }
208 }
209
210 sub _parse_key_value
211 {
212     local $_ = shift;
213     my $encoding = shift;
214     my $key;
215     ($key, $_) = _parse_quoted_string ($_);
216     return undef unless defined $key;
217     return undef unless substr ($_, 0, 1) eq "=";
218     return _parse_value ($key, substr ($_, 1), $encoding);
219 }
220
221 # Parse a double-quoted string, returning the string.  \ is used to
222 # escape double-quotes and other backslash characters.
223 #
224 # If called in array context and if there is anything after the quoted
225 # string, it is returned as the second element of the array.
226 #
227 # Returns undef if there was a parse error.
228 sub _parse_quoted_string
229 {
230     local $_ = shift;
231
232     # No initial quote character.
233     return undef if substr ($_, 0, 1) ne "\"";
234
235     my $i;
236     my $out = "";
237     for ($i = 1; $i < length; ++$i) {
238         my $c = substr ($_, $i, 1);
239         if ($c eq "\"") {
240             last
241         } elsif ($c eq "\\") {
242             $i++;
243             $c = substr ($_, $i, 1);
244             $out .= $c;
245         } else {
246             $out .= $c;
247         }
248     }
249
250     # No final quote character.
251     return undef if $i == length;
252
253     $_ = substr ($_, $i+1);
254     if (wantarray) {
255         return ($out, $_);
256     } else {
257         return $out;
258     }
259 }
260
261 # Parse the value, optionally prefixed by a type.
262
263 sub _parse_value
264 {
265     local $_;
266     my $key = shift;
267     $_ = shift;
268     my $encoding = shift;       # default encoding for strings
269
270     my $type;
271     my $data;
272
273     if (m/^dword:([[:xdigit:]]{8})$/) { # DWORD
274         $type = 4;
275         $data = _dword_le (hex ($1));
276     } elsif (m/^hex:(.*)$/) {   # hex digits
277         $type = 3;
278         $data = _data_from_hex_digits ($1);
279         return undef unless defined $data;
280     } elsif (m/^hex\(([[:xdigit:]]+)\):(.*)$/) {   # hex digits
281         $type = hex ($1);
282         $data = _data_from_hex_digits ($2);
283         return undef unless defined $data;
284     } elsif (m/^str:(".*")$/) { # only in Wine fake-registries, I think
285         $type = 1;
286         $data = _parse_quoted_string ($1);
287         return undef unless defined $data;
288         $data .= "\0"; # Value strings are implicitly ASCIIZ.
289         $data = encode ($encoding, $data);
290     } elsif (m/^str\(([[:xdigit:]]+)\):(".*")$/) {
291         $type = hex ($1);
292         $data = _parse_quoted_string ($2);
293         return undef unless defined $data;
294         $data .= "\0"; # Value strings are implicitly ASCIIZ.
295         $data = encode ($encoding, $data);
296     } elsif (m/^(".*")$/) {
297         $type = 1;
298         $data = _parse_quoted_string ($1);
299         return undef unless defined $data;
300         $data .= "\0"; # Value strings are implicitly ASCIIZ.
301         $data = encode ($encoding, $data);
302     } else {
303         return undef;
304     }
305
306     my %h = ( key => $key, t => $type, value => $data );
307     return \%h;
308 }
309
310 sub _dword_le
311 {
312     pack ("V", $_[0]);
313 }
314
315 sub _data_from_hex_digits
316 {
317     local $_ = shift;
318     s/[,[:space:]]//g;
319     pack ("H*", $_)
320 }
321
322 sub _merge_node
323 {
324     local $_;
325     my $hmap = shift;
326     my $params = shift;
327     my $path = shift;
328     my $newvalues = shift;
329     my $delvalues = shift;
330
331     my $h;
332     ($h, $path) = _map_handle ($hmap, $path);
333
334     my $node = _node_lookup ($h, $path);
335     if (!defined $node) {       # Need to create this node.
336         my $name = $path;
337         $name = $1 if $path =~ /([^\\]+)$/;
338         my $parentpath = $path;
339         $parentpath =~ s/[^\\]+$//;
340         my $parent = _node_lookup ($h, $parentpath);
341         if (!defined $parent) {
342             confess "reg_import: cannot create $path since parent $parentpath does not exist"
343         }
344         $node = $h->node_add_child ($parent, $name);
345     }
346
347     # Get the current set of values at this node.
348     my @values = $h->node_values ($node);
349
350     # Delete values in @delvalues original and values that are going
351     # to be replaced.
352     my @delvalues = @$delvalues;
353     foreach (@$newvalues) {
354         push @delvalues, $_->{key};
355     }
356     @values = grep { ! _imember ($h->value_key ($_), @delvalues) } @values;
357
358     # Get the actual values from the hive.
359     @values = map {
360         my $key = $h->value_key ($_);
361         my ($type, $data) = $h->value_value ($_);
362         my %h = ( key => $key, t => $type, value => $data );
363         $_ = \%h;
364     } @values;
365
366     # Add the new values.
367     push @values, @$newvalues;
368
369     $h->node_set_values ($node, \@values);
370 }
371
372 sub _delete_node
373 {
374     local $_;
375     my $hmap = shift;
376     my $params = shift;
377     my $path = shift;
378
379     my $h;
380     ($h, $path) = _map_handle ($hmap, $path);
381
382     my $node = _node_lookup ($h, $path);
383     # Not an error to delete a non-existant node.
384     return unless defined $node;
385
386     # However you cannot delete the root node.
387     confess "reg_import: the root node of a hive cannot be deleted"
388         if $node == $h->root ();
389
390     $h->node_delete_child ($node);
391 }
392
393 # Call the map function, if necessary.
394 sub _map_handle
395 {
396     local $_; # called function may use this
397     my $hmap = shift;
398     my $path = shift;
399     my $h = $hmap;
400
401     if (ref ($hmap) eq "CODE") {
402         ($h, $path) = &$hmap ($path);
403     }
404     return ($h, $path);
405 }
406
407 sub _imember
408 {
409     local $_;
410     my $item = shift;
411
412     foreach (@_) {
413         return 1 if lc ($_) eq lc ($item);
414     }
415     return 0;
416 }
417
418 sub _unexpected
419 {
420     local $_ = shift;
421     my $lineno = shift;
422
423     "reg_import: parse error: unexpected text found at line $lineno near\n$_"
424 }
425
426 sub _parse_error
427 {
428     local $_ = shift;
429     my $lineno = shift;
430
431     "reg_import: parse error: at line $lineno near\n$_"
432 }
433
434 =head2 reg_export
435
436  reg_export ($h, $key, $fh,
437              [prefix => $prefix],
438              [unsafe_printable_strings => 1]);
439
440 This function exports the registry keys starting at the root
441 C<$key> and recursively downwards into the file handle C<$fh>.
442
443 C<$key> is a case-insensitive path of the node to start from, relative
444 to the root of the hive.  It is an error if this path does not exist.
445 Path elements should be separated by backslash characters.
446
447 C<$prefix> is prefixed to each key name.  The usual use for this is to
448 make key names appear as they would on Windows.  For example the key
449 C<\Foo> in the SOFTWARE Registry, with $prefix
450 C<HKEY_LOCAL_MACHINE\SOFTWARE>, would be written as:
451
452  [HKEY_LOCAL_MACHINE\SOFTWARE\Foo]
453  "Key 1"=...
454  "Key 2"=...
455
456 If C<unsafe_printable_strings> is not given or is false, then the
457 output is written as pure 7 bit ASCII, with line endings which are the
458 default for the local host.  Strings are always encoded as hex bytes.
459 This is safe because it preserves the original content and encoding of
460 strings.  See L</ENCODING STRINGS> below.
461
462 If C<unsafe_printable_strings> is true, then strings are assumed to be
463 UTF-16LE and are converted to UTF-8 for output.  The final zero
464 codepoint in the string is removed if there is one.  This is unsafe
465 because it does not preserve the fidelity of the strings in the
466 Registry and because the content type of strings is not always
467 UTF-16LE.  However it is useful if you just want to display strings
468 for quick hacking and debugging.
469
470 You may need to convert the file's encoding using L<iconv(1)> and line
471 endings using L<unix2dos(1)> if sending to a Windows user.
472
473 Nodes and keys are sorted alphabetically in the output.
474
475 This function does I<not> print a header.  The real regedit program
476 will print a header like:
477
478  Windows Registry Editor Version 5.00
479
480 followed by a blank line.  (Other headers are possible, see the
481 Wikipedia page on the Windows Registry).  If you want a header, you
482 need to write it out yourself.
483
484 =cut
485
486 sub reg_export
487 {
488     my $h = shift;
489     my $key = shift;
490
491     my $node = _node_lookup ($h, $key);
492     croak "$key: path not found in this hive" unless $node;
493
494     reg_export_node ($h, $node, @_);
495 }
496
497 =head2 reg_export_node
498
499  reg_export_node ($h, $node, $fh, ...);
500
501 This is exactly the same as L</reg_export> except that instead
502 of specifying the path to a key as a string, you pass a hivex
503 library C<$node> handle.
504
505 =cut
506
507 sub reg_export_node
508 {
509     local $_;
510     my $h = shift;
511     my $node = shift;
512     my $fh = shift;
513     my %params = @_;
514
515     confess "reg_export_node: \$node parameter was undef" unless defined $node;
516
517     # Get the canonical path of this node.
518     my $path = _node_canonical_path ($h, $node);
519
520     # Print the path.
521     print $fh "[";
522     my $prefix = $params{prefix};
523     if (defined $prefix) {
524         chop $prefix if substr ($prefix, -1, 1) eq "\\";
525         print $fh $prefix;
526     }
527     print $fh $path;
528     print $fh "]\n";
529
530     my $unsafe_printable_strings = $params{unsafe_printable_strings};
531
532     # Get the values.
533     my @values = $h->node_values ($node);
534
535     foreach (@values) {
536         use bytes;
537
538         my $key = $h->value_key ($_);
539         my ($type, $data) = $h->value_value ($_);
540         $_ = { key => $key, type => $type, data => $data }
541     }
542
543     @values = sort { $a->{key} cmp $b->{key} } @values;
544
545     # Print the values.
546     foreach (@values) {
547         my $key = $_->{key};
548         my $type = $_->{type};
549         my $data = $_->{data};
550
551         if ($key eq "") {
552             print $fh '@='    # default key
553         } else {
554             print $fh '"', _escape_quotes ($key), '"='
555         }
556
557         if ($type eq 4 && length ($data) == 4) { # only handle dword specially
558             my $dword = unpack ("V", $data);
559             printf $fh "dword:%08x\n", $dword
560         } elsif ($unsafe_printable_strings && ($type eq 1 || $type eq 2)) {
561             # Guess that the encoding is UTF-16LE.  Convert it to UTF-8
562             # for printing.
563             $data = decode ("utf16le", $data);
564             $data =~ s/\x{0}$//; # remove final zero codepoint
565             $data =~ s/"/\\"/g; # XXX more quoting needed?
566             printf $fh "str(%x):\"%s\"\n", $type, $data;
567         } else {
568             # Encode everything else as hex, see encoding section below.
569             printf $fh "hex(%x):", $type;
570             my $hex = join (",", map { sprintf "%02x", ord } split (//, $data));
571             print $fh "$hex\n"
572         }
573     }
574     print $fh "\n";
575
576     my @children = $h->node_children ($node);
577     @children = sort { $h->node_name ($a) cmp $h->node_name ($b) } @children;
578     reg_export_node ($h, $_, $fh, @_) foreach @children;
579 }
580
581 # Escape " and \ when printing keys.
582 sub _escape_quotes
583 {
584     local $_ = shift;
585     s/\\/\\\\/g;
586     s/"/\\"/g;
587     $_;
588 }
589
590 # Look up a node in the registry starting from the path.
591 # Return undef if it doesn't exist.
592
593 sub _node_lookup
594 {
595     local $_;
596     my $h = shift;
597     my $path = shift;
598
599     my @path = split /\\/, $path;
600     shift @path if @path > 0 && $path[0] eq "";
601
602     my $node = $h->root ();
603     foreach (@path) {
604         $node = $h->node_get_child ($node, $_);
605         return undef unless defined $node;
606     }
607
608     return $node;
609 }
610
611 # Return the canonical path of node in the hive.
612
613 sub _node_canonical_path
614 {
615     local $_;
616     my $h = shift;
617     my $node = shift;
618
619     return "\\" if $node == $h->root ();
620     $_ = $h->node_name ($node);
621     my $parent = $h->node_parent ($node);
622     my $path = _node_canonical_path ($h, $parent);
623     if ($path eq "\\") {
624         return "$path$_"
625     } else {
626         return "$path\\$_"
627     }
628 }
629
630 =head1 ENCODING STRINGS
631
632 The situation with encoding strings in the Registry on Windows is very
633 confused.  There are two main encodings that you would find in the
634 binary (hive) file, 7 bit ASCII and UTF-16LE.  (Other encodings are
635 possible, it's also possible to have arbitrary binary data incorrectly
636 marked with a string type).
637
638 The hive file itself doesn't contain any indication of string
639 encoding.  Windows probably guesses the encoding.
640
641 We think that regedit probably either guesses which encoding to use
642 based on the file encoding, or else has different defaults for
643 different versions of Windows.  Neither choice is appropriate for a
644 tool used in a real operating system.
645
646 When using L</reg_import>, you should specify the default encoding for
647 strings using the C<encoding> parameter.  If not specified, it
648 defaults to UTF-16LE.
649
650 The file itself that is imported should be in the local encoding for
651 files (usually UTF-8 on modern Linux systems).  This means if you
652 receive a regedit file from a Windows system, you may sometimes have
653 to reencode it:
654
655  iconv -f utf-16le -t utf-8 < input.reg | dos2unix > output.reg
656
657 When writing regedit files (L</reg_export>) we bypass this madness
658 completely.  I<All> strings (even pure ASCII) are written as hex bytes
659 so there is no doubt about how they should be encoded when they are
660 read back in.
661
662 =cut
663
664 1;
665
666 =head1 COPYRIGHT
667
668 Copyright (C) 2010-2011 Red Hat Inc.
669
670 =head1 LICENSE
671
672 Please see the file COPYING.LIB for the full license.
673
674 =head1 SEE ALSO
675
676 L<Win::Hivex(3)>,
677 L<hivexregedit(1)>,
678 L<virt-win-reg(1)>,
679 L<iconv(1)>,
680 L<dos2unix(1)>,
681 L<unix2dos(1)>,
682 L<hivex(3)>,
683 L<hivexsh(1)>,
684 L<http://libguestfs.org>,
685 L<Sys::Guestfs(3)>.
686
687 =cut