SAM_USER_FIXED_DATA FixedUserData;
PSAM_DB_OBJECT DomainObject;
PSAM_DB_OBJECT UserObject;
+ GROUP_MEMBERSHIP GroupMembership;
UCHAR LogonHours[23];
ULONG ulSize;
ULONG ulRid;
return Status;
}
- /* FIXME: Set Groups attribute*/
+ /* Set Groups attribute*/
+ GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
+ GroupMembership.Attributes = SE_GROUP_MANDATORY |
+ SE_GROUP_ENABLED |
+ SE_GROUP_ENABLED_BY_DEFAULT;
+
+ Status = SampSetObjectAttribute(UserObject,
+ L"Groups",
+ REG_BINARY,
+ &GroupMembership,
+ sizeof(GROUP_MEMBERSHIP));
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
/* Set LMPwd attribute*/
Status = SampSetObjectAttribute(UserObject,
L"LMPwd",
REG_BINARY,
- NULL,
- 0);
+ &EmptyLmHash,
+ sizeof(ENCRYPTED_LM_OWF_PASSWORD));
if (!NT_SUCCESS(Status))
{
TRACE("failed with status 0x%08lx\n", Status);
Status = SampSetObjectAttribute(UserObject,
L"NTPwd",
REG_BINARY,
- NULL,
- 0);
+ &EmptyNtHash,
+ sizeof(ENCRYPTED_NT_OWF_PASSWORD));
if (!NT_SUCCESS(Status))
{
TRACE("failed with status 0x%08lx\n", Status);
}
+static NTSTATUS
+SampSetGroupName(PSAM_DB_OBJECT GroupObject,
+ PSAMPR_GROUP_INFO_BUFFER Buffer)
+{
+ UNICODE_STRING OldGroupName = {0, 0, NULL};
+ UNICODE_STRING NewGroupName;
+ NTSTATUS Status;
+
+ Status = SampGetObjectAttributeString(GroupObject,
+ L"Name",
+ (PRPC_UNICODE_STRING)&OldGroupName);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
+ goto done;
+ }
+
+ NewGroupName.Length = Buffer->Name.Name.Length;
+ NewGroupName.MaximumLength = Buffer->Name.Name.MaximumLength;
+ NewGroupName.Buffer = Buffer->Name.Name.Buffer;
+
+ if (!RtlEqualUnicodeString(&OldGroupName, &NewGroupName, TRUE))
+ {
+ Status = SampCheckAccountNameInDomain(GroupObject->ParentObject,
+ NewGroupName.Buffer);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Group name \'%S\' already exists in domain (Status 0x%08lx)\n",
+ NewGroupName.Buffer, Status);
+ goto done;
+ }
+ }
+
+ Status = SampSetAccountNameInDomain(GroupObject->ParentObject,
+ L"Groups",
+ NewGroupName.Buffer,
+ GroupObject->RelativeId);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
+ goto done;
+ }
+
+ Status = SampRemoveAccountNameFromDomain(GroupObject->ParentObject,
+ L"Groups",
+ OldGroupName.Buffer);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
+ goto done;
+ }
+
+ Status = SampSetObjectAttribute(GroupObject,
+ L"Name",
+ REG_SZ,
+ NewGroupName.Buffer,
+ NewGroupName.Length + sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+ }
+
+done:
+ if (OldGroupName.Buffer != NULL)
+ midl_user_free(OldGroupName.Buffer);
+
+ return Status;
+}
+
+
static NTSTATUS
SampSetGroupAttribute(PSAM_DB_OBJECT GroupObject,
PSAMPR_GROUP_INFO_BUFFER Buffer)
switch (GroupInformationClass)
{
case GroupNameInformation:
- Status = SampSetObjectAttribute(GroupObject,
- L"Name",
- REG_SZ,
- Buffer->Name.Name.Buffer,
- Buffer->Name.Name.Length + sizeof(WCHAR));
+ Status = SampSetGroupName(GroupObject,
+ Buffer);
break;
case GroupAttributeInformation:
}
+static NTSTATUS
+SampSetAliasName(PSAM_DB_OBJECT AliasObject,
+ PSAMPR_ALIAS_INFO_BUFFER Buffer)
+{
+ UNICODE_STRING OldAliasName = {0, 0, NULL};
+ UNICODE_STRING NewAliasName;
+ NTSTATUS Status;
+
+ Status = SampGetObjectAttributeString(AliasObject,
+ L"Name",
+ (PRPC_UNICODE_STRING)&OldAliasName);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
+ goto done;
+ }
+
+ NewAliasName.Length = Buffer->Name.Name.Length;
+ NewAliasName.MaximumLength = Buffer->Name.Name.MaximumLength;
+ NewAliasName.Buffer = Buffer->Name.Name.Buffer;
+
+ if (!RtlEqualUnicodeString(&OldAliasName, &NewAliasName, TRUE))
+ {
+ Status = SampCheckAccountNameInDomain(AliasObject->ParentObject,
+ NewAliasName.Buffer);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("Alias name \'%S\' already exists in domain (Status 0x%08lx)\n",
+ NewAliasName.Buffer, Status);
+ goto done;
+ }
+ }
+
+ Status = SampSetAccountNameInDomain(AliasObject->ParentObject,
+ L"Aliases",
+ NewAliasName.Buffer,
+ AliasObject->RelativeId);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
+ goto done;
+ }
+
+ Status = SampRemoveAccountNameFromDomain(AliasObject->ParentObject,
+ L"Aliases",
+ OldAliasName.Buffer);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
+ goto done;
+ }
+
+ Status = SampSetObjectAttribute(AliasObject,
+ L"Name",
+ REG_SZ,
+ NewAliasName.Buffer,
+ NewAliasName.Length + sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+ }
+
+done:
+ if (OldAliasName.Buffer != NULL)
+ midl_user_free(OldAliasName.Buffer);
+
+ return Status;
+}
+
+
/* Function 29 */
NTSTATUS
NTAPI
switch (AliasInformationClass)
{
case AliasNameInformation:
- Status = SampSetObjectAttribute(AliasObject,
- L"Name",
- REG_SZ,
- Buffer->Name.Name.Buffer,
- Buffer->Name.Name.Length + sizeof(WCHAR));
+ Status = SampSetAliasName(AliasObject,
+ Buffer);
break;
case AliasAdminCommentInformation:
NTSTATUS Status;
/* Validate the alias handle */
- Status = SampValidateDbObject(AliasHandle,
+ Status = SampValidateDbObject(*AliasHandle,
SamDbAliasObject,
DELETE,
&AliasObject);
}
+static NTSTATUS
+SampSetUserName(PSAM_DB_OBJECT UserObject,
+ PRPC_UNICODE_STRING NewUserName)
+{
+ UNICODE_STRING OldUserName = {0, 0, NULL};
+ NTSTATUS Status;
+
+ Status = SampGetObjectAttributeString(UserObject,
+ L"Name",
+ (PRPC_UNICODE_STRING)&OldUserName);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampGetObjectAttributeString failed (Status 0x%08lx)\n", Status);
+ goto done;
+ }
+
+ if (!RtlEqualUnicodeString(&OldUserName, (PCUNICODE_STRING)NewUserName, TRUE))
+ {
+ Status = SampCheckAccountNameInDomain(UserObject->ParentObject,
+ NewUserName->Buffer);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("User name \'%S\' already exists in domain (Status 0x%08lx)\n",
+ NewUserName->Buffer, Status);
+ goto done;
+ }
+ }
+
+ Status = SampSetAccountNameInDomain(UserObject->ParentObject,
+ L"Users",
+ NewUserName->Buffer,
+ UserObject->RelativeId);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampSetAccountNameInDomain failed (Status 0x%08lx)\n", Status);
+ goto done;
+ }
+
+ Status = SampRemoveAccountNameFromDomain(UserObject->ParentObject,
+ L"Users",
+ OldUserName.Buffer);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampRemoveAccountNameFromDomain failed (Status 0x%08lx)\n", Status);
+ goto done;
+ }
+
+ Status = SampSetObjectAttribute(UserObject,
+ L"Name",
+ REG_SZ,
+ NewUserName->Buffer,
+ NewUserName->Length + sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampSetObjectAttribute failed (Status 0x%08lx)\n", Status);
+ }
+
+done:
+ if (OldUserName.Buffer != NULL)
+ midl_user_free(OldUserName.Buffer);
+
+ return Status;
+}
+
+
static NTSTATUS
SampSetUserGeneral(PSAM_DB_OBJECT UserObject,
PSAMPR_USER_INFO_BUFFER Buffer)
if (!NT_SUCCESS(Status))
goto done;
- Status = SampSetObjectAttribute(UserObject,
- L"Name",
- REG_SZ,
- Buffer->General.UserName.Buffer,
- Buffer->General.UserName.MaximumLength);
+ Status = SampSetUserName(UserObject,
+ &Buffer->General.UserName);
if (!NT_SUCCESS(Status))
goto done;
if (WhichFields & USER_ALL_USERNAME)
{
- Status = SampSetObjectAttribute(UserObject,
- L"Name",
- REG_SZ,
- Buffer->All.UserName.Buffer,
- Buffer->All.UserName.MaximumLength);
+ Status = SampSetUserName(UserObject,
+ &Buffer->All.UserName);
if (!NT_SUCCESS(Status))
goto done;
}
break;
case UserNameInformation:
- Status = SampSetObjectAttribute(UserObject,
- L"Name",
- REG_SZ,
- Buffer->Name.UserName.Buffer,
- Buffer->Name.UserName.MaximumLength);
+ Status = SampSetUserName(UserObject,
+ &Buffer->Name.UserName);
if (!NT_SUCCESS(Status))
break;
break;
case UserAccountNameInformation:
- Status = SampSetObjectAttribute(UserObject,
- L"Name",
- REG_SZ,
- Buffer->AccountName.UserName.Buffer,
- Buffer->AccountName.UserName.MaximumLength);
+ Status = SampSetUserName(UserObject,
+ &Buffer->AccountName.UserName);
break;
case UserFullNameInformation:
IN unsigned char LmCrossEncryptionPresent,
IN PENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithNewNt)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ ENCRYPTED_LM_OWF_PASSWORD StoredLmPassword;
+ ENCRYPTED_NT_OWF_PASSWORD StoredNtPassword;
+ PENCRYPTED_LM_OWF_PASSWORD OldLmPassword;
+ 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",
+ UserHandle, LmPresent, OldLmEncryptedWithNewLm, NewLmEncryptedWithOldLm,
+ NtPresent, OldNtEncryptedWithNewNt, NewNtEncryptedWithOldNt, NtCrossEncryptionPresent,
+ NewNtEncryptedWithNewLm, LmCrossEncryptionPresent, NewLmEncryptedWithNewNt);
+
+ /* Validate the user handle */
+ Status = SampValidateDbObject(UserHandle,
+ SamDbUserObject,
+ USER_CHANGE_PASSWORD,
+ &UserObject);
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("SampValidateDbObject failed with status 0x%08lx\n", Status);
+ 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,
+ L"LMPwd",
+ NULL,
+ &StoredLmPassword,
+ &Length);
+ 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 */
+ Length = sizeof(ENCRYPTED_NT_OWF_PASSWORD);
+ Status = SampGetObjectAttribute(UserObject,
+ L"NTPwd",
+ 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 */
+ OldLmPassword = OldLmEncryptedWithNewLm;
+ NewLmPassword = NewLmEncryptedWithOldLm;
+ OldNtPassword = OldNtEncryptedWithNewNt;
+ NewNtPassword = NewNtEncryptedWithOldNt;
+
+ /* Check if the old passwords match the stored ones */
+ if (NtPresent)
+ {
+ if (LmPresent)
+ {
+ if (!RtlEqualMemory(&StoredLmPassword,
+ OldLmPassword,
+ sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
+ {
+ TRACE("Old LM Password does not match!\n");
+ Status = STATUS_WRONG_PASSWORD;
+ }
+ else
+ {
+ if (!RtlEqualMemory(&StoredNtPassword,
+ OldNtPassword,
+ sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
+ {
+ TRACE("Old NT Password does not match!\n");
+ Status = STATUS_WRONG_PASSWORD;
+ }
+ }
+ }
+ else
+ {
+ if (!RtlEqualMemory(&StoredNtPassword,
+ OldNtPassword,
+ sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
+ {
+ TRACE("Old NT Password does not match!\n");
+ Status = STATUS_WRONG_PASSWORD;
+ }
+ }
+ }
+ else
+ {
+ if (LmPresent)
+ {
+ if (!RtlEqualMemory(&StoredLmPassword,
+ OldLmPassword,
+ sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
+ {
+ TRACE("Old LM Password does not match!\n");
+ Status = STATUS_WRONG_PASSWORD;
+ }
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ /* Store the new password hashes */
+ if (NT_SUCCESS(Status))
+ {
+ Status = SampSetUserPassword(UserObject,
+ NewNtPassword,
+ NtPresent,
+ NewLmPassword,
+ LmPresent);
+ if (NT_SUCCESS(Status))
+ {
+ /* Update PasswordLastSet */
+ UserFixedData.PasswordLastSet.QuadPart = SystemTime.QuadPart;
+
+ /* Set the fixed size user data */
+ Length = sizeof(SAM_USER_FIXED_DATA);
+ Status = SampSetObjectAttribute(UserObject,
+ L"F",
+ REG_BINARY,
+ &UserFixedData,
+ Length);
+ }
+ }
+
+ 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);
+ }
+
+ return Status;
}
SAM_USER_FIXED_DATA FixedUserData;
PSAM_DB_OBJECT DomainObject;
PSAM_DB_OBJECT UserObject;
+ GROUP_MEMBERSHIP GroupMembership;
+ UCHAR LogonHours[23];
ULONG ulSize;
ULONG ulRid;
WCHAR szRid[9];
return Status;
}
- /* FIXME: Set LogonHours attribute*/
- /* FIXME: Set Groups attribute*/
+ /* Set LogonHours attribute*/
+ *((PUSHORT)LogonHours) = 168;
+ memset(&(LogonHours[2]), 0xff, 21);
+
+ Status = SampSetObjectAttribute(UserObject,
+ L"LogonHours",
+ REG_BINARY,
+ &LogonHours,
+ sizeof(LogonHours));
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ /* Set Groups attribute*/
+ GroupMembership.RelativeId = DOMAIN_GROUP_RID_USERS;
+ GroupMembership.Attributes = SE_GROUP_MANDATORY |
+ SE_GROUP_ENABLED |
+ SE_GROUP_ENABLED_BY_DEFAULT;
+
+ Status = SampSetObjectAttribute(UserObject,
+ L"Groups",
+ REG_BINARY,
+ &GroupMembership,
+ sizeof(GROUP_MEMBERSHIP));
+ if (!NT_SUCCESS(Status))
+ {
+ TRACE("failed with status 0x%08lx\n", Status);
+ return Status;
+ }
/* Set LMPwd attribute*/
Status = SampSetObjectAttribute(UserObject,
return STATUS_NOT_IMPLEMENTED;
}
+
/* Function 57 */
NTSTATUS
NTAPI
OUT SAMPR_HANDLE *ServerHandle,
IN ACCESS_MASK DesiredAccess)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ TRACE("(%p %p %lx)\n", ServerName, ServerHandle, DesiredAccess);
+
+ return SamrConnect(ServerName,
+ ServerHandle,
+ DesiredAccess);
}