[MSV1_0]
[reactos.git] / reactos / dll / win32 / msv1_0 / msv1_0.c
index 4c080fb..046f48f 100644 (file)
@@ -428,6 +428,31 @@ MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
     PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer;
     ULONG_PTR PtrOffset;
 
+    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;
+
+    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;
+
     TRACE("()\n");
 
     RequestBuffer = (PMSV1_0_CHANGEPASSWORD_REQUEST)ProtocolSubmitBuffer;
@@ -445,8 +470,215 @@ MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
     TRACE("Old Password: %S\n", RequestBuffer->OldPassword.Buffer);
     TRACE("New Password: %S\n", RequestBuffer->NewPassword.Buffer);
 
+    /* Connect to the SAM server */
+    Status = SamIConnect(NULL,
+                         &ServerHandle,
+                         SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
+                         TRUE);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
 
-    return STATUS_SUCCESS;
+    /* 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;
+    }
+
+    /* Open the domain */
+    Status = SamrOpenDomain(ServerHandle,
+                            DOMAIN_LOOKUP,
+                            DomainSid,
+                            &DomainHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SamrOpenDomain failed (Status %08lx)\n", Status);
+        goto done;
+    }
+
+    Names[0].Length = RequestBuffer->AccountName.Length;
+    Names[0].MaximumLength = RequestBuffer->AccountName.MaximumLength;
+    Names[0].Buffer = RequestBuffer->AccountName.Buffer;
+
+    /* Try to get the RID for the user name */
+    Status = SamrLookupNamesInDomain(DomainHandle,
+                                     1,
+                                     Names,
+                                     &RelativeIds,
+                                     &Use);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
+        Status = STATUS_NO_SUCH_USER;
+        goto done;
+    }
+
+    /* 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;
+    }
+
+    /* 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;
+    }
+
+
+    /* 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;
+    }
+
+    /* 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;
+        }
+    }
+
+    /* 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;
+    }
+
+    /* 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;
+    }
+
+    /* 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;
+    }
+
+done:
+    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;
 }
 
 
@@ -734,6 +966,10 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
     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");
@@ -773,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))
     {
@@ -848,11 +1088,8 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
         goto done;
     }
 
-
     TRACE("UserName: %S\n", UserInfo->All.UserName.Buffer);
 
-    /* FIXME: Check restrictions */
-
     /* Check the password */
     if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
     {
@@ -865,6 +1102,65 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
         }
     }
 
+    /* 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 */
 
     /* Create and return a new logon id */
@@ -962,7 +1258,7 @@ done:
         Status = STATUS_LOGON_FAILURE;
     }
 
-    TRACE("LsaApLogonUser done (Status %08lx)\n", Status);
+    TRACE("LsaApLogonUser done (Status 0x%08lx  SubStatus 0x%08lx)\n", Status, *SubStatus);
 
     return Status;
 }