my $uri;
-=item B<--connect URI> | B<-c URI>
+=item B<-c URI>
+
+=item B<--connect URI>
If using libvirt, connect to the given I<URI>. If omitted, then we
connect to the default libvirt hypervisor.
sub map_path_to_hive
{
local $_ = shift;
- my ($hiveshortname, $hivefile, $prefix);
+ my ($hiveshortname, $hivefile, $path, $prefix);
if (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SAM(\\.*)?$/i) {
$hiveshortname = "sam";
$hivefile = "$systemroot/system32/config/$hiveshortname";
- $_ = defined $1 ? $1 : "\\";
+ $path = defined $1 ? $1 : "\\";
$prefix = "HKEY_LOCAL_MACHINE\\SAM";
}
elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SECURITY(\\.*)?$/i) {
$hiveshortname = "security";
$hivefile = "$systemroot/system32/config/$hiveshortname";
- $_ = defined $1 ? $1 : "\\";
+ $path = defined $1 ? $1 : "\\";
$prefix = "HKEY_LOCAL_MACHINE\\SECURITY";
}
elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SOFTWARE(\\.*)?$/i) {
$hiveshortname = "software";
$hivefile = "$systemroot/system32/config/$hiveshortname";
- $_ = defined $1 ? $1 : "\\";
+ $path = defined $1 ? $1 : "\\";
$prefix = "HKEY_LOCAL_MACHINE\\SOFTWARE";
}
elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SYSTEM(\\.*)?$/i) {
$hiveshortname = "system";
$hivefile = "$systemroot/system32/config/$hiveshortname";
- $_ = defined $1 ? $1 : "\\";
+ $path = defined $1 ? $1 : "\\";
$prefix = "HKEY_LOCAL_MACHINE\\SYSTEM";
}
elsif (/^\\?(?:HKEY_USERS|HKU)\\.DEFAULT(\\.*)?$/i) {
$hiveshortname = "default";
$hivefile = "$systemroot/system32/config/$hiveshortname";
- $_ = defined $1 ? $1 : "\\";
+ $path = defined $1 ? $1 : "\\";
$prefix = "HKEY_LOCAL_MACHINE\\.DEFAULT";
}
+ elsif (/^\\?(?:HKEY_USERS|HKU)\\(S-1-5-[-\d]+)(\\.*)?$/i) {
+ my $sid = $1;
+ $hiveshortname = $sid;
+ $prefix = "HKEY_USERS\\$sid";
+ $path = defined $2 ? $2 : "\\";
+ # This requires a recursive call to download the SOFTWARE hive.
+ $hivefile = lookup_pip_of_user_sid ($sid) . "/ntuser.dat";
+ }
+ elsif (/^\\?(?:HKEY_USERS|HKU)\\LocalSystem(\\.*)?$/i) {
+ my $sid = "S-1-5-18";
+ $hiveshortname = $sid;
+ $prefix = "HKEY_USERS\\$sid";
+ $path = defined $1 ? $1 : "\\";
+ # This requires a recursive call to download the SOFTWARE hive.
+ $hivefile = lookup_pip_of_user_sid ($sid) . "/ntuser.dat";
+ }
+ elsif (/^\\?(?:HKEY_USERS|HKU)\\LocalService(\\.*)?$/i) {
+ my $sid = "S-1-5-19";
+ $hiveshortname = $sid;
+ $prefix = "HKEY_USERS\\$sid";
+ $path = defined $1 ? $1 : "\\";
+ # This requires a recursive call to download the SOFTWARE hive.
+ $hivefile = lookup_pip_of_user_sid ($sid) . "/ntuser.dat";
+ }
+ elsif (/^\\?(?:HKEY_USERS|HKU)\\NetworkService(\\.*)?$/i) {
+ my $sid = "S-1-5-20";
+ $hiveshortname = $sid;
+ $prefix = "HKEY_USERS\\$sid";
+ $path = defined $1 ? $1 : "\\";
+ # This requires a recursive call to download the SOFTWARE hive.
+ $hivefile = lookup_pip_of_user_sid ($sid) . "/ntuser.dat";
+ }
+ elsif (/^\\?(?:HKEY_USERS|HKU)\\(.*?)(\\.*)?$/i) {
+ $hiveshortname = "user_$1";
+ $prefix = "HKEY_USERS\\$1";
+ $path = defined $2 ? $2 : "\\";
+ # XXX We should probably look this up properly.
+ if (is_dir_nocase ("/Users/$1")) {
+ $hivefile = "/Users/$1/ntuser.dat"
+ } elsif (is_dir_nocase ("/Documents and Settings/$1")) {
+ $hivefile = "/Documents and Settings/$1/ntuser.dat"
+ } else {
+ die __x("virt-win-reg: {p}: cannot find user directory\n",
+ p => $1)
+ }
+ }
else {
die __x("virt-win-reg: {p}: not a supported Windows Registry path\n",
p => $_)
}
- return ($hiveshortname, $hivefile, $_, $prefix);
+ return ($hiveshortname, $hivefile, $path, $prefix);
+}
+
+# Given a User SID, consult
+# HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$sid
+# and return the ProfileImagePath value.
+sub lookup_pip_of_user_sid
+{
+ local $_;
+ my $sid = shift;
+
+ my $path =
+ "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\".
+ $sid;
+
+ my ($hiveshortname, $hivefile, $prefix);
+ ($hiveshortname, $hivefile, $path, $prefix) = map_path_to_hive ($path);
+
+ download_hive ($hivefile, $hiveshortname)
+ unless -f "$tmpdir/$hiveshortname";
+
+ my @args = ("$tmpdir/$hiveshortname", $path, "ProfileImagePath");
+ warn "running hivexget ", join (" ", @args), " ..." if $debug;
+
+ my $fh;
+ open $fh, "-|", "hivexget", @args
+ or die "hivexget: see earlier errors: $!";
+ $_ = <$fh>;
+ close $fh or die "hivexget: see earlier errors: $!";
+
+ chomp;
+
+ # The contents of the registry are a windows path, possibly
+ # containing %systemroot% and %systemdrive% (on Win XP). Expand
+ # it and remove some other windows-isms. The caller will do
+ # case_sensitive_path for us, so we don't need to do that.
+ s/%systemroot%/$systemroot/i;
+ s/%systemdrive%//i;
+ s/^c://i;
+ s,\\,/,g;
+
+ $_;
+}
+
+sub is_dir_nocase
+{
+ local $_;
+ my $dir = shift;
+
+ my $windir;
+ eval { $windir = $g->case_sensitive_path ($dir); };
+ if ($@) {
+ return 0;
+ }
+ return $g->is_dir ($windir);
}
# Download a named hive file. Die on failure.
The program currently supports Windows NT-derived guests starting with
Windows XP through to at least Windows 7.
-Registry support is done for C<HKEY_LOCAL_MACHINE\SAM>,
-C<HKEY_LOCAL_MACHINE\SECURITY>, C<HKEY_LOCAL_MACHINE\SOFTWARE>,
-C<HKEY_LOCAL_MACHINE\SYSTEM> and C<HKEY_USERS\.DEFAULT>.
+The following Registry keys are supported:
+
+=over 4
+
+=item C<HKEY_LOCAL_MACHINE\SAM>
+
+=item C<HKEY_LOCAL_MACHINE\SECURITY>
+
+=item C<HKEY_LOCAL_MACHINE\SOFTWARE>
+
+=item C<HKEY_LOCAL_MACHINE\SYSTEM>
+
+=item C<HKEY_USERS\.DEFAULT>
+
+=item C<HKEY_USERS\I<SID>>
+
+where I<SID> is a Windows User SID (eg. C<S-1-5-18>).
+
+=item C<HKEY_USERS\I<username>>
+
+where I<username> is a local user name (this is a libguestfs extension).
+
+=back
You can use C<HKLM> as a shorthand for C<HKEY_LOCAL_MACHINE>, and
C<HKU> for C<HKEY_USERS>.
-C<HKEY_USERS\$SID> and C<HKEY_CURRENT_USER> are B<not> supported at
-this time.
+The literal keys C<HKEY_USERS\$SID> and C<HKEY_CURRENT_USER> are not
+supported (there is no "current user").
=head1 ENCODING