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:
parent
67f7d6872b
commit
8c5638aa5e
|
@ -208,7 +208,7 @@
|
|||
# @ stub NtEnumerateSystemEnvironmentValuesEx
|
||||
@ stdcall -syscall NtEnumerateValueKey(long long long ptr long ptr)
|
||||
@ stub NtExtendSection
|
||||
# @ stub NtFilterToken
|
||||
@ stdcall -syscall NtFilterToken(long long ptr ptr ptr ptr)
|
||||
@ stdcall -syscall NtFindAtom(ptr long ptr)
|
||||
@ stdcall -syscall NtFlushBuffersFile(long ptr)
|
||||
@ stdcall -syscall NtFlushInstructionCache(long ptr long)
|
||||
|
|
|
@ -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.@)
|
||||
*/
|
||||
|
|
|
@ -4501,6 +4501,22 @@ struct duplicate_token_reply
|
|||
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 request_header __header;
|
||||
|
@ -5646,6 +5662,7 @@ enum request
|
|||
REQ_get_token_privileges,
|
||||
REQ_check_token_privileges,
|
||||
REQ_duplicate_token,
|
||||
REQ_filter_token,
|
||||
REQ_access_check,
|
||||
REQ_get_token_sid,
|
||||
REQ_get_token_groups,
|
||||
|
@ -5933,6 +5950,7 @@ union generic_request
|
|||
struct get_token_privileges_request get_token_privileges_request;
|
||||
struct check_token_privileges_request check_token_privileges_request;
|
||||
struct duplicate_token_request duplicate_token_request;
|
||||
struct filter_token_request filter_token_request;
|
||||
struct access_check_request access_check_request;
|
||||
struct get_token_sid_request get_token_sid_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 check_token_privileges_reply check_token_privileges_reply;
|
||||
struct duplicate_token_reply duplicate_token_reply;
|
||||
struct filter_token_reply filter_token_reply;
|
||||
struct access_check_reply access_check_reply;
|
||||
struct get_token_sid_reply get_token_sid_reply;
|
||||
struct get_token_groups_reply get_token_groups_reply;
|
||||
|
@ -6281,7 +6300,7 @@ union generic_reply
|
|||
|
||||
/* ### protocol_version begin ### */
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 645
|
||||
#define SERVER_PROTOCOL_VERSION 646
|
||||
|
||||
/* ### protocol_version end ### */
|
||||
|
||||
|
|
|
@ -4288,6 +4288,11 @@ typedef enum _TOKEN_INFORMATION_CLASS {
|
|||
TOKEN_ADJUST_SESSIONID | \
|
||||
TOKEN_ADJUST_DEFAULT )
|
||||
|
||||
#define DISABLE_MAX_PRIVILEGE 0x1
|
||||
#define SANDBOX_INERT 0x2
|
||||
#define LUA_TOKEN 0x4
|
||||
#define WRITE_RESTRICTED 0x8
|
||||
|
||||
#ifndef _SECURITY_DEFINED
|
||||
#define _SECURITY_DEFINED
|
||||
|
||||
|
|
|
@ -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 NtEnumerateValueKey(HANDLE,ULONG,KEY_VALUE_INFORMATION_CLASS,PVOID,ULONG,PULONG);
|
||||
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 NtFlushBuffersFile(HANDLE,IO_STATUS_BLOCK*);
|
||||
NTSYSAPI NTSTATUS WINAPI NtFlushInstructionCache(HANDLE,LPCVOID,SIZE_T);
|
||||
|
|
|
@ -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 */
|
||||
{
|
||||
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;
|
||||
if (current->token) release_object( current->token );
|
||||
current->token = token;
|
||||
|
|
|
@ -581,7 +581,7 @@ struct process *create_process( int fd, struct process *parent, int inherit_all,
|
|||
: alloc_handle_table( process, 0 );
|
||||
/* Note: for security reasons, starting a new process does not attempt
|
||||
* 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;
|
||||
}
|
||||
if (!process->handles || !process->token) goto error;
|
||||
|
|
|
@ -3152,6 +3152,16 @@ enum caret_state
|
|||
obj_handle_t new_handle; /* duplicated handle */
|
||||
@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)
|
||||
obj_handle_t handle; /* handle to the token */
|
||||
unsigned int desired_access; /* desired access to the object */
|
||||
|
|
|
@ -340,6 +340,7 @@ DECL_HANDLER(adjust_token_privileges);
|
|||
DECL_HANDLER(get_token_privileges);
|
||||
DECL_HANDLER(check_token_privileges);
|
||||
DECL_HANDLER(duplicate_token);
|
||||
DECL_HANDLER(filter_token);
|
||||
DECL_HANDLER(access_check);
|
||||
DECL_HANDLER(get_token_sid);
|
||||
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_check_token_privileges,
|
||||
(req_handler)req_duplicate_token,
|
||||
(req_handler)req_filter_token,
|
||||
(req_handler)req_access_check,
|
||||
(req_handler)req_get_token_sid,
|
||||
(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( FIELD_OFFSET(struct duplicate_token_reply, new_handle) == 8 );
|
||||
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, desired_access) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct access_check_request, mapping_read) == 20 );
|
||||
|
|
|
@ -56,7 +56,9 @@ extern const PSID security_high_label_sid;
|
|||
extern struct token *token_create_admin(void);
|
||||
extern int token_assign_label( struct token *token, PSID label );
|
||||
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,
|
||||
const LUID_AND_ATTRIBUTES *reqprivs,
|
||||
unsigned int count, LUID_AND_ATTRIBUTES *usedprivs);
|
||||
|
|
|
@ -286,6 +286,19 @@ static int acl_is_valid( const ACL *acl, data_size_t size )
|
|||
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
|
||||
* of memory specified */
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
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 =
|
||||
primary || (impersonation_level == src_token->impersonation_level) ?
|
||||
|
@ -664,6 +705,12 @@ struct token *token_duplicate( struct token *src_token, unsigned primary,
|
|||
return NULL;
|
||||
}
|
||||
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 );
|
||||
if (src_token->primary_group == &group->sid)
|
||||
{
|
||||
|
@ -675,11 +722,14 @@ struct token *token_duplicate( struct token *src_token, unsigned primary,
|
|||
|
||||
/* copy privileges */
|
||||
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 ))
|
||||
{
|
||||
release_object( token );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (sd) default_set_sd( &token->obj, sd, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
||||
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION );
|
||||
|
@ -1312,7 +1362,7 @@ DECL_HANDLER(duplicate_token)
|
|||
TOKEN_DUPLICATE,
|
||||
&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)
|
||||
{
|
||||
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 */
|
||||
DECL_HANDLER(check_token_privileges)
|
||||
{
|
||||
|
|
|
@ -3814,6 +3814,20 @@ static void dump_duplicate_token_reply( const struct duplicate_token_reply *req
|
|||
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 )
|
||||
{
|
||||
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_check_token_privileges_request,
|
||||
(dump_func)dump_duplicate_token_request,
|
||||
(dump_func)dump_filter_token_request,
|
||||
(dump_func)dump_access_check_request,
|
||||
(dump_func)dump_get_token_sid_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_check_token_privileges_reply,
|
||||
(dump_func)dump_duplicate_token_reply,
|
||||
(dump_func)dump_filter_token_reply,
|
||||
(dump_func)dump_access_check_reply,
|
||||
(dump_func)dump_get_token_sid_reply,
|
||||
(dump_func)dump_get_token_groups_reply,
|
||||
|
@ -5197,6 +5213,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"get_token_privileges",
|
||||
"check_token_privileges",
|
||||
"duplicate_token",
|
||||
"filter_token",
|
||||
"access_check",
|
||||
"get_token_sid",
|
||||
"get_token_groups",
|
||||
|
|
Loading…
Reference in New Issue