From 546289dc59e5208cf20789fac02b46d8014d4f84 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 20 Jan 2016 22:02:03 +0900 Subject: [PATCH] server: Create window stations objects in a standard directory. Signed-off-by: Alexandre Julliard --- dlls/user32/winstation.c | 25 +++++++++++++++++++++++++ include/wine/server_protocol.h | 6 ++++-- server/directory.c | 10 +++++++++- server/protocol.def | 2 ++ server/request.h | 4 +++- server/trace.c | 2 ++ server/winstation.c | 27 ++++++++++++++++++--------- 7 files changed, 63 insertions(+), 13 deletions(-) diff --git a/dlls/user32/winstation.c b/dlls/user32/winstation.c index ae1d6adcb43..4e431b552e3 100644 --- a/dlls/user32/winstation.c +++ b/dlls/user32/winstation.c @@ -28,6 +28,8 @@ #include "winerror.h" #include "wingdi.h" #include "winuser.h" +#include "winternl.h" +#include "ddk/wdm.h" #include "wine/server.h" #include "wine/unicode.h" #include "wine/debug.h" @@ -53,6 +55,27 @@ static BOOL CALLBACK enum_names_WtoA( LPWSTR name, LPARAM lparam ) return data->func( buffer, data->lparam ); } +/* return a handle to the directory where window station objects are created */ +static HANDLE get_winstations_dir_handle(void) +{ + static HANDLE handle = NULL; + static const WCHAR basenameW[] = {'\\','W','i','n','d','o','w','s','\\', + 'W','i','n','d','o','w','S','t','a','t','i','o','n','s',0}; + UNICODE_STRING str; + OBJECT_ATTRIBUTES attr; + + if (!handle) + { + HANDLE dir; + + RtlInitUnicodeString( &str, basenameW ); + InitializeObjectAttributes( &attr, &str, 0, 0, NULL ); + NtOpenDirectoryObject( &dir, DIRECTORY_CREATE_OBJECT | DIRECTORY_TRAVERSE, &attr ); + if (InterlockedCompareExchangePointer( &handle, dir, 0 ) != 0) /* someone beat us here */ + CloseHandle( dir ); + } + return handle; +} /*********************************************************************** * CreateWindowStationA (USER32.@) @@ -93,6 +116,7 @@ HWINSTA WINAPI CreateWindowStationW( LPCWSTR name, DWORD reserved, ACCESS_MASK a req->access = access; req->attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF | ((sa && sa->bInheritHandle) ? OBJ_INHERIT : 0); + req->rootdir = wine_server_obj_handle( get_winstations_dir_handle() ); wine_server_add_data( req, name, len * sizeof(WCHAR) ); /* it doesn't seem to set last error */ wine_server_call( req ); @@ -137,6 +161,7 @@ HWINSTA WINAPI OpenWindowStationW( LPCWSTR name, BOOL inherit, ACCESS_MASK acces { req->access = access; req->attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0); + req->rootdir = wine_server_obj_handle( get_winstations_dir_handle() ); wine_server_add_data( req, name, len * sizeof(WCHAR) ); if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle ); } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 753f8e35b12..61e6d3f0362 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3795,7 +3795,9 @@ struct create_winstation_request unsigned int flags; unsigned int access; unsigned int attributes; + obj_handle_t rootdir; /* VARARG(name,unicode_str); */ + char __pad_28[4]; }; struct create_winstation_reply { @@ -3811,8 +3813,8 @@ struct open_winstation_request struct request_header __header; unsigned int access; unsigned int attributes; + obj_handle_t rootdir; /* VARARG(name,unicode_str); */ - char __pad_20[4]; }; struct open_winstation_reply { @@ -6155,6 +6157,6 @@ union generic_reply struct terminate_job_reply terminate_job_reply; }; -#define SERVER_PROTOCOL_VERSION 499 +#define SERVER_PROTOCOL_VERSION 500 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/directory.c b/server/directory.c index 05dddeceaec..9369e78c4f4 100644 --- a/server/directory.c +++ b/server/directory.c @@ -380,6 +380,8 @@ void init_directories(void) static const WCHAR dir_objtypeW[] = {'O','b','j','e','c','t','T','y','p','e','s'}; static const WCHAR dir_sessionsW[] = {'S','e','s','s','i','o','n','s'}; static const WCHAR dir_kernelW[] = {'K','e','r','n','e','l','O','b','j','e','c','t','s'}; + static const WCHAR dir_windowsW[] = {'W','i','n','d','o','w','s'}; + static const WCHAR dir_winstationsW[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n','s'}; static const struct unicode_str dir_global_str = {dir_globalW, sizeof(dir_globalW)}; static const struct unicode_str dir_driver_str = {dir_driverW, sizeof(dir_driverW)}; static const struct unicode_str dir_device_str = {dir_deviceW, sizeof(dir_deviceW)}; @@ -390,6 +392,8 @@ void init_directories(void) static const struct unicode_str dir_objtype_str = {dir_objtypeW, sizeof(dir_objtypeW)}; static const struct unicode_str dir_sessions_str = {dir_sessionsW, sizeof(dir_sessionsW)}; static const struct unicode_str dir_kernel_str = {dir_kernelW, sizeof(dir_kernelW)}; + static const struct unicode_str dir_windows_str = {dir_windowsW, sizeof(dir_windowsW)}; + static const struct unicode_str dir_winstations_str = {dir_winstationsW, sizeof(dir_winstationsW)}; /* symlinks */ static const WCHAR link_dosdevW[] = {'D','o','s','D','e','v','i','c','e','s'}; @@ -438,7 +442,7 @@ void init_directories(void) }; static const struct unicode_str keyed_event_crit_sect_str = {keyed_event_crit_sectW, sizeof(keyed_event_crit_sectW)}; - struct directory *dir_driver, *dir_device, *dir_global, *dir_basenamed, *dir_sessions, *dir_kernel; + struct directory *dir_driver, *dir_device, *dir_global, *dir_basenamed, *dir_sessions, *dir_kernel, *dir_windows, *dir_winstation; struct symlink *link_dosdev, *link_global1, *link_global2, *link_local, *link_nul, *link_pipe, *link_mailslot, *link_0, *link_session; struct keyed_event *keyed_event; unsigned int i; @@ -449,9 +453,12 @@ void init_directories(void) dir_objtype = create_directory( root_directory, &dir_objtype_str, 0, HASH_SIZE, NULL ); dir_sessions = create_directory( root_directory, &dir_sessions_str, 0, HASH_SIZE, NULL ); dir_kernel = create_directory( root_directory, &dir_kernel_str, 0, HASH_SIZE, NULL ); + dir_windows = create_directory( root_directory, &dir_windows_str, 0, HASH_SIZE, NULL ); + dir_winstation = create_directory( dir_windows, &dir_winstations_str, 0, HASH_SIZE, NULL ); make_object_static( &root_directory->obj ); make_object_static( &dir_driver->obj ); make_object_static( &dir_objtype->obj ); + make_object_static( &dir_winstation->obj ); dir_global = create_directory( NULL, &dir_global_str, 0, HASH_SIZE, NULL ); /* use a larger hash table for this one since it can contain a lot of objects */ @@ -497,6 +504,7 @@ void init_directories(void) release_object( dir_basenamed ); release_object( dir_sessions ); release_object( dir_kernel ); + release_object( dir_windows ); } /* create a directory object */ diff --git a/server/protocol.def b/server/protocol.def index 08c5bc16df0..2819382413a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2719,6 +2719,7 @@ enum coords_relative unsigned int flags; /* window station flags */ unsigned int access; /* wanted access rights */ unsigned int attributes; /* object attributes */ + obj_handle_t rootdir; /* root directory */ VARARG(name,unicode_str); /* object name */ @REPLY obj_handle_t handle; /* handle to the window station */ @@ -2729,6 +2730,7 @@ enum coords_relative @REQ(open_winstation) unsigned int access; /* wanted access rights */ unsigned int attributes; /* object attributes */ + obj_handle_t rootdir; /* root directory */ VARARG(name,unicode_str); /* object name */ @REPLY obj_handle_t handle; /* handle to the window station */ diff --git a/server/request.h b/server/request.h index d21a539ec62..8e53e39d1c3 100644 --- a/server/request.h +++ b/server/request.h @@ -1766,11 +1766,13 @@ C_ASSERT( sizeof(struct get_window_properties_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct create_winstation_request, flags) == 12 ); C_ASSERT( FIELD_OFFSET(struct create_winstation_request, access) == 16 ); C_ASSERT( FIELD_OFFSET(struct create_winstation_request, attributes) == 20 ); -C_ASSERT( sizeof(struct create_winstation_request) == 24 ); +C_ASSERT( FIELD_OFFSET(struct create_winstation_request, rootdir) == 24 ); +C_ASSERT( sizeof(struct create_winstation_request) == 32 ); C_ASSERT( FIELD_OFFSET(struct create_winstation_reply, handle) == 8 ); C_ASSERT( sizeof(struct create_winstation_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct open_winstation_request, access) == 12 ); C_ASSERT( FIELD_OFFSET(struct open_winstation_request, attributes) == 16 ); +C_ASSERT( FIELD_OFFSET(struct open_winstation_request, rootdir) == 20 ); C_ASSERT( sizeof(struct open_winstation_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct open_winstation_reply, handle) == 8 ); C_ASSERT( sizeof(struct open_winstation_reply) == 16 ); diff --git a/server/trace.c b/server/trace.c index 84ed113dcd2..1b6389444bd 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3245,6 +3245,7 @@ static void dump_create_winstation_request( const struct create_winstation_reque fprintf( stderr, " flags=%08x", req->flags ); fprintf( stderr, ", access=%08x", req->access ); fprintf( stderr, ", attributes=%08x", req->attributes ); + fprintf( stderr, ", rootdir=%04x", req->rootdir ); dump_varargs_unicode_str( ", name=", cur_size ); } @@ -3257,6 +3258,7 @@ static void dump_open_winstation_request( const struct open_winstation_request * { fprintf( stderr, " access=%08x", req->access ); fprintf( stderr, ", attributes=%08x", req->attributes ); + fprintf( stderr, ", rootdir=%04x", req->rootdir ); dump_varargs_unicode_str( ", name=", cur_size ); } diff --git a/server/winstation.c b/server/winstation.c index 50161844aaf..33e121fc847 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -99,8 +99,8 @@ static const struct object_ops desktop_ops = #define DESKTOP_ALL_ACCESS 0x01ff /* create a winstation object */ -static struct winstation *create_winstation( const struct unicode_str *name, unsigned int attr, - unsigned int flags ) +static struct winstation *create_winstation( struct directory *root, const struct unicode_str *name, + unsigned int attr, unsigned int flags ) { struct winstation *winstation; @@ -113,7 +113,7 @@ static struct winstation *create_winstation( const struct unicode_str *name, uns return NULL; } - if ((winstation = create_named_object( winstation_namespace, &winstation_ops, name, attr ))) + if ((winstation = create_named_object_dir( root, name, attr, &winstation_ops ))) { if (get_error() != STATUS_OBJECT_NAME_EXISTS) { @@ -443,27 +443,36 @@ DECL_HANDLER(create_winstation) { struct winstation *winstation; struct unicode_str name; + struct directory *root = NULL; reply->handle = 0; get_req_unicode_str( &name ); - if ((winstation = create_winstation( &name, req->attributes, req->flags ))) + if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 ))) return; + + if ((winstation = create_winstation( root, &name, req->attributes, req->flags ))) { reply->handle = alloc_handle( current->process, winstation, req->access, req->attributes ); release_object( winstation ); } + if (root) release_object( root ); } /* open a handle to a window station */ DECL_HANDLER(open_winstation) { + struct winstation *winstation; struct unicode_str name; + struct directory *root = NULL; get_req_unicode_str( &name ); - if (winstation_namespace) - reply->handle = open_object( winstation_namespace, &name, &winstation_ops, req->access, - req->attributes ); - else - set_error( STATUS_OBJECT_NAME_NOT_FOUND ); + if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 ))) return; + + if ((winstation = open_object_dir( root, &name, req->attributes, &winstation_ops ))) + { + reply->handle = alloc_handle( current->process, &winstation->obj, req->access, req->attributes ); + release_object( winstation ); + } + if (root) release_object( root ); }