handle.c 26.2 KB
Newer Older
1 2 3 4
/*
 * Server-side handle management
 *
 * Copyright (C) 1998 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20
 */

21 22 23
#include "config.h"
#include "wine/port.h"

24 25 26
#include <assert.h>
#include <limits.h>
#include <string.h>
27
#include <stdarg.h>
28 29 30
#include <stdio.h>
#include <stdlib.h>

31 32
#include "ntstatus.h"
#define WIN32_NO_STATUS
33
#include "windef.h"
34
#include "winternl.h"
35 36 37 38

#include "handle.h"
#include "process.h"
#include "thread.h"
39
#include "security.h"
40
#include "request.h"
41 42 43

struct handle_entry
{
44 45
    struct object *ptr;       /* object */
    unsigned int   access;    /* access rights */
46 47
};

48 49 50 51 52 53 54 55 56 57 58
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;
59 60

/* reserved handle access rights */
61
#define RESERVED_SHIFT         26
62 63 64 65 66
#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
67
#define MAX_HANDLE_ENTRIES  0x00ffffff
68

69

70 71
/* handle to table index conversion */

72
/* handles are a multiple of 4 under NT; handle 0 is not used */
73
static inline obj_handle_t index_to_handle( int index )
74
{
75
    return (obj_handle_t)((index + 1) << 2);
76
}
77
static inline int handle_to_index( obj_handle_t handle )
78
{
79
    return (handle >> 2) - 1;
80 81 82 83 84 85
}

/* global handle conversion */

#define HANDLE_OBFUSCATOR 0x544a4def

86
static inline int handle_is_global( obj_handle_t handle)
87
{
88
    return (handle ^ HANDLE_OBFUSCATOR) <= (MAX_HANDLE_ENTRIES << 2);
89
}
90
static inline obj_handle_t handle_local_to_global( obj_handle_t handle )
91
{
92
    if (!handle) return 0;
93
    return handle ^ HANDLE_OBFUSCATOR;
94
}
95
static inline obj_handle_t handle_global_to_local( obj_handle_t handle )
96
{
97
    return handle ^ HANDLE_OBFUSCATOR;
98 99
}

100 101 102 103 104 105 106 107 108 109 110 111 112 113
/* 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 );
}
114

115 116 117 118 119
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 =
{
120 121
    sizeof(struct handle_table),     /* size */
    handle_table_dump,               /* dump */
122
    no_get_type,                     /* get_type */
123 124 125 126
    no_add_queue,                    /* add_queue */
    NULL,                            /* remove_queue */
    NULL,                            /* signaled */
    NULL,                            /* satisfied */
127
    no_signal,                       /* signal */
128
    no_get_fd,                       /* get_fd */
129
    no_map_access,                   /* map_access */
130 131
    default_get_sd,                  /* get_sd */
    default_set_sd,                  /* set_sd */
132
    no_lookup_name,                  /* lookup_name */
133 134
    no_link_name,                    /* link_name */
    NULL,                            /* unlink_name */
135
    no_open_file,                    /* open_file */
136
    no_close_handle,                 /* close_handle */
137
    handle_table_destroy             /* destroy */
138 139 140 141 142 143 144
};

