* include/sys/cygwin.h: Add new cygwin_getinfo_type

CW_SET_EXTERNAL_TOKEN.
	Add new enum CW_TOKEN_IMPERSONATION, CW_TOKEN_RESTRICTED.
	* cygheap.h (cyguser): New flags ext_token_is_restricted,
	curr_token_is_restricted and setuid_to_restricted.
	* external.cc (cygwin_internal): Add CW_SET_EXTERNAL_TOKEN.
	* sec_auth.cc (set_imp_token): New function.
	(cygwin_set_impersonation_token): Call set_imp_token ().
	* security.h (set_imp_token): New prototype.
	* spawn.cc (spawn_guts): Use CreateProcessAsUserW if restricted token
	was enabled by setuid().  Do not create new window station in this case.
	* syscalls.cc (seteuid32): Add handling of restricted external tokens.
	Set HANDLE_FLAG_INHERIT for primary token.
	(setuid32): Set setuid_to_restricted flag.
	* uinfo.cc (uinfo_init): Do not reimpersonate if restricted token was
	enabled by setuid ().  Initialize user.*_restricted flags.
This commit is contained in:
Corinna Vinschen 2009-10-13 10:23:31 +00:00
parent 6c41e710c9
commit 0191627a26
9 changed files with 122 additions and 16 deletions

View File

@ -1,3 +1,23 @@
2009-10-13 Christian Franke <franke@computer.org>
Corinna Vinschen <corinna@vinschen.de>
* include/sys/cygwin.h: Add new cygwin_getinfo_type
CW_SET_EXTERNAL_TOKEN.
Add new enum CW_TOKEN_IMPERSONATION, CW_TOKEN_RESTRICTED.
* cygheap.h (cyguser): New flags ext_token_is_restricted,
curr_token_is_restricted and setuid_to_restricted.
* external.cc (cygwin_internal): Add CW_SET_EXTERNAL_TOKEN.
* sec_auth.cc (set_imp_token): New function.
(cygwin_set_impersonation_token): Call set_imp_token ().
* security.h (set_imp_token): New prototype.
* spawn.cc (spawn_guts): Use CreateProcessAsUserW if restricted token
was enabled by setuid(). Do not create new window station in this case.
* syscalls.cc (seteuid32): Add handling of restricted external tokens.
Set HANDLE_FLAG_INHERIT for primary token.
(setuid32): Set setuid_to_restricted flag.
* uinfo.cc (uinfo_init): Do not reimpersonate if restricted token was
enabled by setuid (). Initialize user.*_restricted flags.
2009-10-13 Eric Blake <ebb9@byu.net>
* hires.h (hires_ms): Change initime_us to initime_ns, with 10x

View File

@ -108,6 +108,9 @@ public:
HANDLE internal_token;
HANDLE curr_primary_token;
HANDLE curr_imp_token;
bool ext_token_is_restricted; /* external_token is restricted token */
bool curr_token_is_restricted; /* curr_primary_token is restricted token */
bool setuid_to_restricted; /* switch to restricted token by setuid () */
/* CGF 2002-06-27. I removed the initializaton from this constructor
since this class is always allocated statically. That means that everything

View File

@ -415,6 +415,13 @@ cygwin_internal (cygwin_getinfo_types t, ...)
int useTerminateProcess = va_arg (arg, int);
exit_process (status, !!useTerminateProcess); /* no return */
}
case CW_SET_EXTERNAL_TOKEN:
{
HANDLE token = va_arg (arg, HANDLE);
int type = va_arg (arg, int);
set_imp_token (token, type);
return 0;
}
default:
break;

View File

@ -143,9 +143,17 @@ typedef enum
CW_SET_DOS_FILE_WARNING,
CW_SET_PRIV_KEY,
CW_SETERRNO,
CW_EXIT_PROCESS
CW_EXIT_PROCESS,
CW_SET_EXTERNAL_TOKEN
} cygwin_getinfo_types;
/* Token type for CW_SET_EXTERNAL_TOKEN */
enum
{
CW_TOKEN_IMPERSONATION = 0,
CW_TOKEN_RESTRICTED = 1
};
#define CW_NEXTPID 0x80000000 /* or with pid to get next one */
unsigned long cygwin_internal (cygwin_getinfo_types, ...);

