diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c
index cc3b4d69e2000eb40b61da2e051bb9ebc829e5c6..4fbb973a2f3752ce7d627ef8872c7c79209a84c3 100644
--- a/dlls/ntdll/om.c
+++ b/dlls/ntdll/om.c
@@ -636,35 +636,31 @@ NTSTATUS WINAPI NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle, IN ACCESS_MASK
  *  Failure: An NTSTATUS error code.
  */
 NTSTATUS WINAPI NtCreateSymbolicLinkObject(OUT PHANDLE SymbolicLinkHandle,IN ACCESS_MASK DesiredAccess,
-	                                   IN POBJECT_ATTRIBUTES ObjectAttributes,
-                                           IN PUNICODE_STRING TargetName)
+	                                   POBJECT_ATTRIBUTES attr, PUNICODE_STRING TargetName)
 {
     NTSTATUS ret;
+    data_size_t len;
+    struct object_attributes *objattr;
 
     if (!SymbolicLinkHandle || !TargetName) return STATUS_ACCESS_VIOLATION;
     if (!TargetName->Buffer) return STATUS_INVALID_PARAMETER;
 
     TRACE("(%p,0x%08x,%s -> %s)\n", SymbolicLinkHandle, DesiredAccess,
-          debugstr_ObjectAttributes(ObjectAttributes), debugstr_us(TargetName));
+          debugstr_ObjectAttributes(attr), debugstr_us(TargetName));
+
+    if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
 
     SERVER_START_REQ(create_symlink)
     {
         req->access = DesiredAccess;
-        req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0;
-        req->rootdir = wine_server_obj_handle( ObjectAttributes ? ObjectAttributes->RootDirectory : 0 );
-        if (ObjectAttributes && ObjectAttributes->ObjectName)
-        {
-            req->name_len = ObjectAttributes->ObjectName->Length;
-            wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
-                                 ObjectAttributes->ObjectName->Length);
-        }
-        else
-            req->name_len = 0;
+        wine_server_add_data( req, objattr, len );
         wine_server_add_data(req, TargetName->Buffer, TargetName->Length);
         ret = wine_server_call( req );
         *SymbolicLinkHandle = wine_server_ptr_handle( reply->handle );
     }
     SERVER_END_REQ;
+
+    RtlFreeHeap( GetProcessHeap(), 0, objattr );
     return ret;
 }
 
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 8566617407800f1c3e18b67984d882e9de8c420f..4614c983257a75237095bf2cc94db1dfe77bb6a7 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -4760,12 +4760,8 @@ struct create_symlink_request
 {
     struct request_header __header;
     unsigned int   access;
-    unsigned int   attributes;
-    obj_handle_t   rootdir;
-    data_size_t    name_len;
-    /* VARARG(name,unicode_str,name_len); */
+    /* VARARG(objattr,object_attributes); */
     /* VARARG(target_name,unicode_str); */
-    char __pad_28[4];
 };
 struct create_symlink_reply
 {
diff --git a/server/directory.c b/server/directory.c
index d05b60fe7bbb38e620a5f12226bea9d145636745..05dddeceaecf100834ff85ef7f5285921ae067ca 100644
--- a/server/directory.c
+++ b/server/directory.c
@@ -463,15 +463,15 @@ void init_directories(void)
     create_unix_device( dir_device, &null_str, "/dev/null" );
 
     /* symlinks */
-    link_dosdev    = create_symlink( root_directory, &link_dosdev_str, 0, &dir_global_str );
-    link_global1   = create_symlink( dir_global, &link_global_str, 0, &dir_global_str );
-    link_global2   = create_symlink( dir_basenamed, &link_global_str, 0, &dir_basenamed_str );
-    link_local     = create_symlink( dir_basenamed, &link_local_str, 0, &dir_basenamed_str );
-    link_nul       = create_symlink( dir_global, &link_nul_str, 0, &dir_null_str );
-    link_pipe      = create_symlink( dir_global, &link_pipe_str, 0, &dir_named_pipe_str );
-    link_mailslot  = create_symlink( dir_global, &link_mailslot_str, 0, &dir_mailslot_str );
-    link_0         = create_symlink( dir_sessions, &link_0_str, 0, &dir_basenamed_str );
-    link_session   = create_symlink( dir_basenamed, &link_session_str, 0, &link_sessions_str );
+    link_dosdev    = create_symlink( root_directory, &link_dosdev_str, 0, &dir_global_str, NULL );
+    link_global1   = create_symlink( dir_global, &link_global_str, 0, &dir_global_str, NULL );
+    link_global2   = create_symlink( dir_basenamed, &link_global_str, 0, &dir_basenamed_str, NULL );
+    link_local     = create_symlink( dir_basenamed, &link_local_str, 0, &dir_basenamed_str, NULL );
+    link_nul       = create_symlink( dir_global, &link_nul_str, 0, &dir_null_str, NULL );
+    link_pipe      = create_symlink( dir_global, &link_pipe_str, 0, &dir_named_pipe_str, NULL );
+    link_mailslot  = create_symlink( dir_global, &link_mailslot_str, 0, &dir_mailslot_str, NULL );
+    link_0         = create_symlink( dir_sessions, &link_0_str, 0, &dir_basenamed_str, NULL );
+    link_session   = create_symlink( dir_basenamed, &link_session_str, 0, &link_sessions_str, NULL );
     make_object_static( (struct object *)link_dosdev );
     make_object_static( (struct object *)link_global1 );
     make_object_static( (struct object *)link_global2 );
diff --git a/server/object.h b/server/object.h
index b59811f44b02caad11575aad6149285cac02560d..8e010a3fb18589a098c29940bb09e4549f23986c 100644
--- a/server/object.h
+++ b/server/object.h
@@ -222,7 +222,8 @@ extern void init_directories(void);
 /* symbolic link functions */
 
 extern struct symlink *create_symlink( struct directory *root, const struct unicode_str *name,
-                                       unsigned int attr, const struct unicode_str *target );
+                                       unsigned int attr, const struct unicode_str *target,
+                                       const struct security_descriptor *sd );
 
 /* global variables */
 
