From 37503be65497b97fe5197c2c5c28486e3ff73e59 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Mon, 1 Feb 2016 14:57:37 +0900
Subject: [PATCH] server: Fix checks for a valid directory in object
 attributes.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
---
 dlls/ntdll/tests/om.c | 84 ++++---------------------------------------
 server/completion.c   |  5 ++-
 server/directory.c    |  5 ++-
 server/event.c        | 13 +++----
 server/file.c         |  2 +-
 server/handle.c       | 10 ++++--
 server/mailslot.c     | 15 ++++++--
 server/mapping.c      |  7 ++--
 server/mutex.c        |  7 ++--
 server/named_pipe.c   | 15 +++++---
 server/process.c      |  6 ++--
 server/registry.c     |  4 +--
 server/request.c      |  9 ++++-
 server/request.h      |  3 +-
 server/semaphore.c    |  7 ++--
 server/symlink.c      |  6 ++--
 server/timer.c        |  5 ++-
 17 files changed, 70 insertions(+), 133 deletions(-)

diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c
index c6794cca733..1884e3fa415 100644
--- a/dlls/ntdll/tests/om.c
+++ b/dlls/ntdll/tests/om.c
@@ -472,84 +472,69 @@ static void test_name_limits(void)
 
     str.Length = 0;
     status = pNtCreateMutant( &ret, GENERIC_ALL, &attr2, FALSE );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtCreateMutant failed %x\n", str.Length, status );
     attr3.RootDirectory = ret;
     status = pNtOpenMutant( &ret2, GENERIC_ALL, &attr );
     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenMutant failed %x\n", str.Length, status );
     status = pNtOpenMutant( &ret2, GENERIC_ALL, &attr3 );
-    todo_wine
     ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
         "%u: NtOpenMutant failed %x\n", str.Length, status );
     pNtClose( ret );
     status = pNtCreateSemaphore( &ret, GENERIC_ALL, &attr2, 1, 2 );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtCreateSemaphore failed %x\n", str.Length, status );
     attr3.RootDirectory = ret;
     status = pNtOpenSemaphore( &ret2, GENERIC_ALL, &attr );
     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenSemaphore failed %x\n", str.Length, status );
     status = pNtOpenSemaphore( &ret2, GENERIC_ALL, &attr3 );
-    todo_wine
     ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
         "%u: NtOpenSemaphore failed %x\n", str.Length, status );
     pNtClose( ret );
     status = pNtCreateEvent( &ret, GENERIC_ALL, &attr2, 1, 0 );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtCreateEvent failed %x\n", str.Length, status );
     attr3.RootDirectory = ret;
     status = pNtOpenEvent( &ret2, GENERIC_ALL, &attr );
     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenEvent failed %x\n", str.Length, status );
     status = pNtOpenEvent( &ret2, GENERIC_ALL, &attr3 );
-    todo_wine
     ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
         "%u: NtOpenEvent failed %x\n", str.Length, status );
     pNtClose( ret );
     status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, &attr2, 0 );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtCreateKeyedEvent failed %x\n", str.Length, status );
     attr3.RootDirectory = ret;
     status = pNtOpenKeyedEvent( &ret2, GENERIC_ALL, &attr );
     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenKeyedEvent failed %x\n", str.Length, status );
     status = pNtOpenKeyedEvent( &ret2, GENERIC_ALL, &attr3 );
-    todo_wine
     ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
         "%u: NtOpenKeyedEvent failed %x\n", str.Length, status );
     pNtClose( ret );
     status = pNtCreateTimer( &ret, GENERIC_ALL, &attr2, NotificationTimer );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtCreateTimer failed %x\n", str.Length, status );
     attr3.RootDirectory = ret;
     status = pNtOpenTimer( &ret2, GENERIC_ALL, &attr );
     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenTimer failed %x\n", str.Length, status );
     status = pNtOpenTimer( &ret2, GENERIC_ALL, &attr3 );
-    todo_wine
     ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
         "%u: NtOpenTimer failed %x\n", str.Length, status );
     pNtClose( ret );
     status = pNtCreateIoCompletion( &ret, GENERIC_ALL, &attr2, 0 );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtCreateCompletion failed %x\n", str.Length, status );
     attr3.RootDirectory = ret;
     status = pNtOpenIoCompletion( &ret2, GENERIC_ALL, &attr );
     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenCompletion failed %x\n", str.Length, status );
     status = pNtOpenIoCompletion( &ret2, GENERIC_ALL, &attr3 );
