* 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.
This commit is contained in:
@@ -45,6 +45,7 @@ bool allow_ntsec;
|
||||
It's defined here because of it's strong relationship to allow_ntsec.
|
||||
The default is TRUE to reflect the old behaviour. */
|
||||
bool allow_smbntsec;
|
||||
bool allow_traverse;
|
||||
|
||||
cygsid *
|
||||
cygsidlist::alloc_sids (int n)
|
||||
@@ -593,36 +594,44 @@ get_setgroups_sidlist (cygsidlist &tmp_list, PTOKEN_GROUPS my_grps,
|
||||
tmp_list += pgpsid;
|
||||
}
|
||||
|
||||
static const char *sys_privs[] = {
|
||||
SE_TCB_NAME,
|
||||
SE_ASSIGNPRIMARYTOKEN_NAME,
|
||||
SE_CREATE_TOKEN_NAME,
|
||||
SE_CHANGE_NOTIFY_NAME,
|
||||
SE_SECURITY_NAME,
|
||||
SE_BACKUP_NAME,
|
||||
SE_RESTORE_NAME,
|
||||
SE_SYSTEMTIME_NAME,
|
||||
SE_SHUTDOWN_NAME,
|
||||
SE_REMOTE_SHUTDOWN_NAME,
|
||||
SE_TAKE_OWNERSHIP_NAME,
|
||||
SE_DEBUG_NAME,
|
||||
SE_SYSTEM_ENVIRONMENT_NAME,
|
||||
SE_SYSTEM_PROFILE_NAME,
|
||||
SE_PROF_SINGLE_PROCESS_NAME,
|
||||
SE_INC_BASE_PRIORITY_NAME,
|
||||
SE_LOAD_DRIVER_NAME,
|
||||
SE_CREATE_PAGEFILE_NAME,
|
||||
SE_INCREASE_QUOTA_NAME
|
||||
static const cygpriv_idx sys_privs[] = {
|
||||
SE_TCB_PRIV,
|
||||
SE_ASSIGNPRIMARYTOKEN_PRIV,
|
||||
SE_CREATE_TOKEN_PRIV,
|
||||
SE_CHANGE_NOTIFY_PRIV,
|
||||
SE_SECURITY_PRIV,
|
||||
SE_BACKUP_PRIV,
|
||||
SE_RESTORE_PRIV,
|
||||
SE_SYSTEMTIME_PRIV,
|
||||
SE_SHUTDOWN_PRIV,
|
||||
SE_REMOTE_SHUTDOWN_PRIV,
|
||||
SE_TAKE_OWNERSHIP_PRIV,
|
||||
SE_DEBUG_PRIV,
|
||||
SE_SYSTEM_ENVIRONMENT_PRIV,
|
||||
SE_SYSTEM_PROFILE_PRIV,
|
||||
SE_PROF_SINGLE_PROCESS_PRIV,
|
||||
SE_INC_BASE_PRIORITY_PRIV,
|
||||
SE_LOAD_DRIVER_PRIV,
|
||||
SE_CREATE_PAGEFILE_PRIV,
|
||||
SE_INCREASE_QUOTA_PRIV,
|
||||
SE_LOCK_MEMORY_PRIV,
|
||||
SE_CREATE_PERMANENT_PRIV,
|
||||
SE_AUDIT_PRIV,
|
||||
SE_UNDOCK_PRIV,
|
||||
SE_MANAGE_VOLUME_PRIV,
|
||||
SE_IMPERSONATE_PRIV,
|
||||
SE_CREATE_GLOBAL_PRIV
|
||||
};
|
||||
|
||||
#define SYSTEM_PERMISSION_COUNT (sizeof sys_privs / sizeof (const char *))
|
||||
#define SYSTEM_PRIVILEGES_COUNT (sizeof sys_privs / sizeof *sys_privs)
|
||||
|
||||
PTOKEN_PRIVILEGES
|
||||
get_system_priv_list (cygsidlist &grp_list)
|
||||
{
|
||||
LUID priv;
|
||||
const LUID *priv;
|
||||
PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES)
|
||||
malloc (sizeof (ULONG) + 20 * sizeof (LUID_AND_ATTRIBUTES));
|
||||
malloc (sizeof (ULONG)
|
||||
+ SYSTEM_PRIVILEGES_COUNT * sizeof (LUID_AND_ATTRIBUTES));
|
||||
if (!privs)
|
||||
{
|
||||
debug_printf ("malloc (system_privs) failed.");
|
||||
@@ -630,10 +639,10 @@ get_system_priv_list (cygsidlist &grp_list)
|
||||
}
|
||||
privs->PrivilegeCount = 0;
|
||||
|
||||
for (DWORD i = 0; i < SYSTEM_PERMISSION_COUNT; ++i)
|
||||
if (LookupPrivilegeValue (NULL, sys_privs[i], &priv))
|
||||
for (DWORD i = 0; i < SYSTEM_PRIVILEGES_COUNT; ++i)
|
||||
if ((priv = privilege_luid (sys_privs[i])))
|
||||
{
|
||||
privs->Privileges[privs->PrivilegeCount].Luid = priv;
|
||||
privs->Privileges[privs->PrivilegeCount].Luid = *priv;
|
||||
privs->Privileges[privs->PrivilegeCount].Attributes =
|
||||
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
|
||||
++privs->PrivilegeCount;
|
||||
@@ -667,17 +676,23 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
|
||||
continue;
|
||||
for (ULONG i = 0; i < cnt; ++i)
|
||||
{
|
||||
LUID priv;
|
||||
const LUID *priv;
|
||||
PTOKEN_PRIVILEGES tmp;
|
||||
DWORD tmp_count;
|
||||
|
||||
lsa2str (buf, privstrs[i], sizeof (buf) - 1);
|
||||
if (!LookupPrivilegeValue (NULL, buf, &priv))
|
||||
if (!(priv = privilege_luid_by_name (buf)))
|
||||
continue;
|
||||
|
||||
for (DWORD p = 0; privs && p < privs->PrivilegeCount; ++p)
|
||||
if (!memcmp (&priv, &privs->Privileges[p].Luid, sizeof (LUID)))
|
||||
goto next_account_right;
|
||||
if (privs)
|
||||
{
|
||||
DWORD pcnt = privs->PrivilegeCount;
|
||||
LUID_AND_ATTRIBUTES *p = privs->Privileges;
|
||||
for (; pcnt > 0; --pcnt, ++p)
|
||||
if (priv->HighPart == p->Luid.HighPart
|
||||
&& priv->LowPart == p->Luid.LowPart)
|
||||
goto next_account_right;
|
||||
}
|
||||
|
||||
tmp_count = privs ? privs->PrivilegeCount : 0;
|
||||
tmp = (PTOKEN_PRIVILEGES)
|
||||
@@ -693,7 +708,7 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
|
||||
}
|
||||
tmp->PrivilegeCount = tmp_count;
|
||||
privs = tmp;
|
||||
privs->Privileges[privs->PrivilegeCount].Luid = priv;
|
||||
privs->Privileges[privs->PrivilegeCount].Luid = *priv;
|
||||
privs->Privileges[privs->PrivilegeCount].Attributes =
|
||||
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
|
||||
++privs->PrivilegeCount;
|
||||
@@ -812,16 +827,13 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
|
||||
{
|
||||
NTSTATUS ret;
|
||||
LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
|
||||
int old_priv_state;
|
||||
|
||||
cygsidlist tmp_gsids (cygsidlist_auto, 12);
|
||||
|
||||
SECURITY_QUALITY_OF_SERVICE sqos =
|
||||
{ sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
|
||||
OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos };
|
||||
PSECURITY_ATTRIBUTES psa;
|
||||
bool special_pgrp = false;
|
||||
char sa_buf[1024];
|
||||
LUID auth_luid = SYSTEM_LUID;
|
||||
LARGE_INTEGER exp = { QuadPart:INT64_MAX };
|
||||
|
||||
@@ -840,13 +852,11 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
|
||||
HANDLE token = INVALID_HANDLE_VALUE;
|
||||
HANDLE primary_token = INVALID_HANDLE_VALUE;
|
||||
|
||||
HANDLE my_token = INVALID_HANDLE_VALUE;
|
||||
PTOKEN_GROUPS my_tok_gsids = NULL;
|
||||
DWORD size;
|
||||
|
||||
/* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
|
||||
if ((old_priv_state = set_process_privilege (SE_CREATE_TOKEN_NAME)) < 0)
|
||||
goto out;
|
||||
push_self_privilege (SE_CREATE_TOKEN_PRIV, true);
|
||||
|
||||
/* Open policy object. */
|
||||
if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
|
||||
@@ -858,35 +868,32 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
|
||||
owner.Owner = usersid;
|
||||
|
||||
/* Retrieve authentication id and group list from own process. */
|
||||
if (!OpenProcessToken (hMainProc, TOKEN_QUERY, &my_token))
|
||||
debug_printf ("OpenProcessToken(my_token), %E");
|
||||
else
|
||||
if (hProcToken)
|
||||
{
|
||||
/* Switching user context to SYSTEM doesn't inherit the authentication
|
||||
id of the user account running current process. */
|
||||
if (usersid != well_known_system_sid)
|
||||
if (!GetTokenInformation (my_token, TokenStatistics,
|
||||
if (!GetTokenInformation (hProcToken, TokenStatistics,
|
||||
&stats, sizeof stats, &size))
|
||||
debug_printf
|
||||
("GetTokenInformation(my_token, TokenStatistics), %E");
|
||||
("GetTokenInformation(hProcToken, TokenStatistics), %E");
|
||||
else
|
||||
auth_luid = stats.AuthenticationId;
|
||||
|
||||
/* Retrieving current processes group list to be able to inherit
|
||||
some important well known group sids. */
|
||||
if (!GetTokenInformation (my_token, TokenGroups, NULL, 0, &size) &&
|
||||
if (!GetTokenInformation (hProcToken, TokenGroups, NULL, 0, &size) &&
|
||||
GetLastError () != ERROR_INSUFFICIENT_BUFFER)
|
||||
debug_printf ("GetTokenInformation(my_token, TokenGroups), %E");
|
||||
debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
|
||||
else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
|
||||
debug_printf ("malloc (my_tok_gsids) failed.");
|
||||
else if (!GetTokenInformation (my_token, TokenGroups, my_tok_gsids,
|
||||
else if (!GetTokenInformation (hProcToken, TokenGroups, my_tok_gsids,
|
||||
size, &size))
|
||||
{
|
||||
debug_printf ("GetTokenInformation(my_token, TokenGroups), %E");
|
||||
debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
|
||||
free (my_tok_gsids);
|
||||
my_tok_gsids = NULL;
|
||||
}
|
||||
CloseHandle (my_token);
|
||||
}
|
||||
|
||||
/* Create list of groups, the user is member in. */
|
||||
@@ -932,18 +939,10 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set security descriptor and primary group */
|
||||
psa = sec_user (sa_buf, usersid);
|
||||
if (psa->lpSecurityDescriptor &&
|
||||
!SetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR)
|
||||
psa->lpSecurityDescriptor,
|
||||
special_pgrp ? new_groups.pgsid
|
||||
: well_known_null_sid,
|
||||
FALSE))
|
||||
debug_printf ("SetSecurityDescriptorGroup %E");
|
||||
/* Convert to primary token. */
|
||||
if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa, SecurityImpersonation,
|
||||
TokenPrimary, &primary_token))
|
||||
if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, &sec_none,
|
||||
SecurityImpersonation, TokenPrimary,
|
||||
&primary_token))
|
||||
{
|
||||
__seterrno ();
|
||||
debug_printf ("DuplicateTokenEx %E");
|
||||
@@ -951,8 +950,7 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
|
||||
}
|
||||
|
||||
out:
|
||||
if (old_priv_state >= 0)
|
||||
set_process_privilege (SE_CREATE_TOKEN_NAME, old_priv_state);
|
||||
pop_self_privilege ();
|
||||
if (token != INVALID_HANDLE_VALUE)
|
||||
CloseHandle (token);
|
||||
if (privs)
|
||||
@@ -993,13 +991,10 @@ subauth (struct passwd *pw)
|
||||
QUOTA_LIMITS quota;
|
||||
char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
|
||||
char nt_user[UNLEN + 1];
|
||||
SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE };
|
||||
HANDLE user_token = INVALID_HANDLE_VALUE;
|
||||
HANDLE primary_token = INVALID_HANDLE_VALUE;
|
||||
int old_tcb_state;
|
||||
|
||||
if ((old_tcb_state = set_process_privilege (SE_TCB_NAME)) < 0)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
push_self_privilege (SE_TCB_PRIV, true);
|
||||
|
||||
/* Register as logon process. */
|
||||
str2lsa (name, "Cygwin");
|
||||
@@ -1057,12 +1052,12 @@ subauth (struct passwd *pw)
|
||||
}
|
||||
LsaFreeReturnBuffer (profile);
|
||||
/* Convert to primary token. */
|
||||
if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa,
|
||||
if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sec_none,
|
||||
SecurityImpersonation, TokenPrimary, &primary_token))
|
||||
__seterrno ();
|
||||
|
||||
out:
|
||||
set_process_privilege (SE_TCB_NAME, old_tcb_state);
|
||||
pop_self_privilege ();
|
||||
if (user_token != INVALID_HANDLE_VALUE)
|
||||
CloseHandle (user_token);
|
||||
return primary_token;
|
||||
@@ -1832,7 +1827,7 @@ check_file_access (const char *fn, int flags)
|
||||
|
||||
security_descriptor sd;
|
||||
|
||||
HANDLE hToken, hIToken;
|
||||
HANDLE hToken;
|
||||
BOOL status;
|
||||
char pbuf[sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES)];
|
||||
DWORD desired = 0, granted, plength = sizeof pbuf;
|
||||
@@ -1845,17 +1840,8 @@ check_file_access (const char *fn, int flags)
|
||||
|
||||
if (cygheap->user.issetuid ())
|
||||
hToken = cygheap->user.token ();
|
||||
else if (!OpenProcessToken (hMainProc, TOKEN_DUPLICATE, &hToken))
|
||||
{
|
||||
__seterrno ();
|
||||
goto done;
|
||||
}
|
||||
if (!(status = DuplicateToken (hToken, SecurityIdentification, &hIToken)))
|
||||
__seterrno ();
|
||||
if (!cygheap->user.issetuid ())
|
||||
CloseHandle (hToken);
|
||||
if (!status)
|
||||
goto done;
|
||||
else
|
||||
hToken = hProcImpToken;
|
||||
|
||||
if (flags & R_OK)
|
||||
desired |= FILE_READ_DATA;
|
||||
@@ -1863,14 +1849,13 @@ check_file_access (const char *fn, int flags)
|
||||
desired |= FILE_WRITE_DATA;
|
||||
if (flags & X_OK)
|
||||
desired |= FILE_EXECUTE;
|
||||
if (!AccessCheck (sd, hIToken, desired, &mapping,
|
||||
if (!AccessCheck (sd, hToken, desired, &mapping,
|
||||
(PPRIVILEGE_SET) pbuf, &plength, &granted, &status))
|
||||
__seterrno ();
|
||||
else if (!status)
|
||||
set_errno (EACCES);
|
||||
else
|
||||
ret = 0;
|
||||
CloseHandle (hIToken);
|
||||
done:
|
||||
debug_printf ("flags %x, ret %d", flags, ret);
|
||||
return ret;
|
||||
|
Reference in New Issue
Block a user