mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3608 lines
81 KiB
3608 lines
81 KiB
/*++
|
|
|
|
Copyright (c) 1987-1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
replutil.c
|
|
|
|
Abstract:
|
|
|
|
Low level functions for SSI Replication apis
|
|
|
|
Author:
|
|
|
|
Ported from Lan Man 2.0
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
Contains NT-specific code.
|
|
Requires ANSI C extensions: slash-slash comments, long external names.
|
|
|
|
Revision History:
|
|
|
|
22-Jul-1991 (cliffv)
|
|
Ported to NT. Converted to NT style.
|
|
|
|
02-Jan-1992 (madana)
|
|
added support for builtin/multidomain replication.
|
|
|
|
04-Apr-1992 (madana)
|
|
Added support for LSA replication.
|
|
|
|
--*/
|
|
|
|
//
|
|
// Common include files.
|
|
//
|
|
|
|
#include <logonsrv.h> // Include files common to entire service
|
|
|
|
//
|
|
// Include files specific to this .c file
|
|
//
|
|
|
|
#include <align.h>
|
|
#include <accessp.h> // NetpConvertWorkstationList
|
|
#include <replutil.h> // Local procedure forwards
|
|
#include <lsarepl.h>
|
|
|
|
|
|
|
|
DWORD
|
|
NlCopyUnicodeString (
|
|
IN PUNICODE_STRING InString,
|
|
OUT PUNICODE_STRING OutString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies the input string to the output. It assumes that
|
|
the input string is allocated by MIDL_user_allocate() and sets the
|
|
input string buffer pointer to NULL so that the buffer will be not
|
|
freed on return.
|
|
|
|
Arguments:
|
|
|
|
InString - Points to the UNICODE string to copy.
|
|
|
|
OutString - Points to the UNICODE string which will be updated to point
|
|
to the input string.
|
|
|
|
Return Value:
|
|
|
|
Return the size of the MIDL buffer.
|
|
|
|
--*/
|
|
{
|
|
if ( InString->Length == 0 || InString->Buffer == NULL ) {
|
|
OutString->Length = 0;
|
|
OutString->MaximumLength = 0;
|
|
OutString->Buffer = NULL;
|
|
} else {
|
|
OutString->Length = InString->Length;
|
|
OutString->MaximumLength = InString->Length;
|
|
OutString->Buffer = InString->Buffer;
|
|
InString->Buffer = NULL;
|
|
}
|
|
|
|
return( OutString->MaximumLength );
|
|
}
|
|
|
|
|
|
DWORD
|
|
NlCopyData(
|
|
IN LPBYTE *InData,
|
|
OUT LPBYTE *OutData,
|
|
DWORD DataLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies the input data pointer to output data pointer.
|
|
It assumes that the input data buffer is allocated by the
|
|
MIDL_user_allocate() and sets the input buffer buffer pointer to
|
|
NULL on return so that the data buffer will not be freed by SamIFree
|
|
rountine.
|
|
|
|
Arguments:
|
|
|
|
InData - Points to input data buffer pointer.
|
|
|
|
OutString - Pointer to output data buffer pointer.
|
|
|
|
DataLength - Length of input data.
|
|
|
|
Return Value:
|
|
|
|
Return the size of the data copied.
|
|
|
|
--*/
|
|
{
|
|
*OutData = *InData;
|
|
*InData = NULL;
|
|
|
|
return(DataLength);
|
|
}
|
|
|
|
|
|
VOID
|
|
NlFreeDBDelta(
|
|
IN PNETLOGON_DELTA_ENUM Delta
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will free the midl buffers that are allocated for
|
|
a delta. This routine does nothing but call the midl generated free
|
|
routine.
|
|
|
|
Arguments:
|
|
|
|
Delta: pointer to the delta structure which has to be freed.
|
|
|
|
Return Value:
|
|
|
|
nothing
|
|
|
|
--*/
|
|
{
|
|
if( Delta != NULL ) {
|
|
_fgs__NETLOGON_DELTA_ENUM (Delta);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
NlFreeDBDeltaArray(
|
|
IN PNETLOGON_DELTA_ENUM DeltaArray,
|
|
IN DWORD ArraySize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will free up all delta entries in enum array and the
|
|
array itself.
|
|
|
|
Arguments:
|
|
|
|
Delta: pointer to the delta structure array.
|
|
|
|
ArraySize: num of delta structures in the array.
|
|
|
|
Return Value:
|
|
|
|
nothing
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
|
|
if( DeltaArray != NULL ) {
|
|
|
|
for( i = 0; i < ArraySize; i++) {
|
|
NlFreeDBDelta( &DeltaArray[i] );
|
|
}
|
|
|
|
MIDL_user_free( DeltaArray );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NlPackSamUser (
|
|
IN ULONG RelativeId,
|
|
IN OUT PNETLOGON_DELTA_ENUM Delta,
|
|
IN PDB_INFO DBInfo,
|
|
IN LPDWORD BufferSize,
|
|
IN PSESSION_INFO SessionInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pack a description of the specified user into the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
RelativeId - The relative Id of the user query.
|
|
|
|
Delta: pointer to the delta structure where the new delta will
|
|
be returned.
|
|
|
|
DBInfo: pointer to the database info structure.
|
|
|
|
BufferSize: size of MIDL buffer that is consumed for this delta is
|
|
returned here.
|
|
|
|
SessionInfo: Info describing BDC that's calling us
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE UserHandle = NULL;
|
|
PNETLOGON_DELTA_USER DeltaUser;
|
|
PSAMPR_USER_INFO_BUFFER UserAll = NULL;
|
|
|
|
|
|
|
|
DEFPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Packing User Object %lx\n", RelativeId));
|
|
|
|
*BufferSize = 0;
|
|
|
|
Delta->DeltaType = AddOrChangeUser;
|
|
Delta->DeltaID.Rid = RelativeId;
|
|
Delta->DeltaUnion.DeltaUser = NULL;
|
|
|
|
//
|
|
// Open a handle to the specified user.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrOpenUser( DBInfo->DBHandle,
|
|
0, // No desired access
|
|
RelativeId,
|
|
&UserHandle );
|
|
STOPSAMTIMER;
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
UserHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Query everything there is to know about this user.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrQueryInformationUser(
|
|
UserHandle,
|
|
UserInternal3Information,
|
|
&UserAll );
|
|
STOPSAMTIMER;
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
UserAll = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
NlPrint((NL_SYNC_MORE,
|
|
"\t User Object name %wZ\n",
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.UserName));
|
|
|
|
#define FIELDS_USED ( USER_ALL_USERNAME | \
|
|
USER_ALL_FULLNAME | \
|
|
USER_ALL_USERID | \
|
|
USER_ALL_PRIMARYGROUPID | \
|
|
USER_ALL_HOMEDIRECTORY | \
|
|
USER_ALL_HOMEDIRECTORYDRIVE | \
|
|
USER_ALL_SCRIPTPATH | \
|
|
USER_ALL_PROFILEPATH | \
|
|
USER_ALL_ADMINCOMMENT | \
|
|
USER_ALL_WORKSTATIONS | \
|
|
USER_ALL_LOGONHOURS | \
|
|
USER_ALL_LASTLOGON | \
|
|
USER_ALL_LASTLOGOFF | \
|
|
USER_ALL_BADPASSWORDCOUNT | \
|
|
USER_ALL_LOGONCOUNT | \
|
|
USER_ALL_PASSWORDLASTSET | \
|
|
USER_ALL_ACCOUNTEXPIRES | \
|
|
USER_ALL_USERACCOUNTCONTROL | \
|
|
USER_ALL_USERCOMMENT | \
|
|
USER_ALL_COUNTRYCODE | \
|
|
USER_ALL_CODEPAGE | \
|
|
USER_ALL_PARAMETERS | \
|
|
USER_ALL_NTPASSWORDPRESENT | \
|
|
USER_ALL_LMPASSWORDPRESENT | \
|
|
USER_ALL_PRIVATEDATA | \
|
|
USER_ALL_SECURITYDESCRIPTOR )
|
|
|
|
NlAssert( (UserAll->Internal3.I1.WhichFields & FIELDS_USED) == FIELDS_USED );
|
|
|
|
|
|
|
|
//
|
|
// Allocate a buffer to return to the caller.
|
|
//
|
|
|
|
DeltaUser = (PNETLOGON_DELTA_USER)
|
|
MIDL_user_allocate( sizeof(NETLOGON_DELTA_USER) );
|
|
|
|
if (DeltaUser == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// wipe off the buffer so that cleanup will not be in fault.
|
|
//
|
|
|
|
RtlZeroMemory( DeltaUser, sizeof(NETLOGON_DELTA_USER) );
|
|
|
|
Delta->DeltaUnion.DeltaUser = DeltaUser;
|
|
*BufferSize += sizeof(NETLOGON_DELTA_USER);
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.UserName,
|
|
&DeltaUser->UserName );
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.FullName,
|
|
&DeltaUser->FullName );
|
|
|
|
DeltaUser->UserId = UserAll->Internal3.I1.UserId;
|
|
DeltaUser->PrimaryGroupId = UserAll->Internal3.I1.PrimaryGroupId;
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.HomeDirectory,
|
|
&DeltaUser->HomeDirectory );
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.HomeDirectoryDrive,
|
|
&DeltaUser->HomeDirectoryDrive );
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.ScriptPath,
|
|
&DeltaUser->ScriptPath );
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.AdminComment,
|
|
&DeltaUser->AdminComment );
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.WorkStations,
|
|
&DeltaUser->WorkStations );
|
|
|
|
DeltaUser->LastLogon = UserAll->Internal3.I1.LastLogon;
|
|
DeltaUser->LastLogoff = UserAll->Internal3.I1.LastLogoff;
|
|
|
|
//
|
|
// Copy Logon Hours
|
|
//
|
|
|
|
DeltaUser->LogonHours.UnitsPerWeek = UserAll->Internal3.I1.LogonHours.UnitsPerWeek;
|
|
DeltaUser->LogonHours.LogonHours = UserAll->Internal3.I1.LogonHours.LogonHours;
|
|
UserAll->Internal3.I1.LogonHours.LogonHours = NULL; // Don't let SAM free this.
|
|
*BufferSize += (UserAll->Internal3.I1.LogonHours.UnitsPerWeek + 7) / 8;
|
|
|
|
|
|
|
|
DeltaUser->BadPasswordCount = UserAll->Internal3.I1.BadPasswordCount;
|
|
DeltaUser->LogonCount = UserAll->Internal3.I1.LogonCount;
|
|
|
|
DeltaUser->PasswordLastSet = UserAll->Internal3.I1.PasswordLastSet;
|
|
DeltaUser->AccountExpires = UserAll->Internal3.I1.AccountExpires;
|
|
|
|
//
|
|
// Don't copy lockout bit to BDC unless it understands it.
|
|
//
|
|
|
|
DeltaUser->UserAccountControl = UserAll->Internal3.I1.UserAccountControl;
|
|
if ( (SessionInfo->NegotiatedFlags & NETLOGON_SUPPORTS_ACCOUNT_LOCKOUT) == 0 ){
|
|
DeltaUser->UserAccountControl &= ~USER_ACCOUNT_AUTO_LOCKED;
|
|
}
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.UserComment,
|
|
&DeltaUser->UserComment );
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.Parameters,
|
|
&DeltaUser->Parameters );
|
|
|
|
DeltaUser->CountryCode = UserAll->Internal3.I1.CountryCode;
|
|
DeltaUser->CodePage = UserAll->Internal3.I1.CodePage;
|
|
|
|
//
|
|
// Set private data.
|
|
// Includes passwords and password history.
|
|
//
|
|
|
|
DeltaUser->PrivateData.SensitiveData = UserAll->Internal3.I1.PrivateDataSensitive;
|
|
|
|
if ( UserAll->Internal3.I1.PrivateDataSensitive ) {
|
|
|
|
CRYPT_BUFFER Data;
|
|
|
|
//
|
|
// encrypt private data using session key
|
|
// Re-use the SAM's buffer and encrypt it in place.
|
|
//
|
|
|
|
Data.Length = Data.MaximumLength = UserAll->Internal3.I1.PrivateData.Length;
|
|
Data.Buffer = (PUCHAR) UserAll->Internal3.I1.PrivateData.Buffer;
|
|
UserAll->Internal3.I1.PrivateData.Buffer = NULL;
|
|
|
|
Status = NlEncryptSensitiveData( &Data, SessionInfo );
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DeltaUser->PrivateData.DataLength = Data.Length;
|
|
DeltaUser->PrivateData.Data = Data.Buffer;
|
|
} else {
|
|
|
|
DeltaUser->PrivateData.DataLength = UserAll->Internal3.I1.PrivateData.Length;
|
|
DeltaUser->PrivateData.Data = (PUCHAR) UserAll->Internal3.I1.PrivateData.Buffer;
|
|
|
|
UserAll->Internal3.I1.PrivateData.Buffer = NULL;
|
|
}
|
|
|
|
{ // ?? Macro requires a Local named SecurityDescriptor
|
|
PSAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
SecurityDescriptor = &UserAll->Internal3.I1.SecurityDescriptor;
|
|
DELTA_SECOBJ_INFO(DeltaUser);
|
|
}
|
|
|
|
INIT_PLACE_HOLDER(DeltaUser);
|
|
|
|
//
|
|
// copy profile path in DummyStrings
|
|
//
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&UserAll->Internal3.I1.ProfilePath,
|
|
&DeltaUser->DummyString1 );
|
|
|
|
//
|
|
// Copy LastBadPasswordTime to DummyLong1 and DummyLong2.
|
|
//
|
|
|
|
DeltaUser->DummyLong1 = UserAll->Internal3.LastBadPasswordTime.HighPart;
|
|
DeltaUser->DummyLong2 = UserAll->Internal3.LastBadPasswordTime.LowPart;
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
|
|
Cleanup:
|
|
|
|
|
|
STARTSAMTIMER;
|
|
|
|
if( UserHandle != NULL ) {
|
|
(VOID) SamrCloseHandle( &UserHandle );
|
|
}
|
|
|
|
if ( UserAll != NULL ) {
|
|
SamIFree_SAMPR_USER_INFO_BUFFER( UserAll, UserInternal3Information );
|
|
}
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
NlFreeDBDelta( Delta );
|
|
*BufferSize = 0;
|
|
}
|
|
|
|
STOPPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Time taken to pack USER object:\n"));
|
|
PRINTPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlPackSamGroup (
|
|
IN ULONG RelativeId,
|
|
IN OUT PNETLOGON_DELTA_ENUM Delta,
|
|
IN PDB_INFO DBInfo,
|
|
LPDWORD BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pack a description of the specified group into the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
RelativeId - The relative Id of the group query.
|
|
|
|
Delta: pointer to the delta structure where the new delta will
|
|
be returned.
|
|
|
|
DBInfo: pointer to the database info structure.
|
|
|
|
BufferSize: size of MIDL buffer that is consumed for this delta is
|
|
returned here.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE GroupHandle = NULL;
|
|
PNETLOGON_DELTA_GROUP DeltaGroup;
|
|
|
|
//
|
|
// Information returned from SAM
|
|
//
|
|
|
|
PSAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
|
PSAMPR_GROUP_INFO_BUFFER GroupGeneral = NULL;
|
|
|
|
DEFPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Packing Group Object %lx\n", RelativeId ));
|
|
|
|
*BufferSize = 0;
|
|
|
|
Delta->DeltaType = AddOrChangeGroup;
|
|
Delta->DeltaID.Rid = RelativeId;
|
|
Delta->DeltaUnion.DeltaGroup = NULL;
|
|
|
|
//
|
|
// Open a handle to the specified group.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrOpenGroup( DBInfo->DBHandle,
|
|
0, // No desired access
|
|
RelativeId,
|
|
&GroupHandle );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
GroupHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
STOPSAMTIMER;
|
|
|
|
QUERY_SAM_SECOBJ_INFO(GroupHandle);
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrQueryInformationGroup(
|
|
GroupHandle,
|
|
GroupGeneralInformation,
|
|
&GroupGeneral );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
GroupGeneral = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
NlPrint((NL_SYNC_MORE,
|
|
"\t Group Object name %wZ\n",
|
|
(PUNICODE_STRING)&GroupGeneral->General.Name ));
|
|
|
|
DeltaGroup = (PNETLOGON_DELTA_GROUP)
|
|
MIDL_user_allocate( sizeof(NETLOGON_DELTA_GROUP) );
|
|
|
|
if( DeltaGroup == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// wipe off the buffer so that cleanup will not be in fault.
|
|
//
|
|
|
|
RtlZeroMemory( DeltaGroup, sizeof(NETLOGON_DELTA_GROUP) );
|
|
|
|
Delta->DeltaUnion.DeltaGroup = DeltaGroup;
|
|
*BufferSize += sizeof(NETLOGON_DELTA_GROUP);
|
|
|
|
*BufferSize = NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&GroupGeneral->General.Name,
|
|
&DeltaGroup->Name );
|
|
|
|
DeltaGroup->RelativeId = RelativeId;
|
|
DeltaGroup->Attributes = GroupGeneral->General.Attributes;
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&GroupGeneral->General.AdminComment,
|
|
&DeltaGroup->AdminComment );
|
|
|
|
DeltaGroup->RelativeId = RelativeId;
|
|
DeltaGroup->Attributes = GroupGeneral->General.Attributes;
|
|
|
|
DELTA_SECOBJ_INFO(DeltaGroup);
|
|
INIT_PLACE_HOLDER(DeltaGroup);
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Cleanup:
|
|
STARTSAMTIMER;
|
|
|
|
if( GroupHandle != NULL ) {
|
|
(VOID) SamrCloseHandle( &GroupHandle );
|
|
}
|
|
|
|
if ( SecurityDescriptor != NULL ) {
|
|
SamIFree_SAMPR_SR_SECURITY_DESCRIPTOR( SecurityDescriptor );
|
|
}
|
|
|
|
if ( GroupGeneral != NULL ) {
|
|
SamIFree_SAMPR_GROUP_INFO_BUFFER( GroupGeneral,
|
|
GroupGeneralInformation );
|
|
}
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
NlFreeDBDelta( Delta );
|
|
*BufferSize = 0;
|
|
}
|
|
|
|
STOPPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Time taken to pack GROUP object:\n"));
|
|
PRINTPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlPackSamGroupMember (
|
|
IN ULONG RelativeId,
|
|
IN OUT PNETLOGON_DELTA_ENUM Delta,
|
|
IN PDB_INFO DBInfo,
|
|
LPDWORD BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pack a description of the membership of the specified group into
|
|
the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
RelativeId - The relative Id of the group query.
|
|
|
|
Delta: pointer to the delta structure where the new delta will
|
|
be returned.
|
|
|
|
DBInfo: pointer to the database info structure.
|
|
|
|
BufferSize: size of MIDL buffer that is consumed for this delta is
|
|
returned here.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE GroupHandle = NULL;
|
|
DWORD Size;
|
|
PNETLOGON_DELTA_GROUP_MEMBER DeltaGroupMember;
|
|
|
|
//
|
|
// Information returned from SAM
|
|
//
|
|
|
|
PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
|
|
|
|
DEFPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Packing GroupMember Object %lx\n", RelativeId));
|
|
|
|
*BufferSize = 0;
|
|
|
|
Delta->DeltaType = ChangeGroupMembership;
|
|
Delta->DeltaID.Rid = RelativeId;
|
|
Delta->DeltaUnion.DeltaGroupMember = NULL;
|
|
|
|
//
|
|
// Open a handle to the specified group.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrOpenGroup( DBInfo->DBHandle,
|
|
0, // No desired access
|
|
RelativeId,
|
|
&GroupHandle );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
GroupHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Find out everything there is to know about the group.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrGetMembersInGroup( GroupHandle, &MembersBuffer );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
MembersBuffer = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
DeltaGroupMember = (PNETLOGON_DELTA_GROUP_MEMBER)
|
|
MIDL_user_allocate( sizeof(NETLOGON_DELTA_GROUP_MEMBER) );
|
|
|
|
if( DeltaGroupMember == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// wipe off the buffer so that cleanup will not be in fault.
|
|
//
|
|
|
|
RtlZeroMemory( DeltaGroupMember,
|
|
sizeof(NETLOGON_DELTA_GROUP_MEMBER) );
|
|
|
|
Delta->DeltaUnion.DeltaGroupMember = DeltaGroupMember;
|
|
*BufferSize += sizeof(NETLOGON_DELTA_GROUP_MEMBER);
|
|
|
|
if ( MembersBuffer->MemberCount != 0 ) {
|
|
Size = MembersBuffer->MemberCount * sizeof(*MembersBuffer->Members);
|
|
|
|
*BufferSize += NlCopyData(
|
|
(LPBYTE *)&MembersBuffer->Members,
|
|
(LPBYTE *)&DeltaGroupMember->MemberIds,
|
|
Size );
|
|
|
|
Size = MembersBuffer->MemberCount *
|
|
sizeof(*MembersBuffer->Attributes);
|
|
|
|
*BufferSize += NlCopyData(
|
|
(LPBYTE *)&MembersBuffer->Attributes,
|
|
(LPBYTE *)&DeltaGroupMember->Attributes,
|
|
Size );
|
|
}
|
|
|
|
DeltaGroupMember->MemberCount = MembersBuffer->MemberCount;
|
|
|
|
//
|
|
// Initialize placeholder strings to NULL.
|
|
//
|
|
|
|
DeltaGroupMember->DummyLong1 = 0;
|
|
DeltaGroupMember->DummyLong2 = 0;
|
|
DeltaGroupMember->DummyLong3 = 0;
|
|
DeltaGroupMember->DummyLong4 = 0;
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Cleanup:
|
|
STARTSAMTIMER;
|
|
|
|
if( GroupHandle != NULL ) {
|
|
(VOID) SamrCloseHandle( &GroupHandle );
|
|
}
|
|
|
|
if ( MembersBuffer != NULL ) {
|
|
SamIFree_SAMPR_GET_MEMBERS_BUFFER( MembersBuffer );
|
|
}
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
NlFreeDBDelta( Delta );
|
|
*BufferSize = 0;
|
|
}
|
|
|
|
STOPPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Time taken to pack GROUPMEMBER object:\n"));
|
|
PRINTPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlPackSamAlias (
|
|
IN ULONG RelativeId,
|
|
IN OUT PNETLOGON_DELTA_ENUM Delta,
|
|
IN PDB_INFO DBInfo,
|
|
LPDWORD BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pack a description of the specified alias into the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
RelativeId - The relative Id of the alias query.
|
|
|
|
Delta: pointer to the delta structure where the new delta will
|
|
be returned.
|
|
|
|
DBInfo: pointer to the database info structure.
|
|
|
|
BufferSize: size of MIDL buffer that is consumed for this delta is
|
|
returned here.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE AliasHandle = NULL;
|
|
PNETLOGON_DELTA_ALIAS DeltaAlias;
|
|
|
|
//
|
|
// Information returned from SAM
|
|
//
|
|
|
|
PSAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
|
|
|
PSAMPR_ALIAS_INFO_BUFFER AliasGeneral = NULL;
|
|
|
|
DEFPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Packing Alias Object %lx\n", RelativeId));
|
|
|
|
*BufferSize = 0;
|
|
|
|
Delta->DeltaType = AddOrChangeAlias;
|
|
Delta->DeltaID.Rid = RelativeId;
|
|
Delta->DeltaUnion.DeltaAlias = NULL;
|
|
|
|
//
|
|
// Open a handle to the specified alias.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrOpenAlias( DBInfo->DBHandle,
|
|
0, // No desired access
|
|
RelativeId,
|
|
&AliasHandle );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
AliasHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
QUERY_SAM_SECOBJ_INFO(AliasHandle);
|
|
|
|
//
|
|
// Determine the alias name.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrQueryInformationAlias(
|
|
AliasHandle,
|
|
AliasGeneralInformation,
|
|
&AliasGeneral );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
AliasGeneral = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
NlPrint((NL_SYNC_MORE, "\t Alias Object name %wZ\n",
|
|
(PUNICODE_STRING)&(AliasGeneral->General.Name)));
|
|
|
|
DeltaAlias = (PNETLOGON_DELTA_ALIAS)
|
|
MIDL_user_allocate( sizeof(NETLOGON_DELTA_ALIAS) );
|
|
|
|
if( DeltaAlias == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// wipe off the buffer so that cleanup will not be in fault.
|
|
//
|
|
|
|
RtlZeroMemory( DeltaAlias, sizeof(NETLOGON_DELTA_ALIAS) );
|
|
|
|
Delta->DeltaUnion.DeltaAlias = DeltaAlias;
|
|
*BufferSize += sizeof(NETLOGON_DELTA_ALIAS);
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&(AliasGeneral->General.Name),
|
|
&DeltaAlias->Name );
|
|
|
|
DeltaAlias->RelativeId = RelativeId;
|
|
|
|
DELTA_SECOBJ_INFO(DeltaAlias);
|
|
INIT_PLACE_HOLDER(DeltaAlias);
|
|
|
|
//
|
|
// copy comment string
|
|
//
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&(AliasGeneral->General.AdminComment),
|
|
&DeltaAlias->DummyString1 );
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Cleanup:
|
|
STARTSAMTIMER;
|
|
|
|
if( AliasHandle != NULL ) {
|
|
(VOID) SamrCloseHandle( &AliasHandle );
|
|
}
|
|
|
|
if ( SecurityDescriptor != NULL ) {
|
|
SamIFree_SAMPR_SR_SECURITY_DESCRIPTOR( SecurityDescriptor );
|
|
}
|
|
|
|
|
|
if( AliasGeneral != NULL ) {
|
|
|
|
SamIFree_SAMPR_ALIAS_INFO_BUFFER (
|
|
AliasGeneral,
|
|
AliasGeneralInformation );
|
|
}
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
NlFreeDBDelta( Delta );
|
|
*BufferSize = 0;
|
|
}
|
|
|
|
STOPPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Time taken to pack ALIAS object:\n"));
|
|
PRINTPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlPackSamAliasMember (
|
|
IN ULONG RelativeId,
|
|
IN OUT PNETLOGON_DELTA_ENUM Delta,
|
|
IN PDB_INFO DBInfo,
|
|
LPDWORD BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pack a description of the membership of the specified alias into
|
|
the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
RelativeId - The relative Id of the alias query.
|
|
|
|
Delta: pointer to the delta structure where the new delta will
|
|
be returned.
|
|
|
|
DBInfo: pointer to the database info structure.
|
|
|
|
BufferSize: size of MIDL buffer that is consumed for this delta is
|
|
returned here.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE AliasHandle = NULL;
|
|
PNETLOGON_DELTA_ALIAS_MEMBER DeltaAliasMember;
|
|
DWORD i;
|
|
|
|
//
|
|
// Information returned from SAM
|
|
//
|
|
|
|
NLPR_SID_ARRAY Members;
|
|
PNLPR_SID_INFORMATION Sids;
|
|
|
|
DEFPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Packing AliasMember Object %lx\n", RelativeId));
|
|
|
|
*BufferSize = 0;
|
|
|
|
Delta->DeltaType = ChangeAliasMembership;
|
|
Delta->DeltaID.Rid = RelativeId;
|
|
Delta->DeltaUnion.DeltaAliasMember = NULL;
|
|
|
|
Members.Sids = NULL;
|
|
|
|
|
|
//
|
|
// Open a handle to the specified alias.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrOpenAlias( DBInfo->DBHandle,
|
|
0, // No desired access
|
|
RelativeId,
|
|
&AliasHandle );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
AliasHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Find out everything there is to know about the alias.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrGetMembersInAlias( AliasHandle,
|
|
(PSAMPR_PSID_ARRAY)&Members );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
Members.Sids = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
DeltaAliasMember = (PNETLOGON_DELTA_ALIAS_MEMBER)
|
|
MIDL_user_allocate( sizeof(NETLOGON_DELTA_ALIAS_MEMBER) );
|
|
|
|
if( DeltaAliasMember == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// wipe off the buffer so that cleanup will not be in fault.
|
|
//
|
|
|
|
RtlZeroMemory( DeltaAliasMember,
|
|
sizeof(NETLOGON_DELTA_ALIAS_MEMBER) );
|
|
|
|
Delta->DeltaUnion.DeltaAliasMember = DeltaAliasMember;
|
|
*BufferSize += sizeof(NETLOGON_DELTA_ALIAS_MEMBER);
|
|
|
|
//
|
|
// tie up sam return node to our return node
|
|
//
|
|
|
|
DeltaAliasMember->Members = Members;
|
|
|
|
//
|
|
// however, compute the MIDL buffer consumed for members node.
|
|
//
|
|
|
|
for(i = 0, Sids = Members.Sids; i < Members.Count; ++i, Sids++) {
|
|
|
|
*BufferSize += (sizeof(PNLPR_SID_INFORMATION) +
|
|
RtlLengthSid(Sids->SidPointer));
|
|
|
|
}
|
|
|
|
*BufferSize += sizeof(SAMPR_PSID_ARRAY);
|
|
|
|
//
|
|
// Initialize placeholder strings to NULL.
|
|
//
|
|
|
|
DeltaAliasMember->DummyLong1 = 0;
|
|
DeltaAliasMember->DummyLong2 = 0;
|
|
DeltaAliasMember->DummyLong3 = 0;
|
|
DeltaAliasMember->DummyLong4 = 0;
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
STARTSAMTIMER;
|
|
|
|
if( AliasHandle != NULL ) {
|
|
(VOID) SamrCloseHandle( &AliasHandle );
|
|
}
|
|
|
|
if ( Members.Sids != NULL ) {
|
|
|
|
//
|
|
// don't free this node because we have tied up this
|
|
// node to our return info to RPC which will free it up
|
|
// when it is done with it.
|
|
//
|
|
// however, free this node under error conditions
|
|
//
|
|
|
|
}
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
|
|
SamIFree_SAMPR_PSID_ARRAY( (PSAMPR_PSID_ARRAY)&Members );
|
|
|
|
if( Delta->DeltaUnion.DeltaAliasMember != NULL ) {
|
|
Delta->DeltaUnion.DeltaAliasMember->Members.Sids = NULL;
|
|
}
|
|
|
|
NlFreeDBDelta( Delta );
|
|
*BufferSize = 0;
|
|
}
|
|
|
|
STOPSAMTIMER;
|
|
|
|
STOPPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Timing for ALIASMEBER object packing:\n"));
|
|
PRINTPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlPackSamDomain (
|
|
IN OUT PNETLOGON_DELTA_ENUM Delta,
|
|
IN PDB_INFO DBInfo,
|
|
IN LPDWORD BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pack a description of the sam domain into the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
Delta: pointer to the delta structure where the new delta will
|
|
be returned.
|
|
|
|
DBInfo: pointer to the database info structure.
|
|
|
|
BufferSize: size of MIDL buffer that is consumed for this delta is
|
|
returned here.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PNETLOGON_DELTA_DOMAIN DeltaDomain = NULL;
|
|
|
|
//
|
|
// Information returned from SAM
|
|
//
|
|
|
|
PSAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
|
PSAMPR_DOMAIN_INFO_BUFFER DomainGeneral = NULL;
|
|
PSAMPR_DOMAIN_INFO_BUFFER DomainPassword = NULL;
|
|
PSAMPR_DOMAIN_INFO_BUFFER DomainModified = NULL;
|
|
PSAMPR_DOMAIN_INFO_BUFFER DomainLockout = NULL;
|
|
|
|
DEFPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Packing Domain Object\n"));
|
|
|
|
*BufferSize = 0;
|
|
|
|
Delta->DeltaType = AddOrChangeDomain;
|
|
Delta->DeltaID.Rid = 0;
|
|
Delta->DeltaUnion.DeltaDomain = NULL;
|
|
|
|
|
|
QUERY_SAM_SECOBJ_INFO(DBInfo->DBHandle);
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrQueryInformationDomain(
|
|
DBInfo->DBHandle,
|
|
DomainGeneralInformation,
|
|
&DomainGeneral );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DomainGeneral = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// As a side effect, make sure our UAS Compatibility mode is correct.
|
|
//
|
|
NlGlobalUasCompatibilityMode =
|
|
DomainGeneral->General.UasCompatibilityRequired ;
|
|
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrQueryInformationDomain(
|
|
DBInfo->DBHandle,
|
|
DomainPasswordInformation,
|
|
&DomainPassword );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DomainPassword = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrQueryInformationDomain(
|
|
DBInfo->DBHandle,
|
|
DomainModifiedInformation,
|
|
&DomainModified );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DomainModified = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrQueryInformationDomain(
|
|
DBInfo->DBHandle,
|
|
DomainLockoutInformation,
|
|
&DomainLockout );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DomainLockout = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Fill in the delta structure
|
|
//
|
|
|
|
|
|
DeltaDomain = (PNETLOGON_DELTA_DOMAIN)
|
|
MIDL_user_allocate( sizeof(NETLOGON_DELTA_DOMAIN) );
|
|
|
|
if( DeltaDomain == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Zero the buffer so that cleanup will not access violate.
|
|
//
|
|
|
|
RtlZeroMemory( DeltaDomain, sizeof(NETLOGON_DELTA_DOMAIN) );
|
|
|
|
Delta->DeltaUnion.DeltaDomain = DeltaDomain;
|
|
*BufferSize += sizeof(NETLOGON_DELTA_DOMAIN);
|
|
|
|
*BufferSize += NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&DomainGeneral->General.DomainName,
|
|
&DeltaDomain->DomainName );
|
|
|
|
*BufferSize = NlCopyUnicodeString(
|
|
(PUNICODE_STRING)&DomainGeneral->General.OemInformation,
|
|
&DeltaDomain->OemInformation );
|
|
|
|
DeltaDomain->ForceLogoff = DomainGeneral->General.ForceLogoff;
|
|
DeltaDomain->MinPasswordLength =
|
|
DomainPassword->Password.MinPasswordLength;
|
|
DeltaDomain->PasswordHistoryLength =
|
|
DomainPassword->Password.PasswordHistoryLength;
|
|
|
|
NEW_TO_OLD_LARGE_INTEGER(
|
|
DomainPassword->Password.MaxPasswordAge,
|
|
DeltaDomain->MaxPasswordAge );
|
|
|
|
NEW_TO_OLD_LARGE_INTEGER(
|
|
DomainPassword->Password.MinPasswordAge,
|
|
DeltaDomain->MinPasswordAge );
|
|
|
|
NEW_TO_OLD_LARGE_INTEGER(
|
|
DomainModified->Modified.DomainModifiedCount,
|
|
DeltaDomain->DomainModifiedCount );
|
|
|
|
NEW_TO_OLD_LARGE_INTEGER(
|
|
DomainModified->Modified.CreationTime,
|
|
DeltaDomain->DomainCreationTime );
|
|
|
|
|
|
DELTA_SECOBJ_INFO(DeltaDomain);
|
|
INIT_PLACE_HOLDER(DeltaDomain);
|
|
|
|
//
|
|
// replicate PasswordProperties using reserved field.
|
|
//
|
|
|
|
DeltaDomain->DummyLong1 =
|
|
DomainPassword->Password.PasswordProperties;
|
|
|
|
//
|
|
// Replicate DOMAIN_LOCKOUT_INFORMATION using reserved field.
|
|
//
|
|
|
|
DeltaDomain->DummyString1.Buffer = (LPWSTR) DomainLockout;
|
|
DeltaDomain->DummyString1.MaximumLength =
|
|
DeltaDomain->DummyString1.Length = sizeof( DomainLockout->Lockout);
|
|
DomainLockout = NULL;
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
STARTSAMTIMER;
|
|
|
|
if ( SecurityDescriptor != NULL ) {
|
|
SamIFree_SAMPR_SR_SECURITY_DESCRIPTOR( SecurityDescriptor );
|
|
}
|
|
|
|
if ( DomainGeneral != NULL ) {
|
|
SamIFree_SAMPR_DOMAIN_INFO_BUFFER( DomainGeneral,
|
|
DomainGeneralInformation );
|
|
}
|
|
|
|
if ( DomainPassword != NULL ) {
|
|
SamIFree_SAMPR_DOMAIN_INFO_BUFFER( DomainPassword,
|
|
DomainPasswordInformation );
|
|
}
|
|
|
|
if ( DomainModified != NULL ) {
|
|
SamIFree_SAMPR_DOMAIN_INFO_BUFFER( DomainModified,
|
|
DomainModifiedInformation );
|
|
}
|
|
|
|
if ( DomainLockout != NULL ) {
|
|
SamIFree_SAMPR_DOMAIN_INFO_BUFFER( DomainLockout,
|
|
DomainLockoutInformation );
|
|
}
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
NlFreeDBDelta( Delta );
|
|
*BufferSize = 0;
|
|
}
|
|
|
|
STOPPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Timing for DOMAIN object packing:\n"));
|
|
PRINTPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NlUnpackSamUser (
|
|
IN PNETLOGON_DELTA_USER DeltaUser,
|
|
IN PDB_INFO DBInfo,
|
|
OUT PULONG ConflictingRID,
|
|
IN PSESSION_INFO SessionInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the Sam User to look like the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
DeltaUser - Description of the user.
|
|
|
|
SessionInfo - Info shared between PDC and BDC
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE UserHandle = NULL;
|
|
SAMPR_USER_INFO_BUFFER UserInfo;
|
|
#ifdef notdef
|
|
NT_OWF_PASSWORD NtOwfPassword;
|
|
LM_OWF_PASSWORD LmOwfPassword;
|
|
#endif // notdef
|
|
|
|
PUCHAR PrivateDataAllocated = NULL;
|
|
LPWSTR WorkstationList = NULL;
|
|
|
|
BOOLEAN SetUserNameField = FALSE;
|
|
|
|
DEFUNPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITUNPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTUNPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "UnPacking User Object (%lx) %wZ\n",
|
|
DeltaUser->UserId,
|
|
&DeltaUser->UserName ));
|
|
|
|
//
|
|
// Open a handle to the specified user.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamICreateAccountByRid(
|
|
DBInfo->DBHandle,
|
|
SamObjectUser,
|
|
DeltaUser->UserId,
|
|
(PRPC_UNICODE_STRING) &DeltaUser->UserName,
|
|
0, // No desired access
|
|
&UserHandle,
|
|
ConflictingRID );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
if( (Status == STATUS_USER_EXISTS) &&
|
|
(DeltaUser->UserId == *ConflictingRID) ) {
|
|
|
|
//
|
|
// this user account has been renamed.
|
|
//
|
|
|
|
SetUserNameField = TRUE;
|
|
|
|
Status = SamrOpenUser(
|
|
DBInfo->DBHandle,
|
|
0,
|
|
DeltaUser->UserId,
|
|
&UserHandle );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
UserHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else {
|
|
|
|
NlPrint((NL_SYNC_MORE, "Parameters to SamICreateAccountByRid:\n"
|
|
"\tDomainHandle = %lx\n"
|
|
"\tAccountType = %lx\n"
|
|
"\tRelativeId = %lx\n"
|
|
"\tAccountName = %wZ\n"
|
|
"\tDesiredAccess = %lx\n"
|
|
"\tAccountHandle = %lx\n"
|
|
"\tConflictingAccountRid = %lx\n",
|
|
(DWORD)(DBInfo->DBHandle),
|
|
(DWORD)SamObjectUser,
|
|
(DWORD)DeltaUser->UserId,
|
|
&DeltaUser->UserName,
|
|
0,
|
|
(DWORD)&UserHandle,
|
|
(DWORD)*ConflictingRID ));
|
|
|
|
NlPrint((NL_SYNC_MORE, "SamICreateAccountByRid returning %lx\n",
|
|
Status ));
|
|
|
|
UserHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Set the attributes of the user.
|
|
//
|
|
// Notice that the actual text strings remain in the DeltaUser
|
|
// structure. I only copy a pointer to them to the user specific
|
|
// structure.
|
|
//
|
|
RtlZeroMemory( &UserInfo, sizeof(UserInfo) );
|
|
UserInfo.Internal3.I1.WhichFields = 0;
|
|
|
|
//
|
|
// if this account is renamed then set user name.
|
|
//
|
|
|
|
if( SetUserNameField ) {
|
|
UserInfo.Internal3.I1.UserName =
|
|
* ((PRPC_UNICODE_STRING) &DeltaUser->UserName);
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_USERNAME;
|
|
}
|
|
|
|
UserInfo.Internal3.I1.SecurityDescriptor.SecurityDescriptor =
|
|
((PSECURITY_DESCRIPTOR) DeltaUser->SecurityDescriptor);
|
|
UserInfo.Internal3.I1.SecurityDescriptor.Length = DeltaUser->SecuritySize;
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_SECURITYDESCRIPTOR;
|
|
|
|
UserInfo.Internal3.I1.FullName = * ((PRPC_UNICODE_STRING) &DeltaUser->FullName);
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_FULLNAME;
|
|
|
|
UserInfo.Internal3.I1.PrimaryGroupId = DeltaUser->PrimaryGroupId;
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_PRIMARYGROUPID;
|
|
|
|
UserInfo.Internal3.I1.HomeDirectory =
|
|
* ((PRPC_UNICODE_STRING) &DeltaUser->HomeDirectory);
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_HOMEDIRECTORY;
|
|
|
|
UserInfo.Internal3.I1.HomeDirectoryDrive =
|
|
* ((PRPC_UNICODE_STRING) &DeltaUser->HomeDirectoryDrive);
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_HOMEDIRECTORYDRIVE;
|
|
|
|
UserInfo.Internal3.I1.ScriptPath =
|
|
* ((PRPC_UNICODE_STRING) &DeltaUser->ScriptPath);
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_SCRIPTPATH;
|
|
|
|
UserInfo.Internal3.I1.ProfilePath =
|
|
* ((PRPC_UNICODE_STRING) &DeltaUser->DummyString1);
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_PROFILEPATH;
|
|
|
|
UserInfo.Internal3.I1.AdminComment =
|
|
* ((PRPC_UNICODE_STRING) &DeltaUser->AdminComment);
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_ADMINCOMMENT;
|
|
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_WORKSTATIONS;
|
|
|
|
//
|
|
// Don't replicate these. Retain the old values.
|
|
//
|
|
|
|
// UserInfo.Internal3.I1.LastLogon = DeltaUser->LastLogon;
|
|
// UserInfo.Internal3.I1.LastLogoff = DeltaUser->LastLogoff;
|
|
// UserInfo.Internal3.I1.LogonCount = DeltaUser->LogonCount;
|
|
|
|
UserInfo.Internal3.I1.PasswordLastSet = DeltaUser->PasswordLastSet;
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_PASSWORDLASTSET;
|
|
|
|
UserInfo.Internal3.I1.LogonHours.UnitsPerWeek = DeltaUser->LogonHours.UnitsPerWeek;
|
|
UserInfo.Internal3.I1.LogonHours.LogonHours = DeltaUser->LogonHours.LogonHours;
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_LOGONHOURS;
|
|
|
|
UserInfo.Internal3.I1.AccountExpires = DeltaUser->AccountExpires;
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_ACCOUNTEXPIRES;
|
|
|
|
UserInfo.Internal3.I1.UserAccountControl = DeltaUser->UserAccountControl;
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
|
|
|
|
UserInfo.Internal3.I1.UserComment = *((PRPC_UNICODE_STRING) &DeltaUser->UserComment);
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_USERCOMMENT;
|
|
|
|
UserInfo.Internal3.I1.CountryCode = DeltaUser->CountryCode;
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_COUNTRYCODE;
|
|
|
|
UserInfo.Internal3.I1.CodePage = DeltaUser->CodePage;
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_CODEPAGE;
|
|
|
|
UserInfo.Internal3.I1.Parameters = * ((PRPC_UNICODE_STRING) &DeltaUser->Parameters);
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_PARAMETERS;
|
|
|
|
//
|
|
// Set workstation list information.
|
|
//
|
|
UserInfo.Internal3.I1.WorkStations =
|
|
* ((PRPC_UNICODE_STRING) &DeltaUser->WorkStations);
|
|
|
|
|
|
|
|
//
|
|
// Set private data
|
|
// Includes passwords and password history.
|
|
//
|
|
|
|
if( DeltaUser->PrivateData.SensitiveData ) {
|
|
|
|
CRYPT_BUFFER EncryptedData;
|
|
CRYPT_BUFFER Data;
|
|
|
|
//
|
|
// need to decrypt the private data
|
|
//
|
|
|
|
EncryptedData.Length =
|
|
EncryptedData.MaximumLength =
|
|
DeltaUser->PrivateData.DataLength;
|
|
|
|
EncryptedData.Buffer = DeltaUser->PrivateData.Data;
|
|
|
|
|
|
Status = NlDecryptSensitiveData(
|
|
&EncryptedData,
|
|
&Data,
|
|
SessionInfo );
|
|
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
PrivateDataAllocated = Data.Buffer;
|
|
UserInfo.Internal3.I1.PrivateData.Buffer = (WCHAR *) Data.Buffer;
|
|
UserInfo.Internal3.I1.PrivateData.Length = (USHORT) Data.Length;
|
|
|
|
|
|
} else {
|
|
|
|
UserInfo.Internal3.I1.PrivateData.Buffer = (WCHAR *) DeltaUser->PrivateData.Data;
|
|
UserInfo.Internal3.I1.PrivateData.Length = (USHORT)
|
|
DeltaUser->PrivateData.DataLength;
|
|
}
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_PRIVATEDATA;
|
|
|
|
//
|
|
// Copy LastBadPasswordTime from DummyLong1 and DummyLong2.
|
|
//
|
|
|
|
UserInfo.Internal3.I1.BadPasswordCount = DeltaUser->BadPasswordCount;
|
|
UserInfo.Internal3.LastBadPasswordTime.HighPart = DeltaUser->DummyLong1;
|
|
UserInfo.Internal3.LastBadPasswordTime.LowPart = DeltaUser->DummyLong2;
|
|
UserInfo.Internal3.I1.WhichFields |= USER_ALL_BADPASSWORDCOUNT;
|
|
|
|
|
|
//
|
|
// Finally, set the data in SAM
|
|
//
|
|
|
|
for (;;) {
|
|
|
|
NTSTATUS TempStatus;
|
|
SAMPR_HANDLE GroupHandle;
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetInformationUser(
|
|
UserHandle,
|
|
UserInternal3Information,
|
|
&UserInfo );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
//
|
|
// If the User isn't a member of his primary group,
|
|
// make him one.
|
|
//
|
|
|
|
if ( Status == STATUS_MEMBER_NOT_IN_GROUP ) {
|
|
|
|
NlPrint((NL_CRITICAL,
|
|
"User (%lx) %wZ: User isn't member of his primary group (%lx) -- recover.\n",
|
|
DeltaUser->UserId,
|
|
&DeltaUser->UserName,
|
|
UserInfo.Internal3.I1.PrimaryGroupId ));
|
|
|
|
//
|
|
// Open the user's primary group.
|
|
//
|
|
|
|
|
|
STARTSAMTIMER;
|
|
TempStatus = SamrOpenGroup( DBInfo->DBHandle,
|
|
0, // No desired access
|
|
UserInfo.Internal3.I1.PrimaryGroupId,
|
|
&GroupHandle );
|
|
STOPSAMTIMER;
|
|
|
|
|
|
if ( !NT_SUCCESS(TempStatus)) {
|
|
|
|
NlPrint((NL_CRITICAL,
|
|
"User (%lx) %wZ: Failed to open user's primary group %lx -- Status = 0x%lx.\n",
|
|
DeltaUser->UserId,
|
|
&DeltaUser->UserName,
|
|
UserInfo.Internal3.I1.PrimaryGroupId,
|
|
TempStatus ));
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Add this user as a member of the group.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
TempStatus = SamrAddMemberToGroup( GroupHandle,
|
|
DeltaUser->UserId,
|
|
SE_GROUP_MANDATORY |
|
|
SE_GROUP_ENABLED_BY_DEFAULT |
|
|
SE_GROUP_ENABLED );
|
|
|
|
SamrCloseHandle( &GroupHandle );
|
|
STOPSAMTIMER;
|
|
|
|
if ( !NT_SUCCESS(TempStatus) ) {
|
|
NlPrint((NL_CRITICAL,
|
|
"User (%lx) %wZ: Failed to make user member of primary group %lx -- Status = 0x%lx.\n",
|
|
DeltaUser->UserId,
|
|
&DeltaUser->UserName,
|
|
UserInfo.Internal3.I1.PrimaryGroupId,
|
|
TempStatus ));
|
|
goto Cleanup;
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// No other conditions are handled.
|
|
//
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Cleanup:
|
|
|
|
|
|
if ( UserHandle != NULL ) {
|
|
STARTSAMTIMER;
|
|
SamrCloseHandle( &UserHandle );
|
|
STOPSAMTIMER;
|
|
}
|
|
|
|
|
|
if( PrivateDataAllocated != NULL ) {
|
|
MIDL_user_free( PrivateDataAllocated );
|
|
}
|
|
|
|
if ( WorkstationList != NULL ) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, WorkstationList );
|
|
}
|
|
|
|
STOPUNPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Time taken to unpack USER object:\n"));
|
|
PRINTUNPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlDeleteSamUser(
|
|
SAMPR_HANDLE DomainHandle,
|
|
ULONG Rid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete an user object.
|
|
|
|
Arguments:
|
|
|
|
DomainHandle - handle of the SAM domain.
|
|
|
|
Rid - Rid of the object to be deleted.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE UserHandle;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Delete User Object %lx\n", Rid));
|
|
|
|
Status = SamrOpenUser( DomainHandle, 0, Rid, &UserHandle );
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
Status = SamrDeleteUser( &UserHandle );
|
|
}
|
|
else if ( Status == STATUS_NO_SUCH_USER ) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
NlPrint((NL_CRITICAL, "Unable to delete User Object %lx\n", Rid));
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlDeleteSamGroup(
|
|
SAMPR_HANDLE DomainHandle,
|
|
ULONG Rid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete an group object.
|
|
|
|
Arguments:
|
|
|
|
DomainHandle - handle of the SAM domain.
|
|
|
|
Rid - Rid of the object to be deleted.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE GroupHandle;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Delete Group Object %lx\n", Rid));
|
|
|
|
Status = SamrOpenGroup( DomainHandle, 0, Rid, &GroupHandle );
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
Status = SamrDeleteGroup( &GroupHandle );
|
|
|
|
if ( Status == STATUS_MEMBER_IN_GROUP ) {
|
|
|
|
PSAMPR_GET_MEMBERS_BUFFER MembersBuffer = NULL;
|
|
DWORD i;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Deleting Group Members before "
|
|
"deleting Group Object \n"));
|
|
|
|
//
|
|
// if we are unable to delete this group because we
|
|
// still have members in this group then remove members
|
|
// first and delete it again.
|
|
//
|
|
|
|
Status = SamrGetMembersInGroup( GroupHandle, &MembersBuffer );
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
NlAssert( MembersBuffer->MemberCount != 0 );
|
|
|
|
for( i = 0; i < MembersBuffer->MemberCount; i++) {
|
|
|
|
NlPrint((NL_SYNC_MORE, "Deleting Group Member %lx\n",
|
|
MembersBuffer->Members[i] ));
|
|
|
|
Status = SamrRemoveMemberFromGroup(
|
|
GroupHandle,
|
|
MembersBuffer->Members[i] );
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
MembersBuffer = NULL;
|
|
}
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// since we have deleted all members successfully,
|
|
// delete the group now.
|
|
//
|
|
|
|
Status = SamrDeleteGroup( &GroupHandle );
|
|
}
|
|
|
|
//
|
|
// free up the sam resource consumed here.
|
|
//
|
|
|
|
if ( MembersBuffer != NULL ) {
|
|
SamIFree_SAMPR_GET_MEMBERS_BUFFER( MembersBuffer );
|
|
}
|
|
|
|
}
|
|
}
|
|
else if ( Status == STATUS_NO_SUCH_GROUP ) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
NlPrint((NL_CRITICAL, "Unable to delete Group Object %lx\n", Rid));
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlDeleteSamAlias(
|
|
SAMPR_HANDLE DomainHandle,
|
|
ULONG Rid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete an alias object.
|
|
|
|
Arguments:
|
|
|
|
DomainHandle - handle of the SAM domain.
|
|
|
|
Rid - Rid of the object to be deleted.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE AliasHandle;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Delete Alias Object %lx\n", Rid));
|
|
|
|
Status = SamrOpenAlias( DomainHandle, 0, Rid, &AliasHandle );
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
Status = SamrDeleteAlias( &AliasHandle );
|
|
|
|
if ( Status == STATUS_MEMBER_IN_ALIAS ) {
|
|
|
|
SAMPR_PSID_ARRAY Members = {0, NULL};
|
|
DWORD i;
|
|
|
|
NlPrint((NL_SYNC_MORE, "Deleting Alias Members before "
|
|
"deleting Alias Object \n"));
|
|
|
|
//
|
|
// if we are unable to delete this alias because we
|
|
// still have members in this alias then remove members
|
|
// first and delete it again.
|
|
//
|
|
|
|
Status = SamrGetMembersInAlias( AliasHandle, &Members );
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
NlAssert( Members.Count != 0 );
|
|
|
|
for( i = 0; i < Members.Count; i++) {
|
|
|
|
NlPrint((NL_SYNC_MORE, "Deleting Alias Member: " ));
|
|
NlpDumpSid( NL_SYNC_MORE, Members.Sids[i].SidPointer );
|
|
|
|
Status = SamrRemoveMemberFromAlias(
|
|
AliasHandle,
|
|
Members.Sids[i].SidPointer );
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
Members.Sids = NULL;
|
|
}
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// since we have deleted all members successfully,
|
|
// delete the alias now.
|
|
//
|
|
|
|
Status = SamrDeleteAlias( &AliasHandle );
|
|
}
|
|
|
|
//
|
|
// free up the sam resource consumed here.
|
|
//
|
|
|
|
if ( Members.Sids != NULL ) {
|
|
SamIFree_SAMPR_PSID_ARRAY( (PSAMPR_PSID_ARRAY)&Members );
|
|
}
|
|
|
|
}
|
|
}
|
|
else if ( Status == STATUS_NO_SUCH_ALIAS ) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
NlPrint((NL_CRITICAL, "Unable to delete Alias Object %lx\n", Rid));
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlUnpackSamGroup (
|
|
IN PNETLOGON_DELTA_GROUP DeltaGroup,
|
|
IN PDB_INFO DBInfo,
|
|
OUT PULONG ConflictingRID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the Sam Group to look like the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
DeltaGroup - Description of the group.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE GroupHandle = NULL;
|
|
SAMPR_GROUP_INFO_BUFFER GroupInfo;
|
|
SAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
BOOLEAN SetGroupNameField = FALSE;
|
|
|
|
DEFUNPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITUNPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTUNPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "UnPacking Group Object (%lx) %wZ\n",
|
|
DeltaGroup->RelativeId,
|
|
&DeltaGroup->Name ));
|
|
|
|
//
|
|
// Open a handle to the specified group.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamICreateAccountByRid(
|
|
DBInfo->DBHandle,
|
|
SamObjectGroup,
|
|
DeltaGroup->RelativeId,
|
|
(PRPC_UNICODE_STRING) &DeltaGroup->Name,
|
|
0, // No desired access
|
|
&GroupHandle,
|
|
ConflictingRID );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
if( (Status == STATUS_GROUP_EXISTS) &&
|
|
(DeltaGroup->RelativeId == *ConflictingRID) ) {
|
|
|
|
//
|
|
// this group account has been renamed.
|
|
//
|
|
|
|
SetGroupNameField = TRUE;
|
|
|
|
Status = SamrOpenGroup(
|
|
DBInfo->DBHandle,
|
|
0,
|
|
DeltaGroup->RelativeId,
|
|
&GroupHandle );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
GroupHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else {
|
|
|
|
GroupHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
SET_SAM_SECOBJ_INFO(DeltaGroup, GroupHandle);
|
|
|
|
//
|
|
// Set the other attributes of the group.
|
|
//
|
|
// Notice that the actual text strings remain in the DeltaGroup
|
|
// structure. I only copy a pointer to them to the group specific
|
|
// structure.
|
|
//
|
|
|
|
//
|
|
// if this account is renamed, then set new group name.
|
|
//
|
|
|
|
if ( SetGroupNameField ) {
|
|
|
|
GroupInfo.Name.Name =
|
|
* (PRPC_UNICODE_STRING) &DeltaGroup->Name;
|
|
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetInformationGroup(
|
|
GroupHandle,
|
|
GroupNameInformation,
|
|
&GroupInfo );
|
|
|
|
STOPSAMTIMER;
|
|
}
|
|
|
|
GroupInfo.Attribute.Attributes = DeltaGroup->Attributes;
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetInformationGroup(
|
|
GroupHandle,
|
|
GroupAttributeInformation,
|
|
&GroupInfo );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
GroupInfo.AdminComment.AdminComment =
|
|
* ((PRPC_UNICODE_STRING) &DeltaGroup->AdminComment);
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetInformationGroup(
|
|
GroupHandle,
|
|
GroupAdminCommentInformation,
|
|
&GroupInfo );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Cleanup:
|
|
|
|
if ( GroupHandle != NULL ) {
|
|
|
|
STARTSAMTIMER;
|
|
|
|
SamrCloseHandle( &GroupHandle );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
}
|
|
|
|
STOPUNPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Time taken to unpack GROUP object:\n"));
|
|
PRINTUNPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlUnpackSamGroupMember (
|
|
IN ULONG RelativeId,
|
|
IN PNETLOGON_DELTA_GROUP_MEMBER DeltaGroupMember,
|
|
IN PDB_INFO DBInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the Sam Group membership to look like the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
RelativeId - Relative Id of the group to open.
|
|
|
|
DeltaGroup - Description of the group membership.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE GroupHandle = NULL;
|
|
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
//
|
|
// Info returned from SAM.
|
|
//
|
|
|
|
PSAMPR_GET_MEMBERS_BUFFER OldMembersBuffer = NULL;
|
|
|
|
DEFUNPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
|
|
INITUNPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTUNPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "UnPacking GroupMember Object %lx\n", RelativeId));
|
|
|
|
//
|
|
// Open a handle to the specified group.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrOpenGroup( DBInfo->DBHandle,
|
|
0, // No desired access
|
|
RelativeId,
|
|
&GroupHandle );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
GroupHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Determine the current membership of the group.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrGetMembersInGroup( GroupHandle, &OldMembersBuffer );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
OldMembersBuffer = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// For each new member,
|
|
// If the member doesn't currently exist, add it.
|
|
// If the member exists but the attributes are wrong, change them.
|
|
//
|
|
|
|
for ( i=0; i<DeltaGroupMember->MemberCount; i++ ) {
|
|
BOOL MemberAlreadyExists;
|
|
|
|
//
|
|
// Check if this new member is already a member.
|
|
//
|
|
|
|
MemberAlreadyExists = FALSE;
|
|
for ( j=0; j<OldMembersBuffer->MemberCount; j++ ) {
|
|
if ( OldMembersBuffer->Members[j] == DeltaGroupMember->MemberIds[i] ) {
|
|
MemberAlreadyExists = TRUE;
|
|
OldMembersBuffer->Members[j] = 0; // Mark that we've used this entry
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the membership is not there already,
|
|
// add the new membership.
|
|
//
|
|
|
|
if ( !MemberAlreadyExists ) {
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrAddMemberToGroup( GroupHandle,
|
|
DeltaGroupMember->MemberIds[i],
|
|
DeltaGroupMember->Attributes[i] );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// if this member is not created yet on the backup then
|
|
// ignore the error STATUS_NO_SUCH_USER, this user
|
|
// will be added to this group automatically when his
|
|
// account is created.
|
|
//
|
|
// We could let the redo log handle this problem, but that'll
|
|
// log an error to the event log.
|
|
//
|
|
|
|
if( Status != STATUS_NO_SUCH_USER ) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If membership attributes are different,
|
|
// set the new attributes.
|
|
//
|
|
|
|
} else {
|
|
|
|
if ( DeltaGroupMember->Attributes[i] !=
|
|
OldMembersBuffer->Attributes[j] ) {
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetMemberAttributesOfGroup(
|
|
GroupHandle,
|
|
DeltaGroupMember->MemberIds[i],
|
|
DeltaGroupMember->Attributes[i] );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Loop through the list of old members, deleting those that should
|
|
// no longer exist.
|
|
//
|
|
|
|
for ( j=0; j<OldMembersBuffer->MemberCount; j++ ) {
|
|
if ( OldMembersBuffer->Members[j] != 0 ) {
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrRemoveMemberFromGroup(
|
|
GroupHandle,
|
|
OldMembersBuffer->Members[j]);
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// if this is the member's primary group then the
|
|
// user does exist on the primary, this membership
|
|
// should goaway when we do cleanup.
|
|
//
|
|
|
|
if( Status != STATUS_MEMBERS_PRIMARY_GROUP ) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Free up any locally used resources.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
if ( OldMembersBuffer != NULL ) {
|
|
SamIFree_SAMPR_GET_MEMBERS_BUFFER( OldMembersBuffer );
|
|
}
|
|
|
|
if ( GroupHandle != NULL ) {
|
|
SamrCloseHandle( &GroupHandle );
|
|
}
|
|
|
|
STOPSAMTIMER;
|
|
|
|
STOPUNPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Time taken to unpack GROUP MEMBER object:\n"));
|
|
PRINTUNPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlUnpackSamAlias (
|
|
IN PNETLOGON_DELTA_ALIAS DeltaAlias,
|
|
IN PDB_INFO DBInfo,
|
|
OUT PULONG ConflictingRID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the Sam Alias to look like the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
DeltaAlias - Description of the alias.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE AliasHandle = NULL;
|
|
|
|
SAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
SAMPR_ALIAS_INFO_BUFFER AliasInfo;
|
|
BOOLEAN SetAliasNameField = FALSE;
|
|
|
|
DEFUNPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITUNPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTUNPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "UnPacking Alias Object (%lx) %wZ\n",
|
|
DeltaAlias->RelativeId,
|
|
&DeltaAlias->Name
|
|
));
|
|
|
|
//
|
|
// Open a handle to the specified alias.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamICreateAccountByRid(
|
|
DBInfo->DBHandle,
|
|
SamObjectAlias,
|
|
DeltaAlias->RelativeId,
|
|
(PRPC_UNICODE_STRING) &DeltaAlias->Name,
|
|
0, // No desired access
|
|
&AliasHandle,
|
|
ConflictingRID );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
if( (Status == STATUS_ALIAS_EXISTS) &&
|
|
(DeltaAlias->RelativeId == *ConflictingRID) ) {
|
|
|
|
//
|
|
// this group account has been renamed.
|
|
//
|
|
|
|
SetAliasNameField = TRUE;
|
|
|
|
Status = SamrOpenAlias(
|
|
DBInfo->DBHandle,
|
|
0,
|
|
DeltaAlias->RelativeId,
|
|
&AliasHandle );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
AliasHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else {
|
|
|
|
AliasHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
SET_SAM_SECOBJ_INFO(DeltaAlias, AliasHandle);
|
|
|
|
//
|
|
// set alias name if it has been renamed.
|
|
//
|
|
|
|
if ( SetAliasNameField ) {
|
|
|
|
AliasInfo.Name.Name =
|
|
* (PRPC_UNICODE_STRING) &DeltaAlias->Name;
|
|
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetInformationAlias(
|
|
AliasHandle,
|
|
AliasNameInformation,
|
|
&AliasInfo );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
AliasInfo.AdminComment.AdminComment =
|
|
* (PRPC_UNICODE_STRING) &DeltaAlias->DummyString1;
|
|
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetInformationAlias(
|
|
AliasHandle,
|
|
AliasAdminCommentInformation,
|
|
&AliasInfo );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Cleanup:
|
|
|
|
if ( AliasHandle != NULL ) {
|
|
|
|
STARTSAMTIMER;
|
|
|
|
SamrCloseHandle( &AliasHandle );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
}
|
|
|
|
STOPUNPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Time taken to unpack ALIAS object:\n"));
|
|
PRINTUNPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlUnpackSamAliasMember (
|
|
IN ULONG RelativeId,
|
|
IN PNETLOGON_DELTA_ALIAS_MEMBER DeltaAliasMember,
|
|
IN PDB_INFO DBInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the Sam Alias membership to look like the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
RelativeId - Relative Id of the alias to open.
|
|
|
|
DeltaAlias - Description of the alias membership.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
SAMPR_HANDLE AliasHandle = NULL;
|
|
|
|
PNLPR_SID_INFORMATION DeltaSid;
|
|
PSAMPR_SID_INFORMATION MemberSid;
|
|
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
PBOOL MemberFound = NULL;
|
|
|
|
//
|
|
// Info returned from SAM.
|
|
//
|
|
|
|
SAMPR_PSID_ARRAY Members;
|
|
|
|
DEFUNPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITUNPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTUNPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "UnPacking AliasMember Object %lx\n", RelativeId));
|
|
|
|
Members.Sids = NULL;
|
|
|
|
//
|
|
// Open a handle to the specified alias.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrOpenAlias( DBInfo->DBHandle,
|
|
0, // No desired access
|
|
RelativeId,
|
|
&AliasHandle );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
AliasHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Determine the current membership of the alias.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrGetMembersInAlias( AliasHandle, &Members );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
Members.Sids = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Setup MemberFound Array
|
|
//
|
|
|
|
if( Members.Count != 0) {
|
|
|
|
MemberFound = (PBOOL) NetpMemoryAllocate(
|
|
(sizeof(BOOL)) * Members.Count );
|
|
|
|
if( MemberFound == NULL ) {
|
|
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
for ( j=0; j<Members.Count; j++ ) {
|
|
|
|
MemberFound[j] = FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// For each new member,
|
|
// If the member doesn't currently exist, add it.
|
|
// If the member exists but the attributes are wrong, change them.
|
|
//
|
|
|
|
DeltaSid = DeltaAliasMember->Members.Sids;
|
|
|
|
for ( i=0; i<DeltaAliasMember->Members.Count; i++, DeltaSid++ ) {
|
|
|
|
BOOL MemberAlreadyExists = FALSE;
|
|
|
|
//
|
|
// Check if this new member is already a member.
|
|
//
|
|
|
|
//
|
|
// first member sid pointer
|
|
//
|
|
|
|
MemberSid = Members.Sids;
|
|
|
|
for ( j=0; j<Members.Count; j++, MemberSid++ ) {
|
|
|
|
|
|
if ( RtlEqualSid( DeltaSid->SidPointer,
|
|
MemberSid->SidPointer ) ) {
|
|
|
|
MemberAlreadyExists = TRUE;
|
|
MemberFound[j] = TRUE; // Mark that we've used this entry
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If the membership is not there already,
|
|
// add the new membership.
|
|
//
|
|
|
|
if ( !MemberAlreadyExists ) {
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrAddMemberToAlias(
|
|
AliasHandle,
|
|
(PRPC_SID)((*DeltaSid).SidPointer));
|
|
|
|
STOPSAMTIMER;
|
|
|
|
|
|
//
|
|
// If the newly added member doesn't exist,
|
|
// ignore the error.
|
|
// (Either this is a deleted user, and all is OK)
|
|
// (OR this is a newly added member and partial replication
|
|
// will pick it up.)
|
|
//
|
|
//
|
|
// However, DON'T IGNORE the above errors for BUILDIN
|
|
// database due to the following reason.
|
|
//
|
|
// During the initial database replication (or forced
|
|
// fullsync replication of all three databases) the ACCOUNT
|
|
// database is replicated first then the BUILTIN
|
|
// database. For some reason the ACCOUNT database
|
|
// fullsync replication fails, the fullsync replication
|
|
// of the BUILTIN database returns this error
|
|
// (STATUS_INVALID_MEMBER or STATUS_NO_SUCH_ERROR)
|
|
// because the builtin local group may contain the SID
|
|
// of the account database user/group which is not
|
|
// replicated successfully. So if we ignore this error,
|
|
// the builtin group membership is left incomplete.
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status) &&
|
|
(( DBInfo->DBIndex == BUILTIN_DB) ||
|
|
( (Status != STATUS_INVALID_MEMBER) &&
|
|
(Status != STATUS_NO_SUCH_MEMBER)) )) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Loop through the list of old members, deleting those that should
|
|
// no longer exist.
|
|
//
|
|
|
|
MemberSid = Members.Sids;
|
|
|
|
for ( j=0; j<Members.Count; j++, MemberSid++ ) {
|
|
|
|
if ( MemberFound[j] == FALSE ) {
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrRemoveMemberFromAlias( AliasHandle,
|
|
MemberSid->SidPointer );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Free up any locally used resources.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
if ( Members.Sids != NULL ) {
|
|
SamIFree_SAMPR_PSID_ARRAY( &Members );
|
|
}
|
|
|
|
if ( AliasHandle != NULL ) {
|
|
SamrCloseHandle( &AliasHandle );
|
|
}
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if( MemberFound != NULL ) {
|
|
|
|
NetpMemoryFree( MemberFound );
|
|
|
|
}
|
|
|
|
STOPUNPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Time taken to unpack ALIASMEMBER object:\n"));
|
|
PRINTUNPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlUnpackSamDomain (
|
|
IN PNETLOGON_DELTA_DOMAIN DeltaDomain,
|
|
IN PDB_INFO DBInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the SamDomain to look like the specified buffer.
|
|
|
|
Arguments:
|
|
|
|
DeltaDomain - Description of the domain.
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Information as passed to SAM
|
|
//
|
|
|
|
SAMPR_DOMAIN_INFO_BUFFER DomainInfo;
|
|
SAMPR_SR_SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
|
|
PSAMPR_DOMAIN_INFO_BUFFER QueryDomainInfoBuf = NULL;
|
|
|
|
DEFUNPACKTIMER;
|
|
DEFSAMTIMER;
|
|
|
|
INITUNPACKTIMER;
|
|
INITSAMTIMER;
|
|
|
|
STARTUNPACKTIMER;
|
|
|
|
NlPrint((NL_SYNC_MORE, "UnPacking Domain Object\n"));
|
|
|
|
SET_SAM_SECOBJ_INFO(DeltaDomain, DBInfo->DBHandle);
|
|
|
|
//
|
|
// Set the other attributes of the domain.
|
|
//
|
|
|
|
//
|
|
// We can't set the domain name information, however we can compare
|
|
// the name information on the database with the one we received
|
|
// in the delta. If they don't match we return appropriate error.
|
|
//
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrQueryInformationDomain(
|
|
DBInfo->DBHandle,
|
|
DomainNameInformation,
|
|
&QueryDomainInfoBuf );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// compare name info.
|
|
//
|
|
|
|
if( !RtlEqualDomainName(
|
|
&DeltaDomain->DomainName,
|
|
(PUNICODE_STRING)&QueryDomainInfoBuf->Name.DomainName) ) {
|
|
|
|
Status = STATUS_NO_SUCH_DOMAIN; // ?? check status code.
|
|
goto Cleanup;
|
|
}
|
|
|
|
DomainInfo.Oem.OemInformation =
|
|
* ((PRPC_UNICODE_STRING) &DeltaDomain->OemInformation);
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetInformationDomain(
|
|
DBInfo->DBHandle,
|
|
DomainOemInformation,
|
|
&DomainInfo );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
OLD_TO_NEW_LARGE_INTEGER(
|
|
DeltaDomain->ForceLogoff,
|
|
DomainInfo.Logoff.ForceLogoff );
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetInformationDomain(
|
|
DBInfo->DBHandle,
|
|
DomainLogoffInformation,
|
|
&DomainInfo );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DomainInfo.Password.MinPasswordLength = DeltaDomain->MinPasswordLength;
|
|
DomainInfo.Password.PasswordHistoryLength = DeltaDomain->PasswordHistoryLength;
|
|
DomainInfo.Password.PasswordProperties = DeltaDomain->DummyLong1;
|
|
|
|
OLD_TO_NEW_LARGE_INTEGER(
|
|
DeltaDomain->MaxPasswordAge,
|
|
DomainInfo.Password.MaxPasswordAge );
|
|
|
|
OLD_TO_NEW_LARGE_INTEGER(
|
|
DeltaDomain->MinPasswordAge,
|
|
DomainInfo.Password.MinPasswordAge );
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetInformationDomain(
|
|
DBInfo->DBHandle,
|
|
DomainPasswordInformation,
|
|
&DomainInfo );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If the PDC passed us lockout information,
|
|
// use it.
|
|
//
|
|
// NT 1.0 PDCs will pass a zero length.
|
|
//
|
|
|
|
if ( DeltaDomain->DummyString1.Length >= sizeof(DOMAIN_LOCKOUT_INFORMATION) ) {
|
|
RtlCopyMemory( &DomainInfo.Lockout,
|
|
DeltaDomain->DummyString1.Buffer,
|
|
DeltaDomain->DummyString1.Length );
|
|
|
|
STARTSAMTIMER;
|
|
|
|
Status = SamrSetInformationDomain(
|
|
DBInfo->DBHandle,
|
|
DomainLockoutInformation,
|
|
&DomainInfo );
|
|
|
|
STOPSAMTIMER;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Don't unpack DomainModifiedCount and DomainCreationDate!!
|
|
// These will be handled separately during a full sync.
|
|
//
|
|
|
|
//
|
|
// All Done
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if ( QueryDomainInfoBuf != NULL ) {
|
|
|
|
STARTSAMTIMER;
|
|
|
|
SamIFree_SAMPR_DOMAIN_INFO_BUFFER( QueryDomainInfoBuf,
|
|
DomainNameInformation );
|
|
STOPSAMTIMER;
|
|
}
|
|
|
|
STOPUNPACKTIMER;
|
|
|
|
NlPrint((NL_REPL_OBJ_TIME,"Time taken to unpack DOMAIN object:\n"));
|
|
PRINTUNPACKTIMER;
|
|
PRINTSAMTIMER;
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// builtin domain support
|
|
//
|
|
|
|
NTSTATUS
|
|
NlUnpackSam(
|
|
IN PNETLOGON_DELTA_ENUM Delta,
|
|
IN PDB_INFO DBInfo,
|
|
OUT PULONG ConflictingRID,
|
|
PSESSION_INFO SessionInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Install a delta into the local SAM database.
|
|
|
|
Arguments:
|
|
|
|
Deltas - The delta to install
|
|
|
|
SessionInfo - Info shared between PDC and BDC
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Handle each delta type differently.
|
|
//
|
|
|
|
*ConflictingRID = 0;
|
|
|
|
switch ( Delta->DeltaType ) {
|
|
case AddOrChangeDomain:
|
|
Status = NlUnpackSamDomain(
|
|
Delta->DeltaUnion.DeltaDomain,
|
|
DBInfo);
|
|
break;
|
|
|
|
case AddOrChangeGroup:
|
|
Status = NlUnpackSamGroup(
|
|
Delta->DeltaUnion.DeltaGroup,
|
|
DBInfo,
|
|
ConflictingRID );
|
|
break;
|
|
|
|
case AddOrChangeAlias:
|
|
Status = NlUnpackSamAlias(
|
|
Delta->DeltaUnion.DeltaAlias,
|
|
DBInfo,
|
|
ConflictingRID );
|
|
break;
|
|
|
|
case AddOrChangeUser:
|
|
Status = NlUnpackSamUser(
|
|
Delta->DeltaUnion.DeltaUser,
|
|
DBInfo,
|
|
ConflictingRID,
|
|
SessionInfo );
|
|
break;
|
|
|
|
case ChangeGroupMembership:
|
|
Status = NlUnpackSamGroupMember(
|
|
Delta->DeltaID.Rid,
|
|
Delta->DeltaUnion.DeltaGroupMember,
|
|
DBInfo );
|
|
break;
|
|
|
|
case ChangeAliasMembership:
|
|
Status = NlUnpackSamAliasMember(
|
|
Delta->DeltaID.Rid,
|
|
Delta->DeltaUnion.DeltaAliasMember,
|
|
DBInfo );
|
|
break;
|
|
|
|
case DeleteGroup:
|
|
case DeleteGroupByName:
|
|
Status = NlDeleteSamGroup(
|
|
DBInfo->DBHandle,
|
|
Delta->DeltaID.Rid );
|
|
|
|
break;
|
|
|
|
case DeleteAlias:
|
|
Status = NlDeleteSamAlias(
|
|
DBInfo->DBHandle,
|
|
Delta->DeltaID.Rid );
|
|
|
|
break;
|
|
|
|
case DeleteUser:
|
|
case DeleteUserByName:
|
|
Status = NlDeleteSamUser(
|
|
DBInfo->DBHandle,
|
|
Delta->DeltaID.Rid );
|
|
|
|
break;
|
|
|
|
case AddOrChangeLsaPolicy:
|
|
Status = NlUnpackLsaPolicy(
|
|
Delta->DeltaUnion.DeltaPolicy,
|
|
DBInfo );
|
|
break;
|
|
|
|
case AddOrChangeLsaTDomain:
|
|
Status = NlUnpackLsaTDomain(
|
|
Delta->DeltaID.Sid,
|
|
Delta->DeltaUnion.DeltaTDomains,
|
|
DBInfo );
|
|
break;
|
|
|
|
case AddOrChangeLsaAccount:
|
|
Status = NlUnpackLsaAccount(
|
|
Delta->DeltaID.Sid,
|
|
Delta->DeltaUnion.DeltaAccounts,
|
|
DBInfo );
|
|
break;
|
|
|
|
case AddOrChangeLsaSecret:
|
|
Status = NlUnpackLsaSecret(
|
|
Delta->DeltaID.Name,
|
|
Delta->DeltaUnion.DeltaSecret,
|
|
DBInfo,
|
|
SessionInfo );
|
|
break;
|
|
|
|
case DeleteLsaTDomain:
|
|
Status = NlDeleteLsaTDomain(
|
|
Delta->DeltaID.Sid,
|
|
DBInfo );
|
|
break;
|
|
|
|
case DeleteLsaAccount:
|
|
Status = NlDeleteLsaAccount(
|
|
Delta->DeltaID.Sid,
|
|
DBInfo );
|
|
break;
|
|
|
|
case DeleteLsaSecret:
|
|
Status = NlDeleteLsaSecret(
|
|
Delta->DeltaID.Name,
|
|
DBInfo );
|
|
break;
|
|
|
|
// Nothing to unpack for this delta
|
|
case SerialNumberSkip:
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
NlPrint((NL_CRITICAL, "NlUnpackSam: invalid delta type %lx\n", Delta->DeltaType ));
|
|
Status = STATUS_SYNCHRONIZATION_REQUIRED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlEncryptSensitiveData(
|
|
IN OUT PCRYPT_BUFFER Data,
|
|
IN PSESSION_INFO SessionInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Encrypt data using the the server session key.
|
|
|
|
Either DES or RC4 will be used depending on the negotiated flags in SessionInfo.
|
|
|
|
Arguments:
|
|
|
|
Data: Pointer to the data to be decrypted. If the decrypted data is longer
|
|
than the encrypt data, this routine will allocate a buffer for
|
|
the returned data using MIDL_user_allocate and return a description to
|
|
that buffer here. In that case, this routine will free the buffer
|
|
containing the encrypted text data using MIDL_user_free.
|
|
|
|
SessionInfo: Info describing BDC that's calling us
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
DATA_KEY KeyData;
|
|
|
|
|
|
//
|
|
// If both sides support RC4 encryption, use it.
|
|
//
|
|
|
|
if ( SessionInfo->NegotiatedFlags & NETLOGON_SUPPORTS_RC4_ENCRYPTION ) {
|
|
|
|
NlEncryptRC4( Data->Buffer, Data->Length, SessionInfo );
|
|
Status = STATUS_SUCCESS;
|
|
|
|
|
|
//
|
|
// If the other side is running NT 1.0,
|
|
// use the slower DES based encryption.
|
|
//
|
|
|
|
} else {
|
|
CYPHER_DATA TempData;
|
|
|
|
//
|
|
// Build a data buffer to describe the encryption key.
|
|
//
|
|
|
|
KeyData.Length = sizeof(NETLOGON_SESSION_KEY);
|
|
KeyData.MaximumLength = sizeof(NETLOGON_SESSION_KEY);
|
|
KeyData.Buffer = (PVOID)&SessionInfo->SessionKey;
|
|
|
|
//
|
|
// Build a data buffer to describe the encrypted data.
|
|
//
|
|
|
|
TempData.Length = 0;
|
|
TempData.MaximumLength = 0;
|
|
TempData.Buffer = NULL;
|
|
|
|
//
|
|
// First time make the encrypt call to determine the length.
|
|
//
|
|
|
|
Status = RtlEncryptData(
|
|
(PCLEAR_DATA)Data,
|
|
&KeyData,
|
|
&TempData );
|
|
|
|
if( Status != STATUS_BUFFER_TOO_SMALL ) {
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// allocate output buffer.
|
|
//
|
|
|
|
TempData.MaximumLength = TempData.Length;
|
|
TempData.Buffer = MIDL_user_allocate( TempData.Length );
|
|
|
|
if( TempData.Buffer == NULL ) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Encrypt the data.
|
|
//
|
|
|
|
IF_DEBUG( ENCRYPT ) {
|
|
NlPrint((NL_ENCRYPT, "NlEncryptSensitiveData: Clear data\n" ));
|
|
NlpDumpHexData( NL_ENCRYPT,
|
|
(LPDWORD)Data->Buffer,
|
|
Data->Length / sizeof(DWORD) );
|
|
}
|
|
|
|
Status = RtlEncryptData(
|
|
(PCLEAR_DATA)Data,
|
|
&KeyData,
|
|
&TempData );
|
|
|
|
IF_DEBUG( ENCRYPT ) {
|
|
NlPrint((NL_ENCRYPT, "NlEncryptSensitiveData: Encrypted data\n" ));
|
|
NlpDumpHexData( NL_ENCRYPT,
|
|
(LPDWORD)TempData.Buffer,
|
|
TempData.Length / sizeof(DWORD) );
|
|
}
|
|
|
|
//
|
|
// Return either the clear text or encrypted buffer to the caller.
|
|
//
|
|
|
|
if( NT_SUCCESS(Status) ) {
|
|
MIDL_user_free( Data->Buffer );
|
|
Data->Length = TempData.Length;
|
|
Data->MaximumLength = TempData.MaximumLength;
|
|
Data->Buffer = TempData.Buffer;
|
|
} else {
|
|
MIDL_user_free( TempData.Buffer );
|
|
}
|
|
|
|
}
|
|
|
|
return( Status );
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NlDecryptSensitiveData(
|
|
IN PCRYPT_BUFFER Data,
|
|
OUT PCRYPT_BUFFER DecryptedData,
|
|
IN PSESSION_INFO SessionInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decrypt data using the the server session key.
|
|
|
|
Either DES or RC4 will be used depending on the negotiated flags in SessionInfo.
|
|
|
|
Note: this routine doesn't decrypt in place since the caller typically
|
|
wants to save the encrypted data so that the operation can be retried.
|
|
Perhaps, I could mark the buffer that the decryption had already
|
|
taken place.
|
|
|
|
Arguments:
|
|
|
|
Data: Pointer to the data to be decrypted.
|
|
|
|
DecryptedData: Returns a decriptor of the decypted data. The buffer
|
|
should be deallocated using MIDL_user_free.
|
|
|
|
SessionInfo: Info describing BDC that's calling us
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
//
|
|
// If both sides support RC4 encryption, use it.
|
|
//
|
|
|
|
if ( SessionInfo->NegotiatedFlags & NETLOGON_SUPPORTS_RC4_ENCRYPTION ) {
|
|
|
|
//
|
|
// Allocate a buffer and copy the encrypted data into it.
|
|
// RC4 decrypts in place.
|
|
//
|
|
|
|
DecryptedData->Buffer = MIDL_user_allocate( Data->Length );
|
|
if ( DecryptedData->Buffer == NULL ) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
DecryptedData->Length = DecryptedData->MaximumLength = Data->Length;
|
|
RtlCopyMemory( DecryptedData->Buffer, Data->Buffer, Data->Length );
|
|
|
|
NlDecryptRC4( DecryptedData->Buffer, DecryptedData->Length, SessionInfo );
|
|
return STATUS_SUCCESS;
|
|
|
|
|
|
//
|
|
// If the other side is running NT 1.0,
|
|
// use the slower DES based encryption.
|
|
//
|
|
|
|
} else {
|
|
NTSTATUS Status;
|
|
DATA_KEY KeyData;
|
|
|
|
|
|
//
|
|
// build keydata buffer.
|
|
//
|
|
|
|
KeyData.Length = sizeof(NETLOGON_SESSION_KEY);
|
|
KeyData.MaximumLength = sizeof(NETLOGON_SESSION_KEY);
|
|
KeyData.Buffer = (PVOID)&SessionInfo->SessionKey;
|
|
|
|
|
|
//
|
|
// First time make the decrypt call to determine the length.
|
|
//
|
|
|
|
DecryptedData->Length = 0;
|
|
DecryptedData->MaximumLength = 0;
|
|
DecryptedData->Buffer = NULL;
|
|
|
|
Status = RtlDecryptData( Data, &KeyData, DecryptedData );
|
|
|
|
if( Status != STATUS_BUFFER_TOO_SMALL ) {
|
|
|
|
if( NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// set return buffer
|
|
//
|
|
|
|
DecryptedData->Length = 0;
|
|
DecryptedData->MaximumLength = 0;
|
|
DecryptedData->Buffer = NULL;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// allocate output buffer.
|
|
//
|
|
|
|
DecryptedData->MaximumLength = DecryptedData->Length;
|
|
DecryptedData->Buffer = MIDL_user_allocate( DecryptedData->Length );
|
|
|
|
if( DecryptedData->Buffer == NULL ) {
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Decrypt the data
|
|
//
|
|
|
|
IF_DEBUG( ENCRYPT ) {
|
|
NlPrint((NL_ENCRYPT, "NlDecryptSensitiveData: Encrypted data\n" ));
|
|
NlpDumpHexData( NL_ENCRYPT,
|
|
(LPDWORD)Data->Buffer,
|
|
Data->Length / sizeof(DWORD) );
|
|
}
|
|
|
|
Status = RtlDecryptData( Data, &KeyData, DecryptedData);
|
|
|
|
IF_DEBUG( ENCRYPT ) {
|
|
NlPrint((NL_ENCRYPT, "NlDecryptSensitiveData: Clear data\n" ));
|
|
NlpDumpHexData( NL_ENCRYPT,
|
|
(LPDWORD)DecryptedData->Buffer,
|
|
DecryptedData->Length / sizeof(DWORD) );
|
|
}
|
|
|
|
//
|
|
// Free the buffer if we couldn't decrypt into it.
|
|
//
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
MIDL_user_free( DecryptedData->Buffer );
|
|
DecryptedData->Buffer = NULL;
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|