[MSV1_0]
[reactos.git] / reactos / dll / win32 / msv1_0 / msv1_0.c
index e1fe77c..046f48f 100644 (file)
@@ -227,22 +227,20 @@ AppendRidToSid(PSID SrcSid,
 {
     PSID DstSid = NULL;
     UCHAR RidCount;
-    ULONG Size;
-    ULONG i;
 
     RidCount = *RtlSubAuthorityCountSid(SrcSid);
     if (RidCount >= 8)
         return NULL;
 
-    Size = RtlLengthRequiredSid(RidCount + 1);
-
-    DstSid = DispatchTable.AllocateLsaHeap(Size);
+    DstSid = DispatchTable.AllocateLsaHeap(RtlLengthRequiredSid(RidCount + 1));
     if (DstSid == NULL)
         return NULL;
 
-    for (i = 0; i < RidCount; i++)
-        *RtlSubAuthoritySid(DstSid, i) = *RtlSubAuthoritySid(SrcSid, i);
+    RtlCopyMemory(DstSid,
+                  SrcSid,
+                  RtlLengthRequiredSid(RidCount));
 
+    *RtlSubAuthorityCountSid(DstSid) = RidCount + 1;
     *RtlSubAuthoritySid(DstSid, RidCount) = Rid;
 
     return DstSid;
@@ -256,6 +254,12 @@ BuildTokenUser(OUT PTOKEN_USER User,
 {
     User->User.Sid = AppendRidToSid(AccountDomainSid,
                                     RelativeId);
+    if (User->User.Sid == NULL)
+    {
+        ERR("Could not create the user SID\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
     User->User.Attributes = 0;
 
     return STATUS_SUCCESS;
@@ -264,17 +268,30 @@ BuildTokenUser(OUT PTOKEN_USER User,
 
 static
 NTSTATUS
-BuildTokenGroups(IN PSID AccountDomainSid,
-                 IN PLUID LogonId,
-                 OUT PTOKEN_GROUPS *Groups,
-                 OUT PSID *PrimaryGroupSid,
-                 OUT PSID *OwnerSid)
+BuildTokenPrimaryGroup(OUT PTOKEN_PRIMARY_GROUP PrimaryGroup,
+                       IN PSID AccountDomainSid,
+                       IN ULONG RelativeId)
+{
+    PrimaryGroup->PrimaryGroup = AppendRidToSid(AccountDomainSid,
+                                                RelativeId);
+    if (PrimaryGroup->PrimaryGroup == NULL)
+    {
+        ERR("Could not create the primary group SID\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+static
+NTSTATUS
+BuildTokenGroups(OUT PTOKEN_GROUPS *Groups,
+                 IN PSID AccountDomainSid)
 {
-    SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
-    SID_IDENTIFIER_AUTHORITY LocalAuthority = {SECURITY_LOCAL_SID_AUTHORITY};
     SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
     PTOKEN_GROUPS TokenGroups;
-#define MAX_GROUPS 8
+#define MAX_GROUPS 2
     DWORD GroupCount = 0;
     PSID Sid;
     NTSTATUS Status = STATUS_SUCCESS;
@@ -296,115 +313,8 @@ BuildTokenGroups(IN PSID AccountDomainSid,
     TokenGroups->Groups[GroupCount].Sid = Sid;
     TokenGroups->Groups[GroupCount].Attributes =
         SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
-    *PrimaryGroupSid = Sid;
     GroupCount++;
 
-    /* Member of 'Everyone' */
-    RtlAllocateAndInitializeSid(&WorldAuthority,
-                                1,
-                                SECURITY_WORLD_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                &Sid);
-    TokenGroups->Groups[GroupCount].Sid = Sid;
-    TokenGroups->Groups[GroupCount].Attributes =
-        SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
-    GroupCount++;
-
-#if 1
-    /* Member of 'Administrators' */
-    RtlAllocateAndInitializeSid(&SystemAuthority,
-                                2,
-                                SECURITY_BUILTIN_DOMAIN_RID,
-                                DOMAIN_ALIAS_RID_ADMINS,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                &Sid);
-    TokenGroups->Groups[GroupCount].Sid = Sid;
-    TokenGroups->Groups[GroupCount].Attributes =
-        SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
-    GroupCount++;
-#else
-    TRACE("Not adding user to Administrators group\n");
-#endif
-
-    /* Member of 'Users' */
-    RtlAllocateAndInitializeSid(&SystemAuthority,
-                                2,
-                                SECURITY_BUILTIN_DOMAIN_RID,
-                                DOMAIN_ALIAS_RID_USERS,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                &Sid);
-    TokenGroups->Groups[GroupCount].Sid = Sid;
-    TokenGroups->Groups[GroupCount].Attributes =
-        SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
-    GroupCount++;
-
-    /* Logon SID */
-    RtlAllocateAndInitializeSid(&SystemAuthority,
-                                SECURITY_LOGON_IDS_RID_COUNT,
-                                SECURITY_LOGON_IDS_RID,
-                                LogonId->HighPart,
-                                LogonId->LowPart,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                &Sid);
-    TokenGroups->Groups[GroupCount].Sid = Sid;
-    TokenGroups->Groups[GroupCount].Attributes =
-        SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY | SE_GROUP_LOGON_ID;
-    GroupCount++;
-    *OwnerSid = Sid;
-
-    /* Member of 'Local users */
-    RtlAllocateAndInitializeSid(&LocalAuthority,
-                                1,
-                                SECURITY_LOCAL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                &Sid);
-    TokenGroups->Groups[GroupCount].Sid = Sid;
-    TokenGroups->Groups[GroupCount].Attributes =
-        SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
-    GroupCount++;
-
-    /* Member of 'Interactive users' */
-    RtlAllocateAndInitializeSid(&SystemAuthority,
-                                1,
-                                SECURITY_INTERACTIVE_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                &Sid);
-    TokenGroups->Groups[GroupCount].Sid = Sid;
-    TokenGroups->Groups[GroupCount].Attributes =
-        SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
-    GroupCount++;
 
     /* Member of 'Authenticated users' */
     RtlAllocateAndInitializeSid(&SystemAuthority,
@@ -434,109 +344,72 @@ BuildTokenGroups(IN PSID AccountDomainSid,
 
 static
 NTSTATUS
-BuildTokenPrimaryGroup(PTOKEN_PRIMARY_GROUP PrimaryGroup,
-                       PSID PrimaryGroupSid)
+BuildTokenInformationBuffer(PLSA_TOKEN_INFORMATION_V1 *TokenInformation,
+                            PRPC_SID AccountDomainSid,
+                            PSAMPR_USER_INFO_BUFFER UserInfo)
 {
-    ULONG RidCount;
-    ULONG Size;
-
-    RidCount = *RtlSubAuthorityCountSid(PrimaryGroupSid);
-    Size = RtlLengthRequiredSid(RidCount);
+    PLSA_TOKEN_INFORMATION_V1 Buffer = NULL;
+    ULONG i;
+    NTSTATUS Status = STATUS_SUCCESS;
 
-    PrimaryGroup->PrimaryGroup = DispatchTable.AllocateLsaHeap(Size);
-    if (PrimaryGroup->PrimaryGroup == NULL)
+    Buffer = DispatchTable.AllocateLsaHeap(sizeof(LSA_TOKEN_INFORMATION_V1));
+    if (Buffer == NULL)
     {
-        return STATUS_INSUFFICIENT_RESOURCES;
+        TRACE("Failed to allocate the local buffer!\n");
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto done;
     }
 
-    RtlCopyMemory(PrimaryGroup->PrimaryGroup,
-                  PrimaryGroupSid,
-                  Size);
-
-    return STATUS_SUCCESS;
-}
+    /* FIXME: */
+    Buffer->ExpirationTime.QuadPart = -1;
 
-static
-NTSTATUS
-BuildTokenPrivileges(PTOKEN_PRIVILEGES *TokenPrivileges)
-{
-    /* FIXME shouldn't use hard-coded list of privileges */
-    static struct
-    {
-      LPCWSTR PrivName;
-      DWORD Attributes;
-    }
-    DefaultPrivs[] =
-    {
-      { L"SeMachineAccountPrivilege", 0 },
-      { L"SeSecurityPrivilege", 0 },
-      { L"SeTakeOwnershipPrivilege", 0 },
-      { L"SeLoadDriverPrivilege", 0 },
-      { L"SeSystemProfilePrivilege", 0 },
-      { L"SeSystemtimePrivilege", 0 },
-      { L"SeProfileSingleProcessPrivilege", 0 },
-      { L"SeIncreaseBasePriorityPrivilege", 0 },
-      { L"SeCreatePagefilePrivilege", 0 },
-      { L"SeBackupPrivilege", 0 },
-      { L"SeRestorePrivilege", 0 },
-      { L"SeShutdownPrivilege", 0 },
-      { L"SeDebugPrivilege", 0 },
-      { L"SeSystemEnvironmentPrivilege", 0 },
-      { L"SeChangeNotifyPrivilege", SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
-      { L"SeRemoteShutdownPrivilege", 0 },
-      { L"SeUndockPrivilege", 0 },
-      { L"SeEnableDelegationPrivilege", 0 },
-      { L"SeImpersonatePrivilege", SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
-      { L"SeCreateGlobalPrivilege", SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT }
-    };
-    PTOKEN_PRIVILEGES Privileges = NULL;
-    ULONG i;
-    RPC_UNICODE_STRING PrivilegeName;
-    LSAPR_HANDLE PolicyHandle = NULL;
-    NTSTATUS Status = STATUS_SUCCESS;
+    Status = BuildTokenUser(&Buffer->User,
+                            (PSID)AccountDomainSid,
+                            UserInfo->All.UserId);
+    if (!NT_SUCCESS(Status))
+        goto done;
 
-    Status = LsaIOpenPolicyTrusted(&PolicyHandle);
+    Status = BuildTokenPrimaryGroup(&Buffer->PrimaryGroup,
+                                    (PSID)AccountDomainSid,
+                                    UserInfo->All.PrimaryGroupId);
     if (!NT_SUCCESS(Status))
-    {
         goto done;
-    }
 
-    /* Allocate and initialize token privileges */
-    Privileges = DispatchTable.AllocateLsaHeap(sizeof(TOKEN_PRIVILEGES) +
-                                               sizeof(DefaultPrivs) / sizeof(DefaultPrivs[0]) *
-                                               sizeof(LUID_AND_ATTRIBUTES));
-    if (Privileges == NULL)
-    {
-        Status = STATUS_INSUFFICIENT_RESOURCES;
+    Status = BuildTokenGroups(&Buffer->Groups,
+                              (PSID)AccountDomainSid);
+    if (!NT_SUCCESS(Status))
         goto done;
-    }
 
-    Privileges->PrivilegeCount = 0;
-    for (i = 0; i < sizeof(DefaultPrivs) / sizeof(DefaultPrivs[0]); i++)
-    {
-        PrivilegeName.Length = wcslen(DefaultPrivs[i].PrivName) * sizeof(WCHAR);
-        PrivilegeName.MaximumLength = PrivilegeName.Length + sizeof(WCHAR);
-        PrivilegeName.Buffer = (LPWSTR)DefaultPrivs[i].PrivName;
+    *TokenInformation = Buffer;
 
-        Status = LsarLookupPrivilegeValue(PolicyHandle,
-                                          &PrivilegeName,
-                                          &Privileges->Privileges[Privileges->PrivilegeCount].Luid);
-        if (!NT_SUCCESS(Status))
-        {
-            WARN("Can't set privilege %S\n", DefaultPrivs[i].PrivName);
-        }
-        else
+done:
+    if (!NT_SUCCESS(Status))
+    {
+        if (Buffer != NULL)
         {
-            Privileges->Privileges[Privileges->PrivilegeCount].Attributes = DefaultPrivs[i].Attributes;
-            Privileges->PrivilegeCount++;
-        }
-    }
+            if (Buffer->User.User.Sid != NULL)
+                DispatchTable.FreeLsaHeap(Buffer->User.User.Sid);
 
-    *TokenPrivileges = Privileges;
+            if (Buffer->Groups != NULL)
+            {
+                for (i = 0; i < Buffer->Groups->GroupCount; i++)
+                {
+                    if (Buffer->Groups->Groups[i].Sid != NULL)
+                        DispatchTable.FreeLsaHeap(Buffer->Groups->Groups[i].Sid);
+                }
 
-done:
-    if (PolicyHandle != NULL)
-        LsarClose(PolicyHandle);
+                DispatchTable.FreeLsaHeap(Buffer->Groups);
+            }
+
+            if (Buffer->PrimaryGroup.PrimaryGroup != NULL)
+                DispatchTable.FreeLsaHeap(Buffer->PrimaryGroup.PrimaryGroup);
+
+            if (Buffer->DefaultDacl.DefaultDacl != NULL)
+                DispatchTable.FreeLsaHeap(Buffer->DefaultDacl.DefaultDacl);
+
+            DispatchTable.FreeLsaHeap(Buffer);
+        }
+    }
 
     return Status;
 }
@@ -544,183 +417,357 @@ done:
 
 static
 NTSTATUS
-BuildTokenOwner(PTOKEN_OWNER Owner,
-                PSID OwnerSid)
+MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
+                   IN PVOID ProtocolSubmitBuffer,
+                   IN PVOID ClientBufferBase,
+                   IN ULONG SubmitBufferLength,
+                   OUT PVOID *ProtocolReturnBuffer,
+                   OUT PULONG ReturnBufferLength,
+                   OUT PNTSTATUS ProtocolStatus)
 {
-    ULONG RidCount;
-    ULONG Size;
+    PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer;
+    ULONG_PTR PtrOffset;
 
-    RidCount = *RtlSubAuthorityCountSid(OwnerSid);
-    Size = RtlLengthRequiredSid(RidCount);
+    SAMPR_HANDLE ServerHandle = NULL;
+    SAMPR_HANDLE DomainHandle = NULL;
+    SAMPR_HANDLE UserHandle = NULL;
+    PRPC_SID DomainSid = NULL;
+    RPC_UNICODE_STRING Names[1];
+    SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
+    SAMPR_ULONG_ARRAY Use = {0, NULL};
+    NTSTATUS Status;
 
-    Owner->Owner = DispatchTable.AllocateLsaHeap(Size);
-    if (Owner->Owner == NULL)
-    {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
+    ENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
+    ENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
+    ENCRYPTED_LM_OWF_PASSWORD OldLmPassword;
+    ENCRYPTED_LM_OWF_PASSWORD NewLmPassword;
+    OEM_STRING LmPwdString;
+    CHAR LmPwdBuffer[15];
+    BOOLEAN OldLmPasswordPresent = FALSE;
+    BOOLEAN NewLmPasswordPresent = FALSE;
+
+    ENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm;
+    ENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm;
+    ENCRYPTED_LM_OWF_PASSWORD OldNtEncryptedWithNewNt;
+    ENCRYPTED_LM_OWF_PASSWORD NewNtEncryptedWithOldNt;
+    PENCRYPTED_LM_OWF_PASSWORD pOldLmEncryptedWithNewLm = NULL;
+    PENCRYPTED_LM_OWF_PASSWORD pNewLmEncryptedWithOldLm = NULL;
 
-    RtlCopyMemory(Owner->Owner,
-                  OwnerSid,
-                  Size);
+    TRACE("()\n");
 
-    return STATUS_SUCCESS;
-}
+    RequestBuffer = (PMSV1_0_CHANGEPASSWORD_REQUEST)ProtocolSubmitBuffer;
 
+    /* Fix-up pointers in the request buffer info */
+    PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
 
-static
-NTSTATUS
-BuildTokenDefaultDacl(PTOKEN_DEFAULT_DACL DefaultDacl,
-                      PSID OwnerSid)
-{
-    SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
-    PSID LocalSystemSid = NULL;
-    PACL Dacl = NULL;
-    NTSTATUS Status = STATUS_SUCCESS;
+    RequestBuffer->DomainName.Buffer = FIXUP_POINTER(RequestBuffer->DomainName.Buffer, PtrOffset);
+    RequestBuffer->AccountName.Buffer = FIXUP_POINTER(RequestBuffer->AccountName.Buffer, PtrOffset);
+    RequestBuffer->OldPassword.Buffer = FIXUP_POINTER(RequestBuffer->OldPassword.Buffer, PtrOffset);
+    RequestBuffer->NewPassword.Buffer = FIXUP_POINTER(RequestBuffer->NewPassword.Buffer, PtrOffset);
 
-    RtlAllocateAndInitializeSid(&SystemAuthority,
-                                1,
-                                SECURITY_LOCAL_SYSTEM_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                SECURITY_NULL_RID,
-                                &LocalSystemSid);
+    TRACE("Domain: %S\n", RequestBuffer->DomainName.Buffer);
+    TRACE("Account: %S\n", RequestBuffer->AccountName.Buffer);
+    TRACE("Old Password: %S\n", RequestBuffer->OldPassword.Buffer);
+    TRACE("New Password: %S\n", RequestBuffer->NewPassword.Buffer);
 
-    Dacl = DispatchTable.AllocateLsaHeap(1024);
-    if (Dacl == NULL)
+    /* Connect to the SAM server */
+    Status = SamIConnect(NULL,
+                         &ServerHandle,
+                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
+                         TRUE);
+    if (!NT_SUCCESS(Status))
     {
-        Status = STATUS_INSUFFICIENT_RESOURCES;
+        TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
         goto done;
     }
 
-    Status = RtlCreateAcl(Dacl, 1024, ACL_REVISION);
+    /* Get the domain SID */
+    Status = SamrLookupDomainInSamServer(ServerHandle,
+                                         (PRPC_UNICODE_STRING)&RequestBuffer->DomainName,
+                                         &DomainSid);
     if (!NT_SUCCESS(Status))
+    {
+        TRACE("SamrLookupDomainInSamServer failed (Status %08lx)\n", Status);
         goto done;
+    }
 
-    RtlAddAccessAllowedAce(Dacl,
-                           ACL_REVISION,
-                           GENERIC_ALL,
-                           OwnerSid);
-
-    /* SID: S-1-5-18 */
-    RtlAddAccessAllowedAce(Dacl,
-                           ACL_REVISION,
-                           GENERIC_ALL,
-                           LocalSystemSid);
-
-    DefaultDacl->DefaultDacl = Dacl;
-
-done:
+    /* Open the domain */
+    Status = SamrOpenDomain(ServerHandle,
+                            DOMAIN_LOOKUP,
+                            DomainSid,
+                            &DomainHandle);
     if (!NT_SUCCESS(Status))
     {
-        if (Dacl != NULL)
-            DispatchTable.FreeLsaHeap(Dacl);
+        TRACE("SamrOpenDomain failed (Status %08lx)\n", Status);
+        goto done;
     }
 
-    if (LocalSystemSid != NULL)
-        RtlFreeSid(LocalSystemSid);
+    Names[0].Length = RequestBuffer->AccountName.Length;
+    Names[0].MaximumLength = RequestBuffer->AccountName.MaximumLength;
+    Names[0].Buffer = RequestBuffer->AccountName.Buffer;
 
-    return Status;
-}
-
-
-static
-NTSTATUS
-BuildTokenInformationBuffer(PLSA_TOKEN_INFORMATION_V1 *TokenInformation,
-                            PRPC_SID AccountDomainSid,
-                            ULONG RelativeId,
-                            PLUID LogonId)
-{
-    PLSA_TOKEN_INFORMATION_V1 Buffer = NULL;
-    PSID OwnerSid = NULL;
-    PSID PrimaryGroupSid = NULL;
-    ULONG i;
-    NTSTATUS Status = STATUS_SUCCESS;
-
-    Buffer = DispatchTable.AllocateLsaHeap(sizeof(LSA_TOKEN_INFORMATION_V1));
-    if (Buffer == NULL)
+    /* Try to get the RID for the user name */
+    Status = SamrLookupNamesInDomain(DomainHandle,
+                                     1,
+                                     Names,
+                                     &RelativeIds,
+                                     &Use);
+    if (!NT_SUCCESS(Status))
     {
-        TRACE("Failed to allocate the local buffer!\n");
-        Status = STATUS_INSUFFICIENT_RESOURCES;
+        TRACE("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
+        Status = STATUS_NO_SUCH_USER;
         goto done;
     }
 
-    /* FIXME: */
-    Buffer->ExpirationTime.QuadPart = -1;
+    /* Fail, if it is not a user account */
+    if (Use.Element[0] != SidTypeUser)
+    {
+        TRACE("Account is not a user account!\n");
+        Status = STATUS_NO_SUCH_USER;
+        goto done;
+    }
 
-    Status = BuildTokenUser(&Buffer->User,
-                            (PSID)AccountDomainSid,
-                            RelativeId);
+    /* Open the user object */
+    Status = SamrOpenUser(DomainHandle,
+                          USER_CHANGE_PASSWORD,
+                          RelativeIds.Element[0],
+                          &UserHandle);
     if (!NT_SUCCESS(Status))
+    {
+        TRACE("SamrOpenUser failed (Status %08lx)\n", Status);
         goto done;
+    }
+
 
-    Status = BuildTokenGroups((PSID)AccountDomainSid,
-                              LogonId,
-                              &Buffer->Groups,
-                              &PrimaryGroupSid,
-                              &OwnerSid);
+    /* Calculate the NT hash for the old password */
+    Status = SystemFunction007(&RequestBuffer->OldPassword,
+                               (LPBYTE)&OldNtPassword);
     if (!NT_SUCCESS(Status))
+    {
+        TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status);
         goto done;
+    }
 
-    Status = BuildTokenPrimaryGroup(&Buffer->PrimaryGroup,
-                                    PrimaryGroupSid);
+    /* Calculate the NT hash for the new password */
+    Status = SystemFunction007(&RequestBuffer->NewPassword,
+                               (LPBYTE)&NewNtPassword);
     if (!NT_SUCCESS(Status))
+    {
+        TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status);
         goto done;
+    }
+
+    /* Calculate the LM password and hash for the old password */
+    LmPwdString.Length = 15;
+    LmPwdString.MaximumLength = 15;
+    LmPwdString.Buffer = LmPwdBuffer;
+    ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
+
+    Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
+                                               &RequestBuffer->OldPassword,
+                                               FALSE);
+    if (NT_SUCCESS(Status))
+    {
+        /* Calculate the LM hash value of the password */
+        Status = SystemFunction006(LmPwdString.Buffer,
+                                   (LPSTR)&OldLmPassword);
+        if (NT_SUCCESS(Status))
+        {
+            OldLmPasswordPresent = TRUE;
+        }
+    }
+
+    /* Calculate the LM password and hash for the new password */
+    LmPwdString.Length = 15;
+    LmPwdString.MaximumLength = 15;
+    LmPwdString.Buffer = LmPwdBuffer;
+    ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
+
+    Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
+                                               &RequestBuffer->NewPassword,
+                                               FALSE);
+    if (NT_SUCCESS(Status))
+    {
+        /* Calculate the LM hash value of the password */
+        Status = SystemFunction006(LmPwdString.Buffer,
+                                   (LPSTR)&NewLmPassword);
+        if (NT_SUCCESS(Status))
+        {
+            NewLmPasswordPresent = TRUE;
+        }
+    }
 
-    Status = BuildTokenPrivileges(&Buffer->Privileges);
+    /* Encrypt the old and new LM passwords, if they exist */
+    if (OldLmPasswordPresent && NewLmPasswordPresent)
+    {
+        /* Encrypt the old LM password */
+        Status = SystemFunction012((const BYTE *)&OldLmPassword,
+                                   (const BYTE *)&NewLmPassword,
+                                   (LPBYTE)&OldLmEncryptedWithNewLm);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        /* Encrypt the new LM password */
+        Status = SystemFunction012((const BYTE *)&NewLmPassword,
+                                   (const BYTE *)&OldLmPassword,
+                                   (LPBYTE)&NewLmEncryptedWithOldLm);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
+            goto done;
+        }
+
+        pOldLmEncryptedWithNewLm = &OldLmEncryptedWithNewLm;
+        pNewLmEncryptedWithOldLm = &NewLmEncryptedWithOldLm;
+    }
+
+    /* Encrypt the old NT password */
+    Status = SystemFunction012((const BYTE *)&OldNtPassword,
+                               (const BYTE *)&NewNtPassword,
+                               (LPBYTE)&OldNtEncryptedWithNewNt);
     if (!NT_SUCCESS(Status))
+    {
+        TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
         goto done;
+    }
 
-    Status = BuildTokenOwner(&Buffer->Owner,
-                             OwnerSid);
+    /* Encrypt the new NT password */
+    Status = SystemFunction012((const BYTE *)&NewNtPassword,
+                               (const BYTE *)&OldNtPassword,
+                               (LPBYTE)&NewNtEncryptedWithOldNt);
     if (!NT_SUCCESS(Status))
+    {
+        TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
         goto done;
+    }
 
-    Status = BuildTokenDefaultDacl(&Buffer->DefaultDacl,
-                                   OwnerSid);
+    /* Change the password */
+    Status = SamrChangePasswordUser(UserHandle,
+                                    OldLmPasswordPresent && NewLmPasswordPresent,
+                                    pOldLmEncryptedWithNewLm,
+                                    pNewLmEncryptedWithOldLm,
+                                    TRUE,
+                                    &OldNtEncryptedWithNewNt,
+                                    &NewNtEncryptedWithOldNt,
+                                    FALSE,
+                                    NULL,
+                                    FALSE,
+                                    NULL);
     if (!NT_SUCCESS(Status))
+    {
+        TRACE("SamrChangePasswordUser failed (Status %08lx)\n", Status);
         goto done;
-
-    *TokenInformation = Buffer;
+    }
 
 done:
-    if (!NT_SUCCESS(Status))
+    if (UserHandle != NULL)
+        SamrCloseHandle(&UserHandle);
+
+    SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
+    SamIFree_SAMPR_ULONG_ARRAY(&Use);
+
+    if (DomainHandle != NULL)
+        SamrCloseHandle(&DomainHandle);
+
+    if (DomainSid != NULL)
+        SamIFreeVoid(DomainSid);
+
+    if (ServerHandle != NULL)
+        SamrCloseHandle(&ServerHandle);
+
+    return Status;
+}
+
+
+static
+NTSTATUS
+MsvpCheckPassword(PUNICODE_STRING UserPassword,
+                  PSAMPR_USER_INFO_BUFFER UserInfo)
+{
+    ENCRYPTED_NT_OWF_PASSWORD UserNtPassword;
+    ENCRYPTED_LM_OWF_PASSWORD UserLmPassword;
+    BOOLEAN UserLmPasswordPresent = FALSE;
+    BOOLEAN UserNtPasswordPresent = FALSE;
+    OEM_STRING LmPwdString;
+    CHAR LmPwdBuffer[15];
+    NTSTATUS Status;
+
+    TRACE("(%p %p)\n", UserPassword, UserInfo);
+
+    /* Calculate the LM password and hash for the users password */
+    LmPwdString.Length = 15;
+    LmPwdString.MaximumLength = 15;
+    LmPwdString.Buffer = LmPwdBuffer;
+    ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
+
+    Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
+                                               UserPassword,
+                                               FALSE);
+    if (NT_SUCCESS(Status))
     {
-        if (Buffer != NULL)
+        /* Calculate the LM hash value of the users password */
+        Status = SystemFunction006(LmPwdString.Buffer,
+                                   (LPSTR)&UserLmPassword);
+        if (NT_SUCCESS(Status))
         {
-            if (Buffer->User.User.Sid != NULL)
-                DispatchTable.FreeLsaHeap(Buffer->User.User.Sid);
-
-            if (Buffer->Groups != NULL)
-            {
-                for (i = 0; i < Buffer->Groups->GroupCount; i++)
-                {
-                    if (Buffer->Groups->Groups[i].Sid != NULL)
-                        DispatchTable.FreeLsaHeap(Buffer->Groups->Groups[i].Sid);
-                }
+            UserLmPasswordPresent = TRUE;
+        }
+    }
 
-                DispatchTable.FreeLsaHeap(Buffer->Groups);
-            }
+    /* Calculate the NT hash of the users password */
+    Status = SystemFunction007(UserPassword,
+                               (LPBYTE)&UserNtPassword);
+    if (NT_SUCCESS(Status))
+    {
+        UserNtPasswordPresent = TRUE;
+    }
 
-            if (Buffer->PrimaryGroup.PrimaryGroup != NULL)
-                DispatchTable.FreeLsaHeap(Buffer->PrimaryGroup.PrimaryGroup);
+    Status = STATUS_WRONG_PASSWORD;
 
-            if (Buffer->Privileges != NULL)
-                DispatchTable.FreeLsaHeap(Buffer->Privileges);
+    /* Succeed, if no password has been set */
+    if (UserInfo->All.NtPasswordPresent == FALSE &&
+        UserInfo->All.LmPasswordPresent == FALSE)
+    {
+        TRACE("No password check!\n");
+        Status = STATUS_SUCCESS;
+        goto done;
+    }
 
-            if (Buffer->Owner.Owner != NULL)
-                DispatchTable.FreeLsaHeap(Buffer->Owner.Owner);
+    /* Succeed, if NT password matches */
+    if (UserNtPasswordPresent && UserInfo->All.NtPasswordPresent)
+    {
+        TRACE("Check NT password hashes:\n");
+        if (RtlEqualMemory(&UserNtPassword,
+                           UserInfo->All.NtOwfPassword.Buffer,
+                           sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
+        {
+            TRACE("  success!\n");
+            Status = STATUS_SUCCESS;
+            goto done;
+        }
 
-            if (Buffer->DefaultDacl.DefaultDacl != NULL)
-                DispatchTable.FreeLsaHeap(Buffer->DefaultDacl.DefaultDacl);
+        TRACE("  failed!\n");
+    }
 
-            DispatchTable.FreeLsaHeap(Buffer);
+    /* Succeed, if LM password matches */
+    if (UserLmPasswordPresent && UserInfo->All.LmPasswordPresent)
+    {
+        TRACE("Check LM password hashes:\n");
+        if (RtlEqualMemory(&UserLmPassword,
+                           UserInfo->All.LmOwfPassword.Buffer,
+                           sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
+        {
+            TRACE("  success!\n");
+            Status = STATUS_SUCCESS;
+            goto done;
         }
+        TRACE("  failed!\n");
     }
 
+done:
     return Status;
 }
 
@@ -738,8 +785,53 @@ LsaApCallPackage(IN PLSA_CLIENT_REQUEST ClientRequest,
                  OUT PULONG ReturnBufferLength,
                  OUT PNTSTATUS ProtocolStatus)
 {
+    ULONG MessageType;
+    NTSTATUS Status;
+
     TRACE("()\n");
-    return STATUS_NOT_IMPLEMENTED;
+
+    if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE))
+        return STATUS_INVALID_PARAMETER;
+
+    MessageType = (ULONG)*((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
+
+    *ProtocolReturnBuffer = NULL;
+    *ReturnBufferLength = 0;
+
+    switch (MessageType)
+    {
+        case MsV1_0Lm20ChallengeRequest:
+        case MsV1_0Lm20GetChallengeResponse:
+        case MsV1_0EnumerateUsers:
+        case MsV1_0GetUserInfo:
+        case MsV1_0ReLogonUsers:
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case MsV1_0ChangePassword:
+            Status = MsvpChangePassword(ClientRequest,
+                                        ProtocolSubmitBuffer,
+                                        ClientBufferBase,
+                                        SubmitBufferLength,
+                                        ProtocolReturnBuffer,
+                                        ReturnBufferLength,
+                                        ProtocolStatus);
+            break;
+
+        case MsV1_0ChangeCachedPassword:
+        case MsV1_0GenericPassthrough:
+        case MsV1_0CacheLogon:
+        case MsV1_0SubAuth:
+        case MsV1_0DeriveCredential:
+        case MsV1_0CacheLookup:
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        default:
+            return STATUS_INVALID_PARAMETER;
+    }
+
+    return Status;
 }
 
 
@@ -798,6 +890,11 @@ LsaApInitializePackage(IN ULONG AuthenticationPackageId,
           Confidentiality, AuthenticationPackageName);
 
     /* Get the dispatch table entries */
+    DispatchTable.CreateLogonSession = LsaDispatchTable->CreateLogonSession;
+    DispatchTable.DeleteLogonSession = LsaDispatchTable->DeleteLogonSession;
+    DispatchTable.AddCredential = LsaDispatchTable->AddCredential;
+    DispatchTable.GetCredentials = LsaDispatchTable->GetCredentials;
+    DispatchTable.DeleteCredential = LsaDispatchTable->DeleteCredential;
     DispatchTable.AllocateLsaHeap = LsaDispatchTable->AllocateLsaHeap;
     DispatchTable.FreeLsaHeap = LsaDispatchTable->FreeLsaHeap;
     DispatchTable.AllocateClientBuffer = LsaDispatchTable->AllocateClientBuffer;
@@ -805,7 +902,6 @@ LsaApInitializePackage(IN ULONG AuthenticationPackageId,
     DispatchTable.CopyToClientBuffer = LsaDispatchTable->CopyToClientBuffer;
     DispatchTable.CopyFromClientBuffer = LsaDispatchTable->CopyFromClientBuffer;
 
-
     /* Return the package name */
     NameString = DispatchTable.AllocateLsaHeap(sizeof(LSA_STRING));
     if (NameString == NULL)
@@ -869,6 +965,11 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
     SAMPR_ULONG_ARRAY Use = {0, NULL};
     PSAMPR_USER_INFO_BUFFER UserInfo = NULL;
     UNICODE_STRING LogonServer;
+    BOOLEAN SessionCreated = FALSE;
+    LARGE_INTEGER LogonTime;
+//    LARGE_INTEGER AccountExpires;
+    LARGE_INTEGER PasswordMustChange;
+    LARGE_INTEGER PasswordLastSet;
     NTSTATUS Status;
 
     TRACE("()\n");
@@ -877,7 +978,6 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
     TRACE("AuthenticationInformation: %p\n", AuthenticationInformation);
     TRACE("AuthenticationInformationLength: %lu\n", AuthenticationInformationLength);
 
-
     *ProfileBuffer = NULL;
     *ProfileBufferLength = 0;
     *SubStatus = STATUS_SUCCESS;
@@ -893,9 +993,9 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
         /* Fix-up pointers in the authentication info */
         PtrOffset = (ULONG_PTR)AuthenticationInformation - (ULONG_PTR)ClientAuthenticationBase;
 
-        LogonInfo->LogonDomainName.Buffer = (PWSTR)((ULONG_PTR)LogonInfo->LogonDomainName.Buffer + PtrOffset);
-        LogonInfo->UserName.Buffer = (PWSTR)((ULONG_PTR)LogonInfo->UserName.Buffer + PtrOffset);
-        LogonInfo->Password.Buffer = (PWSTR)((ULONG_PTR)LogonInfo->Password.Buffer + PtrOffset);
+        LogonInfo->LogonDomainName.Buffer = FIXUP_POINTER(LogonInfo->LogonDomainName.Buffer, PtrOffset);
+        LogonInfo->UserName.Buffer = FIXUP_POINTER(LogonInfo->UserName.Buffer, PtrOffset);
+        LogonInfo->Password.Buffer = FIXUP_POINTER(LogonInfo->Password.Buffer, PtrOffset);
 
         TRACE("Domain: %S\n", LogonInfo->LogonDomainName.Buffer);
         TRACE("User: %S\n", LogonInfo->UserName.Buffer);
@@ -909,6 +1009,10 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
         return STATUS_NOT_IMPLEMENTED;
     }
 
+    /* Get the logon time */
+    NtQuerySystemTime(&LogonTime);
+
+    /* Get the domain SID */
     Status = GetDomainSid(&AccountDomainSid);
     if (!NT_SUCCESS(Status))
     {
@@ -984,16 +1088,77 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
         goto done;
     }
 
-
     TRACE("UserName: %S\n", UserInfo->All.UserName.Buffer);
 
-    /* FIXME: Check restrictions */
-
-    /* FIXME: Check the password */
+    /* Check the password */
     if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
     {
-        FIXME("Must check the password!\n");
+        Status = MsvpCheckPassword(&(LogonInfo->Password),
+                                   UserInfo);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("MsvpCheckPassword failed (Status %08lx)\n", Status);
+            goto done;
+        }
+    }
+
+    /* Check account restrictions for non-administrator accounts */
+    if (RelativeIds.Element[0] != DOMAIN_USER_RID_ADMIN)
+    {
+        /* Check if the account has been disabled */
+        if (UserInfo->All.UserAccountControl & USER_ACCOUNT_DISABLED)
+        {
+            ERR("Account disabled!\n");
+            *SubStatus = STATUS_ACCOUNT_DISABLED;
+            Status = STATUS_ACCOUNT_RESTRICTION;
+            goto done;
+        }
 
+        /* Check if the account has been locked */
+        if (UserInfo->All.UserAccountControl & USER_ACCOUNT_AUTO_LOCKED)
+        {
+            ERR("Account locked!\n");
+            *SubStatus = STATUS_ACCOUNT_LOCKED_OUT;
+            Status = STATUS_ACCOUNT_RESTRICTION;
+            goto done;
+        }
+
+#if 0
+        /* Check if the account expired */
+        AccountExpires.LowPart = UserInfo->All.AccountExpires.LowPart;
+        AccountExpires.HighPart = UserInfo->All.AccountExpires.HighPart;
+
+        if (AccountExpires.QuadPart != 0 &&
+            LogonTime.QuadPart >= AccountExpires.QuadPart)
+        {
+            ERR("Account expired!\n");
+            *SubStatus = STATUS_ACCOUNT_EXPIRED;
+            Status = STATUS_ACCOUNT_RESTRICTION;
+            goto done;
+        }
+#endif
+
+        /* Check if the password expired */
+        PasswordMustChange.LowPart = UserInfo->All.PasswordMustChange.LowPart;
+        PasswordMustChange.HighPart = UserInfo->All.PasswordMustChange.HighPart;
+        PasswordLastSet.LowPart = UserInfo->All.PasswordLastSet.LowPart;
+        PasswordLastSet.HighPart = UserInfo->All.PasswordLastSet.HighPart;
+
+        if (LogonTime.QuadPart >= PasswordMustChange.QuadPart)
+        {
+            ERR("Password expired!\n");
+            if (PasswordLastSet.QuadPart == 0)
+                *SubStatus = STATUS_PASSWORD_MUST_CHANGE;
+            else
+                *SubStatus = STATUS_PASSWORD_EXPIRED;
+
+            Status = STATUS_ACCOUNT_RESTRICTION;
+            goto done;
+        }
+
+        /* FIXME: more checks */
+        // STATUS_INVALID_LOGON_HOURS;
+        // STATUS_INVALID_WORKSTATION;
     }
 
     /* Return logon information */
@@ -1006,6 +1171,16 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
         goto done;
     }
 
+    /* Create the logon session */
+    Status = DispatchTable.CreateLogonSession(LogonId);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("CreateLogonSession failed (Status %08lx)\n", Status);
+        goto done;
+    }
+
+    SessionCreated = TRUE;
+
     /* Build and fill the interactve profile buffer */
     Status = BuildInteractiveProfileBuffer(ClientRequest,
                                            UserInfo,
@@ -1024,16 +1199,13 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
     /* Build and fill the token information buffer */
     Status = BuildTokenInformationBuffer((PLSA_TOKEN_INFORMATION_V1*)TokenInformation,
                                          AccountDomainSid,
-                                         RelativeIds.Element[0],
-                                         LogonId);
+                                         UserInfo);
     if (!NT_SUCCESS(Status))
     {
         TRACE("BuildTokenInformationBuffer failed (Status %08lx)\n", Status);
         goto done;
     }
 
-    *SubStatus = STATUS_SUCCESS;
-
 done:
     /* Return the account name */
     *AccountName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
@@ -1051,6 +1223,9 @@ done:
 
     if (!NT_SUCCESS(Status))
     {
+        if (SessionCreated == TRUE)
+            DispatchTable.DeleteLogonSession(LogonId);
+
         if (*ProfileBuffer != NULL)
         {
             DispatchTable.FreeClientBuffer(ClientRequest,
@@ -1076,7 +1251,14 @@ done:
     if (AccountDomainSid != NULL)
         RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid);
 
-    TRACE("LsaApLogonUser done (Status %08lx)\n", Status);
+    if (Status == STATUS_NO_SUCH_USER ||
+        Status == STATUS_WRONG_PASSWORD)
+    {
+        *SubStatus = Status;
+        Status = STATUS_LOGON_FAILURE;
+    }
+
+    TRACE("LsaApLogonUser done (Status 0x%08lx  SubStatus 0x%08lx)\n", Status, *SubStatus);
 
     return Status;
 }
@@ -1085,6 +1267,7 @@ done:
 /*
  * @unimplemented
  */
+#if 0
 NTSTATUS
 NTAPI
 LsaApLogonUserEx(IN PLSA_CLIENT_REQUEST ClientRequest,
@@ -1143,5 +1326,6 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
 
     return STATUS_NOT_IMPLEMENTED;
 }
+#endif
 
 /* EOF */