vattr.c 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /*
  13. Virtual Attributes
  14. This file implements the "virtual attribute API", which is the interface
  15. by which any joe servercode gets the values of attributes associated with an
  16. entry which are _not_ stored with the entry. Attributes which _are_ stored
  17. with the entry will also be returned by this interface, unless the caller
  18. specifies the SLAPI_REALATTRS_ONLY flag. This means that the casual caller
  19. looking for attribute values should probably call the virtual attribute interface
  20. rather than the regular Slapi_Entry_Attr_Find... and so on calls.
  21. This interface is different from that one in that the data returned is
  22. a copy, to be freed by the caller. Details on how to free the returned data is
  23. given individually for each function.
  24. The thing is implemented with a service provider model. The code in here
  25. does NOT know how to generate computed attr values etc, it just calls the
  26. registered providers of such information. It also takes care of any crusty
  27. special cases. Everything above the line here is crispy clean.
  28. Implicit in this interface is the assumption that the value of an attribute
  29. can only depend on the entry and some independent stored state. For example,
  30. the value can't depend upon who is asking, since we don't pass that information
  31. over the interface.
  32. More design: we'd like to have the regular result returning code in result.c call this
  33. interface. However, as it stands, his would incur a malloc, a copy and a free for every
  34. value. Too expensive. So, it would be good to modify the interface such that when we
  35. retrieve values from inside the entry, we just fetch a pointer like before. When we
  36. retrieve values which are generated, we get copies of the data (or can we get pointers
  37. there too ?? --- no).
  38. One way to achieve this: allow the caller to say that they perfer to receive pointers
  39. and not copies. They are then informed by the function whether they did receive pointers
  40. or copies. They then call the free function only when needed. The implicit lifetime of
  41. the returned pointers is the lifetime of the entry object passed into the function.
  42. Nasty, but one has to do these things in the name of the god performance.
  43. DBDB: remember to rename the structures mark complained weren't compliant with the slapi naming scheme.
  44. */
  45. #include "slap.h"
  46. #include "vattr_spi.h"
  47. #include "statechange.h"
  48. #ifdef SOURCEFILE
  49. #undef SOURCEFILE
  50. #endif
  51. #define SOURCEFILE "vattr.c"
  52. static char *sourcefile = SOURCEFILE;
  53. /* Define only for module test code */
  54. /* #define VATTR_TEST_CODE */
  55. /* Loop context structure */
  56. struct _vattr_context {
  57. Slapi_PBlock *pb;
  58. unsigned int vattr_context_loop_count;
  59. unsigned int error_displayed;
  60. };
  61. #define VATTR_LOOP_COUNT_MAX 50
  62. typedef vattr_sp_handle vattr_sp_handle_list;
  63. /* Local prototypes */
  64. static int vattr_map_create();
  65. static void vattr_map_destroy();
  66. int vattr_map_sp_insert(char *type_to_add, vattr_sp_handle *sp, void *hint);
  67. vattr_sp_handle_list *vattr_map_sp_getlist(char *type_to_find);
  68. vattr_sp_handle_list *vattr_map_namespace_sp_getlist(Slapi_DN *dn, const char *type_to_find);
  69. vattr_sp_handle_list *vattr_map_sp_get_complete_list();
  70. vattr_sp_handle *vattr_map_sp_first(vattr_sp_handle_list *list,void **hint);
  71. vattr_sp_handle *vattr_map_sp_next(vattr_sp_handle_list *list,void **hint);
  72. vattr_sp_handle *vattr_list_sp_first(vattr_sp_handle_list *list);
  73. vattr_sp_handle *vattr_list_sp_next(vattr_sp_handle_list *list);
  74. int vattr_call_sp_get_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *buffer_flags, void *hint);
  75. int vattr_call_sp_get_batch_values(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, char **type, Slapi_ValueSet*** results,int **type_name_disposition, char*** actual_type_name, int flags, int *buffer_flags, void** hint);
  76. int vattr_call_sp_compare_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, const char *type, Slapi_Value* test_this,int *result, int flags, void* hint);
  77. int vattr_call_sp_get_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags);
  78. void schema_changed_callback(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data);
  79. int slapi_vattrspi_register_internal(vattr_sp_handle **h, vattr_get_fn_type get_fn, vattr_get_ex_fn_type get_ex_fn, vattr_compare_fn_type compare_fn, vattr_types_fn_type types_fn, void *options);
  80. #ifdef VATTR_TEST_CODE
  81. int vattr_basic_sp_init();
  82. #endif
  83. void **statechange_api;
  84. /* Housekeeping Functions, called by server startup/shutdown code */
  85. /* Called on server startup, init all structures etc */
  86. void vattr_init()
  87. {
  88. statechange_api = 0;
  89. vattr_map_create();
  90. #ifdef VATTR_TEST_CODE
  91. vattr_basic_sp_init();
  92. #endif
  93. }
  94. /* Called on server shutdown, free all structures, inform service providers that we're going down etc */
  95. void vattr_cleanup()
  96. {
  97. vattr_map_destroy();
  98. }
  99. /* The public interface functions start here */
  100. /* Function which returns the value(s) of an attribute, given an entry and the attribute type name */
  101. /* Return 0 if OK, ?? if attr doesn't exist, ?? if some error condition ?? if result doesn't need to be free'ed */
  102. int slapi_vattr_values_get(/* Entry we're interested in */ Slapi_Entry *e, /* attr type name */ char *type, /* pointer to result set */ Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *buffer_flags)
  103. {
  104. vattr_context *c = NULL;
  105. return slapi_vattr_values_get_sp(c,e,type,results,type_name_disposition,actual_type_name,flags, buffer_flags);
  106. }
  107. int slapi_vattr_values_get_ex(/* Entry we're interested in */ Slapi_Entry *e,/* attr type name */ char *type, /* pointer to result set */ Slapi_ValueSet*** results,int **type_name_disposition, char*** actual_type_name, int flags, int *buffer_flags, int *subtype_count)
  108. {
  109. vattr_context *c = NULL;
  110. return slapi_vattr_values_get_sp_ex(c,e,type,results,type_name_disposition,actual_type_name,flags, buffer_flags, subtype_count);
  111. }
  112. int slapi_vattr_namespace_values_get(/* Entry we're interested in */ Slapi_Entry *e, /* backend namespace dn*/ Slapi_DN *namespace_dn, /* attr type name */ char *type, /* pointer to result set */ Slapi_ValueSet*** results,int **type_name_disposition, char*** actual_type_name, int flags, int *buffer_flags, int *subtype_count)
  113. {
  114. vattr_context *c = NULL;
  115. return slapi_vattr_namespace_values_get_sp(c,e,namespace_dn,type,results,type_name_disposition,actual_type_name,flags, buffer_flags, subtype_count);
  116. }
  117. /*
  118. * If pointers into the entry were requested then we might have
  119. * a stashed pointer to the entry values, otherwise will be null.
  120. */
  121. Slapi_ValueSet *vattr_typethang_get_values(vattr_type_thang *t)
  122. {
  123. return t->type_values;
  124. }
  125. /*
  126. * This can be much faster than using slapi_vattr_values_get()
  127. * when you have a vattr_type_thang list returned from slapi_vattr_list_types().
  128. *
  129. * We call the vattr SPs to get values for an attribute type in the list only
  130. * if the results field for that attribute type is null.
  131. * If the type list comes from slapi_vattr_list_types() then the value is null
  132. * only for attributes for which an SP wishes to provide a value, so fo the other
  133. * ones don't bother calling the SPs again--just use the real value we picked up
  134. * from the entry.
  135. *
  136. */
  137. int slapi_vattr_values_type_thang_get(
  138. Slapi_Entry *e,
  139. vattr_type_thang *type_thang,
  140. Slapi_ValueSet **results,
  141. int *type_name_disposition,
  142. char **actual_type_name,
  143. int flags,
  144. int *buffer_flags
  145. )
  146. {
  147. int rc = 0;
  148. char *type = NULL;
  149. type = vattr_typethang_get_name(type_thang);
  150. *results = vattr_typethang_get_values(type_thang);
  151. if (*results != NULL) {
  152. /* we already have a pointer directly into the entry */
  153. *actual_type_name = type;
  154. *type_name_disposition =
  155. SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
  156. *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
  157. } else {
  158. /* fall back to usual implementation */
  159. rc = slapi_vattr_values_get(e,type,results,
  160. type_name_disposition,
  161. actual_type_name,
  162. flags,buffer_flags);
  163. }
  164. return rc;
  165. }
  166. static void vattr_helper_get_entry_conts(Slapi_Entry *e,char *type, vattr_get_thang *my_get)
  167. {
  168. Slapi_Attr *a = NULL;
  169. void *dummy = 0;
  170. a = attrlist_find_ex(e->e_attrs,type,&(my_get->get_name_disposition), &(my_get->get_type_name), &dummy);
  171. if (a) {
  172. my_get->get_present = 1;
  173. my_get->get_present_values = &(a->a_present_values);
  174. my_get->get_attr = a;
  175. }
  176. }
  177. static int vattr_helper_get_entry_conts_with_subtypes(Slapi_Entry *e,const char *type, vattr_get_thang **my_get)
  178. {
  179. Slapi_Attr *a = NULL;
  180. void *hint = 0;
  181. int counter = 0;
  182. int attr_count = attrlist_count_subtypes(e->e_attrs,type);
  183. if(attr_count > 0)
  184. {
  185. *my_get = (vattr_get_thang *)slapi_ch_calloc(attr_count, sizeof(vattr_get_thang));
  186. /* pick up attributes with sub-types and slip into the get_thang list */
  187. for(counter = 0; counter < attr_count; counter++)
  188. {
  189. a = attrlist_find_ex(e->e_attrs,type,&((*my_get)[counter].get_name_disposition), &((*my_get)[counter].get_type_name), &hint);
  190. if (a) {
  191. (*my_get)[counter].get_present = 1;
  192. (*my_get)[counter].get_present_values = &(a->a_present_values);
  193. (*my_get)[counter].get_attr = a;
  194. }
  195. }
  196. }
  197. return attr_count;
  198. }
  199. static int vattr_helper_get_entry_conts_no_subtypes(Slapi_Entry *e,const char *type, vattr_get_thang **my_get)
  200. {
  201. int attr_count = 0;
  202. Slapi_Attr *a = attrlist_find(e->e_attrs,type);
  203. if (a) {
  204. attr_count = 1;
  205. *my_get = (vattr_get_thang *)slapi_ch_calloc(1, sizeof(vattr_get_thang));
  206. (*my_get)[0].get_present = 1;
  207. (*my_get)[0].get_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
  208. (*my_get)[0].get_type_name = a->a_type;
  209. (*my_get)[0].get_present_values = &(a->a_present_values);
  210. (*my_get)[0].get_attr = a;
  211. }
  212. return attr_count;
  213. }
  214. static int vattr_helper_get_entry_conts_ex(Slapi_Entry *e,const char *type, vattr_get_thang **my_get, int suppress_subtypes)
  215. {
  216. int rc;
  217. if ( suppress_subtypes ) {
  218. rc = vattr_helper_get_entry_conts_no_subtypes(e, type, my_get);
  219. } else {
  220. rc = vattr_helper_get_entry_conts_with_subtypes(e, type, my_get);
  221. }
  222. return rc;
  223. }
  224. vattr_context *vattr_context_new( Slapi_PBlock *pb )
  225. {
  226. vattr_context *c = NULL;
  227. if (pb && pb->pb_vattr_context) {
  228. c = (vattr_context *)pb->pb_vattr_context;
  229. } else {
  230. c = (vattr_context *)slapi_ch_calloc(1, sizeof(vattr_context));
  231. }
  232. /* The payload is zero, which is what we want */
  233. if ( c ) {
  234. c->pb = pb;
  235. }
  236. if ( pb && c != (vattr_context *)pb->pb_vattr_context ) {
  237. pb->pb_vattr_context = (void *)c;
  238. }
  239. return c;
  240. }
  241. static int vattr_context_check(vattr_context *c)
  242. {
  243. /* Observe the loop count and see if it's higher than is allowed */
  244. if (c->vattr_context_loop_count > VATTR_LOOP_COUNT_MAX) {
  245. return SLAPI_VIRTUALATTRS_LOOP_DETECTED;
  246. } else return 0;
  247. }
  248. static void vattr_context_mark(vattr_context *c)
  249. {
  250. c->vattr_context_loop_count += 1;
  251. }
  252. static int vattr_context_unmark(vattr_context *c)
  253. {
  254. return (c->vattr_context_loop_count -= 1);
  255. }
  256. /* modify the context structure on exit from a vattr sp function */
  257. static void vattr_context_ungrok(vattr_context **c)
  258. {
  259. /* Decrement the loop count */
  260. if (0 == vattr_context_unmark(*c)) {
  261. /* If necessary, delete the structure */
  262. if ((*c)->pb) {
  263. (*c)->pb->pb_vattr_context = NULL;
  264. }
  265. slapi_ch_free((void **)c);
  266. }
  267. }
  268. static int vattr_context_grok_pb( Slapi_PBlock *pb, vattr_context **c )
  269. {
  270. int rc = -1;
  271. if (NULL == c) {
  272. return rc;
  273. }
  274. *c = vattr_context_new( pb );
  275. if (NULL == *c) {
  276. return ENOMEM;
  277. }
  278. rc = vattr_context_check(*c);
  279. vattr_context_mark(*c); /* increment loop count */
  280. return rc;
  281. }
  282. /* Check and mess with the context structure on entry to a vattr sp function */
  283. static int vattr_context_grok(vattr_context **c)
  284. {
  285. int rc = 0;
  286. /* First check that we've not got into an infinite loop.
  287. We do so by means of the vattr_context structure.
  288. */
  289. /* Do we have a context at all ?? */
  290. if (NULL == *c) {
  291. /* No, so let's make one */
  292. *c = vattr_context_new( NULL );
  293. if (NULL == *c) {
  294. return ENOMEM;
  295. }
  296. } else {
  297. /* Yes, so let's check its contents */
  298. rc = vattr_context_check(*c);
  299. }
  300. /* mark the context as having been used once */
  301. vattr_context_mark(*c);
  302. return rc;
  303. }
  304. /* keep track of error messages so we don't spam the error log */
  305. static void vattr_context_set_loop_msg_displayed(vattr_context **c)
  306. {
  307. (*c)->error_displayed = 1;
  308. }
  309. static int vattr_context_is_loop_msg_displayed(vattr_context **c)
  310. {
  311. return (*c)->error_displayed;
  312. }
  313. /*
  314. * vattr_test_filter:
  315. *
  316. * . tests an ava, presence or substring filter against e.
  317. * . group these filter types together to avoid having to duplicate the
  318. * . vattr specific code in three seperate routines.
  319. * . handles virtual attrs in the filter.
  320. * . does update the vattrcache if a call to this calculates vattrs
  321. *
  322. * returns: 0 filter matched
  323. * -1 filter did not match
  324. * >0 an ldap error code
  325. *
  326. */
  327. int vattr_test_filter( Slapi_PBlock *pb,
  328. /* Entry we're interested in */ Slapi_Entry *e,
  329. Slapi_Filter *f,
  330. filter_type_t filter_type,
  331. char * type)
  332. {
  333. int rc = -1;
  334. int sp_bit = 0; /* Set if an SP supplied an answer */
  335. vattr_sp_handle_list *list = NULL;
  336. Slapi_DN *sdn;
  337. Slapi_Backend *be;
  338. Slapi_DN *namespace_dn;
  339. /* get the namespace this entry belongs to */
  340. sdn = slapi_entry_get_sdn( e );
  341. be = slapi_be_select( sdn );
  342. namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
  343. /* Look for attribute in the map */
  344. if(namespace_dn)
  345. {
  346. list = vattr_map_namespace_sp_getlist(namespace_dn, type);
  347. }
  348. else
  349. {
  350. list = vattr_map_namespace_sp_getlist(NULL, type);
  351. }
  352. if (list) {
  353. vattr_sp_handle *current_handle = NULL;
  354. /* first lets consult the cache to save work */
  355. int cache_status;
  356. cache_status = slapi_entry_vattrcache_findAndTest(e, type,
  357. f,
  358. filter_type,
  359. &rc);
  360. switch(cache_status)
  361. {
  362. case SLAPI_ENTRY_VATTR_RESOLVED_EXISTS: /* cached vattr */
  363. {
  364. sp_bit = 1;
  365. break;
  366. }
  367. case SLAPI_ENTRY_VATTR_RESOLVED_ABSENT: /* does not exist */
  368. break; /* look in entry */
  369. case SLAPI_ENTRY_VATTR_NOT_RESOLVED: /* not resolved */
  370. default: /* any other result, resolve */
  371. {
  372. int flags = SLAPI_VIRTUALATTRS_REQUEST_POINTERS;
  373. void *hint = NULL;
  374. Slapi_ValueSet **results = NULL; /* pointer to result set */
  375. int *type_name_disposition;
  376. char **actual_type_name;
  377. int buffer_flags;
  378. vattr_get_thang my_get = {0};
  379. /* bit cacky, but need to make a null terminated lists for now
  380. * for the (unimplemented and so fake) batch attribute request
  381. */
  382. char *types[2];
  383. void *hint_list[2];
  384. vattr_context *ctx;
  385. vattr_context_grok_pb( pb, &ctx ); /* get or new context */
  386. types[0] = type;
  387. types[1] = 0;
  388. hint_list[1] = 0;
  389. for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint))
  390. {
  391. hint_list[0] = hint;
  392. rc = vattr_call_sp_get_batch_values(current_handle,ctx,e,
  393. &my_get,types,&results,&type_name_disposition,
  394. &actual_type_name,flags,&buffer_flags, hint_list);
  395. if (0 == rc)
  396. {
  397. sp_bit = 1;
  398. break;
  399. }
  400. }
  401. vattr_context_ungrok(&ctx);
  402. if(!sp_bit)
  403. {
  404. /*
  405. * No vattr sp supplied an answer so will look in the
  406. * entry itself.
  407. * but first lets cache the no result
  408. */
  409. slapi_entry_vattrcache_merge_sv(e, type, NULL, buffer_flags);
  410. }
  411. else
  412. {
  413. /*
  414. * A vattr sp supplied an answer.
  415. * so turn the value into a Slapi_Attr, pass
  416. * to the syntax plugin for comparison.
  417. */
  418. if ( filter_type == FILTER_TYPE_AVA ||
  419. filter_type == FILTER_TYPE_SUBSTRING ) {
  420. Slapi_Attr *a = NULL;
  421. int i=0;
  422. /* may need this when we have a passin interface for set_valueset */
  423. /*Slapi_ValueSet null_valueset = {0};*/
  424. rc=-1;
  425. if(results && actual_type_name && type_name_disposition)
  426. {
  427. while(results[i] && rc)
  428. {
  429. a = slapi_attr_new();
  430. slapi_attr_init(a, type);
  431. /* a now contains a *copy* of results */
  432. slapi_attr_set_valueset( a, results[i]);
  433. if ( filter_type == FILTER_TYPE_AVA ) {
  434. rc = plugin_call_syntax_filter_ava( a,
  435. f->f_choice, &f->f_ava );
  436. } else if ( filter_type == FILTER_TYPE_SUBSTRING) {
  437. rc = plugin_call_syntax_filter_sub( pb, a,
  438. &f->f_sub);
  439. }
  440. /*
  441. * Cache stuff: dups results
  442. */
  443. slapi_entry_vattrcache_merge_sv(e, actual_type_name[i],
  444. results[i], buffer_flags);
  445. /*
  446. * Free stuff, just in case we did not
  447. * get pointers.
  448. */
  449. slapi_vattr_values_free( &(results[i]),
  450. &(actual_type_name[i]),
  451. buffer_flags);
  452. /* may need this when we support a passin set_valueset */
  453. /*slapi_attr_set_valueset( a, &null_valueset);*/
  454. /* since a contains a copy of results, we must free it */
  455. slapi_attr_free(&a);
  456. i++;
  457. }
  458. }
  459. slapi_ch_free((void**)&results);
  460. slapi_ch_free((void**)&actual_type_name);
  461. slapi_ch_free((void**)&type_name_disposition);
  462. } else if ( filter_type == FILTER_TYPE_PRES ) {
  463. /*
  464. * Cache stuff: dups results
  465. */
  466. int i=0;
  467. while(results[i])
  468. {
  469. slapi_entry_vattrcache_merge_sv(e, actual_type_name[i],
  470. results[i], buffer_flags);
  471. /*
  472. * Free stuff, just in case we did not
  473. * get pointers.
  474. */
  475. slapi_vattr_values_free( &results[i],
  476. &actual_type_name[i],
  477. buffer_flags);
  478. }
  479. slapi_ch_free((void**)&results);
  480. slapi_ch_free((void**)&actual_type_name);
  481. slapi_ch_free((void**)&type_name_disposition);
  482. }
  483. }
  484. break;
  485. }
  486. }/* switch */
  487. }
  488. /* If no SP supplied the answer, take it from the entry */
  489. if (rc <= 1 && !sp_bit) /* if LDAP ERROR is set, skip further testing */
  490. {
  491. int acl_test_done;
  492. if ( filter_type == FILTER_TYPE_AVA ) {
  493. rc = test_ava_filter( NULL /* pb not needed */,
  494. e, e->e_attrs, &f->f_ava,
  495. f->f_choice,
  496. 0 /* no access check */,
  497. 0 /* do test filter */,
  498. &acl_test_done);
  499. } else if ( filter_type == FILTER_TYPE_SUBSTRING ) {
  500. rc = test_substring_filter( pb, e, f, 0 /* no access check */,
  501. 0 /* do test filter */, &acl_test_done);
  502. } else if ( filter_type == FILTER_TYPE_PRES ) {
  503. rc = test_presence_filter( NULL, e, f->f_type,
  504. 0 /* no access check */,
  505. 0 /* do test filter */,
  506. &acl_test_done);
  507. }
  508. }
  509. return rc;
  510. }
  511. /*
  512. * deprecated in favour of slapi_vattr_values_get_sp_ex() which
  513. * returns subtypes too.
  514. */
  515. SLAPI_DEPRECATED int
  516. slapi_vattr_values_get_sp(vattr_context *c,
  517. /* Entry we're interested in */ Slapi_Entry *e,
  518. /* attr type name */ char *type,
  519. /* pointer to result set */ Slapi_ValueSet** results,
  520. int *type_name_disposition,
  521. char** actual_type_name, int flags,
  522. int *buffer_flags)
  523. {
  524. PRBool use_local_ctx = PR_FALSE;
  525. Slapi_PBlock *local_pb = NULL;
  526. vattr_context *ctx = NULL;
  527. int rc = 0;
  528. int sp_bit = 0; /* Set if an SP supplied an answer */
  529. vattr_sp_handle_list *list = NULL;
  530. vattr_get_thang my_get = {0};
  531. if (c != NULL) {
  532. rc = vattr_context_grok(&c);
  533. if (0 != rc) {
  534. if(!vattr_context_is_loop_msg_displayed(&c))
  535. {
  536. /* Print a handy error log message */
  537. LDAPDebug(LDAP_DEBUG_ANY,
  538. "Detected virtual attribute loop in get on entry %s, attribute %s\n",
  539. slapi_entry_get_dn_const(e), type, 0);
  540. vattr_context_set_loop_msg_displayed(&c);
  541. }
  542. return rc;
  543. }
  544. ctx = c;
  545. } else {
  546. use_local_ctx = PR_TRUE;
  547. local_pb = slapi_pblock_new();
  548. ctx = vattr_context_new( local_pb );
  549. ctx->vattr_context_loop_count = 1;
  550. ctx->error_displayed = 0;
  551. }
  552. /* For attributes which are in the entry, we just need to get to the Slapi_Attr structure and yank out the slapi_value_set
  553. structure. We either return a pointer directly to it, or we copy it, depending upon whether the caller asked us to try to
  554. avoid copying.
  555. */
  556. /* First grok the entry, and remember what we saw. This call does no more than walk down the entry attribute list, do some string compares and copy pointers. */
  557. vattr_helper_get_entry_conts(e,type, &my_get);
  558. /* Having done that, we now consult the attribute map to find service providers who are interested */
  559. /* Look for attribute in the map */
  560. if(!(flags & SLAPI_REALATTRS_ONLY))
  561. {
  562. list = vattr_map_sp_getlist(type);
  563. if (list) {
  564. vattr_sp_handle *current_handle = NULL;
  565. void *hint = NULL;
  566. /* first lets consult the cache to save work */
  567. int cache_status;
  568. cache_status =
  569. slapi_entry_vattrcache_find_values_and_type(e, type,
  570. results,
  571. actual_type_name);
  572. switch(cache_status)
  573. {
  574. case SLAPI_ENTRY_VATTR_RESOLVED_EXISTS: /* cached vattr */
  575. {
  576. sp_bit = 1;
  577. /* Complete analysis of type matching */
  578. if ( 0 == slapi_attr_type_cmp( type , *actual_type_name, SLAPI_TYPE_CMP_EXACT) )
  579. {
  580. *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
  581. } else {
  582. *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE;
  583. }
  584. break;
  585. }
  586. case SLAPI_ENTRY_VATTR_RESOLVED_ABSENT: /* does not exist */
  587. break; /* look in entry */
  588. case SLAPI_ENTRY_VATTR_NOT_RESOLVED: /* not resolved */
  589. default: /* any other result, resolve */
  590. {
  591. for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint))
  592. {
  593. rc = vattr_call_sp_get_value(current_handle,ctx,e,&my_get,type,results,type_name_disposition,actual_type_name,flags,buffer_flags, hint);
  594. if (0 == rc)
  595. {
  596. sp_bit = 1;
  597. break;
  598. }
  599. }
  600. if(!sp_bit)
  601. {
  602. /* clean up, we have failed and must now examine the
  603. * entry itself
  604. * But first lets cache the no result
  605. * Creates the type (if necessary).
  606. */
  607. slapi_entry_vattrcache_merge_sv(e, type, NULL, *buffer_flags);
  608. }
  609. else
  610. {
  611. /*
  612. * we need to cache the virtual attribute
  613. * creates the type (if necessary) and dups
  614. * results.
  615. */
  616. slapi_entry_vattrcache_merge_sv(e, *actual_type_name,
  617. *results, *buffer_flags);
  618. }
  619. break;
  620. }
  621. }
  622. }
  623. }
  624. /* If no SP supplied the answer, take it from the entry */
  625. if (!sp_bit && !(flags & SLAPI_VIRTUALATTRS_ONLY))
  626. {
  627. rc = 0; /* reset return code (cause an sp must have failed) */
  628. *type_name_disposition = my_get.get_name_disposition;
  629. if (my_get.get_present) {
  630. if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
  631. *results = my_get.get_present_values;
  632. *actual_type_name = my_get.get_type_name;
  633. } else {
  634. *results = valueset_dup(my_get.get_present_values);
  635. if (NULL == *results) {
  636. rc = ENOMEM;
  637. } else {
  638. *actual_type_name = slapi_ch_strdup(my_get.get_type_name);
  639. if (NULL == *actual_type_name) {
  640. rc = ENOMEM;
  641. }
  642. }
  643. }
  644. if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
  645. *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
  646. } else {
  647. *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
  648. }
  649. } else {
  650. rc = SLAPI_VIRTUALATTRS_NOT_FOUND;
  651. }
  652. }
  653. if (use_local_ctx) {
  654. /* slapi_pblock_destroy cleans up pb_vattr_context, as well */
  655. slapi_pblock_destroy(local_pb);
  656. } else {
  657. vattr_context_ungrok(&c);
  658. }
  659. return rc;
  660. }
  661. /*
  662. *
  663. * returns 0: (no_error && type found ) in which case:
  664. * results: contains the current values for type and
  665. * all it's subtypes in e
  666. * type_name_disposition: how each type was matched
  667. * SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS
  668. * SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE
  669. * actual_type_name: type name as found
  670. * flags: bit mask of options:
  671. * SLAPI_REALATTRS_ONLY
  672. * SLAPI_VIRTUALATTRS_ONLY
  673. * SLAPI_VIRTUALATTRS_REQUEST_POINTERS
  674. * SLAPI_VIRTUALATTRS_LIST_OPERATIONAL_ATTRS
  675. * buffer_flags: bit mask to be used as input flags for
  676. * slapi_values_free()
  677. * SLAPI_VIRTUALATTRS_RETURNED_POINTERS
  678. * SLAPI_VIRTUALATTRS_RETURNED_COPIES
  679. * SLAPI_VIRTUALATTRS_REALATTRS_ONLY
  680. * item_count: number of subtypes matched
  681. * otherwise:
  682. * SLAPI_VIRTUALATTRS_LOOP_DETECTED (failed to eval a vattr)
  683. * SLAPI_VIRTUALATTRS_NOT_FOUND (type not recognised by any vattr
  684. * sp && not a real attr in entry )
  685. * ENOMEM (memory error)
  686. *
  687. * Note:
  688. * . modifes the virtual cache in the entry.
  689. * . for cached vattrs you always get a copy, so it will need to be
  690. * freed via slapi_values_free().
  691. *
  692. */
  693. int slapi_vattr_values_get_sp_ex(vattr_context *c,
  694. /* Entry we're interested in */ Slapi_Entry *e,
  695. /* attr type name */ char *type,
  696. /* pointer to result set */ Slapi_ValueSet*** results,
  697. int **type_name_disposition,
  698. char*** actual_type_name, int flags,
  699. int *buffer_flags, int *item_count)
  700. {
  701. return slapi_vattr_namespace_values_get_sp(
  702. c, e, NULL, type, results, type_name_disposition,
  703. actual_type_name, flags, buffer_flags, item_count
  704. );
  705. }
  706. int slapi_vattr_namespace_values_get_sp(vattr_context *c,
  707. /* Entry we're interested in */ Slapi_Entry *e,
  708. /* DN denoting backend namespace */ Slapi_DN *namespace_dn,
  709. /* attr type name */ char *type,
  710. /* pointer to result set */ Slapi_ValueSet*** results,
  711. int **type_name_disposition,
  712. char*** actual_type_name, int flags,
  713. int *buffer_flags, int *item_count)
  714. {
  715. int rc = 0;
  716. int sp_bit = 0; /* Set if an SP supplied an answer */
  717. vattr_sp_handle_list *list = NULL;
  718. vattr_get_thang *my_get = NULL;
  719. int attr_count = 0;
  720. int ignore_vattrs;
  721. ignore_vattrs = config_get_ignore_vattrs();
  722. if(!ignore_vattrs){
  723. rc = vattr_context_grok(&c);
  724. if (0 != rc) {
  725. /* Print a handy error log message */
  726. if(!vattr_context_is_loop_msg_displayed(&c))
  727. {
  728. LDAPDebug(LDAP_DEBUG_ANY,"Detected virtual attribute loop in get on entry %s, attribute %s\n", slapi_entry_get_dn_const(e), type, 0);
  729. vattr_context_set_loop_msg_displayed(&c);
  730. }
  731. return rc;
  732. }
  733. }
  734. /* Having done that, we now consult the attribute map to find service providers who are interested */
  735. /* Look for attribute in the map */
  736. if(!(flags & SLAPI_REALATTRS_ONLY) && !ignore_vattrs)
  737. {
  738. /* we use the vattr namespace aware version of this */
  739. list = vattr_map_namespace_sp_getlist(namespace_dn, type);
  740. if (list) {
  741. vattr_sp_handle *current_handle = NULL;
  742. void *hint = NULL;
  743. /* first lets consult the cache to save work */
  744. int cache_status;
  745. cache_status =
  746. slapi_entry_vattrcache_find_values_and_type_ex(e, type,
  747. results,
  748. actual_type_name);
  749. switch(cache_status)
  750. {
  751. case SLAPI_ENTRY_VATTR_RESOLVED_EXISTS: /* cached vattr */
  752. {
  753. sp_bit = 1;
  754. /* Complete analysis of type matching */
  755. *type_name_disposition =
  756. (int *)slapi_ch_malloc(sizeof(**type_name_disposition));
  757. if ( 0 == slapi_attr_type_cmp( type , **actual_type_name, SLAPI_TYPE_CMP_EXACT) )
  758. {
  759. **type_name_disposition =
  760. SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
  761. } else {
  762. **type_name_disposition =
  763. SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE;
  764. }
  765. *item_count = 1;
  766. break;
  767. }
  768. case SLAPI_ENTRY_VATTR_RESOLVED_ABSENT: /* does not exist */
  769. break; /* look in entry */
  770. case SLAPI_ENTRY_VATTR_NOT_RESOLVED: /* not resolved */
  771. default: /* any other result, resolve */
  772. {
  773. /* bit cacky, but need to make a null terminated lists for now
  774. * for the (unimplemented and so fake) batch attribute request
  775. */
  776. char **type_list = (char**)slapi_ch_calloc(2,sizeof(char*));
  777. void **hint_list = (void**)slapi_ch_calloc(2,sizeof(void*));
  778. type_list[0] = type;
  779. for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint)) {
  780. /* call this SP */
  781. hint_list[0] = hint;
  782. rc = vattr_call_sp_get_batch_values(current_handle,c,e,my_get,
  783. type_list,results,type_name_disposition,
  784. actual_type_name, flags,buffer_flags, hint_list);
  785. if (0 == rc) {
  786. sp_bit = 1; /* this sp provided an answer, we are done */
  787. /* count the items in the (null terminated) result list */
  788. *item_count = 0;
  789. while((*results)[*item_count])
  790. {
  791. (*item_count)++;
  792. }
  793. break;
  794. }
  795. }
  796. slapi_ch_free((void**)&type_list);
  797. slapi_ch_free((void**)&hint_list);
  798. if(!sp_bit)
  799. {
  800. /* we have failed and must now examine the entry itself
  801. *
  802. * But first lets cache the no result
  803. * dups the type (if necessary).
  804. */
  805. slapi_entry_vattrcache_merge_sv(e, type, NULL, *buffer_flags);
  806. }
  807. else
  808. {
  809. /*
  810. * we need to cache the virtual attribute
  811. * dups the type (if necessary) and results.
  812. */
  813. /*
  814. * this (and above) will of course need to get updated
  815. * when we do real batched attributes
  816. */
  817. slapi_entry_vattrcache_merge_sv(e, **actual_type_name,
  818. **results, *buffer_flags);
  819. }
  820. }
  821. }
  822. }
  823. }
  824. /* If no SP supplied the answer, take it from the entry */
  825. if (!sp_bit && !(flags & SLAPI_VIRTUALATTRS_ONLY))
  826. {
  827. int counter;
  828. /* First grok the entry - allocates memory for list */
  829. attr_count = vattr_helper_get_entry_conts_ex(e,type, &my_get,
  830. (0 != (flags & SLAPI_VIRTUALATTRS_SUPPRESS_SUBTYPES)));
  831. *item_count = attr_count;
  832. rc = 0; /* reset return code (cause an sp must have failed) */
  833. if(attr_count > 0)
  834. {
  835. *results = (Slapi_ValueSet**)slapi_ch_calloc(1, sizeof(**results) * attr_count);
  836. *type_name_disposition = (int *)slapi_ch_malloc(sizeof(**type_name_disposition) * attr_count);
  837. *actual_type_name = (char**)slapi_ch_malloc(sizeof(**actual_type_name) * attr_count);
  838. /* For attributes which are in the entry, we just need to get to the Slapi_Attr structure and yank out the slapi_value_set
  839. structure. We either return a pointer directly to it, or we copy it, depending upon whether the caller asked us to try to
  840. avoid copying.
  841. */
  842. for(counter = 0; counter < attr_count; counter++)
  843. {
  844. (*type_name_disposition)[counter] = my_get[counter].get_name_disposition;
  845. if (my_get[counter].get_present) {
  846. if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
  847. /* pointers will do, good */
  848. (*results)[counter] = my_get[counter].get_present_values;
  849. (*actual_type_name)[counter] = my_get[counter].get_type_name;
  850. } else {
  851. /* need to copy the values */
  852. (*results)[counter] = valueset_dup(my_get[counter].get_present_values);
  853. if (NULL == (*results)[counter]) {
  854. rc = ENOMEM;
  855. } else {
  856. (*actual_type_name)[counter] = slapi_ch_strdup(my_get[counter].get_type_name);
  857. if (NULL == (*actual_type_name)[counter]) {
  858. rc = ENOMEM;
  859. }
  860. }
  861. }
  862. if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
  863. *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
  864. } else {
  865. *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
  866. }
  867. } else {
  868. rc = SLAPI_VIRTUALATTRS_NOT_FOUND;
  869. }
  870. }
  871. slapi_ch_free((void **)&my_get);
  872. }
  873. }
  874. vattr_context_ungrok(&c);
  875. return rc;
  876. }
  877. /* Do we need a call to free the results from the above ? */
  878. void slapi_vattr_values_free(Slapi_ValueSet **value, char** actual_type_name,
  879. int flags)
  880. {
  881. /* Check whether we need to free the strings */
  882. if (flags & SLAPI_VIRTUALATTRS_RETURNED_POINTERS) {
  883. /* We don't need to free the values */
  884. } else {
  885. /* Free the valueset */
  886. if (*value) {
  887. slapi_valueset_free(*value);
  888. }
  889. if (*actual_type_name) {
  890. slapi_ch_free((void **)actual_type_name);
  891. }
  892. }
  893. *actual_type_name = NULL;
  894. *value = NULL;
  895. }
  896. /* Function like the one above but doing a compare operation */
  897. /* Same return codes as above. Compare result value returned in "result": 0 if compare true, 1 if compare false */
  898. int slapi_vattr_value_compare(Slapi_Entry *e, char *type, Slapi_Value *test_this, int *result, int flags)
  899. {
  900. return slapi_vattr_namespace_value_compare_sp(NULL,e,NULL,type,test_this,result,flags);
  901. }
  902. /* namespace version of above */
  903. int slapi_vattr_namespace_value_compare(Slapi_Entry *e, Slapi_DN *namespace_dn, const char *type, Slapi_Value *test_this, int *result, int flags)
  904. {
  905. return slapi_vattr_namespace_value_compare_sp(NULL,e,namespace_dn,type,test_this,result,flags);
  906. }
  907. int slapi_vattr_value_compare_sp(vattr_context *c,/* Entry we're interested in */ Slapi_Entry *e,/* attr type name */ char *type, Slapi_Value *test_this,/* pointer to result */ int *result, int flags)
  908. {
  909. return slapi_vattr_namespace_value_compare_sp(c,e,NULL,type,test_this,result,flags);
  910. }
  911. int slapi_vattr_namespace_value_compare_sp(vattr_context *c,/* Entry we're interested in */ Slapi_Entry *e, /* backend namespace dn*/Slapi_DN *namespace_dn, /* attr type name */ const char *type, Slapi_Value *test_this,/* pointer to result */ int *result, int flags)
  912. {
  913. int rc = 0;
  914. int sp_bit = 0; /* Set if an SP supplied an answer */
  915. vattr_sp_handle_list *list = NULL;
  916. vattr_get_thang *my_get = 0;
  917. *result = 0; /* return "compare false" by default */
  918. rc = vattr_context_grok(&c);
  919. if (0 != rc) {
  920. if(!vattr_context_is_loop_msg_displayed(&c)) {
  921. /* Print a handy error log message */
  922. LDAPDebug(LDAP_DEBUG_ANY,"Detected virtual attribute loop in compare on entry %s, attribute %s\n", slapi_entry_get_dn_const(e), type, 0);
  923. vattr_context_set_loop_msg_displayed(&c);
  924. }
  925. return rc;
  926. }
  927. /* Having done that, we now consult the attribute map to find service providers who are interested */
  928. /* Look for attribute in the map */
  929. list = vattr_map_namespace_sp_getlist(namespace_dn, type);
  930. if (list) {
  931. vattr_sp_handle *current_handle = NULL;
  932. void *hint = NULL;
  933. for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint)) {
  934. /* call this SP */
  935. rc = vattr_call_sp_compare_value(current_handle,c,e,my_get,type,test_this,result,flags, hint);
  936. if (0 == rc) {
  937. sp_bit = 1;
  938. break;
  939. }
  940. }
  941. }
  942. /* If no SP supplied the answer, take it from the entry */
  943. if (!sp_bit) {
  944. /* Grok the entry, and remember what we saw. This call does no more than walk down the entry attribute list, do some string compares and copy pointers. */
  945. int attr_count = vattr_helper_get_entry_conts_ex(e,type, &my_get,
  946. (0 != (flags & SLAPI_VIRTUALATTRS_SUPPRESS_SUBTYPES)));
  947. if (my_get && my_get->get_present) {
  948. int i;
  949. Slapi_Value *Dummy_value = NULL;
  950. /* Put the required stuff in the fake attr */
  951. rc = 0; /* found real attr - now see if we have the requested value*/
  952. *result = 0; /* return "compare false" by default */
  953. for(i=0;i<attr_count;i++)
  954. {
  955. Dummy_value = slapi_valueset_find( my_get[i].get_attr, my_get[i].get_present_values, test_this );
  956. if (Dummy_value) {
  957. *result = 1; /* return "compare true" */
  958. break;
  959. }
  960. }
  961. } else {
  962. /* no such attribute */
  963. rc = SLAPI_VIRTUALATTRS_NOT_FOUND;
  964. }
  965. }
  966. vattr_context_ungrok(&c);
  967. slapi_ch_free((void **)&my_get);
  968. return rc;
  969. }
  970. /* Function to obtain the list of attribute types which are available on this entry */
  971. /*
  972. Need to call service providers here:
  973. We know only the entry's DN and so we could restrict our choice of SPs based on that.
  974. However, we don't yet implement such fancyness.
  975. For now, we just crawl through all the SPs, asking them in turn to contribute.
  976. This is pretty inefficient because we will trawl the list for each wildcard attribute type search operation.
  977. Service providers should therefore handle the call as fast as they can.
  978. */
  979. struct _vattr_type_list_context {
  980. unsigned int vattr_context_loop_count;
  981. vattr_type_thang *types;
  982. int realattrs_only; /* TRUE implies list contains only real attrs */
  983. int list_is_copies;
  984. int flags;
  985. size_t list_length;
  986. size_t block_length;
  987. };
  988. /* Helper function which converts a type list from pointers to copies */
  989. static int vattr_convert_type_list(vattr_type_list_context *thang)
  990. {
  991. vattr_type_thang *old_list = NULL;
  992. vattr_type_thang *new_list = NULL;
  993. size_t index = 0;
  994. old_list = thang->types;
  995. /* Make a new list */
  996. new_list = (vattr_type_thang*)slapi_ch_calloc(thang->block_length, sizeof(vattr_type_thang));
  997. if (NULL == new_list) {
  998. return ENOMEM;
  999. }
  1000. /* Walk the list strdup'ing the type name and copying the rest of the structure contents */
  1001. for (index = 0; index < thang->list_length; index++) {
  1002. new_list[index].type_flags = old_list[index].type_flags;
  1003. new_list[index].type_name = slapi_ch_strdup(old_list[index].type_name);
  1004. /*
  1005. * list_is_copies does not affect type_values as it
  1006. * is always a pointer never a copy.
  1007. */
  1008. new_list[index].type_values = old_list[index].type_values;
  1009. }
  1010. /* Mark it a copy list */
  1011. thang->list_is_copies = 1;
  1012. /* Free the original list */
  1013. slapi_ch_free((void **)&(thang->types));
  1014. /* swap lists */
  1015. thang->types = new_list;
  1016. return 0;
  1017. }
  1018. /*
  1019. * Returns all the attribute types from e, both real and virtual.
  1020. *
  1021. * Any of the attributes found in the entry to start with, for
  1022. * whom no vattr SP volunteered, will also have a pointer to the
  1023. * original valueset in the entry--this fact can be used by
  1024. * calling slapi_vattr_values_type_thang_get(), which will
  1025. * take the values present in the vattr_type_thang list
  1026. * rather than calling slapi_vattr_values_get() to retrieve the value.
  1027. */
  1028. #define TYPE_LIST_EXTRA_SPACE 5 /* Number of extra slots we allow for SP's to insert types */
  1029. int slapi_vattr_list_attrs(/* Entry we're interested in */ Slapi_Entry *e,
  1030. /* pointer to receive the list */ vattr_type_thang **types,
  1031. int flags, int *buffer_flags)
  1032. {
  1033. int rc = 0;
  1034. size_t attr_count = 0;
  1035. vattr_type_thang *result_array = NULL ;
  1036. Slapi_Attr *current_attr = NULL;
  1037. size_t i = 0;
  1038. int list_is_copies = 0;
  1039. vattr_sp_handle_list *list = NULL;
  1040. size_t list_length = 0;
  1041. size_t block_length = 0;
  1042. vattr_type_list_context type_context = {0};
  1043. if (NULL == types || NULL == buffer_flags) {
  1044. LDAPDebug(LDAP_DEBUG_ANY, "slapi_vattr_list_attrs: invalid param\n", 0, 0, 0);
  1045. return -1;
  1046. }
  1047. block_length = 1 + TYPE_LIST_EXTRA_SPACE;
  1048. if(!(flags & SLAPI_VIRTUALATTRS_ONLY))
  1049. {
  1050. /* First find what's in the entry itself*/
  1051. /* Count the attributes */
  1052. for (current_attr = e->e_attrs; current_attr != NULL; current_attr = current_attr->a_next, attr_count++) ;
  1053. block_length += attr_count;
  1054. /* Allocate the pointer array */
  1055. result_array = (vattr_type_thang*)slapi_ch_calloc(block_length,sizeof(vattr_type_thang));
  1056. if (NULL == result_array) {
  1057. return ENOMEM;
  1058. }
  1059. list_length = attr_count;
  1060. /* Now copy the pointers into the array */
  1061. i = 0;
  1062. for (current_attr = e->e_attrs; current_attr != NULL; current_attr = current_attr->a_next) {
  1063. char *mypointer = NULL;
  1064. if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
  1065. mypointer = current_attr->a_type;
  1066. result_array[i].type_values = &(current_attr->a_present_values);
  1067. } else {
  1068. mypointer = slapi_ch_strdup(current_attr->a_type);
  1069. list_is_copies = 1;
  1070. }
  1071. if (NULL == current_attr->a_plugin) {
  1072. /* could be lazy plugin initialization, get it now */
  1073. slapi_attr_init_syntax(current_attr);
  1074. }
  1075. result_array[i].type_flags = current_attr->a_flags;
  1076. result_array[i++].type_name = mypointer;
  1077. }
  1078. PR_ASSERT(i == attr_count);
  1079. }
  1080. /* if we didnt send real attrs we need to allocate result array */
  1081. if(NULL == result_array)
  1082. {
  1083. result_array = (vattr_type_thang*)slapi_ch_calloc(block_length,sizeof(vattr_type_thang));
  1084. if (NULL == result_array) {
  1085. return ENOMEM;
  1086. }
  1087. }
  1088. /* Then ask the service providers for their input */
  1089. type_context.flags = flags;
  1090. type_context.realattrs_only = 1; /* until we know otherwise */
  1091. type_context.list_is_copies = list_is_copies;
  1092. type_context.types = result_array;
  1093. type_context.list_length = list_length;
  1094. type_context.block_length = block_length;
  1095. /*
  1096. * At this point type_context.types is a list of all
  1097. * the attributetypes (copies or pointers) and values (copies, if present)
  1098. * found in the entry.
  1099. */
  1100. if(!(flags & SLAPI_REALATTRS_ONLY))
  1101. {
  1102. list = vattr_map_sp_get_complete_list();
  1103. if (list) {
  1104. vattr_sp_handle *current_handle = NULL;
  1105. for (current_handle = vattr_list_sp_first(list); current_handle; current_handle = vattr_list_sp_next((vattr_sp_handle_list *)current_handle)) {
  1106. /* call this SP */
  1107. rc = vattr_call_sp_get_types(current_handle,e,&type_context,
  1108. flags);
  1109. if (0 != rc) {
  1110. /* DBDB do what on error condition ? */
  1111. }
  1112. }
  1113. /* assert enough space for the null terminator */
  1114. PR_ASSERT( type_context.list_length < type_context.block_length);
  1115. i = type_context.list_length;
  1116. }
  1117. }
  1118. /*
  1119. * Now type_context.types is a list of all the types in this entry--
  1120. * real and virtual. For real ones, the values field is filled in.
  1121. * For virtual ones (including virtual ones which will overwrite a real
  1122. * value) the values field is null--this fact may used
  1123. * subsequently by callers of slapi_vattr_list_attrs()
  1124. * by calling slapi_vattr_values_type_thang_get() which
  1125. * will only calculate the values for attributetypes with
  1126. * non-null values.
  1127. */
  1128. flags = type_context.flags;
  1129. list_is_copies = type_context.list_is_copies;
  1130. result_array = type_context.types;
  1131. list_length = type_context.list_length;
  1132. block_length = type_context.block_length;
  1133. if (list_is_copies) {
  1134. *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
  1135. } else {
  1136. *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
  1137. }
  1138. /* Let the caller know if the list contains only real attrs */
  1139. if (type_context.realattrs_only) {
  1140. *buffer_flags |= SLAPI_VIRTUALATTRS_REALATTRS_ONLY;
  1141. }
  1142. result_array[i].type_name = NULL;
  1143. if (list_length)
  1144. *types = result_array;
  1145. else
  1146. *types = 0;
  1147. return rc;
  1148. }
  1149. static int vattr_add_thang_to_list(vattr_type_list_context *c, vattr_type_thang *thang)
  1150. {
  1151. vattr_type_thang *new_list = NULL;
  1152. /* Will it fit in the current block ? */
  1153. if (c->list_length == c->block_length - 1) {
  1154. c->block_length *= 2;
  1155. new_list = (vattr_type_thang*)slapi_ch_realloc((char *)c->types,
  1156. c->block_length * (int)sizeof(vattr_type_thang));
  1157. if (NULL == new_list) {
  1158. return ENOMEM;
  1159. }
  1160. c->types = new_list;
  1161. }
  1162. /* Add to the end of the list */
  1163. c->types[c->list_length ] = *thang;
  1164. c->list_length += 1;
  1165. return 0;
  1166. }
  1167. /* Called by SP's during their get_types call, to have the server add a
  1168. * type to the type list.
  1169. *
  1170. * c: the vattr_type_list_context passed from the original caller of
  1171. * slapi_vattr_list_attrs()
  1172. * thang: the new type to be added to the type list.
  1173. * flags: tells the routine whether to copy the thang or not.
  1174. * SLAPI_VIRTUALATTRS_REQUEST_POINTERS--no need to copy it.
  1175. * !(SLAPI_VIRTUALATTRS_REQUEST_POINTERS)--need to copy it.
  1176. *
  1177. * Checks to see if the requested type is already in the list,
  1178. * and if it is, if the value of the attribute is
  1179. * non-null, it resets the value to null. This means that when used
  1180. * subsequently, the type list indicates whether, for a given attribute type,
  1181. * the SP's need to be called to retrieve the value.
  1182. *
  1183. */
  1184. int slapi_vattrspi_add_type(vattr_type_list_context *c,
  1185. vattr_type_thang *thang, int flags)
  1186. {
  1187. int rc = 0;
  1188. unsigned int index = 0;
  1189. vattr_type_thang thang_to_add = {0};
  1190. int found_it = 0;
  1191. PR_ASSERT(c);
  1192. /* We are no longer sure that the list contains only real attrs */
  1193. c->realattrs_only = 0;
  1194. /* Check to see if the type is in the list already */
  1195. for (index = 0; index < c->list_length; index++) {
  1196. if (0 == slapi_UTF8CASECMP(c->types[index].type_name,thang->type_name)) {
  1197. found_it = 1;
  1198. break;
  1199. }
  1200. }
  1201. /*
  1202. * If found and there are values specified in the vattr_type_thang, then
  1203. * that means it's a real attribute--because SP's do not add values
  1204. * when called via slapi_vattr_list_attrs()/vattr_call_sp_get_types().
  1205. * However, an SP is willing to claim responsibility for this attribute
  1206. * type, so to ensure that that virtual value will get calculated, set the
  1207. * original real value to NULL here.
  1208. * The guiding rule here is "if an SP is prepared
  1209. * to provide a value for an attribute type, then that is the one
  1210. * that must be returned to the user". Note, this does not prevent
  1211. * the SP implementing a "merge real with virtual policy", if they
  1212. * wish.
  1213. */
  1214. if (found_it) {
  1215. if ( c->types[index].type_values != NULL ) {
  1216. /*
  1217. * Any values in this list are always pointers.
  1218. * See slapi_vattr_list_types() and vattr_convert_type_list()
  1219. */
  1220. c->types[index].type_values = NULL;
  1221. }
  1222. return 0;
  1223. }
  1224. /*
  1225. * If it's not in the list then we need to add it.
  1226. * If the list is already copies, then we need to make a copy of what the
  1227. * SP passed us.
  1228. * If the SP indicated that the type name it passed us is volatile,
  1229. * !(flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS)
  1230. * then we need to copy it anyway.
  1231. */
  1232. /* rbyrneXXX optimisation for COS: if each type_thang could have a
  1233. * free_flag
  1234. * then we would not have to convert all the real attrs to copies
  1235. * just because an SP returned a copy (note: only COS rrequires copies;
  1236. * roles returns a pointer to a static string "nsRole").
  1237. */
  1238. if (!c->list_is_copies &&
  1239. (0 == (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS))) {
  1240. /* Means we need to turn the existing list into a list of copies */
  1241. vattr_convert_type_list(c);
  1242. }
  1243. if (c->list_is_copies) {
  1244. thang_to_add.type_flags = thang->type_flags;
  1245. thang_to_add.type_name = slapi_ch_strdup(thang->type_name);
  1246. } else {
  1247. thang_to_add = *thang;
  1248. }
  1249. /* Lastly, we add to the list, using a function which hides the complexity of extending the list if it fills up */
  1250. vattr_add_thang_to_list(c, &thang_to_add);
  1251. return rc;
  1252. }
  1253. /* Function to free the list returned in the function above */
  1254. /* Written, reviewed, debug stepped */
  1255. void slapi_vattr_attrs_free(vattr_type_thang **types, int flags)
  1256. {
  1257. if (NULL == *types) {
  1258. return;
  1259. }
  1260. /* Check whether we need to free the strings */
  1261. if (flags & SLAPI_VIRTUALATTRS_RETURNED_POINTERS) {
  1262. /* We don't need to free the values */
  1263. } else {
  1264. char *attr_name_to_free = NULL;
  1265. size_t i = 0;
  1266. /* Walk down the set of values, fr eeing each one in turn */
  1267. for (; (attr_name_to_free = (*types)[i].type_name) != NULL; i++) {
  1268. slapi_ch_free((void **)&attr_name_to_free);
  1269. }
  1270. }
  1271. /* We always need to free the pointer block */
  1272. slapi_ch_free((void **)types);
  1273. }
  1274. char *vattr_typethang_get_name(vattr_type_thang *t)
  1275. {
  1276. return t->type_name;
  1277. }
  1278. unsigned long vattr_typethang_get_flags(vattr_type_thang *t)
  1279. {
  1280. return t->type_flags;
  1281. }
  1282. vattr_type_thang *vattr_typethang_next(vattr_type_thang *t)
  1283. {
  1284. t++;
  1285. if (t->type_name) {
  1286. return t;
  1287. } else {
  1288. return NULL;
  1289. }
  1290. }
  1291. vattr_type_thang *vattr_typethang_first(vattr_type_thang *t)
  1292. {
  1293. return t;
  1294. }
  1295. vattr_get_thang *slapi_vattr_getthang_first(vattr_get_thang *t)
  1296. {
  1297. return t;
  1298. }
  1299. vattr_get_thang *slapi_vattr_getthang_next(vattr_get_thang *t)
  1300. {
  1301. t++;
  1302. if (t->get_present) {
  1303. return t;
  1304. } else {
  1305. return NULL;
  1306. }
  1307. }
  1308. /* End of the public interface functions */
  1309. /* Everything below here is the SPI interface, only callable by vattr service providers.
  1310. Currently this interface is not public. Interface definitions are in vattr_spi.h
  1311. */
  1312. /* Structures used in the SPI interface */
  1313. /* Service provider object */
  1314. struct _vattr_sp {
  1315. /* vtbl */
  1316. vattr_get_fn_type sp_get_fn;
  1317. vattr_get_ex_fn_type sp_get_ex_fn;
  1318. vattr_compare_fn_type sp_compare_fn;
  1319. vattr_types_fn_type sp_types_fn;
  1320. void *sp_data; /* Pointer for use by the Service Provider */
  1321. };
  1322. typedef struct _vattr_sp vattr_sp;
  1323. /* Service provider handle */
  1324. struct _vattr_sp_handle {
  1325. vattr_sp *sp;
  1326. struct _vattr_sp_handle *next; /* So we can link them together in the map */
  1327. void *hint; /* Hint to the SP */
  1328. };
  1329. /* Calls made by Service Providers */
  1330. /* Call to register as a service provider */
  1331. /* This function needs to do the following:
  1332. o Let the provider say "hey, I'm here". It should probably get some handle back which it can use in future calls.
  1333. o Say whether it wants to be called to resolve every single query, or whether it will say in advance what attrs it services.
  1334. */
  1335. static vattr_sp_handle *vattr_sp_list = NULL;
  1336. int slapi_vattrspi_register(vattr_sp_handle **h, vattr_get_fn_type get_fn, vattr_compare_fn_type compare_fn, vattr_types_fn_type types_fn)
  1337. {
  1338. return slapi_vattrspi_register_internal(h, get_fn, 0, compare_fn, types_fn, 0);
  1339. }
  1340. int slapi_vattrspi_register_ex(vattr_sp_handle **h, vattr_get_ex_fn_type get_fn, vattr_compare_fn_type compare_fn, vattr_types_fn_type types_fn, void *options)
  1341. {
  1342. return slapi_vattrspi_register_internal(h, 0, get_fn, compare_fn, types_fn, options);
  1343. }
  1344. /* options not used yet - for future expansion */
  1345. int slapi_vattrspi_register_internal(vattr_sp_handle **h, vattr_get_fn_type get_fn, vattr_get_ex_fn_type get_ex_fn, vattr_compare_fn_type compare_fn, vattr_types_fn_type types_fn, void *options)
  1346. {
  1347. vattr_sp_handle *return_to_caller = NULL;
  1348. vattr_sp_handle *list_handle = NULL;
  1349. vattr_sp *new_sp = NULL;
  1350. /* Make a service provider handle */
  1351. new_sp = (vattr_sp*)slapi_ch_calloc(1,sizeof(vattr_sp));
  1352. new_sp->sp_get_fn = get_fn;
  1353. new_sp->sp_get_ex_fn = get_ex_fn;
  1354. new_sp->sp_compare_fn = compare_fn;
  1355. new_sp->sp_types_fn = types_fn;
  1356. return_to_caller = (vattr_sp_handle*)slapi_ch_calloc(1,sizeof(vattr_sp_handle));
  1357. return_to_caller->sp = new_sp;
  1358. /* Add to the service provider list */
  1359. /* Make a handle for the list */
  1360. list_handle = (vattr_sp_handle*)slapi_ch_calloc(1, sizeof (vattr_sp_handle));
  1361. *list_handle = *return_to_caller;
  1362. list_handle->next = vattr_sp_list;
  1363. vattr_sp_list = list_handle;
  1364. /* Return the handle to the caller */
  1365. *h = return_to_caller;
  1366. return 0;
  1367. }
  1368. vattr_sp_handle_list *vattr_map_sp_get_complete_list()
  1369. {
  1370. return vattr_sp_list;
  1371. }
  1372. int slapi_vattrspi_regattr(vattr_sp_handle *h,char *type_name_to_register, char* DN , void *hint)
  1373. {
  1374. int ret = 0;
  1375. char *type_to_add;
  1376. int free_type_to_add = 0;
  1377. Slapi_DN original_dn;
  1378. slapi_sdn_init(&original_dn);
  1379. /* Supplying a DN means that the plugin requires to be called
  1380. * only when the considering attributes in relevant entries - almost
  1381. *
  1382. * Actually the smallest namespace is the backend.
  1383. *
  1384. * atttributes that are tied to backends have the format DN::attr
  1385. * this essentially makes the attribute have split namespaces
  1386. * that are treated as separate attributes in the vattr code
  1387. */
  1388. if(DN)
  1389. {
  1390. /* as a coutesy we accept any old DN and will convert
  1391. * to a namespace DN, this helps to hide details
  1392. * (that we might decide to change) anyway
  1393. */
  1394. Slapi_Backend *be;
  1395. Slapi_DN *namespace_dn;
  1396. slapi_sdn_set_dn_byref(&original_dn,DN);
  1397. be = slapi_be_select( &original_dn );
  1398. namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
  1399. if(namespace_dn && be != defbackend_get_backend()) /* just in case someone thinks "" is a good namespace */
  1400. {
  1401. type_to_add = slapi_ch_smprintf("%s::%s",
  1402. (char*)slapi_sdn_get_dn(namespace_dn),
  1403. type_name_to_register);
  1404. free_type_to_add = 1;
  1405. }
  1406. else
  1407. {
  1408. type_to_add = type_name_to_register;
  1409. }
  1410. }
  1411. else
  1412. {
  1413. type_to_add = type_name_to_register;
  1414. }
  1415. ret = vattr_map_sp_insert(type_to_add,h,hint);
  1416. slapi_sdn_done(&original_dn);
  1417. if(free_type_to_add)
  1418. {
  1419. slapi_ch_free((void **)&type_to_add);
  1420. }
  1421. return ret;
  1422. }
  1423. /* Call to advertise or refute that you generate the value for some attribute, and to signal that the definition for this attribute has changed */
  1424. /* This call needs to do the following:
  1425. o Let the SP say "you know, I will generate the value of attribute "foo", within subtree "bar". (we might ignore the subtree for now to keep things simple
  1426. o Same as above, but say "you know, I'm not doing that any more". (we'll do that with a addordel flag).
  1427. o Say, "you know that definition I said I did, well it's changed".
  1428. */
  1429. /* Functions to handle the context stucture */
  1430. int slapi_vattr_context_create(vattr_context **c)
  1431. {
  1432. return 0;
  1433. }
  1434. void slapi_vattr_context_destroy(vattr_context *c)
  1435. {
  1436. }
  1437. int vattr_call_sp_get_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *buffer_flags, void* hint)
  1438. {
  1439. int ret = -1;
  1440. if(handle->sp->sp_get_fn)
  1441. {
  1442. ret = ((handle->sp->sp_get_fn)(handle,c,e,type,results,type_name_disposition,actual_type_name,flags,buffer_flags, hint));
  1443. }
  1444. return ret;
  1445. }
  1446. int vattr_call_sp_get_batch_values(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, char **type, Slapi_ValueSet*** results,int **type_name_disposition, char*** actual_type_name, int flags, int *buffer_flags, void** hint)
  1447. {
  1448. int ret = 0;
  1449. if(handle->sp->sp_get_ex_fn)
  1450. {
  1451. ret = ((handle->sp->sp_get_ex_fn)(handle,c,e,type,results,type_name_disposition,actual_type_name,flags,buffer_flags, hint));
  1452. }
  1453. else
  1454. {
  1455. /* make our args look like the simple non-batched case */
  1456. *results = (Slapi_ValueSet**)slapi_ch_calloc(2, sizeof(**results)); /* 2 for null terminated list */
  1457. *type_name_disposition = (int *)slapi_ch_calloc(2, sizeof(**type_name_disposition));
  1458. *actual_type_name = (char**)slapi_ch_calloc(2, sizeof(**actual_type_name));
  1459. ret =((handle->sp->sp_get_fn)(handle,c,e,*type,*results,*type_name_disposition,*actual_type_name,flags,buffer_flags, hint));
  1460. if (ret)
  1461. {
  1462. slapi_ch_free((void**)results );
  1463. slapi_ch_free((void**)type_name_disposition );
  1464. slapi_ch_free((void**)actual_type_name );
  1465. }
  1466. }
  1467. return ret;
  1468. }
  1469. int vattr_call_sp_compare_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, const char *type, Slapi_Value* test_this,int *result, int flags, void* hint)
  1470. {
  1471. return ((handle->sp->sp_compare_fn)(handle,c,e,(char*)type,test_this,result,flags, hint));
  1472. }
  1473. int vattr_call_sp_get_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags)
  1474. {
  1475. return ((handle->sp->sp_types_fn)(handle,e,type_context,flags));
  1476. }
  1477. /* Service provider entry point prototypes */
  1478. /* Call which allows a SP to say what attributes can be used to define a given attribute, used for loop detection */
  1479. /* Not implementing this yet */
  1480. /* typedef int (*vattrspi_explain_definition) (); */
  1481. /* Function called to indicate to the SP that the game is over, we free the handle, not the SP */
  1482. typedef int (*vattrspi_deregister) (vattr_sp_handle *h);
  1483. /* End of the SPI functions */
  1484. /* Implementation functions only after here */
  1485. /* The attribute map */
  1486. /* We need a structure which can map attribute type names to SP's which might tell us
  1487. something useful. We need a function which, given an attr type name, can return
  1488. a set of SP's to ask about said attr. SP's which don't tell us which attrs they are
  1489. handling always get asked. The first SP which tells us the answer wins, we don't
  1490. attempt to arbitrate between them. One might imaging doing this stuff in a unified
  1491. way with other stuff pertaining to types (schema, syntax). Someday. For now this
  1492. is a separate thing in the insterests of stability.
  1493. */
  1494. /* Virtual Attribute map implementation */
  1495. /* The virtual attribute type map is implemented as a hash table.
  1496. The single key is the attribute type base name (not an alias)
  1497. (what about subtypes??). The hash table takes care of translating
  1498. this key to a list of probable service providers for the type.
  1499. Other than the obvious lookup function, we need functions to
  1500. allow entries to be added and removed from the map.
  1501. Because the map is likely to be consulted at least once for every search
  1502. operation performed by the server, it's important that it is free from
  1503. performance deficiencies such as lock contention (is the NSPR hash table
  1504. implementation even thread safe ?
  1505. */
  1506. #define VARRT_MAP_HASHTABLE_SIZE 10
  1507. /* Attribute map oject */
  1508. /* Needs to contain: a linked list of pointers to provider handles handles,
  1509. The type name,
  1510. other stuff ?
  1511. Access to the entire map will be controlled via a single RW lock.
  1512. */
  1513. struct _objAttrValue
  1514. {
  1515. struct _objAttrValue *pNext;
  1516. Slapi_Value *val;
  1517. };
  1518. typedef struct _objAttrValue objAttrValue;
  1519. struct _vattr_map_entry {
  1520. char * /* currect ? */ type_name;
  1521. vattr_sp_handle *sp_list;
  1522. objAttrValue *objectclasses; /* objectclasses for this type to check schema with*/
  1523. };
  1524. typedef struct _vattr_map_entry vattr_map_entry;
  1525. vattr_map_entry test_entry = {NULL};
  1526. struct _vattr_map {
  1527. Slapi_RWLock *lock;
  1528. PLHashTable *hashtable; /* Hash table */
  1529. };
  1530. typedef struct _vattr_map vattr_map;
  1531. static vattr_map *the_map = NULL;
  1532. static PRIntn vattr_hash_compare_keys(const void *v1, const void *v2)
  1533. {
  1534. /* Should this be subtype aware, etc ? */
  1535. return ( (0 == strcasecmp(v1,v2)) ? 1 : 0) ;
  1536. }
  1537. static PRIntn vattr_hash_compare_values(const void *v1, const void *v2)
  1538. {
  1539. return( ((char *)v1 == (char *)v2 ) ? 1 : 0);
  1540. }
  1541. static PLHashNumber vattr_hash_fn(const void *type_name)
  1542. {
  1543. /* need a hash function here */
  1544. /* Sum the bytes for now */
  1545. PLHashNumber result = 0;
  1546. char * current_position = NULL;
  1547. char current_char = 0;
  1548. for (current_position = (char*) type_name; *current_position; current_position++) {
  1549. current_char = tolower(*current_position);
  1550. result += current_char;
  1551. }
  1552. return result;
  1553. }
  1554. static int vattr_map_create()
  1555. {
  1556. the_map = (vattr_map*)slapi_ch_calloc(1, sizeof(vattr_map));
  1557. if (NULL == the_map) {
  1558. slapd_nasty(sourcefile,1,0);
  1559. return ENOMEM;
  1560. }
  1561. the_map->hashtable = PL_NewHashTable(VARRT_MAP_HASHTABLE_SIZE,
  1562. vattr_hash_fn, vattr_hash_compare_keys,
  1563. vattr_hash_compare_values, NULL, NULL);
  1564. if (NULL == the_map->hashtable) {
  1565. slapd_nasty(sourcefile,2,0);
  1566. return ENOMEM;
  1567. }
  1568. the_map->lock = slapi_new_rwlock();
  1569. if (NULL == the_map) {
  1570. slapd_nasty(sourcefile,3,0);
  1571. return ENOMEM;
  1572. }
  1573. return 0;
  1574. }
  1575. static void vattr_map_destroy()
  1576. {
  1577. if (the_map) {
  1578. if (the_map->hashtable) {
  1579. PL_HashTableDestroy(the_map->hashtable);
  1580. }
  1581. if (the_map->lock) {
  1582. slapi_destroy_rwlock(the_map->lock);
  1583. }
  1584. }
  1585. slapi_ch_free ((void**)&the_map);
  1586. }
  1587. /* Returns 0 if present, entry returned in result. Returns SLAPI_VIRTUALATTRS_NOT_FOUND if not found */
  1588. static int vattr_map_lookup(const char *type_to_find, vattr_map_entry **result)
  1589. {
  1590. char *basetype = 0;
  1591. char *tmp = 0;
  1592. char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
  1593. *result = NULL;
  1594. PR_ASSERT(the_map);
  1595. /* vattrs need to support subtypes
  1596. * we insist that one service provider
  1597. * will support all subtypes for a
  1598. * given superior, hence we look for
  1599. * superiors only here
  1600. */
  1601. tmp = slapi_attr_basetype( type_to_find, buf, sizeof(buf));
  1602. if(tmp)
  1603. {
  1604. basetype = tmp;
  1605. }
  1606. else
  1607. {
  1608. basetype = buf;
  1609. }
  1610. /* Get the reader lock */
  1611. slapi_rwlock_rdlock(the_map->lock);
  1612. *result = (vattr_map_entry*)PL_HashTableLookupConst(the_map->hashtable,
  1613. (void*)basetype);
  1614. /* Release ze lock */
  1615. slapi_rwlock_unlock(the_map->lock);
  1616. if(tmp)
  1617. {
  1618. slapi_ch_free_string(&tmp);
  1619. }
  1620. if (*result) {
  1621. return 0;
  1622. } else {
  1623. return SLAPI_VIRTUALATTRS_NOT_FOUND;
  1624. }
  1625. }
  1626. /* Insert an entry into the attribute map */
  1627. int vattr_map_insert(vattr_map_entry *vae)
  1628. {
  1629. char *copy_of_type_name = NULL;
  1630. PR_ASSERT(the_map);
  1631. copy_of_type_name = slapi_ch_strdup(vae->type_name);
  1632. if (NULL == copy_of_type_name) {
  1633. slapd_nasty(sourcefile,6,0);
  1634. return ENOMEM;
  1635. }
  1636. /* Get the writer lock */
  1637. slapi_rwlock_wrlock(the_map->lock);
  1638. /* Insert the thing */
  1639. /* It's illegal to call this function if the entry is already there */
  1640. PR_ASSERT(NULL == PL_HashTableLookupConst(the_map->hashtable,(void*)copy_of_type_name));
  1641. PL_HashTableAdd(the_map->hashtable,(void*)copy_of_type_name,(void*)vae);
  1642. /* Unlock and we're done */
  1643. slapi_rwlock_unlock(the_map->lock);
  1644. return 0;
  1645. }
  1646. /*
  1647. vattr_delete_attrvals
  1648. ---------------------
  1649. deletes a value list
  1650. */
  1651. void vattr_delete_attrvals(objAttrValue **attrval)
  1652. {
  1653. objAttrValue *val = *attrval;
  1654. while(val)
  1655. {
  1656. objAttrValue *next = val->pNext;
  1657. slapi_value_free(&val->val);
  1658. slapi_ch_free((void**)&val);
  1659. val = next;
  1660. }
  1661. }
  1662. /*
  1663. vattr_add_attrval
  1664. -----------------
  1665. adds a value to an attribute value list
  1666. */
  1667. int vattr_add_attrval(objAttrValue **attrval, char *val)
  1668. {
  1669. int ret = 0;
  1670. objAttrValue *theVal;
  1671. LDAPDebug( LDAP_DEBUG_TRACE, "--> vattr_add_attrval\n",0,0,0);
  1672. /* create the attrvalue */
  1673. theVal = (objAttrValue*) slapi_ch_malloc(sizeof(objAttrValue));
  1674. if(theVal)
  1675. {
  1676. theVal->val = slapi_value_new_string(val);
  1677. if(theVal->val)
  1678. {
  1679. theVal->pNext = *attrval;
  1680. *attrval = theVal;
  1681. }
  1682. else
  1683. {
  1684. slapi_ch_free((void**)&theVal);
  1685. LDAPDebug( LDAP_DEBUG_ANY, "vattr_add_attrval: failed to allocate memory\n",0,0,0);
  1686. ret = -1;
  1687. }
  1688. }
  1689. else
  1690. {
  1691. LDAPDebug( LDAP_DEBUG_ANY, "vattr_add_attrval: failed to allocate memory\n",0,0,0);
  1692. ret = -1;
  1693. }
  1694. LDAPDebug( LDAP_DEBUG_TRACE, "<-- vattr_add_attrval\n",0,0,0);
  1695. return ret;
  1696. }
  1697. objAttrValue *vattr_map_entry_build_schema(char *type_name)
  1698. {
  1699. objAttrValue *ret = 0;
  1700. struct objclass *oc;
  1701. LDAPDebug( LDAP_DEBUG_TRACE, "--> vattr_map_entry_build_schema\n",0,0,0);
  1702. /* this is the first opportunity to register
  1703. * with the statechange api, our init function
  1704. * gets called prior to loading plugins, so it
  1705. * was not available then
  1706. */
  1707. if(!statechange_api)
  1708. {
  1709. /* grab statechange api - we never release this */
  1710. if(!slapi_apib_get_interface(StateChange_v1_0_GUID, &statechange_api))
  1711. {
  1712. /* register for schema changes via dn */
  1713. statechange_register(statechange_api, "vattr", "cn=schema", NULL, NULL, (notify_callback) schema_changed_callback);
  1714. }
  1715. }
  1716. if(!config_get_schemacheck())
  1717. {
  1718. LDAPDebug( LDAP_DEBUG_TRACE, "<-- vattr_map_entry_build_schema - schema off\n",0,0,0);
  1719. return 0;
  1720. }
  1721. oc_lock_read();
  1722. for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next )
  1723. {
  1724. char **pppAttrs[2];
  1725. int index;
  1726. int attrType = 0;
  1727. int oc_added = 0;
  1728. pppAttrs[0] = oc->oc_required;
  1729. pppAttrs[1] = oc->oc_allowed;
  1730. /* we need to check both required and allowed attributes */
  1731. while(!oc_added && attrType < 2)
  1732. {
  1733. if(pppAttrs[attrType])
  1734. {
  1735. index = 0;
  1736. while(pppAttrs[attrType][index])
  1737. {
  1738. if(!PL_strcasecmp(pppAttrs[attrType][index], type_name))
  1739. {
  1740. vattr_add_attrval(&ret, oc->oc_name);
  1741. oc_added = 1;
  1742. break;
  1743. }
  1744. index++;
  1745. }
  1746. }
  1747. attrType++;
  1748. }
  1749. }
  1750. oc_unlock();
  1751. LDAPDebug( LDAP_DEBUG_TRACE, "<-- vattr_map_entry_build_schema\n",0,0,0);
  1752. return ret;
  1753. }
  1754. static PRIntn vattr_map_entry_rebuild_schema(PLHashEntry *he, PRIntn i, void *arg)
  1755. {
  1756. vattr_map_entry *entry = (vattr_map_entry *)(he->value);
  1757. if(entry->objectclasses)
  1758. vattr_delete_attrvals(&(entry->objectclasses));
  1759. entry->objectclasses = vattr_map_entry_build_schema(entry->type_name);
  1760. return HT_ENUMERATE_NEXT;
  1761. }
  1762. void schema_changed_callback(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data)
  1763. {
  1764. /* Get the writer lock */
  1765. slapi_rwlock_wrlock(the_map->lock);
  1766. /* go through the list */
  1767. PL_HashTableEnumerateEntries(the_map->hashtable, vattr_map_entry_rebuild_schema, 0);
  1768. /* Unlock and we're done */
  1769. slapi_rwlock_unlock(the_map->lock);
  1770. }
  1771. int slapi_vattr_schema_check_type(Slapi_Entry *e, char *type)
  1772. {
  1773. int ret = 0;
  1774. vattr_map_entry *map_entry;
  1775. if(config_get_schemacheck())
  1776. {
  1777. Slapi_Attr *attr;
  1778. if(0 == slapi_entry_attr_find(e, "objectclass", &attr))
  1779. {
  1780. Slapi_ValueSet *vs;
  1781. if(0 == slapi_attr_get_valueset(attr, &vs))
  1782. {
  1783. objAttrValue *obj;
  1784. if(0 == vattr_map_lookup(type, &map_entry))
  1785. {
  1786. slapi_rwlock_rdlock(the_map->lock);
  1787. obj = map_entry->objectclasses;
  1788. while(obj)
  1789. {
  1790. if(slapi_valueset_find(attr, vs, obj->val))
  1791. {
  1792. /* this entry has an objectclass
  1793. * that allows or requires the
  1794. * attribute type
  1795. */
  1796. ret = -1;
  1797. break;
  1798. }
  1799. obj = obj->pNext;
  1800. }
  1801. slapi_rwlock_unlock(the_map->lock);
  1802. }
  1803. slapi_valueset_free(vs);
  1804. }
  1805. }
  1806. }
  1807. else
  1808. ret = -1;
  1809. return ret;
  1810. }
  1811. vattr_map_entry *vattr_map_entry_new(char *type_name, vattr_sp_handle *sph, void* hint)
  1812. {
  1813. vattr_map_entry *result = NULL;
  1814. vattr_sp_handle *sp_copy = NULL;
  1815. sp_copy = (vattr_sp_handle*)slapi_ch_calloc(1, sizeof (vattr_sp_handle));
  1816. sp_copy->sp = sph->sp;
  1817. sp_copy->hint = hint;
  1818. result = (vattr_map_entry*)slapi_ch_calloc(1, sizeof (vattr_map_entry));
  1819. result->type_name = slapi_ch_strdup(type_name);
  1820. result->sp_list = sp_copy;
  1821. /* go get schema */
  1822. result->objectclasses = vattr_map_entry_build_schema(type_name);
  1823. return result;
  1824. }
  1825. /* On top of the map, we need functions to manipulate the SP handles from within */
  1826. /* Function to get the SP list from the map, given a type name */
  1827. /* The resulting list is in the map, but is safe to read regardless of concurrent updates */
  1828. vattr_sp_handle_list *vattr_map_sp_getlist(char *type_to_find)
  1829. {
  1830. int ret = 0;
  1831. vattr_map_entry *result = NULL;
  1832. ret = vattr_map_lookup(type_to_find,&result);
  1833. if (0 == ret) {
  1834. return (vattr_sp_handle_list*) result->sp_list;
  1835. } else {
  1836. return NULL;
  1837. }
  1838. }
  1839. /* same as above, but filters the list based on the supplied backend dn
  1840. * when we stored these dn based attributes, we concatenated them with
  1841. * the dn like this dn::attribute, so we need to do two checks for the
  1842. * attribute, one with, and one without the dn
  1843. */
  1844. vattr_sp_handle_list *vattr_map_namespace_sp_getlist(Slapi_DN *dn, const char *type_to_find)
  1845. {
  1846. int ret = 0;
  1847. vattr_map_entry *result = NULL;
  1848. vattr_sp_handle_list* return_list = 0;
  1849. if(config_get_ignore_vattrs()){
  1850. /* we don't care about vattrs */
  1851. return NULL;
  1852. }
  1853. ret = vattr_map_lookup(type_to_find,&result);
  1854. if (0 == ret) {
  1855. return_list = (vattr_sp_handle_list*) result->sp_list;
  1856. } else {
  1857. /* we have allowed the global namespace provider a shot
  1858. * now it is time to query for split namespace providers
  1859. */
  1860. if(dn) {
  1861. char *split_dn = (char*)slapi_sdn_get_dn(dn);
  1862. char *split_type_to_find =
  1863. slapi_ch_smprintf("%s::%s",split_dn, type_to_find);
  1864. if(split_type_to_find)
  1865. {
  1866. ret = vattr_map_lookup(split_type_to_find,&result);
  1867. if (0 == ret) {
  1868. return_list = (vattr_sp_handle_list*) result->sp_list;
  1869. }
  1870. slapi_ch_free((void **)&split_type_to_find);
  1871. }
  1872. }
  1873. }
  1874. return return_list;
  1875. }
  1876. /* Iterator function for the list */
  1877. vattr_sp_handle *vattr_map_sp_next(vattr_sp_handle_list *list, void **hint)
  1878. {
  1879. vattr_sp_handle *result = NULL;
  1880. vattr_sp_handle *current = (vattr_sp_handle*) list;
  1881. PR_ASSERT(list);
  1882. PR_ASSERT(hint);
  1883. result = current->next;
  1884. *hint = current->hint;
  1885. return result;
  1886. }
  1887. /* Iterator function for the list */
  1888. vattr_sp_handle *vattr_map_sp_first(vattr_sp_handle_list *list, void **hint)
  1889. {
  1890. vattr_sp_handle *result = NULL;
  1891. PR_ASSERT(list);
  1892. PR_ASSERT(hint);
  1893. result = (vattr_sp_handle*)list;
  1894. *hint = result->hint;
  1895. return result;
  1896. }
  1897. /* Iterator function for the list */
  1898. vattr_sp_handle *vattr_list_sp_next(vattr_sp_handle_list *list)
  1899. {
  1900. vattr_sp_handle *result = NULL;
  1901. vattr_sp_handle *current = (vattr_sp_handle*) list;
  1902. PR_ASSERT(list);
  1903. result = current->next;
  1904. return result;
  1905. }
  1906. /* Iterator function for the list */
  1907. vattr_sp_handle *vattr_list_sp_first(vattr_sp_handle_list *list)
  1908. {
  1909. vattr_sp_handle *result = NULL;
  1910. PR_ASSERT(list);
  1911. result = (vattr_sp_handle*)list;
  1912. return result;
  1913. }
  1914. /* Function to insert an SP into the map entry for a given type name */
  1915. /* Note that SP's can't ever remmove themselves from the map---if they could
  1916. we'd need to hold a lock on the read path, which we don't want to do.
  1917. So any SP which relinquishes its need to handle a type needs to continue
  1918. to handle the calls on it, but return nothing */
  1919. /* DBDB need to sort out memory ownership here, it's not quite right */
  1920. int vattr_map_sp_insert(char *type_to_add, vattr_sp_handle *sp, void *hint)
  1921. {
  1922. int result = 0;
  1923. vattr_map_entry *map_entry = NULL;
  1924. /* Is this type already there ? */
  1925. result = vattr_map_lookup(type_to_add,&map_entry);
  1926. /* If it is, add this SP to the list, safely even if readers are traversing the list at the same time */
  1927. if (0 == result) {
  1928. int found = 0;
  1929. vattr_sp_handle *list_entry = NULL;
  1930. /* Walk the list checking that the daft SP isn't already here */
  1931. for (list_entry = map_entry->sp_list ; list_entry; list_entry = list_entry->next) {
  1932. if (list_entry == sp) {
  1933. found = 1;
  1934. break;
  1935. }
  1936. }
  1937. /* If it is, we do nothing */
  1938. if(found) {
  1939. return 0;
  1940. }
  1941. /* We insert the SP handle into the linked list at the head */
  1942. sp->next = map_entry->sp_list;
  1943. map_entry->sp_list = sp;
  1944. } else {
  1945. /* If not, add it */
  1946. map_entry = vattr_map_entry_new(type_to_add,sp,hint);
  1947. if (NULL == map_entry) {
  1948. return ENOMEM;
  1949. }
  1950. return vattr_map_insert(map_entry);
  1951. }
  1952. return 0;
  1953. }
  1954. /*
  1955. * returns non-zero if type is a cachable virtual attr, zero otherwise.
  1956. *
  1957. * Decision point for caching vattrs...to be expanded to be configurable,
  1958. * allow sp's to have a say etc.
  1959. */
  1960. static int cache_all = 0;
  1961. int slapi_vattrcache_iscacheable( const char * type ) {
  1962. int rc = 0;
  1963. if(/*cache_all ||*/ !slapi_UTF8CASECMP((char *)type, "nsrole")) {
  1964. rc = 1;
  1965. }
  1966. return(rc);
  1967. }
  1968. /*
  1969. * slapi_vattrcache_cache_all and slapi_vattrcache_cache_none
  1970. * ----------------------------------------------------------
  1971. * limited control for deciding whether to
  1972. * cache anything, in reality controls whether
  1973. * to cache cos attributes right now
  1974. */
  1975. void slapi_vattrcache_cache_all()
  1976. {
  1977. cache_all = -1;
  1978. }
  1979. void slapi_vattrcache_cache_none()
  1980. {
  1981. cache_all = 0;
  1982. }
  1983. Slapi_PBlock *
  1984. slapi_vattr_get_pblock_from_context(vattr_context *c)
  1985. {
  1986. if (c) {
  1987. return c->pb;
  1988. } else {
  1989. return NULL;
  1990. }
  1991. }
  1992. #ifdef VATTR_TEST_CODE
  1993. /* Prototype SP begins here */
  1994. /* Get value function */
  1995. int vattr_basic_sp_get_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *buffer_flags, void *hint)
  1996. {
  1997. Slapi_Value *value = NULL;
  1998. *buffer_flags = 0;
  1999. *actual_type_name = slapi_ch_strdup("dbtestattr");
  2000. value = slapi_value_new_string("Hello Client");
  2001. *results = slapi_ch_calloc(1,sizeof(Slapi_ValueSet));
  2002. slapi_valueset_init(*results);
  2003. slapi_valueset_add_value_ext(*results,value,SLAPI_VALUE_FLAG_PASSIN);
  2004. return 0;
  2005. }
  2006. /* Compare value function */
  2007. int vattr_basic_sp_compare_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result,int flags, void *hint)
  2008. {
  2009. *result = 0;
  2010. return 0;
  2011. }
  2012. int vattr_basic_sp_list_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags)
  2013. {
  2014. static char* test_type_name = "dbtestattr";
  2015. vattr_type_thang thang = {0};
  2016. thang.type_name = test_type_name;
  2017. thang.type_flags = 0;
  2018. slapi_vattrspi_add_type(type_context,&thang,SLAPI_VIRTUALATTRS_REQUEST_POINTERS);
  2019. return 0;
  2020. }
  2021. int vattr_basic_sp_init()
  2022. {
  2023. int ret = 0;
  2024. vattr_sp_handle *my_handle = NULL;
  2025. /* Register SP */
  2026. ret = slapi_vattrspi_register(&my_handle,vattr_basic_sp_get_value, vattr_basic_sp_compare_value, vattr_basic_sp_list_types);
  2027. if (ret) {
  2028. slapd_nasty(sourcefile,4,0);
  2029. return ret;
  2030. }
  2031. /* Register interest in some attribute over the entire tree */
  2032. ret = slapi_vattrspi_regattr(my_handle,"dbtestattr","", NULL);
  2033. if (ret) {
  2034. slapd_nasty(sourcefile,5,0);
  2035. return ret;
  2036. }
  2037. /* Register interest in some attribute over the entire tree */
  2038. ret = slapi_vattrspi_regattr(my_handle,"dbtestattr1","", NULL);
  2039. if (ret) {
  2040. slapd_nasty(sourcefile,5,0);
  2041. return ret;
  2042. }
  2043. /* Register interest in some attribute over the entire tree */
  2044. ret = slapi_vattrspi_regattr(my_handle,"dbtestattr2","", NULL);
  2045. if (ret) {
  2046. slapd_nasty(sourcefile,5,0);
  2047. return ret;
  2048. }
  2049. /* Register interest in some attribute over the entire tree */
  2050. ret = slapi_vattrspi_regattr(my_handle,"dbtestatt3r","", NULL);
  2051. if (ret) {
  2052. slapd_nasty(sourcefile,5,0);
  2053. return ret;
  2054. }
  2055. return ret;
  2056. }
  2057. /* What do we do on shutdown ? */
  2058. int vattr_basic_sp_cleanup()
  2059. {
  2060. return 0;
  2061. }
  2062. #endif