diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c
index 06ec9f63ab48d28ad1c61a2b13fc179ec58e4aa7..7cb7f06006a48248851439c524bba9cd17da8122 100644
--- a/dlls/ntdll/om.c
+++ b/dlls/ntdll/om.c
@@ -162,152 +162,84 @@ NTSTATUS WINAPI NtSetInformationObject(IN HANDLE handle,
  *
  * An ntdll analogue to GetKernelObjectSecurity().
  *
- * NOTES
- *  only the lowest 4 bit of SecurityObjectInformationClass are used
- *  0x7-0xf returns STATUS_ACCESS_DENIED (even running with system privileges)
- *
- * FIXME
- *  We are constructing a fake sid (Administrators:Full, System:Full, Everyone:Read)
  */
 NTSTATUS WINAPI
 NtQuerySecurityObject(
 	IN HANDLE Object,
 	IN SECURITY_INFORMATION RequestedInformation,
-	OUT PSECURITY_DESCRIPTOR pSecurityDesriptor,
+	OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
 	IN ULONG Length,
 	OUT PULONG ResultLength)
 {
-	static const SID_IDENTIFIER_AUTHORITY localSidAuthority = {SECURITY_NT_AUTHORITY};
-	static const SID_IDENTIFIER_AUTHORITY worldSidAuthority = {SECURITY_WORLD_SID_AUTHORITY};
-	BYTE Buffer[256];
-	PISECURITY_DESCRIPTOR_RELATIVE psd = (PISECURITY_DESCRIPTOR_RELATIVE)Buffer;
-	UINT BufferIndex = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
-
-	FIXME("(%p,0x%08x,%p,0x%08x,%p) stub!\n",
-	Object, RequestedInformation, pSecurityDesriptor, Length, ResultLength);
-
-	RequestedInformation &= 0x0000000f;
-
-	ZeroMemory(Buffer, 256);
-	RtlCreateSecurityDescriptor((PSECURITY_DESCRIPTOR)psd, SECURITY_DESCRIPTOR_REVISION);
-	psd->Control = SE_SELF_RELATIVE |
-	  ((RequestedInformation & DACL_SECURITY_INFORMATION) ? SE_DACL_PRESENT:0);
-
-	/* owner: administrator S-1-5-20-220*/
-	if (OWNER_SECURITY_INFORMATION & RequestedInformation)
-	{
-	  SID* psid = (SID*)&(Buffer[BufferIndex]);
-
-	  psd->Owner = BufferIndex;
-	  BufferIndex += RtlLengthRequiredSid(2);
-
-	  psid->Revision = SID_REVISION;
-	  psid->SubAuthorityCount = 2;
-	  psid->IdentifierAuthority = localSidAuthority;
-	  psid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
-	  psid->SubAuthority[1] = DOMAIN_ALIAS_RID_ADMINS;
-	}
-
-	/* group: built in domain S-1-5-12 */
-	if (GROUP_SECURITY_INFORMATION & RequestedInformation)
-	{
-	  SID* psid = (SID*) &(Buffer[BufferIndex]);
-
-	  psd->Group = BufferIndex;
-	  BufferIndex += RtlLengthRequiredSid(1);
-
-	  psid->Revision = SID_REVISION;
-	  psid->SubAuthorityCount = 1;
-	  psid->IdentifierAuthority = localSidAuthority;
-	  psid->SubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID;
-	}
-
-	/* discretionary ACL */
-	if (DACL_SECURITY_INFORMATION & RequestedInformation)
-	{
-	  /* acl header */
-	  PACL pacl = (PACL)&(Buffer[BufferIndex]);
-	  PACCESS_ALLOWED_ACE pace;
-	  SID* psid;
-
-	  psd->Dacl = BufferIndex;
-
-	  pacl->AclRevision = MIN_ACL_REVISION;
-	  pacl->AceCount = 3;
-	  pacl->AclSize = BufferIndex; /* storing the start index temporary */
-
-	  BufferIndex += sizeof(ACL);
-
-	  /* ACE System - full access */
-	  pace = (PACCESS_ALLOWED_ACE)&(Buffer[BufferIndex]);
-	  BufferIndex += sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD);
-
-	  pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
-	  pace->Header.AceFlags = CONTAINER_INHERIT_ACE;
-	  pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + RtlLengthRequiredSid(1);
-          pace->Mask = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL;
-	  pace->SidStart = BufferIndex;
-
-	  /* SID S-1-5-12 (System) */
-	  psid = (SID*)&(Buffer[BufferIndex]);
-
-	  BufferIndex += RtlLengthRequiredSid(1);
-
-	  psid->Revision = SID_REVISION;
-	  psid->SubAuthorityCount = 1;
-	  psid->IdentifierAuthority = localSidAuthority;
-	  psid->SubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID;
-
-	  /* ACE Administrators - full access*/
-	  pace = (PACCESS_ALLOWED_ACE) &(Buffer[BufferIndex]);
-	  BufferIndex += sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD);
-
-	  pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
-	  pace->Header.AceFlags = CONTAINER_INHERIT_ACE;
-	  pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + RtlLengthRequiredSid(2);
-          pace->Mask = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL;
-	  pace->SidStart = BufferIndex;
-
-	  /* S-1-5-12 (Administrators) */
-	  psid = (SID*)&(Buffer[BufferIndex]);
-
-	  BufferIndex += RtlLengthRequiredSid(2);
-
-	  psid->Revision = SID_REVISION;
-	  psid->SubAuthorityCount = 2;
-	  psid->IdentifierAuthority = localSidAuthority;
-	  psid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
-	  psid->SubAuthority[1] = DOMAIN_ALIAS_RID_ADMINS;
-
-	  /* ACE Everyone - read access */
-	  pace = (PACCESS_ALLOWED_ACE)&(Buffer[BufferIndex]);
-	  BufferIndex += sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD);
-
-	  pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
-	  pace->Header.AceFlags = CONTAINER_INHERIT_ACE;
-	  pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + RtlLengthRequiredSid(1);
-	  pace->Mask = READ_CONTROL| 0x19;
-	  pace->SidStart = BufferIndex;
-
-	  /* SID S-1-1-0 (Everyone) */
-	  psid = (SID*)&(Buffer[BufferIndex]);
-
-	  BufferIndex += RtlLengthRequiredSid(1);
-
-	  psid->Revision = SID_REVISION;
-	  psid->SubAuthorityCount = 1;
-	  psid->IdentifierAuthority = worldSidAuthority;
-	  psid->SubAuthority[0] = 0;
-
-	  /* calculate used bytes */
-	  pacl->AclSize = BufferIndex - pacl->AclSize;
-	}
-	*ResultLength = BufferIndex;
-	TRACE("len=%u\n", *ResultLength);
-	if (Length < *ResultLength) return STATUS_BUFFER_TOO_SMALL;
-	memcpy(pSecurityDesriptor, Buffer, *ResultLength);
-
-	return STATUS_SUCCESS;
+    PISECURITY_DESCRIPTOR_RELATIVE psd = pSecurityDescriptor;
+    NTSTATUS status;
+    unsigned int buffer_size = 512;
+    BOOLEAN need_more_memory = FALSE;
+
+    TRACE("(%p,0x%08x,%p,0x%08x,%p)\n",
+	Object, RequestedInformation, pSecurityDescriptor, Length, ResultLength);
+
+    do
+    {
+        char *buffer = RtlAllocateHeap(GetProcessHeap(), 0, buffer_size);
+        if (!buffer)
+            return STATUS_NO_MEMORY;
+
+        SERVER_START_REQ( get_security_object )
+        {
+            req->handle = Object;
+            req->security_info = RequestedInformation;
+            wine_server_set_reply( req, buffer, buffer_size );
+            status = wine_server_call( req );
+            if (status == STATUS_SUCCESS)
+            {
+                struct security_descriptor *sd = (struct security_descriptor *)buffer;
+                if (reply->sd_len)
+                {
+                    *ResultLength = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
+                        sd->owner_len + sd->group_len + sd->sacl_len + sd->dacl_len;
+                    if (Length >= *ResultLength)
+                    {
+                        psd->Revision = SECURITY_DESCRIPTOR_REVISION;
+                        psd->Sbz1 = 0;
+                        psd->Control = sd->control | SE_SELF_RELATIVE;
+                        psd->Owner = sd->owner_len ? sizeof(SECURITY_DESCRIPTOR_RELATIVE) : 0;
+                        psd->Group = sd->group_len ? sizeof(SECURITY_DESCRIPTOR_RELATIVE) + sd->owner_len : 0;
+                        psd->Sacl = sd->sacl_len ? sizeof(SECURITY_DESCRIPTOR_RELATIVE) + sd->owner_len + sd->group_len : 0;
+                        psd->Dacl = sd->dacl_len ? sizeof(SECURITY_DESCRIPTOR_RELATIVE) + sd->owner_len + sd->group_len + sd->sacl_len : 0;
+                        /* owner, group, sacl and dacl are the same type as in the server
+                         * and in the same order so we copy the memory in one block */
+                        memcpy((char *)pSecurityDescriptor + sizeof(SECURITY_DESCRIPTOR_RELATIVE),
+                               buffer + sizeof(struct security_descriptor),
+                               sd->owner_len + sd->group_len + sd->sacl_len + sd->dacl_len);
+                    }
+                    else
+                        status = STATUS_BUFFER_TOO_SMALL;
+                }
+                else
+                {
+                    *ResultLength = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
+                    if (Length >= *ResultLength)
+                    {
+                        memset(psd, 0, sizeof(*psd));
+                        psd->Revision = SECURITY_DESCRIPTOR_REVISION;
+                        psd->Control = SE_SELF_RELATIVE;
+                    }
+                    else
+                        status = STATUS_BUFFER_TOO_SMALL;
+                }
+            }
+            else if (status == STATUS_BUFFER_TOO_SMALL)
+            {
+                buffer_size = reply->sd_len;
+                need_more_memory = TRUE;
+            }
+        }
+        SERVER_END_REQ;
+        RtlFreeHeap(GetProcessHeap(), 0, buffer);
+    } while (need_more_memory);
+
+    return status;
 }
 
 
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 314a3a624ecda58c17b11db794927fbf36dbd70a..edaea23be644952e56dc067426c08a63a2ff837e 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3832,6 +3832,19 @@ struct set_security_object_reply
     struct reply_header __header;
 };
 
