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.

1220 lines
33 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. group.cxx
  5. Abstract:
  6. Routines implementing the Group object
  7. Author:
  8. Cliff Van Dyke (cliffv) 11-Apr-2001
  9. --*/
  10. #include "pch.hxx"
  11. //
  12. // Define the default values for all scalar attributes
  13. //
  14. ULONG AzGlDefGroupType = AZ_GROUPTYPE_BASIC;
  15. AZP_DEFAULT_VALUE AzGlGroupDefaultValues[] = {
  16. { AZ_PROP_GROUP_TYPE, AZ_DIRTY_GROUP_TYPE, &AzGlDefGroupType },
  17. { AZ_PROP_GROUP_LDAP_QUERY, AZ_DIRTY_GROUP_LDAP_QUERY, NULL },
  18. { 0, 0, NULL }
  19. };
  20. DWORD
  21. AzpGroupInit(
  22. IN PGENERIC_OBJECT ParentGenericObject,
  23. IN PGENERIC_OBJECT ChildGenericObject
  24. )
  25. /*++
  26. Routine Description:
  27. This routine is a worker routine for AzGroupCreate. It does any object specific
  28. initialization that needs to be done.
  29. On entry, AzGlResource must be locked exclusively.
  30. Arguments:
  31. ParentGenericObject - Specifies the parent object to add the child object onto.
  32. The reference count has been incremented on this object.
  33. ChildGenericObject - Specifies the newly allocated child object.
  34. The reference count has been incremented on this object.
  35. Return Value:
  36. NO_ERROR - The operation was successful
  37. ERROR_NOT_ENOUGH_MEMORY - not enough memory
  38. Other exception status codes
  39. --*/
  40. {
  41. PAZP_GROUP Group = (PAZP_GROUP) ChildGenericObject;
  42. PAZP_AZSTORE AzAuthorizationStore = NULL;
  43. PAZP_APPLICATION Application = NULL;
  44. PAZP_SCOPE Scope = NULL;
  45. PGENERIC_OBJECT_HEAD ParentSids = NULL;
  46. //
  47. // Initialization
  48. //
  49. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  50. //
  51. // Behave differently depending on the object type of the parent object
  52. //
  53. // A group references SID objects that are siblings of itself.
  54. // That way, the back links on the SID object references just the groups
  55. // that are siblings of the SID object.
  56. //
  57. if ( ParentGenericObject->ObjectType == OBJECT_TYPE_AZAUTHSTORE ) {
  58. AzAuthorizationStore = (PAZP_AZSTORE) ParentGenericObject;
  59. } else if ( ParentGenericObject->ObjectType == OBJECT_TYPE_APPLICATION ) {
  60. AzAuthorizationStore = ParentGenericObject->AzStoreObject;
  61. Application = (PAZP_APPLICATION) ParentGenericObject;
  62. } else if ( ParentGenericObject->ObjectType == OBJECT_TYPE_SCOPE ) {
  63. AzAuthorizationStore = ParentGenericObject->AzStoreObject;
  64. Application = (PAZP_APPLICATION) ParentOfChild( ParentGenericObject );
  65. Scope = (PAZP_SCOPE) ParentGenericObject;
  66. } else {
  67. ASSERT( FALSE );
  68. }
  69. ParentSids = &ParentGenericObject->AzpSids;
  70. //
  71. // Groups reference other groups.
  72. // These other groups can be siblings of this group or siblings of our parents.
  73. //
  74. // Let the generic object manager know all of the lists we support
  75. //
  76. ChildGenericObject->GenericObjectLists = &Group->AppMembers;
  77. ObInitObjectList( &Group->AppMembers,
  78. &Group->AppNonMembers,
  79. FALSE, // Forward link
  80. AZP_LINKPAIR_MEMBERS,
  81. AZ_DIRTY_GROUP_APP_MEMBERS,
  82. &AzAuthorizationStore->Groups,
  83. Application == NULL ? NULL : &Application->Groups,
  84. Scope == NULL ? NULL : &Scope->Groups );
  85. // Same for non members
  86. ObInitObjectList( &Group->AppNonMembers,
  87. &Group->backAppMembers,
  88. FALSE, // Forward link
  89. AZP_LINKPAIR_NON_MEMBERS,
  90. AZ_DIRTY_GROUP_APP_NON_MEMBERS,
  91. &AzAuthorizationStore->Groups,
  92. Application == NULL ? NULL : &Application->Groups,
  93. Scope == NULL ? NULL : &Scope->Groups );
  94. // back links for the above
  95. ObInitObjectList( &Group->backAppMembers,
  96. &Group->backAppNonMembers,
  97. TRUE, // backward link
  98. AZP_LINKPAIR_MEMBERS,
  99. 0, // No dirty bit on back link
  100. NULL,
  101. NULL,
  102. NULL );
  103. ObInitObjectList( &Group->backAppNonMembers,
  104. &Group->backRoles,
  105. TRUE, // backward link
  106. AZP_LINKPAIR_NON_MEMBERS,
  107. 0, // No dirty bit on back link
  108. NULL,
  109. NULL,
  110. NULL );
  111. // Groups are referenced by "Roles"
  112. ObInitObjectList( &Group->backRoles,
  113. &Group->SidMembers,
  114. TRUE, // Backward link
  115. 0, // No link pair id
  116. 0, // No dirty bit on back link
  117. NULL,
  118. NULL,
  119. NULL );
  120. // Groups reference SID objects
  121. ObInitObjectList( &Group->SidMembers,
  122. &Group->SidNonMembers,
  123. FALSE, // Forward link
  124. AZP_LINKPAIR_SID_MEMBERS,
  125. AZ_DIRTY_GROUP_MEMBERS,
  126. ParentSids,
  127. NULL,
  128. NULL );
  129. // Same for non members
  130. ObInitObjectList( &Group->SidNonMembers,
  131. NULL,
  132. FALSE, // Forward link
  133. AZP_LINKPAIR_SID_NON_MEMBERS,
  134. AZ_DIRTY_GROUP_NON_MEMBERS,
  135. ParentSids,
  136. NULL,
  137. NULL );
  138. return NO_ERROR;
  139. }
  140. VOID
  141. AzpGroupFree(
  142. IN PGENERIC_OBJECT GenericObject
  143. )
  144. /*++
  145. Routine Description:
  146. This routine is a worker routine for Group object free. It does any object specific
  147. cleanup that needs to be done.
  148. On entry, AzGlResource must be locked exclusively.
  149. Arguments:
  150. GenericObject - Specifies a pointer to the object to be deleted.
  151. Return Value:
  152. None
  153. --*/
  154. {
  155. PAZP_GROUP Group = (PAZP_GROUP) GenericObject;
  156. //
  157. // Initialization
  158. //
  159. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  160. //
  161. // Free any local strings
  162. //
  163. AzpFreeString( &Group->LdapQuery );
  164. }
  165. DWORD
  166. AzpGroupNameConflict(
  167. IN PGENERIC_OBJECT ParentGenericObject,
  168. IN PAZP_STRING ChildObjectNameString
  169. )
  170. /*++
  171. Routine Description:
  172. This routine is a worker routine to determine if the specified ChildObjectNameString
  173. conflicts with the names of other objects that share a namespace with Groups.
  174. On entry, AzGlResource must be locked exclusively.
  175. Arguments:
  176. ParentGenericObject - Specifies the parent object to add the child object onto.
  177. The reference count has been incremented on this object.
  178. ChildObjectNameString - Specifies the name of the child object.
  179. Return Value:
  180. NO_ERROR - The operation was successful
  181. ERROR_ALREADY_EXISTS - An object by that name already exists
  182. --*/
  183. {
  184. PAZP_AZSTORE AzAuthorizationStore = NULL;
  185. PAZP_APPLICATION Application = NULL;
  186. ULONG WinStatus;
  187. PGENERIC_OBJECT ConflictGenericObject;
  188. //
  189. // Initialization
  190. //
  191. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  192. //
  193. // Behave differently depending on the object type of the parent object
  194. //
  195. // A group that is a child of the authorization store,
  196. // cannot have the same name as any groups that are children of any of the child applications, and
  197. // cannot have the same name as any groups that are children of any of the grandchild child scopes.
  198. //
  199. if ( ParentGenericObject->ObjectType == OBJECT_TYPE_AZAUTHSTORE ) {
  200. AzAuthorizationStore = (PAZP_AZSTORE) ParentGenericObject;
  201. //
  202. // Check groups that are children and grandchildren
  203. //
  204. WinStatus = ObCheckNameConflict( &AzAuthorizationStore->Applications,
  205. ChildObjectNameString,
  206. offsetof(_AZP_APPLICATION, Groups),
  207. offsetof(_AZP_APPLICATION, Scopes),
  208. offsetof(_AZP_SCOPE, Groups) );
  209. //
  210. // A group that is a child of an application
  211. // cannot have the same name as groups that are children of the authorization store,
  212. // and cannot have the same name as any groups that are children of any of the child scopes.
  213. //
  214. } else if ( ParentGenericObject->ObjectType == OBJECT_TYPE_APPLICATION ) {
  215. AzAuthorizationStore = ParentGenericObject->AzStoreObject;
  216. Application = (PAZP_APPLICATION) ParentGenericObject;
  217. //
  218. // Check groups that are children of the authorization store
  219. //
  220. //
  221. WinStatus = ObReferenceObjectByName( &AzAuthorizationStore->Groups,
  222. ChildObjectNameString,
  223. 0, // No special flags
  224. &ConflictGenericObject );
  225. if ( WinStatus == NO_ERROR ) {
  226. ObDereferenceObject( ConflictGenericObject );
  227. return ERROR_ALREADY_EXISTS;
  228. }
  229. //
  230. // Check groups that are children of child scopes.
  231. //
  232. WinStatus = ObCheckNameConflict( &Application->Scopes,
  233. ChildObjectNameString,
  234. offsetof(_AZP_SCOPE, Groups),
  235. 0,
  236. 0 );
  237. //
  238. // A group that is a child of a scope,
  239. // cannot have the same name as groups that are children of the application or authorization store
  240. //
  241. } else if ( ParentGenericObject->ObjectType == OBJECT_TYPE_SCOPE ) {
  242. AzAuthorizationStore = ParentGenericObject->AzStoreObject;
  243. Application = (PAZP_APPLICATION) ParentOfChild( ParentGenericObject );
  244. //
  245. // Check groups that are children of the application.
  246. //
  247. WinStatus = ObReferenceObjectByName( &Application->Groups,
  248. ChildObjectNameString,
  249. 0, // No special flags
  250. &ConflictGenericObject );
  251. if ( WinStatus == NO_ERROR ) {
  252. ObDereferenceObject( ConflictGenericObject );
  253. return ERROR_ALREADY_EXISTS;
  254. }
  255. //
  256. // Check groups that are children of the authorization store
  257. //
  258. //
  259. WinStatus = ObReferenceObjectByName( &AzAuthorizationStore->Groups,
  260. ChildObjectNameString,
  261. 0, // No special flags
  262. &ConflictGenericObject );
  263. if ( WinStatus == NO_ERROR ) {
  264. ObDereferenceObject( ConflictGenericObject );
  265. return ERROR_ALREADY_EXISTS;
  266. }
  267. WinStatus = NO_ERROR;
  268. } else {
  269. WinStatus = ERROR_INTERNAL_ERROR;
  270. ASSERT( FALSE );
  271. }
  272. return WinStatus;
  273. }
  274. DWORD
  275. AzpGroupGetProperty(
  276. IN PGENERIC_OBJECT GenericObject,
  277. IN ULONG Flags,
  278. IN ULONG PropertyId,
  279. OUT PVOID *PropertyValue
  280. )
  281. /*++
  282. Routine Description:
  283. This routine is the Group specific worker routine for AzGetProperty.
  284. It does any object specific property gets.
  285. On entry, AzGlResource must be locked shared.
  286. Arguments:
  287. GenericObject - Specifies a pointer to the object to be queried
  288. Flags - Specifies internal flags
  289. AZP_FLAGS_BY_GUID - name lists should be returned as GUID lists
  290. AZP_FLAGS_PERSIST_* - Call is from the persistence provider
  291. PropertyId - Specifies which property to return.
  292. PropertyValue - Specifies a pointer to return the property in.
  293. The returned pointer must be freed using AzFreeMemory.
  294. The returned value and type depends in PropertyId. The valid values are:
  295. AZ_PROP_GROUP_TYPE PULONG - Group type of the group
  296. AZ_PROP_GROUP_APP_MEMBERS AZ_STRING_ARRAY - Application groups that are members of this group
  297. AZ_PROP_GROUP_APP_NON_MEMBERS AZ_STRING_ARRAY - Application groups that are non-members of this group
  298. AZ_PROP_GROUP_LDAP_QUERY LPWSTR - Ldap query string of the group
  299. AZ_PROP_GROUP_MEMBERS AZ_SID_ARRAY - NT sids that are members of this group
  300. AZ_PROP_GROUP_NON_MEMBERS AZ_SID_ARRAY - NT sids that are non-members of this group
  301. Return Value:
  302. Status of the operation
  303. --*/
  304. {
  305. DWORD WinStatus = NO_ERROR;
  306. PAZP_GROUP Group = (PAZP_GROUP) GenericObject;
  307. //
  308. // Initialization
  309. //
  310. ASSERT( AzpIsLockedShared( &AzGlResource ) );
  311. //
  312. // Return any object specific attribute
  313. //
  314. //
  315. switch ( PropertyId ) {
  316. case AZ_PROP_GROUP_TYPE:
  317. *PropertyValue = AzpGetUlongProperty( Group->GroupType );
  318. if ( *PropertyValue == NULL ) {
  319. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  320. }
  321. break;
  322. // Return the set of app members to the caller
  323. case AZ_PROP_GROUP_APP_MEMBERS:
  324. if ( Flags & AZP_FLAGS_BY_GUID )
  325. {
  326. *PropertyValue = ObGetPropertyItemGuids( &Group->AppMembers );
  327. }
  328. else
  329. {
  330. *PropertyValue = ObGetPropertyItems( &Group->AppMembers );
  331. }
  332. if ( *PropertyValue == NULL ) {
  333. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  334. }
  335. break;
  336. case AZ_PROP_GROUP_APP_NON_MEMBERS:
  337. if ( Flags & AZP_FLAGS_BY_GUID )
  338. {
  339. *PropertyValue = ObGetPropertyItemGuids( &Group->AppNonMembers );
  340. }
  341. else
  342. {
  343. *PropertyValue = ObGetPropertyItems( &Group->AppNonMembers );
  344. }
  345. if ( *PropertyValue == NULL ) {
  346. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  347. }
  348. break;
  349. // Return the set of sid members to the caller
  350. case AZ_PROP_GROUP_MEMBERS:
  351. *PropertyValue = ObGetPropertyItems( &Group->SidMembers );
  352. if ( *PropertyValue == NULL ) {
  353. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  354. }
  355. break;
  356. case AZ_PROP_GROUP_NON_MEMBERS:
  357. *PropertyValue = ObGetPropertyItems( &Group->SidNonMembers );
  358. if ( *PropertyValue == NULL ) {
  359. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  360. }
  361. break;
  362. //
  363. // Return ldap query string to the caller
  364. //
  365. case AZ_PROP_GROUP_LDAP_QUERY:
  366. *PropertyValue = AzpGetStringProperty( &Group->LdapQuery );
  367. if ( *PropertyValue == NULL ) {
  368. WinStatus = ERROR_NOT_ENOUGH_MEMORY;
  369. }
  370. break;
  371. default:
  372. AzPrint(( AZD_INVPARM, "AzpGroupGetProperty: invalid opcode %ld\n", PropertyId ));
  373. WinStatus = ERROR_INVALID_PARAMETER;
  374. break;
  375. }
  376. return WinStatus;
  377. }
  378. DWORD
  379. AzpGroupSetProperty(
  380. IN PGENERIC_OBJECT GenericObject,
  381. IN ULONG Flags,
  382. IN ULONG PropertyId,
  383. IN PVOID PropertyValue
  384. )
  385. /*++
  386. Routine Description:
  387. This routine is the Group object specific worker routine for AzSetProperty.
  388. It does any object specific property sets.
  389. On entry, AzGlResource must be locked exclusive.
  390. Arguments:
  391. GenericObject - Specifies a pointer to the object to be modified
  392. Flags - Specifies flags controlling to operation of the routine
  393. AZP_FLAGS_SETTING_TO_DEFAULT - Property is being set to default value
  394. AZP_FLAGS_PERSIST_* - Call is from the persistence provider
  395. PropertyId - Specifies which property to set.
  396. PropertyValue - Specifies a pointer to the property.
  397. The specified value and type depends in PropertyId. The valid values are:
  398. AZ_PROP_GROUP_TYPE PULONG - Group type of the group
  399. AZ_PROP_GROUP_LDAP_QUERY LPWSTR - Ldap query string of the group
  400. Return Value:
  401. Status of the operation
  402. --*/
  403. {
  404. DWORD WinStatus = NO_ERROR;
  405. PAZP_GROUP Group = (PAZP_GROUP) GenericObject;
  406. AZP_STRING CapturedString;
  407. LONG LocalGroupType;
  408. BOOL bHasChanged = TRUE;
  409. //
  410. // Initialization
  411. //
  412. UNREFERENCED_PARAMETER( Flags );
  413. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  414. AzpInitString( &CapturedString, NULL );
  415. //
  416. // Set the group type
  417. //
  418. switch ( PropertyId ) {
  419. case AZ_PROP_GROUP_TYPE:
  420. BEGIN_SETPROP( &WinStatus, Group, Flags, AZ_DIRTY_GROUP_TYPE ) {
  421. WinStatus = AzpCaptureLong( PropertyValue, &LocalGroupType );
  422. if ( WinStatus != NO_ERROR ) {
  423. goto Cleanup;
  424. }
  425. //
  426. // Do parameter validity checking
  427. //
  428. BEGIN_VALIDITY_CHECKING( Flags ) {
  429. //
  430. // Ensure that changing the group type doesn't orphan any data
  431. //
  432. if ( LocalGroupType == AZ_GROUPTYPE_LDAP_QUERY ) {
  433. //
  434. // An LDAP query group can have no membership links
  435. //
  436. if ( Group->AppMembers.GenericObjects.UsedCount != 0 ||
  437. Group->AppNonMembers.GenericObjects.UsedCount != 0 ||
  438. Group->SidMembers.GenericObjects.UsedCount != 0 ||
  439. Group->SidNonMembers.GenericObjects.UsedCount != 0 ) {
  440. AzPrint(( AZD_INVPARM, "AzpGroupGetProperty: cannot set group type to ldap query if group has membership.\n" ));
  441. WinStatus = ERROR_INVALID_PARAMETER;
  442. goto Cleanup;
  443. }
  444. } else if ( LocalGroupType == AZ_GROUPTYPE_BASIC ) {
  445. //
  446. // A basic group can have no LDAP query string
  447. //
  448. if ( Group->LdapQuery.StringSize != 0 ) {
  449. AzPrint(( AZD_INVPARM, "AzpGroupGetProperty: cannot set group type to basic if group has ldap query string.\n" ));
  450. WinStatus = ERROR_INVALID_PARAMETER;
  451. goto Cleanup;
  452. }
  453. } else {
  454. AzPrint(( AZD_INVPARM, "AzpGroupGetProperty: invalid grouptype %ld\n", LocalGroupType ));
  455. WinStatus = ERROR_INVALID_PARAMETER;
  456. goto Cleanup;
  457. }
  458. } END_VALIDITY_CHECKING;
  459. Group->GroupType = LocalGroupType;
  460. } END_SETPROP(bHasChanged);
  461. break;
  462. //
  463. // Set LDAP Query string on the object
  464. //
  465. case AZ_PROP_GROUP_LDAP_QUERY:
  466. BEGIN_SETPROP( &WinStatus, Group, Flags, AZ_DIRTY_GROUP_LDAP_QUERY ) {
  467. //
  468. // Capture the input string
  469. //
  470. WinStatus = AzpCaptureString( &CapturedString,
  471. (LPWSTR) PropertyValue,
  472. CHECK_STRING_LENGTH( Flags, AZ_MAX_GROUP_LDAP_QUERY_LENGTH),
  473. TRUE ); // NULL is OK
  474. if ( WinStatus != NO_ERROR ) {
  475. goto Cleanup;
  476. }
  477. //
  478. // Only process the change if the strings have changed
  479. //
  480. bHasChanged = !AzpEqualStrings( &CapturedString, &Group->LdapQuery );
  481. if ( bHasChanged ) {
  482. //
  483. // Do parameter validity checking
  484. //
  485. BEGIN_VALIDITY_CHECKING( Flags ) {
  486. //
  487. // Only allow this propery if the group type is right
  488. // (But let them clear it out)
  489. //
  490. if ( Group->GroupType != AZ_GROUPTYPE_LDAP_QUERY &&
  491. CapturedString.StringSize != 0 ) {
  492. AzPrint(( AZD_INVPARM, "AzpGroupSetProperty: can't set ldap query before group type\n" ));
  493. WinStatus = ERROR_INVALID_PARAMETER;
  494. goto Cleanup;
  495. }
  496. } END_VALIDITY_CHECKING;
  497. //
  498. // Swap the old/new names
  499. //
  500. AzpSwapStrings( &CapturedString, &Group->LdapQuery );
  501. //
  502. // Mark that the group membership caches need flushing
  503. //
  504. Group->GenericObject.AzStoreObject->GroupEvalSerialNumber ++;
  505. AzPrint(( AZD_ACCESS_MORE, "AzpGroupSetProperty: GroupEvalSerialNumber set to %ld\n",
  506. Group->GenericObject.AzStoreObject->GroupEvalSerialNumber ));
  507. }
  508. } END_SETPROP(bHasChanged);
  509. break;
  510. default:
  511. AzPrint(( AZD_INVPARM, "AzpGroupSetProperty: invalid propid %ld\n", PropertyId ));
  512. WinStatus = ERROR_INVALID_PARAMETER;
  513. goto Cleanup;
  514. }
  515. //
  516. // Free any local resources
  517. //
  518. Cleanup:
  519. AzpFreeString( &CapturedString );
  520. return WinStatus;
  521. }
  522. DWORD
  523. AzpGroupCheckRefLoop(
  524. IN PAZP_GROUP ParentGroup,
  525. IN PAZP_GROUP CurrentGroup,
  526. IN ULONG GenericObjectListOffset
  527. )
  528. /*++
  529. Routine Description:
  530. This routine determines whether the group members of "CurrentGroup"
  531. reference "ParentGroup". This is done to detect loops where the
  532. group references itself directly or indirectly.
  533. On entry, AzGlResource must be locked shared.
  534. Arguments:
  535. ParentGroup - Group that contains the original membership.
  536. CurrentGroup - Group that is currently being inspected to see if it
  537. loops back to ParentGroup
  538. GenericObjectListOffset - Offset to the particular GenericObjectList being
  539. checked.
  540. Return Value:
  541. Status of the operation
  542. ERROR_DS_LOOP_DETECT - A loop has been detected.
  543. --*/
  544. {
  545. ULONG WinStatus;
  546. PGENERIC_OBJECT_LIST GenericObjectList;
  547. ULONG i;
  548. PAZP_GROUP NextGroup;
  549. //
  550. // Check for a reference to ourself
  551. //
  552. ASSERT( AzpIsLockedShared( &AzGlResource ) );
  553. if ( ParentGroup == CurrentGroup ) {
  554. return ERROR_DS_LOOP_DETECT;
  555. }
  556. //
  557. // Compute a pointer to the membership list to check
  558. //
  559. GenericObjectList = (PGENERIC_OBJECT_LIST)
  560. (((LPBYTE)CurrentGroup)+GenericObjectListOffset);
  561. //
  562. // Check all groups that are members of the current group
  563. //
  564. for ( i=0; i<GenericObjectList->GenericObjects.UsedCount; i++ ) {
  565. NextGroup = (PAZP_GROUP) (GenericObjectList->GenericObjects.Array[i]);
  566. //
  567. // Recursively check this group
  568. //
  569. WinStatus = AzpGroupCheckRefLoop( ParentGroup, NextGroup, GenericObjectListOffset );
  570. if ( WinStatus != NO_ERROR ) {
  571. return WinStatus;
  572. }
  573. }
  574. return NO_ERROR;
  575. }
  576. DWORD
  577. AzpGroupAddPropertyItem(
  578. IN PGENERIC_OBJECT GenericObject,
  579. IN PGENERIC_OBJECT_LIST GenericObjectList,
  580. IN PGENERIC_OBJECT LinkedToObject
  581. )
  582. /*++
  583. Routine Description:
  584. This routine is the group object specific worker routine for AzAddPropertyItem.
  585. It does any object specific property adds
  586. On entry, AzGlResource must be locked exclusive.
  587. Arguments:
  588. GenericObject - Specifies a pointer to the object to be modified
  589. GenericObjectList - Specifies the object list the object is to be added to
  590. LinkedToObject - Specifies the object that is being linked to
  591. Return Value:
  592. Status of the operation
  593. --*/
  594. {
  595. DWORD WinStatus = NO_ERROR;
  596. PAZP_GROUP Group = (PAZP_GROUP) GenericObject;
  597. //
  598. // Initialization
  599. //
  600. ASSERT( AzpIsLockedExclusive( &AzGlResource ) );
  601. //
  602. // All item adds are membership additions.
  603. // Ensure the group has the right group type.
  604. //
  605. if ( Group->GroupType != AZ_GROUPTYPE_BASIC ) {
  606. AzPrint(( AZD_INVPARM, "AzpGroupAddPropertyItem: invalid group type %ld\n", Group->GroupType ));
  607. WinStatus = ERROR_INVALID_PARAMETER;
  608. goto Cleanup;
  609. }
  610. //
  611. // If we're linking to a group,
  612. // Ensure this newly added membership doesn't cause a group membership loop
  613. //
  614. if ( LinkedToObject->ObjectType == OBJECT_TYPE_GROUP ) {
  615. WinStatus = AzpGroupCheckRefLoop( Group,
  616. (PAZP_GROUP)LinkedToObject,
  617. (ULONG)(((LPBYTE)GenericObjectList)-((LPBYTE)Group)) );
  618. }
  619. //
  620. // Free any local resources
  621. //
  622. Cleanup:
  623. return WinStatus;
  624. }
  625. DWORD
  626. AzpGroupGetGenericChildHead(
  627. IN AZ_HANDLE ParentHandle,
  628. OUT PULONG ObjectType,
  629. OUT PGENERIC_OBJECT_HEAD *GenericChildHead
  630. )
  631. /*++
  632. Routine Description:
  633. This routine determines whether ParentHandle supports Group objects as
  634. children.
  635. Arguments:
  636. ParentHandle - Specifies a handle to the object that is the parent of the group.
  637. This may be an authorization store handle, an Application Handle, or a
  638. Scope handle.
  639. ObjectType - Returns the object type of the ParentHandle.
  640. GenericChildHead - Returns a pointer to the head of the list of groups objects
  641. that are children of the object specified by ParentHandle. This in an unverified
  642. pointer. The pointer is only valid after ParentHandle has been validated.
  643. Return Value:
  644. Status of the operation.
  645. --*/
  646. {
  647. DWORD WinStatus;
  648. //
  649. // Determine the type of the parent handle
  650. //
  651. WinStatus = ObGetHandleType( (PGENERIC_OBJECT)ParentHandle,
  652. FALSE, // ignore deleted objects
  653. ObjectType );
  654. if ( WinStatus != NO_ERROR ) {
  655. return WinStatus;
  656. }
  657. //
  658. // Verify that the specified handle support children groups.
  659. //
  660. switch ( *ObjectType ) {
  661. case OBJECT_TYPE_AZAUTHSTORE:
  662. *GenericChildHead = &(((PAZP_AZSTORE)ParentHandle)->Groups);
  663. break;
  664. case OBJECT_TYPE_APPLICATION:
  665. *GenericChildHead = &(((PAZP_APPLICATION)ParentHandle)->Groups);
  666. break;
  667. case OBJECT_TYPE_SCOPE:
  668. *GenericChildHead = &(((PAZP_SCOPE)ParentHandle)->Groups);
  669. break;
  670. default:
  671. return ERROR_INVALID_HANDLE;
  672. }
  673. return NO_ERROR;
  674. }
  675. DWORD
  676. WINAPI
  677. AzGroupCreate(
  678. IN AZ_HANDLE ParentHandle,
  679. IN LPCWSTR GroupName,
  680. IN DWORD Reserved,
  681. OUT PAZ_HANDLE GroupHandle
  682. )
  683. /*++
  684. Routine Description:
  685. This routine adds a group into the scope of the specified parent object.
  686. Arguments:
  687. ParentHandle - Specifies a handle to the object that is the parent of the group.
  688. This may be an authorization store handle, an Application Handle, or a
  689. Scope handle.
  690. GroupName - Specifies the name of the group to add.
  691. Reserved - Reserved. Must by zero.
  692. GroupHandle - Return a handle to the group.
  693. The caller must close this handle by calling AzCloseHandle.
  694. Return Value:
  695. NO_ERROR - The operation was successful
  696. ERROR_ALREADY_EXISTS - An object by that name already exists
  697. --*/
  698. {
  699. DWORD WinStatus;
  700. DWORD ObjectType;
  701. PGENERIC_OBJECT_HEAD GenericChildHead;
  702. //
  703. // Determine that the parent handle supports groups as children
  704. //
  705. WinStatus = AzpGroupGetGenericChildHead( ParentHandle,
  706. &ObjectType,
  707. &GenericChildHead );
  708. if ( WinStatus != NO_ERROR ) {
  709. return WinStatus;
  710. }
  711. //
  712. // Call the common routine to do most of the work
  713. //
  714. return ObCommonCreateObject(
  715. (PGENERIC_OBJECT) ParentHandle,
  716. ObjectType,
  717. GenericChildHead,
  718. OBJECT_TYPE_GROUP,
  719. GroupName,
  720. Reserved,
  721. (PGENERIC_OBJECT *) GroupHandle );
  722. }
  723. DWORD
  724. WINAPI
  725. AzGroupOpen(
  726. IN AZ_HANDLE ParentHandle,
  727. IN LPCWSTR GroupName,
  728. IN DWORD Reserved,
  729. OUT PAZ_HANDLE GroupHandle
  730. )
  731. /*++
  732. Routine Description:
  733. This routine opens a group into the scope of the specified parent object.
  734. Arguments:
  735. ParentHandle - Specifies a handle to the object that is the parent of the group.
  736. This may be an authorization store handle, an Application Handle, or a
  737. Scope handle.
  738. GroupName - Specifies the name of the group to open
  739. Reserved - Reserved. Must by zero.
  740. GroupHandle - Return a handle to the group.
  741. The caller must close this handle by calling AzCloseHandle.
  742. Return Value:
  743. NO_ERROR - The operation was successful
  744. ERROR_NOT_FOUND - There is no group by that name
  745. --*/
  746. {
  747. DWORD WinStatus;
  748. DWORD ObjectType;
  749. PGENERIC_OBJECT_HEAD GenericChildHead;
  750. //
  751. // Determine that the parent handle supports groups as children
  752. //
  753. WinStatus = AzpGroupGetGenericChildHead( ParentHandle,
  754. &ObjectType,
  755. &GenericChildHead );
  756. if ( WinStatus != NO_ERROR ) {
  757. return WinStatus;
  758. }
  759. //
  760. // Call the common routine to do most of the work
  761. //
  762. return ObCommonOpenObject(
  763. (PGENERIC_OBJECT) ParentHandle,
  764. ObjectType,
  765. GenericChildHead,
  766. OBJECT_TYPE_GROUP,
  767. GroupName,
  768. Reserved,
  769. (PGENERIC_OBJECT *) GroupHandle );
  770. }
  771. DWORD
  772. WINAPI
  773. AzGroupEnum(
  774. IN AZ_HANDLE ParentHandle,
  775. IN DWORD Reserved,
  776. IN OUT PULONG EnumerationContext,
  777. OUT PAZ_HANDLE GroupHandle
  778. )
  779. /*++
  780. Routine Description:
  781. Enumerates all of the groups for the specified parent object.
  782. Arguments:
  783. ParentHandle - Specifies a handle to the object that is the parent of the group.
  784. This may be an authorization store handle, an Application Handle, or a
  785. Scope handle.
  786. Reserved - Reserved. Must by zero.
  787. EnumerationContext - Specifies a context indicating the next group to return
  788. On input for the first call, should point to zero.
  789. On input for subsequent calls, should point to the value returned on the previous call.
  790. On output, returns a value to be passed on the next call.
  791. GroupHandle - Returns a handle to the next group object.
  792. The caller must close this handle by calling AzCloseHandle.
  793. Return Value:
  794. NO_ERROR - The operation was successful (a handle was returned)
  795. ERROR_NO_MORE_ITEMS - No more items were available for enumeration
  796. --*/
  797. {
  798. DWORD WinStatus;
  799. DWORD ObjectType;
  800. PGENERIC_OBJECT_HEAD GenericChildHead;
  801. //
  802. // Determine that the parent handle supports groups as children
  803. //
  804. WinStatus = AzpGroupGetGenericChildHead( ParentHandle,
  805. &ObjectType,
  806. &GenericChildHead );
  807. if ( WinStatus != NO_ERROR ) {
  808. return WinStatus;
  809. }
  810. //
  811. // Call the common routine to do most of the work
  812. //
  813. return ObCommonEnumObjects(
  814. (PGENERIC_OBJECT) ParentHandle,
  815. ObjectType,
  816. GenericChildHead,
  817. EnumerationContext,
  818. Reserved,
  819. (PGENERIC_OBJECT *) GroupHandle );
  820. }
  821. DWORD
  822. WINAPI
  823. AzGroupDelete(
  824. IN AZ_HANDLE ParentHandle,
  825. IN LPCWSTR GroupName,
  826. IN DWORD Reserved
  827. )
  828. /*++
  829. Routine Description:
  830. This routine deletes a group from the scope of the specified parent object.
  831. Also deletes any child objects of GroupName.
  832. Arguments:
  833. ParentHandle - Specifies a handle to the object that is the parent of the group.
  834. This may be an authorization store handle, an Application Handle, or a
  835. Scope handle.
  836. GroupName - Specifies the name of the group to delete.
  837. Reserved - Reserved. Must by zero.
  838. Return Value:
  839. NO_ERROR - The operation was successful
  840. ERROR_NOT_FOUND - An object by that name cannot be found
  841. --*/
  842. {
  843. DWORD WinStatus;
  844. DWORD ObjectType;
  845. PGENERIC_OBJECT_HEAD GenericChildHead;
  846. //
  847. // Determine that the parent handle supports groups as children
  848. //
  849. WinStatus = AzpGroupGetGenericChildHead( ParentHandle,
  850. &ObjectType,
  851. &GenericChildHead );
  852. if ( WinStatus != NO_ERROR ) {
  853. return WinStatus;
  854. }
  855. //
  856. // Call the common routine to do most of the work
  857. //
  858. return ObCommonDeleteObject(
  859. (PGENERIC_OBJECT) ParentHandle,
  860. ObjectType,
  861. GenericChildHead,
  862. OBJECT_TYPE_GROUP,
  863. GroupName,
  864. Reserved );
  865. }