[SAMSRV]
[reactos.git] / reactos / dll / win32 / samsrv / samrpc.c
index e891e49..5932c3b 100644 (file)
@@ -7,12 +7,8 @@
  * PROGRAMMERS:     Eric Kohl
  */
 
-/* INCLUDES ******************************************************************/
-
 #include "samsrv.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(samsrv);
-
 /* GLOBALS *******************************************************************/
 
 static SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
@@ -221,8 +217,97 @@ SamrQuerySecurityObject(IN SAMPR_HANDLE ObjectHandle,
                         IN SECURITY_INFORMATION SecurityInformation,
                         OUT PSAMPR_SR_SECURITY_DESCRIPTOR *SecurityDescriptor)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PSAM_DB_OBJECT SamObject;
+    PSAMPR_SR_SECURITY_DESCRIPTOR SamSD = NULL;
+    PSECURITY_DESCRIPTOR SdBuffer = NULL;
+    ACCESS_MASK DesiredAccess = 0;
+    ULONG Length = 0;
+    NTSTATUS Status;
+
+    TRACE("(%p %lx %p)\n",
+          ObjectHandle, SecurityInformation, SecurityDescriptor);
+
+    *SecurityDescriptor = NULL;
+
+    RtlAcquireResourceShared(&SampResource,
+                             TRUE);
+
+    if (SecurityInformation & (DACL_SECURITY_INFORMATION |
+                               OWNER_SECURITY_INFORMATION |
+                               GROUP_SECURITY_INFORMATION))
+        DesiredAccess |= READ_CONTROL;
+
+    if (SecurityInformation & SACL_SECURITY_INFORMATION)
+        DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+
+    /* Validate the server handle */
+    Status = SampValidateDbObject(ObjectHandle,
+                                  SamDbIgnoreObject,
+                                  DesiredAccess,
+                                  &SamObject);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    SamSD = midl_user_allocate(sizeof(SAMPR_SR_SECURITY_DESCRIPTOR));
+    if (SamSD == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    Status = SampGetObjectAttribute(SamObject,
+                                    L"SecDesc",
+                                    NULL,
+                                    NULL,
+                                    &Length);
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    TRACE("SD Length: %lu\n", Length);
+
+    SdBuffer = midl_user_allocate(Length);
+    if (SdBuffer == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
+    }
+
+    Status = SampGetObjectAttribute(SamObject,
+                                    L"SecDesc",
+                                    NULL,
+                                    SdBuffer,
+                                    &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("Status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    /* FIXME: Use SecurityInformation to return only the requested information */
+
+    SamSD->Length = Length;
+    SamSD->SecurityDescriptor = SdBuffer;
+
+done:
+    RtlReleaseResource(&SampResource);
+
+    if (NT_SUCCESS(Status))
+    {
+        *SecurityDescriptor = SamSD;
+    }
+    else
+    {
+        if (SdBuffer != NULL)
+            midl_user_free(SdBuffer);
+
+        if (SamSD != NULL)
+            midl_user_free(SamSD);
+    }
+
+    return Status;
 }
 
 
@@ -1770,6 +1855,8 @@ SamrCreateGroupInDomain(IN SAMPR_HANDLE DomainHandle,
     SAM_GROUP_FIXED_DATA FixedGroupData;
     PSAM_DB_OBJECT DomainObject;
     PSAM_DB_OBJECT GroupObject;
+    PSECURITY_DESCRIPTOR Sd = NULL;
+    ULONG SdSize = 0;
     ULONG ulSize;
     ULONG ulRid;
     WCHAR szRid[9];
@@ -1814,6 +1901,15 @@ SamrCreateGroupInDomain(IN SAMPR_HANDLE DomainHandle,
         goto done;
     }
 
+    /* Create the security descriptor */
+    Status = SampCreateGroupSD(&Sd,
+                               &SdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SampCreateGroupSD failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
     /* Get the fixed domain attributes */
     ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
     Status = SampGetObjectAttribute(DomainObject,
@@ -1910,6 +2006,18 @@ SamrCreateGroupInDomain(IN SAMPR_HANDLE DomainHandle,
         goto done;
     }
 
+    /* Set the SecDesc attribute*/
+    Status = SampSetObjectAttribute(GroupObject,
+                                    L"SecDesc",
+                                    REG_BINARY,
+                                    Sd,
+                                    SdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("failed with status 0x%08lx\n", Status);
+        goto done;
+    }
+
     if (NT_SUCCESS(Status))
     {
         *GroupHandle = (SAMPR_HANDLE)GroupObject;
@@ -1917,6 +2025,9 @@ SamrCreateGroupInDomain(IN SAMPR_HANDLE DomainHandle,
     }
 
 done:
+    if (Sd != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
+
     RtlReleaseResource(&SampResource);
 
     TRACE("returns with status 0x%08lx\n", Status);
@@ -2068,7 +2179,7 @@ SamrEnumerateGroupsInDomain(IN SAMPR_HANDLE DomainHandle,
         EnumBuffer->Buffer[i].RelativeId = Rid;
 
         EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
-        EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
+        EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
 
 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
 #if 0
@@ -2148,6 +2259,9 @@ SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
     ULONG ulSize;
     ULONG ulRid;
     WCHAR szRid[9];
+    PSECURITY_DESCRIPTOR Sd = NULL;
+    ULONG SdSize = 0;
+    PSID UserSid = NULL;
     NTSTATUS Status;
 
     TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
@@ -2213,6 +2327,28 @@ SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
     ulRid = FixedDomainData.NextRid;
     FixedDomainData.NextRid++;
 
+    TRACE("RID: %lx\n", ulRid);
+
+    /* Create the user SID */
+    Status = SampCreateAccountSid(DomainObject,
+                                  ulRid,
+                                  &UserSid);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    /* Create the security descriptor */
+    Status = SampCreateUserSD(UserSid,
+                              &Sd,
+                              &SdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
     /* Store the fixed domain attributes */
     Status = SampSetObjectAttribute(DomainObject,
                            L"F",
@@ -2225,8 +2361,6 @@ SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
         goto done;
     }
 
-    TRACE("RID: %lx\n", ulRid);
-
     /* Convert the RID into a string (hex) */
     swprintf(szRid, L"%08lX", ulRid);
 
@@ -2469,7 +2603,27 @@ SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
         goto done;
     }
 
-    /* FIXME: Set SecDesc attribute*/
+    /* Set the PrivateData attribute */
+    Status = SampSetObjectAttributeString(UserObject,
+                                          L"PrivateData",
+                                          NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("failed with status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    /* Set the SecDesc attribute*/
+    Status = SampSetObjectAttribute(UserObject,
+                                    L"SecDesc",
+                                    REG_BINARY,
+                                    Sd,
+                                    SdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("failed with status 0x%08lx\n", Status);
+        goto done;
+    }
 
     if (NT_SUCCESS(Status))
     {
@@ -2478,6 +2632,12 @@ SamrCreateUserInDomain(IN SAMPR_HANDLE DomainHandle,
     }
 
 done:
+    if (Sd != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
+
+    if (UserSid != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
+
     RtlReleaseResource(&SampResource);
 
     TRACE("returns with status 0x%08lx\n", Status);
@@ -2630,7 +2790,7 @@ SamrEnumerateUsersInDomain(IN SAMPR_HANDLE DomainHandle,
         EnumBuffer->Buffer[i].RelativeId = Rid;
 
         EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
-        EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
+        EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
 
 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
 #if 0
@@ -2704,6 +2864,8 @@ SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
     SAM_DOMAIN_FIXED_DATA FixedDomainData;
     PSAM_DB_OBJECT DomainObject;
     PSAM_DB_OBJECT AliasObject;
+    PSECURITY_DESCRIPTOR Sd = NULL;
+    ULONG SdSize = 0;
     ULONG ulSize;
     ULONG ulRid;
     WCHAR szRid[9];
@@ -2748,6 +2910,15 @@ SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
         goto done;
     }
 
+    /* Create the security descriptor */
+    Status = SampCreateAliasSD(&Sd,
+                               &SdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SampCreateAliasSD failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
     /* Get the fixed domain attributes */
     ulSize = sizeof(SAM_DOMAIN_FIXED_DATA);
     Status = SampGetObjectAttribute(DomainObject,
@@ -2827,6 +2998,18 @@ SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
         goto done;
     }
 
+    /* Set the SecDesc attribute*/
+    Status = SampSetObjectAttribute(AliasObject,
+                                    L"SecDesc",
+                                    REG_BINARY,
+                                    Sd,
+                                    SdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("failed with status 0x%08lx\n", Status);
+        goto done;
+    }
+
     if (NT_SUCCESS(Status))
     {
         *AliasHandle = (SAMPR_HANDLE)AliasObject;
@@ -2834,6 +3017,9 @@ SamrCreateAliasInDomain(IN SAMPR_HANDLE DomainHandle,
     }
 
 done:
+    if (Sd != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
+
     RtlReleaseResource(&SampResource);
 
     TRACE("returns with status 0x%08lx\n", Status);
@@ -2985,7 +3171,7 @@ SamrEnumerateAliasesInDomain(IN SAMPR_HANDLE DomainHandle,
         EnumBuffer->Buffer[i].RelativeId = Rid;
 
         EnumBuffer->Buffer[i].Name.Length = (USHORT)NameLength;
-        EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(DataLength + sizeof(UNICODE_NULL));
+        EnumBuffer->Buffer[i].Name.MaximumLength = (USHORT)(NameLength + sizeof(UNICODE_NULL));
 
 /* FIXME: Disabled because of bugs in widl and rpcrt4 */
 #if 0
@@ -3064,6 +3250,7 @@ SamrGetAliasMembership(IN SAMPR_HANDLE DomainHandle,
     ULONG ValueCount;
     ULONG DataLength;
     ULONG i, j;
+    ULONG RidIndex;
     NTSTATUS Status;
     WCHAR NameBuffer[9];
 
@@ -3148,6 +3335,7 @@ TRACE("Open %S\n", MemberSidString);
         goto done;
     }
 
+    RidIndex = 0;
     for (i = 0; i < SidArray->Count; i++)
     {
         ConvertSidToStringSid(SidArray->Sids[i].SidPointer, &MemberSidString);
@@ -3179,7 +3367,9 @@ TRACE("Open %S\n", MemberSidString);
                                                    NULL);
                     if (NT_SUCCESS(Status))
                     {
-                        RidArray[j] = wcstoul(NameBuffer, NULL, 16);
+                        /* FIXME: Do not return each RID more than once. */
+                        RidArray[RidIndex] = wcstoul(NameBuffer, NULL, 16);
+                        RidIndex++;
                     }
                 }
             }
@@ -3191,7 +3381,6 @@ TRACE("Open %S\n", MemberSidString);
     }
 
 done:
-    SampRegCloseKey(&MembersKeyHandle);
     SampRegCloseKey(&MembersKeyHandle);
     SampRegCloseKey(&AliasesKeyHandle);
 
@@ -3486,7 +3675,7 @@ SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
     }
 
     /* Allocate the names array */
-    Names->Element = midl_user_allocate(Count * sizeof(ULONG));
+    Names->Element = midl_user_allocate(Count * sizeof(*Names->Element));
     if (Names->Element == NULL)
     {
         Status = STATUS_INSUFFICIENT_RESOURCES;
@@ -3494,7 +3683,7 @@ SamrLookupIdsInDomain(IN SAMPR_HANDLE DomainHandle,
     }
 
     /* Allocate the use array */
-    Use->Element = midl_user_allocate(Count * sizeof(ULONG));
+    Use->Element = midl_user_allocate(Count * sizeof(*Use->Element));
     if (Use->Element == NULL)
     {
         Status = STATUS_INSUFFICIENT_RESOURCES;
@@ -4980,7 +5169,13 @@ SamrDeleteAlias(IN OUT SAMPR_HANDLE *AliasHandle)
         goto done;
     }
 
-    /* FIXME: Remove all members from the alias */
+    /* Remove all members from the alias */
+    Status = SampRemoveAllMembersFromAlias(AliasObject);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SampRemoveAllMembersFromAlias() failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
 
     /* Delete the alias from the database */
     Status = SampDeleteAccountDbObject(AliasObject);
@@ -5085,10 +5280,8 @@ SamrGetMembersInAlias(IN SAMPR_HANDLE AliasHandle,
                       OUT PSAMPR_PSID_ARRAY_OUT Members)
 {
     PSAM_DB_OBJECT AliasObject;
-    HANDLE MembersKeyHandle = NULL;
     PSAMPR_SID_INFORMATION MemberArray = NULL;
-    ULONG ValueCount = 0;
-    ULONG DataLength;
+    ULONG MemberCount = 0;
     ULONG Index;
     NTSTATUS Status;
 
@@ -5109,83 +5302,14 @@ SamrGetMembersInAlias(IN SAMPR_HANDLE AliasHandle,
         goto done;
     }
 
-    /* Open the members key of the alias objct */
-    Status = SampRegOpenKey(AliasObject->KeyHandle,
-                            L"Members",
-                            KEY_READ,
-                            &MembersKeyHandle);
-    if (!NT_SUCCESS(Status))
-    {
-        ERR("SampRegOpenKey failed with status 0x%08lx\n", Status);
-        goto done;
-    }
-
-    /* Get the number of members */
-    Status = SampRegQueryKeyInfo(MembersKeyHandle,
-                                 NULL,
-                                 &ValueCount);
-    if (!NT_SUCCESS(Status))
-    {
-        ERR("SampRegQueryKeyInfo failed with status 0x%08lx\n", Status);
-        goto done;
-    }
-
-    /* Allocate the member array */
-    MemberArray = midl_user_allocate(ValueCount * sizeof(SAMPR_SID_INFORMATION));
-    if (MemberArray == NULL)
-    {
-        Status = STATUS_INSUFFICIENT_RESOURCES;
-        goto done;
-    }
-
-    /* Enumerate the members */
-    Index = 0;
-    while (TRUE)
-    {
-        /* Get the size of the next SID */
-        DataLength = 0;
-        Status = SampRegEnumerateValue(MembersKeyHandle,
-                                       Index,
-                                       NULL,
-                                       NULL,
-                                       NULL,
-                                       NULL,
-                                       &DataLength);
-        if (!NT_SUCCESS(Status))
-        {
-            if (Status == STATUS_NO_MORE_ENTRIES)
-                Status = STATUS_SUCCESS;
-            break;
-        }
-
-        /* Allocate a buffer for the SID */
-        MemberArray[Index].SidPointer = midl_user_allocate(DataLength);
-        if (MemberArray[Index].SidPointer == NULL)
-        {
-            Status = STATUS_INSUFFICIENT_RESOURCES;
-            goto done;
-        }
-
-        /* Read the SID into the buffer */
-        Status = SampRegEnumerateValue(MembersKeyHandle,
-                                       Index,
-                                       NULL,
-                                       NULL,
-                                       NULL,
-                                       (PVOID)MemberArray[Index].SidPointer,
-                                       &DataLength);
-        if (!NT_SUCCESS(Status))
-        {
-            goto done;
-        }
-
-        Index++;
-    }
+    Status = SampGetMembersInAlias(AliasObject,
+                                   &MemberCount,
+                                   &MemberArray);
 
     /* Return the number of members and the member array */
     if (NT_SUCCESS(Status))
     {
-        Members->Count = ValueCount;
+        Members->Count = MemberCount;
         Members->Sids = MemberArray;
     }
 
@@ -5195,7 +5319,7 @@ done:
     {
         if (MemberArray != NULL)
         {
-            for (Index = 0; Index < ValueCount; Index++)
+            for (Index = 0; Index < MemberCount; Index++)
             {
                 if (MemberArray[Index].SidPointer != NULL)
                     midl_user_free(MemberArray[Index].SidPointer);
@@ -5205,9 +5329,6 @@ done:
         }
     }
 
-    /* Close the members key */
-    SampRegCloseKey(&MembersKeyHandle);
-
     RtlReleaseResource(&SampResource);
 
     return Status;
@@ -5306,9 +5427,21 @@ SamrDeleteUser(IN OUT SAMPR_HANDLE *UserHandle)
         goto done;
     }
 
-    /* FIXME: Remove the user from all groups */
+    /* Remove the user from all groups */
+    Status = SampRemoveUserFromAllGroups(UserObject);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SampRemoveUserFromAllGroups() failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
 
-    /* FIXME: Remove the user from all aliases */
+    /* Remove the user from all aliases */
+    Status = SampRemoveUserFromAllAliases(UserObject);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SampRemoveUserFromAllAliases() failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
 
     /* Delete the user from the database */
     Status = SampDeleteAccountDbObject(UserObject);
@@ -6373,6 +6506,9 @@ SampQueryUserInternal1(PSAM_DB_OBJECT UserObject,
     if (InfoBuffer == NULL)
         return STATUS_INSUFFICIENT_RESOURCES;
 
+    InfoBuffer->Internal1.LmPasswordPresent = FALSE;
+    InfoBuffer->Internal1.NtPasswordPresent = FALSE;
+
     /* Get the NT password */
     Length = 0;
     SampGetObjectAttribute(UserObject,
@@ -6390,9 +6526,13 @@ SampQueryUserInternal1(PSAM_DB_OBJECT UserObject,
                                         &Length);
         if (!NT_SUCCESS(Status))
             goto done;
+
+        if (memcmp(&InfoBuffer->Internal1.EncryptedNtOwfPassword,
+                   &EmptyNtHash,
+                   sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
+            InfoBuffer->Internal1.NtPasswordPresent = TRUE;
     }
 
-    InfoBuffer->Internal1.NtPasswordPresent = (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD));
 
     /* Get the LM password */
     Length = 0;
@@ -6411,9 +6551,12 @@ SampQueryUserInternal1(PSAM_DB_OBJECT UserObject,
                                         &Length);
         if (!NT_SUCCESS(Status))
             goto done;
-    }
 
-    InfoBuffer->Internal1.LmPasswordPresent = (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD));
+        if (memcmp(&InfoBuffer->Internal1.EncryptedLmOwfPassword,
+                   &EmptyLmHash,
+                   sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
+            InfoBuffer->Internal1.LmPasswordPresent = TRUE;
+    }
 
     InfoBuffer->Internal1.PasswordExpired = FALSE;
 
@@ -6511,9 +6654,42 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
     if (!NT_SUCCESS(Status))
         goto done;
 
-    if (UserObject->Access & USER_READ_GENERAL)
+    /* Set the fields to be returned */
+    if (UserObject->Trusted)
+    {
+        InfoBuffer->All.WhichFields = USER_ALL_READ_GENERAL_MASK |
+                                      USER_ALL_READ_LOGON_MASK |
+                                      USER_ALL_READ_ACCOUNT_MASK |
+                                      USER_ALL_READ_PREFERENCES_MASK |
+                                      USER_ALL_READ_TRUSTED_MASK;
+    }
+    else
+    {
+        InfoBuffer->All.WhichFields = 0;
+
+        if (UserObject->Access & USER_READ_GENERAL)
+            InfoBuffer->All.WhichFields |= USER_ALL_READ_GENERAL_MASK;
+
+        if (UserObject->Access & USER_READ_LOGON)
+            InfoBuffer->All.WhichFields |= USER_ALL_READ_LOGON_MASK;
+
+        if (UserObject->Access & USER_READ_ACCOUNT)
+            InfoBuffer->All.WhichFields |= USER_ALL_READ_ACCOUNT_MASK;
+
+        if (UserObject->Access & USER_READ_PREFERENCES)
+            InfoBuffer->All.WhichFields |= USER_ALL_READ_PREFERENCES_MASK;
+    }
+
+    /* Fail, if no fields are to be returned */
+    if (InfoBuffer->All.WhichFields == 0)
+    {
+        Status = STATUS_ACCESS_DENIED;
+        goto done;
+    }
+
+    /* Get the UserName attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_USERNAME)
     {
-        /* Get the Name string */
         Status = SampGetObjectAttributeString(UserObject,
                                               L"Name",
                                               &InfoBuffer->All.UserName);
@@ -6522,8 +6698,11 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
+    }
 
-        /* Get the FullName string */
+    /* Get the FullName attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_FULLNAME)
+    {
         Status = SampGetObjectAttributeString(UserObject,
                                               L"FullName",
                                               &InfoBuffer->All.FullName);
@@ -6532,14 +6711,23 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
+    }
 
-        /* Get the user ID*/
+    /* Get the UserId attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_USERID)
+    {
         InfoBuffer->All.UserId = FixedData.UserId;
+    }
 
-        /* Get the primary group ID */
+    /* Get the PrimaryGroupId attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_PRIMARYGROUPID)
+    {
         InfoBuffer->All.PrimaryGroupId = FixedData.PrimaryGroupId;
+    }
 
-        /* Get the AdminComment string */
+    /* Get the AdminComment attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_ADMINCOMMENT)
+    {
         Status = SampGetObjectAttributeString(UserObject,
                                               L"AdminComment",
                                               &InfoBuffer->All.AdminComment);
@@ -6548,8 +6736,11 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
+    }
 
-        /* Get the UserComment string */
+    /* Get the UserComment attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_USERCOMMENT)
+    {
         Status = SampGetObjectAttributeString(UserObject,
                                               L"UserComment",
                                               &InfoBuffer->All.UserComment);
@@ -6558,19 +6749,11 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
-
-        InfoBuffer->All.WhichFields |= USER_ALL_READ_GENERAL_MASK;
-//            USER_ALL_USERNAME |
-//            USER_ALL_FULLNAME |
-//            USER_ALL_USERID |
-//            USER_ALL_PRIMARYGROUPID |
-//            USER_ALL_ADMINCOMMENT |
-//            USER_ALL_USERCOMMENT;
     }
 
-    if (UserObject->Access & USER_READ_LOGON)
+    /* Get the HomeDirectory attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORY)
     {
-        /* Get the HomeDirectory string */
         Status = SampGetObjectAttributeString(UserObject,
                                               L"HomeDirectory",
                                               &InfoBuffer->All.HomeDirectory);
@@ -6579,8 +6762,11 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
+    }
 
-        /* Get the HomeDirectoryDrive string */
+    /* Get the HomeDirectoryDrive attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_HOMEDIRECTORYDRIVE)
+    {
         Status = SampGetObjectAttributeString(UserObject,
                                               L"HomeDirectoryDrive",
                                               &InfoBuffer->Home.HomeDirectoryDrive);
@@ -6589,8 +6775,11 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
+    }
 
-        /* Get the ScriptPath string */
+    /* Get the ScriptPath attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_SCRIPTPATH)
+    {
         Status = SampGetObjectAttributeString(UserObject,
                                               L"ScriptPath",
                                               &InfoBuffer->All.ScriptPath);
@@ -6599,8 +6788,11 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
+    }
 
-        /* Get the ProfilePath string */
+    /* Get the ProfilePath attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_PROFILEPATH)
+    {
         Status = SampGetObjectAttributeString(UserObject,
                                               L"ProfilePath",
                                               &InfoBuffer->All.ProfilePath);
@@ -6609,8 +6801,11 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
+    }
 
-        /* Get the WorkStations string */
+    /* Get the WorkStations attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_WORKSTATIONS)
+    {
         Status = SampGetObjectAttributeString(UserObject,
                                               L"WorkStations",
                                               &InfoBuffer->All.WorkStations);
@@ -6619,8 +6814,25 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
+    }
+
+    /* Get the LastLogon attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGON)
+    {
+        InfoBuffer->All.LastLogon.LowPart = FixedData.LastLogon.LowPart;
+        InfoBuffer->All.LastLogon.HighPart = FixedData.LastLogon.HighPart;
+    }
+
+    /* Get the LastLogoff attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_LASTLOGOFF)
+    {
+        InfoBuffer->All.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
+        InfoBuffer->All.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
+    }
 
-        /* Get the LogonHours attribute */
+    /* Get the LogonHours attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_LOGONHOURS)
+    {
         Status = SampGetLogonHoursAttrbute(UserObject,
                                            &InfoBuffer->All.LogonHours);
         if (!NT_SUCCESS(Status))
@@ -6628,55 +6840,61 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
+    }
 
-        InfoBuffer->All.LastLogon.LowPart = FixedData.LastLogon.LowPart;
-        InfoBuffer->All.LastLogon.HighPart = FixedData.LastLogon.HighPart;
-
-        InfoBuffer->All.LastLogoff.LowPart = FixedData.LastLogoff.LowPart;
-        InfoBuffer->All.LastLogoff.HighPart = FixedData.LastLogoff.HighPart;
-
+    /* Get the BadPasswordCount attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_BADPASSWORDCOUNT)
+    {
         InfoBuffer->All.BadPasswordCount = FixedData.BadPasswordCount;
+    }
 
+    /* Get the LogonCount attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_LOGONCOUNT)
+    {
         InfoBuffer->All.LogonCount = FixedData.LogonCount;
+    }
 
+    /* Get the PasswordCanChange attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDCANCHANGE)
+    {
         PasswordCanChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
                                                       DomainFixedData.MinPasswordAge);
         InfoBuffer->All.PasswordCanChange.LowPart = PasswordCanChange.LowPart;
         InfoBuffer->All.PasswordCanChange.HighPart = PasswordCanChange.HighPart;
+    }
 
+    /* Get the PasswordMustChange attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDMUSTCHANGE)
+    {
         PasswordMustChange = SampAddRelativeTimeToTime(FixedData.PasswordLastSet,
                                                        DomainFixedData.MaxPasswordAge);
         InfoBuffer->All.PasswordMustChange.LowPart = PasswordMustChange.LowPart;
         InfoBuffer->All.PasswordMustChange.HighPart = PasswordMustChange.HighPart;
+    }
 
-        InfoBuffer->All. WhichFields |= USER_ALL_READ_LOGON_MASK;
-/*
-            USER_ALL_HOMEDIRECTORY |
-            USER_ALL_HOMEDIRECTORYDRIVE |
-            USER_ALL_SCRIPTPATH |
-            USER_ALL_PROFILEPATH |
-            USER_ALL_WORKSTATIONS |
-            USER_ALL_LASTLOGON |
-            USER_ALL_LASTLOGOFF |
-            USER_ALL_LOGONHOURS |
-            USER_ALL_BADPASSWORDCOUNT |
-            USER_ALL_LOGONCOUNT;
-            USER_ALL_PASSWORDCANCHANGE |
-            USER_ALL_PASSWORDMUSTCHANGE;
-*/
-    }
-
-    if (UserObject->Access & USER_READ_ACCOUNT)
+    /* Get the PasswordLastSet attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDLASTSET)
     {
         InfoBuffer->All.PasswordLastSet.LowPart = FixedData.PasswordLastSet.LowPart;
         InfoBuffer->All.PasswordLastSet.HighPart = FixedData.PasswordLastSet.HighPart;
+    }
 
+    /* Get the AccountExpires attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_ACCOUNTEXPIRES)
+    {
         InfoBuffer->All.AccountExpires.LowPart = FixedData.AccountExpires.LowPart;
         InfoBuffer->All.AccountExpires.HighPart = FixedData.AccountExpires.HighPart;
+    }
 
+    /* Get the UserAccountControl attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_USERACCOUNTCONTROL)
+    {
         InfoBuffer->All.UserAccountControl = FixedData.UserAccountControl;
+    }
 
-        /* Get the Parameters string */
+    /* Get the Parameters attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_PARAMETERS)
+    {
         Status = SampGetObjectAttributeString(UserObject,
                                               L"Parameters",
                                               &InfoBuffer->All.Parameters);
@@ -6685,23 +6903,140 @@ SampQueryUserAll(PSAM_DB_OBJECT UserObject,
             TRACE("Status 0x%08lx\n", Status);
             goto done;
         }
-
-        InfoBuffer->All. WhichFields |= USER_ALL_READ_ACCOUNT_MASK;
-//            USER_ALL_PASSWORDLASTSET |
-//            USER_ALL_ACCOUNTEXPIRES |
-//            USER_ALL_USERACCOUNTCONTROL |
-//            USER_ALL_PARAMETERS;
     }
 
-    if (UserObject->Access & USER_READ_PREFERENCES)
+    /* Get the CountryCode attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_COUNTRYCODE)
     {
         InfoBuffer->All.CountryCode = FixedData.CountryCode;
+    }
 
+    /* Get the CodePage attribute */
+    if (InfoBuffer->All.WhichFields & USER_ALL_CODEPAGE)
+    {
         InfoBuffer->All.CodePage = FixedData.CodePage;
+    }
+
+    /* Get the LmPassword and NtPassword attributes */
+    if (InfoBuffer->All.WhichFields & (USER_ALL_NTPASSWORDPRESENT | USER_ALL_LMPASSWORDPRESENT))
+    {
+        InfoBuffer->All.LmPasswordPresent = FALSE;
+        InfoBuffer->All.NtPasswordPresent = FALSE;
+
+        /* Get the NT password */
+        Length = 0;
+        SampGetObjectAttribute(UserObject,
+                               L"NTPwd",
+                               NULL,
+                               NULL,
+                               &Length);
+
+        if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
+        {
+            InfoBuffer->All.NtOwfPassword.Buffer = midl_user_allocate(sizeof(ENCRYPTED_NT_OWF_PASSWORD));
+            if (InfoBuffer->All.NtOwfPassword.Buffer == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                goto done;
+            }
+
+            InfoBuffer->All.NtOwfPassword.Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
+            InfoBuffer->All.NtOwfPassword.MaximumLength = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
+
+            Status = SampGetObjectAttribute(UserObject,
+                                            L"NTPwd",
+                                            NULL,
+                                            (PVOID)InfoBuffer->All.NtOwfPassword.Buffer,
+                                            &Length);
+            if (!NT_SUCCESS(Status))
+                goto done;
+
+            if (memcmp(InfoBuffer->All.NtOwfPassword.Buffer,
+                       &EmptyNtHash,
+                       sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
+                InfoBuffer->All.NtPasswordPresent = TRUE;
+        }
+
+        /* Get the LM password */
+        Length = 0;
+        SampGetObjectAttribute(UserObject,
+                               L"LMPwd",
+                               NULL,
+                               NULL,
+                               &Length);
+
+        if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
+        {
+            InfoBuffer->All.LmOwfPassword.Buffer = midl_user_allocate(sizeof(ENCRYPTED_LM_OWF_PASSWORD));
+            if (InfoBuffer->All.LmOwfPassword.Buffer == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                goto done;
+            }
+
+            InfoBuffer->All.LmOwfPassword.Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
+            InfoBuffer->All.LmOwfPassword.MaximumLength = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
+
+            Status = SampGetObjectAttribute(UserObject,
+                                            L"LMPwd",
+                                            NULL,
+                                            (PVOID)InfoBuffer->All.LmOwfPassword.Buffer,
+                                            &Length);
+            if (!NT_SUCCESS(Status))
+                goto done;
+
+            if (memcmp(InfoBuffer->All.LmOwfPassword.Buffer,
+                       &EmptyLmHash,
+                       sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
+                InfoBuffer->All.LmPasswordPresent = TRUE;
+        }
+    }
 
-        InfoBuffer->All. WhichFields |= USER_ALL_READ_PREFERENCES_MASK;
-//            USER_ALL_COUNTRYCODE |
-//            USER_ALL_CODEPAGE;
+    if (InfoBuffer->All.WhichFields & USER_ALL_PRIVATEDATA)
+    {
+        Status = SampGetObjectAttributeString(UserObject,
+                                              L"PrivateData",
+                                              &InfoBuffer->All.PrivateData);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("Status 0x%08lx\n", Status);
+            goto done;
+        }
+    }
+
+    if (InfoBuffer->All.WhichFields & USER_ALL_PASSWORDEXPIRED)
+    {
+        /* FIXME */
+    }
+
+    if (InfoBuffer->All.WhichFields & USER_ALL_SECURITYDESCRIPTOR)
+    {
+        Length = 0;
+        SampGetObjectAttribute(UserObject,
+                               L"SecDesc",
+                               NULL,
+                               NULL,
+                               &Length);
+
+        if (Length > 0)
+        {
+            InfoBuffer->All.SecurityDescriptor.SecurityDescriptor = midl_user_allocate(Length);
+            if (InfoBuffer->All.SecurityDescriptor.SecurityDescriptor == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                goto done;
+            }
+
+            InfoBuffer->All.SecurityDescriptor.Length = Length;
+
+            Status = SampGetObjectAttribute(UserObject,
+                                            L"SecDesc",
+                                            NULL,
+                                            (PVOID)InfoBuffer->All.SecurityDescriptor.SecurityDescriptor,
+                                            &Length);
+            if (!NT_SUCCESS(Status))
+                goto done;
+        }
     }
 
     *Buffer = InfoBuffer;
@@ -6744,6 +7079,18 @@ done:
             if (InfoBuffer->All.Parameters.Buffer != NULL)
                 midl_user_free(InfoBuffer->All.Parameters.Buffer);
 
+            if (InfoBuffer->All.LmOwfPassword.Buffer != NULL)
+                midl_user_free(InfoBuffer->All.LmOwfPassword.Buffer);
+
+            if (InfoBuffer->All.NtOwfPassword.Buffer != NULL)
+                midl_user_free(InfoBuffer->All.NtOwfPassword.Buffer);
+
+            if (InfoBuffer->All.PrivateData.Buffer != NULL)
+                midl_user_free(InfoBuffer->All.PrivateData.Buffer);
+
+            if (InfoBuffer->All.SecurityDescriptor.SecurityDescriptor != NULL)
+                midl_user_free(InfoBuffer->All.SecurityDescriptor.SecurityDescriptor);
+
             midl_user_free(InfoBuffer);
         }
     }
@@ -7222,13 +7569,13 @@ SampSetUserInternal1(PSAM_DB_OBJECT UserObject,
 
     if (Buffer->Internal1.PasswordExpired)
     {
-        /* The pasword was last set ages ago */
+        /* The password was last set ages ago */
         FixedData.PasswordLastSet.LowPart = 0;
         FixedData.PasswordLastSet.HighPart = 0;
     }
     else
     {
-        /* The pasword was last set right now */
+        /* The password was last set right now */
         Status = NtQuerySystemTime(&FixedData.PasswordLastSet);
         if (!NT_SUCCESS(Status))
             goto done;
@@ -7431,6 +7778,15 @@ SampSetUserAll(PSAM_DB_OBJECT UserObject,
         WriteFixedData = TRUE;
     }
 
+    if (WhichFields & USER_ALL_PRIVATEDATA)
+    {
+        Status = SampSetObjectAttributeString(UserObject,
+                                              L"PrivateData",
+                                              &Buffer->All.PrivateData);
+        if (!NT_SUCCESS(Status))
+            goto done;
+    }
+
     if (WhichFields & USER_ALL_PASSWORDEXPIRED)
     {
         if (Buffer->All.PasswordExpired)
@@ -7450,6 +7806,15 @@ SampSetUserAll(PSAM_DB_OBJECT UserObject,
         WriteFixedData = TRUE;
     }
 
+    if (WhichFields & USER_ALL_SECURITYDESCRIPTOR)
+    {
+        Status = SampSetObjectAttribute(UserObject,
+                                        L"SecDesc",
+                                        REG_BINARY,
+                                        Buffer->All.SecurityDescriptor.SecurityDescriptor,
+                                        Buffer->All.SecurityDescriptor.Length);
+    }
+
     if (WriteFixedData == TRUE)
     {
         Status = SampSetObjectAttribute(UserObject,
@@ -7682,10 +8047,10 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
 {
     ENCRYPTED_LM_OWF_PASSWORD StoredLmPassword;
     ENCRYPTED_NT_OWF_PASSWORD StoredNtPassword;
-    PENCRYPTED_LM_OWF_PASSWORD OldLmPassword;
-    PENCRYPTED_LM_OWF_PASSWORD NewLmPassword;
-    PENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
-    PENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
+    ENCRYPTED_LM_OWF_PASSWORD OldLmPassword;
+    ENCRYPTED_LM_OWF_PASSWORD NewLmPassword;
+    ENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
+    ENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
     BOOLEAN StoredLmPresent = FALSE;
     BOOLEAN StoredNtPresent = FALSE;
     BOOLEAN StoredLmEmpty = TRUE;
@@ -7697,6 +8062,10 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
     LARGE_INTEGER SystemTime;
     NTSTATUS Status;
 
+    DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmPresent);
+    DBG_UNREFERENCED_LOCAL_VARIABLE(StoredNtPresent);
+    DBG_UNREFERENCED_LOCAL_VARIABLE(StoredLmEmpty);
+
     TRACE("(%p %u %p %p %u %p %p %u %p %u %p)\n",
           UserHandle, LmPresent, OldLmEncryptedWithNewLm, NewLmEncryptedWithOldLm,
           NtPresent, OldNtEncryptedWithNewNt, NewNtEncryptedWithOldNt, NtCrossEncryptionPresent,
@@ -7788,21 +8157,62 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
         if (!NT_SUCCESS(Status))
         {
             TRACE("SampGetObjectAttribute failed to retrieve the fixed domain data (Status 0x%08lx)\n", Status);
-            return Status;
+            goto done;
         }
 
         if (DomainFixedData.MinPasswordAge.QuadPart > 0)
         {
             if (SystemTime.QuadPart < (UserFixedData.PasswordLastSet.QuadPart + DomainFixedData.MinPasswordAge.QuadPart))
-                return STATUS_ACCOUNT_RESTRICTION;
+            {
+                Status = STATUS_ACCOUNT_RESTRICTION;
+                goto done;
+            }
+        }
+    }
+
+    /* Decrypt the LM passwords, if present */
+    if (LmPresent)
+    {
+        Status = SystemFunction013((const BYTE *)NewLmEncryptedWithOldLm,
+                                   (const BYTE *)&StoredLmPassword,
+                                   (LPBYTE)&NewLmPassword);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        Status = SystemFunction013((const BYTE *)OldLmEncryptedWithNewLm,
+                                   (const BYTE *)&NewLmPassword,
+                                   (LPBYTE)&OldLmPassword);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
+            goto done;
         }
     }
 
-    /* FIXME: Decrypt passwords */
-    OldLmPassword = OldLmEncryptedWithNewLm;
-    NewLmPassword = NewLmEncryptedWithOldLm;
-    OldNtPassword = OldNtEncryptedWithNewNt;
-    NewNtPassword = NewNtEncryptedWithOldNt;
+    /* Decrypt the NT passwords, if present */
+    if (NtPresent)
+    {
+        Status = SystemFunction013((const BYTE *)NewNtEncryptedWithOldNt,
+                                   (const BYTE *)&StoredNtPassword,
+                                   (LPBYTE)&NewNtPassword);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        Status = SystemFunction013((const BYTE *)OldNtEncryptedWithNewNt,
+                                   (const BYTE *)&NewNtPassword,
+                                   (LPBYTE)&OldNtPassword);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("SystemFunction013 failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+    }
 
     /* Check if the old passwords match the stored ones */
     if (NtPresent)
@@ -7810,7 +8220,7 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
         if (LmPresent)
         {
             if (!RtlEqualMemory(&StoredLmPassword,
-                                OldLmPassword,
+                                &OldLmPassword,
                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
             {
                 TRACE("Old LM Password does not match!\n");
@@ -7819,7 +8229,7 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
             else
             {
                 if (!RtlEqualMemory(&StoredNtPassword,
-                                    OldNtPassword,
+                                    &OldNtPassword,
                                     sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
                 {
                     TRACE("Old NT Password does not match!\n");
@@ -7830,7 +8240,7 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
         else
         {
             if (!RtlEqualMemory(&StoredNtPassword,
-                                OldNtPassword,
+                                &OldNtPassword,
                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
             {
                 TRACE("Old NT Password does not match!\n");
@@ -7843,7 +8253,7 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
         if (LmPresent)
         {
             if (!RtlEqualMemory(&StoredLmPassword,
-                                OldLmPassword,
+                                &OldLmPassword,
                                 sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
             {
                 TRACE("Old LM Password does not match!\n");
@@ -7860,9 +8270,9 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
     if (NT_SUCCESS(Status))
     {
         Status = SampSetUserPassword(UserObject,
-                                     NewNtPassword,
+                                     &NewNtPassword,
                                      NtPresent,
-                                     NewLmPassword,
+                                     &NewLmPassword,
                                      LmPresent);
         if (NT_SUCCESS(Status))
         {
@@ -8294,6 +8704,9 @@ SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
     ULONG ulSize;
     ULONG ulRid;
     WCHAR szRid[9];
+    PSECURITY_DESCRIPTOR Sd = NULL;
+    ULONG SdSize = 0;
+    PSID UserSid = NULL;
     NTSTATUS Status;
 
     TRACE("SamrCreateUserInDomain(%p %p %lx %p %p)\n",
@@ -8367,6 +8780,28 @@ SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
     ulRid = FixedDomainData.NextRid;
     FixedDomainData.NextRid++;
 
+    TRACE("RID: %lx\n", ulRid);
+
+    /* Create the user SID */
+    Status = SampCreateAccountSid(DomainObject,
+                                  ulRid,
+                                  &UserSid);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SampCreateAccountSid failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    /* Create the security descriptor */
+    Status = SampCreateUserSD(UserSid,
+                              &Sd,
+                              &SdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SampCreateUserSD failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
     /* Store the fixed domain attributes */
     Status = SampSetObjectAttribute(DomainObject,
                                     L"F",
@@ -8379,8 +8814,6 @@ SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
         goto done;
     }
 
-    TRACE("RID: %lx\n", ulRid);
-
     /* Convert the RID into a string (hex) */
     swprintf(szRid, L"%08lX", ulRid);
 
@@ -8622,7 +9055,27 @@ SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
         goto done;
     }
 
-    /* FIXME: Set SecDesc attribute*/
+    /* Set the PrivateData attribute */
+    Status = SampSetObjectAttributeString(UserObject,
+                                          L"PrivateData",
+                                          NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("failed with status 0x%08lx\n", Status);
+        goto done;
+    }
+
+    /* Set the SecDesc attribute*/
+    Status = SampSetObjectAttribute(UserObject,
+                                    L"SecDesc",
+                                    REG_BINARY,
+                                    Sd,
+                                    SdSize);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("failed with status 0x%08lx\n", Status);
+        goto done;
+    }
 
     if (NT_SUCCESS(Status))
     {
@@ -8632,6 +9085,12 @@ SamrCreateUser2InDomain(IN SAMPR_HANDLE DomainHandle,
     }
 
 done:
+    if (Sd != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, Sd);
+
+    if (UserSid != NULL)
+        RtlFreeHeap(RtlGetProcessHeap(), 0, UserSid);
+
     RtlReleaseResource(&SampResource);
 
     TRACE("returns with status 0x%08lx\n", Status);