+struct get_security_object_request
+{
+    struct request_header __header;
+    obj_handle_t    handle;
+    unsigned int    security_info;
+};
+struct get_security_object_reply
+{
+    struct reply_header __header;
+    unsigned int    sd_len;
+    /* VARARG(sd,security_descriptor); */
+};
+
 
 struct create_mailslot_request
 {
@@ -4376,6 +4389,7 @@ enum request
     REQ_get_token_user,
     REQ_get_token_groups,
     REQ_set_security_object,
+    REQ_get_security_object,
     REQ_create_mailslot,
     REQ_set_mailslot_info,
     REQ_create_directory,
@@ -4609,6 +4623,7 @@ union generic_request
     struct get_token_user_request get_token_user_request;
     struct get_token_groups_request get_token_groups_request;
     struct set_security_object_request set_security_object_request;
+    struct get_security_object_request get_security_object_request;
     struct create_mailslot_request create_mailslot_request;
     struct set_mailslot_info_request set_mailslot_info_request;
     struct create_directory_request create_directory_request;
@@ -4840,6 +4855,7 @@ union generic_reply
     struct get_token_user_reply get_token_user_reply;
     struct get_token_groups_reply get_token_groups_reply;
     struct set_security_object_reply set_security_object_reply;
+    struct get_security_object_reply get_security_object_reply;
     struct create_mailslot_reply create_mailslot_reply;
     struct set_mailslot_info_reply set_mailslot_info_reply;
     struct create_directory_reply create_directory_reply;
@@ -4864,6 +4880,6 @@ union generic_reply
     struct set_completion_info_reply set_completion_info_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 315
+#define SERVER_PROTOCOL_VERSION 316
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/handle.c b/server/handle.c
index 39911fb3e858f74855e94439c5df2d5802e74ef3..65b4205d24cd6c856034a90dd37125956a43165a 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -615,3 +615,68 @@ DECL_HANDLER(set_security_object)
     set_object_sd( obj, sd, req->security_info );
     release_object( obj );
 }
