mirror of
https://github.com/reactos/reactos.git
synced 2024-08-21 19:03:01 +00:00
731 lines
20 KiB
C
731 lines
20 KiB
C
/*
|
|
* PROJECT: Local Security Authority Server DLL
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: dll/win32/samsrv/user.c
|
|
* PURPOSE: User specific helper functions
|
|
* COPYRIGHT: Copyright 2013 Eric Kohl
|
|
*/
|
|
|
|
#include "samsrv.h"
|
|
|
|
/* FUNCTIONS ***************************************************************/
|
|
|
|
NTSTATUS
|
|
SampOpenUserObject(IN PSAM_DB_OBJECT DomainObject,
|
|
IN ULONG UserId,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
OUT PSAM_DB_OBJECT *UserObject)
|
|
{
|
|
WCHAR szRid[9];
|
|
|
|
TRACE("(%p %lu %lx %p)\n",
|
|
DomainObject, UserId, DesiredAccess, UserObject);
|
|
|
|
/* Convert the RID into a string (hex) */
|
|
swprintf(szRid, L"%08lX", UserId);
|
|
|
|
/* Create the user object */
|
|
return SampOpenDbObject(DomainObject,
|
|
L"Users",
|
|
szRid,
|
|
UserId,
|
|
SamDbUserObject,
|
|
DesiredAccess,
|
|
UserObject);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampAddGroupMembershipToUser(IN PSAM_DB_OBJECT UserObject,
|
|
IN ULONG GroupId,
|
|
IN ULONG Attributes)
|
|
{
|
|
PGROUP_MEMBERSHIP GroupsBuffer = NULL;
|
|
ULONG GroupsCount = 0;
|
|
ULONG Length = 0;
|
|
ULONG i;
|
|
NTSTATUS Status;
|
|
|
|
TRACE("(%p %lu %lx)\n",
|
|
UserObject, GroupId, Attributes);
|
|
|
|
Status = SampGetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
NULL,
|
|
NULL,
|
|
&Length);
|
|
if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
|
|
goto done;
|
|
|
|
GroupsBuffer = midl_user_allocate(Length + sizeof(GROUP_MEMBERSHIP));
|
|
if (GroupsBuffer == NULL)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
|
|
{
|
|
Status = SampGetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
NULL,
|
|
GroupsBuffer,
|
|
&Length);
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
|
|
GroupsCount = Length / sizeof(GROUP_MEMBERSHIP);
|
|
}
|
|
|
|
for (i = 0; i < GroupsCount; i++)
|
|
{
|
|
if (GroupsBuffer[i].RelativeId == GroupId)
|
|
{
|
|
Status = STATUS_MEMBER_IN_GROUP;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
GroupsBuffer[GroupsCount].RelativeId = GroupId;
|
|
GroupsBuffer[GroupsCount].Attributes = Attributes;
|
|
Length += sizeof(GROUP_MEMBERSHIP);
|
|
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
REG_BINARY,
|
|
GroupsBuffer,
|
|
Length);
|
|
|
|
done:
|
|
if (GroupsBuffer != NULL)
|
|
midl_user_free(GroupsBuffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampRemoveGroupMembershipFromUser(IN PSAM_DB_OBJECT UserObject,
|
|
IN ULONG GroupId)
|
|
{
|
|
PGROUP_MEMBERSHIP GroupsBuffer = NULL;
|
|
ULONG GroupsCount = 0;
|
|
ULONG Length = 0;
|
|
ULONG i;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
TRACE("(%p %lu)\n",
|
|
UserObject, GroupId);
|
|
|
|
SampGetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
NULL,
|
|
NULL,
|
|
&Length);
|
|
|
|
if (Length == 0)
|
|
return STATUS_MEMBER_NOT_IN_GROUP;
|
|
|
|
GroupsBuffer = midl_user_allocate(Length);
|
|
if (GroupsBuffer == NULL)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
Status = SampGetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
NULL,
|
|
GroupsBuffer,
|
|
&Length);
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
|
|
Status = STATUS_MEMBER_NOT_IN_GROUP;
|
|
|
|
GroupsCount = Length / sizeof(GROUP_MEMBERSHIP);
|
|
for (i = 0; i < GroupsCount; i++)
|
|
{
|
|
if (GroupsBuffer[i].RelativeId == GroupId)
|
|
{
|
|
Length -= sizeof(GROUP_MEMBERSHIP);
|
|
Status = STATUS_SUCCESS;
|
|
|
|
if (GroupsCount - i - 1 > 0)
|
|
{
|
|
CopyMemory(&GroupsBuffer[i],
|
|
&GroupsBuffer[i + 1],
|
|
(GroupsCount - i - 1) * sizeof(GROUP_MEMBERSHIP));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
REG_BINARY,
|
|
GroupsBuffer,
|
|
Length);
|
|
|
|
done:
|
|
if (GroupsBuffer != NULL)
|
|
midl_user_free(GroupsBuffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampGetUserGroupAttributes(IN PSAM_DB_OBJECT DomainObject,
|
|
IN ULONG UserId,
|
|
IN ULONG GroupId,
|
|
OUT PULONG GroupAttributes)
|
|
{
|
|
PSAM_DB_OBJECT UserObject = NULL;
|
|
PGROUP_MEMBERSHIP GroupsBuffer = NULL;
|
|
ULONG Length = 0;
|
|
ULONG i;
|
|
NTSTATUS Status;
|
|
|
|
Status = SampOpenUserObject(DomainObject,
|
|
UserId,
|
|
0,
|
|
&UserObject);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
SampGetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
NULL,
|
|
NULL,
|
|
&Length);
|
|
|
|
if (Length == 0)
|
|
return STATUS_UNSUCCESSFUL; /* FIXME */
|
|
|
|
GroupsBuffer = midl_user_allocate(Length);
|
|
if (GroupsBuffer == NULL)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
Status = SampGetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
NULL,
|
|
GroupsBuffer,
|
|
&Length);
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
|
|
for (i = 0; i < (Length / sizeof(GROUP_MEMBERSHIP)); i++)
|
|
{
|
|
if (GroupsBuffer[i].RelativeId == GroupId)
|
|
{
|
|
*GroupAttributes = GroupsBuffer[i].Attributes;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (GroupsBuffer != NULL)
|
|
midl_user_free(GroupsBuffer);
|
|
|
|
if (UserObject != NULL)
|
|
SampCloseDbObject(UserObject);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampSetUserGroupAttributes(IN PSAM_DB_OBJECT DomainObject,
|
|
IN ULONG UserId,
|
|
IN ULONG GroupId,
|
|
IN ULONG GroupAttributes)
|
|
{
|
|
PSAM_DB_OBJECT UserObject = NULL;
|
|
PGROUP_MEMBERSHIP GroupsBuffer = NULL;
|
|
ULONG Length = 0;
|
|
ULONG i;
|
|
NTSTATUS Status;
|
|
|
|
Status = SampOpenUserObject(DomainObject,
|
|
UserId,
|
|
0,
|
|
&UserObject);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
SampGetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
NULL,
|
|
NULL,
|
|
&Length);
|
|
|
|
if (Length == 0)
|
|
return STATUS_UNSUCCESSFUL; /* FIXME */
|
|
|
|
GroupsBuffer = midl_user_allocate(Length);
|
|
if (GroupsBuffer == NULL)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
Status = SampGetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
NULL,
|
|
GroupsBuffer,
|
|
&Length);
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
|
|
for (i = 0; i < (Length / sizeof(GROUP_MEMBERSHIP)); i++)
|
|
{
|
|
if (GroupsBuffer[i].RelativeId == GroupId)
|
|
{
|
|
GroupsBuffer[i].Attributes = GroupAttributes;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
REG_BINARY,
|
|
GroupsBuffer,
|
|
Length);
|
|
|
|
done:
|
|
if (GroupsBuffer != NULL)
|
|
midl_user_free(GroupsBuffer);
|
|
|
|
if (UserObject != NULL)
|
|
SampCloseDbObject(UserObject);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampRemoveUserFromAllGroups(IN PSAM_DB_OBJECT UserObject)
|
|
{
|
|
PGROUP_MEMBERSHIP GroupsBuffer = NULL;
|
|
PSAM_DB_OBJECT GroupObject;
|
|
ULONG Length = 0;
|
|
ULONG i;
|
|
NTSTATUS Status;
|
|
|
|
SampGetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
NULL,
|
|
NULL,
|
|
&Length);
|
|
|
|
if (Length == 0)
|
|
return STATUS_SUCCESS;
|
|
|
|
GroupsBuffer = midl_user_allocate(Length);
|
|
if (GroupsBuffer == NULL)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
Status = SampGetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
NULL,
|
|
GroupsBuffer,
|
|
&Length);
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
|
|
for (i = 0; i < (Length / sizeof(GROUP_MEMBERSHIP)); i++)
|
|
{
|
|
Status = SampOpenGroupObject(UserObject->ParentObject,
|
|
GroupsBuffer[i].RelativeId,
|
|
0,
|
|
&GroupObject);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
Status = SampRemoveMemberFromGroup(GroupObject,
|
|
UserObject->RelativeId);
|
|
if (Status == STATUS_MEMBER_NOT_IN_GROUP)
|
|
Status = STATUS_SUCCESS;
|
|
|
|
SampCloseDbObject(GroupObject);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* Remove all groups from the Groups attribute */
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"Groups",
|
|
REG_BINARY,
|
|
NULL,
|
|
0);
|
|
|
|
done:
|
|
if (GroupsBuffer != NULL)
|
|
midl_user_free(GroupsBuffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampRemoveUserFromAllAliases(IN PSAM_DB_OBJECT UserObject)
|
|
{
|
|
FIXME("(%p)\n", UserObject);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampSetUserPassword(IN PSAM_DB_OBJECT UserObject,
|
|
IN PENCRYPTED_NT_OWF_PASSWORD NtPassword,
|
|
IN BOOLEAN NtPasswordPresent,
|
|
IN PENCRYPTED_LM_OWF_PASSWORD LmPassword,
|
|
IN BOOLEAN LmPasswordPresent)
|
|
{
|
|
PENCRYPTED_NT_OWF_PASSWORD NtHistory = NULL;
|
|
PENCRYPTED_LM_OWF_PASSWORD LmHistory = NULL;
|
|
ULONG NtHistoryLength = 0;
|
|
ULONG LmHistoryLength = 0;
|
|
ULONG CurrentHistoryLength;
|
|
ULONG MaxHistoryLength = 3;
|
|
ULONG Length = 0;
|
|
BOOLEAN UseNtPassword;
|
|
BOOLEAN UseLmPassword;
|
|
NTSTATUS Status;
|
|
|
|
UseNtPassword =
|
|
((NtPasswordPresent != FALSE) &&
|
|
(NtPassword != NULL) &&
|
|
(memcmp(NtPassword, &EmptyNtHash, sizeof(ENCRYPTED_NT_OWF_PASSWORD)) != 0));
|
|
|
|
UseLmPassword =
|
|
((LmPasswordPresent != FALSE) &&
|
|
(LmPassword != NULL) &&
|
|
(memcmp(LmPassword, &EmptyLmHash, sizeof(ENCRYPTED_LM_OWF_PASSWORD)) != 0));
|
|
|
|
/* Update the NT password history only if we have a new non-empty NT password */
|
|
if (UseNtPassword)
|
|
{
|
|
/* Get the size of the NT history */
|
|
SampGetObjectAttribute(UserObject,
|
|
L"NTPwdHistory",
|
|
NULL,
|
|
NULL,
|
|
&Length);
|
|
|
|
CurrentHistoryLength = Length / sizeof(ENCRYPTED_NT_OWF_PASSWORD);
|
|
if (CurrentHistoryLength < MaxHistoryLength)
|
|
{
|
|
NtHistoryLength = (CurrentHistoryLength + 1) * sizeof(ENCRYPTED_NT_OWF_PASSWORD);
|
|
}
|
|
else
|
|
{
|
|
NtHistoryLength = MaxHistoryLength * sizeof(ENCRYPTED_NT_OWF_PASSWORD);
|
|
}
|
|
|
|
/* Allocate the history buffer */
|
|
NtHistory = midl_user_allocate(NtHistoryLength);
|
|
if (NtHistory == NULL)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if (Length > 0)
|
|
{
|
|
/* Get the history */
|
|
Status = SampGetObjectAttribute(UserObject,
|
|
L"NTPwdHistory",
|
|
NULL,
|
|
NtHistory,
|
|
&Length);
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
}
|
|
|
|
/* Move the old passwords down by one entry */
|
|
if (NtHistoryLength > sizeof(ENCRYPTED_NT_OWF_PASSWORD))
|
|
{
|
|
MoveMemory(&(NtHistory[1]),
|
|
&(NtHistory[0]),
|
|
NtHistoryLength - sizeof(ENCRYPTED_NT_OWF_PASSWORD));
|
|
}
|
|
|
|
/* Add the new password to the top of the history */
|
|
if (NtPasswordPresent)
|
|
{
|
|
CopyMemory(&(NtHistory[0]),
|
|
NtPassword,
|
|
sizeof(ENCRYPTED_NT_OWF_PASSWORD));
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory(&(NtHistory[0]),
|
|
sizeof(ENCRYPTED_NT_OWF_PASSWORD));
|
|
}
|
|
|
|
/* Set the history */
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"NTPwdHistory",
|
|
REG_BINARY,
|
|
(PVOID)NtHistory,
|
|
NtHistoryLength);
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
}
|
|
|
|
/* Update the LM password history only if we have a new non-empty LM password */
|
|
if (UseLmPassword)
|
|
{
|
|
/* Get the size of the LM history */
|
|
Length = 0;
|
|
SampGetObjectAttribute(UserObject,
|
|
L"LMPwdHistory",
|
|
NULL,
|
|
NULL,
|
|
&Length);
|
|
|
|
CurrentHistoryLength = Length / sizeof(ENCRYPTED_LM_OWF_PASSWORD);
|
|
if (CurrentHistoryLength < MaxHistoryLength)
|
|
{
|
|
LmHistoryLength = (CurrentHistoryLength + 1) * sizeof(ENCRYPTED_LM_OWF_PASSWORD);
|
|
}
|
|
else
|
|
{
|
|
LmHistoryLength = MaxHistoryLength * sizeof(ENCRYPTED_LM_OWF_PASSWORD);
|
|
}
|
|
|
|
/* Allocate the history buffer */
|
|
LmHistory = midl_user_allocate(LmHistoryLength);
|
|
if (LmHistory == NULL)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if (Length > 0)
|
|
{
|
|
/* Get the history */
|
|
Status = SampGetObjectAttribute(UserObject,
|
|
L"LMPwdHistory",
|
|
NULL,
|
|
LmHistory,
|
|
&Length);
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
}
|
|
|
|
/* Move the old passwords down by one entry */
|
|
if (LmHistoryLength > sizeof(ENCRYPTED_LM_OWF_PASSWORD))
|
|
{
|
|
MoveMemory(&(LmHistory[1]),
|
|
&(LmHistory[0]),
|
|
LmHistoryLength - sizeof(ENCRYPTED_LM_OWF_PASSWORD));
|
|
}
|
|
|
|
/* Add the new password to the top of the history */
|
|
if (LmPasswordPresent)
|
|
{
|
|
CopyMemory(&(LmHistory[0]),
|
|
LmPassword,
|
|
sizeof(ENCRYPTED_LM_OWF_PASSWORD));
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory(&(LmHistory[0]),
|
|
sizeof(ENCRYPTED_LM_OWF_PASSWORD));
|
|
}
|
|
|
|
/* Set the LM password history */
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"LMPwdHistory",
|
|
REG_BINARY,
|
|
(PVOID)LmHistory,
|
|
LmHistoryLength);
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
}
|
|
|
|
/* Set the new NT password */
|
|
if (UseNtPassword)
|
|
{
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"NTPwd",
|
|
REG_BINARY,
|
|
(PVOID)NtPassword,
|
|
sizeof(ENCRYPTED_NT_OWF_PASSWORD));
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"NTPwd",
|
|
REG_BINARY,
|
|
&EmptyNtHash,
|
|
sizeof(ENCRYPTED_NT_OWF_PASSWORD));
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
}
|
|
|
|
/* Set the new LM password */
|
|
if (UseLmPassword)
|
|
{
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"LMPwd",
|
|
REG_BINARY,
|
|
(PVOID)LmPassword,
|
|
sizeof(ENCRYPTED_LM_OWF_PASSWORD));
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"LMPwd",
|
|
REG_BINARY,
|
|
&EmptyLmHash,
|
|
sizeof(ENCRYPTED_LM_OWF_PASSWORD));
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
if (NtHistory != NULL)
|
|
midl_user_free(NtHistory);
|
|
|
|
if (LmHistory != NULL)
|
|
midl_user_free(LmHistory);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampGetLogonHoursAttribute(IN PSAM_DB_OBJECT UserObject,
|
|
IN OUT PSAMPR_LOGON_HOURS LogonHours)
|
|
{
|
|
PUCHAR RawBuffer = NULL;
|
|
ULONG Length = 0;
|
|
ULONG BufferLength = 0;
|
|
NTSTATUS Status;
|
|
|
|
Status = SampGetObjectAttribute(UserObject,
|
|
L"LogonHours",
|
|
NULL,
|
|
NULL,
|
|
&Length);
|
|
if (Status != STATUS_BUFFER_OVERFLOW)
|
|
{
|
|
TRACE("SampGetObjectAttribute failed (Status 0x%08lx)\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
if (Length == 0)
|
|
{
|
|
LogonHours->UnitsPerWeek = 0;
|
|
LogonHours->LogonHours = NULL;
|
|
}
|
|
else
|
|
{
|
|
RawBuffer = midl_user_allocate(Length);
|
|
if (RawBuffer == NULL)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
Status = SampGetObjectAttribute(UserObject,
|
|
L"LogonHours",
|
|
NULL,
|
|
(PVOID)RawBuffer,
|
|
&Length);
|
|
if (!NT_SUCCESS(Status))
|
|
goto done;
|
|
|
|
LogonHours->UnitsPerWeek = *((PUSHORT)RawBuffer);
|
|
|
|
BufferLength = (((ULONG)LogonHours->UnitsPerWeek) + 7) / 8;
|
|
|
|
LogonHours->LogonHours = midl_user_allocate(BufferLength);
|
|
if (LogonHours->LogonHours == NULL)
|
|
{
|
|
TRACE("Failed to allocate LogonHours buffer!\n");
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
memcpy(LogonHours->LogonHours,
|
|
&(RawBuffer[2]),
|
|
BufferLength);
|
|
}
|
|
|
|
done:
|
|
|
|
if (RawBuffer != NULL)
|
|
midl_user_free(RawBuffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SampSetLogonHoursAttribute(IN PSAM_DB_OBJECT UserObject,
|
|
IN PSAMPR_LOGON_HOURS LogonHours)
|
|
{
|
|
PUCHAR RawBuffer = NULL;
|
|
ULONG BufferLength;
|
|
ULONG Length = 0;
|
|
NTSTATUS Status;
|
|
|
|
if (LogonHours->UnitsPerWeek > 0)
|
|
{
|
|
BufferLength = (((ULONG)LogonHours->UnitsPerWeek) + 7) / 8;
|
|
|
|
Length = BufferLength + sizeof(USHORT);
|
|
|
|
RawBuffer = midl_user_allocate(Length);
|
|
if (RawBuffer == NULL)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto done;
|
|
}
|
|
|
|
*((PUSHORT)RawBuffer) = LogonHours->UnitsPerWeek;
|
|
|
|
memcpy(&(RawBuffer[2]),
|
|
LogonHours->LogonHours,
|
|
BufferLength);
|
|
}
|
|
|
|
Status = SampSetObjectAttribute(UserObject,
|
|
L"LogonHours",
|
|
REG_BINARY,
|
|
RawBuffer,
|
|
Length);
|
|
|
|
done:
|
|
if (RawBuffer != NULL)
|
|
midl_user_free(RawBuffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* EOF */
|