blob: c7cd41729c57b9d8b8161e48f72e93b2f9491823 [file] [log] [blame]
Alexandre Julliard43c190e1999-05-15 10:48:19 +00001/*
2 * Server-side handle management
3 *
4 * Copyright (C) 1998 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard43c190e1999-05-15 10:48:19 +000019 */
20
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000021#include "config.h"
22#include "wine/port.h"
23
Alexandre Julliard43c190e1999-05-15 10:48:19 +000024#include <assert.h>
25#include <limits.h>
26#include <string.h>
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000027#include <stdarg.h>
Alexandre Julliard43c190e1999-05-15 10:48:19 +000028#include <stdio.h>
29#include <stdlib.h>
30
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010031#include "ntstatus.h"
32#define WIN32_NO_STATUS
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000033#include "windef.h"
Vitaliy Margolena9960002005-10-27 18:30:37 +000034#include "winternl.h"
Alexandre Julliard43c190e1999-05-15 10:48:19 +000035
36#include "handle.h"
37#include "process.h"
38#include "thread.h"
Rob Shearman6a76a0a2007-02-21 13:59:59 +000039#include "security.h"
Alexandre Julliard5bc78081999-06-22 17:26:53 +000040#include "request.h"
Alexandre Julliard43c190e1999-05-15 10:48:19 +000041
42struct handle_entry
43{
Alexandre Julliardd549f692000-12-22 02:04:15 +000044 struct object *ptr; /* object */
45 unsigned int access; /* access rights */
Alexandre Julliard43c190e1999-05-15 10:48:19 +000046};
47
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +000048struct handle_table
49{
50 struct object obj; /* object header */
51 struct process *process; /* process owning this table */
52 int count; /* number of allocated entries */
53 int last; /* last used entry */
54 int free; /* first entry that may be free */
55 struct handle_entry *entries; /* handle entries */
56};
57
58static struct handle_table *global_table;
Alexandre Julliard43c190e1999-05-15 10:48:19 +000059
60/* reserved handle access rights */
Alexandre Julliard78a3e632005-06-09 12:07:12 +000061#define RESERVED_SHIFT 26
Alexandre Julliard43c190e1999-05-15 10:48:19 +000062#define RESERVED_INHERIT (HANDLE_FLAG_INHERIT << RESERVED_SHIFT)
63#define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT)
64#define RESERVED_ALL (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT)
65
Alexandre Julliard43c190e1999-05-15 10:48:19 +000066#define MIN_HANDLE_ENTRIES 32
Alexandre Julliard9434e192008-12-04 16:12:04 +010067#define MAX_HANDLE_ENTRIES 0x00ffffff
Alexandre Julliard43c190e1999-05-15 10:48:19 +000068
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +000069
Alexandre Julliardceeb6931999-11-04 02:33:45 +000070/* handle to table index conversion */
71
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000072/* handles are a multiple of 4 under NT; handle 0 is not used */
Andrew Talbotb1788c82007-03-17 10:52:14 +000073static inline obj_handle_t index_to_handle( int index )
Alexandre Julliardceeb6931999-11-04 02:33:45 +000074{
Alexandre Julliard0d3d4562008-12-08 16:04:20 +010075 return (obj_handle_t)((index + 1) << 2);
Alexandre Julliardceeb6931999-11-04 02:33:45 +000076}
Andrew Talbotb1788c82007-03-17 10:52:14 +000077static inline int handle_to_index( obj_handle_t handle )
Alexandre Julliardceeb6931999-11-04 02:33:45 +000078{
Alexandre Julliard0d3d4562008-12-08 16:04:20 +010079 return (handle >> 2) - 1;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000080}
81
82/* global handle conversion */
83
84#define HANDLE_OBFUSCATOR 0x544a4def
85
Andrew Talbotb1788c82007-03-17 10:52:14 +000086static inline int handle_is_global( obj_handle_t handle)
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000087{
Alexandre Julliard0d3d4562008-12-08 16:04:20 +010088 return (handle ^ HANDLE_OBFUSCATOR) <= (MAX_HANDLE_ENTRIES << 2);
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000089}
Andrew Talbotb1788c82007-03-17 10:52:14 +000090static inline obj_handle_t handle_local_to_global( obj_handle_t handle )
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000091{
92 if (!handle) return 0;
Alexandre Julliard0d3d4562008-12-08 16:04:20 +010093 return handle ^ HANDLE_OBFUSCATOR;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000094}
Andrew Talbotb1788c82007-03-17 10:52:14 +000095static inline obj_handle_t handle_global_to_local( obj_handle_t handle )
Alexandre Julliard8081e5a2001-01-05 04:08:07 +000096{
Alexandre Julliard0d3d4562008-12-08 16:04:20 +010097 return handle ^ HANDLE_OBFUSCATOR;
Alexandre Julliardceeb6931999-11-04 02:33:45 +000098}
99
100
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000101static void handle_table_dump( struct object *obj, int verbose );
102static void handle_table_destroy( struct object *obj );
103
104static const struct object_ops handle_table_ops =
105{
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000106 sizeof(struct handle_table), /* size */
107 handle_table_dump, /* dump */
Alexandre Julliard8382eb02007-12-05 18:16:42 +0100108 no_get_type, /* get_type */
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000109 no_add_queue, /* add_queue */
110 NULL, /* remove_queue */
111 NULL, /* signaled */
112 NULL, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +0000113 no_signal, /* signal */
Alexandre Julliard1ab243b2000-12-19 02:12:45 +0000114 no_get_fd, /* get_fd */
Alexandre Julliard28beba32005-12-12 14:57:40 +0100115 no_map_access, /* map_access */
Rob Shearmanc1707d82007-10-03 13:10:37 +0100116 default_get_sd, /* get_sd */
117 default_set_sd, /* set_sd */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +0000118 no_lookup_name, /* lookup_name */
Alexandre Julliard7e71c1d2007-03-22 11:44:29 +0100119 no_open_file, /* open_file */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +0000120 no_close_handle, /* close_handle */
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000121 handle_table_destroy /* destroy */
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000122};
123
124/* dump a handle table */
125static void handle_table_dump( struct object *obj, int verbose )
126{
127 int i;
128 struct handle_table *table = (struct handle_table *)obj;
André Hentschelc7becc32011-07-05 21:38:01 +0200129 struct handle_entry *entry;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000130
131 assert( obj->ops == &handle_table_ops );
132
133 fprintf( stderr, "Handle table last=%d count=%d process=%p\n",
134 table->last, table->count, table->process );
135 if (!verbose) return;
136 entry = table->entries;
137 for (i = 0; i <= table->last; i++, entry++)
138 {
139 if (!entry->ptr) continue;
Alexandre Julliard0d3d4562008-12-08 16:04:20 +0100140 fprintf( stderr, " %04x: %p %08x ",
Alexandre Julliard0ec183c2005-09-27 09:36:54 +0000141 index_to_handle(i), entry->ptr, entry->access );
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000142 entry->ptr->ops->dump( entry->ptr, 0 );
143 }
144}
145
146/* destroy a handle table */
147static void handle_table_destroy( struct object *obj )
148{
149 int i;
150 struct handle_table *table = (struct handle_table *)obj;
Alexandre Julliard0901b232005-06-14 19:16:56 +0000151 struct handle_entry *entry;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000152
153 assert( obj->ops == &handle_table_ops );
154
Alexandre Julliard0901b232005-06-14 19:16:56 +0000155 /* first notify all objects that handles are being closed */
156 if (table->process)
157 {
158 for (i = 0, entry = table->entries; i <= table->last; i++, entry++)
159 {
160 struct object *obj = entry->ptr;
161 if (obj) obj->ops->close_handle( obj, table->process, index_to_handle(i) );
162 }
163 }
164
165 for (i = 0, entry = table->entries; i <= table->last; i++, entry++)
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000166 {
167 struct object *obj = entry->ptr;
168 entry->ptr = NULL;
169 if (obj) release_object( obj );
170 }
171 free( table->entries );
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000172}
173
Alexandre Julliard350c0ca2010-08-24 12:10:51 +0200174/* close all the process handles and free the handle table */
175void close_process_handles( struct process *process )
176{
177 struct handle_table *table = process->handles;
178
179 process->handles = NULL;
180 if (table) release_object( table );
181}
182
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000183/* allocate a new handle table */
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000184struct handle_table *alloc_handle_table( struct process *process, int count )
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000185{
186 struct handle_table *table;
187
188 if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
Alexandre Julliarde66207e2003-02-19 00:33:32 +0000189 if (!(table = alloc_object( &handle_table_ops )))
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000190 return NULL;
191 table->process = process;
192 table->count = count;
193 table->last = -1;
194 table->free = 0;
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000195 if ((table->entries = mem_alloc( count * sizeof(*table->entries) ))) return table;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000196 release_object( table );
197 return NULL;
198}
199
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000200/* grow a handle table */
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000201static int grow_handle_table( struct handle_table *table )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000202{
203 struct handle_entry *new_entries;
Alexandre Julliard9434e192008-12-04 16:12:04 +0100204 int count = min( table->count * 2, MAX_HANDLE_ENTRIES );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000205
Alexandre Julliard9434e192008-12-04 16:12:04 +0100206 if (count == table->count ||
207 !(new_entries = realloc( table->entries, count * sizeof(struct handle_entry) )))
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000208 {
Alexandre Julliard9434e192008-12-04 16:12:04 +0100209 set_error( STATUS_INSUFFICIENT_RESOURCES );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000210 return 0;
211 }
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000212 table->entries = new_entries;
213 table->count = count;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000214 return 1;
215}
216
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000217/* allocate the first free entry in the handle table */
Alexandre Julliard51885742002-05-30 20:12:58 +0000218static obj_handle_t alloc_entry( struct handle_table *table, void *obj, unsigned int access )
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000219{
220 struct handle_entry *entry = table->entries + table->free;
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000221 int i;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000222
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000223 for (i = table->free; i <= table->last; i++, entry++) if (!entry->ptr) goto found;
224 if (i >= table->count)
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000225 {
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000226 if (!grow_handle_table( table )) return 0;
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000227 entry = table->entries + i; /* the entries may have moved */
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000228 }
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000229 table->last = i;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000230 found:
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000231 table->free = i + 1;
232 entry->ptr = grab_object( obj );
233 entry->access = access;
234 return index_to_handle(i);
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000235}
236
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000237/* allocate a handle for an object, incrementing its refcount */
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000238/* return the handle, or 0 on error */
Rob Shearman92db6d22007-11-05 14:23:36 +0000239obj_handle_t alloc_handle_no_access_check( struct process *process, void *ptr, unsigned int access, unsigned int attr )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000240{
Alexandre Julliard28beba32005-12-12 14:57:40 +0100241 struct object *obj = ptr;
242
Alexandre Julliardc976db12005-07-13 12:09:49 +0000243 access &= ~RESERVED_ALL;
Alexandre Julliard24560e72005-12-09 13:58:25 +0100244 if (attr & OBJ_INHERIT) access |= RESERVED_INHERIT;
Alexandre Julliardc976db12005-07-13 12:09:49 +0000245 if (!process->handles)
246 {
247 set_error( STATUS_NO_MEMORY );
248 return 0;
249 }
250 return alloc_entry( process->handles, obj, access );
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000251}
252
Rob Shearman6a76a0a2007-02-21 13:59:59 +0000253/* allocate a handle for an object, checking the dacl allows the process to */
254/* access it and incrementing its refcount */
255/* return the handle, or 0 on error */
256obj_handle_t alloc_handle( struct process *process, void *ptr, unsigned int access, unsigned int attr )
257{
258 struct object *obj = ptr;
259 access = obj->ops->map_access( obj, access );
260 if (access && !check_object_access( obj, &access )) return 0;
261 return alloc_handle_no_access_check( process, ptr, access, attr );
262}
263
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000264/* allocate a global handle for an object, incrementing its refcount */
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000265/* return the handle, or 0 on error */
Rob Shearman6a76a0a2007-02-21 13:59:59 +0000266static obj_handle_t alloc_global_handle_no_access_check( void *obj, unsigned int access )
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000267{
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000268 if (!global_table)
269 {
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000270 if (!(global_table = (struct handle_table *)alloc_handle_table( NULL, 0 )))
271 return 0;
Alexandre Julliardb00fb172006-03-22 20:32:04 +0100272 make_object_static( &global_table->obj );
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000273 }
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000274 return handle_local_to_global( alloc_entry( global_table, obj, access ));
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000275}
276
Rob Shearman6a76a0a2007-02-21 13:59:59 +0000277/* allocate a global handle for an object, checking the dacl allows the */
278/* process to access it and incrementing its refcount and incrementing its refcount */
279/* return the handle, or 0 on error */
280static obj_handle_t alloc_global_handle( void *obj, unsigned int access )
281{
282 if (access && !check_object_access( obj, &access )) return 0;
283 return alloc_global_handle_no_access_check( obj, access );
284}
285
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000286/* return a handle entry, or NULL if the handle is invalid */
Alexandre Julliard51885742002-05-30 20:12:58 +0000287static struct handle_entry *get_handle( struct process *process, obj_handle_t handle )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000288{
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000289 struct handle_table *table = process->handles;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000290 struct handle_entry *entry;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000291 int index;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000292
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000293 if (handle_is_global(handle))
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000294 {
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000295 handle = handle_global_to_local(handle);
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000296 table = global_table;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000297 }
Alexandre Julliard1a6c4722009-12-01 13:49:43 +0100298 if (!table) return NULL;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000299 index = handle_to_index( handle );
Alexandre Julliard1a6c4722009-12-01 13:49:43 +0100300 if (index < 0) return NULL;
301 if (index > table->last) return NULL;
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000302 entry = table->entries + index;
Alexandre Julliard1a6c4722009-12-01 13:49:43 +0100303 if (!entry->ptr) return NULL;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000304 return entry;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000305}
306
307/* attempt to shrink a table */
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000308static void shrink_handle_table( struct handle_table *table )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000309{
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000310 struct handle_entry *entry = table->entries + table->last;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000311 struct handle_entry *new_entries;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000312 int count = table->count;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000313
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000314 while (table->last >= 0)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000315 {
316 if (entry->ptr) break;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000317 table->last--;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000318 entry--;
319 }
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000320 if (table->last >= count / 4) return; /* no need to shrink */
321 if (count < MIN_HANDLE_ENTRIES * 2) return; /* too small to shrink */
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000322 count /= 2;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000323 if (!(new_entries = realloc( table->entries, count * sizeof(*new_entries) ))) return;
324 table->count = count;
325 table->entries = new_entries;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000326}
327
328/* copy the handle table of the parent process */
329/* return 1 if OK, 0 on error */
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000330struct handle_table *copy_handle_table( struct process *process, struct process *parent )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000331{
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000332 struct handle_table *parent_table = parent->handles;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000333 struct handle_table *table;
334 int i;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000335
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000336 assert( parent_table );
337 assert( parent_table->obj.ops == &handle_table_ops );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000338
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000339 if (!(table = (struct handle_table *)alloc_handle_table( process, parent_table->count )))
340 return NULL;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000341
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000342 if ((table->last = parent_table->last) >= 0)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000343 {
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000344 struct handle_entry *ptr = table->entries;
345 memcpy( ptr, parent_table->entries, (table->last + 1) * sizeof(struct handle_entry) );
346 for (i = 0; i <= table->last; i++, ptr++)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000347 {
348 if (!ptr->ptr) continue;
349 if (ptr->access & RESERVED_INHERIT) grab_object( ptr->ptr );
350 else ptr->ptr = NULL; /* don't inherit this entry */
351 }
352 }
353 /* attempt to shrink the table */
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000354 shrink_handle_table( table );
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000355 return table;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000356}
357
358/* close a handle and decrement the refcount of the associated object */
Alexandre Julliard60efdd52009-12-01 13:59:41 +0100359unsigned int close_handle( struct process *process, obj_handle_t handle )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000360{
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000361 struct handle_table *table;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000362 struct handle_entry *entry;
363 struct object *obj;
364
Alexandre Julliard60efdd52009-12-01 13:59:41 +0100365 if (!(entry = get_handle( process, handle ))) return STATUS_INVALID_HANDLE;
366 if (entry->access & RESERVED_CLOSE_PROTECT) return STATUS_HANDLE_NOT_CLOSABLE;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000367 obj = entry->ptr;
Alexandre Julliard60efdd52009-12-01 13:59:41 +0100368 if (!obj->ops->close_handle( obj, process, handle )) return STATUS_HANDLE_NOT_CLOSABLE;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000369 entry->ptr = NULL;
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000370 table = handle_is_global(handle) ? global_table : process->handles;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000371 if (entry < table->entries + table->free) table->free = entry - table->entries;
372 if (entry == table->entries + table->last) shrink_handle_table( table );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000373 release_object( obj );
Alexandre Julliard60efdd52009-12-01 13:59:41 +0100374 return STATUS_SUCCESS;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000375}
376
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000377/* retrieve the object corresponding to one of the magic pseudo-handles */
Alexandre Julliard51885742002-05-30 20:12:58 +0000378static inline struct object *get_magic_handle( obj_handle_t handle )
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000379{
Alexandre Julliard0d3d4562008-12-08 16:04:20 +0100380 switch(handle)
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000381 {
382 case 0xfffffffe: /* current thread pseudo-handle */
383 return &current->obj;
384 case 0x7fffffff: /* current process pseudo-handle */
385 case 0xffffffff: /* current process pseudo-handle */
386 return (struct object *)current->process;
387 default:
388 return NULL;
389 }
390}
391
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000392/* retrieve the object corresponding to a handle, incrementing its refcount */
Alexandre Julliard51885742002-05-30 20:12:58 +0000393struct object *get_handle_obj( struct process *process, obj_handle_t handle,
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000394 unsigned int access, const struct object_ops *ops )
395{
396 struct handle_entry *entry;
397 struct object *obj;
398
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000399 if (!(obj = get_magic_handle( handle )))
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000400 {
Alexandre Julliard1a6c4722009-12-01 13:49:43 +0100401 if (!(entry = get_handle( process, handle )))
402 {
403 set_error( STATUS_INVALID_HANDLE );
404 return NULL;
405 }
Bernhard Loosbf3c2a02011-07-19 13:20:39 +0200406 obj = entry->ptr;
407 if (ops && (obj->ops != ops))
408 {
409 set_error( STATUS_OBJECT_TYPE_MISMATCH ); /* not the right type */
410 return NULL;
411 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000412 if ((entry->access & access) != access)
413 {
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000414 set_error( STATUS_ACCESS_DENIED );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000415 return NULL;
416 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000417 }
Bernhard Loosbf3c2a02011-07-19 13:20:39 +0200418 else if (ops && (obj->ops != ops))
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000419 {
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000420 set_error( STATUS_OBJECT_TYPE_MISMATCH ); /* not the right type */
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000421 return NULL;
422 }
423 return grab_object( obj );
424}
425
Mike McCormackf92fff62005-04-24 17:35:52 +0000426/* retrieve the access rights of a given handle */
427unsigned int get_handle_access( struct process *process, obj_handle_t handle )
428{
429 struct handle_entry *entry;
430
Vitaliy Margolenbae75022007-01-24 23:43:04 -0700431 if (get_magic_handle( handle )) return ~RESERVED_ALL; /* magic handles have all access rights */
Mike McCormackf92fff62005-04-24 17:35:52 +0000432 if (!(entry = get_handle( process, handle ))) return 0;
Vitaliy Margolenbae75022007-01-24 23:43:04 -0700433 return entry->access & ~RESERVED_ALL;
Mike McCormackf92fff62005-04-24 17:35:52 +0000434}
435
Alexandre Julliard526a28d2002-10-02 23:49:30 +0000436/* find the first inherited handle of the given type */
437/* this is needed for window stations and desktops (don't ask...) */
438obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops )
439{
440 struct handle_table *table = process->handles;
441 struct handle_entry *ptr;
442 int i;
443
444 if (!table) return 0;
445
446 for (i = 0, ptr = table->entries; i <= table->last; i++, ptr++)
447 {
448 if (!ptr->ptr) continue;
449 if (ptr->ptr->ops != ops) continue;
450 if (ptr->access & RESERVED_INHERIT) return index_to_handle(i);
451 }
452 return 0;
453}
454
Alexandre Julliardd30b5742007-12-05 16:45:32 +0100455/* enumerate handles of a given type */
456/* this is needed for window stations and desktops */
457obj_handle_t enumerate_handles( struct process *process, const struct object_ops *ops,
458 unsigned int *index )
459{
460 struct handle_table *table = process->handles;
461 unsigned int i;
462 struct handle_entry *entry;
463
464 if (!table) return 0;
465
466 for (i = *index, entry = &table->entries[i]; i <= table->last; i++, entry++)
467 {
468 if (!entry->ptr) continue;
469 if (entry->ptr->ops != ops) continue;
470 *index = i + 1;
471 return index_to_handle(i);
472 }
473 return 0;
474}
475
Alexandre Julliardd549f692000-12-22 02:04:15 +0000476/* get/set the handle reserved flags */
477/* return the old flags (or -1 on error) */
Alexandre Julliard38502f72005-08-23 18:43:50 +0000478static int set_handle_flags( struct process *process, obj_handle_t handle, int mask, int flags )
Alexandre Julliardd549f692000-12-22 02:04:15 +0000479{
480 struct handle_entry *entry;
481 unsigned int old_access;
482
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000483 if (get_magic_handle( handle ))
484 {
485 /* we can retrieve but not set info for magic handles */
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000486 if (mask) set_error( STATUS_ACCESS_DENIED );
Alexandre Julliardceeb6931999-11-04 02:33:45 +0000487 return 0;
488 }
Alexandre Julliard1a6c4722009-12-01 13:49:43 +0100489 if (!(entry = get_handle( process, handle )))
490 {
491 set_error( STATUS_INVALID_HANDLE );
492 return -1;
493 }
Alexandre Julliardd549f692000-12-22 02:04:15 +0000494 old_access = entry->access;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000495 mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
496 flags = (flags << RESERVED_SHIFT) & mask;
497 entry->access = (entry->access & ~mask) | flags;
Alexandre Julliardd549f692000-12-22 02:04:15 +0000498 return (old_access & RESERVED_ALL) >> RESERVED_SHIFT;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000499}
500
501/* duplicate a handle */
Alexandre Julliard51885742002-05-30 20:12:58 +0000502obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, struct process *dst,
Alexandre Julliard24560e72005-12-09 13:58:25 +0100503 unsigned int access, unsigned int attr, unsigned int options )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000504{
Alexandre Julliard51885742002-05-30 20:12:58 +0000505 obj_handle_t res;
Rob Shearman6a76a0a2007-02-21 13:59:59 +0000506 struct handle_entry *entry;
507 unsigned int src_access;
Alexandre Julliard0042cb31999-05-29 11:17:25 +0000508 struct object *obj = get_handle_obj( src, src_handle, 0, NULL );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000509
Alexandre Julliard8081e5a2001-01-05 04:08:07 +0000510 if (!obj) return 0;
Rob Shearman6a76a0a2007-02-21 13:59:59 +0000511 if ((entry = get_handle( src, src_handle )))
512 src_access = entry->access;
513 else /* pseudo-handle, give it full access */
Rob Shearman6a76a0a2007-02-21 13:59:59 +0000514 src_access = obj->ops->map_access( obj, GENERIC_ALL );
Rob Shearman6a76a0a2007-02-21 13:59:59 +0000515 src_access &= ~RESERVED_ALL;
516
517 if (options & DUP_HANDLE_SAME_ACCESS)
518 access = src_access;
Alexandre Julliardeb2e77f1999-06-04 19:49:54 +0000519 else
Rob Shearman6a76a0a2007-02-21 13:59:59 +0000520 access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL;
521
522 /* asking for the more access rights than src_access? */
523 if (access & ~src_access)
524 {
525 if (options & DUP_HANDLE_MAKE_GLOBAL)
526 res = alloc_global_handle( obj, access );
527 else
528 res = alloc_handle( dst, obj, access, attr );
529 }
530 else
531 {
532 if (options & DUP_HANDLE_MAKE_GLOBAL)
533 res = alloc_global_handle_no_access_check( obj, access );
534 else
535 res = alloc_handle_no_access_check( dst, obj, access, attr );
536 }
537
Alexandre Julliard0042cb31999-05-29 11:17:25 +0000538 release_object( obj );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000539 return res;
540}
541
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000542/* open a new handle to an existing object */
Alexandre Julliardead9b062005-11-18 16:31:18 +0000543obj_handle_t open_object( const struct namespace *namespace, const struct unicode_str *name,
Vitaliy Margolena9960002005-10-27 18:30:37 +0000544 const struct object_ops *ops, unsigned int access, unsigned int attr )
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000545{
Alexandre Julliard51885742002-05-30 20:12:58 +0000546 obj_handle_t handle = 0;
Alexandre Julliardead9b062005-11-18 16:31:18 +0000547 struct object *obj = find_object( namespace, name, attr );
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000548 if (obj)
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000549 {
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000550 if (ops && obj->ops != ops)
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000551 set_error( STATUS_OBJECT_TYPE_MISMATCH );
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000552 else
Alexandre Julliard24560e72005-12-09 13:58:25 +0100553 handle = alloc_handle( current->process, obj, access, attr );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000554 release_object( obj );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000555 }
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000556 else
Alexandre Julliardcb1fc732000-01-24 21:58:06 +0000557 set_error( STATUS_OBJECT_NAME_NOT_FOUND );
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000558 return handle;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000559}
560
Eric Pouech9fd54b22003-09-16 01:07:21 +0000561/* return the size of the handle table of a given process */
562unsigned int get_handle_table_count( struct process *process )
563{
Alexandre Julliardc976db12005-07-13 12:09:49 +0000564 if (!process->handles) return 0;
Eric Pouech9fd54b22003-09-16 01:07:21 +0000565 return process->handles->count;
566}
567
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000568/* close a handle */
569DECL_HANDLER(close_handle)
570{
Alexandre Julliard60efdd52009-12-01 13:59:41 +0100571 unsigned int err = close_handle( current->process, req->handle );
572 set_error( err );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000573}
574
575/* set a handle information */
576DECL_HANDLER(set_handle_info)
577{
Alexandre Julliard38502f72005-08-23 18:43:50 +0000578 reply->old_flags = set_handle_flags( current->process, req->handle, req->mask, req->flags );
579}
580
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000581/* duplicate a handle */
582DECL_HANDLER(dup_handle)
583{
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000584 struct process *src, *dst;
585
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000586 reply->handle = 0;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000587 if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
588 {
589 if (req->options & DUP_HANDLE_MAKE_GLOBAL)
590 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000591 reply->handle = duplicate_handle( src, req->src_handle, NULL,
Alexandre Julliard24560e72005-12-09 13:58:25 +0100592 req->access, req->attributes, req->options );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000593 }
594 else if ((dst = get_process_from_handle( req->dst_process, PROCESS_DUP_HANDLE )))
595 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000596 reply->handle = duplicate_handle( src, req->src_handle, dst,
Alexandre Julliard24560e72005-12-09 13:58:25 +0100597 req->access, req->attributes, req->options );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000598 release_object( dst );
599 }
600 /* close the handle no matter what happened */
Alexandre Julliard60efdd52009-12-01 13:59:41 +0100601 if (req->options & DUP_HANDLE_CLOSE_SOURCE) reply->closed = !close_handle( src, req->src_handle );
Alexandre Julliard34103542007-01-18 12:18:51 +0100602 reply->self = (src == current->process);
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000603 release_object( src );
604 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000605}
Vitaliy Margolenbae75022007-01-24 23:43:04 -0700606
607DECL_HANDLER(get_object_info)
608{
609 struct object *obj;
Alexandre Julliard658dae92010-01-08 13:01:50 +0100610 WCHAR *name;
Vitaliy Margolenbae75022007-01-24 23:43:04 -0700611
612 if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL ))) return;
613
614 reply->access = get_handle_access( current->process, req->handle );
615 reply->ref_count = obj->refcount;
Alexandre Julliard658dae92010-01-08 13:01:50 +0100616 if ((name = get_object_full_name( obj, &reply->total )))
617 set_reply_data_ptr( name, min( reply->total, get_reply_max_size() ));
Vitaliy Margolenbae75022007-01-24 23:43:04 -0700618 release_object( obj );
619}
Rob Shearman5af809a2007-10-02 15:54:51 +0100620
621DECL_HANDLER(set_security_object)
622{
623 data_size_t sd_size = get_req_data_size();
624 const struct security_descriptor *sd = get_req_data();
625 struct object *obj;
626 unsigned int access = 0;
627
628 if (!sd_is_valid( sd, sd_size ))
629 {
630 set_error( STATUS_ACCESS_VIOLATION );
631 return;
632 }
633
634 if (req->security_info & OWNER_SECURITY_INFORMATION ||
635 req->security_info & GROUP_SECURITY_INFORMATION)
636 access |= WRITE_OWNER;
637 if (req->security_info & SACL_SECURITY_INFORMATION)
638 access |= ACCESS_SYSTEM_SECURITY;
639 if (req->security_info & DACL_SECURITY_INFORMATION)
640 access |= WRITE_DAC;
641
642 if (!(obj = get_handle_obj( current->process, req->handle, access, NULL ))) return;
643
Rob Shearmanc1707d82007-10-03 13:10:37 +0100644 obj->ops->set_sd( obj, sd, req->security_info );
Rob Shearman5af809a2007-10-02 15:54:51 +0100645 release_object( obj );
646}
Rob Shearman5356bfd2007-10-02 15:55:13 +0100647
648DECL_HANDLER(get_security_object)
649{
650 const struct security_descriptor *sd;
651 struct object *obj;
652 unsigned int access = READ_CONTROL;
653 struct security_descriptor req_sd;
654 int present;
655 const SID *owner, *group;
656 const ACL *sacl, *dacl;
657
658 if (req->security_info & SACL_SECURITY_INFORMATION)
659 access |= ACCESS_SYSTEM_SECURITY;
660
661 if (!(obj = get_handle_obj( current->process, req->handle, access, NULL ))) return;
662
Rob Shearmanc1707d82007-10-03 13:10:37 +0100663 sd = obj->ops->get_sd( obj );
Rob Shearman5356bfd2007-10-02 15:55:13 +0100664 if (sd)
665 {
666 req_sd.control = sd->control & ~SE_SELF_RELATIVE;
667
668 owner = sd_get_owner( sd );
669 if (req->security_info & OWNER_SECURITY_INFORMATION)
670 req_sd.owner_len = sd->owner_len;
Rob Shearman9980f472007-10-31 16:53:37 +0000671 else
672 req_sd.owner_len = 0;
Rob Shearman5356bfd2007-10-02 15:55:13 +0100673
674 group = sd_get_group( sd );
675 if (req->security_info & GROUP_SECURITY_INFORMATION)
676 req_sd.group_len = sd->group_len;
Rob Shearman9980f472007-10-31 16:53:37 +0000677 else
678 req_sd.group_len = 0;
Rob Shearman5356bfd2007-10-02 15:55:13 +0100679
680 req_sd.control |= SE_SACL_PRESENT;
681 sacl = sd_get_sacl( sd, &present );
682 if (req->security_info & SACL_SECURITY_INFORMATION && present)
683 req_sd.sacl_len = sd->sacl_len;
684 else
685 req_sd.sacl_len = 0;
686
687 req_sd.control |= SE_DACL_PRESENT;
688 dacl = sd_get_dacl( sd, &present );
689 if (req->security_info & DACL_SECURITY_INFORMATION && present)
690 req_sd.dacl_len = sd->dacl_len;
691 else
692 req_sd.dacl_len = 0;
693
694 reply->sd_len = sizeof(req_sd) + req_sd.owner_len + req_sd.group_len +
695 req_sd.sacl_len + req_sd.dacl_len;
696 if (reply->sd_len <= get_reply_max_size())
697 {
698 char *ptr = set_reply_data_size(reply->sd_len);
699
700 memcpy( ptr, &req_sd, sizeof(req_sd) );
701 ptr += sizeof(req_sd);
702 memcpy( ptr, owner, req_sd.owner_len );
703 ptr += req_sd.owner_len;
704 memcpy( ptr, group, req_sd.group_len );
705 ptr += req_sd.group_len;
706 memcpy( ptr, sacl, req_sd.sacl_len );
707 ptr += req_sd.sacl_len;
708 memcpy( ptr, dacl, req_sd.dacl_len );
709 }
710 else
711 set_error(STATUS_BUFFER_TOO_SMALL);
712 }
713
714 release_object( obj );
715}