newlib/winsup/cygwin/registry.cc
Corinna Vinschen f4a1f8a1db * cygheap.cc (cygheap_init): Accomodate set_process_privilege change.
* cygheap.h (cygheap_user::curr_primary_token): New member.
	(cygheap_user::primary_token): New method.
	(cygheap_user::deimpersonate): Always revert to processes'
	impersonation token.
	(cygheap_user::reimpersonate): Set processes' or setuid token as
	necessary.
	(cygheap_user::has_impersonation_tokens): Look for curr_primary_token
	value.
	(cygheap_user::close_impersonation_tokens): Close curr_primary_token
	here if necessary.  Don't reset token values to NO_IMPERSONATION since
	that's done in uinfo_init anyway.
	(init_cygheap::luid): New LUID array keeping privilege LUIDs.
	* cygtls.cc (_cygtls::init_thread): Call cygheap->user.reimpersonate.
	* dcrt0.cc (hProcToken): New global variable to keep process token.
	(hProcImpToken): Ditto for process impersonation token.
	(dll_crt0_0): Open process token here once.  Duplicate to create
	hProcImpToken.
	(dll_crt0_1): Call set_cygwin_privileges.
	* environ.cc (allow_ntea): Drop duplicate declaration.
	(allow_smbntsec): Ditto.
	(set_traverse): Only set allow_traverse here.
	(environ_init): Ditto.
	* fhandler_disk_file.cc (fhandler_disk_file::fchmod): Drop call to
	enable_restore_privilege.
	(fhandler_disk_file::fchown): Ditto.
	(fhandler_disk_file::facl): Ditto.
	* fork.cc (fork_child): Move call to cygheap->user.reimpersonate after
	syn with parent. Call set_cygwin_privileges.
	* grp.cc (internal_getgroups): Use hProcImpToken instead of opening
	process token.
	* path.cc (fs_info::update): Bypass traverse checking when retrieving
	volume information using push/pop_thread_privileges.
	* registry.cc (load_registry_hive): Drop setting restore privilege
	since it's already set if available.
	* sec_helper.cc: Include cygtls.h.
	(cygpriv): Privilege string array.
	(privilege_luid): New function, evaluate LUID from cygpriv_idx.
	(privilege_luid_by_name): New function, evaluate LUID from privilege
	string.
	(privilege_name): New function, evaluate privilege string from
	cygpriv_idx.
	(set_privilege): New static function called by set_process_privilege
	and set_thread_privilege.  Call privilege_luid to get privilege LUID.
	Fix bug in return value evaluation. Improve debug output.
	(set_cygwin_privileges): New function.
	(set_process_privilege): Remove.
	(enable_restore_privilege): Remove.
	* security.cc (allow_traverse): New global variable.
	(sys_privs): Change type to cygpriv_idx and store privilege indices
	instead of strings.
	(SYSTEM_PRIVILEGES_COUNT): Renamed from SYSTEM_PERMISSION_COUNT.
	(get_system_priv_list): Don't use numerical constant in malloc call.
	Use privilege_luid to get privilege LUIDs.
	(get_priv_list): Call privilege_luid_by_name to get LUIDs. Improve
	inner privilege LUID comparison loop.
	(create_token): Enable create token privilege using
	push/pop_self_privileges. Use hProcToken instead of opening process
	token. Use default DACL when duplicating token.
	(subauth): Enable tcb privilege using push/pop_self_privileges.
	Use sec_none instead of homw made security attributes when duplicating
	token.
	(check_file_access): Don't duplicate access token, use active
	impersonation token as is.
	* security.h (enum cygpriv_idx): New enumeration type enumerating
	possible privileges.
	(privilege_luid): Declare new function.
	(privilege_luid_by_name): Ditto.
	(privilege_name): Ditto.
	(allow_traverse): Declare.
	(set_privilege): Declare function.
	(set_process_privilege): Define as macro.
	(enable_restore_privilege): Remove declaration.
	(_push_thread_privilege): Define macro.
	(push_thread_privilege): Ditto.
	(pop_thread_privilege): Ditto.
	(pop_self_privilege): Ditto.
	* spawn.cc (spawn_guts): Use cygheap->user.primary_token instead of
	cygheap->user.token.
	* syscalls.cc (statvfs): Bypass traverse checking when retrieving
	volume information using push/pop_thread_privileges. Rearrange code
	to simplify push/pop bracketing.
	(seteuid32): Use hProcToken instead of opening process token. Call
	cygheap->user.deimpersonate instead of RevertToSelf.  Create
	impersonation token from primary internal or external token.  Set
	cygheap->user.curr_primary_token and cygheap->user.current_token
	privileges once here.  Drop "failed" and "failed_ptok" labels.
	Drop setting DefaultDacl of process token.
	(setegid32): Use hProcToken and hProcImpToken instead of opening
	process token. Always reimpersonate afterwards.
	* uinfo.cc (cygheap_user::init): Use hProcToken instead of opening
	process token.
	(internal_getlogin): Ditto. Set hProcImpToken, too.
	(uinfo_init): Initialize cygheap->user.curr_primary_token.
	* winsup.h (hProcToken): Declare.
	(hProcImpToken): Declare.
2005-04-03 13:06:43 +00:00

265 lines
5.9 KiB
C++

