Cygwin: drop create_token and dependent functions

Given we only called create_token on W7 WOW64 anyway, we can now
drop this function and all other functions only called from there
entirely.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2022-03-07 11:29:42 +01:00
parent 23b5466aed
commit 7bed18558d
4 changed files with 9 additions and 392 deletions

View File

@ -379,41 +379,6 @@ sid_in_token_groups (PTOKEN_GROUPS grps, cygpsid sid)
return false; return false;
} }
static void
get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps)
{
if (my_grps)
{
grp_list += well_known_local_sid;
grp_list += well_known_console_logon_sid;
if (sid_in_token_groups (my_grps, well_known_dialup_sid))
grp_list *= well_known_dialup_sid;
if (sid_in_token_groups (my_grps, well_known_network_sid))
grp_list *= well_known_network_sid;
if (sid_in_token_groups (my_grps, well_known_batch_sid))
grp_list *= well_known_batch_sid;
grp_list *= well_known_interactive_sid;
#if 0
/* Don't add the SERVICE group when switching the user context.
That's much too dangerous, since the service group adds the
SE_IMPERSONATE_NAME privilege to the user. After all, the
process started with this token is not the service process
anymore anyway. */
if (sid_in_token_groups (my_grps, well_known_service_sid))
grp_list *= well_known_service_sid;
#endif
if (sid_in_token_groups (my_grps, well_known_this_org_sid))
grp_list *= well_known_this_org_sid;
grp_list *= well_known_users_sid;
}
else
{
grp_list += well_known_local_sid;
grp_list *= well_known_interactive_sid;
grp_list *= well_known_users_sid;
}
}
bool bool
get_server_groups (cygsidlist &grp_list, PSID usersid, get_server_groups (cygsidlist &grp_list, PSID usersid,
acct_disabled_chk_t check_account_disabled) acct_disabled_chk_t check_account_disabled)
@ -470,180 +435,6 @@ get_server_groups (cygsidlist &grp_list, PSID usersid,
return true; return true;
} }
static bool
get_initgroups_sidlist (cygsidlist &grp_list, PSID usersid, PSID pgrpsid,
PTOKEN_GROUPS my_grps)
{
if (well_known_system_sid != usersid)
get_token_group_sidlist (grp_list, my_grps);
if (!get_server_groups (grp_list, usersid, CHK_DISABLED))
return false;
/* special_pgrp true if pgrpsid is not in normal groups */
grp_list += pgrpsid;
return true;
}
static bool
get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid,
PTOKEN_GROUPS my_grps, user_groups &groups)
{
get_token_group_sidlist (tmp_list, my_grps);
if (!get_server_groups (tmp_list, usersid, CHK_DISABLED))
return false;
for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
tmp_list += groups.sgsids.sids[gidx];
tmp_list += groups.pgsid;
return true;
}
/* Fixed size TOKEN_PRIVILEGES list to reflect privileges given to the
SYSTEM account by default. */
const struct
{
DWORD PrivilegeCount;
LUID_AND_ATTRIBUTES Privileges[28];
} sys_privs =
{
28,
{
{ { SE_CREATE_TOKEN_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_LOCK_MEMORY_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_INCREASE_QUOTA_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_TCB_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_SECURITY_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_TAKE_OWNERSHIP_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_LOAD_DRIVER_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_SYSTEM_PROFILE_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_SYSTEMTIME_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_PROF_SINGLE_PROCESS_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_INC_BASE_PRIORITY_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_CREATE_PAGEFILE_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_CREATE_PERMANENT_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_BACKUP_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_RESTORE_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_SHUTDOWN_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_DEBUG_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_AUDIT_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_SYSTEM_ENVIRONMENT_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_CHANGE_NOTIFY_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_UNDOCK_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_MANAGE_VOLUME_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_IMPERSONATE_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_CREATE_GLOBAL_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_INCREASE_WORKING_SET_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_TIME_ZONE_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_CREATE_SYMBOLIC_LINK_PRIVILEGE, 0 },
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT }
}
};
static PTOKEN_PRIVILEGES
get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list,
size_t &size, cygpsid *mandatory_integrity_sid)
{
PLSA_UNICODE_STRING privstrs;
ULONG cnt;
PTOKEN_PRIVILEGES privs = NULL;
if (usersid == well_known_system_sid)
{
if (mandatory_integrity_sid)
*mandatory_integrity_sid = mandatory_system_integrity_sid;
return (PTOKEN_PRIVILEGES) &sys_privs;
}
if (mandatory_integrity_sid)
*mandatory_integrity_sid = mandatory_medium_integrity_sid;
for (int grp = -1; grp < grp_list.count (); ++grp)
{
if (grp == -1)
{
if (LsaEnumerateAccountRights (lsa, usersid, &privstrs, &cnt)
!= STATUS_SUCCESS)
continue;
}
else if (LsaEnumerateAccountRights (lsa, grp_list.sids[grp],
&privstrs, &cnt) != STATUS_SUCCESS)
continue;
for (ULONG i = 0; i < cnt; ++i)
{
LUID priv;
PTOKEN_PRIVILEGES tmp;
DWORD tmp_count;
bool high_integrity;
if (!privilege_luid (privstrs[i].Buffer, priv, high_integrity))
continue;
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;
size = sizeof (DWORD)
+ (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES);
tmp = (PTOKEN_PRIVILEGES) realloc (privs, size);
if (!tmp)
{
if (privs)
free (privs);
LsaFreeMemory (privstrs);
debug_printf ("realloc (privs) failed.");
return NULL;
}
tmp->PrivilegeCount = tmp_count;
privs = tmp;
privs->Privileges[privs->PrivilegeCount].Luid = priv;
privs->Privileges[privs->PrivilegeCount].Attributes =
SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
++privs->PrivilegeCount;
if (mandatory_integrity_sid && high_integrity)
*mandatory_integrity_sid = mandatory_high_integrity_sid;
next_account_right:
;
}
LsaFreeMemory (privstrs);
}
return privs;
}
/* Accept a token if /* Accept a token if
- the requested usersid matches the TokenUser and - the requested usersid matches the TokenUser and
- if setgroups has been called: - if setgroups has been called:
@ -654,9 +445,8 @@ get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list,
they match and verify only the primary groups. they match and verify only the primary groups.
The requested primary group must appear in the token. The requested primary group must appear in the token.
The primary group in the token is a group associated with the usersid, The primary group in the token is a group associated with the usersid,
except if the token is internal and the group is in the token SD except if the token is internal and the group is in the token SD. In
(see create_token). In that latter case that group must match the that latter case that group must match the requested primary group. */
requested primary group. */
bool bool
verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern) verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
{ {
@ -786,160 +576,6 @@ account_restriction (NTSTATUS status)
return type; return type;
} }
HANDLE
create_token (cygsid &usersid, user_groups &new_groups)
{
NTSTATUS status;
LSA_HANDLE lsa = NULL;
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 };
/* Up to Windows 7, when using an authentication LUID other than "Anonymous",
Windows whoami prints the wrong username, the one from the login session,
not the one from the actual user token of the process. This is apparently
fixed in Windows 8. However, starting with Windows 8, access rights of
the anonymous logon session is further restricted. Therefore we create
the new user token with the authentication id of the local service
account. Hopefully that's sufficient. */
const LUID auth_luid_7 = ANONYMOUS_LOGON_LUID;
const LUID auth_luid_8 = LOCALSERVICE_LUID;
LUID auth_luid = wincap.has_broken_whoami () ? auth_luid_7 : auth_luid_8;
LARGE_INTEGER exp = { QuadPart:INT64_MAX };
TOKEN_USER user;
PTOKEN_GROUPS new_tok_gsids = NULL;
PTOKEN_PRIVILEGES privs = NULL;
TOKEN_OWNER owner;
TOKEN_PRIMARY_GROUP pgrp;
TOKEN_DEFAULT_DACL dacl = {};
TOKEN_SOURCE source;
TOKEN_STATISTICS stats;
memcpy (source.SourceName, "Cygwin.1", 8);
source.SourceIdentifier.HighPart = 0;
source.SourceIdentifier.LowPart = 0x0101;
HANDLE token = NULL;
HANDLE primary_token = NULL;
tmp_pathbuf tp;
PTOKEN_GROUPS my_tok_gsids = NULL;
cygpsid mandatory_integrity_sid;
ULONG size;
size_t psize = 0;
/* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
push_self_privilege (SE_CREATE_TOKEN_PRIVILEGE, true);
/* Open policy object. */
if (!(lsa = lsa_open_policy (NULL, POLICY_EXECUTE)))
goto out;
/* User, owner, primary group. */
user.User.Sid = usersid;
user.User.Attributes = 0;
owner.Owner = usersid;
/* Retrieve authentication id and group list from own process. */
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)
/* nothing to do */;
else
{
status = NtQueryInformationToken (hProcToken, TokenStatistics,
&stats, sizeof stats, &size);
if (!NT_SUCCESS (status))
debug_printf ("NtQueryInformationToken(hProcToken, "
"TokenStatistics), %y", status);
}
/* Retrieving current processes group list to be able to inherit
some important well known group sids. */
my_tok_gsids = (PTOKEN_GROUPS) tp.w_get ();
status = NtQueryInformationToken (hProcToken, TokenGroups, my_tok_gsids,
2 * NT_MAX_PATH, &size);
if (!NT_SUCCESS (status))
{
debug_printf ("NtQueryInformationToken(hProcToken, TokenGroups), "
"%y", status);
my_tok_gsids = NULL;
}
}
/* Create list of groups, the user is member in. */
if (new_groups.issetgroups ())
{
if (!get_setgroups_sidlist (tmp_gsids, usersid, my_tok_gsids, new_groups))
goto out;
}
else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid,
my_tok_gsids))
goto out;
/* Primary group. */
pgrp.PrimaryGroup = new_groups.pgsid;
/* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
new_tok_gsids = (PTOKEN_GROUPS)
alloca (sizeof (DWORD) + (tmp_gsids.count () + 1)
* sizeof (SID_AND_ATTRIBUTES));
new_tok_gsids->GroupCount = tmp_gsids.count ();
for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
{
new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED;
}
/* Retrieve list of privileges of that user. Based on the usersid and
the returned privileges, get_priv_list sets the mandatory_integrity_sid
pointer to the correct MIC SID for UAC. */
if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize,
&mandatory_integrity_sid)))
goto out;
new_tok_gsids->Groups[new_tok_gsids->GroupCount].Attributes =
SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;
new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid
= mandatory_integrity_sid;
/* Let's be heroic... */
status = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
&auth_luid, &exp, &user, new_tok_gsids, privs, &owner,
&pgrp, &dacl, &source);
if (status)
__seterrno_from_nt_status (status);
else
{
/* Convert to primary token. */
if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, &sec_none,
SecurityImpersonation, TokenPrimary,
&primary_token))
{
__seterrno ();
debug_printf ("DuplicateTokenEx %E");
primary_token = NULL;
}
}
out:
pop_self_privilege ();
if (token != INVALID_HANDLE_VALUE)
CloseHandle (token);
if (privs && privs != (PTOKEN_PRIVILEGES) &sys_privs)
free (privs);
lsa_close_policy (lsa);
debug_printf ("%p = create_token ()", primary_token);
return primary_token;
}
#define SFU_LSA_KEY_SUFFIX L"_microsoft_sfu_utility" #define SFU_LSA_KEY_SUFFIX L"_microsoft_sfu_utility"
HANDLE HANDLE

