Revert "out-of-tree build: daemon"
[libguestfs.git] / tools / virt-win-reg
index 056ecce..1063617 100755 (executable)
@@ -125,7 +125,9 @@ Enable debugging messages.
 
 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.
@@ -367,44 +369,144 @@ sub import_mapper
 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.
@@ -456,15 +558,35 @@ sub upload_hive
 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
 
@@ -518,6 +640,17 @@ to find out is to look at the C<HKLM\SYSTEM\Select> key:
 Similarly, other C<Current...> keys in the path may need to
 be replaced.
 
+=head1 DELETING REGISTRY KEYS AND VALUES
+
+To delete a whole registry key, use the syntax:
+
+ [-HKEY_LOCAL_MACHINE\Foo]
+
+To delete a single value within a key, use the syntax:
+
+ [HKEY_LOCAL_MACHINE\Foo]
+ "Value"=-
+
 =head1 WINDOWS TIPS
 
 Note that some of these tips modify the guest disk image.  The guest