diff --git a/server/protocol.def b/server/protocol.def
index 28c70223151cac90d2daa7899571ba988cbc5c44..cbf5ea74a2f45f0ebe1e0514e95bd9c8c127f44c 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3331,10 +3331,7 @@ struct handle_info
 /* Create a symbolic link object */
 @REQ(create_symlink)
     unsigned int   access;        /* access flags */
-    unsigned int   attributes;    /* object attributes */
-    obj_handle_t   rootdir;       /* root directory */
-    data_size_t    name_len;      /* length of the symlink name in bytes */
-    VARARG(name,unicode_str,name_len); /* symlink name */
+    VARARG(objattr,object_attributes); /* object attributes */
     VARARG(target_name,unicode_str);   /* target name */
 @REPLY
     obj_handle_t   handle;        /* handle to the symlink */
diff --git a/server/request.h b/server/request.h
index 2acf9cdf89a3ab3d68b9ca2466d9e1bab159b76b..e1d2487007eb2d3207748d15057948433241891d 100644
--- a/server/request.h
+++ b/server/request.h
@@ -2110,10 +2110,7 @@ C_ASSERT( sizeof(struct get_directory_entry_request) == 24 );
 C_ASSERT( FIELD_OFFSET(struct get_directory_entry_reply, name_len) == 8 );
 C_ASSERT( sizeof(struct get_directory_entry_reply) == 16 );
 C_ASSERT( FIELD_OFFSET(struct create_symlink_request, access) == 12 );
-C_ASSERT( FIELD_OFFSET(struct create_symlink_request, attributes) == 16 );
-C_ASSERT( FIELD_OFFSET(struct create_symlink_request, rootdir) == 20 );
-C_ASSERT( FIELD_OFFSET(struct create_symlink_request, name_len) == 24 );
-C_ASSERT( sizeof(struct create_symlink_request) == 32 );
+C_ASSERT( sizeof(struct create_symlink_request) == 16 );
 C_ASSERT( FIELD_OFFSET(struct create_symlink_reply, handle) == 8 );
 C_ASSERT( sizeof(struct create_symlink_reply) == 16 );
 C_ASSERT( FIELD_OFFSET(struct open_symlink_request, access) == 12 );
diff --git a/server/symlink.c b/server/symlink.c
index 2330fde1cea690552f0852e67381d2552a0ac0f5..28d51abbed4b1ca530b9d5490af88f8e63601d37 100644
--- a/server/symlink.c
+++ b/server/symlink.c
@@ -132,7 +132,8 @@ static void symlink_destroy( struct object *obj )
 }
 
 struct symlink *create_symlink( struct directory *root, const struct unicode_str *name,
-                                unsigned int attr, const struct unicode_str *target )
+                                unsigned int attr, const struct unicode_str *target,
+                                const struct security_descriptor *sd )
 {
     struct symlink *symlink;
 
@@ -145,7 +146,13 @@ struct symlink *create_symlink( struct directory *root, const struct unicode_str
         (get_error() != STATUS_OBJECT_NAME_EXISTS))
     {
         if ((symlink->target = memdup( target->str, target->len )))
+        {
             symlink->len = target->len;
+            if (sd)
+                default_set_sd( &symlink->obj, sd,
+                                OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+                                DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION );
+        }
         else
         {
             release_object( symlink );
@@ -162,23 +169,20 @@ DECL_HANDLER(create_symlink)
     struct symlink *symlink;
     struct unicode_str name, target;
     struct directory *root = NULL;
+    const struct security_descriptor *sd;
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name );
 
-    if (req->name_len > get_req_data_size())
-    {
-        set_error( STATUS_INVALID_PARAMETER );
-        return;
-    }
-    name.str   = get_req_data();
-    target.str = name.str + req->name_len / sizeof(WCHAR);
-    name.len   = (target.str - name.str) * sizeof(WCHAR);
-    target.len = ((get_req_data_size() - name.len) / sizeof(WCHAR)) * sizeof(WCHAR);
+    if (!objattr) return;
 
-    if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
-        return;
+    target.str = (const WCHAR *)get_req_data() + sizeof(*objattr) / sizeof(WCHAR) +
+                  objattr->sd_len / sizeof(WCHAR) + name.len / sizeof(WCHAR);
+    target.len = get_req_data_size() - ((const char *)target.str - (const char *)get_req_data());
+
+    if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 ))) return;
 
-    if ((symlink = create_symlink( root, &name, req->attributes, &target )))
+    if ((symlink = create_symlink( root, &name, objattr->attributes, &target, sd )))
     {
-        reply->handle = alloc_handle( current->process, symlink, req->access, req->attributes );
+        reply->handle = alloc_handle( current->process, symlink, req->access, objattr->attributes );
         release_object( symlink );
     }