View File

@ -457,8 +457,6 @@ int setacl (HANDLE, path_conv &, int, struct acl *, bool &);
/* Set impersonation or restricted token. */ /* Set impersonation or restricted token. */
void set_imp_token (HANDLE token, int type); void set_imp_token (HANDLE token, int type);
/* Function creating a token by calling NtCreateToken. */
HANDLE create_token (cygsid &usersid, user_groups &groups);
/* LSA private key storage authentication, same as when using service logons. */ /* LSA private key storage authentication, same as when using service logons. */
HANDLE lsaprivkeyauth (struct passwd *pw); HANDLE lsaprivkeyauth (struct passwd *pw);
/* Kerberos or MsV1 S4U logon. */ /* Kerberos or MsV1 S4U logon. */

View File

@ -752,11 +752,9 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
sa = sec_user ((PSECURITY_ATTRIBUTES) alloca (1024), sa = sec_user ((PSECURITY_ATTRIBUTES) alloca (1024),
::cygheap->user.sid ()); ::cygheap->user.sid ());
/* We're creating a window station per user, not per logon /* We're creating a window station per user, not per logon
session First of all we might not have a valid logon session session. It doesn't make sense in terms of security to
for the user (logon by create_token), and second, it doesn't create a new window station for every logon of the same user.
make sense in terms of security to create a new window It just fills up the system with window stations. */
station for every logon of the same user. It just fills up
the system with window stations for no good reason. */
hwst = CreateWindowStationW (::cygheap->user.get_windows_id (sid), hwst = CreateWindowStationW (::cygheap->user.get_windows_id (sid),
0, GENERIC_READ | GENERIC_WRITE, sa); 0, GENERIC_READ | GENERIC_WRITE, sa);
if (!hwst) if (!hwst)

