https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f42b4bbe172be699323b3…
commit f42b4bbe172be699323b3b38e3ed43c178fdc662
Author: Eric Kohl <eric.kohl(a)reactos.org>
AuthorDate: Sat May 26 18:42:31 2018 +0200
Commit: Eric Kohl <eric.kohl(a)reactos.org>
CommitDate: Sat May 26 18:43:46 2018 +0200
[MSV1_0] Add logon support for the LocalService and NetworkService accounts
---
dll/win32/msv1_0/msv1_0.c | 386 ++++++++++++++++++++++++++++++----------------
1 file changed, 256 insertions(+), 130 deletions(-)
diff --git a/dll/win32/msv1_0/msv1_0.c b/dll/win32/msv1_0/msv1_0.c
index 624ea2b417..8c9a1b617b 100644
--- a/dll/win32/msv1_0/msv1_0.c
+++ b/dll/win32/msv1_0/msv1_0.c
@@ -22,7 +22,7 @@ LSA_DISPATCH_TABLE DispatchTable;
static
NTSTATUS
-GetDomainSid(PRPC_SID *Sid)
+GetAccountDomainSid(PRPC_SID *Sid)
{
LSAPR_HANDLE PolicyHandle = NULL;
PLSAPR_POLICY_INFORMATION PolicyInfo = NULL;
@@ -69,6 +69,27 @@ done:
}
+static
+NTSTATUS
+GetNtAuthorityDomainSid(PRPC_SID *Sid)
+{
+ SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
+ ULONG Length = 0;
+
+ Length = RtlLengthRequiredSid(0);
+ *Sid = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
+ if (*Sid == NULL)
+ {
+ ERR("Failed to allocate SID\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlInitializeSid(*Sid,&NtAuthority, 0);
+
+ return STATUS_SUCCESS;
+}
+
+
static
NTSTATUS
BuildInteractiveProfileBuffer(IN PLSA_CLIENT_REQUEST ClientRequest,
@@ -287,34 +308,72 @@ BuildTokenPrimaryGroup(OUT PTOKEN_PRIMARY_GROUP PrimaryGroup,
static
NTSTATUS
BuildTokenGroups(OUT PTOKEN_GROUPS *Groups,
- IN PSID AccountDomainSid)
+ IN PSID AccountDomainSid,
+ IN ULONG RelativeId,
+ IN BOOL SpecialAccount)
{
SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
PTOKEN_GROUPS TokenGroups;
-#define MAX_GROUPS 2
DWORD GroupCount = 0;
+ DWORD MaxGroups = 2;
PSID Sid;
NTSTATUS Status = STATUS_SUCCESS;
+ if (SpecialAccount)
+ MaxGroups++;
+
TokenGroups = DispatchTable.AllocateLsaHeap(sizeof(TOKEN_GROUPS) +
- MAX_GROUPS *
sizeof(SID_AND_ATTRIBUTES));
+ MaxGroups * sizeof(SID_AND_ATTRIBUTES));
if (TokenGroups == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
- Sid = AppendRidToSid(AccountDomainSid, DOMAIN_GROUP_RID_USERS);
- if (Sid == NULL)
+ if (SpecialAccount)
{
+ /* Self */
+ Sid = AppendRidToSid(AccountDomainSid, RelativeId);
+ if (Sid == NULL)
+ {
+
+ }
+ TokenGroups->Groups[GroupCount].Sid = Sid;
+ TokenGroups->Groups[GroupCount].Attributes =
+ SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
+ GroupCount++;
+
+ /* Member of 'Users' alias */
+ 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++;
}
+ else
+ {
+ /* Member of the domains users group */
+ Sid = AppendRidToSid(AccountDomainSid, DOMAIN_GROUP_RID_USERS);
+ if (Sid == NULL)
+ {
- /* Member of the domain */
- TokenGroups->Groups[GroupCount].Sid = Sid;
- TokenGroups->Groups[GroupCount].Attributes =
- SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
- GroupCount++;
+ }
+ 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,
@@ -334,7 +393,7 @@ BuildTokenGroups(OUT PTOKEN_GROUPS *Groups,
GroupCount++;
TokenGroups->GroupCount = GroupCount;
- ASSERT(TokenGroups->GroupCount <= MAX_GROUPS);
+ ASSERT(TokenGroups->GroupCount <= MaxGroups);
*Groups = TokenGroups;
@@ -346,7 +405,8 @@ static
NTSTATUS
BuildTokenInformationBuffer(PLSA_TOKEN_INFORMATION_V1 *TokenInformation,
PRPC_SID AccountDomainSid,
- PSAMPR_USER_INFO_BUFFER UserInfo)
+ PSAMPR_USER_INFO_BUFFER UserInfo,
+ BOOL SpecialAccount)
{
PLSA_TOKEN_INFORMATION_V1 Buffer = NULL;
ULONG i;
@@ -376,7 +436,9 @@ BuildTokenInformationBuffer(PLSA_TOKEN_INFORMATION_V1
*TokenInformation,
goto done;
Status = BuildTokenGroups(&Buffer->Groups,
- (PSID)AccountDomainSid);
+ (PSID)AccountDomainSid,
+ UserInfo->All.UserId,
+ SpecialAccount);
if (!NT_SUCCESS(Status))
goto done;
@@ -970,9 +1032,10 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
// LARGE_INTEGER AccountExpires;
LARGE_INTEGER PasswordMustChange;
LARGE_INTEGER PasswordLastSet;
+ BOOL SpecialAccount = FALSE;
NTSTATUS Status;
- TRACE("()\n");
+ TRACE("LsaApLogonUser()\n");
TRACE("LogonType: %lu\n", LogonType);
TRACE("AuthenticationInformation: %p\n", AuthenticationInformation);
@@ -1012,153 +1075,215 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
/* Get the logon time */
NtQuerySystemTime(&LogonTime);
- /* Get the domain SID */
- Status = GetDomainSid(&AccountDomainSid);
- if (!NT_SUCCESS(Status))
- {
- TRACE("GetDomainSid() failed (Status 0x%08lx)\n", Status);
- return Status;
- }
-
- /* Connect to the SAM server */
- Status = SamIConnect(NULL,
- &ServerHandle,
- SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
- TRUE);
- if (!NT_SUCCESS(Status))
+ /* Check for special accounts */
+ if (_wcsicmp(LogonInfo->LogonDomainName.Buffer, L"NT AUTHORITY") == 0)
{
- TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
- goto done;
- }
+ SpecialAccount = TRUE;
- /* Open the account domain */
- Status = SamrOpenDomain(ServerHandle,
- DOMAIN_LOOKUP,
- AccountDomainSid,
- &DomainHandle);
- if (!NT_SUCCESS(Status))
- {
- TRACE("SamrOpenDomain failed (Status %08lx)\n", Status);
- goto done;
- }
+ /* Get the authority domain SID */
+ Status = GetNtAuthorityDomainSid(&AccountDomainSid);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("GetNtAuthorityDomainSid() failed (Status 0x%08lx)\n",
Status);
+ return Status;
+ }
- Names[0].Length = LogonInfo->UserName.Length;
- Names[0].MaximumLength = LogonInfo->UserName.MaximumLength;
- Names[0].Buffer = LogonInfo->UserName.Buffer;
+ if (_wcsicmp(LogonInfo->UserName.Buffer, L"LocalService") == 0)
+ {
+ TRACE("SpecialAccount: LocalService\n");
- /* 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;
- }
+ if (LogonType != Service)
+ return STATUS_LOGON_FAILURE;
- /* 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;
- }
+ UserInfo = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(SAMPR_USER_ALL_INFORMATION));
+ if (UserInfo == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
- /* Open the user object */
- Status = SamrOpenUser(DomainHandle,
- USER_READ_GENERAL | USER_READ_LOGON |
- USER_READ_ACCOUNT | USER_READ_PREFERENCES, /* FIXME */
- RelativeIds.Element[0],
- &UserHandle);
- if (!NT_SUCCESS(Status))
- {
- TRACE("SamrOpenUser failed (Status %08lx)\n", Status);
- goto done;
- }
+ UserInfo->All.UserId = SECURITY_LOCAL_SERVICE_RID;
+ UserInfo->All.PrimaryGroupId = SECURITY_LOCAL_SERVICE_RID;
+ }
+ else if (_wcsicmp(LogonInfo->UserName.Buffer, L"NetworkService") ==
0)
+ {
+ TRACE("SpecialAccount: NetworkService\n");
- Status = SamrQueryInformationUser(UserHandle,
- UserAllInformation,
- &UserInfo);
- if (!NT_SUCCESS(Status))
- {
- TRACE("SamrQueryInformationUser failed (Status %08lx)\n", Status);
- goto done;
- }
+ if (LogonType != Service)
+ return STATUS_LOGON_FAILURE;
- TRACE("UserName: %S\n", UserInfo->All.UserName.Buffer);
+ UserInfo = RtlAllocateHeap(RtlGetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(SAMPR_USER_ALL_INFORMATION));
+ if (UserInfo == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
- /* Check the password */
- if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
- {
- Status = MsvpCheckPassword(&(LogonInfo->Password),
- UserInfo);
- if (!NT_SUCCESS(Status))
+ UserInfo->All.UserId = SECURITY_NETWORK_SERVICE_RID;
+ UserInfo->All.PrimaryGroupId = SECURITY_NETWORK_SERVICE_RID;
+ }
+ else
{
- TRACE("MsvpCheckPassword failed (Status %08lx)\n", Status);
+ Status = STATUS_NO_SUCH_USER;
goto done;
}
}
-
- /* Check account restrictions for non-administrator accounts */
- if (RelativeIds.Element[0] != DOMAIN_USER_RID_ADMIN)
+ else
{
- /* Check if the account has been disabled */
- if (UserInfo->All.UserAccountControl & USER_ACCOUNT_DISABLED)
+ TRACE("NormalAccount\n");
+
+ /* Get the account domain SID */
+ Status = GetAccountDomainSid(&AccountDomainSid);
+ if (!NT_SUCCESS(Status))
{
- ERR("Account disabled!\n");
- *SubStatus = STATUS_ACCOUNT_DISABLED;
- Status = STATUS_ACCOUNT_RESTRICTION;
+ ERR("GetAccountDomainSid() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+
+ /* 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;
}
- /* Check if the account has been locked */
- if (UserInfo->All.UserAccountControl & USER_ACCOUNT_AUTO_LOCKED)
+ /* Open the account domain */
+ Status = SamrOpenDomain(ServerHandle,
+ DOMAIN_LOOKUP,
+ AccountDomainSid,
+ &DomainHandle);
+ if (!NT_SUCCESS(Status))
{
- ERR("Account locked!\n");
- *SubStatus = STATUS_ACCOUNT_LOCKED_OUT;
- Status = STATUS_ACCOUNT_RESTRICTION;
+ ERR("SamrOpenDomain failed (Status %08lx)\n", Status);
goto done;
}
-#if 0
- /* Check if the account expired */
- AccountExpires.LowPart = UserInfo->All.AccountExpires.LowPart;
- AccountExpires.HighPart = UserInfo->All.AccountExpires.HighPart;
+ Names[0].Length = LogonInfo->UserName.Length;
+ Names[0].MaximumLength = LogonInfo->UserName.MaximumLength;
+ Names[0].Buffer = LogonInfo->UserName.Buffer;
- if (AccountExpires.QuadPart != 0 &&
- LogonTime.QuadPart >= AccountExpires.QuadPart)
+ /* Try to get the RID for the user name */
+ Status = SamrLookupNamesInDomain(DomainHandle,
+ 1,
+ Names,
+ &RelativeIds,
+ &Use);
+ if (!NT_SUCCESS(Status))
{
- ERR("Account expired!\n");
- *SubStatus = STATUS_ACCOUNT_EXPIRED;
- Status = STATUS_ACCOUNT_RESTRICTION;
+ ERR("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
+ Status = STATUS_NO_SUCH_USER;
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;
+ /* Fail, if it is not a user account */
+ if (Use.Element[0] != SidTypeUser)
+ {
+ ERR("Account is not a user account!\n");
+ Status = STATUS_NO_SUCH_USER;
+ goto done;
+ }
- if (LogonTime.QuadPart >= PasswordMustChange.QuadPart)
+ /* Open the user object */
+ Status = SamrOpenUser(DomainHandle,
+ USER_READ_GENERAL | USER_READ_LOGON |
+ USER_READ_ACCOUNT | USER_READ_PREFERENCES, /* FIXME */
+ RelativeIds.Element[0],
+ &UserHandle);
+ if (!NT_SUCCESS(Status))
{
- ERR("Password expired!\n");
- if (PasswordLastSet.QuadPart == 0)
- *SubStatus = STATUS_PASSWORD_MUST_CHANGE;
- else
- *SubStatus = STATUS_PASSWORD_EXPIRED;
+ ERR("SamrOpenUser failed (Status %08lx)\n", Status);
+ goto done;
+ }
- Status = STATUS_ACCOUNT_RESTRICTION;
+ Status = SamrQueryInformationUser(UserHandle,
+ UserAllInformation,
+ &UserInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("SamrQueryInformationUser failed (Status %08lx)\n", Status);
goto done;
}
- /* FIXME: more checks */
- // STATUS_INVALID_LOGON_HOURS;
- // STATUS_INVALID_WORKSTATION;
+ TRACE("UserName: %S\n", UserInfo->All.UserName.Buffer);
+
+ /* Check the password */
+ if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
+ {
+ Status = MsvpCheckPassword(&(LogonInfo->Password),
+ UserInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("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 */
@@ -1199,7 +1324,8 @@ LsaApLogonUser(IN PLSA_CLIENT_REQUEST ClientRequest,
/* Build and fill the token information buffer */
Status = BuildTokenInformationBuffer((PLSA_TOKEN_INFORMATION_V1*)TokenInformation,
AccountDomainSid,
- UserInfo);
+ UserInfo,
+ SpecialAccount);
if (!NT_SUCCESS(Status))
{
TRACE("BuildTokenInformationBuffer failed (Status %08lx)\n", Status);