views.c 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867
  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. /* plugin which implements directory server views */
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include "portable.h"
  45. #include "slapi-plugin.h"
  46. #include "statechange.h"
  47. #include "views.h"
  48. #include "slapi-plugin-compat4.h"
  49. #include "slapi-private.h"
  50. #define VIEW_OBJECTCLASS "nsView"
  51. #define VIEW_FILTER_ATTR "nsViewFilter"
  52. #define STATECHANGE_VIEWS_ID "Views"
  53. #define STATECHANGE_VIEWS_CONFG_FILTER "objectclass=" VIEW_OBJECTCLASS
  54. /* get file mode flags for unix */
  55. #ifndef _WIN32
  56. #include <sys/stat.h>
  57. #endif
  58. #define VIEWS_PLUGIN_SUBSYSTEM "views-plugin" /* used for logging */
  59. /* cache data structs */
  60. struct _viewLinkedList
  61. {
  62. void *pNext;
  63. void *pPrev;
  64. };
  65. typedef struct _viewLinkedList viewLinkedList;
  66. #if defined(DEBUG)
  67. #define _VIEW_DEBUG_FILTERS /* Turning on hurts performance */
  68. #endif
  69. struct _viewEntry
  70. {
  71. viewLinkedList list;
  72. char *pDn;
  73. char *viewfilter; /* the raw view */
  74. Slapi_Filter *includeAncestorFiltersFilter; /* the filter with all ancestor filters */
  75. Slapi_Filter *excludeAllButDescendentViewsFilter; /* for building the view of views */
  76. Slapi_Filter *excludeChildFiltersFilter; /* NOT all children views, for one level searches */
  77. Slapi_Filter *excludeGrandChildViewsFilter; /* view filter for one level searches */
  78. Slapi_Filter *includeChildViewsFilter; /* view filter for subtree searches */
  79. #ifdef _VIEW_DEBUG_FILTERS
  80. /* monitor the cached filters with these */
  81. char includeAncestorFiltersFilter_str[1024]; /* the filter with all ancestor filters */
  82. char excludeAllButDescendentViewsFilter_str[1024]; /* for building the view of views */
  83. char excludeChildFiltersFilter_str[1024]; /* NOT all children views, for one level searches */
  84. char excludeGrandChildViewsFilter_str[1024]; /* view filter for one level searches */
  85. char includeChildViewsFilter_str[1024]; /* view filter for subtree searches */
  86. #endif
  87. char *pSearch_base; /* the parent of the top most view */
  88. void *pParent;
  89. void **pChildren;
  90. int child_count;
  91. unsigned long entryid; /* unique identifier for this entry */
  92. unsigned long parentid; /* unique identifier for the parent entry */
  93. };
  94. typedef struct _viewEntry viewEntry;
  95. struct _globalViewCache
  96. {
  97. viewEntry *pCacheViews;
  98. viewEntry **ppViewIndex;
  99. int cache_built;
  100. int view_count;
  101. PRThread *currentUpdaterThread;
  102. };
  103. typedef struct _globalViewCache golbalViewCache;
  104. static golbalViewCache theCache;
  105. /* other function prototypes */
  106. int views_init( Slapi_PBlock *pb );
  107. static int views_start( Slapi_PBlock *pb );
  108. static int views_close( Slapi_PBlock *pb );
  109. static int views_cache_create();
  110. static void views_update_views_cache( Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data );
  111. static int views_cache_build_view_list(viewEntry **pViews);
  112. static int views_cache_index();
  113. static int views_dn_views_cb (Slapi_Entry* e, void *callback_data);
  114. static int views_cache_add_dn_views(char *dn, viewEntry **pViews);
  115. static void views_cache_add_ll_entry(void** attrval, void *theVal);
  116. static void views_cache_discover_parent(viewEntry *pView);
  117. static void views_cache_discover_parent_for_children(viewEntry *pView);
  118. static void views_cache_discover_children(viewEntry *pView);
  119. static void views_cache_discover_view_scope(viewEntry *pView);
  120. static void views_cache_create_applied_filter(viewEntry *pView);
  121. static void views_cache_create_exclusion_filter(viewEntry *pView);
  122. static void views_cache_create_inclusion_filter(viewEntry *pView);
  123. Slapi_Filter *views_cache_create_descendent_filter(viewEntry *ancestor, PRBool useID);
  124. static int view_search_rewrite_callback(Slapi_PBlock *pb);
  125. static void views_cache_backend_state_change(void *handle, char *be_name, int old_be_state, int new_be_state);
  126. static void views_cache_act_on_change_thread(void *arg);
  127. static viewEntry *views_cache_find_view(char *view);
  128. /* our api broker published api */
  129. static void *api[3];
  130. static int _internal_api_views_entry_exists(char *view_dn, Slapi_Entry *e);
  131. static int _internal_api_views_entry_dn_exists(char *view_dn, char *e_dn);
  132. static int _internal_api_views_entry_exists_general(char *view_dn, Slapi_Entry *e, char *e_dn);
  133. static Slapi_PluginDesc pdesc = { "views", VENDOR, DS_PACKAGE_VERSION,
  134. "virtual directory information tree views plugin" };
  135. static void * view_plugin_identity = NULL;
  136. static PRRWLock *g_views_cache_lock;
  137. #ifdef _WIN32
  138. int *module_ldap_debug = 0;
  139. void plugin_init_debug_level(int *level_ptr)
  140. {
  141. module_ldap_debug = level_ptr;
  142. }
  143. #endif
  144. /*
  145. ** Plugin identity mgmt
  146. */
  147. void view_set_plugin_identity(void * identity)
  148. {
  149. view_plugin_identity=identity;
  150. }
  151. void * view_get_plugin_identity()
  152. {
  153. return view_plugin_identity;
  154. }
  155. /*
  156. views_init
  157. --------
  158. adds our callbacks to the list
  159. */
  160. int views_init( Slapi_PBlock *pb )
  161. {
  162. int ret = 0;
  163. void * plugin_identity=NULL;
  164. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_init\n");
  165. /*
  166. ** Store the plugin identity for later use.
  167. ** Used for internal operations
  168. */
  169. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
  170. view_set_plugin_identity(plugin_identity);
  171. if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
  172. SLAPI_PLUGIN_VERSION_01 ) != 0 ||
  173. slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
  174. (void *) views_start ) != 0 ||
  175. slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
  176. (void *) views_close ) != 0 ||
  177. slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
  178. (void *)&pdesc ) != 0 )
  179. {
  180. slapi_log_error( SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM,
  181. "views_init: failed to register plugin\n" );
  182. ret = -1;
  183. }
  184. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_init\n");
  185. return ret;
  186. }
  187. void views_read_lock()
  188. {
  189. PR_RWLock_Rlock(g_views_cache_lock);
  190. }
  191. void views_write_lock()
  192. {
  193. PR_RWLock_Wlock(g_views_cache_lock);
  194. }
  195. void views_unlock()
  196. {
  197. PR_RWLock_Unlock(g_views_cache_lock);
  198. }
  199. /*
  200. views_start
  201. ---------
  202. This function publishes the interface for this plugin
  203. */
  204. static int views_start( Slapi_PBlock *pb )
  205. {
  206. int ret = 0;
  207. void **statechange_api;
  208. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_start\n");
  209. theCache.cache_built = 0;
  210. g_views_cache_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "views");
  211. /* first register our backend state change func (we'll use func pointer as handle) */
  212. slapi_register_backend_state_change((void *)views_cache_backend_state_change, views_cache_backend_state_change);
  213. /* create the view cache */
  214. views_cache_create();
  215. /* register callbacks for filter and search rewriting */
  216. slapi_compute_add_search_rewriter(view_search_rewrite_callback);
  217. /* register for state changes to view configuration */
  218. if(!slapi_apib_get_interface(StateChange_v1_0_GUID, &statechange_api))
  219. {
  220. statechange_register(statechange_api, STATECHANGE_VIEWS_ID, NULL, STATECHANGE_VIEWS_CONFG_FILTER, NULL, views_update_views_cache);
  221. }
  222. /* register our api so that other subsystems can be views aware */
  223. api[0] = NULL; /* reserved for api broker use */
  224. api[1] = (void *)_internal_api_views_entry_exists;
  225. api[2] = (void *)_internal_api_views_entry_dn_exists;
  226. if( slapi_apib_register(Views_v1_0_GUID, api) )
  227. {
  228. slapi_log_error( SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM, "views: failed to publish views interface\n");
  229. ret = -1;
  230. }
  231. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_start\n");
  232. return ret;
  233. }
  234. /* _internal_api_views_entry_exists()
  235. * ----------------------------------
  236. * externally published api to allow other subsystems to
  237. * be views aware. Given a view and an entry, this function
  238. * returns PR_TRUE if the entry would be returned by a subtree
  239. * search on the view, PR_FALSE otherwise.
  240. */
  241. static int _internal_api_views_entry_exists(char *view_dn, Slapi_Entry *e)
  242. {
  243. return _internal_api_views_entry_exists_general(view_dn, e, NULL);
  244. }
  245. static int _internal_api_views_entry_dn_exists(char *view_dn, char *e_dn)
  246. {
  247. return _internal_api_views_entry_exists_general(view_dn, NULL, e_dn);
  248. }
  249. static int _internal_api_views_entry_exists_general(char *view_dn, Slapi_Entry *e, char *e_dn)
  250. {
  251. int ret = 0;
  252. viewEntry *view;
  253. char *dn;
  254. /* there are two levels of scope for a view,
  255. * from the parent of the view without a view filter
  256. * and the parent of the top most view including a
  257. * view filter - either match will do
  258. */
  259. /* Read lock the cache */
  260. views_read_lock();
  261. /* find the view */
  262. view = views_cache_find_view(view_dn);
  263. if(0==view)
  264. {
  265. /* this is not the entry you are looking for */
  266. goto bail;
  267. }
  268. /* normal scope - is the view an ancestor of the entry */
  269. if(e_dn)
  270. dn = e_dn;
  271. else
  272. dn = slapi_entry_get_ndn(e);
  273. if(slapi_dn_issuffix(dn, view_dn))
  274. {
  275. /* this entry is physically contained in the view hiearchy */
  276. ret = -1;
  277. goto bail;
  278. }
  279. /* view scope - view hiearchy scope plus view filter */
  280. if(slapi_dn_issuffix(dn, view->pSearch_base))
  281. {
  282. if(0==e)
  283. {
  284. Slapi_DN *sdn = slapi_sdn_new_dn_byref(dn);
  285. slapi_search_internal_get_entry( sdn, NULL, &e , view_get_plugin_identity());
  286. slapi_sdn_free(&sdn);
  287. }
  288. /* so far so good, apply filter */
  289. if(0==slapi_filter_test_simple(e,view->includeAncestorFiltersFilter))
  290. {
  291. /* this entry would appear in the view */
  292. ret = -1;
  293. }
  294. }
  295. bail:
  296. views_unlock();
  297. return ret;
  298. }
  299. void views_cache_free()
  300. {
  301. viewEntry *head = theCache.pCacheViews;
  302. viewEntry *current;
  303. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_cache_free\n");
  304. /* free the cache */
  305. current = head;
  306. while(current != NULL)
  307. {
  308. viewEntry *theView = current;
  309. current = current->list.pNext;
  310. /* free the view */
  311. slapi_ch_free((void**)&theView->pDn);
  312. slapi_ch_free((void**)&theView->viewfilter);
  313. slapi_filter_free(theView->includeAncestorFiltersFilter,1);
  314. slapi_filter_free(theView->excludeAllButDescendentViewsFilter,1);
  315. slapi_filter_free(theView->excludeChildFiltersFilter,1);
  316. slapi_filter_free(theView->excludeGrandChildViewsFilter,1);
  317. slapi_filter_free(theView->includeChildViewsFilter,1);
  318. slapi_ch_free((void**)&theView->pSearch_base);
  319. slapi_ch_free((void**)&theView->pChildren);
  320. slapi_ch_free((void**)&theView);
  321. }
  322. theCache.pCacheViews = NULL;
  323. slapi_ch_free((void**)&theCache.ppViewIndex);
  324. theCache.view_count = 0;
  325. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_cache_free\n");
  326. }
  327. /*
  328. views_close
  329. ---------
  330. unregisters the interface for this plugin
  331. */
  332. static int views_close( Slapi_PBlock *pb )
  333. {
  334. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_close\n");
  335. /* unregister backend state change notification */
  336. slapi_unregister_backend_state_change((void *)views_cache_backend_state_change);
  337. views_cache_free();
  338. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_close\n");
  339. return 0;
  340. }
  341. /*
  342. views_cache_create
  343. ---------------------
  344. Walks the views in the DIT and populates the cache.
  345. */
  346. static int views_cache_create()
  347. {
  348. int ret = -1;
  349. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_cache_create\n");
  350. /* lock cache */
  351. views_write_lock();
  352. theCache.currentUpdaterThread = PR_GetCurrentThread(); /* to avoid deadlock */
  353. if(theCache.pCacheViews)
  354. {
  355. /* need to get rid of the existing views */
  356. views_cache_free();
  357. }
  358. /* grab the view entries */
  359. ret = views_cache_build_view_list(&(theCache.pCacheViews));
  360. if(!ret && theCache.pCacheViews)
  361. {
  362. viewEntry *head = theCache.pCacheViews;
  363. viewEntry *current;
  364. /* OK, we have a basic cache, now we need to
  365. * fix up parent and children pointers
  366. */
  367. for(current = head; current != NULL; current = current->list.pNext)
  368. {
  369. views_cache_discover_parent(current);
  370. views_cache_discover_children(current);
  371. }
  372. /* scope of views and cache search filters... */
  373. for(current = head; current != NULL; current = current->list.pNext)
  374. {
  375. views_cache_discover_view_scope(current);
  376. views_cache_create_applied_filter(current);
  377. views_cache_create_exclusion_filter(current);
  378. views_cache_create_inclusion_filter(current);
  379. }
  380. /* create the view index */
  381. ret = views_cache_index();
  382. if(ret != 0)
  383. {
  384. /* currently we cannot go on without the indexes */
  385. slapi_log_error(SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM, "views_cache_create: failed to index cache\n");
  386. }
  387. else
  388. theCache.cache_built = 1;
  389. }
  390. else
  391. {
  392. /* its ok to not have views to cache */
  393. theCache.cache_built = 0;
  394. ret = 0;
  395. }
  396. theCache.currentUpdaterThread = 0;
  397. /* unlock cache */
  398. views_unlock();
  399. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_cache_create\n");
  400. return ret;
  401. }
  402. /*
  403. * views_cache_view_compare
  404. * -----------------------
  405. * compares the dns of two views - used for sorting the index
  406. */
  407. int views_cache_view_compare(const void *e1, const void *e2)
  408. {
  409. int ret;
  410. Slapi_DN *dn1 = slapi_sdn_new_dn_byval((*(viewEntry**)e1)->pDn);
  411. Slapi_DN *dn2 = slapi_sdn_new_dn_byval((*(viewEntry**)e2)->pDn);
  412. ret = slapi_sdn_compare(dn1, dn2);
  413. slapi_sdn_free(&dn1);
  414. slapi_sdn_free(&dn2);
  415. return ret;
  416. }
  417. /*
  418. * views_cache_dn_compare
  419. * -----------------------
  420. * compares a dn with the dn of a view - used for searching the index
  421. */
  422. int views_cache_dn_compare(const void *e1, const void *e2)
  423. {
  424. int ret;
  425. Slapi_DN *dn1 = slapi_sdn_new_dn_byval((char*)e1);
  426. Slapi_DN *dn2 = slapi_sdn_new_dn_byval(((viewEntry*)e2)->pDn);
  427. ret = slapi_sdn_compare(dn1, dn2);
  428. slapi_sdn_free(&dn1);
  429. slapi_sdn_free(&dn2);
  430. return ret;
  431. }
  432. /*
  433. * views_cache_index
  434. * ----------------
  435. * indexes the cache for fast look up of views
  436. */
  437. static int views_cache_index()
  438. {
  439. int ret = -1;
  440. int i;
  441. viewEntry *theView = theCache.pCacheViews;
  442. viewEntry *current = 0;
  443. if(theCache.ppViewIndex)
  444. slapi_ch_free((void**)&theCache.ppViewIndex);
  445. theCache.view_count = 0;
  446. /* lets count the views */
  447. for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
  448. theCache.view_count++;
  449. theCache.ppViewIndex = (viewEntry**)slapi_ch_calloc(theCache.view_count, sizeof(viewEntry*));
  450. if(theCache.ppViewIndex)
  451. {
  452. /* copy over the views */
  453. for(i=0; i<theCache.view_count; i++)
  454. {
  455. theCache.ppViewIndex[i] = theView;
  456. theView = theView->list.pNext;
  457. }
  458. /* sort the views */
  459. qsort(theCache.ppViewIndex, theCache.view_count, sizeof(viewEntry*), views_cache_view_compare);
  460. ret = 0;
  461. }
  462. return ret;
  463. }
  464. /*
  465. views_cache_view_index_bsearch - RECURSIVE
  466. ----------------------------------------
  467. performs a binary search on the cache view index
  468. return -1 if key is not found
  469. */
  470. viewEntry *views_cache_view_index_bsearch( const char *key, int lower, int upper )
  471. {
  472. viewEntry *ret = 0;
  473. int index = 0;
  474. int compare_ret = 0;
  475. if(upper >= lower)
  476. {
  477. if(upper != 0)
  478. index = ((upper-lower)/2) + lower;
  479. else
  480. index = 0;
  481. compare_ret = views_cache_dn_compare(key, theCache.ppViewIndex[index]);
  482. if(!compare_ret)
  483. {
  484. ret = (theCache.ppViewIndex)[index];
  485. }
  486. else
  487. {
  488. /* seek elsewhere */
  489. if(compare_ret < 0)
  490. {
  491. /* take the low road */
  492. ret = views_cache_view_index_bsearch(key, lower, index-1);
  493. }
  494. else
  495. {
  496. /* go high */
  497. ret = views_cache_view_index_bsearch(key, index+1, upper);
  498. }
  499. }
  500. }
  501. return ret;
  502. }
  503. /*
  504. views_cache_find_view
  505. -------------------
  506. searches for a view, and if found returns it, null otherwise
  507. */
  508. static viewEntry *views_cache_find_view(char *view)
  509. {
  510. viewEntry *ret = 0; /* assume failure */
  511. if(theCache.view_count != 1)
  512. ret = views_cache_view_index_bsearch(view, 0, theCache.view_count-1);
  513. else
  514. {
  515. /* only one view (that will fool our bsearch) lets check it here */
  516. if(!slapi_utf8casecmp((unsigned char*)view, (unsigned char*)theCache.ppViewIndex[0]->pDn))
  517. {
  518. ret = theCache.ppViewIndex[0];
  519. }
  520. }
  521. return ret;
  522. }
  523. /*
  524. views_cache_discover_parent
  525. ------------------------------
  526. finds the parent of this view and caches it in view
  527. */
  528. static void views_cache_discover_parent(viewEntry *pView)
  529. {
  530. viewEntry *head = theCache.pCacheViews;
  531. viewEntry *current;
  532. int found = 0;
  533. for(current = head; current != NULL && !found; current = current->list.pNext)
  534. {
  535. if(slapi_dn_isparent( current->pDn, pView->pDn ))
  536. {
  537. found = 1;
  538. pView->pParent = current;
  539. }
  540. }
  541. if(!found)
  542. {
  543. /* this is a top view */
  544. pView->pParent = NULL;
  545. }
  546. }
  547. /*
  548. views_cache_discover_parent_for_children
  549. ------------------------------
  550. The current node is being deleted - for each child, need
  551. to find a new parent
  552. */
  553. static void views_cache_discover_parent_for_children(viewEntry *pView)
  554. {
  555. int ii = 0;
  556. for (ii = 0; pView->pChildren && (ii < pView->child_count); ++ii)
  557. {
  558. viewEntry *current = (viewEntry *)pView->pChildren[ii];
  559. views_cache_discover_parent(current);
  560. }
  561. }
  562. /*
  563. views_cache_discover_children
  564. ------------------------------
  565. finds the children of this view and caches them in view
  566. */
  567. static void views_cache_discover_children(viewEntry *pView)
  568. {
  569. viewEntry *head = theCache.pCacheViews;
  570. viewEntry *current;
  571. int child_count = 0;
  572. int add_count = 0;
  573. if(pView->pChildren)
  574. {
  575. slapi_ch_free((void**)&pView->pChildren);
  576. pView->pChildren = NULL;
  577. }
  578. /* first lets count the children */
  579. for(current = head; current != NULL; current = current->list.pNext)
  580. {
  581. if(slapi_dn_isparent(pView->pDn, current->pDn))
  582. child_count++;
  583. }
  584. /* make the space for them */
  585. pView->child_count = child_count;
  586. if (child_count > 0)
  587. {
  588. pView->pChildren = (void **)slapi_ch_calloc(child_count, sizeof(viewEntry*));
  589. /* add them */
  590. for(current = head; current != NULL; current = current->list.pNext)
  591. {
  592. if(slapi_dn_isparent(pView->pDn, current->pDn))
  593. {
  594. ((viewEntry**)pView->pChildren)[add_count] = current;
  595. add_count++;
  596. }
  597. }
  598. }
  599. }
  600. /*
  601. views_cache_discover_view_scope
  602. ------------------------------
  603. finds the parent of the top most view and sets the scope of the view search
  604. */
  605. static void views_cache_discover_view_scope(viewEntry *pView)
  606. {
  607. viewEntry *current = pView;
  608. if(pView->pSearch_base)
  609. slapi_ch_free((void**)&pView->pSearch_base);
  610. while(current != NULL)
  611. {
  612. if(current->pParent == NULL)
  613. {
  614. /* found top */
  615. pView->pSearch_base = slapi_dn_parent(current->pDn);
  616. }
  617. current = current->pParent;
  618. }
  619. }
  620. /*
  621. views_cache_create_applied_filter
  622. --------------------------------
  623. builds the filters for:
  624. char *includeAncestorFiltersFilter; the view with all ancestor views
  625. */
  626. static void views_cache_create_applied_filter(viewEntry *pView)
  627. {
  628. viewEntry *current = pView;
  629. Slapi_Filter *pCurrentFilter = 0;
  630. Slapi_Filter *pBuiltFilter = 0;
  631. Slapi_Filter *pViewEntryExcludeFilter = 0;
  632. char *excludeFilter;
  633. if(pView->includeAncestorFiltersFilter)
  634. {
  635. /* release the current filter */
  636. slapi_filter_free(pView->includeAncestorFiltersFilter, 1);
  637. pView->includeAncestorFiltersFilter = 0;
  638. }
  639. /* create applied view filter (this view filter plus ancestors) */
  640. while(current != NULL)
  641. {
  642. /* add this view filter to the built filter using AND */
  643. char *buf;
  644. if(!current->viewfilter)
  645. {
  646. current = current->pParent;
  647. continue; /* skip this view */
  648. }
  649. buf = slapi_ch_strdup(current->viewfilter);
  650. pCurrentFilter = slapi_str2filter( buf );
  651. if (!pCurrentFilter) {
  652. char ebuf[BUFSIZ];
  653. slapi_log_error(SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM,
  654. "Error: the view filter [%s] in entry [%s] is not valid\n",
  655. buf, escape_string(current->pDn, ebuf));
  656. }
  657. if(pBuiltFilter && pCurrentFilter)
  658. pBuiltFilter = slapi_filter_join_ex( LDAP_FILTER_AND, pBuiltFilter, pCurrentFilter, 0 );
  659. else
  660. pBuiltFilter = pCurrentFilter;
  661. slapi_ch_free((void **)&buf);
  662. current = current->pParent;
  663. }
  664. /* filter for removing view entries from search */
  665. /* richm - slapi_str2filter _writes_ to it's argument, so we have to pass in
  666. some writeable memory, or core dump, do not pass go */
  667. excludeFilter = slapi_ch_strdup("(!(objectclass=" VIEW_OBJECTCLASS "))");
  668. pViewEntryExcludeFilter = slapi_str2filter( excludeFilter );
  669. slapi_ch_free_string(&excludeFilter);
  670. if(pBuiltFilter)
  671. pView->includeAncestorFiltersFilter = slapi_filter_join_ex( LDAP_FILTER_AND, pBuiltFilter, pViewEntryExcludeFilter, 0 );
  672. else
  673. pView->includeAncestorFiltersFilter = pViewEntryExcludeFilter;
  674. #ifdef _VIEW_DEBUG_FILTERS
  675. slapi_filter_to_string(pView->includeAncestorFiltersFilter, pView->includeAncestorFiltersFilter_str, sizeof(pView->includeAncestorFiltersFilter_str));
  676. #endif
  677. }
  678. /* views_cache_create_exclusion_filter
  679. * ----------------------------------
  680. * makes a filter which is used for one level searches
  681. * so that views show up correctly if the client filter
  682. * allows: excludeGrandChildViewsFilter
  683. *
  684. * Also makes the filter which excludes entries which
  685. * belong in descendent views: excludeChildFiltersFilter
  686. */
  687. static void views_cache_create_exclusion_filter(viewEntry *pView)
  688. {
  689. /*
  690. viewEntry *current = pView;
  691. Slapi_Filter *pOrSubFilter = 0;
  692. int child_count = 0;
  693. */
  694. Slapi_Filter *excludeChildFiltersFilter = 0;
  695. char *buf = 0;
  696. /* create exclusion filter for one level searches
  697. * this requires the rdns of the grandchildren of
  698. * this view to be in a filter
  699. */
  700. if(pView->excludeGrandChildViewsFilter)
  701. {
  702. /* release the current filter */
  703. slapi_filter_free(pView->excludeGrandChildViewsFilter, 1);
  704. pView->excludeGrandChildViewsFilter = 0;
  705. }
  706. if(pView->excludeChildFiltersFilter)
  707. {
  708. /* release the current filter */
  709. slapi_filter_free(pView->excludeChildFiltersFilter, 1);
  710. pView->excludeChildFiltersFilter = 0;
  711. }
  712. /* if(pView->child_count == 0)
  713. {
  714. */ /* this view has no children */
  715. /* pView->excludeGrandChildViewsFilter = 0;
  716. pView->excludeChildFiltersFilter = 0;
  717. return;
  718. }
  719. while(child_count < pView->child_count)
  720. {
  721. current = pView->pChildren[child_count];
  722. if(current->child_count == 0)
  723. {
  724. */ /* no grandchildren here, skip */
  725. /* child_count++;
  726. continue;
  727. }
  728. */
  729. /* for each child we need to add its descendants */
  730. /* if(pOrSubFilter)
  731. {
  732. Slapi_Filter *pDescendents = views_cache_create_descendent_filter(current, TRUE);
  733. if(pDescendents)
  734. pOrSubFilter = slapi_filter_join_ex( LDAP_FILTER_OR, pOrSubFilter, pDescendents, 0 );
  735. }
  736. else
  737. pOrSubFilter = views_cache_create_descendent_filter(current, TRUE);
  738. child_count++;
  739. }
  740. */
  741. buf=PR_smprintf("(parentid=%lu)", pView->entryid);
  742. pView->excludeGrandChildViewsFilter = slapi_str2filter( buf );
  743. PR_smprintf_free(buf);
  744. /* if(pOrSubFilter)
  745. pView->excludeGrandChildViewsFilter = slapi_filter_join_ex( LDAP_FILTER_NOT, pOrSubFilter, NULL, 0 );*/
  746. excludeChildFiltersFilter = views_cache_create_descendent_filter(pView, PR_FALSE);
  747. if(excludeChildFiltersFilter)
  748. pView->excludeChildFiltersFilter = slapi_filter_join_ex( LDAP_FILTER_NOT, excludeChildFiltersFilter, NULL, 0 );
  749. #ifdef _VIEW_DEBUG_FILTERS
  750. slapi_filter_to_string(pView->excludeGrandChildViewsFilter, pView->excludeGrandChildViewsFilter_str, sizeof(pView->excludeGrandChildViewsFilter_str));
  751. slapi_filter_to_string(pView->excludeChildFiltersFilter, pView->excludeChildFiltersFilter_str, sizeof(pView->excludeChildFiltersFilter_str));
  752. #endif
  753. }
  754. Slapi_Filter *views_cache_create_descendent_filter(viewEntry *ancestor, PRBool useEntryID)
  755. {
  756. int child_count = 0;
  757. Slapi_Filter *pOrSubFilter = 0;
  758. while(child_count < ancestor->child_count)
  759. {
  760. Slapi_Filter *pDescendentSubFilter = 0;
  761. /*
  762. Slapi_RDN *rdn = 0;
  763. char *str_rdn = 0;
  764. int len = 0;
  765. */
  766. Slapi_Filter *pCurrentFilter = 0;
  767. viewEntry *currentChild = ancestor->pChildren[child_count];
  768. char *buf = 0;
  769. /* for each child we need to add its descendants
  770. * we do this now before processing this view
  771. * to try to help the filter code out by having
  772. * the most significant filters first
  773. */
  774. pDescendentSubFilter = views_cache_create_descendent_filter(currentChild, useEntryID);
  775. if(pDescendentSubFilter)
  776. {
  777. if(pOrSubFilter)
  778. pOrSubFilter = slapi_filter_join_ex( LDAP_FILTER_OR, pOrSubFilter, pDescendentSubFilter, 0 );
  779. else
  780. pOrSubFilter = pDescendentSubFilter;
  781. }
  782. if(useEntryID)
  783. {
  784. /* we need the RDN of this child */
  785. /* rdn = slapi_rdn_new_dn(currentChild->pDn);
  786. str_rdn = (char *)slapi_rdn_get_rdn(rdn);
  787. len = strlen(str_rdn);
  788. buf=PR_smprintf("(%s)", str_rdn);*/
  789. /* uniquely identify this child */
  790. buf=PR_smprintf("(parentid=%lu)", currentChild->entryid);
  791. }
  792. else
  793. {
  794. /* this is a filter based filter */
  795. if(currentChild->viewfilter)
  796. {
  797. buf=PR_smprintf("%s",currentChild->viewfilter);
  798. }
  799. }
  800. if(buf)
  801. {
  802. pCurrentFilter = slapi_str2filter( buf );
  803. if (!pCurrentFilter) {
  804. char ebuf[BUFSIZ];
  805. slapi_log_error(SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM,
  806. "Error: the view filter [%s] in entry [%s] is not valid\n",
  807. buf, escape_string(currentChild->pDn, ebuf));
  808. }
  809. if(pOrSubFilter && pCurrentFilter)
  810. pOrSubFilter = slapi_filter_join_ex( LDAP_FILTER_OR, pOrSubFilter, pCurrentFilter, 0 );
  811. else
  812. pOrSubFilter = pCurrentFilter;
  813. PR_smprintf_free(buf);
  814. }
  815. child_count++;
  816. }
  817. return pOrSubFilter;
  818. }
  819. /* views_cache_create_inclusion_filter
  820. * ----------------------------------
  821. * makes a filter which is used for subtree searches
  822. * so that views show up correctly if the client filter
  823. * allows
  824. */
  825. static void views_cache_create_inclusion_filter(viewEntry *pView)
  826. {
  827. #if 0
  828. viewEntry *head = theCache.pCacheViews;
  829. #endif
  830. /* viewEntry *current; */
  831. /* Slapi_Filter *view_filter; */
  832. char *view_filter_str;
  833. if(pView->includeChildViewsFilter)
  834. {
  835. /* release the current filter */
  836. slapi_filter_free(pView->includeChildViewsFilter, 1);
  837. pView->includeChildViewsFilter = 0;
  838. }
  839. #if 0
  840. for(current = head; current != NULL; current = current->list.pNext)
  841. {
  842. Slapi_DN *viewDN;
  843. Slapi_RDN *viewRDN;
  844. char *viewRDNstr;
  845. char *buf = 0;
  846. Slapi_Filter *viewSubFilter;
  847. /* if this is this a descendent, ignore it */
  848. if(slapi_dn_issuffix(current->pDn,pView->pDn) && !(current == pView))
  849. continue;
  850. viewDN = slapi_sdn_new_dn_byref(current->pDn);
  851. viewRDN = slapi_rdn_new();
  852. slapi_sdn_get_rdn(viewDN,viewRDN);
  853. viewRDNstr = (char *)slapi_rdn_get_rdn(viewRDN);
  854. buf = slapi_ch_calloc(1, strlen(viewRDNstr) + 11 ); /* 3 for filter */
  855. sprintf(buf, "(%s)", viewRDNstr );
  856. viewSubFilter = slapi_str2filter( buf );
  857. if (!viewSubFilter) {
  858. char ebuf[BUFSIZ];
  859. slapi_log_error(SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM,
  860. "Error: the view filter [%s] in entry [%s] is not valid\n",
  861. buf, escape_string(current->pDn, ebuf));
  862. }
  863. if(pView->includeChildViewsFilter && viewSubFilter)
  864. pView->includeChildViewsFilter = slapi_filter_join_ex( LDAP_FILTER_OR, pView->includeChildViewsFilter, viewSubFilter, 0 );
  865. else
  866. pView->includeChildViewsFilter = viewSubFilter;
  867. slapi_ch_free((void **)&buf);
  868. slapi_sdn_free(&viewDN);
  869. slapi_rdn_free(&viewRDN);
  870. child_count++;
  871. }
  872. #endif
  873. /* exclude all other view entries but decendents */
  874. /* pView->includeChildViewsFilter = slapi_filter_join_ex( LDAP_FILTER_NOT, pView->includeChildViewsFilter, NULL, 0 );
  875. */
  876. /* it seems reasonable to include entries which
  877. * may not fit the view decription but which
  878. * are actually *contained* in the view
  879. * therefore we use parentids for the view
  880. * filter
  881. */
  882. /* add decendents */
  883. pView->includeChildViewsFilter = views_cache_create_descendent_filter(pView, PR_TRUE);
  884. /* add this view */
  885. view_filter_str = PR_smprintf("(|(parentid=%lu)(entryid=%lu))", pView->entryid, pView->entryid);
  886. if(pView->includeChildViewsFilter)
  887. {
  888. pView->includeChildViewsFilter = slapi_filter_join_ex( LDAP_FILTER_OR, slapi_str2filter( view_filter_str ), pView->includeChildViewsFilter, PR_FALSE);
  889. }
  890. else
  891. {
  892. pView->includeChildViewsFilter = slapi_str2filter( view_filter_str );
  893. }
  894. PR_smprintf_free(view_filter_str);
  895. view_filter_str = NULL;
  896. /* and make sure the this applies only to views */
  897. /* if(pView->includeChildViewsFilter)
  898. {*/
  899. /* Not necessary since we now use entryid in the filter,
  900. so all will be views anyway, and the less sub-filters
  901. the better
  902. view_filter_str = strdup("(objectclass=" VIEW_OBJECTCLASS ")");
  903. view_filter = slapi_str2filter( view_filter_str );
  904. */
  905. /* child views first because entryid indexed
  906. * and makes evaluation faster when a bunch
  907. * of indexed filter evaluations with only one
  908. * target are evaluated first rather than an
  909. * indexed filter which will provide many entries
  910. * that may trigger an index evaluation short
  911. * circuit. i.e. if one of the child filters is
  912. * true then we have one entry, if not, then we
  913. * have used indexes completely to determine that
  914. * no entry matches and (objectclass=nsview) is never
  915. * evaluated.
  916. * I should imagine this will hold for all but the
  917. * very deepest, widest view trees when subtree
  918. * searches are performed from the top
  919. */
  920. /* pView->includeChildViewsFilter = slapi_filter_join_ex( LDAP_FILTER_AND, pView->includeChildViewsFilter, view_filter, 0 );
  921. }
  922. else
  923. {
  924. view_filter_str = strdup("(objectclass=nsviewincludenone)"); *//* hackery to get the right result */
  925. /* pView->includeChildViewsFilter = slapi_str2filter( view_filter_str );
  926. }
  927. */
  928. #ifdef _VIEW_DEBUG_FILTERS
  929. slapi_filter_to_string(pView->includeChildViewsFilter, pView->includeChildViewsFilter_str, sizeof(pView->includeChildViewsFilter_str));
  930. #endif
  931. }
  932. /*
  933. views_cache_build_view_list
  934. -------------------------------
  935. builds the list of views by searching for them throughout the DIT
  936. */
  937. static int views_cache_build_view_list(viewEntry **pViews)
  938. {
  939. int ret = 0;
  940. Slapi_PBlock *pSuffixSearch = 0;
  941. Slapi_Entry **pSuffixList = 0;
  942. Slapi_Attr *suffixAttr;
  943. struct berval **suffixVals;
  944. char *attrType = 0;
  945. char *attrs[2];
  946. int suffixIndex = 0;
  947. int valIndex = 0;
  948. slapi_log_error(SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_cache_build_view_list\n");
  949. /*
  950. the views may be anywhere in the DIT,
  951. so our first task is to find them.
  952. */
  953. attrs[0] = "namingcontexts";
  954. attrs[1] = 0;
  955. slapi_log_error(SLAPI_LOG_PLUGIN, VIEWS_PLUGIN_SUBSYSTEM, "views: Building view cache.\n");
  956. pSuffixSearch = slapi_search_internal("",LDAP_SCOPE_BASE,"(objectclass=*)",NULL,attrs,0);
  957. if(pSuffixSearch)
  958. slapi_pblock_get( pSuffixSearch, SLAPI_PLUGIN_INTOP_RESULT, &ret);
  959. if(pSuffixSearch && ret == LDAP_SUCCESS)
  960. {
  961. /* iterate through the suffixes and search for views */
  962. slapi_pblock_get( pSuffixSearch, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &pSuffixList);
  963. if(pSuffixList)
  964. {
  965. while(pSuffixList[suffixIndex])
  966. {
  967. if(!slapi_entry_first_attr(pSuffixList[suffixIndex], &suffixAttr))
  968. {
  969. do
  970. {
  971. attrType = 0;
  972. slapi_attr_get_type(suffixAttr, &attrType);
  973. if(attrType && !slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"namingcontexts"))
  974. {
  975. if(!slapi_attr_get_bervals_copy(suffixAttr, &suffixVals))
  976. {
  977. valIndex = 0;
  978. if(suffixVals)
  979. {
  980. while(suffixVals[valIndex])
  981. {
  982. /* here's a suffix, lets search it... */
  983. if(suffixVals[valIndex]->bv_val)
  984. views_cache_add_dn_views(suffixVals[valIndex]->bv_val ,pViews);
  985. valIndex++;
  986. }
  987. ber_bvecfree( suffixVals );
  988. suffixVals = NULL;
  989. }
  990. }
  991. }
  992. } while(!slapi_entry_next_attr(pSuffixList[suffixIndex], suffixAttr, &suffixAttr));
  993. }
  994. suffixIndex++;
  995. }
  996. }
  997. }
  998. else
  999. {
  1000. slapi_log_error(SLAPI_LOG_PLUGIN, VIEWS_PLUGIN_SUBSYSTEM, "views_cache_build_view_list: failed to find suffixes\n");
  1001. ret = -1;
  1002. }
  1003. /* clean up */
  1004. if(pSuffixSearch)
  1005. {
  1006. slapi_free_search_results_internal(pSuffixSearch);
  1007. slapi_pblock_destroy(pSuffixSearch);
  1008. }
  1009. slapi_log_error(SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_cache_build_view_list\n");
  1010. return ret;
  1011. }
  1012. /* struct to support search callback API */
  1013. struct dn_views_info {
  1014. viewEntry **pViews;
  1015. int ret;
  1016. };
  1017. /* does same funcationality as views_add_dn_views except it is invoked via a callback */
  1018. static int views_dn_views_cb (Slapi_Entry* e, void *callback_data) {
  1019. struct dn_views_info *info;
  1020. char *pDn = 0;
  1021. struct berval **dnVals;
  1022. Slapi_Attr *dnAttr;
  1023. char *attrType = 0;
  1024. viewEntry *pView;
  1025. info=(struct dn_views_info *)callback_data;
  1026. info->ret = 0;
  1027. pDn = slapi_entry_get_ndn(e);
  1028. /* create the view */
  1029. pView = (viewEntry *)slapi_ch_calloc(1, sizeof(viewEntry));
  1030. pView->pDn = slapi_ch_strdup(pDn);
  1031. if(!slapi_entry_first_attr(e, &dnAttr))
  1032. {
  1033. do
  1034. {
  1035. attrType = 0;
  1036. /* get the filter */
  1037. slapi_attr_get_type(dnAttr, &attrType);
  1038. if(attrType && !strcasecmp(attrType,VIEW_FILTER_ATTR))
  1039. {
  1040. if(!slapi_attr_get_bervals_copy(dnAttr, &dnVals))
  1041. {
  1042. /* add filter */
  1043. pView->viewfilter = slapi_ch_strdup(dnVals[0]->bv_val);
  1044. }
  1045. ber_bvecfree( dnVals );
  1046. dnVals = NULL;
  1047. }
  1048. if(attrType && !strcasecmp(attrType,"entryid"))
  1049. {
  1050. Slapi_Value *val = 0;
  1051. slapi_attr_first_value(dnAttr, &val);
  1052. pView->entryid = slapi_value_get_ulong(val);
  1053. }
  1054. if(attrType && !strcasecmp(attrType,"parentid"))
  1055. {
  1056. Slapi_Value *val = 0;
  1057. slapi_attr_first_value(dnAttr, &val);
  1058. pView->parentid = slapi_value_get_ulong(val);
  1059. }
  1060. } while(!slapi_entry_next_attr(e, dnAttr, &dnAttr));
  1061. }
  1062. /* add view to the cache */
  1063. views_cache_add_ll_entry((void**)info->pViews, (void *)pView);
  1064. return info->ret;
  1065. }
  1066. /*
  1067. views_cache_add_dn_views
  1068. -------------------------
  1069. takes a dn as argument and searches the dn for views,
  1070. adding any found to the view cache. Change to use search callback API
  1071. */
  1072. #define DN_VIEW_FILTER "(objectclass=" VIEW_OBJECTCLASS ")"
  1073. static int views_cache_add_dn_views(char *dn, viewEntry **pViews)
  1074. {
  1075. Slapi_PBlock *pDnSearch = 0;
  1076. struct dn_views_info info = {NULL, -1};
  1077. pDnSearch = slapi_pblock_new();
  1078. if (pDnSearch) {
  1079. info.ret=-1;
  1080. info.pViews=pViews;
  1081. slapi_search_internal_set_pb(pDnSearch, dn, LDAP_SCOPE_SUBTREE,
  1082. DN_VIEW_FILTER,NULL,0,
  1083. NULL,NULL,view_get_plugin_identity(),0);
  1084. slapi_search_internal_callback_pb(pDnSearch,
  1085. &info /* callback_data */,
  1086. NULL/* result_callback */,
  1087. views_dn_views_cb,
  1088. NULL /* referral_callback */);
  1089. slapi_pblock_destroy (pDnSearch);
  1090. }
  1091. return info.ret;
  1092. }
  1093. /*
  1094. views_cache_add_ll_entry
  1095. ---------------------------------------------------
  1096. the element is added to the head of the linked list
  1097. *NOTE* this function assumes and *requires* that the structures
  1098. passed to it in "attrval" and "theVal" have a viewLinkedList
  1099. member, and it is the *first* member of the structure. This
  1100. is safe because this is a module level function, and all functions
  1101. which call this one are part of the same sub-system.
  1102. */
  1103. static void views_cache_add_ll_entry(void** attrval, void *theVal)
  1104. {
  1105. slapi_log_error(SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_cache_add_ll_entry\n");
  1106. if(*attrval)
  1107. {
  1108. /* push this to the start of the list (because its quick) */
  1109. ((viewLinkedList*)theVal)->pNext = *attrval;
  1110. ((viewLinkedList*)(*attrval))->pPrev = theVal;
  1111. *attrval = theVal;
  1112. }
  1113. else
  1114. {
  1115. /* new or end of list */
  1116. ((viewLinkedList*)theVal)->pNext = NULL;
  1117. ((viewLinkedList*)theVal)->pPrev = NULL;
  1118. *attrval = theVal;
  1119. }
  1120. slapi_log_error(SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_cache_add_ll_entry\n");
  1121. }
  1122. /*
  1123. views_update_views_cache
  1124. -----------------------
  1125. update internal view cache after state change
  1126. */
  1127. static void views_update_views_cache( Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data )
  1128. {
  1129. char *pDn;
  1130. viewEntry *theView;
  1131. viewEntry *current;
  1132. Slapi_Attr *attr;
  1133. struct berval val;
  1134. int build_cache = 0;
  1135. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_update_views_cache\n");
  1136. views_write_lock();
  1137. if(!theCache.cache_built)
  1138. {
  1139. /* zarro views = no cache,
  1140. * this is probably an add op
  1141. * lets build the cache
  1142. */
  1143. build_cache = 1;
  1144. goto unlock_cache;
  1145. }
  1146. pDn = slapi_entry_get_ndn(e);
  1147. theView = views_cache_find_view(pDn);
  1148. switch(modtype)
  1149. {
  1150. case LDAP_CHANGETYPE_MODIFY:
  1151. /* if still a view and exists
  1152. * update string filter
  1153. * update the filters of all views
  1154. * if just became a view fall through to add op
  1155. * if stopped being a view fall through to delete op
  1156. */
  1157. /* determine what happenned - does the view exist currently? */
  1158. if(theView)
  1159. {
  1160. /* does it have the view objectclass? */
  1161. if(!slapi_entry_attr_find( e, "objectclass", &attr ))
  1162. {
  1163. val.bv_len = 8;
  1164. val.bv_val = VIEW_OBJECTCLASS;
  1165. if(!slapi_attr_value_find( attr, &val))
  1166. {
  1167. /* it is a view */
  1168. attr = 0;
  1169. /* has the filter changed? */
  1170. slapi_entry_attr_find( e, VIEW_FILTER_ATTR, &attr );
  1171. if(attr)
  1172. {
  1173. if(theView->viewfilter) /* NULL means a filter added */
  1174. {
  1175. /* we could translate the string filter into
  1176. * a real filter and compare against
  1177. * the view - that would tell us if the filter
  1178. * was substantively changed.
  1179. *
  1180. * But we're not gonna do that :)
  1181. */
  1182. val.bv_len = strlen(theView->viewfilter)+1;
  1183. val.bv_val = theView->viewfilter;
  1184. if(!slapi_attr_value_find( attr, &val))
  1185. {
  1186. /* filter unchanged */
  1187. break;
  1188. }
  1189. }
  1190. }
  1191. else
  1192. {
  1193. /* if no filter in view, then no change */
  1194. if(theView->viewfilter == 0)
  1195. break;
  1196. }
  1197. /* this was indeed a significant mod, add the new filter */
  1198. if(theView->viewfilter)
  1199. slapi_ch_free((void**)&theView->viewfilter);
  1200. if(attr)
  1201. {
  1202. Slapi_Value *v;
  1203. slapi_attr_first_value( attr, &v );
  1204. theView->viewfilter = slapi_ch_strdup(slapi_value_get_string(v));
  1205. }
  1206. /* update all filters */
  1207. for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
  1208. {
  1209. views_cache_create_applied_filter(current);
  1210. views_cache_create_exclusion_filter(current);
  1211. views_cache_create_inclusion_filter(current);
  1212. }
  1213. }
  1214. else
  1215. {
  1216. /* this is a delete operation */
  1217. modtype = LDAP_CHANGETYPE_DELETE;
  1218. }
  1219. }
  1220. else
  1221. /* thats bad */
  1222. break;
  1223. }
  1224. else
  1225. {
  1226. /* this is an add operation */
  1227. modtype = LDAP_CHANGETYPE_ADD;
  1228. }
  1229. case LDAP_CHANGETYPE_DELETE:
  1230. /* remove view entry from list
  1231. * update children of parent
  1232. * update all child filters
  1233. * re-index
  1234. */
  1235. if(modtype == LDAP_CHANGETYPE_DELETE)
  1236. {
  1237. if(theCache.view_count-1)
  1238. {
  1239. /* detach view */
  1240. if(theView->list.pPrev)
  1241. ((viewEntry*)(theView->list.pPrev))->list.pNext = theView->list.pNext;
  1242. if(theView->list.pNext)
  1243. {
  1244. ((viewEntry*)(theView->list.pNext))->list.pPrev = theView->list.pPrev;
  1245. if(theView->list.pPrev == NULL) /* if this is the head */
  1246. theCache.pCacheViews = (viewEntry*)(theView->list.pNext);
  1247. }
  1248. /* the parent of this node needs to know about its children */
  1249. if(theView->pParent)
  1250. views_cache_discover_children((viewEntry*)theView->pParent);
  1251. /* each child of the deleted node will need to discover a new parent */
  1252. views_cache_discover_parent_for_children((viewEntry*)theView);
  1253. /* update filters */
  1254. for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
  1255. {
  1256. views_cache_create_applied_filter(current);
  1257. views_cache_create_exclusion_filter(current);
  1258. views_cache_create_inclusion_filter(current);
  1259. }
  1260. /* reindex */
  1261. views_cache_index();
  1262. }
  1263. else
  1264. {
  1265. theCache.pCacheViews = NULL;
  1266. theCache.view_count = 0;
  1267. theCache.cache_built = 0;
  1268. }
  1269. /* free the view */
  1270. slapi_ch_free((void**)&theView->pDn);
  1271. slapi_ch_free((void**)&theView->viewfilter);
  1272. slapi_filter_free(theView->includeAncestorFiltersFilter,1);
  1273. slapi_filter_free(theView->excludeAllButDescendentViewsFilter,1);
  1274. slapi_filter_free(theView->excludeChildFiltersFilter,1);
  1275. slapi_filter_free(theView->excludeGrandChildViewsFilter,1);
  1276. slapi_filter_free(theView->includeChildViewsFilter,1);
  1277. slapi_ch_free((void**)&theView->pSearch_base);
  1278. slapi_ch_free((void**)&theView->pChildren);
  1279. slapi_ch_free((void**)&theView);
  1280. break;
  1281. }
  1282. case LDAP_CHANGETYPE_ADD:
  1283. /* create view entry
  1284. * add it to list
  1285. * update children of parent
  1286. * update all child filters
  1287. * re-index
  1288. */
  1289. if(modtype == LDAP_CHANGETYPE_ADD)
  1290. {
  1291. theView = (viewEntry *)slapi_ch_calloc(1, sizeof(viewEntry));
  1292. theView->pDn = slapi_ch_strdup(pDn);
  1293. /* get the view filter, the entryid, and the parentid */
  1294. slapi_entry_attr_find( e, VIEW_FILTER_ATTR, &attr );
  1295. if(attr)
  1296. {
  1297. Slapi_Value *v;
  1298. slapi_attr_first_value( attr, &v );
  1299. theView->viewfilter = slapi_ch_strdup(slapi_value_get_string(v));
  1300. }
  1301. else
  1302. theView->viewfilter = NULL;
  1303. slapi_entry_attr_find( e, "entryid", &attr );
  1304. if(attr)
  1305. {
  1306. Slapi_Value *v;
  1307. slapi_attr_first_value( attr, &v );
  1308. theView->entryid = slapi_value_get_ulong(v);
  1309. }
  1310. else
  1311. theView->entryid = 0;
  1312. slapi_entry_attr_find( e, "parentid", &attr );
  1313. if(attr)
  1314. {
  1315. Slapi_Value *v;
  1316. slapi_attr_first_value( attr, &v );
  1317. theView->parentid = slapi_value_get_ulong(v);
  1318. }
  1319. else
  1320. theView->parentid = 0;
  1321. /* add view to the cache */
  1322. views_cache_add_ll_entry((void**)&theCache.pCacheViews, (void *)theView);
  1323. views_cache_discover_parent(theView);
  1324. if(theView->pParent)
  1325. views_cache_discover_children((viewEntry*)theView->pParent);
  1326. /* update filters */
  1327. for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
  1328. {
  1329. views_cache_discover_view_scope(current); /* if ns-view oc added, new view may be top */
  1330. views_cache_create_applied_filter(current);
  1331. views_cache_create_exclusion_filter(current);
  1332. views_cache_create_inclusion_filter(current);
  1333. }
  1334. /* reindex */
  1335. views_cache_index();
  1336. break;
  1337. }
  1338. case LDAP_CHANGETYPE_MODDN:
  1339. /* get old dn to find the view
  1340. * change dn
  1341. * update parents and children
  1342. * update all filters
  1343. * reindex
  1344. */
  1345. {
  1346. char *old_dn;
  1347. Slapi_Entry *old_entry;
  1348. slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &old_entry );
  1349. old_dn = slapi_entry_get_ndn(old_entry);
  1350. theView = views_cache_find_view(old_dn);
  1351. if(theView)
  1352. {
  1353. slapi_ch_free((void**)&theView->pDn);
  1354. theView->pDn = slapi_ch_strdup(pDn);
  1355. for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
  1356. {
  1357. views_cache_discover_parent(current);
  1358. views_cache_discover_children(current);
  1359. }
  1360. for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
  1361. {
  1362. views_cache_discover_view_scope(current);
  1363. views_cache_create_applied_filter(current);
  1364. views_cache_create_exclusion_filter(current);
  1365. views_cache_create_inclusion_filter(current);
  1366. }
  1367. }
  1368. /* reindex */
  1369. views_cache_index();
  1370. break;
  1371. }
  1372. default:
  1373. /* we don't care about this op */
  1374. break;
  1375. }
  1376. unlock_cache:
  1377. views_unlock();
  1378. if(build_cache)
  1379. {
  1380. views_cache_create();
  1381. }
  1382. slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_update_views_cache\n");
  1383. }
  1384. /*
  1385. * view_search_rewrite_callback
  1386. * ----------------------------
  1387. * this is the business end of the plugin
  1388. * this function is called from slapd
  1389. * rewrites the search to conform to the view
  1390. * Meaning of the return code :
  1391. * -1 : keep looking
  1392. * 0 : rewrote OK
  1393. * 1 : refuse to do this search
  1394. * 2 : operations error
  1395. */
  1396. static int view_search_rewrite_callback(Slapi_PBlock *pb)
  1397. {
  1398. int ret = -1;
  1399. char *base = 0;
  1400. Slapi_Filter *clientFilter = 0;
  1401. Slapi_Filter *includeAncestorFiltersFilter = 0; /* the view with all ancestor views */
  1402. Slapi_Filter *excludeChildFiltersFilter = 0; /* NOT all children views, for one level searches */
  1403. Slapi_Filter *excludeGrandChildViewsFilter = 0; /* view filter for one level searches */
  1404. Slapi_Filter *includeChildViewsFilter = 0; /* view filter for subtree searches */
  1405. Slapi_Filter *seeViewsFilter = 0; /* view filter to see views */
  1406. Slapi_Filter *outFilter = 0;
  1407. int scope = 0;
  1408. int set_scope = LDAP_SCOPE_SUBTREE;
  1409. viewEntry *theView = 0;
  1410. #ifdef _VIEW_DEBUG_FILTERS
  1411. char outFilter_str[1024];
  1412. char clientFilter_str[1024];
  1413. char includeAncestorFiltersFilter_str[1024];
  1414. char excludeChildFiltersFilter_str[1024];
  1415. char excludeGrandChildViewsFilter_str[1024];
  1416. char includeChildViewsFilter_str[1024];
  1417. #endif
  1418. /* if no cache, no views */
  1419. if(!theCache.cache_built)
  1420. goto end;
  1421. /* avoid locking if this thread is the updater */
  1422. if(theCache.currentUpdaterThread)
  1423. {
  1424. PRThread *thisThread = PR_GetCurrentThread();
  1425. if(thisThread == theCache.currentUpdaterThread)
  1426. goto end;
  1427. }
  1428. /* first, find out if this is a base search (we do nothing) */
  1429. slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope);
  1430. if(scope == LDAP_SCOPE_BASE)
  1431. goto end;
  1432. /* if base of the search is a view */
  1433. slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &base);
  1434. /* Read lock the cache */
  1435. views_read_lock();
  1436. theView = views_cache_find_view(base);
  1437. /* if the view is disabled (we service subtree searches in this case) */
  1438. if(!theView || (!theView->viewfilter && scope == LDAP_SCOPE_ONELEVEL))
  1439. {
  1440. /* unlock the cache */
  1441. views_unlock();
  1442. goto end;
  1443. }
  1444. /* this is a view search, and we are smokin' */
  1445. /* grab the view filters we are going to need now so we can release the cache lock */
  1446. if(scope == LDAP_SCOPE_ONELEVEL)
  1447. {
  1448. excludeChildFiltersFilter = slapi_filter_dup(theView->excludeChildFiltersFilter);
  1449. excludeGrandChildViewsFilter = slapi_filter_dup(theView->excludeGrandChildViewsFilter);
  1450. #ifdef _VIEW_DEBUG_FILTERS
  1451. slapi_filter_to_string(excludeChildFiltersFilter, excludeChildFiltersFilter_str, sizeof(excludeChildFiltersFilter_str));
  1452. slapi_filter_to_string(excludeGrandChildViewsFilter, excludeGrandChildViewsFilter_str, sizeof(excludeGrandChildViewsFilter_str));
  1453. #endif
  1454. }
  1455. else
  1456. {
  1457. includeChildViewsFilter = slapi_filter_dup(theView->includeChildViewsFilter);
  1458. }
  1459. #ifdef _VIEW_DEBUG_FILTERS
  1460. slapi_filter_to_string(includeChildViewsFilter, includeChildViewsFilter_str, sizeof(includeChildViewsFilter_str));
  1461. #endif
  1462. /* always used */
  1463. includeAncestorFiltersFilter = slapi_filter_dup(theView->includeAncestorFiltersFilter);
  1464. #ifdef _VIEW_DEBUG_FILTERS
  1465. slapi_filter_to_string(includeAncestorFiltersFilter, includeAncestorFiltersFilter_str, sizeof(includeAncestorFiltersFilter_str));
  1466. #endif
  1467. /* unlock the cache */
  1468. views_unlock();
  1469. /* rewrite search scope and base*/
  1470. slapi_pblock_set(pb, SLAPI_SEARCH_SCOPE, &set_scope);
  1471. base = slapi_ch_strdup(theView->pSearch_base);
  1472. slapi_pblock_set(pb, SLAPI_SEARCH_TARGET, base);
  1473. /* concatenate the filters */
  1474. /* grab the client filter - we need 2 copies */
  1475. slapi_pblock_get(pb, SLAPI_SEARCH_FILTER, &clientFilter);
  1476. #ifdef _VIEW_DEBUG_FILTERS
  1477. slapi_filter_to_string(clientFilter, clientFilter_str, sizeof(clientFilter_str));
  1478. #endif
  1479. /* There are two major clauses in a views filter, one looks
  1480. for entries that match the view filters themselves plus
  1481. the presented client filter, and the other looks for entries
  1482. that exist in the view hierarchy that also match the client
  1483. presented filter
  1484. */
  1485. /* client supplied filter AND views inclusion filter
  1486. - make sure we can see entries in the view tree */
  1487. if(scope == LDAP_SCOPE_ONELEVEL)
  1488. {
  1489. /* this filter is to lock our view to the onelevel search */
  1490. if(excludeGrandChildViewsFilter)
  1491. {
  1492. seeViewsFilter = excludeGrandChildViewsFilter;
  1493. }
  1494. }
  1495. else
  1496. {
  1497. /* this filter is to lock our view to the subtree search */
  1498. if(includeChildViewsFilter)
  1499. {
  1500. seeViewsFilter = includeChildViewsFilter;
  1501. }
  1502. }
  1503. /* but only view tree entries that match the client filter */
  1504. if(seeViewsFilter)
  1505. {
  1506. seeViewsFilter = slapi_filter_join_ex( LDAP_FILTER_AND, slapi_filter_dup(clientFilter), seeViewsFilter, 0 );
  1507. }
  1508. /* create target filter */
  1509. if(includeAncestorFiltersFilter)
  1510. outFilter = slapi_filter_join_ex( LDAP_FILTER_AND, includeAncestorFiltersFilter, clientFilter, 0 );
  1511. else
  1512. outFilter = clientFilter;
  1513. if(scope == LDAP_SCOPE_ONELEVEL)
  1514. {
  1515. if(excludeChildFiltersFilter)
  1516. outFilter = slapi_filter_join_ex( LDAP_FILTER_AND, outFilter, excludeChildFiltersFilter, 0 );
  1517. }
  1518. if(seeViewsFilter)
  1519. outFilter = slapi_filter_join_ex( LDAP_FILTER_OR, outFilter, seeViewsFilter, 0 );
  1520. #ifdef _VIEW_DEBUG_FILTERS
  1521. slapi_filter_to_string(outFilter, outFilter_str, sizeof(outFilter_str));
  1522. #endif
  1523. /* make it happen */
  1524. slapi_pblock_set(pb, SLAPI_SEARCH_FILTER, outFilter);
  1525. ret = -2;
  1526. end:
  1527. return ret;
  1528. }
  1529. /*
  1530. * views_cache_backend_state_change()
  1531. * --------------------------------
  1532. * This is called when a backend changes state
  1533. * We simply signal to rebuild the cache in this case
  1534. *
  1535. */
  1536. static void views_cache_backend_state_change(void *handle, char *be_name,
  1537. int old_be_state, int new_be_state)
  1538. {
  1539. /* we will create a thread to do this since
  1540. * calling views_cache_create() directly will
  1541. * hold up the op
  1542. */
  1543. if ((PR_CreateThread (PR_USER_THREAD,
  1544. views_cache_act_on_change_thread,
  1545. NULL,
  1546. PR_PRIORITY_NORMAL,
  1547. PR_GLOBAL_THREAD,
  1548. PR_UNJOINABLE_THREAD,
  1549. SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL )
  1550. {
  1551. slapi_log_error( SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM,
  1552. "views_cache_backend_state_change: PR_CreateThread failed\n" );
  1553. }
  1554. }
  1555. static void views_cache_act_on_change_thread(void *arg)
  1556. {
  1557. views_cache_create();
  1558. }