acllist.c 26 KB

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