f4a1f8a1db
* 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.
265 lines
5.9 KiB
C++
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);
|
|
}
|
|
}
|
|
|