[SAMSRV]
[reactos.git] / reactos / dll / win32 / samsrv / samrpc.c
index b571fa9..385187c 100644 (file)
@@ -7475,8 +7475,15 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
     PENCRYPTED_LM_OWF_PASSWORD NewLmPassword;
     PENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
     PENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
+    BOOLEAN StoredLmPresent = FALSE;
+    BOOLEAN StoredNtPresent = FALSE;
+    BOOLEAN StoredLmEmpty = TRUE;
+    BOOLEAN StoredNtEmpty = TRUE;
     PSAM_DB_OBJECT UserObject;
     ULONG Length;
+    SAM_USER_FIXED_DATA UserFixedData;
+    SAM_DOMAIN_FIXED_DATA DomainFixedData;
+    LARGE_INTEGER SystemTime;
     NTSTATUS Status;
 
     TRACE("(%p %u %p %p %u %p %p %u %p %u %p)\n",
@@ -7495,6 +7502,14 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
         return Status;
     }
 
+    /* Get the current time */
+    Status = NtQuerySystemTime(&SystemTime);
+    if (!NT_SUCCESS(Status))
+    {
+        TRACE("NtQuerySystemTime failed (Status 0x%08lx)\n", Status);
+        return Status;
+    }
+
     /* Retrieve the LM password */
     Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
     Status = SampGetObjectAttribute(UserObject,
@@ -7502,9 +7517,16 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
                                     NULL,
                                     &StoredLmPassword,
                                     &Length);
-    if (!NT_SUCCESS(Status))
+    if (NT_SUCCESS(Status))
     {
-
+        if (Length == sizeof(ENCRYPTED_LM_OWF_PASSWORD))
+        {
+            StoredLmPresent = TRUE;
+            if (!RtlEqualMemory(&StoredLmPassword,
+                                &EmptyLmHash,
+                                sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
+                StoredLmEmpty = FALSE;
+        }
     }
 
     /* Retrieve the NT password */
@@ -7514,9 +7536,52 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
                                     NULL,
                                     &StoredNtPassword,
                                     &Length);
+    if (NT_SUCCESS(Status))
+    {
+        if (Length == sizeof(ENCRYPTED_NT_OWF_PASSWORD))
+        {
+            StoredNtPresent = TRUE;
+            if (!RtlEqualMemory(&StoredNtPassword,
+                                &EmptyNtHash,
+                                sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
+                StoredNtEmpty = FALSE;
+        }
+    }
+
+    /* Retrieve the fixed size user data */
+    Length = sizeof(SAM_USER_FIXED_DATA);
+    Status = SampGetObjectAttribute(UserObject,
+                                    L"F",
+                                    NULL,
+                                    &UserFixedData,
+                                    &Length);
     if (!NT_SUCCESS(Status))
     {
+        TRACE("SampGetObjectAttribute failed to retrieve the fixed user data (Status 0x%08lx)\n", Status);
+        return Status;
+    }
 
+    /* Check if we can change the password at this time */
+    if ((StoredNtEmpty == FALSE) || (StoredNtEmpty == FALSE))
+    {
+        /* Get fixed domain data */
+        Length = sizeof(SAM_DOMAIN_FIXED_DATA);
+        Status = SampGetObjectAttribute(UserObject->ParentObject,
+                                        L"F",
+                                        NULL,
+                                        &DomainFixedData,
+                                        &Length);
+        if (!NT_SUCCESS(Status))
+        {
+            TRACE("SampGetObjectAttribute failed to retrieve the fixed domain data (Status 0x%08lx)\n", Status);
+            return Status;
+        }
+
+        if (DomainFixedData.MinPasswordAge.QuadPart > 0)
+        {
+            if (SystemTime.QuadPart < (UserFixedData.PasswordLastSet.QuadPart + DomainFixedData.MinPasswordAge.QuadPart))
+                return STATUS_ACCOUNT_RESTRICTION;
+        }
     }
 
     /* FIXME: Decrypt passwords */
@@ -7577,41 +7642,44 @@ SamrChangePasswordUser(IN SAMPR_HANDLE UserHandle,
         }
     }
 
-    /* Store the new LM password */
+    /* Store the new password hashes */
     if (NT_SUCCESS(Status))
     {
-        if (LmPresent)
+        Status = SampSetUserPassword(UserObject,
+                                     NewNtPassword,
+                                     NtPresent,
+                                     NewLmPassword,
+                                     LmPresent);
+        if (NT_SUCCESS(Status))
         {
-            Length = sizeof(ENCRYPTED_LM_OWF_PASSWORD);
-            Status = SampSetObjectAttribute(UserObject,
-                                            L"LMPwd",
-                                            REG_BINARY,
-                                            NewLmPassword,
-                                            Length);
-            if (!NT_SUCCESS(Status))
-            {
-                goto done;
-            }
-        }
+            /* Update PasswordLastSet */
+            UserFixedData.PasswordLastSet.QuadPart = SystemTime.QuadPart;
 
-        /* Store the new NT password */
-        if (NtPresent)
-        {
-            Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
+            /* Set the fixed size user data */
+            Length = sizeof(SAM_USER_FIXED_DATA);
             Status = SampSetObjectAttribute(UserObject,
-                                            L"NTPwd",
+                                            L"F",
                                             REG_BINARY,
-                                            NewNtPassword,
+                                            &UserFixedData,
                                             Length);
-            if (!NT_SUCCESS(Status))
-            {
-                goto done;
-            }
         }
     }
 
+    if (Status == STATUS_WRONG_PASSWORD)
+    {
+        /* Update BadPasswordCount and LastBadPasswordTime */
+        UserFixedData.BadPasswordCount++;
+        UserFixedData.LastBadPasswordTime.QuadPart = SystemTime.QuadPart;
+
+        /* Set the fixed size user data */
+        Length = sizeof(SAM_USER_FIXED_DATA);
+        Status = SampSetObjectAttribute(UserObject,
+                                        L"F",
+                                        REG_BINARY,
+                                        &UserFixedData,
+                                        Length);
+    }
 
-done:
     return Status;
 }