+
+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;
+
+    if (req->security_info & SACL_SECURITY_INFORMATION)
+        access |= ACCESS_SYSTEM_SECURITY;
+
+    if (!(obj = get_handle_obj( current->process, req->handle, access, NULL ))) return;
+
+    sd = obj->sd;
+    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;
+
+        group = sd_get_group( sd );
+        if (req->security_info & GROUP_SECURITY_INFORMATION)
+            req_sd.group_len = sd->group_len;
+
+        req_sd.control |= SE_SACL_PRESENT;
+        sacl = sd_get_sacl( sd, &present );
+        if (req->security_info & SACL_SECURITY_INFORMATION && present)
+            req_sd.sacl_len = sd->sacl_len;
+        else
+            req_sd.sacl_len = 0;
+
+        req_sd.control |= SE_DACL_PRESENT;
+        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);
+    }
+
+    release_object( obj );
+}
diff --git a/server/protocol.def b/server/protocol.def
index 2e83c12ebd585f5708398e9aa80f50c16a267ac9..d7d424803384bb8ec534fb408f690a6ea660b14e 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2768,6 +2768,14 @@ enum message_type
     VARARG(sd,security_descriptor); /* security descriptor to set */
 @END
 
+@REQ(get_security_object)
+    obj_handle_t    handle;       /* handle to the object */
+    unsigned int    security_info; /* which parts of security descriptor to get */
+@REPLY
+    unsigned int    sd_len;         /* buffer size needed for sd */
+    VARARG(sd,security_descriptor); /* retrieved security descriptor */
+@END
+
 /* Create a mailslot */
 @REQ(create_mailslot)
     unsigned int   access;        /* wanted access rights */
