acllist.c 27 KB

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