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.

800 lines
16 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. obsdata.c
  5. Abstract:
  6. Object Manager Security Descriptor Caching
  7. Author:
  8. Robert Reichel (robertre) 12-Oct-1993
  9. Revision History:
  10. --*/
  11. #include "obp.h"
  12. #if DBG
  13. #define OB_DIAGNOSTICS_ENABLED 1
  14. #endif // DBG
  15. //
  16. // These definitions are useful diagnostics aids
  17. //
  18. #if OB_DIAGNOSTICS_ENABLED
  19. ULONG ObDebugFlags = 0;
  20. //
  21. // Test for enabled diagnostic
  22. //
  23. #define IF_OB_GLOBAL( FlagName ) \
  24. if (ObDebugFlags & (OB_DEBUG_##FlagName))
  25. //
  26. // Diagnostics print statement
  27. //
  28. #define ObPrint( FlagName, _Text_ ) \
  29. IF_OB_GLOBAL( FlagName ) \
  30. DbgPrint _Text_
  31. #else
  32. //
  33. // diagnostics not enabled - No diagnostics included in build
  34. //
  35. //
  36. // Test for diagnostics enabled
  37. //
  38. #define IF_OB_GLOBAL( FlagName ) if (FALSE)
  39. //
  40. // Diagnostics print statement (expands to no-op)
  41. //
  42. #define ObPrint( FlagName, _Text_ ) ;
  43. #endif // OB_DIAGNOSTICS_ENABLED
  44. #if OB_DIAGNOSTICS_ENABLED
  45. ULONG TotalCacheEntries = 0;
  46. #endif
  47. //
  48. // The following flags enable or disable various diagnostic
  49. // capabilities within OB code. These flags are set in
  50. // ObGlobalFlag (only available within a DBG system).
  51. //
  52. //
  53. #define OB_DEBUG_ALLOC_TRACKING ((ULONG) 0x00000001L)
  54. #define OB_DEBUG_CACHE_FREES ((ULONG) 0x00000002L)
  55. #define OB_DEBUG_BREAK_ON_INIT ((ULONG) 0x00000004L)
  56. #define OB_DEBUG_SHOW_COLLISIONS ((ULONG) 0x00000008L)
  57. #define OB_DEBUG_SHOW_STATISTICS ((ULONG) 0x00000010L)
  58. #define OB_DEBUG_SHOW_REFERENCES ((ULONG) 0x00000020L)
  59. #define OB_DEBUG_SHOW_DEASSIGN ((ULONG) 0x00000040L)
  60. #define OB_DEBUG_STOP_INVALID_DESCRIPTOR ((ULONG) 0x00000080L)
  61. #define OB_DEBUG_SHOW_HEADER_FREE ((ULONG) 0x00000100L)
  62. //
  63. // Array of pointers to security descriptor entries
  64. //
  65. PLIST_ENTRY *SecurityDescriptorCache = NULL;
  66. //
  67. // Resource used to protect the security descriptor cache
  68. //
  69. ERESOURCE SecurityDescriptorCacheLock;
  70. #if defined (ALLOC_PRAGMA)
  71. #pragma alloc_text(PAGE,ObpDereferenceSecurityDescriptor)
  72. #pragma alloc_text(PAGE,ObpDestroySecurityDescriptorHeader)
  73. #pragma alloc_text(PAGE,ObpHashBuffer)
  74. #pragma alloc_text(PAGE,ObpHashSecurityDescriptor)
  75. #pragma alloc_text(PAGE,ObpInitSecurityDescriptorCache)
  76. #pragma alloc_text(PAGE,ObpLogSecurityDescriptor)
  77. #pragma alloc_text(PAGE,ObpReferenceSecurityDescriptor)
  78. #pragma alloc_text(PAGE,OpbCreateCacheEntry)
  79. #endif
  80. NTSTATUS
  81. ObpInitSecurityDescriptorCache(
  82. VOID
  83. )
  84. /*++
  85. Routine Description:
  86. Allocates and initializes the Security Descriptor Cache
  87. Arguments:
  88. None
  89. Return Value:
  90. STATUS_SUCCESS on success, NTSTATUS on failure.
  91. --*/
  92. {
  93. ULONG Size;
  94. NTSTATUS Status;
  95. IF_OB_GLOBAL( BREAK_ON_INIT ) {
  96. DbgBreakPoint();
  97. }
  98. Size = SECURITY_DESCRIPTOR_CACHE_ENTRIES * sizeof(PLIST_ENTRY);
  99. SecurityDescriptorCache = ExAllocatePoolWithTag( PagedPool, Size, 'cCdS' );
  100. if (SecurityDescriptorCache == NULL ) {
  101. return( STATUS_INSUFFICIENT_RESOURCES );
  102. }
  103. RtlZeroMemory( SecurityDescriptorCache, Size );
  104. Status = ExInitializeResource ( &SecurityDescriptorCacheLock );
  105. if ( !NT_SUCCESS(Status) ) {
  106. ExFreePool( SecurityDescriptorCache );
  107. return( Status );
  108. }
  109. return( STATUS_SUCCESS );
  110. }
  111. ULONG
  112. ObpHashSecurityDescriptor(
  113. PSECURITY_DESCRIPTOR SecurityDescriptor
  114. )
  115. /*++
  116. Routine Description:
  117. Hashes a security descriptor to a 32 bit value
  118. Arguments:
  119. SecurityDescriptor - Provides the security descriptor to be hashed
  120. Return Value:
  121. ULONG - a 32 bit hash value.
  122. --*/
  123. {
  124. PSID Owner = NULL;
  125. PSID Group = NULL;
  126. PACL Dacl;
  127. PACL Sacl;
  128. ULONG Hash = 0;
  129. BOOLEAN Junk;
  130. NTSTATUS Status;
  131. BOOLEAN DaclPresent = FALSE;
  132. BOOLEAN SaclPresent = FALSE;
  133. PISECURITY_DESCRIPTOR sd;
  134. sd = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
  135. Status = RtlGetOwnerSecurityDescriptor ( sd, &Owner, &Junk );
  136. Status = RtlGetGroupSecurityDescriptor( sd, &Group, &Junk );
  137. Status = RtlGetDaclSecurityDescriptor ( sd, &DaclPresent, &Dacl, &Junk );
  138. Status = RtlGetSaclSecurityDescriptor ( sd, &SaclPresent, &Sacl, &Junk );
  139. if ( Owner != NULL ) {
  140. Hash = ObpHashBuffer( Owner, RtlLengthSid( Owner ));
  141. }
  142. if ( Group != NULL ) {
  143. Hash += ObpHashBuffer( Group, RtlLengthSid( Group));
  144. }
  145. if ( DaclPresent && (Dacl != NULL)) {
  146. Hash += ObpHashBuffer( Dacl, Dacl->AclSize);
  147. }
  148. if ( SaclPresent && (Sacl != NULL)) {
  149. Hash += ObpHashBuffer( Sacl, Sacl->AclSize);
  150. }
  151. return( Hash );
  152. }
  153. ULONG
  154. ObpHashBuffer(
  155. PVOID Data,
  156. ULONG Length
  157. )
  158. /*++
  159. Routine Description:
  160. Hashes a buffer into a 32 bit value
  161. Arguments:
  162. Data - Buffer containing the data to be hashed.
  163. Length - The length in bytes of the buffer
  164. Return Value:
  165. ULONG - a 32 bit hash value.
  166. --*/
  167. {
  168. PCHAR Buffer;
  169. ULONG Result = 0;
  170. LONG i;
  171. Buffer = (PCHAR)Data;
  172. for (i=0 ; i<=(LONG)((Length-3)-sizeof(ULONG)) ; i++) {
  173. ULONG Tmp;
  174. Tmp = *((ULONG UNALIGNED *)(Buffer + i));
  175. Result += Tmp;
  176. }
  177. return( Result );
  178. }
  179. NTSTATUS
  180. ObpLogSecurityDescriptor(
  181. IN PSECURITY_DESCRIPTOR InputSecurityDescriptor,
  182. OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor
  183. )
  184. /*++
  185. Routine Description:
  186. Takes a passed security descriptor and registers it into the
  187. security descriptor database.
  188. Arguments:
  189. InputSecurityDescriptor - The new security descriptor to be logged into the database.
  190. OutputSecurityDescriptor - Output security descriptor to be used by the caller.
  191. Return Value:
  192. NT_STATUS
  193. --*/
  194. {
  195. ULONG FullHash;
  196. UCHAR SmallHash;
  197. PSECURITY_DESCRIPTOR_HEADER NewDescriptor;
  198. PLIST_ENTRY Front;
  199. PLIST_ENTRY Back;
  200. PSECURITY_DESCRIPTOR_HEADER Header;
  201. BOOLEAN Match;
  202. FullHash = ObpHashSecurityDescriptor( InputSecurityDescriptor );
  203. SmallHash = (UCHAR)FullHash;
  204. //
  205. // See if the entry matching SmallHash is in use.
  206. // Lock the table first, unlock if if we don't need it.
  207. //
  208. ObpAcquireDescriptorCacheWriteLock();
  209. Front = SecurityDescriptorCache[SmallHash];
  210. Back = NULL;
  211. Match = FALSE;
  212. while ( Front != NULL ) {
  213. Header = LINK_TO_SD_HEADER( Front );
  214. if ( Header->FullHash > FullHash ) {
  215. break;
  216. }
  217. if ( Header->FullHash == FullHash ) {
  218. Match = ObpCompareSecurityDescriptors( InputSecurityDescriptor,
  219. &Header->SecurityDescriptor
  220. );
  221. if ( Match ) {
  222. break;
  223. }
  224. ObPrint( SHOW_COLLISIONS,("Got a collision on %d, no match\n",SmallHash));
  225. }
  226. Back = Front;
  227. Front = Front->Flink;
  228. }
  229. if ( Match ) {
  230. Header->RefCount++;
  231. ObPrint( SHOW_REFERENCES, ("Reference Index = %d, New RefCount = %d\n",Header->Index,Header->RefCount));
  232. *OutputSecurityDescriptor = &Header->SecurityDescriptor;
  233. ExFreePool( InputSecurityDescriptor );
  234. ObpReleaseDescriptorCacheLock();
  235. return( STATUS_SUCCESS );
  236. }
  237. //
  238. // Can't use an existing one, create a new entry
  239. // and insert it into the list.
  240. //
  241. NewDescriptor = OpbCreateCacheEntry( InputSecurityDescriptor,
  242. FullHash,
  243. SmallHash
  244. );
  245. if ( NewDescriptor == NULL ) {
  246. ObpReleaseDescriptorCacheLock();
  247. return( STATUS_INSUFFICIENT_RESOURCES );
  248. }
  249. #if OB_DIAGNOSTICS_ENABLED
  250. TotalCacheEntries++;
  251. #endif
  252. ObPrint( SHOW_STATISTICS, ("TotalCacheEntries = %d \n",TotalCacheEntries));
  253. ObPrint( SHOW_COLLISIONS, ("Adding new entry for index #%d \n",SmallHash));
  254. //
  255. // We don't need the old security descriptor any more.
  256. //
  257. ExFreePool( InputSecurityDescriptor );
  258. if ( Back == NULL ) {
  259. //
  260. // We're inserting at the beginning of the list for this
  261. // minor index
  262. //
  263. NewDescriptor->Link.Flink = SecurityDescriptorCache[SmallHash];
  264. SecurityDescriptorCache[SmallHash] = &NewDescriptor->Link;
  265. if ( NewDescriptor->Link.Flink != NULL ) {
  266. NewDescriptor->Link.Flink->Blink = &NewDescriptor->Link;
  267. }
  268. } else {
  269. //
  270. // Hook new descriptor entry into list.
  271. //
  272. NewDescriptor->Link.Flink = Front;
  273. NewDescriptor->Link.Blink = Back;
  274. Back->Flink = &NewDescriptor->Link;
  275. if (Front != NULL) {
  276. Front->Blink = &NewDescriptor->Link;
  277. }
  278. }
  279. *OutputSecurityDescriptor = &NewDescriptor->SecurityDescriptor;
  280. ObpReleaseDescriptorCacheLock();
  281. return( STATUS_SUCCESS );
  282. }
  283. PSECURITY_DESCRIPTOR_HEADER
  284. OpbCreateCacheEntry(
  285. PSECURITY_DESCRIPTOR InputSecurityDescriptor,
  286. ULONG FullHash,
  287. UCHAR SmallHash
  288. )
  289. /*++
  290. Routine Description:
  291. Allocates and initializes a new cache entry.
  292. Arguments:
  293. InputSecurityDescriptor - The security descriptor to be cached.
  294. FullHash - Full 32 bit hash of the security descriptor.
  295. SmallHash - Index into the cache table.
  296. Return Value:
  297. A pointer to the newly allocated cache entry, or NULL
  298. --*/
  299. {
  300. ULONG SecurityDescriptorLength;
  301. ULONG CacheEntrySize;
  302. PSECURITY_DESCRIPTOR_HEADER NewDescriptor;
  303. SecurityDescriptorLength = RtlLengthSecurityDescriptor ( InputSecurityDescriptor );
  304. CacheEntrySize = SecurityDescriptorLength + (sizeof(SECURITY_DESCRIPTOR_HEADER) - sizeof( QUAD ));
  305. NewDescriptor = ExAllocatePoolWithTag( PagedPool, CacheEntrySize, 'dSeS');
  306. if ( NewDescriptor == NULL ) {
  307. return( NULL );
  308. }
  309. NewDescriptor->Index = SmallHash;
  310. NewDescriptor->RefCount = 1;
  311. NewDescriptor->FullHash = FullHash;
  312. NewDescriptor->Link.Flink = NULL;
  313. NewDescriptor->Link.Blink = NULL;
  314. RtlCopyMemory( &NewDescriptor->SecurityDescriptor, InputSecurityDescriptor, SecurityDescriptorLength );
  315. return( NewDescriptor );
  316. }
  317. PSECURITY_DESCRIPTOR
  318. ObpReferenceSecurityDescriptor(
  319. PVOID Object
  320. )
  321. /*++
  322. Routine Description:
  323. References the security descriptor of the passed object.
  324. Arguments:
  325. Object - Object being access validated.
  326. Return Value:
  327. The security descriptor of the object.
  328. --*/
  329. {
  330. PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
  331. POBJECT_HEADER ObjectHeader;
  332. POBJECT_TYPE ObjectType;
  333. PSECURITY_DESCRIPTOR SecurityDescriptor;
  334. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  335. ObjectType = ObjectHeader->Type;
  336. ASSERT( ObpCentralizedSecurity(ObjectType) );
  337. ObpAcquireDescriptorCacheWriteLock();
  338. SecurityDescriptor = OBJECT_TO_OBJECT_HEADER( Object )->SecurityDescriptor;
  339. IF_OB_GLOBAL( STOP_INVALID_DESCRIPTOR ) {
  340. if( !RtlValidSecurityDescriptor ( SecurityDescriptor )) {
  341. DbgBreakPoint();
  342. }
  343. }
  344. if ( SecurityDescriptor != NULL ) {
  345. SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
  346. ObPrint( SHOW_REFERENCES, ("Referencing index #%d, Refcount = %d \n",SecurityDescriptorHeader->Index,SecurityDescriptorHeader->RefCount));
  347. SecurityDescriptorHeader->RefCount++;
  348. }
  349. ObpReleaseDescriptorCacheLock();
  350. return( SecurityDescriptor );
  351. }
  352. NTSTATUS
  353. ObDeassignSecurity (
  354. IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor
  355. )
  356. {
  357. PSECURITY_DESCRIPTOR_HEADER Header;
  358. Header = SD_TO_SD_HEADER( *SecurityDescriptor );
  359. ObPrint( SHOW_DEASSIGN,("Deassigning security descriptor %x, Index = %d\n",*SecurityDescriptor, Header->Index));
  360. ObpDereferenceSecurityDescriptor( *SecurityDescriptor );
  361. //
  362. // NULL out the SecurityDescriptor in the object's
  363. // header so we don't try to free it again.
  364. //
  365. *SecurityDescriptor = NULL;
  366. return( STATUS_SUCCESS );
  367. }
  368. VOID
  369. ObpDereferenceSecurityDescriptor(
  370. PSECURITY_DESCRIPTOR SecurityDescriptor
  371. )
  372. /*++
  373. Routine Description:
  374. Decrements the refcount of a cached security descriptor
  375. Arguments:
  376. SecurityDescriptor - Points to a cached security descriptor
  377. Return Value:
  378. None.
  379. --*/
  380. {
  381. PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader;
  382. ObpAcquireDescriptorCacheWriteLock();
  383. SecurityDescriptorHeader = SD_TO_SD_HEADER( SecurityDescriptor );
  384. ObPrint( SHOW_REFERENCES, ("Dereferencing SecurityDescriptor %x, index #%d, refcount = %d \n", SecurityDescriptor, SecurityDescriptorHeader->Index,SecurityDescriptorHeader->RefCount));
  385. // DbgPrint("Dereferencing SecurityDescriptor %x, index #%d, refcount = %d \n", SecurityDescriptor, SecurityDescriptorHeader->Index,SecurityDescriptorHeader->RefCount);
  386. ASSERT(SecurityDescriptorHeader->RefCount != 0);
  387. if (--SecurityDescriptorHeader->RefCount == 0) {
  388. ObpDestroySecurityDescriptorHeader( SecurityDescriptorHeader );
  389. }
  390. ObpReleaseDescriptorCacheLock();
  391. }
  392. VOID
  393. ObpDestroySecurityDescriptorHeader(
  394. IN PSECURITY_DESCRIPTOR_HEADER Header
  395. )
  396. /*++
  397. Routine Description:
  398. Frees a cached security descriptor and unlinks it from the chain.
  399. Does nothing if it's being reused.
  400. Arguments:
  401. Header - Pointer to a security descriptor header (cached security descriptor)
  402. Return Value:
  403. None.
  404. --*/
  405. {
  406. PLIST_ENTRY Forward;
  407. PLIST_ENTRY Rear;
  408. UCHAR Index;
  409. ASSERT ( Header->RefCount == 0 );
  410. #if OB_DIAGNOSTICS_ENABLED
  411. TotalCacheEntries--;
  412. #endif
  413. ObPrint( SHOW_STATISTICS, ("TotalCacheEntries = %d \n",TotalCacheEntries));
  414. Index = Header->Index;
  415. Forward = Header->Link.Flink;
  416. Rear = Header->Link.Blink;
  417. if ( Forward != NULL ) {
  418. Forward->Blink = Rear;
  419. }
  420. if ( Rear != NULL ) {
  421. Rear->Flink = Forward;
  422. } else {
  423. //
  424. // if Rear is NULL, we're deleting the head of the list
  425. //
  426. SecurityDescriptorCache[Index] = Forward;
  427. }
  428. ObPrint( SHOW_HEADER_FREE, ("Freeing memory at %x \n",Header));
  429. ExFreePool( Header );
  430. return;
  431. }
  432. BOOLEAN
  433. ObpCompareSecurityDescriptors(
  434. IN PSECURITY_DESCRIPTOR SD1,
  435. IN PSECURITY_DESCRIPTOR SD2
  436. )
  437. /*++
  438. Routine Description:
  439. Performs a byte by byte comparison of two self relative security descriptors
  440. to determine if they are identical.
  441. Arguments:
  442. SD1, SD2 - Security descriptors to be compared.
  443. Return Value:
  444. TRUE - They are the same.
  445. FALSE - They are different.
  446. --*/
  447. {
  448. ULONG Length1;
  449. ULONG Length2;
  450. ULONG Compare;
  451. //
  452. // Calculating the lenght is pretty fast, see if we
  453. // can get away with doing only that.
  454. //
  455. Length1 = RtlLengthSecurityDescriptor ( SD1 );
  456. Length2 = RtlLengthSecurityDescriptor ( SD2 );
  457. if (Length1 != Length2) {
  458. return( FALSE );
  459. }
  460. return (BOOLEAN)RtlEqualMemory ( SD1, SD2, Length1 );
  461. }
  462. VOID
  463. ObpAcquireDescriptorCacheWriteLock(
  464. VOID
  465. )
  466. /*++
  467. Routine Description:
  468. Takes a write lock on the security descriptor cache.
  469. Arguments:
  470. none
  471. Return Value:
  472. None.
  473. --*/
  474. {
  475. KeEnterCriticalRegion();
  476. (VOID) ExAcquireResourceExclusive( &SecurityDescriptorCacheLock, TRUE );
  477. return;
  478. }
  479. VOID
  480. ObpAcquireDescriptorCacheReadLock(
  481. VOID
  482. )
  483. /*++
  484. Routine Description:
  485. Takes a read lock on the security descriptor cache.
  486. Arguments:
  487. none
  488. Return Value:
  489. None.
  490. --*/
  491. {
  492. KeEnterCriticalRegion();
  493. (VOID)ExAcquireResourceShared( &SecurityDescriptorCacheLock,TRUE);
  494. return;
  495. }
  496. VOID
  497. ObpReleaseDescriptorCacheLock(
  498. VOID
  499. )
  500. /*++
  501. Routine Description:
  502. Releases a lock on the security descriptor cache.
  503. Arguments:
  504. none
  505. Return Value:
  506. None.
  507. --*/
  508. {
  509. (VOID) ExReleaseResource( &SecurityDescriptorCacheLock );
  510. KeLeaveCriticalRegion ();
  511. return;
  512. }