server: Check object's security when creating handles.
Don't check object's security when duplicating a handle of the same or lower access rights. Based on a patch by Vitaliy Margolen.
This commit is contained in:
parent
ca6fe3fbf2
commit
6a76a0ac7a
|
@ -857,7 +857,7 @@ static void test_token_attr(void)
|
|||
BYTE buf[1024];
|
||||
DWORD bufsize = sizeof(buf);
|
||||
ret = GetTokenInformation(Token, TokenUser,(void*)buf, bufsize, &bufsize);
|
||||
todo_wine ok(ret, "GetTokenInformation failed with error %d\n", GetLastError());
|
||||
ok(ret, "GetTokenInformation failed with error %d\n", GetLastError());
|
||||
CloseHandle(Token);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "handle.h"
|
||||
#include "process.h"
|
||||
#include "thread.h"
|
||||
#include "security.h"
|
||||
#include "request.h"
|
||||
|
||||
struct handle_entry
|
||||
|
@ -222,11 +223,10 @@ static obj_handle_t alloc_entry( struct handle_table *table, void *obj, unsigned
|
|||
|
||||
/* allocate a handle for an object, incrementing its refcount */
|
||||
/* return the handle, or 0 on error */
|
||||
obj_handle_t alloc_handle( struct process *process, void *ptr, unsigned int access, unsigned int attr )
|
||||
static obj_handle_t alloc_handle_no_access_check( struct process *process, void *ptr, unsigned int access, unsigned int attr )
|
||||
{
|
||||
struct object *obj = ptr;
|
||||
|
||||
access = obj->ops->map_access( obj, access );
|
||||
access &= ~RESERVED_ALL;
|
||||
if (attr & OBJ_INHERIT) access |= RESERVED_INHERIT;
|
||||
if (!process->handles)
|
||||
|
@ -237,9 +237,20 @@ obj_handle_t alloc_handle( struct process *process, void *ptr, unsigned int acce
|
|||
return alloc_entry( process->handles, obj, access );
|
||||
}
|
||||
|
||||
/* allocate a handle for an object, checking the dacl allows the process to */
|
||||
/* access it and incrementing its refcount */
|
||||
/* return the handle, or 0 on error */
|
||||
obj_handle_t alloc_handle( struct process *process, void *ptr, unsigned int access, unsigned int attr )
|
||||
{
|
||||
struct object *obj = ptr;
|
||||
access = obj->ops->map_access( obj, access );
|
||||
if (access && !check_object_access( obj, &access )) return 0;
|
||||
return alloc_handle_no_access_check( process, ptr, access, attr );
|
||||
}
|
||||
|
||||
/* allocate a global handle for an object, incrementing its refcount */
|
||||
/* return the handle, or 0 on error */
|
||||
static obj_handle_t alloc_global_handle( void *obj, unsigned int access )
|
||||
static obj_handle_t alloc_global_handle_no_access_check( void *obj, unsigned int access )
|
||||
{
|
||||
if (!global_table)
|
||||
{
|
||||
|
@ -250,6 +261,15 @@ static obj_handle_t alloc_global_handle( void *obj, unsigned int access )
|
|||
return handle_local_to_global( alloc_entry( global_table, obj, access ));
|
||||
}
|
||||
|
||||
/* allocate a global handle for an object, checking the dacl allows the */
|
||||
/* process to access it and incrementing its refcount and incrementing its refcount */
|
||||
/* return the handle, or 0 on error */
|
||||
static obj_handle_t alloc_global_handle( void *obj, unsigned int access )
|
||||
{
|
||||
if (access && !check_object_access( obj, &access )) return 0;
|
||||
return alloc_global_handle_no_access_check( obj, access );
|
||||
}
|
||||
|
||||
/* return a handle entry, or NULL if the handle is invalid */
|
||||
static struct handle_entry *get_handle( struct process *process, obj_handle_t handle )
|
||||
{
|
||||
|
@ -449,25 +469,41 @@ obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, str
|
|||
unsigned int access, unsigned int attr, unsigned int options )
|
||||
{
|
||||
obj_handle_t res;
|
||||
struct handle_entry *entry;
|
||||
unsigned int src_access;
|
||||
struct object *obj = get_handle_obj( src, src_handle, 0, NULL );
|
||||
|
||||
if (!obj) return 0;
|
||||
if (options & DUP_HANDLE_SAME_ACCESS)
|
||||
if ((entry = get_handle( src, src_handle )))
|
||||
src_access = entry->access;
|
||||
else /* pseudo-handle, give it full access */
|
||||
{
|
||||
struct handle_entry *entry = get_handle( src, src_handle );
|
||||
if (entry)
|
||||
access = entry->access;
|
||||
else /* pseudo-handle, give it full access */
|
||||
{
|
||||
access = obj->ops->map_access( obj, GENERIC_ALL );
|
||||
clear_error();
|
||||
}
|
||||
src_access = obj->ops->map_access( obj, GENERIC_ALL );
|
||||
clear_error();
|
||||
}
|
||||
access &= ~RESERVED_ALL;
|
||||
if (options & DUP_HANDLE_MAKE_GLOBAL)
|
||||
res = alloc_global_handle( obj, access );
|
||||
src_access &= ~RESERVED_ALL;
|
||||
|
||||
if (options & DUP_HANDLE_SAME_ACCESS)
|
||||
access = src_access;
|
||||
else
|
||||
res = alloc_handle( dst, obj, access, attr );
|
||||
access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL;
|
||||
|
||||
/* asking for the more access rights than src_access? */
|
||||
if (access & ~src_access)
|
||||
{
|
||||
if (options & DUP_HANDLE_MAKE_GLOBAL)
|
||||
res = alloc_global_handle( obj, access );
|
||||
else
|
||||
res = alloc_handle( dst, obj, access, attr );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (options & DUP_HANDLE_MAKE_GLOBAL)
|
||||
res = alloc_global_handle_no_access_check( obj, access );
|
||||
else
|
||||
res = alloc_handle_no_access_check( dst, obj, access, attr );
|
||||
}
|
||||
|
||||
release_object( obj );
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ extern int token_check_privileges( struct token *token, int all_required,
|
|||
unsigned int count, LUID_AND_ATTRIBUTES *usedprivs);
|
||||
extern const ACL *token_get_default_dacl( struct token *token );
|
||||
extern void security_set_thread_token( struct thread *thread, obj_handle_t handle );
|
||||
extern int check_object_access( struct object *obj, unsigned int *access );
|
||||
|
||||
static inline int thread_single_check_privilege( struct thread *thread, const LUID *priv)
|
||||
{
|
||||
|
|
|
@ -1005,6 +1005,36 @@ static void set_object_sd( struct object *obj, const struct security_descriptor
|
|||
obj->sd = pnew_sd;
|
||||
}
|
||||
|
||||
int check_object_access(struct object *obj, unsigned int *access)
|
||||
{
|
||||
GENERIC_MAPPING mapping;
|
||||
struct token *token = current->token ? current->token : current->process->token;
|
||||
LUID_AND_ATTRIBUTES priv;
|
||||
unsigned int status, priv_count = 1;
|
||||
int res;
|
||||
|
||||
mapping.GenericAll = obj->ops->map_access( obj, GENERIC_ALL );
|
||||
|
||||
if (!obj->sd)
|
||||
{
|
||||
if (*access & MAXIMUM_ALLOWED)
|
||||
*access = mapping.GenericAll;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
mapping.GenericRead = obj->ops->map_access( obj, GENERIC_READ );
|
||||
mapping.GenericWrite = obj->ops->map_access( obj, GENERIC_WRITE );
|
||||
mapping.GenericExecute = obj->ops->map_access( obj, GENERIC_EXECUTE );
|
||||
|
||||
res = token_access_check( token, obj->sd, *access, &priv, &priv_count,
|
||||
&mapping, access, &status ) == STATUS_SUCCESS &&
|
||||
status == STATUS_SUCCESS;
|
||||
|
||||
if (!res) set_error( STATUS_ACCESS_DENIED );
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* open a security token */
|
||||
DECL_HANDLER(open_token)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue