[MSV1_0] Check logon hours and workstation names on logon. Also return the machine...
authorEric Kohl <eric.kohl@reactos.org>
Mon, 4 Mar 2019 16:25:11 +0000 (17:25 +0100)
committerEric Kohl <eric.kohl@reactos.org>
Mon, 4 Mar 2019 16:26:27 +0000 (17:26 +0100)
dll/win32/msv1_0/msv1_0.c

index 9ff2b92..6529cd0 100644 (file)
@@ -94,7 +94,7 @@ static
 NTSTATUS
 BuildInteractiveProfileBuffer(IN PLSA_CLIENT_REQUEST ClientRequest,
                               IN PSAMPR_USER_INFO_BUFFER UserInfo,
-                              IN PUNICODE_STRING LogonServer,
+                              IN PWSTR ComputerName,
                               OUT PMSV1_0_INTERACTIVE_PROFILE *ProfileBuffer,
                               OUT PULONG ProfileBufferLength)
 {
@@ -113,7 +113,7 @@ BuildInteractiveProfileBuffer(IN PLSA_CLIENT_REQUEST ClientRequest,
                    UserInfo->All.HomeDirectoryDrive.Length + sizeof(WCHAR) +
                    UserInfo->All.ScriptPath.Length + sizeof(WCHAR) +
                    UserInfo->All.ProfilePath.Length + sizeof(WCHAR) +
-                   LogonServer->Length + sizeof(WCHAR);
+                   ((wcslen(ComputerName) + 3) * sizeof(WCHAR));
 
     LocalBuffer = DispatchTable.AllocateLsaHeap(BufferLength);
     if (LocalBuffer == NULL)
@@ -204,12 +204,11 @@ BuildInteractiveProfileBuffer(IN PLSA_CLIENT_REQUEST ClientRequest,
 
     Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->HomeDirectoryDrive.MaximumLength);
 
-    LocalBuffer->LogonServer.Length = LogonServer->Length;
-    LocalBuffer->LogonServer.MaximumLength = LogonServer->Length + sizeof(WCHAR);
+    LocalBuffer->LogonServer.Length = (wcslen(ComputerName) + 2) * sizeof(WCHAR);
+    LocalBuffer->LogonServer.MaximumLength = LocalBuffer->LogonServer.Length + sizeof(WCHAR);
     LocalBuffer->LogonServer.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer);
-    memcpy(Ptr,
-           LogonServer->Buffer,
-           LogonServer->Length);
+    wcscpy(Ptr, L"\\");
+    wcscat(Ptr, ComputerName);
 
     LocalBuffer->UserFlags = 0;
 
@@ -844,6 +843,73 @@ done:
 }
 
 
+static
+BOOL
+MsvpCheckLogonHours(
+    _In_ PSAMPR_LOGON_HOURS LogonHours,
+    _In_ PLARGE_INTEGER LogonTime)
+{
+    LARGE_INTEGER LocalLogonTime;
+    TIME_FIELDS TimeFields;
+    USHORT MinutesPerUnit, Offset;
+
+    TRACE("MsvpCheckLogonHours(%p %p)\n", LogonHours, LogonTime);
+
+    if (LogonHours->UnitsPerWeek == 0 || LogonHours->LogonHours == NULL)
+        return TRUE;
+
+    RtlSystemTimeToLocalTime(LogonTime, &LocalLogonTime);
+    RtlTimeToTimeFields(&LocalLogonTime, &TimeFields);
+
+    TRACE("UnitsPerWeek: %u\n", LogonHours->UnitsPerWeek);
+    MinutesPerUnit = 10080 / LogonHours->UnitsPerWeek;
+
+    Offset = ((TimeFields.Weekday * 24 + TimeFields.Hour) * 60 + TimeFields.Minute) / MinutesPerUnit;
+
+    return (BOOL)(LogonHours->LogonHours[Offset / 8] & (1 << (Offset % 8)));
+}
+
+
+static
+BOOL
+MsvpCheckWorkstations(
+    _In_ PRPC_UNICODE_STRING WorkStations,
+    _In_ PWSTR ComputerName)
+{
+    PWSTR pStart, pEnd;
+    BOOL bFound = FALSE;
+
+    TRACE("MsvpCheckWorkstations(%wZ %S)\n", WorkStations, ComputerName);
+
+    if (WorkStations->Length == 0 || WorkStations->Buffer == NULL)
+        return TRUE;
+
+    pStart = WorkStations->Buffer;
+    for (;;)
+    {
+        pEnd = wcschr(pStart, L',');
+        if (pEnd != NULL)
+            *pEnd = UNICODE_NULL;
+
+        if (_wcsicmp(ComputerName, pStart) == 0)
+        {
+            bFound = TRUE;
+            if (pEnd != NULL)
+                *pEnd = L',';
+            break;
+        }
+
+        if (pEnd == NULL)
+            break;
+
+        *pEnd = L',';
+        pStart = pEnd + 1;
+    }
+
+    return bFound;
+}
+
+
 /*
  * @unimplemented
  */
