cos_cache.c 102 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688
  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. The cos cache keeps in memory all of
  14. the data related to cos. This allows
  15. very fast lookups at the expense of RAM.
  16. All meta data is indexed, allowing fast
  17. binary search lookups.
  18. The cache is not dynamic, in the sense
  19. that it does not iteratively modify
  20. itself as changes are made to the cos
  21. meta-data. Rather, it is designed to
  22. be fast to read, with non-locking
  23. multiple thread access to the cache,
  24. at the expense of modification speed.
  25. This means that when changes do occur,
  26. the cache must be rebuilt from scratch.
  27. However, this is achieved in such a way,
  28. so as to allow cache queries during the
  29. building of the new cache - so once a
  30. cache has been built, there is no down
  31. time.
  32. Of course, the configuration of the cos meta
  33. data is likely to be a thing which does not
  34. happen often. Any other use, is probably a
  35. mis-use of the mechanism, and certainly will
  36. suffer from performance problems.
  37. */
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include "portable.h"
  42. #include "slapi-plugin.h"
  43. /* this is naughty, but the api for backend state change is currently here */
  44. #include "slapi-private.h"
  45. /* include NSPR header files */
  46. #include "prthread.h"
  47. #include "prlock.h"
  48. #include "prerror.h"
  49. #include "prcvar.h"
  50. #include "prio.h"
  51. #include "vattr_spi.h"
  52. #include "cos_cache.h"
  53. #include "views.h"
  54. static void **views_api;
  55. /*** secret functions and structs in slapd ***/
  56. /*
  57. these are required here because they are not available
  58. in any public header. They must exactly match their
  59. counterparts in the server or they will fail to work
  60. correctly.
  61. */
  62. /*** from slap.h ***/
  63. struct objclass {
  64. char *oc_name; /* NAME */
  65. char *oc_desc; /* DESC */
  66. char *oc_oid; /* object identifier */
  67. char *oc_superior; /* SUP -- XXXmcs: should be an array */
  68. PRUint8 oc_kind; /* ABSTRACT/STRUCTURAL/AUXILIARY */
  69. PRUint8 oc_flags; /* misc. flags, e.g., OBSOLETE */
  70. char **oc_required;
  71. char **oc_allowed;
  72. char **oc_orig_required; /* MUST */
  73. char **oc_orig_allowed; /* MAY */
  74. char **oc_origin; /* X-ORIGIN extension */
  75. struct objclass *oc_next;
  76. };
  77. /*** from proto-slap.h ***/
  78. int config_get_schemacheck(void);
  79. void oc_lock_read( void );
  80. void oc_unlock( void );
  81. struct objclass* g_get_global_oc_nolock(void);
  82. int slapd_log_error_proc( int sev_level, char *subsystem, char *fmt, ... );
  83. /* defined in cos.c */
  84. void * cos_get_plugin_identity(void);
  85. /*** end secrets ***/
  86. #define COS_PLUGIN_SUBSYSTEM "cos-plugin" /* used for logging */
  87. #define COSTYPE_BADTYPE 0
  88. #define COSTYPE_CLASSIC 1
  89. #define COSTYPE_POINTER 2
  90. #define COSTYPE_INDIRECT 3
  91. #define COS_DEF_ERROR_NO_TEMPLATES -2
  92. /* the global plugin handle */
  93. static volatile vattr_sp_handle *vattr_handle = NULL;
  94. /* both variables are protected by change_lock */
  95. static int cos_cache_notify_flag = 0;
  96. static PRBool cos_cache_at_work = PR_FALSE;
  97. /* service definition cache structs */
  98. /* cosIndexedLinkedList: provides an object oriented type interface to
  99. link lists where each element contains an index for the entire
  100. list. All structures that contain this one must specify this one
  101. as the first member otherwise the supporting functions will not work.
  102. {PARPAR} The indexing ability is not currently used since the
  103. fastest lookup is achieved via a cache level index of all attributes,
  104. however this mechanism may prove useful in the future
  105. */
  106. struct _cosIndexedLinkedList
  107. {
  108. void *pNext;
  109. void **index;
  110. };
  111. typedef struct _cosIndexedLinkedList cosIndexedLinkedList;
  112. struct _cosAttrValue
  113. {
  114. cosIndexedLinkedList list;
  115. char *val;
  116. };
  117. typedef struct _cosAttrValue cosAttrValue;
  118. struct _cosAttribute
  119. {
  120. cosIndexedLinkedList list;
  121. char *pAttrName;
  122. cosAttrValue *pAttrValue;
  123. cosAttrValue *pObjectclasses;
  124. int attr_override;
  125. int attr_operational;
  126. int attr_operational_default;
  127. int attr_cos_merge;
  128. void *pParent;
  129. };
  130. typedef struct _cosAttribute cosAttributes;
  131. struct _cosTemplate
  132. {
  133. cosIndexedLinkedList list;
  134. cosAttrValue *pDn;
  135. cosAttrValue *pObjectclasses;
  136. cosAttributes *pAttrs;
  137. char *cosGrade;
  138. int template_default;
  139. void *pParent;
  140. unsigned long cosPriority;
  141. };
  142. typedef struct _cosTemplate cosTemplates;
  143. struct _cosDefinition
  144. {
  145. cosIndexedLinkedList list;
  146. int cosType;
  147. cosAttrValue *pDn;
  148. cosAttrValue *pCosTargetTree;
  149. cosAttrValue *pCosTemplateDn;
  150. cosAttrValue *pCosSpecifier;
  151. cosAttrValue *pCosAttrs;
  152. cosAttrValue *pCosOverrides;
  153. cosAttrValue *pCosOperational;
  154. cosAttrValue *pCosOpDefault;
  155. cosAttrValue *pCosMerge;
  156. cosTemplates *pCosTmps;
  157. };
  158. typedef struct _cosDefinition cosDefinitions;
  159. struct _cos_cache
  160. {
  161. cosDefinitions *pDefs;
  162. cosAttributes **ppAttrIndex;
  163. int attrCount;
  164. char **ppTemplateList;
  165. int templateCount;
  166. int refCount;
  167. int vattr_cacheable;
  168. };
  169. typedef struct _cos_cache cosCache;
  170. /* cache manipulation function prototypes*/
  171. static cosCache *pCache; /* always the current global cache, only use getref to get */
  172. /* the place to start if you want a new cache */
  173. static int cos_cache_create_unlock(void);
  174. static int cos_cache_creation_lock(void);
  175. /* cache index related functions */
  176. static int cos_cache_index_all(cosCache *pCache);
  177. static int cos_cache_attr_compare(const void *e1, const void *e2);
  178. static int cos_cache_template_index_compare(const void *e1, const void *e2);
  179. static int cos_cache_string_compare(const void *e1, const void *e2);
  180. static int cos_cache_template_index_bsearch(const char *dn);
  181. static int cos_cache_attr_index_bsearch( const cosCache *pCache, const cosAttributes *key, int lower, int upper );
  182. /* the multi purpose list creation function, pass it something and it links it */
  183. static void cos_cache_add_ll_entry(void **attrval, void *theVal, int ( *compare )(const void *elem1, const void *elem2 ));
  184. /* cosAttrValue manipulation */
  185. static int cos_cache_add_attrval(cosAttrValue **attrval, char *val);
  186. static void cos_cache_del_attrval_list(cosAttrValue **pVal);
  187. static int cos_cache_attrval_exists(cosAttrValue *pAttrs, const char *val);
  188. /* cosAttributes manipulation */
  189. static int cos_cache_add_attr(cosAttributes **pAttrs, char *name, cosAttrValue *val);
  190. static void cos_cache_del_attr_list(cosAttributes **pAttrs);
  191. static int cos_cache_find_attr(cosCache *pCache, char *type);
  192. static int cos_cache_total_attr_count(cosCache *pCache);
  193. static int cos_cache_cos_2_slapi_valueset(cosAttributes *pAttr, Slapi_ValueSet **out_vs);
  194. static int cos_cache_cmp_attr(cosAttributes *pAttr, Slapi_Value *test_this, int *result);
  195. /* cosTemplates manipulation */
  196. static int cos_cache_add_dn_tmpls(char *dn, cosAttrValue *pCosSpecifier, cosAttrValue *pAttrs, cosTemplates **pTmpls);
  197. static int cos_cache_add_tmpl(cosTemplates **pTemplates, cosAttrValue *dn, cosAttrValue *objclasses, cosAttrValue *pCosSpecifier, cosAttributes *pAttrs,cosAttrValue *cosPriority);
  198. /* cosDefinitions manipulation */
  199. static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_cacheable);
  200. static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs);
  201. static int cos_cache_add_defn(cosDefinitions **pDefs, cosAttrValue **dn, int cosType, cosAttrValue **tree, cosAttrValue **tmpDn, cosAttrValue **spec, cosAttrValue **pAttrs, cosAttrValue **pOverrides, cosAttrValue **pOperational, cosAttrValue **pCosMerge, cosAttrValue **pCosOpDefault);
  202. static int cos_cache_entry_is_cos_related( Slapi_Entry *e);
  203. /* schema checking */
  204. static int cos_cache_schema_check(cosCache *pCache, int cache_attr_index, Slapi_Attr *pObjclasses);
  205. static int cos_cache_schema_build(cosCache *pCache);
  206. static void cos_cache_del_schema(cosCache *pCache);
  207. /* special cos scheme implimentations (special = other than cos classic) */
  208. static int cos_cache_follow_pointer( vattr_context *context, const char *dn, char *type, Slapi_ValueSet **out_vs, Slapi_Value *test_this, int *result, int flags );
  209. /* this dude is the thread function which performs dynamic config of the cache */
  210. static void cos_cache_wait_on_change(void *arg);
  211. /* this gets called when a backend changes state */
  212. void cos_cache_backend_state_change(void *handle, char *be_name,
  213. int old_be_state, int new_be_state);
  214. /* operation callbacks for vattr service */
  215. static int cos_cache_vattr_get(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 *free_flags, void *hint);
  216. static int cos_cache_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result, int flags, void *hint);
  217. static int cos_cache_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags);
  218. static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, Slapi_Value *test_this, int *result, int *ops, int *indirect_cos);
  219. /*
  220. compares s2 to s1 starting from end of string until the beginning of either
  221. matches result in the s2 value being clipped from s1 with a NULL char
  222. and 1 being returned as opposed to 0
  223. */
  224. static int cos_cache_backwards_stricmp_and_clip(char*s1,char*s2);
  225. /* module level thread control stuff */
  226. static int keeprunning = 0;
  227. static int started = 0;
  228. static Slapi_Mutex *cache_lock;
  229. static Slapi_Mutex *change_lock;
  230. static Slapi_Mutex *start_lock;
  231. static Slapi_Mutex *stop_lock;
  232. static Slapi_CondVar *something_changed = NULL;
  233. static Slapi_CondVar *start_cond = NULL;
  234. /*
  235. cos_cache_init
  236. --------------
  237. starts up the thread which waits for changes and
  238. fires off the cache re-creation when one is detected
  239. also registers vattr callbacks
  240. */
  241. int cos_cache_init(void)
  242. {
  243. int ret = 0;
  244. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_init\n");
  245. slapi_vattrcache_cache_none();
  246. cache_lock = slapi_new_mutex();
  247. change_lock = slapi_new_mutex();
  248. stop_lock = slapi_new_mutex();
  249. something_changed = slapi_new_condvar(change_lock);
  250. keeprunning =1;
  251. start_lock = slapi_new_mutex();
  252. start_cond = slapi_new_condvar(start_lock);
  253. started = 0;
  254. if (stop_lock == NULL ||
  255. change_lock == NULL ||
  256. cache_lock == NULL ||
  257. stop_lock == NULL ||
  258. start_lock == NULL ||
  259. start_cond == NULL ||
  260. something_changed == NULL)
  261. {
  262. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM,
  263. "cos_cache_init - Cannot create mutexes\n" );
  264. ret = -1;
  265. goto out;
  266. }
  267. /* grab the views interface */
  268. if(slapi_apib_get_interface(Views_v1_0_GUID, &views_api))
  269. {
  270. /* lets be tolerant if views is disabled */
  271. views_api = 0;
  272. }
  273. if (slapi_vattrspi_register((vattr_sp_handle **)&vattr_handle,
  274. cos_cache_vattr_get,
  275. cos_cache_vattr_compare,
  276. cos_cache_vattr_types) != 0)
  277. {
  278. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM,
  279. "cos_cache_init - Cannot register as service provider\n" );
  280. ret = -1;
  281. goto out;
  282. }
  283. if ( PR_CreateThread (PR_USER_THREAD,
  284. cos_cache_wait_on_change,
  285. NULL,
  286. PR_PRIORITY_NORMAL,
  287. PR_GLOBAL_THREAD,
  288. PR_UNJOINABLE_THREAD,
  289. SLAPD_DEFAULT_THREAD_STACKSIZE) == NULL )
  290. {
  291. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM,
  292. "cos_cache_init - PR_CreateThread failed\n" );
  293. ret = -1;
  294. goto out;
  295. }
  296. /* wait for that thread to get started */
  297. if (ret == 0) {
  298. slapi_lock_mutex(start_lock);
  299. while (!started) {
  300. while (slapi_wait_condvar(start_cond, NULL) == 0);
  301. }
  302. slapi_unlock_mutex(start_lock);
  303. }
  304. out:
  305. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_init\n");
  306. return ret;
  307. }
  308. /*
  309. cos_cache_wait_on_change
  310. ------------------------
  311. sit around waiting on a notification that something has
  312. changed, then fires off the cache re-creation
  313. The way this stuff is written, we can look for the
  314. template for a definiton, before the template has been added--I think
  315. that's OK--we'll see it when it arrives--get this error message:
  316. "skipping cos definition cn=cosPointerGenerateSt,ou=People,o=cosAll--no templates found"
  317. */
  318. static void cos_cache_wait_on_change(void *arg __attribute__((unused)))
  319. {
  320. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_wait_on_change thread\n");
  321. slapi_lock_mutex(stop_lock);
  322. slapi_lock_mutex(change_lock);
  323. /* first register our backend state change func (we'll use func pointer as handle) */
  324. slapi_register_backend_state_change((void *)cos_cache_backend_state_change, cos_cache_backend_state_change);
  325. pCache = 0;
  326. /* create initial cache */
  327. cos_cache_creation_lock();
  328. slapi_lock_mutex(start_lock);
  329. started = 1;
  330. slapi_notify_condvar(start_cond, 1);
  331. slapi_unlock_mutex(start_lock);
  332. while(keeprunning)
  333. {
  334. slapi_unlock_mutex(change_lock);
  335. slapi_lock_mutex(change_lock);
  336. if ( !cos_cache_notify_flag && keeprunning) {
  337. /*
  338. * Nothing to do right now, so go to sleep--as
  339. * we have the mutex, we are sure to wait before any modify
  340. * thread notifies our condvar, and so we will not miss any
  341. * notifications, including the shutdown notification.
  342. */
  343. slapi_wait_condvar( something_changed, NULL );
  344. } else {
  345. /* Something to do...do it below */
  346. }
  347. /*
  348. * We're here because:
  349. * 1. we were asleep and got a signal, on our condvar OR
  350. * 2. we were about to wait on the condvar and noticed that a modfiy
  351. * thread
  352. * had passed, setting the cos_cache_notify_flag and notifying us--
  353. * we did not wait in that case as we would have missed the notify
  354. * (notify when noone is waiting == no-op).
  355. * before we go running off doing lots of stuff lets check if we should stop
  356. */
  357. if(keeprunning) {
  358. cos_cache_creation_lock();
  359. }
  360. cos_cache_notify_flag = 0; /* Dealt with it */
  361. }/* while */
  362. /* shut down the cache */
  363. slapi_unlock_mutex(change_lock);
  364. slapi_unlock_mutex(stop_lock);
  365. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_wait_on_change thread exit\n");
  366. }
  367. /*
  368. cos_cache_create_unlock
  369. ---------------------
  370. Walks the definitions in the DIT and creates the cache.
  371. Once created, it swaps the new cache for the old one,
  372. releasing its refcount to the old cache and allowing it
  373. to be destroyed.
  374. called while change_lock is NOT held
  375. */
  376. static int cos_cache_create_unlock(void)
  377. {
  378. int ret = -1;
  379. cosCache *pNewCache;
  380. static int firstTime = 1;
  381. int cache_built = 0;
  382. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_create_unlock\n");
  383. pNewCache = (cosCache*)slapi_ch_malloc(sizeof(cosCache));
  384. if(pNewCache)
  385. {
  386. pNewCache->pDefs = 0;
  387. pNewCache->refCount = 1; /* 1 is for us */
  388. pNewCache->vattr_cacheable = 0; /* default is not cacheable */
  389. ret = cos_cache_build_definition_list(&(pNewCache->pDefs), &(pNewCache->vattr_cacheable));
  390. if(!ret)
  391. {
  392. /* OK, we have a cache, lets add indexing for
  393. that faster than slow feeling */
  394. ret = cos_cache_index_all(pNewCache);
  395. if(ret == 0)
  396. {
  397. /* right, indexed cache, lets do our duty for the schema */
  398. ret = cos_cache_schema_build(pNewCache);
  399. if(ret == 0)
  400. {
  401. /* now to swap the new cache for the old cache */
  402. cosCache *pOldCache;
  403. slapi_lock_mutex(cache_lock);
  404. /* turn off caching until the old cache is done */
  405. if(pCache)
  406. {
  407. slapi_vattrcache_cache_none();
  408. /*
  409. * be sure not to uncache other stuff
  410. * like roles if there is no change in
  411. * state
  412. */
  413. if(pCache->vattr_cacheable)
  414. slapi_entrycache_vattrcache_watermark_invalidate();
  415. }
  416. else
  417. {
  418. if(pNewCache && pNewCache->vattr_cacheable)
  419. {
  420. slapi_vattrcache_cache_all();
  421. }
  422. }
  423. pOldCache = pCache;
  424. pCache = pNewCache;
  425. slapi_unlock_mutex(cache_lock);
  426. if(pOldCache)
  427. cos_cache_release(pOldCache);
  428. cache_built = 1;
  429. }
  430. else
  431. {
  432. /* we should not go on without proper schema checking */
  433. cos_cache_release(pNewCache);
  434. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_create_unlock - Failed to cache the schema\n");
  435. }
  436. }
  437. else
  438. {
  439. /* currently we cannot go on without the indexes */
  440. cos_cache_release(pNewCache);
  441. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_create_unlock - Failed to index cache\n");
  442. }
  443. }
  444. else
  445. {
  446. if(firstTime)
  447. {
  448. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_create_unlock - cos disabled\n");
  449. firstTime = 0;
  450. }
  451. slapi_ch_free((void**)&pNewCache);
  452. }
  453. }
  454. else
  455. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_create_unlock - Memory allocation failure\n");
  456. /* make sure we have a new cache */
  457. if(!cache_built)
  458. {
  459. /* we do not have a new cache, must make sure the old cache is destroyed */
  460. cosCache *pOldCache;
  461. slapi_lock_mutex(cache_lock);
  462. slapi_vattrcache_cache_none();
  463. /*
  464. * be sure not to uncache other stuff
  465. * like roles if there is no change in
  466. * state
  467. */
  468. if(pCache && pCache->vattr_cacheable)
  469. slapi_entrycache_vattrcache_watermark_invalidate();
  470. pOldCache = pCache;
  471. pCache = NULL;
  472. slapi_unlock_mutex(cache_lock);
  473. if(pOldCache)
  474. cos_cache_release(pOldCache); /* release our reference to the old cache */
  475. }
  476. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_create_unlock\n");
  477. return ret;
  478. }
  479. /* cos_cache_creation_lock is called with change_lock being hold:
  480. * slapi_lock_mutex(change_lock)
  481. *
  482. * To rebuild the cache cos_cache_creation gets cos definitions from backend, that
  483. * means change_lock is held then cos_cache_creation will acquire some backend pages.
  484. *
  485. * A deadlock can happen if cos_post_op is called while backend is locked.
  486. * For example if a bepreop (urp) does an internal update on a cos definition,
  487. * the thread holds backend pages that will be needed by cos_cache_creation.
  488. *
  489. * A solution is to use a flag 'cos_cache_at_work' protected by change_lock,
  490. * release change_lock, recreate the cos_cache, acquire change_lock reset the flag.
  491. *
  492. * returned value: result of cos_cache_create_unlock
  493. *
  494. */
  495. static int cos_cache_creation_lock(void)
  496. {
  497. int ret = -1;
  498. int max_tries = 10;
  499. for (; max_tries != 0; max_tries--) {
  500. /* if the cos_cache is already under work (cos_cache_create_unlock)
  501. * wait 1 second
  502. */
  503. if (cos_cache_at_work) {
  504. slapi_log_err(SLAPI_LOG_FATAL, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_creation_lock already rebuilding cos_cache... retry\n");
  505. DS_Sleep (PR_MillisecondsToInterval(1000));
  506. continue;
  507. }
  508. cos_cache_at_work = PR_TRUE;
  509. slapi_unlock_mutex(change_lock);
  510. ret = cos_cache_create_unlock();
  511. slapi_lock_mutex(change_lock);
  512. cos_cache_at_work = PR_FALSE;
  513. break;
  514. }
  515. if (!max_tries) {
  516. slapi_log_err(SLAPI_LOG_FATAL, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_creation_lock rebuilt was to long, skip this rebuild\n");
  517. }
  518. return ret;
  519. }
  520. /*
  521. cos_cache_build_definition_list
  522. -------------------------------
  523. builds the list of cos definitions by searching for them throughout the DIT
  524. */
  525. static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_cacheable)
  526. {
  527. int ret = 0;
  528. Slapi_PBlock *pSuffixSearch = 0;
  529. Slapi_Entry **pSuffixList = 0;
  530. Slapi_Attr *suffixAttr;
  531. struct berval **suffixVals;
  532. char *attrType = 0;
  533. char *attrs[2];
  534. int suffixIndex = 0;
  535. int valIndex = 0;
  536. int cos_def_available = 0;
  537. static int firstTime = 1;
  538. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_build_definition_list\n");
  539. /*
  540. * The class of service definitions may be anywhere in the DIT,
  541. * so our first task is to find them.
  542. */
  543. attrs[0] = "namingcontexts";
  544. attrs[1] = 0;
  545. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_build_definition_list - "
  546. "Building class of service cache after status change.\n");
  547. /*
  548. * XXXrbyrne: this looks really inefficient--should be using
  549. * slapi_get_next_suffix(), rather than searching for namingcontexts.
  550. */
  551. pSuffixSearch = slapi_search_internal("",LDAP_SCOPE_BASE,"(objectclass=*)",NULL,attrs,0);
  552. if(pSuffixSearch)
  553. slapi_pblock_get( pSuffixSearch, SLAPI_PLUGIN_INTOP_RESULT, &ret);
  554. if(!pSuffixSearch || ret != LDAP_SUCCESS) {
  555. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM,
  556. "cos_cache_build_definition_list - Failed to find suffixes\n");
  557. ret = -1;
  558. goto next;
  559. }
  560. /* iterate through the suffixes and search for cos definitions */
  561. slapi_pblock_get( pSuffixSearch, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  562. &pSuffixList );
  563. if(!pSuffixList) {
  564. goto next;
  565. }
  566. while(pSuffixList[suffixIndex])
  567. {
  568. if(!slapi_entry_first_attr(pSuffixList[suffixIndex], &suffixAttr))
  569. {
  570. do
  571. {
  572. attrType = 0;
  573. slapi_attr_get_type(suffixAttr, &attrType);
  574. if(attrType && !slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"namingcontexts"))
  575. {
  576. if(!slapi_attr_get_bervals_copy(suffixAttr, &suffixVals))
  577. {
  578. valIndex = 0;
  579. if(suffixVals)
  580. {
  581. while(suffixVals[valIndex])
  582. {
  583. /* here's a suffix, lets search it... */
  584. if(suffixVals[valIndex]->bv_val)
  585. {
  586. if(!cos_cache_add_dn_defs(suffixVals[valIndex]->bv_val ,pDefs))
  587. {
  588. *vattr_cacheable = -1;
  589. cos_def_available = 1;
  590. }
  591. }
  592. valIndex++;
  593. }
  594. ber_bvecfree( suffixVals );
  595. suffixVals = NULL;
  596. }
  597. }
  598. }
  599. } while(!slapi_entry_next_attr(pSuffixList[suffixIndex], suffixAttr, &suffixAttr));
  600. }
  601. suffixIndex++;
  602. }
  603. next:
  604. if(cos_def_available == 0)
  605. {
  606. if(firstTime)
  607. {
  608. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_build_definition_list - "
  609. "Found no cos definitions, cos disabled while waiting for updates\n");
  610. firstTime = 0;
  611. }
  612. ret = -1;
  613. }
  614. else
  615. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_build_definition_list - "
  616. "Class of service cache built.\n");
  617. /* clean up */
  618. if(pSuffixSearch)
  619. {
  620. slapi_free_search_results_internal(pSuffixSearch);
  621. slapi_pblock_destroy(pSuffixSearch);
  622. }
  623. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_build_definition_list\n");
  624. return ret;
  625. }
  626. /* struct to support search callback API */
  627. struct dn_defs_info {
  628. cosDefinitions **pDefs;
  629. int vattr_cacheable;
  630. int ret;
  631. };
  632. /*
  633. * Currently, always returns 0 to continue the search for definitions, even
  634. * if a particular attempt to add a definition fails: info.ret gets set to
  635. * zero only if we succeed to add a def.
  636. */
  637. static int
  638. cos_dn_defs_cb (Slapi_Entry* e, void *callback_data)
  639. {
  640. struct dn_defs_info *info;
  641. cosAttrValue **pSneakyVal = 0;
  642. cosAttrValue *pObjectclass = 0;
  643. cosAttrValue *pCosTargetTree = 0;
  644. cosAttrValue *pCosTemplateDn = 0;
  645. cosAttrValue *pCosSpecifier = 0;
  646. cosAttrValue *pCosAttribute = 0;
  647. cosAttrValue *pCosOverrides = 0;
  648. cosAttrValue *pCosOperational = 0;
  649. cosAttrValue *pCosOpDefault = 0;
  650. cosAttrValue *pCosMerge = 0;
  651. cosAttrValue *pDn = 0;
  652. struct berval **dnVals;
  653. int cosType = 0;
  654. int valIndex = 0;
  655. Slapi_Attr *dnAttr;
  656. char *attrType = 0;
  657. char *norm_dn = NULL;
  658. info=(struct dn_defs_info *)callback_data;
  659. cos_cache_add_attrval(&pDn, slapi_entry_get_dn(e));
  660. if(slapi_entry_first_attr(e, &dnAttr)) {
  661. goto bail;
  662. }
  663. do {
  664. attrType = 0;
  665. /* we need to fill in the details of the definition now */
  666. slapi_attr_get_type(dnAttr, &attrType);
  667. if(!attrType) {
  668. continue;
  669. }
  670. pSneakyVal = 0;
  671. if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"objectclass"))
  672. pSneakyVal = &pObjectclass;
  673. else if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"cosTargetTree")){
  674. if(pCosTargetTree){
  675. norm_dn = slapi_create_dn_string("%s", pCosTargetTree->val);
  676. if(norm_dn){
  677. slapi_ch_free_string(&pCosTargetTree->val);
  678. pCosTargetTree->val = norm_dn;
  679. }
  680. }
  681. pSneakyVal = &pCosTargetTree;
  682. } else if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"cosTemplateDn"))
  683. pSneakyVal = &pCosTemplateDn;
  684. else if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"cosSpecifier"))
  685. pSneakyVal = &pCosSpecifier;
  686. else if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"cosAttribute"))
  687. pSneakyVal = &pCosAttribute;
  688. else if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"cosIndirectSpecifier"))
  689. pSneakyVal = &pCosSpecifier;
  690. if(!pSneakyVal) {
  691. continue;
  692. }
  693. /* It's a type we're interested in */
  694. if(slapi_attr_get_bervals_copy(dnAttr, &dnVals)) {
  695. continue;
  696. }
  697. valIndex = 0;
  698. if(!dnVals) {
  699. continue;
  700. }
  701. for (valIndex = 0; dnVals[valIndex]; valIndex++)
  702. {
  703. if(!dnVals[valIndex]->bv_val) {
  704. continue;
  705. }
  706. /*
  707. parse any overide or default values
  708. and deal with them
  709. */
  710. if(pSneakyVal == &pCosAttribute)
  711. {
  712. int qualifier_hit = 0;
  713. int op_qualifier_hit = 0;
  714. int merge_schemes_qualifier_hit = 0;
  715. int override_qualifier_hit =0;
  716. int default_qualifier_hit = 0;
  717. int operational_default_qualifier_hit = 0;
  718. do
  719. {
  720. qualifier_hit = 0;
  721. if(cos_cache_backwards_stricmp_and_clip(dnVals[valIndex]->bv_val, " operational"))
  722. {
  723. /* matched */
  724. op_qualifier_hit = 1;
  725. qualifier_hit = 1;
  726. }
  727. if(cos_cache_backwards_stricmp_and_clip(dnVals[valIndex]->bv_val, " merge-schemes"))
  728. {
  729. /* matched */
  730. merge_schemes_qualifier_hit = 1;
  731. qualifier_hit = 1;
  732. }
  733. if(cos_cache_backwards_stricmp_and_clip(dnVals[valIndex]->bv_val, " override"))
  734. {
  735. /* matched */
  736. override_qualifier_hit = 1;
  737. qualifier_hit = 1;
  738. }
  739. if(cos_cache_backwards_stricmp_and_clip(dnVals[valIndex]->bv_val, " default")) {
  740. default_qualifier_hit = 1;
  741. qualifier_hit = 1;
  742. }
  743. if(cos_cache_backwards_stricmp_and_clip(dnVals[valIndex]->bv_val, " operational-default")) {
  744. operational_default_qualifier_hit = 1;
  745. qualifier_hit = 1;
  746. }
  747. }
  748. while(qualifier_hit == 1);
  749. /*
  750. * At this point, dnVals[valIndex]->bv_val
  751. * is the value of cosAttribute, stripped of
  752. * any qualifiers, so add this pure attribute type to
  753. * the appropriate lists.
  754. */
  755. if ( op_qualifier_hit ) {
  756. cos_cache_add_attrval(&pCosOperational,
  757. dnVals[valIndex]->bv_val);
  758. }
  759. if ( merge_schemes_qualifier_hit ) {
  760. cos_cache_add_attrval(&pCosMerge, dnVals[valIndex]->bv_val);
  761. }
  762. if ( override_qualifier_hit ) {
  763. cos_cache_add_attrval(&pCosOverrides,
  764. dnVals[valIndex]->bv_val);
  765. }
  766. if ( default_qualifier_hit ) {
  767. /* attr is added below in pSneakyVal, in any case */
  768. }
  769. if ( operational_default_qualifier_hit ) {
  770. cos_cache_add_attrval(&pCosOpDefault,
  771. dnVals[valIndex]->bv_val);
  772. }
  773. slapi_vattrspi_regattr((vattr_sp_handle *)vattr_handle,
  774. dnVals[valIndex]->bv_val, NULL, NULL);
  775. } /* if(attrType is cosAttribute) */
  776. /*
  777. * Add the attributetype to the appropriate
  778. * list.
  779. */
  780. cos_cache_add_attrval(pSneakyVal, dnVals[valIndex]->bv_val);
  781. }/* for (valIndex = 0; dnVals[valIndex]; valIndex++) */
  782. ber_bvecfree( dnVals );
  783. dnVals = NULL;
  784. } while(!slapi_entry_next_attr(e, dnAttr, &dnAttr));
  785. if (pCosAttribute && (!pCosTargetTree || !pCosTemplateDn)) {
  786. /* get the parent of the definition */
  787. char *orig = slapi_dn_parent(pDn->val);
  788. char *parent = NULL;
  789. if (orig) {
  790. parent = slapi_create_dn_string("%s", orig);
  791. if (!parent) {
  792. parent = orig;
  793. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM,
  794. "cos_dn_defs_cb - "
  795. "Failed to normalize parent dn %s. "
  796. "Adding the pre normalized dn.\n",
  797. parent);
  798. }
  799. if (!pCosTargetTree) {
  800. cos_cache_add_attrval(&pCosTargetTree, parent);
  801. }
  802. if (!pCosTemplateDn) {
  803. cos_cache_add_attrval(&pCosTemplateDn, parent);
  804. }
  805. if (parent != orig) {
  806. slapi_ch_free_string(&parent);
  807. }
  808. slapi_ch_free_string(&orig);
  809. } else {
  810. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM,
  811. "cos_dn_defs_cb - "
  812. "Failed to get parent dn of cos definition %s.\n",
  813. pDn->val);
  814. if (!pCosTemplateDn) {
  815. if (!pCosTargetTree) {
  816. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_dn_defs_cb - cosTargetTree and cosTemplateDn are not set.\n");
  817. } else {
  818. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_dn_defs_cb - cosTemplateDn is not set.\n");
  819. }
  820. } else if (!pCosTargetTree) {
  821. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_dn_defs_cb - cosTargetTree is not set.\n");
  822. }
  823. }
  824. }
  825. /*
  826. determine the type of class of service scheme
  827. */
  828. if(pObjectclass)
  829. {
  830. if(cos_cache_attrval_exists(pObjectclass, "cosDefinition"))
  831. {
  832. cosType = COSTYPE_CLASSIC;
  833. }
  834. else if(cos_cache_attrval_exists(pObjectclass, "cosClassicDefinition"))
  835. {
  836. cosType = COSTYPE_CLASSIC;
  837. }
  838. else if(cos_cache_attrval_exists(pObjectclass, "cosPointerDefinition"))
  839. {
  840. cosType = COSTYPE_POINTER;
  841. }
  842. else if(cos_cache_attrval_exists(pObjectclass, "cosIndirectDefinition"))
  843. {
  844. cosType = COSTYPE_INDIRECT;
  845. }
  846. else
  847. cosType = COSTYPE_BADTYPE;
  848. }
  849. /*
  850. we should now have a full definition,
  851. do some sanity checks because we don't
  852. want bogus entries in the cache
  853. then ship it
  854. */
  855. /* these must exist */
  856. if(pDn && pObjectclass &&
  857. (
  858. (cosType == COSTYPE_CLASSIC &&
  859. pCosTemplateDn &&
  860. pCosSpecifier &&
  861. pCosAttribute )
  862. ||
  863. (cosType == COSTYPE_POINTER &&
  864. pCosTemplateDn &&
  865. pCosAttribute )
  866. ||
  867. (cosType == COSTYPE_INDIRECT &&
  868. pCosSpecifier &&
  869. pCosAttribute )
  870. )
  871. )
  872. {
  873. int rc = 0;
  874. /*
  875. we'll leave the referential integrity stuff
  876. up to the referint plug-in and assume all
  877. is good - if it's not then we just have a
  878. useless definition and we'll nag copiously later.
  879. */
  880. char *pTmpDn = slapi_ch_strdup(pDn->val); /* because dn gets hosed on error */
  881. if(!(rc = cos_cache_add_defn(info->pDefs, &pDn, cosType,
  882. &pCosTargetTree, &pCosTemplateDn,
  883. &pCosSpecifier, &pCosAttribute,
  884. &pCosOverrides, &pCosOperational,
  885. &pCosMerge, &pCosOpDefault))) {
  886. info->ret = 0; /* we have succeeded to add the defn*/
  887. } else {
  888. /*
  889. * Failed but we will continue the search for other defs
  890. * Don't reset info->ret....it keeps track of any success
  891. */
  892. if ( rc == COS_DEF_ERROR_NO_TEMPLATES) {
  893. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_dn_defs_cb - Skipping CoS Definition %s"
  894. "--no CoS Templates found, which should be added before the CoS Definition.\n",
  895. pTmpDn);
  896. } else {
  897. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_dn_defs_cb - Skipping CoS Definition %s\n"
  898. "--error(%d)\n",
  899. pTmpDn, rc);
  900. }
  901. }
  902. slapi_ch_free_string(&pTmpDn);
  903. }
  904. else
  905. {
  906. /*
  907. this definition is brain dead - bail
  908. if we have a dn use it to report, if not then *really* bad
  909. things are going on
  910. */
  911. if(pDn)
  912. {
  913. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_dn_defs_cb - "
  914. "Incomplete cos definition detected in %s, discarding from cache.\n",pDn->val);
  915. }
  916. else
  917. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_dn_defs_cb - "
  918. "Incomplete cos definition detected, no DN to report, discarding from cache.\n");
  919. if(pCosTargetTree)
  920. cos_cache_del_attrval_list(&pCosTargetTree);
  921. if(pCosTemplateDn)
  922. cos_cache_del_attrval_list(&pCosTemplateDn);
  923. if(pCosSpecifier)
  924. cos_cache_del_attrval_list(&pCosSpecifier);
  925. if(pCosAttribute)
  926. cos_cache_del_attrval_list(&pCosAttribute);
  927. if(pDn)
  928. cos_cache_del_attrval_list(&pDn);
  929. }
  930. bail:
  931. /* we don't keep the objectclasses, so lets free them */
  932. if(pObjectclass) {
  933. cos_cache_del_attrval_list(&pObjectclass);
  934. }
  935. /* This particular definition may not have yielded anything
  936. * worth caching (eg. no template was found for it) but
  937. * that should not cause us to abort the search for other more well behaved
  938. * definitions unless we are shutting down.
  939. * return info->ret;
  940. */
  941. return slapi_is_shutting_down();
  942. }
  943. /*
  944. cos_cache_add_dn_defs
  945. -------------------------
  946. takes a dn as argument and searches the dn for cos definitions,
  947. adding any found to the definition list. Change to use search callback API.
  948. Returns: 0: found at least one definition entry that got added to the
  949. cache successfully.
  950. non-zero: added no cos defs to the cache.
  951. */
  952. #define DN_DEF_FILTER "(&(|(objectclass=cosSuperDefinition)(objectclass=cosDefinition))(objectclass=ldapsubentry))"
  953. static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs)
  954. {
  955. Slapi_PBlock *pDnSearch = 0;
  956. struct dn_defs_info info = {NULL, 0, 0};
  957. pDnSearch = slapi_pblock_new();
  958. if (pDnSearch) {
  959. info.ret=-1; /* assume no good defs */
  960. info.pDefs=pDefs;
  961. slapi_search_internal_set_pb(pDnSearch, dn, LDAP_SCOPE_SUBTREE,
  962. DN_DEF_FILTER,NULL,0,
  963. NULL,NULL,cos_get_plugin_identity(),0);
  964. slapi_search_internal_callback_pb(pDnSearch,
  965. &info /* callback_data */,
  966. NULL/* result_callback */,
  967. cos_dn_defs_cb,
  968. NULL /* referral_callback */);
  969. slapi_pblock_destroy (pDnSearch);
  970. }
  971. return info.ret;
  972. }
  973. /* struct to support call back API */
  974. struct tmpl_info {
  975. cosAttrValue *pCosSpecifier;
  976. cosAttrValue *pAttrs;
  977. cosTemplates **pTmpls;
  978. int ret;
  979. };
  980. /*
  981. * Currently, always returns 0 to continue the search for templates, even
  982. * if a particular attempt to add a template fails: info.ret gets set to
  983. * zero only if we succeed to add at least one tmpl.
  984. */
  985. static int cos_dn_tmpl_entries_cb (Slapi_Entry* e, void *callback_data) {
  986. cosAttrValue *pDn = 0;
  987. cosAttrValue *pCosPriority = 0;
  988. cosAttributes *pAttributes = 0;
  989. cosAttrValue *pObjectclass = 0;
  990. cosAttrValue *pCosAttribute = 0;
  991. Slapi_Attr *dnAttr;
  992. struct berval **dnVals;
  993. int itsAnAttr = 0;
  994. int valIndex = 0;
  995. cosAttrValue **pSneakyVal = 0;
  996. char *attrType = 0;
  997. struct tmpl_info *info;
  998. info = (struct tmpl_info *)callback_data;
  999. pDn = 0;
  1000. cos_cache_add_attrval(&pDn, slapi_entry_get_dn(e));
  1001. pAttributes = 0;
  1002. pObjectclass = 0;
  1003. pCosPriority = 0;
  1004. if(!slapi_entry_first_attr(e, &dnAttr))
  1005. {
  1006. int attrs_present = 0;
  1007. do
  1008. {
  1009. attrType = 0;
  1010. pCosAttribute = 0;
  1011. /* we need to fill in the details of the template now */
  1012. slapi_attr_get_type(dnAttr, &attrType);
  1013. if(attrType)
  1014. {
  1015. itsAnAttr = 0;
  1016. pSneakyVal = 0;
  1017. if(!slapi_utf8casecmp((unsigned char*)attrType,
  1018. (unsigned char*)"objectclass"))
  1019. pSneakyVal = &pObjectclass;
  1020. if(!slapi_utf8casecmp((unsigned char*)attrType,
  1021. (unsigned char*)"cosPriority"))
  1022. pSneakyVal = &pCosPriority;
  1023. if(pSneakyVal == NULL)
  1024. {
  1025. /* look for the attribute in the dynamic attributes */
  1026. if(cos_cache_attrval_exists(info->pAttrs, attrType))
  1027. {
  1028. pSneakyVal = &pCosAttribute;
  1029. itsAnAttr = 1;
  1030. attrs_present = 1;
  1031. }
  1032. }
  1033. if(pSneakyVal)
  1034. {
  1035. if(!slapi_attr_get_bervals_copy(dnAttr, &dnVals))
  1036. {
  1037. valIndex = 0;
  1038. if(dnVals)
  1039. {
  1040. while(dnVals[valIndex])
  1041. {
  1042. if(dnVals[valIndex]->bv_val)
  1043. cos_cache_add_attrval(pSneakyVal,
  1044. dnVals[valIndex]->bv_val);
  1045. valIndex++;
  1046. }
  1047. if(itsAnAttr)
  1048. {
  1049. /* got all vals, add this attribute to the attribute list */
  1050. cos_cache_add_attr(&pAttributes, attrType,
  1051. *pSneakyVal);
  1052. }
  1053. ber_bvecfree( dnVals );
  1054. dnVals = NULL;
  1055. }
  1056. }
  1057. }
  1058. }
  1059. } while(!slapi_entry_next_attr(e, dnAttr, &dnAttr));
  1060. /*
  1061. we should now have a full template,
  1062. do some sanity checks because we don't
  1063. want bogus entries in the cache if we can help it
  1064. - then ship it
  1065. */
  1066. /* these must exist */
  1067. if(
  1068. attrs_present &&
  1069. pObjectclass &&
  1070. pAttributes &&
  1071. pDn
  1072. )
  1073. {
  1074. /*
  1075. we'll leave the referential integrity stuff
  1076. up to the referint plug-in if set up and assume all
  1077. is good - if it's not then we just have a
  1078. useless definition and we'll nag copiously later.
  1079. */
  1080. if(!cos_cache_add_tmpl(info->pTmpls, pDn, pObjectclass,
  1081. info->pCosSpecifier, pAttributes,pCosPriority)){
  1082. info->ret = 0; /* we have succeed to add the tmpl */
  1083. } else {
  1084. /* Don't reset info->ret....it keeps track of any success */
  1085. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_dn_tmpl_entries_cb - "
  1086. "Could not cache cos template %s\n",pDn->val);
  1087. }
  1088. }
  1089. else
  1090. {
  1091. /*
  1092. this template is brain dead - bail
  1093. if we have a dn use it to report, if not then *really* bad
  1094. things are going on
  1095. - of course it might not be a template, so lets
  1096. not tell the world unless the world wants to know,
  1097. we'll make it a plugin level message
  1098. */
  1099. if(pDn)
  1100. {
  1101. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_dn_tmpls - "
  1102. "Incomplete cos template detected in %s, discarding from cache.\n",pDn->val);
  1103. }
  1104. else
  1105. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_dn_tmpls - "
  1106. "Incomplete cos template detected, no DN to report, discarding from cache.\n");
  1107. if(pObjectclass)
  1108. cos_cache_del_attrval_list(&pObjectclass);
  1109. if(pCosAttribute)
  1110. cos_cache_del_attrval_list(&pCosAttribute);
  1111. if(pDn)
  1112. cos_cache_del_attrval_list(&pDn);
  1113. if(pAttributes)
  1114. cos_cache_del_attr_list(&pAttributes);
  1115. if(pCosPriority)
  1116. cos_cache_del_attrval_list(&pCosPriority);
  1117. }
  1118. }
  1119. /*
  1120. * Always continue the search even if a particular attempt
  1121. * to add a template failed unless we are shutting down
  1122. */
  1123. return slapi_is_shutting_down();
  1124. }
  1125. /*
  1126. cos_cache_add_dn_tmpls
  1127. -------------------------
  1128. takes a dn as argument and searches the dn for cos templates,
  1129. adding any found to the template list
  1130. This is the new version using call back search API
  1131. Returns: zero for success--found at least one good tmpl for this def.
  1132. non-zero: failed to add any templs for this def.
  1133. */
  1134. #define TMPL_FILTER "(&(objectclass=costemplate)(|(objectclass=costemplate)(objectclass=ldapsubentry)))"
  1135. static int cos_cache_add_dn_tmpls(char *dn, cosAttrValue *pCosSpecifier, cosAttrValue *pAttrs, cosTemplates **pTmpls)
  1136. {
  1137. void *plugin_id;
  1138. int scope;
  1139. struct tmpl_info info = {NULL, 0, 0, 0};
  1140. Slapi_PBlock *pDnSearch = 0;
  1141. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_add_dn_tmpls\n");
  1142. /* no cos specifier means this is an indirect scheme */
  1143. if(pCosSpecifier)
  1144. scope = LDAP_SCOPE_ONELEVEL;
  1145. else
  1146. scope = LDAP_SCOPE_BASE;
  1147. /* Use new internal operation API */
  1148. pDnSearch = slapi_pblock_new();
  1149. plugin_id=cos_get_plugin_identity();
  1150. if (pDnSearch) {
  1151. info.pAttrs=pAttrs;
  1152. info.pTmpls=pTmpls;
  1153. info.pCosSpecifier=pCosSpecifier;
  1154. info.ret=-1; /* assume no good tmpls */
  1155. slapi_search_internal_set_pb(pDnSearch, dn, scope,
  1156. TMPL_FILTER,NULL,0,
  1157. NULL,NULL,plugin_id,0);
  1158. slapi_search_internal_callback_pb(pDnSearch,
  1159. &info /* callback_data */,
  1160. NULL/* result_callback */,
  1161. cos_dn_tmpl_entries_cb,
  1162. NULL /* referral_callback */);
  1163. slapi_pblock_destroy (pDnSearch);
  1164. }
  1165. /*
  1166. * info.ret comes out zero only if we succeed to add at least one
  1167. * tmpl to the cache.
  1168. */
  1169. return (info.ret);
  1170. }
  1171. /*
  1172. cos_cache_add_defn
  1173. ------------------
  1174. Add a cos definition to the list and create the template
  1175. cache for this definition
  1176. returns: 0: successfully added the definition to the cache
  1177. non-zero: failed to add the definition to the cache (eg. because
  1178. there was no template for it.)
  1179. ret==COS_DEF_ERROR_NO_TEMPLATES then no templs were found
  1180. for thsi def. We make a special case of this and pass the
  1181. back the error so we can roll two messages into one--this
  1182. is to reduce the number of error messages at cos definiton
  1183. load time--it is common to see the defs before the tmpls
  1184. arrive.
  1185. */
  1186. static int cos_cache_add_defn(
  1187. cosDefinitions **pDefs,
  1188. cosAttrValue **dn,
  1189. int cosType,
  1190. cosAttrValue **tree,
  1191. cosAttrValue **tmpDn,
  1192. cosAttrValue **spec,
  1193. cosAttrValue **pAttrs,
  1194. cosAttrValue **pOverrides,
  1195. cosAttrValue **pOperational,
  1196. cosAttrValue **pCosMerge,
  1197. cosAttrValue **pCosOpDefault
  1198. )
  1199. {
  1200. int ret = 0;
  1201. int tmplCount = 0;
  1202. cosDefinitions *theDef = 0;
  1203. cosAttrValue *pTmpTmplDn = 0;
  1204. cosAttrValue *pDummyAttrVal = 0;
  1205. cosAttrValue *pAttrsIter = 0;
  1206. cosAttributes *pDummyAttributes = 0;
  1207. cosAttrValue *pSpecsIter = 0;
  1208. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_add_defn\n");
  1209. if (!spec) {
  1210. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_defn - Missing spec\n");
  1211. ret = -1;
  1212. goto out;
  1213. }
  1214. pSpecsIter = *spec;
  1215. if (!tmpDn) {
  1216. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_defn - Missing tmpDn\n");
  1217. ret = -1;
  1218. goto out;
  1219. }
  1220. pTmpTmplDn = *tmpDn;
  1221. /* we don't want cosspecifiers that can be supplied by the same scheme */
  1222. while( pSpecsIter )
  1223. {
  1224. if( cos_cache_attrval_exists(*pAttrs, pSpecsIter->val ) )
  1225. {
  1226. /* no, this is not sane, lets reject the whole darn scheme in disgust */
  1227. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_defn - "
  1228. "cos definition %s supplies its own cosspecifier, rejecting scheme\n",(*dn)->val);
  1229. ret = -1;
  1230. }
  1231. pSpecsIter = pSpecsIter->list.pNext;
  1232. }
  1233. /* create the definition */
  1234. if(0 == ret)
  1235. {
  1236. theDef = (cosDefinitions*) slapi_ch_malloc(sizeof(cosDefinitions));
  1237. if(theDef)
  1238. {
  1239. theDef->pCosTmps = NULL;
  1240. /* process each template in turn */
  1241. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_defn - "
  1242. "Processing cosDefinition %s\n",(*dn)->val);
  1243. while(pTmpTmplDn && cosType != COSTYPE_INDIRECT)
  1244. {
  1245. /* create the template */
  1246. if(!cos_cache_add_dn_tmpls(pTmpTmplDn->val, *spec, *pAttrs, &(theDef->pCosTmps)))
  1247. tmplCount++;
  1248. pTmpTmplDn = pTmpTmplDn->list.pNext;
  1249. }
  1250. if(tmplCount == 0 && cosType != COSTYPE_INDIRECT)
  1251. {
  1252. /* without our golden templates we are nothing
  1253. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_defn -"
  1254. "no templates for cos definition at %s.\n",(*dn)->val);*/
  1255. ret = COS_DEF_ERROR_NO_TEMPLATES;
  1256. }
  1257. else
  1258. {
  1259. if(cosType == COSTYPE_INDIRECT)
  1260. {
  1261. /*
  1262. Indirect cos schemes have no templates,
  1263. however, in order to take advantage of existing code
  1264. which is optimized to do a binary search on attributes
  1265. which are found through their templates, we add a dummy
  1266. template and dummy attributes. The value of the attributes
  1267. will be ignored when later assessing a query.
  1268. */
  1269. pAttrsIter = *pAttrs;
  1270. while(pAttrsIter)
  1271. {
  1272. pDummyAttrVal = NULL;
  1273. cos_cache_add_attrval(&pDummyAttrVal, "not used");
  1274. cos_cache_add_attr(&pDummyAttributes, pAttrsIter->val, pDummyAttrVal);
  1275. pAttrsIter = pAttrsIter->list.pNext;
  1276. }
  1277. cos_cache_add_attrval(tmpDn, "cn=dummy,");
  1278. cos_cache_add_tmpl(&(theDef->pCosTmps), *tmpDn, NULL, *spec, pDummyAttributes,NULL);
  1279. *tmpDn = 0;
  1280. }
  1281. theDef->pDn = *dn;
  1282. theDef->cosType = cosType;
  1283. theDef->pCosTargetTree = *tree;
  1284. theDef->pCosTemplateDn = *tmpDn;
  1285. theDef->pCosSpecifier = *spec;
  1286. theDef->pCosAttrs = *pAttrs;
  1287. theDef->pCosOverrides = *pOverrides;
  1288. theDef->pCosOperational = *pOperational;
  1289. theDef->pCosMerge = *pCosMerge;
  1290. theDef->pCosOpDefault = *pCosOpDefault;
  1291. cos_cache_add_ll_entry((void**)pDefs, theDef, NULL);
  1292. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_defn - "
  1293. "Added cosDefinition %s\n",(*dn)->val);
  1294. }
  1295. }
  1296. else
  1297. {
  1298. ret = -1;
  1299. }
  1300. }
  1301. out:
  1302. if(ret < 0)
  1303. {
  1304. slapi_ch_free((void**)&theDef);
  1305. if(dn)
  1306. cos_cache_del_attrval_list(dn);
  1307. if(tree)
  1308. cos_cache_del_attrval_list(tree);
  1309. if(tmpDn)
  1310. cos_cache_del_attrval_list(tmpDn);
  1311. if(spec)
  1312. cos_cache_del_attrval_list(spec);
  1313. if(pAttrs)
  1314. cos_cache_del_attrval_list(pAttrs);
  1315. }
  1316. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_add_defn\n");
  1317. return ret;
  1318. }
  1319. /*
  1320. cos_cache_del_attrval_list
  1321. --------------------------
  1322. walks the list deleting as it goes
  1323. */
  1324. static void cos_cache_del_attrval_list(cosAttrValue **pVal)
  1325. {
  1326. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_del_attrval_list\n");
  1327. while(*pVal)
  1328. {
  1329. cosAttrValue *pTmp = (*pVal)->list.pNext;
  1330. slapi_ch_free((void**)&((*pVal)->val));
  1331. slapi_ch_free((void**)&(*pVal));
  1332. *pVal = pTmp;
  1333. }
  1334. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_del_attrval_list\n");
  1335. }
  1336. /*
  1337. cos_cache_add_attrval
  1338. ---------------------
  1339. adds a value to an attribute value list
  1340. */
  1341. static int
  1342. cos_cache_add_attrval(cosAttrValue **attrval, char *val)
  1343. {
  1344. int ret = 0;
  1345. cosAttrValue *theVal;
  1346. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_add_attrval\n");
  1347. /* create the attrvalue */
  1348. theVal = (cosAttrValue*) slapi_ch_malloc(sizeof(cosAttrValue));
  1349. if(theVal)
  1350. {
  1351. theVal->val = slapi_ch_strdup(val);
  1352. if(theVal->val)
  1353. {
  1354. cos_cache_add_ll_entry((void**)attrval, theVal, NULL);
  1355. }
  1356. else
  1357. {
  1358. slapi_ch_free((void**)&theVal);
  1359. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_attrval - Failed to allocate memory\n");
  1360. ret = -1;
  1361. }
  1362. }
  1363. else
  1364. {
  1365. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_attrval - Failed to allocate memory\n");
  1366. ret = -1;
  1367. }
  1368. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_add_attrval\n");
  1369. return ret;
  1370. }
  1371. /*
  1372. cos_cache_add_ll_entry - RECURSIVE for sorted lists
  1373. ---------------------------------------------------
  1374. if a compare function is passed as argument, the element
  1375. is added to the linked list in the sorted order according
  1376. to that compare functions algorithm. This prepares the list
  1377. for ultra fast indexing - requiring only to walk the list once
  1378. to build the index.
  1379. if no compare function is passed, the element is added
  1380. to the head of the linked list
  1381. the index is created after the linked list is complete,
  1382. and so is always null until explicitly indexed
  1383. *NOTE* this function assumes and *requires* that the structures
  1384. passed to it in "attrval" and "theVal" have a cosIndexedLinkedList
  1385. member, and it is the *first* member of the structure. This
  1386. is safe because this is a module level function, and all functions
  1387. which call this one are part of the same sub-system.
  1388. The compare function will also make a similar assumption, but
  1389. likely one that recognizes the full structure or type, it is
  1390. the responsibility of the caller to match input structures with
  1391. the appropriate compare function.
  1392. WARNING: current recursive sorting code never used, never tested
  1393. */
  1394. static void cos_cache_add_ll_entry(void** attrval, void *theVal, int ( *compare )(const void *elem1, const void *elem2 ))
  1395. {
  1396. static cosIndexedLinkedList *pLastList = 0;
  1397. static cosIndexedLinkedList *first_element;
  1398. static int call_count = 0;
  1399. call_count++;
  1400. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_add_ll_entry - "
  1401. "recursion level %d\n",call_count);
  1402. /*
  1403. need to save the first element of the list
  1404. we update this first element whenever an entry
  1405. is added to the start of the list, this way
  1406. we can ensure that the head of the list is always
  1407. *attrval - callers pass us the head of the list
  1408. and can expect that what they get back is also
  1409. the head of the list
  1410. */
  1411. if(call_count == 1)
  1412. first_element = *attrval;
  1413. if(*attrval)
  1414. {
  1415. if(compare == NULL)
  1416. {
  1417. /* we dont want this list sorted */
  1418. /* push this to the start of the list (because its quick) */
  1419. ((cosIndexedLinkedList*)theVal)->pNext = *attrval;
  1420. ((cosIndexedLinkedList*)theVal)->index = NULL;
  1421. *attrval = theVal;
  1422. }
  1423. else
  1424. {
  1425. /* insert this in the list in sorted order
  1426. (because its quicker for building indexes later) */
  1427. int comp_ret = 0;
  1428. comp_ret = compare(*attrval, theVal);
  1429. if(comp_ret == 0 || comp_ret > 0)
  1430. {
  1431. /* insert prior to this element */
  1432. if(pLastList)
  1433. pLastList->pNext = theVal;
  1434. else
  1435. first_element = theVal;
  1436. ((cosIndexedLinkedList*)theVal)->pNext = *attrval;
  1437. ((cosIndexedLinkedList*)theVal)->index = NULL;
  1438. }
  1439. else
  1440. {
  1441. /* still looking - recurse on next element */
  1442. pLastList = (cosIndexedLinkedList*)attrval;
  1443. cos_cache_add_ll_entry(&(((cosIndexedLinkedList*)attrval)->pNext), theVal, compare);
  1444. }
  1445. if(call_count == 1)
  1446. *attrval = first_element;
  1447. }
  1448. }
  1449. else
  1450. {
  1451. /* new or end of list */
  1452. ((cosIndexedLinkedList*)theVal)->pNext = NULL;
  1453. ((cosIndexedLinkedList*)theVal)->index = NULL;
  1454. if(call_count == 1) /* if new list */
  1455. *attrval = theVal;
  1456. }
  1457. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_add_ll_entry - recursion level %d\n",call_count);
  1458. call_count--;
  1459. }
  1460. /*
  1461. cos_cache_getref
  1462. ----------------
  1463. retrieves a reference to the current cache and adds to the cache reference count
  1464. */
  1465. int cos_cache_getref(cos_cache **pptheCache)
  1466. {
  1467. int ret = -1;
  1468. static int first_time = 1;
  1469. cosCache **ppCache = (cosCache**)pptheCache;
  1470. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_getref\n");
  1471. if(first_time)
  1472. {
  1473. first_time = 0;
  1474. /* first customer, create the cache */
  1475. slapi_lock_mutex(change_lock);
  1476. if(pCache == NULL)
  1477. {
  1478. if(cos_cache_creation_lock())
  1479. {
  1480. /* there was a problem or no COS definitions were found */
  1481. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_getref - No cos cache created\n");
  1482. }
  1483. }
  1484. slapi_unlock_mutex(change_lock);
  1485. }
  1486. slapi_lock_mutex(cache_lock);
  1487. *ppCache = pCache;
  1488. if(pCache)
  1489. ret = ++((*ppCache)->refCount);
  1490. slapi_unlock_mutex(cache_lock);
  1491. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_getref\n");
  1492. return ret;
  1493. }
  1494. /*
  1495. cos_cache_addref
  1496. ----------------
  1497. adds 1 to the cache reference count
  1498. */
  1499. int cos_cache_addref(cos_cache *ptheCache)
  1500. {
  1501. int ret = 0;
  1502. cosCache *pCache = (cosCache*)ptheCache;
  1503. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_addref\n");
  1504. slapi_lock_mutex(cache_lock);
  1505. if(pCache)
  1506. ret = ++(pCache->refCount);
  1507. slapi_unlock_mutex(cache_lock);
  1508. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_addref\n");
  1509. return ret;
  1510. }
  1511. /*
  1512. cos_cache_release
  1513. -----------------
  1514. subtracts 1 from the cache reference count, if the count falls
  1515. below 1, the cache is destroyed.
  1516. */
  1517. int cos_cache_release(cos_cache *ptheCache)
  1518. {
  1519. int ret = 0;
  1520. int destroy = 0;
  1521. cosCache *pOldCache = (cosCache*)ptheCache;
  1522. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_release\n");
  1523. slapi_lock_mutex(cache_lock);
  1524. if(pOldCache)
  1525. {
  1526. ret = --(pOldCache->refCount);
  1527. if(ret == 0)
  1528. destroy = 1;
  1529. }
  1530. slapi_unlock_mutex(cache_lock);
  1531. if(destroy)
  1532. {
  1533. cosDefinitions *pDef = pOldCache->pDefs;
  1534. /* now is the first time it is
  1535. * safe to assess whether
  1536. * vattr caching can be turned on
  1537. */
  1538. if(pCache && pCache->vattr_cacheable)
  1539. {
  1540. slapi_vattrcache_cache_all();
  1541. }
  1542. /* destroy the cache here - no locking required, no references outstanding */
  1543. if(pDef)
  1544. cos_cache_del_schema(pOldCache);
  1545. while(pDef)
  1546. {
  1547. cosDefinitions *pTmpD = pDef;
  1548. cosTemplates *pCosTmps = pDef->pCosTmps;
  1549. while(pCosTmps)
  1550. {
  1551. cosTemplates *pTmpT = pCosTmps;
  1552. pCosTmps = pCosTmps->list.pNext;
  1553. cos_cache_del_attr_list(&(pTmpT->pAttrs));
  1554. cos_cache_del_attrval_list(&(pTmpT->pObjectclasses));
  1555. cos_cache_del_attrval_list(&(pTmpT->pDn));
  1556. slapi_ch_free((void**)&(pTmpT->cosGrade));
  1557. slapi_ch_free((void**)&pTmpT);
  1558. }
  1559. pDef = pDef->list.pNext;
  1560. cos_cache_del_attrval_list(&(pTmpD->pDn));
  1561. cos_cache_del_attrval_list(&(pTmpD->pCosTargetTree));
  1562. cos_cache_del_attrval_list(&(pTmpD->pCosTemplateDn));
  1563. cos_cache_del_attrval_list(&(pTmpD->pCosSpecifier));
  1564. cos_cache_del_attrval_list(&(pTmpD->pCosAttrs));
  1565. cos_cache_del_attrval_list(&(pTmpD->pCosOverrides));
  1566. cos_cache_del_attrval_list(&(pTmpD->pCosOperational));
  1567. cos_cache_del_attrval_list(&(pTmpD->pCosMerge));
  1568. cos_cache_del_attrval_list(&(pTmpD->pCosOpDefault));
  1569. slapi_ch_free((void**)&pTmpD);
  1570. }
  1571. if(pOldCache->ppAttrIndex)
  1572. slapi_ch_free((void**)&(pOldCache->ppAttrIndex));
  1573. if(pOldCache->ppTemplateList)
  1574. slapi_ch_free((void**)&(pOldCache->ppTemplateList));
  1575. slapi_ch_free((void**)&pOldCache);
  1576. }
  1577. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_release\n");
  1578. return ret;
  1579. }
  1580. /*
  1581. cos_cache_del_attr_list
  1582. -----------------------
  1583. walk the list deleting as we go
  1584. */
  1585. static void cos_cache_del_attr_list(cosAttributes **pAttrs)
  1586. {
  1587. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_del_attr_list\n");
  1588. while(*pAttrs)
  1589. {
  1590. cosAttributes *pTmp = (*pAttrs)->list.pNext;
  1591. cos_cache_del_attrval_list(&((*pAttrs)->pAttrValue));
  1592. slapi_ch_free((void**)&((*pAttrs)->pAttrName));
  1593. slapi_ch_free((void**)&(*pAttrs));
  1594. *pAttrs = pTmp;
  1595. }
  1596. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_del_attr_list\n");
  1597. }
  1598. /*
  1599. cos_cache_del_schema
  1600. --------------------
  1601. delete the object class lists used for schema checking
  1602. */
  1603. static void cos_cache_del_schema(cosCache *pCache)
  1604. {
  1605. char *pLastName = 0;
  1606. int attr_index = 0;
  1607. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_del_schema\n");
  1608. if(pCache && pCache->attrCount && pCache->ppAttrIndex)
  1609. {
  1610. pLastName = pCache->ppAttrIndex[0]->pAttrName;
  1611. for(attr_index=1; attr_index<pCache->attrCount; attr_index++)
  1612. {
  1613. if(slapi_utf8casecmp((unsigned char*)pCache->ppAttrIndex[attr_index]->pAttrName, (unsigned char*)pLastName))
  1614. {
  1615. /* remember what went before */
  1616. pLastName = pCache->ppAttrIndex[attr_index]->pAttrName;
  1617. /* then blow it away */
  1618. cos_cache_del_attrval_list(&(pCache->ppAttrIndex[attr_index]->pObjectclasses));
  1619. }
  1620. }
  1621. /* Finally, remove the first attribute's objectclass list */
  1622. cos_cache_del_attrval_list(&(pCache->ppAttrIndex[0]->pObjectclasses));
  1623. }
  1624. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_del_schema\n");
  1625. }
  1626. /*
  1627. cos_cache_add_attr
  1628. ------------------
  1629. Adds an attribute to the list
  1630. */
  1631. static int cos_cache_add_attr(cosAttributes **pAttrs, char *name, cosAttrValue *val)
  1632. {
  1633. int ret =0;
  1634. cosAttributes *theAttr;
  1635. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_add_attr\n");
  1636. /* create the attribute */
  1637. theAttr = (cosAttributes*) slapi_ch_malloc(sizeof(cosAttributes));
  1638. if(theAttr)
  1639. {
  1640. theAttr->pAttrValue = val;
  1641. theAttr->pObjectclasses = 0; /* schema issues come later */
  1642. theAttr->pAttrName = slapi_ch_strdup(name);
  1643. if(theAttr->pAttrName)
  1644. {
  1645. cos_cache_add_ll_entry((void**)pAttrs, theAttr, NULL);
  1646. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_attr - Added attribute %s\n",name);
  1647. }
  1648. else
  1649. {
  1650. slapi_ch_free((void**)&theAttr);
  1651. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_attr - Failed to allocate memory\n");
  1652. ret = -1;
  1653. }
  1654. }
  1655. else
  1656. {
  1657. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_attr - Failed to allocate memory\n");
  1658. ret = -1;
  1659. }
  1660. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_add_attr\n");
  1661. return ret;
  1662. }
  1663. /*
  1664. cos_cache_add_tmpl
  1665. ------------------
  1666. Adds a template to the list
  1667. */
  1668. static int cos_cache_add_tmpl(cosTemplates **pTemplates, cosAttrValue *dn, cosAttrValue *objclasses, cosAttrValue *pCosSpecifier, cosAttributes *pAttrs,cosAttrValue *cosPriority)
  1669. {
  1670. int ret =0;
  1671. cosTemplates *theTemp;
  1672. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_add_tmpl\n");
  1673. /* create the attribute */
  1674. theTemp = (cosTemplates*) slapi_ch_malloc(sizeof(cosTemplates));
  1675. if(theTemp)
  1676. {
  1677. char *grade = NULL;
  1678. int grade_index = 0;
  1679. int index = 0;
  1680. int template_default = 0;
  1681. char *ptr = NULL;
  1682. char *normed = slapi_create_dn_string("%s", dn->val);
  1683. if (normed) {
  1684. slapi_ch_free_string(&dn->val);
  1685. dn->val = normed;
  1686. } else {
  1687. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM,
  1688. "cos_cache_add_tmpl - Failed to normalize dn %s. "
  1689. "Processing the pre normalized dn.\n",
  1690. dn->val);
  1691. }
  1692. grade = (char*)slapi_ch_malloc(strlen(dn->val)+1);
  1693. /* extract the cos grade */
  1694. ptr = strchr(dn->val, '=');
  1695. if (ptr)
  1696. {
  1697. int quotes = 0;
  1698. int lastindex = strlen(dn->val) - 1;
  1699. index = ptr - dn->val + 1;
  1700. /* copy the grade (supports one level of quote nesting in rdn) */
  1701. while(dn->val[index] != ',' || dn->val[index-1] == '\\' || quotes == 1)
  1702. {
  1703. if(dn->val[index] == '"')
  1704. {
  1705. if(quotes == 0)
  1706. quotes = 1;
  1707. else
  1708. quotes = 0;
  1709. }
  1710. else
  1711. {
  1712. if(dn->val[index] == '\\')
  1713. {
  1714. if ((index+2 <= lastindex) && isxdigit(dn->val[index+1]) &&
  1715. isxdigit(dn->val[index+2])) {
  1716. /* Convert ESC HEX HEX to a real char */
  1717. int n = slapi_hexchar2int(dn->val[index+1]);
  1718. int n2 = slapi_hexchar2int(dn->val[index+2]);
  1719. n = (n << 4) + n2;
  1720. if (n == 0) { /* don't change \00 */
  1721. grade[grade_index] = dn->val[index++]; /* '\\' */
  1722. grade_index++;
  1723. grade[grade_index] = dn->val[index++]; /* 0 */
  1724. grade_index++;
  1725. grade[grade_index] = dn->val[index]; /* 0 */
  1726. grade_index++;
  1727. } else {
  1728. grade[grade_index] = n;
  1729. index += 2;
  1730. grade_index++;
  1731. }
  1732. } /* else: skip escape chars */
  1733. }
  1734. else
  1735. {
  1736. grade[grade_index] = dn->val[index];
  1737. grade_index++;
  1738. }
  1739. }
  1740. index++;
  1741. }
  1742. grade[grade_index] = '\0';
  1743. /* ok, grade copied, is it the default template? */
  1744. if(pCosSpecifier) /* some schemes don't have one */
  1745. {
  1746. char tmpGrade[BUFSIZ];
  1747. if (strlen(pCosSpecifier->val) < (sizeof(tmpGrade) - 9)) { /* 9 for "-default" */
  1748. strcpy(tmpGrade, pCosSpecifier->val);
  1749. strcat(tmpGrade, "-default");
  1750. if(!slapi_utf8casecmp((unsigned char*)grade, (unsigned char*)tmpGrade))
  1751. template_default = 1;
  1752. }
  1753. else
  1754. {
  1755. /*
  1756. * We shouldn't pass ever through this code as we expect
  1757. * pCosSpecifier values to be reasonably smaller than BUFSIZ
  1758. *
  1759. * only 2 lines of code -> no need to set an indirect char *
  1760. * duplicate the lines of code for clearness instead
  1761. */
  1762. char * newTmpGrade = PR_smprintf("%s-default", pCosSpecifier->val);
  1763. if(!slapi_utf8casecmp((unsigned char*)grade, (unsigned char*)newTmpGrade))
  1764. template_default = 1;
  1765. PR_smprintf_free(newTmpGrade);
  1766. }
  1767. }
  1768. }
  1769. else
  1770. {
  1771. /* mmm, should never get here, it means the dn is whacky */
  1772. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_tmpl - Malformed dn detected: %s\n",dn->val);
  1773. grade[0] = '\0';
  1774. }
  1775. /* now fill in the blanks */
  1776. theTemp->pDn = dn;
  1777. theTemp->pObjectclasses = objclasses;
  1778. theTemp->pAttrs = pAttrs;
  1779. theTemp->cosGrade = slapi_ch_strdup(grade);
  1780. theTemp->template_default = template_default;
  1781. theTemp->cosPriority = (unsigned long)-1;
  1782. if(cosPriority)
  1783. {
  1784. theTemp->cosPriority = atol(cosPriority->val);
  1785. cos_cache_del_attrval_list(&cosPriority);
  1786. }
  1787. cos_cache_add_ll_entry((void**)pTemplates, theTemp, NULL);
  1788. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_tmpl - Added template %s\n",dn->val);
  1789. slapi_ch_free((void**)&grade);
  1790. }
  1791. else
  1792. {
  1793. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_add_tmpl - Failed to allocate memory\n");
  1794. ret = -1;
  1795. }
  1796. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_add_tmpl\n");
  1797. return ret;
  1798. }
  1799. /*
  1800. cos_cache_attrval_exists
  1801. ------------------------
  1802. performs linear search on the list for a
  1803. cosAttrValue that matches val
  1804. however, if the "index" member of cosAttrValue
  1805. is non-null then a binary search is performed
  1806. on the index {PARPAR: TO BE DONE}
  1807. return 1 on found, 0 otherwise
  1808. */
  1809. static int cos_cache_attrval_exists(cosAttrValue *pAttrs, const char *val)
  1810. {
  1811. int ret = 0;
  1812. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_attrval_exists\n");
  1813. while(pAttrs)
  1814. {
  1815. if(!slapi_utf8casecmp((unsigned char*)pAttrs->val,(unsigned char*)val))
  1816. {
  1817. ret = 1;
  1818. break;
  1819. }
  1820. pAttrs = pAttrs->list.pNext;
  1821. }
  1822. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_attrval_exists\n");
  1823. return ret;
  1824. }
  1825. static int cos_cache_vattr_get(vattr_sp_handle *handle __attribute__((unused)),
  1826. vattr_context *c,
  1827. Slapi_Entry *e,
  1828. char *type,
  1829. Slapi_ValueSet** results,
  1830. int *type_name_disposition,
  1831. char** actual_type_name,
  1832. int flags __attribute__((unused)),
  1833. int *free_flags,
  1834. void *hint __attribute__((unused)))
  1835. {
  1836. cos_cache *pCache = 0;
  1837. int indirect_cos = 0;
  1838. int ret = -1;
  1839. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_vattr_get\n");
  1840. if(cos_cache_getref(&pCache) < 1)
  1841. {
  1842. /* problems we are hosed */
  1843. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_vattr_get - "
  1844. "Failed to get class of service reference\n");
  1845. goto bail;
  1846. }
  1847. ret = cos_cache_query_attr(pCache, c, e, type, results, NULL, NULL, NULL, &indirect_cos);
  1848. if(ret == 0)
  1849. {
  1850. if(indirect_cos){
  1851. /* we can't cache indirect cos */
  1852. *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
  1853. } else {
  1854. *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES | SLAPI_VIRTUALATTRS_VALUES_CACHEABLE;
  1855. }
  1856. *actual_type_name = slapi_ch_strdup(type);
  1857. *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
  1858. }
  1859. cos_cache_release(pCache);
  1860. bail:
  1861. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_vattr_get\n");
  1862. return ret;
  1863. }
  1864. static int cos_cache_vattr_compare(vattr_sp_handle *handle __attribute__((unused)),
  1865. vattr_context *c,
  1866. Slapi_Entry *e,
  1867. char *type,
  1868. Slapi_Value *test_this,
  1869. int* result,
  1870. int flags __attribute__((unused)),
  1871. void *hint __attribute__((unused)))
  1872. {
  1873. int ret = -1;
  1874. cos_cache *pCache = 0;
  1875. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_vattr_compare\n");
  1876. if(cos_cache_getref(&pCache) < 1)
  1877. {
  1878. /* problems we are hosed */
  1879. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_vattr_compare - Failed to get class of service reference\n");
  1880. goto bail;
  1881. }
  1882. ret = cos_cache_query_attr(pCache, c, e, type, NULL, test_this, result, NULL, NULL);
  1883. cos_cache_release(pCache);
  1884. bail:
  1885. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_vattr_compare\n");
  1886. return ret;
  1887. }
  1888. /*
  1889. * this imp is damn slow
  1890. *
  1891. */
  1892. static int cos_cache_vattr_types(vattr_sp_handle *handle __attribute__((unused)),
  1893. Slapi_Entry *e,
  1894. vattr_type_list_context *type_context,
  1895. int flags __attribute__((unused)))
  1896. {
  1897. int ret = 0;
  1898. int index = 0;
  1899. cosCache *pCache;
  1900. char *lastattr = "thisisfakeforcos";
  1901. int props = 0;
  1902. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_vattr_types\n");
  1903. if(cos_cache_getref((cos_cache **)&pCache) < 1)
  1904. {
  1905. /* problems we are hosed */
  1906. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_vattr_types - Failed to get class of service reference\n");
  1907. goto bail;
  1908. }
  1909. while(index < pCache->attrCount )
  1910. {
  1911. if(slapi_utf8casecmp(
  1912. (unsigned char *)pCache->ppAttrIndex[index]->pAttrName,
  1913. (unsigned char *)lastattr))
  1914. {
  1915. lastattr = pCache->ppAttrIndex[index]->pAttrName;
  1916. if(1 == cos_cache_query_attr(pCache, NULL, e, lastattr, NULL, NULL,
  1917. NULL, &props, NULL))
  1918. {
  1919. /* entry contains this attr */
  1920. vattr_type_thang thang = {0};
  1921. thang.type_name = lastattr;
  1922. thang.type_flags = props;
  1923. slapi_vattrspi_add_type(type_context,&thang,0);
  1924. }
  1925. }
  1926. index++;
  1927. }
  1928. cos_cache_release(pCache);
  1929. bail:
  1930. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_vattr_types\n");
  1931. return ret;
  1932. }
  1933. /*
  1934. cos_cache_query_attr
  1935. --------------------
  1936. queries the cache to determine if this entry
  1937. should have an attribute of "type", and if so,
  1938. returns the attribute values in "vals" - which
  1939. should be subsequently freed by a call to
  1940. cos_cache_query_attr_free()
  1941. returns
  1942. 0 on success, we added a computed attribute
  1943. 1 on outright failure
  1944. > LDAP ERROR CODE
  1945. -1 when doesn't know about attribute
  1946. {PARPAR} must also check the attribute does not exist if we are not
  1947. overriding and allow the DS logic to pick it up by denying knowledge
  1948. of attribute
  1949. */
  1950. static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context,
  1951. Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr,
  1952. Slapi_Value *test_this, int *result, int *props,
  1953. int *indirect_cos)
  1954. {
  1955. int ret = -1;
  1956. cosCache *pCache = (cosCache*)ptheCache;
  1957. char *pDn = 0;
  1958. Slapi_Attr *pObjclasses = 0;
  1959. int attr_index = 0; /* for looping through attributes */
  1960. int attr_matched_index = 0; /* for identifying the matched attribute */
  1961. int hit = 0;
  1962. cosAttributes *pDefAttr = 0;
  1963. Slapi_Value *val;
  1964. /* int type_name_disposition;
  1965. char *actual_type_name;
  1966. int flags = 0;
  1967. int free_flags;*/
  1968. Slapi_Attr *pTmpVals;
  1969. int using_default = 0;
  1970. int entry_has_value = 0;
  1971. int merge_mode = 0;
  1972. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_query_attr\n");
  1973. if(out_attr)
  1974. *out_attr = 0;
  1975. /*
  1976. to perform this operation we need to know:
  1977. * if we know about the attribute, if not just exit
  1978. --
  1979. * dn,to determine its relevancy to any cos definition,
  1980. it must be a child of cosTargetTree
  1981. --
  1982. * objectclasses,to determine if the cos attribute will
  1983. violate schema (only when schema checking is on)
  1984. --
  1985. * class of service specifier, for matching definitions
  1986. - cosSpecifier is the attribute name and is used to
  1987. determine the cosDefinition to use, its value determines
  1988. the template to use
  1989. --
  1990. * the cosAttribute(s) (from the cosDefinition(s)) that match
  1991. the attribute name.
  1992. ($$)If these have a postfix of "default", then it is the same
  1993. as no postfix i.e. this acts as the default value. If it has
  1994. a postfix of "override", then the value in the matching template
  1995. is used regardless of any value stored in the entry. This has
  1996. been worked out previously so we can use a bool indicator in
  1997. the cosDefinition structure to determine what to do.
  1998. --
  1999. * the value of the attribute in the entry -
  2000. if present it overrides any default template value (see $$)
  2001. Also this ordering ensures least work done to fail (in this
  2002. implementation)
  2003. */
  2004. /** attribute **/
  2005. /*
  2006. lets be sure we need to do something
  2007. most of the time we probably don't
  2008. */
  2009. attr_index = cos_cache_find_attr(pCache, type);
  2010. if(attr_index == -1)
  2011. {
  2012. /* we don't know about this attribute */
  2013. goto bail;
  2014. }
  2015. /*
  2016. if there is a value in the entry the outcome
  2017. of the cos attribute resolution may be different
  2018. */
  2019. slapi_entry_attr_find(e, type, &pTmpVals);
  2020. if(pTmpVals)
  2021. entry_has_value = 1;
  2022. /** dn **/
  2023. pDn = slapi_entry_get_dn(e);
  2024. if(pDn == 0)
  2025. {
  2026. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_query_attr - Failed to get entry dn\n");
  2027. ret = 1;
  2028. goto bail;
  2029. }
  2030. slapi_dn_normalize( pDn );
  2031. /** objectclasses **/
  2032. if(pCache->ppAttrIndex[attr_index]->attr_operational == 0 && config_get_schemacheck() &&
  2033. pCache->ppAttrIndex[attr_index]->attr_operational_default == 0)
  2034. {
  2035. /* does this entry violate schema? */
  2036. if(slapi_entry_attr_find( e, "objectclass", &pObjclasses ))
  2037. {
  2038. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_query_attr - Failed to get objectclass from %s\n",pDn);
  2039. goto bail;
  2040. }
  2041. if(!cos_cache_schema_check(pCache, attr_index, pObjclasses))
  2042. {
  2043. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_query_attr - cos attribute %s failed schema check on dn: %s\n",type,pDn);
  2044. goto bail;
  2045. }
  2046. }
  2047. /** class of service specifier **/
  2048. /*
  2049. Now we need to iterate through the attributes to discover
  2050. if one fits all the criteria, we'll take the first that does
  2051. and blow off the rest unless the definition has merge-scheme
  2052. set.
  2053. */
  2054. do
  2055. {
  2056. /* for convenience, define some pointers */
  2057. cosAttributes *pAttr = pCache->ppAttrIndex[attr_index];
  2058. cosTemplates *pTemplate = (cosTemplates*)pAttr->pParent;
  2059. cosDefinitions *pDef = (cosDefinitions*)pTemplate->pParent;
  2060. cosAttrValue *pTargetTree = pDef->pCosTargetTree;
  2061. /* now for the tests */
  2062. /* would we be allowed to supply this attribute if we had one? */
  2063. if (entry_has_value && !pAttr->attr_override && !pAttr->attr_operational && !pAttr->attr_operational_default)
  2064. {
  2065. /* answer: no, move on to the next attribute */
  2066. attr_index++;
  2067. continue;
  2068. }
  2069. /* if we are in merge_mode, can the attribute be merged? */
  2070. if(merge_mode && pAttr->attr_cos_merge == 0)
  2071. {
  2072. /* answer: no, move on to the next attribute */
  2073. attr_index++;
  2074. continue;
  2075. }
  2076. /* If we haven't found a hit yet, or if we are in merge mode, look for
  2077. * hits. We only check if this entry is a child of the target tree(s). */
  2078. while((hit == 0 || merge_mode) && pTargetTree)
  2079. {
  2080. if( pTargetTree->val == 0 ||
  2081. slapi_dn_issuffix(pDn, pTargetTree->val) != 0 ||
  2082. (views_api && views_entry_exists(views_api, pTargetTree->val, e)) /* might be in a view */
  2083. )
  2084. {
  2085. cosAttrValue *pSpec = pDef->pCosSpecifier;
  2086. Slapi_ValueSet *pAttrSpecs = 0;
  2087. /* Does this entry have a correct cosSpecifier? */
  2088. do
  2089. {
  2090. int type_name_disposition = 0;
  2091. char *actual_type_name = 0;
  2092. int free_flags = 0;
  2093. if(pSpec && pSpec->val) {
  2094. ret = slapi_vattr_values_get_sp(context, e, pSpec->val, &pAttrSpecs, &type_name_disposition, &actual_type_name, 0, &free_flags);
  2095. /* MAB: We need to free actual_type_name here !!!
  2096. XXX BAD--should use slapi_vattr_values_free() */
  2097. slapi_ch_free((void **) &actual_type_name);
  2098. }
  2099. if(pAttrSpecs || pDef->cosType == COSTYPE_POINTER)
  2100. {
  2101. int index = 0;
  2102. /* does the cosSpecifier value correspond to this template? */
  2103. if(pDef->cosType == COSTYPE_INDIRECT)
  2104. {
  2105. /*
  2106. it always does correspond for indirect schemes (it's a dummy value)
  2107. now we must follow the dn of our pointer and retrieve a value to
  2108. return
  2109. Note: we support one dn only, the result of multiple pointers is undefined
  2110. */
  2111. Slapi_Value *indirectdn;
  2112. Slapi_ValueSet *tmp_vals = NULL;
  2113. int pointer_flags = 0;
  2114. int hint = 0;
  2115. hint = slapi_valueset_first_value( pAttrSpecs, &indirectdn );
  2116. if(props)
  2117. pointer_flags = *props;
  2118. while (indirectdn != NULL)
  2119. {
  2120. if (cos_cache_follow_pointer( context, (char*)slapi_value_get_string(indirectdn),
  2121. type, &tmp_vals, test_this, result, pointer_flags) == 0)
  2122. {
  2123. if(indirect_cos){
  2124. *indirect_cos = 1;
  2125. }
  2126. hit = 1;
  2127. /* If the caller requested values, set them. We need
  2128. * to append values when we follow multiple pointers DNs. */
  2129. if (out_attr && tmp_vals)
  2130. {
  2131. if (*out_attr)
  2132. {
  2133. Slapi_Attr *attr = NULL;
  2134. Slapi_Value *val = NULL;
  2135. int idx = 0;
  2136. /* Create an attr to use for duplicate detection. */
  2137. attr = slapi_attr_new();
  2138. slapi_attr_init(attr, type);
  2139. /* Copy any values into out_attr if they don't already exist. */
  2140. for (idx = slapi_valueset_first_value(tmp_vals, &val);
  2141. val && (idx != -1);
  2142. idx = slapi_valueset_next_value(tmp_vals, idx, &val))
  2143. {
  2144. if (slapi_valueset_find(attr, *out_attr, val) == NULL)
  2145. {
  2146. slapi_valueset_add_value(*out_attr, val);
  2147. }
  2148. }
  2149. slapi_attr_free(&attr);
  2150. slapi_valueset_free(tmp_vals);
  2151. tmp_vals = NULL;
  2152. } else {
  2153. *out_attr = tmp_vals;
  2154. tmp_vals = NULL;
  2155. }
  2156. }
  2157. }
  2158. /* If this definition has merge-scheme set, we
  2159. * need to follow the rest of the pointers. */
  2160. if (pAttr->attr_cos_merge)
  2161. {
  2162. hint = slapi_valueset_next_value(pAttrSpecs, hint, &indirectdn);
  2163. } else {
  2164. indirectdn = NULL;
  2165. }
  2166. }
  2167. /* If merge-scheme is specified, set merge mode. This will allow
  2168. * us to merge in values from other CoS definitions for this attr. */
  2169. if (pAttr->attr_cos_merge)
  2170. {
  2171. merge_mode = 1;
  2172. attr_matched_index = attr_index;
  2173. }
  2174. }
  2175. else
  2176. {
  2177. if(pDef->cosType != COSTYPE_POINTER)
  2178. index = slapi_valueset_first_value( pAttrSpecs, &val );
  2179. while(pDef->cosType == COSTYPE_POINTER || val)
  2180. {
  2181. if(pDef->cosType == COSTYPE_POINTER || !slapi_utf8casecmp((unsigned char*)pTemplate->cosGrade, (unsigned char*)slapi_value_get_string(val)))
  2182. {
  2183. /* we have a hit */
  2184. if(out_attr)
  2185. {
  2186. if(cos_cache_cos_2_slapi_valueset(pAttr, out_attr) == 0)
  2187. hit = 1;
  2188. else
  2189. {
  2190. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM,
  2191. "cos_cache_query_attr - Could not create values to return\n");
  2192. goto bail;
  2193. }
  2194. if(pAttr->attr_cos_merge)
  2195. {
  2196. merge_mode = 1;
  2197. attr_matched_index = attr_index;
  2198. }
  2199. }
  2200. else
  2201. {
  2202. if(test_this && result)
  2203. {
  2204. /* compare op */
  2205. if(cos_cache_cmp_attr(pAttr, test_this, result))
  2206. {
  2207. hit = 1;
  2208. }
  2209. }
  2210. else
  2211. {
  2212. /* well, this must be a request for type only */
  2213. hit = 1;
  2214. }
  2215. }
  2216. break;
  2217. }
  2218. if(pDef->cosType != COSTYPE_POINTER)
  2219. index = slapi_valueset_next_value( pAttrSpecs, index, &val );
  2220. }
  2221. }
  2222. }
  2223. if(pSpec)
  2224. pSpec = pSpec->list.pNext;
  2225. } while(hit == 0 && pSpec);
  2226. /* MAB: We need to free pAttrSpecs here !!!
  2227. XXX BAD--should use slapi_vattr_values_free()*/
  2228. slapi_valueset_free(pAttrSpecs);
  2229. /* is the cosTemplate the default template? */
  2230. if(hit == 0 && pTemplate->template_default && !pDefAttr)
  2231. {
  2232. /* then lets save the attr in case we need it later */
  2233. pDefAttr = pAttr;
  2234. }
  2235. }
  2236. pTargetTree = pTargetTree->list.pNext;
  2237. } /* while(hit == 0 && pTargetTree) */
  2238. if(hit==0 || merge_mode)
  2239. attr_index++;
  2240. } while(
  2241. (hit == 0 || merge_mode) &&
  2242. pCache->attrCount > attr_index &&
  2243. !slapi_utf8casecmp((unsigned char*)type, (unsigned char*)pCache->ppAttrIndex[attr_index]->pAttrName)
  2244. );
  2245. if(!merge_mode)
  2246. attr_matched_index = attr_index;
  2247. /* should we use a default value? */
  2248. if(hit == 0 && pDefAttr)
  2249. {
  2250. /* we have a hit */
  2251. using_default = 1;
  2252. if(out_attr)
  2253. {
  2254. if(cos_cache_cos_2_slapi_valueset(pDefAttr, out_attr) == 0)
  2255. hit = 1;
  2256. else
  2257. {
  2258. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_query_attr - "
  2259. "Could not create values to return\n");
  2260. goto bail;
  2261. }
  2262. }
  2263. else
  2264. {
  2265. if(test_this && result)
  2266. {
  2267. /* compare op */
  2268. if(cos_cache_cmp_attr(pDefAttr, test_this, result))
  2269. hit = 1;
  2270. }
  2271. else
  2272. {
  2273. /* well, this must be a request for type only and the entry gets default template value */
  2274. hit = 1;
  2275. }
  2276. }
  2277. }
  2278. if(hit == 1 && out_attr == NULL && test_this == NULL)
  2279. ret = 1;
  2280. else if(hit == 1)
  2281. ret = 0;
  2282. else
  2283. ret = -1;
  2284. if(props)
  2285. *props = 0;
  2286. if(hit == 1 && props) {
  2287. if (
  2288. (using_default && pDefAttr &&
  2289. ((pDefAttr->attr_operational == 1) || (pDefAttr->attr_operational_default == 1))) ||
  2290. (!using_default && pCache && pCache->ppAttrIndex && pCache->ppAttrIndex[attr_matched_index] &&
  2291. ((pCache->ppAttrIndex[attr_matched_index]->attr_operational == 1) ||
  2292. (pCache->ppAttrIndex[attr_matched_index]->attr_operational_default == 1))))
  2293. {
  2294. /* this is an operational attribute, lets mark it so */
  2295. *props |= SLAPI_ATTR_FLAG_OPATTR;
  2296. }
  2297. }
  2298. bail:
  2299. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_query_attr\n");
  2300. return ret;
  2301. }
  2302. /*
  2303. cos_cache_find_attr
  2304. -------------------
  2305. searches for the attribute "type", and if found returns the index
  2306. of the first occurrance of the attribute in the cache top level
  2307. indexed attribute list.
  2308. */
  2309. static int cos_cache_find_attr(cosCache *pCache, char *type)
  2310. {
  2311. int ret = -1; /* assume failure */
  2312. cosAttributes attr;
  2313. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_find_attr\n");
  2314. attr.pAttrName = type;
  2315. if(pCache->attrCount-1 != 0)
  2316. ret = cos_cache_attr_index_bsearch(pCache, &attr, 0, pCache->attrCount-1);
  2317. else
  2318. {
  2319. /* only one attribute (that will fool our bsearch) lets check it here */
  2320. if(!slapi_utf8casecmp((unsigned char*)type, (unsigned char*)(pCache->ppAttrIndex)[0]->pAttrName))
  2321. {
  2322. ret = 0;
  2323. }
  2324. }
  2325. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_find_attr\n");
  2326. return ret;
  2327. }
  2328. /*
  2329. cos_cache_schema_check
  2330. ----------------------
  2331. check those object classes which match in the input list and the
  2332. cached set for allowed attribute types
  2333. return non-null for schema matches, zero otherwise
  2334. */
  2335. static int cos_cache_schema_check(cosCache *pCache, int attr_index, Slapi_Attr *pObjclasses)
  2336. {
  2337. int ret = 0; /* assume failure */
  2338. Slapi_Value *val;
  2339. int hint;
  2340. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_schema_check\n");
  2341. hint = slapi_attr_first_value( pObjclasses, &val );
  2342. while(hint != -1)
  2343. {
  2344. ret = cos_cache_attrval_exists(pCache->ppAttrIndex[attr_index]->pObjectclasses, (char*) slapi_value_get_string(val));
  2345. if(ret)
  2346. break;
  2347. hint = slapi_attr_next_value( pObjclasses, hint, &val );
  2348. }
  2349. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_schema_check\n");
  2350. return ret;
  2351. }
  2352. /*
  2353. cos_cache_schema_build
  2354. ----------------------
  2355. For each attribute in our global cache add the objectclasses which allow it.
  2356. This may be referred to later to check schema is not being violated.
  2357. */
  2358. static int cos_cache_schema_build(cosCache *pCache)
  2359. {
  2360. int ret = 0; /* we assume success, with operational attributes not supplied in schema we might fail otherwise */
  2361. struct objclass *oc;
  2362. char *pLastName = 0;
  2363. cosAttrValue *pLastRef = 0;
  2364. int attr_index = 0;
  2365. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_schema_build\n");
  2366. if(!config_get_schemacheck())
  2367. ret = 0;
  2368. /*
  2369. it is expected that in all but the most hard core cases, the number of
  2370. objectclasses will out number the attributes we look after - so we make
  2371. the objectclasses the outside loop. However, even if they are not, we
  2372. perform binary searches on the attribute list anyway, so it should be
  2373. considerably faster to search than the linked list of objectclasses (even
  2374. with the string comparisons going on)
  2375. */
  2376. oc_lock_read();
  2377. for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next )
  2378. {
  2379. char **pppAttrs[2];
  2380. int index;
  2381. int attrType = 0;
  2382. pppAttrs[0] = oc->oc_required;
  2383. pppAttrs[1] = oc->oc_allowed;
  2384. /* we need to check both required and allowed attributes I think */
  2385. while(attrType < 2)
  2386. {
  2387. if(pppAttrs[attrType])
  2388. {
  2389. index = 0;
  2390. while(pppAttrs[attrType][index])
  2391. {
  2392. attr_index = cos_cache_find_attr(pCache, pppAttrs[attrType][index]);
  2393. if(attr_index != -1)
  2394. {
  2395. /*
  2396. this attribute is one of ours, add this
  2397. objectclass to the objectclass list
  2398. note the index refers to the first
  2399. occurrence of this attribute in the list,
  2400. later we will copy over references to this
  2401. list to all the other attribute duplicates.
  2402. */
  2403. cos_cache_add_attrval(&(pCache->ppAttrIndex[attr_index]->pObjectclasses), oc->oc_name);
  2404. ret = 0;
  2405. }
  2406. index++;
  2407. }
  2408. }
  2409. attrType++;
  2410. }
  2411. }
  2412. oc_unlock();
  2413. /*
  2414. OK, now we need to add references to the real
  2415. lists to the duplicate attribute entries.
  2416. (this allows the schema check to be a little
  2417. less complex and just a little quicker)
  2418. */
  2419. pLastName = pCache->ppAttrIndex[0]->pAttrName;
  2420. pLastRef = pCache->ppAttrIndex[0]->pObjectclasses;
  2421. for(attr_index=1; attr_index<pCache->attrCount; attr_index++)
  2422. {
  2423. if(!slapi_utf8casecmp((unsigned char*)pCache->ppAttrIndex[attr_index]->pAttrName, (unsigned char*)pLastName))
  2424. {
  2425. /* copy over reference */
  2426. pCache->ppAttrIndex[attr_index]->pObjectclasses = pLastRef;
  2427. }
  2428. else
  2429. {
  2430. /* remember what went before */
  2431. pLastName = pCache->ppAttrIndex[attr_index]->pAttrName;
  2432. pLastRef = pCache->ppAttrIndex[attr_index]->pObjectclasses;
  2433. }
  2434. }
  2435. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_schema_build\n");
  2436. return ret;
  2437. }
  2438. /*
  2439. cos_cache_index_all
  2440. -------------------
  2441. Indexes every attribute in the cache for fast binary lookup
  2442. on attributes from the top level of the cache.
  2443. Also fixes up all parent pointers so that a single attribute
  2444. lookup will allow access to all information regarding that attribute.
  2445. Attributes that appear more than once in the cache will also
  2446. be indexed more than once - this means that a pure binary
  2447. search is not possible, but it is possible to make use of a
  2448. duplicate entry aware binary search function - which are rare beasts,
  2449. so we'll need to provide cos_cache_attr_bsearch()
  2450. This is also a handy time to mark the attributes as overides if
  2451. necessary
  2452. */
  2453. static int cos_cache_index_all(cosCache *pCache)
  2454. {
  2455. int ret = -1;
  2456. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_index_all\n");
  2457. /*
  2458. first fixup the index array so we can use qsort()
  2459. also fixup the parent pointers
  2460. */
  2461. pCache->ppTemplateList = 0;
  2462. pCache->templateCount = 0;
  2463. pCache->ppAttrIndex = 0;
  2464. pCache->attrCount = cos_cache_total_attr_count(pCache);
  2465. if(pCache->attrCount && pCache->templateCount)
  2466. {
  2467. int tmpindex = 0;
  2468. int cmpindex = 0;
  2469. int actualCount = 0;
  2470. pCache->ppAttrIndex = (cosAttributes**)slapi_ch_malloc(sizeof(cosAttributes*) * pCache->attrCount);
  2471. pCache->ppTemplateList = (char**)slapi_ch_calloc((pCache->templateCount + 1) * 2, sizeof(char*));
  2472. if(pCache->ppAttrIndex && pCache->ppTemplateList)
  2473. {
  2474. int attrcount = 0;
  2475. cosDefinitions *pDef = pCache->pDefs;
  2476. cosAttrValue *pAttrVal = 0;
  2477. while(pDef)
  2478. {
  2479. cosTemplates *pCosTmps = pDef->pCosTmps;
  2480. while(pCosTmps)
  2481. {
  2482. cosAttributes *pAttrs = pCosTmps->pAttrs;
  2483. pCosTmps->pParent = pDef;
  2484. while(pAttrs)
  2485. {
  2486. pAttrs->pParent = pCosTmps;
  2487. (pCache->ppAttrIndex)[attrcount] = pAttrs;
  2488. if(cos_cache_attrval_exists(pDef->pCosOverrides, pAttrs->pAttrName))
  2489. pAttrs->attr_override = 1;
  2490. else
  2491. pAttrs->attr_override = 0;
  2492. if(cos_cache_attrval_exists(pDef->pCosOperational, pAttrs->pAttrName))
  2493. pAttrs->attr_operational = 1;
  2494. else
  2495. pAttrs->attr_operational = 0;
  2496. if(cos_cache_attrval_exists(pDef->pCosMerge, pAttrs->pAttrName))
  2497. pAttrs->attr_cos_merge = 1;
  2498. else
  2499. pAttrs->attr_cos_merge = 0;
  2500. if(cos_cache_attrval_exists(pDef->pCosOpDefault, pAttrs->pAttrName))
  2501. pAttrs->attr_operational_default = 1;
  2502. else
  2503. pAttrs->attr_operational_default = 0;
  2504. attrcount++;
  2505. pAttrs = pAttrs->list.pNext;
  2506. }
  2507. pCosTmps = pCosTmps->list.pNext;
  2508. }
  2509. /*
  2510. we need to build the template dn list too,
  2511. we are going to take care that we do not
  2512. add duplicate dns or dns that have
  2513. ancestors elsewhere in the list since this
  2514. list will be binary searched (with a special
  2515. BS alg) to find an ancestor tree for a target
  2516. that has been modified - that comes later in
  2517. this function however - right now we'll just
  2518. slap them in the list
  2519. */
  2520. pAttrVal = pDef->pCosTemplateDn;
  2521. while(pAttrVal)
  2522. {
  2523. char *normed = slapi_create_dn_string("%s", pAttrVal->val);
  2524. if (normed) {
  2525. slapi_ch_free_string(&pAttrVal->val);
  2526. pAttrVal->val = normed;
  2527. } else {
  2528. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM,
  2529. "cos_cache_index_all - Failed to normalize dn %s. "
  2530. "Processing the pre normalized dn.\n",
  2531. pAttrVal->val);
  2532. }
  2533. pCache->ppTemplateList[tmpindex] = pAttrVal->val;
  2534. tmpindex++;
  2535. pAttrVal = pAttrVal->list.pNext;
  2536. }
  2537. pDef = pDef->list.pNext;
  2538. }
  2539. /* now sort the index array */
  2540. qsort(pCache->ppAttrIndex, attrcount, sizeof(cosAttributes*), cos_cache_attr_compare);
  2541. qsort(pCache->ppTemplateList, tmpindex, sizeof(char*), cos_cache_string_compare);
  2542. /*
  2543. now we have the sorted template dn list, we can get rid of
  2544. duplicates and entries that have an ancestor elsewhere in
  2545. the list - all this in the name of faster searches
  2546. */
  2547. /* first go through zapping the useless PARPAR - THIS DOES NOT WORK */
  2548. tmpindex = 1;
  2549. cmpindex = 0;
  2550. actualCount = pCache->templateCount;
  2551. while(tmpindex < pCache->templateCount)
  2552. {
  2553. if(
  2554. !slapi_utf8casecmp((unsigned char*)pCache->ppTemplateList[tmpindex],(unsigned char*)pCache->ppTemplateList[cmpindex]) ||
  2555. slapi_dn_issuffix(pCache->ppTemplateList[tmpindex], pCache->ppTemplateList[cmpindex])
  2556. )
  2557. {
  2558. /* this guy is a waste of space */
  2559. pCache->ppTemplateList[tmpindex] = 0;
  2560. actualCount--;
  2561. }
  2562. else
  2563. cmpindex = tmpindex;
  2564. tmpindex++;
  2565. }
  2566. /* now shuffle everything up to the front to cover the bald spots */
  2567. tmpindex = 1;
  2568. cmpindex = 0;
  2569. while(tmpindex < pCache->templateCount)
  2570. {
  2571. if(pCache->ppTemplateList[tmpindex] != 0)
  2572. {
  2573. if(cmpindex)
  2574. {
  2575. pCache->ppTemplateList[cmpindex] = pCache->ppTemplateList[tmpindex];
  2576. pCache->ppTemplateList[tmpindex] = 0;
  2577. cmpindex++;
  2578. }
  2579. }
  2580. else
  2581. {
  2582. if(cmpindex == 0)
  2583. cmpindex = tmpindex;
  2584. }
  2585. tmpindex++;
  2586. }
  2587. pCache->templateCount = actualCount;
  2588. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_index_all - cos cache index built\n");
  2589. ret = 0;
  2590. }
  2591. else
  2592. {
  2593. if(pCache->ppAttrIndex)
  2594. slapi_ch_free((void**)(&pCache->ppAttrIndex));
  2595. if(pCache->ppTemplateList)
  2596. slapi_ch_free((void**)(&pCache->ppTemplateList));
  2597. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_index_all - "
  2598. "Failed to allocate index memory\n");
  2599. }
  2600. }
  2601. else
  2602. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_index_all - No attributes to index\n");
  2603. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_index_all\n");
  2604. return ret;
  2605. }
  2606. /*
  2607. cos_cache_total_attr_count
  2608. --------------------------
  2609. walks the entire cache counting all attributes
  2610. note: this is coded so that it may be called
  2611. prior to the cache indexing of attributes - in
  2612. fact it is called by the code that creates the
  2613. index. Once indexing has been performed, it is
  2614. *much* *much* faster to get the count from the
  2615. cache object itself - cosCache::attrCount.
  2616. Additionally - a side effect is that the template
  2617. target trees are counted and placed in the cache level
  2618. target tree count - probably should be renamed,
  2619. but lets let it slide for now
  2620. returns the number of attributes counted
  2621. */
  2622. static int cos_cache_total_attr_count(cosCache *pCache)
  2623. {
  2624. int count = 0;
  2625. cosDefinitions *pDef = pCache->pDefs;
  2626. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_total_attr_count\n");
  2627. pCache->templateCount = 0;
  2628. while(pDef)
  2629. {
  2630. cosTemplates *pCosTmps = pDef->pCosTmps;
  2631. while(pCosTmps)
  2632. {
  2633. cosAttributes *pAttrs = pCosTmps->pAttrs;
  2634. while(pAttrs)
  2635. {
  2636. count++;
  2637. pAttrs = pAttrs->list.pNext;
  2638. }
  2639. pCache->templateCount++;
  2640. pCosTmps = pCosTmps->list.pNext;
  2641. }
  2642. pDef = pDef->list.pNext;
  2643. }
  2644. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_total_attr_count\n");
  2645. return count;
  2646. }
  2647. static int cos_cache_attr_compare(const void *e1, const void *e2)
  2648. {
  2649. int com_Result;
  2650. cosAttributes *pAttr = (*(cosAttributes**)e1);
  2651. cosTemplates *pTemplate = (cosTemplates*)pAttr->pParent;
  2652. cosAttributes *pAttr1 = (*(cosAttributes**)e2);
  2653. cosTemplates *pTemplate1 = (cosTemplates*)pAttr1->pParent;
  2654. /* Now compare the names of the attributes */
  2655. com_Result = slapi_utf8casecmp((unsigned char*)(*(cosAttributes**)e1)->pAttrName,
  2656. (unsigned char*)(*(cosAttributes**)e2)->pAttrName);
  2657. if(0 == com_Result){
  2658. /* Now compare the cosPriorities */
  2659. com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
  2660. }
  2661. if(0 == com_Result)
  2662. return -1;
  2663. return com_Result;
  2664. }
  2665. static int cos_cache_string_compare(const void *e1, const void *e2)
  2666. {
  2667. if (!e1 && e2) {
  2668. return 1;
  2669. } else if (e1 && !e2) {
  2670. return -1;
  2671. } else if (!e1 && !e2) {
  2672. return 0;
  2673. }
  2674. return slapi_utf8casecmp((*(unsigned char**)e1),(*(unsigned char**)e2));
  2675. }
  2676. static int cos_cache_template_index_compare(const void *e1, const void *e2)
  2677. {
  2678. int ret = 0;
  2679. if (!e1 && e2) {
  2680. return 1;
  2681. } else if (e1 && !e2) {
  2682. return -1;
  2683. } else if (!e1 && !e2) {
  2684. return 0;
  2685. }
  2686. if(0 == slapi_dn_issuffix((const char*)e1,*(const char**)e2))
  2687. ret = slapi_utf8casecmp(*(unsigned char**)e2,(unsigned char*)e1);
  2688. else
  2689. ret = 0;
  2690. return ret;
  2691. }
  2692. /*
  2693. cos_cache_template_index_bsearch
  2694. --------------------------------
  2695. searches the template dn index for a match
  2696. */
  2697. static int cos_cache_template_index_bsearch(const char *dn)
  2698. {
  2699. int ret = 0;
  2700. cosCache *pCache;
  2701. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_template_index_bsearch\n");
  2702. if(-1 != cos_cache_getref((cos_cache**)&pCache))
  2703. {
  2704. if(bsearch(dn, pCache->ppTemplateList, pCache->templateCount, sizeof(char*), cos_cache_template_index_compare))
  2705. ret = 1;
  2706. cos_cache_release((cos_cache*)pCache);
  2707. }
  2708. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_template_index_bsearch\n");
  2709. return ret;
  2710. }
  2711. /*
  2712. cos_cache_attr_index_bsearch - RECURSIVE
  2713. ----------------------------------------
  2714. performs a binary search on the cache attribute index
  2715. return -1 if key is not found
  2716. the index into attribute index array of the first occurrance
  2717. of that attribute type otherwise
  2718. */
  2719. static int cos_cache_attr_index_bsearch( const cosCache *pCache, const cosAttributes *key, int lower, int upper )
  2720. {
  2721. int ret = -1;
  2722. int index = 0;
  2723. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_attr_index_bsearch\n");
  2724. if(upper >= lower)
  2725. {
  2726. if(upper != 0)
  2727. index = ((upper-lower)/2) + lower;
  2728. else
  2729. index = 0;
  2730. ret = slapi_utf8casecmp((unsigned char*)key->pAttrName, (unsigned char*)(pCache->ppAttrIndex)[index]->pAttrName);
  2731. if(ret == 0)
  2732. {
  2733. /*
  2734. we have a match, backtrack to the
  2735. first occurrance of this attribute
  2736. type
  2737. */
  2738. do
  2739. {
  2740. index--;
  2741. if(index >= 0)
  2742. ret = slapi_utf8casecmp((unsigned char*)key->pAttrName, (unsigned char*)(pCache->ppAttrIndex)[index]->pAttrName);
  2743. } while(index >= 0 && ret == 0);
  2744. index++;
  2745. }
  2746. else
  2747. {
  2748. /* seek elsewhere */
  2749. if(ret < 0)
  2750. {
  2751. /* take the low road */
  2752. index = cos_cache_attr_index_bsearch(pCache, key, lower, index-1);
  2753. }
  2754. else
  2755. {
  2756. /* go high */
  2757. index = cos_cache_attr_index_bsearch(pCache, key, index+1, upper);
  2758. }
  2759. }
  2760. }
  2761. else
  2762. index = -1;
  2763. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_attr_index_bsearch\n");
  2764. return index;
  2765. }
  2766. static int cos_cache_cmp_attr(cosAttributes *pAttr, Slapi_Value *test_this, int *result)
  2767. {
  2768. int ret = 0;
  2769. int index = 0;
  2770. cosAttrValue *pAttrVal = pAttr->pAttrValue;
  2771. char *the_cmp = (char *)slapi_value_get_string(test_this);
  2772. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_cmp_attr\n");
  2773. *result = 0;
  2774. while( pAttrVal )
  2775. {
  2776. ret = 1; /* CoS attribute exists; return 1 */
  2777. if(!slapi_utf8casecmp((unsigned char*)the_cmp, (unsigned char*)pAttrVal->val))
  2778. {
  2779. /* compare match */
  2780. *result = 1;
  2781. break;
  2782. }
  2783. pAttrVal = pAttrVal->list.pNext;
  2784. index++;
  2785. }
  2786. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_cmp_attr\n");
  2787. return ret;
  2788. }
  2789. /*
  2790. cos_cache_cos_2_slapi_attr
  2791. ----------------------
  2792. converts a cosAttributes structure to a Slapi_Attribute
  2793. */
  2794. static int cos_cache_cos_2_slapi_valueset(cosAttributes *pAttr, Slapi_ValueSet **out_vs)
  2795. {
  2796. int ret = 0;
  2797. int index = 0;
  2798. cosAttrValue *pAttrVal = pAttr->pAttrValue;
  2799. int add_mode = 0;
  2800. static Slapi_Attr *attr = 0; /* allocated once, never freed */
  2801. static int done_once = 0;
  2802. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_cos_2_slapi_valueset\n");
  2803. /* test out_vs for existing values */
  2804. if(*out_vs)
  2805. {
  2806. add_mode = 1;
  2807. if(!done_once)
  2808. {
  2809. attr = slapi_attr_new(); /* lord knows why this is needed by slapi_valueset_find*/
  2810. slapi_attr_init(attr, "cos-bogus");
  2811. done_once = 1;
  2812. }
  2813. }
  2814. else
  2815. *out_vs = slapi_valueset_new();
  2816. if(*out_vs)
  2817. {
  2818. if(!add_mode)
  2819. slapi_valueset_init(*out_vs);
  2820. while( pAttrVal )
  2821. {
  2822. Slapi_Value *val = slapi_value_new_string(pAttrVal->val);
  2823. if(val) {
  2824. if(!add_mode || !slapi_valueset_find(attr, *out_vs, val)) {
  2825. slapi_valueset_add_value_ext(*out_vs, val, SLAPI_VALUE_FLAG_PASSIN);
  2826. }
  2827. else {
  2828. slapi_value_free(&val);
  2829. }
  2830. }
  2831. else
  2832. {
  2833. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_cos_2_slapi_valueset - "
  2834. "Memory allocation error\n");
  2835. ret = -1;
  2836. goto bail;
  2837. }
  2838. pAttrVal = pAttrVal->list.pNext;
  2839. index++;
  2840. }
  2841. }
  2842. else
  2843. {
  2844. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_cos_2_slapi_valueset - "
  2845. "Memory allocation error\n");
  2846. ret = -1;
  2847. }
  2848. bail:
  2849. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_cos_2_slapi_valueset\n");
  2850. return ret;
  2851. }
  2852. /*
  2853. cos_cache_change_notify
  2854. -----------------------
  2855. determines if the change effects the cache and if so
  2856. signals a rebuild.
  2857. XXXrbyrne This whole mechanism needs to be revisited--it means that
  2858. the modifying client gets his LDAP response, and an unspecified and
  2859. variable
  2860. period of time later, his mods get taken into account in the cos cache.
  2861. This makes it hard to program reliable admin tools for COS--DSAME
  2862. has already indicated this is an issue for them.
  2863. Additionally, it regenerates the _whole_ cache even for eeny weeny mods--
  2864. does it really neeed to ? Additionally, in order to ensure we
  2865. do not miss any mods, we may tend to regen the cache, even if we've already
  2866. taken a mod into account in an earlier regeneration--currently there is no
  2867. way to know we've already dealt with the mod.
  2868. The right thing is something like: figure out what's being changed
  2869. and change only that in the cos cache and do it _before_ the response
  2870. goes to the client....or do a task that he can poll.
  2871. */
  2872. void cos_cache_change_notify(Slapi_PBlock *pb)
  2873. {
  2874. const char *dn;
  2875. Slapi_DN *sdn = NULL;
  2876. int do_update = 0;
  2877. struct slapi_entry *e;
  2878. Slapi_Backend *be=NULL;
  2879. int rc = 0;
  2880. int optype = -1;
  2881. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_change_notify\n");
  2882. /* Don't update local cache when remote entries are updated. */
  2883. slapi_pblock_get( pb, SLAPI_BACKEND, &be );
  2884. if ((be && (slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA))) ||
  2885. (NULL == be)) {
  2886. goto bail;
  2887. }
  2888. /* need to work out if a cache rebuild is necessary */
  2889. if(slapi_pblock_get( pb, SLAPI_TARGET_SDN, &sdn )) {
  2890. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_change_notify - "
  2891. "Failed to get dn of changed entry\n");
  2892. goto bail;
  2893. }
  2894. dn = slapi_sdn_get_dn(sdn);
  2895. slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc);
  2896. if (0 != rc) {
  2897. /* The operation did not succeed. As far as the cos cache is concerned, no need to update anything */
  2898. goto bail;
  2899. }
  2900. /*
  2901. * For DELETE, MODIFY, MODRDN: see if the pre-op entry was cos significant.
  2902. * For ADD, MODIFY, MODRDN: see if the post-op was cos significant.
  2903. * Touching a cos significant entry triggers the update
  2904. * of the whole cache.
  2905. */
  2906. slapi_pblock_get ( pb, SLAPI_OPERATION_TYPE, &optype );
  2907. if ( optype == SLAPI_OPERATION_DELETE ||
  2908. optype == SLAPI_OPERATION_MODIFY ||
  2909. optype == SLAPI_OPERATION_MODRDN ) {
  2910. slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
  2911. if ( cos_cache_entry_is_cos_related(e)) {
  2912. do_update = 1;
  2913. }
  2914. }
  2915. if ( !do_update &&
  2916. (optype == SLAPI_OPERATION_ADD ||
  2917. optype == SLAPI_OPERATION_MODIFY ||
  2918. optype == SLAPI_OPERATION_MODRDN )) {
  2919. /* Adds have null pre-op entries */
  2920. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
  2921. if ( cos_cache_entry_is_cos_related(e)) {
  2922. do_update = 1;
  2923. }
  2924. }
  2925. /*
  2926. * Check if this was an entry in a template tree (dn contains
  2927. * the old dn value).
  2928. * It's only relevant for indirect templates, which will
  2929. * not usually contain the "objectclass: costemplate" pair
  2930. * and so will not get detected by the above code.
  2931. * In fact, everything would still work fine if
  2932. * we just ignored a mod of one of these indirect templates,
  2933. * as we do not cache values from them, but the advantage of
  2934. * triggering an update here is that
  2935. * we can maintain the invariant that we only ever cache
  2936. * definitions that have _valid_ templates--the active cache
  2937. * stays lean in the face of errors.
  2938. */
  2939. if( !do_update && cos_cache_template_index_bsearch(dn)) {
  2940. slapi_log_err(SLAPI_LOG_PLUGIN, COS_PLUGIN_SUBSYSTEM, "cos_cache_change_notify - "
  2941. "Updating due to indirect template change(%s)\n", dn);
  2942. do_update = 1;
  2943. }
  2944. /* Do the update if required */
  2945. if(do_update)
  2946. {
  2947. slapi_lock_mutex(change_lock);
  2948. slapi_notify_condvar( something_changed, 1 );
  2949. cos_cache_notify_flag = 1;
  2950. slapi_unlock_mutex(change_lock);
  2951. }
  2952. bail:
  2953. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_change_notify\n");
  2954. }
  2955. /*
  2956. cos_cache_stop
  2957. --------------
  2958. notifies the cache thread we are stopping
  2959. */
  2960. void cos_cache_stop(void)
  2961. {
  2962. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_stop\n");
  2963. /* first deregister our state change func */
  2964. slapi_unregister_backend_state_change((void *)cos_cache_backend_state_change);
  2965. slapi_lock_mutex(change_lock);
  2966. keeprunning = 0;
  2967. slapi_notify_condvar( something_changed, 1 );
  2968. slapi_unlock_mutex(change_lock);
  2969. /* wait on shutdown */
  2970. slapi_lock_mutex(stop_lock);
  2971. /* release the caches reference to the cache */
  2972. cos_cache_release(pCache);
  2973. slapi_destroy_mutex(cache_lock); cache_lock = NULL;
  2974. slapi_destroy_mutex(change_lock); change_lock = NULL;
  2975. slapi_destroy_condvar(something_changed); something_changed = NULL;
  2976. slapi_unlock_mutex(stop_lock);
  2977. slapi_destroy_mutex(stop_lock); stop_lock = NULL;
  2978. slapi_destroy_condvar(start_cond); start_cond = NULL;
  2979. slapi_destroy_mutex(start_lock); start_lock = NULL;
  2980. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_stop\n");
  2981. }
  2982. /*
  2983. cos_cache_backwards_stricmp_and_clip
  2984. ------------------------------------
  2985. compares s2 to s1 starting from end of the strings until the beginning of
  2986. either matches result in the s2 value being clipped from s1 with a NULL char
  2987. and 1 being returned as opposed to 0
  2988. */
  2989. static int cos_cache_backwards_stricmp_and_clip(char*s1,char*s2)
  2990. {
  2991. int ret = 0;
  2992. int s1len = 0;
  2993. int s2len = 0;
  2994. s1len = strlen(s1);
  2995. s2len = strlen(s2);
  2996. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "--> cos_cache_backwards_stricmp_and_clip - s1 %d s2 %d\n",s1len,s2len);
  2997. if(s1len > s2len && s2len > 0)
  2998. {
  2999. /* In some cases this can go below 0 causing invalid reads
  3000. * We make the check for > 0, because if we are at 1 -> 0 is next
  3001. * If the check is > -1, we can easily get to 0, then -1, creating invalid read.
  3002. */
  3003. while(s1len > 0 && s2len > 0)
  3004. {
  3005. s1len--;
  3006. s2len--;
  3007. if(s1[s1len] != s2[s2len])
  3008. break;
  3009. else
  3010. {
  3011. if(s2len == 0)
  3012. {
  3013. /* hit! now clip */
  3014. ret = 1;
  3015. s1[s1len] = '\0';
  3016. }
  3017. }
  3018. }
  3019. }
  3020. slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_backwards_stricmp_and_clip\n");
  3021. return ret;
  3022. }
  3023. static int cos_cache_follow_pointer( vattr_context *c, const char *dn, char *type, Slapi_ValueSet **out_vs, Slapi_Value *test_this, int *result, int flags)
  3024. {
  3025. int ret = -1; /* assume failure */
  3026. Slapi_PBlock *pDnSearch = 0;
  3027. Slapi_Entry **pEntryList = 0;
  3028. char *attrs[2];
  3029. int op = 0;
  3030. int type_test = 0;
  3031. int type_name_disposition = 0;
  3032. char *actual_type_name = 0;
  3033. int free_flags = 0;
  3034. Slapi_ValueSet *tmp_vs = 0;
  3035. attrs[0] = type;
  3036. attrs[1] = 0;
  3037. /* Use new internal operation API */
  3038. pDnSearch = slapi_pblock_new();
  3039. if (pDnSearch) {
  3040. slapi_search_internal_set_pb(pDnSearch, dn, LDAP_SCOPE_BASE,"(|(objectclass=*)(objectclass=ldapsubentry))",attrs,
  3041. 0,NULL,NULL,cos_get_plugin_identity(),0);
  3042. slapi_search_internal_pb(pDnSearch);
  3043. slapi_pblock_get( pDnSearch, SLAPI_PLUGIN_INTOP_RESULT, &ret);
  3044. }
  3045. if(pDnSearch && (ret == LDAP_SUCCESS))
  3046. {
  3047. ret = -1;
  3048. slapi_pblock_get( pDnSearch, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &pEntryList);
  3049. if(pEntryList)
  3050. {
  3051. if(out_vs) /* if this set, a value is required */
  3052. op = 1;
  3053. else if(test_this && result) /* compare op */
  3054. op = 2;
  3055. else
  3056. {
  3057. /* requires only type present */
  3058. op = 1;
  3059. type_test = 1;
  3060. }
  3061. switch(op)
  3062. {
  3063. case 1:
  3064. /* straight value return or type test */
  3065. if(type_test)
  3066. out_vs = &tmp_vs;
  3067. ret = slapi_vattr_values_get_sp(c, pEntryList[0], type, out_vs,&type_name_disposition, &actual_type_name, flags, &free_flags);
  3068. if(actual_type_name)
  3069. slapi_ch_free((void **) &actual_type_name);
  3070. if(type_test && free_flags == SLAPI_VIRTUALATTRS_RETURNED_COPIES)
  3071. slapi_valueset_free(*out_vs);
  3072. break;
  3073. case 2:
  3074. /* this must be a compare op */
  3075. ret = slapi_vattr_value_compare_sp(c, pEntryList[0],type, test_this, result, flags);
  3076. break;
  3077. }
  3078. }
  3079. }
  3080. /* clean up */
  3081. if(pDnSearch)
  3082. {
  3083. slapi_free_search_results_internal(pDnSearch);
  3084. slapi_pblock_destroy(pDnSearch);
  3085. }
  3086. return ret;
  3087. }
  3088. /*
  3089. * cos_cache_backend_state_change()
  3090. * --------------------------------
  3091. * This is called when a backend changes state
  3092. * We simply signal to rebuild the cos cache in this case
  3093. *
  3094. */
  3095. void cos_cache_backend_state_change(void *handle __attribute__((unused)),
  3096. char *be_name __attribute__((unused)),
  3097. int old_be_state __attribute__((unused)),
  3098. int new_be_state __attribute__((unused)))
  3099. {
  3100. slapi_lock_mutex(change_lock);
  3101. slapi_notify_condvar( something_changed, 1 );
  3102. slapi_unlock_mutex(change_lock);
  3103. }
  3104. /*
  3105. * returns non-zero: entry is cos significant (note does not detect indirect
  3106. * template entries).
  3107. * 0 : entry is not cos significant.
  3108. */
  3109. static int cos_cache_entry_is_cos_related( Slapi_Entry *e) {
  3110. int rc = 0;
  3111. Slapi_Attr *pObjclasses = NULL;
  3112. if ( e == NULL ) {
  3113. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_entry_is_cos_related - "
  3114. "Modified entry is NULL--updating cache just in case\n");
  3115. rc = 1;
  3116. } else {
  3117. if(slapi_entry_attr_find( e, "objectclass", &pObjclasses ))
  3118. {
  3119. slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_entry_is_cos_related - "
  3120. "Failed to get objectclass from %s\n",
  3121. slapi_entry_get_dn(e));
  3122. rc = 0;
  3123. } else {
  3124. Slapi_Value *val = NULL;
  3125. int index = 0;
  3126. char *pObj;
  3127. /* check out the object classes to see if this was a cosDefinition */
  3128. index = slapi_attr_first_value( pObjclasses, &val );
  3129. while(!rc && val)
  3130. {
  3131. pObj = (char*)slapi_value_get_string(val);
  3132. if(!strcasecmp(pObj, "cosdefinition") ||
  3133. !strcasecmp(pObj, "cossuperdefinition") ||
  3134. !strcasecmp(pObj, "costemplate"))
  3135. {
  3136. rc = 1;
  3137. }
  3138. index = slapi_attr_next_value( pObjclasses, index, &val );
  3139. }
  3140. }
  3141. }
  3142. return(rc);
  3143. }