Commit 6a76a0ac authored by Rob Shearman's avatar Rob Shearman Committed by Alexandre Julliard

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.
parent ca6fe3fb
......@@ -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)
{
struct handle_entry *entry = get_handle( src, src_handle );
if (entry)
access = entry->access;
if ((entry = get_handle( src, src_handle )))
src_access = entry->access;
else /* pseudo-handle, give it full access */
{
access = obj->ops->map_access( obj, GENERIC_ALL );
src_access = obj->ops->map_access( obj, GENERIC_ALL );
clear_error();
}
}
access &= ~RESERVED_ALL;
src_access &= ~RESERVED_ALL;
if (options & DUP_HANDLE_SAME_ACCESS)
access = src_access;
else
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)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment