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