123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972 |
- /*
- * Server-side handle management
- *
- * Copyright (C) 1998 Alexandre Julliard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
- #include "config.h"
- #include "wine/port.h"
- #include <assert.h>
- #include <limits.h>
- #include <string.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include "ntstatus.h"
- #define WIN32_NO_STATUS
- #include "windef.h"
- #include "winternl.h"
- #include "handle.h"
- #include "process.h"
- #include "thread.h"
- #include "security.h"
- #include "device.h"
- #include "request.h"
- struct handle_entry
- {
- struct object *ptr; /* object */
- unsigned int access; /* access rights */
- };
- struct handle_table
- {
- struct object obj; /* object header */
- struct process *process; /* process owning this table */
- int count; /* number of allocated entries */
- int last; /* last used entry */
- int free; /* first entry that may be free */
- struct handle_entry *entries; /* handle entries */
- };
- static struct handle_table *global_table;
- /* reserved handle access rights */
- #define RESERVED_SHIFT 26
- #define RESERVED_INHERIT (HANDLE_FLAG_INHERIT << RESERVED_SHIFT)
- #define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT)
- #define RESERVED_ALL (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT)
- #define MIN_HANDLE_ENTRIES 32
- #define MAX_HANDLE_ENTRIES 0x00ffffff
- /* handle to table index conversion */
- /* handles are a multiple of 4 under NT; handle 0 is not used */
- static inline obj_handle_t index_to_handle( int index )
- {
- return (obj_handle_t)((index + 1) << 2);
- }
- static inline int handle_to_index( obj_handle_t handle )
- {
- return (handle >> 2) - 1;
- }
- /* global handle conversion */
- #define HANDLE_OBFUSCATOR 0x544a4def
- static inline int handle_is_global( obj_handle_t handle)
- {
- return (handle ^ HANDLE_OBFUSCATOR) <= (MAX_HANDLE_ENTRIES << 2);
- }
- static inline obj_handle_t handle_local_to_global( obj_handle_t handle )
- {
- if (!handle) return 0;
- return handle ^ HANDLE_OBFUSCATOR;
- }
- static inline obj_handle_t handle_global_to_local( obj_handle_t handle )
- {
- return handle ^ HANDLE_OBFUSCATOR;
- }
- /* grab an object and increment its handle count */
- static struct object *grab_object_for_handle( struct object *obj )
- {
- obj->handle_count++;
- return grab_object( obj );
- }
- /* release an object and decrement its handle count */
- static void release_object_from_handle( struct object *obj )
- {
- assert( obj->handle_count );
- obj->handle_count--;
- release_object( obj );
- }
- static void handle_table_dump( struct object *obj, int verbose );
- static void handle_table_destroy( struct object *obj );
- static const struct object_ops handle_table_ops =
- {
- sizeof(struct handle_table), /* size */
- handle_table_dump, /* dump */
- no_get_type, /* get_type */
- no_add_queue, /* add_queue */
- NULL, /* remove_queue */
- NULL, /* signaled */
- NULL, /* get_esync_fd */
- NULL, /* satisfied */
- no_signal, /* signal */
- no_get_fd, /* get_fd */
- no_map_access, /* map_access */
- default_get_sd, /* get_sd */
- default_set_sd, /* set_sd */
- no_lookup_name, /* lookup_name */
- no_link_name, /* link_name */
- NULL, /* unlink_name */
- no_open_file, /* open_file */
- no_kernel_obj_list, /* get_kernel_obj_list */
- no_alloc_handle, /* alloc_handle */
- no_close_handle, /* close_handle */
- handle_table_destroy /* destroy */
- };
- /* dump a handle table */
- static void handle_table_dump( struct object *obj, int verbose )
- {
- int i;
- struct handle_table *table = (struct handle_table *)obj;
- struct handle_entry *entry;
- assert( obj->ops == &handle_table_ops );
- fprintf( stderr, "Handle table last=%d count=%d process=%p\n",
- table->last, table->count, table->process );
- if (!verbose) return;
- entry = table->entries;
- for (i = 0; i <= table->last; i++, entry++)
- {
- if (!entry->ptr) continue;
- fprintf( stderr, " %04x: %p %08x ",
- index_to_handle(i), entry->ptr, entry->access );
- dump_object_name( entry->ptr );
- entry->ptr->ops->dump( entry->ptr, 0 );
- }
- }
- /* destroy a handle table */
- static void handle_table_destroy( struct object *obj )
- {
- int i;
- struct handle_table *table = (struct handle_table *)obj;
- struct handle_entry *entry;
- assert( obj->ops == &handle_table_ops );
- /* first notify all objects that handles are being closed */
- if (table->process)
- {
- for (i = 0, entry = table->entries; i <= table->last; i++, entry++)
- {
- struct object *obj = entry->ptr;
- if (obj) obj->ops->close_handle( obj, table->process, index_to_handle(i) );
- }
- }
- for (i = 0, entry = table->entries; i <= table->last; i++, entry++)
- {
- struct object *obj = entry->ptr;
- entry->ptr = NULL;
- if (obj) release_object_from_handle( obj );
- }
- free( table->entries );
- }
- /* close all the process handles and free the handle table */
- void close_process_handles( struct process *process )
- {
- struct handle_table *table = process->handles;
- process->handles = NULL;
- if (table) release_object( table );
- }
- /* allocate a new handle table */
- struct handle_table *alloc_handle_table( struct process *process, int count )
- {
- struct handle_table *table;
- if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
- if (!(table = alloc_object( &handle_table_ops )))
- return NULL;
- table->process = process;
- table->count = count;
- table->last = -1;
- table->free = 0;
- if ((table->entries = mem_alloc( count * sizeof(*table->entries) ))) return table;
- release_object( table );
- return NULL;
- }
- /* grow a handle table */
- static int grow_handle_table( struct handle_table *table )
- {
- struct handle_entry *new_entries;
- int count = min( table->count * 2, MAX_HANDLE_ENTRIES );
- if (count == table->count ||
- !(new_entries = realloc( table->entries, count * sizeof(struct handle_entry) )))
- {
- set_error( STATUS_INSUFFICIENT_RESOURCES );
- return 0;
- }
- table->entries = new_entries;
- table->count = count;
- return 1;
- }
- /* allocate the first free entry in the handle table */
- static obj_handle_t alloc_entry( struct handle_table *table, struct object *obj, unsigned int access )
- {
- struct handle_entry *entry = table->entries + table->free;
- int i;
- for (i = table->free; i <= table->last; i++, entry++) if (!entry->ptr) goto found;
- if (i >= table->count)
- {
- if (!grow_handle_table( table )) return 0;
- entry = table->entries + i; /* the entries may have moved */
- }
- table->last = i;
- found:
- table->free = i + 1;
- entry->ptr = grab_object_for_handle( obj );
- entry->access = access;
- if (table->process)
- obj->ops->alloc_handle( obj, table->process, index_to_handle(i) );
- return index_to_handle(i);
- }
- /* allocate a handle for an object, incrementing its refcount */
- static obj_handle_t alloc_handle_entry( struct process *process, void *ptr,
- unsigned int access, unsigned int attr )
- {
- struct object *obj = ptr;
- obj_handle_t res;
- assert( !(access & RESERVED_ALL) );
- if (attr & OBJ_INHERIT) access |= RESERVED_INHERIT;
- if (attr & OBJ_FROM_KERNEL)
- {
- if (current->process == process && process->is_kernel && current->attached_process && !(attr & OBJ_KERNEL_HANDLE))
- {
- process = current->attached_process;
- }
- }
- if (!process->handles)
- {
- set_error( STATUS_PROCESS_IS_TERMINATING );
- return 0;
- }
- res = alloc_entry( process->handles, obj, access );
- if (process->is_kernel)
- res |= KERNEL_HANDLE_FLAG;
- return res;
- }
- void queue_handle_callback(struct process *process, struct object *obj, unsigned int access, obj_handle_t res)
- {
- if (is_process(obj) || is_thread(obj))
- {
- krnl_cbdata_t cbdata;
- cbdata.cb_type = SERVER_CALLBACK_HANDLE_EVENT;
- cbdata.handle_event.op_type = is_process(obj) ? CREATE_PROC : CREATE_THRD;
- cbdata.handle_event.access = access;
- cbdata.handle_event.status = get_error();
- cbdata.handle_event.target_pid = process->id;
- grab_object(obj);
- cbdata.handle_event.object = (obj_handle_t) (((unsigned long int)obj) >> 32);
- cbdata.handle_event.padding = (unsigned int) (unsigned long int) obj;
- queue_callback(&cbdata, NULL, NULL);
- }
- }
- /* allocate a handle for an object, incrementing its refcount */
- /* return the handle, or 0 on error */
- obj_handle_t alloc_handle_no_access_check( struct process *process, void *ptr, unsigned int access, unsigned int attr )
- {
- struct object *obj = ptr;
- obj_handle_t res;
- if (access & MAXIMUM_ALLOWED) access = GENERIC_ALL;
- access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL;
- res = alloc_handle_entry( process, ptr, access, attr );
- queue_handle_callback(process, obj, access, res);
- return res;
- }
- /* 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;
- obj_handle_t res = 0;
- access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL;
- if (!access || check_object_access( obj, &access ))
- res = alloc_handle_entry( process, ptr, access, attr );
- queue_handle_callback(process, obj, access, res);
- return res;
- }
- /* allocate a global handle for an object, incrementing its refcount */
- /* return the handle, or 0 on error */
- static obj_handle_t alloc_global_handle_no_access_check( void *obj, unsigned int access )
- {
- if (!global_table)
- {
- if (!(global_table = alloc_handle_table( NULL, 0 )))
- return 0;
- make_object_static( &global_table->obj );
- }
- 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 )
- {
- struct handle_table *table = process->handles;
- struct handle_entry *entry;
- int index;
- if (handle == 0)
- return NULL;
- if (handle_is_global(handle))
- {
- handle = handle_global_to_local(handle);
- table = global_table;
- }
- if (process->is_kernel)
- {
- if (handle & KERNEL_HANDLE_FLAG)
- handle &= ~KERNEL_HANDLE_FLAG;
- else
- {
- struct thread *client_thread;
- if (!process->dev_mgr)
- {
- set_error( STATUS_INVALID_HANDLE );
- return NULL;
- }
- if (current->attached_process)
- {
- process = current->attached_process;
- }
- else if ((client_thread = device_manager_client_thread(process->dev_mgr, current)))
- {
- process = client_thread->process;
- release_object(client_thread);
- }
- else
- {
- set_error( STATUS_INVALID_HANDLE );
- return NULL;
- }
- }
- }
- if (!table) return NULL;
- index = handle_to_index( handle );
- if (index < 0) return NULL;
- if (index > table->last) return NULL;
- entry = table->entries + index;
- if (!entry->ptr) return NULL;
- return entry;
- }
- /* attempt to shrink a table */
- static void shrink_handle_table( struct handle_table *table )
- {
- struct handle_entry *entry = table->entries + table->last;
- struct handle_entry *new_entries;
- int count = table->count;
- while (table->last >= 0)
- {
- if (entry->ptr) break;
- table->last--;
- entry--;
- }
- if (table->last >= count / 4) return; /* no need to shrink */
- if (count < MIN_HANDLE_ENTRIES * 2) return; /* too small to shrink */
- count /= 2;
- if (!(new_entries = realloc( table->entries, count * sizeof(*new_entries) ))) return;
- table->count = count;
- table->entries = new_entries;
- }
- /* copy the handle table of the parent process */
- /* return 1 if OK, 0 on error */
- struct handle_table *copy_handle_table( struct process *process, struct process *parent )
- {
- struct handle_table *parent_table = parent->handles;
- struct handle_table *table;
- int i;
- assert( parent_table );
- assert( parent_table->obj.ops == &handle_table_ops );
- if (!(table = alloc_handle_table( process, parent_table->count )))
- return NULL;
- if ((table->last = parent_table->last) >= 0)
- {
- struct handle_entry *ptr = table->entries;
- memcpy( ptr, parent_table->entries, (table->last + 1) * sizeof(struct handle_entry) );
- for (i = 0; i <= table->last; i++, ptr++)
- {
- if (!ptr->ptr) continue;
- if (ptr->access & RESERVED_INHERIT)
- {
- ptr->ptr->ops->alloc_handle( ptr->ptr, process, index_to_handle(i) );
- grab_object_for_handle( ptr->ptr );
- }
- else ptr->ptr = NULL; /* don't inherit this entry */
- }
- }
- /* attempt to shrink the table */
- shrink_handle_table( table );
- return table;
- }
- /* close a handle and decrement the refcount of the associated object */
- unsigned int close_handle( struct process *process, obj_handle_t handle )
- {
- struct handle_table *table;
- struct handle_entry *entry;
- struct object *obj;
- if (!(entry = get_handle( process, handle ))) return STATUS_INVALID_HANDLE;
- if (entry->access & RESERVED_CLOSE_PROTECT) return STATUS_HANDLE_NOT_CLOSABLE;
- obj = entry->ptr;
- if (!obj->ops->close_handle( obj, process, handle )) return STATUS_HANDLE_NOT_CLOSABLE;
- entry->ptr = NULL;
- table = handle_is_global(handle) ? global_table : process->handles;
- if (entry < table->entries + table->free) table->free = entry - table->entries;
- if (entry == table->entries + table->last) shrink_handle_table( table );
- release_object_from_handle( obj );
- return STATUS_SUCCESS;
- }
- /* retrieve the object corresponding to one of the magic pseudo-handles */
- static inline struct object *get_magic_handle( obj_handle_t handle )
- {
- switch(handle)
- {
- case 0xfffffffa: /* current thread impersonation token pseudo-handle */
- return (struct object *)thread_get_impersonation_token( current );
- case 0xfffffffb: /* current thread token pseudo-handle */
- return (struct object *)current->token;
- case 0xfffffffc: /* current process token pseudo-handle */
- return (struct object *)current->process->token;
- case 0xfffffffe: /* current thread pseudo-handle */
- return ¤t->obj;
- case 0x7fffffff: /* current process pseudo-handle */
- case 0xffffffff: /* current process pseudo-handle */
- return (struct object *)current->process;
- default:
- return NULL;
- }
- }
- /* retrieve the object corresponding to a handle, incrementing its refcount */
- struct object *get_handle_obj( struct process *process, obj_handle_t handle,
- unsigned int access, const struct object_ops *ops )
- {
- struct handle_entry *entry;
- struct object *obj;
- if (!(obj = get_magic_handle( handle )))
- {
- if (!(entry = get_handle( process, handle )))
- {
- set_error( STATUS_INVALID_HANDLE );
- return NULL;
- }
- obj = entry->ptr;
- if (ops && (obj->ops != ops))
- {
- set_error( STATUS_OBJECT_TYPE_MISMATCH ); /* not the right type */
- return NULL;
- }
- if ((entry->access & access) != access)
- {
- set_error( STATUS_ACCESS_DENIED );
- return NULL;
- }
- }
- else if (ops && (obj->ops != ops))
- {
- set_error( STATUS_OBJECT_TYPE_MISMATCH ); /* not the right type */
- return NULL;
- }
- return grab_object( obj );
- }
- /* retrieve the access rights of a given handle */
- unsigned int get_handle_access( struct process *process, obj_handle_t handle )
- {
- struct handle_entry *entry;
- if (get_magic_handle( handle )) return ~RESERVED_ALL; /* magic handles have all access rights */
- if (!(entry = get_handle( process, handle ))) return 0;
- return entry->access & ~RESERVED_ALL;
- }
- /* find the first inherited handle of the given type */
- /* this is needed for window stations and desktops (don't ask...) */
- obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops )
- {
- struct handle_table *table = process->handles;
- struct handle_entry *ptr;
- int i;
- if (!table) return 0;
- for (i = 0, ptr = table->entries; i <= table->last; i++, ptr++)
- {
- if (!ptr->ptr) continue;
- if (ptr->ptr->ops != ops) continue;
- if (ptr->access & RESERVED_INHERIT) return index_to_handle(i);
- }
- return 0;
- }
- /* enumerate handles of a given type */
- /* this is needed for window stations and desktops */
- obj_handle_t enumerate_handles( struct process *process, const struct object_ops *ops,
- obj_handle_t *index, struct object **obj )
- {
- struct handle_table *table = process->handles;
- unsigned int i;
- struct handle_entry *entry;
- if (!table) return 0;
- for (i = *index, entry = &table->entries[i]; i <= table->last; i++, entry++)
- {
- if (!entry->ptr) continue;
- if (entry->ptr->ops != ops) continue;
- *index = i + 1;
- if (obj) *obj = grab_object( entry->ptr );
- return index_to_handle(i);
- }
- return 0;
- }
- /* get/set the handle reserved flags */
- /* return the old flags (or -1 on error) */
- static int set_handle_flags( struct process *process, obj_handle_t handle, int mask, int flags )
- {
- struct handle_entry *entry;
- unsigned int old_access;
- if (get_magic_handle( handle ))
- {
- /* we can retrieve but not set info for magic handles */
- if (mask) set_error( STATUS_ACCESS_DENIED );
- return 0;
- }
- if (!(entry = get_handle( process, handle )))
- {
- set_error( STATUS_INVALID_HANDLE );
- return -1;
- }
- old_access = entry->access;
- mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
- flags = (flags << RESERVED_SHIFT) & mask;
- entry->access = (entry->access & ~mask) | flags;
- return (old_access & RESERVED_ALL) >> RESERVED_SHIFT;
- }
- /* duplicate a handle */
- obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, struct process *dst,
- 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 ((entry = get_handle( src, src_handle )))
- src_access = entry->access;
- else /* pseudo-handle, give it full access */
- src_access = obj->ops->map_access( obj, GENERIC_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 if ((options & DUP_HANDLE_CLOSE_SOURCE) && src == dst &&
- entry && !(entry->access & RESERVED_CLOSE_PROTECT))
- {
- if (attr & OBJ_INHERIT) access |= RESERVED_INHERIT;
- entry->access = access;
- res = src_handle;
- }
- else
- res = alloc_handle_entry( dst, obj, access, attr );
- }
- release_object( obj );
- return res;
- }
- /* open a new handle to an existing object */
- obj_handle_t open_object( struct process *process, obj_handle_t parent, unsigned int access,
- const struct object_ops *ops, const struct unicode_str *name,
- unsigned int attributes )
- {
- obj_handle_t handle = 0;
- struct object *obj, *root = NULL;
- if (name->len >= 65534)
- {
- set_error( STATUS_OBJECT_NAME_INVALID );
- return 0;
- }
- if (parent)
- {
- if (name->len)
- root = get_directory_obj( process, parent );
- else /* opening the object itself can work for non-directories too */
- root = get_handle_obj( process, parent, 0, NULL );
- if (!root) return 0;
- }
- if ((obj = open_named_object( root, ops, name, attributes )))
- {
- handle = alloc_handle( process, obj, access, attributes );
- release_object( obj );
- }
- if (root) release_object( root );
- return handle;
- }
- /* return the size of the handle table of a given process */
- unsigned int get_handle_table_count( struct process *process )
- {
- if (!process->handles) return 0;
- return process->handles->count;
- }
- /* open a handle */
- DECL_HANDLER(open_handle)
- {
- struct unicode_str name = get_req_unicode_str();
- reply->handle = open_object( current->process, req->rootdir, req->access,
- NULL, &name, req->attributes );
- }
- /* close a handle */
- DECL_HANDLER(close_handle)
- {
- unsigned int err = close_handle( current->process, req->handle );
- set_error( err );
- }
- /* set a handle information */
- DECL_HANDLER(set_handle_info)
- {
- reply->old_flags = set_handle_flags( current->process, req->handle, req->mask, req->flags );
- }
- /* duplicate a handle */
- DECL_HANDLER(dup_handle)
- {
- struct process *src, *dst = NULL;
- reply->handle = 0;
- if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
- {
- if (req->options & DUP_HANDLE_MAKE_GLOBAL)
- {
- reply->handle = duplicate_handle( src, req->src_handle, NULL,
- req->access, req->attributes, req->options );
- }
- else if ((dst = get_process_from_handle( req->dst_process, PROCESS_DUP_HANDLE )))
- {
- reply->handle = duplicate_handle( src, req->src_handle, dst,
- req->access, req->attributes, req->options );
- {
- struct object *obj = get_handle_obj( src, req->src_handle, 0, NULL );
- if (is_process(obj) || is_thread(obj))
- {
- krnl_cbdata_t cbdata;
- cbdata.cb_type = SERVER_CALLBACK_HANDLE_EVENT;
- cbdata.handle_event.op_type = is_process(obj) ? DUP_PROC : DUP_THRD;
- cbdata.handle_event.access = req->access;
- cbdata.handle_event.status = get_error();
- grab_object(obj);
- cbdata.handle_event.object = (obj_handle_t) (((unsigned long int)obj) >> 32);
- cbdata.handle_event.padding = (unsigned int) (unsigned long int) obj;
- cbdata.handle_event.source_pid = src->id;
- cbdata.handle_event.target_pid = dst->id;
- queue_callback(&cbdata, NULL, NULL);
- }
- release_object(obj);
- }
- release_object( dst );
- }
- /* close the handle no matter what happened */
- if ((req->options & DUP_HANDLE_CLOSE_SOURCE) && (src != dst || req->src_handle != reply->handle))
- reply->closed = !close_handle( src, req->src_handle );
- reply->self = (src == current->process);
- release_object( src );
- }
- }
- DECL_HANDLER(get_object_info)
- {
- struct object *obj;
- WCHAR *name;
- if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL ))) return;
- reply->access = get_handle_access( current->process, req->handle );
- reply->ref_count = obj->refcount;
- reply->handle_count = obj->handle_count;
- if ((name = get_object_full_name( obj, &reply->total )))
- set_reply_data_ptr( name, min( reply->total, get_reply_max_size() ));
- release_object( obj );
- }
- DECL_HANDLER(set_security_object)
- {
- data_size_t sd_size = get_req_data_size();
- const struct security_descriptor *sd = get_req_data();
- struct object *obj;
- unsigned int access = 0;
- if (!sd_is_valid( sd, sd_size ))
- {
- set_error( STATUS_ACCESS_VIOLATION );
- return;
- }
- if (req->security_info & OWNER_SECURITY_INFORMATION ||
- req->security_info & GROUP_SECURITY_INFORMATION ||
- req->security_info & LABEL_SECURITY_INFORMATION)
- access |= WRITE_OWNER;
- if (req->security_info & SACL_SECURITY_INFORMATION)
- access |= ACCESS_SYSTEM_SECURITY;
- if (req->security_info & DACL_SECURITY_INFORMATION)
- access |= WRITE_DAC;
- if (!(obj = get_handle_obj( current->process, req->handle, access, NULL ))) return;
- obj->ops->set_sd( obj, sd, req->security_info );
- release_object( obj );
- }
- DECL_HANDLER(get_security_object)
- {
- const struct security_descriptor *sd;
- struct object *obj;
- unsigned int access = READ_CONTROL;
- struct security_descriptor req_sd;
- int present;
- const SID *owner, *group;
- const ACL *sacl, *dacl;
- ACL *label_acl = NULL;
- if (req->security_info & SACL_SECURITY_INFORMATION)
- access |= ACCESS_SYSTEM_SECURITY;
- if (!(obj = get_handle_obj( current->process, req->handle, access, NULL ))) return;
- sd = obj->ops->get_sd( obj );
- if (sd)
- {
- req_sd.control = sd->control & ~SE_SELF_RELATIVE;
- owner = sd_get_owner( sd );
- if (req->security_info & OWNER_SECURITY_INFORMATION)
- req_sd.owner_len = sd->owner_len;
- else
- req_sd.owner_len = 0;
- group = sd_get_group( sd );
- if (req->security_info & GROUP_SECURITY_INFORMATION)
- req_sd.group_len = sd->group_len;
- else
- req_sd.group_len = 0;
- sacl = sd_get_sacl( sd, &present );
- if (req->security_info & SACL_SECURITY_INFORMATION && present)
- req_sd.sacl_len = sd->sacl_len;
- else if (req->security_info & LABEL_SECURITY_INFORMATION && present && sacl)
- {
- if (!(label_acl = extract_security_labels( sacl ))) goto done;
- req_sd.sacl_len = label_acl->AclSize;
- sacl = label_acl;
- }
- else
- req_sd.sacl_len = 0;
- dacl = sd_get_dacl( sd, &present );
- if (req->security_info & DACL_SECURITY_INFORMATION && present)
- req_sd.dacl_len = sd->dacl_len;
- else
- req_sd.dacl_len = 0;
- reply->sd_len = sizeof(req_sd) + req_sd.owner_len + req_sd.group_len +
- req_sd.sacl_len + req_sd.dacl_len;
- if (reply->sd_len <= get_reply_max_size())
- {
- char *ptr = set_reply_data_size(reply->sd_len);
- memcpy( ptr, &req_sd, sizeof(req_sd) );
- ptr += sizeof(req_sd);
- memcpy( ptr, owner, req_sd.owner_len );
- ptr += req_sd.owner_len;
- memcpy( ptr, group, req_sd.group_len );
- ptr += req_sd.group_len;
- memcpy( ptr, sacl, req_sd.sacl_len );
- ptr += req_sd.sacl_len;
- memcpy( ptr, dacl, req_sd.dacl_len );
- }
- else
- set_error(STATUS_BUFFER_TOO_SMALL);
- }
- done:
- release_object( obj );
- free( label_acl );
- }
- struct enum_handle_info
- {
- unsigned int count;
- struct handle_info *handle;
- };
- static int enum_handles( struct process *process, void *user )
- {
- struct enum_handle_info *info = user;
- struct handle_table *table = process->handles;
- struct handle_entry *entry;
- struct handle_info *handle;
- struct object_type *type;
- unsigned int i;
- if (!table)
- return 0;
- for (i = 0, entry = table->entries; i <= table->last; i++, entry++)
- {
- client_ptr_t object_ptr = 0;
- if (!entry->ptr) continue;
- if (current->process->dev_mgr && !(object_ptr = get_kernel_object_ptr(current->process->dev_mgr, entry->ptr)))
- continue;
- if (!info->handle)
- {
- info->count++;
- continue;
- }
- assert( info->count );
- handle = info->handle++;
- handle->owner = process->id;
- handle->handle = index_to_handle(i);
- handle->access = entry->access & ~RESERVED_ALL;
- handle->object = object_ptr;
- if ((type = entry->ptr->ops->get_type(entry->ptr)))
- {
- handle->type = type_get_index(type);
- release_object(type);
- }
- else
- handle->type = 0;
- info->count--;
- }
- return 0;
- }
- DECL_HANDLER(get_system_handles)
- {
- struct enum_handle_info info;
- struct handle_info *handle;
- data_size_t max_handles = get_reply_max_size() / sizeof(*handle);
- info.handle = NULL;
- info.count = 0;
- enum_processes( enum_handles, &info );
- reply->count = info.count;
- if (max_handles < info.count)
- set_error( STATUS_BUFFER_TOO_SMALL );
- else if ((handle = set_reply_data_size( info.count * sizeof(*handle) )))
- {
- info.handle = handle;
- enum_processes( enum_handles, &info );
- }
- }
|