//+----------------------------------------------------------------------- // // 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 #define TIMESYNC_ALLOCATE #include extern "C" { #include } #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; SafeEnterCriticalSection(&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(); } SafeLeaveCriticalSection(&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 = SafeInitializeCriticalSection( &KerbSkewState.Lock, KERB_SKEW_STATE_LOCK_ENUM ); 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