* 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>
* debug.h (being_debugged): New macro.

View File

@ -1938,274 +1938,248 @@ extern struct passwd *internal_getlogin (cygheap_user &user);
extern "C" int
seteuid (__uid16_t uid)
{
sigframe thisframe (mainthread);
if (wincap.has_security ())
if (!wincap.has_security ()) return 0;
if (uid == ILLEGAL_UID)
{
char orig_username[UNLEN + 1];
char orig_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
char username[UNLEN + 1];
DWORD ulen = UNLEN + 1;
char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
SID_NAME_USE use;
debug_printf ("new euid == illegal euid, nothing happens");
return 0;
}
if (uid == ILLEGAL_UID || uid == myself->uid)
{
debug_printf ("new euid == current euid, nothing happens");
return 0;
}
struct passwd *pw_new = getpwuid (uid);
if (!pw_new)
{
set_errno (EINVAL);
return -1;
sigframe thisframe (mainthread);
DWORD ulen = UNLEN + 1;
DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
char orig_username[UNLEN + 1];
char orig_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
char username[UNLEN + 1];
char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
cygsid usersid, pgrpsid;
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;
debug_printf ("uid: %d myself->gid: %d", uid, myself->gid);
pw_new = getpwuid (uid);
if (!usersid.getfrompw (pw_new) ||
(!pgrpsid.getfromgr (getgrgid (myself->gid))))
{
set_errno (EINVAL);
return -1;
}
/* Save current information */
sav_token = cygheap->user.token;
sav_impersonated = cygheap->user.impersonated;
char *env;
orig_username[0] = orig_domain[0] = '\0';
if ((env = getenv ("USERNAME")))
strlcpy (orig_username, env, sizeof(orig_username));
if ((env = getenv ("USERDOMAIN")))
strlcpy (orig_domain, env, sizeof(orig_domain));
RevertToSelf();
if (!OpenProcessToken (GetCurrentProcess (),
TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &ptok))
{
__seterrno ();
goto failed;
}
/* Verify if the process token is suitable.
Currently we do not try to differentiate between
internal tokens and others */
process_ok = verify_token(ptok, usersid, pgrpsid);
debug_printf("Process token %sverified", process_ok?"":"not ");
if (process_ok)
{
if (cygheap->user.token == INVALID_HANDLE_VALUE ||
! cygheap->user.impersonated )
{
CloseHandle (ptok);
return 0; /* No change */
}
else cygheap->user.impersonated = FALSE;
}
cygsid tok_usersid;
DWORD siz;
char *env;
orig_username[0] = orig_domain[0] = '\0';
if ((env = getenv ("USERNAME")))
strncat (orig_username, env, UNLEN + 1);
if ((env = getenv ("USERDOMAIN")))
strncat (orig_domain, env, INTERNET_MAX_HOST_NAME_LENGTH + 1);
if (uid == cygheap->user.orig_uid)
{
debug_printf ("RevertToSelf () (uid == orig_uid, token=%d)",
cygheap->user.token);
RevertToSelf ();
if (cygheap->user.token != INVALID_HANDLE_VALUE)
cygheap->user.impersonated = FALSE;
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);
setenv ("USERDOMAIN", domain, 1);
}
if (ptok != INVALID_HANDLE_VALUE)
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 */
char dacl_buf[MAX_DACL_LEN(5)];
if (usersid != (origpsid = cygheap->user.orig_sid())) psid2 = usersid;
if (sec_acl ((PACL) dacl_buf, FALSE, origpsid, psid2))
{
TOKEN_DEFAULT_DACL tdacl;
tdacl.DefaultDacl = (PACL) dacl_buf;
if (!SetTokenInformation (ptok, TokenDefaultDacl,
&tdacl, sizeof dacl_buf))
debug_printf ("SetTokenInformation"
"(TokenDefaultDacl): %E");
}
CloseHandle (ptok);
if (!process_ok && cygheap->user.token == INVALID_HANDLE_VALUE)
{
/* If no impersonation token is available, try to
authenticate using NtCreateToken() or subauthentication. */
cygheap->user.token = create_token (usersid, pgrpsid);
if (cygheap->user.token != INVALID_HANDLE_VALUE)
explicitly_created_token = TRUE;
else
{
cygsid usersid, pgrpsid, origsid;
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)
{
debug_printf ("Impersonate (uid == %d)", uid);
RevertToSelf ();
/* 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");
}
/* Set process def dacl to allow access to impersonated token */
char dacl_buf[MAX_DACL_LEN(5)];
origsid = cygheap->user.orig_sid ();
if (usersid && origsid &&
sec_acl((PACL) dacl_buf, FALSE, origsid, usersid))
{
HANDLE ptok = INVALID_HANDLE_VALUE;
TOKEN_DEFAULT_DACL tdacl;
tdacl.DefaultDacl = (PACL) dacl_buf;
if (!OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_DEFAULT,
&ptok))
debug_printf ("OpenProcessToken(): %E");
else
{
if (!SetTokenInformation (ptok, TokenDefaultDacl,
&tdacl, sizeof dacl_buf))
debug_printf ("SetTokenInformation"
"(TokenDefaultDacl): %E");
}
if (ptok != INVALID_HANDLE_VALUE) CloseHandle (ptok);
}
/* Now try to impersonate. */
if (!LookupAccountSid (NULL, usersid, username, &ulen,
domain, &dlen, &use))
debug_printf ("LookupAccountSid (): %E");
else if (!ImpersonateLoggedOnUser (cygheap->user.token))
system_printf ("Impersonating (%d) in set(e)uid failed: %E",
cygheap->user.token);
else
{
cygheap->user.impersonated = TRUE;
setenv ("USERNAME", username, 1);
setenv ("USERDOMAIN", domain, 1);
}
}
{
/* create_token failed. Try subauthentication. */
debug_printf ("create token failed, try subauthentication.");
cygheap->user.token = subauth (pw_new);
if (cygheap->user.token == INVALID_HANDLE_VALUE) goto failed;
}
}
cygheap_user user;
/* user.token is used in internal_getlogin () to determine if
impersonation is active. If so, the token is used for
retrieving user's SID. */
user.token = cygheap->user.impersonated ? cygheap->user.token
: INVALID_HANDLE_VALUE;
/* Unsetting these both env vars is necessary to get NetUserGetInfo()
called in internal_getlogin (). Otherwise the wrong path is used
after a user switch, probably. */
unsetenv ("HOMEDRIVE");
unsetenv ("HOMEPATH");
struct passwd *pw_cur = internal_getlogin (user);
if (pw_cur != pw_new)
{
debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d",
cygheap->user.token, pw_cur->pw_uid,
pw_new->pw_uid, cygheap->user.orig_uid);
setenv ("USERNAME", orig_username, 1);
setenv ("USERDOMAIN", orig_domain, 1);
set_errno (EPERM);
return -1;
/* 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
impersonation is active. If so, the token is used for
retrieving user's SID. */
user.token = cygheap->user.impersonated ? cygheap->user.token
: INVALID_HANDLE_VALUE;
/* Unsetting these two env vars is necessary to get NetUserGetInfo()
called in internal_getlogin (). Otherwise the wrong path is used
after a user switch, probably. */
unsetenv ("HOMEDRIVE");
unsetenv ("HOMEPATH");
setenv ("USERDOMAIN", domain, 1);
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;
}
else
set_errno (ENOSYS);
debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
return 0;
debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d",
cygheap->user.token, pw_cur->pw_uid,
pw_new->pw_uid, cygheap->user.orig_uid);
set_errno (EPERM);
failed:
setenv ("USERNAME", orig_username, 1);
setenv ("USERDOMAIN", orig_domain, 1);
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;
}
/* setegid: from System V. */
extern "C" int
setegid (__gid16_t gid)
{
if ((!wincap.has_security ()) ||
(gid == ILLEGAL_GID))
return 0;
sigframe thisframe (mainthread);
if (wincap.has_security ())
cygsid gsid;
HANDLE ptok;
if (!(gsid.getfromgr (getgrgid (gid))))
{
if (gid != ILLEGAL_GID)
{
struct __group16 *gr;
if (!(gr = getgrgid (gid)))
{
set_errno (EINVAL);
return -1;
}
myself->gid = gid;
if (allow_ntsec)
{
cygsid gsid;
HANDLE ptok;
if (gsid.getfromgr (gr))
{
/* Remove impersonation */
if (cygheap->user.token != INVALID_HANDLE_VALUE
&& cygheap->user.impersonated)
{
if (!SetTokenInformation (cygheap->user.token,
TokenPrimaryGroup,
&gsid, sizeof gsid))
debug_printf ("SetTokenInformation(primary, "
"TokenPrimaryGroup): %E");
RevertToSelf ();
}
if (!OpenProcessToken (GetCurrentProcess (),
TOKEN_ADJUST_DEFAULT,
&ptok))
debug_printf ("OpenProcessToken(): %E\n");
else
{
if (!SetTokenInformation (ptok, TokenPrimaryGroup,
&gsid, sizeof gsid))
debug_printf ("SetTokenInformation(process, "
"TokenPrimaryGroup): %E");
CloseHandle (ptok);
}
if (cygheap->user.token != INVALID_HANDLE_VALUE
&& cygheap->user.impersonated)
ImpersonateLoggedOnUser (cygheap->user.token);
}
}
}
set_errno (EINVAL);
return -1;
}
myself->gid = gid;
/* If impersonated, update primary group and revert */
if (cygheap->user.token != INVALID_HANDLE_VALUE
&& cygheap->user.impersonated)
{
if (!SetTokenInformation (cygheap->user.token,
TokenPrimaryGroup,
&gsid, sizeof gsid))
debug_printf ("SetTokenInformation(thread, "
"TokenPrimaryGroup): %E");
RevertToSelf ();
}
if (!OpenProcessToken (GetCurrentProcess (),
TOKEN_ADJUST_DEFAULT,
&ptok))
debug_printf ("OpenProcessToken(): %E\n");
else
set_errno (ENOSYS);
{
if (!SetTokenInformation (ptok, TokenPrimaryGroup,
&gsid, sizeof gsid))
debug_printf ("SetTokenInformation(process, "
"TokenPrimaryGroup): %E");
CloseHandle (ptok);
}
if (cygheap->user.token != INVALID_HANDLE_VALUE
&& cygheap->user.impersonated
&& !ImpersonateLoggedOnUser (cygheap->user.token))
system_printf ("Impersonating in setegid failed: %E");
return 0;
}