-    todo_wine
     ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
         "%u: NtOpenCompletion failed %x\n", str.Length, status );
     pNtClose( ret );
     status = pNtCreateJobObject( &ret, GENERIC_ALL, &attr2 );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtCreateJobObject failed %x\n", str.Length, status );
     attr3.RootDirectory = ret;
     status = pNtOpenJobObject( &ret2, GENERIC_ALL, &attr );
     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenJobObject failed %x\n", str.Length, status );
     status = pNtOpenJobObject( &ret2, GENERIC_ALL, &attr3 );
-    todo_wine
     ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
         "%u: NtOpenJobObject failed %x\n", str.Length, status );
     pNtClose( ret );
     status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, &attr2 );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtCreateDirectoryObject failed %x\n", str.Length, status );
     attr3.RootDirectory = ret;
     status = pNtOpenDirectoryObject( &ret2, GENERIC_ALL, &attr );
@@ -557,12 +542,10 @@ static void test_name_limits(void)
         "%u: NtOpenDirectoryObject failed %x\n", str.Length, status );
     if (!status) pNtClose( ret2 );
     status = pNtOpenDirectoryObject( &ret2, GENERIC_ALL, &attr3 );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtOpenDirectoryObject failed %x\n", str.Length, status );
     pNtClose( ret2 );
     pNtClose( ret );
     status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, &attr2, &target );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtCreateSymbolicLinkObject failed %x\n", str.Length, status );
     attr3.RootDirectory = ret;
     status = pNtOpenSymbolicLinkObject( &ret2, GENERIC_ALL, &attr );
@@ -573,13 +556,11 @@ static void test_name_limits(void)
     pNtClose( ret2 );
     pNtClose( ret );
     status = pNtCreateSection( &ret, SECTION_MAP_WRITE, &attr2, &size, PAGE_READWRITE, SEC_COMMIT, 0 );
-    todo_wine
     ok( status == STATUS_SUCCESS, "%u: NtCreateSection failed %x\n", str.Length, status );
     attr3.RootDirectory = ret;
     status = pNtOpenSection( &ret2, SECTION_MAP_WRITE, &attr );
     ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenSection failed %x\n", str.Length, status );
     status = pNtOpenSection( &ret2, SECTION_MAP_WRITE, &attr3 );
-    todo_wine
     ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
         "%u: NtOpenSection failed %x\n", str.Length, status );
     pNtClose( ret );
@@ -587,6 +568,12 @@ static void test_name_limits(void)
     str.Length = 67;
     test_all_kernel_objects( __LINE__, &attr2, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_INVALID );
 
+    str.Length = 65532;
+    test_all_kernel_objects( __LINE__, &attr, STATUS_SUCCESS, STATUS_SUCCESS );
+
+    str.Length = 65534;
+    test_all_kernel_objects( __LINE__, &attr, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_INVALID );
+
     str.Length = 128;
     for (attr.Length = 0; attr.Length <= 2 * sizeof(attr); attr.Length++)
     {
@@ -597,61 +584,6 @@ static void test_name_limits(void)
     }
     attr.Length = sizeof(attr);
 
