Leaked source code of windows server 2003
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.

526 lines
14 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: authen.cxx
  7. //
  8. // Contents: Authenticator verification code
  9. //
  10. // Classes: CAuthenticatorList
  11. //
  12. // Functions: Compare, AuthenAllocate, AuthenFree
  13. //
  14. // History: 4-04-93 WadeR Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "krbprgma.h"
  18. #include <secpch2.hxx>
  19. #pragma hdrstop
  20. //
  21. // Security include files.
  22. //
  23. #include <kerbcomm.h>
  24. #include <authen.hxx>
  25. extern "C"
  26. {
  27. #include <md5.h>
  28. }
  29. #include "debug.h"
  30. typedef struct _KERB_AUTHEN_HEADER
  31. {
  32. LARGE_INTEGER tsTime;
  33. ULONG Count;
  34. BYTE Checksum[MD5DIGESTLEN];
  35. } KERB_AUTHEN_HEADER, *PKERB_AUTHEN_HEADER;
  36. #define KERB_MAX_AUTHEN_SIZE 1024
  37. //+---------------------------------------------------------------------------
  38. //
  39. // Function: Compare
  40. //
  41. // Synopsis: Compares two KerbInternalAuthenticators for RTL_GENERIC_TABLE
  42. //
  43. // Effects: none.
  44. //
  45. // Arguments: [Table] -- ignored
  46. // [FirstStruct] --
  47. // [SecondStruct] --
  48. //
  49. // Returns: GenericEqual, GenericLessThan, GenericGreaterThan.
  50. //
  51. // Algorithm: Sorts by TimeStamp first, than nonce, then principal, and
  52. // finally by realm
  53. //
  54. // History: 4-04-93 WadeR Created
  55. //
  56. // Notes: This must impose a complete ordering. The table package
  57. // will not allow an authenticator to be inserted in the table
  58. // if it is equal (according to this function) to one already
  59. // there.
  60. //
  61. //----------------------------------------------------------------------------
  62. RTL_GENERIC_COMPARE_RESULTS
  63. Compare(
  64. IN struct _RTL_GENERIC_TABLE *Table,
  65. IN PVOID FirstStruct,
  66. IN PVOID SecondStruct
  67. )
  68. {
  69. PKERB_AUTHEN_HEADER pOne, pTwo;
  70. RTL_GENERIC_COMPARE_RESULTS ret;
  71. int comp;
  72. pOne = (PKERB_AUTHEN_HEADER) FirstStruct ;
  73. pTwo = (PKERB_AUTHEN_HEADER) SecondStruct ;
  74. DsysAssert( (pOne != NULL) && (pTwo != NULL) );
  75. comp = memcmp( pOne->Checksum,
  76. pTwo->Checksum,
  77. MD5DIGESTLEN );
  78. if (comp > 0)
  79. {
  80. ret = GenericGreaterThan;
  81. }
  82. else if (comp < 0)
  83. {
  84. ret = GenericLessThan;
  85. }
  86. else
  87. {
  88. ret = GenericEqual;
  89. }
  90. return(ret);
  91. }
  92. //+---------------------------------------------------------------------------
  93. //
  94. // Function: AuthenAllocate
  95. //
  96. // Synopsis: Memory allocator for RTL_GENERIC_TABLE
  97. //
  98. // Effects: Allcoates memory.
  99. //
  100. // Arguments: [Table] -- ignored
  101. // [ByteSize] -- number of bytes to allocate
  102. //
  103. // Signals: Throws exception on failure.
  104. //
  105. // History: 4-04-93 WadeR Created
  106. //
  107. // Notes:
  108. //
  109. //----------------------------------------------------------------------------
  110. PVOID
  111. AuthenAllocate( struct _RTL_GENERIC_TABLE *Table, CLONG ByteSize )
  112. {
  113. return(MIDL_user_allocate ( ByteSize ) );
  114. }
  115. //+---------------------------------------------------------------------------
  116. //
  117. // Function: AuthenFree
  118. //
  119. // Synopsis: Memory deallacotor for the RTL_GENERIC_TABLE.
  120. //
  121. // Effects: frees memory.
  122. //
  123. // Arguments: [Table] -- ingnored
  124. // [Buffer] -- buffer to free
  125. //
  126. // History: 4-04-93 WadeR Created
  127. //
  128. // Notes:
  129. //
  130. //----------------------------------------------------------------------------
  131. VOID
  132. AuthenFree( struct _RTL_GENERIC_TABLE *Table, PVOID Buffer )
  133. {
  134. MIDL_user_free ( Buffer );
  135. }
  136. //+---------------------------------------------------------------------------
  137. //
  138. // Member: CAuthenticatorList::CAuthenticatorList
  139. //
  140. // Synopsis: Initializes the authenticator list.
  141. //
  142. // Effects: Calls RtlInitializeGenericTable (does not allocate memory).
  143. //
  144. // Arguments: [tsMax] -- Maximum acceptable age for an authenticator.
  145. //
  146. // History: 4-04-93 WadeR Created
  147. //
  148. // Notes:
  149. //
  150. //----------------------------------------------------------------------------
  151. CAuthenticatorList::CAuthenticatorList(LARGE_INTEGER tsMax, ULONG maxCount, BOOLEAN debugme)
  152. :_tsMaxAge(tsMax), _uMaxCount(maxCount), _fDebug(debugme)
  153. {
  154. _fMutexInitialized = FALSE;
  155. RtlInitializeGenericTable( &_Table, Compare, AuthenAllocate, AuthenFree, NULL );
  156. }
  157. //+---------------------------------------------------------------------------
  158. //
  159. // Member: CAuthenticatorList::~CAuthenticatorList
  160. //
  161. // Synopsis: Destructor removes all authenticators in the list.
  162. //
  163. // Effects: Frees memory
  164. //
  165. // Arguments: (none)
  166. //
  167. // Algorithm: Uses "Age" to remove everything.
  168. //
  169. // History: 4-04-93 WadeR Created
  170. //
  171. // Notes:
  172. //
  173. //----------------------------------------------------------------------------
  174. CAuthenticatorList::~CAuthenticatorList()
  175. {
  176. LARGE_INTEGER tsForever;
  177. LARGE_INTEGER tsZero = {0};
  178. SetMaxTimeStamp( tsForever );
  179. (void) Age( tsForever, tsZero );
  180. DsysAssert( RtlIsGenericTableEmpty( &_Table ) );
  181. if (_fMutexInitialized)
  182. {
  183. RtlDeleteCriticalSection(&_Mutex);
  184. }
  185. }
  186. //+---------------------------------------------------------------------------
  187. //
  188. // Member: CAuthenticatorList::Init
  189. //
  190. // Synopsis: Can't return values from a C++ destructor -- initialization
  191. // that can fail should go here
  192. //
  193. // Effects:
  194. //
  195. // Arguments:
  196. //
  197. // Algorithm:
  198. //
  199. // History: 5-24-94 WadeR Created
  200. //
  201. // Notes:
  202. //
  203. //----------------------------------------------------------------------------
  204. NTSTATUS
  205. CAuthenticatorList::Init()
  206. {
  207. NTSTATUS Status;
  208. Status = RtlInitializeCriticalSection(&_Mutex);
  209. if (NT_SUCCESS(Status))
  210. {
  211. _fMutexInitialized = TRUE;
  212. }
  213. return Status;
  214. }
  215. //+---------------------------------------------------------------------------
  216. //
  217. // Member: CAuthenticatorList::SetMaxAge
  218. //
  219. // Synopsis: Changes the new maximum age for an Authenticator.
  220. //
  221. // Effects: May cause some authenticators to be aged out.
  222. //
  223. // Arguments: [tsNewMaxAge] --
  224. //
  225. // Algorithm:
  226. //
  227. // History: 24-May-94 wader Created
  228. //
  229. // Notes:
  230. //
  231. //----------------------------------------------------------------------------
  232. void
  233. CAuthenticatorList::SetMaxAge( LARGE_INTEGER tsNewMaxAge )
  234. {
  235. LARGE_INTEGER tsNow;
  236. LARGE_INTEGER tsCutoffPast, tsCutoffFuture;
  237. _tsMaxAge = tsNewMaxAge;
  238. GetSystemTimeAsFileTime((PFILETIME) &tsNow );
  239. tsCutoffPast.QuadPart = tsNow.QuadPart - _tsMaxAge.QuadPart;
  240. tsCutoffFuture.QuadPart = tsNow.QuadPart + _tsMaxAge.QuadPart;
  241. (void) Age( tsCutoffPast, tsCutoffFuture );
  242. }
  243. //+---------------------------------------------------------------------------
  244. //
  245. // Member: CAuthenticatorList::Age
  246. //
  247. // Synopsis: Deletes all entries from the table that are earlier than
  248. // the given time.
  249. //
  250. // Effects: Frees memory
  251. //
  252. // Arguments: [tsCutoffTime] -- Delete all elements before this time.
  253. //
  254. // Returns: number of elements deleted.
  255. //
  256. // Algorithm: Get the oldest element in the table. If it is older than
  257. // the time, delete it and loop back. Else return.
  258. //
  259. // History: 4-04-93 WadeR Created
  260. //
  261. // Notes: The table contains the packed forms of Authenticators (as
  262. // created by PackAuthenticator in Kerbsupp). The TimeStamp
  263. // must be first.
  264. //
  265. //----------------------------------------------------------------------------
  266. ULONG
  267. CAuthenticatorList::Age(const LARGE_INTEGER& tsCutoffPast, const LARGE_INTEGER& tsCutoffFuture)
  268. {
  269. PKERB_AUTHEN_HEADER pahOldest;
  270. BOOL fDeleted;
  271. ULONG cDeleted = 0;
  272. do
  273. {
  274. // Number 0 is the oldest element in the table.
  275. pahOldest = (PKERB_AUTHEN_HEADER) RtlGetElementGenericTable( &_Table, 0 );
  276. if ((pahOldest != NULL) &&
  277. ((pahOldest->tsTime.QuadPart < tsCutoffPast.QuadPart) ||
  278. (pahOldest->tsTime.QuadPart > tsCutoffFuture.QuadPart))) // Bug # - clean up entires after clock reset
  279. {
  280. fDeleted = RtlDeleteElementGenericTable( &_Table, pahOldest );
  281. DsysAssert( fDeleted );
  282. cDeleted++;
  283. }
  284. else
  285. {
  286. fDeleted = FALSE;
  287. }
  288. } while ( fDeleted );
  289. return(cDeleted);
  290. }
  291. //+---------------------------------------------------------------------------
  292. //
  293. // Member: CAuthenticatorList::Check
  294. //
  295. // Synopsis: Determines if an authenticator is valid. This check always
  296. // checks for time skew and optionally checks for repeats. This is necessary
  297. // since we check for repeats on AP requests but not TGS requests.
  298. //
  299. // Effects: Allocates memory
  300. //
  301. // Arguments: [pedAuth] -- Authenticator to check (decrypted, but marshalled)
  302. //
  303. // Returns: KDC_ERR_NONE if authenticator is OK.
  304. // KRB_AP_ERR_SKEW if authenticator is expired (assumes clock skew).
  305. // KRB_AP_ERR_REPEAT if authenticator has been used already.
  306. // some other error if something throws an exception.
  307. //
  308. // Signals: none.
  309. //
  310. // Modifies: _Table
  311. //
  312. // History: 4-04-93 WadeR Created
  313. //
  314. // Notes:
  315. //
  316. //----------------------------------------------------------------------------
  317. KERBERR
  318. CAuthenticatorList::Check(
  319. IN PVOID Buffer,
  320. IN ULONG BufferLength,
  321. IN OPTIONAL PVOID OptionalBuffer,
  322. IN OPTIONAL ULONG OptionalBufferLength,
  323. IN PLARGE_INTEGER Time,
  324. IN BOOLEAN Insert,
  325. IN BOOLEAN PurgeEntry,
  326. IN BOOLEAN fCheckReplay
  327. )
  328. {
  329. PKERB_AUTHEN_HEADER pDataInTable = NULL;
  330. KERBERR KerbErr = KDC_ERR_NONE;
  331. LARGE_INTEGER tsNow;
  332. LARGE_INTEGER tsCutoffPast;
  333. LARGE_INTEGER tsCutoffFuture;
  334. //
  335. // Determine the cut off time.
  336. //
  337. GetSystemTimeAsFileTime((PFILETIME) &tsNow );
  338. tsCutoffPast.QuadPart = tsNow.QuadPart - _tsMaxAge.QuadPart;
  339. tsCutoffFuture.QuadPart = tsNow.QuadPart + _tsMaxAge.QuadPart;
  340. if ((Time->QuadPart < tsCutoffPast.QuadPart) ||
  341. (Time->QuadPart > tsCutoffFuture.QuadPart))
  342. {
  343. KerbErr = KRB_AP_ERR_SKEW;
  344. }
  345. //
  346. // Hold the mutex until we have finished the insert and the Age
  347. // operations.
  348. //
  349. if (fCheckReplay)
  350. {
  351. RtlEnterCriticalSection(&_Mutex);
  352. __try
  353. {
  354. // Age out the old ones.
  355. (void) Age( tsCutoffPast, tsCutoffFuture );
  356. BOOLEAN fIsNew;
  357. KERB_AUTHEN_HEADER Header;
  358. MD5_CTX Md5Context;
  359. //
  360. // Store the first chunk of the authenticator. If the authenticator
  361. // doesn't fit on the stack, allocate some space on the heap.
  362. //
  363. Header.tsTime = *Time;
  364. MD5Init(
  365. &Md5Context
  366. );
  367. MD5Update(
  368. &Md5Context,
  369. (PBYTE) Buffer,
  370. BufferLength
  371. );
  372. if ((OptionalBuffer != NULL) && (OptionalBufferLength != 0))
  373. {
  374. MD5Update(
  375. &Md5Context,
  376. (PBYTE) OptionalBuffer,
  377. OptionalBufferLength
  378. );
  379. }
  380. MD5Final(
  381. &Md5Context
  382. );
  383. RtlCopyMemory(
  384. Header.Checksum,
  385. Md5Context.digest,
  386. MD5DIGESTLEN
  387. );
  388. if (Insert)
  389. {
  390. pDataInTable = (PKERB_AUTHEN_HEADER) RtlInsertElementGenericTable(
  391. &_Table,
  392. &Header,
  393. sizeof( KERB_AUTHEN_HEADER ),
  394. &fIsNew
  395. );
  396. if ( pDataInTable == NULL )
  397. {
  398. KerbErr = KRB_ERR_GENERIC;
  399. __leave;
  400. }
  401. if ( fIsNew )
  402. {
  403. pDataInTable->Count = 1;
  404. if (_fDebug)
  405. {
  406. D_DebugLog((DEB_ERROR, "NEW cache entry\n"));
  407. }
  408. }
  409. else if ( ++(pDataInTable->Count) >= _uMaxCount )
  410. {
  411. KerbErr = KRB_AP_ERR_REPEAT;
  412. if (_fDebug)
  413. {
  414. D_DebugLog((DEB_ERROR, "Repeat <on insert>\n"));
  415. }
  416. }
  417. }
  418. else
  419. {
  420. pDataInTable = (PKERB_AUTHEN_HEADER)RtlLookupElementGenericTable(
  421. &_Table,
  422. &Header
  423. );
  424. if (NULL != pDataInTable)
  425. {
  426. if (PurgeEntry)
  427. {
  428. BOOLEAN fCompleted = FALSE;
  429. fCompleted = RtlDeleteElementGenericTable(&_Table, pDataInTable);
  430. DsysAssert(fCompleted);
  431. if (_fDebug)
  432. {
  433. D_DebugLog((DEB_ERROR, "Purged cache entry\n"));
  434. }
  435. }
  436. else if (pDataInTable->Count >= _uMaxCount)
  437. {
  438. KerbErr = KRB_AP_ERR_REPEAT;
  439. if (_fDebug)
  440. {
  441. D_DebugLog((DEB_ERROR, "Repeat detected \n"));
  442. }
  443. }
  444. }
  445. }
  446. }
  447. __except(EXCEPTION_EXECUTE_HANDLER)
  448. {
  449. KerbErr = KRB_ERR_GENERIC;
  450. }
  451. RtlLeaveCriticalSection(&_Mutex);
  452. }
  453. return(KerbErr);
  454. }