/* dump a handle table */
static void handle_table_dump( struct object *obj, int verbose )
{
    int i;
    struct handle_table *table = (struct handle_table *)obj;
145
    struct handle_entry *entry;
146 147 148 149 150 151 152 153 154 155

    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;
156
        fprintf( stderr, "    %04x: %p %08x ",
157
                 index_to_handle(i), entry->ptr, entry->access );
158
        dump_object_name( entry->ptr );
159 160 161 162 163 164 165 166 167
        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;
168
    struct handle_entry *entry;
169 170 171

    assert( obj->ops == &handle_table_ops );

172 173 174 175 176 177 178 179 180 181 182
    /* 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++)
183 184 185
    {
        struct object *obj = entry->ptr;
        entry->ptr = NULL;
186
        if (obj) release_object_from_handle( obj );
187 188 189 190
    }
    free( table->entries );
}

191 192 193 194 195 196 197 198 199
/* 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 );
}

200
/* allocate a new handle table */
201
struct handle_table *alloc_handle_table( struct process *process, int count )
202 203 204 205
{
    struct handle_table *table;

    if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
206
    if (!(table = alloc_object( &handle_table_ops )))
207 208 209 210 211
        return NULL;
    table->process = process;
    table->count   = count;
    table->last    = -1;
    table->free    = 0;
212
    if ((table->entries = mem_alloc( count * sizeof(*table->entries) ))) return table;
213 214 215 216
    release_object( table );
    return NULL;
}

217
/* grow a handle table */
218
static int grow_handle_table( struct handle_table *table )
219 220
{
    struct handle_entry *new_entries;
221
    int count = min( table->count * 2, MAX_HANDLE_ENTRIES );
222

223 224
    if (count == table->count ||
        !(new_entries = realloc( table->entries, count * sizeof(struct handle_entry) )))
225
    {
226
        set_error( STATUS_INSUFFICIENT_RESOURCES );
227 228
        return 0;
    }
229 230
    table->entries = new_entries;
    table->count   = count;
231 232 233
    return 1;
}

234
/* allocate the first free entry in the handle table */
235
static obj_handle_t alloc_entry( struct handle_table *table, void *obj, unsigned int access )
236 237
{
    struct handle_entry *entry = table->entries + table->free;
238
    int i;
239

240 241
    for (i = table->free; i <= table->last; i++, entry++) if (!entry->ptr) goto found;
    if (i >= table->count)
242
    {
243
        if (!grow_handle_table( table )) return 0;
244
        entry = table->entries + i;  /* the entries may have moved */
245
    }
246
    table->last = i;
247
 found:
248
    table->free = i + 1;
249
    entry->ptr    = grab_object_for_handle( obj );
250 251
    entry->access = access;
    return index_to_handle(i);
252 253
}

254
/* allocate a handle for an object, incrementing its refcount */
255 256
static obj_handle_t alloc_handle_entry( struct process *process, void *ptr,
                                        unsigned int access, unsigned int attr )
257
{
258 259
    struct object *obj = ptr;

260
    assert( !(access & RESERVED_ALL) );
261
    if (attr & OBJ_INHERIT) access |= RESERVED_INHERIT;
262 263
    if (!process->handles)
    {
264
        set_error( STATUS_PROCESS_IS_TERMINATING );
265 266 267
        return 0;
    }
    return alloc_entry( process->handles, obj, access );
268
}
269

270 271 272 273 274
/* 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;
275
    if (access & MAXIMUM_ALLOWED) access = GENERIC_ALL;
276 277 278 279
    access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL;
    return alloc_handle_entry( process, ptr, access, attr );
}

280 281 282 283 284 285
/* 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;
286
    access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL;
287
    if (access && !check_object_access( obj, &access )) return 0;
288
    return alloc_handle_entry( process, ptr, access, attr );
289 290
}

291
/* allocate a global handle for an object, incrementing its refcount */
292
/* return the handle, or 0 on error */
293
static obj_handle_t alloc_global_handle_no_access_check( void *obj, unsigned int access )
294 295
{
    if (!global_table)
296
    {
297
        if (!(global_table = alloc_handle_table( NULL, 0 )))
298
            return 0;
299
        make_object_static( &global_table->obj );
300
    }
301
    return handle_local_to_global( alloc_entry( global_table, obj, access ));
302 303
}

304 305 306 307 308 309 310 311 312
/* 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 );
}

313
/* return a handle entry, or NULL if the handle is invalid */
314
static struct handle_entry *get_handle( struct process *process, obj_handle_t handle )
315
{
316
    struct handle_table *table = process->handles;
317
    struct handle_entry *entry;
318
    int index;
319

320
    if (handle_is_global(handle))
321
    {
322
        handle = handle_global_to_local(handle);
323
        table = global_table;
324
    }
325
    if (!table) return NULL;
326
    index = handle_to_index( handle );
327 328
    if (index < 0) return NULL;
    if (index > table->last) return NULL;
329
    entry = table->entries + index;
330
    if (!entry->ptr) return NULL;
331 332 333 334
    return entry;
}

/* attempt to shrink a table */
335
static void shrink_handle_table( struct handle_table *table )
336
{
337
    struct handle_entry *entry = table->entries + table->last;
338
    struct handle_entry *new_entries;
339
    int count = table->count;
340

341
    while (table->last >= 0)
342 343
    {
        if (entry->ptr) break;
344
        table->last--;
345 346
        entry--;
    }
347 348
    if (table->last >= count / 4) return;  /* no need to shrink */
    if (count < MIN_HANDLE_ENTRIES * 2) return;  /* too small to shrink */
349
    count /= 2;
350 351 352
    if (!(new_entries = realloc( table->entries, count * sizeof(*new_entries) ))) return;
    table->count   = count;
    table->entries = new_entries;
353 354 355 356
}

/* copy the handle table of the parent process */
/* return 1 if OK, 0 on error */
357
struct handle_table *copy_handle_table( struct process *process, struct process *parent )
358
{
359
    struct handle_table *parent_table = parent->handles;
360 361
    struct handle_table *table;
    int i;
362

363 364
    assert( parent_table );
    assert( parent_table->obj.ops == &handle_table_ops );
365

366
    if (!(table = alloc_handle_table( process, parent_table->count )))
367
        return NULL;
368

369
    if ((table->last = parent_table->last) >= 0)
370
    {
371 372 373
        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++)
374 375
        {
            if (!ptr->ptr) continue;
376
            if (ptr->access & RESERVED_INHERIT) grab_object_for_handle( ptr->ptr );
377 378 379 380
            else ptr->ptr = NULL; /* don't inherit this entry */
        }
    }
    /* attempt to shrink the table */
381
    shrink_handle_table( table );
382
    return table;
383 384 385
}