/* registry.cc: registry interface
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005 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 "shared_info.h"
#include "registry.h"
#include "security.h"
#include <cygwin/version.h>
#include "cygerrno.h"
#include "path.h"
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
static const char cygnus_class[] = "cygnus";
reg_key::reg_key (HKEY top, REGSAM access, ...)
{
va_list av;
va_start (av, access);
build_reg (top, access, av);
va_end (av);
}
/* Opens a key under the appropriate Cygwin key.
Do not use HKCU per MS KB 199190 */
reg_key::reg_key (bool isHKLM, REGSAM access, ...)
{
va_list av;
HKEY top;
if (isHKLM)
top = HKEY_LOCAL_MACHINE;
else
{
char name[128];
const char *names[2] = {cygheap->user.get_windows_id (name), ".DEFAULT"};
for (int i = 0; i < 2; i++)
{
key_is_invalid = RegOpenKeyEx (HKEY_USERS, names[i], 0, access, &top);
if (key_is_invalid == ERROR_SUCCESS)
goto OK;
debug_printf ("HKU\\%s failed, Win32 error %ld", names[i], key_is_invalid);
}
return;
}
OK:
new (this) reg_key (top, access, "SOFTWARE",
CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
CYGWIN_INFO_CYGWIN_REGISTRY_NAME, NULL);
if (top != HKEY_LOCAL_MACHINE)
RegCloseKey (top);
if (key_is_invalid)
return;
top = key;
va_start (av, access);
build_reg (top, access, av);
va_end (av);
if (top != key)
RegCloseKey (top);
}
void
reg_key::build_reg (HKEY top, REGSAM access, va_list av)
{
char *name;
HKEY r = top;
key_is_invalid = 0;
/* FIXME: Most of the time a valid mount area should exist. Perhaps
we should just try an open of the correct key first and only resort
to this method in the unlikely situation that it's the first time
the current mount areas are being used. */
while ((name = va_arg (av, char *)) != NULL)
{
int res = RegCreateKeyExA (r,
name,
0,
(char *) cygnus_class,
REG_OPTION_NON_VOLATILE,
access,
&sec_none_nih,
&key,
NULL);
if (r != top)
RegCloseKey (r);
r = key;
if (res != ERROR_SUCCESS)
{
key_is_invalid = res;
debug_printf ("failed to create key %s in the registry", name);
break;
}
}
}
/* Given the current registry key, return the specific int value
requested. Return def on failure. */
int
reg_key::get_int (const char *name, int def)
{
DWORD type;
DWORD dst;
DWORD size = sizeof (dst);
if (key_is_invalid)
return def;
LONG res = RegQueryValueExA (key, name, 0, &type, (unsigned char *) &dst,
&size);
if (type != REG_DWORD || res != ERROR_SUCCESS)
return def;
return dst;
}
/* Given the current registry key, set a specific int value. */
int
reg_key::set_int (const char *name, int val)
{
DWORD value = val;
if (key_is_invalid)
return key_is_invalid;
return (int) RegSetValueExA (key, name, 0, REG_DWORD,
(unsigned char *) &value, sizeof (value));
}
/* Given the current registry key, return the specific string value
requested. Return zero on success, non-zero on failure. */
int
reg_key::get_string (const char *name, char *dst, size_t max, const char * def)
{
DWORD size = max;
DWORD type;
LONG res;
if (key_is_invalid)
res = key_is_invalid;
else
res = RegQueryValueExA (key, name, 0, &type, (unsigned char *) dst, &size);
if ((def != 0) && ((type != REG_SZ) || (res != ERROR_SUCCESS)))
strcpy (dst, def);
return (int) res;
}
/* Given the current registry key, set a specific string value. */
int
reg_key::set_string (const char *name, const char *src)
{
if (key_is_invalid)
return key_is_invalid;
return (int) RegSetValueExA (key, name, 0, REG_SZ, (unsigned char*) src,
strlen (src) + 1);
}
/* Return the handle to key. */
HKEY
reg_key::get_key ()
{
return key;
}
/* Delete subkey of current key. Returns the error code from the
RegDeleteKeyA invocation. */
int
reg_key::kill (const char *name)
{
if (key_is_invalid)
return key_is_invalid;
return RegDeleteKeyA (key, name);
}
/* Delete the value specified by name of current key. Returns the error code
from the RegDeleteValueA invocation. */
int
reg_key::killvalue (const char *name)
{
if (key_is_invalid)
return key_is_invalid;
return RegDeleteValueA (key, name);
}
reg_key::~reg_key ()
{
if (!key_is_invalid)
RegCloseKey (key);
key_is_invalid = 1;
}
char *
get_registry_hive_path (const char *name, char *path)
{
char key[256];
HKEY hkey;
if (!name || !path)
return NULL;
__small_sprintf (key, "SOFTWARE\\Microsoft\\Windows%s\\CurrentVersion\\ProfileList\\",
wincap.is_winnt ()?" NT":"");
strcat (key, name);
if (!RegOpenKeyExA (HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hkey))
{
char buf[256];
DWORD type, siz;
path[0] = '\0';
if (!RegQueryValueExA (hkey, "ProfileImagePath", 0, &type,
(BYTE *)buf, (siz = sizeof (buf), &siz)))
ExpandEnvironmentStringsA (buf, path, CYG_MAX_PATH);
RegCloseKey (hkey);
if (path[0])
return path;
}
debug_printf ("HKLM\\%s not found", key);
return NULL;
}
void
load_registry_hive (const char * name)
{
char path[CYG_MAX_PATH];
HKEY hkey;
LONG ret;
if (!name)
return;
/* Check if user hive is already loaded. */
if (!RegOpenKeyExA (HKEY_USERS, name, 0, KEY_READ, &hkey))
{
debug_printf ("User registry hive for %s already exists", name);
RegCloseKey (hkey);
return;
}
if (get_registry_hive_path (name, path))
{
if (wincap.is_winnt ())
strcat (path, "\\NTUSER.DAT");
else
strcat (path, "\\USER.DAT");
if ((ret = RegLoadKeyA (HKEY_USERS, name, path)) != ERROR_SUCCESS)
debug_printf ("Loading user registry hive for %s failed: %d", name, ret);
}
}