RLIMIT_STACK. * registry.cc (get_registry_hive_path): Expect the user hive path to be never longer than MAX_PATH. Don't prepend native NT path prefix here. Add comment. (load_registry_hive): Prepend native NT path prefix here. Additionally try to load user's classes hive. * uinfo.cc (cygheap_user::env_userprofile): Reduce size of userprofile_env_buf to MAX_PATH. Add comment.
		
			
				
	
	
		
			309 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* 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.
 | 
						|
 | 
						|
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"
 | 
						|
#include "tls_pbuf.h"
 | 
						|
#include "ntdll.h"
 | 
						|
#include <wchar.h>
 | 
						|
#include <alloca.h>
 | 
						|
 | 
						|
/* 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)
 | 
						|
{
 | 
						|
  WCHAR rbuf[PATH_MAX], *p;
 | 
						|
  UNICODE_STRING rpath;
 | 
						|
  OBJECT_ATTRIBUTES attr;
 | 
						|
  NTSTATUS status;
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
reg_key::reg_key (HKEY top, REGSAM access, ...): _disposition (0)
 | 
						|
{
 | 
						|
  va_list av;
 | 
						|
  va_start (av, access);
 | 
						|
  build_reg (top, access, av);
 | 
						|
  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);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
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)
 | 
						|
    {
 | 
						|
      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);
 | 
						|
      r = key;
 | 
						|
      if (!NT_SUCCESS (status))
 | 
						|
	{
 | 
						|
	  key_is_invalid = status;
 | 
						|
	  debug_printf ("failed to create key %S in the registry", uname);
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Given the current registry key, return the specific DWORD value
 | 
						|
   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)
 | 
						|
    return def;
 | 
						|
  DWORD *dst = (DWORD *) vbuf->Data;
 | 
						|
  return *dst;
 | 
						|
}
 | 
						|
 | 
						|
/* Given the current registry key, set a specific DWORD value. */
 | 
						|
 | 
						|
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));
 | 
						|
}
 | 
						|
 | 
						|
/* 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)
 | 
						|
{
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/* Given the current registry key, set a specific string value. */
 | 
						|
 | 
						|
NTSTATUS
 | 
						|
reg_key::set_string (PCWSTR name, PCWSTR src)
 | 
						|
{
 | 
						|
  if (key_is_invalid)
 | 
						|
    return key_is_invalid;
 | 
						|
 | 
						|
  UNICODE_STRING uname;
 | 
						|
  RtlInitUnicodeString (&uname, name);
 | 
						|
  return NtSetValueKey (key, &uname, 0, REG_SZ, (PVOID) src,
 | 
						|
			(wcslen (src) + 1) * sizeof (WCHAR));
 | 
						|
}
 | 
						|
 | 
						|
reg_key::~reg_key ()
 | 
						|
{
 | 
						|
  if (!key_is_invalid)
 | 
						|
    NtClose (key);
 | 
						|
  key_is_invalid = 1;
 | 
						|
}
 | 
						|
 | 
						|
/* 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)
 | 
						|
    {
 | 
						|
      debug_printf ("ProfileImagePath for %W not found, status %p", 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. */
 | 
						|
  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))
 | 
						|
    {
 | 
						|
      debug_printf ("Loading user registry hive %S into %S failed: %p",
 | 
						|
		    &upath, &ukey, status);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  debug_printf ("Loading user registry hive %S into %S SUCCEEDED: %p",
 | 
						|
		&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))
 | 
						|
    debug_printf ("Loading user classes hive %S into %S failed: %p",
 | 
						|
		  &upath, &ukey, status);
 | 
						|
  else
 | 
						|
    debug_printf ("Loading user classes hive %S into %S SUCCEEDED: %p",
 | 
						|
		  &upath, &ukey, status);
 | 
						|
}
 |