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.

7068 lines
210 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. context.cxx
  5. Abstract:
  6. Routines implementing the client context API
  7. Author:
  8. Cliff Van Dyke (cliffv) 22-May-2001
  9. --*/
  10. #include "pch.hxx"
  11. #include <winber.h>
  12. #include <ntseapi.h>
  13. #include <kerberos.h>
  14. #include <azroles.h>
  15. //
  16. // Structure definitions
  17. //
  18. //
  19. // Structure representing an APP group that a client context may be a member of
  20. //
  21. typedef struct _AZP_MEMBER_EVALUATION {
  22. //
  23. // Link to next entry in the list of member evaluation structs for this
  24. // client context.
  25. //
  26. LIST_ENTRY Next;
  27. //
  28. // Group being evaluated
  29. //
  30. PAZP_GROUP Group;
  31. //
  32. // Status of the evaluation
  33. // NO_ERROR: Membership has been determined
  34. // NOT_YET_DONE: Membership has not yet been determined
  35. // ERROR_NO_SUCH_DOMAIN: We couldn't contact the domain controller
  36. //
  37. DWORD WinStatus;
  38. #define NOT_YET_DONE 0xFFFFFFFF
  39. //
  40. // Indicates whether the client is a member of the specified group.
  41. // This field is valid only if WinStatus is NO_ERROR.
  42. //
  43. BOOLEAN IsMember;
  44. } AZP_MEMBER_EVALUATION, *PAZP_MEMBER_EVALUATION;
  45. //
  46. // Macros
  47. //
  48. // PopUlong: remove a ULONG from an array of ULONGs
  49. // Simply replace the element by the last element in the array and
  50. // make the array shorter
  51. //
  52. #define PopUlong( _Array, _Index, _Count ) { \
  53. (_Count)--; \
  54. (_Array)[_Index] = (_Array)[_Count]; \
  55. }
  56. extern BOOL AzIsDC;
  57. extern PSID AzAccountDomainSid;
  58. extern BOOL AzAccountDomainSidInitialized;
  59. //
  60. // Procedure forwards
  61. //
  62. DWORD
  63. AzpCheckGroupMembershipOne(
  64. IN PAZP_CLIENT_CONTEXT ClientContext,
  65. IN PAZP_GROUP Group,
  66. IN BOOLEAN LocalOnly,
  67. IN DWORD RecursionLevel,
  68. OUT PBOOLEAN RetIsMember,
  69. OUT LPDWORD ExtendedStatus
  70. );
  71. DWORD
  72. AzpAccessCheckGenerateAudit(
  73. IN PACCESS_CHECK_CONTEXT AcContext
  74. )
  75. /*++
  76. Routine Description:
  77. This routine generates run-time access check audits. One success or failure
  78. audit is generated per operation.
  79. Arguments:
  80. AcContext - Specifies the context of the user who will be audited.
  81. Return Value:
  82. NO_ERROR - The operation was successful
  83. Other exception status codes
  84. --*/
  85. {
  86. BOOL b;
  87. ULONG i;
  88. DWORD WinStatus = NO_ERROR;
  89. PAUDIT_PARAMS pAuditParams = NULL;
  90. PAZP_AZSTORE AzAuthorizationStore;
  91. AUTHZ_AUDIT_EVENT_HANDLE hAuditEvent = NULL;
  92. PAZP_APPLICATION Application = AcContext->Application;
  93. AUTHZ_AUDIT_EVENT_TYPE_HANDLE hAuditHandle = NULL;
  94. //
  95. // Get the authorization store pointer for the application
  96. //
  97. AzAuthorizationStore = (PAZP_AZSTORE) ParentOfChild(&AcContext->Application->GenericObject);
  98. //
  99. // If audit handle is null, then do not generate any audits
  100. //
  101. if ( (AzAuthorizationStore->hAccessCheckAuditEventType == NULL) &&
  102. (AzAuthorizationStore->hAccessCheckNameAuditEventType == NULL) ) {
  103. return NO_ERROR;
  104. }
  105. if (!AuthziAllocateAuditParams(
  106. &pAuditParams,
  107. AZP_ACCESSCHECK_AUDITPARAMS_NO+2
  108. )) {
  109. goto Cleanup;
  110. }
  111. //
  112. // Loop thru all the operations and generate one audit per operation
  113. //
  114. for ( i=0; i < AcContext->OperationCount; i++ ) {
  115. //
  116. // Decide on whether this is a success or a failure audit
  117. //
  118. DWORD Flags = (AcContext->Results[i] == NO_ERROR) ?
  119. APF_AuditSuccess :
  120. APF_AuditFailure;
  121. //
  122. // The structure of the audit is as follows
  123. // %tApplication Name:%t%1%n
  124. // %tApplication Instance ID
  125. // %tObject Name:%t%3%n
  126. // %tScope Names:%t%4%n
  127. // %tClient Name:%t%5%n
  128. // %tClient Domain:%t%6%n
  129. // %tClient Context ID:%t%7%
  130. // %tRole:%t%8%n
  131. // %tGroups:%t%9%n
  132. // %tOperation:%t%10%n
  133. // %tOperation ID:%t%11%n
  134. //
  135. //
  136. // Fill in the audit parameters array
  137. //
  138. if ( AcContext->ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_TOKEN ) {
  139. hAuditHandle = AzAuthorizationStore->hAccessCheckAuditEventType;
  140. b = AuthziInitializeAuditParamsWithRM( Flags,
  141. Application->AuthzResourceManager,
  142. AZP_ACCESSCHECK_AUDITPARAMS_NO,
  143. pAuditParams,
  144. APT_String, Application->GenericObject.ObjectName->ObjectName.String,
  145. APT_Luid, Application->InstanceId,
  146. APT_String, AcContext->ObjectNameString.String,
  147. APT_String, AcContext->ScopeNameString.String ? AcContext->ScopeNameString.String : L"-",
  148. APT_LogonId, AcContext->ClientContext->LogonId,
  149. APT_String, L"Role",
  150. APT_String, L"Group",
  151. APT_String, AcContext->OperationObjects[i]->GenericObject.ObjectName->ObjectName.String,
  152. APT_Ulong, AcContext->OperationObjects[i]->OperationId );
  153. } else if ( AcContext->ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_NAME ||
  154. AcContext->ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_SID ) {
  155. hAuditHandle = AzAuthorizationStore->hAccessCheckNameAuditEventType;
  156. //
  157. // both from name and from SID audit share the same audit layout
  158. //
  159. // We do not have the client Logon Id here since the context was created
  160. // from name or SID. So, we pass the Logon id that we allocated as a LUID and
  161. // the Domain Name, Client Name as separate strings. LSA can not lookup
  162. // the names from the LUID since no logon session exists.
  163. //
  164. b = AuthziInitializeAuditParamsWithRM( Flags,
  165. Application->AuthzResourceManager,
  166. AZP_ACCESSCHECK_AUDITPARAMS_NO+2,
  167. pAuditParams,
  168. APT_String, Application->GenericObject.ObjectName->ObjectName.String,
  169. APT_Luid, Application->InstanceId,
  170. APT_String, AcContext->ObjectNameString.String,
  171. APT_String, AcContext->ScopeNameString.String ? AcContext->ScopeNameString.String : L"-",
  172. APT_String, AcContext->ClientContext->ClientName,
  173. APT_String, AcContext->ClientContext->DomainName ? AcContext->ClientContext->DomainName : L"",
  174. APT_Luid, AcContext->ClientContext->LogonId,
  175. APT_String, L"Role",
  176. APT_String, L"Group",
  177. APT_String, AcContext->OperationObjects[i]->GenericObject.ObjectName->ObjectName.String,
  178. APT_Ulong, AcContext->OperationObjects[i]->OperationId );
  179. } else {
  180. ASSERT( FALSE );
  181. b = FALSE;
  182. WinStatus = ERROR_INVALID_PARAMETER;
  183. goto Cleanup;
  184. }
  185. if (!b) {
  186. WinStatus = GetLastError();
  187. goto Cleanup;
  188. }
  189. //
  190. // Fill in the Audit event handle
  191. //
  192. b = AuthziInitializeAuditEvent( 0,
  193. NULL,
  194. hAuditHandle,
  195. pAuditParams,
  196. NULL,
  197. INFINITE,
  198. L"", L"", L"", L"",
  199. &hAuditEvent );
  200. if (!b) {
  201. WinStatus = GetLastError();
  202. goto Cleanup;
  203. }
  204. //
  205. // Send off the audit to LSA
  206. //
  207. b = AuthziLogAuditEvent( 0,
  208. hAuditEvent,
  209. NULL );
  210. if (!b) {
  211. WinStatus = GetLastError();
  212. goto Cleanup;
  213. }
  214. //
  215. // Free the audit event sructure and set it to NULL
  216. //
  217. AuthzFreeAuditEvent( hAuditEvent );
  218. hAuditEvent = NULL;
  219. }
  220. Cleanup:
  221. //
  222. // Free the audit event handle
  223. //
  224. if ( hAuditEvent != NULL ) {
  225. AuthzFreeAuditEvent( hAuditEvent );
  226. }
  227. //
  228. // Free the PAUDIT_PARAMS structure
  229. //
  230. if ( pAuditParams ) {
  231. AuthziFreeAuditParams( pAuditParams );
  232. }
  233. return WinStatus;
  234. }
  235. DWORD
  236. AzpClientContextGenerateCreateSuccessAudit(
  237. IN PAZP_CLIENT_CONTEXT ClientContext,
  238. IN PAZP_APPLICATION Application
  239. )
  240. /*++
  241. Routine Description:
  242. This routine generates success audit for client context creation.
  243. Arguments:
  244. ClientContext - Specifies the context of the user who will be audited.
  245. Application - Specifies the application in whose scope the client context
  246. has been created.
  247. Return Value:
  248. NO_ERROR - The operation was successful
  249. Other exception status codes
  250. --*/
  251. {
  252. BOOL b;
  253. DWORD WinStatus = NO_ERROR;
  254. PAUDIT_PARAMS pAuditParams = NULL;
  255. PAZP_AZSTORE AzAuthorizationStore;
  256. AUTHZ_AUDIT_EVENT_HANDLE hAuditEvent = NULL;
  257. AUTHZ_AUDIT_EVENT_TYPE_HANDLE hAuditHandle = NULL;
  258. //
  259. // Get the authorization store pointer
  260. //
  261. AzAuthorizationStore = (PAZP_AZSTORE) ParentOfChild(&Application->GenericObject);
  262. //
  263. // If audit handle is null, then do not generate any audits
  264. //
  265. if ( (AzAuthorizationStore->hClientContextCreateAuditEventType == NULL) &&
  266. (AzAuthorizationStore->hClientContextCreateNameAuditEventType == NULL) ) {
  267. return NO_ERROR;
  268. }
  269. if (!AuthziAllocateAuditParams(
  270. &pAuditParams,
  271. AZP_ACCESSCHECK_AUDITPARAMS_NO+2
  272. )) {
  273. goto Cleanup;
  274. }
  275. //
  276. // The structure of the audit is as follows
  277. // %tApplication Name:%t%1%n
  278. // %tApplication Instance ID:%t%2%n
  279. // %tClient Name:%t%3%n
  280. // %tClient Domain:%t%4%n
  281. // %tClient Context ID:%t%5%n
  282. // %tStatus:%t%6%n
  283. //
  284. //
  285. // Fill in the audit parameters array
  286. //
  287. if ( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_TOKEN ) {
  288. hAuditHandle = AzAuthorizationStore->hClientContextCreateAuditEventType;
  289. b = AuthziInitializeAuditParamsWithRM( APF_AuditSuccess,
  290. Application->AuthzResourceManager,
  291. AZP_CLIENTCREATE_AUDITPARAMS_NO,
  292. pAuditParams,
  293. APT_String, Application->GenericObject.ObjectName->ObjectName.String,
  294. APT_Luid, Application->InstanceId,
  295. APT_LogonId, ClientContext->LogonId,
  296. APT_Ulong, NO_ERROR );
  297. } else if ( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_NAME ||
  298. ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_SID ) {
  299. hAuditHandle = AzAuthorizationStore->hClientContextCreateNameAuditEventType;
  300. //
  301. // both from name or from SID contexts share the same audit layout
  302. //
  303. // We do not have the client Logon Id here since the context was created
  304. // from name or SID. So, we pass the Logon id that we allocated as a LUID and
  305. // the Domain Name, Client Name as separate strings. LSA can not lookup
  306. // the names from the LUID since no logon session exists.
  307. //
  308. b = AuthziInitializeAuditParamsWithRM( APF_AuditSuccess,
  309. Application->AuthzResourceManager,
  310. AZP_CLIENTCREATE_AUDITPARAMS_NO+2,
  311. pAuditParams,
  312. APT_String, Application->GenericObject.ObjectName->ObjectName.String,
  313. APT_Luid, Application->InstanceId,
  314. APT_String, ClientContext->ClientName,
  315. APT_String, ClientContext->DomainName ? ClientContext->DomainName : L"",
  316. APT_Luid, ClientContext->LogonId,
  317. APT_Ulong, NO_ERROR );
  318. } else {
  319. ASSERT( FALSE );
  320. b = FALSE;
  321. WinStatus = ERROR_INVALID_PARAMETER;
  322. goto Cleanup;
  323. }
  324. if (!b) {
  325. WinStatus = GetLastError();
  326. goto Cleanup;
  327. }
  328. //
  329. // Fill in the Audit event handle
  330. //
  331. b = AuthziInitializeAuditEvent( 0,
  332. NULL,
  333. hAuditHandle,
  334. pAuditParams,
  335. NULL,
  336. INFINITE,
  337. L"", L"", L"", L"",
  338. &hAuditEvent );
  339. if (!b) {
  340. WinStatus = GetLastError();
  341. goto Cleanup;
  342. }
  343. //
  344. // Send off the audit to LSA
  345. //
  346. b = AuthziLogAuditEvent( 0,
  347. hAuditEvent,
  348. NULL );
  349. if (!b) {
  350. WinStatus = GetLastError();
  351. goto Cleanup;
  352. }
  353. Cleanup:
  354. //
  355. // Free the audit event handle
  356. //
  357. if ( hAuditEvent != NULL ) {
  358. AuthzFreeAuditEvent( hAuditEvent );
  359. }
  360. //
  361. // Free the PAUDIT_PARAMS structure
  362. //
  363. if ( pAuditParams ) {
  364. AuthziFreeAuditParams( pAuditParams );
  365. }
  366. return WinStatus;
  367. }
  368. DWORD
  369. AzpClientContextGenerateDeleteAudit(
  370. IN PAZP_CLIENT_CONTEXT ClientContext,
  371. IN PAZP_APPLICATION Application
  372. )
  373. /*++
  374. Routine Description:
  375. This routine generates audit for client context deletion.
  376. On entry, AzGlResource must be locked exclusively.
  377. Arguments:
  378. ClientContext - Specifies the context of the user who will be audited.
  379. Application - Specifies the application in whose scope the client context
  380. has been created.
  381. Return Value:
  382. NO_ERROR - The operation was successful
  383. Other exception status codes
  384. --*/
  385. {
  386. DWORD WinStatus = NO_ERROR;
  387. BOOL b;
  388. AUTHZ_AUDIT_EVENT_HANDLE hAuditEvent = NULL;
  389. PAUDIT_PARAMS pAuditParams = NULL;
  390. PAZP_AZSTORE AzAuthorizationStore;
  391. AUTHZ_AUDIT_EVENT_TYPE_HANDLE hAuditHandle = NULL;
  392. //
  393. // Get the authorization store pointer
  394. //
  395. AzAuthorizationStore = (PAZP_AZSTORE) ParentOfChild(&Application->GenericObject);
  396. //
  397. // If audit handles are null, then do not generate any audtis
  398. //
  399. if ( (AzAuthorizationStore->hClientContextDeleteAuditEventType == NULL) &&
  400. (AzAuthorizationStore->hClientContextDeleteNameAuditEventType == NULL) ) {
  401. return NO_ERROR;
  402. }
  403. if (!AuthziAllocateAuditParams(
  404. &pAuditParams,
  405. AZP_ACCESSCHECK_AUDITPARAMS_NO+2
  406. )) {
  407. goto Cleanup;
  408. }
  409. //
  410. // The structure of the audit is as follows
  411. // %tApplication Name:%t%1%n
  412. // %tApplication Instance ID:%t%2%n
  413. // %tClient Name:%t%3%n
  414. // %tClient Domain:%t%4%n
  415. // %tClient Context ID:%t%5%n
  416. //
  417. //
  418. // Fill in the audit parameters array
  419. //
  420. if ( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_TOKEN ) {
  421. hAuditHandle = AzAuthorizationStore->hClientContextDeleteAuditEventType;
  422. b = AuthziInitializeAuditParamsWithRM( APF_AuditSuccess,
  423. Application->AuthzResourceManager,
  424. AZP_CLIENTDELETE_AUDITPARAMS_NO,
  425. pAuditParams,
  426. APT_String, Application->GenericObject.ObjectName->ObjectName.String,
  427. APT_Luid, Application->InstanceId,
  428. APT_LogonId, ClientContext->LogonId );
  429. } else if ( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_NAME ||
  430. ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_SID ) {
  431. hAuditHandle = AzAuthorizationStore->hClientContextDeleteNameAuditEventType;
  432. //
  433. // both from name or from SID contexts share the same audit layout
  434. //
  435. // We do not have the client Logon Id here since the context was created
  436. // from name or SID. So, we pass the Logon id that we allocated as a LUID and
  437. // the Domain Name, Client Name as separate strings. LSA can not lookup
  438. // the names from the LUID since no logon session exists.
  439. //
  440. b = AuthziInitializeAuditParamsWithRM( APF_AuditSuccess,
  441. Application->AuthzResourceManager,
  442. AZP_CLIENTDELETE_AUDITPARAMS_NO+2,
  443. pAuditParams,
  444. APT_String, Application->GenericObject.ObjectName->ObjectName.String,
  445. APT_Luid, Application->InstanceId,
  446. APT_String, ClientContext->ClientName,
  447. APT_String, ClientContext->DomainName ? ClientContext->DomainName : L"",
  448. APT_Luid, ClientContext->LogonId);
  449. } else {
  450. ASSERT( FALSE );
  451. b = FALSE;
  452. WinStatus = ERROR_INVALID_PARAMETER;
  453. goto Cleanup;
  454. }
  455. if (!b) {
  456. WinStatus = GetLastError();
  457. goto Cleanup;
  458. }
  459. //
  460. // Fill in the Audit event handle
  461. //
  462. b = AuthziInitializeAuditEvent( 0,
  463. NULL,
  464. hAuditHandle,
  465. pAuditParams,
  466. NULL,
  467. INFINITE,
  468. L"", L"", L"", L"",
  469. &hAuditEvent );
  470. if (!b) {
  471. WinStatus = GetLastError();
  472. goto Cleanup;
  473. }
  474. //
  475. // Send off the audit to LSA
  476. //
  477. b = AuthziLogAuditEvent( 0,
  478. hAuditEvent,
  479. NULL );
  480. if (!b) {
  481. WinStatus = GetLastError();
  482. goto Cleanup;
  483. }
  484. Cleanup:
  485. //
  486. // Free the audit event handle
  487. //
  488. if ( hAuditEvent != NULL ) {
  489. AuthzFreeAuditEvent( hAuditEvent );
  490. }
  491. //
  492. // Free the PAUDIT_PARAMS structure
  493. //
  494. if ( pAuditParams ) {
  495. AuthziFreeAuditParams( pAuditParams );
  496. }
  497. return WinStatus;
  498. }
  499. VOID
  500. AzpFlushGroupEval(
  501. IN PAZP_CLIENT_CONTEXT ClientContext
  502. )
  503. /*++
  504. Routine Description:
  505. This routine flushes the group evaluation for the specified client context
  506. On entry, AzGlResource must be locked shared
  507. Arguments:
  508. ClientContext - Specifies the client context for which all group evaluation is
  509. to be flushed.
  510. Return Value:
  511. None.
  512. --*/
  513. {
  514. //
  515. // Initialization
  516. //
  517. ASSERT( AzpIsLockedShared( &AzGlResource ) );
  518. //
  519. // Free the cache of group membership evaluations
  520. //
  521. while ( !IsListEmpty( &ClientContext->MemEval ) ) {
  522. PAZP_MEMBER_EVALUATION MemEval;
  523. PLIST_ENTRY ListEntry;
  524. //
  525. // Remove the entry from the list
  526. //
  527. ListEntry = RemoveHeadList( &ClientContext->MemEval );
  528. MemEval = CONTAINING_RECORD( ListEntry,
  529. AZP_MEMBER_EVALUATION,
  530. Next );
  531. AzpFreeHeap( MemEval );
  532. }
  533. }
  534. DWORD
  535. AzpClientContextInit(
  536. IN PGENERIC_OBJECT ParentGenericObject,
  537. IN PGENERIC_OBJECT ChildGenericObject
  538. )
  539. /*++
  540. Routine Description:
  541. This routine is a worker routine for AzInitializeClientContextFrom*. It does any object specific
  542. initialization that needs to be done.
  543. On entry, AzGlResource must be locked exclusively.
  544. Arguments:
  545. ParentGenericObject - Specifies the parent object to add the child object onto.
  546. The reference count has been incremented on this object.
  547. ChildGenericObject - Specifies the newly allocated child object.
  548. The reference count has been incremented on this object.
  549. Return Value:
  550. NO_ERROR - The operation was successful
  551. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  552. Other exception status codes
  553. --*/
  554. {
  555. NTSTATUS Status;
  556. PAZP_CLIENT_CONTEXT ClientContext = (PAZP_CLIENT_CONTEXT) ChildGenericObject;
  557. UNREFERENCED_PARAMETER( ParentGenericObject );
  558. //
  559. // Initialization
  560. //
  561. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  562. //
  563. // Initialize the client context critical section
  564. //
  565. Status = SafeInitializeCriticalSection( &ClientContext->CritSect, SAFE_CLIENT_CONTEXT );
  566. if ( !NT_SUCCESS( Status )) {
  567. return RtlNtStatusToDosError( Status );
  568. }
  569. ClientContext->CritSectInitialized = TRUE;
  570. //
  571. // ClientContexts are referenced by "Applications"
  572. // Let the generic object manager know all of the lists we support
  573. // This is a "back" link so we don't need to define which applications can reference this client context.
  574. //
  575. ChildGenericObject->GenericObjectLists = &ClientContext->backApplications;
  576. // Back link to applications
  577. ObInitObjectList( &ClientContext->backApplications,
  578. NULL,
  579. TRUE, // Backward link
  580. 0, // No link pair id
  581. 0, // No dirty bit on back link
  582. NULL,
  583. NULL,
  584. NULL );
  585. //
  586. // Maintain a handle to the user's token / identity.
  587. //
  588. ClientContext->TokenHandle = INVALID_HANDLE_VALUE;
  589. ClientContext->ClientName = NULL;
  590. ClientContext->DomainName = NULL;
  591. AzpInitString(&ClientContext->RoleName, NULL);
  592. //
  593. // Initialize the cache of group membership evaluations
  594. //
  595. InitializeListHead( &ClientContext->MemEval );
  596. //
  597. // Store the serial number of that cache
  598. //
  599. ClientContext->GroupEvalSerialNumber =
  600. ClientContext->GenericObject.AzStoreObject->GroupEvalSerialNumber;
  601. //
  602. // Initialize the operation cache
  603. //
  604. AzpInitOperationCache( ClientContext );
  605. return NO_ERROR;
  606. }
  607. VOID
  608. AzpClientContextFree(
  609. IN PGENERIC_OBJECT GenericObject
  610. )
  611. /*++
  612. Routine Description:
  613. This routine is a worker routine for ClientContext object free. It does any object specific
  614. cleanup that needs to be done.
  615. On entry, AzGlResource must be locked exclusively.
  616. Arguments:
  617. GenericObject - Specifies a pointer to the object to be deleted.
  618. Return Value:
  619. None
  620. --*/
  621. {
  622. PAZP_CLIENT_CONTEXT ClientContext = (PAZP_CLIENT_CONTEXT) GenericObject;
  623. PAZP_APPLICATION Application = (PAZP_APPLICATION) ParentOfChild( &ClientContext->GenericObject );
  624. PAZP_AZSTORE AzAuthorizationStore = (PAZP_AZSTORE) ParentOfChild( &Application->GenericObject );
  625. DWORD WinStatus;
  626. //
  627. // Initialization
  628. //
  629. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  630. //
  631. // Generate a Client context deletion audit if needed.
  632. //
  633. if ( Application->GenericObject.IsGeneratingAudits &&
  634. !AzpOpenToManageStore(AzAuthorizationStore) ) {
  635. WinStatus = AzpClientContextGenerateDeleteAudit( ClientContext,
  636. Application );
  637. if ( WinStatus != NO_ERROR ) {
  638. AzPrint(( AZD_ACCESS_MORE, "AzpClientContextFree: AzpClientContextGenerateDeleteAudit failed with %ld\n", WinStatus ));
  639. }
  640. }
  641. //
  642. // Free any local strings
  643. //
  644. if ( ClientContext->AccountDn != NULL ) {
  645. AzpFreeHeap( ClientContext->AccountDn );
  646. }
  647. //
  648. // Free the reference to the account domain
  649. //
  650. if ( ClientContext->Domain != NULL ) {
  651. AzpDereferenceDomain( ClientContext->Domain );
  652. }
  653. //
  654. // Free any authz context
  655. //
  656. if ( ClientContext->AuthzClientContext != NULL ) {
  657. if ( !AuthzFreeContext( ClientContext->AuthzClientContext ) ) {
  658. ASSERT( FALSE );
  659. }
  660. }
  661. //
  662. // Close the user's token
  663. //
  664. if ( ClientContext->TokenHandle != INVALID_HANDLE_VALUE ) {
  665. CloseHandle( ClientContext->TokenHandle );
  666. ClientContext->TokenHandle = INVALID_HANDLE_VALUE;
  667. ASSERT( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_TOKEN );
  668. }
  669. //
  670. // Free the client name and the domain name.
  671. //
  672. if ( ClientContext->DomainName != NULL ) {
  673. AzpFreeHeap( ClientContext->DomainName );
  674. ClientContext->DomainName = NULL;
  675. ASSERT( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_NAME );
  676. }
  677. if ( ClientContext->ClientName != NULL ) {
  678. AzpFreeHeap( ClientContext->ClientName );
  679. ClientContext->ClientName = NULL;
  680. ASSERT( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_NAME ||
  681. ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_SID );
  682. }
  683. //
  684. // free the role name if it's specified in the context
  685. //
  686. AzpFreeString( &ClientContext->RoleName );
  687. //
  688. // Free the cache of group membership evaluations
  689. //
  690. AzpFlushGroupEval( ClientContext );
  691. //
  692. // Free the cache of previously evaluated operations
  693. //
  694. AzpFlushOperationCache( ClientContext );
  695. //
  696. // Delete the client context critical section
  697. //
  698. if ( ClientContext->CritSectInitialized ) {
  699. SafeDeleteCriticalSection( &ClientContext->CritSect );
  700. ClientContext->CritSectInitialized = FALSE;
  701. }
  702. }
  703. DWORD
  704. AzpGetUserNameEx(
  705. IN PAZP_CLIENT_CONTEXT ClientContext,
  706. IN EXTENDED_NAME_FORMAT NameFormat,
  707. IN LPWSTR *NameBuffer,
  708. OUT BOOLEAN *pbIsDomainDnsName
  709. )
  710. /*++
  711. Routine Description:
  712. This routine is a wrapper around GetUserNameEx.
  713. It impersonates the token implied by ClientContext,
  714. It handles allocating the buffer so the caller doesn't have to guess.
  715. On entry, ClientContext->ReferenceCount must be incremented.
  716. Arguments:
  717. ClientContext - Specifies the context of the user to check group membership of.
  718. NameFormat - Any name format that is valid for GetUserNameEx
  719. NameBuffer - On success, returns a buffer in the same format as GetUserNameEx
  720. The returned buffer should be freed using AzpFreeHeap,
  721. pbIsDomainDnsName - set to TRUE if the returned Domain names is in DNS format
  722. Return Value:
  723. Same as GetUserNameEx.
  724. --*/
  725. {
  726. DWORD WinStatus;
  727. LPWSTR Buffer = NULL;
  728. ULONG BufferSize;
  729. HANDLE CurrentToken = NULL;
  730. BOOL Impersonating = FALSE;
  731. TOKEN_STATISTICS TokenStats = {0};
  732. PTOKEN_USER pUserToken = NULL;
  733. DWORD RetSize = 0;
  734. LPWSTR ClientName = NULL;
  735. //
  736. // Initialization
  737. //
  738. ASSERT( ClientContext->GenericObject.ReferenceCount != 0 );
  739. //
  740. // Make sure that we have a valid token.
  741. //
  742. if ( ClientContext->TokenHandle == INVALID_HANDLE_VALUE ) {
  743. AzPrint(( AZD_INVPARM, "AzpGetUserNameEx: no cached token handle\n" ));
  744. return ERROR_NOT_SUPPORTED;
  745. }
  746. //
  747. // Get the token stats to retreive the impersonation level
  748. //
  749. if ( !GetTokenInformation( ClientContext->TokenHandle,
  750. TokenStatistics,
  751. &TokenStats,
  752. sizeof(TOKEN_STATISTICS),
  753. &RetSize ) ) {
  754. WinStatus = GetLastError();
  755. AzPrint(( AZD_CRITICAL,
  756. "AzpGetUserNameEx: Cannot get token statistics: %ld\n",
  757. WinStatus
  758. ));
  759. goto Cleanup;
  760. }
  761. //
  762. // Check to see if we're already impersonating
  763. //
  764. if ( !OpenThreadToken(
  765. GetCurrentThread(),
  766. TOKEN_IMPERSONATE,
  767. TRUE, // as self to ensure we never fail
  768. &CurrentToken
  769. ) ) {
  770. WinStatus = GetLastError();
  771. if ( WinStatus != ERROR_NO_TOKEN ) {
  772. AzPrint(( AZD_CRITICAL, "AzpGetUserNameEx: Cannot GetThreadToken %ld\n", WinStatus ));
  773. goto Cleanup;
  774. }
  775. CurrentToken = NULL;
  776. }
  777. //
  778. // Impersonate the user's token
  779. //
  780. if ( !SetThreadToken( NULL, ClientContext->TokenHandle ) ) {
  781. WinStatus = GetLastError();
  782. AzPrint(( AZD_CRITICAL, "AzpGetUserNameEx: Cannot SetThreadToken %ld\n", WinStatus ));
  783. goto Cleanup;
  784. }
  785. Impersonating = TRUE;
  786. //
  787. // Determine the size of the buffer
  788. //
  789. BufferSize = 0;
  790. if ( GetUserNameExW( NameFormat, NULL, &BufferSize ) ) {
  791. WinStatus = ERROR_INTERNAL_ERROR;
  792. goto Cleanup;
  793. }
  794. WinStatus = GetLastError();
  795. if ( WinStatus != ERROR_MORE_DATA ) {
  796. AzPrint(( AZD_CRITICAL, "AzpGetUserNameEx: Cannot GetUserNameExW %ld\n", WinStatus ));
  797. goto Cleanup;
  798. }
  799. //
  800. // Allocate a buffer
  801. //
  802. Buffer = (LPWSTR) AzpAllocateHeap( BufferSize * sizeof(WCHAR), "CNGUSER" );
  803. if ( Buffer == NULL ) {
  804. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  805. goto Cleanup;
  806. }
  807. //
  808. // Determine the DNS domain name
  809. //
  810. if ( !GetUserNameExW( NameFormat, Buffer, &BufferSize ) ) {
  811. WinStatus = GetLastError();
  812. AzPrint(( AZD_CRITICAL, "AzpGetUserNameEx: Cannot GetUserNameExW %ld\n", WinStatus ));
  813. goto Cleanup;
  814. }
  815. *pbIsDomainDnsName = TRUE;
  816. WinStatus = NO_ERROR;
  817. //
  818. // Free any local resources
  819. //
  820. Cleanup:
  821. if ( Impersonating ) {
  822. //
  823. // Revert to self
  824. //
  825. if ( !SetThreadToken( NULL, CurrentToken ) ) {
  826. DWORD TempStatus = GetLastError();
  827. AzPrint(( AZD_CRITICAL, "AzpGetUserNameEx: Cannot SetThreadToken (revert) %ld\n", TempStatus ));
  828. if ( WinStatus == NO_ERROR ) {
  829. WinStatus = TempStatus;
  830. }
  831. }
  832. }
  833. if ( WinStatus == NO_ERROR ) {
  834. //
  835. // Return the buffer to the caller
  836. //
  837. *NameBuffer = Buffer;
  838. Buffer = NULL;
  839. }
  840. if ( Buffer != NULL ) {
  841. AzpFreeHeap( Buffer );
  842. }
  843. if ( pUserToken != NULL ) {
  844. AzpFreeHeap( pUserToken );
  845. }
  846. if ( ClientName != NULL ) {
  847. AzpFreeHeap( ClientName );
  848. }
  849. //
  850. // Close the handle to the current token to prevent any leaks
  851. //
  852. if ( CurrentToken != NULL ) {
  853. CloseHandle( CurrentToken );
  854. }
  855. return WinStatus;
  856. }
  857. DWORD
  858. AzpClientContextGetProperty(
  859. IN PGENERIC_OBJECT GenericObject,
  860. IN ULONG Flags,
  861. IN ULONG PropertyId,
  862. OUT PVOID *PropertyValue
  863. )
  864. /*++
  865. Routine Description:
  866. This routine is the ClientContext specific worker routine for AzGetProperty.
  867. It does any object specific property gets. If the client context has
  868. AZP_CONTEXT_CREATED_FROM_SID flag set, then only
  869. RoleForAccessCheck property will be returned. All the rest will be returned
  870. for AZP_CONTEXT_CREATED_FROM_TOKEN and AZP_CONTEXT_CREATED_FROM_NAME.
  871. On entry, AzGlResource must be locked shared.
  872. Arguments:
  873. GenericObject - Specifies a pointer to the object to be queried
  874. Flags - Specifies internal flags
  875. AZP_FLAGS_BY_GUID - name lists should be returned as GUID lists
  876. AZP_FLAGS_PERSIST_* - Call is from the persistence provider
  877. PropertyId - Specifies which property to return.
  878. PropertyValue - Specifies a pointer to return the property in.
  879. The returned pointer must be freed using AzFreeMemory.
  880. The returned value and type depends in PropertyId. The valid values are:
  881. AZ_PROP_CLIENT_CONTEXT_USER_DN LPWSTR - DN of the user
  882. AZ_PROP_CLIENT_CONTEXT_USER_SAM_COMPAT LPWSTR - Sam compatible name of the user
  883. AZ_PROP_CLIENT_CONTEXT_USER_DISPLAY LPWSTR - Display name of the user
  884. AZ_PROP_CLIENT_CONTEXT_USER_GUID LPWSTR - GUID of the user
  885. AZ_PROP_CLIENT_CONTEXT_USER_CANONICAL LPWSTR - Canonical name of the user
  886. AZ_PROP_CLIENT_CONTEXT_USER_UPN LPWSTR - UPN of the user
  887. AZ_PROP_CLIENT_CONTEXT_USER_DNS_SAM_COMPAT LPWSTR - DNS same compat name of the user
  888. AZ_PROP_CLIENT_CONTEXT_ROLE_FOR_ACCESS_CHECK LPWSTR - role name (may be NULL) for the access check
  889. Return Value:
  890. Status of the operation
  891. --*/
  892. {
  893. DWORD WinStatus = NO_ERROR;
  894. PAZP_CLIENT_CONTEXT ClientContext = (PAZP_CLIENT_CONTEXT) GenericObject;
  895. EXTENDED_NAME_FORMAT NameFormat;
  896. LPWSTR PropertyString = NULL;
  897. AZP_STRING PropertyAzpString;
  898. BOOLEAN Ignore = FALSE;
  899. DWORD RetSize = 0;
  900. DWORD UserNameSize = 0;
  901. TOKEN_STATISTICS TokenStats = {0};
  902. PWSTR UserName = NULL;
  903. UNREFERENCED_PARAMETER(Flags); //ignore
  904. //
  905. // Initialization
  906. //
  907. ASSERT( AzpIsLockedShared( &AzGlResource ) );
  908. //
  909. // Return any object specific attribute
  910. //
  911. switch ( PropertyId ) {
  912. case AZ_PROP_CLIENT_CONTEXT_USER_DN:
  913. NameFormat = NameFullyQualifiedDN; break;
  914. case AZ_PROP_CLIENT_CONTEXT_USER_SAM_COMPAT:
  915. NameFormat = NameSamCompatible; break;
  916. case AZ_PROP_CLIENT_CONTEXT_USER_DISPLAY:
  917. NameFormat = NameDisplay; break;
  918. case AZ_PROP_CLIENT_CONTEXT_USER_GUID:
  919. NameFormat = NameUniqueId; break;
  920. case AZ_PROP_CLIENT_CONTEXT_USER_CANONICAL:
  921. NameFormat = NameCanonical; break;
  922. case AZ_PROP_CLIENT_CONTEXT_USER_UPN:
  923. NameFormat = NameUserPrincipal; break;
  924. case AZ_PROP_CLIENT_CONTEXT_USER_DNS_SAM_COMPAT:
  925. NameFormat = NameDnsDomain; break;
  926. case AZ_PROP_CLIENT_CONTEXT_ROLE_FOR_ACCESS_CHECK:
  927. //
  928. // this is a property that stored in the client context structure
  929. // do not need to go through getusernameex
  930. //
  931. *PropertyValue = AzpGetStringProperty( &ClientContext->RoleName );
  932. if ( *PropertyValue == NULL ) {
  933. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  934. }
  935. return WinStatus;
  936. default:
  937. AzPrint(( AZD_CRITICAL, "AzpClientContextGetProperty: invalid opcode %ld\n", PropertyId ));
  938. WinStatus = ERROR_INVALID_PARAMETER;
  939. goto Cleanup;
  940. }
  941. //
  942. // If the client context has been created from token, then use GetUserNameEx
  943. // to retrieve the different name properties.
  944. // If the client was created from Name, then we need to use TranslateName API
  945. // to retrieve the various name information properties (since no token is available).
  946. // However, TranslateName does not support NameDnsDomain format, and will return a
  947. // ERROR_NO_SUCH_USER - this needs to be returned to the caller as ERROR_NOT_SUPPORTED.
  948. // If the client was created from a StringSID with AZ_CLIENT_CONTEXT_SKIP_GROUP flag set,
  949. // then we return ERROR_NOT_SUPPORTED
  950. //
  951. if ( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_SID ) {
  952. WinStatus = ERROR_NOT_SUPPORTED;
  953. goto Cleanup;
  954. } else if ( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_TOKEN ) {
  955. //
  956. // Get the token stats to retreive the impersonation level
  957. //
  958. if ( !GetTokenInformation( ClientContext->TokenHandle,
  959. TokenStatistics,
  960. &TokenStats,
  961. sizeof(TOKEN_STATISTICS),
  962. &RetSize ) ) {
  963. WinStatus = GetLastError();
  964. AzPrint(( AZD_CRITICAL,
  965. "AzpClientContextGetProperty: Cannot get token statistics: %ld\n",
  966. WinStatus
  967. ));
  968. goto Cleanup;
  969. }
  970. //
  971. // Get the attribute from the LSA
  972. //
  973. WinStatus = AzpGetUserNameEx( ClientContext,
  974. NameFormat,
  975. &PropertyString,
  976. &Ignore );
  977. if ( WinStatus != NO_ERROR ) {
  978. goto Cleanup;
  979. }
  980. } else if ( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_NAME ) {
  981. //
  982. // Get the size required for the return string value
  983. //
  984. UserNameSize = (DWORD) (wcslen(ClientContext->ClientName)+wcslen(ClientContext->DomainName)+2)*
  985. sizeof(WCHAR);
  986. UserName = (PWSTR) AzpAllocateHeap( UserNameSize, "USRNAME" );
  987. if ( UserName == NULL ) {
  988. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  989. goto Cleanup;
  990. }
  991. wnsprintf( UserName, UserNameSize, L"%ws\\%ws", ClientContext->DomainName, ClientContext->ClientName );
  992. TranslateName( UserName,
  993. NameSamCompatible,
  994. NameFormat,
  995. NULL, // get size for return buffer
  996. &RetSize
  997. );
  998. if ( (GetLastError() == ERROR_NO_SUCH_USER) &&
  999. (PropertyId == AZ_PROP_CLIENT_CONTEXT_USER_DNS_SAM_COMPAT) ) {
  1000. WinStatus = ERROR_NOT_SUPPORTED;
  1001. goto Cleanup;
  1002. }
  1003. //
  1004. // Now that we have the size of the buffer we want, allocate
  1005. // and call TranslateName. The buffer will have the name in
  1006. // required format
  1007. //
  1008. PropertyString = (LPWSTR) AzpAllocateHeap( RetSize*sizeof(WCHAR), "CLNTNAM" );
  1009. if ( PropertyString == NULL ) {
  1010. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1011. goto Cleanup;
  1012. }
  1013. if ( !TranslateName( UserName,
  1014. NameSamCompatible,
  1015. NameFormat,
  1016. PropertyString,
  1017. &RetSize
  1018. ) ) {
  1019. WinStatus = GetLastError();
  1020. AzPrint(( AZD_CRITICAL,
  1021. "AzpClientContextGetProperty: Cannot translate name: %ld\n",
  1022. WinStatus
  1023. ));
  1024. goto Cleanup;
  1025. }
  1026. }
  1027. //
  1028. // Copy the string back to the caller
  1029. //
  1030. AzpInitString( &PropertyAzpString, PropertyString );
  1031. *PropertyValue = AzpGetStringProperty( &PropertyAzpString );
  1032. if ( *PropertyValue == NULL ) {
  1033. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1034. goto Cleanup;
  1035. }
  1036. WinStatus = NO_ERROR;
  1037. //
  1038. // Free any local resources
  1039. //
  1040. Cleanup:
  1041. if ( PropertyString != NULL ) {
  1042. AzpFreeHeap( PropertyString );
  1043. }
  1044. if ( UserName != NULL ) {
  1045. AzpFreeHeap( UserName );
  1046. }
  1047. return WinStatus;
  1048. }
  1049. DWORD
  1050. AzpClientContextSetProperty(
  1051. IN PGENERIC_OBJECT GenericObject,
  1052. IN ULONG Flags,
  1053. IN ULONG PropertyId,
  1054. IN PVOID PropertyValue
  1055. )
  1056. /*++
  1057. Routine Description:
  1058. This routine is the ClientContext object specific worker routine for AzSetProperty.
  1059. It does any object specific property sets.
  1060. On entry, AzGlResource must be locked exclusive.
  1061. Arguments:
  1062. GenericObject - Specifies a pointer to the object to be modified
  1063. Flags - Specifies flags controlling to operation of the routine
  1064. AZP_FLAGS_SETTING_TO_DEFAULT - Property is being set to default value
  1065. AZP_FLAGS_PERSIST_* - Call is from the persistence provider
  1066. PropertyId - Specifies which property to set.
  1067. PropertyValue - Specifies a pointer to the property.
  1068. The specified value and type depends in PropertyId. The valid values are:
  1069. AZ_PROP_CLIENT_CONTEXT_ROLE_FOR_ACCESS_CHECK LPWSTR - role specified for this access check
  1070. Return Value:
  1071. Status of the operation
  1072. --*/
  1073. {
  1074. DWORD WinStatus = NO_ERROR;
  1075. PAZP_CLIENT_CONTEXT ClientContext = (PAZP_CLIENT_CONTEXT) GenericObject;
  1076. //
  1077. // Initialization
  1078. //
  1079. UNREFERENCED_PARAMETER( Flags );
  1080. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  1081. //
  1082. // Set any object specific attribute
  1083. //
  1084. // Set role name
  1085. //
  1086. switch ( PropertyId ) {
  1087. case AZ_PROP_CLIENT_CONTEXT_ROLE_FOR_ACCESS_CHECK:
  1088. //
  1089. // role name set to the client context is not persisted (via submit)
  1090. // so there is no need to define a dirty bit for this property.
  1091. //
  1092. // It's only temporarialy set in the client context structure,
  1093. // which will be used by AccessCheck only
  1094. //
  1095. AZP_STRING TempString;
  1096. WinStatus = AzpCaptureString(&TempString,
  1097. (LPCWSTR)PropertyValue,
  1098. AZ_MAX_ROLE_NAME_LENGTH,
  1099. TRUE
  1100. );
  1101. if ( WinStatus != NO_ERROR ) {
  1102. goto Cleanup;
  1103. }
  1104. //
  1105. // swap the new role name with existing role name and free the existing one
  1106. //
  1107. AzpSwapStrings(&ClientContext->RoleName,&TempString);
  1108. //
  1109. // free the existing role name specifed in the context, if any
  1110. //
  1111. AzpFreeString(&TempString);
  1112. break;
  1113. default:
  1114. AzPrint(( AZD_INVPARM, "AzpClientContextSetProperty: invalid prop id %ld\n", PropertyId ));
  1115. WinStatus = ERROR_INVALID_PARAMETER;
  1116. break;
  1117. }
  1118. Cleanup:
  1119. return WinStatus;
  1120. }
  1121. DWORD
  1122. AzpCheckSidMembership(
  1123. IN PAZP_CLIENT_CONTEXT ClientContext,
  1124. IN PGENERIC_OBJECT_LIST SidList,
  1125. OUT PBOOLEAN IsMember
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. This routine checks to see if client context contains any of the Sids in SidList.
  1130. Do this be creating a security descriptor with all of the sids in a DACL and doing
  1131. and access check.
  1132. ??? Consider caching the SecurityDescriptors
  1133. On entry, AzGlResource must be locked Shared.
  1134. Arguments:
  1135. ClientContext - Specifies the context of the user to check group membership of.
  1136. SidList - Specifies the list of sids to check membership for
  1137. IsMember - Returns TRUE if the user has one or more of the listed sids in his token.
  1138. Returns FALSE if the user has none of the listed sids in his token.
  1139. Return Value:
  1140. NO_ERROR - The function was successful
  1141. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  1142. Any failure returned here should be returned to the caller.
  1143. --*/
  1144. {
  1145. DWORD WinStatus;
  1146. #define CHECK_SID_ACCESS_MASK 1
  1147. ULONG FirstSid;
  1148. ULONG LastSid;
  1149. BOOLEAN UseBiggest = FALSE;
  1150. ULONG i;
  1151. PSID Sid = NULL;
  1152. DWORD AclSize;
  1153. PACL Acl = NULL;
  1154. AUTHZ_ACCESS_REQUEST AccessRequest = { CHECK_SID_ACCESS_MASK };
  1155. AUTHZ_ACCESS_REPLY AccessReply;
  1156. DWORD GrantedAccess;
  1157. DWORD AuthStatus;
  1158. SECURITY_DESCRIPTOR SecurityDescriptor;
  1159. //
  1160. // Initialization
  1161. //
  1162. ASSERT( AzpIsLockedShared( &AzGlResource ) );
  1163. ASSERT( ClientContext->GenericObject.ReferenceCount != 0 );
  1164. *IsMember = FALSE;
  1165. //
  1166. // If there isn't at least one sid,
  1167. // then we're not a member.
  1168. //
  1169. if ( SidList->GenericObjects.UsedCount == 0 ) {
  1170. WinStatus = NO_ERROR;
  1171. goto Cleanup;
  1172. }
  1173. //
  1174. // Loop doing at most 64KB at a time since that's the ACL limit
  1175. //
  1176. #define BIGGEST_ACL 0xFFFF
  1177. for ( FirstSid=0; FirstSid<SidList->GenericObjects.UsedCount; FirstSid=LastSid ) {
  1178. //
  1179. // Loop through the list of sids computing the ACL size
  1180. //
  1181. AclSize = sizeof(ACL);
  1182. LastSid = SidList->GenericObjects.UsedCount;
  1183. for ( i=FirstSid; i<LastSid; i++ ) {
  1184. DWORD AceSize;
  1185. ASSERT(((PGENERIC_OBJECT)(SidList->GenericObjects.Array[i]))->ObjectType == OBJECT_TYPE_SID );
  1186. Sid = (PSID)((PAZP_SID)(SidList->GenericObjects.Array[i]))->GenericObject.ObjectName->ObjectName.String;
  1187. AceSize = ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
  1188. RtlLengthSid( Sid );
  1189. if ( AclSize + AceSize >= BIGGEST_ACL) {
  1190. LastSid = i;
  1191. UseBiggest = TRUE;
  1192. break;
  1193. }
  1194. AclSize += AceSize;
  1195. }
  1196. AzPrint(( AZD_ACCESS_MORE,
  1197. "AzpCheckSidMembership: Process sids %ld to %ld with %ld byte ACL\n",
  1198. FirstSid,
  1199. LastSid,
  1200. AclSize ));
  1201. //
  1202. // Allocate memory for Acl
  1203. //
  1204. if ( Acl == NULL ) {
  1205. SafeAllocaAllocate( Acl, UseBiggest ? BIGGEST_ACL : AclSize );
  1206. if ( Acl == NULL ) {
  1207. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1208. goto Cleanup;
  1209. }
  1210. }
  1211. //
  1212. // Initialize the buffer
  1213. //
  1214. if (!InitializeAcl( Acl, AclSize, ACL_REVISION)) {
  1215. WinStatus = GetLastError();
  1216. goto Cleanup;
  1217. }
  1218. //
  1219. // Loop through the list of sids adding them to the ACL
  1220. //
  1221. for ( i=FirstSid; i<LastSid; i++ ) {
  1222. Sid = (PSID)((PAZP_SID)(SidList->GenericObjects.Array[i]))->GenericObject.ObjectName->ObjectName.String;
  1223. if ( !AddAccessAllowedAce(
  1224. Acl,
  1225. ACL_REVISION,
  1226. CHECK_SID_ACCESS_MASK,
  1227. Sid ) ) {
  1228. WinStatus = GetLastError();
  1229. goto Cleanup;
  1230. }
  1231. }
  1232. //
  1233. // Initialize the security descriptor
  1234. //
  1235. if ( !InitializeSecurityDescriptor(
  1236. &SecurityDescriptor,
  1237. SECURITY_DESCRIPTOR_REVISION ) ) {
  1238. WinStatus = GetLastError();
  1239. goto Cleanup;
  1240. }
  1241. if ( !SetSecurityDescriptorDacl(
  1242. &SecurityDescriptor,
  1243. TRUE,
  1244. Acl,
  1245. FALSE ) ) {
  1246. WinStatus = GetLastError();
  1247. goto Cleanup;
  1248. }
  1249. //
  1250. // Use an arbitrary SID as the "owner".
  1251. //
  1252. // AuthzAccessCheck uses it to replace "CreatorOwner" and to determine
  1253. // ReadControl/WriteDac. None of those apply to us. But we need to placate
  1254. // AuthzAccessCheck.
  1255. //
  1256. if ( !SetSecurityDescriptorOwner(
  1257. &SecurityDescriptor,
  1258. Sid,
  1259. FALSE ) ) {
  1260. WinStatus = GetLastError();
  1261. goto Cleanup;
  1262. }
  1263. //
  1264. // Check if the client has any of the sids in his context
  1265. //
  1266. AccessReply.ResultListLength = 1;
  1267. AccessReply.GrantedAccessMask = &GrantedAccess;
  1268. AccessReply.Error = &AuthStatus;
  1269. if ( !AuthzAccessCheck(
  1270. 0, // No Flags
  1271. ClientContext->AuthzClientContext,
  1272. &AccessRequest,
  1273. NULL, // No auditing
  1274. &SecurityDescriptor,
  1275. NULL, // No extra security descriptors
  1276. 0, // No extra security descriptors
  1277. &AccessReply,
  1278. NULL ) ) { // No Cached results
  1279. WinStatus = GetLastError();
  1280. goto Cleanup;
  1281. }
  1282. if ( GrantedAccess & CHECK_SID_ACCESS_MASK ) {
  1283. *IsMember = TRUE;
  1284. break;
  1285. }
  1286. }
  1287. WinStatus = NO_ERROR;
  1288. //
  1289. // Free any local resources
  1290. //
  1291. Cleanup:
  1292. if ( Acl != NULL ) {
  1293. SafeAllocaFree( Acl );
  1294. }
  1295. return WinStatus;
  1296. }
  1297. DWORD
  1298. AzpCheckGroupMembership(
  1299. IN PAZP_CLIENT_CONTEXT ClientContext,
  1300. IN PGENERIC_OBJECT_LIST GroupList,
  1301. IN BOOLEAN LocalOnly,
  1302. IN DWORD RecursionLevel,
  1303. OUT PBOOLEAN RetIsMember,
  1304. OUT LPDWORD RetExtendedStatus
  1305. )
  1306. /*++
  1307. Routine Description:
  1308. This routine checks to see if the user specified by ClientContext is a member of
  1309. any of the groups specified by GroupList.
  1310. On entry, AzGlResource must be locked Shared.
  1311. *** Note: this routine will temporarily drop AzGlResource in cases where it hits the wire
  1312. Arguments:
  1313. ClientContext - Specifies the context of the user to check group membership of.
  1314. GroupList - Specifies the list of groups to check group membership of
  1315. LocalOnly - Specifies that the caller doesn't want to go off machine to determine
  1316. the membership.
  1317. RecursionLevel - Indicates the level of recursion.
  1318. Used to prevent infinite recursion.
  1319. RetIsMember - Returns whether the caller is a member of the specified group.
  1320. RetExtendedStatus - Returns extended status information about the operation.
  1321. NO_ERROR is returned if the group membership was determined.
  1322. The Caller may use the value returned in IsMember.
  1323. If LocalOnly is TRUE, NOT_YET_DONE means that the caller must call again with
  1324. with LocalOnly set to false to get the group membership.
  1325. If LocalOnly is FALSE, an error value indicates that the LDAP server returned
  1326. an error while evaluating the request. The caller may return this error
  1327. to the original API caller if this group membership is required to determine
  1328. whether the access check worked or not.
  1329. Return Value:
  1330. NO_ERROR - The function was successful
  1331. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  1332. Any failure returned here should be returned to the caller.
  1333. --*/
  1334. {
  1335. DWORD WinStatus;
  1336. ULONG i;
  1337. DWORD SavedExtendedStatus = NO_ERROR;
  1338. //
  1339. // Initialization
  1340. //
  1341. ASSERT( AzpIsLockedShared( &AzGlResource ) );
  1342. if ( RecursionLevel > 100 ) {
  1343. return ERROR_DS_LOOP_DETECT;
  1344. }
  1345. //
  1346. // Loop through the list of groups evaluating each
  1347. //
  1348. for ( i=0; i<GroupList->GenericObjects.UsedCount; i++ ) {
  1349. PAZP_GROUP Group;
  1350. BOOLEAN IsMember;
  1351. DWORD ExtendedStatus;
  1352. //
  1353. // Check the membership of one group
  1354. //
  1355. ASSERT(((PGENERIC_OBJECT)(GroupList->GenericObjects.Array[i]))->ObjectType == OBJECT_TYPE_GROUP );
  1356. Group = (PAZP_GROUP) GroupList->GenericObjects.Array[i];
  1357. WinStatus = AzpCheckGroupMembershipOne(
  1358. ClientContext,
  1359. Group,
  1360. LocalOnly,
  1361. RecursionLevel,
  1362. &IsMember,
  1363. &ExtendedStatus );
  1364. if ( WinStatus != NO_ERROR ) {
  1365. return WinStatus;
  1366. }
  1367. //
  1368. // If we're definitively a member,
  1369. // tell our caller.
  1370. //
  1371. if ( ExtendedStatus == NO_ERROR ) {
  1372. if ( IsMember ) {
  1373. *RetIsMember = TRUE;
  1374. *RetExtendedStatus = NO_ERROR;
  1375. return NO_ERROR;
  1376. }
  1377. //
  1378. // If we don't have a definitive answer,
  1379. // remember the answer hoping that we can get a definitive answer.
  1380. //
  1381. } else {
  1382. SavedExtendedStatus = ExtendedStatus;
  1383. }
  1384. }
  1385. //
  1386. // ASSERT: we couldn't prove we're a member
  1387. // Return any defered status we may have
  1388. //
  1389. *RetExtendedStatus = SavedExtendedStatus;
  1390. *RetIsMember = FALSE;
  1391. return NO_ERROR;
  1392. }
  1393. DWORD
  1394. AzpComputeAccountDn(
  1395. IN AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientContext,
  1396. OUT LPWSTR *RetAccountDn
  1397. )
  1398. /*++
  1399. Routine Description:
  1400. This routine computes the DN of the account to query.
  1401. Arguments:
  1402. AuthzClientContext - Client context for the account
  1403. RetAccountDn - Returns a pointer to the string containing the DN for the account
  1404. The caller must free this string using AzpFreeHeap.
  1405. Return Value:
  1406. NO_ERROR - The function was successful.
  1407. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  1408. Any failure returned here should be returned to the caller.
  1409. --*/
  1410. {
  1411. DWORD WinStatus;
  1412. ULONG BufferSize;
  1413. PTOKEN_USER UserSid = NULL;
  1414. ULONG UserSidSize;
  1415. LPWSTR AccountDn = NULL;
  1416. ULONG i;
  1417. LPBYTE InBuffer;
  1418. WCHAR *OutBuffer;
  1419. //
  1420. // Determine the length of the sid
  1421. //
  1422. if ( AuthzGetInformationFromContext( AuthzClientContext,
  1423. AuthzContextInfoUserSid,
  1424. 0,
  1425. &BufferSize,
  1426. NULL ) ) {
  1427. WinStatus = ERROR_INTERNAL_ERROR;
  1428. AzPrint(( AZD_CRITICAL,
  1429. "AzpComputeAccountDn: AuthzGetInformationFromContext failed %ld\n",
  1430. WinStatus ));
  1431. goto Cleanup;
  1432. }
  1433. WinStatus = GetLastError();
  1434. if ( WinStatus != ERROR_INSUFFICIENT_BUFFER ) {
  1435. AzPrint(( AZD_CRITICAL,
  1436. "AzpComputeAccountDn: AuthzGetInformationFromContext failed %ld\n",
  1437. WinStatus ));
  1438. goto Cleanup;
  1439. }
  1440. //
  1441. // Allocate a buffer for the SID
  1442. //
  1443. SafeAllocaAllocate( UserSid, BufferSize );
  1444. if ( UserSid == NULL ) {
  1445. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1446. AzPrint(( AZD_CRITICAL,
  1447. "AzpComputeAccountDn: SafeAllocaAllocate failed %ld\n",
  1448. WinStatus ));
  1449. goto Cleanup;
  1450. }
  1451. //
  1452. // Read the user sid into the buffer.
  1453. //
  1454. if ( !AuthzGetInformationFromContext( AuthzClientContext,
  1455. AuthzContextInfoUserSid,
  1456. BufferSize,
  1457. &BufferSize,
  1458. UserSid ) ) {
  1459. WinStatus = GetLastError();
  1460. AzPrint(( AZD_CRITICAL,
  1461. "AzpComputeAccountDn: AuthzGetInformationFromContext failed %ld\n",
  1462. WinStatus ));
  1463. goto Cleanup;
  1464. }
  1465. //
  1466. // Convert the Sid to a DN
  1467. //
  1468. // Allocate a buffer for the DN
  1469. //
  1470. #define DN_PREFIX L"<Sid="
  1471. #define DN_PREFIX_LENGTH ((sizeof(DN_PREFIX)/sizeof(WCHAR))-1)
  1472. #define DN_SUFFIX L">"
  1473. #define DN_SUFFIX_LENGTH ((sizeof(DN_SUFFIX)/sizeof(WCHAR))-1)
  1474. UserSidSize = RtlLengthSid( UserSid->User.Sid );
  1475. AccountDn = (LPWSTR) AzpAllocateHeap(
  1476. (DN_PREFIX_LENGTH +
  1477. UserSidSize * 2 +
  1478. DN_SUFFIX_LENGTH +
  1479. 1) * sizeof(WCHAR), "CNACCDN" );
  1480. if ( AccountDn == NULL ) {
  1481. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1482. AzPrint(( AZD_CRITICAL,
  1483. "AzpComputeAccountDn: AzpAllocateHeap failed %ld\n",
  1484. WinStatus ));
  1485. goto Cleanup;
  1486. }
  1487. //
  1488. // Build the DN.
  1489. // The form is <SID=0104000000000005150000005951B81766725D2564633B0B>
  1490. // Where each byte of the SID has been turned into two ASCII hex digits.
  1491. // This format will work on both win2k and whistler.
  1492. //
  1493. RtlCopyMemory( AccountDn, DN_PREFIX, DN_PREFIX_LENGTH*sizeof(WCHAR) );
  1494. InBuffer = (LPBYTE) UserSid->User.Sid;
  1495. OutBuffer = &AccountDn[DN_PREFIX_LENGTH];
  1496. CHAR XlateArray[] = { '0', '1', '2', '3', '4' ,'5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
  1497. for ( i=0; i<UserSidSize; i++ ) {
  1498. *OutBuffer++ = XlateArray[ (InBuffer[i] >> 4) & 0xF ];
  1499. *OutBuffer++ = XlateArray[ InBuffer[i] & 0xF ];
  1500. }
  1501. RtlCopyMemory( OutBuffer,
  1502. DN_SUFFIX,
  1503. (DN_SUFFIX_LENGTH+1)*sizeof(WCHAR) );
  1504. //
  1505. // Save it away
  1506. //
  1507. *RetAccountDn = AccountDn;
  1508. AccountDn = NULL;
  1509. WinStatus = NO_ERROR;
  1510. //
  1511. // Free locally used resources
  1512. //
  1513. Cleanup:
  1514. if ( UserSid != NULL ) {
  1515. SafeAllocaFree( UserSid );
  1516. }
  1517. if ( AccountDn != NULL ) {
  1518. AzpFreeHeap( AccountDn );
  1519. }
  1520. return WinStatus;
  1521. }
  1522. DWORD
  1523. AzpLdapSupported(
  1524. IN PSID UserSid,
  1525. OUT PBOOLEAN LdapSupported
  1526. )
  1527. /*++
  1528. Routine description:
  1529. This routine decides whether a given user is a domain user or a local
  1530. machine user.
  1531. On a DC, we support LdapQueries since the user account is surely a domain
  1532. account.
  1533. On a non-dc, we compare the User sid with the AccountDomainSid. If the two
  1534. are equal then this is a local user on a non-DC and we do not support Ldap
  1535. queries.
  1536. Arguments:
  1537. UserSid - Sid of the client.
  1538. LdapSupported - Returns whether or not we support LdapQueries.
  1539. Return Value:
  1540. Returns ERROR_SUCCESS on success, appropriate failure value otherwise.
  1541. --*/
  1542. {
  1543. BOOL Equal = FALSE;
  1544. *LdapSupported = TRUE;
  1545. //
  1546. // If this is a DC, we support LdapQueries.
  1547. //
  1548. if ( AzIsDC ) {
  1549. return NO_ERROR;
  1550. }
  1551. ASSERT( AzAccountDomainSidInitialized );
  1552. //
  1553. // Check whether the user belongs to the current machine account domain.
  1554. //
  1555. if ( !EqualDomainSid( AzAccountDomainSid, UserSid, &Equal ) ) {
  1556. return GetLastError();
  1557. }
  1558. //
  1559. // If they are equal this is a local account.
  1560. //
  1561. if ( Equal ) {
  1562. *LdapSupported = FALSE;
  1563. }
  1564. return NO_ERROR;
  1565. }
  1566. DWORD
  1567. AzpCheckGroupMembershipLdap(
  1568. IN PAZP_CLIENT_CONTEXT ClientContext,
  1569. IN OUT PAZP_MEMBER_EVALUATION MemEval
  1570. )
  1571. /*++
  1572. Routine Description:
  1573. This routine checks to see if the user specified by ClientContext is a member of
  1574. the specified LDAP_QUERY AppGroup.
  1575. Client context created from SID (to skip ldap group check) will not be allowed
  1576. in this routine (ERROR_INVALID_PARAMETER will be returned)
  1577. This routine goes over the wire so AzGlResource must not be locked.
  1578. On entry, ClientContext.CritSect must be locked.
  1579. Arguments:
  1580. ClientContext - Specifies the context of the user to check group membership of.
  1581. MemEval - Membership evaluation cache entry for this group
  1582. The cache entry is updated to reflect group membership or
  1583. the reason for failure to find group membership.
  1584. Return Value:
  1585. NO_ERROR - The function was successful. (MemEval was updated.)
  1586. MemEval->WinStatus is either set to NO_ERROR or ERROR_NO_SUCH_DOMAIN.
  1587. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  1588. Any failure returned here should be returned to the caller.
  1589. --*/
  1590. {
  1591. DWORD WinStatus;
  1592. PAZP_AZSTORE AzAuthorizationStore = ClientContext->GenericObject.AzStoreObject;
  1593. LPWSTR DnsDomainName = NULL;
  1594. ULONG GetDcContext;
  1595. PAZP_DC Dc = NULL;
  1596. WCHAR *p;
  1597. ULONG LdapStatus;
  1598. LDAP_TIMEVAL LdapTimeout;
  1599. LPWSTR Attributes[2];
  1600. PLDAPMessage LdapMessage = NULL;
  1601. ULONG EntryCount;
  1602. BOOLEAN IsDomainDnsName = FALSE;
  1603. //
  1604. // Initialization
  1605. //
  1606. ASSERT( AzpIsCritsectLocked( &ClientContext->CritSect ) );
  1607. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipLdap: %ws\n", MemEval->Group->GenericObject.ObjectName->ObjectName.String ));
  1608. //
  1609. // If we don't yet know what domain this user is in,
  1610. // find out.
  1611. //
  1612. if ( ClientContext->Domain == NULL ) {
  1613. //
  1614. // If we know the domain doesn't support LDAP,
  1615. // we're sure that the user isn't a member of the group.
  1616. //
  1617. if ( ClientContext->LdapNotSupported ) {
  1618. MemEval->IsMember = FALSE;
  1619. MemEval->WinStatus = NO_ERROR;
  1620. AzPrint(( AZD_ACCESS_MORE,
  1621. "AzpCheckGroupMembershipLdap: %ws: User is in NT 4 domain or local account: Membership is %ld\n",
  1622. MemEval->Group->GenericObject.ObjectName->ObjectName.String,
  1623. MemEval->IsMember ));
  1624. WinStatus = NO_ERROR;
  1625. goto Cleanup;
  1626. }
  1627. if ( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_TOKEN ) {
  1628. //
  1629. // Get the dns domain name from the LSA
  1630. //
  1631. WinStatus = AzpGetUserNameEx( ClientContext,
  1632. NameDnsDomain,
  1633. &DnsDomainName,
  1634. &IsDomainDnsName );
  1635. if ( WinStatus != NO_ERROR ) {
  1636. //
  1637. // If the account is a local account,
  1638. // or the domain is an NT 4.0 (or older domain),
  1639. // then the user isn't a member of this ldap group.
  1640. //
  1641. if ( WinStatus == ERROR_NONE_MAPPED ) {
  1642. ClientContext->LdapNotSupported = TRUE;
  1643. MemEval->IsMember = FALSE;
  1644. MemEval->WinStatus = NO_ERROR;
  1645. AzPrint(( AZD_ACCESS_MORE,
  1646. "AzpCheckGroupMembershipLdap: %ws: User is in NT 4 domain or local account: Membership is %ld\n",
  1647. MemEval->Group->GenericObject.ObjectName->ObjectName.String,
  1648. MemEval->IsMember ));
  1649. WinStatus = NO_ERROR;
  1650. goto Cleanup;
  1651. }
  1652. AzPrint(( AZD_CRITICAL,
  1653. "AzpCheckGroupMembershipLdap: %ws: AzpGetUserNameEx failed %ld\n",
  1654. MemEval->Group->GenericObject.ObjectName->ObjectName.String,
  1655. WinStatus ));
  1656. //
  1657. // The DC can be down.
  1658. // In that case, ERROR_NO_SUCH_DOMAIN is returned above and
  1659. // Cleanup puts it in MemEval->WinStatus
  1660. //
  1661. goto Cleanup;
  1662. }
  1663. //
  1664. // AzpGetUserNameEx may return the DnsDomainName with the user name
  1665. // Trim it off if it exists
  1666. //
  1667. p = wcschr( DnsDomainName, L'\\' );
  1668. if ( p != NULL ) {
  1669. *p = '\0';
  1670. }
  1671. //
  1672. // Get the domain handle for this domain
  1673. //
  1674. ClientContext->Domain = AzpReferenceDomain( AzAuthorizationStore,
  1675. DnsDomainName,
  1676. IsDomainDnsName );
  1677. } else if ( ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_NAME ) {
  1678. //
  1679. // Check whether we support Ldap Queries.
  1680. // We do not support Ldap queries if the account is local.
  1681. //
  1682. // Note, AZP_CONTEXT_CREATED_FROM_SID will not get into this code path
  1683. // because SKIP_GROUP is set so ldap group evaluation is skipped.
  1684. WinStatus = AzpLdapSupported( (PSID) ClientContext->SidBuffer, &ClientContext->LdapNotSupported );
  1685. if ( WinStatus != NO_ERROR ) {
  1686. goto Cleanup;
  1687. }
  1688. if ( !ClientContext->LdapNotSupported ) {
  1689. MemEval->IsMember = FALSE;
  1690. MemEval->WinStatus = NO_ERROR;
  1691. goto Cleanup;
  1692. }
  1693. //
  1694. // We have the domain name available already. It's in NetBios name
  1695. // format.
  1696. //
  1697. ClientContext->Domain = AzpReferenceDomain( AzAuthorizationStore,
  1698. ClientContext->DomainName,
  1699. FALSE );
  1700. } else {
  1701. ASSERT( FALSE );
  1702. WinStatus = ERROR_INVALID_PARAMETER;
  1703. goto Cleanup;
  1704. }
  1705. if ( ClientContext->Domain == NULL ) {
  1706. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1707. goto Cleanup;
  1708. }
  1709. }
  1710. //
  1711. // Loop handling failed DCs
  1712. //
  1713. GetDcContext = 0;
  1714. for ( ;; ) {
  1715. //
  1716. // Free the name from the previous iteration
  1717. //
  1718. if ( Dc != NULL ) {
  1719. AzpDereferenceDc( Dc );
  1720. Dc = NULL;
  1721. }
  1722. //
  1723. // Get the name of a DC to try
  1724. //
  1725. WinStatus = AzpGetDc( AzAuthorizationStore,
  1726. ClientContext->Domain,
  1727. &GetDcContext,
  1728. &Dc );
  1729. if ( WinStatus != NO_ERROR ) {
  1730. AzPrint(( AZD_ACCESS,
  1731. "AzpCheckGroupMembershipLdap: %ws: DsGetDcName failed %ld\n",
  1732. MemEval->Group->GenericObject.ObjectName->ObjectName.String,
  1733. WinStatus ));
  1734. goto Cleanup;
  1735. }
  1736. //
  1737. // Free up resources from the previous iteration
  1738. //
  1739. if ( LdapMessage != NULL ) {
  1740. ldap_msgfree( LdapMessage );
  1741. LdapMessage = NULL;
  1742. }
  1743. //
  1744. // Ensure we have an DN of the user object
  1745. //
  1746. if ( ClientContext->AccountDn == NULL ) {
  1747. WinStatus = AzpComputeAccountDn(
  1748. ClientContext->AuthzClientContext,
  1749. &ClientContext->AccountDn );
  1750. if ( WinStatus != NO_ERROR ) {
  1751. goto Cleanup;
  1752. }
  1753. }
  1754. //
  1755. // Read the user object
  1756. //
  1757. LdapTimeout.tv_sec = 30; // Wait at most 30 seconds
  1758. LdapTimeout.tv_usec = 0;
  1759. Attributes[0] = L"ObjectClass"; // Pick a random attribute to ask for
  1760. Attributes[1] = NULL;
  1761. LdapStatus = ldap_search_ext_sW(
  1762. Dc->LdapHandle,
  1763. ClientContext->AccountDn,
  1764. LDAP_SCOPE_BASE,
  1765. MemEval->Group->LdapQuery.String,
  1766. Attributes, // Ask for only one attribute
  1767. TRUE, // Only attribute types (not values)
  1768. NULL, // No server controls
  1769. NULL, // No client controls
  1770. &LdapTimeout,
  1771. 0, // No limit on size of response
  1772. &LdapMessage );
  1773. if ( LdapStatus != LDAP_SUCCESS ) {
  1774. AzPrint(( AZD_ACCESS,
  1775. "AzpCheckGroupMembershipLdap: %ws: ldap_search failed on %ws: %ld: %s\n",
  1776. MemEval->Group->GenericObject.ObjectName->ObjectName.String,
  1777. Dc->DcName.String,
  1778. LdapStatus,
  1779. ldap_err2stringA( LdapStatus )));
  1780. WinStatus = AzpLdapErrorToWin32Error(LdapStatus);
  1781. //
  1782. // If the DC is down,
  1783. // find another one.
  1784. //
  1785. if ( WinStatus == ERROR_NO_SUCH_DOMAIN ) {
  1786. continue;
  1787. }
  1788. goto Cleanup;
  1789. }
  1790. //
  1791. // Loop through the list of objects returned
  1792. //
  1793. EntryCount = ldap_count_entries( Dc->LdapHandle, LdapMessage );
  1794. if ( EntryCount == 0xFFFFFFFF ) {
  1795. LdapStatus = LdapGetLastError();
  1796. AzPrint(( AZD_CRITICAL,
  1797. "AzpCheckGroupMembershipLdap: %ws: ldap_count_entries failed on %ws: %ld: %s\n",
  1798. MemEval->Group->GenericObject.ObjectName->ObjectName.String,
  1799. Dc->DcName.String,
  1800. LdapStatus,
  1801. ldap_err2stringA( LdapStatus )));
  1802. WinStatus = AzpLdapErrorToWin32Error(LdapStatus);
  1803. goto Cleanup;
  1804. }
  1805. #if 0 // Run dlcheck.exe if this is ever turned on
  1806. //
  1807. // Perhaps just debug code, but display all of the attributes returned
  1808. //
  1809. ULONG EntryIndex;
  1810. LPWSTR AttributeName;
  1811. BerElement *BerState;
  1812. PLDAPMessage CurrentEntry;
  1813. CurrentEntry = NULL;
  1814. for ( EntryIndex = 0; EntryIndex < EntryCount; EntryIndex ++ ) {
  1815. //
  1816. // Get the next entry
  1817. //
  1818. if ( EntryIndex == 0) {
  1819. CurrentEntry = ldap_first_entry( Dc->LdapHandle, LdapMessage );
  1820. } else {
  1821. CurrentEntry = ldap_next_entry( Dc->LdapHandle, CurrentEntry );
  1822. }
  1823. if ( CurrentEntry == NULL ) {
  1824. LdapStatus = LdapGetLastError();
  1825. if ( LdapStatus != LDAP_SUCCESS ) {
  1826. AzPrint(( AZD_CRITICAL,
  1827. "AzpCheckGroupMembershipLdap: %ws: ldap_xxx_entry failed on %ws: %ld: %s\n",
  1828. MemEval->Group->GenericObject.ObjectName->ObjectName.String,
  1829. Dc->DcName.String,
  1830. LdapStatus,
  1831. ldap_err2stringA( LdapStatus )));
  1832. }
  1833. WinStatus = AzpLdapErrorToWin32Error(LdapStatus);
  1834. goto Cleanup;
  1835. }
  1836. //
  1837. // Loop through the attributes
  1838. //
  1839. AttributeName = ldap_first_attributeW( Dc->LdapHandle, CurrentEntry, &BerState );
  1840. AzPrint(( AZD_ACCESS_MORE, "Object %ld\n", EntryIndex ));
  1841. while ( AttributeName != NULL ) {
  1842. AzPrint(( AZD_ACCESS_MORE, " %ws\n", AttributeName ));
  1843. ldap_memfree( AttributeName );
  1844. AttributeName = ldap_next_attributeW( Dc->LdapHandle, CurrentEntry, BerState );
  1845. }
  1846. if ( BerState != NULL ) {
  1847. ber_free( BerState, 0 );
  1848. }
  1849. LdapStatus = LdapGetLastError();
  1850. if ( LdapStatus != LDAP_SUCCESS ) {
  1851. AzPrint(( AZD_CRITICAL,
  1852. "AzpCheckGroupMembershipLdap: %ws: ldap_xxx_attribute failed on %ws: %ld: %s\n",
  1853. MemEval->Group->GenericObject.ObjectName->ObjectName.String,
  1854. Dc->DcName.String,
  1855. LdapStatus,
  1856. ldap_err2stringA( LdapStatus )));
  1857. WinStatus = AzpLdapErrorToWin32Error(LdapStatus);
  1858. goto Cleanup;
  1859. }
  1860. }
  1861. #endif // 0
  1862. //
  1863. // The query worked.
  1864. // We're a member of the group depending on whether the entry was actually returned.
  1865. //
  1866. MemEval->IsMember = (EntryCount != 0);
  1867. MemEval->WinStatus = NO_ERROR;
  1868. AzPrint(( AZD_ACCESS_MORE,
  1869. "AzpCheckGroupMembershipLdap: %ws: ldap_search worked on %ws: Membership is %ld\n",
  1870. MemEval->Group->GenericObject.ObjectName->ObjectName.String,
  1871. Dc->DcName.String,
  1872. MemEval->IsMember ));
  1873. WinStatus = NO_ERROR;
  1874. goto Cleanup;
  1875. }
  1876. // ASSERT: Not reached
  1877. //
  1878. // Free locally used resources
  1879. //
  1880. Cleanup:
  1881. if ( LdapMessage != NULL ) {
  1882. ldap_msgfree( LdapMessage );
  1883. LdapMessage = NULL;
  1884. }
  1885. if ( Dc != NULL ) {
  1886. AzpDereferenceDc( Dc );
  1887. }
  1888. if ( DnsDomainName != NULL ) {
  1889. AzpFreeHeap( DnsDomainName );
  1890. }
  1891. //
  1892. // If the failure came from the DC,
  1893. // indicate that we need to try again sometime.
  1894. //
  1895. if ( WinStatus == ERROR_NO_SUCH_DOMAIN ) {
  1896. MemEval->WinStatus = WinStatus;
  1897. WinStatus = NO_ERROR;
  1898. }
  1899. return WinStatus;
  1900. }
  1901. DWORD
  1902. AzpCheckGroupMembershipOne(
  1903. IN PAZP_CLIENT_CONTEXT ClientContext,
  1904. IN PAZP_GROUP Group,
  1905. IN BOOLEAN LocalOnly,
  1906. IN DWORD RecursionLevel,
  1907. OUT PBOOLEAN RetIsMember,
  1908. OUT LPDWORD ExtendedStatus
  1909. )
  1910. /*++
  1911. Routine Description:
  1912. This routine checks to see if the user specified by ClientContext is a member of
  1913. the specified AppGroup.
  1914. On entry, ClientContext.CritSect must be locked.
  1915. On entry, AzGlResource must be locked Shared.
  1916. *** Note: this routine will temporarily drop AzGlResource in cases where it hits the wire
  1917. Arguments:
  1918. ClientContext - Specifies the context of the user to check group membership of.
  1919. Group - Specifies the group to check group membership of
  1920. LocalOnly - Specifies that the caller doesn't want to go off machine to determine
  1921. the membership.
  1922. RecursionLevel - Indicates the level of recursion.
  1923. Used to prevent infinite recursion.
  1924. RetIsMember - Returns whether the caller is a member of the specified group.
  1925. ExtendedStatus - Returns extended status information about the operation.
  1926. NO_ERROR is returned if the group membership was determined.
  1927. The Caller may use the value returned in IsMember.
  1928. If LocalOnly is TRUE, NOT_YET_DONE means that the caller must call again with
  1929. with LocalOnly set to false to get the group membership.
  1930. If LocalOnly is FALSE, an error value indicates that the LDAP server returned
  1931. an error while evaluating the request. The caller may return this error
  1932. to the original API caller if this group membership is required to determine
  1933. whether the access check worked or not.
  1934. Return Value:
  1935. NO_ERROR - The function was successful
  1936. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  1937. Any failure returned here should be returned to the caller.
  1938. --*/
  1939. {
  1940. DWORD WinStatus;
  1941. PLIST_ENTRY ListEntry;
  1942. PAZP_MEMBER_EVALUATION MemEval;
  1943. BOOLEAN IsMember;
  1944. BOOLEAN IsNonMember;
  1945. //
  1946. // Initialization
  1947. //
  1948. ASSERT( AzpIsLockedShared( &AzGlResource ) );
  1949. ASSERT( AzpIsCritsectLocked( &ClientContext->CritSect ) );
  1950. *RetIsMember = FALSE;
  1951. *ExtendedStatus = NO_ERROR;
  1952. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws\n", Group->GenericObject.ObjectName->ObjectName.String ));
  1953. //
  1954. // Loop through the list of groups that have previously been evaluated
  1955. //
  1956. MemEval = NULL;
  1957. for ( ListEntry = ClientContext->MemEval.Flink;
  1958. ListEntry != &ClientContext->MemEval;
  1959. ListEntry = ListEntry->Flink) {
  1960. MemEval = CONTAINING_RECORD( ListEntry,
  1961. AZP_MEMBER_EVALUATION,
  1962. Next );
  1963. if ( MemEval->Group == Group ) {
  1964. break;
  1965. }
  1966. MemEval = NULL;
  1967. }
  1968. //
  1969. // If we didn't find one,
  1970. // create one.
  1971. //
  1972. if ( MemEval == NULL ) {
  1973. //
  1974. // Allocate it
  1975. //
  1976. MemEval = (PAZP_MEMBER_EVALUATION) AzpAllocateHeap( sizeof( AZP_MEMBER_EVALUATION ), "CNMEMEVL");
  1977. if ( MemEval == NULL ) {
  1978. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  1979. goto Cleanup;
  1980. }
  1981. //
  1982. // Initialize it
  1983. //
  1984. MemEval->Group = Group;
  1985. MemEval->WinStatus = NOT_YET_DONE;
  1986. MemEval->IsMember = FALSE;
  1987. //
  1988. // Link it in
  1989. //
  1990. InsertHeadList( &ClientContext->MemEval,
  1991. &MemEval->Next );
  1992. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Create cache entry\n", Group->GenericObject.ObjectName->ObjectName.String ));
  1993. }
  1994. //
  1995. // If we already know the membership,
  1996. // return the cached answer.
  1997. //
  1998. if ( MemEval->WinStatus == NO_ERROR ) {
  1999. WinStatus = NO_ERROR;
  2000. *ExtendedStatus = NO_ERROR;
  2001. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: %ld: %ld: Answer found in cache\n", Group->GenericObject.ObjectName->ObjectName.String, *ExtendedStatus, MemEval->IsMember ));
  2002. goto Cleanup;
  2003. }
  2004. //
  2005. // Handle a membership group,
  2006. //
  2007. if ( Group->GroupType == AZ_GROUPTYPE_BASIC ) {
  2008. DWORD AppNonMemberStatus;
  2009. DWORD AppMemberStatus;
  2010. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Is a basic group\n", Group->GenericObject.ObjectName->ObjectName.String ));
  2011. //
  2012. // Check the NT Group non-membership
  2013. //
  2014. WinStatus = AzpCheckSidMembership(
  2015. ClientContext,
  2016. &Group->SidNonMembers,
  2017. &IsNonMember );
  2018. if ( WinStatus != NO_ERROR ) {
  2019. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Cannot AzpCheckSidMembership (non member) %ld\n", Group->GenericObject.ObjectName->ObjectName.String, WinStatus ));
  2020. goto Cleanup;
  2021. }
  2022. //
  2023. // If we're not a member,
  2024. // that's definitive
  2025. //
  2026. if ( IsNonMember ) {
  2027. // Cache the answer
  2028. MemEval->IsMember = FALSE;
  2029. MemEval->WinStatus = NO_ERROR;
  2030. // Return the cached answer
  2031. WinStatus = NO_ERROR;
  2032. *ExtendedStatus = MemEval->WinStatus;
  2033. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Is non member via NT Sid\n", Group->GenericObject.ObjectName->ObjectName.String ));
  2034. goto Cleanup;
  2035. }
  2036. //
  2037. // Check the app group non-membership
  2038. //
  2039. WinStatus = AzpCheckGroupMembership(
  2040. ClientContext,
  2041. &Group->AppNonMembers,
  2042. LocalOnly,
  2043. RecursionLevel+1, // Increment recursion level
  2044. &IsNonMember,
  2045. &AppNonMemberStatus );
  2046. if ( WinStatus != NO_ERROR ) {
  2047. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Cannot AzpCheckGroupMembership (non member) %ld\n", Group->GenericObject.ObjectName->ObjectName.String, WinStatus ));
  2048. goto Cleanup;
  2049. }
  2050. //
  2051. // If we're not a member,
  2052. // that's definitive.
  2053. //
  2054. // Note that if we couldn't determine non-membership,
  2055. // we wait to report back to the caller until we find out if we're a member.
  2056. // No use worrying the caller if we definitely aren't a member.
  2057. //
  2058. if ( AppNonMemberStatus == NO_ERROR ) {
  2059. if ( IsNonMember ) {
  2060. // Cache the answer
  2061. MemEval->IsMember = FALSE;
  2062. MemEval->WinStatus = NO_ERROR;
  2063. // Return the cached answer
  2064. WinStatus = NO_ERROR;
  2065. *ExtendedStatus = MemEval->WinStatus;
  2066. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Is non member via app group\n", Group->GenericObject.ObjectName->ObjectName.String ));
  2067. goto Cleanup;
  2068. }
  2069. }
  2070. //
  2071. // Check the NT Group membership
  2072. //
  2073. WinStatus = AzpCheckSidMembership(
  2074. ClientContext,
  2075. &Group->SidMembers,
  2076. &IsMember );
  2077. if ( WinStatus != NO_ERROR ) {
  2078. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Cannot AzpCheckSidMembership (member) %ld\n", Group->GenericObject.ObjectName->ObjectName.String, WinStatus ));
  2079. goto Cleanup;
  2080. }
  2081. //
  2082. // If we couldn't determine membership based on SIDs,
  2083. // try via app groups
  2084. //
  2085. if ( !IsMember ) {
  2086. //
  2087. // Check the app group membership
  2088. //
  2089. WinStatus = AzpCheckGroupMembership(
  2090. ClientContext,
  2091. &Group->AppMembers,
  2092. LocalOnly,
  2093. RecursionLevel+1, // Increment recursion level
  2094. &IsMember,
  2095. &AppMemberStatus );
  2096. if ( WinStatus != NO_ERROR ) {
  2097. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Cannot AzpCheckGroupMembership (member) %ld\n", Group->GenericObject.ObjectName->ObjectName.String, WinStatus ));
  2098. goto Cleanup;
  2099. }
  2100. //
  2101. // If we couldn't determine membership,
  2102. // return that status to our caller.
  2103. //
  2104. if ( AppMemberStatus != NO_ERROR ) {
  2105. // We cache this failure only on the LDAP_QUERY group that
  2106. // caused it.
  2107. MemEval->IsMember = FALSE;
  2108. MemEval->WinStatus = NOT_YET_DONE;
  2109. // Return the cached answer
  2110. WinStatus = NO_ERROR;
  2111. *ExtendedStatus = AppMemberStatus;
  2112. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Cannot AzpCheckGroupMembership (member) extended status: %ld\n", Group->GenericObject.ObjectName->ObjectName.String, AppMemberStatus ));
  2113. goto Cleanup;
  2114. }
  2115. }
  2116. //
  2117. // ASSERT: We've determined membership via the SID or APP group mechanisms
  2118. //
  2119. // If we're a member and we couldn't find non-membership,
  2120. // tell the caller now.
  2121. //
  2122. if ( IsMember ) {
  2123. if ( AppNonMemberStatus != NO_ERROR ) {
  2124. // We cache this failure only on the LDAP_QUERY group that
  2125. // caused it.
  2126. MemEval->IsMember = FALSE;
  2127. MemEval->WinStatus = NOT_YET_DONE;
  2128. // Return the cached answer
  2129. WinStatus = NO_ERROR;
  2130. *ExtendedStatus = AppNonMemberStatus;
  2131. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Cannot AzpCheckGroupMembership (non member) extended status: %ld\n", Group->GenericObject.ObjectName->ObjectName.String, AppNonMemberStatus ));
  2132. goto Cleanup;
  2133. }
  2134. }
  2135. //
  2136. // Finally, we've found out whether we're a member
  2137. // Tell the caller
  2138. //
  2139. MemEval->IsMember = IsMember;
  2140. MemEval->WinStatus = NO_ERROR;
  2141. *ExtendedStatus = NO_ERROR;
  2142. WinStatus = NO_ERROR;
  2143. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: %ld: %ld: Answer computed\n", Group->GenericObject.ObjectName->ObjectName.String, *ExtendedStatus, MemEval->IsMember ));
  2144. //
  2145. // Handle an LDAP_QUERY group.
  2146. //
  2147. } else if ( Group->GroupType == AZ_GROUPTYPE_LDAP_QUERY ) {
  2148. //
  2149. // If the caller only wants local processing,
  2150. // or skip ldap group in which case the context is created from SID,
  2151. // We're done for now.
  2152. //
  2153. if ( LocalOnly ||
  2154. (ClientContext->CreationType == AZP_CONTEXT_CREATED_FROM_SID) ) {
  2155. WinStatus = NO_ERROR;
  2156. //
  2157. // ERROR_NO_SUCH_DOMAIN isn't definitive.
  2158. // Convert it to NOT_YET_DONE to ensure we try again.
  2159. //
  2160. ASSERT( MemEval->WinStatus == ERROR_NO_SUCH_DOMAIN || MemEval->WinStatus == NOT_YET_DONE );
  2161. *ExtendedStatus = NOT_YET_DONE;
  2162. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Avoid ldapquery group\n", Group->GenericObject.ObjectName->ObjectName.String ));
  2163. goto Cleanup;
  2164. }
  2165. //
  2166. // Query the DC to determine group membership
  2167. //
  2168. // Drop AzGlResource while going over the wire
  2169. //
  2170. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Is an ldapquery group\n", Group->GenericObject.ObjectName->ObjectName.String ));
  2171. AzpUnlockResource( &AzGlResource );
  2172. WinStatus = AzpCheckGroupMembershipLdap(
  2173. ClientContext,
  2174. MemEval );
  2175. AzpLockResourceShared( &AzGlResource );
  2176. if ( WinStatus != NO_ERROR ) {
  2177. goto Cleanup;
  2178. }
  2179. *ExtendedStatus = MemEval->WinStatus;
  2180. //
  2181. // Handle invalid group types
  2182. //
  2183. } else {
  2184. AzPrint(( AZD_ACCESS_MORE, "AzpCheckGroupMembershipOne: %ws: Is an invalid group type\n", Group->GenericObject.ObjectName->ObjectName.String, Group->GroupType ));
  2185. //
  2186. // Don't fail the AccessCheck because of malformed policy data
  2187. //
  2188. MemEval->IsMember = FALSE;
  2189. MemEval->WinStatus = NO_ERROR;
  2190. // Return the cached answer
  2191. WinStatus = NO_ERROR;
  2192. *ExtendedStatus = MemEval->WinStatus;
  2193. }
  2194. //
  2195. // Free any local resources
  2196. //
  2197. Cleanup:
  2198. if ( WinStatus == NO_ERROR &&
  2199. *ExtendedStatus == NO_ERROR ) {
  2200. *RetIsMember = MemEval->IsMember;
  2201. }
  2202. return WinStatus;
  2203. }
  2204. DWORD
  2205. AzpWalkTaskTree(
  2206. IN PACCESS_CHECK_CONTEXT AcContext,
  2207. IN PGENERIC_OBJECT_LIST OperationObjectList,
  2208. IN PGENERIC_OBJECT_LIST TaskObjectList,
  2209. IN DWORD RecursionLevel,
  2210. IN OUT LPDWORD *AllocatedMemory OPTIONAL,
  2211. IN OUT LPDWORD MemoryRequired,
  2212. IN OUT LPDWORD TaskInfoArraySize,
  2213. OUT PAZ_OPS_AND_TASKS OpsAndTasks OPTIONAL,
  2214. OUT PBOOLEAN CallAgain
  2215. )
  2216. /*++
  2217. Routine Description:
  2218. This routine walks a tree of tasks collecting information about the tasks. The caller should
  2219. call this routine twice. Once to determine how much memory to allocate. The second to initialize
  2220. that memory.
  2221. On the first pass, AllocatedMemory and AcContext->TaskInfo should be passed in as null.
  2222. On the first pass, this routine simply counts the number of tasks and operations in the tree.
  2223. Between the first and second passes, the caller should allocate two buffers.
  2224. The first should be MemoryRequired bytes long and should be passed in AllocatedMemory on the
  2225. second pass. The second should be TaskInfoArraySize bytes long and should
  2226. be passed in AcContext->TaskInfo on the second pass. (The caller is responsible for freeing
  2227. this memory.)
  2228. On the second pass, this routine fills in the allocated arrays. AcContext->TaskInfo is
  2229. filled in with each task found. However, this routine weeds out duplicates. By weeding
  2230. out duplicates, the TaskInfo array has a single entry for each applicable task and we can
  2231. ensure that each task is processed at most one time.
  2232. Since duplicates are weeded out, the TaskInfo array may be larger than the number of entries used.
  2233. On entry, AcContext->ClientContext.CritSect must be locked.
  2234. On entry, AzGlResource must be locked Shared. (The AzGlResource should not be dropped between
  2235. the two calls to AzpWalkTaskTree mentioned above.)
  2236. Arguments:
  2237. AcContext - Specifies the context of the user to check group membership of.
  2238. OperationObjectList - Specifies a list of operations referenced by the parent object.
  2239. TaskObjectList - Specifies the list of tasks referenced by the parent object.
  2240. RecursionLevel - Indicates the level of recursion.
  2241. Used to prevent infinite recursion.
  2242. AllocatedMemory - On the first pass, this pointer should be NULL.
  2243. On the second pass, this is a pointer to the memory allocated by the caller.
  2244. MemoryRequired - This variable is incremented by the amount of memory required on the second pass.
  2245. TaskInfoArraySize - This variable is incremented by the amount of memory required on the second pass.
  2246. OpsAndTasks - On the second pass, this structure is filled in with the indices to all
  2247. of the applicable operations from OperationObjectList and tasks from TaskObjectList.
  2248. CallAgain - Set to TRUE if an operation was found in OperationObjectList or
  2249. recursively in TaskObjectList.
  2250. FALSE if the OperationObjectList and TaskObjectList should never be processed again.
  2251. Return Value:
  2252. NO_ERROR - The function was successful
  2253. --*/
  2254. {
  2255. DWORD WinStatus;
  2256. BOOLEAN FirstPass = (AllocatedMemory==NULL);
  2257. ULONG Size;
  2258. ULONG i;
  2259. //
  2260. // Initialization
  2261. //
  2262. ASSERT( AzpIsLockedShared( &AzGlResource ) );
  2263. ASSERT( AzpIsCritsectLocked( &AcContext->ClientContext->CritSect ) );
  2264. if ( RecursionLevel > 100 ) {
  2265. return ERROR_DS_LOOP_DETECT;
  2266. }
  2267. if ( FirstPass ) {
  2268. ASSERT( OpsAndTasks == NULL );
  2269. ASSERT( AcContext->TaskInfo == NULL );
  2270. } else {
  2271. ASSERT( OpsAndTasks != NULL );
  2272. ASSERT( AcContext->TaskInfo != NULL );
  2273. }
  2274. *CallAgain = FALSE;
  2275. if ( OpsAndTasks != NULL ) {
  2276. RtlZeroMemory( OpsAndTasks, sizeof(*OpsAndTasks) );
  2277. }
  2278. //
  2279. // If the caller passed in any operations,
  2280. // see which are applicable
  2281. //
  2282. if ( OperationObjectList->GenericObjects.UsedCount ) {
  2283. ULONG OpIndex;
  2284. //
  2285. // Allocate a buffer for the array of indices to the operations
  2286. //
  2287. Size = OperationObjectList->GenericObjects.UsedCount*sizeof(ULONG);
  2288. *MemoryRequired += Size;
  2289. if ( !FirstPass ) {
  2290. // AzPrint(( AZD_ACCESS_MORE, "Used: 0x%lx (0x%lx)\n", *AllocatedMemory, Size ));
  2291. OpsAndTasks->OpIndexes = *AllocatedMemory;
  2292. *AllocatedMemory = (LPDWORD)(((LPBYTE)(*AllocatedMemory)) + Size);
  2293. }
  2294. //
  2295. // Determine which operations are applicable
  2296. //
  2297. for ( OpIndex = 0;
  2298. OpIndex < OperationObjectList->GenericObjects.UsedCount;
  2299. OpIndex++ ) {
  2300. PAZP_OPERATION Operation;
  2301. Operation = (PAZP_OPERATION)(OperationObjectList->GenericObjects.Array[OpIndex]);
  2302. ASSERT( Operation->GenericObject.ObjectType == OBJECT_TYPE_OPERATION );
  2303. //
  2304. // Find this operation in the list of operations requested by the caller.
  2305. //
  2306. for ( i=0; i<AcContext->OperationCount; i++ ) {
  2307. //
  2308. // If the Task operation matches a requested operation,
  2309. // then we have a match.
  2310. //
  2311. if ( Operation->OperationId == AcContext->OperationObjects[i]->OperationId ) {
  2312. //
  2313. // Indicate that we've found an operation
  2314. //
  2315. *CallAgain = TRUE;
  2316. //
  2317. // On the second pass,
  2318. // Remember an index for this operation.
  2319. //
  2320. if ( !FirstPass ) {
  2321. OpsAndTasks->OpIndexes[OpsAndTasks->OpCount] = i;
  2322. OpsAndTasks->OpCount++;
  2323. }
  2324. break;
  2325. }
  2326. }
  2327. }
  2328. }
  2329. //
  2330. // If the caller passed in any tasks,
  2331. // see which are applicable
  2332. //
  2333. if ( TaskObjectList->GenericObjects.UsedCount ) {
  2334. ULONG TaskIndex;
  2335. PAZ_TASK_INFO TaskInfo;
  2336. //
  2337. // Allocate a buffer for the array of indices to the tasks
  2338. //
  2339. Size = TaskObjectList->GenericObjects.UsedCount*sizeof(ULONG);
  2340. *MemoryRequired += Size;
  2341. if ( !FirstPass ) {
  2342. // AzPrint(( AZD_ACCESS_MORE, "Used: 0x%lx (0x%lx)\n", *AllocatedMemory, Size ));
  2343. OpsAndTasks->TaskIndexes = *AllocatedMemory;
  2344. *AllocatedMemory = (LPDWORD)(((LPBYTE)(*AllocatedMemory)) + Size);
  2345. }
  2346. //
  2347. // Walk the task object list
  2348. //
  2349. for ( TaskIndex = 0;
  2350. TaskIndex < TaskObjectList->GenericObjects.UsedCount;
  2351. TaskIndex ++ ) {
  2352. PAZP_TASK Task;
  2353. BOOLEAN LocalCallAgain;
  2354. Task = (PAZP_TASK)(TaskObjectList->GenericObjects.Array[TaskIndex]);
  2355. ASSERT( Task->GenericObject.ObjectType == OBJECT_TYPE_TASK );
  2356. //
  2357. // If this is the not the first pass,
  2358. // find a TaskInfo.
  2359. //
  2360. *TaskInfoArraySize += sizeof(AZ_TASK_INFO);
  2361. TaskInfo = NULL;
  2362. if ( !FirstPass ) {
  2363. //
  2364. // Determine if this task already has a taskinfo
  2365. //
  2366. for ( i=0; i<AcContext->TaskCount; i++ ) {
  2367. if ( Task == AcContext->TaskInfo[i].Task ) {
  2368. TaskInfo = &AcContext->TaskInfo[i];
  2369. break;
  2370. }
  2371. }
  2372. //
  2373. // If there isn't already a task info,
  2374. // allocate one
  2375. //
  2376. if ( TaskInfo == NULL ) {
  2377. //
  2378. // Grab the next TaskInfo and initialize to zero.
  2379. //
  2380. TaskInfo = &AcContext->TaskInfo[AcContext->TaskCount];
  2381. AcContext->TaskCount++;
  2382. RtlZeroMemory( TaskInfo, sizeof(*TaskInfo) );
  2383. //
  2384. // Reference the task
  2385. // Need to grab a reference since the global lock will be dropped during the
  2386. // lifetime of this task info.
  2387. //
  2388. InterlockedIncrement( &Task->GenericObject.ReferenceCount );
  2389. AzpDumpGoRef( "Task reference", &Task->GenericObject );
  2390. TaskInfo->Task = Task;
  2391. }
  2392. }
  2393. //
  2394. // Recurse.
  2395. //
  2396. WinStatus = AzpWalkTaskTree( AcContext,
  2397. &Task->Operations,
  2398. &Task->Tasks,
  2399. RecursionLevel+1,
  2400. AllocatedMemory,
  2401. MemoryRequired,
  2402. TaskInfoArraySize,
  2403. FirstPass ? NULL : &TaskInfo->OpsAndTasks,
  2404. &LocalCallAgain );
  2405. if ( WinStatus != NO_ERROR ) {
  2406. return WinStatus;
  2407. }
  2408. //
  2409. // If operations were found in the subtree,
  2410. // then process the subtree.
  2411. //
  2412. if ( LocalCallAgain ) {
  2413. *CallAgain = TRUE;
  2414. //
  2415. // On the second pass,
  2416. // Remember an index for this task
  2417. //
  2418. if ( !FirstPass ) {
  2419. OpsAndTasks->TaskIndexes[OpsAndTasks->TaskCount] =
  2420. (ULONG)(TaskInfo - AcContext->TaskInfo);
  2421. OpsAndTasks->TaskCount++;
  2422. }
  2423. //
  2424. // If no applicable operations were found anywhere,
  2425. // ditch this task.
  2426. //
  2427. } else {
  2428. if ( !FirstPass ) {
  2429. TaskInfo->TaskProcessed = TRUE;
  2430. }
  2431. }
  2432. }
  2433. }
  2434. return NO_ERROR;
  2435. }
  2436. DWORD
  2437. AzpCaptureBizRuleParameters(
  2438. IN PACCESS_CHECK_CONTEXT AcContext,
  2439. IN VARIANT *ParameterNames OPTIONAL,
  2440. IN VARIANT *ParameterValues OPTIONAL
  2441. )
  2442. /*++
  2443. Routine Description:
  2444. This routine captures the access check parameters related to BizRule evaluation.
  2445. The captured parameters are remembered in the AcContext.
  2446. Arguments:
  2447. AcContext - Specifies the access check context
  2448. ParameterNames - See AzContextAccessCheck
  2449. ParameterValues - See AzContextAccessCheck
  2450. Return Value:
  2451. NO_ERROR - The function was successful
  2452. ERROR_INVALID_PARAMETER - One of the parameters are invalid
  2453. Any failure returned here should be returned to the caller.
  2454. --*/
  2455. {
  2456. DWORD WinStatus;
  2457. HRESULT hr;
  2458. SAFEARRAY* SaNames;
  2459. SAFEARRAY* SaValues;
  2460. VARIANT HUGEP *Names = NULL;
  2461. VARIANT HUGEP *Values = NULL;
  2462. LONG NamesLower;
  2463. LONG NamesUpper;
  2464. LONG ValuesLower;
  2465. LONG ValuesUpper;
  2466. ULONG ParameterCount;
  2467. ULONG Index;
  2468. //
  2469. // We don't actually capture. But we do reference several fields. Do those
  2470. // references under a try/except.
  2471. //
  2472. // All uses of these parameters are done under try/except.
  2473. //
  2474. __try {
  2475. //
  2476. // Canonicalize the array references
  2477. //
  2478. WinStatus = AzpSafeArrayPointerFromVariant( ParameterNames,
  2479. TRUE,
  2480. &SaNames );
  2481. if ( WinStatus != NO_ERROR ) {
  2482. goto Cleanup;
  2483. }
  2484. WinStatus = AzpSafeArrayPointerFromVariant( ParameterValues,
  2485. TRUE,
  2486. &SaValues );
  2487. if ( WinStatus != NO_ERROR ) {
  2488. goto Cleanup;
  2489. }
  2490. //
  2491. // If one is null, both must be.
  2492. //
  2493. if ( SaNames == NULL ) {
  2494. if ( SaValues == NULL ) {
  2495. WinStatus = NO_ERROR;
  2496. AcContext->ParameterNames = NULL;
  2497. AcContext->ParameterValues = NULL;
  2498. AcContext->ParameterCount = 0;
  2499. } else {
  2500. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Names is NULL but Values isn't\n" ));
  2501. WinStatus = ERROR_INVALID_PARAMETER;
  2502. }
  2503. goto Cleanup;
  2504. } else if ( SaValues == NULL ) {
  2505. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Values is NULL but Names isn't\n" ));
  2506. WinStatus = ERROR_INVALID_PARAMETER;
  2507. goto Cleanup;
  2508. }
  2509. //
  2510. // Both must have the same upper and lower bounds
  2511. //
  2512. hr = SafeArrayGetLBound( SaNames, 1, &NamesLower );
  2513. if ( FAILED(hr)) {
  2514. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Can't get name lbound 0x%lx\n", hr ));
  2515. WinStatus = ERROR_INVALID_PARAMETER;
  2516. goto Cleanup;
  2517. }
  2518. hr = SafeArrayGetLBound( SaValues, 1, &ValuesLower );
  2519. if ( FAILED(hr)) {
  2520. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Can't get value lbound 0x%lx\n", hr ));
  2521. WinStatus = ERROR_INVALID_PARAMETER;
  2522. goto Cleanup;
  2523. }
  2524. hr = SafeArrayGetUBound( SaNames, 1, &NamesUpper );
  2525. if ( FAILED(hr)) {
  2526. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Can't get name ubound 0x%lx\n", hr ));
  2527. WinStatus = ERROR_INVALID_PARAMETER;
  2528. goto Cleanup;
  2529. }
  2530. hr = SafeArrayGetUBound( SaValues, 1, &ValuesUpper );
  2531. if ( FAILED(hr)) {
  2532. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Can't get value ubound 0x%lx\n", hr ));
  2533. WinStatus = ERROR_INVALID_PARAMETER;
  2534. goto Cleanup;
  2535. }
  2536. if ( NamesLower != ValuesLower ||
  2537. NamesUpper != ValuesUpper ) {
  2538. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Array bounds don't match %ld %ld %ld %ld\n", NamesLower, ValuesLower, NamesUpper, ValuesUpper ));
  2539. WinStatus = ERROR_INVALID_PARAMETER;
  2540. goto Cleanup;
  2541. }
  2542. //
  2543. // Lock the arrays
  2544. //
  2545. hr = SafeArrayAccessData( SaNames, (void HUGEP**)&Names);
  2546. if (FAILED(hr)) {
  2547. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Can't access ParameterNames 0x%lx\n", hr ));
  2548. WinStatus = ERROR_INVALID_PARAMETER;
  2549. goto Cleanup;
  2550. }
  2551. hr = SafeArrayAccessData( SaValues, (void HUGEP**)&Values);
  2552. if (FAILED(hr)) {
  2553. SafeArrayUnaccessData( SaNames );
  2554. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Can't access ParameterValues 0x%lx\n", hr ));
  2555. WinStatus = ERROR_INVALID_PARAMETER;
  2556. goto Cleanup;
  2557. }
  2558. //
  2559. // Loop validating the parameter arrays
  2560. //
  2561. ParameterCount = NamesUpper - NamesLower + 1;
  2562. for ( Index=0; Index<ParameterCount; Index++ ) {
  2563. //
  2564. // Stop at the end of the array
  2565. //
  2566. if ( V_VT( &Names[Index] ) == VT_EMPTY ) {
  2567. ParameterCount = Index;
  2568. break;
  2569. }
  2570. //
  2571. // Only allow BSTRs
  2572. //
  2573. if ( V_VT( &Names[Index] ) != VT_BSTR ) {
  2574. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Parameter %ld isn't a VT_BSTR\n", Index ));
  2575. WinStatus = ERROR_INVALID_PARAMETER;
  2576. goto Cleanup;
  2577. }
  2578. //
  2579. // Value cannot be an interface
  2580. //
  2581. if ( V_VT( &Values[Index] ) == VT_DISPATCH ||
  2582. V_VT( &Values[Index] ) == VT_UNKNOWN ) {
  2583. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleParameters: Parameter %ws should have an interface value\n",
  2584. V_BSTR(&Names[Index] ) ));
  2585. WinStatus = ERROR_INVALID_PARAMETER;
  2586. goto Cleanup;
  2587. }
  2588. #if DBG
  2589. //
  2590. // On a checked build, ensure the parameters are already sorted
  2591. //
  2592. // Only compare after the first iteration
  2593. //
  2594. if ( Index != 0 ) {
  2595. if ( AzpCompareParameterNames(&Names[Index-1], &Names[Index] ) >= 0 ) {
  2596. AzPrint(( AZD_INVPARM,
  2597. "AzpBuildParameterDescriptor: Parameters not sorted: %ws: %ws\n",
  2598. V_BSTR(&Names[Index-1] ),
  2599. V_BSTR(&Names[Index] ) ));
  2600. WinStatus = ERROR_INVALID_PARAMETER;
  2601. goto Cleanup;
  2602. }
  2603. }
  2604. #endif // DBG
  2605. }
  2606. //
  2607. // Remember the data
  2608. //
  2609. AcContext->SaParameterNames = SaNames;
  2610. AcContext->ParameterNames = Names;
  2611. AcContext->SaParameterValues = SaValues;
  2612. AcContext->ParameterValues = Values;
  2613. AcContext->ParameterCount = ParameterCount;
  2614. WinStatus = NO_ERROR;
  2615. Cleanup:;
  2616. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  2617. WinStatus = RtlNtStatusToDosError( GetExceptionCode());
  2618. }
  2619. return WinStatus;
  2620. }
  2621. INT __cdecl
  2622. AzpCompareParameterNames(
  2623. IN const void *pArg1,
  2624. IN const void *pArg2
  2625. )
  2626. /*++
  2627. Routine Description:
  2628. This routine compares two parameter names for the qsort/bsearch API
  2629. Arguments:
  2630. pArg1 - First string for comparison
  2631. pArg2 - Second String for comparison
  2632. Return Values:
  2633. <0 - First string is smaller
  2634. 0 - strings are same
  2635. >0 - First string is larger
  2636. --*/
  2637. {
  2638. HRESULT hr;
  2639. VARIANT *var1 = (VARIANT *) pArg1;
  2640. VARIANT *var2 = (VARIANT *) pArg2;
  2641. //
  2642. // Compare the parameter names
  2643. // This comparison has proven to be a bottleneck for AccessCheck performance.
  2644. // Consider replacing this with some combination of SysStringByteLen and memcmp.
  2645. // I'm not sure that all callers pass in strings when SysStringByteLen isn't longer
  2646. // than the useful part of the string.
  2647. // I'm not sure that memcmp returns the same sort order as a case sensitive VarCmp.
  2648. //
  2649. ASSERT( V_VT(var1) == VT_BSTR );
  2650. ASSERT( V_VT(var2) == VT_BSTR );
  2651. hr = VarCmp( var1, var2, LOCALE_USER_DEFAULT, 0);
  2652. if ( hr == VARCMP_LT ) {
  2653. return -1;
  2654. } else if ( hr == (HRESULT)VARCMP_GT ) {
  2655. return 1;
  2656. } else {
  2657. return 0;
  2658. }
  2659. }
  2660. INT __cdecl
  2661. AzpCaseInsensitiveCompareParameterNames(
  2662. IN const void *pArg1,
  2663. IN const void *pArg2
  2664. )
  2665. /*++
  2666. Routine Description:
  2667. This routine compares case-insensitively two parameter
  2668. names for the qsort/bsearch API
  2669. Arguments:
  2670. pArg1 - First string for comparison
  2671. pArg2 - Second String for comparison
  2672. Return Values:
  2673. <0 - First string is smaller
  2674. 0 - strings are same
  2675. >0 - First string is larger
  2676. --*/
  2677. {
  2678. HRESULT hr;
  2679. VARIANT *var1 = (VARIANT *) pArg1;
  2680. VARIANT *var2 = (VARIANT *) pArg2;
  2681. //
  2682. // See comments in AzpCompareParameterNames
  2683. //
  2684. ASSERT( V_VT(var1) == VT_BSTR );
  2685. ASSERT( V_VT(var2) == VT_BSTR );
  2686. hr = VarCmp( var1, var2, LOCALE_USER_DEFAULT, NORM_IGNORECASE);
  2687. if ( hr == VARCMP_LT ) {
  2688. return -1;
  2689. } else if ( hr == (HRESULT)VARCMP_GT ) {
  2690. return 1;
  2691. } else {
  2692. return 0;
  2693. }
  2694. }
  2695. DWORD
  2696. AzpCaptureBizRuleInterfaces(
  2697. IN PACCESS_CHECK_CONTEXT AcContext,
  2698. IN VARIANT *InterfaceNames OPTIONAL,
  2699. IN VARIANT *InterfaceFlags OPTIONAL,
  2700. IN VARIANT *Interfaces OPTIONAL
  2701. )
  2702. /*++
  2703. Routine Description:
  2704. This routine captures the access check interfaces related to BizRule evaluation.
  2705. The captured parameters are remembered in the AcContext.
  2706. On entry, AzGlResource must be locked Shared.
  2707. Arguments:
  2708. AcContext - Specifies the access check context
  2709. InterfaceNames - See AzContextAccessCheck
  2710. InterfaceFlags - See AzContextAccessCheck
  2711. Interfaces - See AzContextAccessCheck
  2712. Return Value:
  2713. NO_ERROR - The function was successful
  2714. ERROR_INVALID_PARAMETER - One of the parameters are invalid
  2715. Any failure returned here should be returned to the caller.
  2716. --*/
  2717. {
  2718. DWORD WinStatus;
  2719. HRESULT hr;
  2720. SAFEARRAY* Names;
  2721. SAFEARRAY* Flags;
  2722. SAFEARRAY* SaInterfaces;
  2723. LONG NamesLower;
  2724. LONG NamesUpper;
  2725. LONG FlagsLower;
  2726. LONG FlagsUpper;
  2727. LONG InterfacesLower;
  2728. LONG InterfacesUpper;
  2729. //
  2730. // We don't actually capture. But we do reference several fields. Do those
  2731. // references under a try/except.
  2732. //
  2733. // All uses of these parameters are done under try/except.
  2734. //
  2735. __try {
  2736. //
  2737. // Canonicalize the array references
  2738. //
  2739. WinStatus = AzpSafeArrayPointerFromVariant( InterfaceNames,
  2740. TRUE,
  2741. &Names );
  2742. if ( WinStatus != NO_ERROR ) {
  2743. goto Cleanup;
  2744. }
  2745. WinStatus = AzpSafeArrayPointerFromVariant( InterfaceFlags,
  2746. TRUE,
  2747. &Flags );
  2748. if ( WinStatus != NO_ERROR ) {
  2749. goto Cleanup;
  2750. }
  2751. WinStatus = AzpSafeArrayPointerFromVariant( Interfaces,
  2752. TRUE,
  2753. &SaInterfaces );
  2754. if ( WinStatus != NO_ERROR ) {
  2755. goto Cleanup;
  2756. }
  2757. //
  2758. // If one is null, all must be.
  2759. //
  2760. if ( Names == NULL ) {
  2761. if ( Flags == NULL && SaInterfaces == NULL ) {
  2762. WinStatus = NO_ERROR;
  2763. AcContext->InterfaceNames = NULL;
  2764. AcContext->InterfaceFlags = NULL;
  2765. AcContext->Interfaces = NULL;
  2766. } else {
  2767. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleInterfaces: Names is NULL but Flags or Interfaces isn't\n" ));
  2768. WinStatus = ERROR_INVALID_PARAMETER;
  2769. }
  2770. goto Cleanup;
  2771. } else if ( Flags == NULL || SaInterfaces == NULL ) {
  2772. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleInterfaces: Flags or Interfaces is NULL but Names isn't\n" ));
  2773. WinStatus = ERROR_INVALID_PARAMETER;
  2774. goto Cleanup;
  2775. }
  2776. //
  2777. // All must have the same upper and lower bounds
  2778. //
  2779. hr = SafeArrayGetLBound( Names, 1, &NamesLower );
  2780. if ( FAILED(hr)) {
  2781. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleInterfaces: Can't get name lbound 0x%lx\n", hr ));
  2782. WinStatus = ERROR_INVALID_PARAMETER;
  2783. goto Cleanup;
  2784. }
  2785. hr = SafeArrayGetLBound( Flags, 1, &FlagsLower );
  2786. if ( FAILED(hr)) {
  2787. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleInterfaces: Can't get value lbound 0x%lx\n", hr ));
  2788. WinStatus = ERROR_INVALID_PARAMETER;
  2789. goto Cleanup;
  2790. }
  2791. hr = SafeArrayGetLBound( SaInterfaces, 1, &InterfacesLower );
  2792. if ( FAILED(hr)) {
  2793. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleInterfaces: Can't get interfaces lbound 0x%lx\n", hr ));
  2794. WinStatus = ERROR_INVALID_PARAMETER;
  2795. goto Cleanup;
  2796. }
  2797. hr = SafeArrayGetUBound( Names, 1, &NamesUpper );
  2798. if ( FAILED(hr)) {
  2799. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleInterfaces: Can't get name ubound 0x%lx\n", hr ));
  2800. WinStatus = ERROR_INVALID_PARAMETER;
  2801. goto Cleanup;
  2802. }
  2803. hr = SafeArrayGetUBound( Flags, 1, &FlagsUpper );
  2804. if ( FAILED(hr)) {
  2805. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleInterfaces: Can't get value ubound 0x%lx\n", hr ));
  2806. WinStatus = ERROR_INVALID_PARAMETER;
  2807. goto Cleanup;
  2808. }
  2809. hr = SafeArrayGetUBound( SaInterfaces, 1, &InterfacesUpper );
  2810. if ( FAILED(hr)) {
  2811. AzPrint(( AZD_INVPARM, "AzpCaptureBizRuleInterfaces: Can't get interfaces ubound 0x%lx\n", hr ));
  2812. WinStatus = ERROR_INVALID_PARAMETER;
  2813. goto Cleanup;
  2814. }
  2815. if ( NamesLower != FlagsLower ||
  2816. NamesLower != InterfacesLower ||
  2817. NamesUpper != FlagsUpper ||
  2818. NamesUpper != InterfacesUpper ) {
  2819. AzPrint(( AZD_INVPARM,
  2820. "AzpCaptureBizRuleInterfaces: Array bounds don't match %ld %ld %ld %ld %ld %ld\n",
  2821. NamesLower, FlagsLower, InterfacesLower,
  2822. NamesUpper, FlagsUpper, InterfacesUpper ));
  2823. WinStatus = ERROR_INVALID_PARAMETER;
  2824. goto Cleanup;
  2825. }
  2826. //
  2827. // Remember the data
  2828. //
  2829. AcContext->InterfaceNames = Names;
  2830. AcContext->InterfaceFlags = Flags;
  2831. AcContext->Interfaces = SaInterfaces;
  2832. AcContext->InterfaceLower = NamesLower;
  2833. AcContext->InterfaceUpper = NamesUpper;
  2834. WinStatus = NO_ERROR;
  2835. Cleanup:;
  2836. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  2837. WinStatus = RtlNtStatusToDosError( GetExceptionCode());
  2838. }
  2839. //
  2840. // Validate the parameters
  2841. //
  2842. return WinStatus;
  2843. }
  2844. typedef enum {
  2845. WeedOutFinishedOps,
  2846. SetResultStatus
  2847. } OPS_AND_TASKS_OPCODE;
  2848. DWORD
  2849. AzpWalkOpsAndTasks(
  2850. IN PACCESS_CHECK_CONTEXT AcContext,
  2851. IN PAZP_STRING Name,
  2852. IN PAZ_OPS_AND_TASKS OpsAndTasks,
  2853. IN OPS_AND_TASKS_OPCODE Opcode,
  2854. IN DWORD ResultStatus,
  2855. IN BOOLEAN BizrulesOk,
  2856. OUT PBOOLEAN CallAgain
  2857. )
  2858. /*++
  2859. Routine Description:
  2860. This routine walks the OpsAndTasks tree built by AzpWalkTaskTree performing the function
  2861. specified by Opcode.
  2862. On entry, AcContext->ClientContext.CritSect must be locked.
  2863. On entry, AzGlResource must be locked Shared.
  2864. *** Note: this routine will temporarily drop AzGlResource in cases where it hits the wire
  2865. Arguments:
  2866. AcContext - Specifies the context of the user to check group membership of.
  2867. Name - Name of the object containing OpsAndTasks.
  2868. OpsAndTasks - Specifies the set of operations and tasks for a particular role or task.
  2869. Opcode - Specifies the operation to perform.
  2870. WeedOutFinishedOps: update OpsAndTasks to remove operations that are already finished
  2871. and return CallAgain if there are any operations left.
  2872. SetResultStatus: Set ResultStatus on all operations that haven't yet been processed
  2873. ResultStatus - Specifies the ResultStatus to be set for the SetResultStatus opcode.
  2874. BizrulesOk - Specifies TRUE if it is OK to process Bizrules.
  2875. If FALSE, only Ops and Tasks without bizrules are processed.
  2876. This boolean is ignored for the WeedOutFinishedOps opcode.
  2877. CallAgain - Set to TRUE if the caller should call again for this OpsAndTasks.
  2878. FALSE if the OpsAndTasks should never be processed again.
  2879. Return Value:
  2880. NO_ERROR - The function was successful
  2881. --*/
  2882. {
  2883. DWORD WinStatus;
  2884. ULONG i;
  2885. ULONG OpIndex;
  2886. //
  2887. // Initialization
  2888. //
  2889. UNREFERENCED_PARAMETER( Name ); // Not referenced on a free build
  2890. ASSERT( AzpIsLockedShared( &AzGlResource ) );
  2891. ASSERT( AzpIsCritsectLocked( &AcContext->ClientContext->CritSect ) );
  2892. *CallAgain = FALSE;
  2893. //
  2894. // Loop through the list of operations seeing if they're still applicable.
  2895. //
  2896. for ( i = 0; i < OpsAndTasks->OpCount; ) {
  2897. ASSERT( i < AcContext->OperationCount );
  2898. //
  2899. // If all operations have now been processed,
  2900. // we're done.
  2901. //
  2902. if ( AcContext->ProcessedOperationCount == AcContext->OperationCount ) {
  2903. AzPrint(( AZD_ACCESS_MORE,
  2904. "AzpWalkOpsAndTasks: %ws: %ws: All operations have been processed %ld.\n",
  2905. AcContext->ObjectNameString.String,
  2906. AcContext->ScopeNameString.String ? AcContext->ScopeNameString.String : L"",
  2907. AcContext->OperationCount ));
  2908. break;
  2909. }
  2910. //
  2911. // If the operation result is already known,
  2912. // ditch it from this list.
  2913. //
  2914. OpIndex = OpsAndTasks->OpIndexes[i];
  2915. if ( AcContext->OperationWasProcessed[OpIndex] ) {
  2916. PopUlong( OpsAndTasks->OpIndexes, i, OpsAndTasks->OpCount );
  2917. //
  2918. // If the operation still needs to be processed,
  2919. // note the fact and move on
  2920. //
  2921. } else {
  2922. //
  2923. // Update the Results array
  2924. //
  2925. if ( Opcode == SetResultStatus ) {
  2926. //
  2927. // If permission is now granted to the operation,
  2928. // mark it so.
  2929. //
  2930. if ( ResultStatus == NO_ERROR ) {
  2931. AzPrint(( AZD_ACCESS_MORE,
  2932. "AzpWalkOpsAndTasks: %ws: %ws: %ws: Operation granted\n",
  2933. AcContext->ObjectNameString.String,
  2934. Name->String,
  2935. AcContext->OperationObjects[OpIndex]->GenericObject.ObjectName->ObjectName.String ));
  2936. AcContext->Results[OpIndex] = NO_ERROR;
  2937. AcContext->OperationWasProcessed[OpIndex] = TRUE;
  2938. AcContext->ProcessedOperationCount++;
  2939. //
  2940. // If we don't already know that result,
  2941. // update it.
  2942. //
  2943. // If the result is already ERROR_ACCESS_DENIED, any status other than NO_ERROR is
  2944. // less informative than the one we already have.
  2945. //
  2946. } else if ( AcContext->Results[OpIndex] != ERROR_ACCESS_DENIED ) {
  2947. AcContext->Results[OpIndex] = ResultStatus;
  2948. AzPrint(( AZD_ACCESS_MORE,
  2949. "AzpWalkOpsAndTasks: %ws: %ws: %ws: Operation extended failure %ld\n",
  2950. AcContext->ObjectNameString.String,
  2951. Name->String,
  2952. AcContext->OperationObjects[OpIndex]->GenericObject.ObjectName->ObjectName.String,
  2953. ResultStatus ));
  2954. }
  2955. }
  2956. //
  2957. // If the operation has now been granted access,
  2958. // ditch it from this list.
  2959. //
  2960. if ( AcContext->Results[OpIndex] == NO_ERROR ) {
  2961. PopUlong( OpsAndTasks->OpIndexes, i, OpsAndTasks->OpCount );
  2962. } else {
  2963. *CallAgain = TRUE;
  2964. i++;
  2965. }
  2966. }
  2967. }
  2968. //
  2969. // Loop through the list of tasks recursing
  2970. //
  2971. for ( i=0; i<OpsAndTasks->TaskCount; ) {
  2972. PAZ_TASK_INFO TaskInfo;
  2973. BOOLEAN LocalCallAgain;
  2974. //
  2975. // If the task has already been processed,
  2976. // ditch it from the list.
  2977. //
  2978. ASSERT( i < AcContext->TaskCount );
  2979. TaskInfo = &AcContext->TaskInfo[OpsAndTasks->TaskIndexes[i]];
  2980. if ( TaskInfo->TaskProcessed ) {
  2981. PopUlong( OpsAndTasks->TaskIndexes, i, OpsAndTasks->TaskCount );
  2982. //
  2983. // If the task still needs to be processed,
  2984. // do so now.
  2985. //
  2986. } else {
  2987. BOOLEAN WalkTree;
  2988. //
  2989. // If the task has a BizRule,
  2990. // process the BizRule
  2991. //
  2992. //
  2993. WalkTree = TRUE;
  2994. if ( TaskInfo->Task->BizRule.StringSize != 0 ) {
  2995. //
  2996. // If we're just weeding out operations
  2997. // don't process the BizRule and continue walking the tree
  2998. //
  2999. if ( Opcode == WeedOutFinishedOps ) {
  3000. WalkTree = TRUE;
  3001. //
  3002. // If we're setting ResultStatus,
  3003. // and we're not yet processing BizRules,
  3004. // we're done for now
  3005. //
  3006. } else if ( !BizrulesOk ) {
  3007. WalkTree = FALSE;
  3008. //
  3009. // If we're setting ResultStatus,
  3010. // and we're allowed to process the bizrule,
  3011. // do so now.
  3012. //
  3013. } else {
  3014. //
  3015. // If we haven't yet cached the result of the BizRule,
  3016. // process the BizRule now.
  3017. //
  3018. if ( !TaskInfo->BizRuleProcessed ) {
  3019. BOOL BizRuleResult = FALSE;
  3020. //
  3021. // If there exists a bizrule in a task under a delegated scope, we need to return
  3022. // an error back to the user telling them that the store is in an inconsistent state.
  3023. // Tasks under delegated scopes are not allowed to have any bizrules. If they do, then
  3024. // the store has either been compromised, or changed not using azroles.dll. The business
  3025. // rule then should be evaluated to a FALSE, and a reason returned to the user.
  3026. //
  3027. if ( (((PGENERIC_OBJECT)
  3028. (TaskInfo->Task))->ParentGenericObjectHead->ParentGenericObject)->ObjectType
  3029. == OBJECT_TYPE_SCOPE &&
  3030. (((PGENERIC_OBJECT)
  3031. (TaskInfo->Task))->ParentGenericObjectHead->ParentGenericObject)->PolicyAdmins.GenericObjects.UsedCount
  3032. != 0 ) {
  3033. WinStatus = ERROR_FILE_CORRUPT;
  3034. return WinStatus;
  3035. }
  3036. // Drop AzGlResource while going over the wire
  3037. AzpUnlockResource( &AzGlResource );
  3038. WinStatus = AzpProcessBizRule( AcContext, TaskInfo->Task, &BizRuleResult );
  3039. AzpLockResourceShared( &AzGlResource );
  3040. if ( WinStatus != NO_ERROR ) {
  3041. return WinStatus;
  3042. }
  3043. TaskInfo->BizRuleProcessed = TRUE;
  3044. TaskInfo->BizRuleResult = (BOOLEAN)BizRuleResult;
  3045. }
  3046. //
  3047. // If the BizRule granted access,
  3048. // walk the tree.
  3049. //
  3050. if ( TaskInfo->BizRuleResult ) {
  3051. WalkTree = TRUE;
  3052. //
  3053. // If the BizRule didn't grant access,
  3054. // don't walk the tree and never process this task again
  3055. //
  3056. } else {
  3057. WalkTree = FALSE;
  3058. TaskInfo->TaskProcessed = TRUE;
  3059. }
  3060. }
  3061. }
  3062. //
  3063. // If we need to recurse,
  3064. // do so now
  3065. //
  3066. if ( WalkTree ) {
  3067. //
  3068. // Process all of the operations and tasks for this task
  3069. //
  3070. WinStatus = AzpWalkOpsAndTasks( AcContext,
  3071. &TaskInfo->Task->GenericObject.ObjectName->ObjectName,
  3072. &TaskInfo->OpsAndTasks,
  3073. Opcode,
  3074. ResultStatus,
  3075. BizrulesOk,
  3076. &LocalCallAgain );
  3077. if ( WinStatus != NO_ERROR ) {
  3078. return WinStatus;
  3079. }
  3080. //
  3081. // If we're not to walk the tree again,
  3082. // mark it so.
  3083. //
  3084. if ( !LocalCallAgain ) {
  3085. TaskInfo->TaskProcessed = TRUE;
  3086. }
  3087. }
  3088. //
  3089. // If the task is now marked as processed,
  3090. // ditch it from the list.
  3091. //
  3092. if ( TaskInfo->TaskProcessed ) {
  3093. PopUlong( OpsAndTasks->TaskIndexes, i, OpsAndTasks->TaskCount );
  3094. //
  3095. // Otherwise process it again
  3096. //
  3097. } else {
  3098. *CallAgain = TRUE;
  3099. i++;
  3100. }
  3101. }
  3102. }
  3103. return NO_ERROR;
  3104. }
  3105. DWORD
  3106. WINAPI
  3107. AzInitializeContextFromToken(
  3108. IN AZ_HANDLE ApplicationHandle,
  3109. IN HANDLE TokenHandle OPTIONAL,
  3110. IN DWORD Reserved,
  3111. OUT PAZ_HANDLE ClientContextHandle
  3112. )
  3113. /*++
  3114. Routine Description:
  3115. This routine creates a client context based on a passed in token handle or on
  3116. the impersonation token of the caller's thread.
  3117. Arguments:
  3118. ApplicationHandle - Specifies a handle to the application object that
  3119. is this client context applies to.
  3120. TokenHandle - Handle to the NT token describing the cleint.
  3121. NULL implies the impersonation token of the caller's thread.
  3122. The token mast have been opened for TOKEN_QUERY, TOKEN_IMPERSONATION, and
  3123. TOKEN_DUPLICATE access.
  3124. Reserved - Reserved. Must by zero.
  3125. ClientContextHandle - Return a handle to the client context
  3126. The caller must close this handle by calling AzCloseHandle.
  3127. Return Value:
  3128. NO_ERROR - The operation was successful
  3129. ERROR_NOT_SUPPORTED - Function not supported in current store mode (ie, manage store)
  3130. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  3131. Other exception status codes
  3132. --*/
  3133. {
  3134. DWORD WinStatus;
  3135. LUID Identifier = {0};
  3136. PAZP_CLIENT_CONTEXT ClientContext = NULL;
  3137. HANDLE TempTokenHandle = INVALID_HANDLE_VALUE;
  3138. TOKEN_STATISTICS TokenStats = {0};
  3139. PAZP_AZSTORE AzAuthorizationStore = (PAZP_AZSTORE) ParentOfChild(
  3140. &((PAZP_APPLICATION)ApplicationHandle)->GenericObject );
  3141. DWORD Ignore;
  3142. DWORD dwDesiredAccess; // Desired access for DuplicateTokenEx
  3143. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; // Impersonation level for DuplicateTokenEx
  3144. //
  3145. // If the store is in manage mode only, then no runtime is allowed
  3146. // Return ERROR_NOT_SUPPORTED
  3147. //
  3148. if ( AzpOpenToManageStore(AzAuthorizationStore) ) {
  3149. WinStatus = ERROR_NOT_SUPPORTED;
  3150. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromToken: Cannot initialize context since store is in manage mode %ld\n",
  3151. WinStatus
  3152. ));
  3153. goto Cleanup;
  3154. }
  3155. //
  3156. // Call the common routine to create our client context object
  3157. //
  3158. WinStatus = ObCommonCreateObject(
  3159. (PGENERIC_OBJECT) ApplicationHandle,
  3160. OBJECT_TYPE_APPLICATION,
  3161. &(((PAZP_APPLICATION)ApplicationHandle)->ClientContexts),
  3162. OBJECT_TYPE_CLIENT_CONTEXT,
  3163. NULL,
  3164. Reserved,
  3165. (PGENERIC_OBJECT *) &ClientContext );
  3166. if ( WinStatus != NO_ERROR ) {
  3167. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromToken: Cannot ObCommonCreateObject %ld\n", WinStatus ));
  3168. goto Cleanup;
  3169. }
  3170. //
  3171. // Client context isn't persisted.
  3172. //
  3173. ASSERT( ClientContext->GenericObject.DirtyBits == 0);
  3174. //
  3175. // If the user didn't pass a handle in,
  3176. // open a thread or process token handle.
  3177. //
  3178. ClientContext->CreationType = AZP_CONTEXT_CREATED_FROM_TOKEN;
  3179. if ( TokenHandle == NULL ) {
  3180. if ( !OpenThreadToken( GetCurrentThread(),
  3181. TOKEN_QUERY | TOKEN_IMPERSONATE,
  3182. TRUE,
  3183. &ClientContext->TokenHandle ) ) {
  3184. WinStatus = GetLastError();
  3185. //
  3186. // If there is not thread token,
  3187. // use the process token.
  3188. //
  3189. if ( WinStatus == ERROR_NO_TOKEN ) {
  3190. if ( !OpenProcessToken( GetCurrentProcess(),
  3191. TOKEN_DUPLICATE,
  3192. &TempTokenHandle ) ) {
  3193. WinStatus = GetLastError();
  3194. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromToken: Cannot OpenProcessToken %ld\n", WinStatus ));
  3195. goto Cleanup;
  3196. }
  3197. //
  3198. // Need an impersonation token
  3199. //
  3200. if ( !DuplicateTokenEx( TempTokenHandle,
  3201. TOKEN_QUERY | TOKEN_IMPERSONATE,
  3202. NULL,
  3203. SecurityImpersonation,
  3204. TokenImpersonation,
  3205. &ClientContext->TokenHandle ) ) {
  3206. WinStatus = GetLastError();
  3207. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromToken: Cannot DuplicateTokenEx %ld\n", WinStatus ));
  3208. goto Cleanup;
  3209. }
  3210. } else {
  3211. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromToken: Cannot OpenThreadToken %ld\n", WinStatus ));
  3212. goto Cleanup;
  3213. }
  3214. }
  3215. //
  3216. // If the user did pass a handle in,
  3217. // dup it
  3218. //
  3219. } else {
  3220. if ( !GetTokenInformation( TokenHandle,
  3221. TokenStatistics,
  3222. &TokenStats,
  3223. sizeof(TOKEN_STATISTICS),
  3224. &Ignore ) ) {
  3225. WinStatus = GetLastError();
  3226. AzPrint(( AZD_ACCESS, "AzInitializeContextFromToken: GetTokenInformation failed with %ld\n", WinStatus ));
  3227. goto Cleanup;
  3228. }
  3229. dwDesiredAccess = TOKEN_QUERY | TOKEN_IMPERSONATE;
  3230. if ( TokenStats.ImpersonationLevel > SecurityIdentification ) {
  3231. ImpersonationLevel = SecurityImpersonation;
  3232. } else {
  3233. ImpersonationLevel = SecurityIdentification;
  3234. }
  3235. if ( !DuplicateTokenEx( TokenHandle,
  3236. dwDesiredAccess,
  3237. NULL,
  3238. ImpersonationLevel,
  3239. TokenImpersonation,
  3240. &ClientContext->TokenHandle ) ) {
  3241. WinStatus = GetLastError();
  3242. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromToken: Cannot DuplicateTokenEx %ld\n", WinStatus ));
  3243. goto Cleanup;
  3244. }
  3245. }
  3246. //
  3247. // Read the token authentication Id
  3248. //
  3249. if ( !GetTokenInformation( ClientContext->TokenHandle,
  3250. TokenStatistics,
  3251. &TokenStats,
  3252. sizeof(TOKEN_STATISTICS),
  3253. &Ignore ) ) {
  3254. WinStatus = GetLastError();
  3255. AzPrint(( AZD_ACCESS, "AzInitializeContextFromToken: GetTokenInformation failed with %ld\n", WinStatus ));
  3256. goto Cleanup;
  3257. }
  3258. ClientContext->LogonId = TokenStats.AuthenticationId;
  3259. //
  3260. // Initialize Authz
  3261. //
  3262. if ( !AuthzInitializeContextFromToken(
  3263. 0, // No Flags
  3264. ClientContext->TokenHandle,
  3265. (((PAZP_APPLICATION)ApplicationHandle)->AuthzResourceManager),
  3266. NULL, // No expiration time
  3267. Identifier,
  3268. NULL, // No dynamic group args
  3269. &ClientContext->AuthzClientContext ) ) {
  3270. WinStatus = GetLastError();
  3271. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromToken: Cannot AuthzInitializeContextFromToken %ld\n", WinStatus ));
  3272. goto Cleanup;
  3273. }
  3274. //
  3275. // Generate a client context creation audit based on the audit boolean.
  3276. //
  3277. if ( ((PAZP_APPLICATION) ApplicationHandle)->GenericObject.IsGeneratingAudits &&
  3278. !AzpOpenToManageStore(AzAuthorizationStore) ) {
  3279. WinStatus = AzpClientContextGenerateCreateSuccessAudit( ClientContext,
  3280. (PAZP_APPLICATION) ApplicationHandle );
  3281. if ( WinStatus != NO_ERROR ) {
  3282. AzPrint(( AZD_ACCESS, "AzpGenerateContextCreateAudit: Cannot ObCommonCreateObject %ld\n", WinStatus ));
  3283. goto Cleanup;
  3284. }
  3285. }
  3286. WinStatus = NO_ERROR;
  3287. *ClientContextHandle = ClientContext;
  3288. ClientContext = NULL;
  3289. //
  3290. // Free any local resources
  3291. //
  3292. Cleanup:
  3293. if ( ClientContext != NULL ) {
  3294. AzCloseHandle( ClientContext, 0 );
  3295. }
  3296. if ( TempTokenHandle != INVALID_HANDLE_VALUE ) {
  3297. CloseHandle( TempTokenHandle );
  3298. }
  3299. return WinStatus;
  3300. }
  3301. DWORD
  3302. AzpGetClientContextTokenS4U(
  3303. IN LPCWSTR ClientName,
  3304. IN LPCWSTR DomainName OPTIONAL,
  3305. OUT PHANDLE pTokenHandle
  3306. )
  3307. /*++
  3308. Routine Description:
  3309. This routine tries to get an identify-level token for the user
  3310. using KERB_S4U_LOGON authentication package.
  3311. Arguments:
  3312. ClientName - Name of the user
  3313. DomainName - An optional domain name for the user
  3314. pTokenHandle - Handle to the acquired identify-level token
  3315. Return Value:
  3316. NO_ERROR - The operation was successful
  3317. ERROR_NOT_ENOUGH_MEMORY - lack of memory resources
  3318. Other Status code returned from LsaLogonUser specific calls.
  3319. --*/
  3320. {
  3321. DWORD WinStatus = NO_ERROR;
  3322. NTSTATUS Status;
  3323. NTSTATUS subStatus;
  3324. HANDLE hLsa = INVALID_HANDLE_VALUE;
  3325. LSA_STRING asProcessName;
  3326. LSA_STRING asPackageName;
  3327. ULONG ulAuthPackage;
  3328. LUID luid;
  3329. DWORD ClientNameLength = 0;
  3330. DWORD DomainNameLength = 0;
  3331. PKERB_S4U_LOGON pPackage = NULL;
  3332. ULONG ulPackageSize = 0;
  3333. TOKEN_SOURCE sourceContext;
  3334. PVOID pProfileBuffer = NULL;
  3335. ULONG ulProfileLength = 0;
  3336. QUOTA_LIMITS quota;
  3337. //
  3338. // Validation
  3339. //
  3340. ASSERT( ClientName != NULL );
  3341. ClientNameLength = (DWORD)(wcslen( ClientName )*sizeof(WCHAR));
  3342. //
  3343. // Setup the Authentication package
  3344. //
  3345. ulPackageSize = sizeof( KERB_S4U_LOGON );
  3346. ulPackageSize += ClientNameLength;
  3347. if ( DomainName ) {
  3348. DomainNameLength = (DWORD)(wcslen( DomainName )*sizeof(WCHAR));
  3349. ulPackageSize += DomainNameLength;
  3350. }
  3351. pPackage = (PKERB_S4U_LOGON) LocalAlloc(LMEM_FIXED, ulPackageSize);
  3352. if ( pPackage == NULL ) {
  3353. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  3354. goto Cleanup;
  3355. }
  3356. pPackage->MessageType = KerbS4ULogon;
  3357. pPackage->Flags = 0;
  3358. pPackage->ClientUpn.Length = (USHORT)ClientNameLength;
  3359. pPackage->ClientUpn.MaximumLength = (USHORT)ClientNameLength;
  3360. pPackage->ClientUpn.Buffer = (LPWSTR)(pPackage + 1);
  3361. RtlCopyMemory(
  3362. pPackage->ClientUpn.Buffer,
  3363. ClientName,
  3364. ClientNameLength
  3365. );
  3366. if ( DomainName ) {
  3367. pPackage->ClientRealm.Length = (USHORT)DomainNameLength;
  3368. pPackage->ClientRealm.MaximumLength = (USHORT)DomainNameLength;
  3369. pPackage->ClientRealm.Buffer = (LPWSTR)
  3370. (((PBYTE)(pPackage->ClientUpn.Buffer)) + pPackage->ClientUpn.Length);
  3371. RtlCopyMemory(
  3372. pPackage->ClientRealm.Buffer,
  3373. DomainName,
  3374. DomainNameLength
  3375. );
  3376. } else {
  3377. pPackage->ClientRealm.Length = 0;
  3378. pPackage->ClientRealm.MaximumLength = 0;
  3379. pPackage->ClientRealm.Buffer = NULL;
  3380. }
  3381. //
  3382. // Initialize process name
  3383. //
  3384. RtlInitString(
  3385. &asProcessName,
  3386. "AzManAPI"
  3387. );
  3388. //
  3389. // Register with Lsa
  3390. //
  3391. Status = LsaConnectUntrusted(
  3392. &hLsa
  3393. );
  3394. if ( !NT_SUCCESS( Status ) ) {
  3395. WinStatus = LsaNtStatusToWinError( Status );
  3396. goto Cleanup;
  3397. }
  3398. //
  3399. // Get the Autherntication package
  3400. //
  3401. RtlInitString( &asPackageName, MICROSOFT_KERBEROS_NAME_A );
  3402. Status = LsaLookupAuthenticationPackage(
  3403. hLsa,
  3404. &asPackageName,
  3405. &ulAuthPackage
  3406. );
  3407. if ( !NT_SUCCESS( Status ) ) {
  3408. WinStatus = LsaNtStatusToWinError( Status );
  3409. goto Cleanup;
  3410. }
  3411. //
  3412. // Prepare the source context
  3413. //
  3414. RtlCopyMemory(
  3415. sourceContext.SourceName,
  3416. "AzRoles ",
  3417. sizeof(sourceContext.SourceName)
  3418. );
  3419. Status = NtAllocateLocallyUniqueId(
  3420. &sourceContext.SourceIdentifier
  3421. );
  3422. if ( !NT_SUCCESS( Status ) ) {
  3423. WinStatus = RtlNtStatusToDosError( Status );
  3424. goto Cleanup;
  3425. }
  3426. //
  3427. // Now that everything is set up, do the actual logon
  3428. //
  3429. Status = LsaLogonUser(
  3430. hLsa,
  3431. &asPackageName,
  3432. Network,
  3433. ulAuthPackage,
  3434. pPackage,
  3435. ulPackageSize,
  3436. 0,
  3437. &sourceContext,
  3438. &pProfileBuffer,
  3439. &ulProfileLength,
  3440. &luid,
  3441. pTokenHandle,
  3442. &quota,
  3443. &subStatus
  3444. );
  3445. if ( !NT_SUCCESS( Status ) ) {
  3446. WinStatus = LsaNtStatusToWinError( Status );
  3447. goto Cleanup;
  3448. }
  3449. WinStatus = NO_ERROR;
  3450. Cleanup:
  3451. if ( pPackage ) {
  3452. LocalFree( pPackage );
  3453. }
  3454. if ( pProfileBuffer ) {
  3455. LsaFreeReturnBuffer( pProfileBuffer );
  3456. }
  3457. if ( hLsa != INVALID_HANDLE_VALUE ) {
  3458. LsaDeregisterLogonProcess( hLsa );
  3459. }
  3460. return WinStatus;
  3461. }
  3462. DWORD
  3463. WINAPI
  3464. AzInitializeContextFromName(
  3465. IN AZ_HANDLE ApplicationHandle,
  3466. IN LPWSTR DomainName OPTIONAL,
  3467. IN LPWSTR ClientName,
  3468. IN DWORD Reserved,
  3469. OUT PAZ_HANDLE ClientContextHandle
  3470. )
  3471. /*++
  3472. Routine Description:
  3473. This routine creates a client context based on a passed in token handle or on
  3474. the impersonation token of the caller's thread.
  3475. Arguments:
  3476. ApplicationHandle - Specifies a handle to the application object that
  3477. is this client context applies to.
  3478. DomainName - Domain in which the user account lives. This may be NULL.
  3479. ClientName - Name of the user account. Together these two represent a user
  3480. account which may be looked up using LookupAccountName.
  3481. Reserved - Reserved. Must by zero.
  3482. ClientContextHandle - Return a handle to the client context
  3483. The caller must close this handle by calling AzCloseHandle.
  3484. Return Value:
  3485. NO_ERROR - The operation was successful
  3486. ERROR_NOT_SUPPORTED - Function not supported in current store mode (ie, manage store)
  3487. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  3488. Other exception status codes
  3489. --*/
  3490. {
  3491. DWORD WinStatus;
  3492. LUID Identifier = {0};
  3493. PAZP_CLIENT_CONTEXT ClientContext = NULL;
  3494. DWORD SidSize = SECURITY_MAX_SID_SIZE;
  3495. PWCHAR LocalDomainBuffer[MAX_COMPUTERNAME_LENGTH+1];
  3496. DWORD DomainSize = MAX_COMPUTERNAME_LENGTH;
  3497. SID_NAME_USE SidType = SidTypeUnknown;
  3498. DWORD ClientNameSize = 0;
  3499. DWORD DomainNameSize = 0;
  3500. PAZP_AZSTORE AzAuthorizationStore = (PAZP_AZSTORE) ParentOfChild(
  3501. &((PAZP_APPLICATION)ApplicationHandle)->GenericObject );
  3502. NTSTATUS Status;
  3503. DWORD Ignore = 0;
  3504. PWCHAR pSamCompatName = NULL;
  3505. DWORD SamCompatNameSize = 0;
  3506. HANDLE hToken = INVALID_HANDLE_VALUE;
  3507. //
  3508. // If the store is in manage mode only, then no runtime is allowed
  3509. // Return ERROR_NOT_SUPPORTED
  3510. //
  3511. if ( AzpOpenToManageStore(AzAuthorizationStore) ) {
  3512. WinStatus = ERROR_NOT_SUPPORTED;
  3513. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromName: Cannot initialize context since store is in manage mode %ld\n",
  3514. WinStatus
  3515. ));
  3516. goto Cleanup;
  3517. }
  3518. //
  3519. // Try to logon user using KERB_S4U_LOGON. This will give
  3520. // us an identify-level token for the user. Use this to
  3521. // create the client context from token. If S4U is not supported
  3522. // then use LookupAccountName/SID to intialize Authz using the SID
  3523. //
  3524. WinStatus = AzpGetClientContextTokenS4U(
  3525. ClientName,
  3526. ((DomainName == NULL)? NULL:((wcslen(DomainName) == 0)?NULL:DomainName)),
  3527. &hToken
  3528. );
  3529. if ( WinStatus == NO_ERROR ) {
  3530. WinStatus = AzInitializeContextFromToken(
  3531. ApplicationHandle,
  3532. hToken,
  3533. Ignore,
  3534. ClientContextHandle
  3535. );
  3536. if ( WinStatus != NO_ERROR ) {
  3537. AzPrint(( AZD_CRITICAL,
  3538. "AzInitializeContextFromName: Cannot AzInitializeFromToken %ld\n",
  3539. WinStatus
  3540. ));
  3541. goto Cleanup;
  3542. }
  3543. return WinStatus;
  3544. }
  3545. //
  3546. // Call the common routine to create our client context object
  3547. //
  3548. WinStatus = ObCommonCreateObject(
  3549. (PGENERIC_OBJECT) ApplicationHandle,
  3550. OBJECT_TYPE_APPLICATION,
  3551. &(((PAZP_APPLICATION)ApplicationHandle)->ClientContexts),
  3552. OBJECT_TYPE_CLIENT_CONTEXT,
  3553. NULL,
  3554. Reserved,
  3555. (PGENERIC_OBJECT *) &ClientContext );
  3556. if ( WinStatus != NO_ERROR ) {
  3557. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromName: Cannot ObCommonCreateObject %ld\n", WinStatus ));
  3558. goto Cleanup;
  3559. }
  3560. //
  3561. // Client context isn't persisted.
  3562. //
  3563. ASSERT( ClientContext->GenericObject.DirtyBits == 0);
  3564. ClientContext->CreationType = AZP_CONTEXT_CREATED_FROM_NAME;
  3565. //
  3566. // Allocate a LUID to represent out client. We need this for linking
  3567. // audits.
  3568. //
  3569. Status = NtAllocateLocallyUniqueId(&ClientContext->LogonId);
  3570. if ( !NT_SUCCESS( Status )) {
  3571. WinStatus = RtlNtStatusToDosError( Status );
  3572. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromName: Cannot allocate LUID %ld\n", WinStatus ));
  3573. goto Cleanup;
  3574. }
  3575. //
  3576. // If passed in name is not in UPN (detected by presence of "@") or SamCompat (detected by
  3577. // presence of "\") format, then we need to append it to the passed in domain name.
  3578. //
  3579. if ( ((DomainName != NULL) && (*DomainName != NULL)) &&
  3580. ((wcschr( ClientName, L'@' ) == NULL) && (wcschr( ClientName, L'\\' ) == NULL))
  3581. ) {
  3582. SamCompatNameSize = (DWORD)((wcslen(DomainName) + wcslen(ClientName) + 2) * sizeof(WCHAR));
  3583. pSamCompatName = (PWCHAR) AzpAllocateHeap( SamCompatNameSize, "TCLNTNAM" );
  3584. if ( pSamCompatName == NULL ) {
  3585. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  3586. goto Cleanup;
  3587. }
  3588. wnsprintf( pSamCompatName, SamCompatNameSize, L"%ws\\%ws", DomainName, ClientName );
  3589. }
  3590. //
  3591. // Lookup the name of client name.
  3592. //
  3593. if ( !LookupAccountNameW(
  3594. NULL,
  3595. pSamCompatName?pSamCompatName:ClientName,
  3596. ClientContext->SidBuffer,
  3597. &SidSize,
  3598. (LPWSTR) LocalDomainBuffer,
  3599. &DomainSize,
  3600. &SidType ) ) {
  3601. WinStatus = GetLastError();
  3602. ASSERT( WinStatus != ERROR_INSUFFICIENT_BUFFER );
  3603. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromName: LookupAccoutName failed with %ld\n", WinStatus ));
  3604. }
  3605. //
  3606. // We only support SidTypeUser account type.
  3607. //
  3608. if ( SidType != SidTypeUser ) {
  3609. WinStatus = ERROR_INVALID_PARAMETER;
  3610. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromName: Invalid user type - expected SIdTypeUser, got %ld\n", SidType ));
  3611. goto Cleanup;
  3612. }
  3613. //
  3614. // Do the reverse lookup and store the domain name and the client name.
  3615. // We have to do this since the domain name is optional.
  3616. // Get the size of the buffer in the first call.
  3617. //
  3618. if ( !LookupAccountSidW(
  3619. NULL,
  3620. ClientContext->SidBuffer,
  3621. NULL,
  3622. &ClientNameSize,
  3623. NULL,
  3624. &DomainNameSize,
  3625. &SidType ) ) {
  3626. WinStatus = GetLastError();
  3627. if ( WinStatus != ERROR_INSUFFICIENT_BUFFER ) {
  3628. goto Cleanup;
  3629. }
  3630. //
  3631. // Note that these get freed when then client context is released - even in
  3632. // error cases in this routine itself.
  3633. //
  3634. //
  3635. // Since LookupAccountSid returns size in characters and not bytes...
  3636. //
  3637. DomainNameSize *= sizeof( WCHAR );
  3638. ClientNameSize *= sizeof( WCHAR );
  3639. ClientContext->DomainName = (LPWSTR) AzpAllocateHeap( DomainNameSize, "CNDOMNM" );
  3640. if ( ClientContext->DomainName == NULL ) {
  3641. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  3642. goto Cleanup;
  3643. }
  3644. ClientContext->ClientName = (LPWSTR) AzpAllocateHeap( ClientNameSize, "CNCLNTNM" );
  3645. if ( ClientContext->ClientName == NULL ) {
  3646. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  3647. goto Cleanup;
  3648. }
  3649. if ( !LookupAccountSidW(
  3650. NULL,
  3651. ClientContext->SidBuffer,
  3652. ClientContext->ClientName,
  3653. &ClientNameSize,
  3654. ClientContext->DomainName,
  3655. &DomainNameSize,
  3656. &SidType ) ) {
  3657. WinStatus = GetLastError();
  3658. goto Cleanup;
  3659. }
  3660. } else {
  3661. //
  3662. // This can not happen since we supplied a NULL buffer.
  3663. //
  3664. ASSERT( FALSE );
  3665. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  3666. goto Cleanup;
  3667. }
  3668. //
  3669. // Initialize Authz
  3670. //
  3671. if ( !AuthzInitializeContextFromSid(
  3672. 0, // No Flags
  3673. ClientContext->SidBuffer,
  3674. (((PAZP_APPLICATION)ApplicationHandle)->AuthzResourceManager),
  3675. NULL, // No expiration time
  3676. Identifier,
  3677. NULL, // No dynamic group args
  3678. &ClientContext->AuthzClientContext ) ) {
  3679. WinStatus = GetLastError();
  3680. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromToken: Cannot AuthzInitializeContextFromToken %ld\n", WinStatus ));
  3681. goto Cleanup;
  3682. }
  3683. //
  3684. // Generate a client context creation audit based on the audit boolean.
  3685. //
  3686. if ( ((PAZP_APPLICATION) ApplicationHandle)->GenericObject.IsGeneratingAudits &&
  3687. !AzpOpenToManageStore(AzAuthorizationStore) ) {
  3688. WinStatus = AzpClientContextGenerateCreateSuccessAudit( ClientContext,
  3689. (PAZP_APPLICATION) ApplicationHandle );
  3690. if ( WinStatus != NO_ERROR ) {
  3691. AzPrint(( AZD_ACCESS, "AzpGenerateContextCreateAudit: Cannot ObCommonCreateObject %ld\n", WinStatus ));
  3692. goto Cleanup;
  3693. }
  3694. }
  3695. WinStatus = NO_ERROR;
  3696. *ClientContextHandle = ClientContext;
  3697. ClientContext = NULL;
  3698. //
  3699. // Free any local resources
  3700. //
  3701. Cleanup:
  3702. if ( pSamCompatName != NULL ) {
  3703. AzpFreeHeap( pSamCompatName ) ;
  3704. }
  3705. if ( hToken != INVALID_HANDLE_VALUE ) {
  3706. CloseHandle( hToken );
  3707. }
  3708. if ( ClientContext != NULL ) {
  3709. AzCloseHandle( ClientContext, 0 );
  3710. }
  3711. return WinStatus;
  3712. }
  3713. DWORD
  3714. WINAPI
  3715. AzInitializeContextFromStringSid(
  3716. IN AZ_HANDLE ApplicationHandle,
  3717. IN LPCWSTR SidString,
  3718. IN DWORD lOptions,
  3719. OUT PAZ_HANDLE ClientContextHandle
  3720. )
  3721. /*++
  3722. Routine Description:
  3723. This routine creates a client context based on a passed in SID string.
  3724. Note, the sid string can be any arbitary SID and the lOptions will indicate
  3725. if Lldap group should be skipped (for the arbitary SID)
  3726. if AZ_CLIENT_CONTEXT_SKIP_GROUP is true, we will skip the ldap group check
  3727. even if this is a valid NT user sid.
  3728. if AZ_CLIENT_CONTEXT_SKIP_GROUP is false, we will require the SID string is
  3729. a valid NT user sid (LookupSid must be able to find the domain name and
  3730. client name).
  3731. Arguments:
  3732. ApplicationHandle - Specifies a handle to the application object that
  3733. is this client context applies to.
  3734. SidString - Sid string of the account.
  3735. lOptions - options for the method
  3736. AZ_CLIENT_CONTEXT_SKIP_GROUP
  3737. ClientContextHandle - Return a handle to the client context
  3738. The caller must close this handle by calling AzCloseHandle.
  3739. Return Value:
  3740. NO_ERROR - The operation was successful
  3741. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  3742. Other exception status codes
  3743. --*/
  3744. {
  3745. DWORD WinStatus;
  3746. LUID Identifier = {0};
  3747. PAZP_CLIENT_CONTEXT ClientContext = NULL;
  3748. PSID pAccountSid = NULL;
  3749. NTSTATUS Status;
  3750. LPWSTR DomainName = NULL;
  3751. LPWSTR ClientName = NULL;
  3752. DWORD DomainNameSize = 0;
  3753. DWORD ClientNameSize = 0;
  3754. SID_NAME_USE SidType = SidTypeUnknown;
  3755. PAZP_AZSTORE AzAuthorizationStore = (PAZP_AZSTORE) ParentOfChild(
  3756. &((PAZP_APPLICATION)ApplicationHandle)->GenericObject );
  3757. //
  3758. // check parameter
  3759. //
  3760. if ( SidString == NULL ) {
  3761. return ERROR_INVALID_PARAMETER;
  3762. }
  3763. //
  3764. // If the store is in manage mode only, then no runtime is allowed
  3765. // Return ERROR_NOT_SUPPORTED
  3766. //
  3767. if ( AzpOpenToManageStore(AzAuthorizationStore) ) {
  3768. WinStatus = ERROR_NOT_SUPPORTED;
  3769. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromStringSid: Cannot initialize context since store is in manage mode %ld\n",
  3770. WinStatus
  3771. ));
  3772. goto Cleanup;
  3773. }
  3774. //
  3775. // Lookup the SID (binary) of the SID string.
  3776. //
  3777. if ( !ConvertStringSidToSidW(
  3778. SidString,
  3779. &pAccountSid) ) {
  3780. WinStatus = GetLastError();
  3781. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromStringSid: ConvertSidStringToSid failed with %ld\n", WinStatus ));
  3782. goto Cleanup;
  3783. }
  3784. //
  3785. // if flag AZ_CLIENT_CONTEXT_SKIP_GROUP is not set
  3786. // we assume this ia a valid NT user account
  3787. // check if the SID is a valid NT account
  3788. //
  3789. if ( !(lOptions & AZ_CLIENT_CONTEXT_SKIP_GROUP) ) {
  3790. if ( !LookupAccountSidW(
  3791. NULL,
  3792. pAccountSid,
  3793. NULL,
  3794. &ClientNameSize,
  3795. NULL,
  3796. &DomainNameSize,
  3797. &SidType ) ) {
  3798. //
  3799. // should get ERROR_INSUFFICIENT_BUFFER if the account is resolved
  3800. //
  3801. WinStatus = GetLastError();
  3802. if ( WinStatus != ERROR_INSUFFICIENT_BUFFER ) {
  3803. //
  3804. // the SID string cannot be resolved
  3805. //
  3806. goto Cleanup;
  3807. }
  3808. //
  3809. // Since LookupAccountSid returns size in characters and not bytes...
  3810. //
  3811. DomainNameSize *= sizeof( WCHAR );
  3812. ClientNameSize *= sizeof( WCHAR );
  3813. DomainName = (LPWSTR) AzpAllocateHeap( DomainNameSize, "CNDOMNM" );
  3814. if ( DomainName == NULL ) {
  3815. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  3816. goto Cleanup;
  3817. }
  3818. ClientName = (LPWSTR) AzpAllocateHeap( ClientNameSize, "CNCLNTNM" );
  3819. if ( ClientName == NULL ) {
  3820. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  3821. goto Cleanup;
  3822. }
  3823. if ( !LookupAccountSidW(
  3824. NULL,
  3825. pAccountSid,
  3826. ClientName,
  3827. &ClientNameSize,
  3828. DomainName,
  3829. &DomainNameSize,
  3830. &SidType ) ) {
  3831. WinStatus = GetLastError();
  3832. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromStringSid: LookupAccountSid failed with %ld\n", WinStatus ));
  3833. goto Cleanup;
  3834. }
  3835. //
  3836. // We only support SidTypeUser account type.
  3837. //
  3838. if ( SidType != SidTypeUser ) {
  3839. WinStatus = ERROR_INVALID_PARAMETER;
  3840. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromStringSid: Invalid user type - expected SIdTypeUser, got %ld\n", SidType ));
  3841. goto Cleanup;
  3842. }
  3843. } else {
  3844. //
  3845. // This can not happen since we supplied a NULL buffer.
  3846. //
  3847. ASSERT( FALSE );
  3848. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  3849. goto Cleanup;
  3850. }
  3851. //
  3852. // hand the call to InitializeContextFromName
  3853. //
  3854. WinStatus = AzInitializeContextFromName(
  3855. ApplicationHandle,
  3856. DomainName,
  3857. ClientName,
  3858. 0,
  3859. ClientContextHandle
  3860. );
  3861. //
  3862. // the client context is handled by FromName
  3863. // we are done now so go to clean up
  3864. //
  3865. goto Cleanup;
  3866. }
  3867. //
  3868. // when it's get here, the client context will be initialzied from SID
  3869. // and ldap group check will be skipped later on during access check
  3870. //
  3871. // Call the common routine to create our client context object
  3872. //
  3873. WinStatus = ObCommonCreateObject(
  3874. (PGENERIC_OBJECT) ApplicationHandle,
  3875. OBJECT_TYPE_APPLICATION,
  3876. &(((PAZP_APPLICATION)ApplicationHandle)->ClientContexts),
  3877. OBJECT_TYPE_CLIENT_CONTEXT,
  3878. NULL,
  3879. 0,
  3880. (PGENERIC_OBJECT *) &ClientContext );
  3881. if ( WinStatus != NO_ERROR ) {
  3882. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromStringSid: Cannot ObCommonCreateObject %ld\n", WinStatus ));
  3883. goto Cleanup;
  3884. }
  3885. //
  3886. // Client context isn't persisted.
  3887. //
  3888. ASSERT( ClientContext->GenericObject.DirtyBits == 0);
  3889. //
  3890. // Allocate a LUID to represent out client. We need this for linking
  3891. // audits.
  3892. //
  3893. Status = NtAllocateLocallyUniqueId(&ClientContext->LogonId);
  3894. if ( !NT_SUCCESS( Status )) {
  3895. WinStatus = RtlNtStatusToDosError( Status );
  3896. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromStringSid: Cannot allocate LUID %ld\n", WinStatus ));
  3897. goto Cleanup;
  3898. }
  3899. ClientContext->CreationType = AZP_CONTEXT_CREATED_FROM_SID;
  3900. //
  3901. // copy the SID to sid buffer
  3902. //
  3903. if ( !CopySid (
  3904. SECURITY_MAX_SID_SIZE,
  3905. (PSID)(ClientContext->SidBuffer),
  3906. pAccountSid
  3907. ) ) {
  3908. WinStatus = GetLastError();
  3909. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromStringSid: CopySid failed with %ld\n", WinStatus ));
  3910. goto Cleanup;
  3911. }
  3912. //
  3913. // save the SID string in the client name buffer (for auditing purpose)
  3914. //
  3915. ClientNameSize = (DWORD)wcslen(SidString);
  3916. ClientContext->ClientName = (LPWSTR) AzpAllocateHeap( (ClientNameSize+1)*sizeof(WCHAR), "CNCLNTNM" );
  3917. if ( ClientContext->ClientName == NULL ) {
  3918. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  3919. goto Cleanup;
  3920. }
  3921. wcsncpy(ClientContext->ClientName, SidString, ClientNameSize);
  3922. ClientContext->ClientName[ClientNameSize] = L'\0';
  3923. //
  3924. // Initialize Authz
  3925. //
  3926. if ( !AuthzInitializeContextFromSid(
  3927. AUTHZ_SKIP_TOKEN_GROUPS,
  3928. ClientContext->SidBuffer,
  3929. (((PAZP_APPLICATION)ApplicationHandle)->AuthzResourceManager),
  3930. NULL, // No expiration time
  3931. Identifier,
  3932. NULL, // No dynamic group args
  3933. &ClientContext->AuthzClientContext ) ) {
  3934. WinStatus = GetLastError();
  3935. AzPrint(( AZD_CRITICAL, "AzInitializeContextFromToken: Cannot AuthzInitializeContextFromToken %ld\n", WinStatus ));
  3936. goto Cleanup;
  3937. }
  3938. //
  3939. // Generate a client context creation audit based on the audit boolean.
  3940. //
  3941. if ( ((PAZP_APPLICATION) ApplicationHandle)->GenericObject.IsGeneratingAudits ) {
  3942. WinStatus = AzpClientContextGenerateCreateSuccessAudit( ClientContext,
  3943. (PAZP_APPLICATION) ApplicationHandle );
  3944. if ( WinStatus != NO_ERROR ) {
  3945. AzPrint(( AZD_ACCESS, "AzpGenerateContextCreateAudit: Cannot ObCommonCreateObject %ld\n", WinStatus ));
  3946. goto Cleanup;
  3947. }
  3948. }
  3949. WinStatus = NO_ERROR;
  3950. *ClientContextHandle = ClientContext;
  3951. ClientContext = NULL;
  3952. //
  3953. // Free any local resources
  3954. //
  3955. Cleanup:
  3956. if ( ClientContext != NULL ) {
  3957. AzCloseHandle( ClientContext, 0 );
  3958. }
  3959. if ( pAccountSid ) {
  3960. LocalFree(pAccountSid);
  3961. }
  3962. if ( DomainName ) {
  3963. AzpFreeHeap( DomainName );
  3964. }
  3965. if ( ClientName ) {
  3966. AzpFreeHeap( ClientName );
  3967. }
  3968. return WinStatus;
  3969. }
  3970. DWORD
  3971. WINAPI
  3972. AzContextAccessCheck(
  3973. IN AZ_HANDLE ApplicationObjectHandle,
  3974. IN DWORD ApplicationSequenceNumber,
  3975. IN AZ_HANDLE ClientContextHandle,
  3976. IN LPCWSTR ObjectName,
  3977. IN ULONG ScopeCount,
  3978. IN LPCWSTR * ScopeNames OPTIONAL,
  3979. IN ULONG OperationCount,
  3980. IN PLONG Operations,
  3981. OUT ULONG *Results,
  3982. OUT LPWSTR *BusinessRuleString OPTIONAL,
  3983. IN VARIANT *ParameterNames OPTIONAL,
  3984. IN VARIANT *ParameterValues OPTIONAL,
  3985. IN VARIANT *InterfaceNames OPTIONAL,
  3986. IN VARIANT *InterfaceFlags OPTIONAL,
  3987. IN VARIANT *Interfaces OPTIONAL
  3988. )
  3989. /*++
  3990. Routine Description:
  3991. The application calls the AccessCheck function whenever it wants to check if a
  3992. particular operation is allowed to the client.
  3993. The specified Operation may require application group membership to be evaluated.
  3994. The application group membership is added to the client context so that it need not
  3995. be evaluated again on subsequent AccessCheck calls on this same client context.
  3996. The AccessCheck method may not be called by a BizRule.
  3997. The AccessCheck function does not directly support the concept of "maximum allowed".
  3998. If the script engine timeout is set to 0, then biz rules evaluated as returning FALSE.
  3999. Arguments:
  4000. ApplicationObjectHandle - Handle to the parent application object of the client context object
  4001. ApplicationSequenceNumber - Sequence number on the parent application object
  4002. ClientContextHandle - Specifies a handle to the client context object indentifying
  4003. the client.
  4004. ObjectName - Specifies the object being accessed. (Meant for auditing purposes)
  4005. ScopeCount - Specifies the number of elements in the ScopeNames array.
  4006. Some application do not create scopes, and treat al objects as if in the
  4007. first scope. 0 is passed in if there are no scopes defined
  4008. ScopeNames - Specifies an optional list of scope names. Must be
  4009. NULL if ScopeCount is 0. ERROR_INVALID_PARAMETER is returned otherwise.
  4010. OperationCount - Specifies the number of elements in the Operations array.
  4011. Operations - Specifies which operations to check access for. Each element
  4012. is the Operation Id of an operation in the AzApplication policy.
  4013. An operation should apear only once in this array. If not, the first occurrence
  4014. in the matching Results array will have the result set correctly. The
  4015. value in the Results array is undefined for the other occurrences.
  4016. Results - Returns an array of results of the access check. Each element in
  4017. this array corresponds to the corresponding element in the Operations array.
  4018. A value of NO_ERROR indicates that the access is granted.
  4019. A value of ERROR_ACCESS_DENIED indicates that the access is not granted.
  4020. Other values indicate that access should not be granted and describes the
  4021. reason. For instance, permission to perform this operation may have required
  4022. the evaluation of an LDAP_QUERY group and the domain controller may have been
  4023. unavailable.
  4024. BusinessRuleString - Returns the string set by any BizRules via the
  4025. SetBusinessRuleReturnString method.
  4026. Any returned sting must be freed by calling AzFreeMemory.
  4027. ParameterNames - Specifies an array of names of the parameters.
  4028. There are ParameterCount elements in the array. The name defines a way for the
  4029. BizRule script to reference the corresponding element in the ParameterValues array.
  4030. See IAzBizRuleContext::GetParameter for more information.
  4031. This parameter may be NULL. This parameter may be a pointer to an empty variant. This
  4032. parameter may be a pointer to a single dimension safe array variant where each element is a
  4033. BSTR.
  4034. ParameterValues - Specifies an array of values of the parameters. Each element in this array
  4035. contains the value of the parameter named by the corresponding element in ParameterNames.
  4036. Each element in this array may be of any type.
  4037. InterfaceNames - Specifies an array of names. Each element specifies the name that
  4038. the interface will be known by in the script. AccessCheck will call the
  4039. IActiveScript::AddNamedItem method for each name.
  4040. InterfaceFlags - Specifies an array of flags that will be passed to
  4041. IActiveScript::AddNamedItem. Each element matches the corresponding element
  4042. in the InterfaceNames array.
  4043. Interfaces - Specifies an array of IUnknown interfaces. These interfaces will be
  4044. made available to the BizRule script. In addition, these interfaces should
  4045. support the IActiveScriptSite interface. During BizRule script evaluation,
  4046. anytime the script host engine calls the IActiveScriptSite interface supplied
  4047. by AccessCheck, AccessCheck will forward those calls to the IActiveScriptSite
  4048. interface specified here. For instance, AccessCheck calls the application's
  4049. IActiveScriptSite::GetItemInfo in AccessChecks GetItemInfo routine if the
  4050. ItemName string passed to me was an InterfaceNames from above.
  4051. Each element matches the corresponding element in the InterfaceNames array.
  4052. Return Value:
  4053. Returns the status of the function. Does not indicate where the operation is permitted. NO_ERROR is returned whether permission is granted or not.
  4054. NO_ERROR - The operation was successful
  4055. ERROR_INVALID_PARAMETER - If ScopeCount is 0, but there are ScopeName present
  4056. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  4057. ERROR_NOT_FOUND - One of the ScopeNames or Operations is not defined in the
  4058. AZ policy database.
  4059. OLESCRIPT_E_SYNTAX - The syntax of the bizrule is invalid
  4060. Other status codes
  4061. --*/
  4062. {
  4063. DWORD WinStatus;
  4064. ULONG i;
  4065. BOOLEAN CritSectLocked = FALSE;
  4066. ACCESS_CHECK_CONTEXT AcContext;
  4067. ULONG LocalIndex;
  4068. BOOLEAN LocalOnly;
  4069. BOOLEAN BizrulesOk;
  4070. LPBYTE AllocatedBuffer = NULL;
  4071. PULONG TempAllocatedMemory;
  4072. ULONG MemoryRequired;
  4073. ULONG TaskInfoArraySize;
  4074. ULONG RoleIndex;
  4075. PAZP_ROLE Role;
  4076. PAZ_ROLE_INFO RoleInfo;
  4077. ULONG RoleListIndex;
  4078. #define ROLE_LIST_COUNT 2
  4079. PGENERIC_OBJECT_HEAD RoleLists[ROLE_LIST_COUNT];
  4080. ULONG RoleListCount;
  4081. ULONG ProcessedRoleCount = 0;
  4082. BOOLEAN CallAgain;
  4083. //
  4084. // Initialization
  4085. //
  4086. RtlZeroMemory( &AcContext, sizeof( AcContext ) );
  4087. //
  4088. // Grab the locks needed.
  4089. //
  4090. // Note, that even though the global lock is grabbed here, it is dropped during
  4091. // BizRule and LDAP Queries. By ensuring that the global lock isn't held while
  4092. // going off-machine, the policy cache can be updated via the change notification
  4093. // or the AzUpdateCache mechanisms.
  4094. //
  4095. //
  4096. if ( ApplicationSequenceNumber != AzpRetrieveApplicationSequenceNumber( ApplicationObjectHandle ) ) {
  4097. WinStatus = ERROR_INVALID_HANDLE;
  4098. goto Cleanup;
  4099. }
  4100. AzpLockResourceShared( &AzGlResource );
  4101. //
  4102. // validate that the ScopeCount and ScopeNames match
  4103. //
  4104. if ( ScopeCount == 0 &&
  4105. ScopeNames != NULL ) {
  4106. WinStatus = ERROR_INVALID_PARAMETER;
  4107. goto Cleanup;
  4108. }
  4109. //
  4110. // Validate the passed in handle
  4111. //
  4112. WinStatus = ObReferenceObjectByHandle( (PGENERIC_OBJECT)ClientContextHandle,
  4113. FALSE, // Don't allow deleted objects
  4114. FALSE, // No cache to refresh
  4115. OBJECT_TYPE_CLIENT_CONTEXT );
  4116. if ( WinStatus != NO_ERROR ) {
  4117. goto Cleanup;
  4118. }
  4119. AcContext.ClientContext = (PAZP_CLIENT_CONTEXT) ClientContextHandle;
  4120. AcContext.Application = (PAZP_APPLICATION) ParentOfChild( &AcContext.ClientContext->GenericObject );
  4121. //
  4122. // Grab the lock on the client context (observing locking order)
  4123. //
  4124. // This locking order allows the context crit sect to be locked for the life of the
  4125. // access check call and for the global lock to be periodically dropped when we
  4126. // go off-machine.
  4127. //
  4128. AzpUnlockResource( &AzGlResource );
  4129. SafeEnterCriticalSection( &AcContext.ClientContext->CritSect );
  4130. CritSectLocked = TRUE;
  4131. AzpLockResourceShared( &AzGlResource );
  4132. //
  4133. // If group memberships have changed,
  4134. // flush the cache.
  4135. //
  4136. // This code doesn't prevent the group membership from changing *during* the access check
  4137. // call. That's fine. It does protect against changes made prior to the access check call.
  4138. //
  4139. if ( AcContext.ClientContext->GroupEvalSerialNumber !=
  4140. AcContext.ClientContext->GenericObject.AzStoreObject->GroupEvalSerialNumber ) {
  4141. AzpFlushGroupEval( AcContext.ClientContext );
  4142. //
  4143. // Update the serial number to the new serial number
  4144. //
  4145. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: GroupEvalSerialNumber changed from %ld to %ld\n",
  4146. AcContext.ObjectNameString.String,
  4147. AcContext.ClientContext->GroupEvalSerialNumber,
  4148. AcContext.ClientContext->GenericObject.AzStoreObject->GroupEvalSerialNumber ));
  4149. AcContext.ClientContext->GroupEvalSerialNumber =
  4150. AcContext.ClientContext->GenericObject.AzStoreObject->GroupEvalSerialNumber;
  4151. }
  4152. //
  4153. // Capture the object name
  4154. //
  4155. WinStatus = AzpCaptureString( &AcContext.ObjectNameString,
  4156. ObjectName,
  4157. AZ_MAX_SCOPE_NAME_LENGTH,
  4158. FALSE ); // NULL not ok
  4159. if ( WinStatus != NO_ERROR ) {
  4160. goto Cleanup;
  4161. }
  4162. //
  4163. // Capture the scopes
  4164. //
  4165. if ( ScopeCount > 0 ) {
  4166. WinStatus = AzpCaptureString( &AcContext.ScopeNameString,
  4167. *ScopeNames,
  4168. AZ_MAX_SCOPE_NAME_LENGTH,
  4169. FALSE ); // NULL not ok
  4170. if ( WinStatus != NO_ERROR ) {
  4171. goto Cleanup;
  4172. }
  4173. WinStatus = ObReferenceObjectByName( &AcContext.Application->Scopes,
  4174. &AcContext.ScopeNameString,
  4175. AZP_FLAGS_REFRESH_CACHE,
  4176. (PGENERIC_OBJECT *)&AcContext.Scope );
  4177. if ( WinStatus != NO_ERROR ) {
  4178. //
  4179. // if a scope cannot be found, ObReferenceObjectByName will
  4180. // return ERROR_NOT_FOUND. We need to mask it to more specific error
  4181. // code before returning to the caller
  4182. //
  4183. if ( WinStatus == ERROR_NOT_FOUND ) {
  4184. WinStatus = ERROR_SCOPE_NOT_FOUND;
  4185. }
  4186. goto Cleanup;
  4187. }
  4188. //
  4189. // If the scope referenced does not have its children loaded into cache,
  4190. // then do so now. However, if the scope has not been submitted, then neither
  4191. // have its children, and they are already in cache
  4192. //
  4193. if ( !((PGENERIC_OBJECT)(AcContext.Scope))->AreChildrenLoaded ) {
  4194. //
  4195. // grab the resource lock exclusively
  4196. //
  4197. AzpLockResourceSharedToExclusive( &AzGlResource );
  4198. WinStatus = AzPersistUpdateChildrenCache(
  4199. (PGENERIC_OBJECT)AcContext.Scope
  4200. );
  4201. AzpLockResourceExclusiveToShared( &AzGlResource );
  4202. if ( WinStatus != NO_ERROR ) {
  4203. AzPrint(( AZD_ACCESS_MORE,
  4204. "AzAccessCheck: Failed to load children for %ws: %ld",
  4205. ((PGENERIC_OBJECT)AcContext.Scope)->ObjectName,
  4206. WinStatus
  4207. ));
  4208. goto Cleanup;
  4209. }
  4210. }
  4211. } else {
  4212. AzpInitString( &AcContext.ScopeNameString, NULL );
  4213. }
  4214. //
  4215. // Capture the Operations
  4216. //
  4217. if ( OperationCount == 0 ) {
  4218. AzPrint(( AZD_INVPARM, "AzAccessCheck: %ws: invalid OperationCount %ld\n", AcContext.ObjectNameString.String, OperationCount ));
  4219. WinStatus = ERROR_INVALID_PARAMETER;
  4220. goto Cleanup;
  4221. }
  4222. SafeAllocaAllocate( AcContext.OperationObjects,
  4223. OperationCount*(sizeof(PAZP_OPERATION) + sizeof(BOOLEAN)) );
  4224. if ( AcContext.OperationObjects == NULL ) {
  4225. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  4226. goto Cleanup;
  4227. }
  4228. RtlZeroMemory( AcContext.OperationObjects,
  4229. OperationCount*(sizeof(PAZP_OPERATION) + sizeof(BOOLEAN)) );
  4230. AcContext.OperationWasProcessed = (PBOOLEAN)(&AcContext.OperationObjects[OperationCount]);
  4231. AcContext.OperationCount = OperationCount;
  4232. AcContext.Results = Results;
  4233. for ( i=0; i<AcContext.OperationCount; i++ ) {
  4234. //
  4235. // The operation isn't allowed until proven otherwise
  4236. //
  4237. Results[i] = NOT_YET_DONE;
  4238. //
  4239. // Find the specific operation
  4240. //
  4241. WinStatus = AzpReferenceOperationByOpId( AcContext.Application,
  4242. Operations[i],
  4243. TRUE, // Refresh the cache if it needs it
  4244. &AcContext.OperationObjects[i] );
  4245. if ( WinStatus != NO_ERROR ) {
  4246. //
  4247. // if an operation cannot be found, AzpReferenceOperationByOpId will
  4248. // return ERROR_NOT_FOUND. We need to mask it to more specific error
  4249. // code before returning to the caller
  4250. //
  4251. if ( WinStatus == ERROR_NOT_FOUND ) {
  4252. WinStatus = ERROR_INVALID_OPERATION;
  4253. }
  4254. goto Cleanup;
  4255. }
  4256. }
  4257. //
  4258. // Capture the Bizrule parameters
  4259. //
  4260. if ( BusinessRuleString != NULL ) {
  4261. *BusinessRuleString = NULL;
  4262. }
  4263. WinStatus = AzpCaptureBizRuleParameters( &AcContext, ParameterNames, ParameterValues );
  4264. if ( WinStatus != NO_ERROR ) {
  4265. goto Cleanup;
  4266. }
  4267. //
  4268. // Allocate an array to hold the list of used paramaters
  4269. //
  4270. if ( AcContext.ParameterCount != 0 ) {
  4271. // Allocate the array on the stack
  4272. SafeAllocaAllocate( AcContext.UsedParameters, AcContext.ParameterCount * sizeof(*AcContext.UsedParameters) );
  4273. if ( AcContext.UsedParameters == NULL ) {
  4274. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  4275. goto Cleanup;
  4276. }
  4277. RtlZeroMemory( AcContext.UsedParameters, AcContext.ParameterCount * sizeof(*AcContext.UsedParameters) );
  4278. }
  4279. //
  4280. // Capture the Interfaces parameters
  4281. //
  4282. WinStatus = AzpCaptureBizRuleInterfaces( &AcContext, InterfaceNames, InterfaceFlags, Interfaces );
  4283. if ( WinStatus != NO_ERROR ) {
  4284. goto Cleanup;
  4285. }
  4286. //
  4287. // Determine if we've already cached the result of this access check
  4288. //
  4289. if ( AzpCheckOperationCache( &AcContext ) ) {
  4290. // Entire access check was satisfied from cache
  4291. WinStatus = NO_ERROR;
  4292. goto Cleanup;
  4293. }
  4294. //
  4295. // Compute the roles that apply to the scope
  4296. //
  4297. // There are two such lists: the roles that are children of the scope, and
  4298. // the roles that are children of the application the scope is in.
  4299. //
  4300. // If there was no scope specified, the just the roles for the application
  4301. // are set
  4302. //
  4303. RoleLists[0] = &AcContext.Application->Roles;
  4304. AcContext.RoleCount = RoleLists[0]->ObjectCount;
  4305. RoleListCount = 1;
  4306. if ( ScopeCount > 0 ) {
  4307. RoleLists[RoleListCount] = &AcContext.Scope->Roles;
  4308. AcContext.RoleCount += RoleLists[RoleListCount]->ObjectCount;
  4309. RoleListCount++;
  4310. }
  4311. //
  4312. // If there are no applicable roles,
  4313. // access is denied to all operations
  4314. //
  4315. if ( AcContext.RoleCount == 0 ) {
  4316. WinStatus = NO_ERROR;
  4317. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: There are no roles for this scope\n", AcContext.ObjectNameString.String,
  4318. AcContext.ScopeNameString.String ? AcContext.ScopeNameString.String : L""));
  4319. goto Cleanup;
  4320. }
  4321. //
  4322. // Capture the roles.
  4323. // Create references so we can drop AzGlResource when we hit the wire
  4324. //
  4325. SafeAllocaAllocate( AcContext.RoleInfo, AcContext.RoleCount*sizeof(*AcContext.RoleInfo) );
  4326. if ( AcContext.RoleInfo == NULL ) {
  4327. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  4328. goto Cleanup;
  4329. }
  4330. RoleIndex = 0;
  4331. MemoryRequired = 0;
  4332. TaskInfoArraySize = 0;
  4333. //
  4334. // boolean to indicate if the requested role is already found
  4335. //
  4336. BOOL bFoundRole=FALSE;
  4337. for ( RoleListIndex=0; RoleListIndex<RoleListCount; RoleListIndex++ ) {
  4338. PLIST_ENTRY ListEntry;
  4339. for ( ListEntry = RoleLists[RoleListIndex]->Head.Flink ;
  4340. ListEntry != &RoleLists[RoleListIndex]->Head ;
  4341. ListEntry = ListEntry->Flink ,
  4342. RoleIndex++ ) {
  4343. PGENERIC_OBJECT GenericObject;
  4344. //
  4345. // Grab a pointer to the next role to process
  4346. //
  4347. RoleInfo = &AcContext.RoleInfo[RoleIndex];
  4348. GenericObject = CONTAINING_RECORD( ListEntry,
  4349. GENERIC_OBJECT,
  4350. Next );
  4351. ASSERT( GenericObject->ObjectType == OBJECT_TYPE_ROLE );
  4352. //
  4353. // Grab a reference
  4354. //
  4355. InterlockedIncrement( &GenericObject->ReferenceCount );
  4356. AzpDumpGoRef( "Role reference", GenericObject );
  4357. Role = (PAZP_ROLE) GenericObject;
  4358. //
  4359. // Initialize the RoleInfo entry
  4360. //
  4361. RoleInfo = &AcContext.RoleInfo[RoleIndex];
  4362. RoleInfo->Role = Role;
  4363. RoleInfo->RoleProcessed = FALSE;
  4364. RoleInfo->SidsProcessed = FALSE;
  4365. RoleInfo->ResultStatus = NOT_YET_DONE;
  4366. //
  4367. // if a role is specified in the client context
  4368. // only perform access check on this role
  4369. //
  4370. if ( AcContext.ClientContext->RoleName.StringSize != 0 &&
  4371. ( bFoundRole ||
  4372. !AzpEqualStrings( &(Role->GenericObject.ObjectName->ObjectName),
  4373. &AcContext.ClientContext->RoleName ) ) ) {
  4374. //
  4375. // this role is not the one, skip it
  4376. //
  4377. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: This role %ws is not the requested role %ws \n", Role->GenericObject.ObjectName->ObjectName.String, AcContext.ClientContext->RoleName.String ));
  4378. RoleInfo->RoleProcessed = TRUE;
  4379. ProcessedRoleCount++;
  4380. } else {
  4381. //
  4382. // either this is the requested role, or
  4383. // we need to check for all roles
  4384. //
  4385. //
  4386. // Walk the list of operations and tasks so see which are applicable
  4387. // This is pass 1 which only determines the amount of memory needed
  4388. //
  4389. // Determine if this role has any operations that apply to this access check
  4390. //
  4391. WinStatus = AzpWalkTaskTree( &AcContext,
  4392. &Role->Operations,
  4393. &Role->Tasks,
  4394. 0, // RecursionLevel
  4395. NULL, // No allocated memory, yet
  4396. &MemoryRequired,
  4397. &TaskInfoArraySize,
  4398. NULL, // No OpsAndTasks to fill in
  4399. &CallAgain );
  4400. if ( WinStatus != NO_ERROR ) {
  4401. goto Cleanup;
  4402. }
  4403. //
  4404. // If no applicable operations were found anywhere,
  4405. // ditch this task.
  4406. //
  4407. if ( !CallAgain ) {
  4408. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: No operations for this role apply\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String ));
  4409. RoleInfo->RoleProcessed = TRUE;
  4410. ProcessedRoleCount++;
  4411. }
  4412. //
  4413. // remember that the requested role is already found
  4414. //
  4415. bFoundRole = TRUE;
  4416. }
  4417. }
  4418. }
  4419. ASSERT( AcContext.RoleCount == RoleIndex );
  4420. //
  4421. // If we've processed all of the roles,
  4422. // we're done.
  4423. //
  4424. if ( ProcessedRoleCount == AcContext.RoleCount ) {
  4425. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: No roles have applicable operations %ld.\n", AcContext.ObjectNameString.String,
  4426. AcContext.ScopeNameString.String ? AcContext.ScopeNameString.String : L"", AcContext.RoleCount ));
  4427. WinStatus = NO_ERROR;
  4428. goto Cleanup;
  4429. }
  4430. //
  4431. // Allocate a buffer for the task info and index arrays
  4432. //
  4433. ASSERT( (MemoryRequired+TaskInfoArraySize) != 0 );
  4434. SafeAllocaAllocate( AllocatedBuffer, MemoryRequired+TaskInfoArraySize );
  4435. if ( AllocatedBuffer == NULL ) {
  4436. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  4437. goto Cleanup;
  4438. }
  4439. // AzPrint(( AZD_ACCESS_MORE, "Allocated: 0x%lx (0x%lx)\n", AllocatedBuffer, MemoryRequired+TaskInfoArraySize ));
  4440. AcContext.TaskInfo = (PAZ_TASK_INFO) AllocatedBuffer;
  4441. TempAllocatedMemory = (PULONG)(AllocatedBuffer + TaskInfoArraySize);
  4442. //
  4443. // Walk the list of operations and tasks so see which are applicable
  4444. // This is pass 2 which actually initializes the data structures
  4445. //
  4446. MemoryRequired = 0;
  4447. TaskInfoArraySize = 0;
  4448. for ( RoleIndex=0; RoleIndex<AcContext.RoleCount; RoleIndex++ ) {
  4449. //
  4450. // Grab a pointer to the next role to process
  4451. //
  4452. RoleInfo = &AcContext.RoleInfo[RoleIndex];
  4453. Role = RoleInfo->Role;
  4454. if ( RoleInfo->RoleProcessed ) {
  4455. continue;
  4456. }
  4457. //
  4458. // Determine if this role has any operations that apply to this access check
  4459. //
  4460. WinStatus = AzpWalkTaskTree( &AcContext,
  4461. &Role->Operations,
  4462. &Role->Tasks,
  4463. 0, // RecursionLevel
  4464. &TempAllocatedMemory,
  4465. &MemoryRequired,
  4466. &TaskInfoArraySize,
  4467. &RoleInfo->OpsAndTasks,
  4468. &CallAgain );
  4469. if ( WinStatus != NO_ERROR ) {
  4470. goto Cleanup;
  4471. }
  4472. ASSERT( CallAgain );
  4473. if ( !CallAgain ) {
  4474. RoleInfo->RoleProcessed = TRUE;
  4475. ProcessedRoleCount++;
  4476. }
  4477. }
  4478. AzPrint(( AZD_ACCESS_MORE,
  4479. "AzContextAccessCheck: Starting Access Check loops\n"
  4480. ));
  4481. //
  4482. // Loop through the roles several times. Each time be more willing to go off-machine.
  4483. //
  4484. // There are 3 iterations of this loop
  4485. // 0: Local only, no bizrules.
  4486. // 1: Local only, bizrules. If script engine timeout is set to 0, then skip this iteration.
  4487. // 2: remote ok, bizrules. If script engine timeout is set to 0, bizrules are not evaluated.
  4488. //
  4489. for ( LocalIndex=0 ; LocalIndex<3; LocalIndex++ ) {
  4490. LocalOnly = (LocalIndex < 2);
  4491. //
  4492. // If script engine timeout is set to 0, skip the 2nd iteration
  4493. //
  4494. if ( (LocalIndex == 1) &&
  4495. ((AcContext.ClientContext)->GenericObject).AzStoreObject->ScriptEngineTimeout == 0 ) {
  4496. continue;
  4497. }
  4498. BizrulesOk = (LocalIndex > 0) &&
  4499. (((AcContext.ClientContext)->GenericObject).AzStoreObject->ScriptEngineTimeout != 0);
  4500. //
  4501. // If we've processed all of the roles,
  4502. // we're done.
  4503. //
  4504. if ( ProcessedRoleCount == AcContext.RoleCount ) {
  4505. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: All roles have been processed %ld.\n", AcContext.ObjectNameString.String,
  4506. AcContext.ScopeNameString.String ? AcContext.ScopeNameString.String : L"", AcContext.RoleCount ));
  4507. break;
  4508. }
  4509. //
  4510. // Loop through the list of roles
  4511. //
  4512. for ( RoleIndex=0; RoleIndex<AcContext.RoleCount; RoleIndex++ ) {
  4513. // BOOLEAN FoundOperation;
  4514. ULONG AppMemberStatus;
  4515. BOOLEAN IsMember;
  4516. //
  4517. // Grab a pointer to the next role to process
  4518. //
  4519. RoleInfo = &AcContext.RoleInfo[RoleIndex];
  4520. Role = RoleInfo->Role;
  4521. //
  4522. // If we've processed all of the operations,
  4523. // we're done.
  4524. //
  4525. if ( AcContext.ProcessedOperationCount == AcContext.OperationCount ) {
  4526. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: All operations have been processed %ld.\n", AcContext.ObjectNameString.String,
  4527. AcContext.ScopeNameString.String ? AcContext.ScopeNameString.String : L"", AcContext.OperationCount ));
  4528. break;
  4529. }
  4530. //
  4531. // If we've already processed this role,
  4532. // don't do it again.
  4533. //
  4534. if ( RoleInfo->RoleProcessed ) {
  4535. continue;
  4536. }
  4537. //
  4538. // Be verbose
  4539. //
  4540. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: Process role\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String ));
  4541. //
  4542. // Ensure the role still references at least one operation that hasn't previously
  4543. // been granted access.
  4544. //
  4545. // This check is cheaper than processing group membership or bizrules.
  4546. //
  4547. if ( AcContext.ProcessedOperationCount != 0 ) {
  4548. WinStatus = AzpWalkOpsAndTasks( &AcContext,
  4549. &Role->GenericObject.ObjectName->ObjectName,
  4550. &RoleInfo->OpsAndTasks,
  4551. WeedOutFinishedOps,
  4552. ERROR_INTERNAL_ERROR, // Not used for this opcode
  4553. BizrulesOk,
  4554. &CallAgain );
  4555. if ( WinStatus != NO_ERROR ) {
  4556. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: AzpWalkOpsAndTasks failed %ld\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String, WinStatus ));
  4557. goto Cleanup;
  4558. }
  4559. //
  4560. // If no operations from this role apply,
  4561. // ignore the entire role.
  4562. //
  4563. if ( !CallAgain ) {
  4564. // Mark this role as having been processed
  4565. RoleInfo->RoleProcessed = TRUE;
  4566. ProcessedRoleCount ++;
  4567. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: No operations for this role apply\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String ));
  4568. continue;
  4569. }
  4570. }
  4571. //
  4572. // Check the group memberhsip of the role if we haven't done so already
  4573. //
  4574. if ( RoleInfo->ResultStatus == NOT_YET_DONE ) {
  4575. //
  4576. // Check the NT Group membership in the role
  4577. // NT Group membership is always evaluated locally
  4578. //
  4579. if ( !RoleInfo->SidsProcessed ) {
  4580. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: CheckSidMembership of role\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String ));
  4581. WinStatus = AzpCheckSidMembership(
  4582. AcContext.ClientContext,
  4583. &Role->SidMembers,
  4584. &IsMember );
  4585. if ( WinStatus != NO_ERROR ) {
  4586. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: CheckSidMembership failed %ld\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String, WinStatus ));
  4587. goto Cleanup;
  4588. }
  4589. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: CheckSidMembership is %ld\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String, IsMember ));
  4590. // Convert the membership to a status code
  4591. RoleInfo->ResultStatus = IsMember ? NO_ERROR : NOT_YET_DONE;
  4592. RoleInfo->SidsProcessed = TRUE;
  4593. }
  4594. //
  4595. // If we couldn't determine membership based on SIDs,
  4596. // try via app groups
  4597. //
  4598. if ( RoleInfo->ResultStatus == NOT_YET_DONE ) {
  4599. //
  4600. // Check the app group membership
  4601. //
  4602. // *** Note: this routine will temporarily drop AzGlResource in cases where it hits the wire
  4603. //
  4604. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: CheckGroupMembership of role\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String ));
  4605. WinStatus = AzpCheckGroupMembership(
  4606. AcContext.ClientContext,
  4607. &Role->AppMembers,
  4608. LocalOnly,
  4609. 0, // No recursion yet
  4610. &IsMember,
  4611. &AppMemberStatus );
  4612. if ( WinStatus != NO_ERROR ) {
  4613. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: CheckGroupMembership failed %ld\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String, WinStatus ));
  4614. goto Cleanup;
  4615. }
  4616. //
  4617. // If we couldn't determine membership,
  4618. // remember the status to return to our caller.
  4619. //
  4620. if ( AppMemberStatus != NO_ERROR ) {
  4621. RoleInfo->ResultStatus = AppMemberStatus;
  4622. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: CheckGroupMembership extended status %ld\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String, AppMemberStatus ));
  4623. } else {
  4624. // Convert the membership to a status code
  4625. RoleInfo->ResultStatus = IsMember ? NO_ERROR : ERROR_ACCESS_DENIED;
  4626. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: CheckGroupMembership is %ld\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String, IsMember ));
  4627. }
  4628. }
  4629. }
  4630. //
  4631. // If we've found an answer,
  4632. // update the results array.
  4633. //
  4634. if ( RoleInfo->ResultStatus != NOT_YET_DONE ) {
  4635. //
  4636. // ASSERT: We have a ResultStatus for this Role
  4637. //
  4638. // Set the ResultStatus in the Results array for every operation granted
  4639. // by this role.
  4640. //
  4641. // *** Note: this routine will temporarily drop AzGlResource in cases where it hits the wire
  4642. //
  4643. WinStatus = AzpWalkOpsAndTasks( &AcContext,
  4644. &Role->GenericObject.ObjectName->ObjectName,
  4645. &RoleInfo->OpsAndTasks,
  4646. SetResultStatus,
  4647. RoleInfo->ResultStatus,
  4648. BizrulesOk,
  4649. &CallAgain );
  4650. if ( WinStatus != NO_ERROR ) {
  4651. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: AzpWalkOpsAndTasks failed %ld\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String, WinStatus ));
  4652. goto Cleanup;
  4653. }
  4654. //
  4655. // If no operations from this role apply,
  4656. // ignore the entire role.
  4657. //
  4658. if ( !CallAgain ) {
  4659. // Mark this role as having been processed
  4660. RoleInfo->RoleProcessed = TRUE;
  4661. ProcessedRoleCount ++;
  4662. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: Role finished being processed\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String ));
  4663. continue;
  4664. }
  4665. //
  4666. // AzpWalkOpsAndTasks says CallAgain for ERROR_ACCESS_DENIED hoping for a NO_ERROR.
  4667. // That won't happen for a Role since the ResultStatus won't change.
  4668. //
  4669. if ( RoleInfo->ResultStatus == ERROR_ACCESS_DENIED &&
  4670. BizrulesOk ) {
  4671. // Mark this role as having been processed
  4672. RoleInfo->RoleProcessed = TRUE;
  4673. ProcessedRoleCount ++;
  4674. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: %ws: Role finished being processed due to ACCESS_DENIED\n", AcContext.ObjectNameString.String, Role->GenericObject.ObjectName->ObjectName.String ));
  4675. continue;
  4676. }
  4677. }
  4678. }
  4679. }
  4680. WinStatus = NO_ERROR;
  4681. //
  4682. // Free any local resources
  4683. //
  4684. Cleanup:
  4685. //
  4686. // If access wasn't granted,
  4687. // process the results array to ensure the best status possible is returned
  4688. //
  4689. if ( WinStatus == NO_ERROR &&
  4690. AcContext.OperationCount != AcContext.ProcessedOperationCount ) {
  4691. for ( i=0; i<AcContext.OperationCount; i++ ) {
  4692. //
  4693. // Convert unknown status to a definitive access denied status
  4694. //
  4695. switch ( Results[i] ) {
  4696. case NOT_YET_DONE:
  4697. Results[i] = ERROR_ACCESS_DENIED;
  4698. break;
  4699. //
  4700. // A definitive status should be left alone
  4701. //
  4702. case NO_ERROR:
  4703. case ERROR_ACCESS_DENIED:
  4704. break;
  4705. //
  4706. // All other status codes should fail the access check API and not just
  4707. // deny access.
  4708. //
  4709. // Other status codes are temporarily put in the results array in hopes
  4710. // that a better status will be found via later processing.
  4711. //
  4712. // The only known status code is ERROR_NO_SUCH_DOMAIN.
  4713. //
  4714. default:
  4715. ASSERT( FALSE );
  4716. case ERROR_NO_SUCH_DOMAIN:
  4717. WinStatus = Results[i];
  4718. break;
  4719. }
  4720. }
  4721. }
  4722. //
  4723. // Generate the access check audits if the audit boolean is set to TRUE.
  4724. //
  4725. if ( WinStatus == NO_ERROR ) {
  4726. if ( AcContext.Application->GenericObject.IsGeneratingAudits &&
  4727. !AzpOpenToManageStore(AcContext.ClientContext->GenericObject.AzStoreObject) ) {
  4728. WinStatus = AzpAccessCheckGenerateAudit( &AcContext );
  4729. if ( WinStatus != NO_ERROR ) {
  4730. AzPrint(( AZD_ACCESS_MORE, "AzAccessCheck: %ws: AzpAccessCheckGenerateAudit failed with %ld\n", AcContext.ObjectNameString.String, WinStatus ));
  4731. }
  4732. }
  4733. }
  4734. //
  4735. // Update the cache of results
  4736. //
  4737. if ( WinStatus == NO_ERROR ) {
  4738. AzpUpdateOperationCache( &AcContext );
  4739. }
  4740. //
  4741. // Free the operation objects
  4742. //
  4743. if ( AcContext.OperationObjects != NULL ) {
  4744. for ( i=0; i<AcContext.OperationCount; i++ ) {
  4745. if ( AcContext.OperationObjects[i] != NULL ) {
  4746. ObDereferenceObject( (PGENERIC_OBJECT)AcContext.OperationObjects[i] );
  4747. }
  4748. }
  4749. SafeAllocaFree( AcContext.OperationObjects );
  4750. }
  4751. //
  4752. // Free the role info
  4753. //
  4754. if ( AcContext.RoleInfo != NULL ) {
  4755. for ( RoleIndex=0; RoleIndex<AcContext.RoleCount; RoleIndex++ ) {
  4756. ObDereferenceObject( (PGENERIC_OBJECT)AcContext.RoleInfo[RoleIndex].Role );
  4757. // SafeAllocaFree( AcContext.RoleInfo[RoleIndex].OpsAndTasks.OpIndexes ); // Part of AllocatedBuffer
  4758. }
  4759. SafeAllocaFree ( AcContext.RoleInfo );
  4760. }
  4761. //
  4762. // Free the task info
  4763. //
  4764. if ( AcContext.TaskInfo != NULL ) {
  4765. for ( i=0; i<AcContext.TaskCount; i++ ) {
  4766. ObDereferenceObject( (PGENERIC_OBJECT)AcContext.TaskInfo[i].Task );
  4767. // SafeAllocaFree( AcContext.TaskInfo[i].OpsAndTasks.OpIndexes ); // Part of AllocatedBuffer
  4768. }
  4769. // SafeAllocaFree ( AcContext.TaskInfo ); // Part of AllocatedBuffer
  4770. }
  4771. SafeAllocaFree( AllocatedBuffer );
  4772. //
  4773. // Free sundry other data
  4774. //
  4775. if ( AcContext.Scope != NULL ) {
  4776. ObDereferenceObject( (PGENERIC_OBJECT) AcContext.Scope );
  4777. }
  4778. AzpFreeString( &AcContext.ObjectNameString );
  4779. AzpFreeString( &AcContext.ScopeNameString );
  4780. if ( AcContext.ClientContext != NULL ) {
  4781. ObDereferenceObject( (PGENERIC_OBJECT)AcContext.ClientContext );
  4782. }
  4783. if ( AcContext.SaParameterNames != NULL ) {
  4784. SafeArrayUnaccessData( AcContext.SaParameterNames );
  4785. }
  4786. if ( AcContext.SaParameterValues != NULL ) {
  4787. SafeArrayUnaccessData( AcContext.SaParameterValues );
  4788. }
  4789. SafeAllocaFree( AcContext.UsedParameters );
  4790. //
  4791. // Drop the locks
  4792. //
  4793. AzpUnlockResource( &AzGlResource );
  4794. if ( CritSectLocked ) {
  4795. SafeLeaveCriticalSection( &AcContext.ClientContext->CritSect );
  4796. }
  4797. //
  4798. // Return the BusinessRuleString to the caller
  4799. //
  4800. if ( WinStatus == NO_ERROR && BusinessRuleString != NULL ) {
  4801. *BusinessRuleString = AcContext.BusinessRuleString.String;
  4802. } else {
  4803. AzpFreeString( &AcContext.BusinessRuleString );
  4804. }
  4805. return WinStatus;
  4806. }
  4807. DWORD
  4808. WINAPI
  4809. AzContextGetRoles(
  4810. IN AZ_HANDLE ClientContextHandle,
  4811. IN LPCWSTR ScopeName OPTIONAL,
  4812. OUT LPWSTR **RoleNames,
  4813. OUT DWORD *Count
  4814. )
  4815. /*++
  4816. Routine Description:
  4817. The application calls the GetRoles function whenever it wants to find the
  4818. roles the client belongs to in a specified scope.
  4819. If the ScopeName parameter is NULL, Roles applicable at the default Scope
  4820. are returned.
  4821. Otherwise, only those Roles applicable at the speficied scope (and not
  4822. including the roles at the default scope) are returned.
  4823. Biz rules re not evaluated since they do not come in the picture.
  4824. Arguments:
  4825. ClientContextHandle - Specifies a handle to the client context object indentifying
  4826. the client.
  4827. ScopeName - Specifies the scope name from which the roles are applicable.
  4828. NULL scope represents the Application scope.
  4829. RoleNames - Returns an array of role names applicable at the given scope.
  4830. RoleCount - Returns the number of eleements in the array.
  4831. Return Value:
  4832. Returns the status of the function.
  4833. NO_ERROR - The operation was successful
  4834. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  4835. ERROR_NOT_FOUND - ScopeName is not defined in the AZ policy database.
  4836. Other status codes
  4837. --*/
  4838. {
  4839. DWORD WinStatus = NO_ERROR;
  4840. AZP_STRING ScopeNameString = {0};
  4841. PAZP_SCOPE Scope = NULL;
  4842. BOOLEAN CritSectLocked = FALSE;
  4843. PAZP_CLIENT_CONTEXT ClientContext = NULL;
  4844. PAZP_APPLICATION Application = NULL;
  4845. PGENERIC_OBJECT_HEAD RoleList = NULL;
  4846. PAZP_ROLE Role = NULL;
  4847. PAZ_ROLE_INFO RoleInfo = NULL;
  4848. ULONG RoleCount = 0;
  4849. ULONG RoleIndex = 0;
  4850. ULONG ProcessedRoleCount = 0;
  4851. ULONG ApplicableRoleCount = 0;
  4852. ULONG LocalIndex = 0;
  4853. BOOLEAN LocalOnly = FALSE;
  4854. ULONG Size;
  4855. ULONG i;
  4856. PLIST_ENTRY ListEntry = NULL;
  4857. //
  4858. // Initialization
  4859. //
  4860. *Count = 0;
  4861. *RoleNames = NULL;
  4862. //
  4863. // Grab the locks needed.
  4864. //
  4865. // Note, that even though the global lock is grabbed here, it is dropped during
  4866. // LDAP Queries. By ensuring that the global lock isn't held while
  4867. // going off-machine, the policy cache can be updated via the change notification
  4868. // or the AzUpdateCache mechanisms.
  4869. //
  4870. //
  4871. AzpLockResourceShared( &AzGlResource );
  4872. //
  4873. // Validate the passed in handle
  4874. //
  4875. WinStatus = ObReferenceObjectByHandle( (PGENERIC_OBJECT)ClientContextHandle,
  4876. FALSE, // Don't allow deleted objects
  4877. FALSE, // No cache to refresh
  4878. OBJECT_TYPE_CLIENT_CONTEXT );
  4879. if ( WinStatus != NO_ERROR ) {
  4880. goto Cleanup;
  4881. }
  4882. ClientContext = (PAZP_CLIENT_CONTEXT) ClientContextHandle;
  4883. Application = (PAZP_APPLICATION) ParentOfChild( &ClientContext->GenericObject );
  4884. if (!ARGUMENT_PRESENT(ScopeName)) {
  4885. //
  4886. // If ScopeName is not provided, we pick the Application Scope as the
  4887. // default scope.
  4888. //
  4889. RoleList = &Application->Roles;
  4890. } else {
  4891. //
  4892. // Capture the ScopeName provided and reference the Scope object.
  4893. //
  4894. WinStatus = AzpCaptureString( &ScopeNameString,
  4895. ScopeName,
  4896. AZ_MAX_SCOPE_NAME_LENGTH,
  4897. FALSE ); // NULL not ok
  4898. if ( WinStatus != NO_ERROR ) {
  4899. goto Cleanup;
  4900. }
  4901. WinStatus = ObReferenceObjectByName( &Application->Scopes,
  4902. &ScopeNameString,
  4903. AZP_FLAGS_REFRESH_CACHE,
  4904. (PGENERIC_OBJECT *)&Scope );
  4905. if ( WinStatus != NO_ERROR ) {
  4906. //
  4907. // if a scope cannot be found, ObReferenceObjectByName will
  4908. // return ERROR_NOT_FOUND. We need to mask it to more specific error
  4909. // code before returning to the caller
  4910. //
  4911. if ( WinStatus == ERROR_NOT_FOUND ) {
  4912. WinStatus = ERROR_SCOPE_NOT_FOUND;
  4913. }
  4914. goto Cleanup;
  4915. }
  4916. RoleList = &Scope->Roles;
  4917. }
  4918. //
  4919. // If there are no applicable roles, return now.
  4920. //
  4921. RoleCount = RoleList->ObjectCount;
  4922. if ( RoleCount == 0 ) {
  4923. WinStatus = NO_ERROR;
  4924. goto Cleanup;
  4925. }
  4926. //
  4927. // Grab the lock on the client context (observing locking order)
  4928. //
  4929. // This locking order allows the context crit sect to be locked for the life of the
  4930. // access check call and for the global lock to be periodically dropped when we
  4931. // go off-machine.
  4932. //
  4933. AzpUnlockResource( &AzGlResource );
  4934. SafeEnterCriticalSection( &ClientContext->CritSect );
  4935. CritSectLocked = TRUE;
  4936. AzpLockResourceShared( &AzGlResource );
  4937. //
  4938. // Recheck just in case someone deleted all the roles in our scope when
  4939. // we dropped the global lock.
  4940. //
  4941. RoleCount = RoleList->ObjectCount;
  4942. if ( RoleCount == 0 ) {
  4943. WinStatus = NO_ERROR;
  4944. goto Cleanup;
  4945. }
  4946. //
  4947. // Allocate memory for Role structures.
  4948. //
  4949. SafeAllocaAllocate( RoleInfo, RoleCount*sizeof(AZ_ROLE_INFO) );
  4950. if ( RoleInfo == NULL ) {
  4951. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  4952. goto Cleanup;
  4953. }
  4954. //
  4955. // Grab all the roles, put them into a list and reference them. Now we will
  4956. // not lose them if we have to drop the global lock while going off the machine.
  4957. //
  4958. //
  4959. for ( ListEntry = RoleList->Head.Flink ;
  4960. ListEntry != &RoleList->Head ;
  4961. ListEntry = ListEntry->Flink, RoleIndex++ ) {
  4962. PGENERIC_OBJECT GenericObject;
  4963. //
  4964. // Grab a pointer to the next role to process
  4965. //
  4966. GenericObject = CONTAINING_RECORD( ListEntry,
  4967. GENERIC_OBJECT,
  4968. Next );
  4969. ASSERT( GenericObject->ObjectType == OBJECT_TYPE_ROLE );
  4970. //
  4971. // Grab a reference
  4972. //
  4973. InterlockedIncrement( &GenericObject->ReferenceCount );
  4974. AzpDumpGoRef( "Role reference", GenericObject );
  4975. Role = (PAZP_ROLE) GenericObject;
  4976. //
  4977. // Initialize the RoleInfo entry
  4978. //
  4979. RoleInfo[RoleIndex].Role = Role;
  4980. RoleInfo[RoleIndex].RoleProcessed = FALSE;
  4981. RoleInfo[RoleIndex].SidsProcessed = FALSE;
  4982. RoleInfo[RoleIndex].ResultStatus = NOT_YET_DONE;
  4983. }
  4984. //
  4985. // There are 2 iterations of this loop
  4986. // 0: Local only
  4987. // 1: remote ok
  4988. // Note that we do not evaluate BizRules like AccessCheck does.
  4989. //
  4990. for ( LocalIndex=0 ; LocalIndex<2; LocalIndex++ ) {
  4991. LocalOnly = (LocalIndex < 1);
  4992. //
  4993. // If we've processed all of the roles,
  4994. // we're done.
  4995. //
  4996. if ( ProcessedRoleCount == RoleCount ) {
  4997. break;
  4998. }
  4999. //
  5000. // Loop through the list of roles
  5001. //
  5002. for ( RoleIndex=0; RoleIndex<RoleCount; RoleIndex++ ) {
  5003. ULONG AppMemberStatus = NO_ERROR;
  5004. BOOLEAN IsMember = FALSE;
  5005. //
  5006. // If we've already processed this role,
  5007. // don't do it again.
  5008. //
  5009. if ( RoleInfo[RoleIndex].RoleProcessed ) {
  5010. continue;
  5011. }
  5012. //
  5013. // Grab a pointer to the next role to process
  5014. //
  5015. Role = RoleInfo[RoleIndex].Role;
  5016. //
  5017. // Check the group memberhsip of the role if we haven't done so already
  5018. //
  5019. if ( RoleInfo[RoleIndex].ResultStatus == NOT_YET_DONE ) {
  5020. //
  5021. // Check the NT Group membership in the role
  5022. // NT Group membership is always evaluated locally
  5023. //
  5024. if ( !RoleInfo[RoleIndex].SidsProcessed ) {
  5025. AzPrint(( AZD_ACCESS_MORE, "GetRoles: %ws: CheckSidMembership of role\n", Role->GenericObject.ObjectName->ObjectName.String ));
  5026. WinStatus = AzpCheckSidMembership(
  5027. ClientContext,
  5028. &Role->SidMembers,
  5029. &IsMember );
  5030. if ( WinStatus != NO_ERROR ) {
  5031. AzPrint(( AZD_ACCESS_MORE, "GetRoles: %ws: CheckSidMembership failed %ld\n", Role->GenericObject.ObjectName->ObjectName.String, WinStatus ));
  5032. goto Cleanup;
  5033. }
  5034. AzPrint(( AZD_ACCESS_MORE, "GetRoles: %ws: CheckSidMembership is %ld\n", Role->GenericObject.ObjectName->ObjectName.String, IsMember ));
  5035. // Convert the membership to a status code
  5036. if ( IsMember ) {
  5037. RoleInfo[RoleIndex].ResultStatus = NO_ERROR;
  5038. ApplicableRoleCount++;
  5039. } else {
  5040. RoleInfo[RoleIndex].ResultStatus = NOT_YET_DONE;
  5041. }
  5042. RoleInfo[RoleIndex].SidsProcessed = TRUE;
  5043. }
  5044. //
  5045. // If we couldn't determine membership based on SIDs,
  5046. // try via app groups
  5047. //
  5048. if ( RoleInfo[RoleIndex].ResultStatus == NOT_YET_DONE ) {
  5049. //
  5050. // Check the app group membership
  5051. //
  5052. // *** Note: this routine will temporarily drop AzGlResource in cases where it hits the wire
  5053. //
  5054. AzPrint(( AZD_ACCESS_MORE, "GetRoles: %ws: CheckGroupMembership of role\n", Role->GenericObject.ObjectName->ObjectName.String ));
  5055. WinStatus = AzpCheckGroupMembership(
  5056. ClientContext,
  5057. &Role->AppMembers,
  5058. LocalOnly,
  5059. 0, // No recursion yet
  5060. &IsMember,
  5061. &AppMemberStatus );
  5062. if ( WinStatus != NO_ERROR ) {
  5063. AzPrint(( AZD_ACCESS_MORE, "GetRoles: %ws: CheckGroupMembership failed %ld\n", Role->GenericObject.ObjectName->ObjectName.String, WinStatus ));
  5064. goto Cleanup;
  5065. }
  5066. //
  5067. // Let check if we could determine membership,
  5068. //
  5069. if ( AppMemberStatus == NO_ERROR ) {
  5070. // Convert the membership to a status code
  5071. if ( IsMember ) {
  5072. RoleInfo[RoleIndex].ResultStatus = NO_ERROR;
  5073. ApplicableRoleCount++;
  5074. } else {
  5075. RoleInfo[RoleIndex].ResultStatus = ERROR_ACCESS_DENIED;
  5076. }
  5077. AzPrint(( AZD_ACCESS_MORE, "GetRoles: %ws: CheckGroupMembership is %ld\n", Role->GenericObject.ObjectName->ObjectName.String, IsMember ));
  5078. } else if (AppMemberStatus == ERROR_ACCESS_DENIED ||
  5079. AppMemberStatus == NOT_YET_DONE) {
  5080. //
  5081. // These error codes are ok. We did not encounter an
  5082. // error.
  5083. //
  5084. RoleInfo[RoleIndex].ResultStatus = AppMemberStatus;
  5085. } else {
  5086. //
  5087. // We failed to determine membership. The likely error
  5088. // code here would be ERROR_NO_SUCH_DOMAIN. We do not
  5089. // want to continue.
  5090. //
  5091. WinStatus = AppMemberStatus;
  5092. goto Cleanup;
  5093. }
  5094. AzPrint(( AZD_ACCESS_MORE, "GetRoles: %ws: CheckGroupMembership extended status %ld\n", Role->GenericObject.ObjectName->ObjectName.String, AppMemberStatus ));
  5095. }
  5096. }
  5097. //
  5098. // Mark the role as processed if
  5099. // we have determined that the client belongs/does not belong to the role
  5100. // OR
  5101. // if this is the last iteration
  5102. //
  5103. //
  5104. if ( RoleInfo[RoleIndex].ResultStatus != NOT_YET_DONE || !LocalOnly ) {
  5105. // Mark this role as having been processed
  5106. RoleInfo[RoleIndex].RoleProcessed = TRUE;
  5107. ProcessedRoleCount ++;
  5108. AzPrint(( AZD_ACCESS_MORE, "GetRoles: %ws: Role finished being processed \n", Role->GenericObject.ObjectName->ObjectName.String ));
  5109. }
  5110. }
  5111. }
  5112. ASSERT( ProcessedRoleCount == RoleCount );
  5113. //
  5114. // Check that we are returning non zero number of roles.
  5115. //
  5116. if ( ApplicableRoleCount > 0) {
  5117. PUCHAR Current = NULL;
  5118. //
  5119. // Get the size of the buffer required to return the strings for role names.
  5120. //
  5121. Size = (sizeof(LPWSTR)) * ApplicableRoleCount;
  5122. for ( RoleIndex=0; RoleIndex<RoleCount; RoleIndex++ ) {
  5123. // Pick only applicable roles.
  5124. if ( RoleInfo[RoleIndex].ResultStatus == NO_ERROR ) {
  5125. // Note that the StringSize also includes the NULL character.
  5126. Size += RoleInfo[RoleIndex].Role->GenericObject.ObjectName->ObjectName.StringSize;
  5127. } else if ( RoleInfo[RoleIndex].ResultStatus != ERROR_ACCESS_DENIED &&
  5128. RoleInfo[RoleIndex].ResultStatus != NOT_YET_DONE ) {
  5129. WinStatus = RoleInfo[RoleIndex].ResultStatus;
  5130. //
  5131. // This should not happen. We have taken care to break out early.
  5132. //
  5133. ASSERT(FALSE);
  5134. goto Cleanup;
  5135. }
  5136. }
  5137. //
  5138. // Allocate memory required to hold the strings.
  5139. //
  5140. *RoleNames = (LPWSTR *) AzpAllocateHeap( Size, "GETROLES" );
  5141. if ( *RoleNames == NULL ) {
  5142. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  5143. goto Cleanup;
  5144. }
  5145. //
  5146. // Set the number of RoleNames we will return.
  5147. //
  5148. *Count = ApplicableRoleCount;
  5149. //
  5150. // Set the current buffer pointer.
  5151. //
  5152. Current = (PUCHAR) ( (*RoleNames)+ApplicableRoleCount );
  5153. //
  5154. // Copy all the applicable roles into our buffer.
  5155. //
  5156. for ( i=0, RoleIndex=0; RoleIndex<RoleCount; RoleIndex++ ) {
  5157. if ( RoleInfo[RoleIndex].ResultStatus == NO_ERROR ) {
  5158. (*RoleNames)[i] = (LPWSTR) Current;
  5159. RtlCopyMemory( Current,
  5160. RoleInfo[RoleIndex].Role->GenericObject.ObjectName->ObjectName.String,
  5161. RoleInfo[RoleIndex].Role->GenericObject.ObjectName->ObjectName.StringSize );
  5162. Current += RoleInfo[RoleIndex].Role->GenericObject.ObjectName->ObjectName.StringSize;
  5163. i++;
  5164. }
  5165. }
  5166. }
  5167. WinStatus = NO_ERROR;
  5168. Cleanup:
  5169. //
  5170. // Release references to all the object we touched.
  5171. //
  5172. //
  5173. if ( ClientContext != NULL ) {
  5174. ObDereferenceObject( (PGENERIC_OBJECT)ClientContext );
  5175. }
  5176. if ( Scope != NULL ) {
  5177. ObDereferenceObject( (PGENERIC_OBJECT)Scope );
  5178. }
  5179. if ( RoleInfo != NULL ) {
  5180. for ( RoleIndex=0; RoleIndex<RoleCount; RoleIndex++ ) {
  5181. ObDereferenceObject( (PGENERIC_OBJECT)RoleInfo[RoleIndex].Role );
  5182. }
  5183. SafeAllocaFree ( RoleInfo );
  5184. }
  5185. if ( ScopeName != NULL ) {
  5186. AzpFreeString( &ScopeNameString );
  5187. }
  5188. //
  5189. // Drop the locks
  5190. //
  5191. AzpUnlockResource( &AzGlResource );
  5192. if ( CritSectLocked ) {
  5193. SafeLeaveCriticalSection( &ClientContext->CritSect );
  5194. }
  5195. return WinStatus;
  5196. }
  5197. inline BOOL
  5198. AzpOpenToManageStore (
  5199. IN PAZP_AZSTORE pAzStore
  5200. )
  5201. /*++
  5202. Routine Description:
  5203. Detect if the store is opened for manage only
  5204. Arguments:
  5205. pAzStore - The authorization store object
  5206. Return Value:
  5207. TRUE if and only if the store's initialization flag has
  5208. set the manage only flag.
  5209. --*/
  5210. {
  5211. return (pAzStore->InitializeFlag & AZ_AZSTORE_FLAG_MANAGE_STORE_ONLY);
  5212. }