if (User->User.Sid == NULL)
{
ERR("Could not create the user SID\n");
- return STATUS_UNSUCCESSFUL;
+ return STATUS_INSUFFICIENT_RESOURCES;
}
User->User.Attributes = 0;
static
NTSTATUS
-BuildTokenGroups(IN PSID AccountDomainSid,
- IN PLUID LogonId,
- OUT PTOKEN_GROUPS *Groups,
- OUT PSID *PrimaryGroupSid)
+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 SystemAuthority = {SECURITY_NT_AUTHORITY};
PTOKEN_GROUPS TokenGroups;
-#define MAX_GROUPS 4
+#define MAX_GROUPS 2
DWORD GroupCount = 0;
PSID Sid;
NTSTATUS Status = STATUS_SUCCESS;
/* Member of the domain */
TokenGroups->Groups[GroupCount].Sid = Sid;
- TokenGroups->Groups[GroupCount].Attributes =
- SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
- *PrimaryGroupSid = Sid;
- 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++;
}
-static
-NTSTATUS
-BuildTokenPrimaryGroup(PTOKEN_PRIMARY_GROUP PrimaryGroup,
- PSID PrimaryGroupSid)
-{
- ULONG RidCount;
- ULONG Size;
-
- RidCount = *RtlSubAuthorityCountSid(PrimaryGroupSid);
- Size = RtlLengthRequiredSid(RidCount);
-
- PrimaryGroup->PrimaryGroup = DispatchTable.AllocateLsaHeap(Size);
- if (PrimaryGroup->PrimaryGroup == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- RtlCopyMemory(PrimaryGroup->PrimaryGroup,
- PrimaryGroupSid,
- Size);
-
- return STATUS_SUCCESS;
-}
-
-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 = LsaIOpenPolicyTrusted(&PolicyHandle);
- 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;
- 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;
-
- Status = LsarLookupPrivilegeValue(PolicyHandle,
- &PrivilegeName,
- &Privileges->Privileges[Privileges->PrivilegeCount].Luid);
- if (!NT_SUCCESS(Status))
- {
- WARN("Can't set privilege %S\n", DefaultPrivs[i].PrivName);
- }
- else
- {
- Privileges->Privileges[Privileges->PrivilegeCount].Attributes = DefaultPrivs[i].Attributes;
- Privileges->PrivilegeCount++;
- }
- }
-
- *TokenPrivileges = Privileges;
-
-done:
- if (PolicyHandle != NULL)
- LsarClose(&PolicyHandle);
-
- return Status;
-}
-
-
static
NTSTATUS
BuildTokenInformationBuffer(PLSA_TOKEN_INFORMATION_V1 *TokenInformation,
PRPC_SID AccountDomainSid,
- ULONG RelativeId,
- PLUID LogonId)
+ PSAMPR_USER_INFO_BUFFER UserInfo)
{
PLSA_TOKEN_INFORMATION_V1 Buffer = NULL;
- PSID PrimaryGroupSid = NULL;
ULONG i;
NTSTATUS Status = STATUS_SUCCESS;
Status = BuildTokenUser(&Buffer->User,
(PSID)AccountDomainSid,
- RelativeId);
- if (!NT_SUCCESS(Status))
- goto done;
-
- Status = BuildTokenGroups((PSID)AccountDomainSid,
- LogonId,
- &Buffer->Groups,
- &PrimaryGroupSid);
+ UserInfo->All.UserId);
if (!NT_SUCCESS(Status))
goto done;
Status = BuildTokenPrimaryGroup(&Buffer->PrimaryGroup,
- PrimaryGroupSid);
+ (PSID)AccountDomainSid,
+ UserInfo->All.PrimaryGroupId);
if (!NT_SUCCESS(Status))
goto done;
- Status = BuildTokenPrivileges(&Buffer->Privileges);
+ Status = BuildTokenGroups(&Buffer->Groups,
+ (PSID)AccountDomainSid);
if (!NT_SUCCESS(Status))
goto done;
if (Buffer->PrimaryGroup.PrimaryGroup != NULL)
DispatchTable.FreeLsaHeap(Buffer->PrimaryGroup.PrimaryGroup);
- if (Buffer->Privileges != NULL)
- DispatchTable.FreeLsaHeap(Buffer->Privileges);
-
if (Buffer->DefaultDacl.DefaultDacl != NULL)
DispatchTable.FreeLsaHeap(Buffer->DefaultDacl.DefaultDacl);
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;
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;
}
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");
return STATUS_NOT_IMPLEMENTED;
}
+ /* Get the logon time */
+ NtQuerySystemTime(&LogonTime);
+
+ /* Get the domain SID */
Status = GetDomainSid(&AccountDomainSid);
if (!NT_SUCCESS(Status))
{
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)
{
}
}
+ /* 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 */
/* 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);
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;
}