| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415 |
- /** BEGIN COPYRIGHT BLOCK
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- *
- * License: GPL (version 3 or any later version).
- * See LICENSE for details.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- /*
- Virtual Attributes
-
- This file implements the "virtual attribute API", which is the interface
- by which any joe servercode gets the values of attributes associated with an
- entry which are _not_ stored with the entry. Attributes which _are_ stored
- with the entry will also be returned by this interface, unless the caller
- specifies the SLAPI_REALATTRS_ONLY flag. This means that the casual caller
- looking for attribute values should probably call the virtual attribute interface
- rather than the regular Slapi_Entry_Attr_Find... and so on calls.
- This interface is different from that one in that the data returned is
- a copy, to be freed by the caller. Details on how to free the returned data is
- given individually for each function.
- The thing is implemented with a service provider model. The code in here
- does NOT know how to generate computed attr values etc, it just calls the
- registered providers of such information. It also takes care of any crusty
- special cases. Everything above the line here is crispy clean.
- Implicit in this interface is the assumption that the value of an attribute
- can only depend on the entry and some independent stored state. For example,
- the value can't depend upon who is asking, since we don't pass that information
- over the interface.
- More design: we'd like to have the regular result returning code in result.c call this
- interface. However, as it stands, his would incur a malloc, a copy and a free for every
- value. Too expensive. So, it would be good to modify the interface such that when we
- retrieve values from inside the entry, we just fetch a pointer like before. When we
- retrieve values which are generated, we get copies of the data (or can we get pointers
- there too ?? --- no).
- One way to achieve this: allow the caller to say that they perfer to receive pointers
- and not copies. They are then informed by the function whether they did receive pointers
- or copies. They then call the free function only when needed. The implicit lifetime of
- the returned pointers is the lifetime of the entry object passed into the function.
- Nasty, but one has to do these things in the name of the god performance.
- DBDB: remember to rename the structures mark complained weren't compliant with the slapi naming scheme.
-
- */
- #include "slap.h"
- #include "vattr_spi.h"
- #include "statechange.h"
- #ifdef SOURCEFILE
- #undef SOURCEFILE
- #endif
- #define SOURCEFILE "vattr.c"
- static char *sourcefile = SOURCEFILE;
- /* Define only for module test code */
- /* #define VATTR_TEST_CODE */
- /* Loop context structure */
- struct _vattr_context {
- Slapi_PBlock *pb;
- unsigned int vattr_context_loop_count;
- unsigned int error_displayed;
- };
- #define VATTR_LOOP_COUNT_MAX 50
- typedef vattr_sp_handle vattr_sp_handle_list;
- /* Local prototypes */
- static int vattr_map_create();
- static void vattr_map_destroy();
- int vattr_map_sp_insert(char *type_to_add, vattr_sp_handle *sp, void *hint);
- vattr_sp_handle_list *vattr_map_sp_getlist(char *type_to_find);
- vattr_sp_handle_list *vattr_map_namespace_sp_getlist(Slapi_DN *dn, const char *type_to_find);
- vattr_sp_handle_list *vattr_map_sp_get_complete_list();
- vattr_sp_handle *vattr_map_sp_first(vattr_sp_handle_list *list,void **hint);
- vattr_sp_handle *vattr_map_sp_next(vattr_sp_handle_list *list,void **hint);
- vattr_sp_handle *vattr_list_sp_first(vattr_sp_handle_list *list);
- vattr_sp_handle *vattr_list_sp_next(vattr_sp_handle_list *list);
- 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);
- 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);
- 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);
- int vattr_call_sp_get_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags);
- void schema_changed_callback(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data);
- 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);
- #ifdef VATTR_TEST_CODE
- int vattr_basic_sp_init();
- #endif
- void **statechange_api;
- /* Housekeeping Functions, called by server startup/shutdown code */
- /* Called on server startup, init all structures etc */
- void vattr_init()
- {
- statechange_api = 0;
- vattr_map_create();
- #ifdef VATTR_TEST_CODE
- vattr_basic_sp_init();
- #endif
- }
- /* Called on server shutdown, free all structures, inform service providers that we're going down etc */
- void vattr_cleanup()
- {
- vattr_map_destroy();
- }
- /* The public interface functions start here */
- /* Function which returns the value(s) of an attribute, given an entry and the attribute type name */
- /* Return 0 if OK, ?? if attr doesn't exist, ?? if some error condition ?? if result doesn't need to be free'ed */
- 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)
- {
- vattr_context *c = NULL;
- return slapi_vattr_values_get_sp(c,e,type,results,type_name_disposition,actual_type_name,flags, buffer_flags);
- }
- 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)
- {
- vattr_context *c = NULL;
- return slapi_vattr_values_get_sp_ex(c,e,type,results,type_name_disposition,actual_type_name,flags, buffer_flags, subtype_count);
- }
- 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)
- {
- vattr_context *c = NULL;
- return slapi_vattr_namespace_values_get_sp(c,e,namespace_dn,type,results,type_name_disposition,actual_type_name,flags, buffer_flags, subtype_count);
- }
- /*
- * If pointers into the entry were requested then we might have
- * a stashed pointer to the entry values, otherwise will be null.
- */
- Slapi_ValueSet *vattr_typethang_get_values(vattr_type_thang *t)
- {
- return t->type_values;
- }
- /*
- * This can be much faster than using slapi_vattr_values_get()
- * when you have a vattr_type_thang list returned from slapi_vattr_list_types().
- *
- * We call the vattr SPs to get values for an attribute type in the list only
- * if the results field for that attribute type is null.
- * If the type list comes from slapi_vattr_list_types() then the value is null
- * only for attributes for which an SP wishes to provide a value, so fo the other
- * ones don't bother calling the SPs again--just use the real value we picked up
- * from the entry.
- *
- */
- int slapi_vattr_values_type_thang_get(
- Slapi_Entry *e,
- vattr_type_thang *type_thang,
- Slapi_ValueSet **results,
- int *type_name_disposition,
- char **actual_type_name,
- int flags,
- int *buffer_flags
- )
- {
- int rc = 0;
- char *type = NULL;
- type = vattr_typethang_get_name(type_thang);
- *results = vattr_typethang_get_values(type_thang);
- if (*results != NULL) {
- /* we already have a pointer directly into the entry */
- *actual_type_name = type;
- *type_name_disposition =
- SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
- *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
- } else {
- /* fall back to usual implementation */
- rc = slapi_vattr_values_get(e,type,results,
- type_name_disposition,
- actual_type_name,
- flags,buffer_flags);
- }
- return rc;
- }
- static void vattr_helper_get_entry_conts(Slapi_Entry *e,char *type, vattr_get_thang *my_get)
- {
- Slapi_Attr *a = NULL;
- void *dummy = 0;
- a = attrlist_find_ex(e->e_attrs,type,&(my_get->get_name_disposition), &(my_get->get_type_name), &dummy);
- if (a) {
- my_get->get_present = 1;
- my_get->get_present_values = &(a->a_present_values);
- my_get->get_attr = a;
- }
- }
- static int vattr_helper_get_entry_conts_with_subtypes(Slapi_Entry *e,const char *type, vattr_get_thang **my_get)
- {
- Slapi_Attr *a = NULL;
- void *hint = 0;
- int counter = 0;
- int attr_count = attrlist_count_subtypes(e->e_attrs,type);
- if(attr_count > 0)
- {
- *my_get = (vattr_get_thang *)slapi_ch_calloc(attr_count, sizeof(vattr_get_thang));
- /* pick up attributes with sub-types and slip into the get_thang list */
- for(counter = 0; counter < attr_count; counter++)
- {
- a = attrlist_find_ex(e->e_attrs,type,&((*my_get)[counter].get_name_disposition), &((*my_get)[counter].get_type_name), &hint);
- if (a) {
- (*my_get)[counter].get_present = 1;
- (*my_get)[counter].get_present_values = &(a->a_present_values);
- (*my_get)[counter].get_attr = a;
- }
- }
- }
- return attr_count;
- }
- static int vattr_helper_get_entry_conts_no_subtypes(Slapi_Entry *e,const char *type, vattr_get_thang **my_get)
- {
- int attr_count = 0;
- Slapi_Attr *a = attrlist_find(e->e_attrs,type);
- if (a) {
- attr_count = 1;
- *my_get = (vattr_get_thang *)slapi_ch_calloc(1, sizeof(vattr_get_thang));
- (*my_get)[0].get_present = 1;
- (*my_get)[0].get_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
- (*my_get)[0].get_type_name = a->a_type;
- (*my_get)[0].get_present_values = &(a->a_present_values);
- (*my_get)[0].get_attr = a;
- }
- return attr_count;
- }
- static int vattr_helper_get_entry_conts_ex(Slapi_Entry *e,const char *type, vattr_get_thang **my_get, int suppress_subtypes)
- {
- int rc;
- if ( suppress_subtypes ) {
- rc = vattr_helper_get_entry_conts_no_subtypes(e, type, my_get);
- } else {
- rc = vattr_helper_get_entry_conts_with_subtypes(e, type, my_get);
- }
- return rc;
- }
- vattr_context *vattr_context_new( Slapi_PBlock *pb )
- {
- vattr_context *c = NULL;
- if (pb && pb->pb_vattr_context) {
- c = (vattr_context *)pb->pb_vattr_context;
- } else {
- c = (vattr_context *)slapi_ch_calloc(1, sizeof(vattr_context));
- }
- /* The payload is zero, which is what we want */
- if ( c ) {
- c->pb = pb;
- }
- if ( pb && c != (vattr_context *)pb->pb_vattr_context ) {
- pb->pb_vattr_context = (void *)c;
- }
- return c;
- }
- static int vattr_context_check(vattr_context *c)
- {
- /* Observe the loop count and see if it's higher than is allowed */
- if (c->vattr_context_loop_count > VATTR_LOOP_COUNT_MAX) {
- return SLAPI_VIRTUALATTRS_LOOP_DETECTED;
- } else return 0;
- }
- static void vattr_context_mark(vattr_context *c)
- {
- c->vattr_context_loop_count += 1;
- }
- static int vattr_context_unmark(vattr_context *c)
- {
- return (c->vattr_context_loop_count -= 1);
- }
- /* modify the context structure on exit from a vattr sp function */
- static void vattr_context_ungrok(vattr_context **c)
- {
- /* Decrement the loop count */
- if (0 == vattr_context_unmark(*c)) {
- /* If necessary, delete the structure */
- if ((*c)->pb) {
- (*c)->pb->pb_vattr_context = NULL;
- }
- slapi_ch_free((void **)c);
- }
- }
- static int vattr_context_grok_pb( Slapi_PBlock *pb, vattr_context **c )
- {
- int rc = -1;
- if (NULL == c) {
- return rc;
- }
- *c = vattr_context_new( pb );
- if (NULL == *c) {
- return ENOMEM;
- }
- rc = vattr_context_check(*c);
- vattr_context_mark(*c); /* increment loop count */
- return rc;
- }
- /* Check and mess with the context structure on entry to a vattr sp function */
- static int vattr_context_grok(vattr_context **c)
- {
- int rc = 0;
- /* First check that we've not got into an infinite loop.
- We do so by means of the vattr_context structure.
- */
- /* Do we have a context at all ?? */
- if (NULL == *c) {
- /* No, so let's make one */
- *c = vattr_context_new( NULL );
- if (NULL == *c) {
- return ENOMEM;
- }
- } else {
- /* Yes, so let's check its contents */
- rc = vattr_context_check(*c);
- }
- /* mark the context as having been used once */
- vattr_context_mark(*c);
- return rc;
- }
- /* keep track of error messages so we don't spam the error log */
- static void vattr_context_set_loop_msg_displayed(vattr_context **c)
- {
- (*c)->error_displayed = 1;
- }
- static int vattr_context_is_loop_msg_displayed(vattr_context **c)
- {
- return (*c)->error_displayed;
- }
- /*
- * vattr_test_filter:
- *
- * . tests an ava, presence or substring filter against e.
- * . group these filter types together to avoid having to duplicate the
- * . vattr specific code in three seperate routines.
- * . handles virtual attrs in the filter.
- * . does update the vattrcache if a call to this calculates vattrs
- *
- * returns: 0 filter matched
- * -1 filter did not match
- * >0 an ldap error code
- *
- */
- int vattr_test_filter( Slapi_PBlock *pb,
- /* Entry we're interested in */ Slapi_Entry *e,
- Slapi_Filter *f,
- filter_type_t filter_type,
- char * type)
- {
- int rc = -1;
- int sp_bit = 0; /* Set if an SP supplied an answer */
- vattr_sp_handle_list *list = NULL;
- Slapi_DN *sdn;
- Slapi_Backend *be;
- Slapi_DN *namespace_dn;
- /* get the namespace this entry belongs to */
- sdn = slapi_entry_get_sdn( e );
- be = slapi_be_select( sdn );
- namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
-
- /* Look for attribute in the map */
-
- if(namespace_dn)
- {
- list = vattr_map_namespace_sp_getlist(namespace_dn, type);
- }
- else
- {
- list = vattr_map_namespace_sp_getlist(NULL, type);
- }
- if (list) {
- vattr_sp_handle *current_handle = NULL;
- /* first lets consult the cache to save work */
- int cache_status;
-
- cache_status = slapi_entry_vattrcache_findAndTest(e, type,
- f,
- filter_type,
- &rc);
- switch(cache_status)
- {
- case SLAPI_ENTRY_VATTR_RESOLVED_EXISTS: /* cached vattr */
- {
- sp_bit = 1;
- break;
- }
- case SLAPI_ENTRY_VATTR_RESOLVED_ABSENT: /* does not exist */
- break; /* look in entry */
- case SLAPI_ENTRY_VATTR_NOT_RESOLVED: /* not resolved */
- default: /* any other result, resolve */
- {
- int flags = SLAPI_VIRTUALATTRS_REQUEST_POINTERS;
- void *hint = NULL;
- Slapi_ValueSet **results = NULL; /* pointer to result set */
- int *type_name_disposition;
- char **actual_type_name;
- int buffer_flags;
- vattr_get_thang my_get = {0};
- /* bit cacky, but need to make a null terminated lists for now
- * for the (unimplemented and so fake) batch attribute request
- */
- char *types[2];
- void *hint_list[2];
- vattr_context *ctx;
- vattr_context_grok_pb( pb, &ctx ); /* get or new context */
- types[0] = type;
- types[1] = 0;
- hint_list[1] = 0;
- for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint))
- {
- hint_list[0] = hint;
- rc = vattr_call_sp_get_batch_values(current_handle,ctx,e,
- &my_get,types,&results,&type_name_disposition,
- &actual_type_name,flags,&buffer_flags, hint_list);
-
- if (0 == rc)
- {
- sp_bit = 1;
- break;
- }
- }
- vattr_context_ungrok(&ctx);
- if(!sp_bit)
- {
- /*
- * No vattr sp supplied an answer so will look in the
- * entry itself.
- * but first lets cache the no result
- */
- slapi_entry_vattrcache_merge_sv(e, type, NULL, buffer_flags);
- }
- else
- {
- /*
- * A vattr sp supplied an answer.
- * so turn the value into a Slapi_Attr, pass
- * to the syntax plugin for comparison.
- */
- if ( filter_type == FILTER_TYPE_AVA ||
- filter_type == FILTER_TYPE_SUBSTRING ) {
- Slapi_Attr *a = NULL;
- int i=0;
- /* may need this when we have a passin interface for set_valueset */
- /*Slapi_ValueSet null_valueset = {0};*/
- rc=-1;
- if(results && actual_type_name && type_name_disposition)
- {
- while(results[i] && rc)
- {
- a = slapi_attr_new();
- slapi_attr_init(a, type);
- /* a now contains a *copy* of results */
- slapi_attr_set_valueset( a, results[i]);
- if ( filter_type == FILTER_TYPE_AVA ) {
- rc = plugin_call_syntax_filter_ava( a,
- f->f_choice, &f->f_ava );
- } else if ( filter_type == FILTER_TYPE_SUBSTRING) {
- rc = plugin_call_syntax_filter_sub( pb, a,
- &f->f_sub);
- }
- /*
- * Cache stuff: dups results
- */
- slapi_entry_vattrcache_merge_sv(e, actual_type_name[i],
- results[i], buffer_flags);
- /*
- * Free stuff, just in case we did not
- * get pointers.
- */
- slapi_vattr_values_free( &(results[i]),
- &(actual_type_name[i]),
- buffer_flags);
- /* may need this when we support a passin set_valueset */
- /*slapi_attr_set_valueset( a, &null_valueset);*/
- /* since a contains a copy of results, we must free it */
- slapi_attr_free(&a);
- i++;
- }
- }
- slapi_ch_free((void**)&results);
- slapi_ch_free((void**)&actual_type_name);
- slapi_ch_free((void**)&type_name_disposition);
- } else if ( filter_type == FILTER_TYPE_PRES ) {
- /*
- * Cache stuff: dups results
- */
- int i=0;
- while(results[i])
- {
- slapi_entry_vattrcache_merge_sv(e, actual_type_name[i],
- results[i], buffer_flags);
- /*
- * Free stuff, just in case we did not
- * get pointers.
- */
- slapi_vattr_values_free( &results[i],
- &actual_type_name[i],
- buffer_flags);
- }
- slapi_ch_free((void**)&results);
- slapi_ch_free((void**)&actual_type_name);
- slapi_ch_free((void**)&type_name_disposition);
- }
- }
- break;
- }
- }/* switch */
- }
- /* If no SP supplied the answer, take it from the entry */
- if (rc <= 1 && !sp_bit) /* if LDAP ERROR is set, skip further testing */
- {
- int acl_test_done;
- if ( filter_type == FILTER_TYPE_AVA ) {
-
- rc = test_ava_filter( NULL /* pb not needed */,
- e, e->e_attrs, &f->f_ava,
- f->f_choice,
- 0 /* no access check */,
- 0 /* do test filter */,
- &acl_test_done);
-
- } else if ( filter_type == FILTER_TYPE_SUBSTRING ) {
-
- rc = test_substring_filter( pb, e, f, 0 /* no access check */,
- 0 /* do test filter */, &acl_test_done);
-
- } else if ( filter_type == FILTER_TYPE_PRES ) {
-
- rc = test_presence_filter( NULL, e, f->f_type,
- 0 /* no access check */,
- 0 /* do test filter */,
- &acl_test_done);
- }
- }
- return rc;
- }
- /*
- * deprecated in favour of slapi_vattr_values_get_sp_ex() which
- * returns subtypes too.
- */
- SLAPI_DEPRECATED int
- slapi_vattr_values_get_sp(vattr_context *c,
- /* 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)
- {
- PRBool use_local_ctx = PR_FALSE;
- Slapi_PBlock *local_pb = NULL;
- vattr_context *ctx = NULL;
- int rc = 0;
- int sp_bit = 0; /* Set if an SP supplied an answer */
- vattr_sp_handle_list *list = NULL;
- vattr_get_thang my_get = {0};
- if (c != NULL) {
- rc = vattr_context_grok(&c);
- if (0 != rc) {
- if(!vattr_context_is_loop_msg_displayed(&c))
- {
- /* Print a handy error log message */
- LDAPDebug(LDAP_DEBUG_ANY,
- "Detected virtual attribute loop in get on entry %s, attribute %s\n",
- slapi_entry_get_dn_const(e), type, 0);
- vattr_context_set_loop_msg_displayed(&c);
- }
- return rc;
- }
- ctx = c;
- } else {
- use_local_ctx = PR_TRUE;
- local_pb = slapi_pblock_new();
- ctx = vattr_context_new( local_pb );
- ctx->vattr_context_loop_count = 1;
- ctx->error_displayed = 0;
- }
- /* For attributes which are in the entry, we just need to get to the Slapi_Attr structure and yank out the slapi_value_set
- structure. We either return a pointer directly to it, or we copy it, depending upon whether the caller asked us to try to
- avoid copying.
- */
- /* 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. */
- vattr_helper_get_entry_conts(e,type, &my_get);
- /* Having done that, we now consult the attribute map to find service providers who are interested */
- /* Look for attribute in the map */
- if(!(flags & SLAPI_REALATTRS_ONLY))
- {
- list = vattr_map_sp_getlist(type);
- if (list) {
- vattr_sp_handle *current_handle = NULL;
- void *hint = NULL;
- /* first lets consult the cache to save work */
- int cache_status;
-
- cache_status =
- slapi_entry_vattrcache_find_values_and_type(e, type,
- results,
- actual_type_name);
- switch(cache_status)
- {
- case SLAPI_ENTRY_VATTR_RESOLVED_EXISTS: /* cached vattr */
- {
- sp_bit = 1;
- /* Complete analysis of type matching */
- if ( 0 == slapi_attr_type_cmp( type , *actual_type_name, SLAPI_TYPE_CMP_EXACT) )
- {
- *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
- } else {
- *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE;
- }
- break;
- }
- case SLAPI_ENTRY_VATTR_RESOLVED_ABSENT: /* does not exist */
- break; /* look in entry */
- case SLAPI_ENTRY_VATTR_NOT_RESOLVED: /* not resolved */
- default: /* any other result, resolve */
- {
- for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint))
- {
- rc = vattr_call_sp_get_value(current_handle,ctx,e,&my_get,type,results,type_name_disposition,actual_type_name,flags,buffer_flags, hint);
- if (0 == rc)
- {
- sp_bit = 1;
- break;
- }
- }
- if(!sp_bit)
- {
- /* clean up, we have failed and must now examine the
- * entry itself
- * But first lets cache the no result
- * Creates the type (if necessary).
- */
- slapi_entry_vattrcache_merge_sv(e, type, NULL, *buffer_flags);
- }
- else
- {
- /*
- * we need to cache the virtual attribute
- * creates the type (if necessary) and dups
- * results.
- */
- slapi_entry_vattrcache_merge_sv(e, *actual_type_name,
- *results, *buffer_flags);
- }
- break;
- }
- }
- }
- }
- /* If no SP supplied the answer, take it from the entry */
- if (!sp_bit && !(flags & SLAPI_VIRTUALATTRS_ONLY))
- {
- rc = 0; /* reset return code (cause an sp must have failed) */
- *type_name_disposition = my_get.get_name_disposition;
- if (my_get.get_present) {
- if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
- *results = my_get.get_present_values;
- *actual_type_name = my_get.get_type_name;
- } else {
- *results = valueset_dup(my_get.get_present_values);
- if (NULL == *results) {
- rc = ENOMEM;
- } else {
- *actual_type_name = slapi_ch_strdup(my_get.get_type_name);
- if (NULL == *actual_type_name) {
- rc = ENOMEM;
- }
- }
- }
- if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
- *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
- } else {
- *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
- }
- } else {
- rc = SLAPI_VIRTUALATTRS_NOT_FOUND;
- }
- }
- if (use_local_ctx) {
- /* slapi_pblock_destroy cleans up pb_vattr_context, as well */
- slapi_pblock_destroy(local_pb);
- } else {
- vattr_context_ungrok(&c);
- }
- return rc;
- }
- /*
- *
- * returns 0: (no_error && type found ) in which case:
- * results: contains the current values for type and
- * all it's subtypes in e
- * type_name_disposition: how each type was matched
- * SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS
- * SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE
- * actual_type_name: type name as found
- * flags: bit mask of options:
- * SLAPI_REALATTRS_ONLY
- * SLAPI_VIRTUALATTRS_ONLY
- * SLAPI_VIRTUALATTRS_REQUEST_POINTERS
- * SLAPI_VIRTUALATTRS_LIST_OPERATIONAL_ATTRS
- * buffer_flags: bit mask to be used as input flags for
- * slapi_values_free()
- * SLAPI_VIRTUALATTRS_RETURNED_POINTERS
- * SLAPI_VIRTUALATTRS_RETURNED_COPIES
- * SLAPI_VIRTUALATTRS_REALATTRS_ONLY
- * item_count: number of subtypes matched
- * otherwise:
- * SLAPI_VIRTUALATTRS_LOOP_DETECTED (failed to eval a vattr)
- * SLAPI_VIRTUALATTRS_NOT_FOUND (type not recognised by any vattr
- * sp && not a real attr in entry )
- * ENOMEM (memory error)
- *
- * Note:
- * . modifes the virtual cache in the entry.
- * . for cached vattrs you always get a copy, so it will need to be
- * freed via slapi_values_free().
- *
- */
- int slapi_vattr_values_get_sp_ex(vattr_context *c,
- /* 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 *item_count)
- {
- return slapi_vattr_namespace_values_get_sp(
- c, e, NULL, type, results, type_name_disposition,
- actual_type_name, flags, buffer_flags, item_count
- );
- }
- int slapi_vattr_namespace_values_get_sp(vattr_context *c,
- /* Entry we're interested in */ Slapi_Entry *e,
- /* DN denoting backend namespace */ 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 *item_count)
- {
- int rc = 0;
- int sp_bit = 0; /* Set if an SP supplied an answer */
- vattr_sp_handle_list *list = NULL;
- vattr_get_thang *my_get = NULL;
- int attr_count = 0;
- int ignore_vattrs;
- ignore_vattrs = config_get_ignore_vattrs();
- if(!ignore_vattrs){
- rc = vattr_context_grok(&c);
- if (0 != rc) {
- /* Print a handy error log message */
- if(!vattr_context_is_loop_msg_displayed(&c))
- {
- LDAPDebug(LDAP_DEBUG_ANY,"Detected virtual attribute loop in get on entry %s, attribute %s\n", slapi_entry_get_dn_const(e), type, 0);
- vattr_context_set_loop_msg_displayed(&c);
- }
- return rc;
- }
- }
- /* Having done that, we now consult the attribute map to find service providers who are interested */
- /* Look for attribute in the map */
- if(!(flags & SLAPI_REALATTRS_ONLY) && !ignore_vattrs)
- {
- /* we use the vattr namespace aware version of this */
- list = vattr_map_namespace_sp_getlist(namespace_dn, type);
- if (list) {
- vattr_sp_handle *current_handle = NULL;
- void *hint = NULL;
- /* first lets consult the cache to save work */
- int cache_status;
-
- cache_status =
- slapi_entry_vattrcache_find_values_and_type_ex(e, type,
- results,
- actual_type_name);
- switch(cache_status)
- {
- case SLAPI_ENTRY_VATTR_RESOLVED_EXISTS: /* cached vattr */
- {
- sp_bit = 1;
- /* Complete analysis of type matching */
- *type_name_disposition =
- (int *)slapi_ch_malloc(sizeof(**type_name_disposition));
- if ( 0 == slapi_attr_type_cmp( type , **actual_type_name, SLAPI_TYPE_CMP_EXACT) )
- {
- **type_name_disposition =
- SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
- } else {
- **type_name_disposition =
- SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE;
- }
- *item_count = 1;
- break;
- }
- case SLAPI_ENTRY_VATTR_RESOLVED_ABSENT: /* does not exist */
- break; /* look in entry */
- case SLAPI_ENTRY_VATTR_NOT_RESOLVED: /* not resolved */
- default: /* any other result, resolve */
- {
- /* bit cacky, but need to make a null terminated lists for now
- * for the (unimplemented and so fake) batch attribute request
- */
- char **type_list = (char**)slapi_ch_calloc(2,sizeof(char*));
- void **hint_list = (void**)slapi_ch_calloc(2,sizeof(void*));
- type_list[0] = type;
- for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint)) {
- /* call this SP */
- hint_list[0] = hint;
- rc = vattr_call_sp_get_batch_values(current_handle,c,e,my_get,
- type_list,results,type_name_disposition,
- actual_type_name, flags,buffer_flags, hint_list);
- if (0 == rc) {
- sp_bit = 1; /* this sp provided an answer, we are done */
- /* count the items in the (null terminated) result list */
- *item_count = 0;
- while((*results)[*item_count])
- {
- (*item_count)++;
- }
- break;
- }
- }
- slapi_ch_free((void**)&type_list);
- slapi_ch_free((void**)&hint_list);
- if(!sp_bit)
- {
- /* we have failed and must now examine the entry itself
- *
- * But first lets cache the no result
- * dups the type (if necessary).
- */
- slapi_entry_vattrcache_merge_sv(e, type, NULL, *buffer_flags);
- }
- else
- {
- /*
- * we need to cache the virtual attribute
- * dups the type (if necessary) and results.
- */
- /*
- * this (and above) will of course need to get updated
- * when we do real batched attributes
- */
- slapi_entry_vattrcache_merge_sv(e, **actual_type_name,
- **results, *buffer_flags);
- }
- }
- }
- }
- }
- /* If no SP supplied the answer, take it from the entry */
- if (!sp_bit && !(flags & SLAPI_VIRTUALATTRS_ONLY))
- {
- int counter;
- /* First grok the entry - allocates memory for list */
- attr_count = vattr_helper_get_entry_conts_ex(e,type, &my_get,
- (0 != (flags & SLAPI_VIRTUALATTRS_SUPPRESS_SUBTYPES)));
- *item_count = attr_count;
- rc = 0; /* reset return code (cause an sp must have failed) */
- if(attr_count > 0)
- {
- *results = (Slapi_ValueSet**)slapi_ch_calloc(1, sizeof(**results) * attr_count);
- *type_name_disposition = (int *)slapi_ch_malloc(sizeof(**type_name_disposition) * attr_count);
- *actual_type_name = (char**)slapi_ch_malloc(sizeof(**actual_type_name) * attr_count);
- /* For attributes which are in the entry, we just need to get to the Slapi_Attr structure and yank out the slapi_value_set
- structure. We either return a pointer directly to it, or we copy it, depending upon whether the caller asked us to try to
- avoid copying.
- */
- for(counter = 0; counter < attr_count; counter++)
- {
- (*type_name_disposition)[counter] = my_get[counter].get_name_disposition;
- if (my_get[counter].get_present) {
- if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
- /* pointers will do, good */
- (*results)[counter] = my_get[counter].get_present_values;
- (*actual_type_name)[counter] = my_get[counter].get_type_name;
- } else {
- /* need to copy the values */
- (*results)[counter] = valueset_dup(my_get[counter].get_present_values);
- if (NULL == (*results)[counter]) {
- rc = ENOMEM;
- } else {
- (*actual_type_name)[counter] = slapi_ch_strdup(my_get[counter].get_type_name);
- if (NULL == (*actual_type_name)[counter]) {
- rc = ENOMEM;
- }
- }
- }
- if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
- *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
- } else {
- *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
- }
- } else {
- rc = SLAPI_VIRTUALATTRS_NOT_FOUND;
- }
- }
- slapi_ch_free((void **)&my_get);
- }
- }
- vattr_context_ungrok(&c);
- return rc;
- }
- /* Do we need a call to free the results from the above ? */
- void slapi_vattr_values_free(Slapi_ValueSet **value, char** actual_type_name,
- int flags)
- {
- /* Check whether we need to free the strings */
- if (flags & SLAPI_VIRTUALATTRS_RETURNED_POINTERS) {
- /* We don't need to free the values */
- } else {
- /* Free the valueset */
- if (*value) {
- slapi_valueset_free(*value);
- }
- if (*actual_type_name) {
- slapi_ch_free((void **)actual_type_name);
- }
- }
- *actual_type_name = NULL;
- *value = NULL;
- }
- /* Function like the one above but doing a compare operation */
- /* Same return codes as above. Compare result value returned in "result": 0 if compare true, 1 if compare false */
- int slapi_vattr_value_compare(Slapi_Entry *e, char *type, Slapi_Value *test_this, int *result, int flags)
- {
- return slapi_vattr_namespace_value_compare_sp(NULL,e,NULL,type,test_this,result,flags);
- }
- /* namespace version of above */
- int slapi_vattr_namespace_value_compare(Slapi_Entry *e, Slapi_DN *namespace_dn, const char *type, Slapi_Value *test_this, int *result, int flags)
- {
- return slapi_vattr_namespace_value_compare_sp(NULL,e,namespace_dn,type,test_this,result,flags);
- }
- 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)
- {
- return slapi_vattr_namespace_value_compare_sp(c,e,NULL,type,test_this,result,flags);
- }
- 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)
- {
- int rc = 0;
- int sp_bit = 0; /* Set if an SP supplied an answer */
- vattr_sp_handle_list *list = NULL;
- vattr_get_thang *my_get = 0;
- *result = 0; /* return "compare false" by default */
- rc = vattr_context_grok(&c);
- if (0 != rc) {
- if(!vattr_context_is_loop_msg_displayed(&c)) {
- /* Print a handy error log message */
- LDAPDebug(LDAP_DEBUG_ANY,"Detected virtual attribute loop in compare on entry %s, attribute %s\n", slapi_entry_get_dn_const(e), type, 0);
- vattr_context_set_loop_msg_displayed(&c);
- }
- return rc;
- }
- /* Having done that, we now consult the attribute map to find service providers who are interested */
- /* Look for attribute in the map */
- list = vattr_map_namespace_sp_getlist(namespace_dn, type);
- if (list) {
- vattr_sp_handle *current_handle = NULL;
- void *hint = NULL;
- for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint)) {
- /* call this SP */
- rc = vattr_call_sp_compare_value(current_handle,c,e,my_get,type,test_this,result,flags, hint);
- if (0 == rc) {
- sp_bit = 1;
- break;
- }
- }
- }
- /* If no SP supplied the answer, take it from the entry */
- if (!sp_bit) {
- /* 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. */
- int attr_count = vattr_helper_get_entry_conts_ex(e,type, &my_get,
- (0 != (flags & SLAPI_VIRTUALATTRS_SUPPRESS_SUBTYPES)));
- if (my_get && my_get->get_present) {
- int i;
- Slapi_Value *Dummy_value = NULL;
-
- /* Put the required stuff in the fake attr */
- rc = 0; /* found real attr - now see if we have the requested value*/
- *result = 0; /* return "compare false" by default */
- for(i=0;i<attr_count;i++)
- {
- Dummy_value = slapi_valueset_find( my_get[i].get_attr, my_get[i].get_present_values, test_this );
- if (Dummy_value) {
- *result = 1; /* return "compare true" */
- break;
- }
- }
- } else {
- /* no such attribute */
- rc = SLAPI_VIRTUALATTRS_NOT_FOUND;
- }
- }
- vattr_context_ungrok(&c);
- slapi_ch_free((void **)&my_get);
- return rc;
- }
- /* Function to obtain the list of attribute types which are available on this entry */
- /*
- Need to call service providers here:
- We know only the entry's DN and so we could restrict our choice of SPs based on that.
- However, we don't yet implement such fancyness.
- For now, we just crawl through all the SPs, asking them in turn to contribute.
- This is pretty inefficient because we will trawl the list for each wildcard attribute type search operation.
- Service providers should therefore handle the call as fast as they can.
- */
- struct _vattr_type_list_context {
- unsigned int vattr_context_loop_count;
- vattr_type_thang *types;
- int realattrs_only; /* TRUE implies list contains only real attrs */
- int list_is_copies;
- int flags;
- size_t list_length;
- size_t block_length;
- };
- /* Helper function which converts a type list from pointers to copies */
- static int vattr_convert_type_list(vattr_type_list_context *thang)
- {
- vattr_type_thang *old_list = NULL;
- vattr_type_thang *new_list = NULL;
- size_t index = 0;
- old_list = thang->types;
- /* Make a new list */
- new_list = (vattr_type_thang*)slapi_ch_calloc(thang->block_length, sizeof(vattr_type_thang));
- if (NULL == new_list) {
- return ENOMEM;
- }
- /* Walk the list strdup'ing the type name and copying the rest of the structure contents */
- for (index = 0; index < thang->list_length; index++) {
- new_list[index].type_flags = old_list[index].type_flags;
- new_list[index].type_name = slapi_ch_strdup(old_list[index].type_name);
- /*
- * list_is_copies does not affect type_values as it
- * is always a pointer never a copy.
- */
- new_list[index].type_values = old_list[index].type_values;
- }
- /* Mark it a copy list */
- thang->list_is_copies = 1;
- /* Free the original list */
- slapi_ch_free((void **)&(thang->types));
- /* swap lists */
- thang->types = new_list;
- return 0;
- }
- /*
- * Returns all the attribute types from e, both real and virtual.
- *
- * Any of the attributes found in the entry to start with, for
- * whom no vattr SP volunteered, will also have a pointer to the
- * original valueset in the entry--this fact can be used by
- * calling slapi_vattr_values_type_thang_get(), which will
- * take the values present in the vattr_type_thang list
- * rather than calling slapi_vattr_values_get() to retrieve the value.
- */
- #define TYPE_LIST_EXTRA_SPACE 5 /* Number of extra slots we allow for SP's to insert types */
- int slapi_vattr_list_attrs(/* Entry we're interested in */ Slapi_Entry *e,
- /* pointer to receive the list */ vattr_type_thang **types,
- int flags, int *buffer_flags)
- {
- int rc = 0;
- size_t attr_count = 0;
- vattr_type_thang *result_array = NULL ;
- Slapi_Attr *current_attr = NULL;
- size_t i = 0;
- int list_is_copies = 0;
- vattr_sp_handle_list *list = NULL;
- size_t list_length = 0;
- size_t block_length = 0;
- vattr_type_list_context type_context = {0};
- if (NULL == types || NULL == buffer_flags) {
- LDAPDebug(LDAP_DEBUG_ANY, "slapi_vattr_list_attrs: invalid param\n", 0, 0, 0);
- return -1;
- }
- block_length = 1 + TYPE_LIST_EXTRA_SPACE;
- if(!(flags & SLAPI_VIRTUALATTRS_ONLY))
- {
- /* First find what's in the entry itself*/
- /* Count the attributes */
- for (current_attr = e->e_attrs; current_attr != NULL; current_attr = current_attr->a_next, attr_count++) ;
- block_length += attr_count;
- /* Allocate the pointer array */
- result_array = (vattr_type_thang*)slapi_ch_calloc(block_length,sizeof(vattr_type_thang));
- if (NULL == result_array) {
- return ENOMEM;
- }
- list_length = attr_count;
- /* Now copy the pointers into the array */
- i = 0;
- for (current_attr = e->e_attrs; current_attr != NULL; current_attr = current_attr->a_next) {
- char *mypointer = NULL;
- if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
- mypointer = current_attr->a_type;
- result_array[i].type_values = &(current_attr->a_present_values);
- } else {
- mypointer = slapi_ch_strdup(current_attr->a_type);
- list_is_copies = 1;
- }
- if (NULL == current_attr->a_plugin) {
- /* could be lazy plugin initialization, get it now */
- slapi_attr_init_syntax(current_attr);
- }
- result_array[i].type_flags = current_attr->a_flags;
- result_array[i++].type_name = mypointer;
- }
- PR_ASSERT(i == attr_count);
- }
- /* if we didnt send real attrs we need to allocate result array */
- if(NULL == result_array)
- {
- result_array = (vattr_type_thang*)slapi_ch_calloc(block_length,sizeof(vattr_type_thang));
- if (NULL == result_array) {
- return ENOMEM;
- }
- }
- /* Then ask the service providers for their input */
- type_context.flags = flags;
- type_context.realattrs_only = 1; /* until we know otherwise */
- type_context.list_is_copies = list_is_copies;
- type_context.types = result_array;
- type_context.list_length = list_length;
- type_context.block_length = block_length;
- /*
- * At this point type_context.types is a list of all
- * the attributetypes (copies or pointers) and values (copies, if present)
- * found in the entry.
- */
- if(!(flags & SLAPI_REALATTRS_ONLY))
- {
- list = vattr_map_sp_get_complete_list();
- if (list) {
- vattr_sp_handle *current_handle = NULL;
-
- for (current_handle = vattr_list_sp_first(list); current_handle; current_handle = vattr_list_sp_next((vattr_sp_handle_list *)current_handle)) {
- /* call this SP */
- rc = vattr_call_sp_get_types(current_handle,e,&type_context,
- flags);
- if (0 != rc) {
- /* DBDB do what on error condition ? */
- }
- }
- /* assert enough space for the null terminator */
- PR_ASSERT( type_context.list_length < type_context.block_length);
- i = type_context.list_length;
- }
- }
- /*
- * Now type_context.types is a list of all the types in this entry--
- * real and virtual. For real ones, the values field is filled in.
- * For virtual ones (including virtual ones which will overwrite a real
- * value) the values field is null--this fact may used
- * subsequently by callers of slapi_vattr_list_attrs()
- * by calling slapi_vattr_values_type_thang_get() which
- * will only calculate the values for attributetypes with
- * non-null values.
- */
-
- flags = type_context.flags;
- list_is_copies = type_context.list_is_copies;
- result_array = type_context.types;
- list_length = type_context.list_length;
- block_length = type_context.block_length;
- if (list_is_copies) {
- *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
- } else {
- *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
- }
- /* Let the caller know if the list contains only real attrs */
- if (type_context.realattrs_only) {
- *buffer_flags |= SLAPI_VIRTUALATTRS_REALATTRS_ONLY;
- }
- result_array[i].type_name = NULL;
- if (list_length)
- *types = result_array;
- else
- *types = 0;
- return rc;
- }
- static int vattr_add_thang_to_list(vattr_type_list_context *c, vattr_type_thang *thang)
- {
- vattr_type_thang *new_list = NULL;
- /* Will it fit in the current block ? */
- if (c->list_length == c->block_length - 1) {
- c->block_length *= 2;
- new_list = (vattr_type_thang*)slapi_ch_realloc((char *)c->types,
- c->block_length * (int)sizeof(vattr_type_thang));
- if (NULL == new_list) {
- return ENOMEM;
- }
- c->types = new_list;
- }
- /* Add to the end of the list */
- c->types[c->list_length ] = *thang;
- c->list_length += 1;
- return 0;
- }
- /* Called by SP's during their get_types call, to have the server add a
- * type to the type list.
- *
- * c: the vattr_type_list_context passed from the original caller of
- * slapi_vattr_list_attrs()
- * thang: the new type to be added to the type list.
- * flags: tells the routine whether to copy the thang or not.
- * SLAPI_VIRTUALATTRS_REQUEST_POINTERS--no need to copy it.
- * !(SLAPI_VIRTUALATTRS_REQUEST_POINTERS)--need to copy it.
- *
- * Checks to see if the requested type is already in the list,
- * and if it is, if the value of the attribute is
- * non-null, it resets the value to null. This means that when used
- * subsequently, the type list indicates whether, for a given attribute type,
- * the SP's need to be called to retrieve the value.
- *
- */
- int slapi_vattrspi_add_type(vattr_type_list_context *c,
- vattr_type_thang *thang, int flags)
- {
- int rc = 0;
- unsigned int index = 0;
- vattr_type_thang thang_to_add = {0};
- int found_it = 0;
- PR_ASSERT(c);
- /* We are no longer sure that the list contains only real attrs */
- c->realattrs_only = 0;
- /* Check to see if the type is in the list already */
- for (index = 0; index < c->list_length; index++) {
- if (0 == slapi_UTF8CASECMP(c->types[index].type_name,thang->type_name)) {
- found_it = 1;
- break;
- }
- }
- /*
- * If found and there are values specified in the vattr_type_thang, then
- * that means it's a real attribute--because SP's do not add values
- * when called via slapi_vattr_list_attrs()/vattr_call_sp_get_types().
- * However, an SP is willing to claim responsibility for this attribute
- * type, so to ensure that that virtual value will get calculated, set the
- * original real value to NULL here.
- * The guiding rule here is "if an SP is prepared
- * to provide a value for an attribute type, then that is the one
- * that must be returned to the user". Note, this does not prevent
- * the SP implementing a "merge real with virtual policy", if they
- * wish.
- */
-
- if (found_it) {
-
- if ( c->types[index].type_values != NULL ) {
- /*
- * Any values in this list are always pointers.
- * See slapi_vattr_list_types() and vattr_convert_type_list()
- */
- c->types[index].type_values = NULL;
- }
-
- return 0;
- }
- /*
- * If it's not in the list then we need to add it.
- * If the list is already copies, then we need to make a copy of what the
- * SP passed us.
- * If the SP indicated that the type name it passed us is volatile,
- * !(flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS)
- * then we need to copy it anyway.
- */
- /* rbyrneXXX optimisation for COS: if each type_thang could have a
- * free_flag
- * then we would not have to convert all the real attrs to copies
- * just because an SP returned a copy (note: only COS rrequires copies;
- * roles returns a pointer to a static string "nsRole").
- */
- if (!c->list_is_copies &&
- (0 == (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS))) {
- /* Means we need to turn the existing list into a list of copies */
- vattr_convert_type_list(c);
- }
- if (c->list_is_copies) {
- thang_to_add.type_flags = thang->type_flags;
- thang_to_add.type_name = slapi_ch_strdup(thang->type_name);
- } else {
- thang_to_add = *thang;
- }
- /* Lastly, we add to the list, using a function which hides the complexity of extending the list if it fills up */
- vattr_add_thang_to_list(c, &thang_to_add);
- return rc;
- }
- /* Function to free the list returned in the function above */
- /* Written, reviewed, debug stepped */
- void slapi_vattr_attrs_free(vattr_type_thang **types, int flags)
- {
- if (NULL == *types) {
- return;
- }
- /* Check whether we need to free the strings */
- if (flags & SLAPI_VIRTUALATTRS_RETURNED_POINTERS) {
- /* We don't need to free the values */
- } else {
- char *attr_name_to_free = NULL;
- size_t i = 0;
- /* Walk down the set of values, fr eeing each one in turn */
- for (; (attr_name_to_free = (*types)[i].type_name) != NULL; i++) {
- slapi_ch_free((void **)&attr_name_to_free);
- }
- }
- /* We always need to free the pointer block */
- slapi_ch_free((void **)types);
- }
- char *vattr_typethang_get_name(vattr_type_thang *t)
- {
- return t->type_name;
- }
- unsigned long vattr_typethang_get_flags(vattr_type_thang *t)
- {
- return t->type_flags;
- }
- vattr_type_thang *vattr_typethang_next(vattr_type_thang *t)
- {
- t++;
- if (t->type_name) {
- return t;
- } else {
- return NULL;
- }
- }
- vattr_type_thang *vattr_typethang_first(vattr_type_thang *t)
- {
- return t;
- }
- vattr_get_thang *slapi_vattr_getthang_first(vattr_get_thang *t)
- {
- return t;
- }
- vattr_get_thang *slapi_vattr_getthang_next(vattr_get_thang *t)
- {
- t++;
- if (t->get_present) {
- return t;
- } else {
- return NULL;
- }
- }
- /* End of the public interface functions */
- /* Everything below here is the SPI interface, only callable by vattr service providers.
- Currently this interface is not public. Interface definitions are in vattr_spi.h
- */
- /* Structures used in the SPI interface */
- /* Service provider object */
- struct _vattr_sp {
- /* vtbl */
- vattr_get_fn_type sp_get_fn;
- vattr_get_ex_fn_type sp_get_ex_fn;
- vattr_compare_fn_type sp_compare_fn;
- vattr_types_fn_type sp_types_fn;
- void *sp_data; /* Pointer for use by the Service Provider */
- };
- typedef struct _vattr_sp vattr_sp;
- /* Service provider handle */
- struct _vattr_sp_handle {
- vattr_sp *sp;
- struct _vattr_sp_handle *next; /* So we can link them together in the map */
- void *hint; /* Hint to the SP */
- };
- /* Calls made by Service Providers */
- /* Call to register as a service provider */
- /* This function needs to do the following:
- o Let the provider say "hey, I'm here". It should probably get some handle back which it can use in future calls.
- o Say whether it wants to be called to resolve every single query, or whether it will say in advance what attrs it services.
- */
- static vattr_sp_handle *vattr_sp_list = NULL;
- 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)
- {
- return slapi_vattrspi_register_internal(h, get_fn, 0, compare_fn, types_fn, 0);
- }
- 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)
- {
- return slapi_vattrspi_register_internal(h, 0, get_fn, compare_fn, types_fn, options);
- }
- /* options not used yet - for future expansion */
- 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)
- {
- vattr_sp_handle *return_to_caller = NULL;
- vattr_sp_handle *list_handle = NULL;
- vattr_sp *new_sp = NULL;
- /* Make a service provider handle */
- new_sp = (vattr_sp*)slapi_ch_calloc(1,sizeof(vattr_sp));
- new_sp->sp_get_fn = get_fn;
- new_sp->sp_get_ex_fn = get_ex_fn;
- new_sp->sp_compare_fn = compare_fn;
- new_sp->sp_types_fn = types_fn;
- return_to_caller = (vattr_sp_handle*)slapi_ch_calloc(1,sizeof(vattr_sp_handle));
- return_to_caller->sp = new_sp;
- /* Add to the service provider list */
- /* Make a handle for the list */
- list_handle = (vattr_sp_handle*)slapi_ch_calloc(1, sizeof (vattr_sp_handle));
- *list_handle = *return_to_caller;
- list_handle->next = vattr_sp_list;
- vattr_sp_list = list_handle;
- /* Return the handle to the caller */
- *h = return_to_caller;
- return 0;
- }
- vattr_sp_handle_list *vattr_map_sp_get_complete_list()
- {
- return vattr_sp_list;
- }
- int slapi_vattrspi_regattr(vattr_sp_handle *h,char *type_name_to_register, char* DN , void *hint)
- {
- int ret = 0;
- char *type_to_add;
- int free_type_to_add = 0;
- Slapi_DN original_dn;
- slapi_sdn_init(&original_dn);
- /* Supplying a DN means that the plugin requires to be called
- * only when the considering attributes in relevant entries - almost
- *
- * Actually the smallest namespace is the backend.
- *
- * atttributes that are tied to backends have the format DN::attr
- * this essentially makes the attribute have split namespaces
- * that are treated as separate attributes in the vattr code
- */
- if(DN)
- {
- /* as a coutesy we accept any old DN and will convert
- * to a namespace DN, this helps to hide details
- * (that we might decide to change) anyway
- */
- Slapi_Backend *be;
- Slapi_DN *namespace_dn;
-
- slapi_sdn_set_dn_byref(&original_dn,DN);
- be = slapi_be_select( &original_dn );
- namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
- if(namespace_dn && be != defbackend_get_backend()) /* just in case someone thinks "" is a good namespace */
- {
- type_to_add = slapi_ch_smprintf("%s::%s",
- (char*)slapi_sdn_get_dn(namespace_dn),
- type_name_to_register);
- free_type_to_add = 1;
- }
- else
- {
- type_to_add = type_name_to_register;
- }
- }
- else
- {
- type_to_add = type_name_to_register;
- }
- ret = vattr_map_sp_insert(type_to_add,h,hint);
- slapi_sdn_done(&original_dn);
- if(free_type_to_add)
- {
- slapi_ch_free((void **)&type_to_add);
- }
- return ret;
- }
- /* Call to advertise or refute that you generate the value for some attribute, and to signal that the definition for this attribute has changed */
- /* This call needs to do the following:
- 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
- o Same as above, but say "you know, I'm not doing that any more". (we'll do that with a addordel flag).
- o Say, "you know that definition I said I did, well it's changed".
- */
- /* Functions to handle the context stucture */
- int slapi_vattr_context_create(vattr_context **c)
- {
- return 0;
- }
- void slapi_vattr_context_destroy(vattr_context *c)
- {
- }
- 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)
- {
- int ret = -1;
- if(handle->sp->sp_get_fn)
- {
- ret = ((handle->sp->sp_get_fn)(handle,c,e,type,results,type_name_disposition,actual_type_name,flags,buffer_flags, hint));
- }
- return ret;
- }
- 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)
- {
- int ret = 0;
- if(handle->sp->sp_get_ex_fn)
- {
- ret = ((handle->sp->sp_get_ex_fn)(handle,c,e,type,results,type_name_disposition,actual_type_name,flags,buffer_flags, hint));
- }
- else
- {
- /* make our args look like the simple non-batched case */
- *results = (Slapi_ValueSet**)slapi_ch_calloc(2, sizeof(**results)); /* 2 for null terminated list */
- *type_name_disposition = (int *)slapi_ch_calloc(2, sizeof(**type_name_disposition));
- *actual_type_name = (char**)slapi_ch_calloc(2, sizeof(**actual_type_name));
- ret =((handle->sp->sp_get_fn)(handle,c,e,*type,*results,*type_name_disposition,*actual_type_name,flags,buffer_flags, hint));
- if (ret)
- {
- slapi_ch_free((void**)results );
- slapi_ch_free((void**)type_name_disposition );
- slapi_ch_free((void**)actual_type_name );
- }
- }
- return ret;
- }
- 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)
- {
- return ((handle->sp->sp_compare_fn)(handle,c,e,(char*)type,test_this,result,flags, hint));
- }
- int vattr_call_sp_get_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags)
- {
- return ((handle->sp->sp_types_fn)(handle,e,type_context,flags));
- }
- /* Service provider entry point prototypes */
- /* Call which allows a SP to say what attributes can be used to define a given attribute, used for loop detection */
- /* Not implementing this yet */
- /* typedef int (*vattrspi_explain_definition) (); */
- /* Function called to indicate to the SP that the game is over, we free the handle, not the SP */
- typedef int (*vattrspi_deregister) (vattr_sp_handle *h);
- /* End of the SPI functions */
- /* Implementation functions only after here */
- /* The attribute map */
- /* We need a structure which can map attribute type names to SP's which might tell us
- something useful. We need a function which, given an attr type name, can return
- a set of SP's to ask about said attr. SP's which don't tell us which attrs they are
- handling always get asked. The first SP which tells us the answer wins, we don't
- attempt to arbitrate between them. One might imaging doing this stuff in a unified
- way with other stuff pertaining to types (schema, syntax). Someday. For now this
- is a separate thing in the insterests of stability.
- */
- /* Virtual Attribute map implementation */
- /* The virtual attribute type map is implemented as a hash table.
- The single key is the attribute type base name (not an alias)
- (what about subtypes??). The hash table takes care of translating
- this key to a list of probable service providers for the type.
- Other than the obvious lookup function, we need functions to
- allow entries to be added and removed from the map.
- Because the map is likely to be consulted at least once for every search
- operation performed by the server, it's important that it is free from
- performance deficiencies such as lock contention (is the NSPR hash table
- implementation even thread safe ?
- */
- #define VARRT_MAP_HASHTABLE_SIZE 10
- /* Attribute map oject */
- /* Needs to contain: a linked list of pointers to provider handles handles,
- The type name,
- other stuff ?
- Access to the entire map will be controlled via a single RW lock.
- */
- struct _objAttrValue
- {
- struct _objAttrValue *pNext;
- Slapi_Value *val;
- };
- typedef struct _objAttrValue objAttrValue;
- struct _vattr_map_entry {
- char * /* currect ? */ type_name;
- vattr_sp_handle *sp_list;
- objAttrValue *objectclasses; /* objectclasses for this type to check schema with*/
- };
- typedef struct _vattr_map_entry vattr_map_entry;
- vattr_map_entry test_entry = {NULL};
- struct _vattr_map {
- Slapi_RWLock *lock;
- PLHashTable *hashtable; /* Hash table */
- };
- typedef struct _vattr_map vattr_map;
- static vattr_map *the_map = NULL;
- static PRIntn vattr_hash_compare_keys(const void *v1, const void *v2)
- {
- /* Should this be subtype aware, etc ? */
- return ( (0 == strcasecmp(v1,v2)) ? 1 : 0) ;
- }
- static PRIntn vattr_hash_compare_values(const void *v1, const void *v2)
- {
- return( ((char *)v1 == (char *)v2 ) ? 1 : 0);
- }
- static PLHashNumber vattr_hash_fn(const void *type_name)
- {
- /* need a hash function here */
- /* Sum the bytes for now */
- PLHashNumber result = 0;
- char * current_position = NULL;
- char current_char = 0;
- for (current_position = (char*) type_name; *current_position; current_position++) {
- current_char = tolower(*current_position);
- result += current_char;
- }
- return result;
- }
- static int vattr_map_create()
- {
- the_map = (vattr_map*)slapi_ch_calloc(1, sizeof(vattr_map));
- if (NULL == the_map) {
- slapd_nasty(sourcefile,1,0);
- return ENOMEM;
- }
- the_map->hashtable = PL_NewHashTable(VARRT_MAP_HASHTABLE_SIZE,
- vattr_hash_fn, vattr_hash_compare_keys,
- vattr_hash_compare_values, NULL, NULL);
- if (NULL == the_map->hashtable) {
- slapd_nasty(sourcefile,2,0);
- return ENOMEM;
- }
- the_map->lock = slapi_new_rwlock();
- if (NULL == the_map) {
- slapd_nasty(sourcefile,3,0);
- return ENOMEM;
- }
- return 0;
- }
- static void vattr_map_destroy()
- {
- if (the_map) {
- if (the_map->hashtable) {
- PL_HashTableDestroy(the_map->hashtable);
- }
- if (the_map->lock) {
- slapi_destroy_rwlock(the_map->lock);
- }
- }
- slapi_ch_free ((void**)&the_map);
- }
- /* Returns 0 if present, entry returned in result. Returns SLAPI_VIRTUALATTRS_NOT_FOUND if not found */
- static int vattr_map_lookup(const char *type_to_find, vattr_map_entry **result)
- {
- char *basetype = 0;
- char *tmp = 0;
- char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
- *result = NULL;
- PR_ASSERT(the_map);
- /* vattrs need to support subtypes
- * we insist that one service provider
- * will support all subtypes for a
- * given superior, hence we look for
- * superiors only here
- */
- tmp = slapi_attr_basetype( type_to_find, buf, sizeof(buf));
- if(tmp)
- {
- basetype = tmp;
- }
- else
- {
- basetype = buf;
- }
- /* Get the reader lock */
- slapi_rwlock_rdlock(the_map->lock);
- *result = (vattr_map_entry*)PL_HashTableLookupConst(the_map->hashtable,
- (void*)basetype);
- /* Release ze lock */
- slapi_rwlock_unlock(the_map->lock);
- if(tmp)
- {
- slapi_ch_free_string(&tmp);
- }
- if (*result) {
- return 0;
- } else {
- return SLAPI_VIRTUALATTRS_NOT_FOUND;
- }
- }
- /* Insert an entry into the attribute map */
- int vattr_map_insert(vattr_map_entry *vae)
- {
- char *copy_of_type_name = NULL;
- PR_ASSERT(the_map);
- copy_of_type_name = slapi_ch_strdup(vae->type_name);
- if (NULL == copy_of_type_name) {
- slapd_nasty(sourcefile,6,0);
- return ENOMEM;
- }
- /* Get the writer lock */
- slapi_rwlock_wrlock(the_map->lock);
- /* Insert the thing */
- /* It's illegal to call this function if the entry is already there */
- PR_ASSERT(NULL == PL_HashTableLookupConst(the_map->hashtable,(void*)copy_of_type_name));
- PL_HashTableAdd(the_map->hashtable,(void*)copy_of_type_name,(void*)vae);
- /* Unlock and we're done */
- slapi_rwlock_unlock(the_map->lock);
- return 0;
- }
- /*
- vattr_delete_attrvals
- ---------------------
- deletes a value list
- */
- void vattr_delete_attrvals(objAttrValue **attrval)
- {
- objAttrValue *val = *attrval;
- while(val)
- {
- objAttrValue *next = val->pNext;
- slapi_value_free(&val->val);
- slapi_ch_free((void**)&val);
- val = next;
- }
- }
- /*
- vattr_add_attrval
- -----------------
- adds a value to an attribute value list
- */
- int vattr_add_attrval(objAttrValue **attrval, char *val)
- {
- int ret = 0;
- objAttrValue *theVal;
- LDAPDebug( LDAP_DEBUG_TRACE, "--> vattr_add_attrval\n",0,0,0);
- /* create the attrvalue */
- theVal = (objAttrValue*) slapi_ch_malloc(sizeof(objAttrValue));
- if(theVal)
- {
- theVal->val = slapi_value_new_string(val);
- if(theVal->val)
- {
- theVal->pNext = *attrval;
- *attrval = theVal;
- }
- else
- {
- slapi_ch_free((void**)&theVal);
- LDAPDebug( LDAP_DEBUG_ANY, "vattr_add_attrval: failed to allocate memory\n",0,0,0);
- ret = -1;
- }
- }
- else
- {
- LDAPDebug( LDAP_DEBUG_ANY, "vattr_add_attrval: failed to allocate memory\n",0,0,0);
- ret = -1;
- }
- LDAPDebug( LDAP_DEBUG_TRACE, "<-- vattr_add_attrval\n",0,0,0);
- return ret;
- }
- objAttrValue *vattr_map_entry_build_schema(char *type_name)
- {
- objAttrValue *ret = 0;
- struct objclass *oc;
- LDAPDebug( LDAP_DEBUG_TRACE, "--> vattr_map_entry_build_schema\n",0,0,0);
- /* this is the first opportunity to register
- * with the statechange api, our init function
- * gets called prior to loading plugins, so it
- * was not available then
- */
- if(!statechange_api)
- {
- /* grab statechange api - we never release this */
- if(!slapi_apib_get_interface(StateChange_v1_0_GUID, &statechange_api))
- {
- /* register for schema changes via dn */
- statechange_register(statechange_api, "vattr", "cn=schema", NULL, NULL, (notify_callback) schema_changed_callback);
- }
- }
- if(!config_get_schemacheck())
- {
- LDAPDebug( LDAP_DEBUG_TRACE, "<-- vattr_map_entry_build_schema - schema off\n",0,0,0);
- return 0;
- }
- oc_lock_read();
- for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next )
- {
- char **pppAttrs[2];
- int index;
- int attrType = 0;
- int oc_added = 0;
- pppAttrs[0] = oc->oc_required;
- pppAttrs[1] = oc->oc_allowed;
- /* we need to check both required and allowed attributes */
- while(!oc_added && attrType < 2)
- {
- if(pppAttrs[attrType])
- {
- index = 0;
- while(pppAttrs[attrType][index])
- {
- if(!PL_strcasecmp(pppAttrs[attrType][index], type_name))
- {
- vattr_add_attrval(&ret, oc->oc_name);
- oc_added = 1;
- break;
- }
- index++;
- }
- }
- attrType++;
- }
- }
- oc_unlock();
- LDAPDebug( LDAP_DEBUG_TRACE, "<-- vattr_map_entry_build_schema\n",0,0,0);
- return ret;
- }
- static PRIntn vattr_map_entry_rebuild_schema(PLHashEntry *he, PRIntn i, void *arg)
- {
- vattr_map_entry *entry = (vattr_map_entry *)(he->value);
- if(entry->objectclasses)
- vattr_delete_attrvals(&(entry->objectclasses));
-
- entry->objectclasses = vattr_map_entry_build_schema(entry->type_name);
- return HT_ENUMERATE_NEXT;
- }
- void schema_changed_callback(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data)
- {
- /* Get the writer lock */
- slapi_rwlock_wrlock(the_map->lock);
- /* go through the list */
- PL_HashTableEnumerateEntries(the_map->hashtable, vattr_map_entry_rebuild_schema, 0);
- /* Unlock and we're done */
- slapi_rwlock_unlock(the_map->lock);
- }
- int slapi_vattr_schema_check_type(Slapi_Entry *e, char *type)
- {
- int ret = 0;
- vattr_map_entry *map_entry;
- if(config_get_schemacheck())
- {
- Slapi_Attr *attr;
- if(0 == slapi_entry_attr_find(e, "objectclass", &attr))
- {
- Slapi_ValueSet *vs;
- if(0 == slapi_attr_get_valueset(attr, &vs))
- {
- objAttrValue *obj;
- if(0 == vattr_map_lookup(type, &map_entry))
- {
- slapi_rwlock_rdlock(the_map->lock);
- obj = map_entry->objectclasses;
- while(obj)
- {
- if(slapi_valueset_find(attr, vs, obj->val))
- {
- /* this entry has an objectclass
- * that allows or requires the
- * attribute type
- */
- ret = -1;
- break;
- }
- obj = obj->pNext;
- }
- slapi_rwlock_unlock(the_map->lock);
- }
- slapi_valueset_free(vs);
- }
- }
- }
- else
- ret = -1;
- return ret;
- }
- vattr_map_entry *vattr_map_entry_new(char *type_name, vattr_sp_handle *sph, void* hint)
- {
- vattr_map_entry *result = NULL;
- vattr_sp_handle *sp_copy = NULL;
- sp_copy = (vattr_sp_handle*)slapi_ch_calloc(1, sizeof (vattr_sp_handle));
- sp_copy->sp = sph->sp;
- sp_copy->hint = hint;
- result = (vattr_map_entry*)slapi_ch_calloc(1, sizeof (vattr_map_entry));
- result->type_name = slapi_ch_strdup(type_name);
- result->sp_list = sp_copy;
- /* go get schema */
- result->objectclasses = vattr_map_entry_build_schema(type_name);
- return result;
- }
- /* On top of the map, we need functions to manipulate the SP handles from within */
- /* Function to get the SP list from the map, given a type name */
- /* The resulting list is in the map, but is safe to read regardless of concurrent updates */
- vattr_sp_handle_list *vattr_map_sp_getlist(char *type_to_find)
- {
- int ret = 0;
- vattr_map_entry *result = NULL;
- ret = vattr_map_lookup(type_to_find,&result);
- if (0 == ret) {
- return (vattr_sp_handle_list*) result->sp_list;
- } else {
- return NULL;
- }
- }
- /* same as above, but filters the list based on the supplied backend dn
- * when we stored these dn based attributes, we concatenated them with
- * the dn like this dn::attribute, so we need to do two checks for the
- * attribute, one with, and one without the dn
- */
- vattr_sp_handle_list *vattr_map_namespace_sp_getlist(Slapi_DN *dn, const char *type_to_find)
- {
- int ret = 0;
- vattr_map_entry *result = NULL;
- vattr_sp_handle_list* return_list = 0;
- if(config_get_ignore_vattrs()){
- /* we don't care about vattrs */
- return NULL;
- }
- ret = vattr_map_lookup(type_to_find,&result);
- if (0 == ret) {
- return_list = (vattr_sp_handle_list*) result->sp_list;
- } else {
- /* we have allowed the global namespace provider a shot
- * now it is time to query for split namespace providers
- */
- if(dn) {
- char *split_dn = (char*)slapi_sdn_get_dn(dn);
- char *split_type_to_find =
- slapi_ch_smprintf("%s::%s",split_dn, type_to_find);
- if(split_type_to_find)
- {
- ret = vattr_map_lookup(split_type_to_find,&result);
- if (0 == ret) {
- return_list = (vattr_sp_handle_list*) result->sp_list;
- }
- slapi_ch_free((void **)&split_type_to_find);
- }
- }
- }
- return return_list;
- }
- /* Iterator function for the list */
- vattr_sp_handle *vattr_map_sp_next(vattr_sp_handle_list *list, void **hint)
- {
- vattr_sp_handle *result = NULL;
- vattr_sp_handle *current = (vattr_sp_handle*) list;
- PR_ASSERT(list);
- PR_ASSERT(hint);
- result = current->next;
- *hint = current->hint;
- return result;
- }
- /* Iterator function for the list */
- vattr_sp_handle *vattr_map_sp_first(vattr_sp_handle_list *list, void **hint)
- {
- vattr_sp_handle *result = NULL;
- PR_ASSERT(list);
- PR_ASSERT(hint);
- result = (vattr_sp_handle*)list;
- *hint = result->hint;
- return result;
- }
- /* Iterator function for the list */
- vattr_sp_handle *vattr_list_sp_next(vattr_sp_handle_list *list)
- {
- vattr_sp_handle *result = NULL;
- vattr_sp_handle *current = (vattr_sp_handle*) list;
- PR_ASSERT(list);
- result = current->next;
- return result;
- }
- /* Iterator function for the list */
- vattr_sp_handle *vattr_list_sp_first(vattr_sp_handle_list *list)
- {
- vattr_sp_handle *result = NULL;
- PR_ASSERT(list);
- result = (vattr_sp_handle*)list;
- return result;
- }
- /* Function to insert an SP into the map entry for a given type name */
- /* Note that SP's can't ever remmove themselves from the map---if they could
- we'd need to hold a lock on the read path, which we don't want to do.
- So any SP which relinquishes its need to handle a type needs to continue
- to handle the calls on it, but return nothing */
- /* DBDB need to sort out memory ownership here, it's not quite right */
- int vattr_map_sp_insert(char *type_to_add, vattr_sp_handle *sp, void *hint)
- {
- int result = 0;
- vattr_map_entry *map_entry = NULL;
- /* Is this type already there ? */
- result = vattr_map_lookup(type_to_add,&map_entry);
- /* If it is, add this SP to the list, safely even if readers are traversing the list at the same time */
- if (0 == result) {
- int found = 0;
- vattr_sp_handle *list_entry = NULL;
- /* Walk the list checking that the daft SP isn't already here */
- for (list_entry = map_entry->sp_list ; list_entry; list_entry = list_entry->next) {
- if (list_entry == sp) {
- found = 1;
- break;
- }
- }
- /* If it is, we do nothing */
- if(found) {
- return 0;
- }
- /* We insert the SP handle into the linked list at the head */
- sp->next = map_entry->sp_list;
- map_entry->sp_list = sp;
- } else {
- /* If not, add it */
- map_entry = vattr_map_entry_new(type_to_add,sp,hint);
- if (NULL == map_entry) {
- return ENOMEM;
- }
- return vattr_map_insert(map_entry);
- }
- return 0;
- }
- /*
- * returns non-zero if type is a cachable virtual attr, zero otherwise.
- *
- * Decision point for caching vattrs...to be expanded to be configurable,
- * allow sp's to have a say etc.
- */
- static int cache_all = 0;
- int slapi_vattrcache_iscacheable( const char * type ) {
- int rc = 0;
- if(/*cache_all ||*/ !slapi_UTF8CASECMP((char *)type, "nsrole")) {
- rc = 1;
- }
- return(rc);
- }
- /*
- * slapi_vattrcache_cache_all and slapi_vattrcache_cache_none
- * ----------------------------------------------------------
- * limited control for deciding whether to
- * cache anything, in reality controls whether
- * to cache cos attributes right now
- */
- void slapi_vattrcache_cache_all()
- {
- cache_all = -1;
- }
- void slapi_vattrcache_cache_none()
- {
- cache_all = 0;
- }
- Slapi_PBlock *
- slapi_vattr_get_pblock_from_context(vattr_context *c)
- {
- if (c) {
- return c->pb;
- } else {
- return NULL;
- }
- }
- #ifdef VATTR_TEST_CODE
- /* Prototype SP begins here */
- /* Get value function */
- 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)
- {
- Slapi_Value *value = NULL;
- *buffer_flags = 0;
- *actual_type_name = slapi_ch_strdup("dbtestattr");
- value = slapi_value_new_string("Hello Client");
- *results = slapi_ch_calloc(1,sizeof(Slapi_ValueSet));
- slapi_valueset_init(*results);
- slapi_valueset_add_value_ext(*results,value,SLAPI_VALUE_FLAG_PASSIN);
- return 0;
- }
- /* Compare value function */
- 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)
- {
- *result = 0;
- return 0;
- }
- int vattr_basic_sp_list_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags)
- {
- static char* test_type_name = "dbtestattr";
- vattr_type_thang thang = {0};
- thang.type_name = test_type_name;
- thang.type_flags = 0;
- slapi_vattrspi_add_type(type_context,&thang,SLAPI_VIRTUALATTRS_REQUEST_POINTERS);
- return 0;
- }
- int vattr_basic_sp_init()
- {
- int ret = 0;
- vattr_sp_handle *my_handle = NULL;
- /* Register SP */
- ret = slapi_vattrspi_register(&my_handle,vattr_basic_sp_get_value, vattr_basic_sp_compare_value, vattr_basic_sp_list_types);
- if (ret) {
- slapd_nasty(sourcefile,4,0);
- return ret;
- }
- /* Register interest in some attribute over the entire tree */
- ret = slapi_vattrspi_regattr(my_handle,"dbtestattr","", NULL);
- if (ret) {
- slapd_nasty(sourcefile,5,0);
- return ret;
- }
- /* Register interest in some attribute over the entire tree */
- ret = slapi_vattrspi_regattr(my_handle,"dbtestattr1","", NULL);
- if (ret) {
- slapd_nasty(sourcefile,5,0);
- return ret;
- }
- /* Register interest in some attribute over the entire tree */
- ret = slapi_vattrspi_regattr(my_handle,"dbtestattr2","", NULL);
- if (ret) {
- slapd_nasty(sourcefile,5,0);
- return ret;
- }
- /* Register interest in some attribute over the entire tree */
- ret = slapi_vattrspi_regattr(my_handle,"dbtestatt3r","", NULL);
- if (ret) {
- slapd_nasty(sourcefile,5,0);
- return ret;
- }
- return ret;
- }
- /* What do we do on shutdown ? */
- int vattr_basic_sp_cleanup()
- {
- return 0;
- }
- #endif
|