char *
guestfs__hivex_value_utf8 (guestfs_h *g, int64_t valueh)
{
  char *ret;
  size_t buflen;

  CLEANUP_FREE char *buf = guestfs_hivex_value_value (g, valueh, &buflen);
  if (buf == NULL)
    return NULL;

  ret = utf16_to_utf8 (buf, buflen);
  if (ret == NULL) {
    perrorf (g, "hivex: conversion of registry value to UTF8 failed");
    return NULL;
  }

  return ret;
}
static int
check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
{
  int r;
  size_t len = strlen (fs->windows_systemroot) + 64;
  char system[len];
  snprintf (system, len, "%s/system32/config/system",
            fs->windows_systemroot);

  CLEANUP_FREE char *system_path = guestfs_case_sensitive_path (g, system);
  if (!system_path)
    return -1;

  r = guestfs_is_file (g, system_path);
  if (r == -1)
    return -1;
  /* If the system hive doesn't exist, just accept that we cannot
   * find hostname etc.
   */
  if (r == 0)
    return 0;

  int ret = -1;
  int64_t root, node, value;
  CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values = NULL;
  CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values2 = NULL;
  int32_t dword;
  size_t i, count;
  CLEANUP_FREE void *buf = NULL;
  size_t buflen;
  const char *hivepath[] =
    { NULL /* current control set */, "Services", "Tcpip", "Parameters" };

  if (guestfs_hivex_open (g, system_path,
                          GUESTFS_HIVEX_OPEN_VERBOSE, g->verbose, -1) == -1)
    goto out;

  root = guestfs_hivex_root (g);
  if (root == 0)
    goto out;

  /* Get the CurrentControlSet. */
  node = guestfs_hivex_node_get_child (g, root, "Select");
  if (node == -1)
    goto out;

  if (node == 0) {
    error (g, "hivex: could not locate HKLM\\SYSTEM\\Select");
    goto out;
  }

  value = guestfs_hivex_node_get_value (g, node, "Current");
  if (value == -1)
    goto out;

  if (value == 0) {
    error (g, "hivex: HKLM\\System\\Select Default entry not found");
    goto out;
  }

  /* XXX Should check the type. */
  buf = guestfs_hivex_value_value (g, value, &buflen);
  if (buflen != 4) {
    error (g, "hivex: HKLM\\System\\Select\\Current expected to be DWORD");
    goto out;
  }
  dword = le32toh (*(int32_t *)buf);
  fs->windows_current_control_set = safe_asprintf (g, "ControlSet%03d", dword);

  /* Get the drive mappings.
   * This page explains the contents of HKLM\System\MountedDevices:
   * http://www.goodells.net/multiboot/partsigs.shtml
   */
  node = guestfs_hivex_node_get_child (g, root, "MountedDevices");
  if (node == -1)
    goto out;

  if (node == 0)
    /* Not found: skip getting drive letter mappings (RHBZ#803664). */
    goto skip_drive_letter_mappings;

  values = guestfs_hivex_node_values (g, node);

  /* Count how many DOS drive letter mappings there are.  This doesn't
   * ignore removable devices, so it overestimates, but that doesn't
   * matter because it just means we'll allocate a few bytes extra.
   */
  for (i = count = 0; i < values->len; ++i) {
    CLEANUP_FREE char *key =
      guestfs_hivex_value_key (g, values->val[i].hivex_value_h);
    if (key == NULL)
      goto out;
    if (STRCASEEQLEN (key, "\\DosDevices\\", 12) &&
        c_isalpha (key[12]) && key[13] == ':')
      count++;
  }

  fs->drive_mappings = safe_calloc (g, 2*count + 1, sizeof (char *));

  for (i = count = 0; i < values->len; ++i) {
    int64_t v = values->val[i].hivex_value_h;
    CLEANUP_FREE char *key = guestfs_hivex_value_key (g, v);
    if (key == NULL)
      goto out;
    if (STRCASEEQLEN (key, "\\DosDevices\\", 12) &&
        c_isalpha (key[12]) && key[13] == ':') {
      /* Get the binary value.  Is it a fixed disk? */
      CLEANUP_FREE char *blob = NULL;
      char *device;
      size_t len;
      int64_t type;

      type = guestfs_hivex_value_type (g, v);
      blob = guestfs_hivex_value_value (g, v, &len);
      if (blob != NULL && type == 3 && len == 12) {
        /* Try to map the blob to a known disk and partition. */
        device = map_registry_disk_blob (g, blob);
        if (device != NULL) {
          fs->drive_mappings[count++] = safe_strndup (g, &key[12], 1);
          fs->drive_mappings[count++] = device;
        }
      }
    }
  }

 skip_drive_letter_mappings:;
  /* Get the hostname. */
  hivepath[0] = fs->windows_current_control_set;
  for (node = root, i = 0;
       node > 0 && i < sizeof hivepath / sizeof hivepath[0];
       ++i) {
    node = guestfs_hivex_node_get_child (g, node, hivepath[i]);
  }

  if (node == -1)
    goto out;

  if (node == 0) {
    perrorf (g, "hivex: cannot locate HKLM\\SYSTEM\\%s\\Services\\Tcpip\\Parameters",
             fs->windows_current_control_set);
    goto out;
  }

  values2 = guestfs_hivex_node_values (g, node);
  if (values2 == NULL)
    goto out;

  for (i = 0; i < values2->len; ++i) {
    int64_t v = values2->val[i].hivex_value_h;
    CLEANUP_FREE char *key = guestfs_hivex_value_key (g, v);
    if (key == NULL)
      goto out;

    if (STRCASEEQ (key, "Hostname")) {
      fs->hostname = guestfs_hivex_value_utf8 (g, v);
      if (!fs->hostname)
        goto out;
    }
    /* many other interesting fields here ... */
  }

  ret = 0;

 out:
  guestfs_hivex_close (g);

  return ret;
}
Example #3
0
/* At the moment, pull just the ProductName and version numbers from
 * the registry.  In future there is a case for making many more
 * registry fields available to callers.
 */
