memberof.c 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2010 Red Hat, Inc.
  3. * All rights reserved.
  4. *
  5. * License: GPL (version 3 or any later version).
  6. * See LICENSE for details.
  7. * END COPYRIGHT BLOCK
  8. **/
  9. /* The memberof plugin updates the memberof attribute of entries
  10. * based on modifications performed on groupofuniquenames entries
  11. *
  12. * In addition the plugin provides a DS task that may be started
  13. * administrative clients and that creates the initial memberof
  14. * list for imported entries and/or fixes the memberof list of
  15. * existing entries that have inconsistent state (for example,
  16. * if the memberof attribute was incorrectly edited directly)
  17. *
  18. * To start the memberof task add an entry like:
  19. *
  20. * dn: cn=mytask, cn=memberof task, cn=tasks, cn=config
  21. * objectClass: top
  22. * objectClass: extensibleObject
  23. * cn: mytask
  24. * basedn: dc=example, dc=com
  25. * filter: (uid=test4)
  26. *
  27. * where "basedn" is required and refers to the top most node to perform the
  28. * task on, and where "filter" is an optional attribute that provides a filter
  29. * describing the entries to be worked on
  30. */
  31. #ifdef HAVE_CONFIG_H
  32. # include <config.h>
  33. #endif
  34. #include "slapi-plugin.h"
  35. #include "string.h"
  36. #include "nspr.h"
  37. #include "memberof.h"
  38. static Slapi_PluginDesc pdesc = { "memberof", VENDOR,
  39. DS_PACKAGE_VERSION, "memberof plugin" };
  40. static void* _PluginID = NULL;
  41. static Slapi_DN* _ConfigAreaDN = NULL;
  42. static Slapi_RWLock *config_rwlock = NULL;
  43. static Slapi_DN* _pluginDN = NULL;
  44. static PRMonitor *memberof_operation_lock = 0;
  45. MemberOfConfig *qsortConfig = 0;
  46. static int usetxn = 0;
  47. static int premodfn = 0;
  48. typedef struct _memberofstringll
  49. {
  50. const char *dn;
  51. void *next;
  52. } memberofstringll;
  53. typedef struct _memberof_get_groups_data
  54. {
  55. MemberOfConfig *config;
  56. Slapi_Value *memberdn_val;
  57. Slapi_ValueSet **groupvals;
  58. Slapi_ValueSet **group_norm_vals;
  59. } memberof_get_groups_data;
  60. /*** function prototypes ***/
  61. /* exported functions */
  62. int memberof_postop_init(Slapi_PBlock *pb );
  63. static int memberof_internal_postop_init(Slapi_PBlock *pb);
  64. static int memberof_preop_init(Slapi_PBlock *pb);
  65. /* plugin callbacks */
  66. static int memberof_postop_del(Slapi_PBlock *pb );
  67. static int memberof_postop_modrdn(Slapi_PBlock *pb );
  68. static int memberof_postop_modify(Slapi_PBlock *pb );
  69. static int memberof_postop_add(Slapi_PBlock *pb );
  70. static int memberof_postop_start(Slapi_PBlock *pb);
  71. static int memberof_postop_close(Slapi_PBlock *pb);
  72. /* supporting cast */
  73. static int memberof_oktodo(Slapi_PBlock *pb);
  74. static Slapi_DN *memberof_getsdn(Slapi_PBlock *pb);
  75. static int memberof_modop_one(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op,
  76. Slapi_DN *op_this_sdn, Slapi_DN *op_to_sdn);
  77. static int memberof_modop_one_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op,
  78. Slapi_DN *group_sdn, Slapi_DN *op_this_sdn, Slapi_DN *op_to_sdn,
  79. memberofstringll *stack);
  80. static int memberof_add_one(Slapi_PBlock *pb, MemberOfConfig *config,
  81. Slapi_DN *addthis_sdn, Slapi_DN *addto_sdn);
  82. static int memberof_del_one(Slapi_PBlock *pb, MemberOfConfig *config,
  83. Slapi_DN *delthis_sdn, Slapi_DN *delfrom_sdn);
  84. static int memberof_mod_smod_list(Slapi_PBlock *pb, MemberOfConfig *config,
  85. int mod, Slapi_DN *group_sdn, Slapi_Mod *smod);
  86. static int memberof_add_smod_list(Slapi_PBlock *pb, MemberOfConfig *config,
  87. Slapi_DN *group_sdn, Slapi_Mod *smod);
  88. static int memberof_del_smod_list(Slapi_PBlock *pb, MemberOfConfig *config,
  89. Slapi_DN *group_sdn, Slapi_Mod *smod);
  90. static int memberof_mod_attr_list(Slapi_PBlock *pb, MemberOfConfig *config, int mod,
  91. Slapi_DN *group_sdn, Slapi_Attr *attr);
  92. static int memberof_mod_attr_list_r(Slapi_PBlock *pb, MemberOfConfig *config,
  93. int mod, Slapi_DN *group_sdn, Slapi_DN *op_this_sdn, Slapi_Attr *attr,
  94. memberofstringll *stack);
  95. static int memberof_add_attr_list(Slapi_PBlock *pb, MemberOfConfig *config,
  96. Slapi_DN *group_sdn, Slapi_Attr *attr);
  97. static int memberof_del_attr_list(Slapi_PBlock *pb, MemberOfConfig *config,
  98. Slapi_DN *group_sdn, Slapi_Attr *attr);
  99. static int memberof_moddn_attr_list(Slapi_PBlock *pb, MemberOfConfig *config,
  100. Slapi_DN *pre_sdn, Slapi_DN *post_sdn, Slapi_Attr *attr);
  101. static int memberof_replace_list(Slapi_PBlock *pb, MemberOfConfig *config,
  102. Slapi_DN *group_sdn);
  103. static void memberof_set_plugin_id(void * plugin_id);
  104. static int memberof_compare(MemberOfConfig *config, const void *a, const void *b);
  105. static int memberof_qsort_compare(const void *a, const void *b);
  106. static void memberof_load_array(Slapi_Value **array, Slapi_Attr *attr);
  107. static int memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_DN *sdn);
  108. static int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn, MemberOfConfig *config,
  109. char **types, plugin_search_entry_callback callback, void *callback_data);
  110. static int memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn,
  111. Slapi_Value *memberdn);
  112. static int memberof_is_grouping_attr(char *type, MemberOfConfig *config);
  113. static Slapi_ValueSet *memberof_get_groups(MemberOfConfig *config, Slapi_DN *member_sdn);
  114. static int memberof_get_groups_r(MemberOfConfig *config, Slapi_DN *member_sdn,
  115. memberof_get_groups_data *data);
  116. static int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data);
  117. static int memberof_test_membership(Slapi_PBlock *pb, MemberOfConfig *config,
  118. Slapi_DN *group_sdn);
  119. static int memberof_test_membership_callback(Slapi_Entry *e, void *callback_data);
  120. static int memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data);
  121. static int memberof_replace_dn_type_callback(Slapi_Entry *e, void *callback_data);
  122. static int memberof_replace_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config,
  123. Slapi_DN *pre_sdn, Slapi_DN *post_sdn);
  124. static int memberof_modop_one_replace_r(Slapi_PBlock *pb, MemberOfConfig *config,
  125. int mod_op, Slapi_DN *group_sdn, Slapi_DN *op_this_sdn,
  126. Slapi_DN *replace_with_sdn, Slapi_DN *op_to_sdn, memberofstringll *stack);
  127. static int memberof_task_add(Slapi_PBlock *pb, Slapi_Entry *e,
  128. Slapi_Entry *eAfter, int *returncode, char *returntext,
  129. void *arg);
  130. static void memberof_task_destructor(Slapi_Task *task);
  131. static const char *fetch_attr(Slapi_Entry *e, const char *attrname,
  132. const char *default_val);
  133. static void memberof_fixup_task_thread(void *arg);
  134. static int memberof_fix_memberof(MemberOfConfig *config, char *dn, char *filter_str);
  135. static int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data);
  136. static int memberof_entry_in_scope(MemberOfConfig *config, Slapi_DN *sdn);
  137. static int memberof_add_objectclass(char *auto_add_oc, const char *dn);
  138. static int memberof_add_memberof_attr(LDAPMod **mods, const char *dn, char *add_oc);
  139. /*** implementation ***/
  140. /*** exported functions ***/
  141. /*
  142. * memberof_postop_init()
  143. *
  144. * Register plugin call backs
  145. *
  146. */
  147. int
  148. memberof_postop_init(Slapi_PBlock *pb)
  149. {
  150. int ret = 0;
  151. char *memberof_plugin_identity = 0;
  152. Slapi_Entry *plugin_entry = NULL;
  153. char *plugin_type = NULL;
  154. char *preop_plugin_type = NULL;
  155. int delfn = SLAPI_PLUGIN_POST_DELETE_FN;
  156. int mdnfn = SLAPI_PLUGIN_POST_MODRDN_FN;
  157. int modfn = SLAPI_PLUGIN_POST_MODIFY_FN;
  158. int addfn = SLAPI_PLUGIN_POST_ADD_FN;
  159. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  160. "--> memberof_postop_init\n" );
  161. /* get args */
  162. if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
  163. plugin_entry &&
  164. (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
  165. plugin_type && strstr(plugin_type, "betxn")) {
  166. usetxn = 1;
  167. delfn = SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN;
  168. mdnfn = SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN;
  169. modfn = SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN;
  170. addfn = SLAPI_PLUGIN_BE_TXN_POST_ADD_FN;
  171. }
  172. slapi_ch_free_string(&plugin_type);
  173. if(usetxn){
  174. preop_plugin_type = "betxnpreoperation";
  175. premodfn = SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN;
  176. } else {
  177. preop_plugin_type = "preoperation";
  178. premodfn = SLAPI_PLUGIN_PRE_MODIFY_FN;
  179. }
  180. if(plugin_entry){
  181. memberof_set_plugin_area(slapi_entry_get_sdn(plugin_entry));
  182. }
  183. /*
  184. * Get plugin identity and stored it for later use
  185. * Used for internal operations
  186. */
  187. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &memberof_plugin_identity);
  188. PR_ASSERT (memberof_plugin_identity);
  189. memberof_set_plugin_id(memberof_plugin_identity);
  190. ret = ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
  191. slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&pdesc ) != 0 ||
  192. slapi_pblock_set( pb, delfn, (void *) memberof_postop_del ) != 0 ||
  193. slapi_pblock_set( pb, mdnfn, (void *) memberof_postop_modrdn ) != 0 ||
  194. slapi_pblock_set( pb, modfn, (void *) memberof_postop_modify ) != 0 ||
  195. slapi_pblock_set( pb, addfn, (void *) memberof_postop_add ) != 0 ||
  196. slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) memberof_postop_start ) != 0 ||
  197. slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) memberof_postop_close ) != 0 );
  198. if (!ret && !usetxn &&
  199. slapi_register_plugin("internalpostoperation", /* op type */
  200. 1, /* Enabled */
  201. "memberof_postop_init", /* this function desc */
  202. memberof_internal_postop_init, /* init func */
  203. MEMBEROF_INT_PREOP_DESC, /* plugin desc */
  204. NULL, /* ? */
  205. memberof_plugin_identity /* access control */))
  206. {
  207. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  208. "memberof_postop_init failed\n" );
  209. ret = -1;
  210. }
  211. else if (ret)
  212. {
  213. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  214. "memberof_postop_init failed\n" );
  215. ret = -1;
  216. }
  217. /*
  218. * Setup the preop plugin for shared config updates
  219. */
  220. if (!ret && slapi_register_plugin(preop_plugin_type, /* op type */
  221. 1, /* Enabled */
  222. "memberof_preop_init", /* this function desc */
  223. memberof_preop_init, /* init func */
  224. MEMBEROF_PREOP_DESC, /* plugin desc */
  225. NULL, /* ? */
  226. memberof_plugin_identity /* access control */))
  227. {
  228. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  229. "memberof_preop_init failed\n" );
  230. ret = -1;
  231. }
  232. else if (ret)
  233. {
  234. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  235. "memberof_preop_init failed\n");
  236. ret = -1;
  237. }
  238. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  239. "<-- memberof_postop_init\n" );
  240. return ret;
  241. }
  242. static int
  243. memberof_preop_init(Slapi_PBlock *pb)
  244. {
  245. int status = 0;
  246. if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) != 0 ||
  247. slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &pdesc) != 0 ||
  248. slapi_pblock_set(pb, premodfn, (void *)memberof_shared_config_validate) != 0)
  249. {
  250. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  251. "memberof_internal_postop_init: failed to register plugin\n");
  252. status = -1;
  253. }
  254. return status;
  255. }
  256. static int
  257. memberof_internal_postop_init(Slapi_PBlock *pb)
  258. {
  259. int status = 0;
  260. if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  261. SLAPI_PLUGIN_VERSION_01) != 0 ||
  262. slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
  263. (void *) &pdesc) != 0 ||
  264. slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN,
  265. (void *) memberof_postop_del) != 0 ||
  266. slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN,
  267. (void *) memberof_postop_modrdn ) != 0 ||
  268. slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN,
  269. (void *) memberof_postop_modify ) != 0 ||
  270. slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN,
  271. (void *) memberof_postop_add ) != 0) {
  272. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  273. "memberof_internal_postop_init: failed to register plugin\n");
  274. status = -1;
  275. }
  276. return status;
  277. }
  278. /*
  279. * memberof_postop_start()
  280. *
  281. * Do plugin start up stuff
  282. *
  283. */
  284. int memberof_postop_start(Slapi_PBlock *pb)
  285. {
  286. Slapi_PBlock *search_pb = NULL;
  287. Slapi_Entry **entries = NULL;
  288. Slapi_Entry *config_e = NULL; /* entry containing plugin config */
  289. char *config_area = NULL;
  290. int result = 0;
  291. int rc = 0;
  292. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  293. "--> memberof_postop_start\n" );
  294. memberof_operation_lock = PR_NewMonitor();
  295. if(0 == memberof_operation_lock)
  296. {
  297. rc = -1;
  298. goto bail;
  299. }
  300. if(config_rwlock == NULL){
  301. if((config_rwlock = slapi_new_rwlock()) == NULL){
  302. rc = -1;
  303. goto bail;
  304. }
  305. }
  306. /* Set the alternate config area if one is defined. */
  307. slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_AREA, &config_area);
  308. if (config_area)
  309. {
  310. search_pb = slapi_pblock_new();
  311. slapi_search_internal_set_pb(search_pb, config_area, LDAP_SCOPE_BASE, "objectclass=*",
  312. NULL, 0, NULL, NULL, memberof_get_plugin_id(), 0);
  313. slapi_search_internal_pb(search_pb);
  314. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
  315. if (LDAP_SUCCESS != result) {
  316. if (result == LDAP_NO_SUCH_OBJECT) {
  317. /* log an error and use the plugin entry for the config */
  318. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  319. "memberof_postop_start: Config entry \"%s\" does "
  320. "not exist.\n", config_area);
  321. rc = -1;
  322. goto bail;
  323. }
  324. } else {
  325. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  326. if(entries && entries[0]){
  327. config_e = entries[0];
  328. } else {
  329. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  330. "memberof_postop_start: Config entry \"%s\" was "
  331. "not located.\n", config_area);
  332. rc = -1;
  333. goto bail;
  334. }
  335. }
  336. } else {
  337. /* The plugin entry itself contains the config */
  338. if ( slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &config_e ) != 0 ) {
  339. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  340. "missing config entry\n" );
  341. rc = -1;
  342. goto bail;
  343. }
  344. }
  345. memberof_set_config_area(slapi_entry_get_sdn(config_e));
  346. if (( rc = memberof_config( config_e, pb )) != LDAP_SUCCESS ) {
  347. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  348. "configuration failed (%s)\n", ldap_err2string( rc ));
  349. rc = -1;
  350. goto bail;
  351. }
  352. rc = slapi_plugin_task_register_handler("memberof task", memberof_task_add, pb);
  353. if(rc)
  354. {
  355. goto bail;
  356. }
  357. /*
  358. * TODO: start up operation actor thread
  359. * need to get to a point where server failure
  360. * or shutdown doesn't hose our operations
  361. * so we should create a task entry that contains
  362. * all required information to complete the operation
  363. * then the tasks can be restarted safely if
  364. * interrupted
  365. */
  366. bail:
  367. slapi_free_search_results_internal(search_pb);
  368. slapi_pblock_destroy(search_pb);
  369. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  370. "<-- memberof_postop_start\n" );
  371. return rc;
  372. }
  373. /*
  374. * memberof_postop_close()
  375. *
  376. * Do plugin shut down stuff
  377. *
  378. */
  379. int memberof_postop_close(Slapi_PBlock *pb)
  380. {
  381. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  382. "--> memberof_postop_close\n" );
  383. slapi_plugin_task_unregister_handler("memberof task", memberof_task_add);
  384. memberof_release_config();
  385. slapi_sdn_free(&_ConfigAreaDN);
  386. slapi_sdn_free(&_pluginDN);
  387. slapi_destroy_rwlock(config_rwlock);
  388. config_rwlock = NULL;
  389. PR_DestroyMonitor(memberof_operation_lock);
  390. memberof_operation_lock = NULL;
  391. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  392. "<-- memberof_postop_close\n" );
  393. return 0;
  394. }
  395. void
  396. memberof_set_config_area(Slapi_DN *dn)
  397. {
  398. slapi_rwlock_wrlock(config_rwlock);
  399. slapi_sdn_free(&_ConfigAreaDN);
  400. _ConfigAreaDN = slapi_sdn_dup(dn);
  401. slapi_rwlock_unlock(config_rwlock);
  402. }
  403. Slapi_DN *
  404. memberof_get_config_area()
  405. {
  406. return _ConfigAreaDN;
  407. }
  408. int
  409. memberof_sdn_config_cmp(Slapi_DN *sdn)
  410. {
  411. int rc = 0;
  412. slapi_rwlock_rdlock(config_rwlock);
  413. rc = slapi_sdn_compare(sdn, memberof_get_config_area());
  414. slapi_rwlock_unlock(config_rwlock);
  415. return rc;
  416. }
  417. void
  418. memberof_set_plugin_area(Slapi_DN *sdn)
  419. {
  420. slapi_sdn_free(&_pluginDN);
  421. _pluginDN = slapi_sdn_dup(sdn);
  422. }
  423. Slapi_DN *
  424. memberof_get_plugin_area()
  425. {
  426. return _pluginDN;
  427. }
  428. /*
  429. * memberof_postop_del()
  430. *
  431. * All entries with a memberOf attribute that contains the group DN get retrieved
  432. * and have the their memberOf attribute regenerated (it is far too complex and
  433. * error prone to attempt to change only those dn values involved in this case -
  434. * mainly because the deleted group may itself be a member of other groups which
  435. * may be members of other groups etc. in a big recursive mess involving dependency
  436. * chains that must be created and traversed in order to decide if an entry should
  437. * really have those groups removed too)
  438. */
  439. int memberof_postop_del(Slapi_PBlock *pb)
  440. {
  441. int ret = SLAPI_PLUGIN_SUCCESS;
  442. MemberOfConfig *mainConfig = NULL;
  443. MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  444. Slapi_DN *sdn;
  445. void *caller_id = NULL;
  446. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  447. "--> memberof_postop_del\n" );
  448. /* We don't want to process internal modify
  449. * operations that originate from this plugin. */
  450. slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &caller_id);
  451. if (caller_id == memberof_get_plugin_id()) {
  452. /* Just return without processing */
  453. return SLAPI_PLUGIN_SUCCESS;
  454. }
  455. if(memberof_oktodo(pb) && (sdn = memberof_getsdn(pb)))
  456. {
  457. struct slapi_entry *e = NULL;
  458. slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &e );
  459. memberof_rlock_config();
  460. mainConfig = memberof_get_config();
  461. if(!memberof_entry_in_scope(mainConfig, slapi_entry_get_sdn(e))){
  462. /* The entry is not in scope, bail...*/
  463. memberof_unlock_config();
  464. goto bail;
  465. }
  466. memberof_copy_config(&configCopy, memberof_get_config());
  467. memberof_unlock_config();
  468. /* get the memberOf operation lock */
  469. memberof_lock();
  470. /* remove this DN from the
  471. * membership lists of groups
  472. */
  473. if((ret = memberof_del_dn_from_groups(pb, &configCopy, sdn))){
  474. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  475. "memberof_postop_del: error deleting dn (%s) from group. Error (%d)\n",
  476. slapi_sdn_get_dn(sdn),ret);
  477. memberof_unlock();
  478. goto bail;
  479. }
  480. /* is the entry of interest as a group? */
  481. if(e && configCopy.group_filter && 0 == slapi_filter_test_simple(e, configCopy.group_filter))
  482. {
  483. int i = 0;
  484. Slapi_Attr *attr = 0;
  485. /* Loop through to find each grouping attribute separately. */
  486. for (i = 0; configCopy.groupattrs[i] && ret == LDAP_SUCCESS; i++)
  487. {
  488. if (0 == slapi_entry_attr_find(e, configCopy.groupattrs[i], &attr))
  489. {
  490. if((ret = memberof_del_attr_list(pb, &configCopy, sdn, attr))){
  491. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  492. "memberof_postop_del: error deleting attr list - dn (%s). Error (%d)\n",
  493. slapi_sdn_get_dn(sdn),ret);
  494. }
  495. }
  496. }
  497. }
  498. memberof_unlock();
  499. bail:
  500. memberof_free_config(&configCopy);
  501. }
  502. if(ret){
  503. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
  504. ret = SLAPI_PLUGIN_FAILURE;
  505. }
  506. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  507. "<-- memberof_postop_del\n" );
  508. return ret;
  509. }
  510. typedef struct _memberof_del_dn_data
  511. {
  512. char *dn;
  513. char *type;
  514. } memberof_del_dn_data;
  515. /* Deletes a member dn from all groups that refer to it. */
  516. static int
  517. memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_DN *sdn)
  518. {
  519. int i = 0;
  520. char *groupattrs[2] = {0, 0};
  521. int rc = LDAP_SUCCESS;
  522. /* Loop through each grouping attribute to find groups that have
  523. * dn as a member. For any matches, delete the dn value from the
  524. * same grouping attribute. */
  525. for (i = 0; config->groupattrs && config->groupattrs[i] && rc == LDAP_SUCCESS; i++)
  526. {
  527. memberof_del_dn_data data = {(char *)slapi_sdn_get_dn(sdn),
  528. config->groupattrs[i]};
  529. groupattrs[0] = config->groupattrs[i];
  530. rc = memberof_call_foreach_dn(pb, sdn, config, groupattrs,
  531. memberof_del_dn_type_callback, &data);
  532. }
  533. return rc;
  534. }
  535. int
  536. memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data)
  537. {
  538. int rc = 0;
  539. LDAPMod mod;
  540. LDAPMod *mods[2];
  541. char *val[2];
  542. Slapi_PBlock *mod_pb = 0;
  543. mod_pb = slapi_pblock_new();
  544. mods[0] = &mod;
  545. mods[1] = 0;
  546. val[0] = ((memberof_del_dn_data *)callback_data)->dn;
  547. val[1] = 0;
  548. mod.mod_op = LDAP_MOD_DELETE;
  549. mod.mod_type = ((memberof_del_dn_data *)callback_data)->type;
  550. mod.mod_values = val;
  551. slapi_modify_internal_set_pb_ext(
  552. mod_pb, slapi_entry_get_sdn(e),
  553. mods, 0, 0,
  554. memberof_get_plugin_id(), 0);
  555. slapi_modify_internal_pb(mod_pb);
  556. slapi_pblock_get(mod_pb,
  557. SLAPI_PLUGIN_INTOP_RESULT,
  558. &rc);
  559. slapi_pblock_destroy(mod_pb);
  560. if (rc == LDAP_NO_SUCH_ATTRIBUTE && val[0] == NULL) {
  561. /* if no memberof attribut exists
  562. * handle as success
  563. */
  564. rc = LDAP_SUCCESS;
  565. }
  566. return rc;
  567. }
  568. /* Check if the the entry include scope is a child of the sdn */
  569. static Slapi_DN*
  570. memberof_scope_is_child_of_dn(MemberOfConfig *config, Slapi_DN *sdn)
  571. {
  572. int i = 0;
  573. while(config->entryScopes && config->entryScopes[i]){
  574. if(slapi_sdn_issuffix(config->entryScopes[i], sdn)){
  575. return config->entryScopes[i];
  576. }
  577. i++;
  578. }
  579. return NULL;
  580. }
  581. /*
  582. * Does a callback search of "type=dn" under the db suffix that "dn" is in,
  583. * unless all_backends is set, then we look at all the backends. If "dn"
  584. * is a user, you'd want "type" to be "member". If "dn" is a group, you
  585. * could want type to be either "member" or "memberOf" depending on the case.
  586. */
  587. int
  588. memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
  589. MemberOfConfig *config, char **types, plugin_search_entry_callback callback, void *callback_data)
  590. {
  591. Slapi_PBlock *search_pb = NULL;
  592. Slapi_DN *base_sdn = NULL;
  593. Slapi_Backend *be = NULL;
  594. char *escaped_filter_val;
  595. char *filter_str = NULL;
  596. char *cookie = NULL;
  597. int all_backends = config->allBackends;
  598. int types_name_len = 0;
  599. int num_types = 0;
  600. int dn_len = slapi_sdn_get_ndn_len(sdn);
  601. int free_it = 0;
  602. int rc = 0;
  603. int i = 0;
  604. if (!memberof_entry_in_scope(config, sdn)) {
  605. return (rc);
  606. }
  607. /* Count the number of types. */
  608. for (num_types = 0; types && types[num_types]; num_types++)
  609. {
  610. /* Add up the total length of all attribute names.
  611. * We need to know this for building the filter. */
  612. types_name_len += strlen(types[num_types]);
  613. }
  614. /* Escape the dn, and build the search filter. */
  615. escaped_filter_val = slapi_escape_filter_value((char *)slapi_sdn_get_dn(sdn), dn_len);
  616. if(escaped_filter_val){
  617. dn_len = strlen(escaped_filter_val);
  618. free_it = 1;
  619. } else {
  620. escaped_filter_val = (char *)slapi_sdn_get_dn(sdn);
  621. }
  622. if (num_types > 1)
  623. {
  624. int bytes_out = 0;
  625. int filter_str_len = types_name_len + (num_types * (3 + dn_len)) + 4;
  626. /* Allocate enough space for the filter */
  627. filter_str = slapi_ch_malloc(filter_str_len);
  628. /* Add beginning of filter. */
  629. bytes_out = snprintf(filter_str, filter_str_len - bytes_out, "(|");
  630. /* Add filter section for each type. */
  631. for (i = 0; types[i]; i++)
  632. {
  633. bytes_out += snprintf(filter_str + bytes_out, filter_str_len - bytes_out,
  634. "(%s=%s)", types[i], escaped_filter_val);
  635. }
  636. /* Add end of filter. */
  637. snprintf(filter_str + bytes_out, filter_str_len - bytes_out, ")");
  638. }
  639. else if (num_types == 1)
  640. {
  641. filter_str = slapi_ch_smprintf("(%s=%s)", types[0], escaped_filter_val);
  642. }
  643. if(free_it)
  644. slapi_ch_free_string(&escaped_filter_val);
  645. if(filter_str == NULL){
  646. return rc;
  647. }
  648. search_pb = slapi_pblock_new();
  649. be = slapi_get_first_backend(&cookie);
  650. while(be){
  651. Slapi_DN *scope_sdn = NULL;
  652. if(!all_backends){
  653. be = slapi_be_select(sdn);
  654. if(be == NULL){
  655. break;
  656. }
  657. }
  658. if((base_sdn = (Slapi_DN *)slapi_be_getsuffix(be,0)) == NULL){
  659. if(!all_backends){
  660. break;
  661. } else {
  662. /* its ok, goto the next backend */
  663. be = slapi_get_next_backend(cookie);
  664. continue;
  665. }
  666. }
  667. if (config->entryScopes || config->entryScopeExcludeSubtrees) {
  668. if (memberof_entry_in_scope(config, base_sdn)) {
  669. /* do nothing, entry scope is spanning
  670. * multiple suffixes, start at suffix */
  671. } else if ((scope_sdn = memberof_scope_is_child_of_dn(config, base_sdn))) {
  672. /* scope is below suffix, set search base */
  673. base_sdn = scope_sdn;
  674. } else if(!all_backends){
  675. break;
  676. } else {
  677. /* its ok, goto the next backend */
  678. be = slapi_get_next_backend(cookie);
  679. continue;
  680. }
  681. }
  682. slapi_search_internal_set_pb(search_pb, slapi_sdn_get_dn(base_sdn),
  683. LDAP_SCOPE_SUBTREE, filter_str, 0, 0, 0, 0, memberof_get_plugin_id(), 0);
  684. slapi_search_internal_callback_pb(search_pb, callback_data, 0, callback, 0);
  685. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  686. if(rc != LDAP_SUCCESS){
  687. break;
  688. }
  689. if(!all_backends){
  690. break;
  691. }
  692. slapi_pblock_init(search_pb);
  693. be = slapi_get_next_backend(cookie);
  694. }
  695. slapi_pblock_destroy(search_pb);
  696. slapi_ch_free((void **)&cookie);
  697. slapi_ch_free_string(&filter_str);
  698. return rc;
  699. }
  700. /*
  701. * memberof_postop_modrdn()
  702. *
  703. * All entries with a memberOf attribute that contains the old group DN get retrieved
  704. * and have the old group DN deleted and the new group DN added to their memberOf attribute
  705. */
  706. int memberof_postop_modrdn(Slapi_PBlock *pb)
  707. {
  708. int ret = SLAPI_PLUGIN_SUCCESS;
  709. void *caller_id = NULL;
  710. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  711. "--> memberof_postop_modrdn\n" );
  712. /* We don't want to process internal modify
  713. * operations that originate from this plugin. */
  714. slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &caller_id);
  715. if (caller_id == memberof_get_plugin_id()) {
  716. /* Just return without processing */
  717. return SLAPI_PLUGIN_SUCCESS;
  718. }
  719. if(memberof_oktodo(pb))
  720. {
  721. MemberOfConfig *mainConfig = 0;
  722. MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  723. struct slapi_entry *pre_e = NULL;
  724. struct slapi_entry *post_e = NULL;
  725. Slapi_DN *pre_sdn = 0;
  726. Slapi_DN *post_sdn = 0;
  727. slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &pre_e );
  728. slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &post_e );
  729. if(pre_e && post_e)
  730. {
  731. pre_sdn = slapi_entry_get_sdn(pre_e);
  732. post_sdn = slapi_entry_get_sdn(post_e);
  733. }
  734. /* copy config so it doesn't change out from under us */
  735. memberof_rlock_config();
  736. mainConfig = memberof_get_config();
  737. memberof_copy_config(&configCopy, mainConfig);
  738. memberof_unlock_config();
  739. /* Need to check both the pre/post entries */
  740. if((pre_sdn && !memberof_entry_in_scope(&configCopy, pre_sdn)) &&
  741. (post_sdn && !memberof_entry_in_scope(&configCopy, post_sdn)))
  742. {
  743. /* The entry is not in scope */
  744. goto bail;
  745. }
  746. memberof_lock();
  747. /* update any downstream members */
  748. if(pre_sdn && post_sdn && configCopy.group_filter &&
  749. 0 == slapi_filter_test_simple(post_e, configCopy.group_filter))
  750. {
  751. int i = 0;
  752. Slapi_Attr *attr = 0;
  753. /* get a list of member attributes present in the group
  754. * entry that is being renamed. */
  755. for (i = 0; configCopy.groupattrs[i]; i++)
  756. {
  757. if(0 == slapi_entry_attr_find(post_e, configCopy.groupattrs[i], &attr))
  758. {
  759. if((ret = memberof_moddn_attr_list(pb, &configCopy, pre_sdn,
  760. post_sdn, attr) != 0))
  761. {
  762. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  763. "memberof_postop_modrdn - update failed for (%s), error (%d)\n",
  764. slapi_sdn_get_dn(pre_sdn), ret);
  765. break;
  766. }
  767. }
  768. }
  769. }
  770. /* It's possible that this is an entry who is a member
  771. * of other group entries. We need to update any member
  772. * attributes to refer to the new name. */
  773. if (ret == LDAP_SUCCESS && pre_sdn && post_sdn) {
  774. if (!memberof_entry_in_scope(&configCopy, post_sdn)){
  775. if((ret = memberof_del_dn_from_groups(pb, &configCopy, pre_sdn))){
  776. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  777. "memberof_postop_modrdn - delete dn failed for (%s), error (%d)\n",
  778. slapi_sdn_get_dn(pre_sdn), ret);
  779. }
  780. if(ret == LDAP_SUCCESS && pre_e && configCopy.group_filter &&
  781. 0 == slapi_filter_test_simple(pre_e, configCopy.group_filter))
  782. {
  783. /* is the entry of interest as a group? */
  784. int i = 0;
  785. Slapi_Attr *attr = 0;
  786. /* Loop through to find each grouping attribute separately. */
  787. for (i = 0; configCopy.groupattrs[i] && ret == LDAP_SUCCESS; i++) {
  788. if (0 == slapi_entry_attr_find(pre_e, configCopy.groupattrs[i], &attr)) {
  789. if((ret = memberof_del_attr_list(pb, &configCopy, pre_sdn, attr))){
  790. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  791. "memberof_postop_modrdn: error deleting attr list - dn (%s). Error (%d)\n",
  792. slapi_sdn_get_dn(pre_sdn),ret);
  793. }
  794. }
  795. }
  796. }
  797. if(ret == LDAP_SUCCESS) {
  798. memberof_del_dn_data del_data = {0, configCopy.memberof_attr};
  799. if((ret = memberof_del_dn_type_callback(post_e, &del_data))){
  800. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  801. "memberof_postop_modrdn - delete dn callback failed for (%s), error (%d)\n",
  802. slapi_entry_get_dn(post_e), ret);
  803. }
  804. }
  805. } else {
  806. if((ret = memberof_replace_dn_from_groups(pb, &configCopy, pre_sdn, post_sdn))){
  807. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  808. "memberof_postop_modrdn - replace dn failed for (%s), error (%d)\n",
  809. slapi_sdn_get_dn(pre_sdn), ret);
  810. }
  811. }
  812. }
  813. memberof_unlock();
  814. bail:
  815. memberof_free_config(&configCopy);
  816. }
  817. if(ret){
  818. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
  819. ret = SLAPI_PLUGIN_FAILURE;
  820. }
  821. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  822. "<-- memberof_postop_modrdn\n" );
  823. return ret;
  824. }
  825. typedef struct _replace_dn_data
  826. {
  827. char *pre_dn;
  828. char *post_dn;
  829. char *type;
  830. char *add_oc;
  831. } replace_dn_data;
  832. /* Finds any groups that have pre_dn as a member and modifies them to
  833. * to use post_dn instead. */
  834. static int
  835. memberof_replace_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config,
  836. Slapi_DN *pre_sdn, Slapi_DN *post_sdn)
  837. {
  838. int i = 0;
  839. char *groupattrs[2] = {0, 0};
  840. int ret = LDAP_SUCCESS;
  841. /* Loop through each grouping attribute to find groups that have
  842. * pre_dn as a member. For any matches, replace pre_dn with post_dn
  843. * using the same grouping attribute. */
  844. for (i = 0; config->groupattrs && config->groupattrs[i]; i++)
  845. {
  846. replace_dn_data data = {(char *)slapi_sdn_get_dn(pre_sdn),
  847. (char *)slapi_sdn_get_dn(post_sdn),
  848. config->groupattrs[i],
  849. config->auto_add_oc
  850. };
  851. groupattrs[0] = config->groupattrs[i];
  852. if((ret = memberof_call_foreach_dn(pb, pre_sdn, config, groupattrs,
  853. memberof_replace_dn_type_callback,
  854. &data)))
  855. {
  856. break;
  857. }
  858. }
  859. return ret;
  860. }
  861. int memberof_replace_dn_type_callback(Slapi_Entry *e, void *callback_data)
  862. {
  863. int rc = 0;
  864. LDAPMod delmod;
  865. LDAPMod addmod;
  866. LDAPMod *mods[3];
  867. char *delval[2];
  868. char *addval[2];
  869. char *dn = NULL;
  870. dn = slapi_entry_get_dn(e);
  871. mods[0] = &delmod;
  872. mods[1] = &addmod;
  873. mods[2] = 0;
  874. delval[0] = ((replace_dn_data *)callback_data)->pre_dn;
  875. delval[1] = 0;
  876. delmod.mod_op = LDAP_MOD_DELETE;
  877. delmod.mod_type = ((replace_dn_data *)callback_data)->type;
  878. delmod.mod_values = delval;
  879. addval[0] = ((replace_dn_data *)callback_data)->post_dn;
  880. addval[1] = 0;
  881. addmod.mod_op = LDAP_MOD_ADD;
  882. addmod.mod_type = ((replace_dn_data *)callback_data)->type;
  883. addmod.mod_values = addval;
  884. rc = memberof_add_memberof_attr(mods, dn,
  885. ((replace_dn_data *)callback_data)->add_oc);
  886. return rc;
  887. }
  888. /*
  889. * memberof_postop_modify()
  890. *
  891. * Added members are retrieved and have the group DN added to their memberOf attribute
  892. * Deleted members are retrieved and have the group DN deleted from their memberOf attribute
  893. * On replace of the membership attribute values:
  894. * 1. Sort old and new values
  895. * 2. Iterate through both lists at same time
  896. * 3. Any value not in old list but in new list - add group DN to memberOf attribute
  897. * 4. Any value in old list but not in new list - remove group DN from memberOf attribute
  898. *
  899. * Note: this will suck for large groups but nonetheless is optimal (it's linear) given
  900. * current restrictions i.e. originally adding members in sorted order would allow
  901. * us to sort one list only (the new one) but that is under server control, not this plugin
  902. */
  903. int memberof_postop_modify(Slapi_PBlock *pb)
  904. {
  905. int ret = SLAPI_PLUGIN_SUCCESS;
  906. Slapi_DN *sdn = NULL;
  907. Slapi_Mods *smods = 0;
  908. Slapi_Mod *smod = 0;
  909. LDAPMod **mods;
  910. Slapi_Mod *next_mod = 0;
  911. void *caller_id = NULL;
  912. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  913. "--> memberof_postop_modify\n" );
  914. /* We don't want to process internal modify
  915. * operations that originate from this plugin. */
  916. slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &caller_id);
  917. if (caller_id == memberof_get_plugin_id()) {
  918. /* Just return without processing */
  919. return SLAPI_PLUGIN_SUCCESS;
  920. }
  921. /* check if we are updating the shared config entry */
  922. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
  923. if (memberof_sdn_config_cmp(sdn) == 0)
  924. {
  925. Slapi_Entry *entry = NULL;
  926. char returntext[SLAPI_DSE_RETURNTEXT_SIZE];
  927. int result = 0;
  928. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &entry);
  929. if(entry){
  930. if( SLAPI_DSE_CALLBACK_ERROR == memberof_apply_config (pb, NULL, entry, &result, returntext, NULL)){
  931. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, "%s", returntext);
  932. ret = SLAPI_PLUGIN_FAILURE;
  933. goto done;
  934. }
  935. } else {
  936. /* this should not happen since this was validated in preop */
  937. ret = SLAPI_PLUGIN_FAILURE;
  938. goto done;
  939. }
  940. /* we're done, no need to do the other processing */
  941. goto done;
  942. }
  943. if(memberof_oktodo(pb))
  944. {
  945. int config_copied = 0;
  946. MemberOfConfig *mainConfig = 0;
  947. MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  948. /* get the mod set */
  949. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  950. smods = slapi_mods_new();
  951. slapi_mods_init_byref(smods, mods);
  952. next_mod = slapi_mod_new();
  953. smod = slapi_mods_get_first_smod(smods, next_mod);
  954. while(smod)
  955. {
  956. int interested = 0;
  957. char *type = (char *)slapi_mod_get_type(smod);
  958. /* We only want to copy the config if we encounter an
  959. * operation that we need to act on. We also want to
  960. * only copy the config the first time it's needed so
  961. * it remains the same for all mods in the operation,
  962. * despite any config changes that may be made. */
  963. if (!config_copied){
  964. memberof_rlock_config();
  965. mainConfig = memberof_get_config();
  966. if (memberof_is_grouping_attr(type, mainConfig))
  967. {
  968. interested = 1;
  969. if (!memberof_entry_in_scope(mainConfig, sdn)){
  970. /* Entry is not in scope */
  971. memberof_unlock_config();
  972. goto bail;
  973. }
  974. /* copy config so it doesn't change out from under us */
  975. memberof_copy_config(&configCopy, mainConfig);
  976. config_copied = 1;
  977. }
  978. memberof_unlock_config();
  979. } else {
  980. if (memberof_is_grouping_attr(type, &configCopy))
  981. {
  982. interested = 1;
  983. }
  984. }
  985. if(interested)
  986. {
  987. int op = slapi_mod_get_operation(smod);
  988. memberof_lock();
  989. /* the modify op decides the function */
  990. switch(op & ~LDAP_MOD_BVALUES)
  991. {
  992. case LDAP_MOD_ADD:
  993. {
  994. /* add group DN to targets */
  995. if((ret = memberof_add_smod_list(pb, &configCopy, sdn, smod))){
  996. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  997. "memberof_postop_modify: failed to add dn (%s) to target. "
  998. "Error (%d)\n", slapi_sdn_get_dn(sdn), ret );
  999. slapi_mod_done(next_mod);
  1000. memberof_unlock();
  1001. goto bail;
  1002. }
  1003. break;
  1004. }
  1005. case LDAP_MOD_DELETE:
  1006. {
  1007. /* If there are no values in the smod, we should
  1008. * just do a replace instead. The user is just
  1009. * trying to delete all members from this group
  1010. * entry, which the replace code deals with. */
  1011. if (slapi_mod_get_num_values(smod) == 0)
  1012. {
  1013. if((ret = memberof_replace_list(pb, &configCopy, sdn))){
  1014. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  1015. "memberof_postop_modify: failed to replace list (%s). "
  1016. "Error (%d)\n", slapi_sdn_get_dn(sdn), ret );
  1017. slapi_mod_done(next_mod);
  1018. memberof_unlock();
  1019. goto bail;
  1020. }
  1021. }
  1022. else
  1023. {
  1024. /* remove group DN from target values in smod*/
  1025. if((ret = memberof_del_smod_list(pb, &configCopy, sdn, smod))){
  1026. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  1027. "memberof_postop_modify: failed to remove dn (%s). "
  1028. "Error (%d)\n", slapi_sdn_get_dn(sdn), ret );
  1029. slapi_mod_done(next_mod);
  1030. memberof_unlock();
  1031. goto bail;
  1032. }
  1033. }
  1034. break;
  1035. }
  1036. case LDAP_MOD_REPLACE:
  1037. {
  1038. /* replace current values */
  1039. if((ret = memberof_replace_list(pb, &configCopy, sdn))){
  1040. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  1041. "memberof_postop_modify: failed to replace values in dn (%s). "
  1042. "Error (%d)\n", slapi_sdn_get_dn(sdn), ret );
  1043. slapi_mod_done(next_mod);
  1044. memberof_unlock();
  1045. goto bail;
  1046. }
  1047. break;
  1048. }
  1049. default:
  1050. {
  1051. slapi_log_error(
  1052. SLAPI_LOG_FATAL,
  1053. LOG_ERR,
  1054. MEMBEROF_PLUGIN_SUBSYSTEM,
  1055. "memberof_postop_modify: unknown mod type\n" );
  1056. ret = SLAPI_PLUGIN_FAILURE;
  1057. break;
  1058. }
  1059. }
  1060. memberof_unlock();
  1061. }
  1062. slapi_mod_done(next_mod);
  1063. smod = slapi_mods_get_next_smod(smods, next_mod);
  1064. }
  1065. bail:
  1066. if (config_copied){
  1067. memberof_free_config(&configCopy);
  1068. }
  1069. slapi_mod_free(&next_mod);
  1070. slapi_mods_free(&smods);
  1071. }
  1072. done:
  1073. if(ret){
  1074. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
  1075. ret = SLAPI_PLUGIN_FAILURE;
  1076. }
  1077. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  1078. "<-- memberof_postop_modify\n" );
  1079. return ret;
  1080. }
  1081. /*
  1082. * memberof_postop_add()
  1083. *
  1084. * All members in the membership attribute of the new entry get retrieved
  1085. * and have the group DN added to their memberOf attribute
  1086. */
  1087. int memberof_postop_add(Slapi_PBlock *pb)
  1088. {
  1089. int ret = SLAPI_PLUGIN_SUCCESS;
  1090. int interested = 0;
  1091. Slapi_DN *sdn = 0;
  1092. void *caller_id = NULL;
  1093. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  1094. "--> memberof_postop_add\n" );
  1095. /* We don't want to process internal modify
  1096. * operations that originate from this plugin. */
  1097. slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &caller_id);
  1098. if (caller_id == memberof_get_plugin_id()) {
  1099. /* Just return without processing */
  1100. return SLAPI_PLUGIN_SUCCESS;
  1101. }
  1102. if(memberof_oktodo(pb) && (sdn = memberof_getsdn(pb)))
  1103. {
  1104. struct slapi_entry *e = NULL;
  1105. MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  1106. MemberOfConfig *mainConfig;
  1107. slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &e );
  1108. /* is the entry of interest? */
  1109. memberof_rlock_config();
  1110. mainConfig = memberof_get_config();
  1111. if(e && mainConfig && mainConfig->group_filter &&
  1112. 0 == slapi_filter_test_simple(e, mainConfig->group_filter))
  1113. {
  1114. interested = 1;
  1115. if(!memberof_entry_in_scope(mainConfig, slapi_entry_get_sdn(e))){
  1116. /* Entry is not in scope */
  1117. memberof_unlock_config();
  1118. goto bail;
  1119. }
  1120. memberof_copy_config(&configCopy, memberof_get_config());
  1121. }
  1122. memberof_unlock_config();
  1123. if(interested)
  1124. {
  1125. int i = 0;
  1126. Slapi_Attr *attr = 0;
  1127. memberof_lock();
  1128. for (i = 0; configCopy.groupattrs && configCopy.groupattrs[i]; i++)
  1129. {
  1130. if(0 == slapi_entry_attr_find(e, configCopy.groupattrs[i], &attr))
  1131. {
  1132. if((ret = memberof_add_attr_list(pb, &configCopy, sdn, attr))){
  1133. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  1134. "memberof_postop_add: failed to add dn(%s), error (%d)\n",
  1135. slapi_sdn_get_dn(sdn), ret);
  1136. break;
  1137. }
  1138. }
  1139. }
  1140. memberof_unlock();
  1141. memberof_free_config(&configCopy);
  1142. }
  1143. }
  1144. bail:
  1145. if(ret){
  1146. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
  1147. ret = SLAPI_PLUGIN_FAILURE;
  1148. }
  1149. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  1150. "<-- memberof_postop_add\n" );
  1151. return ret;
  1152. }
  1153. /*** Support functions ***/
  1154. /*
  1155. * memberof_oktodo()
  1156. *
  1157. * Check that the op succeeded
  1158. * Note: we also respond to replicated ops so we don't test for that
  1159. * this does require that the memberOf attribute not be replicated
  1160. * and this means that memberof is consistent with local state
  1161. * not the network system state
  1162. *
  1163. */
  1164. int memberof_oktodo(Slapi_PBlock *pb)
  1165. {
  1166. int ret = 1;
  1167. int oprc = 0;
  1168. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  1169. "--> memberof_postop_oktodo\n" );
  1170. if (!slapi_plugin_running(pb)) {
  1171. ret = 0;
  1172. goto bail;
  1173. }
  1174. if(slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
  1175. {
  1176. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  1177. "memberof_postop_oktodo: could not get parameters\n" );
  1178. ret = -1;
  1179. }
  1180. /* this plugin should only execute if the operation succeeded */
  1181. if(oprc != 0)
  1182. {
  1183. ret = 0;
  1184. }
  1185. bail:
  1186. slapi_log_error(SLAPI_LOG_TRACE, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  1187. "<-- memberof_postop_oktodo\n" );
  1188. return ret;
  1189. }
  1190. /*
  1191. * Return 1 if the entry is in the scope.
  1192. * For MODRDN the caller should check both the preop
  1193. * and postop entries. If we are moving out of, or
  1194. * into scope, we should process it.
  1195. */
  1196. static int
  1197. memberof_entry_in_scope(MemberOfConfig *config, Slapi_DN *sdn)
  1198. {
  1199. if (config->entryScopeExcludeSubtrees){
  1200. int i = 0;
  1201. /* check the excludes */
  1202. while(config->entryScopeExcludeSubtrees[i]){
  1203. if (slapi_sdn_issuffix(sdn, config->entryScopeExcludeSubtrees[i])){
  1204. return 0;
  1205. }
  1206. i++;
  1207. }
  1208. }
  1209. if (config->entryScopes){
  1210. int i = 0;
  1211. /* check the excludes */
  1212. while(config->entryScopes[i]){
  1213. if (slapi_sdn_issuffix(sdn, config->entryScopes[i])){
  1214. return 1;
  1215. }
  1216. i++;
  1217. }
  1218. return 0;
  1219. }
  1220. return 1;
  1221. }
  1222. static Slapi_DN *
  1223. memberof_getsdn(Slapi_PBlock *pb)
  1224. {
  1225. Slapi_DN *sdn = NULL;
  1226. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
  1227. return sdn;
  1228. }
  1229. /*
  1230. * memberof_modop_one()
  1231. *
  1232. * Perform op on memberof attribute of op_to using op_this as the value
  1233. * However, if op_to happens to be a group, we must arrange for the group
  1234. * members to have the mod performed on them instead, and we must take
  1235. * care to not recurse when we have visted a group before
  1236. *
  1237. * Also, we must not delete entries that are a member of the group
  1238. */
  1239. int memberof_modop_one(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op,
  1240. Slapi_DN *op_this_sdn, Slapi_DN *op_to_sdn)
  1241. {
  1242. return memberof_modop_one_r(pb, config, mod_op, op_this_sdn,
  1243. op_this_sdn, op_to_sdn, 0);
  1244. }
  1245. /* memberof_modop_one_r()
  1246. *
  1247. * recursive function to perform above (most things don't need the replace arg)
  1248. */
  1249. int memberof_modop_one_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op,
  1250. Slapi_DN *group_sdn, Slapi_DN *op_this_sdn, Slapi_DN *op_to_sdn,
  1251. memberofstringll *stack)
  1252. {
  1253. return memberof_modop_one_replace_r(
  1254. pb, config, mod_op, group_sdn, op_this_sdn, 0, op_to_sdn, stack);
  1255. }
  1256. /* memberof_modop_one_replace_r()
  1257. *
  1258. * recursive function to perform above (with added replace arg)
  1259. */
  1260. int
  1261. memberof_modop_one_replace_r(Slapi_PBlock *pb, MemberOfConfig *config,
  1262. int mod_op, Slapi_DN *group_sdn, Slapi_DN *op_this_sdn,
  1263. Slapi_DN *replace_with_sdn, Slapi_DN *op_to_sdn, memberofstringll *stack)
  1264. {
  1265. int rc = 0;
  1266. LDAPMod mod;
  1267. LDAPMod replace_mod;
  1268. LDAPMod *mods[3];
  1269. char *val[2];
  1270. char *replace_val[2];
  1271. Slapi_Entry *e = 0;
  1272. memberofstringll *ll = 0;
  1273. char *op_str = 0;
  1274. const char *op_to;
  1275. const char *op_this;
  1276. Slapi_Value *to_dn_val = NULL;
  1277. Slapi_Value *this_dn_val = NULL;
  1278. op_to = slapi_sdn_get_ndn(op_to_sdn);
  1279. op_this = slapi_sdn_get_ndn(op_this_sdn);
  1280. /* Make sure we have valid DN's for the group(op_this) and the new member(op_to) */
  1281. if(op_to && op_this){
  1282. to_dn_val = slapi_value_new_string(op_to);
  1283. this_dn_val = slapi_value_new_string(op_this);
  1284. }
  1285. if(to_dn_val == NULL){
  1286. const char *udn = op_to_sdn ? slapi_sdn_get_udn(op_to_sdn) : "";
  1287. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  1288. "memberof_modop_one_replace_r: failed to get DN value from "
  1289. "member value (%s)\n", udn);
  1290. goto bail;
  1291. }
  1292. if(this_dn_val == NULL){
  1293. const char *udn = op_this_sdn ? slapi_sdn_get_udn(op_this_sdn) : "";
  1294. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  1295. "memberof_modop_one_replace_r: failed to get DN value from"
  1296. "group (%s)\n", udn);
  1297. goto bail;
  1298. }
  1299. /* op_this and op_to are both case-normalized */
  1300. slapi_value_set_flags(this_dn_val, SLAPI_ATTR_FLAG_NORMALIZED_CIS);
  1301. slapi_value_set_flags(to_dn_val, SLAPI_ATTR_FLAG_NORMALIZED_CIS);
  1302. if (config == NULL) {
  1303. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  1304. "memberof_modop_one_replace_r: NULL config parameter\n");
  1305. goto bail;
  1306. }
  1307. /* determine if this is a group op or single entry */
  1308. slapi_search_internal_get_entry( op_to_sdn, config->groupattrs,
  1309. &e, memberof_get_plugin_id());
  1310. if(!e)
  1311. {
  1312. /* In the case of a delete, we need to worry about the
  1313. * missing entry being a nested group. There's a small
  1314. * window where another thread may have deleted a nested
  1315. * group that our group_dn entry refers to. This has the
  1316. * potential of us missing some indirect member entries
  1317. * that need to be updated. */
  1318. if(LDAP_MOD_DELETE == mod_op)
  1319. {
  1320. Slapi_PBlock *search_pb = slapi_pblock_new();
  1321. Slapi_DN *base_sdn = 0;
  1322. Slapi_Backend *be = 0;
  1323. char *filter_str;
  1324. char *cookie = NULL;
  1325. int n_entries = 0;
  1326. int all_backends = config->allBackends;
  1327. filter_str = slapi_filter_sprintf("(%s=%s%s)", config->memberof_attr, ESC_NEXT_VAL, op_to);
  1328. be = slapi_get_first_backend(&cookie);
  1329. while(be){
  1330. /*
  1331. * We can't tell for sure if the op_to entry is a
  1332. * user or a group since the entry doesn't exist
  1333. * anymore. We can safely ignore the missing entry
  1334. * if no other entries have a memberOf attribute that
  1335. * points to the missing entry.
  1336. */
  1337. if(!all_backends){
  1338. be = slapi_be_select(op_to_sdn);
  1339. if(be == NULL){
  1340. break;
  1341. }
  1342. }
  1343. if((base_sdn = (Slapi_DN*)slapi_be_getsuffix(be,0)) == NULL){
  1344. if(!all_backends){
  1345. break;
  1346. } else {
  1347. be = slapi_get_next_backend (cookie);
  1348. continue;
  1349. }
  1350. }
  1351. if(filter_str)
  1352. {
  1353. slapi_search_internal_set_pb(search_pb, slapi_sdn_get_dn(base_sdn),
  1354. LDAP_SCOPE_SUBTREE, filter_str, 0, 0, 0, 0,
  1355. memberof_get_plugin_id(), 0);
  1356. if (slapi_search_internal_pb(search_pb))
  1357. {
  1358. /* get result and log an error */
  1359. int res = 0;
  1360. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  1361. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  1362. "memberof_modop_one_replace_r: error searching for members: %d\n", res);
  1363. } else {
  1364. slapi_pblock_get(search_pb, SLAPI_NENTRIES, &n_entries);
  1365. if(n_entries > 0)
  1366. {
  1367. /* We want to fixup the membership for the
  1368. * entries that referred to the missing group
  1369. * entry. This will fix the references to
  1370. * the missing group as well as the group
  1371. * represented by op_this. */
  1372. memberof_test_membership(pb, config, op_to_sdn);
  1373. }
  1374. }
  1375. slapi_free_search_results_internal(search_pb);
  1376. }
  1377. slapi_pblock_init(search_pb);
  1378. if(!all_backends){
  1379. break;
  1380. }
  1381. be = slapi_get_next_backend (cookie);
  1382. }
  1383. slapi_pblock_destroy(search_pb);
  1384. slapi_ch_free_string(&filter_str);
  1385. slapi_ch_free((void **)&cookie);
  1386. }
  1387. goto bail;
  1388. }
  1389. if(LDAP_MOD_DELETE == mod_op)
  1390. {
  1391. op_str = "DELETE";
  1392. }
  1393. else if(LDAP_MOD_ADD == mod_op)
  1394. {
  1395. op_str = "ADD";
  1396. }
  1397. else if(LDAP_MOD_REPLACE == mod_op)
  1398. {
  1399. op_str = "REPLACE";
  1400. }
  1401. else
  1402. {
  1403. op_str = "UNKNOWN";
  1404. }
  1405. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  1406. "memberof_modop_one_replace_r: %s %s in %s\n"
  1407. ,op_str, op_this, op_to);
  1408. if(config->group_filter && 0 == slapi_filter_test_simple(e, config->group_filter))
  1409. {
  1410. /* group */
  1411. Slapi_Value *ll_dn_val = 0;
  1412. Slapi_Attr *members = 0;
  1413. int i = 0;
  1414. ll = stack;
  1415. /* have we been here before? */
  1416. while(ll)
  1417. {
  1418. ll_dn_val = slapi_value_new_string(ll->dn);
  1419. /* ll->dn is case-normalized */
  1420. slapi_value_set_flags(ll_dn_val, SLAPI_ATTR_FLAG_NORMALIZED_CIS);
  1421. if(0 == memberof_compare(config, &ll_dn_val, &to_dn_val))
  1422. {
  1423. slapi_value_free(&ll_dn_val);
  1424. /* someone set up infinitely
  1425. recursive groups - bail out */
  1426. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG,
  1427. MEMBEROF_PLUGIN_SUBSYSTEM,
  1428. "memberof_modop_one_replace_r: group recursion"
  1429. " detected in %s\n"
  1430. ,op_to);
  1431. goto bail;
  1432. }
  1433. slapi_value_free(&ll_dn_val);
  1434. ll = ll->next;
  1435. }
  1436. /* do op on group */
  1437. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG,
  1438. MEMBEROF_PLUGIN_SUBSYSTEM,
  1439. "memberof_modop_one_replace_r: descending into group %s\n",
  1440. op_to);
  1441. /* Add the nested group's DN to the stack so we can detect loops later. */
  1442. ll = (memberofstringll*)slapi_ch_malloc(sizeof(memberofstringll));
  1443. ll->dn = op_to;
  1444. ll->next = stack;
  1445. /* Go through each grouping attribute one at a time. */
  1446. for (i = 0; config->groupattrs[i]; i++)
  1447. {
  1448. slapi_entry_attr_find( e, config->groupattrs[i], &members );
  1449. if(members)
  1450. {
  1451. if((rc = memberof_mod_attr_list_r(pb, config, mod_op, group_sdn,
  1452. op_this_sdn, members, ll)) != 0){
  1453. goto bail;
  1454. }
  1455. }
  1456. }
  1457. {
  1458. /* crazyness follows:
  1459. * strict-aliasing doesn't like the required cast
  1460. * to void for slapi_ch_free so we are made to
  1461. * juggle to get a normal thing done
  1462. */
  1463. void *pll = ll;
  1464. slapi_ch_free(&pll);
  1465. ll = 0;
  1466. }
  1467. }
  1468. /* continue with operation */
  1469. {
  1470. /* We want to avoid listing a group as a memberOf itself
  1471. * in case someone set up a circular grouping.
  1472. */
  1473. if (0 == memberof_compare(config, &this_dn_val, &to_dn_val))
  1474. {
  1475. const char *strval = "NULL";
  1476. if (this_dn_val) {
  1477. strval = slapi_value_get_string(this_dn_val);
  1478. }
  1479. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG,
  1480. MEMBEROF_PLUGIN_SUBSYSTEM,
  1481. "memberof_modop_one_replace_r: not processing memberOf "
  1482. "operations on self entry: %s\n", strval);
  1483. goto bail;
  1484. }
  1485. /* For add and del modify operations, we just regenerate the
  1486. * memberOf attribute. */
  1487. if(LDAP_MOD_DELETE == mod_op || LDAP_MOD_ADD == mod_op)
  1488. {
  1489. /* find parent groups and replace our member attr */
  1490. rc = memberof_fix_memberof_callback(e, config);
  1491. } else {
  1492. /* single entry - do mod */
  1493. mods[0] = &mod;
  1494. if(LDAP_MOD_REPLACE == mod_op)
  1495. {
  1496. mods[1] = &replace_mod;
  1497. mods[2] = 0;
  1498. }
  1499. else
  1500. {
  1501. mods[1] = 0;
  1502. }
  1503. val[0] = (char *)op_this;
  1504. val[1] = 0;
  1505. mod.mod_op = LDAP_MOD_REPLACE == mod_op?LDAP_MOD_DELETE:mod_op;
  1506. mod.mod_type = config->memberof_attr;
  1507. mod.mod_values = val;
  1508. if(LDAP_MOD_REPLACE == mod_op)
  1509. {
  1510. replace_val[0] = (char *)slapi_sdn_get_dn(replace_with_sdn);
  1511. replace_val[1] = 0;
  1512. replace_mod.mod_op = LDAP_MOD_ADD;
  1513. replace_mod.mod_type = config->memberof_attr;
  1514. replace_mod.mod_values = replace_val;
  1515. }
  1516. rc = memberof_add_memberof_attr(mods, op_to, config->auto_add_oc);
  1517. }
  1518. }
  1519. bail:
  1520. slapi_value_free(&to_dn_val);
  1521. slapi_value_free(&this_dn_val);
  1522. slapi_entry_free(e);
  1523. return rc;
  1524. }
  1525. /*
  1526. * memberof_add_one()
  1527. *
  1528. * Add addthis DN to the memberof attribute of addto
  1529. *
  1530. */
  1531. int
  1532. memberof_add_one(Slapi_PBlock *pb, MemberOfConfig *config,
  1533. Slapi_DN *addthis_sdn, Slapi_DN *addto_sdn)
  1534. {
  1535. return memberof_modop_one(pb, config, LDAP_MOD_ADD, addthis_sdn, addto_sdn);
  1536. }
  1537. /*
  1538. * memberof_del_one()
  1539. *
  1540. * Delete delthis DN from the memberof attribute of delfrom
  1541. *
  1542. */
  1543. int
  1544. memberof_del_one(Slapi_PBlock *pb, MemberOfConfig *config,
  1545. Slapi_DN *delthis_sdn, Slapi_DN *delfrom_sdn)
  1546. {
  1547. return memberof_modop_one(pb, config, LDAP_MOD_DELETE, delthis_sdn, delfrom_sdn);
  1548. }
  1549. /*
  1550. * memberof_mod_smod_list()
  1551. *
  1552. * Perform mod for group DN to the memberof attribute of the list of targets
  1553. *
  1554. */
  1555. int memberof_mod_smod_list(Slapi_PBlock *pb, MemberOfConfig *config, int mod,
  1556. Slapi_DN *group_sdn, Slapi_Mod *smod)
  1557. {
  1558. int rc = 0;
  1559. struct berval *bv = slapi_mod_get_first_value(smod);
  1560. int last_size = 0;
  1561. char *last_str = 0;
  1562. Slapi_DN *sdn = slapi_sdn_new();
  1563. while(bv)
  1564. {
  1565. char *dn_str = 0;
  1566. if(last_size > bv->bv_len)
  1567. {
  1568. dn_str = last_str;
  1569. }
  1570. else
  1571. {
  1572. int the_size = (bv->bv_len * 2) + 1;
  1573. if(last_str)
  1574. slapi_ch_free_string(&last_str);
  1575. dn_str = (char*)slapi_ch_malloc(the_size);
  1576. last_str = dn_str;
  1577. last_size = the_size;
  1578. }
  1579. memset(dn_str, 0, last_size);
  1580. strncpy(dn_str, bv->bv_val, (size_t)bv->bv_len);
  1581. slapi_sdn_set_dn_byref(sdn, dn_str);
  1582. if((rc = memberof_modop_one(pb, config, mod, group_sdn, sdn))){
  1583. break;
  1584. }
  1585. bv = slapi_mod_get_next_value(smod);
  1586. }
  1587. slapi_sdn_free(&sdn);
  1588. if(last_str)
  1589. slapi_ch_free_string(&last_str);
  1590. return rc;
  1591. }
  1592. /*
  1593. * memberof_add_smod_list()
  1594. *
  1595. * Add group DN to the memberof attribute of the list of targets
  1596. *
  1597. */
  1598. int memberof_add_smod_list(Slapi_PBlock *pb, MemberOfConfig *config,
  1599. Slapi_DN *group_sdn, Slapi_Mod *smod)
  1600. {
  1601. return memberof_mod_smod_list(pb, config, LDAP_MOD_ADD, group_sdn, smod);
  1602. }
  1603. /*
  1604. * memberof_del_smod_list()
  1605. *
  1606. * Remove group DN from the memberof attribute of the list of targets
  1607. *
  1608. */
  1609. int memberof_del_smod_list(Slapi_PBlock *pb, MemberOfConfig *config,
  1610. Slapi_DN *group_sdn, Slapi_Mod *smod)
  1611. {
  1612. return memberof_mod_smod_list(pb, config, LDAP_MOD_DELETE, group_sdn, smod);
  1613. }
  1614. /**
  1615. * Plugin identity mgmt
  1616. */
  1617. void memberof_set_plugin_id(void * plugin_id)
  1618. {
  1619. _PluginID=plugin_id;
  1620. }
  1621. void * memberof_get_plugin_id()
  1622. {
  1623. return _PluginID;
  1624. }
  1625. /*
  1626. * memberof_mod_attr_list()
  1627. *
  1628. * Perform mod for group DN to the memberof attribute of the list of targets
  1629. *
  1630. */
  1631. int memberof_mod_attr_list(Slapi_PBlock *pb, MemberOfConfig *config, int mod,
  1632. Slapi_DN *group_sdn, Slapi_Attr *attr)
  1633. {
  1634. return memberof_mod_attr_list_r(pb, config, mod, group_sdn, group_sdn,
  1635. attr, 0);
  1636. }
  1637. int memberof_mod_attr_list_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod,
  1638. Slapi_DN *group_sdn, Slapi_DN *op_this_sdn,
  1639. Slapi_Attr *attr, memberofstringll *stack)
  1640. {
  1641. int rc = 0;
  1642. Slapi_Value *val = 0;
  1643. Slapi_Value *op_this_val = 0;
  1644. int last_size = 0;
  1645. char *last_str = 0;
  1646. int hint = slapi_attr_first_value(attr, &val);
  1647. Slapi_DN *sdn = slapi_sdn_new();
  1648. op_this_val = slapi_value_new_string(slapi_sdn_get_ndn(op_this_sdn));
  1649. slapi_value_set_flags(op_this_val, SLAPI_ATTR_FLAG_NORMALIZED_CIS);
  1650. while(val && rc == 0)
  1651. {
  1652. char *dn_str = 0;
  1653. struct berval *bv = 0;
  1654. /* We don't want to process a memberOf operation on ourselves. */
  1655. if(0 != memberof_compare(config, &val, &op_this_val))
  1656. {
  1657. bv = (struct berval *)slapi_value_get_berval(val);
  1658. if(last_size > bv->bv_len)
  1659. {
  1660. dn_str = last_str;
  1661. }
  1662. else
  1663. {
  1664. int the_size = (bv->bv_len * 2) + 1;
  1665. if(last_str)
  1666. slapi_ch_free_string(&last_str);
  1667. dn_str = (char*)slapi_ch_malloc(the_size);
  1668. last_str = dn_str;
  1669. last_size = the_size;
  1670. }
  1671. memset(dn_str, 0, last_size);
  1672. strncpy(dn_str, bv->bv_val, (size_t)bv->bv_len);
  1673. /* If we're doing a replace (as we would in the MODRDN case), we need
  1674. * to specify the new group DN value */
  1675. slapi_sdn_set_normdn_byref(sdn, dn_str); /* dn_str is normalized */
  1676. if(mod == LDAP_MOD_REPLACE)
  1677. {
  1678. rc = memberof_modop_one_replace_r(pb, config, mod, group_sdn,
  1679. op_this_sdn, group_sdn,
  1680. sdn, stack);
  1681. }
  1682. else
  1683. {
  1684. rc = memberof_modop_one_r(pb, config, mod, group_sdn,
  1685. op_this_sdn, sdn, stack);
  1686. }
  1687. }
  1688. hint = slapi_attr_next_value(attr, hint, &val);
  1689. }
  1690. slapi_value_free(&op_this_val);
  1691. slapi_sdn_free(&sdn);
  1692. if(last_str)
  1693. slapi_ch_free_string(&last_str);
  1694. return rc;
  1695. }
  1696. /*
  1697. * memberof_add_attr_list()
  1698. *
  1699. * Add group DN to the memberof attribute of the list of targets
  1700. *
  1701. */
  1702. int memberof_add_attr_list(Slapi_PBlock *pb, MemberOfConfig *config,
  1703. Slapi_DN *group_sdn, Slapi_Attr *attr)
  1704. {
  1705. return memberof_mod_attr_list(pb, config, LDAP_MOD_ADD, group_sdn, attr);
  1706. }
  1707. /*
  1708. * memberof_del_attr_list()
  1709. *
  1710. * Remove group DN from the memberof attribute of the list of targets
  1711. *
  1712. */
  1713. int memberof_del_attr_list(Slapi_PBlock *pb, MemberOfConfig *config,
  1714. Slapi_DN *group_sdn, Slapi_Attr *attr)
  1715. {
  1716. return memberof_mod_attr_list(pb, config, LDAP_MOD_DELETE, group_sdn, attr);
  1717. }
  1718. /*
  1719. * memberof_moddn_attr_list()
  1720. *
  1721. * Perform mod for group DN to the memberof attribute of the list of targets
  1722. *
  1723. */
  1724. int memberof_moddn_attr_list(Slapi_PBlock *pb, MemberOfConfig *config,
  1725. Slapi_DN *pre_sdn, Slapi_DN *post_sdn, Slapi_Attr *attr)
  1726. {
  1727. int rc = 0;
  1728. Slapi_Value *val = 0;
  1729. int last_size = 0;
  1730. char *last_str = 0;
  1731. int hint = slapi_attr_first_value(attr, &val);
  1732. Slapi_DN *sdn = slapi_sdn_new();
  1733. while(val)
  1734. {
  1735. char *dn_str = 0;
  1736. struct berval *bv = (struct berval *)slapi_value_get_berval(val);
  1737. if(last_size > bv->bv_len)
  1738. {
  1739. dn_str = last_str;
  1740. }
  1741. else
  1742. {
  1743. int the_size = (bv->bv_len * 2) + 1;
  1744. if(last_str)
  1745. slapi_ch_free_string(&last_str);
  1746. dn_str = (char*)slapi_ch_malloc(the_size);
  1747. last_str = dn_str;
  1748. last_size = the_size;
  1749. }
  1750. memset(dn_str, 0, last_size);
  1751. strncpy(dn_str, bv->bv_val, (size_t)bv->bv_len);
  1752. slapi_sdn_set_normdn_byref(sdn, dn_str); /* dn_str is normalized */
  1753. memberof_modop_one_replace_r(pb, config, LDAP_MOD_REPLACE,
  1754. post_sdn, pre_sdn, post_sdn, sdn, 0);
  1755. hint = slapi_attr_next_value(attr, hint, &val);
  1756. }
  1757. slapi_sdn_free(&sdn);
  1758. if(last_str)
  1759. slapi_ch_free_string(&last_str);
  1760. return rc;
  1761. }
  1762. /* memberof_get_groups()
  1763. *
  1764. * Gets a list of all groups that an entry is a member of.
  1765. * This is done by looking only at member attribute values.
  1766. * A Slapi_ValueSet* is returned. It is up to the caller to
  1767. * free it.
  1768. */
  1769. Slapi_ValueSet *
  1770. memberof_get_groups(MemberOfConfig *config, Slapi_DN *member_sdn)
  1771. {
  1772. Slapi_ValueSet *groupvals = slapi_valueset_new();
  1773. Slapi_ValueSet *group_norm_vals = slapi_valueset_new();
  1774. Slapi_Value *memberdn_val =
  1775. slapi_value_new_string(slapi_sdn_get_ndn(member_sdn));
  1776. slapi_value_set_flags(memberdn_val, SLAPI_ATTR_FLAG_NORMALIZED_CIS);
  1777. memberof_get_groups_data data = {config, memberdn_val, &groupvals, &group_norm_vals};
  1778. memberof_get_groups_r(config, member_sdn, &data);
  1779. slapi_value_free(&memberdn_val);
  1780. slapi_valueset_free(group_norm_vals);
  1781. return groupvals;
  1782. }
  1783. int
  1784. memberof_get_groups_r(MemberOfConfig *config, Slapi_DN *member_sdn,
  1785. memberof_get_groups_data *data)
  1786. {
  1787. /* Search for any grouping attributes that point to memberdn.
  1788. * For each match, add it to the list, recurse and do same search */
  1789. return memberof_call_foreach_dn(NULL, member_sdn, config, config->groupattrs,
  1790. memberof_get_groups_callback, data);
  1791. }
  1792. /* memberof_get_groups_callback()
  1793. *
  1794. * Callback to perform work of memberof_get_groups()
  1795. */
  1796. int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data)
  1797. {
  1798. Slapi_DN *group_sdn = slapi_entry_get_sdn(e);
  1799. char *group_ndn = slapi_entry_get_ndn(e);
  1800. char *group_dn = slapi_entry_get_dn(e);
  1801. Slapi_Value *group_ndn_val = 0;
  1802. Slapi_Value *group_dn_val = 0;
  1803. Slapi_ValueSet *groupvals = *((memberof_get_groups_data*)callback_data)->groupvals;
  1804. Slapi_ValueSet *group_norm_vals = *((memberof_get_groups_data*)callback_data)->group_norm_vals;
  1805. MemberOfConfig *config = ((memberof_get_groups_data*)callback_data)->config;
  1806. int rc = 0;
  1807. if(slapi_is_shutting_down()){
  1808. rc = -1;
  1809. goto bail;
  1810. }
  1811. if (!groupvals || !group_norm_vals)
  1812. {
  1813. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  1814. "memberof_get_groups_callback: NULL groupvals or group_norm_vals\n");
  1815. rc = -1;
  1816. goto bail;
  1817. }
  1818. /* get the DN of the group */
  1819. group_ndn_val = slapi_value_new_string(group_ndn);
  1820. /* group_dn is case-normalized */
  1821. slapi_value_set_flags(group_ndn_val, SLAPI_ATTR_FLAG_NORMALIZED_CIS);
  1822. /* check if e is the same as our original member entry */
  1823. if (0 == memberof_compare(((memberof_get_groups_data*)callback_data)->config,
  1824. &((memberof_get_groups_data*)callback_data)->memberdn_val, &group_ndn_val))
  1825. {
  1826. /* A recursive group caused us to find our original
  1827. * entry we passed to memberof_get_groups(). We just
  1828. * skip processing this entry. */
  1829. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  1830. "memberof_get_groups_callback: group recursion"
  1831. " detected in %s\n" ,group_ndn);
  1832. slapi_value_free(&group_ndn_val);
  1833. goto bail;
  1834. }
  1835. /* Have we been here before? Note that we don't loop through all of the group_slapiattrs
  1836. * in config. We only need this attribute for it's syntax so the comparison can be
  1837. * performed. Since all of the grouping attributes are validated to use the Dinstinguished
  1838. * Name syntax, we can safely just use the first group_slapiattr. */
  1839. if (slapi_valueset_find(
  1840. ((memberof_get_groups_data*)callback_data)->config->group_slapiattrs[0], group_norm_vals, group_ndn_val))
  1841. {
  1842. /* we either hit a recursive grouping, or an entry is
  1843. * a member of a group through multiple paths. Either
  1844. * way, we can just skip processing this entry since we've
  1845. * already gone through this part of the grouping hierarchy. */
  1846. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  1847. "memberof_get_groups_callback: possible group recursion"
  1848. " detected in %s\n" ,group_ndn);
  1849. slapi_value_free(&group_ndn_val);
  1850. goto bail;
  1851. }
  1852. /* if the group does not belong to an excluded subtree, adds it to the valueset */
  1853. if (memberof_entry_in_scope(config, group_sdn)) {
  1854. /* Push group_dn_val into the valueset. This memory is now owned
  1855. * by the valueset. */
  1856. group_dn_val = slapi_value_new_string(group_dn);
  1857. slapi_valueset_add_value_ext(groupvals, group_dn_val, SLAPI_VALUE_FLAG_PASSIN);
  1858. slapi_valueset_add_value_ext(group_norm_vals, group_ndn_val, SLAPI_VALUE_FLAG_PASSIN);
  1859. }
  1860. if(!config->skip_nested || config->fixup_task){
  1861. /* now recurse to find parent groups of e */
  1862. memberof_get_groups_r(((memberof_get_groups_data*)callback_data)->config,
  1863. group_sdn, callback_data);
  1864. }
  1865. bail:
  1866. return rc;
  1867. }
  1868. /* memberof_is_direct_member()
  1869. *
  1870. * tests for direct membership of memberdn in group groupdn
  1871. * returns non-zero when true, zero otherwise
  1872. */
  1873. int memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn,
  1874. Slapi_Value *memberdn)
  1875. {
  1876. int rc = 0;
  1877. Slapi_DN *sdn = 0;
  1878. Slapi_Entry *group_e = 0;
  1879. Slapi_Attr *attr = 0;
  1880. int i = 0;
  1881. sdn = slapi_sdn_new_normdn_byref(slapi_value_get_string(groupdn));
  1882. slapi_search_internal_get_entry(sdn, config->groupattrs,
  1883. &group_e, memberof_get_plugin_id());
  1884. if(group_e)
  1885. {
  1886. /* See if memberdn is referred to by any of the group attributes. */
  1887. for (i = 0; config->groupattrs[i]; i++)
  1888. {
  1889. slapi_entry_attr_find(group_e, config->groupattrs[i], &attr );
  1890. if(attr && (0 == slapi_attr_value_find(attr, slapi_value_get_berval(memberdn))))
  1891. {
  1892. rc = 1;
  1893. break;
  1894. }
  1895. }
  1896. slapi_entry_free(group_e);
  1897. }
  1898. slapi_sdn_free(&sdn);
  1899. return rc;
  1900. }
  1901. /* memberof_is_grouping_attr()
  1902. *
  1903. * Checks if a supplied attribute is one of the configured
  1904. * grouping attributes.
  1905. *
  1906. * Returns non-zero when true, zero otherwise.
  1907. */
  1908. static int memberof_is_grouping_attr(char *type, MemberOfConfig *config)
  1909. {
  1910. int match = 0;
  1911. int i = 0;
  1912. for (i = 0; config && config->groupattrs[i]; i++)
  1913. {
  1914. match = slapi_attr_types_equivalent(type, config->groupattrs[i]);
  1915. if (match)
  1916. {
  1917. /* If we found a match, we're done. */
  1918. break;
  1919. }
  1920. }
  1921. return match;
  1922. }
  1923. /* memberof_test_membership()
  1924. *
  1925. * Finds all entries who are a "memberOf" the group
  1926. * represented by "group_dn". For each matching entry, we
  1927. * call memberof_test_membership_callback().
  1928. *
  1929. * for each attribute in the memberof attribute
  1930. * determine if the entry is still a member.
  1931. *
  1932. * test each for direct membership
  1933. * move groups entry is memberof to member group
  1934. * test remaining groups for membership in member groups
  1935. * iterate until a pass fails to move a group over to member groups
  1936. * remaining groups should be deleted
  1937. */
  1938. int
  1939. memberof_test_membership(Slapi_PBlock *pb, MemberOfConfig *config,
  1940. Slapi_DN *group_sdn)
  1941. {
  1942. char *attrs[2] = {config->memberof_attr, 0};
  1943. return memberof_call_foreach_dn(pb, group_sdn, config, attrs,
  1944. memberof_test_membership_callback, config);
  1945. }
  1946. /*
  1947. * memberof_test_membership_callback()
  1948. *
  1949. * A callback function to do the work of memberof_test_membership().
  1950. * Note that this not only tests membership, but updates the memberOf
  1951. * attributes in the entry to be correct.
  1952. */
  1953. int memberof_test_membership_callback(Slapi_Entry *e, void *callback_data)
  1954. {
  1955. int rc = 0;
  1956. Slapi_Attr *attr = 0;
  1957. int total = 0;
  1958. Slapi_Value **member_array = 0;
  1959. Slapi_Value **candidate_array = 0;
  1960. Slapi_Value *entry_dn = 0;
  1961. Slapi_DN *entry_sdn = 0;
  1962. MemberOfConfig *config = (MemberOfConfig *)callback_data;
  1963. Slapi_DN *sdn = slapi_sdn_new();
  1964. entry_sdn = slapi_entry_get_sdn(e);
  1965. entry_dn = slapi_value_new_string(slapi_entry_get_ndn(e));
  1966. if(entry_dn == NULL){
  1967. goto bail;
  1968. }
  1969. slapi_value_set_flags(entry_dn, SLAPI_ATTR_FLAG_NORMALIZED_CIS);
  1970. /* divide groups into member and non-member lists */
  1971. slapi_entry_attr_find(e, config->memberof_attr, &attr );
  1972. if(attr)
  1973. {
  1974. slapi_attr_get_numvalues( attr, &total);
  1975. if(total)
  1976. {
  1977. Slapi_Value *val = 0;
  1978. int hint = 0;
  1979. int c_index = 0;
  1980. int m_index = 0;
  1981. int member_found = 1;
  1982. int outer_index = 0;
  1983. candidate_array =
  1984. (Slapi_Value**)
  1985. slapi_ch_malloc(sizeof(Slapi_Value*)*total);
  1986. memset(candidate_array, 0, sizeof(Slapi_Value*)*total);
  1987. member_array =
  1988. (Slapi_Value**)
  1989. slapi_ch_malloc(sizeof(Slapi_Value*)*total);
  1990. memset(member_array, 0, sizeof(Slapi_Value*)*total);
  1991. hint = slapi_attr_first_value(attr, &val);
  1992. while(val)
  1993. {
  1994. /* test for direct membership */
  1995. if(memberof_is_direct_member(config, val, entry_dn))
  1996. {
  1997. /* it is a member */
  1998. member_array[m_index] = val;
  1999. m_index++;
  2000. }
  2001. else
  2002. {
  2003. /* not a member, still a candidate */
  2004. candidate_array[c_index] = val;
  2005. c_index++;
  2006. }
  2007. hint = slapi_attr_next_value(attr, hint, &val);
  2008. }
  2009. /* now iterate over members testing for membership
  2010. in candidate groups and moving candidates to members
  2011. when successful, quit when a full iteration adds no
  2012. new members
  2013. */
  2014. while(member_found)
  2015. {
  2016. member_found = 0;
  2017. /* For each group that this entry is a verified member of, see if
  2018. * any of the candidate groups are members. If they are, add them
  2019. * to the list of verified groups that this entry is a member of.
  2020. */
  2021. while(outer_index < m_index)
  2022. {
  2023. int inner_index = 0;
  2024. while(inner_index < c_index)
  2025. {
  2026. /* Check for a special value in this position
  2027. * that indicates that the candidate was moved
  2028. * to the member array. */
  2029. if((void*)1 == candidate_array[inner_index])
  2030. {
  2031. /* was moved, skip */
  2032. inner_index++;
  2033. continue;
  2034. }
  2035. if(memberof_is_direct_member(
  2036. config,
  2037. candidate_array[inner_index],
  2038. member_array[outer_index]))
  2039. {
  2040. member_array[m_index] =
  2041. candidate_array
  2042. [inner_index];
  2043. m_index++;
  2044. candidate_array[inner_index] =
  2045. (void*)1;
  2046. member_found = 1;
  2047. }
  2048. inner_index++;
  2049. }
  2050. outer_index++;
  2051. }
  2052. }
  2053. /* here we are left only with values to delete
  2054. from the memberof attribute in the candidate list
  2055. */
  2056. outer_index = 0;
  2057. while(outer_index < c_index)
  2058. {
  2059. /* Check for a special value in this position
  2060. * that indicates that the candidate was moved
  2061. * to the member array. */
  2062. if((void*)1 == candidate_array[outer_index])
  2063. {
  2064. /* item moved, skip */
  2065. outer_index++;
  2066. continue;
  2067. }
  2068. slapi_sdn_set_normdn_byref(sdn,
  2069. slapi_value_get_string(candidate_array[outer_index]));
  2070. memberof_del_one(0, config, sdn, entry_sdn);
  2071. outer_index++;
  2072. }
  2073. {
  2074. /* crazyness follows:
  2075. * strict-aliasing doesn't like the required cast
  2076. * to void for slapi_ch_free so we are made to
  2077. * juggle to get a normal thing done
  2078. */
  2079. void *pmember_array = member_array;
  2080. void *pcandidate_array = candidate_array;
  2081. slapi_ch_free(&pcandidate_array);
  2082. slapi_ch_free(&pmember_array);
  2083. candidate_array = 0;
  2084. member_array = 0;
  2085. }
  2086. }
  2087. }
  2088. bail:
  2089. slapi_sdn_free(&sdn);
  2090. slapi_value_free(&entry_dn);
  2091. return rc;
  2092. }
  2093. /*
  2094. * memberof_replace_list()
  2095. *
  2096. * Perform replace the group DN list in the memberof attribute of the list of targets
  2097. *
  2098. */
  2099. int
  2100. memberof_replace_list(Slapi_PBlock *pb, MemberOfConfig *config,
  2101. Slapi_DN *group_sdn)
  2102. {
  2103. struct slapi_entry *pre_e = NULL;
  2104. struct slapi_entry *post_e = NULL;
  2105. Slapi_Attr *pre_attr = 0;
  2106. Slapi_Attr *post_attr = 0;
  2107. int rc = 0;
  2108. int i = 0;
  2109. slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &pre_e );
  2110. slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &post_e );
  2111. for (i = 0; config && config->groupattrs[i]; i++)
  2112. {
  2113. if(pre_e && post_e)
  2114. {
  2115. slapi_entry_attr_find( pre_e, config->groupattrs[i], &pre_attr );
  2116. slapi_entry_attr_find( post_e, config->groupattrs[i], &post_attr );
  2117. }
  2118. if(pre_attr || post_attr)
  2119. {
  2120. int pre_total = 0;
  2121. int post_total = 0;
  2122. Slapi_Value **pre_array = 0;
  2123. Slapi_Value **post_array = 0;
  2124. int pre_index = 0;
  2125. int post_index = 0;
  2126. Slapi_DN *sdn = slapi_sdn_new();
  2127. /* create arrays of values */
  2128. if(pre_attr)
  2129. {
  2130. slapi_attr_get_numvalues( pre_attr, &pre_total);
  2131. }
  2132. if(post_attr)
  2133. {
  2134. slapi_attr_get_numvalues( post_attr, &post_total);
  2135. }
  2136. /* Stash a plugin global pointer here and have memberof_qsort_compare
  2137. * use it. We have to do this because we use memberof_qsort_compare
  2138. * as the comparator function for qsort, which requires the function
  2139. * to only take two void* args. This is thread-safe since we only
  2140. * store and use the pointer while holding the memberOf operation
  2141. * lock. */
  2142. qsortConfig = config;
  2143. if(pre_total)
  2144. {
  2145. pre_array =
  2146. (Slapi_Value**)
  2147. slapi_ch_malloc(sizeof(Slapi_Value*)*pre_total);
  2148. memberof_load_array(pre_array, pre_attr);
  2149. qsort(
  2150. pre_array,
  2151. pre_total,
  2152. sizeof(Slapi_Value*),
  2153. memberof_qsort_compare);
  2154. }
  2155. if(post_total)
  2156. {
  2157. post_array =
  2158. (Slapi_Value**)
  2159. slapi_ch_malloc(sizeof(Slapi_Value*)*post_total);
  2160. memberof_load_array(post_array, post_attr);
  2161. qsort(
  2162. post_array,
  2163. post_total,
  2164. sizeof(Slapi_Value*),
  2165. memberof_qsort_compare);
  2166. }
  2167. qsortConfig = 0;
  2168. /* work through arrays, following these rules:
  2169. in pre, in post, do nothing
  2170. in pre, not in post, delete from entry
  2171. not in pre, in post, add to entry
  2172. */
  2173. while(rc == 0 && (pre_index < pre_total || post_index < post_total))
  2174. {
  2175. if(pre_index == pre_total)
  2176. {
  2177. /* add the rest of post */
  2178. slapi_sdn_set_normdn_byref(sdn,
  2179. slapi_value_get_string(post_array[post_index]));
  2180. rc = memberof_add_one(pb, config, group_sdn, sdn);
  2181. post_index++;
  2182. }
  2183. else if(post_index == post_total)
  2184. {
  2185. /* delete the rest of pre */
  2186. slapi_sdn_set_normdn_byref(sdn,
  2187. slapi_value_get_string(pre_array[pre_index]));
  2188. rc = memberof_del_one(pb, config, group_sdn, sdn);
  2189. pre_index++;
  2190. }
  2191. else
  2192. {
  2193. /* decide what to do */
  2194. int cmp = memberof_compare(
  2195. config,
  2196. &(pre_array[pre_index]),
  2197. &(post_array[post_index]));
  2198. if(cmp < 0)
  2199. {
  2200. /* delete pre array */
  2201. slapi_sdn_set_normdn_byref(sdn,
  2202. slapi_value_get_string(pre_array[pre_index]));
  2203. rc = memberof_del_one(pb, config, group_sdn, sdn);
  2204. pre_index++;
  2205. }
  2206. else if(cmp > 0)
  2207. {
  2208. /* add post array */
  2209. slapi_sdn_set_normdn_byref(sdn,
  2210. slapi_value_get_string(post_array[post_index]));
  2211. rc = memberof_add_one(pb, config, group_sdn, sdn);
  2212. post_index++;
  2213. }
  2214. else
  2215. {
  2216. /* do nothing, advance */
  2217. pre_index++;
  2218. post_index++;
  2219. }
  2220. }
  2221. }
  2222. slapi_sdn_free(&sdn);
  2223. slapi_ch_free((void **)&pre_array);
  2224. slapi_ch_free((void **)&post_array);
  2225. }
  2226. }
  2227. return rc;
  2228. }
  2229. /* memberof_load_array()
  2230. *
  2231. * put attribute values in array structure
  2232. */
  2233. void memberof_load_array(Slapi_Value **array, Slapi_Attr *attr)
  2234. {
  2235. Slapi_Value *val = 0;
  2236. int hint = slapi_attr_first_value(attr, &val);
  2237. while(val)
  2238. {
  2239. *array = val;
  2240. array++;
  2241. hint = slapi_attr_next_value(attr, hint, &val);
  2242. }
  2243. }
  2244. /* memberof_compare()
  2245. *
  2246. * compare two attr values
  2247. */
  2248. int memberof_compare(MemberOfConfig *config, const void *a, const void *b)
  2249. {
  2250. Slapi_Value *val1;
  2251. Slapi_Value *val2;
  2252. if(a == NULL && b != NULL){
  2253. return 1;
  2254. } else if(a != NULL && b == NULL){
  2255. return -1;
  2256. } else if(a == NULL && b == NULL){
  2257. return 0;
  2258. }
  2259. val1 = *((Slapi_Value **)a);
  2260. val2 = *((Slapi_Value **)b);
  2261. /* We only need to provide a Slapi_Attr here for it's syntax. We
  2262. * already validated all grouping attributes to use the Distinguished
  2263. * Name syntax, so we can safely just use the first attr. */
  2264. return slapi_attr_value_cmp_ext(config->group_slapiattrs[0], val1, val2);
  2265. }
  2266. /* memberof_qsort_compare()
  2267. *
  2268. * This is a version of memberof_compare that uses a plugin
  2269. * global copy of the config. We'd prefer to pass in a copy
  2270. * of config that is local to the running thread, but we can't
  2271. * do this since qsort is using us as a comparator function.
  2272. * We should only use this function when using qsort, and only
  2273. * when the memberOf lock is acquired.
  2274. */
  2275. int memberof_qsort_compare(const void *a, const void *b)
  2276. {
  2277. Slapi_Value *val1 = *((Slapi_Value **)a);
  2278. Slapi_Value *val2 = *((Slapi_Value **)b);
  2279. /* We only need to provide a Slapi_Attr here for it's syntax. We
  2280. * already validated all grouping attributes to use the Distinguished
  2281. * Name syntax, so we can safely just use the first attr. */
  2282. return slapi_attr_value_cmp_ext(qsortConfig->group_slapiattrs[0],
  2283. val1, val2);
  2284. }
  2285. /* betxn: This locking mechanism is necessary to guarantee the memberof
  2286. * consistency */
  2287. void memberof_lock()
  2288. {
  2289. if (usetxn) {
  2290. PR_EnterMonitor(memberof_operation_lock);
  2291. }
  2292. }
  2293. void memberof_unlock()
  2294. {
  2295. if (usetxn) {
  2296. PR_ExitMonitor(memberof_operation_lock);
  2297. }
  2298. }
  2299. typedef struct _task_data
  2300. {
  2301. char *dn;
  2302. char *bind_dn;
  2303. char *filter_str;
  2304. } task_data;
  2305. void memberof_fixup_task_thread(void *arg)
  2306. {
  2307. MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  2308. Slapi_Task *task = (Slapi_Task *)arg;
  2309. task_data *td = NULL;
  2310. int rc = 0;
  2311. Slapi_PBlock *fixup_pb = NULL;
  2312. if (!task) {
  2313. return; /* no task */
  2314. }
  2315. slapi_task_inc_refcount(task);
  2316. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  2317. "memberof_fixup_task_thread --> refcount incremented.\n" );
  2318. /* Fetch our task data from the task */
  2319. td = (task_data *)slapi_task_get_data(task);
  2320. /* set bind DN in the thread data */
  2321. slapi_td_set_dn(slapi_ch_strdup(td->bind_dn));
  2322. slapi_task_begin(task, 1);
  2323. slapi_task_log_notice(task, "Memberof task starts (arg: %s) ...\n",
  2324. td->filter_str);
  2325. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  2326. "Memberof task starts (arg: %s) ...\n", td->filter_str);
  2327. /* We need to get the config lock first. Trying to get the
  2328. * config lock after we already hold the op lock can cause
  2329. * a deadlock. */
  2330. memberof_rlock_config();
  2331. /* copy config so it doesn't change out from under us */
  2332. memberof_copy_config(&configCopy, memberof_get_config());
  2333. memberof_unlock_config();
  2334. /* Mark this as a task operation */
  2335. configCopy.fixup_task = 1;
  2336. if (usetxn) {
  2337. Slapi_DN *sdn = slapi_sdn_new_dn_byref(td->dn);
  2338. Slapi_Backend *be = slapi_be_select(sdn);
  2339. slapi_sdn_free(&sdn);
  2340. if (be) {
  2341. fixup_pb = slapi_pblock_new();
  2342. slapi_pblock_set(fixup_pb, SLAPI_BACKEND, be);
  2343. rc = slapi_back_transaction_begin(fixup_pb);
  2344. if (rc) {
  2345. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  2346. "memberof_fixup_task_thread: failed to start transaction\n");
  2347. }
  2348. } else {
  2349. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  2350. "memberof_fixup_task_thread: failed to get be backend from %s\n",
  2351. td->dn);
  2352. }
  2353. }
  2354. /* get the memberOf operation lock */
  2355. memberof_lock();
  2356. /* do real work */
  2357. rc = memberof_fix_memberof(&configCopy, td->dn, td->filter_str);
  2358. /* release the memberOf operation lock */
  2359. memberof_unlock();
  2360. if (usetxn && fixup_pb) {
  2361. if (rc) { /* failes */
  2362. slapi_back_transaction_abort(fixup_pb);
  2363. } else {
  2364. slapi_back_transaction_commit(fixup_pb);
  2365. }
  2366. slapi_pblock_destroy(fixup_pb);
  2367. }
  2368. memberof_free_config(&configCopy);
  2369. slapi_task_log_notice(task, "Memberof task finished.");
  2370. slapi_task_log_status(task, "Memberof task finished.");
  2371. slapi_task_inc_progress(task);
  2372. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  2373. "Memberof task finished (arg: %s) ...\n", td->filter_str);
  2374. /* this will queue the destruction of the task */
  2375. slapi_task_finish(task, rc);
  2376. slapi_task_dec_refcount(task);
  2377. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  2378. "memberof_fixup_task_thread <-- refcount decremented.\n");
  2379. }
  2380. /* extract a single value from the entry (as a string) -- if it's not in the
  2381. * entry, the default will be returned (which can be NULL).
  2382. * you do not need to free anything returned by this.
  2383. */
  2384. const char *fetch_attr(Slapi_Entry *e, const char *attrname,
  2385. const char *default_val)
  2386. {
  2387. Slapi_Attr *attr;
  2388. Slapi_Value *val = NULL;
  2389. if (slapi_entry_attr_find(e, attrname, &attr) != 0)
  2390. return default_val;
  2391. slapi_attr_first_value(attr, &val);
  2392. return slapi_value_get_string(val);
  2393. }
  2394. int memberof_task_add(Slapi_PBlock *pb, Slapi_Entry *e,
  2395. Slapi_Entry *eAfter, int *returncode, char *returntext,
  2396. void *arg)
  2397. {
  2398. PRThread *thread = NULL;
  2399. int rv = SLAPI_DSE_CALLBACK_OK;
  2400. task_data *mytaskdata = NULL;
  2401. Slapi_Task *task = NULL;
  2402. char *bind_dn;
  2403. const char *filter;
  2404. const char *dn = 0;
  2405. *returncode = LDAP_SUCCESS;
  2406. /* get arg(s) */
  2407. if ((dn = fetch_attr(e, "basedn", 0)) == NULL)
  2408. {
  2409. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  2410. rv = SLAPI_DSE_CALLBACK_ERROR;
  2411. goto out;
  2412. }
  2413. if ((filter = fetch_attr(e, "filter", "(|(objectclass=inetuser)(objectclass=inetadmin))")) == NULL)
  2414. {
  2415. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  2416. rv = SLAPI_DSE_CALLBACK_ERROR;
  2417. goto out;
  2418. }
  2419. /* setup our task data */
  2420. slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &bind_dn);
  2421. mytaskdata = (task_data*)slapi_ch_malloc(sizeof(task_data));
  2422. if (mytaskdata == NULL)
  2423. {
  2424. *returncode = LDAP_OPERATIONS_ERROR;
  2425. rv = SLAPI_DSE_CALLBACK_ERROR;
  2426. goto out;
  2427. }
  2428. mytaskdata->dn = slapi_ch_strdup(dn);
  2429. mytaskdata->filter_str = slapi_ch_strdup(filter);
  2430. mytaskdata->bind_dn = slapi_ch_strdup(bind_dn);
  2431. /* allocate new task now */
  2432. task = slapi_plugin_new_task(slapi_entry_get_ndn(e), arg);
  2433. /* register our destructor for cleaning up our private data */
  2434. slapi_task_set_destructor_fn(task, memberof_task_destructor);
  2435. /* Stash a pointer to our data in the task */
  2436. slapi_task_set_data(task, mytaskdata);
  2437. /* start the sample task as a separate thread */
  2438. thread = PR_CreateThread(PR_USER_THREAD, memberof_fixup_task_thread,
  2439. (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  2440. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  2441. if (thread == NULL)
  2442. {
  2443. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  2444. "unable to create task thread!\n");
  2445. *returncode = LDAP_OPERATIONS_ERROR;
  2446. slapi_task_finish(task, *returncode);
  2447. rv = SLAPI_DSE_CALLBACK_ERROR;
  2448. } else {
  2449. rv = SLAPI_DSE_CALLBACK_OK;
  2450. }
  2451. out:
  2452. return rv;
  2453. }
  2454. void
  2455. memberof_task_destructor(Slapi_Task *task)
  2456. {
  2457. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  2458. "memberof_task_destructor -->\n" );
  2459. if (task) {
  2460. task_data *mydata = (task_data *)slapi_task_get_data(task);
  2461. while (slapi_task_get_refcount(task) > 0) {
  2462. /* Yield to wait for the fixup task finishes. */
  2463. DS_Sleep (PR_MillisecondsToInterval(100));
  2464. }
  2465. if (mydata) {
  2466. slapi_ch_free_string(&mydata->dn);
  2467. slapi_ch_free_string(&mydata->bind_dn);
  2468. slapi_ch_free_string(&mydata->filter_str);
  2469. /* Need to cast to avoid a compiler warning */
  2470. slapi_ch_free((void **)&mydata);
  2471. }
  2472. }
  2473. slapi_log_error(SLAPI_LOG_PLUGIN, LOG_DEBUG, MEMBEROF_PLUGIN_SUBSYSTEM,
  2474. "memberof_task_destructor <--\n" );
  2475. }
  2476. int memberof_fix_memberof(MemberOfConfig *config, char *dn, char *filter_str)
  2477. {
  2478. int rc = 0;
  2479. Slapi_PBlock *search_pb = slapi_pblock_new();
  2480. slapi_search_internal_set_pb(search_pb, dn,
  2481. LDAP_SCOPE_SUBTREE, filter_str, 0, 0,
  2482. 0, 0,
  2483. memberof_get_plugin_id(),
  2484. 0);
  2485. rc = slapi_search_internal_callback_pb(search_pb,
  2486. config,
  2487. 0, memberof_fix_memberof_callback,
  2488. 0);
  2489. slapi_pblock_destroy(search_pb);
  2490. return rc;
  2491. }
  2492. /* memberof_fix_memberof_callback()
  2493. * Add initial and/or fix up broken group list in entry
  2494. *
  2495. * 1. Remove all present memberOf values
  2496. * 2. Add direct group membership memberOf values
  2497. * 3. Add indirect group membership memberOf values
  2498. */
  2499. int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data)
  2500. {
  2501. int rc = 0;
  2502. Slapi_DN *sdn = slapi_entry_get_sdn(e);
  2503. MemberOfConfig *config = (MemberOfConfig *)callback_data;
  2504. memberof_del_dn_data del_data = {0, config->memberof_attr};
  2505. Slapi_ValueSet *groups = 0;
  2506. /*
  2507. * If the server is ordered to shutdown, stop the fixup and return an error.
  2508. */
  2509. if (slapi_is_shutting_down()) {
  2510. rc = -1;
  2511. goto bail;
  2512. }
  2513. /* get a list of all of the groups this user belongs to */
  2514. groups = memberof_get_groups(config, sdn);
  2515. /* If we found some groups, replace the existing memberOf attribute
  2516. * with the found values. */
  2517. if (groups && slapi_valueset_count(groups))
  2518. {
  2519. Slapi_Value *val = 0;
  2520. Slapi_Mod *smod;
  2521. LDAPMod **mods = (LDAPMod **) slapi_ch_malloc(2 * sizeof(LDAPMod *));
  2522. int hint = 0;
  2523. smod = slapi_mod_new();
  2524. slapi_mod_init(smod, 0);
  2525. slapi_mod_set_operation(smod, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
  2526. slapi_mod_set_type(smod, config->memberof_attr);
  2527. /* Loop through all of our values and add them to smod */
  2528. hint = slapi_valueset_first_value(groups, &val);
  2529. while (val)
  2530. {
  2531. /* this makes a copy of the berval */
  2532. slapi_mod_add_value(smod, slapi_value_get_berval(val));
  2533. hint = slapi_valueset_next_value(groups, hint, &val);
  2534. }
  2535. mods[0] = slapi_mod_get_ldapmod_passout(smod);
  2536. mods[1] = 0;
  2537. rc = memberof_add_memberof_attr(mods, slapi_sdn_get_dn(sdn), config->auto_add_oc);
  2538. ldap_mods_free(mods, 1);
  2539. slapi_mod_free(&smod);
  2540. } else {
  2541. /* No groups were found, so remove the memberOf attribute
  2542. * from this entry. */
  2543. memberof_del_dn_type_callback(e, &del_data);
  2544. }
  2545. slapi_valueset_free(groups);
  2546. bail:
  2547. return rc;
  2548. }
  2549. /*
  2550. * Add the "memberof" attribute to the entry. If we get an objectclass violation,
  2551. * check if we are auto adding an objectclass. IF so, add the oc, and try the
  2552. * operation one more time.
  2553. */
  2554. static int
  2555. memberof_add_memberof_attr(LDAPMod **mods, const char *dn, char *add_oc)
  2556. {
  2557. Slapi_PBlock *mod_pb = NULL;
  2558. int added_oc = 0;
  2559. int rc = 0;
  2560. while(1){
  2561. mod_pb = slapi_pblock_new();
  2562. slapi_modify_internal_set_pb(
  2563. mod_pb, dn, mods, 0, 0,
  2564. memberof_get_plugin_id(), 0);
  2565. slapi_modify_internal_pb(mod_pb);
  2566. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  2567. if (rc == LDAP_OBJECT_CLASS_VIOLATION){
  2568. if (!add_oc || added_oc){
  2569. /*
  2570. * We aren't auto adding an objectclass, or we already
  2571. * added the objectclass, and we are still failing.
  2572. */
  2573. break;
  2574. }
  2575. if(memberof_add_objectclass(add_oc, dn)){
  2576. /* Failed to add objectclass */
  2577. break;
  2578. }
  2579. added_oc = 1;
  2580. slapi_pblock_destroy(mod_pb);
  2581. } else if (rc){
  2582. /* Some other fatal error */
  2583. break;
  2584. } else {
  2585. /* success */
  2586. break;
  2587. }
  2588. }
  2589. slapi_pblock_destroy(mod_pb);
  2590. return rc;
  2591. }
  2592. /*
  2593. * Add the "auto add" objectclass to an entry
  2594. */
  2595. static int
  2596. memberof_add_objectclass(char *auto_add_oc, const char *dn)
  2597. {
  2598. Slapi_PBlock *mod_pb = NULL;
  2599. LDAPMod mod;
  2600. LDAPMod *mods[2];
  2601. char *val[2];
  2602. int rc = 0;
  2603. mod_pb = slapi_pblock_new();
  2604. mods[0] = &mod;
  2605. mods[1] = 0;
  2606. val[0] = auto_add_oc;
  2607. val[1] = 0;
  2608. mod.mod_op = LDAP_MOD_ADD;
  2609. mod.mod_type = "objectclass";
  2610. mod.mod_values = val;
  2611. slapi_modify_internal_set_pb(
  2612. mod_pb, dn, mods, 0, 0,
  2613. memberof_get_plugin_id(), 0);
  2614. slapi_modify_internal_pb(mod_pb);
  2615. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  2616. if (rc){
  2617. slapi_log_error(SLAPI_LOG_FATAL, LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM,
  2618. "Failed to add objectclass (%s) to entry (%s)\n",
  2619. auto_add_oc, dn);
  2620. }
  2621. slapi_pblock_destroy(mod_pb);
  2622. return rc;
  2623. }