Source code of Windows XP (NT5)
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

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: timesync.cxx
  8. //
  9. // Contents: Code for logon and logoff for the Kerberos package
  10. //
  11. //
  12. // History: 16-April-1996 Created MikeSw
  13. //
  14. //------------------------------------------------------------------------
  15. #include <kerb.hxx>
  16. #define TIMESYNC_ALLOCATE
  17. #include <kerbp.h>
  18. extern "C"
  19. {
  20. #include <w32timep.h>
  21. }
  22. #ifndef WIN32_CHICAGO
  23. //+-------------------------------------------------------------------------
  24. //
  25. // Function: KerbTimeSyncWorker
  26. //
  27. // Synopsis: Does work of time sync
  28. //
  29. // Effects:
  30. //
  31. // Arguments:
  32. //
  33. // Requires:
  34. //
  35. // Returns:
  36. //
  37. // Notes:
  38. //
  39. //
  40. //--------------------------------------------------------------------------
  41. ULONG
  42. KerbTimeSyncWorker(PVOID Dummy)
  43. {
  44. HANDLE hTimeSlipEvent = NULL;
  45. ULONG Status = STATUS_SUCCESS;
  46. D_DebugLog((DEB_TRACE_TIME, "Calling W32TimeSyncNow\n"));
  47. if (InterlockedIncrement(&KerbSkewState.ActiveSyncs) == 1)
  48. {
  49. // Use this named event instead of W32TimeSyncNow(). W32TimeSyncNow uses kerberos to
  50. // make an authenticated RPC call, which can fail if there is a time skew. We should
  51. // be able to set the named event regardless of skew.
  52. hTimeSlipEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, W32TIME_NAMED_EVENT_SYSTIME_NOT_CORRECT);
  53. if (NULL == hTimeSlipEvent) {
  54. Status = GetLastError();
  55. } else {
  56. if (!SetEvent(hTimeSlipEvent)) {
  57. Status = GetLastError();
  58. }
  59. CloseHandle(hTimeSlipEvent);
  60. }
  61. if (Status != ERROR_SUCCESS)
  62. {
  63. DebugLog((DEB_ERROR,"Failed to sync time: %d\n",Status));
  64. }
  65. }
  66. InterlockedDecrement(&KerbSkewState.ActiveSyncs);
  67. return(Status);
  68. }
  69. //+-------------------------------------------------------------------------
  70. //
  71. // Function: KerbKickoffTime
  72. //
  73. // Synopsis: Puts a item on scavenger queue to time sync
  74. //
  75. // Effects:
  76. //
  77. // Arguments:
  78. //
  79. // Requires:
  80. //
  81. // Returns:
  82. //
  83. // Notes:
  84. //
  85. //
  86. //--------------------------------------------------------------------------
  87. VOID
  88. KerbKickoffTimeSync(
  89. VOID
  90. )
  91. {
  92. ULONG Index;
  93. //
  94. // Reset the time skew data so we don't sync too often.
  95. //
  96. for (Index = 0; Index < KerbSkewState.TotalRequests ; Index++ )
  97. {
  98. KerbSkewState.SkewEntries[Index].Skewed = FALSE;
  99. KerbSkewState.SkewEntries[Index].RequestTime = KerbGlobalWillNeverTime;
  100. }
  101. KerbSkewState.SkewedRequests = 0;
  102. KerbSkewState.SuccessRequests = KerbSkewState.TotalRequests;
  103. KerbSkewState.LastRequest = 0;
  104. LsaFunctions->RegisterNotification(
  105. KerbTimeSyncWorker,
  106. NULL,
  107. NOTIFIER_TYPE_IMMEDIATE,
  108. 0, // no class
  109. NOTIFIER_FLAG_ONE_SHOT,
  110. 0,
  111. NULL
  112. );
  113. }
  114. //+-------------------------------------------------------------------------
  115. //
  116. // Function: KerbUpdateSkewTime
  117. //
  118. // Synopsis: Updates the statistics for time skew. If necessary, triggers
  119. // time skew in another thread
  120. //
  121. // Effects:
  122. //
  123. // Arguments: Skewed - The last request did not generate a time skew error
  124. //
  125. // Requires:
  126. //
  127. // Returns:
  128. //
  129. // Notes:
  130. //
  131. //
  132. //--------------------------------------------------------------------------
  133. VOID
  134. KerbUpdateSkewTime(
  135. IN BOOLEAN Skewed
  136. )
  137. {
  138. TimeStamp CurrentTime;
  139. RtlEnterCriticalSection(&KerbSkewState.Lock);
  140. //
  141. // If this changes the entry, update the counts
  142. //
  143. if (Skewed != KerbSkewState.SkewEntries[KerbSkewState.LastRequest].Skewed)
  144. {
  145. if (KerbSkewState.SkewEntries[KerbSkewState.LastRequest].Skewed)
  146. {
  147. KerbSkewState.SkewedRequests--;
  148. KerbSkewState.SuccessRequests++;
  149. }
  150. else
  151. {
  152. KerbSkewState.SkewedRequests++;
  153. KerbSkewState.SuccessRequests--;
  154. }
  155. KerbSkewState.SkewEntries[KerbSkewState.LastRequest].Skewed = Skewed;
  156. }
  157. D_DebugLog((DEB_TRACE_TIME,"Updating skew statistics: Skewed = %d, successful = %d, latest = %s\n",
  158. KerbSkewState.SkewedRequests,
  159. KerbSkewState.SuccessRequests,
  160. Skewed ? "Skewed" : "Success"
  161. ));
  162. GetSystemTimeAsFileTime((PFILETIME)
  163. &CurrentTime
  164. );
  165. KerbSkewState.SkewEntries[KerbSkewState.LastRequest].RequestTime = CurrentTime;
  166. KerbSkewState.LastRequest = (KerbSkewState.LastRequest + 1) % KerbSkewState.TotalRequests;
  167. //
  168. // Check to see if this triggers a time sync, in that we have enough
  169. // failure events and the last sync was a while ago
  170. //
  171. if ((KerbSkewState.SkewedRequests > KerbSkewState.SkewThreshold) && // enough events
  172. ((CurrentTime.QuadPart - KerbSkewState.LastSync.QuadPart) >
  173. KerbSkewState.MinimumSyncLapse.QuadPart ) && // last sync a while ago
  174. (KerbSkewState.SkewEntries[KerbSkewState.LastRequest].RequestTime.QuadPart >
  175. KerbSkewState.LastSync.QuadPart ) ) // all events were since the last sync
  176. {
  177. KerbSkewState.LastSync = CurrentTime;
  178. KerbKickoffTimeSync();
  179. }
  180. RtlLeaveCriticalSection(&KerbSkewState.Lock);
  181. }
  182. //+-------------------------------------------------------------------------
  183. //
  184. // Function: KerbInitializeSkewState
  185. //
  186. // Synopsis: Initializes all state for the time-sync code
  187. //
  188. // Effects:
  189. //
  190. // Arguments:
  191. //
  192. // Requires:
  193. //
  194. // Returns:
  195. //
  196. // Notes:
  197. //
  198. //
  199. //--------------------------------------------------------------------------
  200. NTSTATUS
  201. KerbInitializeSkewState(
  202. VOID
  203. )
  204. {
  205. ULONG Index;
  206. NTSTATUS Status = STATUS_SUCCESS;
  207. KerbSkewState.TotalRequests = sizeof(KerbSkewEntries) / sizeof(KERB_TIME_SKEW_ENTRY);
  208. Status = RtlInitializeCriticalSection(
  209. &KerbSkewState.Lock
  210. );
  211. if (!NT_SUCCESS(Status))
  212. {
  213. goto Cleanup;
  214. }
  215. //
  216. // Initialize the list of skew entries to show that we are very successful
  217. //
  218. KerbSkewState.SkewEntries = KerbSkewEntries;
  219. for (Index = 0; Index < KerbSkewState.TotalRequests ; Index++ )
  220. {
  221. KerbSkewState.SkewEntries[Index].Skewed = FALSE;
  222. KerbSkewState.SkewEntries[Index].RequestTime = KerbGlobalWillNeverTime;
  223. }
  224. KerbSkewState.SkewedRequests = 0;
  225. KerbSkewState.SuccessRequests = KerbSkewState.TotalRequests;
  226. KerbSkewState.LastRequest = 0;
  227. //
  228. // We need to have 1/2 failures to trigger a skew
  229. //
  230. KerbSkewState.SkewThreshold = KerbSkewState.TotalRequests / 2;
  231. KerbSkewState.MinimumSyncLapse.QuadPart =
  232. (LONGLONG) 10000000 * 60 * 60; // don't sync more than every hour
  233. //
  234. // Start off last sync at zero
  235. //
  236. KerbSkewState.LastSync.QuadPart = 0;
  237. KerbSkewState.ActiveSyncs = 0;
  238. Cleanup:
  239. return(Status);
  240. }
  241. #else // WIN32_CHICAGO
  242. VOID
  243. KerbUpdateSkewTime(
  244. IN BOOLEAN Skewed
  245. )
  246. {
  247. return;
  248. }
  249. NTSTATUS
  250. KerbInitializeSkewState(
  251. VOID
  252. )
  253. {
  254. return(STATUS_SUCCESS);
  255. }
  256. #endif // WIN32_CHICAGO