New APIs: hivex_*

Transscribe many hivex(3) APIs into the libguestfs API.

There is one hive handle per libguestfs handle, as with Augeas.

Note that hivex uses iconv_open for some APIs (eg. hivex_value_string).
But since we delete all the i18n files from the appliance, this
doesn't work -- iconv_open returns EINVAL.  Therefore hivex APIs which
require iconv cannot be bound in the daemon.
This commit is contained in:
Richard W.M. Jones
2012-08-28 16:03:50 +01:00
parent 228d49bb84
commit 8a723ca62e
11 changed files with 745 additions and 10 deletions

View File

@@ -30,6 +30,7 @@
gfs2-utils
grub
hfsplus-tools
hivex
iputils
kernel
MAKEDEV
@@ -57,6 +58,7 @@
hfsplus
iproute
libaugeas0
libhivex0
linux-image
nilfs-tools
ntfs-3g
@@ -76,6 +78,7 @@
btrfs-progs-unstable
cryptsetup
augeas
hivex
zfs-fuse
e2fsprogs
grub

View File

@@ -121,6 +121,7 @@ guestfsd_SOURCES = \
guestfsd.c \
headtail.c \
hexdump.c \
hivex.c \
htonl.c \
initrd.c \
inotify.c \
@@ -176,6 +177,7 @@ guestfsd_LDADD = \
libprotocol.a \
$(SELINUX_LIB) \
$(AUGEAS_LIBS) \
$(HIVEX_LIBS) \
$(top_builddir)/gnulib/lib/.libs/libgnu.a \
$(GETADDRINFO_LIB) \
$(HOSTENT_LIB) \
@@ -186,6 +188,9 @@ guestfsd_LDADD = \
$(SERVENT_LIB)
guestfsd_CPPFLAGS = -I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib
guestfsd_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) $(AUGEAS_CFLAGS)
guestfsd_CFLAGS = \
$(WARN_CFLAGS) $(WERROR_CFLAGS) \
$(AUGEAS_CFLAGS) \
$(HIVEX_CFLAGS)
.PHONY: force

509
daemon/hivex.c Normal file
View File

