[LSASRV]
[reactos.git] / reactos / dll / win32 / lsasrv / lsarpc.c
index 9239916..61e7106 100644 (file)
@@ -138,8 +138,80 @@ NTSTATUS WINAPI LsarQuerySecurityObject(
     SECURITY_INFORMATION SecurityInformation,
     PLSAPR_SR_SECURITY_DESCRIPTOR *SecurityDescriptor)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PLSA_DB_OBJECT DbObject = NULL;
+    PSECURITY_DESCRIPTOR RelativeSd = NULL;
+    PLSAPR_SR_SECURITY_DESCRIPTOR SdData = NULL;
+    ACCESS_MASK DesiredAccess = 0;
+    ULONG RelativeSdSize = 0;
+    NTSTATUS Status;
+
+    if (SecurityDescriptor == NULL)
+        return STATUS_INVALID_PARAMETER;
+
+    if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
+        (SecurityInformation & GROUP_SECURITY_INFORMATION) ||
+        (SecurityInformation & DACL_SECURITY_INFORMATION))
+        DesiredAccess |= READ_CONTROL;
+
+    if (SecurityInformation & SACL_SECURITY_INFORMATION)
+        DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+
+    /* Validate the ObjectHandle */
+    Status = LsapValidateDbObject(ObjectHandle,
+                                  LsaDbIgnoreObject,
+                                  DesiredAccess,
+                                  &DbObject);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* Get the size of the SD */
+    Status = LsapGetObjectAttribute(DbObject,
+                                    L"SecDesc",
+                                    NULL,
+                                    &RelativeSdSize);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* Allocate a buffer for the SD */
+    RelativeSd = MIDL_user_allocate(RelativeSdSize);
+    if (RelativeSd == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Get the SD */
+    Status = LsapGetObjectAttribute(DbObject,
+                                    L"SecDesc",
+                                    RelativeSd,
+                                    &RelativeSdSize);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    /*
+     * FIXME: Invalidate the SD information that was not requested.
+     *        (see SecurityInformation)
+     */
+
+    /* Allocate the SD data buffer */
+    SdData = MIDL_user_allocate(sizeof(LSAPR_SR_SECURITY_DESCRIPTOR));
+    if (SdData == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    /* Fill the SD data buffer and return it to the caller */
+    SdData->Length = RelativeSdSize;
+    SdData->SecurityDescriptor = (PBYTE)RelativeSd;
+
+    *SecurityDescriptor = SdData;
+
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (RelativeSd != NULL)
+            MIDL_user_free(RelativeSd);
+    }
+
+    return Status;
 }
 
 