View File

@ -3609,8 +3609,7 @@ seteuid32 (uid_t uid)
debug_printf ("Found token %p", new_token); debug_printf ("Found token %p", new_token);
/* If no impersonation token is available, try to authenticate using /* If no impersonation token is available, try to authenticate using
LSA private data stored password, LSA authentication using our own LSA private data stored password, or, if that fails, S4U logon. */
LSA module, or, as last chance, NtCreateToken. */
if (new_token == NULL) if (new_token == NULL)
{ {
if (!(new_token = lsaprivkeyauth (pw_new))) if (!(new_token = lsaprivkeyauth (pw_new)))
@ -3623,23 +3622,9 @@ seteuid32 (uid_t uid)
extract_nt_dom_user (pw_new, domain, user); extract_nt_dom_user (pw_new, domain, user);
if (!(new_token = s4uauth (true, domain, user, status))) if (!(new_token = s4uauth (true, domain, user, status)))
{ {
if (status != STATUS_INVALID_PARAMETER) debug_printf ("s4uauth failed, bail out");
{ cygheap->user.reimpersonate ();
debug_printf ("s4uauth failed, bail out"); return -1;
cygheap->user.reimpersonate ();
return -1;
}
/* If s4uauth fails with status code STATUS_INVALID_PARAMETER,
we're running on a system not implementing MsV1_0S4ULogon
(Windows 7 WOW64). Fall back to create_token in this single
case only. */
debug_printf ("s4uauth failed, try create_token.");
if (!(new_token = create_token (usersid, groups)))
{
debug_printf ("create_token failed, bail out");
cygheap->user.reimpersonate ();
return -1;
}
} }
} }