acllist.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. /************************************************************************
  7. *
  8. * ACLLIST
  9. *
  10. * All the ACLs are read when the server is started. The ACLs are
  11. * parsed and kept in an AVL tree. All the ACL List management are
  12. * in this file.
  13. *
  14. * The locking on the aci cache is implemented using the acllist_acicache*()
  15. * routines--a read/write lock.
  16. *
  17. * The granularity of the view of the cache is the entry level--ie.
  18. * when an entry is being modified (mod,add,delete,modrdn) and the mod
  19. * involves the aci attribute, then other operations will see the acl cache
  20. * before the whole change or after the whole change, but not during the change.
  21. * cf. acl.c:acl_modified()
  22. *
  23. * The only tricky issue is that there is also locking
  24. * implemented for the anonymous profile and sometimes we need to take both
  25. * locks cf. aclanom_anom_genProfile(). The rule is
  26. * always take the acicache lock first, followed by the anon lock--following
  27. * this rule will ensure no dead lock scenarios can arise.
  28. *
  29. * Some routines are called in different places with different lock
  30. * contexts--for these routines acl_lock_flag_t is used to
  31. * pass the context.
  32. *
  33. */
  34. #include "acl.h"
  35. static PRRWLock *aci_rwlock = NULL;
  36. #define ACILIST_LOCK_READ() PR_RWLock_Rlock (aci_rwlock )
  37. #define ACILIST_UNLOCK_READ() PR_RWLock_Unlock (aci_rwlock )
  38. #define ACILIST_LOCK_WRITE() PR_RWLock_Wlock (aci_rwlock )
  39. #define ACILIST_UNLOCK_WRITE() PR_RWLock_Unlock (aci_rwlock )
  40. /* Root of the TREE */
  41. static Avlnode *acllistRoot = NULL;
  42. #define CONTAINER_INCR 2000
  43. /* The container array */
  44. static AciContainer **aciContainerArray;
  45. static PRUint32 currContainerIndex =0;
  46. static PRUint32 maxContainerIndex = 0;
  47. static int curAciIndex = 1;
  48. /* PROTOTYPES */
  49. static int __acllist_add_aci ( aci_t *aci );
  50. static int __acllist_aciContainer_node_cmp ( caddr_t d1, caddr_t d2 );
  51. static int __acllist_aciContainer_node_dup ( caddr_t d1, caddr_t d2 );
  52. static void __acllist_free_aciContainer ( AciContainer **container);
  53. static void free_targetattrfilters( Targetattrfilter ***input_attrFilterArray);
  54. void my_print( Avlnode *root );
  55. int
  56. acllist_init ()
  57. {
  58. if (( aci_rwlock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,"ACLLIST LOCK") ) == NULL ) {
  59. slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
  60. "acllist_init:failed in getting the rwlock\n" );
  61. return 1;
  62. }
  63. aciContainerArray = (AciContainer **) slapi_ch_calloc ( 1,
  64. CONTAINER_INCR * sizeof ( AciContainer * ) );
  65. maxContainerIndex = CONTAINER_INCR;
  66. currContainerIndex = 0;
  67. return 0;
  68. }
  69. /*
  70. * This is the callback for backend state changes.
  71. * It needs to add/remove acis as backends come up and go down.
  72. *
  73. * The strategy is simple:
  74. * When a backend moves to the SLAPI_BE_STATE_ON then we go get all the acis
  75. * add them to the cache.
  76. * When a backend moves out of the SLAPI_BE_STATE_ON then we remove them all.
  77. *
  78. */
  79. void acl_be_state_change_fnc ( void *handle, char *be_name, int old_state,
  80. int new_state) {
  81. Slapi_Backend *be=NULL;
  82. const Slapi_DN *sdn;
  83. if ( old_state == SLAPI_BE_STATE_ON && new_state != SLAPI_BE_STATE_ON) {
  84. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  85. "Backend %s is no longer STARTED--deactivating it's acis\n",
  86. be_name);
  87. if ( (be = slapi_be_select_by_instance_name( be_name )) == NULL) {
  88. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  89. "Failed to retreive backend--NOT activating it's acis\n");
  90. return;
  91. }
  92. /*
  93. * Just get the first suffix--if there are multiple XXX ?
  94. */
  95. if ( (sdn = slapi_be_getsuffix( be, 0)) == NULL ) {
  96. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  97. "Failed to retreive backend--NOT activating it's acis\n");
  98. return;
  99. }
  100. aclinit_search_and_update_aci ( 1, /* thisbeonly */
  101. sdn, /* base */
  102. be_name,/* be name */
  103. LDAP_SCOPE_SUBTREE,
  104. ACL_REMOVE_ACIS,
  105. DO_TAKE_ACLCACHE_WRITELOCK);
  106. } else if ( old_state != SLAPI_BE_STATE_ON && new_state == SLAPI_BE_STATE_ON) {
  107. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  108. "Backend %s is now STARTED--activating it's acis\n", be_name);
  109. if ( (be = slapi_be_select_by_instance_name( be_name )) == NULL) {
  110. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  111. "Failed to retreive backend--NOT activating it's acis\n");
  112. return;
  113. }
  114. /*
  115. * In fact there can onlt be one sufffix here.
  116. */
  117. if ( (sdn = slapi_be_getsuffix( be, 0)) == NULL ) {
  118. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  119. "Failed to retreive backend--NOT activating it's acis\n");
  120. return;
  121. }
  122. aclinit_search_and_update_aci ( 1, /* thisbeonly */
  123. sdn,
  124. be_name, /* be name */
  125. LDAP_SCOPE_SUBTREE,
  126. ACL_ADD_ACIS,
  127. DO_TAKE_ACLCACHE_WRITELOCK);
  128. }
  129. }
  130. /* This routine must be called with the acicache write lock taken */
  131. int
  132. acllist_insert_aci_needsLock( const Slapi_DN *e_sdn, const struct berval* aci_attr)
  133. {
  134. aci_t *aci;
  135. char *acl_str;
  136. int rv =0;
  137. if (aci_attr->bv_len <= 0)
  138. return 0;
  139. aci = acllist_get_aci_new ();
  140. slapi_sdn_set_ndn_byval ( aci->aci_sdn, slapi_sdn_get_ndn ( e_sdn ) );
  141. acl_str = slapi_ch_strdup(aci_attr->bv_val);
  142. /* Parse the ACL TEXT */
  143. if ( 0 != (rv = acl_parse ( acl_str, aci )) ) {
  144. slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
  145. "ACL PARSE ERR(rv=%d): %s\n", rv, acl_str );
  146. slapi_ch_free ( (void **) &acl_str );
  147. acllist_free_aci ( aci );
  148. return 1;
  149. }
  150. /* Now add it to the list */
  151. if ( 0 != (rv =__acllist_add_aci ( aci ))) {
  152. slapi_log_error (SLAPI_LOG_ACL, plugin_name,
  153. "ACL ADD ACI ERR(rv=%d): %s\n", rv, acl_str );
  154. slapi_ch_free ( (void **) &acl_str );
  155. acllist_free_aci ( aci );
  156. return 1;
  157. }
  158. slapi_ch_free ( (void **) &acl_str );
  159. acl_regen_aclsignature ();
  160. if ( aci->aci_elevel == ACI_ELEVEL_USERDN_ANYONE)
  161. aclanom_invalidateProfile ();
  162. return 0;
  163. }
  164. /* This routine must be called with the acicache write lock taken */
  165. static int
  166. __acllist_add_aci ( aci_t *aci )
  167. {
  168. int rv = 0; /* OK */
  169. AciContainer *aciListHead;
  170. AciContainer *head;
  171. PRUint32 i;
  172. aciListHead = acllist_get_aciContainer_new ( );
  173. slapi_sdn_set_ndn_byval ( aciListHead->acic_sdn, slapi_sdn_get_ndn ( aci->aci_sdn ) );
  174. /* insert the aci */
  175. switch (avl_insert ( &acllistRoot, aciListHead, __acllist_aciContainer_node_cmp,
  176. __acllist_aciContainer_node_dup ) ) {
  177. case 1: /* duplicate ACL on the same entry */
  178. /* Find the node that contains the acl. */
  179. if ( NULL == (head = (AciContainer *) avl_find( acllistRoot, aciListHead,
  180. (IFP) __acllist_aciContainer_node_cmp ) ) ) {
  181. slapi_log_error ( SLAPI_PLUGIN_ACL, plugin_name,
  182. "Can't insert the acl in the tree\n");
  183. rv = 1;
  184. } else {
  185. aci_t *t_aci;;
  186. /* Attach the list */
  187. t_aci = head->acic_list;;
  188. while ( t_aci && t_aci->aci_next )
  189. t_aci = t_aci->aci_next;
  190. /* Now add the new one to the end of the list */
  191. t_aci->aci_next = aci;
  192. }
  193. slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "Added the ACL:%s to existing container:[%d]%s\n",
  194. aci->aclName, head->acic_index, slapi_sdn_get_ndn( head->acic_sdn ));
  195. /* now free the tmp container */
  196. aciListHead->acic_list = NULL;
  197. __acllist_free_aciContainer ( &aciListHead );
  198. break;
  199. default:
  200. /* The container is inserted. Now hook up the aci and setup the
  201. * container index. Donot free the "aciListHead" here.
  202. */
  203. aciListHead->acic_list = aci;
  204. /*
  205. * First, see if we have an open slot or not - -if we have reuse it
  206. */
  207. i = 0;
  208. while ( (i < currContainerIndex) && aciContainerArray[i] )
  209. i++;
  210. if ( currContainerIndex >= (maxContainerIndex - 2)) {
  211. maxContainerIndex += CONTAINER_INCR;
  212. aciContainerArray = (AciContainer **) slapi_ch_realloc ( (char *) aciContainerArray,
  213. maxContainerIndex * sizeof ( AciContainer * ) );
  214. }
  215. aciListHead->acic_index = i;
  216. /* If i < currContainerIndex, we are just re-using an old slot. */
  217. /* We don't need to increase currContainerIndex if we just re-use an old one. */
  218. if (i == currContainerIndex)
  219. currContainerIndex++;
  220. aciContainerArray[ aciListHead->acic_index ] = aciListHead;
  221. slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "Added %s to container:%d\n",
  222. slapi_sdn_get_ndn( aciListHead->acic_sdn ), aciListHead->acic_index );
  223. break;
  224. }
  225. return rv;
  226. }
  227. static int
  228. __acllist_aciContainer_node_cmp ( caddr_t d1, caddr_t d2 )
  229. {
  230. int rc =0;
  231. AciContainer *c1 = (AciContainer *) d1;
  232. AciContainer *c2 = (AciContainer *) d2;
  233. rc = slapi_sdn_compare ( c1->acic_sdn, c2->acic_sdn );
  234. return rc;
  235. }
  236. static int
  237. __acllist_aciContainer_node_dup ( caddr_t d1, caddr_t d2 )
  238. {
  239. /* we allow duplicates -- they are not exactly duplicates
  240. ** but multiple aci value on the same node
  241. */
  242. return 1;
  243. }
  244. /*
  245. * Remove the ACL
  246. *
  247. * This routine must be called with the aclcache write lock taken.
  248. * It takes in addition the one for the anom profile taken in
  249. * aclanom_invalidateProfile().
  250. * They _must_ be taken in this order or there
  251. * is a deadlock scenario with aclanom_gen_anomProfile() which
  252. * also takes them is this order.
  253. */
  254. int
  255. acllist_remove_aci_needsLock( const Slapi_DN *sdn, const struct berval *attr )
  256. {
  257. aci_t *head, *next;
  258. int rv = 0;
  259. AciContainer *aciListHead, *root;
  260. AciContainer *dContainer;
  261. int removed_anom_acl = 0;
  262. /* we used to delete the ACL by value but we don't do that anymore.
  263. * rather we delete all the acls in that entry and then repopulate it if
  264. * there are any more acls.
  265. */
  266. aciListHead = acllist_get_aciContainer_new ( );
  267. slapi_sdn_set_ndn_byval ( aciListHead->acic_sdn, slapi_sdn_get_ndn ( sdn ) );
  268. /* now find it */
  269. if ( NULL == (root = (AciContainer *) avl_find( acllistRoot, aciListHead,
  270. (IFP) __acllist_aciContainer_node_cmp ))) {
  271. /* In that case we don't have any acl for this entry. cool !!! */
  272. __acllist_free_aciContainer ( &aciListHead );
  273. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  274. "No acis to remove in this entry\n" );
  275. return 0;
  276. }
  277. head = root->acic_list;
  278. if ( head)
  279. next = head->aci_next;
  280. while ( head ) {
  281. if ( head->aci_elevel == ACI_ELEVEL_USERDN_ANYONE)
  282. removed_anom_acl = 1;
  283. /* Free the acl */
  284. acllist_free_aci ( head );
  285. head = next;
  286. next = NULL;
  287. if ( head && head->aci_next )
  288. next = head->aci_next;
  289. }
  290. root->acic_list = NULL;
  291. /* remove the container from the slot */
  292. aciContainerArray[root->acic_index] = NULL;
  293. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  294. "Removing container[%d]=%s\n", root->acic_index,
  295. slapi_sdn_get_ndn ( root->acic_sdn) );
  296. dContainer = (AciContainer *) avl_delete ( &acllistRoot, aciListHead,
  297. __acllist_aciContainer_node_cmp );
  298. __acllist_free_aciContainer ( &dContainer );
  299. acl_regen_aclsignature ();
  300. if ( removed_anom_acl )
  301. aclanom_invalidateProfile ();
  302. /*
  303. * Now read back the entry and repopulate ACLs for that entry, but
  304. * only if a specific aci was deleted, otherwise, we do a
  305. * "When Harry met Sally" and nail 'em all.
  306. */
  307. if ( attr != NULL) {
  308. if (0 != (rv = aclinit_search_and_update_aci ( 0, /* thisbeonly */
  309. sdn, /* base */
  310. NULL, /* be name */
  311. LDAP_SCOPE_BASE,
  312. ACL_ADD_ACIS,
  313. DONT_TAKE_ACLCACHE_WRITELOCK))) {
  314. slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
  315. " Can't add the rest of the acls for entry:%s after delete\n",
  316. slapi_sdn_get_dn ( sdn ) );
  317. }
  318. }
  319. /* Now free the tmp container we used */
  320. __acllist_free_aciContainer ( &aciListHead );
  321. /*
  322. * regenerate the anonymous profile if we have deleted
  323. * anyone acls.
  324. * We don't need the aclcache readlock because the context of
  325. * this routine is we have the write lock already.
  326. */
  327. if ( removed_anom_acl )
  328. aclanom_gen_anomProfile(DONT_TAKE_ACLCACHE_READLOCK);
  329. return rv;
  330. }
  331. AciContainer *
  332. acllist_get_aciContainer_new ( )
  333. {
  334. AciContainer *head;
  335. head = (AciContainer * ) slapi_ch_calloc ( 1, sizeof ( AciContainer ) );
  336. head->acic_sdn = slapi_sdn_new ( );
  337. head->acic_index = -1;
  338. return head;
  339. }
  340. static void
  341. __acllist_free_aciContainer ( AciContainer **container)
  342. {
  343. PR_ASSERT ( container != NULL );
  344. if ( (*container)->acic_index >= 0 )
  345. aciContainerArray[ (*container)->acic_index] = NULL;
  346. if ( (*container)->acic_sdn )
  347. slapi_sdn_free ( &(*container)->acic_sdn );
  348. slapi_ch_free ( (void **) container );
  349. }
  350. void
  351. acllist_done_aciContainer ( AciContainer *head )
  352. {
  353. PR_ASSERT ( head != NULL );
  354. slapi_sdn_done ( head->acic_sdn );
  355. head->acic_index = -1;
  356. /* The caller is responsible for taking care of list */
  357. head->acic_list = NULL;
  358. }
  359. aci_t *
  360. acllist_get_aci_new ()
  361. {
  362. aci_t *aci_item;
  363. aci_item = (aci_t *) slapi_ch_calloc (1, sizeof (aci_t));
  364. aci_item->aci_sdn = slapi_sdn_new ();
  365. aci_item->aci_index = curAciIndex++;
  366. aci_item->aci_elevel = ACI_DEFAULT_ELEVEL; /* by default it's a complex */
  367. aci_item->targetAttr = (Targetattr **) slapi_ch_calloc (
  368. ACL_INIT_ATTR_ARRAY,
  369. sizeof (Targetattr *));
  370. return aci_item;
  371. }
  372. void
  373. acllist_free_aci(aci_t *item)
  374. {
  375. Targetattr **attrArray;
  376. /* The caller is responsible for taking
  377. ** care of list issue
  378. */
  379. if (item == NULL) return;
  380. slapi_sdn_free ( &item->aci_sdn );
  381. slapi_filter_free (item->target, 1);
  382. /* slapi_filter_free(item->targetAttr, 1); */
  383. attrArray = item->targetAttr;
  384. if (attrArray) {
  385. int i = 0;
  386. Targetattr *attr;
  387. while (attrArray[i] != NULL) {
  388. attr = attrArray[i];
  389. if (attr->attr_type & ACL_ATTR_FILTER) {
  390. slapi_filter_free(attr->u.attr_filter, 1);
  391. } else {
  392. slapi_ch_free ( (void **) &attr->u.attr_str );
  393. }
  394. slapi_ch_free ( (void **) &attr );
  395. i++;
  396. }
  397. /* Now free the array */
  398. slapi_ch_free ( (void **) &attrArray );
  399. }
  400. /* Now free any targetattrfilters in this aci item */
  401. if ( item->targetAttrAddFilters ) {
  402. free_targetattrfilters(&item->targetAttrAddFilters);
  403. }
  404. if ( item->targetAttrDelFilters ) {
  405. free_targetattrfilters(&item->targetAttrDelFilters);
  406. }
  407. if (item->targetFilterStr) slapi_ch_free ( (void **) &item->targetFilterStr );
  408. slapi_filter_free(item->targetFilter, 1);
  409. /* free the handle */
  410. if (item->aci_handle) ACL_ListDestroy(NULL, item->aci_handle);
  411. /* Free the name */
  412. if (item->aclName) slapi_ch_free((void **) &item->aclName);
  413. /* Free any macro info*/
  414. if (item->aci_macro) {
  415. slapi_ch_free((void **) &item->aci_macro->match_this);
  416. slapi_ch_free((void **) &item->aci_macro);
  417. }
  418. /* free at last -- free at last */
  419. slapi_ch_free ( (void **) &item );
  420. }
  421. static void free_targetattrfilters( Targetattrfilter ***attrFilterArray) {
  422. if (*attrFilterArray) {
  423. int i = 0;
  424. Targetattrfilter *attrfilter;
  425. while ((*attrFilterArray)[i] != NULL) {
  426. attrfilter = (*attrFilterArray)[i];
  427. if ( attrfilter->attr_str != NULL) {
  428. slapi_ch_free ( (void **) &attrfilter->attr_str );
  429. }
  430. if (attrfilter->filter != NULL) {
  431. slapi_filter_free(attrfilter->filter, 1);
  432. }
  433. if( attrfilter->filterStr != NULL) {
  434. slapi_ch_free ( (void **) &attrfilter->filterStr );
  435. }
  436. slapi_ch_free ( (void **) &attrfilter );
  437. i++;
  438. }
  439. /* Now free the array */
  440. slapi_ch_free ( (void **) attrFilterArray );
  441. }
  442. }
  443. /* SEARCH */
  444. void
  445. acllist_init_scan (Slapi_PBlock *pb, int scope, char *base)
  446. {
  447. Acl_PBlock *aclpb;
  448. int i;
  449. AciContainer *root;
  450. char *basedn = NULL;
  451. int index;
  452. if ( acl_skip_access_check ( pb, NULL ) ) {
  453. return;
  454. }
  455. /*acllist_print_tree ( acllistRoot, &depth, "top", "top") ; */
  456. /* my_print ( acllistRoot );*/
  457. /* If we have an anonymous profile and I am an anom dude - let's skip it */
  458. if ( aclanom_is_client_anonymous ( pb )) {
  459. return;
  460. }
  461. aclpb = acl_get_aclpb (pb, ACLPB_BINDDN_PBLOCK );
  462. if ( !aclpb ) {
  463. slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Missing aclpb 4 \n" );
  464. return;
  465. }
  466. aclpb->aclpb_handles_index[0] = -1;
  467. /* If base is NULL - it means we are going to go thru all the ACLs
  468. * This is needed when we do anonymous profile generation.
  469. */
  470. if ( NULL == base ) {
  471. return;
  472. }
  473. aclpb->aclpb_state |= ACLPB_SEARCH_BASED_ON_LIST ;
  474. acllist_acicache_READ_LOCK();
  475. basedn = slapi_ch_strdup (base);
  476. index = 0;
  477. aclpb->aclpb_search_base = slapi_ch_strdup ( base );
  478. while (basedn ) {
  479. char *tmp = NULL;
  480. slapi_sdn_set_ndn_byref ( aclpb->aclpb_aclContainer->acic_sdn, basedn );
  481. root = (AciContainer *) avl_find( acllistRoot,
  482. (caddr_t) aclpb->aclpb_aclContainer,
  483. (IFP) __acllist_aciContainer_node_cmp);
  484. if ( index >= ACLPB_MAX_SELECTED_ACLS -2 ) {
  485. aclpb->aclpb_handles_index[0] = -1;
  486. slapi_ch_free ( (void **) &basedn);
  487. break;
  488. } else if ( NULL != root ) {
  489. aclpb->aclpb_base_handles_index[index++] = root->acic_index;
  490. aclpb->aclpb_base_handles_index[index] = -1;
  491. }
  492. tmp = slapi_dn_parent ( basedn );
  493. slapi_ch_free ( (void **) &basedn);
  494. basedn = tmp;
  495. }
  496. acllist_done_aciContainer ( aclpb->aclpb_aclContainer);
  497. if ( aclpb->aclpb_base_handles_index[0] == -1 )
  498. aclpb->aclpb_state &= ~ACLPB_SEARCH_BASED_ON_LIST ;
  499. acllist_acicache_READ_UNLOCK();
  500. i = 0;
  501. while ( i < ACLPB_MAX_SELECTED_ACLS && aclpb->aclpb_base_handles_index[i] != -1 ) {
  502. i++;
  503. }
  504. }
  505. /*
  506. * Initialize aclpb_handles_index[] (sentinel -1) to
  507. * contain a list of all aci items at and above edn in the DIT tree.
  508. * This list will be subsequestly scanned to find applicable aci's for
  509. * the given operation.
  510. */
  511. void
  512. acllist_aciscan_update_scan ( Acl_PBlock *aclpb, char *edn )
  513. {
  514. int i, index = 0;
  515. char *basedn = NULL;
  516. AciContainer *root;
  517. int is_not_search_base = 1;
  518. /* First copy the containers indx from the base to the one which is
  519. * going to be used.
  520. * The base handles get done in acllist_init_scan().
  521. * This stuff is only used if it's a search operation.
  522. */
  523. if ( aclpb && aclpb->aclpb_search_base ) {
  524. while ( aclpb->aclpb_base_handles_index[index] != -1 &&
  525. index < ACLPB_MAX_SELECTED_ACLS -2 ) {
  526. aclpb->aclpb_handles_index[index] =
  527. aclpb->aclpb_base_handles_index[index];
  528. index++;
  529. }
  530. if ( strcasecmp ( edn, aclpb->aclpb_search_base) == 0) {
  531. is_not_search_base = 0;
  532. }
  533. }
  534. aclpb->aclpb_handles_index[index] = -1;
  535. /*
  536. * Here, make a list of all the aci's that will apply
  537. * to edn ie. all aci's at and above edn in the DIT tree.
  538. *
  539. * Do this by walking up edn, looking at corresponding
  540. * points in the acllistRoot aci tree.
  541. *
  542. * If is_not_search_base is true, then we need to iterate on edn, otherwise
  543. * we've already got all the base handles above.
  544. *
  545. */
  546. if (is_not_search_base) {
  547. basedn = slapi_ch_strdup ( edn );
  548. while (basedn ) {
  549. char *tmp = NULL;
  550. slapi_sdn_set_ndn_byref ( aclpb->aclpb_aclContainer->acic_sdn, basedn );
  551. root = (AciContainer *) avl_find( acllistRoot,
  552. (caddr_t) aclpb->aclpb_aclContainer,
  553. (IFP) __acllist_aciContainer_node_cmp);
  554. slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
  555. "Searching AVL tree for update:%s: container:%d\n", basedn ,
  556. root ? root->acic_index: -1);
  557. if ( index >= ACLPB_MAX_SELECTED_ACLS -2 ) {
  558. aclpb->aclpb_handles_index[0] = -1;
  559. slapi_ch_free ( (void **) &basedn);
  560. break;
  561. } else if ( NULL != root ) {
  562. aclpb->aclpb_handles_index[index++] = root->acic_index;
  563. aclpb->aclpb_handles_index[index] = -1;
  564. }
  565. tmp = slapi_dn_parent ( basedn );
  566. slapi_ch_free ( (void **) &basedn);
  567. basedn = tmp;
  568. if ( aclpb->aclpb_search_base && tmp &&
  569. ( 0 == strcasecmp ( tmp, aclpb->aclpb_search_base))) {
  570. slapi_ch_free ( (void **) &basedn);
  571. tmp = NULL;
  572. }
  573. } /* while */
  574. }
  575. acllist_done_aciContainer ( aclpb->aclpb_aclContainer );
  576. i = 0;
  577. while ( i < ACLPB_MAX_SELECTED_ACLS && aclpb->aclpb_handles_index[i] != -1 ) {
  578. i++;
  579. }
  580. }
  581. aci_t *
  582. acllist_get_first_aci (Acl_PBlock *aclpb, PRUint32 *cookie )
  583. {
  584. int val;
  585. *cookie = val = 0;
  586. if ( aclpb && aclpb->aclpb_handles_index[0] != -1 ) {
  587. val = aclpb->aclpb_handles_index[*cookie];
  588. }
  589. if ( NULL == aciContainerArray[val]) {
  590. return ( acllist_get_next_aci ( aclpb, NULL, cookie ) );
  591. }
  592. return (aciContainerArray[val]->acic_list );
  593. }
  594. /*
  595. * acllist_get_next_aci
  596. * Return the next aci in the list
  597. *
  598. * Inputs
  599. * Acl_PBlock *aclpb -- acl Main block; if aclpb= NULL,
  600. * -- then we scan thru the whole list.
  601. * -- which is used by anom profile code.
  602. * aci_t *curaci -- the current aci
  603. * PRUint32 *cookie -- cookie -- to maintain a state (what's next)
  604. *
  605. */
  606. aci_t *
  607. acllist_get_next_aci ( Acl_PBlock *aclpb, aci_t *curaci, PRUint32 *cookie )
  608. {
  609. PRUint32 val;
  610. int scan_entire_list;
  611. /*
  612. Here, if we're passed a curaci and there's another aci in the same node,
  613. return that one.
  614. */
  615. if ( curaci && curaci->aci_next )
  616. return ( curaci->aci_next );
  617. /*
  618. Determine if we need to scan the entire list of acis.
  619. We do if the aclpb==NULL or if the first handle index is -1.
  620. That means that we want to go through
  621. the entire aciContainerArray up to the currContainerIndex to get
  622. acis; the -1 in the first position is a special keyword which tells
  623. us that the acis have changed, so we need to go through all of them.
  624. */
  625. scan_entire_list = (aclpb == NULL || aclpb->aclpb_handles_index[0] == -1);
  626. start:
  627. (*cookie)++;
  628. val = *cookie;
  629. /* if we are not scanning the entire aciContainerArray list, we only want to
  630. look at the indexes specified in the handles index */
  631. if ( !scan_entire_list )
  632. val = aclpb->aclpb_handles_index[*cookie];
  633. /* the hard max end */
  634. if ( val >= maxContainerIndex)
  635. return NULL;
  636. /* reached the end of the array */
  637. if ((!scan_entire_list && (*cookie >= (ACLPB_MAX_SELECTED_ACLS-1))) ||
  638. (*cookie >= currContainerIndex)) {
  639. return NULL;
  640. }
  641. /* if we're only using the handles list for our aciContainerArray
  642. indexes, the -1 value marks the end of that list */
  643. if ( !scan_entire_list && (aclpb->aclpb_handles_index[*cookie] == -1) ) {
  644. return NULL;
  645. }
  646. /* if we're scanning the entire list, and we hit a null value in the
  647. middle of the list, just try the next one; this can happen if
  648. an aci was deleted - it can leave "holes" in the array */
  649. if ( scan_entire_list && ( NULL == aciContainerArray[val])) {
  650. goto start;
  651. }
  652. if ( aciContainerArray[val] )
  653. return (aciContainerArray[val]->acic_list );
  654. else
  655. return NULL;
  656. }
  657. void
  658. acllist_acicache_READ_UNLOCK( )
  659. {
  660. ACILIST_UNLOCK_READ ();
  661. }
  662. void
  663. acllist_acicache_READ_LOCK()
  664. {
  665. /* get a reader lock */
  666. ACILIST_LOCK_READ ();
  667. }
  668. void
  669. acllist_acicache_WRITE_UNLOCK( )
  670. {
  671. ACILIST_UNLOCK_WRITE ();
  672. }
  673. void
  674. acllist_acicache_WRITE_LOCK( )
  675. {
  676. ACILIST_LOCK_WRITE ();
  677. }
  678. /* This routine must be called with the acicache write lock taken */
  679. int
  680. acllist_moddn_aci_needsLock ( Slapi_DN *oldsdn, char *newdn )
  681. {
  682. AciContainer *aciListHead;
  683. AciContainer *head;
  684. /* first get the container */
  685. aciListHead = acllist_get_aciContainer_new ( );
  686. slapi_sdn_free(&aciListHead->acic_sdn);
  687. aciListHead->acic_sdn = oldsdn;
  688. if ( NULL == (head = (AciContainer *) avl_find( acllistRoot, aciListHead,
  689. (IFP) __acllist_aciContainer_node_cmp ) ) ) {
  690. slapi_log_error ( SLAPI_PLUGIN_ACL, plugin_name,
  691. "Can't find the acl in the tree for moddn operation:olddn%s\n",
  692. slapi_sdn_get_ndn ( oldsdn ));
  693. aciListHead->acic_sdn = NULL;
  694. __acllist_free_aciContainer ( &aciListHead );
  695. return 1;
  696. }
  697. /* Now set the new DN */
  698. slapi_sdn_done ( head->acic_sdn );
  699. slapi_sdn_set_ndn_byval ( head->acic_sdn, newdn );
  700. aciListHead->acic_sdn = NULL;
  701. __acllist_free_aciContainer ( &aciListHead );
  702. return 0;
  703. }
  704. void
  705. acllist_print_tree ( Avlnode *root, int *depth, char *start, char *side)
  706. {
  707. AciContainer *aciHeadList;
  708. if ( NULL == root ) {
  709. return;
  710. }
  711. aciHeadList = (AciContainer *) root->avl_data;
  712. slapi_log_error ( SLAPI_LOG_ACL, "plugin_name",
  713. "Container[ Depth=%d%s-%s]: %s\n", *depth, start, side,
  714. slapi_sdn_get_ndn ( aciHeadList->acic_sdn ) );
  715. (*depth)++;
  716. acllist_print_tree ( root->avl_left, depth, side, "L" );
  717. acllist_print_tree ( root->avl_right, depth, side, "R" );
  718. (*depth)--;
  719. }
  720. static
  721. void
  722. ravl_print( Avlnode *root, int depth )
  723. {
  724. int i;
  725. AciContainer *aciHeadList;
  726. if ( root == 0 )
  727. return;
  728. ravl_print( root->avl_right, depth+1 );
  729. for ( i = 0; i < depth; i++ )
  730. printf( " " );
  731. aciHeadList = (AciContainer *) root->avl_data;
  732. printf( "%s\n", slapi_sdn_get_ndn ( aciHeadList->acic_sdn ) );
  733. ravl_print( root->avl_left, depth+1 );
  734. }
  735. void
  736. my_print( Avlnode *root )
  737. {
  738. printf( "********\n" );
  739. if ( root == 0 )
  740. printf( "\tNULL\n" );
  741. else
  742. ( void ) ravl_print( root, 0 );
  743. printf( "********\n" );
  744. }