newlib/winsup/cygwin/registry.cc

309 lines
8.3 KiB
C++
Raw Normal View History

2000-02-17 20:38:33 +01:00
/* registry.cc: registry interface
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
2000-02-17 20:38:33 +01:00
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include "registry.h"
#include "cygerrno.h"
#include "path.h"
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
* Makefile.in (DLL_OFILES): Add tls_pbuf.o. * autoload.cc (CreateDesktopW): Replace CreateDesktopA. (CreateWindowStationW): Replace CreateWindowStationA. (GetUserObjectInformationW): Replace GetUserObjectInformationA. * cygheap.h (cwdstuff::get): Assume default buffer size NT_MAX_PATH. * cygtls.cc (_cygtls::remove): Free temporary TLS path buffers. * cygtls.h (TP_NUM_C_BUFS): Define. (TP_NUM_W_BUFS): Define. (class tls_pathbuf): New class to store pointers to thread local temporary path buffers. (_local_storage::pathbufs): New member. * environ.cc (win_env::add_cache): Use temporary TLS path buffer instead of stack based buffer. (posify): Get temporary outenv buffer from calling function. (environ_init): Create temporary TLS path buffer for posify. (build_env): Create Windows environment block as WCHAR buffer. * environ.h (build_env): Change declaration accordingly. * external.cc (sync_winenv): Accommodate build_env change. * fhandler_console.cc (fhandler_console::need_invisible): Use GetUserObjectInformationW and CreateWindowStationW. * fhandler_process.cc (format_process_maps): Use temporary TLS path buffer instead of stack based buffer. * fork.cc (frok::parent): Convert to use CreateProcessW. * path.cc: Throughout use temporary TLS path buffers instead of stack based buffer. Replace checks for CYG_MAX_PATH by checks for NT_MAX_PATH. (getfileattr): New function to replace GetFileAttributesA. (normalize_win32_path): Remove Win32 and NT long path prefixes. (getwd): Assume PATH_MAX + 1 buffer per SUSv3. * path.h (class path_conv): Set path buffer to size NT_MAX_PATH. (iswdrive): Define. * pinfo.cc (commune_process): Use temporary TLS path buffer instead of stack based buffer. * registry.cc (get_registry_hive_path): Ditto. (load_registry_hive): Ditto. * spawn.cc (spawn_guts): Convert to use CreateProcessW and CreateProcessAsUserW. (av::fixup): Open/close file using NtOpenFile/NtClose. * syscalls.cc (mknod_worker): Allow PATH_MAX file name. (mknod32): Ditto. (getusershell): Ditto. * tls_pbuf.cc: New file implementing tls_pathbuf and tmp_pathbuf methods. * tls_pbuf.h: New header for files using tmp_pathbuf. * tlsoffsets.h: Regenerate. * winsup.h (NT_MAX_PATH): Define as 32767 to avoid USHORT overflow.
2008-03-07 12:24:51 +01:00
#include "tls_pbuf.h"
#include "ntdll.h"
#include <wchar.h>
#include <alloca.h>
2000-02-17 20:38:33 +01:00
/* Opens a key under the appropriate Cygwin key.
Do not use HKCU per MS KB 199190 */
static NTSTATUS
top_key (bool isHKLM, REGSAM access, PHANDLE top)
2000-02-17 20:38:33 +01:00
{
WCHAR rbuf[PATH_MAX], *p;
UNICODE_STRING rpath;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
2000-02-17 20:38:33 +01:00
InitializeObjectAttributes (&attr, &rpath, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (isHKLM)
{
wcpcpy (rbuf, L"\\Registry\\Machine");
RtlInitUnicodeString (&rpath, rbuf);
status = NtOpenKey (top, access, &attr);
}
else
{
WCHAR name[128];
PCWSTR names[2] = {cygheap->user.get_windows_id (name),
L".DEFAULT"};
p = wcpcpy (rbuf, L"\\Registry\\User\\");
for (int i = 0; i < 2; i++)
{
wcpcpy (p, names[i]);
RtlInitUnicodeString (&rpath, rbuf);
status = NtOpenKey (top, access, &attr);
if (NT_SUCCESS (status))
break;
}
}
return status;
}
2005-02-13 19:17:29 +01:00
reg_key::reg_key (HKEY top, REGSAM access, ...): _disposition (0)
{
va_list av;
2000-02-17 20:38:33 +01:00
va_start (av, access);
build_reg (top, access, av);
2000-02-17 20:38:33 +01:00
va_end (av);
}
reg_key::reg_key (bool isHKLM, REGSAM access, ...): _disposition (0)
{
va_list av;
HANDLE top;
key_is_invalid = top_key (isHKLM, access, &top);
if (NT_SUCCESS (key_is_invalid))
{
new (this) reg_key ((HKEY) top, access, L"SOFTWARE",
_WIDE (CYGWIN_INFO_CYGWIN_REGISTRY_NAME), NULL);
NtClose (top);
if (key_is_invalid)
return;
top = key;
va_start (av, access);
build_reg ((HKEY) top, access, av);
va_end (av);
if (top != key)
NtClose (top);
}
2000-02-17 20:38:33 +01:00
}
void
reg_key::build_reg (HKEY top, REGSAM access, va_list av)
{
PWCHAR name;
HANDLE r;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
if (top != HKEY_LOCAL_MACHINE && top != HKEY_CURRENT_USER)
r = (HANDLE) top;
else if (!NT_SUCCESS (top_key (top == HKEY_LOCAL_MACHINE, access, &r)))
return;
key_is_invalid = 0;
while ((name = va_arg (av, PWCHAR)) != NULL)
2000-02-17 20:38:33 +01:00
{
RtlInitUnicodeString (&uname, name);
InitializeObjectAttributes (&attr, &uname,
OBJ_CASE_INSENSITIVE | OBJ_OPENIF, r, NULL);
status = NtCreateKey (&key, access, &attr, 0, NULL,
REG_OPTION_NON_VOLATILE, &_disposition);
if (r != (HANDLE) top)
NtClose (r);
2000-02-17 20:38:33 +01:00
r = key;
if (!NT_SUCCESS (status))
2000-02-17 20:38:33 +01:00
{
key_is_invalid = status;
debug_printf ("failed to create key %S in the registry", &uname);
2000-02-17 20:38:33 +01:00
break;
}
}
}
/* Given the current registry key, return the specific DWORD value
2000-02-17 20:38:33 +01:00
requested. Return def on failure. */
DWORD
reg_key::get_dword (PCWSTR name, DWORD def)
{
if (key_is_invalid)
return def;
NTSTATUS status;
UNICODE_STRING uname;
ULONG size = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + sizeof (DWORD);
ULONG rsize;
PKEY_VALUE_PARTIAL_INFORMATION vbuf = (PKEY_VALUE_PARTIAL_INFORMATION)
alloca (size);
RtlInitUnicodeString (&uname, name);
status = NtQueryValueKey (key, &uname, KeyValuePartialInformation, vbuf,
size, &rsize);
if (status != STATUS_SUCCESS || vbuf->Type != REG_DWORD)
2000-02-17 20:38:33 +01:00
return def;
DWORD *dst = (DWORD *) vbuf->Data;
return *dst;
2000-02-17 20:38:33 +01:00
}
/* Given the current registry key, set a specific DWORD value. */
2000-02-17 20:38:33 +01:00
NTSTATUS
reg_key::set_dword (PCWSTR name, DWORD val)
{
if (key_is_invalid)
return key_is_invalid;
DWORD value = (DWORD) val;
UNICODE_STRING uname;
RtlInitUnicodeString (&uname, name);
return NtSetValueKey (key, &uname, 0, REG_DWORD, &value, sizeof (value));
2000-02-17 20:38:33 +01:00
}
/* Given the current registry key, return the specific string value
requested. Return zero on success, non-zero on failure. */
NTSTATUS
reg_key::get_string (PCWSTR name, PWCHAR dst, size_t max, PCWSTR def)
2000-02-17 20:38:33 +01:00
{
NTSTATUS status;
if (key_is_invalid)
{
status = key_is_invalid;
if (def != NULL)
wcpncpy (dst, def, max);
}
else
{
UNICODE_STRING uname;
ULONG size = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + max * sizeof (WCHAR);
ULONG rsize;
PKEY_VALUE_PARTIAL_INFORMATION vbuf = (PKEY_VALUE_PARTIAL_INFORMATION)
alloca (size);
RtlInitUnicodeString (&uname, name);
status = NtQueryValueKey (key, &uname, KeyValuePartialInformation, vbuf,
size, &rsize);
if (status != STATUS_SUCCESS || vbuf->Type != REG_SZ)
wcpncpy (dst, def, max);
else
wcpncpy (dst, (PWCHAR) vbuf->Data, max);
}
return status;
}
2000-02-17 20:38:33 +01:00
/* Given the current registry key, set a specific string value. */
NTSTATUS
reg_key::set_string (PCWSTR name, PCWSTR src)
2000-02-17 20:38:33 +01:00
{
if (key_is_invalid)
return key_is_invalid;
2000-02-17 20:38:33 +01:00
UNICODE_STRING uname;
RtlInitUnicodeString (&uname, name);
return NtSetValueKey (key, &uname, 0, REG_SZ, (PVOID) src,
(wcslen (src) + 1) * sizeof (WCHAR));
}
2000-02-17 20:38:33 +01:00
reg_key::~reg_key ()
{
if (!key_is_invalid)
NtClose (key);
key_is_invalid = 1;
2000-02-17 20:38:33 +01:00
}
/* The buffer path points to should be at least MAX_PATH bytes. */
PWCHAR
get_registry_hive_path (PCWSTR name, PWCHAR path)
{
if (!name || !path)
return NULL;
WCHAR key[256];
UNICODE_STRING buf;
tmp_pathbuf tp;
tp.u_get (&buf);
NTSTATUS status;
RTL_QUERY_REGISTRY_TABLE tab[2] = {
{ NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED,
L"ProfileImagePath", &buf, REG_NONE, NULL, 0 },
{ NULL, 0, NULL, NULL, 0, NULL, 0 }
};
wcpcpy (wcpcpy (key, L"ProfileList\\"), name);
status = RtlQueryRegistryValues (RTL_REGISTRY_WINDOWS_NT, key, tab,
NULL, NULL);
if (!NT_SUCCESS (status) || buf.Length == 0)
{
2013-04-23 11:44:36 +02:00
debug_printf ("ProfileImagePath for %W not found, status %y", name,
status);
return NULL;
}
ExpandEnvironmentStringsW (buf.Buffer, path, MAX_PATH);
debug_printf ("ProfileImagePath for %W: %W", name, path);
return path;
}
void
load_registry_hive (PCWSTR name)
{
if (!name)
return;
/* Fetch the path. Prepend native NT path prefix. */
* Makefile.in (DLL_OFILES): Add tls_pbuf.o. * autoload.cc (CreateDesktopW): Replace CreateDesktopA. (CreateWindowStationW): Replace CreateWindowStationA. (GetUserObjectInformationW): Replace GetUserObjectInformationA. * cygheap.h (cwdstuff::get): Assume default buffer size NT_MAX_PATH. * cygtls.cc (_cygtls::remove): Free temporary TLS path buffers. * cygtls.h (TP_NUM_C_BUFS): Define. (TP_NUM_W_BUFS): Define. (class tls_pathbuf): New class to store pointers to thread local temporary path buffers. (_local_storage::pathbufs): New member. * environ.cc (win_env::add_cache): Use temporary TLS path buffer instead of stack based buffer. (posify): Get temporary outenv buffer from calling function. (environ_init): Create temporary TLS path buffer for posify. (build_env): Create Windows environment block as WCHAR buffer. * environ.h (build_env): Change declaration accordingly. * external.cc (sync_winenv): Accommodate build_env change. * fhandler_console.cc (fhandler_console::need_invisible): Use GetUserObjectInformationW and CreateWindowStationW. * fhandler_process.cc (format_process_maps): Use temporary TLS path buffer instead of stack based buffer. * fork.cc (frok::parent): Convert to use CreateProcessW. * path.cc: Throughout use temporary TLS path buffers instead of stack based buffer. Replace checks for CYG_MAX_PATH by checks for NT_MAX_PATH. (getfileattr): New function to replace GetFileAttributesA. (normalize_win32_path): Remove Win32 and NT long path prefixes. (getwd): Assume PATH_MAX + 1 buffer per SUSv3. * path.h (class path_conv): Set path buffer to size NT_MAX_PATH. (iswdrive): Define. * pinfo.cc (commune_process): Use temporary TLS path buffer instead of stack based buffer. * registry.cc (get_registry_hive_path): Ditto. (load_registry_hive): Ditto. * spawn.cc (spawn_guts): Convert to use CreateProcessW and CreateProcessAsUserW. (av::fixup): Open/close file using NtOpenFile/NtClose. * syscalls.cc (mknod_worker): Allow PATH_MAX file name. (mknod32): Ditto. (getusershell): Ditto. * tls_pbuf.cc: New file implementing tls_pathbuf and tmp_pathbuf methods. * tls_pbuf.h: New header for files using tmp_pathbuf. * tlsoffsets.h: Regenerate. * winsup.h (NT_MAX_PATH): Define as 32767 to avoid USHORT overflow.
2008-03-07 12:24:51 +01:00
tmp_pathbuf tp;
PWCHAR path = tp.w_get ();
if (!get_registry_hive_path (name, wcpcpy (path, L"\\??\\")))
return;
WCHAR key[256];
PWCHAR path_comp;
UNICODE_STRING ukey, upath;
OBJECT_ATTRIBUTES key_attr, path_attr;
NTSTATUS status;
/* Create keyname and path strings and object attributes. */
wcpcpy (wcpcpy (key, L"\\Registry\\User\\"), name);
RtlInitUnicodeString (&ukey, key);
InitializeObjectAttributes (&key_attr, &ukey, OBJ_CASE_INSENSITIVE,
NULL, NULL);
/* First try to load the "normal" registry hive, which is what the user
is supposed to see under HKEY_CURRENT_USER. */
path_comp = wcschr (path, L'\0');
wcpcpy (path_comp, L"\\ntuser.dat");
RtlInitUnicodeString (&upath, path);
InitializeObjectAttributes (&path_attr, &upath, OBJ_CASE_INSENSITIVE,
NULL, NULL);
status = NtLoadKey (&key_attr, &path_attr);
if (!NT_SUCCESS (status))
{
2013-04-23 11:44:36 +02:00
debug_printf ("Loading user registry hive %S into %S failed: %y",
&upath, &ukey, status);
return;
}
2013-04-23 11:44:36 +02:00
debug_printf ("Loading user registry hive %S into %S SUCCEEDED: %y",
&upath, &ukey, status);
/* If loading the normal hive worked, try to load the classes hive into
the sibling *_Classes subkey, which is what the user is supposed to
see under HKEY_CLASSES_ROOT, merged with the machine-wide classes. */
wcscat (key, L"_Classes");
RtlInitUnicodeString (&ukey, key);
/* Path to UsrClass.dat changed in Vista to
\\AppData\\Local\\Microsoft\\Windows\\UsrClass.dat
but old path is still available via symlinks. */
wcpcpy (path_comp, L"\\Local Settings\\Application Data\\Microsoft\\"
"Windows\\UsrClass.dat");
RtlInitUnicodeString (&upath, path);
/* Load UsrClass.dat file into key. */
status = NtLoadKey (&key_attr, &path_attr);
if (!NT_SUCCESS (status))
2013-04-23 11:44:36 +02:00
debug_printf ("Loading user classes hive %S into %S failed: %y",
&upath, &ukey, status);
else
2013-04-23 11:44:36 +02:00
debug_printf ("Loading user classes hive %S into %S SUCCEEDED: %y",
&upath, &ukey, status);
}