windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/lls/server/repl.c
2020-09-26 16:20:57 +08:00

697 lines
21 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
repl.c
Abstract:
Author:
Arthur Hanson (arth) 06-Jan-1995
Revision History:
Jeff Parham (jeffparh) 05-Dec-1995
o Added replication of certificate database and secure service list.
o Log failure to connect during replication only if the target server
is running a build in which license server should be available (i.e.,
1057 (3.51) or greater). If the target server does not support
license server, log a message to that effect only once.
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <dsgetdc.h>
#include "debug.h"
#include "llsutil.h"
#include <llsapi.h>
#include "llssrv.h"
#include "mapping.h"
#include "msvctbl.h"
#include "svctbl.h"
#include "perseat.h"
#include "server.h"
#include "repl.h"
#include "llsrpc_s.h"
#include "pack.h"
#include "llsevent.h"
#include "certdb.h"
#include "registry.h"
HANDLE ReplicationEvent;
volatile HANDLE LlsRPCHandle = NULL; // Make sure it's reread after we enter critsec
PLLS_REPL_CONNECT_W pLlsReplConnect = NULL;
PLLS_REPL_CLOSE pLlsReplClose = NULL;
PLLS_FREE_MEMORY pLlsFreeMemory = NULL;
PLLS_REPLICATION_REQUEST_W pLlsReplicationRequestW = NULL;
PLLS_REPLICATION_SERVER_ADD_W pLlsReplicationServerAddW = NULL;
PLLS_REPLICATION_SERVER_SERVICE_ADD_W pLlsReplicationServerServiceAddW = NULL;
PLLS_REPLICATION_SERVICE_ADD_W pLlsReplicationServiceAddW = NULL;
PLLS_REPLICATION_USER_ADD_W pLlsReplicationUserAddW = NULL;
PLLS_CAPABILITY_IS_SUPPORTED pLlsCapabilityIsSupported = NULL;
PLLS_REPLICATION_CERT_DB_ADD_W pLlsReplicationCertDbAddW = NULL;
PLLS_REPLICATION_PRODUCT_SECURITY_ADD_W pLlsReplicationProductSecurityAddW = NULL;
PLLS_REPLICATION_USER_ADD_EX_W pLlsReplicationUserAddExW = NULL;
PLLS_CONNECT_W pLlsConnectW = NULL;
PLLS_CLOSE pLlsClose = NULL;
PLLS_LICENSE_ADD_W pLlsLicenseAddW = NULL;
NTSTATUS
ReplicationInitDelayed ()
{
if (LlsRPCHandle != NULL)
{
return NOERROR;
}
RtlEnterCriticalSection(&g_csLock);
if (LlsRPCHandle == NULL)
{
//
// Open up our RPC DLL and init our function references.
//
LlsRPCHandle = LoadLibrary(TEXT("LLSRPC.DLL"));
ASSERT(LlsRPCHandle != NULL);
if (LlsRPCHandle != NULL) {
pLlsReplConnect = (PLLS_REPL_CONNECT_W)GetProcAddress(LlsRPCHandle, ("LlsReplConnectW"));
pLlsReplClose = (PLLS_REPL_CLOSE)GetProcAddress(LlsRPCHandle, ("LlsReplClose"));
pLlsFreeMemory = (PLLS_FREE_MEMORY)GetProcAddress(LlsRPCHandle, ("LlsFreeMemory"));
pLlsReplicationRequestW = (PLLS_REPLICATION_REQUEST_W)GetProcAddress(LlsRPCHandle, ("LlsReplicationRequestW"));
pLlsReplicationServerAddW = (PLLS_REPLICATION_SERVER_ADD_W)GetProcAddress(LlsRPCHandle, ("LlsReplicationServerAddW"));
pLlsReplicationServerServiceAddW = (PLLS_REPLICATION_SERVER_SERVICE_ADD_W)GetProcAddress(LlsRPCHandle, ("LlsReplicationServerServiceAddW"));
pLlsReplicationServiceAddW = (PLLS_REPLICATION_SERVICE_ADD_W)GetProcAddress(LlsRPCHandle, ("LlsReplicationServiceAddW"));
pLlsReplicationUserAddW = (PLLS_REPLICATION_USER_ADD_W)GetProcAddress(LlsRPCHandle, ("LlsReplicationUserAddW"));
pLlsReplicationCertDbAddW = (PLLS_REPLICATION_CERT_DB_ADD_W) GetProcAddress(LlsRPCHandle, ("LlsReplicationCertDbAddW"));
pLlsReplicationProductSecurityAddW = (PLLS_REPLICATION_PRODUCT_SECURITY_ADD_W) GetProcAddress(LlsRPCHandle, ("LlsReplicationProductSecurityAddW"));
pLlsReplicationUserAddExW = (PLLS_REPLICATION_USER_ADD_EX_W) GetProcAddress(LlsRPCHandle, ("LlsReplicationUserAddExW"));
pLlsCapabilityIsSupported = (PLLS_CAPABILITY_IS_SUPPORTED) GetProcAddress(LlsRPCHandle, ("LlsCapabilityIsSupported"));
pLlsConnectW = (PLLS_CONNECT_W) GetProcAddress(LlsRPCHandle, ("LlsConnectW"));
pLlsClose = (PLLS_CLOSE) GetProcAddress(LlsRPCHandle, ("LlsClose"));
pLlsLicenseAddW = (PLLS_LICENSE_ADD_W) GetProcAddress(LlsRPCHandle, ("LlsLicenseAddW"));
ASSERT (pLlsReplConnect != NULL);
ASSERT (pLlsReplClose != NULL);
ASSERT (pLlsFreeMemory != NULL);
ASSERT (pLlsReplicationRequestW != NULL);
ASSERT (pLlsReplicationServerAddW != NULL);
ASSERT (pLlsReplicationServerServiceAddW != NULL);
ASSERT (pLlsReplicationServiceAddW != NULL);
ASSERT (pLlsReplicationUserAddW != NULL);
ASSERT (pLlsReplicationCertDbAddW != NULL);
ASSERT (pLlsReplicationProductSecurityAddW != NULL);
ASSERT (pLlsReplicationUserAddExW != NULL);
ASSERT (pLlsCapabilityIsSupported != NULL);
ASSERT (pLlsConnectW != NULL);
ASSERT (pLlsClose != NULL);
ASSERT (pLlsLicenseAddW != NULL);
}
}
RtlLeaveCriticalSection(&g_csLock);
return NOERROR;
}
/////////////////////////////////////////////////////////////////////////
NTSTATUS
ReplicationInit ( )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
DWORD Ignore;
HANDLE Thread;
NTSTATUS Status;
DWORD Time;
#if DBG
if (TraceFlags & (TRACE_FUNCTION_TRACE | TRACE_REPLICATION))
dprintf(TEXT("LLS TRACE: ReplicationInit\n"));
#endif
//
// Create the Replication Management event
//
Status = NtCreateEvent(
&ReplicationEvent,
EVENT_QUERY_STATE | EVENT_MODIFY_STATE | SYNCHRONIZE,
NULL,
SynchronizationEvent,
FALSE
);
ASSERT(NT_SUCCESS(Status));
//
// Fire off the thread to watch for replication.
//
Thread = CreateThread(
NULL,
0L,
(LPTHREAD_START_ROUTINE) ReplicationManager,
0L,
0L,
&Ignore
);
if (NULL != Thread)
CloseHandle(Thread);
return STATUS_SUCCESS;
} // ReplicationInit
/////////////////////////////////////////////////////////////////////////
NTSTATUS
ReplicationDo (
LLS_HANDLE LlsHandle,
LLS_REPL_HANDLE ReplHandle,
DWORD LastReplicated
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
PREPL_SERVICE_RECORD Services = NULL;
ULONG ServicesTotalRecords = 0;
PREPL_SERVER_RECORD Servers = NULL;
ULONG ServersTotalRecords = 0;
PREPL_SERVER_SERVICE_RECORD ServerServices = NULL;
ULONG ServerServicesTotalRecords = 0;
REPL_CERTIFICATE_DB_0 CertificateDB;
REPL_PRODUCT_SECURITY_0 ProductSecurity;
DWORD UserLevel = 0;
REPL_USER_RECORD_CONTAINER UserDB;
#if DBG
if (TraceFlags & (TRACE_FUNCTION_TRACE | TRACE_REPLICATION))
dprintf(TEXT("LLS TRACE: ReplicationDo\n"));
#endif
//
// Pack all of our data into linear / self-relative buffers so we
// can send them over.
//
ZeroMemory( &UserDB, sizeof( UserDB ) );
ZeroMemory( &CertificateDB, sizeof( CertificateDB ) );
ZeroMemory( &ProductSecurity, sizeof( ProductSecurity ) );
if ( (*pLlsCapabilityIsSupported)( LlsHandle, LLS_CAPABILITY_REPLICATE_USERS_EX ) )
{
UserLevel = 1;
Status = PackAll( LastReplicated, &ServicesTotalRecords, &Services, &ServersTotalRecords, &Servers, &ServerServicesTotalRecords, &ServerServices, 1, &UserDB.Level1.NumUsers, &UserDB.Level1.Users );
if (Status != STATUS_SUCCESS)
goto ReplicationDoExit;
}
else
{
UserLevel = 0;
Status = PackAll( LastReplicated, &ServicesTotalRecords, &Services, &ServersTotalRecords, &Servers, &ServerServicesTotalRecords, &ServerServices, 0, &UserDB.Level0.NumUsers, &UserDB.Level0.Users );
if (Status != STATUS_SUCCESS)
goto ReplicationDoExit;
}
if ( (*pLlsCapabilityIsSupported)( LlsHandle, LLS_CAPABILITY_REPLICATE_CERT_DB ) )
{
Status = CertDbPack( &CertificateDB.StringSize, &CertificateDB.Strings, &CertificateDB.HeaderContainer.Level0.NumHeaders, &CertificateDB.HeaderContainer.Level0.Headers, &CertificateDB.ClaimContainer.Level0.NumClaims, &CertificateDB.ClaimContainer.Level0.Claims );
if (Status != STATUS_SUCCESS)
goto ReplicationDoExit;
}
if ( (*pLlsCapabilityIsSupported)( LlsHandle, LLS_CAPABILITY_REPLICATE_PRODUCT_SECURITY ) )
{
Status = ProductSecurityPack( &ProductSecurity.StringSize, &ProductSecurity.Strings );
if (Status != STATUS_SUCCESS)
goto ReplicationDoExit;
}
//
// Transmit...
//
Status = (*pLlsReplicationServiceAddW) ( ReplHandle, ServicesTotalRecords, Services );
if (Status != STATUS_SUCCESS)
goto ReplicationDoExit;
Status = (*pLlsReplicationServerAddW) ( ReplHandle, ServersTotalRecords, Servers );
if (Status != STATUS_SUCCESS)
goto ReplicationDoExit;
Status = (*pLlsReplicationServerServiceAddW) ( ReplHandle, ServerServicesTotalRecords, ServerServices );
if (Status != STATUS_SUCCESS)
goto ReplicationDoExit;
if ( (*pLlsCapabilityIsSupported)( LlsHandle, LLS_CAPABILITY_REPLICATE_USERS_EX ) )
{
Status = (*pLlsReplicationUserAddExW)( ReplHandle, UserLevel, &UserDB );
if (Status != STATUS_SUCCESS)
goto ReplicationDoExit;
}
else
{
Status = (*pLlsReplicationUserAddW) ( ReplHandle, UserDB.Level0.NumUsers, UserDB.Level0.Users );
if (Status != STATUS_SUCCESS)
goto ReplicationDoExit;
}
if ( (*pLlsCapabilityIsSupported)( LlsHandle, LLS_CAPABILITY_REPLICATE_CERT_DB ) )
{
Status = (*pLlsReplicationCertDbAddW)( ReplHandle, 0, &CertificateDB );
if (Status != STATUS_SUCCESS)
goto ReplicationDoExit;
}
if ( (*pLlsCapabilityIsSupported)( LlsHandle, LLS_CAPABILITY_REPLICATE_PRODUCT_SECURITY ) )
{
Status = (*pLlsReplicationProductSecurityAddW)( ReplHandle, 0, &ProductSecurity );
}
ReplicationDoExit:
if (Status != STATUS_SUCCESS) {
#if DBG
dprintf(TEXT("LLS Replication ABORT: 0x%lX\n"), Status);
#endif
}
if (Services != NULL)
MIDL_user_free(Services);
if (Servers != NULL)
MIDL_user_free(Servers);
if ( 0 == UserLevel )
{
if (UserDB.Level0.Users != NULL)
MIDL_user_free(UserDB.Level0.Users);
}
else
{
if (UserDB.Level1.Users != NULL)
MIDL_user_free(UserDB.Level1.Users);
}
if (CertificateDB.Strings != NULL)
MIDL_user_free(CertificateDB.Strings);
if (CertificateDB.HeaderContainer.Level0.Headers != NULL)
MIDL_user_free(CertificateDB.HeaderContainer.Level0.Headers);
if (CertificateDB.ClaimContainer.Level0.Claims != NULL)
MIDL_user_free(CertificateDB.ClaimContainer.Level0.Claims);
if (ProductSecurity.Strings != NULL)
MIDL_user_free(ProductSecurity.Strings);
#if DBG
if (TraceFlags & TRACE_REPLICATION)
dprintf(TEXT(" LLS Replication Finished\n"));
#endif
return Status;
} // ReplicationDo
/////////////////////////////////////////////////////////////////////////
VOID
ReplicationManager (
IN PVOID ThreadParameter
)
/*++
Routine Description:
Arguments:
ThreadParameter - Not used.
Return Value:
This thread never exits.
--*/
{
BOOL DoReplication = FALSE;
NTSTATUS Status;
LLS_REPL_HANDLE ReplHandle = NULL;
LLS_HANDLE LlsHandle = NULL;
PLLS_CONNECT_INFO_0 pConnectInfo;
PREPL_REQUEST pReplInfo;
TCHAR ReplicateTo[MAX_PATH + 1];
DWORD LastReplicated;
LPTSTR pReplicateTo = ReplicateTo;
TCHAR LastFailedConnectionDownlevelReplicateTo[MAX_PATH + 1] = TEXT("");
BOOL Replicate;
#if DBG
if (TraceFlags & (TRACE_FUNCTION_TRACE | TRACE_REPLICATION))
dprintf(TEXT("LLS TRACE: ReplicationManager\n"));
#endif
//
// Loop forever waiting to be given the opportunity to serve the
// greater good.
//
for ( ; ; ) {
//
// Wait to be notified that there is work to be done
//
Status = NtWaitForSingleObject( ReplicationEvent, TRUE, NULL );
#if DELAY_INITIALIZATION
EnsureInitialized();
#endif
// Delayed LoadLibrary
ReplicationInitDelayed();
// Update the replication-related ConfigInfo information.
//
ConfigInfoUpdate(NULL);
RtlEnterCriticalSection(&ConfigInfoLock);
Replicate = ConfigInfo.Replicate;
RtlLeaveCriticalSection(&ConfigInfoLock);
if (Replicate) {
//
// So they said, go replicate my son... Yeah, but first we must ask
// the master for permission.
//
//
// Construct our repl record
//
pReplInfo = MIDL_user_allocate(sizeof(REPL_REQUEST));
ASSERT(pReplInfo != NULL);
if (pReplInfo != NULL) {
ReplicateTo[0] = 0;
pReplInfo->EnterpriseServer[0] = 0;
RtlEnterCriticalSection(&ConfigInfoLock);
if (ConfigInfo.ReplicateTo != NULL)
{
lstrcpyn(ReplicateTo,
ConfigInfo.ReplicateTo,
min(MAX_PATH, lstrlen(ConfigInfo.ReplicateTo) + 1));
}
if (ConfigInfo.EnterpriseServer != NULL)
lstrcpy(pReplInfo->EnterpriseServer, ConfigInfo.EnterpriseServer);
pReplInfo->EnterpriseServerDate = ConfigInfo.EnterpriseServerDate;
pReplInfo->LastReplicated = ConfigInfo.LastReplicatedSeconds;
pReplInfo->CurrentTime = LastUsedTime;
pReplInfo->NumberServices = 0;
pReplInfo->NumberUsers = 0;
pReplInfo->ReplSize = MAX_REPL_SIZE;
pReplInfo->Backoff = 0;
RtlLeaveCriticalSection(&ConfigInfoLock);
#if DBG
if (TraceFlags & TRACE_REPLICATION)
dprintf(TEXT("LLS Starting Replication to: %s @ %s\n"),
ReplicateTo, TimeToString(pReplInfo->CurrentTime));
#endif
Status = (*pLlsReplConnect) ( ReplicateTo,
&ReplHandle );
if ( STATUS_SUCCESS != Status ) {
#if DBG
dprintf(TEXT("LLS Error: LlsReplConnect failed: 0x%lX\n"),
Status);
#endif
ReplHandle = NULL;
}
else {
Status = (*pLlsConnectW)( ReplicateTo, &LlsHandle );
if ( STATUS_SUCCESS != Status ) {
#if DBG
dprintf(TEXT("LLS Error: LlsConnectW failed: 0x%lX\n"),
Status);
#endif
LlsHandle = NULL;
}
}
if (Status != STATUS_SUCCESS) {
DWORD dwWinError;
DWORD dwBuildNumber;
dwWinError = WinNtBuildNumberGet( ReplicateTo,
&dwBuildNumber );
if ( (ERROR_SUCCESS == dwWinError) &&
(dwBuildNumber < 1057L) ) {
// the ReplicateTo machine does not support the license
// service
if ( lstrcmpi(ReplicateTo,
LastFailedConnectionDownlevelReplicateTo ) ) {
lstrcpy( LastFailedConnectionDownlevelReplicateTo,
ReplicateTo );
LogEvent( LLS_EVENT_REPL_DOWNLEVEL_TARGET,
1,
&pReplicateTo,
Status );
}
}
else {
// the ReplicateTo machine should be running the license
// service
*LastFailedConnectionDownlevelReplicateTo = TEXT( '\0' );
ThrottleLogEvent( LLS_EVENT_REPL_NO_CONNECTION,
1,
&pReplicateTo,
Status );
}
}
else {
*LastFailedConnectionDownlevelReplicateTo = TEXT( '\0' );
Status = (*pLlsReplicationRequestW) ( ReplHandle,
REPL_VERSION,
pReplInfo );
if (Status != STATUS_SUCCESS) {
LogEvent( LLS_EVENT_REPL_REQUEST_FAILED,
1,
&pReplicateTo,
Status );
}
else {
RtlEnterCriticalSection(&ConfigInfoLock);
#ifdef DISABLED_FOR_NT5
lstrcpy(ConfigInfo.EnterpriseServer,
pReplInfo->EnterpriseServer);
#endif // DISABLED_FOR_NT5
ConfigInfo.EnterpriseServerDate =
pReplInfo->EnterpriseServerDate;
ConfigInfo.IsReplicating = TRUE;
LastReplicated = pReplInfo->LastReplicated;
//
// And lo, thou may proceed...
//
if (pReplInfo->Backoff == 0) {
if ( ConfigInfo.LogLevel ) {
LogEvent( LLS_EVENT_REPL_START,
1,
&pReplicateTo,
ERROR_SUCCESS );
}
Status = ReplicationDo( LlsHandle,
ReplHandle,
LastReplicated );
if ( STATUS_SUCCESS != Status ) {
LogEvent( LLS_EVENT_REPL_FAILED,
1,
&pReplicateTo,
Status );
}
else if ( ConfigInfo.LogLevel ) {
LogEvent( LLS_EVENT_REPL_END,
1,
&pReplicateTo,
ERROR_SUCCESS );
}
//
// Need to update when next we should replicate
//
ConfigInfo.LastReplicatedSeconds = DateSystemGet();
GetLocalTime(&ConfigInfo.LastReplicated);
ReplicationTimeSet();
}
else {
LogEvent( LLS_EVENT_REPL_BACKOFF,
1,
&pReplicateTo,
ERROR_SUCCESS );
}
ConfigInfo.IsReplicating = FALSE;
RtlLeaveCriticalSection(&ConfigInfoLock);
}
}
//
// Disconnect from Master Server
//
if ( NULL != LlsHandle ) {
(*pLlsClose)( LlsHandle );
LlsHandle = NULL;
}
if ( NULL != ReplHandle ) {
Status = (*pLlsReplClose) ( &ReplHandle );
if ((STATUS_SUCCESS != Status) && (NULL != ReplHandle))
{
RpcSmDestroyClientContext( &ReplHandle );
ReplHandle = NULL;
}
}
MIDL_user_free( pReplInfo );
}
}
}
} // ReplicationManager
/////////////////////////////////////////////////////////////////////////
VOID
ReplicationTimeSet ( )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
DWORD CurrTime, ReplTime, Time;
#if DBG
if (TraceFlags & (TRACE_FUNCTION_TRACE | TRACE_REPLICATION))
dprintf(TEXT("LLS TRACE: ReplicationTimeSet\n"));
#endif
ReplTime = Time = 0;
//
// Figure out what new time to set it to
//
if (!ConfigInfo.Replicate)
return;
//
// If REPLICATE_DELTA it is easy as we just take the delta and apply it to
// the last replication time. Otherwise we have to convert the time from
// midnight.
//
//
// Figure out how long since we last replicated
//
ReplTime = ConfigInfo.ReplicationTime;
if (ConfigInfo.ReplicationType == REPLICATE_DELTA) {
Time = DateSystemGet() - ConfigInfo.LastReplicatedSeconds;
//
// If we have already gone past when we should replicate then schedule
// one real soon now (10 minutes).
//
if (Time > ReplTime)
Time = 10 * 60;
else
Time = ReplTime - Time;
Time += DateLocalGet();
} else {
//
// Need to adjust time to midnight - do this by MOD of seconds
// per day.
//
CurrTime = DateLocalGet();
Time = CurrTime - ((CurrTime / (60 * 60 * 24)) * (60 * 60 * 24));
CurrTime = CurrTime - Time;
//
// Time = seconds past midnight.
// CurrTime = Todays @ 12:00 AM
// Figure out if we are past the replication time, if so schedule it
// for tomorrow, else today.
//
if (Time > ReplTime)
Time = CurrTime + (60 * 60 * 24) + ReplTime;
else
Time = CurrTime + ReplTime;
}
ConfigInfo.NextReplication = Time;
} // ReplicationTimeSet