views.c 46 KB

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