/* close a handle and decrement the refcount of the associated object */
386
unsigned int close_handle( struct process *process, obj_handle_t handle )
387
{
388
    struct handle_table *table;
389 390 391
    struct handle_entry *entry;
    struct object *obj;

392 393
    if (!(entry = get_handle( process, handle ))) return STATUS_INVALID_HANDLE;
    if (entry->access & RESERVED_CLOSE_PROTECT) return STATUS_HANDLE_NOT_CLOSABLE;
394
    obj = entry->ptr;
395
    if (!obj->ops->close_handle( obj, process, handle )) return STATUS_HANDLE_NOT_CLOSABLE;
396
    entry->ptr = NULL;
397
    table = handle_is_global(handle) ? global_table : process->handles;
398 399
    if (entry < table->entries + table->free) table->free = entry - table->entries;
    if (entry == table->entries + table->last) shrink_handle_table( table );
400
    release_object_from_handle( obj );
401
    return STATUS_SUCCESS;
402 403
}

404
/* retrieve the object corresponding to one of the magic pseudo-handles */
405
static inline struct object *get_magic_handle( obj_handle_t handle )
406
{
407
    switch(handle)
408
    {
409 410 411 412 413 414
        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;
415 416 417 418 419 420 421 422 423 424
        case 0xfffffffe:  /* current thread pseudo-handle */
            return &current->obj;
        case 0x7fffffff:  /* current process pseudo-handle */
        case 0xffffffff:  /* current process pseudo-handle */
            return (struct object *)current->process;
        default:
            return NULL;
    }
}

