windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/logonsrv/server/replutil.c

1605 lines
36 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1987-1996 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
#pragma hdrstop
//
// Include files specific to this .c file
//
#include <accessp.h> // NetpConvertWorkstationList
#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 = SamIOpenAccount( DBInfo->DBHandle,
RelativeId,
SecurityDbObjectSamUser,
&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) );
// INIT_PLACE_HOLDER(DeltaUser);
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);
}
//
// 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 = SamIOpenAccount( DBInfo->DBHandle,
RelativeId,
SecurityDbObjectSamGroup,
&GroupHandle );
if (!NT_SUCCESS(Status)) {
GroupHandle = NULL;
goto Cleanup;
}
STOPSAMTIMER;
QUERY_SAM_SECOBJ_INFO(GroupHandle);
STARTSAMTIMER;
Status = SamrQueryInformationGroup(
GroupHandle,
GroupReplicationInformation,
&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) );
// INIT_PLACE_HOLDER(DeltaGroup);
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 );
DELTA_SECOBJ_INFO(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,
GroupReplicationInformation );
}
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 = SamIOpenAccount( DBInfo->DBHandle,
RelativeId,
SecurityDbObjectSamGroup,
&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 = SamIOpenAccount( DBInfo->DBHandle,
RelativeId,
SecurityDbObjectSamAlias,
&AliasHandle );
STOPSAMTIMER;
if (!NT_SUCCESS(Status)) {
AliasHandle = NULL;
goto Cleanup;
}
QUERY_SAM_SECOBJ_INFO(AliasHandle);
//
// Determine the alias name.
//
STARTSAMTIMER;
Status = SamrQueryInformationAlias(
AliasHandle,
AliasReplicationInformation,
&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) );
// INIT_PLACE_HOLDER(DeltaAlias);
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);
//
// 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,
AliasReplicationInformation );
}
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 = SamIOpenAccount( DBInfo->DBHandle,
RelativeId,
SecurityDbObjectSamAlias,
&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;
}
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) );
// INIT_PLACE_HOLDER(DeltaDomain);
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);
//
// 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
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 3.1,
// 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_NL_DEBUG( ENCRYPT ) {
NlPrint((NL_ENCRYPT, "NlEncryptSensitiveData: Clear data: " ));
NlpDumpBuffer( NL_ENCRYPT, Data->Buffer, Data->Length );
}
Status = RtlEncryptData(
(PCLEAR_DATA)Data,
&KeyData,
&TempData );
IF_NL_DEBUG( ENCRYPT ) {
NlPrint((NL_ENCRYPT, "NlEncryptSensitiveData: Encrypted data: " ));
NlpDumpBuffer( NL_ENCRYPT, TempData.Buffer, TempData.Length );
}
//
// 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 );
}