View File

@ -30,11 +30,19 @@ details. */
#include "cygserver_setpwd.h"
#include <cygwin/version.h>
void
set_imp_token (HANDLE token, int type)
{
debug_printf ("set_imp_token (%d, %d)", token, type);
cygheap->user.external_token = (token == INVALID_HANDLE_VALUE
? NO_IMPERSONATION : token);
cygheap->user.ext_token_is_restricted = (type == CW_TOKEN_RESTRICTED);
}
extern "C" void
cygwin_set_impersonation_token (const HANDLE hToken)
{
debug_printf ("set_impersonation_token (%d)", hToken);
cygheap->user.external_token = hToken == INVALID_HANDLE_VALUE ? NO_IMPERSONATION : hToken;
set_imp_token (hToken, CW_TOKEN_IMPERSONATION);
}
void

View File

@ -366,6 +366,8 @@ extern "C" int acl32 (const char *, int, int, __acl32 *);
int getacl (HANDLE, path_conv &, int, __acl32 *);
int setacl (HANDLE, path_conv &, int, __acl32 *, bool &);
/* Set impersonation or restricted token. */
void set_imp_token (HANDLE token, int type);
/* Function creating a token by calling NtCreateToken. */
HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw);
/* LSA authentication function. */

View File

@ -537,7 +537,8 @@ loop:
if (!cygheap->user.issetuid ()
|| (cygheap->user.saved_uid == cygheap->user.real_uid
&& cygheap->user.saved_gid == cygheap->user.real_gid
&& !cygheap->user.groups.issetgroups ()))
&& !cygheap->user.groups.issetgroups ()
&& !cygheap->user.setuid_to_restricted))
{
rc = CreateProcessW (runpath, /* image name - with full path */
wone_line, /* what was passed to exec */
@ -571,7 +572,8 @@ loop:
risk, but we don't want to disable this behaviour for older
OSes because it's still heavily used by some users. They have
been warned. */
if (wcscasecmp (wstname, L"WinSta0") != 0)
if (!cygheap->user.setuid_to_restricted
&& wcscasecmp (wstname, L"WinSta0") != 0)
{
WCHAR sid[128];

View File

@ -2664,7 +2664,28 @@ seteuid32 (__uid32_t uid)
debug_printf ("uid: %u myself->uid: %u myself->gid: %u",
uid, myself->uid, myself->gid);
if (uid == myself->uid && !cygheap->user.groups.ischanged)
/* Same uid as we're just running under is usually a no-op.
Except we have an external token which is a restricted token. Or,
the external token is NULL, but the current impersonation token is
a restricted token. This allows to restrict user rights temporarily
like this:
cygwin_internal(CW_SET_EXTERNAL_TOKEN, restricted_token,
CW_TOKEN_RESTRICTED);
setuid (getuid ());
[...do stuff with restricted rights...]
cygwin_internal(CW_SET_EXTERNAL_TOKEN, INVALID_HANDLE_VALUE,
CW_TOKEN_RESTRICTED);
setuid (getuid ());
Note that using the current uid is a requirement! Starting with Windows
Vista, we have restricted tokens galore (UAC), so this is really just
a special case to restict your own processes to lesser rights. */
bool request_restricted_uid_switch = (uid == myself->uid
&& cygheap->user.ext_token_is_restricted);
if (uid == myself->uid && !cygheap->user.groups.ischanged
&& !request_restricted_uid_switch)
{
debug_printf ("Nothing happens");
return 0;
@ -2686,6 +2707,22 @@ seteuid32 (__uid32_t uid)
cygheap->user.deimpersonate ();
/* Verify if the process token is suitable. */
/* First of all, skip all checks if a switch to a restricted token has been
requested, or if trying to switch back from it. */
if (request_restricted_uid_switch)
{
if (cygheap->user.external_token != NO_IMPERSONATION)
{
debug_printf ("Switch to restricted token");
new_token = cygheap->user.external_token;
}
else
{
debug_printf ("Switch back from restricted token");
new_token = hProcToken;
cygheap->user.ext_token_is_restricted = false;
}
}
/* TODO, CV 2008-11-25: The check against saved_sid is a kludge and a
shortcut. We must check if it's really feasible in the long run.
The reason to add this shortcut is this: sshd switches back to the
@ -2701,8 +2738,9 @@ seteuid32 (__uid32_t uid)
Therefore we try this shortcut now. When switching back to the
privileged user, we probably always want a correct (aka original)
user token for this privileged user, not only in sshd. */
if ((uid == cygheap->user.saved_uid && usersid == cygheap->user.saved_sid ())
|| verify_token (hProcToken, usersid, groups))
else if ((uid == cygheap->user.saved_uid
&& usersid == cygheap->user.saved_sid ())
|| verify_token (hProcToken, usersid, groups))
new_token = hProcToken;
/* Verify if the external token is suitable */
else if (cygheap->user.external_token != NO_IMPERSONATION
@ -2763,9 +2801,12 @@ seteuid32 (__uid32_t uid)
if (new_token != hProcToken)
{
/* Avoid having HKCU use default user */
WCHAR name[128];
load_registry_hive (usersid.string (name));
if (!request_restricted_uid_switch)
{
/* Avoid having HKCU use default user */
WCHAR name[128];
load_registry_hive (usersid.string (name));
}
/* Try setting owner to same value as user. */
if (!SetTokenInformation (new_token, TokenOwner,
@ -2790,6 +2831,8 @@ seteuid32 (__uid32_t uid)
cygheap->user.set_sid (usersid);
cygheap->user.curr_primary_token = new_token == hProcToken ? NO_IMPERSONATION
: new_token;
cygheap->user.curr_token_is_restricted = false;
cygheap->user.setuid_to_restricted = false;
if (cygheap->user.curr_imp_token != NO_IMPERSONATION)
{
CloseHandle (cygheap->user.curr_imp_token);
@ -2797,14 +2840,19 @@ seteuid32 (__uid32_t uid)
}
if (cygheap->user.curr_primary_token != NO_IMPERSONATION)
{
if (!DuplicateTokenEx (cygheap->user.curr_primary_token, MAXIMUM_ALLOWED,
&sec_none, SecurityImpersonation,
TokenImpersonation, &cygheap->user.curr_imp_token))
/* HANDLE_FLAG_INHERIT may be missing in external token. */
if (!SetHandleInformation (cygheap->user.curr_primary_token,
HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)
|| !DuplicateTokenEx (cygheap->user.curr_primary_token,
MAXIMUM_ALLOWED, &sec_none,
SecurityImpersonation, TokenImpersonation,
&cygheap->user.curr_imp_token))
{
__seterrno ();
cygheap->user.curr_primary_token = NO_IMPERSONATION;
return -1;
}
cygheap->user.curr_token_is_restricted = request_restricted_uid_switch;
set_cygwin_privileges (cygheap->user.curr_primary_token);
set_cygwin_privileges (cygheap->user.curr_imp_token);
}
@ -2835,7 +2883,11 @@ setuid32 (__uid32_t uid)
{
int ret = seteuid32 (uid);
if (!ret)
cygheap->user.real_uid = myself->uid;
{
cygheap->user.real_uid = myself->uid;
/* If restricted token, forget original privileges on exec (). */
cygheap->user.setuid_to_restricted = cygheap->user.curr_token_is_restricted;
}
debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
return ret;
}

View File

@ -136,7 +136,8 @@ uinfo_init ()
else if (cygheap->user.issetuid ()
&& cygheap->user.saved_uid == cygheap->user.real_uid
&& cygheap->user.saved_gid == cygheap->user.real_gid
&& !cygheap->user.groups.issetgroups ())
&& !cygheap->user.groups.issetgroups ()
&& !cygheap->user.setuid_to_restricted)
{
cygheap->user.reimpersonate ();
return;
@ -150,6 +151,9 @@ uinfo_init ()
cygheap->user.internal_token = NO_IMPERSONATION;
cygheap->user.curr_primary_token = NO_IMPERSONATION;
cygheap->user.curr_imp_token = NO_IMPERSONATION;
cygheap->user.ext_token_is_restricted = false;
cygheap->user.curr_token_is_restricted = false;
cygheap->user.setuid_to_restricted = false;
cygheap->user.set_saved_sid (); /* Update the original sid */
cygheap->user.reimpersonate ();
}