425
/* retrieve the object corresponding to a handle, incrementing its refcount */
426
struct object *get_handle_obj( struct process *process, obj_handle_t handle,
427 428 429 430 431
                               unsigned int access, const struct object_ops *ops )
{
    struct handle_entry *entry;
    struct object *obj;

432
    if (!(obj = get_magic_handle( handle )))
433
    {
434 435 436 437 438
        if (!(entry = get_handle( process, handle )))
        {
            set_error( STATUS_INVALID_HANDLE );
            return NULL;
        }
439 440 441 442 443 444
        obj = entry->ptr;
        if (ops && (obj->ops != ops))
        {
            set_error( STATUS_OBJECT_TYPE_MISMATCH );  /* not the right type */
            return NULL;
        }
445 446
        if ((entry->access & access) != access)
        {
447
            set_error( STATUS_ACCESS_DENIED );
448 449 450
            return NULL;
        }
    }
451
    else if (ops && (obj->ops != ops))
452
    {
453
        set_error( STATUS_OBJECT_TYPE_MISMATCH );  /* not the right type */
454 455 456 457 458
        return NULL;
    }
    return grab_object( obj );
}

459 460 461 462 463
/* retrieve the access rights of a given handle */
unsigned int get_handle_access( struct process *process, obj_handle_t handle )
{
    struct handle_entry *entry;

464
    if (get_magic_handle( handle )) return ~RESERVED_ALL;  /* magic handles have all access rights */
465
    if (!(entry = get_handle( process, handle ))) return 0;
466
    return entry->access & ~RESERVED_ALL;
467 468
}

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
/* 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;
}

488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
/* 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,
                                unsigned int *index )
{
    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;
        return index_to_handle(i);
    }
    return 0;
}

509
/* get/set the handle reserved flags */
510
/* return the old flags (or -1 on error) */
511
static int set_handle_flags( struct process *process, obj_handle_t handle, int mask, int flags )
512 513
{
    struct handle_entry *entry;
514
    unsigned int old_access;
515

516 517 518
    if (get_magic_handle( handle ))
    {
        /* we can retrieve but not set info for magic handles */
519
        if (mask) set_error( STATUS_ACCESS_DENIED );
520 521
        return 0;
    }
522 523 524 525 526
    if (!(entry = get_handle( process, handle )))
    {
        set_error( STATUS_INVALID_HANDLE );
        return -1;
    }
527
    old_access = entry->access;
528 529 530
    mask  = (mask << RESERVED_SHIFT) & RESERVED_ALL;
    flags = (flags << RESERVED_SHIFT) & mask;
    entry->access = (entry->access & ~mask) | flags;
531
    return (old_access & RESERVED_ALL) >> RESERVED_SHIFT;
532 533 534
}

/* duplicate a handle */
535
obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, struct process *dst,
536
                               unsigned int access, unsigned int attr, unsigned int options )
537
{
538
    obj_handle_t res;
539 540
    struct handle_entry *entry;
    unsigned int src_access;
541
    struct object *obj = get_handle_obj( src, src_handle, 0, NULL );
542

543
    if (!obj) return 0;
544 545 546 547 548 549
    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;

550
    if (options & DUP_HANDLE_SAME_ACCESS)
551 552 553 554 555 556
        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)
557
    {
558 559 560 561
        if (options & DUP_HANDLE_MAKE_GLOBAL)
            res = alloc_global_handle( obj, access );
        else
            res = alloc_handle( dst, obj, access, attr );
562
    }
563
    else
564 565 566
    {
        if (options & DUP_HANDLE_MAKE_GLOBAL)
            res = alloc_global_handle_no_access_check( obj, access );
567 568 569 570 571 572 573
        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;
        }
574
        else
575
            res = alloc_handle_entry( dst, obj, access, attr );
576 577
    }

578
    release_object( obj );
579 580 581 582
    return res;
}

/* open a new handle to an existing object */
583 584 585
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 )
586
{
587
    obj_handle_t handle = 0;
588
    struct object *obj, *root = NULL;
589

590 591 592 593 594 595
    if (name->len >= 65534)
    {
        set_error( STATUS_OBJECT_NAME_INVALID );
        return 0;
    }

596 597 598 599 600 601 602 603
    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;
    }
