* 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>
|
2009-10-13 Eric Blake <ebb9@byu.net>
|
||||||
|
|
||||||
* hires.h (hires_ms): Change initime_us to initime_ns, with 10x
|
* hires.h (hires_ms): Change initime_us to initime_ns, with 10x
|
||||||
|
|
|
@ -108,6 +108,9 @@ public:
|
||||||
HANDLE internal_token;
|
HANDLE internal_token;
|
||||||
HANDLE curr_primary_token;
|
HANDLE curr_primary_token;
|
||||||
HANDLE curr_imp_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
|
/* CGF 2002-06-27. I removed the initializaton from this constructor
|
||||||
since this class is always allocated statically. That means that everything
|
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);
|
int useTerminateProcess = va_arg (arg, int);
|
||||||
exit_process (status, !!useTerminateProcess); /* no return */
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -143,9 +143,17 @@ typedef enum
|
||||||
CW_SET_DOS_FILE_WARNING,
|
CW_SET_DOS_FILE_WARNING,
|
||||||
CW_SET_PRIV_KEY,
|
CW_SET_PRIV_KEY,
|
||||||
CW_SETERRNO,
|
CW_SETERRNO,
|
||||||
CW_EXIT_PROCESS
|
CW_EXIT_PROCESS,
|
||||||
|
CW_SET_EXTERNAL_TOKEN
|
||||||
} cygwin_getinfo_types;
|
} 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 */
|
#define CW_NEXTPID 0x80000000 /* or with pid to get next one */
|
||||||
unsigned long cygwin_internal (cygwin_getinfo_types, ...);
|
unsigned long cygwin_internal (cygwin_getinfo_types, ...);
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,19 @@ details. */
|
||||||
#include "cygserver_setpwd.h"
|
#include "cygserver_setpwd.h"
|
||||||
#include <cygwin/version.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
|
extern "C" void
|
||||||
cygwin_set_impersonation_token (const HANDLE hToken)
|
cygwin_set_impersonation_token (const HANDLE hToken)
|
||||||
{
|
{
|
||||||
debug_printf ("set_impersonation_token (%d)", hToken);
|
set_imp_token (hToken, CW_TOKEN_IMPERSONATION);
|
||||||
cygheap->user.external_token = hToken == INVALID_HANDLE_VALUE ? NO_IMPERSONATION : hToken;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -366,6 +366,8 @@ extern "C" int acl32 (const char *, int, int, __acl32 *);
|
||||||
int getacl (HANDLE, path_conv &, int, __acl32 *);
|
int getacl (HANDLE, path_conv &, int, __acl32 *);
|
||||||
int setacl (HANDLE, path_conv &, int, __acl32 *, bool &);
|
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. */
|
/* Function creating a token by calling NtCreateToken. */
|
||||||
HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw);
|
HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw);
|
||||||
/* LSA authentication function. */
|
/* LSA authentication function. */
|
||||||
|
|
|
@ -537,7 +537,8 @@ loop:
|
||||||
if (!cygheap->user.issetuid ()
|
if (!cygheap->user.issetuid ()
|
||||||
|| (cygheap->user.saved_uid == cygheap->user.real_uid
|
|| (cygheap->user.saved_uid == cygheap->user.real_uid
|
||||||
&& cygheap->user.saved_gid == cygheap->user.real_gid
|
&& 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 */
|
rc = CreateProcessW (runpath, /* image name - with full path */
|
||||||
wone_line, /* what was passed to exec */
|
wone_line, /* what was passed to exec */
|
||||||
|
@ -571,7 +572,8 @@ loop:
|
||||||
risk, but we don't want to disable this behaviour for older
|
risk, but we don't want to disable this behaviour for older
|
||||||
OSes because it's still heavily used by some users. They have
|
OSes because it's still heavily used by some users. They have
|
||||||
been warned. */
|
been warned. */
|
||||||
if (wcscasecmp (wstname, L"WinSta0") != 0)
|
if (!cygheap->user.setuid_to_restricted
|
||||||
|
&& wcscasecmp (wstname, L"WinSta0") != 0)
|
||||||
{
|
{
|
||||||
WCHAR sid[128];
|
WCHAR sid[128];
|
||||||
|
|
||||||
|
|
|
@ -2664,7 +2664,28 @@ seteuid32 (__uid32_t uid)
|
||||||
debug_printf ("uid: %u myself->uid: %u myself->gid: %u",
|
debug_printf ("uid: %u myself->uid: %u myself->gid: %u",
|
||||||
uid, myself->uid, myself->gid);
|
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");
|
debug_printf ("Nothing happens");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2686,6 +2707,22 @@ seteuid32 (__uid32_t uid)
|
||||||
cygheap->user.deimpersonate ();
|
cygheap->user.deimpersonate ();
|
||||||
|
|
||||||
/* Verify if the process token is suitable. */
|
/* 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
|
/* 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.
|
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
|
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
|
Therefore we try this shortcut now. When switching back to the
|
||||||
privileged user, we probably always want a correct (aka original)
|
privileged user, we probably always want a correct (aka original)
|
||||||
user token for this privileged user, not only in sshd. */
|
user token for this privileged user, not only in sshd. */
|
||||||
if ((uid == cygheap->user.saved_uid && usersid == cygheap->user.saved_sid ())
|
else if ((uid == cygheap->user.saved_uid
|
||||||
|| verify_token (hProcToken, usersid, groups))
|
&& usersid == cygheap->user.saved_sid ())
|
||||||
|
|| verify_token (hProcToken, usersid, groups))
|
||||||
new_token = hProcToken;
|
new_token = hProcToken;
|
||||||
/* Verify if the external token is suitable */
|
/* Verify if the external token is suitable */
|
||||||
else if (cygheap->user.external_token != NO_IMPERSONATION
|
else if (cygheap->user.external_token != NO_IMPERSONATION
|
||||||
|
@ -2763,9 +2801,12 @@ seteuid32 (__uid32_t uid)
|
||||||
|
|
||||||
if (new_token != hProcToken)
|
if (new_token != hProcToken)
|
||||||
{
|
{
|
||||||
/* Avoid having HKCU use default user */
|
if (!request_restricted_uid_switch)
|
||||||
WCHAR name[128];
|
{
|
||||||
load_registry_hive (usersid.string (name));
|
/* Avoid having HKCU use default user */
|
||||||
|
WCHAR name[128];
|
||||||
|
load_registry_hive (usersid.string (name));
|
||||||
|
}
|
||||||
|
|
||||||
/* Try setting owner to same value as user. */
|
/* Try setting owner to same value as user. */
|
||||||
if (!SetTokenInformation (new_token, TokenOwner,
|
if (!SetTokenInformation (new_token, TokenOwner,
|
||||||
|
@ -2790,6 +2831,8 @@ seteuid32 (__uid32_t uid)
|
||||||
cygheap->user.set_sid (usersid);
|
cygheap->user.set_sid (usersid);
|
||||||
cygheap->user.curr_primary_token = new_token == hProcToken ? NO_IMPERSONATION
|
cygheap->user.curr_primary_token = new_token == hProcToken ? NO_IMPERSONATION
|
||||||
: new_token;
|
: new_token;
|
||||||
|
cygheap->user.curr_token_is_restricted = false;
|
||||||
|
cygheap->user.setuid_to_restricted = false;
|
||||||
if (cygheap->user.curr_imp_token != NO_IMPERSONATION)
|
if (cygheap->user.curr_imp_token != NO_IMPERSONATION)
|
||||||
{
|
{
|
||||||
CloseHandle (cygheap->user.curr_imp_token);
|
CloseHandle (cygheap->user.curr_imp_token);
|
||||||
|
@ -2797,14 +2840,19 @@ seteuid32 (__uid32_t uid)
|
||||||
}
|
}
|
||||||
if (cygheap->user.curr_primary_token != NO_IMPERSONATION)
|
if (cygheap->user.curr_primary_token != NO_IMPERSONATION)
|
||||||
{
|
{
|
||||||
if (!DuplicateTokenEx (cygheap->user.curr_primary_token, MAXIMUM_ALLOWED,
|
/* HANDLE_FLAG_INHERIT may be missing in external token. */
|
||||||
&sec_none, SecurityImpersonation,
|
if (!SetHandleInformation (cygheap->user.curr_primary_token,
|
||||||
TokenImpersonation, &cygheap->user.curr_imp_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 ();
|
__seterrno ();
|
||||||
cygheap->user.curr_primary_token = NO_IMPERSONATION;
|
cygheap->user.curr_primary_token = NO_IMPERSONATION;
|
||||||
return -1;
|
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_primary_token);
|
||||||
set_cygwin_privileges (cygheap->user.curr_imp_token);
|
set_cygwin_privileges (cygheap->user.curr_imp_token);
|
||||||
}
|
}
|
||||||
|
@ -2835,7 +2883,11 @@ setuid32 (__uid32_t uid)
|
||||||
{
|
{
|
||||||
int ret = seteuid32 (uid);
|
int ret = seteuid32 (uid);
|
||||||
if (!ret)
|
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);
|
debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,8 @@ uinfo_init ()
|
||||||
else if (cygheap->user.issetuid ()
|
else if (cygheap->user.issetuid ()
|
||||||
&& cygheap->user.saved_uid == cygheap->user.real_uid
|
&& cygheap->user.saved_uid == cygheap->user.real_uid
|
||||||
&& cygheap->user.saved_gid == cygheap->user.real_gid
|
&& cygheap->user.saved_gid == cygheap->user.real_gid
|
||||||
&& !cygheap->user.groups.issetgroups ())
|
&& !cygheap->user.groups.issetgroups ()
|
||||||
|
&& !cygheap->user.setuid_to_restricted)
|
||||||
{
|
{
|
||||||
cygheap->user.reimpersonate ();
|
cygheap->user.reimpersonate ();
|
||||||
return;
|
return;
|
||||||
|
@ -150,6 +151,9 @@ uinfo_init ()
|
||||||
cygheap->user.internal_token = NO_IMPERSONATION;
|
cygheap->user.internal_token = NO_IMPERSONATION;
|
||||||
cygheap->user.curr_primary_token = NO_IMPERSONATION;
|
cygheap->user.curr_primary_token = NO_IMPERSONATION;
|
||||||
cygheap->user.curr_imp_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.set_saved_sid (); /* Update the original sid */
|
||||||
cygheap->user.reimpersonate ();
|
cygheap->user.reimpersonate ();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue