* syscalls.cc (seteuid): Do not take allow_ntsec into account.

Attempt to use an existing or new token even when the uid
	matches orig_uid, but the gid is not in the process token.
	Major reorganization after several incremental changes.
	(setegid): Do not take allow_ntsec into account. Minor
	reorganization after several incremental changes.
This commit is contained in:
Corinna Vinschen 2002-05-27 11:48:15 +00:00
parent 31be924314
commit 75bf293153
2 changed files with 228 additions and 245 deletions

View File

@ -1,3 +1,12 @@
2002-05-22 Pierre Humblet <pierre.humblet@ieee.org>
* syscalls.cc (seteuid): Do not take allow_ntsec into account.
Attempt to use an existing or new token even when the uid
matches orig_uid, but the gid is not in the process token.
Major reorganization after several incremental changes.
(setegid): Do not take allow_ntsec into account. Minor
reorganization after several incremental changes.
2002-05-26 Christopher Faylor <cgf@redhat.com> 2002-05-26 Christopher Faylor <cgf@redhat.com>
* debug.h (being_debugged): New macro. * debug.h (being_debugged): New macro.

View File

@ -1938,250 +1938,229 @@ extern struct passwd *internal_getlogin (cygheap_user &user);
extern "C" int extern "C" int
seteuid (__uid16_t uid) seteuid (__uid16_t uid)
{ {
sigframe thisframe (mainthread); if (!wincap.has_security ()) return 0;
if (wincap.has_security ())
if (uid == ILLEGAL_UID)
{ {
debug_printf ("new euid == illegal euid, nothing happens");
return 0;
}
sigframe thisframe (mainthread);
DWORD ulen = UNLEN + 1;
DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
char orig_username[UNLEN + 1]; char orig_username[UNLEN + 1];
char orig_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; char orig_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
char username[UNLEN + 1]; char username[UNLEN + 1];
DWORD ulen = UNLEN + 1;
char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; cygsid usersid, pgrpsid;
SID_NAME_USE use; HANDLE ptok, sav_token;
BOOL sav_impersonated, sav_token_is_internal_token;
BOOL process_ok, explicitly_created_token = FALSE;
struct passwd * pw_new, * pw_cur;
cygheap_user user;
PSID origpsid, psid2 = NO_SID;
if (uid == ILLEGAL_UID || uid == myself->uid) debug_printf ("uid: %d myself->gid: %d", uid, myself->gid);
{
debug_printf ("new euid == current euid, nothing happens"); pw_new = getpwuid (uid);
return 0; if (!usersid.getfrompw (pw_new) ||
} (!pgrpsid.getfromgr (getgrgid (myself->gid))))
struct passwd *pw_new = getpwuid (uid);
if (!pw_new)
{ {
set_errno (EINVAL); set_errno (EINVAL);
return -1; return -1;
} }
/* Save current information */
cygsid tok_usersid; sav_token = cygheap->user.token;
DWORD siz; sav_impersonated = cygheap->user.impersonated;
char *env; char *env;
orig_username[0] = orig_domain[0] = '\0'; orig_username[0] = orig_domain[0] = '\0';
if ((env = getenv ("USERNAME"))) if ((env = getenv ("USERNAME")))
strncat (orig_username, env, UNLEN + 1); strlcpy (orig_username, env, sizeof(orig_username));
if ((env = getenv ("USERDOMAIN"))) if ((env = getenv ("USERDOMAIN")))
strncat (orig_domain, env, INTERNET_MAX_HOST_NAME_LENGTH + 1); strlcpy (orig_domain, env, sizeof(orig_domain));
if (uid == cygheap->user.orig_uid)
{
debug_printf ("RevertToSelf () (uid == orig_uid, token=%d)",
cygheap->user.token);
RevertToSelf(); RevertToSelf();
if (cygheap->user.token != INVALID_HANDLE_VALUE) if (!OpenProcessToken (GetCurrentProcess (),
cygheap->user.impersonated = FALSE; TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &ptok))
HANDLE ptok = INVALID_HANDLE_VALUE;
if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &ptok))
debug_printf ("OpenProcessToken(): %E\n");
else if (!GetTokenInformation (ptok, TokenUser, &tok_usersid,
sizeof tok_usersid, &siz))
debug_printf ("GetTokenInformation(): %E");
else if (!LookupAccountSid (NULL, tok_usersid, username, &ulen,
domain, &dlen, &use))
debug_printf ("LookupAccountSid(): %E");
else
{ {
setenv ("USERNAME", username, 1); __seterrno ();
setenv ("USERDOMAIN", domain, 1); goto failed;
} }
if (ptok != INVALID_HANDLE_VALUE) /* Verify if the process token is suitable.
CloseHandle (ptok); Currently we do not try to differentiate between
} internal tokens and others */
else process_ok = verify_token(ptok, usersid, pgrpsid);
debug_printf("Process token %sverified", process_ok?"":"not ");
if (process_ok)
{ {
cygsid usersid, pgrpsid, origsid; if (cygheap->user.token == INVALID_HANDLE_VALUE ||
HANDLE sav_token = INVALID_HANDLE_VALUE;
BOOL sav_impersonation;
BOOL current_token_is_internal_token = FALSE;
BOOL explicitely_created_token = FALSE;
struct __group16 *gr = getgrgid (myself->gid);
debug_printf ("myself->gid: %d, gr: %d", myself->gid, gr);
usersid.getfrompw (pw_new);
pgrpsid.getfromgr (gr);
/* Only when ntsec is ON! */
/* Check if new user == user of impersonation token and
- if reasonable - new pgrp == pgrp of impersonation token. */
if (allow_ntsec && cygheap->user.token != INVALID_HANDLE_VALUE)
{
if (!verify_token(cygheap->user.token, usersid, pgrpsid,
& current_token_is_internal_token))
{
/* If not, RevertToSelf and close old token. */
debug_printf ("tsid != usersid");
RevertToSelf ();
sav_token = cygheap->user.token;
sav_impersonation = cygheap->user.impersonated;
cygheap->user.token = INVALID_HANDLE_VALUE;
cygheap->user.impersonated = FALSE;
}
}
/* Only when ntsec is ON! */
/* If no impersonation token is available, try to
authenticate using NtCreateToken() or subauthentication. */
if (allow_ntsec && cygheap->user.token == INVALID_HANDLE_VALUE)
{
HANDLE ptok = INVALID_HANDLE_VALUE;
ptok = create_token (usersid, pgrpsid);
if (ptok != INVALID_HANDLE_VALUE)
explicitely_created_token = TRUE;
else
{
/* create_token failed. Try subauthentication. */
debug_printf ("create token failed, try subauthentication.");
ptok = subauth (pw_new);
}
if (ptok != INVALID_HANDLE_VALUE)
{
cygwin_set_impersonation_token (ptok);
/* If sav_token was internally created, destroy it. */
if (sav_token != INVALID_HANDLE_VALUE &&
current_token_is_internal_token)
CloseHandle (sav_token);
}
else if (sav_token != INVALID_HANDLE_VALUE)
cygheap->user.token = sav_token;
}
/* If no impersonation is active but an impersonation
token is available, try to impersonate. */
if (cygheap->user.token != INVALID_HANDLE_VALUE &&
! cygheap->user.impersonated ) ! cygheap->user.impersonated )
{ {
debug_printf ("Impersonate (uid == %d)", uid); CloseHandle (ptok);
RevertToSelf (); return 0; /* No change */
/* If the token was explicitely created, all information has
already been set correctly. */
if (!explicitely_created_token)
{
/* Try setting owner to same value as user. */
if (usersid &&
!SetTokenInformation (cygheap->user.token, TokenOwner,
&usersid, sizeof usersid))
debug_printf ("SetTokenInformation(user.token, "
"TokenOwner): %E");
/* Try setting primary group in token to current group
if token not explicitely created. */
if (pgrpsid &&
!SetTokenInformation (cygheap->user.token,
TokenPrimaryGroup,
&pgrpsid, sizeof pgrpsid))
debug_printf ("SetTokenInformation(user.token, "
"TokenPrimaryGroup): %E");
} }
else cygheap->user.impersonated = FALSE;
}
if (!process_ok && cygheap->user.token != INVALID_HANDLE_VALUE)
{
/* Verify if the current tokem is suitable */
BOOL token_ok = verify_token (cygheap->user.token, usersid, pgrpsid,
& sav_token_is_internal_token);
debug_printf("Thread token %d %sverified",
cygheap->user.token, token_ok?"":"not ");
if (token_ok)
{
/* Return if current token is valid */
if (cygheap->user.impersonated)
{
CloseHandle (ptok);
if (!ImpersonateLoggedOnUser (cygheap->user.token))
system_printf ("Impersonating in seteuid failed: %E");
return 0; /* No change */
}
}
else cygheap->user.token = INVALID_HANDLE_VALUE;
}
/* Set process def dacl to allow access to impersonated token */ /* Set process def dacl to allow access to impersonated token */
char dacl_buf[MAX_DACL_LEN(5)]; char dacl_buf[MAX_DACL_LEN(5)];
origsid = cygheap->user.orig_sid (); if (usersid != (origpsid = cygheap->user.orig_sid())) psid2 = usersid;
if (usersid && origsid && if (sec_acl ((PACL) dacl_buf, FALSE, origpsid, psid2))
sec_acl((PACL) dacl_buf, FALSE, origsid, usersid))
{ {
HANDLE ptok = INVALID_HANDLE_VALUE;
TOKEN_DEFAULT_DACL tdacl; TOKEN_DEFAULT_DACL tdacl;
tdacl.DefaultDacl = (PACL) dacl_buf; tdacl.DefaultDacl = (PACL) dacl_buf;
if (!OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_DEFAULT,
&ptok))
debug_printf ("OpenProcessToken(): %E");
else
{
if (!SetTokenInformation (ptok, TokenDefaultDacl, if (!SetTokenInformation (ptok, TokenDefaultDacl,
&tdacl, sizeof dacl_buf)) &tdacl, sizeof dacl_buf))
debug_printf ("SetTokenInformation" debug_printf ("SetTokenInformation"
"(TokenDefaultDacl): %E"); "(TokenDefaultDacl): %E");
} }
if (ptok != INVALID_HANDLE_VALUE) CloseHandle (ptok); CloseHandle (ptok);
}
/* Now try to impersonate. */ if (!process_ok && cygheap->user.token == INVALID_HANDLE_VALUE)
if (!LookupAccountSid (NULL, usersid, username, &ulen, {
domain, &dlen, &use)) /* If no impersonation token is available, try to
debug_printf ("LookupAccountSid (): %E"); authenticate using NtCreateToken() or subauthentication. */
else if (!ImpersonateLoggedOnUser (cygheap->user.token)) cygheap->user.token = create_token (usersid, pgrpsid);
system_printf ("Impersonating (%d) in set(e)uid failed: %E", if (cygheap->user.token != INVALID_HANDLE_VALUE)
cygheap->user.token); explicitly_created_token = TRUE;
else else
{ {
cygheap->user.impersonated = TRUE; /* create_token failed. Try subauthentication. */
setenv ("USERNAME", username, 1); debug_printf ("create token failed, try subauthentication.");
setenv ("USERDOMAIN", domain, 1); cygheap->user.token = subauth (pw_new);
} if (cygheap->user.token == INVALID_HANDLE_VALUE) goto failed;
} }
} }
cygheap_user user; /* Lookup username and domain before impersonating,
LookupAccountSid() returns a different answer afterwards. */
SID_NAME_USE use;
if (!LookupAccountSid (NULL, usersid, username, &ulen,
domain, &dlen, &use))
{
debug_printf ("LookupAccountSid (): %E");
__seterrno ();
goto failed;
}
/* If using the token, set info and impersonate */
if (! process_ok )
{
/* If the token was explicitly created, all information has
already been set correctly. */
if (!explicitly_created_token)
{
/* Try setting owner to same value as user. */
if (!SetTokenInformation (cygheap->user.token, TokenOwner,
&usersid, sizeof usersid))
debug_printf ("SetTokenInformation(user.token, "
"TokenOwner): %E");
/* Try setting primary group in token to current group */
if (!SetTokenInformation (cygheap->user.token,
TokenPrimaryGroup,
&pgrpsid, sizeof pgrpsid))
debug_printf ("SetTokenInformation(user.token, "
"TokenPrimaryGroup): %E");
}
/* Now try to impersonate. */
if (!ImpersonateLoggedOnUser (cygheap->user.token))
{
debug_printf ("ImpersonateLoggedOnUser %E");
__seterrno ();
goto failed;
}
cygheap->user.impersonated = TRUE;
}
/* user.token is used in internal_getlogin () to determine if /* user.token is used in internal_getlogin () to determine if
impersonation is active. If so, the token is used for impersonation is active. If so, the token is used for
retrieving user's SID. */ retrieving user's SID. */
user.token = cygheap->user.impersonated ? cygheap->user.token user.token = cygheap->user.impersonated ? cygheap->user.token
: INVALID_HANDLE_VALUE; : INVALID_HANDLE_VALUE;
/* Unsetting these both env vars is necessary to get NetUserGetInfo() /* Unsetting these two env vars is necessary to get NetUserGetInfo()
called in internal_getlogin (). Otherwise the wrong path is used called in internal_getlogin (). Otherwise the wrong path is used
after a user switch, probably. */ after a user switch, probably. */
unsetenv ("HOMEDRIVE"); unsetenv ("HOMEDRIVE");
unsetenv ("HOMEPATH"); unsetenv ("HOMEPATH");
struct passwd *pw_cur = internal_getlogin (user); setenv ("USERDOMAIN", domain, 1);
if (pw_cur != pw_new) setenv ("USERNAME", username, 1);
pw_cur = internal_getlogin (user);
if (pw_cur == pw_new)
{ {
/* If sav_token was internally created and is replaced, destroy it. */
if (sav_token != INVALID_HANDLE_VALUE &&
sav_token != cygheap->user.token &&
sav_token_is_internal_token)
CloseHandle (sav_token);
myself->uid = uid;
cygheap->user = user;
return 0;
}
debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d", debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d",
cygheap->user.token, pw_cur->pw_uid, cygheap->user.token, pw_cur->pw_uid,
pw_new->pw_uid, cygheap->user.orig_uid); pw_new->pw_uid, cygheap->user.orig_uid);
set_errno (EPERM);
failed:
setenv ("USERNAME", orig_username, 1); setenv ("USERNAME", orig_username, 1);
setenv ("USERDOMAIN", orig_domain, 1); setenv ("USERDOMAIN", orig_domain, 1);
set_errno (EPERM); cygheap->user.token = sav_token;
cygheap->user.impersonated = sav_impersonated;
if ( cygheap->user.token != INVALID_HANDLE_VALUE &&
cygheap->user.impersonated &&
!ImpersonateLoggedOnUser (cygheap->user.token))
system_printf ("Impersonating in seteuid failed: %E");
return -1; return -1;
} }
myself->uid = uid;
cygheap->user = user;
}
else
set_errno (ENOSYS);
debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
return 0;
}
/* setegid: from System V. */ /* setegid: from System V. */
extern "C" int extern "C" int
setegid (__gid16_t gid) setegid (__gid16_t gid)
{ {
sigframe thisframe (mainthread); if ((!wincap.has_security ()) ||
if (wincap.has_security ()) (gid == ILLEGAL_GID))
{ return 0;
if (gid != ILLEGAL_GID)
{
struct __group16 *gr;
if (!(gr = getgrgid (gid))) sigframe thisframe (mainthread);
cygsid gsid;
HANDLE ptok;
if (!(gsid.getfromgr (getgrgid (gid))))
{ {
set_errno (EINVAL); set_errno (EINVAL);
return -1; return -1;
} }
myself->gid = gid; myself->gid = gid;
if (allow_ntsec)
{
cygsid gsid;
HANDLE ptok;
if (gsid.getfromgr (gr)) /* If impersonated, update primary group and revert */
{
/* Remove impersonation */
if (cygheap->user.token != INVALID_HANDLE_VALUE if (cygheap->user.token != INVALID_HANDLE_VALUE
&& cygheap->user.impersonated) && cygheap->user.impersonated)
{ {
if (!SetTokenInformation (cygheap->user.token, if (!SetTokenInformation (cygheap->user.token,
TokenPrimaryGroup, TokenPrimaryGroup,
&gsid, sizeof gsid)) &gsid, sizeof gsid))
debug_printf ("SetTokenInformation(primary, " debug_printf ("SetTokenInformation(thread, "
"TokenPrimaryGroup): %E"); "TokenPrimaryGroup): %E");
RevertToSelf (); RevertToSelf ();
} }
@ -2198,14 +2177,9 @@ setegid (__gid16_t gid)
CloseHandle (ptok); CloseHandle (ptok);
} }
if (cygheap->user.token != INVALID_HANDLE_VALUE if (cygheap->user.token != INVALID_HANDLE_VALUE
&& cygheap->user.impersonated) && cygheap->user.impersonated
ImpersonateLoggedOnUser (cygheap->user.token); && !ImpersonateLoggedOnUser (cygheap->user.token))
} system_printf ("Impersonating in setegid failed: %E");
}
}
}
else
set_errno (ENOSYS);
return 0; return 0;
} }