ntdll: Implement NtFilterToken.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Michael Müller 2020-09-22 17:31:15 -05:00 committed by Alexandre Julliard
parent 67f7d6872b
commit 8c5638aa5e
12 changed files with 210 additions and 7 deletions

View File

@ -208,7 +208,7 @@
# @ stub NtEnumerateSystemEnvironmentValuesEx # @ stub NtEnumerateSystemEnvironmentValuesEx
@ stdcall -syscall NtEnumerateValueKey(long long long ptr long ptr) @ stdcall -syscall NtEnumerateValueKey(long long long ptr long ptr)
@ stub NtExtendSection @ stub NtExtendSection
# @ stub NtFilterToken @ stdcall -syscall NtFilterToken(long long ptr ptr ptr ptr)
@ stdcall -syscall NtFindAtom(ptr long ptr) @ stdcall -syscall NtFindAtom(ptr long ptr)
@ stdcall -syscall NtFlushBuffersFile(long ptr) @ stdcall -syscall NtFlushBuffersFile(long ptr)
@ stdcall -syscall NtFlushInstructionCache(long ptr long) @ stdcall -syscall NtFlushInstructionCache(long ptr long)

View File

@ -604,6 +604,69 @@ NTSTATUS WINAPI NtAdjustPrivilegesToken( HANDLE token, BOOLEAN disable, TOKEN_PR
} }
/***********************************************************************
* NtFilterToken (NTDLL.@)
*/
NTSTATUS WINAPI NtFilterToken( HANDLE token, ULONG flags, TOKEN_GROUPS *disable_sids,
TOKEN_PRIVILEGES *privileges, TOKEN_GROUPS *restrict_sids, HANDLE *new_token )
{
data_size_t privileges_len = 0;
data_size_t sids_len = 0;
SID *sids = NULL;
NTSTATUS status;
TRACE( "%p %#x %p %p %p %p\n", token, flags, disable_sids, privileges,
restrict_sids, new_token );
if (flags)
FIXME( "flags %#x unsupported\n", flags );
if (restrict_sids)
FIXME( "support for restricting sids not yet implemented\n" );
if (privileges)
privileges_len = privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
if (disable_sids)
{
DWORD len, i;
BYTE *tmp;
for (i = 0; i < disable_sids->GroupCount; i++)
{
SID *sid = disable_sids->Groups[i].Sid;
sids_len += offsetof( SID, SubAuthority[sid->SubAuthorityCount] );
}
sids = malloc( sids_len );
if (!sids) return STATUS_NO_MEMORY;
for (i = 0, tmp = (BYTE *)sids; i < disable_sids->GroupCount; i++, tmp += len)
{
SID *sid = disable_sids->Groups[i].Sid;
len = offsetof( SID, SubAuthority[sid->SubAuthorityCount] );
memcpy( tmp, disable_sids->Groups[i].Sid, len );
}
}
SERVER_START_REQ( filter_token )
{
req->handle = wine_server_obj_handle( token );
req->flags = flags;
req->privileges_size = privileges_len;
wine_server_add_data( req, privileges->Privileges, privileges_len );
wine_server_add_data( req, sids, sids_len );
status = wine_server_call( req );
if (!status) *new_token = wine_server_ptr_handle( reply->new_handle );
}
SERVER_END_REQ;
free( sids );
return status;
}
/*********************************************************************** /***********************************************************************
* NtPrivilegeCheck (NTDLL.@) * NtPrivilegeCheck (NTDLL.@)
*/ */

View File

