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.

1585 lines
43 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. dbhandle.c
  5. Abstract:
  6. LSA Database Handle Manager
  7. Access to an LSA database object involves a sequence of API calls
  8. which involve the following:
  9. o A call to an object-type dependent "open" API
  10. o One or more calls to API that manipulate the object
  11. o A call to the LsaClose API
  12. It is necessary to track context for each open of an object, for example,
  13. the accesses granted and the underlying LSA database handle to the
  14. object. Lsa handles provide this mechanism: an Lsa handle is simply a
  15. pointer to a data structure containing this context.
  16. Author:
  17. Scott Birrell (ScottBi) May 29, 1991
  18. Environment:
  19. Revision History:
  20. --*/
  21. #include <lsapch2.h>
  22. #include "dbp.h"
  23. #include "adtp.h"
  24. //
  25. // Handle Table anchor. The handle table is just a linked list
  26. //
  27. struct _LSAP_DB_HANDLE LsapDbHandleTable;
  28. LSAP_DB_HANDLE_TABLE LsapDbHandleTableEx;
  29. NTSTATUS
  30. LsapDbInitHandleTables(
  31. VOID
  32. )
  33. /*++
  34. Routine Description:
  35. This function initializes the LSA Database Handle Tables. It initializes the table members
  36. and the locks, so it must be called before the table is accessed.
  37. Arguments:
  38. None.
  39. Return Value:
  40. VOID
  41. --*/
  42. {
  43. LsapDbHandleTableEx.UserCount = 0;
  44. InitializeListHead( &LsapDbHandleTableEx.UserHandleList );
  45. LsapDbHandleTableEx.FreedUserEntryCount = 0;
  46. //
  47. // Now, also initialize the flat list
  48. //
  49. LsapDbHandleTable.Next = &LsapDbHandleTable;
  50. LsapDbHandleTable.Previous = &LsapDbHandleTable;
  51. return STATUS_SUCCESS;
  52. }
  53. NTSTATUS
  54. LsapDbInsertHandleInTable(
  55. IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
  56. IN LSAPR_HANDLE NewHandle,
  57. IN PLUID UserId,
  58. IN HANDLE UserToken
  59. )
  60. /*++
  61. Routine Description:
  62. This routine will enter a new handle into the lsa global policy handle table.
  63. Arguments:
  64. ObjectInformation - Information on the object being created.
  65. NewHandle - New handle to be inserted
  66. UserId - LUID of the user creating the handle.
  67. 0: means trusted handle
  68. UserToken - Token handle of the user creating the handle. NULL means local system
  69. Return Value:
  70. STATUS_SUCCESS - Success
  71. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  72. --*/
  73. {
  74. NTSTATUS Status;
  75. PLIST_ENTRY HandleEntry;
  76. PLSAP_DB_HANDLE_TABLE_USER_ENTRY CurrentUserEntry = NULL;
  77. BOOLEAN UserAdded = FALSE;
  78. BOOLEAN PolicyHandleCountIncremented = FALSE;
  79. LSAP_DB_HANDLE DbHandle = ( LSAP_DB_HANDLE )NewHandle;
  80. LsapEnterFunc( "LsapDbInsertHandleInTable" );
  81. //
  82. // First, grab the handle table lock.
  83. //
  84. LsapDbLockAcquire( &LsapDbState.HandleTableLock );
  85. //
  86. // Find the entry that corresponds to our given user.
  87. //
  88. for ( HandleEntry = LsapDbHandleTableEx.UserHandleList.Flink;
  89. HandleEntry != &LsapDbHandleTableEx.UserHandleList;
  90. HandleEntry = HandleEntry->Flink ) {
  91. CurrentUserEntry = CONTAINING_RECORD( HandleEntry,
  92. LSAP_DB_HANDLE_TABLE_USER_ENTRY,
  93. Next );
  94. if ( RtlEqualLuid( &CurrentUserEntry->LogonId, UserId ) ) {
  95. LsapDsDebugOut(( DEB_HANDLE, "Handle 0x%lp belongs to entry 0x%lp\n",
  96. NewHandle,
  97. CurrentUserEntry ));
  98. break;
  99. }
  100. CurrentUserEntry = NULL;
  101. }
  102. //
  103. // Allocate a new entry if necessary.
  104. //
  105. if ( CurrentUserEntry == NULL ) {
  106. LsapDsDebugOut(( DEB_HANDLE, "Handle list not found for user %x:%x\n",
  107. UserId->HighPart,
  108. UserId->LowPart ));
  109. //
  110. // See if we can grab one off the lookaside list
  111. //
  112. if ( LsapDbHandleTableEx.FreedUserEntryCount ) {
  113. CurrentUserEntry = LsapDbHandleTableEx.FreedUserEntryList[
  114. LsapDbHandleTableEx.FreedUserEntryCount - 1 ];
  115. LsapDsDebugOut(( DEB_HANDLE,
  116. "Using user entry 0x%lp from free list spot %lu\n",
  117. CurrentUserEntry,
  118. LsapDbHandleTableEx.FreedUserEntryCount-1 ));
  119. LsapDbHandleTableEx.FreedUserEntryCount--;
  120. ASSERT( CurrentUserEntry );
  121. } else {
  122. CurrentUserEntry = LsapAllocateLsaHeap( sizeof( LSAP_DB_HANDLE_TABLE_USER_ENTRY ) );
  123. if ( CurrentUserEntry == NULL ) {
  124. Status = STATUS_INSUFFICIENT_RESOURCES;
  125. goto InsertHandleInTableEntryExit;
  126. }
  127. }
  128. LsapDsDebugOut(( DEB_HANDLE,
  129. "Allocated user entry 0x%lp\n", CurrentUserEntry ));
  130. //
  131. // Set the information in the new entry, and then insert it into the lists
  132. //
  133. InitializeListHead( &CurrentUserEntry->PolicyHandles );
  134. InitializeListHead( &CurrentUserEntry->ObjectHandles );
  135. CurrentUserEntry->PolicyHandlesCount = 0;
  136. RtlCopyLuid( &CurrentUserEntry->LogonId, UserId );
  137. CurrentUserEntry->MaxPolicyHandles = LSAP_DB_MAXIMUM_HANDLES_PER_USER ;
  138. if ( RtlEqualLuid( UserId, &LsapSystemLogonId ) ||
  139. RtlEqualLuid( UserId, &LsapZeroLogonId ) )
  140. {
  141. CurrentUserEntry->MaxPolicyHandles = 0x7FFFFFFF ;
  142. }
  143. else if ( UserToken != NULL )
  144. {
  145. UCHAR Buffer[ 128 ];
  146. PTOKEN_USER User ;
  147. NTSTATUS Status2 ;
  148. ULONG Size ;
  149. User = (PTOKEN_USER) Buffer ;
  150. Status2 = NtQueryInformationToken(
  151. UserToken,
  152. TokenUser,
  153. User,
  154. sizeof( Buffer ),
  155. &Size );
  156. if ( NT_SUCCESS( Status2 ) )
  157. {
  158. if ( RtlEqualSid( User->User.Sid, LsapAnonymousSid ) )
  159. {
  160. CurrentUserEntry->MaxPolicyHandles = 0x7FFFFFFF ;
  161. }
  162. }
  163. }
  164. #if DBG
  165. if ( UserToken != NULL ) {
  166. OBJECT_ATTRIBUTES ObjAttrs;
  167. SECURITY_QUALITY_OF_SERVICE SecurityQofS;
  168. NTSTATUS Status2;
  169. //
  170. // Duplicate the token
  171. //
  172. InitializeObjectAttributes( &ObjAttrs, NULL, 0L, NULL, NULL );
  173. SecurityQofS.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  174. SecurityQofS.ImpersonationLevel = SecurityImpersonation;
  175. SecurityQofS.ContextTrackingMode = FALSE; // Snapshot client context
  176. SecurityQofS.EffectiveOnly = FALSE;
  177. ObjAttrs.SecurityQualityOfService = &SecurityQofS;
  178. Status2 = NtDuplicateToken( UserToken,
  179. TOKEN_READ | TOKEN_WRITE | TOKEN_EXECUTE,
  180. &ObjAttrs,
  181. FALSE,
  182. TokenImpersonation,
  183. &CurrentUserEntry->UserToken );
  184. if ( !NT_SUCCESS( Status2 ) ) {
  185. LsapDsDebugOut(( DEB_HANDLE,
  186. "Failed to duplicate the token for handle 0x%lp: 0x%lx\n",
  187. NewHandle,
  188. Status2 ));
  189. CurrentUserEntry->UserToken = NULL;
  190. }
  191. //
  192. // A failure to copy the token doesn constitute a failure to add the entry
  193. //
  194. }
  195. #endif
  196. InsertTailList( &LsapDbHandleTableEx.UserHandleList,
  197. &CurrentUserEntry->Next );
  198. LsapDbHandleTableEx.UserCount++;
  199. UserAdded = TRUE;
  200. }
  201. //
  202. // Ok, now that we have the entry, let's add it to the appropriate list...
  203. //
  204. if ( ObjectInformation->ObjectTypeId == PolicyObject ) {
  205. ASSERT( DbHandle->ObjectTypeId == PolicyObject );
  206. if ( CurrentUserEntry->PolicyHandlesCount >= CurrentUserEntry->MaxPolicyHandles ) {
  207. LsapDsDebugOut(( DEB_HANDLE,
  208. "Quota exceeded for user %x:%x, handle 0x%lp\n",
  209. UserId->HighPart,
  210. UserId->LowPart,
  211. NewHandle ));
  212. Status = STATUS_QUOTA_EXCEEDED;
  213. goto InsertHandleInTableEntryExit;
  214. } else {
  215. InsertTailList( &CurrentUserEntry->PolicyHandles, &DbHandle->UserHandleList );
  216. CurrentUserEntry->PolicyHandlesCount++;
  217. PolicyHandleCountIncremented = TRUE;
  218. }
  219. } else {
  220. ASSERT( DbHandle->ObjectTypeId != PolicyObject );
  221. InsertTailList( &CurrentUserEntry->ObjectHandles, &DbHandle->UserHandleList );
  222. }
  223. //
  224. // Finally, make sure to insert it in the flat list
  225. //
  226. DbHandle->Next = LsapDbHandleTable.Next;
  227. DbHandle->Previous = &LsapDbHandleTable;
  228. DbHandle->Next->Previous = DbHandle;
  229. DbHandle->Previous->Next = DbHandle;
  230. DbHandle->UserEntry = ( PVOID )CurrentUserEntry;
  231. Status = STATUS_SUCCESS;
  232. InsertHandleInTableEntryExit:
  233. //
  234. // If we succesfully created the entry, make sure we remove it...
  235. //
  236. if ( !NT_SUCCESS( Status ) && UserAdded ) {
  237. RemoveEntryList( &DbHandle->UserHandleList );
  238. if ( PolicyHandleCountIncremented ) {
  239. CurrentUserEntry->PolicyHandlesCount--;
  240. }
  241. if ( CurrentUserEntry->UserToken ) {
  242. NtClose( CurrentUserEntry->UserToken );
  243. }
  244. LsapDbHandleTableEx.UserCount--;
  245. RemoveEntryList( &CurrentUserEntry->Next );
  246. LsapFreeLsaHeap( CurrentUserEntry );
  247. }
  248. LsapDbLockRelease( &LsapDbState.HandleTableLock );
  249. LsapExitFunc( "LsapDbInsertHandleInTable", Status );
  250. return( Status );
  251. }
  252. BOOLEAN
  253. LsapDbFindIdenticalHandleInTable(
  254. IN OUT PLSAPR_HANDLE OriginalHandle
  255. )
  256. /*++
  257. Routine Description:
  258. This routine will find an existing handle in the lsa global policy handle
  259. table that matches the passed in handle. If a matching handle is found,
  260. the passed in handle is dereferenced and the matching handle is returned.
  261. If no matching handle is found, the original passed in handle is returned.
  262. Arguments:
  263. OriginalHandle - Passes in the original handle to compare with.
  264. Returns the handle that is to be used.
  265. Return Value:
  266. TRUE - Original handle was returned or new handle was returned.
  267. FALSE - New handle would exceed maximum allowed reference count if it were used.
  268. Original handle is returned.
  269. --*/
  270. {
  271. BOOLEAN RetBool = TRUE;
  272. LSAP_DB_HANDLE InputHandle;
  273. LSAP_DB_HANDLE DbHandle;
  274. PLIST_ENTRY HandleEntry;
  275. PLSAP_DB_HANDLE_TABLE_USER_ENTRY CurrentUserEntry = NULL;
  276. LsapEnterFunc( "LsapDbFindIndenticalHandleInTable" );
  277. //
  278. // Return immediately if the handle isn't a policy handle
  279. //
  280. InputHandle = (LSAP_DB_HANDLE) *OriginalHandle;
  281. if ( InputHandle->ObjectTypeId != PolicyObject ) {
  282. LsapExitFunc( "LsapDbFindIdenticalHandleInTable", 0 );
  283. return TRUE;
  284. }
  285. CurrentUserEntry = (PLSAP_DB_HANDLE_TABLE_USER_ENTRY) InputHandle->UserEntry;
  286. ASSERT( CurrentUserEntry != NULL );
  287. //
  288. // First, grab the handle table lock.
  289. //
  290. LsapDbLockAcquire( &LsapDbState.HandleTableLock );
  291. //
  292. // If this is not a trusted handle,
  293. // try to share the handle.
  294. //
  295. if ( !RtlEqualLuid( &CurrentUserEntry->LogonId, &LsapZeroLogonId ) ) {
  296. //
  297. // Now, walk the appropriate list to find one for the matching access.
  298. //
  299. for ( HandleEntry = CurrentUserEntry->PolicyHandles.Flink;
  300. HandleEntry != &CurrentUserEntry->PolicyHandles;
  301. HandleEntry = HandleEntry->Flink ) {
  302. //
  303. // See if the access masks match. If so, we have a winner
  304. //
  305. DbHandle = CONTAINING_RECORD( HandleEntry,
  306. struct _LSAP_DB_HANDLE,
  307. UserHandleList );
  308. //
  309. // Ignore the original handle
  310. //
  311. if ( DbHandle == InputHandle ) {
  312. /* Do nothing here */
  313. //
  314. // The handles are considered identical if the GrantedAccess matches.
  315. //
  316. } else if ( DbHandle->GrantedAccess == InputHandle->GrantedAccess ) {
  317. //
  318. // Don't let this handle be cloned too many times
  319. //
  320. if ( DbHandle->ReferenceCount >= LSAP_DB_MAXIMUM_REFERENCE_COUNT ) {
  321. RetBool = FALSE;
  322. break;
  323. }
  324. DbHandle->ReferenceCount++;
  325. #if DBG
  326. GetSystemTimeAsFileTime( (LPFILETIME) &DbHandle->HandleLastAccessTime );
  327. #endif // DBG
  328. LsapDsDebugOut(( DEB_HANDLE,
  329. "Found handle 0x%lp for user %x:%x using access 0x%lx (%ld)\n",
  330. DbHandle,
  331. CurrentUserEntry->LogonId.HighPart,
  332. CurrentUserEntry->LogonId.LowPart,
  333. DbHandle->GrantedAccess,
  334. DbHandle->ReferenceCount ));
  335. *OriginalHandle = (LSAPR_HANDLE)DbHandle;
  336. //
  337. // Dereference the original handle.
  338. //
  339. LsapDbDereferenceHandle( (LSAPR_HANDLE)InputHandle, TRUE );
  340. break;
  341. } else {
  342. LsapDsDebugOut(( DEB_HANDLE,
  343. "Handle 0x%lp for user %x:%x has access 0x%lx, need 0x%lx\n",
  344. DbHandle,
  345. CurrentUserEntry->LogonId.HighPart,
  346. CurrentUserEntry->LogonId.LowPart,
  347. DbHandle->GrantedAccess,
  348. InputHandle->GrantedAccess ));
  349. }
  350. }
  351. }
  352. LsapDbLockRelease( &LsapDbState.HandleTableLock );
  353. LsapExitFunc( "LsapDbFindIdenticalHandleInTable", 0 );
  354. return RetBool;
  355. }
  356. NTSTATUS
  357. LsapDbRemoveHandleFromTable(
  358. IN PLSAPR_HANDLE Handle
  359. )
  360. /*++
  361. Routine Description:
  362. This routine removes an existing handle from all tables it is in.
  363. Enter with LsapDbState.HandleTableLock locked.
  364. Arguments:
  365. Handle - Handle to remove.
  366. Return Value:
  367. STATUS_SUCCESS - Success
  368. STATUS_OBJECT_NAME_NOT_FOUND - The handle for the specified user cannot be found
  369. --*/
  370. {
  371. NTSTATUS Status = STATUS_SUCCESS;
  372. PLIST_ENTRY HandleList, HandleEntry;
  373. PLSAP_DB_HANDLE_TABLE_USER_ENTRY CurrentUserEntry = NULL;
  374. LSAP_DB_HANDLE DbHandle = ( LSAP_DB_HANDLE )Handle, FoundHandle;
  375. PULONG EntryToDecrement ;
  376. LsapEnterFunc( "LsapDbRemoveHandleFromTable" );
  377. CurrentUserEntry = DbHandle->UserEntry;
  378. ASSERT( CurrentUserEntry != NULL );
  379. if ( DbHandle->ObjectTypeId == PolicyObject ) {
  380. HandleList = &CurrentUserEntry->PolicyHandles;
  381. EntryToDecrement = &CurrentUserEntry->PolicyHandlesCount;
  382. } else {
  383. HandleList = &CurrentUserEntry->ObjectHandles;
  384. EntryToDecrement = NULL ;
  385. }
  386. Status = STATUS_NOT_FOUND;
  387. for ( HandleEntry = HandleList->Flink;
  388. HandleEntry != HandleList;
  389. HandleEntry = HandleEntry->Flink ) {
  390. FoundHandle = CONTAINING_RECORD( HandleEntry,
  391. struct _LSAP_DB_HANDLE,
  392. UserHandleList );
  393. if ( FoundHandle == DbHandle ) {
  394. RemoveEntryList( &FoundHandle->UserHandleList );
  395. FoundHandle->Next->Previous = FoundHandle->Previous;
  396. FoundHandle->Previous->Next = FoundHandle->Next;
  397. if ( EntryToDecrement ) {
  398. *EntryToDecrement -= 1 ;
  399. }
  400. //
  401. // See if we can remove the entry itself
  402. //
  403. if ( IsListEmpty( &CurrentUserEntry->PolicyHandles ) &&
  404. IsListEmpty( &CurrentUserEntry->ObjectHandles ) ) {
  405. LsapDsDebugOut(( DEB_HANDLE,
  406. "Removing empty user list 0x%lp\n",
  407. CurrentUserEntry ));
  408. RemoveEntryList( &CurrentUserEntry->Next );
  409. LsapDbHandleTableEx.UserCount--;
  410. if ( CurrentUserEntry->UserToken ) {
  411. NtClose( CurrentUserEntry->UserToken );
  412. }
  413. LsapDsDebugOut(( DEB_HANDLE,
  414. "Removing user entry 0x%lp\n", CurrentUserEntry ));
  415. if ( LsapDbHandleTableEx.FreedUserEntryCount < LSAP_DB_HANDLE_FREE_LIST_SIZE ) {
  416. LsapDbHandleTableEx.FreedUserEntryList[
  417. LsapDbHandleTableEx.FreedUserEntryCount ] = CurrentUserEntry;
  418. LsapDsDebugOut(( DEB_HANDLE,
  419. "Moving user entry 0x%lp to free list spot %lu\n",
  420. CurrentUserEntry,
  421. LsapDbHandleTableEx.FreedUserEntryCount ));
  422. LsapDbHandleTableEx.FreedUserEntryCount++;
  423. } else {
  424. LsapFreeLsaHeap( CurrentUserEntry );
  425. }
  426. }
  427. Status = STATUS_SUCCESS;
  428. break;
  429. } else {
  430. LsapDsDebugOut(( DEB_HANDLE,
  431. "Looking for user entry 0x%lp against 0x%lp\n",
  432. FoundHandle,
  433. DbHandle ));
  434. }
  435. }
  436. LsapExitFunc( "LsapDbRemoveHandleFromTable", Status );
  437. return( Status );
  438. }
  439. NTSTATUS
  440. LsapDbCreateHandle(
  441. IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
  442. IN ULONG Options,
  443. IN ULONG CreateHandleOptions,
  444. OUT LSAPR_HANDLE *CreatedHandle
  445. )
  446. /*++
  447. Routine Description:
  448. This function creates and initializes a handle for an LSA Database object.
  449. The handle is allocated from the LSA Heap and added to the handle table.
  450. Using the Object Type, and either the Sid or Name provided in
  451. ObjectInformation, the Logical and Physical Names of the object are
  452. constructed and pointers to them are stored in the handle. The LSA
  453. Database must be locked before calling this function.
  454. If there is a Container Handle specified in the ObjectInformation, the
  455. newly created handle inherits its trusted status (TRUE if trusted, else
  456. FALSE). If there is no container handle, the trusted status is set
  457. to FALSE by default. When a non-trusted handle is used to access an
  458. object, impersonation and access validation occurs.
  459. Arguments:
  460. ObjectInformation - Pointer to object information structure which must
  461. have been validated by a calling routine. The following information
  462. items must be specified:
  463. o Object Type Id
  464. o Object Logical Name (as ObjectAttributes->ObjectName, a pointer to
  465. a Unicode string)
  466. o Container object handle (for any object except the Policy object).
  467. o Object Sid (if any)
  468. All other fields in ObjectAttributes portion of ObjectInformation
  469. such as SecurityDescriptor are ignored.
  470. Options - Optional actions
  471. LSAP_DB_TRUSTED - Handle is to be marked as Trusted.
  472. handle is use, access checking will be bypassed. If the
  473. handle is used to create or open a lower level object, that
  474. object's handle will by default inherit the Trusted property.
  475. LSAP_DB_NON_TRUSTED - Handle is to be marked as Non-Trusted.
  476. If neither of the above options is specified, the handle will
  477. either inherit the trusted status of the Container Handle
  478. provilde in ObjectInformation, or, if none, the handle will
  479. be marked non-trusted.
  480. CreateHandleOptions - Options used to control the behavior of the CreateHandle function.
  481. CreatedHandle - Where the created handle is returned
  482. Return Value:
  483. STATUS_SUCCESS -- Success
  484. STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed
  485. STATUS_INVALID_SID - A bogus sid was encountered
  486. --*/
  487. {
  488. NTSTATUS Status = STATUS_SUCCESS;
  489. LSAP_DB_HANDLE Handle = NULL;
  490. PSID Sid = NULL;
  491. ULONG SidLength;
  492. BOOLEAN ObjectInReg = TRUE, ObjectInDs = FALSE, NewTrustObject = FALSE;
  493. HANDLE ClientToken;
  494. LUID UserId;
  495. TOKEN_STATISTICS TokenStats;
  496. ULONG InfoReturned;
  497. BOOL Locked = FALSE ;
  498. HANDLE ClientTokenToFree = NULL;
  499. //
  500. // First, grab the handle table lock.
  501. //
  502. LsapDbLockAcquire( &LsapDbState.HandleTableLock );
  503. Locked = TRUE ;
  504. //
  505. // Get the current users token, unless we are trusted...
  506. //
  507. UserId = LsapZeroLogonId;
  508. if ( ObjectInformation->ObjectAttributes.RootDirectory == NULL ||
  509. !( (LSAP_DB_HANDLE)ObjectInformation->ObjectAttributes.RootDirectory )->Trusted ) {
  510. Status = I_RpcMapWin32Status( RpcImpersonateClient( 0 ) );
  511. if ( NT_SUCCESS( Status ) ) {
  512. Status = NtOpenThreadToken( NtCurrentThread(),
  513. TOKEN_QUERY | TOKEN_DUPLICATE,
  514. TRUE,
  515. &ClientToken );
  516. if ( NT_SUCCESS( Status ) ) {
  517. Status = NtQueryInformationToken( ClientToken,
  518. TokenStatistics,
  519. &TokenStats,
  520. sizeof( TokenStats ),
  521. &InfoReturned );
  522. if ( NT_SUCCESS( Status ) ) {
  523. UserId = TokenStats.AuthenticationId;
  524. }
  525. ClientTokenToFree = ClientToken;
  526. }
  527. Status = I_RpcMapWin32Status( RpcRevertToSelf() );
  528. }
  529. }
  530. LsapDbLockRelease( &LsapDbState.HandleTableLock );
  531. Locked = FALSE ;
  532. //
  533. // Allocate memory for the new handle from the process heap.
  534. //
  535. Handle = LsapAllocateLsaHeap(sizeof(struct _LSAP_DB_HANDLE));
  536. if (Handle == NULL) {
  537. Status = STATUS_INSUFFICIENT_RESOURCES;
  538. goto CreateHandleError;
  539. }
  540. //
  541. // Mark the handle as allocated and initialize the reference count
  542. // to one. Initialize other fields based on the object information
  543. // supplied.
  544. //
  545. Handle->Allocated = TRUE;
  546. Handle->KeyHandle = NULL;
  547. Handle->ReferenceCount = 1;
  548. Handle->ObjectTypeId = ObjectInformation->ObjectTypeId;
  549. Handle->ContainerHandle = ( LSAP_DB_HANDLE )ObjectInformation->ObjectAttributes.RootDirectory;
  550. Handle->Sid = NULL;
  551. Handle->Trusted = FALSE;
  552. Handle->DeletedObject = FALSE;
  553. Handle->GenerateOnClose = FALSE;
  554. Handle->Options = Options;
  555. Handle->LogicalNameU.Buffer = NULL;
  556. Handle->PhysicalNameU.Buffer = NULL;
  557. Handle->PhysicalNameDs.Buffer = NULL;
  558. Handle->RequestedAccess = ObjectInformation->DesiredObjectAccess;
  559. InitializeListHead( &Handle->UserHandleList );
  560. Handle->UserEntry = NULL;
  561. Handle->SceHandle = (( Options & LSAP_DB_SCE_POLICY_HANDLE ) != 0 );
  562. Handle->SceHandleChild = (( ObjectInformation->ObjectAttributes.RootDirectory != NULL ) &&
  563. ((( LSAP_DB_HANDLE )ObjectInformation->ObjectAttributes.RootDirectory)->SceHandle ));
  564. #ifdef DBG
  565. //
  566. // ScePolicy lock must be held when opening an SCE Policy handle
  567. //
  568. if ( Handle->SceHandle ) {
  569. ASSERT( LsapDbResourceIsLocked( ( PSAFE_RESOURCE )&LsapDbState.ScePolicyLock ));
  570. }
  571. RtlZeroMemory( &Handle->HandleLastAccessTime, sizeof( LARGE_INTEGER ) );
  572. GetSystemTimeAsFileTime( (LPFILETIME) &Handle->HandleCreateTime );
  573. #endif
  574. //
  575. // By default, the handle inherits the Trusted status of the
  576. // container handle.
  577. //
  578. if (Handle->ContainerHandle != NULL) {
  579. Handle->Trusted = Handle->ContainerHandle->Trusted;
  580. }
  581. //
  582. // If Trusted/Non-Trusted status is explicitly specified, set the
  583. // status to that specified.
  584. //
  585. if (Options & LSAP_DB_TRUSTED) {
  586. Handle->Trusted = TRUE;
  587. }
  588. //
  589. // Capture the object's Logical and construct Physical Names from the
  590. // Object Information and store them in the handle. These names are
  591. // internal to the Lsa Database. Note that the input Logical Name
  592. // cannot be directly stored in the handle because it will be in
  593. // storage that is scoped only to the underlying server API call if
  594. // the object for which this create handle is being done is of a type
  595. // that is opened or created by name rather than by Sid.
  596. //
  597. //
  598. // Set the objects location
  599. //
  600. Handle->PhysicalNameDs.Length = 0;
  601. switch ( ObjectInformation->ObjectTypeId ) {
  602. case TrustedDomainObject:
  603. case NewTrustedDomainObject:
  604. ObjectInReg = !LsapDsWriteDs;
  605. ObjectInDs = LsapDsWriteDs;
  606. Handle->ObjectTypeId = TrustedDomainObject;
  607. break;
  608. case AccountObject:
  609. case PolicyObject:
  610. ObjectInReg = TRUE;
  611. ObjectInDs = FALSE;
  612. break;
  613. case SecretObject:
  614. ObjectInReg = TRUE;
  615. if ( LsapDsWriteDs && FLAG_ON( Options, LSAP_DB_OBJECT_SCOPE_DS ) ) {
  616. ObjectInDs = TRUE;
  617. }
  618. break;
  619. }
  620. Status = LsapDbGetNamesObject( ObjectInformation,
  621. CreateHandleOptions,
  622. &Handle->LogicalNameU,
  623. ObjectInReg ? &Handle->PhysicalNameU : NULL,
  624. ObjectInDs ? &Handle->PhysicalNameDs : NULL );
  625. if (!NT_SUCCESS(Status)) {
  626. goto CreateHandleError;
  627. }
  628. //
  629. // Make a copy of the object's Sid and store pointer to it in
  630. // the handle.
  631. //
  632. if (ObjectInformation->Sid != NULL) {
  633. Sid = ObjectInformation->Sid;
  634. if (!RtlValidSid( Sid )) {
  635. Status = STATUS_INVALID_SID;
  636. goto CreateHandleError;
  637. }
  638. SidLength = RtlLengthSid( Sid );
  639. Handle->Sid = LsapAllocateLsaHeap( SidLength );
  640. if (Handle->Sid == NULL) {
  641. Status = STATUS_INSUFFICIENT_RESOURCES;
  642. goto CreateHandleError;
  643. }
  644. RtlCopySid( SidLength, Handle->Sid, Sid );
  645. }
  646. //
  647. // Append the handle to the linked list
  648. //
  649. LsapDbLockAcquire( &LsapDbState.HandleTableLock );
  650. Locked = TRUE ;
  651. Status = LsapDbInsertHandleInTable( ObjectInformation,
  652. Handle,
  653. &UserId,
  654. ClientTokenToFree
  655. );
  656. if ( !NT_SUCCESS( Status ) ) {
  657. goto CreateHandleError;
  658. }
  659. //
  660. // Increment the handle table count
  661. //
  662. LsapDbState.OpenHandleCount++;
  663. CreateHandleFinish:
  664. if ( ClientTokenToFree ) {
  665. NtClose( ClientTokenToFree );
  666. }
  667. *CreatedHandle = ( LSAPR_HANDLE )Handle;
  668. LsapDsDebugOut(( DEB_HANDLE, "Handle Created 0x%lp\n",
  669. Handle ));
  670. if ( Locked )
  671. {
  672. LsapDbLockRelease( &LsapDbState.HandleTableLock );
  673. }
  674. return( Status );
  675. CreateHandleError:
  676. //
  677. // If necessary, free the handle and contents.
  678. //
  679. if (Handle != NULL) {
  680. //
  681. // If a Sid was allocated, free it.
  682. //
  683. if (Handle->Sid != NULL) {
  684. LsapFreeLsaHeap( Handle->Sid );
  685. }
  686. //
  687. // If a Logical Name Buffer was allocated, free it.
  688. //
  689. if ((Handle->LogicalNameU.Length != 0) &&
  690. (Handle->LogicalNameU.Buffer != NULL)) {
  691. RtlFreeUnicodeString( &Handle->LogicalNameU );
  692. }
  693. //
  694. // If a Physical Name Buffer was allocated, free it.
  695. //
  696. if ((Handle->PhysicalNameU.Length != 0) &&
  697. (Handle->PhysicalNameU.Buffer != NULL)) {
  698. LsapFreeLsaHeap( Handle->PhysicalNameU.Buffer );
  699. }
  700. //
  701. // Free the handle itself.
  702. //
  703. LsapFreeLsaHeap( Handle );
  704. Handle = NULL;
  705. }
  706. Handle = NULL;
  707. goto CreateHandleFinish;
  708. }
  709. NTSTATUS
  710. LsapDbVerifyHandle(
  711. IN LSAPR_HANDLE ObjectHandle,
  712. IN ULONG Options,
  713. IN LSAP_DB_OBJECT_TYPE_ID ExpectedObjectTypeId,
  714. IN BOOLEAN ReferenceHandle
  715. )
  716. /*++
  717. Routine Description:
  718. This function verifies that a handle has a valid address and is of valid
  719. format. The handle must be allocated and have a positive reference
  720. count within the valid range. The object type id must be within range
  721. and optionally equal to a specified type. The Lsa Database must be
  722. locked before calling this function.
  723. Arguments:
  724. ObjectHandle - Handle to be validated.
  725. Options - Specifies optional actions to be taken
  726. LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES - Allow handles for
  727. deleted objects to pass the validation.
  728. Other option flags may be specified. They will be ignored.
  729. ExpectedObjectTypeId - Expected object type. If NullObject is
  730. specified, the object type id is only range checked.
  731. ReferenceHandle - True if handle reference count is to be incemented
  732. Return Value:
  733. NTSTATUS - Standard Nt Result Code
  734. STATUS_INVALID_HANDLE - Invalid address or handle contents
  735. --*/
  736. {
  737. NTSTATUS Status;
  738. LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) ObjectHandle;
  739. //
  740. // Lock the handle table.
  741. //
  742. LsapDbLockAcquire( &LsapDbState.HandleTableLock );
  743. //
  744. // First verify that the handle's address is valid.
  745. //
  746. if (!LsapDbLookupHandle( ObjectHandle )) {
  747. goto VerifyHandleError;
  748. }
  749. //
  750. // Verify that the handle is allocated
  751. //
  752. if (!Handle->Allocated) {
  753. goto VerifyHandleError;
  754. }
  755. //
  756. // If the handle is marked as invalid, return an error unless
  757. // these are admissible, e.g when validating for a close option
  758. //
  759. if (Handle->DeletedObject) {
  760. if (!(Options & LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES)) {
  761. goto VerifyHandleError;
  762. }
  763. }
  764. //
  765. // Verify that the handle contains a non-NULL handle to a Registry
  766. // Key
  767. //
  768. if (!Handle->fWriteDs && Handle->KeyHandle == NULL) {
  769. goto VerifyHandleError;
  770. }
  771. //
  772. // Now either range-check or match the handle type
  773. //
  774. if (ExpectedObjectTypeId == NullObject) {
  775. if ((Handle->ObjectTypeId < PolicyObject) ||
  776. (Handle->ObjectTypeId >= DummyLastObject)) {
  777. goto VerifyHandleError;
  778. }
  779. } else {
  780. ASSERT (ExpectedObjectTypeId >= PolicyObject &&
  781. ExpectedObjectTypeId < DummyLastObject);
  782. if (Handle->ObjectTypeId != ExpectedObjectTypeId) {
  783. //
  784. // For a secret object, it's possible that we were given a trusted domain
  785. // handle as well.
  786. //
  787. if ( !(ExpectedObjectTypeId == SecretObject &&
  788. Handle->ObjectTypeId == TrustedDomainObject &&
  789. FLAG_ON( Handle->Options, LSAP_DB_DS_TRUSTED_DOMAIN_AS_SECRET ) ) ) {
  790. goto VerifyHandleError;
  791. }
  792. }
  793. }
  794. //
  795. // Verify that the handle's reference count is valid and positive
  796. //
  797. if (Handle->ReferenceCount == 0) {
  798. goto VerifyHandleError;
  799. }
  800. #ifdef LSAP_TRACK_HANDLE
  801. GetSystemTimeAsFileTime( (LPFILETIME) &Handle->HandleLastAccessTime );
  802. #endif
  803. Status = STATUS_SUCCESS;
  804. VerifyHandleFinish:
  805. //ASSERT( Status != STATUS_INVALID_HANDLE );
  806. //
  807. // Reference the handle
  808. //
  809. if ( ReferenceHandle && NT_SUCCESS(Status) ) {
  810. //
  811. // This is an internal reference.
  812. // Don't enforce LSAP_DB_MAXIMUM_REFERENCE_COUNT.
  813. //
  814. Handle->ReferenceCount++;
  815. LsapDsDebugOut(( DEB_HANDLE, "Handle Rref 0x%lp (%ld)\n",
  816. Handle,
  817. Handle->ReferenceCount ));
  818. }
  819. LsapDbLockRelease( &LsapDbState.HandleTableLock );
  820. return(Status);
  821. VerifyHandleError:
  822. Status = STATUS_INVALID_HANDLE;
  823. goto VerifyHandleFinish;
  824. }
  825. BOOLEAN
  826. LsapDbLookupHandle(
  827. IN LSAPR_HANDLE ObjectHandle
  828. )
  829. /*++
  830. Routine Description:
  831. This function checks if a handle address is valid. The Lsa Database must
  832. be locked before calling this function.
  833. Arguments:
  834. ObjectHandle - handle to be validated.
  835. Return Value:
  836. BOOLEAN - TRUE if handle is valid. FALSE if handle does not exist or
  837. is invalid.
  838. --*/
  839. {
  840. BOOLEAN ReturnValue = FALSE;
  841. LSAP_DB_HANDLE ThisHandle;
  842. LsapDbLockAcquire( &LsapDbState.HandleTableLock );
  843. //
  844. // Simply do a linear scan of the small list of handles. Jazz this
  845. // up later if needed.
  846. //
  847. for (ThisHandle = LsapDbHandleTable.Next;
  848. ThisHandle != &LsapDbHandleTable && ThisHandle != NULL;
  849. ThisHandle = ThisHandle->Next) {
  850. if (ThisHandle == (LSAP_DB_HANDLE) ObjectHandle) {
  851. ReturnValue = TRUE;
  852. break;
  853. }
  854. }
  855. ASSERT( ThisHandle );
  856. LsapDbLockRelease( &LsapDbState.HandleTableLock );
  857. return( ReturnValue );
  858. }
  859. NTSTATUS
  860. LsapDbCloseHandle(
  861. IN LSAPR_HANDLE ObjectHandle
  862. )
  863. /*++
  864. Routine Description:
  865. This function closes an LSA Handle. The memory for the handle is
  866. freed. The LSA database must be locked before calling this function.
  867. NOTE: Currently, handles do not have reference counts since they
  868. are not shared among client threads.
  869. Arguments:
  870. ObjectHandle - Handle to be closed.
  871. Return Value:
  872. NTSTATUS - Return code.
  873. --*/
  874. {
  875. NTSTATUS Status;
  876. LSAP_DB_HANDLE TempHandle;
  877. //
  878. // Verify that the handle exists. It may be marked invalid
  879. //
  880. LsapDbLockAcquire( &LsapDbState.HandleTableLock );
  881. Status = LsapDbVerifyHandle(
  882. ObjectHandle,
  883. LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES,
  884. NullObject,
  885. FALSE );
  886. if (!NT_SUCCESS(Status)) {
  887. LsapDbDereferenceHandle( ObjectHandle, FALSE );
  888. }
  889. LsapDbLockRelease( &LsapDbState.HandleTableLock );
  890. return Status;
  891. }
  892. BOOLEAN
  893. LsapDbDereferenceHandle(
  894. IN LSAPR_HANDLE ObjectHandle,
  895. IN BOOLEAN CalledInSuccessPath
  896. )
  897. /*++
  898. Routine Description:
  899. This function decrement the reference count on the handle.
  900. If the reference count is decremented to zero,
  901. this function unlinks a handle and frees its memory. If the handle
  902. contains a non-NULL Registry Key handle that handle is closed.
  903. Arguments:
  904. ObjectHandle - handle to be dereferenced
  905. CalledInSuccessPath - TRUE if this function is called in a success path.
  906. With this information, we can decide if we will crash the server if auditing
  907. fails when LsapCrashOnAuditFail is TRUE.
  908. Return Value:
  909. TRUE if the reference count reached zero.
  910. --*/
  911. {
  912. NTSTATUS Status;
  913. LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) ObjectHandle;
  914. BOOLEAN RetVal = FALSE;
  915. BOOL RevertResult = FALSE;
  916. BOOL Impersonating = FALSE;
  917. //
  918. // Dereference the handle
  919. //
  920. LsapDbLockAcquire( &LsapDbState.HandleTableLock );
  921. Handle->ReferenceCount --;
  922. if ( Handle->ReferenceCount != 0 ) {
  923. LsapDsDebugOut(( DEB_HANDLE, "Handle Deref 0x%lp %ld\n",
  924. Handle,
  925. Handle->ReferenceCount ));
  926. goto Cleanup;
  927. }
  928. //
  929. // Avoid freeing the global policy handle
  930. //
  931. if ( ObjectHandle == LsapPolicyHandle ) {
  932. ASSERT( Handle->ReferenceCount != 0 );
  933. if ( Handle->ReferenceCount == 0 ) {
  934. Handle->ReferenceCount++;
  935. }
  936. #ifdef DBG
  937. DbgPrint("Freeing global policy handle\n");
  938. #endif
  939. goto Cleanup;
  940. }
  941. LsapDsDebugOut(( DEB_HANDLE, "Handle Freed 0x%lp\n",
  942. Handle ));
  943. //
  944. // Unhook the handle from the linked list
  945. //
  946. Status = LsapDbRemoveHandleFromTable( ObjectHandle );
  947. if ( !NT_SUCCESS( Status ) ) {
  948. DbgPrint( "LSASRV:Failed to remove handle 0x%lp from the global table!\n", ObjectHandle );
  949. goto Cleanup;
  950. }
  951. //
  952. // Free the Registry Key Handle (if any).
  953. //
  954. if (Handle->KeyHandle != NULL) {
  955. Status = NtClose(Handle->KeyHandle);
  956. ASSERT(NT_SUCCESS(Status));
  957. Handle->KeyHandle = NULL;
  958. }
  959. //
  960. // we generate the audit only when we are being called in sucess path
  961. // in the failure path, the open audit was not generated thus there is
  962. // no point in generating the close audit either
  963. //
  964. if ( CalledInSuccessPath ) {
  965. //
  966. // impersonate the client so that audit event shows correct user
  967. // Do this only for untrusted clients
  968. if ( !Handle->Trusted ) {
  969. if ( Handle->Options & LSAP_DB_USE_LPC_IMPERSONATE ) {
  970. Status = LsapImpersonateClient( );
  971. } else {
  972. Status = I_RpcMapWin32Status(RpcImpersonateClient(0));
  973. }
  974. if ( NT_SUCCESS(Status) ) {
  975. Impersonating = TRUE;
  976. }
  977. else if ( ( Status == RPC_NT_NO_CALL_ACTIVE ) ||
  978. ( Status == RPC_NT_NO_CONTEXT_AVAILABLE ) ) {
  979. //
  980. // we dont want to fail the audit if
  981. // -- the call is not over RPC (RPC_NT_NO_CALL_ACTIVE)
  982. // -- the client died prematurely (RPC_NT_NO_CONTEXT_AVAILABLE)
  983. //
  984. Status = STATUS_SUCCESS;
  985. }
  986. DsysAssertMsg( NT_SUCCESS(Status), "LsapDbDereferenceHandle: failed to impersonate" );
  987. if (!NT_SUCCESS( Status )) {
  988. LsapAuditFailed( Status );
  989. }
  990. }
  991. //
  992. // Audit that we're closing the handle
  993. //
  994. Status = NtCloseObjectAuditAlarm (
  995. &LsapState.SubsystemName,
  996. ObjectHandle,
  997. Handle->GenerateOnClose );
  998. if (!NT_SUCCESS( Status )) {
  999. LsapAuditFailed( Status );
  1000. }
  1001. if ( !Handle->Trusted ) {
  1002. //
  1003. // unimpersonate
  1004. //
  1005. if ( Impersonating ) {
  1006. if ( Handle->Options & LSAP_DB_USE_LPC_IMPERSONATE ) {
  1007. RevertResult = RevertToSelf();
  1008. DsysAssertMsg( RevertResult, "LsapDbDereferenceHandle: RevertToSelf() failed" );
  1009. } else {
  1010. Status = I_RpcMapWin32Status(RpcRevertToSelf());
  1011. DsysAssertMsg( NT_SUCCESS(Status), "LsapDbDereferenceHandle: RpcRevertToSelf() failed" );
  1012. }
  1013. }
  1014. }
  1015. }
  1016. //
  1017. // Mark the handle as not allocated.
  1018. //
  1019. Handle->Allocated = FALSE;
  1020. //
  1021. // Free fields of the handle
  1022. //
  1023. if (Handle->LogicalNameU.Buffer != NULL) {
  1024. RtlFreeUnicodeString( &Handle->LogicalNameU );
  1025. }
  1026. if (Handle->PhysicalNameU.Buffer != NULL) {
  1027. LsapFreeLsaHeap( Handle->PhysicalNameU.Buffer );
  1028. }
  1029. if (Handle->PhysicalNameDs.Buffer != NULL) {
  1030. LsapFreeLsaHeap( Handle->PhysicalNameDs.Buffer );
  1031. }
  1032. if (Handle->Sid != NULL) {
  1033. LsapFreeLsaHeap( Handle->Sid );
  1034. }
  1035. if (Handle->SceHandle) {
  1036. #ifdef DBG
  1037. ASSERT( WAIT_TIMEOUT == WaitForSingleObject( LsapDbState.SceSyncEvent, 0 ));
  1038. ASSERT( g_ScePolicyLocked );
  1039. g_ScePolicyLocked = FALSE;
  1040. #endif
  1041. RtlReleaseResource( &LsapDbState.ScePolicyLock );
  1042. SetEvent( LsapDbState.SceSyncEvent );
  1043. }
  1044. //
  1045. // Decrement the count of open handles.
  1046. //
  1047. ASSERT(LsapDbState.OpenHandleCount > 0);
  1048. LsapDbState.OpenHandleCount--;
  1049. #ifdef LSAP_TRACK_HANDLE
  1050. if ( Handle->ClientToken ) {
  1051. NtClose( Handle->ClientToken );
  1052. }
  1053. #endif
  1054. //
  1055. // Free the handle structure itself
  1056. LsapFreeLsaHeap( ObjectHandle );
  1057. RetVal = TRUE;
  1058. Cleanup:
  1059. LsapDbLockRelease( &LsapDbState.HandleTableLock );
  1060. return RetVal;
  1061. }
  1062. NTSTATUS
  1063. LsapDbMarkDeletedObjectHandles(
  1064. IN LSAPR_HANDLE ObjectHandle,
  1065. IN BOOLEAN MarkSelf
  1066. )
  1067. /*++
  1068. Routine Description:
  1069. This function invalidates open handles to an object. It is used
  1070. by object deletion code. Once an object has been deleted, the only
  1071. operation permitted on open handles remaining is to close them.
  1072. Arguments:
  1073. ObjectHandle - Handle to an Lsa object.
  1074. MarkSelf - If TRUE, all handles to the object will be marked to
  1075. indicate that the object to which they relate has been deleted.
  1076. including the passed handle. If FALSE, all handles to the object
  1077. except the passed handle will be so marked.
  1078. --*/
  1079. {
  1080. NTSTATUS Status = STATUS_SUCCESS;
  1081. LSAP_DB_HANDLE ThisHandle;
  1082. LSAP_DB_HANDLE Handle = ObjectHandle;
  1083. LsapDbLockAcquire( &LsapDbState.HandleTableLock );
  1084. ThisHandle = LsapDbHandleTable.Next;
  1085. while (ThisHandle != &LsapDbHandleTable) {
  1086. //
  1087. // Match on Object Type Id.
  1088. //
  1089. if (ThisHandle->ObjectTypeId == Handle->ObjectTypeId) {
  1090. //
  1091. // Object Type Id's match. If the Logical Names also
  1092. // match, invalidate the handle unless the handle is the
  1093. // passed one and we're to leave it valid.
  1094. //
  1095. if (RtlEqualUnicodeString(
  1096. &(ThisHandle->LogicalNameU),
  1097. &(Handle->LogicalNameU),
  1098. FALSE
  1099. )) {
  1100. if (MarkSelf || ThisHandle != (LSAP_DB_HANDLE) ObjectHandle) {
  1101. ThisHandle->DeletedObject = TRUE;
  1102. }
  1103. }
  1104. }
  1105. ThisHandle = ThisHandle->Next;
  1106. }
  1107. LsapDbLockRelease( &LsapDbState.HandleTableLock );
  1108. return(Status);
  1109. }