@@ -0,0 +1,509 @@
/* libguestfs - the guestfsd daemon
* Copyright (C) 2012 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "guestfs_protocol.h"
#include "daemon.h"
#include "actions.h"
#include "optgroups.h"
#ifdef HAVE_HIVEX
#include <hivex.h>
int
optgroup_hivex_available (void)
{
return 1;
}
/* The hivex handle. As with Augeas, there is one per guestfs handle /
* daemon.
*/
static hive_h *h = NULL;
/* Clean up the hivex handle on daemon exit. */
static void hivex_finalize (void) __attribute__((destructor));
static void
hivex_finalize (void)
{
if (h) {
hivex_close (h);
h = NULL;
}
}
#define NEED_HANDLE(errcode) \
do { \
if (!h) { \
reply_with_error ("%s: you must call 'hivex-open' first to initialize the hivex handle", __func__); \
return (errcode); \
} \
} \
while (0)
/* Takes optional arguments, consult optargs_bitmask. */
int
do_hivex_open (const char *filename, int verbose, int debug, int write)
{
char *buf;
int flags = 0;
if (h) {
hivex_close (h);
h = NULL;
}
buf = sysroot_path (filename);
if (!buf) {
reply_with_perror ("malloc");
return -1;
}
if (optargs_bitmask & GUESTFS_HIVEX_OPEN_VERBOSE_BITMASK) {
if (verbose)
flags |= HIVEX_OPEN_VERBOSE;
}
if (optargs_bitmask & GUESTFS_HIVEX_OPEN_DEBUG_BITMASK) {
if (debug)
flags |= HIVEX_OPEN_DEBUG;
}
if (optargs_bitmask & GUESTFS_HIVEX_OPEN_WRITE_BITMASK) {
if (write)
flags |= HIVEX_OPEN_WRITE;
}
h = hivex_open (buf, flags);
if (!h) {
reply_with_perror ("hivex failed to open %s", filename);
free (buf);
return -1;
}
free (buf);
return 0;
}
int
do_hivex_close (void)
{
NEED_HANDLE (-1);
hivex_close (h);
h = NULL;
return 0;
}
int64_t
do_hivex_root (void)
{
int64_t r;
NEED_HANDLE (-1);
r = hivex_root (h);
if (r == 0) {
reply_with_perror ("failed");
return -1;
}
return r;
}
char *
do_hivex_node_name (int64_t nodeh)
{
char *r;
NEED_HANDLE (NULL);
r = hivex_node_name (h, nodeh);
if (r == NULL) {
reply_with_perror ("failed");
return NULL;
}
return r;
}
guestfs_int_hivex_node_list *
do_hivex_node_children (int64_t nodeh)
{
guestfs_int_hivex_node_list *ret;
hive_node_h *r;
size_t i, len;
NEED_HANDLE (NULL);
r = hivex_node_children (h, nodeh);
if (r == NULL) {
reply_with_perror ("failed");
return NULL;
}
len = 0;
for (i = 0; r[i] != 0; ++i)
len++;
ret = malloc (sizeof *ret);
if (!ret) {
reply_with_perror ("malloc");
free (r);
return NULL;
}
ret->guestfs_int_hivex_node_list_len = len;
ret->guestfs_int_hivex_node_list_val =
malloc (len * sizeof (guestfs_int_hivex_node));
if (ret->guestfs_int_hivex_node_list_val == NULL) {
reply_with_perror ("malloc");
free (ret);
free (r);
return NULL;
}
for (i = 0; i < len; ++i)
ret->guestfs_int_hivex_node_list_val[i].hivex_node_h = r[i];
free (r);
return ret;
}
int64_t
do_hivex_node_get_child (int64_t nodeh, const char *name)
{
int64_t r;
NEED_HANDLE (-1);
errno = 0;
r = hivex_node_get_child (h, nodeh, name);
if (r == 0 && errno != 0) {
reply_with_perror ("failed");
return -1;
}
return r;
}
int64_t
do_hivex_node_parent (int64_t nodeh)
{
int64_t r;
NEED_HANDLE (-1);
r = hivex_node_parent (h, nodeh);
if (r == 0) {
reply_with_perror ("failed");
return -1;
}
return r;
}
guestfs_int_hivex_value_list *
do_hivex_node_values (int64_t nodeh)
{
guestfs_int_hivex_value_list *ret;
hive_value_h *r;
size_t i, len;
NEED_HANDLE (NULL);
r = hivex_node_values (h, nodeh);
if (r == NULL) {
reply_with_perror ("failed");
return NULL;
}
len = 0;
for (i = 0; r[i] != 0; ++i)
len++;
ret = malloc (sizeof *ret);
if (!ret) {
reply_with_perror ("malloc");
free (r);
return NULL;
}
ret->guestfs_int_hivex_value_list_len = len;
ret->guestfs_int_hivex_value_list_val =
malloc (len * sizeof (guestfs_int_hivex_value));
if (ret->guestfs_int_hivex_value_list_val == NULL) {
reply_with_perror ("malloc");
free (ret);
free (r);
return NULL;
}
for (i = 0; i < len; ++i)
ret->guestfs_int_hivex_value_list_val[i].hivex_value_h = (int64_t) r[i];
free (r);
return ret;
}
int64_t
do_hivex_node_get_value (int64_t nodeh, const char *key)
{
int64_t r;
NEED_HANDLE (-1);
errno = 0;
r = hivex_node_get_value (h, nodeh, key);
if (r == 0 && errno != 0) {
reply_with_perror ("failed");
return -1;
}
return r;
}
char *
do_hivex_value_key (int64_t valueh)
{
char *r;
NEED_HANDLE (NULL);
r = hivex_value_key (h, valueh);
if (r == NULL) {
reply_with_perror ("failed");
return NULL;
}
return r;
}
int64_t
do_hivex_value_type (int64_t valueh)
{
hive_type r;
NEED_HANDLE (-1);
if (hivex_value_type (h, valueh, &r, NULL) == -1) {
reply_with_perror ("failed");
return -1;
}
return r;
}
char *
do_hivex_value_value (int64_t valueh, size_t *size_r)
{
char *r;
size_t size;
NEED_HANDLE (NULL);
r = hivex_value_value (h, valueh, NULL, &size);
if (r == NULL) {
reply_with_perror ("failed");
return NULL;
}
*size_r = size;
return r;
}
int
do_hivex_commit (const char *filename)
{
NEED_HANDLE (-1);
if (hivex_commit (h, filename, 0) == -1) {
reply_with_perror ("failed");
return -1;
}
return 0;
}
int64_t
do_hivex_node_add_child (int64_t parent, const char *name)
{
int64_t r;
NEED_HANDLE (-1);
r = hivex_node_add_child (h, parent, name);
if (r == 0) {
reply_with_perror ("failed");
return -1;
}
return r;
}
int
do_hivex_node_delete_child (int64_t nodeh)
{
NEED_HANDLE (-1);
if (hivex_node_delete_child (h, nodeh) == -1) {
reply_with_perror ("failed");
return -1;
}
return 0;
}
int
do_hivex_node_set_value (int64_t nodeh,
const char *key, int64_t t,
const char *val, size_t val_size)
{
const hive_set_value v =
{ .key = (char *) key, .t = t, .len = val_size, .value = (char *) val };
NEED_HANDLE (-1);
if (hivex_node_set_value (h, nodeh, &v, 0) == -1) {
reply_with_perror ("failed");
return -1;
}
return 0;
}
#else /* !HAVE_HIVEX */
/* Note that the wrapper code (daemon/stubs.c) ensures that the
* functions below are never called because optgroup_hivex_available
* returns false.
*/
int
optgroup_hivex_available (void)
{
return 0;
}
int __attribute__((noreturn))
do_hivex_open (const char *filename, int verbose, int debug, int write)
{
abort ();
}
int __attribute__((noreturn))
do_hivex_close (void)
{
abort ();
}
int64_t __attribute__((noreturn))
do_hivex_root (void)
{
abort ();
}
char * __attribute__((noreturn))
do_hivex_node_name (int64_t nodeh)
{
abort ();
}
guestfs_int_hivex_node_list * __attribute__((noreturn))
do_hivex_node_children (int64_t nodeh)
{
abort ();
}
int64_t __attribute__((noreturn))
do_hivex_node_get_child (int64_t nodeh, const char *name)
{
abort ();
}
int64_t __attribute__((noreturn))
do_hivex_node_parent (int64_t nodeh)
{
abort ();
}
guestfs_int_hivex_value_list * __attribute__((noreturn))
do_hivex_node_values (int64_t nodeh)
{
abort ();
}
int64_t __attribute__((noreturn))
do_hivex_node_get_value (int64_t nodeh, const char *key)
{
abort ();
}
char * __attribute__((noreturn))
do_hivex_value_key (int64_t valueh)
{
abort ();
}
int64_t __attribute__((noreturn))
do_hivex_value_type (int64_t valueh)
{
abort ();
}
char * __attribute__((noreturn))
do_hivex_value_value (int64_t valueh, size_t *size_r)
{
abort ();
}
int __attribute__((noreturn))
do_hivex_commit (const char *filename)
{
abort ();
}
int64_t __attribute__((noreturn))
do_hivex_node_add_child (int64_t parent, const char *name)
{
abort ();
}
int __attribute__((noreturn))
do_hivex_node_delete_child (int64_t nodeh)
{
abort ();
}
int __attribute__((noreturn))
do_hivex_node_set_value (int64_t nodeh, const char *key, int64_t t, const char *val, size_t val_size)
{
abort ();
}
#endif /* !HAVE_HIVEX */