@@ -944,7 +1010,7 @@ LsaApCallPackageUntrusted(IN PLSA_CLIENT_REQUEST ClientRequest,
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 NTAPI
@@ -1008,7 +1074,7 @@ LsaApLogonTerminated(IN PLUID LogonId)
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 NTAPI
@@ -1026,11 +1092,11 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
                   OUT PUNICODE_STRING *AccountName,
                   OUT PUNICODE_STRING *AuthenticatingAuthority,
                   OUT PUNICODE_STRING *MachineName,
-                  OUT PSECPKG_PRIMARY_CRED PrimaryCredentials,
-                  OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY *SupplementalCredentials)
+                  OUT PSECPKG_PRIMARY_CRED PrimaryCredentials, /* Not supported yet */
+                  OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY *SupplementalCredentials) /* Not supported yet */
 {
     PMSV1_0_INTERACTIVE_LOGON LogonInfo;
-
+    WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
     SAMPR_HANDLE ServerHandle = NULL;
     SAMPR_HANDLE DomainHandle = NULL;
     SAMPR_HANDLE UserHandle = NULL;
@@ -1039,12 +1105,12 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
     SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
     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;
+    DWORD ComputerNameSize;
     BOOL SpecialAccount = FALSE;
     NTSTATUS Status;
 
@@ -1078,8 +1144,6 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
         TRACE("Domain: %S\n", LogonInfo->LogonDomainName.Buffer);
         TRACE("User: %S\n", LogonInfo->UserName.Buffer);
         TRACE("Password: %S\n", LogonInfo->Password.Buffer);
-
-        RtlInitUnicodeString(&LogonServer, L"Testserver");
     }
     else
     {
@@ -1090,6 +1154,10 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
     /* Get the logon time */
     NtQuerySystemTime(&LogonTime);
 
+    /* Get the computer name */
+    ComputerNameSize = MAX_COMPUTERNAME_LENGTH + 1;
+    GetComputerNameW(ComputerName, &ComputerNameSize);
+
     /* Check for special accounts */
     if (_wcsicmp(LogonInfo->LogonDomainName.Buffer, L"NT AUTHORITY") == 0)
     {
@@ -1291,9 +1359,23 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
                 goto done;
             }
 
-            /* FIXME: more checks */
-            // STATUS_INVALID_LOGON_HOURS;
-            // STATUS_INVALID_WORKSTATION;
+            /* Check logon hours */
+            if (!MsvpCheckLogonHours(&UserInfo->All.LogonHours, &LogonTime))
+            {
+                ERR("Invalid logon hours!\n");
+                *SubStatus = STATUS_INVALID_LOGON_HOURS;
+                Status = STATUS_ACCOUNT_RESTRICTION;
+                goto done;
+            }
+
+            /* Check workstations */
+            if (!MsvpCheckWorkstations(&UserInfo->All.WorkStations, ComputerName))
+            {
+                ERR("Invalid workstation!\n");
+                *SubStatus = STATUS_INVALID_WORKSTATION;
+                Status = STATUS_ACCOUNT_RESTRICTION;
+                goto done;
+            }
         }
     }
 
@@ -1320,7 +1402,7 @@ LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
     /* Build and fill the interactive profile buffer */
     Status = BuildInteractiveProfileBuffer(ClientRequest,
                                            UserInfo,
-                                           &LogonServer,
+                                           ComputerName,
                                            (PMSV1_0_INTERACTIVE_PROFILE*)ProfileBuffer,
                                            ProfileBufferSize);
     if (!NT_SUCCESS(Status))
@@ -1390,6 +1472,19 @@ done:
         }
     }
 
+    /* Return the machine name */
+    *MachineName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
+    if (*MachineName != NULL)
+    {
+        (*MachineName)->Buffer = DispatchTable.AllocateLsaHeap((ComputerNameSize + 1) * sizeof(WCHAR));
+        if ((*MachineName)->Buffer != NULL)
+        {
+            (*MachineName)->MaximumLength = (ComputerNameSize + 1) * sizeof(WCHAR);
+            (*MachineName)->Length = ComputerNameSize * sizeof(WCHAR);
+            RtlCopyMemory((*MachineName)->Buffer, ComputerName, (*MachineName)->MaximumLength);
+        }
+    }
+
     if (!NT_SUCCESS(Status))
     {
         if (SessionCreated != FALSE)