-    str.Length = 65532;
-    test_all_kernel_objects( __LINE__, &attr, STATUS_SUCCESS, STATUS_SUCCESS );
-
-    str.Length = 65534;
-    status = pNtCreateMutant( &ret, GENERIC_ALL, &attr, FALSE );
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateMutant failed %x\n", str.Length, status );
-    status = pNtOpenMutant( &ret, GENERIC_ALL, &attr );
-    todo_wine
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtOpenMutant failed %x\n", str.Length, status );
-    status = pNtCreateSemaphore( &ret, GENERIC_ALL, &attr, 1, 2 );
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateSemaphore failed %x\n", str.Length, status );
-    status = pNtOpenSemaphore( &ret, GENERIC_ALL, &attr );
-    todo_wine
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtOpenSemaphore failed %x\n", str.Length, status );
-    status = pNtCreateEvent( &ret, GENERIC_ALL, &attr, 1, 0 );
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateEvent failed %x\n", str.Length, status );
-    status = pNtOpenEvent( &ret, GENERIC_ALL, &attr );
-    todo_wine
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtOpenEvent failed %x\n", str.Length, status );
-    status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, &attr, 0 );
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateKeyedEvent failed %x\n", str.Length, status );
-    status = pNtOpenKeyedEvent( &ret, GENERIC_ALL, &attr );
-    todo_wine
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtOpenKeyedEvent failed %x\n", str.Length, status );
-    status = pNtCreateTimer( &ret, GENERIC_ALL, &attr, NotificationTimer );
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateTimer failed %x\n", str.Length, status );
-    status = pNtOpenTimer( &ret, GENERIC_ALL, &attr );
-    todo_wine
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtOpenTimer failed %x\n", str.Length, status );
-    status = pNtCreateIoCompletion( &ret, GENERIC_ALL, &attr, 0 );
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateCompletion failed %x\n", str.Length, status );
-    status = pNtOpenIoCompletion( &ret, GENERIC_ALL, &attr );
-    todo_wine
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtOpenCompletion failed %x\n", str.Length, status );
-    status = pNtCreateJobObject( &ret, GENERIC_ALL, &attr );
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateJobObject failed %x\n", str.Length, status );
-    status = pNtOpenJobObject( &ret, GENERIC_ALL, &attr );
-    todo_wine
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtOpenJobObject failed %x\n", str.Length, status );
-    status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, &attr );
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateDirectoryObject failed %x\n", str.Length, status );
-    status = pNtOpenDirectoryObject( &ret, GENERIC_ALL, &attr );
-    todo_wine
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtOpenDirectoryObject failed %x\n", str.Length, status );
-    status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, &attr, &target );
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateSymbolicLinkObject failed %x\n", str.Length, status );
-    status = pNtOpenSymbolicLinkObject( &ret, GENERIC_ALL, &attr );
-    todo_wine
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtOpenSymbolicLinkObject failed %x\n", str.Length, status );
-    status = pNtCreateSection( &ret, SECTION_MAP_WRITE, &attr, &size, PAGE_READWRITE, SEC_COMMIT, 0 );
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateSection failed %x\n", str.Length, status );
-    status = pNtOpenSection( &ret, SECTION_MAP_WRITE, &attr );
-    todo_wine
-    ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtOpenSection failed %x\n", str.Length, status );
-
     /* null attributes or ObjectName, with or without RootDirectory */
     attr3.RootDirectory = 0;
     attr2.ObjectName = attr3.ObjectName = NULL;
@@ -720,7 +652,6 @@ static void test_name_limits(void)
     timeout.QuadPart = -10000;
     status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE,
                                      FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout );
-    todo_wine
     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status );
     status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr2, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE,
                                      FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout );
@@ -759,7 +690,6 @@ static void test_name_limits(void)
     ok( status == STATUS_OBJECT_NAME_INVALID, "NULL: NtCreateNamedPipeFile failed %x\n", status );
     status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr3, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE,
                                      FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout );
-    todo_wine
     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NULL: NtCreateNamedPipeFile failed %x\n", status );
     status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, NULL, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE,
                                      FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256, 256, &timeout );
@@ -771,7 +701,6 @@ static void test_name_limits(void)
     for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i + sizeof(mailslotW)/sizeof(WCHAR)] = 'a';
     str.Length = 0;
     status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0, NULL );
-    todo_wine
     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "%u: NtCreateMailslotFile failed %x\n", str.Length, status );
     status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr2, &iosb, 0, 0, 0, NULL );
     ok( status == STATUS_INVALID_HANDLE, "%u: NtCreateMailslotFile failed %x\n", str.Length, status );
@@ -803,7 +732,6 @@ static void test_name_limits(void)
     status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr2, &iosb, 0, 0, 0, NULL );
     ok( status == STATUS_OBJECT_NAME_INVALID, "NULL: NtCreateMailslotFile failed %x\n", status );
     status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr3, &iosb, 0, 0, 0, NULL );
-    todo_wine
     ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NULL: NtCreateMailslotFile failed %x\n", status );
     status = pNtCreateMailslotFile( &ret, GENERIC_ALL, NULL, &iosb, 0, 0, 0, NULL );
     ok( status == STATUS_INVALID_PARAMETER, "NULL: NtCreateMailslotFile failed %x\n", status );
