server: Track the impersonation level of tokens.
This commit is contained in:
parent
df0d625351
commit
c9b9847dce
|
@ -812,10 +812,8 @@ static void test_AccessCheck(void)
|
||||||
ret = AccessCheck(SecurityDescriptor, Token, MAXIMUM_ALLOWED, &Mapping,
|
ret = AccessCheck(SecurityDescriptor, Token, MAXIMUM_ALLOWED, &Mapping,
|
||||||
PrivSet, &PrivSetLen, &Access, &AccessStatus);
|
PrivSet, &PrivSetLen, &Access, &AccessStatus);
|
||||||
err = GetLastError();
|
err = GetLastError();
|
||||||
todo_wine {
|
|
||||||
ok(!ret && err == ERROR_BAD_IMPERSONATION_LEVEL, "AccessCheck should have failed "
|
ok(!ret && err == ERROR_BAD_IMPERSONATION_LEVEL, "AccessCheck should have failed "
|
||||||
"with ERROR_BAD_IMPERSONATION_LEVEL, instead of %d\n", err);
|
"with ERROR_BAD_IMPERSONATION_LEVEL, instead of %d\n", err);
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(Token);
|
CloseHandle(Token);
|
||||||
|
|
||||||
|
@ -1572,11 +1570,11 @@ static void test_impersonation_level(void)
|
||||||
ret = ImpersonateSelf(SecurityAnonymous);
|
ret = ImpersonateSelf(SecurityAnonymous);
|
||||||
ok(ret, "ImpersonateSelf(SecurityAnonymous) failed with error %d\n", GetLastError());
|
ok(ret, "ImpersonateSelf(SecurityAnonymous) failed with error %d\n", GetLastError());
|
||||||
ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY_SOURCE | TOKEN_IMPERSONATE | TOKEN_ADJUST_DEFAULT, TRUE, &Token);
|
ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY_SOURCE | TOKEN_IMPERSONATE | TOKEN_ADJUST_DEFAULT, TRUE, &Token);
|
||||||
todo_wine {
|
|
||||||
ok(!ret, "OpenThreadToken should have failed\n");
|
ok(!ret, "OpenThreadToken should have failed\n");
|
||||||
error = GetLastError();
|
error = GetLastError();
|
||||||
ok(error == ERROR_CANT_OPEN_ANONYMOUS, "OpenThreadToken on anonymous token should have returned ERROR_CANT_OPEN_ANONYMOUS instead of %d\n", error);
|
ok(error == ERROR_CANT_OPEN_ANONYMOUS, "OpenThreadToken on anonymous token should have returned ERROR_CANT_OPEN_ANONYMOUS instead of %d\n", error);
|
||||||
/* can't perform access check when opening object against an anonymous impersonation token */
|
/* can't perform access check when opening object against an anonymous impersonation token */
|
||||||
|
todo_wine {
|
||||||
error = RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey);
|
error = RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey);
|
||||||
ok(error == ERROR_INVALID_HANDLE, "RegOpenKeyEx should have failed with ERROR_INVALID_HANDLE instead of %d\n", error);
|
ok(error == ERROR_INVALID_HANDLE, "RegOpenKeyEx should have failed with ERROR_INVALID_HANDLE instead of %d\n", error);
|
||||||
}
|
}
|
||||||
|
@ -1592,10 +1590,8 @@ static void test_impersonation_level(void)
|
||||||
/* can't increase the impersonation level */
|
/* can't increase the impersonation level */
|
||||||
ret = DuplicateToken(Token, SecurityIdentification, &Token2);
|
ret = DuplicateToken(Token, SecurityIdentification, &Token2);
|
||||||
error = GetLastError();
|
error = GetLastError();
|
||||||
todo_wine {
|
|
||||||
ok(!ret && error == ERROR_BAD_IMPERSONATION_LEVEL,
|
ok(!ret && error == ERROR_BAD_IMPERSONATION_LEVEL,
|
||||||
"Duplicating a token and increasing the impersonation level should have failed with ERROR_BAD_IMPERSONATION_LEVEL instead of %d\n", error);
|
"Duplicating a token and increasing the impersonation level should have failed with ERROR_BAD_IMPERSONATION_LEVEL instead of %d\n", error);
|
||||||
}
|
|
||||||
/* we can query anything from an anonymous token, including the user */
|
/* we can query anything from an anonymous token, including the user */
|
||||||
ret = GetTokenInformation(Token, TokenUser, NULL, 0, &Size);
|
ret = GetTokenInformation(Token, TokenUser, NULL, 0, &Size);
|
||||||
error = GetLastError();
|
error = GetLastError();
|
||||||
|
@ -1621,9 +1617,7 @@ static void test_impersonation_level(void)
|
||||||
|
|
||||||
ret = PrivilegeCheck(Token, PrivilegeSet, &AccessGranted);
|
ret = PrivilegeCheck(Token, PrivilegeSet, &AccessGranted);
|
||||||
error = GetLastError();
|
error = GetLastError();
|
||||||
todo_wine {
|
|
||||||
ok(!ret && error == ERROR_BAD_IMPERSONATION_LEVEL, "PrivilegeCheck for SecurityAnonymous token should have failed with ERROR_BAD_IMPERSONATION_LEVEL instead of %d\n", error);
|
ok(!ret && error == ERROR_BAD_IMPERSONATION_LEVEL, "PrivilegeCheck for SecurityAnonymous token should have failed with ERROR_BAD_IMPERSONATION_LEVEL instead of %d\n", error);
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(Token);
|
CloseHandle(Token);
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ struct token
|
||||||
unsigned primary; /* is this a primary or impersonation token? */
|
unsigned primary; /* is this a primary or impersonation token? */
|
||||||
ACL *default_dacl; /* the default DACL to assign to objects created by this user */
|
ACL *default_dacl; /* the default DACL to assign to objects created by this user */
|
||||||
TOKEN_SOURCE source; /* source of the token */
|
TOKEN_SOURCE source; /* source of the token */
|
||||||
|
SECURITY_IMPERSONATION_LEVEL impersonation_level; /* impersonation level this token is capable of if non-primary token */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct privilege
|
struct privilege
|
||||||
|
@ -428,7 +429,8 @@ static struct token *create_token( unsigned primary, const SID *user,
|
||||||
const SID_AND_ATTRIBUTES *groups, unsigned int group_count,
|
const SID_AND_ATTRIBUTES *groups, unsigned int group_count,
|
||||||
const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count,
|
const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count,
|
||||||
const ACL *default_dacl, TOKEN_SOURCE source,
|
const ACL *default_dacl, TOKEN_SOURCE source,
|
||||||
const LUID *modified_id )
|
const LUID *modified_id,
|
||||||
|
SECURITY_IMPERSONATION_LEVEL impersonation_level )
|
||||||
{
|
{
|
||||||
struct token *token = alloc_object( &token_ops );
|
struct token *token = alloc_object( &token_ops );
|
||||||
if (token)
|
if (token)
|
||||||
|
@ -443,6 +445,11 @@ static struct token *create_token( unsigned primary, const SID *user,
|
||||||
list_init( &token->privileges );
|
list_init( &token->privileges );
|
||||||
list_init( &token->groups );
|
list_init( &token->groups );
|
||||||
token->primary = primary;
|
token->primary = primary;
|
||||||
|
/* primary tokens don't have impersonation levels */
|
||||||
|
if (primary)
|
||||||
|
token->impersonation_level = -1;
|
||||||
|
else
|
||||||
|
token->impersonation_level = impersonation_level;
|
||||||
token->default_dacl = NULL;
|
token->default_dacl = NULL;
|
||||||
token->primary_group = NULL;
|
token->primary_group = NULL;
|
||||||
|
|
||||||
|
@ -614,7 +621,7 @@ struct token *token_create_admin( void )
|
||||||
token = create_token( TRUE, &interactive_sid,
|
token = create_token( TRUE, &interactive_sid,
|
||||||
admin_groups, sizeof(admin_groups)/sizeof(admin_groups[0]),
|
admin_groups, sizeof(admin_groups)/sizeof(admin_groups[0]),
|
||||||
admin_privs, sizeof(admin_privs)/sizeof(admin_privs[0]),
|
admin_privs, sizeof(admin_privs)/sizeof(admin_privs[0]),
|
||||||
default_dacl, admin_source, NULL );
|
default_dacl, admin_source, NULL, -1 );
|
||||||
/* we really need a primary group */
|
/* we really need a primary group */
|
||||||
assert( token->primary_group );
|
assert( token->primary_group );
|
||||||
}
|
}
|
||||||
|
@ -1007,10 +1014,15 @@ DECL_HANDLER(open_token)
|
||||||
if (thread)
|
if (thread)
|
||||||
{
|
{
|
||||||
if (thread->token)
|
if (thread->token)
|
||||||
reply->token = alloc_handle( current->process, thread->token, req->access,
|
{
|
||||||
req->attributes );
|
if (thread->token->impersonation_level <= SecurityAnonymous)
|
||||||
|
set_error( STATUS_CANT_OPEN_ANONYMOUS );
|
||||||
|
else
|
||||||
|
reply->token = alloc_handle( current->process, thread->token,
|
||||||
|
req->access, req->attributes );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
set_error(STATUS_NO_TOKEN);
|
set_error( STATUS_NO_TOKEN );
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1023,7 +1035,7 @@ DECL_HANDLER(open_token)
|
||||||
reply->token = alloc_handle( current->process, process->token, req->access,
|
reply->token = alloc_handle( current->process, process->token, req->access,
|
||||||
req->attributes );
|
req->attributes );
|
||||||
else
|
else
|
||||||
set_error(STATUS_NO_TOKEN);
|
set_error( STATUS_NO_TOKEN );
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1114,16 +1126,30 @@ DECL_HANDLER(get_token_privileges)
|
||||||
DECL_HANDLER(duplicate_token)
|
DECL_HANDLER(duplicate_token)
|
||||||
{
|
{
|
||||||
struct token *src_token;
|
struct token *src_token;
|
||||||
|
|
||||||
|
if ((req->impersonation_level < SecurityAnonymous) ||
|
||||||
|
(req->impersonation_level > SecurityDelegation))
|
||||||
|
{
|
||||||
|
set_error( STATUS_BAD_IMPERSONATION_LEVEL );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((src_token = (struct token *)get_handle_obj( current->process, req->handle,
|
if ((src_token = (struct token *)get_handle_obj( current->process, req->handle,
|
||||||
TOKEN_DUPLICATE,
|
TOKEN_DUPLICATE,
|
||||||
&token_ops )))
|
&token_ops )))
|
||||||
{
|
{
|
||||||
/* FIXME: use req->impersonation_level */
|
const LUID *modified_id =
|
||||||
struct token *token = create_token( req->primary, src_token->user,
|
req->primary || (req->impersonation_level == src_token->impersonation_level) ?
|
||||||
NULL, 0, NULL, 0,
|
&src_token->modified_id : NULL;
|
||||||
src_token->default_dacl,
|
struct token *token = NULL;
|
||||||
src_token->source,
|
|
||||||
&src_token->modified_id );
|
if (req->primary || (req->impersonation_level <= src_token->impersonation_level))
|
||||||
|
token = create_token( req->primary, src_token->user, NULL, 0,
|
||||||
|
NULL, 0, src_token->default_dacl,
|
||||||
|
src_token->source, modified_id,
|
||||||
|
req->impersonation_level );
|
||||||
|
else set_error( STATUS_BAD_IMPERSONATION_LEVEL );
|
||||||
|
|
||||||
if (token)
|
if (token)
|
||||||
{
|
{
|
||||||
struct privilege *privilege;
|
struct privilege *privilege;
|
||||||
|
@ -1170,7 +1196,10 @@ DECL_HANDLER(check_token_privileges)
|
||||||
&token_ops )))
|
&token_ops )))
|
||||||
{
|
{
|
||||||
unsigned int count = get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES);
|
unsigned int count = get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES);
|
||||||
if (get_reply_max_size() >= count * sizeof(LUID_AND_ATTRIBUTES))
|
|
||||||
|
if (!token->primary && token->impersonation_level <= SecurityAnonymous)
|
||||||
|
set_error( STATUS_BAD_IMPERSONATION_LEVEL );
|
||||||
|
else if (get_reply_max_size() >= count * sizeof(LUID_AND_ATTRIBUTES))
|
||||||
{
|
{
|
||||||
LUID_AND_ATTRIBUTES *usedprivs = set_reply_data_size( count * sizeof(*usedprivs) );
|
LUID_AND_ATTRIBUTES *usedprivs = set_reply_data_size( count * sizeof(*usedprivs) );
|
||||||
reply->has_privileges = token_check_privileges( token, req->all_required, get_req_data(), count, usedprivs );
|
reply->has_privileges = token_check_privileges( token, req->all_required, get_req_data(), count, usedprivs );
|
||||||
|
@ -1213,6 +1242,13 @@ DECL_HANDLER(access_check)
|
||||||
release_object( token );
|
release_object( token );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* anonymous impersonation tokens can't be used */
|
||||||
|
if (token->impersonation_level <= SecurityAnonymous)
|
||||||
|
{
|
||||||
|
set_error( STATUS_BAD_IMPERSONATION_LEVEL );
|
||||||
|
release_object( token );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mapping.GenericRead = req->mapping_read;
|
mapping.GenericRead = req->mapping_read;
|
||||||
mapping.GenericWrite = req->mapping_write;
|
mapping.GenericWrite = req->mapping_write;
|
||||||
|
|
Loading…
Reference in New Issue