@@ -390,26 +462,54 @@ NTSTATUS WINAPI LsarSetInformationPolicy(
 
     switch (InformationClass)
     {
-        case PolicyAuditEventsInformation:
+        case PolicyAuditLogInformation:      /* 1 */
             Status = STATUS_NOT_IMPLEMENTED;
             break;
 
-        case PolicyPrimaryDomainInformation:
+        case PolicyAuditEventsInformation:   /* 2 */
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case PolicyPrimaryDomainInformation: /* 3 */
             Status = LsarSetPrimaryDomain(PolicyHandle,
                                           (PLSAPR_POLICY_PRIMARY_DOM_INFO)PolicyInformation);
             break;
 
-        case PolicyAccountDomainInformation:
+        case PolicyAccountDomainInformation: /* 5 */
             Status = LsarSetAccountDomain(PolicyHandle,
                                           (PLSAPR_POLICY_ACCOUNT_DOM_INFO)PolicyInformation);
             break;
 
-        case PolicyDnsDomainInformation:
+        case PolicyLsaServerRoleInformation: /* 6 */
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case PolicyReplicaSourceInformation: /* 7 */
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case PolicyDefaultQuotaInformation:  /* 8 */
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case PolicyModificationInformation:  /* 9 */
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case PolicyAuditFullSetInformation:  /* 10 (0xA) */
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case PolicyDnsDomainInformation:      /* 12 (0xC) */
             Status = LsarSetDnsDomain(PolicyHandle,
                                       (PLSAPR_POLICY_DNS_DOMAIN_INFO)PolicyInformation);
             break;
 
-        case PolicyLsaServerRoleInformation:
+        case PolicyDnsDomainInformationInt:   /* 13 (0xD) */
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case PolicyLocalAccountDomainInformation: /* 14 (0xE) */
             Status = STATUS_NOT_IMPLEMENTED;
             break;
 
@@ -441,6 +541,8 @@ NTSTATUS WINAPI LsarCreateAccount(
     PLSA_DB_OBJECT PolicyObject;
     PLSA_DB_OBJECT AccountObject = NULL;
     LPWSTR SidString = NULL;
+    PSECURITY_DESCRIPTOR AccountSd = NULL;
+    ULONG AccountSdSize;
     NTSTATUS Status = STATUS_SUCCESS;
 
     /* Validate the AccountSid */
@@ -467,6 +569,15 @@ NTSTATUS WINAPI LsarCreateAccount(
         goto done;
     }
 
+    /* Create a security descriptor for the account */
+    Status = LsapCreateAccountSd(&AccountSd,
+                                 &AccountSdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapCreateAccountSd returned 0x%08lx\n", Status);
+        return Status;
+    }
+
     /* Create the Account object */
     Status = LsapCreateDbObject(PolicyObject,
                                 L"Accounts",
@@ -485,11 +596,22 @@ NTSTATUS WINAPI LsarCreateAccount(
                                     L"Sid",
                                     (PVOID)AccountSid,
                                     GetLengthSid(AccountSid));
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    /* Set the SecDesc attribute */
+    Status = LsapSetObjectAttribute(AccountObject,
+                                    L"SecDesc",
+                                    AccountSd,
+                                    AccountSdSize);
 
 done:
     if (SidString != NULL)
         LocalFree(SidString);
 
+    if (AccountSd != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, AccountSd);
+
     if (!NT_SUCCESS(Status))
     {
         if (AccountObject != NULL)
@@ -550,89 +672,53 @@ NTSTATUS WINAPI LsarLookupNames(
     LSAP_LOOKUP_LEVEL LookupLevel,
     DWORD *MappedCount)
 {
-    SID_IDENTIFIER_AUTHORITY IdentifierAuthority = {SECURITY_NT_AUTHORITY};
-    static const UNICODE_STRING DomainName = RTL_CONSTANT_STRING(L"DOMAIN");
-    PLSAPR_REFERENCED_DOMAIN_LIST OutputDomains = NULL;
-    PLSA_TRANSLATED_SID OutputSids = NULL;
-    ULONG OutputSidsLength;
+    LSAPR_TRANSLATED_SIDS_EX2 TranslatedSidsEx2;
     ULONG i;
-    PSID Sid;
-    ULONG SidLength;
     NTSTATUS Status;
 
-    TRACE("LsarLookupNames(%p, %lu, %p, %p, %p, %d, %p)\n",
+    TRACE("(%p %lu %p %p %p %d %p)\n",
           PolicyHandle, Count, Names, ReferencedDomains, TranslatedSids,
           LookupLevel, MappedCount);
 
-    TranslatedSids->Entries = Count;
+    TranslatedSids->Entries = 0;
     TranslatedSids->Sids = NULL;
     *ReferencedDomains = NULL;
 
-    OutputSidsLength = Count * sizeof(LSA_TRANSLATED_SID);
-    OutputSids = MIDL_user_allocate(OutputSidsLength);
-    if (OutputSids == NULL)
-    {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    RtlZeroMemory(OutputSids, OutputSidsLength);
+    if (Count == 0)
+        return STATUS_NONE_MAPPED;
 
-    OutputDomains = MIDL_user_allocate(sizeof(LSAPR_REFERENCED_DOMAIN_LIST));
-    if (OutputDomains == NULL)
-    {
-        MIDL_user_free(OutputSids);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
+    TranslatedSidsEx2.Entries = 0;
+    TranslatedSidsEx2.Sids = NULL;
 
-    OutputDomains->Entries = Count;
-    OutputDomains->Domains = MIDL_user_allocate(Count * sizeof(LSA_TRUST_INFORMATION));
-    if (OutputDomains->Domains == NULL)
-    {
-        MIDL_user_free(OutputDomains);
-        MIDL_user_free(OutputSids);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    Status = RtlAllocateAndInitializeSid(&IdentifierAuthority,
-                                         2,
-                                         SECURITY_BUILTIN_DOMAIN_RID,
-                                         DOMAIN_ALIAS_RID_ADMINS,
-                                         0, 0, 0, 0, 0, 0,
-                                         &Sid);
+    Status = LsapLookupNames(Count,
+                             Names,
+                             ReferencedDomains,
+                             &TranslatedSidsEx2,
+                             LookupLevel,
+                             MappedCount,
+                             0,
+                             0);
     if (!NT_SUCCESS(Status))
-    {
-        MIDL_user_free(OutputDomains->Domains);
-        MIDL_user_free(OutputDomains);
-        MIDL_user_free(OutputSids);
         return Status;
-    }
 
-    SidLength = RtlLengthSid(Sid);
-
-    for (i = 0; i < Count; i++)
+    TranslatedSids->Entries = TranslatedSidsEx2.Entries;
+    TranslatedSids->Sids = MIDL_user_allocate(TranslatedSids->Entries * sizeof(LSA_TRANSLATED_SID));
+    if (TranslatedSids->Sids == NULL)
     {
-        OutputDomains->Domains[i].Sid = MIDL_user_allocate(SidLength);
-        RtlCopyMemory(OutputDomains->Domains[i].Sid, Sid, SidLength);
-
-        OutputDomains->Domains[i].Name.Buffer = MIDL_user_allocate(DomainName.MaximumLength);
-        OutputDomains->Domains[i].Name.Length = DomainName.Length;
-        OutputDomains->Domains[i].Name.MaximumLength = DomainName.MaximumLength;
-        RtlCopyMemory(OutputDomains->Domains[i].Name.Buffer, DomainName.Buffer, DomainName.MaximumLength);
+        MIDL_user_free(TranslatedSidsEx2.Sids);
+        MIDL_user_free(*ReferencedDomains);
+        *ReferencedDomains = NULL;
+        return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    for (i = 0; i < Count; i++)
+    for (i = 0; i < TranslatedSidsEx2.Entries; i++)
     {
-        OutputSids[i].Use = SidTypeWellKnownGroup;
-        OutputSids[i].RelativeId = DOMAIN_USER_RID_ADMIN; //DOMAIN_ALIAS_RID_ADMINS;
-        OutputSids[i].DomainIndex = i;
+        TranslatedSids->Sids[i].Use = TranslatedSidsEx2.Sids[i].Use;
+        TranslatedSids->Sids[i].RelativeId = LsapGetRelativeIdFromSid(TranslatedSidsEx2.Sids[i].Sid);
+        TranslatedSids->Sids[i].DomainIndex = TranslatedSidsEx2.Sids[i].DomainIndex;
     }
 
-    *ReferencedDomains = OutputDomains;
-
-    *MappedCount = Count;
-
-    TranslatedSids->Entries = Count;
-    TranslatedSids->Sids = OutputSids;
+    MIDL_user_free(TranslatedSidsEx2.Sids);
 
     return STATUS_SUCCESS;
 }
@@ -647,85 +733,53 @@ NTSTATUS WINAPI LsarLookupSids(
     LSAP_LOOKUP_LEVEL LookupLevel,
     DWORD *MappedCount)
 {
-    SID_IDENTIFIER_AUTHORITY IdentifierAuthority = {SECURITY_NT_AUTHORITY};
-    static const UNICODE_STRING DomainName = RTL_CONSTANT_STRING(L"DOMAIN");
-    PLSAPR_REFERENCED_DOMAIN_LIST OutputDomains = NULL;
-    PLSAPR_TRANSLATED_NAME OutputNames = NULL;
-    ULONG OutputNamesLength;
+    LSAPR_TRANSLATED_NAMES_EX TranslatedNamesEx;
     ULONG i;
-    PSID Sid;
-    ULONG SidLength;
     NTSTATUS Status;
 
-    TRACE("LsarLookupSids(%p, %p, %p, %p, %d, %p)\n",
+    TRACE("(%p %p %p %p %d %p)\n",
           PolicyHandle, SidEnumBuffer, ReferencedDomains, TranslatedNames,
           LookupLevel, MappedCount);
 
+    /* FIXME: Fail, if there is an invalid SID in the SidEnumBuffer */
+
     TranslatedNames->Entries = SidEnumBuffer->Entries;
     TranslatedNames->Names = NULL;
     *ReferencedDomains = NULL;
 
-    OutputNamesLength = SidEnumBuffer->Entries * sizeof(LSA_TRANSLATED_NAME);
-    OutputNames = MIDL_user_allocate(OutputNamesLength);
-    if (OutputNames == NULL)
-    {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
+    TranslatedNamesEx.Entries = SidEnumBuffer->Entries;
+    TranslatedNamesEx.Names = NULL;
 
-    RtlZeroMemory(OutputNames, OutputNamesLength);
-
-    OutputDomains = MIDL_user_allocate(sizeof(LSAPR_REFERENCED_DOMAIN_LIST));
-    if (OutputDomains == NULL)
-    {
-        MIDL_user_free(OutputNames);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
+    Status = LsapLookupSids(SidEnumBuffer,
+                            ReferencedDomains,
+                            &TranslatedNamesEx,
+                            LookupLevel,
+                            MappedCount,
+                            0,
+                            0);
+    if (!NT_SUCCESS(Status))
+        return Status;
 
-    OutputDomains->Entries = SidEnumBuffer->Entries;
-    OutputDomains->Domains = MIDL_user_allocate(SidEnumBuffer->Entries * sizeof(LSA_TRUST_INFORMATION));
-    if (OutputDomains->Domains == NULL)
+    TranslatedNames->Entries = SidEnumBuffer->Entries;
+    TranslatedNames->Names = MIDL_user_allocate(SidEnumBuffer->Entries * sizeof(LSAPR_TRANSLATED_NAME));
+    if (TranslatedNames->Names == NULL)
     {
-        MIDL_user_free(OutputDomains);
-        MIDL_user_free(OutputNames);
+        MIDL_user_free(TranslatedNamesEx.Names);
+        MIDL_user_free(*ReferencedDomains);
+        *ReferencedDomains = NULL;
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    Status = RtlAllocateAndInitializeSid(&IdentifierAuthority,
-                                         2,
-                                         SECURITY_BUILTIN_DOMAIN_RID,
-                                         DOMAIN_ALIAS_RID_ADMINS,
-                                         0, 0, 0, 0, 0, 0,
-                                         &Sid);
-    if (!NT_SUCCESS(Status))
+    for (i = 0; i < TranslatedNamesEx.Entries; i++)
     {
-        MIDL_user_free(OutputDomains->Domains);
-        MIDL_user_free(OutputDomains);
-        MIDL_user_free(OutputNames);
-        return Status;
+        TranslatedNames->Names[i].Use = TranslatedNamesEx.Names[i].Use;
+        TranslatedNames->Names[i].Name.Length = TranslatedNamesEx.Names[i].Name.Length;
+        TranslatedNames->Names[i].Name.MaximumLength = TranslatedNamesEx.Names[i].Name.MaximumLength;
+        TranslatedNames->Names[i].Name.Buffer = TranslatedNamesEx.Names[i].Name.Buffer;
+        TranslatedNames->Names[i].DomainIndex = TranslatedNamesEx.Names[i].DomainIndex;
     }
 
-    SidLength = RtlLengthSid(Sid);
-
-    for (i = 0; i < SidEnumBuffer->Entries; i++)
-    {
-        OutputDomains->Domains[i].Sid = MIDL_user_allocate(SidLength);
-        RtlCopyMemory(OutputDomains->Domains[i].Sid, Sid, SidLength);
-
-        OutputDomains->Domains[i].Name.Buffer = MIDL_user_allocate(DomainName.MaximumLength);
-        OutputDomains->Domains[i].Name.Length = DomainName.Length;
-        OutputDomains->Domains[i].Name.MaximumLength = DomainName.MaximumLength;
-        RtlCopyMemory(OutputDomains->Domains[i].Name.Buffer, DomainName.Buffer, DomainName.MaximumLength);
-    }
-
-    Status = LsapLookupSids(SidEnumBuffer,
-                            OutputNames);
-
-    *ReferencedDomains = OutputDomains;
-
-    *MappedCount = SidEnumBuffer->Entries;
-
-    TranslatedNames->Entries = SidEnumBuffer->Entries;
-    TranslatedNames->Names = OutputNames;
+    MIDL_user_free(TranslatedNamesEx.Names);
 
     return Status;
 }
@@ -741,6 +795,8 @@ NTSTATUS WINAPI LsarCreateSecret(
     PLSA_DB_OBJECT PolicyObject;
     PLSA_DB_OBJECT SecretObject = NULL;
     LARGE_INTEGER Time;
+    PSECURITY_DESCRIPTOR SecretSd = NULL;
+    ULONG SecretSdSize;
     NTSTATUS Status = STATUS_SUCCESS;
 
     /* Validate the PolicyHandle */
@@ -762,6 +818,15 @@ NTSTATUS WINAPI LsarCreateSecret(
         goto done;
     }
 
+    /* Create a security descriptor for the secret */
+    Status = LsapCreateSecretSd(&SecretSd,
+                                &SecretSdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapCreateAccountSd returned 0x%08lx\n", Status);
+        return Status;
+    }
+
     /* Create the Secret object */
     Status = LsapCreateDbObject(PolicyObject,
                                 L"Secrets",
@@ -791,8 +856,22 @@ NTSTATUS WINAPI LsarCreateSecret(
                                     L"OldTime",
                                     (PVOID)&Time,
                                     sizeof(LARGE_INTEGER));
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("LsapSetObjectAttribute (OldTime) failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    /* Set the SecDesc attribute */
+    Status = LsapSetObjectAttribute(SecretObject,
+                                    L"SecDesc",
+                                    SecretSd,
+                                    SecretSdSize);
 
 done:
+    if (SecretSd != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, SecretSd);
+
     if (!NT_SUCCESS(Status))
     {
         if (SecretObject != NULL)
@@ -1977,8 +2056,27 @@ NTSTATUS WINAPI LsarLookupSids2(
     DWORD LookupOptions,
     DWORD ClientRevision)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+
+    TRACE("(%p %p %p %p %d %p %lu %lu)\n",
+          PolicyHandle, SidEnumBuffer, ReferencedDomains, TranslatedNames,
+          LookupLevel, MappedCount, LookupOptions, ClientRevision);
+
+    TranslatedNames->Entries = SidEnumBuffer->Entries;
+    TranslatedNames->Names = NULL;
+    *ReferencedDomains = NULL;
+
+    /* FIXME: Fail, if there is an invalid SID in the SidEnumBuffer */
+
+    Status = LsapLookupSids(SidEnumBuffer,
+                            ReferencedDomains,
+                            TranslatedNames,
+                            LookupLevel,
+                            MappedCount,
+                            LookupOptions,
+                            ClientRevision);
+
+    return Status;
 }
 
 
@@ -1994,8 +2092,56 @@ NTSTATUS WINAPI LsarLookupNames2(
     DWORD LookupOptions,
     DWORD ClientRevision)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    LSAPR_TRANSLATED_SIDS_EX2 TranslatedSidsEx2;
+    ULONG i;
+    NTSTATUS Status;
+
+    TRACE("(%p %lu %p %p %p %d %p %lu %lu)\n",
+          PolicyHandle, Count, Names, ReferencedDomains, TranslatedSids,
+          LookupLevel, MappedCount, LookupOptions, ClientRevision);
+
+    TranslatedSids->Entries = 0;
+    TranslatedSids->Sids = NULL;
+    *ReferencedDomains = NULL;
+
+    if (Count == 0)
+        return STATUS_NONE_MAPPED;
+
+    TranslatedSidsEx2.Entries = 0;
+    TranslatedSidsEx2.Sids = NULL;
+
+    Status = LsapLookupNames(Count,
+                             Names,
+                             ReferencedDomains,
+                             &TranslatedSidsEx2,
+                             LookupLevel,
+                             MappedCount,
+                             LookupOptions,
+                             ClientRevision);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    TranslatedSids->Entries = TranslatedSidsEx2.Entries;
+    TranslatedSids->Sids = MIDL_user_allocate(TranslatedSids->Entries * sizeof(LSA_TRANSLATED_SID));
+    if (TranslatedSids->Sids == NULL)
+    {
+        MIDL_user_free(TranslatedSidsEx2.Sids);
+        MIDL_user_free(*ReferencedDomains);
+        *ReferencedDomains = NULL;
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    for (i = 0; i < TranslatedSidsEx2.Entries; i++)
+    {
+        TranslatedSids->Sids[i].Use = TranslatedSidsEx2.Sids[i].Use;
+        TranslatedSids->Sids[i].RelativeId = LsapGetRelativeIdFromSid(TranslatedSidsEx2.Sids[i].Sid);
+        TranslatedSids->Sids[i].DomainIndex = TranslatedSidsEx2.Sids[i].DomainIndex;
+        TranslatedSids->Sids[i].Flags = TranslatedSidsEx2.Sids[i].Flags;
+    }
+
+    MIDL_user_free(TranslatedSidsEx2.Sids);
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -2098,7 +2244,7 @@ NTSTATUS WINAPI LsarLookupNames3(
 {
     NTSTATUS Status;
 
-    TRACE("LsarLookupNames3(%p, %lu, %p, %p, %p, %d, %p, %lu, %lu)\n",
+    TRACE("(%p %lu %p %p %p %d %p %lu %lu)\n",
           PolicyHandle, Count, Names, ReferencedDomains, TranslatedSids,
           LookupLevel, MappedCount, LookupOptions, ClientRevision);
 
@@ -2204,8 +2350,27 @@ NTSTATUS WINAPI LsarLookupSids3(
     DWORD LookupOptions,
     DWORD ClientRevision)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+
+    TRACE("(%p %p %p %p %d %p %lu %lu)\n",
+          PolicyHandle, SidEnumBuffer, ReferencedDomains, TranslatedNames,
+          LookupLevel, MappedCount, LookupOptions, ClientRevision);
+
+    TranslatedNames->Entries = SidEnumBuffer->Entries;
+    TranslatedNames->Names = NULL;
+    *ReferencedDomains = NULL;
+
+    /* FIXME: Fail, if there is an invalid SID in the SidEnumBuffer */
+
+    Status = LsapLookupSids(SidEnumBuffer,
+                            ReferencedDomains,
+                            TranslatedNames,
+                            LookupLevel,
+                            MappedCount,
+                            LookupOptions,
+                            ClientRevision);
+
+    return Status;
 }
 
 
@@ -2221,8 +2386,29 @@ NTSTATUS WINAPI LsarLookupNames4(
     DWORD LookupOptions,
     DWORD ClientRevision)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+
+    TRACE("(%p %lu %p %p %p %d %p %lu %lu)\n",
+          RpcHandle, Count, Names, ReferencedDomains, TranslatedSids,
+          LookupLevel, MappedCount, LookupOptions, ClientRevision);
+
+    TranslatedSids->Entries = 0;
+    TranslatedSids->Sids = NULL;
+    *ReferencedDomains = NULL;
+
+    if (Count == 0)
+        return STATUS_NONE_MAPPED;
+
+    Status = LsapLookupNames(Count,
+                             Names,
+                             ReferencedDomains,
+                             TranslatedSids,
+                             LookupLevel,
+                             MappedCount,
+                             LookupOptions,
+                             ClientRevision);
+
+    return Status;
 }