diff --git a/server/completion.c b/server/completion.c
index ceebce10d8d..9cf196fdcdd 100644
--- a/server/completion.c
+++ b/server/completion.c
@@ -177,12 +177,11 @@ DECL_HANDLER(create_completion)
 {
     struct completion *completion;
     struct unicode_str name;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return;
 
     if ((completion = create_completion( root, &name, objattr->attributes, req->concurrent, sd )))
     {
diff --git a/server/directory.c b/server/directory.c
index 93fdc74def1..6af489e247e 100644
--- a/server/directory.c
+++ b/server/directory.c
@@ -503,12 +503,11 @@ void init_directories(void)
 DECL_HANDLER(create_directory)
 {
     struct unicode_str name;
-    struct directory *dir, *root = NULL;
+    struct directory *dir, *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return;
 
     if ((dir = create_directory( root, &name, objattr->attributes, HASH_SIZE, sd )))
     {
diff --git a/server/event.c b/server/event.c
index 943bd5b8876..782abee9292 100644
--- a/server/event.c
+++ b/server/event.c
@@ -280,15 +280,12 @@ DECL_HANDLER(create_event)
 {
     struct event *event;
     struct unicode_str name;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
 
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 )))
-        return;
-
     if ((event = create_event( root, &name, objattr->attributes,
                                req->manual_reset, req->initial_state, sd )))
     {
@@ -354,14 +351,12 @@ DECL_HANDLER(create_keyed_event)
 {
     struct keyed_event *event;
     struct unicode_str name;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
 
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return;
-
     if ((event = create_keyed_event( root, &name, objattr->attributes, sd )))
     {
         if (get_error() == STATUS_OBJECT_NAME_EXISTS)
diff --git a/server/file.c b/server/file.c
index 39f6ff0bb6a..bf883f3cf76 100644
--- a/server/file.c
+++ b/server/file.c
@@ -688,7 +688,7 @@ DECL_HANDLER(create_file)
     struct fd *root_fd = NULL;
     struct unicode_str unicode_name;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &unicode_name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &unicode_name, NULL );
     const char *name;
     data_size_t name_len;
 
diff --git a/server/handle.c b/server/handle.c
index ce58894ffea..8d6637ea3a0 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -579,11 +579,17 @@ obj_handle_t open_object( struct process *process, obj_handle_t parent, unsigned
     struct directory *root = NULL;
     struct object *obj;
 
-    if (parent && !(root = get_directory_obj( current->process, parent, 0 ))) return 0;
+    if (name->len >= 65534)
+    {
+        set_error( STATUS_OBJECT_NAME_INVALID );
+        return 0;
+    }
+
+    if (parent && !(root = get_directory_obj( process, parent, 0 ))) return 0;
 
     if ((obj = open_object_dir( root, name, attributes, ops )))
     {
-        handle = alloc_handle( current->process, obj, access, attributes );
+        handle = alloc_handle( process, obj, access, attributes );
         release_object( obj );
     }
     if (root) release_object( root );
diff --git a/server/mailslot.c b/server/mailslot.c
index b135fb2f73f..e388f8e5153 100644
--- a/server/mailslot.c
+++ b/server/mailslot.c
@@ -514,12 +514,21 @@ DECL_HANDLER(create_mailslot)
 {
     struct mailslot *mailslot;
     struct unicode_str name;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return;
+
+    if (!name.len)  /* mailslots need a root directory even without a name */
+    {
+        if (!objattr->rootdir)
+        {
+            set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
+            return;
+        }
+        else if (!(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return;
+    }
 
     if ((mailslot = create_mailslot( root, &name, objattr->attributes, req->max_msgsize,
                                      req->read_timeout, sd )))
diff --git a/server/mapping.c b/server/mapping.c
index 3c7293d0e30..aef174c935f 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -661,15 +661,12 @@ DECL_HANDLER(create_mapping)
 {
     struct object *obj;
     struct unicode_str name;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
 
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 )))
-        return;
-
     if ((obj = create_mapping( root, &name, objattr->attributes,
                                req->size, req->protect, req->file_handle, sd )))
     {
diff --git a/server/mutex.c b/server/mutex.c
index 0d7ae031d19..0482fe0b691 100644
--- a/server/mutex.c
+++ b/server/mutex.c
@@ -208,15 +208,12 @@ DECL_HANDLER(create_mutex)
 {
     struct mutex *mutex;
     struct unicode_str name;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
 
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 )))
-        return;
-
     if ((mutex = create_mutex( root, &name, objattr->attributes, req->owned, sd )))
     {
         if (get_error() == STATUS_OBJECT_NAME_EXISTS)
diff --git a/server/named_pipe.c b/server/named_pipe.c
index aa527aa0581..cbacb9363d1 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -917,9 +917,9 @@ DECL_HANDLER(create_named_pipe)
     struct named_pipe *pipe;
     struct pipe_server *server;
     struct unicode_str name;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
 
@@ -930,8 +930,15 @@ DECL_HANDLER(create_named_pipe)
         return;
     }
 
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 )))
-        return;
+    if (!name.len)  /* pipes need a root directory even without a name */
+    {
+        if (!objattr->rootdir)
+        {
+            set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
+            return;
+        }
+        else if (!(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return;
+    }
 
     pipe = create_named_pipe( root, &name, objattr->attributes | OBJ_OPENIF, sd );
 
diff --git a/server/process.c b/server/process.c
index 40cbf938208..6611de1cec1 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1538,14 +1538,12 @@ DECL_HANDLER(create_job)
 {
     struct job *job;
     struct unicode_str name;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
 
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return;
-
     if ((job = create_job_object( root, &name, objattr->attributes, sd )))
     {
         if (get_error() == STATUS_OBJECT_NAME_EXISTS)
diff --git a/server/registry.c b/server/registry.c
index a41f0addbfc..bdfdb2b621c 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -2026,7 +2026,7 @@ DECL_HANDLER(create_key)
     struct unicode_str name, class;
     unsigned int access = req->access;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
 
     if (!objattr) return;
 
@@ -2183,7 +2183,7 @@ DECL_HANDLER(load_registry)
     struct key *key, *parent;
     struct unicode_str name;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
 
     if (!objattr) return;
 
diff --git a/server/request.c b/server/request.c
index 62e2b0304ff..021878a9231 100644
--- a/server/request.c
+++ b/server/request.c
@@ -167,12 +167,15 @@ void *set_reply_data_size( data_size_t size )
 
 /* return object attributes from the current request */
 const struct object_attributes *get_req_object_attributes( const struct security_descriptor **sd,
-                                                           struct unicode_str *name )
+                                                           struct unicode_str *name,
+                                                           struct directory **root )
 {
     static const struct object_attributes empty_attributes;
     const struct object_attributes *attr = get_req_data();
     data_size_t size = get_req_data_size();
 
+    if (root) *root = NULL;
+
     if (!size)
     {
         *sd = NULL;
@@ -196,6 +199,10 @@ const struct object_attributes *get_req_object_attributes( const struct security
         set_error( STATUS_OBJECT_NAME_INVALID );
         return NULL;
     }
+    if (root && attr->rootdir && attr->name_len)
+    {
+        if (!(*root = get_directory_obj( current->process, attr->rootdir, 0 ))) return NULL;
+    }
     *sd = attr->sd_len ? (const struct security_descriptor *)(attr + 1) : NULL;
     name->len = attr->name_len;
     name->str = (const WCHAR *)(attr + 1) + attr->sd_len / sizeof(WCHAR);
diff --git a/server/request.h b/server/request.h
index e4d20e81408..7ec00cdd86b 100644
--- a/server/request.h
+++ b/server/request.h
@@ -47,7 +47,8 @@ extern void fatal_error( const char *err, ... );
 extern const char *get_config_dir(void);
 extern void *set_reply_data_size( data_size_t size );
 extern const struct object_attributes *get_req_object_attributes( const struct security_descriptor **sd,
-                                                                  struct unicode_str *name );
+                                                                  struct unicode_str *name,
+                                                                  struct directory **root );
 extern const void *get_req_data_after_objattr( const struct object_attributes *attr, data_size_t *len );
 extern int receive_fd( struct process *process );
 extern int send_client_fd( struct process *process, int fd, obj_handle_t handle );
diff --git a/server/semaphore.c b/server/semaphore.c
index 7213effe403..73d4fe239c3 100644
--- a/server/semaphore.c
+++ b/server/semaphore.c
@@ -176,15 +176,12 @@ DECL_HANDLER(create_semaphore)
 {
     struct semaphore *sem;
     struct unicode_str name;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
 
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 )))
-        return;
-
     if ((sem = create_semaphore( root, &name, objattr->attributes, req->initial, req->max, sd )))
     {
         if (get_error() == STATUS_OBJECT_NAME_EXISTS)
diff --git a/server/symlink.c b/server/symlink.c
index 2611dc30b88..4254c71ddae 100644
--- a/server/symlink.c
+++ b/server/symlink.c
@@ -166,17 +166,15 @@ DECL_HANDLER(create_symlink)
 {
     struct symlink *symlink;
     struct unicode_str name, target;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
 
     target.str = get_req_data_after_objattr( objattr, &target.len );
     target.len = (target.len / sizeof(WCHAR)) * sizeof(WCHAR);
 
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return;
-
     if ((symlink = create_symlink( root, &name, objattr->attributes, &target, sd )))
     {
         reply->handle = alloc_handle( current->process, symlink, req->access, objattr->attributes );
diff --git a/server/timer.c b/server/timer.c
index 2b9cb79b202..69d0bef8bc6 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -232,12 +232,11 @@ DECL_HANDLER(create_timer)
 {
     struct timer *timer;
     struct unicode_str name;
-    struct directory *root = NULL;
+    struct directory *root;
     const struct security_descriptor *sd;
-    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
 
     if (!objattr) return;
-    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return;
 
     if ((timer = create_timer( root, &name, objattr->attributes, req->manual, sd )))
     {
-- 
GitLab