View File

@@ -9477,6 +9477,193 @@ Some of the parameters of a mounted filesystem can be examined
and modified using the C<guestfs_xfs_info> and
C<guestfs_xfs_growfs> calls." };
{ defaults with
name = "hivex_open";
style = RErr, [Pathname "filename"], [OBool "verbose"; OBool "debug"; OBool "write"];
proc_nr = Some 350;
optional = Some "hivex";
shortdesc = "open a Windows Registry hive file";
longdesc = "\
Open the Windows Registry hive file named C<filename>.
If there was any previous hivex handle associated with this
guestfs session, then it is closed.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_close";
style = RErr, [], [];
proc_nr = Some 351;
optional = Some "hivex";
shortdesc = "close the current hivex handle";
longdesc = "\
Close the current hivex handle.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_root";
style = RInt64 "nodeh", [], [];
proc_nr = Some 352;
optional = Some "hivex";
shortdesc = "return the root node of the hive";
longdesc = "\
Return the root node of the hive.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_node_name";
style = RString "name", [Int64 "nodeh"], [];
proc_nr = Some 353;
optional = Some "hivex";
shortdesc = "return the name of the node";
longdesc = "\
Return the name of C<nodeh>.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_node_children";
style = RStructList ("nodehs", "hivex_node"), [Int64 "nodeh"], [];
proc_nr = Some 354;
optional = Some "hivex";
shortdesc = "return list of nodes which are subkeys of node";
longdesc = "\
Return the list of nodes which are subkeys of C<nodeh>.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_node_get_child";
style = RInt64 "child", [Int64 "nodeh"; String "name"], [];
proc_nr = Some 355;
optional = Some "hivex";
shortdesc = "return the named child of node";
longdesc = "\
Return the child of C<nodeh> with the name C<name>, if it exists.
This can return C<0> meaning the name was not found.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_node_parent";
style = RInt64 "parent", [Int64 "nodeh"], [];
proc_nr = Some 356;
optional = Some "hivex";
shortdesc = "return the parent of node";
longdesc = "\
Return the parent node of C<nodeh>.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_node_values";
style = RStructList ("valuehs", "hivex_value"), [Int64 "nodeh"], [];
proc_nr = Some 357;
optional = Some "hivex";
shortdesc = "return list of values attached to node";
longdesc = "\
Return the array of (key, datatype, data) tuples attached to C<nodeh>.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_node_get_value";
style = RInt64 "valueh", [Int64 "nodeh"; String "key"], [];
proc_nr = Some 358;
optional = Some "hivex";
shortdesc = "return the named value";
longdesc = "\
Return the value attached to C<nodeh> which has the
name C<key>, if it exists. This can return C<0> meaning
the key was not found.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_value_key";
style = RString "key", [Int64 "valueh"], [];
proc_nr = Some 359;
optional = Some "hivex";
shortdesc = "return the key field from the (key, datatype, data) tuple";
longdesc = "\
Return the key (name) field of a (key, datatype, data) tuple.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_value_type";
style = RInt64 "datatype", [Int64 "valueh"], [];
proc_nr = Some 360;
optional = Some "hivex";
shortdesc = "return the data type from the (key, datatype, data) tuple";
longdesc = "\
Return the data type field from a (key, datatype, data) tuple.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_value_value";
style = RBufferOut "databuf", [Int64 "valueh"], [];
proc_nr = Some 361;
optional = Some "hivex";
shortdesc = "return the data field from the (key, datatype, data) tuple";
longdesc = "\
Return the data field of a (key, datatype, data) tuple.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_commit";
style = RErr, [OptString "filename"], [];
proc_nr = Some 362;
optional = Some "hivex";
shortdesc = "commit (write) changes back to the hive";
longdesc = "\
Commit (write) changes to the hive.
If the optional C<filename> parameter is null, then the changes
are written back to the same hive that was opened. If this is
not null then they are written to the alternate filename given
and the original hive is left untouched.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_node_add_child";
style = RInt64 "nodeh", [Int64 "parent"; String "name"], [];
proc_nr = Some 363;
optional = Some "hivex";
shortdesc = "add a child node";
longdesc = "\
Add a child node to C<parent> named C<name>.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_node_delete_child";
style = RErr, [Int64 "nodeh"], [];
proc_nr = Some 364;
optional = Some "hivex";
shortdesc = "delete a node (recursively)";
longdesc = "\
Delete C<nodeh>, recursively if necessary.
This is a wrapper around the L<hivex(3)> call of the same name." };
{ defaults with
name = "hivex_node_set_value";
style = RErr, [Int64 "nodeh"; String "key"; Int64 "t"; BufferIn "val"], [];
proc_nr = Some 365;
optional = Some "hivex";
shortdesc = "set or replace a single value in a node";
longdesc = "\
Set or replace a single value under the node C<nodeh>. The
C<key> is the name, C<t> is the type, and C<val> is the data.
This is a wrapper around the L<hivex(3)> call of the same name." };
]
(* Non-API meta-commands available only in guestfish.

View File

@@ -263,6 +263,18 @@ let structs = [
"uts_version", FString;
"uts_machine", FString;
];
(* Used by hivex_* APIs to return a list of int64 handles (node
* handles and value handles). Note that we can't add a putative
* 'RInt64List' type to the generator because we need to return
* length and size, and RStructList does this already.
*)
"hivex_node", [
"hivex_node_h", FInt64;
];
"hivex_value", [
"hivex_value_h", FInt64;
];
] (* end of structs *)
(* For bindings which want camel case *)
@@ -284,6 +296,8 @@ let camel_structs = [
"mdstat", "MDStat";
"btrfssubvolume", "BTRFSSubvolume";
"utsname", "UTSName";
"hivex_node", "HivexNode";
"hivex_value", "HivexValue";
]
let camel_structs = List.sort (fun (_,a) (_,b) -> compare a b) camel_structs

View File

@@ -40,6 +40,8 @@ guestfs_gobject_headers= \
include/guestfs-gobject/struct-btrfssubvolume.h \
include/guestfs-gobject/struct-xfsinfo.h \
include/guestfs-gobject/struct-utsname.h \
include/guestfs-gobject/struct-hivex_node.h \
include/guestfs-gobject/struct-hivex_value.h \
include/guestfs-gobject/optargs-internal_test.h \
include/guestfs-gobject/optargs-add_drive.h \
include/guestfs-gobject/optargs-add_domain.h \
@@ -74,7 +76,8 @@ guestfs_gobject_headers= \
include/guestfs-gobject/optargs-rsync.h \
include/guestfs-gobject/optargs-rsync_in.h \
include/guestfs-gobject/optargs-rsync_out.h \
include/guestfs-gobject/optargs-xfs_admin.h
include/guestfs-gobject/optargs-xfs_admin.h \
include/guestfs-gobject/optargs-hivex_open.h
guestfs_gobject_sources= \
src/session.c \
@@ -96,6 +99,8 @@ guestfs_gobject_sources= \
src/struct-btrfssubvolume.c \
src/struct-xfsinfo.c \
src/struct-utsname.c \
src/struct-hivex_node.c \
src/struct-hivex_value.c \
src/optargs-internal_test.c \
src/optargs-add_drive.c \
src/optargs-add_domain.c \
@@ -130,4 +135,5 @@ guestfs_gobject_sources= \
src/optargs-rsync.c \
src/optargs-rsync_in.c \
src/optargs-rsync_out.c \
src/optargs-xfs_admin.c
src/optargs-xfs_admin.c \
src/optargs-hivex_open.c

View File

@@ -23,6 +23,8 @@ java_built_sources = \
com/redhat/et/libguestfs/Application.java \
com/redhat/et/libguestfs/BTRFSSubvolume.java \
com/redhat/et/libguestfs/Dirent.java \
com/redhat/et/libguestfs/HivexNode.java \
com/redhat/et/libguestfs/HivexValue.java \
com/redhat/et/libguestfs/INotifyEvent.java \
com/redhat/et/libguestfs/ISOInfo.java \
com/redhat/et/libguestfs/IntBool.java \

View File

@@ -1,6 +1,8 @@
Application.java
BTRFSSubvolume.java
Dirent.java
HivexNode.java
HivexValue.java
INotifyEvent.java
ISOInfo.java
IntBool.java

View File

@@ -41,6 +41,7 @@ daemon/grub.c
daemon/guestfsd.c
daemon/headtail.c
daemon/hexdump.c
daemon/hivex.c
daemon/htonl.c
daemon/initrd.c
daemon/inotify.c
@@ -148,6 +149,7 @@ gobject/src/optargs-copy_file_to_file.c
gobject/src/optargs-e2fsck.c
gobject/src/optargs-fstrim.c
gobject/src/optargs-grep.c
gobject/src/optargs-hivex_open.c
gobject/src/optargs-inspect_get_icon.c
gobject/src/optargs-internal_test.c
gobject/src/optargs-md_create.c
@@ -174,6 +176,8 @@ gobject/src/session.c
gobject/src/struct-application.c
gobject/src/struct-btrfssubvolume.c
gobject/src/struct-dirent.c
gobject/src/struct-hivex_node.c
gobject/src/struct-hivex_value.c
gobject/src/struct-inotify_event.c
gobject/src/struct-int_bool.c
gobject/src/struct-isoinfo.c

View File

@@ -1 +1 @@
349
365

View File

@@ -723,12 +723,15 @@ length filenames, keep the files in a tarball.
=head3 ACCESSING THE WINDOWS REGISTRY
Libguestfs also provides some help for decoding Windows Registry
"hive" files, through the library C<hivex> which is part of the
libguestfs project although ships as a separate tarball. You have to
locate and download the hive file(s) yourself, and then pass them to
C<hivex> functions. See also the programs L<hivexml(1)>,
L<hivexsh(1)>, L<hivexregedit(1)> and L<virt-win-reg(1)> for more help
on this issue.
"hive" files, through a separate C library called L<hivex(3)>.
Before libguestfs 1.19.35 you had to download the hive file, operate
on it locally using hivex, and upload it again. Since this version,
we have included the major hivex APIs directly in the libguestfs API
(see L</guestfs_hivex_open>). This means that if you have opened a
Windows guest, you can read and write the registry directly.
See also L<virt-win-reg(1)>.
=head3 SYMLINKS ON NTFS-3G FILESYSTEMS