* 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:
parent
31be924314
commit
75bf293153
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue