* 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:
parent
6c41e710c9
commit
0191627a26
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, ...);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue