Blame src/w32-reg.c

Packit fc043f
/* w32-reg.c - Windows registry support
Packit fc043f
 * Copyright (C) 2002, 2005, 2010, 2012, 2017 g10 Code GmbH
Packit fc043f
 *
Packit fc043f
 * This file is part of Libgpg-error.
Packit fc043f
 *
Packit fc043f
 * Libgpg-error is free software; you can redistribute it and/or
Packit fc043f
 * modify it under the terms of the GNU Lesser General Public License
Packit fc043f
 * as published by the Free Software Foundation; either version 2.1 of
Packit fc043f
 * the License, or (at your option) any later version.
Packit fc043f
 *
Packit fc043f
 * Libgpg-error is distributed in the hope that it will be useful, but
Packit fc043f
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit fc043f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit fc043f
 * Lesser General Public License for more details.
Packit fc043f
 *
Packit fc043f
 * You should have received a copy of the GNU Lesser General Public
Packit fc043f
 * License along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit fc043f
 * SPDX-License-Identifier: LGPL-2.1+
Packit fc043f
 */
Packit fc043f
Packit fc043f
#if HAVE_CONFIG_H
Packit fc043f
#include <config.h>
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#ifndef HAVE_W32_SYSTEM
Packit fc043f
# error This module may only be build for Windows.
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#include <stdlib.h>
Packit fc043f
#include <stdio.h>
Packit fc043f
#include <string.h>
Packit fc043f
#include <errno.h>
Packit fc043f
#include <gpg-error.h>
Packit fc043f
#define WIN32_LEAN_AND_MEAN
Packit fc043f
#include <windows.h>
Packit fc043f
Packit fc043f
#include "gpgrt-int.h"
Packit fc043f
Packit fc043f
Packit fc043f
/* Return a string from the W32 Registry or NULL in case of error.
Packit fc043f
 * Caller must release the return value.  A NULL for root is an alias
Packit fc043f
 * for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.  The returned
Packit fc043f
 * string is UTF-8 encoded; ROOT, DIR, and NAME must be plain
Packit fc043f
 * ASCII. */
Packit fc043f
char *
Packit fc043f
_gpgrt_w32_reg_query_string (const char *root, const char *dir,
Packit fc043f
                             const char *name)
Packit fc043f
{
Packit fc043f
  HKEY root_key, key_handle;
Packit fc043f
  DWORD n1, nbytes, type;
Packit fc043f
  char *result = NULL;
Packit fc043f
Packit fc043f
  if (!root)
Packit fc043f
    root_key = HKEY_CURRENT_USER;
Packit fc043f
  else if (!strcmp( root, "HKEY_CLASSES_ROOT"))
Packit fc043f
    root_key = HKEY_CLASSES_ROOT;
Packit fc043f
  else if (!strcmp( root, "HKEY_CURRENT_USER"))
Packit fc043f
    root_key = HKEY_CURRENT_USER;
Packit fc043f
  else if (!strcmp( root, "HKEY_LOCAL_MACHINE"))
Packit fc043f
    root_key = HKEY_LOCAL_MACHINE;
Packit fc043f
  else if (!strcmp( root, "HKEY_USERS"))
Packit fc043f
    root_key = HKEY_USERS;
Packit fc043f
  else if (!strcmp( root, "HKEY_PERFORMANCE_DATA"))
Packit fc043f
    root_key = HKEY_PERFORMANCE_DATA;
Packit fc043f
  else if (!strcmp( root, "HKEY_CURRENT_CONFIG"))
Packit fc043f
    root_key = HKEY_CURRENT_CONFIG;
Packit fc043f
  else
Packit fc043f
    return NULL;
Packit fc043f
Packit fc043f
  if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
Packit fc043f
    {
Packit fc043f
      if (root)
Packit fc043f
        return NULL; /* No need for a RegClose, so return direct.  */
Packit fc043f
      /* It seems to be common practise to fall back to HKLM. */
Packit fc043f
      if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
Packit fc043f
        return NULL; /* still no need for a RegClose, so return direct */
Packit fc043f
    }
Packit fc043f
Packit fc043f
Packit fc043f
  /* FIXME:  Use wide functions and convert to utf-8.  */
Packit fc043f
  nbytes = 1;
Packit fc043f
  if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
Packit fc043f
    {
Packit fc043f
      if (root)
Packit fc043f
        goto leave;
Packit fc043f
      /* Try to fallback to HKLM also for a missing value.  */
Packit fc043f
      RegCloseKey (key_handle);
Packit fc043f
      if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
Packit fc043f
        return NULL; /* Nope.  */
Packit fc043f
      if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
Packit fc043f
        goto leave;
Packit fc043f
    }
Packit fc043f
  n1 = nbytes + 1;
Packit fc043f
  result = xtrymalloc (n1);
Packit fc043f
  if (!result)
Packit fc043f
    goto leave;
Packit fc043f
  if (RegQueryValueExA (key_handle, name, 0, &type, (LPBYTE) result, &n1))
Packit fc043f
    {
Packit fc043f
      xfree (result);
Packit fc043f
      result = NULL;
Packit fc043f
      goto leave;
Packit fc043f
    }
Packit fc043f
  result[nbytes] = 0; /* Make sure it is really a string.  */
Packit fc043f
Packit fc043f
#ifndef HAVE_W32CE_SYSTEM /* (Windows CE has no environment.)  */
Packit fc043f
  if (type == REG_EXPAND_SZ && strchr (result, '%'))
Packit fc043f
    {
Packit fc043f
      char *tmp;
Packit fc043f
Packit fc043f
      n1 += 1000;
Packit fc043f
      tmp = xtrymalloc (n1 + 1);
Packit fc043f
      if (!tmp)
Packit fc043f
        goto leave;
Packit fc043f
      nbytes = ExpandEnvironmentStrings (result, tmp, n1);
Packit fc043f
      if (nbytes && nbytes > n1)
Packit fc043f
        {
Packit fc043f
          xfree (tmp);
Packit fc043f
          n1 = nbytes;
Packit fc043f
          tmp = xtrymalloc (n1 + 1);
Packit fc043f
          if (!tmp)
Packit fc043f
            goto leave;
Packit fc043f
          nbytes = ExpandEnvironmentStrings (result, tmp, n1);
Packit fc043f
          if (nbytes && nbytes > n1) {
Packit fc043f
            xfree (tmp); /* Oops - truncated, better don't expand at all. */
Packit fc043f
            goto leave;
Packit fc043f
          }
Packit fc043f
          tmp[nbytes] = 0;
Packit fc043f
          xfree (result);
Packit fc043f
          result = tmp;
Packit fc043f
        }
Packit fc043f
      else if (nbytes)  /* Okay, reduce the length. */
Packit fc043f
        {
Packit fc043f
          tmp[nbytes] = 0;
Packit fc043f
          xfree (result);
Packit fc043f
          result = xtrymalloc (strlen (tmp)+1);
Packit fc043f
          if (!result)
Packit fc043f
            result = tmp;
Packit fc043f
          else
Packit fc043f
            {
Packit fc043f
              strcpy (result, tmp);
Packit fc043f
              xfree (tmp);
Packit fc043f
            }
Packit fc043f
        }
Packit fc043f
      else  /* Error - don't expand. */
Packit fc043f
        {
Packit fc043f
          xfree (tmp);
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
#endif
Packit fc043f
Packit fc043f
 leave:
Packit fc043f
  RegCloseKey (key_handle);
Packit fc043f
  return result;
Packit fc043f
}