acllist.c 28 KB

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