mirror of https://github.com/tongzx/nt5src
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.
301 lines
7.0 KiB
301 lines
7.0 KiB
//+-----------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1992 - 1996
|
|
//
|
|
// File: timesync.cxx
|
|
//
|
|
// Contents: Code for logon and logoff for the Kerberos package
|
|
//
|
|
//
|
|
// History: 16-April-1996 Created MikeSw
|
|
//
|
|
//------------------------------------------------------------------------
|
|
#include <kerb.hxx>
|
|
#define TIMESYNC_ALLOCATE
|
|
#include <kerbp.h>
|
|
extern "C"
|
|
{
|
|
#include <w32timep.h>
|
|
}
|
|
|
|
#ifndef WIN32_CHICAGO
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: KerbTimeSyncWorker
|
|
//
|
|
// Synopsis: Does work of time sync
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
ULONG
|
|
KerbTimeSyncWorker(PVOID Dummy)
|
|
{
|
|
HANDLE hTimeSlipEvent = NULL;
|
|
ULONG Status = STATUS_SUCCESS;
|
|
|
|
D_DebugLog((DEB_TRACE_TIME, "Calling W32TimeSyncNow\n"));
|
|
if (InterlockedIncrement(&KerbSkewState.ActiveSyncs) == 1)
|
|
{
|
|
// Use this named event instead of W32TimeSyncNow(). W32TimeSyncNow uses kerberos to
|
|
// make an authenticated RPC call, which can fail if there is a time skew. We should
|
|
// be able to set the named event regardless of skew.
|
|
hTimeSlipEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, W32TIME_NAMED_EVENT_SYSTIME_NOT_CORRECT);
|
|
if (NULL == hTimeSlipEvent) {
|
|
Status = GetLastError();
|
|
} else {
|
|
if (!SetEvent(hTimeSlipEvent)) {
|
|
Status = GetLastError();
|
|
}
|
|
|
|
CloseHandle(hTimeSlipEvent);
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
DebugLog((DEB_ERROR,"Failed to sync time: %d\n",Status));
|
|
}
|
|
}
|
|
InterlockedDecrement(&KerbSkewState.ActiveSyncs);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: KerbKickoffTime
|
|
//
|
|
// Synopsis: Puts a item on scavenger queue to time sync
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
VOID
|
|
KerbKickoffTimeSync(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG Index;
|
|
|
|
//
|
|
// Reset the time skew data so we don't sync too often.
|
|
//
|
|
|
|
for (Index = 0; Index < KerbSkewState.TotalRequests ; Index++ )
|
|
{
|
|
KerbSkewState.SkewEntries[Index].Skewed = FALSE;
|
|
KerbSkewState.SkewEntries[Index].RequestTime = KerbGlobalWillNeverTime;
|
|
|
|
}
|
|
|
|
KerbSkewState.SkewedRequests = 0;
|
|
KerbSkewState.SuccessRequests = KerbSkewState.TotalRequests;
|
|
KerbSkewState.LastRequest = 0;
|
|
|
|
LsaFunctions->RegisterNotification(
|
|
KerbTimeSyncWorker,
|
|
NULL,
|
|
NOTIFIER_TYPE_IMMEDIATE,
|
|
0, // no class
|
|
NOTIFIER_FLAG_ONE_SHOT,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: KerbUpdateSkewTime
|
|
//
|
|
// Synopsis: Updates the statistics for time skew. If necessary, triggers
|
|
// time skew in another thread
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: Skewed - The last request did not generate a time skew error
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
VOID
|
|
KerbUpdateSkewTime(
|
|
IN BOOLEAN Skewed
|
|
)
|
|
{
|
|
TimeStamp CurrentTime;
|
|
|
|
RtlEnterCriticalSection(&KerbSkewState.Lock);
|
|
|
|
//
|
|
// If this changes the entry, update the counts
|
|
//
|
|
|
|
if (Skewed != KerbSkewState.SkewEntries[KerbSkewState.LastRequest].Skewed)
|
|
{
|
|
if (KerbSkewState.SkewEntries[KerbSkewState.LastRequest].Skewed)
|
|
{
|
|
KerbSkewState.SkewedRequests--;
|
|
KerbSkewState.SuccessRequests++;
|
|
}
|
|
else
|
|
{
|
|
KerbSkewState.SkewedRequests++;
|
|
KerbSkewState.SuccessRequests--;
|
|
}
|
|
|
|
KerbSkewState.SkewEntries[KerbSkewState.LastRequest].Skewed = Skewed;
|
|
}
|
|
|
|
D_DebugLog((DEB_TRACE_TIME,"Updating skew statistics: Skewed = %d, successful = %d, latest = %s\n",
|
|
KerbSkewState.SkewedRequests,
|
|
KerbSkewState.SuccessRequests,
|
|
Skewed ? "Skewed" : "Success"
|
|
));
|
|
|
|
GetSystemTimeAsFileTime((PFILETIME)
|
|
&CurrentTime
|
|
);
|
|
|
|
KerbSkewState.SkewEntries[KerbSkewState.LastRequest].RequestTime = CurrentTime;
|
|
|
|
KerbSkewState.LastRequest = (KerbSkewState.LastRequest + 1) % KerbSkewState.TotalRequests;
|
|
|
|
//
|
|
// Check to see if this triggers a time sync, in that we have enough
|
|
// failure events and the last sync was a while ago
|
|
//
|
|
|
|
if ((KerbSkewState.SkewedRequests > KerbSkewState.SkewThreshold) && // enough events
|
|
((CurrentTime.QuadPart - KerbSkewState.LastSync.QuadPart) >
|
|
KerbSkewState.MinimumSyncLapse.QuadPart ) && // last sync a while ago
|
|
(KerbSkewState.SkewEntries[KerbSkewState.LastRequest].RequestTime.QuadPart >
|
|
KerbSkewState.LastSync.QuadPart ) ) // all events were since the last sync
|
|
{
|
|
KerbSkewState.LastSync = CurrentTime;
|
|
KerbKickoffTimeSync();
|
|
}
|
|
RtlLeaveCriticalSection(&KerbSkewState.Lock);
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: KerbInitializeSkewState
|
|
//
|
|
// Synopsis: Initializes all state for the time-sync code
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS
|
|
KerbInitializeSkewState(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG Index;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
KerbSkewState.TotalRequests = sizeof(KerbSkewEntries) / sizeof(KERB_TIME_SKEW_ENTRY);
|
|
Status = RtlInitializeCriticalSection(
|
|
&KerbSkewState.Lock
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Initialize the list of skew entries to show that we are very successful
|
|
//
|
|
|
|
KerbSkewState.SkewEntries = KerbSkewEntries;
|
|
for (Index = 0; Index < KerbSkewState.TotalRequests ; Index++ )
|
|
{
|
|
KerbSkewState.SkewEntries[Index].Skewed = FALSE;
|
|
KerbSkewState.SkewEntries[Index].RequestTime = KerbGlobalWillNeverTime;
|
|
|
|
}
|
|
|
|
KerbSkewState.SkewedRequests = 0;
|
|
KerbSkewState.SuccessRequests = KerbSkewState.TotalRequests;
|
|
KerbSkewState.LastRequest = 0;
|
|
//
|
|
// We need to have 1/2 failures to trigger a skew
|
|
//
|
|
|
|
KerbSkewState.SkewThreshold = KerbSkewState.TotalRequests / 2;
|
|
KerbSkewState.MinimumSyncLapse.QuadPart =
|
|
(LONGLONG) 10000000 * 60 * 60; // don't sync more than every hour
|
|
//
|
|
// Start off last sync at zero
|
|
//
|
|
|
|
KerbSkewState.LastSync.QuadPart = 0;
|
|
KerbSkewState.ActiveSyncs = 0;
|
|
Cleanup:
|
|
return(Status);
|
|
}
|
|
#else // WIN32_CHICAGO
|
|
|
|
VOID
|
|
KerbUpdateSkewTime(
|
|
IN BOOLEAN Skewed
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
KerbInitializeSkewState(
|
|
VOID
|
|
)
|
|
{
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
#endif // WIN32_CHICAGO
|