static int
check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
{
  int ret = -1;
  int r;

  CLEANUP_FREE char *software =
    safe_asprintf (g, "%s/system32/config/software", fs->windows_systemroot);

  CLEANUP_FREE char *software_path = guestfs_case_sensitive_path (g, software);
  if (!software_path)
    return -1;

  r = guestfs_is_file (g, software_path);
  if (r == -1)
    return -1;
  /* If the software hive doesn't exist, just accept that we cannot
   * find product_name etc.
   */
  if (r == 0)
    return 0;

  int64_t node;
  const char *hivepath[] =
    { "Microsoft", "Windows NT", "CurrentVersion" };
  size_t i;
  CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values = NULL;
  bool ignore_currentversion = false;

  if (guestfs_hivex_open (g, software_path,
                          GUESTFS_HIVEX_OPEN_VERBOSE, g->verbose, -1) == -1)
    return -1;

  node = guestfs_hivex_root (g);
  for (i = 0; node > 0 && i < sizeof hivepath / sizeof hivepath[0]; ++i)
    node = guestfs_hivex_node_get_child (g, node, hivepath[i]);

  if (node == -1)
    goto out;

  if (node == 0) {
    perrorf (g, "hivex: cannot locate HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
    goto out;
  }

  values = guestfs_hivex_node_values (g, node);

  for (i = 0; i < values->len; ++i) {
    int64_t value = values->val[i].hivex_value_h;
    CLEANUP_FREE char *key = guestfs_hivex_value_key (g, value);
    if (key == NULL)
      goto out;

    if (STRCASEEQ (key, "ProductName")) {
      fs->product_name = guestfs_hivex_value_utf8 (g, value);
      if (!fs->product_name)
        goto out;
    }
    else if (STRCASEEQ (key, "CurrentMajorVersionNumber")) {
      size_t vsize;
      int64_t vtype = guestfs_hivex_value_type (g, value);
      CLEANUP_FREE char *vbuf = guestfs_hivex_value_value (g, value, &vsize);

      if (vbuf == NULL)
        goto out;
      if (vtype != 4 || vsize != 4) {
        error (g, "hivex: expected CurrentVersion\\%s to be a DWORD field",
               "CurrentMajorVersionNumber");
        goto out;
      }

      fs->version.v_major = le32toh (*(int32_t *)vbuf);

      /* Ignore CurrentVersion if we see it after this key. */
      ignore_currentversion = true;
    }
    else if (STRCASEEQ (key, "CurrentMinorVersionNumber")) {
      size_t vsize;
      int64_t vtype = guestfs_hivex_value_type (g, value);
      CLEANUP_FREE char *vbuf = guestfs_hivex_value_value (g, value, &vsize);

      if (vbuf == NULL)
        goto out;
      if (vtype != 4 || vsize != 4) {
        error (g, "hivex: expected CurrentVersion\\%s to be a DWORD field",
               "CurrentMinorVersionNumber");
        goto out;
      }

      fs->version.v_minor = le32toh (*(int32_t *)vbuf);

      /* Ignore CurrentVersion if we see it after this key. */
      ignore_currentversion = true;
    }
    else if (!ignore_currentversion && STRCASEEQ (key, "CurrentVersion")) {
      CLEANUP_FREE char *version = guestfs_hivex_value_utf8 (g, value);
      if (!version)
        goto out;
      if (guestfs_int_version_from_x_y_re (g, &fs->version, version,
                                           re_windows_version) == -1)
        goto out;
    }
    else if (STRCASEEQ (key, "InstallationType")) {
      fs->product_variant = guestfs_hivex_value_utf8 (g, value);
      if (!fs->product_variant)
        goto out;
    }
  }

  ret = 0;

 out:
  guestfs_hivex_close (g);

  return ret;
}