diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c index 8ea1ddd053c..55255a83a41 100644 --- a/dlls/ntdll/nt.c +++ b/dlls/ntdll/nt.c @@ -2004,18 +2004,51 @@ NTSTATUS WINAPI NtQuerySystemInformation( break; case SystemHandleInformation: { - SYSTEM_HANDLE_INFORMATION shi; + struct handle_info *info; + DWORD i, num_handles; - memset(&shi, 0, sizeof(shi)); - len = sizeof(shi); - - if ( Length >= len) + if (Length < sizeof(SYSTEM_HANDLE_INFORMATION)) { - if (!SystemInformation) ret = STATUS_ACCESS_VIOLATION; - else memcpy( SystemInformation, &shi, len); + ret = STATUS_INFO_LENGTH_MISMATCH; + break; } - else ret = STATUS_INFO_LENGTH_MISMATCH; - FIXME("info_class SYSTEM_HANDLE_INFORMATION\n"); + + if (!SystemInformation) + { + ret = STATUS_ACCESS_VIOLATION; + break; + } + + num_handles = (Length - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle )) / sizeof(SYSTEM_HANDLE_ENTRY); + if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) * num_handles ))) + return STATUS_NO_MEMORY; + + SERVER_START_REQ( get_system_handles ) + { + wine_server_set_reply( req, info, sizeof(*info) * num_handles ); + if (!(ret = wine_server_call( req ))) + { + SYSTEM_HANDLE_INFORMATION *shi = SystemInformation; + shi->Count = wine_server_reply_size( req ) / sizeof(*info); + len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[shi->Count] ); + for (i = 0; i < shi->Count; i++) + { + memset( &shi->Handle[i], 0, sizeof(shi->Handle[i]) ); + shi->Handle[i].OwnerPid = info[i].owner; + shi->Handle[i].HandleValue = info[i].handle; + shi->Handle[i].AccessMask = info[i].access; + /* FIXME: Fill out ObjectType, HandleFlags, ObjectPointer */ + } + } + else if (ret == STATUS_BUFFER_TOO_SMALL) + { + len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[reply->count] ); + ret = STATUS_INFO_LENGTH_MISMATCH; + } + } + SERVER_END_REQ; + + RtlFreeHeap( GetProcessHeap(), 0, info ); } break; case SystemCacheInformation: diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 3219dbb687f..da509aac216 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -487,7 +487,7 @@ static void test_query_handle(void) /* Request the needed length : a SystemInformationLength greater than one struct sets ReturnLength */ ReturnLength = 0xdeadbeef; status = pNtQuerySystemInformation(SystemHandleInformation, shi, SystemInformationLength, &ReturnLength); - todo_wine ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); ok( ReturnLength != 0xdeadbeef, "Expected valid ReturnLength\n" ); SystemInformationLength = ReturnLength; @@ -503,13 +503,13 @@ static void test_query_handle(void) } ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status ); ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handle[shi->Count]); - todo_wine ok( ReturnLength == ExpectedLength || broken(ReturnLength == ExpectedLength - sizeof(DWORD)), /* Vista / 2008 */ - "Expected length %u, got %u\n", ExpectedLength, ReturnLength ); - todo_wine ok( shi->Count > 1, "Expected more than 1 handle, got %u\n", shi->Count ); + ok( ReturnLength == ExpectedLength || broken(ReturnLength == ExpectedLength - sizeof(DWORD)), /* Vista / 2008 */ + "Expected length %u, got %u\n", ExpectedLength, ReturnLength ); + ok( shi->Count > 1, "Expected more than 1 handle, got %u\n", shi->Count ); for (i = 0, found = FALSE; i < shi->Count && !found; i++) found = (shi->Handle[i].OwnerPid == GetCurrentProcessId()) && ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle); - todo_wine ok( found, "Expected to find event handle in handle list\n" ); + ok( found, "Expected to find event handle in handle list\n" ); CloseHandle(EventHandle); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index f0dc65a736c..2d8a7f7fe3d 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -4655,6 +4655,29 @@ struct get_security_object_reply }; +struct handle_info +{ + process_id_t owner; + obj_handle_t handle; + unsigned int access; +}; + + +struct get_system_handles_request +{ + struct request_header __header; + char __pad_12[4]; +}; +struct get_system_handles_reply +{ + struct reply_header __header; + unsigned int count; + /* VARARG(data,handle_infos); */ + char __pad_12[4]; +}; + + + struct create_mailslot_request { struct request_header __header; @@ -5560,6 +5583,7 @@ enum request REQ_set_token_default_dacl, REQ_set_security_object, REQ_get_security_object, + REQ_get_system_handles, REQ_create_mailslot, REQ_set_mailslot_info, REQ_create_directory, @@ -5836,6 +5860,7 @@ union generic_request struct set_token_default_dacl_request set_token_default_dacl_request; struct set_security_object_request set_security_object_request; struct get_security_object_request get_security_object_request; + struct get_system_handles_request get_system_handles_request; struct create_mailslot_request create_mailslot_request; struct set_mailslot_info_request set_mailslot_info_request; struct create_directory_request create_directory_request; @@ -6110,6 +6135,7 @@ union generic_reply struct set_token_default_dacl_reply set_token_default_dacl_reply; struct set_security_object_reply set_security_object_reply; struct get_security_object_reply get_security_object_reply; + struct get_system_handles_reply get_system_handles_reply; struct create_mailslot_reply create_mailslot_reply; struct set_mailslot_info_reply set_mailslot_info_reply; struct create_directory_reply create_directory_reply; @@ -6154,6 +6180,6 @@ union generic_reply struct terminate_job_reply terminate_job_reply; }; -#define SERVER_PROTOCOL_VERSION 491 +#define SERVER_PROTOCOL_VERSION 492 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/handle.c b/server/handle.c index 5043ff70b71..05d71bac386 100644 --- a/server/handle.c +++ b/server/handle.c @@ -745,3 +745,59 @@ DECL_HANDLER(get_security_object) release_object( obj ); } + +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 ); + } +} diff --git a/server/protocol.def b/server/protocol.def index bfb9089e41e..ea5bd615292 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3266,6 +3266,22 @@ enum coords_relative VARARG(sd,security_descriptor); /* retrieved security descriptor */ @END + +struct handle_info +{ + process_id_t owner; + obj_handle_t handle; + unsigned int access; +}; + +/* Return a list of all opened handles */ +@REQ(get_system_handles) +@REPLY + unsigned int count; /* number of handles */ + VARARG(data,handle_infos); /* array of handle_infos */ +@END + + /* Create a mailslot */ @REQ(create_mailslot) unsigned int access; /* wanted access rights */ diff --git a/server/request.h b/server/request.h index 9653f0c9562..3f7b36bad36 100644 --- a/server/request.h +++ b/server/request.h @@ -333,6 +333,7 @@ DECL_HANDLER(get_token_default_dacl); DECL_HANDLER(set_token_default_dacl); DECL_HANDLER(set_security_object); DECL_HANDLER(get_security_object); +DECL_HANDLER(get_system_handles); DECL_HANDLER(create_mailslot); DECL_HANDLER(set_mailslot_info); DECL_HANDLER(create_directory); @@ -608,6 +609,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_set_token_default_dacl, (req_handler)req_set_security_object, (req_handler)req_get_security_object, + (req_handler)req_get_system_handles, (req_handler)req_create_mailslot, (req_handler)req_set_mailslot_info, (req_handler)req_create_directory, @@ -2083,6 +2085,9 @@ C_ASSERT( FIELD_OFFSET(struct get_security_object_request, security_info) == 16 C_ASSERT( sizeof(struct get_security_object_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct get_security_object_reply, sd_len) == 8 ); C_ASSERT( sizeof(struct get_security_object_reply) == 16 ); +C_ASSERT( sizeof(struct get_system_handles_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_system_handles_reply, count) == 8 ); +C_ASSERT( sizeof(struct get_system_handles_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct create_mailslot_request, access) == 12 ); C_ASSERT( FIELD_OFFSET(struct create_mailslot_request, attributes) == 16 ); C_ASSERT( FIELD_OFFSET(struct create_mailslot_request, rootdir) == 20 ); diff --git a/server/trace.c b/server/trace.c index 405a1c9621b..c53af3cf1fd 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1142,6 +1142,23 @@ static void dump_varargs_rawinput_devices(const char *prefix, data_size_t size ) fputc( '}', stderr ); } +static void dump_varargs_handle_infos( const char *prefix, data_size_t size ) +{ + const struct handle_info *handle; + + fprintf( stderr, "%s{", prefix ); + while (size >= sizeof(*handle)) + { + handle = cur_data; + fprintf( stderr, "{owner=%04x,handle=%04x,access=%08x}", + handle->owner, handle->handle, handle->access ); + size -= sizeof(*handle); + remove_data( sizeof(*handle) ); + if (size) fputc( ',', stderr ); + } + fputc( '}', stderr ); +} + typedef void (*dump_func)( const void *req ); /* Everything below this line is generated automatically by tools/make_requests */ @@ -3838,6 +3855,16 @@ static void dump_get_security_object_reply( const struct get_security_object_rep dump_varargs_security_descriptor( ", sd=", cur_size ); } +static void dump_get_system_handles_request( const struct get_system_handles_request *req ) +{ +} + +static void dump_get_system_handles_reply( const struct get_system_handles_reply *req ) +{ + fprintf( stderr, " count=%08x", req->count ); + dump_varargs_handle_infos( ", data=", cur_size ); +} + static void dump_create_mailslot_request( const struct create_mailslot_request *req ) { fprintf( stderr, " access=%08x", req->access ); @@ -4501,6 +4528,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_token_default_dacl_request, (dump_func)dump_set_security_object_request, (dump_func)dump_get_security_object_request, + (dump_func)dump_get_system_handles_request, (dump_func)dump_create_mailslot_request, (dump_func)dump_set_mailslot_info_request, (dump_func)dump_create_directory_request, @@ -4773,6 +4801,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { NULL, NULL, (dump_func)dump_get_security_object_reply, + (dump_func)dump_get_system_handles_reply, (dump_func)dump_create_mailslot_reply, (dump_func)dump_set_mailslot_info_reply, (dump_func)dump_create_directory_reply, @@ -5045,6 +5074,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "set_token_default_dacl", "set_security_object", "get_security_object", + "get_system_handles", "create_mailslot", "set_mailslot_info", "create_directory",