Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

641 lines
19 KiB

/*++
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 "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;
HANDLE LlsRPCHandle = NULL;
FARPROC pLlsReplConnect;
FARPROC pLlsReplClose;
FARPROC pLlsFreeMemory;
FARPROC pLlsReplicationRequestW = NULL;
FARPROC pLlsReplicationServerAddW = NULL;
FARPROC pLlsReplicationServerServiceAddW = NULL;
FARPROC pLlsReplicationServiceAddW = NULL;
FARPROC 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;
/////////////////////////////////////////////////////////////////////////
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
//
// Open up our RPC DLL and init our function references.
//
LlsRPCHandle = LoadLibrary(TEXT("LLSRPC.DLL"));
ASSERT(LlsRPCHandle != NULL);
if (LlsRPCHandle != NULL) {
pLlsReplConnect = GetProcAddress(LlsRPCHandle, ("LlsReplConnectW"));
pLlsReplClose = GetProcAddress(LlsRPCHandle, ("LlsReplClose"));
pLlsFreeMemory = GetProcAddress(LlsRPCHandle, ("LlsFreeMemory"));
pLlsReplicationRequestW = GetProcAddress(LlsRPCHandle, ("LlsReplicationRequestW"));
pLlsReplicationServerAddW = GetProcAddress(LlsRPCHandle, ("LlsReplicationServerAddW"));
pLlsReplicationServerServiceAddW = GetProcAddress(LlsRPCHandle, ("LlsReplicationServerServiceAddW"));
pLlsReplicationServiceAddW = GetProcAddress(LlsRPCHandle, ("LlsReplicationServiceAddW"));
pLlsReplicationUserAddW = 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"));
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);
if ((pLlsReplConnect != NULL) && (pLlsReplClose != NULL) &&
(pLlsFreeMemory != NULL) && (pLlsReplicationRequestW != NULL) &&
(pLlsReplicationServerAddW != NULL) && (pLlsReplicationServiceAddW != NULL) &&
(pLlsReplicationServerServiceAddW != NULL) && (pLlsReplicationUserAddW != NULL) &&
(pLlsReplicationCertDbAddW != NULL) && (pLlsReplicationProductSecurityAddW != NULL) &&
(pLlsReplicationUserAddExW != NULL) && (pLlsCapabilityIsSupported != NULL) &&
(pLlsConnectW != NULL) && (pLlsClose != NULL)
) {
//
// 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
);
}
}
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_COMPUTERNAME_LENGTH + 3];
DWORD LastReplicated;
LPTSTR pReplicateTo = ReplicateTo;
TCHAR LastFailedConnectionDownlevelReplicateTo[MAX_COMPUTERNAME_LENGTH + 3] = TEXT("");
#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 );
//
// 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) {
RtlEnterCriticalSection(&ConfigInfoLock);
lstrcpy(ReplicateTo, ConfigInfo.ReplicateTo);
pReplInfo->EnterpriseServerDate = 0;
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, 0, (LPBYTE *) &pConnectInfo );
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' );
LogEvent( 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);
lstrcpy(ConfigInfo.EnterpriseServer, pReplInfo->EnterpriseServer);
ConfigInfo.EnterpriseServerDate = pReplInfo->EnterpriseServerDate;
ConfigInfo.IsReplicating = TRUE;
LastReplicated = pReplInfo->LastReplicated;
RtlLeaveCriticalSection(&ConfigInfoLock);
//
// 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 );
}
RtlEnterCriticalSection(&ConfigInfoLock);
//
// 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 );
RtlEnterCriticalSection(&ConfigInfoLock);
}
ConfigInfo.IsReplicating = FALSE;
RtlLeaveCriticalSection(&ConfigInfoLock);
}
}
//
// Disconnect from Master Server
//
if ( NULL != LlsHandle )
{
(*pLlsClose)( LlsHandle );
LlsHandle = NULL;
}
if ( NULL != ReplHandle )
{
Status = (*pLlsReplClose) ( &ReplHandle );
try
{
RpcSmDestroyClientContext( &ReplHandle );
}
except (TRUE)
{
Status = I_RpcMapWin32Status(RpcExceptionCode());
#if DBG
dprintf(TEXT("ERROR LLSSRV.EXE (Repl): RPC Exception: 0x%lX\n"), Status);
#endif
}
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