@ -4501,6 +4501,22 @@ struct duplicate_token_reply
char __pad_12[4]; char __pad_12[4];
}; };
struct filter_token_request
{
struct request_header __header;
obj_handle_t handle;
unsigned int flags;
data_size_t privileges_size;
/* VARARG(privileges,LUID_AND_ATTRIBUTES,privileges_size); */
/* VARARG(disable_sids,SID); */
};
struct filter_token_reply
{
struct reply_header __header;
obj_handle_t new_handle;
char __pad_12[4];
};
struct access_check_request struct access_check_request
{ {
struct request_header __header; struct request_header __header;
@ -5646,6 +5662,7 @@ enum request
REQ_get_token_privileges, REQ_get_token_privileges,
REQ_check_token_privileges, REQ_check_token_privileges,
REQ_duplicate_token, REQ_duplicate_token,
REQ_filter_token,
REQ_access_check, REQ_access_check,
REQ_get_token_sid, REQ_get_token_sid,
REQ_get_token_groups, REQ_get_token_groups,
@ -5933,6 +5950,7 @@ union generic_request
struct get_token_privileges_request get_token_privileges_request; struct get_token_privileges_request get_token_privileges_request;
struct check_token_privileges_request check_token_privileges_request; struct check_token_privileges_request check_token_privileges_request;
struct duplicate_token_request duplicate_token_request; struct duplicate_token_request duplicate_token_request;
struct filter_token_request filter_token_request;
struct access_check_request access_check_request; struct access_check_request access_check_request;
struct get_token_sid_request get_token_sid_request; struct get_token_sid_request get_token_sid_request;
struct get_token_groups_request get_token_groups_request; struct get_token_groups_request get_token_groups_request;
@ -6218,6 +6236,7 @@ union generic_reply
struct get_token_privileges_reply get_token_privileges_reply; struct get_token_privileges_reply get_token_privileges_reply;
struct check_token_privileges_reply check_token_privileges_reply; struct check_token_privileges_reply check_token_privileges_reply;
struct duplicate_token_reply duplicate_token_reply; struct duplicate_token_reply duplicate_token_reply;
struct filter_token_reply filter_token_reply;
struct access_check_reply access_check_reply; struct access_check_reply access_check_reply;
struct get_token_sid_reply get_token_sid_reply; struct get_token_sid_reply get_token_sid_reply;
struct get_token_groups_reply get_token_groups_reply; struct get_token_groups_reply get_token_groups_reply;
@ -6281,7 +6300,7 @@ union generic_reply
/* ### protocol_version begin ### */ /* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 645 #define SERVER_PROTOCOL_VERSION 646
/* ### protocol_version end ### */ /* ### protocol_version end ### */

View File

@ -4288,6 +4288,11 @@ typedef enum _TOKEN_INFORMATION_CLASS {
TOKEN_ADJUST_SESSIONID | \ TOKEN_ADJUST_SESSIONID | \
TOKEN_ADJUST_DEFAULT ) TOKEN_ADJUST_DEFAULT )
#define DISABLE_MAX_PRIVILEGE 0x1
#define SANDBOX_INERT 0x2
#define LUA_TOKEN 0x4
#define WRITE_RESTRICTED 0x8
#ifndef _SECURITY_DEFINED #ifndef _SECURITY_DEFINED
#define _SECURITY_DEFINED #define _SECURITY_DEFINED

View File

@ -3044,6 +3044,7 @@ NTSYSAPI NTSTATUS WINAPI NtDuplicateToken(HANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES
NTSYSAPI NTSTATUS WINAPI NtEnumerateKey(HANDLE,ULONG,KEY_INFORMATION_CLASS,void *,DWORD,DWORD *); NTSYSAPI NTSTATUS WINAPI NtEnumerateKey(HANDLE,ULONG,KEY_INFORMATION_CLASS,void *,DWORD,DWORD *);
NTSYSAPI NTSTATUS WINAPI NtEnumerateValueKey(HANDLE,ULONG,KEY_VALUE_INFORMATION_CLASS,PVOID,ULONG,PULONG); NTSYSAPI NTSTATUS WINAPI NtEnumerateValueKey(HANDLE,ULONG,KEY_VALUE_INFORMATION_CLASS,PVOID,ULONG,PULONG);
NTSYSAPI NTSTATUS WINAPI NtExtendSection(HANDLE,PLARGE_INTEGER); NTSYSAPI NTSTATUS WINAPI NtExtendSection(HANDLE,PLARGE_INTEGER);
NTSYSAPI NTSTATUS WINAPI NtFilterToken(HANDLE,ULONG,TOKEN_GROUPS*,TOKEN_PRIVILEGES*,TOKEN_GROUPS*,HANDLE*);
NTSYSAPI NTSTATUS WINAPI NtFindAtom(const WCHAR*,ULONG,RTL_ATOM*); NTSYSAPI NTSTATUS WINAPI NtFindAtom(const WCHAR*,ULONG,RTL_ATOM*);
NTSYSAPI NTSTATUS WINAPI NtFlushBuffersFile(HANDLE,IO_STATUS_BLOCK*); NTSYSAPI NTSTATUS WINAPI NtFlushBuffersFile(HANDLE,IO_STATUS_BLOCK*);
NTSYSAPI NTSTATUS WINAPI NtFlushInstructionCache(HANDLE,LPCVOID,SIZE_T); NTSYSAPI NTSTATUS WINAPI NtFlushInstructionCache(HANDLE,LPCVOID,SIZE_T);

View File

@ -1162,7 +1162,7 @@ static int pipe_server_ioctl( struct fd *fd, ioctl_code_t code, struct async *as
if (current->process->token) /* FIXME: use the client token */ if (current->process->token) /* FIXME: use the client token */
{ {
struct token *token; struct token *token;
if (!(token = token_duplicate( current->process->token, 0, SecurityImpersonation, NULL ))) if (!(token = token_duplicate( current->process->token, 0, SecurityImpersonation, NULL, NULL, 0, NULL, 0 )))
return 0; return 0;
if (current->token) release_object( current->token ); if (current->token) release_object( current->token );
current->token = token; current->token = token;

View File

@ -581,7 +581,7 @@ struct process *create_process( int fd, struct process *parent, int inherit_all,
: alloc_handle_table( process, 0 ); : alloc_handle_table( process, 0 );
/* Note: for security reasons, starting a new process does not attempt /* Note: for security reasons, starting a new process does not attempt
* to use the current impersonation token for the new process */ * to use the current impersonation token for the new process */
process->token = token_duplicate( parent->token, TRUE, 0, NULL ); process->token = token_duplicate( parent->token, TRUE, 0, NULL, NULL, 0, NULL, 0 );
process->affinity = parent->affinity; process->affinity = parent->affinity;
} }
if (!process->handles || !process->token) goto error; if (!process->handles || !process->token) goto error;

View File

@ -3152,6 +3152,16 @@ enum caret_state
obj_handle_t new_handle; /* duplicated handle */ obj_handle_t new_handle; /* duplicated handle */
@END @END
@REQ(filter_token)
obj_handle_t handle; /* handle to the token to duplicate */
unsigned int flags; /* flags */
data_size_t privileges_size; /* size of privileges */
VARARG(privileges,LUID_AND_ATTRIBUTES,privileges_size); /* privileges to remove from new token */
VARARG(disable_sids,SID); /* array of groups to remove from new token */
@REPLY
obj_handle_t new_handle; /* filtered handle */
@END
@REQ(access_check) @REQ(access_check)
obj_handle_t handle; /* handle to the token */ obj_handle_t handle; /* handle to the token */
unsigned int desired_access; /* desired access to the object */ unsigned int desired_access; /* desired access to the object */

View File

@ -340,6 +340,7 @@ DECL_HANDLER(adjust_token_privileges);
DECL_HANDLER(get_token_privileges); DECL_HANDLER(get_token_privileges);
DECL_HANDLER(check_token_privileges); DECL_HANDLER(check_token_privileges);
DECL_HANDLER(duplicate_token); DECL_HANDLER(duplicate_token);
DECL_HANDLER(filter_token);
DECL_HANDLER(access_check); DECL_HANDLER(access_check);
DECL_HANDLER(get_token_sid); DECL_HANDLER(get_token_sid);
DECL_HANDLER(get_token_groups); DECL_HANDLER(get_token_groups);
@ -626,6 +627,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_get_token_privileges, (req_handler)req_get_token_privileges,
(req_handler)req_check_token_privileges, (req_handler)req_check_token_privileges,
(req_handler)req_duplicate_token, (req_handler)req_duplicate_token,
(req_handler)req_filter_token,
(req_handler)req_access_check, (req_handler)req_access_check,
(req_handler)req_get_token_sid, (req_handler)req_get_token_sid,
(req_handler)req_get_token_groups, (req_handler)req_get_token_groups,
@ -1991,6 +1993,12 @@ C_ASSERT( FIELD_OFFSET(struct duplicate_token_request, impersonation_level) == 2
C_ASSERT( sizeof(struct duplicate_token_request) == 32 ); C_ASSERT( sizeof(struct duplicate_token_request) == 32 );
C_ASSERT( FIELD_OFFSET(struct duplicate_token_reply, new_handle) == 8 ); C_ASSERT( FIELD_OFFSET(struct duplicate_token_reply, new_handle) == 8 );
C_ASSERT( sizeof(struct duplicate_token_reply) == 16 ); C_ASSERT( sizeof(struct duplicate_token_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct filter_token_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct filter_token_request, flags) == 16 );
C_ASSERT( FIELD_OFFSET(struct filter_token_request, privileges_size) == 20 );
C_ASSERT( sizeof(struct filter_token_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct filter_token_reply, new_handle) == 8 );
C_ASSERT( sizeof(struct filter_token_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct access_check_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct access_check_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct access_check_request, desired_access) == 16 ); C_ASSERT( FIELD_OFFSET(struct access_check_request, desired_access) == 16 );
C_ASSERT( FIELD_OFFSET(struct access_check_request, mapping_read) == 20 ); C_ASSERT( FIELD_OFFSET(struct access_check_request, mapping_read) == 20 );

View File

@ -56,7 +56,9 @@ extern const PSID security_high_label_sid;
extern struct token *token_create_admin(void); extern struct token *token_create_admin(void);
extern int token_assign_label( struct token *token, PSID label ); extern int token_assign_label( struct token *token, PSID label );
extern struct token *token_duplicate( struct token *src_token, unsigned primary, extern struct token *token_duplicate( struct token *src_token, unsigned primary,
int impersonation_level, const struct security_descriptor *sd ); int impersonation_level, const struct security_descriptor *sd,
const LUID_AND_ATTRIBUTES *remove_privs, unsigned int remove_priv_count,
const SID *remove_groups, unsigned int remove_group_count );
extern int token_check_privileges( struct token *token, int all_required, extern int token_check_privileges( struct token *token, int all_required,
const LUID_AND_ATTRIBUTES *reqprivs, const LUID_AND_ATTRIBUTES *reqprivs,
unsigned int count, LUID_AND_ATTRIBUTES *usedprivs); unsigned int count, LUID_AND_ATTRIBUTES *usedprivs);

View File

@ -286,6 +286,19 @@ static int acl_is_valid( const ACL *acl, data_size_t size )
return TRUE; return TRUE;
} }
static unsigned int get_sid_count( const SID *sid, data_size_t size )
{
unsigned int count;
for (count = 0; size >= sizeof(SID) && security_sid_len( sid ) <= size; count++)
{
size -= security_sid_len( sid );
sid = (const SID *)((char *)sid + security_sid_len( sid ));
}
return count;
}
/* checks whether all members of a security descriptor fit inside the size /* checks whether all members of a security descriptor fit inside the size
* of memory specified */ * of memory specified */
int sd_is_valid( const struct security_descriptor *sd, data_size_t size ) int sd_is_valid( const struct security_descriptor *sd, data_size_t size )
@ -627,8 +640,36 @@ static struct token *create_token( unsigned primary, const SID *user,
return token; return token;
} }
static int filter_group( struct group *group, const SID *filter, unsigned int count )
{
unsigned int i;
for (i = 0; i < count; i++)
{
if (security_equal_sid( &group->sid, filter )) return 1;
filter = (const SID *)((char *)filter + security_sid_len( filter ));
}
return 0;
}
static int filter_privilege( struct privilege *privilege, const LUID_AND_ATTRIBUTES *filter, unsigned int count )
{
unsigned int i;
for (i = 0; i < count; i++)
{
if (!memcmp( &privilege->luid, &filter[i].Luid, sizeof(LUID) ))
return 1;
}
return 0;
}
struct token *token_duplicate( struct token *src_token, unsigned primary, struct token *token_duplicate( struct token *src_token, unsigned primary,
int impersonation_level, const struct security_descriptor *sd ) int impersonation_level, const struct security_descriptor *sd,
const LUID_AND_ATTRIBUTES *remove_privs, unsigned int remove_priv_count,
const SID *remove_groups, unsigned int remove_group_count)
{ {
const luid_t *modified_id = const luid_t *modified_id =
primary || (impersonation_level == src_token->impersonation_level) ? primary || (impersonation_level == src_token->impersonation_level) ?
@ -664,6 +705,12 @@ struct token *token_duplicate( struct token *src_token, unsigned primary,
return NULL; return NULL;
} }
memcpy( newgroup, group, size ); memcpy( newgroup, group, size );
if (filter_group( group, remove_groups, remove_group_count ))
{
newgroup->enabled = 0;
newgroup->def = 0;
newgroup->deny_only = 1;
}
list_add_tail( &token->groups, &newgroup->entry ); list_add_tail( &token->groups, &newgroup->entry );
if (src_token->primary_group == &group->sid) if (src_token->primary_group == &group->sid)
{ {
@ -675,11 +722,14 @@ struct token *token_duplicate( struct token *src_token, unsigned primary,
/* copy privileges */ /* copy privileges */
LIST_FOR_EACH_ENTRY( privilege, &src_token->privileges, struct privilege, entry ) LIST_FOR_EACH_ENTRY( privilege, &src_token->privileges, struct privilege, entry )
{
if (filter_privilege( privilege, remove_privs, remove_priv_count )) continue;
if (!privilege_add( token, &privilege->luid, privilege->enabled )) if (!privilege_add( token, &privilege->luid, privilege->enabled ))
{ {
release_object( token ); release_object( token );
return NULL; return NULL;
} }
}
if (sd) default_set_sd( &token->obj, sd, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | if (sd) default_set_sd( &token->obj, sd, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION ); DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION );
@ -1312,7 +1362,7 @@ DECL_HANDLER(duplicate_token)
TOKEN_DUPLICATE, TOKEN_DUPLICATE,
&token_ops ))) &token_ops )))
{ {
struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd ); struct token *token = token_duplicate( src_token, req->primary, req->impersonation_level, sd, NULL, 0, NULL, 0 );
if (token) if (token)
{ {
reply->new_handle = alloc_handle_no_access_check( current->process, token, req->access, objattr->attributes ); reply->new_handle = alloc_handle_no_access_check( current->process, token, req->access, objattr->attributes );
@ -1322,6 +1372,34 @@ DECL_HANDLER(duplicate_token)
} }
} }
/* creates a restricted version of a token */
DECL_HANDLER(filter_token)
{
struct token *src_token;
if ((src_token = (struct token *)get_handle_obj( current->process, req->handle, TOKEN_DUPLICATE, &token_ops )))
{
const LUID_AND_ATTRIBUTES *filter_privileges = get_req_data();
unsigned int priv_count, group_count;
const SID *filter_groups;
struct token *token;
priv_count = min( req->privileges_size, get_req_data_size() ) / sizeof(LUID_AND_ATTRIBUTES);
filter_groups = (const SID *)((char *)filter_privileges + priv_count * sizeof(LUID_AND_ATTRIBUTES));
group_count = get_sid_count( filter_groups, get_req_data_size() - priv_count * sizeof(LUID_AND_ATTRIBUTES) );
token = token_duplicate( src_token, src_token->primary, src_token->impersonation_level, NULL,
filter_privileges, priv_count, filter_groups, group_count );
if (token)
{
unsigned int access = get_handle_access( current->process, req->handle );
reply->new_handle = alloc_handle_no_access_check( current->process, token, access, 0 );
release_object( token );
}
release_object( src_token );
}
}
/* checks the specified privileges are held by the token */ /* checks the specified privileges are held by the token */
DECL_HANDLER(check_token_privileges) DECL_HANDLER(check_token_privileges)
{ {

View File

@ -3814,6 +3814,20 @@ static void dump_duplicate_token_reply( const struct duplicate_token_reply *req
fprintf( stderr, " new_handle=%04x", req->new_handle ); fprintf( stderr, " new_handle=%04x", req->new_handle );
} }
static void dump_filter_token_request( const struct filter_token_request *req )
{
fprintf( stderr, " handle=%04x", req->handle );
fprintf( stderr, ", flags=%08x", req->flags );
fprintf( stderr, ", privileges_size=%u", req->privileges_size );
dump_varargs_LUID_AND_ATTRIBUTES( ", privileges=", min(cur_size,req->privileges_size) );
dump_varargs_SID( ", disable_sids=", cur_size );
}
static void dump_filter_token_reply( const struct filter_token_reply *req )
{
fprintf( stderr, " new_handle=%04x", req->new_handle );
}
static void dump_access_check_request( const struct access_check_request *req ) static void dump_access_check_request( const struct access_check_request *req )
{ {
fprintf( stderr, " handle=%04x", req->handle ); fprintf( stderr, " handle=%04x", req->handle );
@ -4631,6 +4645,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_token_privileges_request, (dump_func)dump_get_token_privileges_request,
(dump_func)dump_check_token_privileges_request, (dump_func)dump_check_token_privileges_request,
(dump_func)dump_duplicate_token_request, (dump_func)dump_duplicate_token_request,
(dump_func)dump_filter_token_request,
(dump_func)dump_access_check_request, (dump_func)dump_access_check_request,
(dump_func)dump_get_token_sid_request, (dump_func)dump_get_token_sid_request,
(dump_func)dump_get_token_groups_request, (dump_func)dump_get_token_groups_request,
@ -4914,6 +4929,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_token_privileges_reply, (dump_func)dump_get_token_privileges_reply,
(dump_func)dump_check_token_privileges_reply, (dump_func)dump_check_token_privileges_reply,
(dump_func)dump_duplicate_token_reply, (dump_func)dump_duplicate_token_reply,
(dump_func)dump_filter_token_reply,
(dump_func)dump_access_check_reply, (dump_func)dump_access_check_reply,
(dump_func)dump_get_token_sid_reply, (dump_func)dump_get_token_sid_reply,
(dump_func)dump_get_token_groups_reply, (dump_func)dump_get_token_groups_reply,
@ -5197,6 +5213,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"get_token_privileges", "get_token_privileges",
"check_token_privileges", "check_token_privileges",
"duplicate_token", "duplicate_token",
"filter_token",
"access_check", "access_check",
"get_token_sid", "get_token_sid",
"get_token_groups", "get_token_groups",