diff --git a/server/request.h b/server/request.h
index 0a013abb3157908da9cb50e033ed14ccb8221c38..90ec2e199269ace2dc1d6baf07e08752efec4c86 100644
--- a/server/request.h
+++ b/server/request.h
@@ -314,6 +314,7 @@ DECL_HANDLER(access_check);
 DECL_HANDLER(get_token_user);
 DECL_HANDLER(get_token_groups);
 DECL_HANDLER(set_security_object);
+DECL_HANDLER(get_security_object);
 DECL_HANDLER(create_mailslot);
 DECL_HANDLER(set_mailslot_info);
 DECL_HANDLER(create_directory);
@@ -546,6 +547,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_get_token_user,
     (req_handler)req_get_token_groups,
     (req_handler)req_set_security_object,
+    (req_handler)req_get_security_object,
     (req_handler)req_create_mailslot,
     (req_handler)req_set_mailslot_info,
     (req_handler)req_create_directory,
diff --git a/server/trace.c b/server/trace.c
index d1575e1b9ed3fc980b16a9f727e7b663d68f9ff0..53e0de8ab7b391a5edaa8dd8256b12816fb13ad7 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3350,6 +3350,19 @@ static void dump_set_security_object_request( const struct set_security_object_r
     dump_varargs_security_descriptor( cur_size );
 }
 
+static void dump_get_security_object_request( const struct get_security_object_request *req )
+{
+    fprintf( stderr, " handle=%p,", req->handle );
+    fprintf( stderr, " security_info=%08x", req->security_info );
+}
+
+static void dump_get_security_object_reply( const struct get_security_object_reply *req )
+{
+    fprintf( stderr, " sd_len=%08x,", req->sd_len );
+    fprintf( stderr, " sd=" );
+    dump_varargs_security_descriptor( cur_size );
+}
+
 static void dump_create_mailslot_request( const struct create_mailslot_request *req )
 {
     fprintf( stderr, " access=%08x,", req->access );
@@ -3840,6 +3853,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_get_token_user_request,
     (dump_func)dump_get_token_groups_request,
     (dump_func)dump_set_security_object_request,
+    (dump_func)dump_get_security_object_request,
     (dump_func)dump_create_mailslot_request,
     (dump_func)dump_set_mailslot_info_request,
     (dump_func)dump_create_directory_request,
@@ -4069,6 +4083,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_get_token_user_reply,
     (dump_func)dump_get_token_groups_reply,
     (dump_func)0,
+    (dump_func)dump_get_security_object_reply,
     (dump_func)dump_create_mailslot_reply,
     (dump_func)dump_set_mailslot_info_reply,
     (dump_func)dump_create_directory_reply,
@@ -4298,6 +4313,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "get_token_user",
     "get_token_groups",
     "set_security_object",
+    "get_security_object",
     "create_mailslot",
     "set_mailslot_info",
     "create_directory",