NT4/private/nlsecutl/nlrepl.c
2020-09-30 17:12:29 +02:00

647 lines
16 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1987-1991 Microsoft Corporation
Module Name:
nlrepl.c
Abstract:
The database replication functions called either from LSA OR SAM.
The actual code resides in netlogon.dll.
Author:
Madan Appiah (Madana)
Environment:
User mode only.
Contains NT-specific code.
Requires ANSI C extensions: slash-slash comments, long external names.
Revision History:
14-Apr-1992 (madana)
Created.
--*/
#include <nt.h> // needed for NTSTATUS
#include <ntrtl.h> // needed for nturtl.h
#include <nturtl.h> // needed for windows.h
#include <windows.h> // win32 typedefs
#include <crypt.h> // samsrv.h will need this
#include <ntlsa.h> // needed for POLICY_LSA_SERVER_ROLE
#include <samrpc.h>
#include <samisrv.h> // needed for SECURITY_DB_TYPE etc.
#include <nlrepl.h> // proto types
#define REPLICATION_ENABLED
typedef NTSTATUS
(*PI_NETNOTIFYDELTA) (
IN SECURITY_DB_TYPE DbType,
IN LARGE_INTEGER ModificationCount,
IN SECURITY_DB_DELTA_TYPE DeltaType,
IN SECURITY_DB_OBJECT_TYPE ObjectType,
IN ULONG ObjectRid,
IN PSID ObjectSid,
IN PUNICODE_STRING ObjectName,
IN DWORD ReplicationImmediately,
IN PSAM_DELTA_DATA MemberId
);
typedef NTSTATUS
(*PI_NETNOTIFYROLE) (
IN POLICY_LSA_SERVER_ROLE Role
);
typedef NTSTATUS
(*PI_NETNOTIFYMACHINEACCOUNT) (
IN ULONG ObjectRid,
IN PSID DomainSid,
IN ULONG OldUserAccountControl,
IN ULONG NewUserAccountControl,
IN PUNICODE_STRING ObjectName
);
typedef NTSTATUS
(*PI_NETGETANYDCNAME) (
IN PUNICODE_STRING DomainName,
OUT PUNICODE_STRING Buffer
);
typedef NTSTATUS
(*PI_NETNOTIFYNETLOGONDLLHANDLE) (
IN PHANDLE Role
);
//
// Global status
//
#ifdef REPLICATION_ENABLED
HANDLE NetlogonDllHandle = NULL;
PI_NETNOTIFYDELTA pI_NetNotifyDelta = NULL;
PI_NETNOTIFYROLE pI_NetNotifyRole = NULL;
PI_NETNOTIFYMACHINEACCOUNT pI_NetNotifyMachineAccount = NULL;
PI_NETGETANYDCNAME pI_NetGetAnyDcName = NULL;
NTSTATUS
NlLoadNetlogonDll(
VOID
)
/*++
Routine Description:
This function loads the netlogon.dll module if it is not loaded
already. If the network is not installed then netlogon.dll will not
present in the system and the LoadLibrary will fail.
Arguments:
None
Return Value:
NT Status code.
--*/
{
static NTSTATUS DllLoadStatus = STATUS_SUCCESS;
PI_NETNOTIFYNETLOGONDLLHANDLE pI_NetNotifyNetlogonDllHandle = NULL;
HANDLE DllHandle = NULL;
//
// If we've tried to load the DLL before and it failed,
// return the same error code again.
//
if( DllLoadStatus != STATUS_SUCCESS ) {
goto Cleanup;
}
//
// Load netlogon.dll
//
DllHandle = LoadLibraryA( "Netlogon" );
if ( DllHandle == NULL ) {
#if DBG
DWORD DbgError;
DbgError = GetLastError();
DbgPrint("[Security Process] can't load netlogon.dll %d \n",
DbgError);
#endif // DBG
DllLoadStatus = STATUS_DLL_NOT_FOUND;
goto Cleanup;
}
//
// Find the address of the I_NetNotifyDelta procedure.
//
pI_NetNotifyDelta = (PI_NETNOTIFYDELTA)
GetProcAddress( DllHandle, "I_NetNotifyDelta" );
if( pI_NetNotifyDelta == NULL ) {
#if DBG
DWORD DbgError;
DbgError = GetLastError();
DbgPrint("[Security Process] can't load I_NetNotifyDelta Proc %ld \n", DbgError);
#endif // DBG
DllLoadStatus = STATUS_PROCEDURE_NOT_FOUND;
goto Cleanup;
}
//
// Find the address of the I_NetNotifyRole procedure.
//
pI_NetNotifyRole = (PI_NETNOTIFYROLE)
GetProcAddress( DllHandle, "I_NetNotifyRole" );
if( pI_NetNotifyRole == NULL ) {
#if DBG
DWORD DbgError;
DbgError = GetLastError();
DbgPrint("[Security Process] can't load I_NetNotifyRole Proc %ld\n",
DbgError);
#endif // DBG
DllLoadStatus = STATUS_PROCEDURE_NOT_FOUND;
goto Cleanup;
}
//
// Find the address of the I_NetNotifyMachineAccount procedure.
//
pI_NetNotifyMachineAccount = (PI_NETNOTIFYMACHINEACCOUNT)
GetProcAddress( DllHandle, "I_NetNotifyMachineAccount" );
if( pI_NetNotifyMachineAccount == NULL ) {
#if DBG
DWORD DbgError;
DbgError = GetLastError();
DbgPrint("[Security Process] can't load I_NetNotifyMachineAccount Proc"
" %ld \n", DbgError);
#endif // DBG
DllLoadStatus = STATUS_PROCEDURE_NOT_FOUND;
goto Cleanup;
}
//
// Find the address of the I_NetGetAnyDcName procedure.
//
pI_NetGetAnyDcName = (PI_NETGETANYDCNAME)
GetProcAddress( DllHandle, "I_NetGetAnyDCName" );
if( pI_NetGetAnyDcName == NULL ) {
#if DBG
DWORD DbgError;
DbgError = GetLastError();
DbgPrint("[Security Process] can't load I_NetGetAnyDcName Proc"
" %ld \n", DbgError);
#endif // DBG
DllLoadStatus = STATUS_PROCEDURE_NOT_FOUND;
goto Cleanup;
}
//
// Find the address of the I_NetNotifyNetlogonDllHandle procedure.
// This is an optional procedure so don't complain if it isn't there.
//
pI_NetNotifyNetlogonDllHandle = (PI_NETNOTIFYNETLOGONDLLHANDLE)
GetProcAddress( DllHandle, "I_NetNotifyNetlogonDllHandle" );
DllLoadStatus = STATUS_SUCCESS;
Cleanup:
if (DllLoadStatus == STATUS_SUCCESS) {
NetlogonDllHandle = DllHandle;
//
// Notify Netlogon that we've loaded it.
//
if( pI_NetNotifyNetlogonDllHandle != NULL ) {
(VOID) (*pI_NetNotifyNetlogonDllHandle)( &NetlogonDllHandle );
}
} else {
if ( DllHandle != NULL ) {
FreeLibrary( DllHandle );
}
}
return( DllLoadStatus );
}
#endif // REPLICATION_ENABLED
NTSTATUS
I_NetNotifyDelta (
IN SECURITY_DB_TYPE DbType,
IN LARGE_INTEGER ModificationCount,
IN SECURITY_DB_DELTA_TYPE DeltaType,
IN SECURITY_DB_OBJECT_TYPE ObjectType,
IN ULONG ObjectRid,
IN PSID ObjectSid,
IN PUNICODE_STRING ObjectName,
IN DWORD ReplicationImmediately,
IN PSAM_DELTA_DATA MemberId
)
/*++
Routine Description:
This function is called by the SAM and LSA services after each
change is made to the SAM and LSA databases. The services describe
the type of object that is modified, the type of modification made
on the object, the serial number of this modification etc. This
information is stored for later retrieval when a BDC or member
server wants a copy of this change. See the description of
I_NetSamDeltas for a description of how the change log is used.
Add a change log entry to circular change log maintained in cache as
well as on the disk and update the head and tail pointers
It is assumed that Tail points to a block where this new change log
entry may be stored.
NOTE: The actual code is in netlogon.dll. This wrapper function
will determine whether the network is installed, if so, it calls the
actual worker function after loading the netlogon.dll module. If the
network is not installed then this will function will return with
appropriate error code.
Arguments:
DbType - Type of the database that has been modified.
ModificationCount - The value of the DomainModifiedCount field for the
domain following the modification.
DeltaType - The type of modification that has been made on the object.
ObjectType - The type of object that has been modified.
ObjectRid - The relative ID of the object that has been modified.
This parameter is valid only when the object type specified is
either SecurityDbObjectSamUser, SecurityDbObjectSamGroup or
SecurityDbObjectSamAlias otherwise this parameter is set to zero.
ObjectSid - The SID of the object that has been modified. If the object
modified is in a SAM database, ObjectSid is the DomainId of the Domain
containing the object.
ObjectName - The name of the secret object when the object type
specified is SecurityDbObjectLsaSecret or the old name of the object
when the object type specified is either SecurityDbObjectSamUser,
SecurityDbObjectSamGroup or SecurityDbObjectSamAlias and the delta
type is SecurityDbRename otherwise this parameter is set to NULL.
ReplicateImmediately - TRUE if the change should be immediately
replicated to all BDCs. A password change should set the flag
TRUE.
MemberId - This parameter is specified when group/alias membership
is modified. This structure will then point to the member's ID that
has been updated.
Return Value:
STATUS_SUCCESS - The Service completed successfully.
--*/
{
#ifdef REPLICATION_ENABLED
NTSTATUS NtStatus;
//
// Load netlogon.dll if it hasn't already been loaded.
//
if( NetlogonDllHandle == NULL ) {
if( (NtStatus = NlLoadNetlogonDll()) != STATUS_SUCCESS ) {
return( NtStatus );
}
}
NtStatus = (*pI_NetNotifyDelta)(
DbType,
ModificationCount,
DeltaType,
ObjectType,
ObjectRid,
ObjectSid,
ObjectName,
ReplicationImmediately,
MemberId
);
#if notdef
//
// Free the library so it can be replace without rebooting. ??
//
(VOID) FreeLibrary( NetlogonDllHandle );
NetlogonDllHandle = NULL;
#endif // notdef
#if notdef
if( !NT_SUCCESS(NtStatus) ) {
DbgPrint("[Security Process] I_NetNotifyDelta returns %lx \n",
NtStatus);
}
#endif // notdef
return( STATUS_SUCCESS );
#else // REPLICATION_ENABLED
return(STATUS_SUCCESS);
DBG_UNREFERENCED_PARAMETER( DbType );
DBG_UNREFERENCED_PARAMETER( ModificationCount );
DBG_UNREFERENCED_PARAMETER( DeltaType );
DBG_UNREFERENCED_PARAMETER( ObjectType );
DBG_UNREFERENCED_PARAMETER( ObjectRid );
DBG_UNREFERENCED_PARAMETER( ObjectSid );
DBG_UNREFERENCED_PARAMETER( ObjectName );
DBG_UNREFERENCED_PARAMETER( ReplicationImmediately );
DBG_UNREFERENCED_PARAMETER( MemberId );
#endif // REPLICATION_ENABLED
}
NTSTATUS
I_NetNotifyRole(
IN POLICY_LSA_SERVER_ROLE Role
)
/*++
Routine Description:
This function is called by the LSA service upon LSA initialization
and when LSA changes domain role. This routine will initialize the
change log cache if the role specified is PDC or delete the change
log cache if the role specified is other than PDC.
When this function initializing the change log if the change log
currently exists on disk, the cache will be initialized from disk.
LSA should treat errors from this routine as non-fatal. LSA should
log the errors so they may be corrected then continue
initialization. However, LSA should treat the system databases as
read-only in this case.
NOTE: The actual code is in netlogon.dll. This wrapper function
will determine whether the network is installed, if so, it calls the
actual worker function after loading the netlogon.dll module. If the
network is not installed then this will function will return with
appropriate error code.
Arguments:
Role - Current role of the server.
Return Value:
STATUS_SUCCESS - The Service completed successfully.
--*/
{
#ifdef REPLICATION_ENABLED
NTSTATUS NtStatus;
//
// Load netlogon.dll if it hasn't already been loaded.
//
if( NetlogonDllHandle == NULL ) {
if( (NtStatus = NlLoadNetlogonDll()) != STATUS_SUCCESS ) {
return( NtStatus );
}
}
NtStatus = (*pI_NetNotifyRole)(
Role
);
#if DBG
if( !NT_SUCCESS(NtStatus) ) {
DbgPrint("[Security Process] I_NetNotifyRole returns 0x%lx \n",
NtStatus);
}
#endif // DBG
return( STATUS_SUCCESS );
#else // REPLICATION_ENABLED
return(STATUS_SUCCESS);
DBG_UNREFERENCED_PARAMETER( Role );
#endif // REPLICATION_ENABLED
}
NTSTATUS
I_NetNotifyMachineAccount (
IN ULONG ObjectRid,
IN PSID DomainSid,
IN ULONG OldUserAccountControl,
IN ULONG NewUserAccountControl,
IN PUNICODE_STRING ObjectName
)
/*++
Routine Description:
This function is called by the SAM to indicate that the account type
of a machine account has changed. Specifically, if
USER_INTERDOMAIN_TRUST_ACCOUNT, USER_WORKSTATION_TRUST_ACCOUNT, or
USER_SERVER_TRUST_ACCOUNT change for a particular account, this
routine is called to let Netlogon know of the account change.
NOTE: The actual code is in netlogon.dll. This wrapper function
will determine whether the network is installed, if so, it calls the
actual worker function after loading the netlogon.dll module. If the
network is not installed then this will function will return with
appropriate error code.
Arguments:
ObjectRid - The relative ID of the object that has been modified.
DomainSid - Specifies the SID of the Domain containing the object.
OldUserAccountControl - Specifies the previous value of the
UserAccountControl field of the user.
NewUserAccountControl - Specifies the new (current) value of the
UserAccountControl field of the user.
ObjectName - The name of the account being changed.
Return Value:
Status of the operation.
--*/
{
NTSTATUS NtStatus;
//
// Load netlogon.dll if it hasn't already been loaded.
//
if( NetlogonDllHandle == NULL ) {
if( (NtStatus = NlLoadNetlogonDll()) != STATUS_SUCCESS ) {
return( NtStatus );
}
}
NtStatus = (*pI_NetNotifyMachineAccount)(
ObjectRid,
DomainSid,
OldUserAccountControl,
NewUserAccountControl,
ObjectName );
#if DBG
if( !NT_SUCCESS(NtStatus) ) {
DbgPrint("[Security Process] I_NetNotifyMachineAccount returns 0x%lx\n",
NtStatus);
}
#endif // DBG
return( NtStatus );
}
NTSTATUS
I_NetGetAnyDCName (
IN PUNICODE_STRING DomainName,
OUT PUNICODE_STRING Buffer
)
/*++
Routine Description:
Get the name of the any domain controller for a trusted domain.
The domain controller found in guaranteed to have be up at one point during
this API call. The machine is also guaranteed to be a DC in the domain
specified.
The caller of this routine should not have any locks held (it calls the
LSA back in several instances). This routine may take some time to execute.
Arguments:
DomainName - name of domain.
UncDcName - Fills in the Unicode string structure to point to an allocated
buffer containing the servername of a DC of the domain.
The server name is prefixed by \\.
The buffer should be deallocated using MIDL_user_free.
Return Value:
STATUS_SUCCESS - Success. Buffer contains DC name prefixed by \\.
STATUS_NO_LOGON_SERVERS - No DC could be found
STATUS_NO_SUCH_DOMAIN - The specified domain is not a trusted domain.
STATUS_NO_TRUST_LSA_SECRET - The client side of the trust relationship is
broken.
STATUS_NO_TRUST_SAM_ACCOUNT - The server side of the trust relationship is
broken or the password is broken.
STATUS_DOMAIN_TRUST_INCONSISTENT - The server that responded is not a proper
domain controller of the specified domain.
--*/
{
NTSTATUS NtStatus;
//
// Load netlogon.dll if it hasn't already been loaded.
//
if( NetlogonDllHandle == NULL ) {
if( (NtStatus = NlLoadNetlogonDll()) != STATUS_SUCCESS ) {
return( NtStatus );
}
}
NtStatus = (*pI_NetGetAnyDcName)(
DomainName,
Buffer );
#if DBG
if( !NT_SUCCESS(NtStatus) ) {
DbgPrint("[Security Process] I_NetGetAnyDcName returns 0x%lx\n",
NtStatus);
}
#endif // DBG
return( NtStatus );
}