604

605
    if ((obj = open_named_object( root, ops, name, attributes )))
606
    {
607
        handle = alloc_handle( process, obj, access, attributes );
608 609
        release_object( obj );
    }
610
    if (root) release_object( root );
611
    return handle;
612 613
}

614 615 616
/* return the size of the handle table of a given process */
unsigned int get_handle_table_count( struct process *process )
{
617
    if (!process->handles) return 0;
618 619 620
    return process->handles->count;
}

621 622 623
/* close a handle */
DECL_HANDLER(close_handle)
{
624 625
    unsigned int err = close_handle( current->process, req->handle );
    set_error( err );
626 627 628 629
}

/* set a handle information */
DECL_HANDLER(set_handle_info)
630 631 632 633
{
    reply->old_flags = set_handle_flags( current->process, req->handle, req->mask, req->flags );
}

634 635 636
/* duplicate a handle */
DECL_HANDLER(dup_handle)
{
637
    struct process *src, *dst = NULL;
638

639
    reply->handle = 0;
640 641 642 643
    if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
    {
        if (req->options & DUP_HANDLE_MAKE_GLOBAL)
        {
644
            reply->handle = duplicate_handle( src, req->src_handle, NULL,
645
                                              req->access, req->attributes, req->options );
646 647 648
        }
        else if ((dst = get_process_from_handle( req->dst_process, PROCESS_DUP_HANDLE )))
        {
649
            reply->handle = duplicate_handle( src, req->src_handle, dst,
650
                                              req->access, req->attributes, req->options );
651 652 653
            release_object( dst );
        }
        /* close the handle no matter what happened */
654 655
        if ((req->options & DUP_HANDLE_CLOSE_SOURCE) && (src != dst || req->src_handle != reply->handle))
            reply->closed = !close_handle( src, req->src_handle );
656
        reply->self = (src == current->process);
657 658 659
        release_object( src );
    }
}
660 661 662 663

DECL_HANDLER(get_object_info)
{
    struct object *obj;
664
    WCHAR *name;
665 666 667 668 669

    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;
670
    reply->handle_count = obj->handle_count;
671 672
    if ((name = get_object_full_name( obj, &reply->total )))
        set_reply_data_ptr( name, min( reply->total, get_reply_max_size() ));
673 674
    release_object( obj );
}
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689

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 ||
690 691
        req->security_info & GROUP_SECURITY_INFORMATION ||
        req->security_info & LABEL_SECURITY_INFORMATION)
692 693 694 695 696 697 698 699
        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;

700
    obj->ops->set_sd( obj, sd, req->security_info );
701 702
    release_object( obj );
}
703 704 705 706 707 708 709 710 711 712

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;
713
    ACL *label_acl = NULL;
714 715 716 717 718 719

    if (req->security_info & SACL_SECURITY_INFORMATION)
        access |= ACCESS_SYSTEM_SECURITY;

    if (!(obj = get_handle_obj( current->process, req->handle, access, NULL ))) return;

720
    sd = obj->ops->get_sd( obj );
721 722 723 724 725 726 727
    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;
728 729
        else
            req_sd.owner_len = 0;
730 731 732 733

        group = sd_get_group( sd );
        if (req->security_info & GROUP_SECURITY_INFORMATION)
            req_sd.group_len = sd->group_len;
734 735
        else
            req_sd.group_len = 0;
736 737 738 739

        sacl = sd_get_sacl( sd, &present );
        if (req->security_info & SACL_SECURITY_INFORMATION && present)
            req_sd.sacl_len = sd->sacl_len;
740 741 742 743 744 745
        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;
        }
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
        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);
    }

775
done:
776
    release_object( obj );
777
    free( label_acl );
778
}
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834

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;
    unsigned int i;

    if (!table)
        return 0;

    for (i = 0, entry = table->entries; i <= table->last; i++, entry++)
    {
        if (!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;
        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 );
    }
}