automember.c 96 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2011 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. #ifdef HAVE_CONFIG_H
  9. #include <config.h>
  10. #endif
  11. /*
  12. * Auto Membership Plug-in
  13. */
  14. #include "automember.h"
  15. /*
  16. * Plug-in globals
  17. */
  18. static PRCList *g_automember_config = NULL;
  19. static Slapi_RWLock *g_automember_config_lock = NULL;
  20. static void *_PluginID = NULL;
  21. static Slapi_DN *_PluginDN = NULL;
  22. static Slapi_DN *_ConfigAreaDN = NULL;
  23. static Slapi_PluginDesc pdesc = {AUTOMEMBER_FEATURE_DESC,
  24. VENDOR,
  25. DS_PACKAGE_VERSION,
  26. AUTOMEMBER_PLUGIN_DESC};
  27. /*
  28. * Plug-in management functions
  29. */
  30. int automember_init(Slapi_PBlock *pb);
  31. static int automember_start(Slapi_PBlock *pb);
  32. static int automember_close(Slapi_PBlock *pb);
  33. static int automember_postop_init(Slapi_PBlock *pb);
  34. static int automember_internal_postop_init(Slapi_PBlock *pb);
  35. /*
  36. * Operation callbacks (where the real work is done)
  37. */
  38. static int automember_mod_post_op(Slapi_PBlock *pb);
  39. static int automember_add_post_op(Slapi_PBlock *pb);
  40. static int automember_del_post_op(Slapi_PBlock *pb);
  41. static int automember_modrdn_post_op(Slapi_PBlock *pb);
  42. static int automember_pre_op(Slapi_PBlock *pb, int modop);
  43. static int automember_mod_pre_op(Slapi_PBlock *pb);
  44. static int automember_add_pre_op(Slapi_PBlock *pb);
  45. /*
  46. * Config cache management functions
  47. */
  48. static int automember_load_config(void);
  49. static void automember_delete_config(void);
  50. static int automember_parse_config_entry(Slapi_Entry *e, int apply);
  51. static void automember_free_config_entry(struct configEntry **entry);
  52. /*
  53. * helpers
  54. */
  55. static Slapi_DN *automember_get_sdn(Slapi_PBlock *pb);
  56. static Slapi_DN *automember_get_config_area(void);
  57. static void automember_set_config_area(Slapi_DN *sdn);
  58. static int automember_dn_is_config(Slapi_DN *sdn);
  59. static int automember_oktodo(Slapi_PBlock *pb);
  60. static int automember_isrepl(Slapi_PBlock *pb);
  61. static void automember_parse_regex_entry(struct configEntry *config, Slapi_Entry *e);
  62. static struct automemberRegexRule *automember_parse_regex_rule(char *rule_string);
  63. static void automember_free_regex_rule(struct automemberRegexRule *rule);
  64. static int automember_parse_grouping_attr(char *value, char **grouping_attr, char **grouping_value);
  65. static int automember_update_membership(struct configEntry *config, Slapi_Entry *e, PRFileDesc *ldif_fd);
  66. static int automember_add_member_value(Slapi_Entry *member_e, const char *group_dn, char *grouping_attr, char *grouping_value, PRFileDesc *ldif_fd);
  67. /*
  68. * task functions
  69. */
  70. static int automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
  71. static int automember_task_add_export_updates(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
  72. static int automember_task_add_map_entries(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
  73. void automember_rebuild_task_thread(void *arg);
  74. void automember_export_task_thread(void *arg);
  75. void automember_map_task_thread(void *arg);
  76. static void automember_task_destructor(Slapi_Task *task);
  77. static void automember_task_export_destructor(Slapi_Task *task);
  78. static void automember_task_map_destructor(Slapi_Task *task);
  79. #define DEFAULT_FILE_MODE PR_IRUSR | PR_IWUSR
  80. /*
  81. * Config cache locking functions
  82. */
  83. void
  84. automember_config_read_lock()
  85. {
  86. slapi_rwlock_rdlock(g_automember_config_lock);
  87. }
  88. void
  89. automember_config_write_lock()
  90. {
  91. slapi_rwlock_wrlock(g_automember_config_lock);
  92. }
  93. void
  94. automember_config_unlock()
  95. {
  96. slapi_rwlock_unlock(g_automember_config_lock);
  97. }
  98. /*
  99. * Plugin identity functions
  100. */
  101. void
  102. automember_set_plugin_id(void *pluginID)
  103. {
  104. _PluginID = pluginID;
  105. }
  106. void *
  107. automember_get_plugin_id()
  108. {
  109. return _PluginID;
  110. }
  111. void
  112. automember_set_plugin_sdn(Slapi_DN *pluginDN)
  113. {
  114. _PluginDN = pluginDN;
  115. }
  116. Slapi_DN *
  117. automember_get_plugin_sdn(void)
  118. {
  119. return _PluginDN;
  120. }
  121. static int plugin_is_betxn = 0;
  122. /*
  123. * Plug-in initialization functions
  124. */
  125. int
  126. automember_init(Slapi_PBlock *pb)
  127. {
  128. int status = 0;
  129. char *plugin_identity = NULL;
  130. Slapi_Entry *plugin_entry = NULL;
  131. char *plugin_type = NULL;
  132. int preadd = SLAPI_PLUGIN_PRE_ADD_FN;
  133. int premod = SLAPI_PLUGIN_PRE_MODIFY_FN;
  134. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  135. "--> automember_init\n");
  136. /* get args */
  137. if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
  138. plugin_entry &&
  139. (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
  140. plugin_type && strstr(plugin_type, "betxn")) {
  141. plugin_is_betxn = 1;
  142. preadd = SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN;
  143. premod = SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN;
  144. }
  145. slapi_ch_free_string(&plugin_type);
  146. /* Store the plugin identity for later use.
  147. * Used for internal operations. */
  148. slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
  149. PR_ASSERT(plugin_identity);
  150. automember_set_plugin_id(plugin_identity);
  151. /* Register callbacks */
  152. if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  153. SLAPI_PLUGIN_VERSION_01) != 0 ||
  154. slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
  155. (void *)automember_start) != 0 ||
  156. slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
  157. (void *)automember_close) != 0 ||
  158. slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
  159. (void *)&pdesc) != 0 ||
  160. slapi_pblock_set(pb, premod, (void *)automember_mod_pre_op) != 0 ||
  161. slapi_pblock_set(pb, preadd, (void *)automember_add_pre_op) != 0) {
  162. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  163. "automember_init - Failed to register plugin\n");
  164. status = -1;
  165. }
  166. if (!plugin_is_betxn && !status &&
  167. slapi_register_plugin("internalpostoperation", /* op type */
  168. 1, /* Enabled */
  169. "automember_init", /* this function desc */
  170. automember_internal_postop_init, /* init func */
  171. AUTOMEMBER_INT_POSTOP_DESC, /* plugin desc */
  172. NULL, /* ? */
  173. plugin_identity /* access control */
  174. )) {
  175. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  176. "automember_init - Failed to register internalpostoperation plugin\n");
  177. status = -1;
  178. }
  179. if (!status) {
  180. plugin_type = "postoperation";
  181. if (plugin_is_betxn) {
  182. plugin_type = "betxnpostoperation";
  183. }
  184. if (slapi_register_plugin(plugin_type, /* op type */
  185. 1, /* Enabled */
  186. "automember_init", /* this function desc */
  187. automember_postop_init, /* init func for post op */
  188. AUTOMEMBER_POSTOP_DESC, /* plugin desc */
  189. NULL, /* ? */
  190. plugin_identity /* access control */
  191. )) {
  192. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  193. "automember_init - Failed to register postop plugin\n");
  194. status = -1;
  195. }
  196. }
  197. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  198. "<-- automember_init\n");
  199. return status;
  200. }
  201. /* not used when using plugin as a betxn plugin - betxn plugins are called for both internal and external ops */
  202. static int
  203. automember_internal_postop_init(Slapi_PBlock *pb)
  204. {
  205. int status = 0;
  206. if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  207. SLAPI_PLUGIN_VERSION_01) != 0 ||
  208. slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
  209. (void *)&pdesc) != 0 ||
  210. slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN,
  211. (void *)automember_add_post_op) != 0 ||
  212. slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN,
  213. (void *)automember_del_post_op) != 0 ||
  214. slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN,
  215. (void *)automember_mod_post_op) != 0 ||
  216. slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN,
  217. (void *)automember_modrdn_post_op) != 0) {
  218. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  219. "automember_internal_postop_init - Failed to register plugin\n");
  220. status = -1;
  221. }
  222. return status;
  223. }
  224. static int
  225. automember_postop_init(Slapi_PBlock *pb)
  226. {
  227. int status = 0;
  228. int addfn = SLAPI_PLUGIN_POST_ADD_FN;
  229. int delfn = SLAPI_PLUGIN_POST_DELETE_FN;
  230. int modfn = SLAPI_PLUGIN_POST_MODIFY_FN;
  231. int mdnfn = SLAPI_PLUGIN_POST_MODRDN_FN;
  232. if (plugin_is_betxn) {
  233. addfn = SLAPI_PLUGIN_BE_TXN_POST_ADD_FN;
  234. delfn = SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN;
  235. modfn = SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN;
  236. mdnfn = SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN;
  237. }
  238. if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  239. SLAPI_PLUGIN_VERSION_01) != 0 ||
  240. slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
  241. (void *)&pdesc) != 0 ||
  242. slapi_pblock_set(pb, addfn, (void *)automember_add_post_op) != 0 ||
  243. slapi_pblock_set(pb, delfn, (void *)automember_del_post_op) != 0 ||
  244. slapi_pblock_set(pb, modfn, (void *)automember_mod_post_op) != 0 ||
  245. slapi_pblock_set(pb, mdnfn, (void *)automember_modrdn_post_op) != 0) {
  246. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  247. "automember_postop_init - Failed to register plugin\n");
  248. status = -1;
  249. }
  250. return status;
  251. }
  252. /* Stash the config area in the pblock for start functions? */
  253. /*
  254. * automember_start()
  255. *
  256. * Creates config lock and loads config cache.
  257. */
  258. static int
  259. automember_start(Slapi_PBlock *pb)
  260. {
  261. Slapi_DN *plugindn = NULL;
  262. char *config_area = NULL;
  263. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  264. "--> automember_start\n");
  265. slapi_plugin_task_register_handler("automember rebuild membership", automember_task_add, pb);
  266. slapi_plugin_task_register_handler("automember export updates", automember_task_add_export_updates, pb);
  267. slapi_plugin_task_register_handler("automember map updates", automember_task_add_map_entries, pb);
  268. if ((g_automember_config_lock = slapi_new_rwlock()) == NULL) {
  269. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  270. "automember_start - Lock creation failed\n");
  271. return -1;
  272. }
  273. /*
  274. * Get the plug-in target dn from the system
  275. * and store it for future use. */
  276. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &plugindn);
  277. if (NULL == plugindn || 0 == slapi_sdn_get_ndn_len(plugindn)) {
  278. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  279. "automember_start - Unable to retrieve plugin dn\n");
  280. return -1;
  281. }
  282. automember_set_plugin_sdn(slapi_sdn_dup(plugindn));
  283. /* Set the alternate config area if one is defined. */
  284. slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_AREA, &config_area);
  285. if (config_area) {
  286. automember_set_config_area(slapi_sdn_new_normdn_byval(config_area));
  287. }
  288. /*
  289. * Load the config cache
  290. */
  291. g_automember_config = (PRCList *)slapi_ch_calloc(1, sizeof(struct configEntry));
  292. PR_INIT_CLIST(g_automember_config);
  293. if (automember_load_config() != 0) {
  294. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  295. "automember_start - Unable to load plug-in configuration\n");
  296. return -1;
  297. }
  298. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  299. "auto membership plug-in: ready for service\n");
  300. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  301. "<-- automember_start\n");
  302. return 0;
  303. }
  304. /*
  305. * automember_close()
  306. *
  307. * Cleans up the config cache.
  308. */
  309. static int
  310. automember_close(Slapi_PBlock *pb __attribute__((unused)))
  311. {
  312. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  313. "--> automember_close\n");
  314. /* unregister the tasks */
  315. slapi_plugin_task_unregister_handler("automember rebuild membership",
  316. automember_task_add);
  317. slapi_plugin_task_unregister_handler("automember export updates",
  318. automember_task_add_export_updates);
  319. slapi_plugin_task_unregister_handler("automember map updates",
  320. automember_task_add_map_entries);
  321. automember_delete_config();
  322. slapi_sdn_free(&_PluginDN);
  323. slapi_sdn_free(&_ConfigAreaDN);
  324. slapi_destroy_rwlock(g_automember_config_lock);
  325. g_automember_config_lock = NULL;
  326. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  327. "<-- automember_close\n");
  328. return 0;
  329. }
  330. /*
  331. * automember_get_config()
  332. *
  333. * Get the config list.
  334. */
  335. PRCList *
  336. automember_get_config()
  337. {
  338. return g_automember_config;
  339. }
  340. /*
  341. * automember_load_config()
  342. *
  343. * Parse and load the config entries.
  344. */
  345. static int
  346. automember_load_config(void)
  347. {
  348. int status = 0;
  349. int result;
  350. int i;
  351. Slapi_PBlock *search_pb;
  352. Slapi_Entry **entries = NULL;
  353. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  354. "--> automember_load_config\n");
  355. /* Clear out any old config. */
  356. automember_config_write_lock();
  357. automember_delete_config();
  358. g_automember_config = (PRCList *)slapi_ch_calloc(1, sizeof(struct configEntry));
  359. PR_INIT_CLIST(g_automember_config);
  360. search_pb = slapi_pblock_new();
  361. /* If an alternate config area is configured, find
  362. * the config entries that are beneath it, otherwise
  363. * we load the entries beneath our top-level plug-in
  364. * config entry. */
  365. if (automember_get_config_area()) {
  366. /* Find the config entries beneath the alternate config area. */
  367. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  368. "automember_load_config - Looking for config entries "
  369. "beneath \"%s\".\n",
  370. slapi_sdn_get_ndn(automember_get_config_area()));
  371. slapi_search_internal_set_pb(search_pb, slapi_sdn_get_ndn(automember_get_config_area()),
  372. LDAP_SCOPE_SUBTREE, AUTOMEMBER_DEFINITION_FILTER,
  373. NULL, 0, NULL, NULL, automember_get_plugin_id(), 0);
  374. } else {
  375. /* Find the config entries beneath our plugin entry. */
  376. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  377. "automember_load_config - Looking for config entries "
  378. "beneath \"%s\".\n",
  379. slapi_sdn_get_ndn(automember_get_plugin_sdn()));
  380. slapi_search_internal_set_pb(search_pb, slapi_sdn_get_ndn(automember_get_plugin_sdn()),
  381. LDAP_SCOPE_SUBTREE, AUTOMEMBER_DEFINITION_FILTER,
  382. NULL, 0, NULL, NULL, automember_get_plugin_id(), 0);
  383. }
  384. slapi_search_internal_pb(search_pb);
  385. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
  386. if (LDAP_SUCCESS != result) {
  387. if (automember_get_config_area() && (result == LDAP_NO_SUCH_OBJECT)) {
  388. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  389. "automember_load_config - Config container \"%s\" does "
  390. "not exist.\n",
  391. slapi_sdn_get_ndn(automember_get_config_area()));
  392. goto cleanup;
  393. } else {
  394. status = -1;
  395. goto cleanup;
  396. }
  397. }
  398. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  399. &entries);
  400. /* Loop through all of the entries we found and parse them. */
  401. for (i = 0; entries && (entries[i] != NULL); i++) {
  402. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  403. "automember_load_config - Parsing config entry "
  404. "\"%s\".\n",
  405. slapi_entry_get_dn(entries[i]));
  406. /* We don't care about the status here because we may have
  407. * some invalid config entries, but we just want to continue
  408. * looking for valid ones. */
  409. automember_parse_config_entry(entries[i], 1);
  410. }
  411. cleanup:
  412. slapi_free_search_results_internal(search_pb);
  413. slapi_pblock_destroy(search_pb);
  414. automember_config_unlock();
  415. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  416. "<-- automember_load_config\n");
  417. return status;
  418. }
  419. /*
  420. * automember_parse_config_entry()
  421. *
  422. * Parses a single config entry. If apply is non-zero, then
  423. * we will load and start using the new config. You can simply
  424. * validate config without making any changes by setting apply
  425. * to 0.
  426. *
  427. * Returns 0 if the entry is valid and -1 if it is invalid.
  428. */
  429. static int
  430. automember_parse_config_entry(Slapi_Entry *e, int apply)
  431. {
  432. char *value = NULL;
  433. char **values = NULL;
  434. struct configEntry *entry = NULL;
  435. struct configEntry *config_entry;
  436. PRCList *list;
  437. Slapi_PBlock *search_pb = NULL;
  438. Slapi_Entry **rule_entries = NULL;
  439. char *filter_str = NULL;
  440. Slapi_DN *dn = NULL;
  441. Slapi_Filter *filter = NULL;
  442. int result;
  443. int entry_added = 0;
  444. int i = 0;
  445. int ret = 0;
  446. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  447. "--> automember_parse_config_entry\n");
  448. /* If this is the main plug-in config entry or
  449. * the config area container, just bail. */
  450. if ((slapi_sdn_compare(automember_get_plugin_sdn(), slapi_entry_get_sdn(e)) == 0) ||
  451. (automember_get_config_area() && (slapi_sdn_compare(automember_get_config_area(),
  452. slapi_entry_get_sdn(e)) == 0))) {
  453. goto bail;
  454. }
  455. /* If this entry is not an automember config definition entry, just bail. */
  456. filter_str = slapi_ch_strdup(AUTOMEMBER_DEFINITION_FILTER);
  457. filter = slapi_str2filter(filter_str);
  458. if (slapi_filter_test_simple(e, filter) != 0) {
  459. goto bail;
  460. }
  461. /* If marked as disabled, just bail. */
  462. value = slapi_entry_attr_get_charptr(e, AUTOMEMBER_DISABLED_TYPE);
  463. if (value) {
  464. slapi_ch_free_string(&value);
  465. goto bail;
  466. }
  467. entry = (struct configEntry *)slapi_ch_calloc(1, sizeof(struct configEntry));
  468. if (NULL == entry) {
  469. ret = -1;
  470. goto bail;
  471. }
  472. value = slapi_entry_get_ndn(e);
  473. if (value) {
  474. entry->dn = slapi_ch_strdup(value);
  475. } else {
  476. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  477. "automember_parse_config_entry - Error "
  478. "reading dn from config entry\n");
  479. ret = -1;
  480. goto bail;
  481. }
  482. slapi_log_err(SLAPI_LOG_CONFIG, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  483. "----------> dn [%s]\n", entry->dn);
  484. /* Load the scope */
  485. value = slapi_entry_attr_get_charptr(e, AUTOMEMBER_SCOPE_TYPE);
  486. if (value) {
  487. entry->scope = value;
  488. } else {
  489. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  490. "automember_parse_config_entry - The %s config "
  491. "setting is required for config entry \"%s\".\n",
  492. AUTOMEMBER_SCOPE_TYPE, entry->dn);
  493. ret = -1;
  494. goto bail;
  495. }
  496. /* Load the filter */
  497. value = slapi_entry_attr_get_charptr(e, AUTOMEMBER_FILTER_TYPE);
  498. if (value) {
  499. /* Convert to a Slapi_Filter to improve performance. */
  500. if (NULL == (entry->filter = slapi_str2filter(value))) {
  501. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  502. "automember_parse_config_entry - Invalid search filter in "
  503. "%s config setting for config entry \"%s\" "
  504. "(filter = \"%s\").\n",
  505. AUTOMEMBER_FILTER_TYPE, entry->dn, value);
  506. ret = -1;
  507. }
  508. slapi_ch_free_string(&value);
  509. if (ret != 0) {
  510. goto bail;
  511. }
  512. } else {
  513. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  514. "automember_parse_config_entry - The %s config "
  515. "setting is required for config entry \"%s\".\n",
  516. AUTOMEMBER_FILTER_TYPE, entry->dn);
  517. ret = -1;
  518. goto bail;
  519. }
  520. /* Load the default groups */
  521. values = slapi_entry_attr_get_charray(e, AUTOMEMBER_DEFAULT_GROUP_TYPE);
  522. if (values) {
  523. /* Just hand off the values */
  524. entry->default_groups = values;
  525. /*
  526. * If we set the config area, we need to make sure that the default groups are not
  527. * in the config area, or else we could deadlock on updates.
  528. */
  529. if (automember_get_config_area()) {
  530. for (i = 0; values && values[i]; i++) {
  531. dn = slapi_sdn_new_dn_byref(values[i]);
  532. if (slapi_sdn_issuffix(dn, automember_get_config_area())) {
  533. /* The groups are under the config area - not good */
  534. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  535. "automember_parse_config_entry - The default group \"%s\" can not be "
  536. "a child of the plugin config area \"%s\".\n",
  537. values[i], slapi_sdn_get_dn(automember_get_config_area()));
  538. slapi_sdn_free(&dn);
  539. ret = -1;
  540. goto bail;
  541. }
  542. slapi_sdn_free(&dn);
  543. }
  544. }
  545. values = NULL;
  546. }
  547. /* Load the grouping attr */
  548. value = slapi_entry_attr_get_charptr(e, AUTOMEMBER_GROUPING_ATTR_TYPE);
  549. if (value) {
  550. if (automember_parse_grouping_attr(value, &(entry->grouping_attr),
  551. &(entry->grouping_value)) != 0) {
  552. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  553. "automember_parse_config_entry - Invalid "
  554. "%s config setting for config entry \"%s\" "
  555. "(value: \"%s\").\n",
  556. AUTOMEMBER_GROUPING_ATTR_TYPE,
  557. entry->dn, value);
  558. ret = -1;
  559. }
  560. slapi_ch_free_string(&value);
  561. if (ret != 0) {
  562. goto bail;
  563. }
  564. } else {
  565. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  566. "automember_parse_config_entry - The %s config "
  567. "setting is required for config entry \"%s\".\n",
  568. AUTOMEMBER_GROUPING_ATTR_TYPE, entry->dn);
  569. ret = -1;
  570. goto bail;
  571. }
  572. /* Find all child regex rule entries */
  573. search_pb = slapi_pblock_new();
  574. slapi_search_internal_set_pb(search_pb, entry->dn, LDAP_SCOPE_SUBTREE,
  575. AUTOMEMBER_REGEX_RULE_FILTER, NULL, 0, NULL,
  576. NULL, automember_get_plugin_id(), 0);
  577. slapi_search_internal_pb(search_pb);
  578. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
  579. /* If this is a new config entry being added, it won't exist yet
  580. * when we are simply validating config. We can just ignore no
  581. * such object errors. */
  582. if ((LDAP_SUCCESS != result) && (LDAP_NO_SUCH_OBJECT != result)) {
  583. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  584. "automember_parse_config_entry - Error searching "
  585. "for child rule entries for config \"%s\" (err=%d).",
  586. entry->dn, result);
  587. ret = -1;
  588. goto bail;
  589. }
  590. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  591. &rule_entries);
  592. /* Go through each child rule entry and parse it. */
  593. for (i = 0; rule_entries && (rule_entries[i] != NULL); i++) {
  594. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  595. "automember_parse_config_entry - Parsing regex rule entry "
  596. "\"%s\".\n",
  597. slapi_entry_get_dn(rule_entries[i]));
  598. automember_parse_regex_entry(entry, rule_entries[i]);
  599. }
  600. /* If we were only called to validate config, we can
  601. * just bail out before applying the config changes */
  602. if (apply == 0) {
  603. goto bail;
  604. }
  605. /* Add the config object to the list. We order by scope. */
  606. if (!PR_CLIST_IS_EMPTY(g_automember_config)) {
  607. list = PR_LIST_HEAD(g_automember_config);
  608. while (list != g_automember_config) {
  609. config_entry = (struct configEntry *)list;
  610. /* If the config entry we are adding has a scope that is
  611. * a child of the scope of the current list item, we insert
  612. * the entry before that list item. */
  613. if (slapi_dn_issuffix(entry->scope, config_entry->scope)) {
  614. PR_INSERT_BEFORE(&(entry->list), list);
  615. slapi_log_err(SLAPI_LOG_CONFIG, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  616. "automember_parse_config_entry - store [%s] before [%s] \n", entry->dn,
  617. config_entry->dn);
  618. entry_added = 1;
  619. break;
  620. }
  621. list = PR_NEXT_LINK(list);
  622. /* If we hit the end of the list, add to the tail. */
  623. if (g_automember_config == list) {
  624. PR_INSERT_BEFORE(&(entry->list), list);
  625. slapi_log_err(SLAPI_LOG_CONFIG, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  626. "automember_parse_config_entry - store [%s] at tail\n", entry->dn);
  627. entry_added = 1;
  628. break;
  629. }
  630. }
  631. } else {
  632. /* first entry */
  633. PR_INSERT_LINK(&(entry->list), g_automember_config);
  634. slapi_log_err(SLAPI_LOG_CONFIG, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  635. "automember_parse_config_entry - store [%s] at head \n", entry->dn);
  636. entry_added = 1;
  637. }
  638. bail:
  639. if (0 == entry_added) {
  640. /* Don't log error if we weren't asked to apply config */
  641. if ((apply != 0) && (entry != NULL)) {
  642. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  643. "automember_parse_config_entry - Invalid config entry "
  644. "[%s] skipped\n",
  645. entry->dn);
  646. }
  647. automember_free_config_entry(&entry);
  648. } else {
  649. ret = 0;
  650. }
  651. slapi_ch_free_string(&filter_str);
  652. slapi_filter_free(filter, 1);
  653. slapi_free_search_results_internal(search_pb);
  654. slapi_pblock_destroy(search_pb);
  655. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  656. "<-- automember_parse_config_entry\n");
  657. return ret;
  658. }
  659. static void
  660. automember_free_config_entry(struct configEntry **entry)
  661. {
  662. struct configEntry *e = *entry;
  663. if (e == NULL)
  664. return;
  665. if (e->dn) {
  666. slapi_log_err(SLAPI_LOG_CONFIG, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  667. "automember_free_config_entry - Freeing config entry [%s]\n", e->dn);
  668. slapi_ch_free_string(&e->dn);
  669. }
  670. if (e->scope) {
  671. slapi_ch_free_string(&e->scope);
  672. }
  673. if (e->filter) {
  674. slapi_filter_free(e->filter, 1);
  675. }
  676. if (e->exclusive_rules) {
  677. PRCList *list;
  678. /* Clear out the list contents. */
  679. while (!PR_CLIST_IS_EMPTY((PRCList *)e->exclusive_rules)) {
  680. list = PR_LIST_HEAD((PRCList *)e->exclusive_rules);
  681. PR_REMOVE_LINK(list);
  682. automember_free_regex_rule((struct automemberRegexRule *)list);
  683. }
  684. /* Free the list itself. */
  685. slapi_ch_free((void **)&(e->exclusive_rules));
  686. }
  687. /* Clear out the list contents. */
  688. if (e->inclusive_rules) {
  689. PRCList *list;
  690. while (!PR_CLIST_IS_EMPTY((PRCList *)e->inclusive_rules)) {
  691. list = PR_LIST_HEAD((PRCList *)e->inclusive_rules);
  692. PR_REMOVE_LINK(list);
  693. automember_free_regex_rule((struct automemberRegexRule *)list);
  694. }
  695. /* Free the list itself. */
  696. slapi_ch_free((void **)&(e->inclusive_rules));
  697. }
  698. if (e->default_groups) {
  699. slapi_ch_array_free(e->default_groups);
  700. }
  701. if (e->grouping_attr) {
  702. slapi_ch_free_string(&e->grouping_attr);
  703. }
  704. if (e->grouping_value) {
  705. slapi_ch_free_string(&e->grouping_value);
  706. }
  707. slapi_ch_free((void **)entry);
  708. }
  709. static void
  710. automember_delete_configEntry(PRCList *entry)
  711. {
  712. PR_REMOVE_LINK(entry);
  713. automember_free_config_entry((struct configEntry **)&entry);
  714. }
  715. static void
  716. automember_delete_config(void)
  717. {
  718. PRCList *list;
  719. /* Delete the config cache. */
  720. while (!PR_CLIST_IS_EMPTY(g_automember_config)) {
  721. list = PR_LIST_HEAD(g_automember_config);
  722. automember_delete_configEntry(list);
  723. }
  724. slapi_ch_free((void **)&g_automember_config);
  725. return;
  726. }
  727. static Slapi_DN *
  728. automember_get_sdn(Slapi_PBlock *pb)
  729. {
  730. Slapi_DN *sdn = 0;
  731. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  732. "--> automember_get_sdn\n");
  733. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
  734. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  735. "<-- automember_get_sdn\n");
  736. return sdn;
  737. }
  738. void
  739. automember_set_config_area(Slapi_DN *sdn)
  740. {
  741. _ConfigAreaDN = sdn;
  742. }
  743. Slapi_DN *
  744. automember_get_config_area(void)
  745. {
  746. return _ConfigAreaDN;
  747. }
  748. /*
  749. * automember_dn_is_config()
  750. *
  751. * Checks if dn is an auto membership config entry.
  752. */
  753. static int
  754. automember_dn_is_config(Slapi_DN *sdn)
  755. {
  756. int ret = 0;
  757. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  758. "--> automember_dn_is_config\n");
  759. if (sdn == NULL) {
  760. goto bail;
  761. }
  762. /* If an alternate config area is configured, treat it's child
  763. * entries as config entries. If the alternate config area is
  764. * not configured, treat children of the top-level plug-in
  765. * config entry as our config entries. */
  766. if (automember_get_config_area()) {
  767. if (slapi_sdn_issuffix(sdn, automember_get_config_area()) &&
  768. slapi_sdn_compare(sdn, automember_get_config_area())) {
  769. ret = 1;
  770. }
  771. } else {
  772. if (slapi_sdn_issuffix(sdn, automember_get_plugin_sdn()) &&
  773. slapi_sdn_compare(sdn, automember_get_plugin_sdn())) {
  774. ret = 1;
  775. }
  776. }
  777. bail:
  778. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  779. "<-- automember_dn_is_config\n");
  780. return ret;
  781. }
  782. /*
  783. * automember_oktodo()
  784. *
  785. * Check if we want to process this operation. We need to be
  786. * sure that the operation succeeded.
  787. */
  788. static int
  789. automember_oktodo(Slapi_PBlock *pb)
  790. {
  791. int ret = 1;
  792. int oprc = 0;
  793. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  794. "--> automember_oktodo\n");
  795. if (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0) {
  796. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  797. "automember_oktodo - Could not get parameters\n");
  798. ret = -1;
  799. }
  800. /* This plugin should only execute if the operation succeeded. */
  801. if (oprc != 0) {
  802. ret = 0;
  803. }
  804. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  805. "<-- automember_oktodo\n");
  806. return ret;
  807. }
  808. /*
  809. * automember_isrepl()
  810. *
  811. * Returns 1 if the operation associated with pb
  812. * is a replicated op. Returns 0 otherwise.
  813. */
  814. static int
  815. automember_isrepl(Slapi_PBlock *pb)
  816. {
  817. int is_repl = 0;
  818. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  819. "--> automember_isrepl\n");
  820. slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_repl);
  821. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  822. "<-- automember_isrepl\n");
  823. return is_repl;
  824. }
  825. /*
  826. * automember_parse_regex_entry()
  827. *
  828. * Parses a rule entry and adds the regex rules to the
  829. * passed in config struct. Invalid regex rules will
  830. * be skipped and logged at the fatal log level.
  831. */
  832. static void
  833. automember_parse_regex_entry(struct configEntry *config, Slapi_Entry *e)
  834. {
  835. char *target_group = NULL;
  836. char **values = NULL;
  837. Slapi_DN *group_dn = NULL;
  838. PRCList *list;
  839. int i = 0;
  840. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  841. "--> automember_parse_regex_entry\n");
  842. /* Make sure the target group was specified. */
  843. target_group = slapi_entry_attr_get_charptr(e, AUTOMEMBER_TARGET_GROUP_TYPE);
  844. if (!target_group) {
  845. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  846. "automember_parse_regex_entry - The %s config "
  847. "setting is required for rule entry \"%s\".\n",
  848. AUTOMEMBER_TARGET_GROUP_TYPE, slapi_entry_get_ndn(e));
  849. goto bail;
  850. }
  851. /* Ensure that the target group DN is valid. */
  852. if (slapi_dn_syntax_check(NULL, target_group, 1) != 0) {
  853. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  854. "automember_parse_regex_entry - Invalid target group DN "
  855. "in rule \"%s\" (dn=\"%s\").\n",
  856. slapi_entry_get_ndn(e),
  857. target_group);
  858. goto bail;
  859. }
  860. /* normalize the group dn and compare it to the configArea DN */
  861. if (automember_get_config_area()) {
  862. group_dn = slapi_sdn_new_dn_byref(target_group);
  863. if (slapi_sdn_issuffix(group_dn, automember_get_config_area())) {
  864. /* The target group is under the plugin config area - not good */
  865. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  866. "automember_parse_regex_entry - The target group \"%s\" can not be "
  867. "a child of the plugin config area \"%s\".\n",
  868. slapi_sdn_get_dn(group_dn), slapi_sdn_get_dn(automember_get_config_area()));
  869. slapi_sdn_free(&group_dn);
  870. goto bail;
  871. }
  872. slapi_sdn_free(&group_dn);
  873. }
  874. /* Load inclusive rules */
  875. values = slapi_entry_attr_get_charray(e, AUTOMEMBER_INC_REGEX_TYPE);
  876. if (values) {
  877. struct automemberRegexRule *rule = NULL;
  878. /* If we haven't loaded any inclusive rules for
  879. * this config definition yet, create a new list. */
  880. if (config->inclusive_rules == NULL) {
  881. /* Create a list to hold our regex rules */
  882. config->inclusive_rules = (struct automemberRegexRule *)slapi_ch_calloc(1, sizeof(struct automemberRegexRule));
  883. PR_INIT_CLIST((PRCList *)config->inclusive_rules);
  884. }
  885. for (i = 0; values && values[i]; ++i) {
  886. rule = automember_parse_regex_rule(values[i]);
  887. if (rule) {
  888. /* Fill in the target group. */
  889. rule->target_group_dn = slapi_sdn_new_normdn_byval(target_group);
  890. if (!PR_CLIST_IS_EMPTY((PRCList *)config->inclusive_rules)) {
  891. list = PR_LIST_HEAD((PRCList *)config->inclusive_rules);
  892. while (list != (PRCList *)config->inclusive_rules) {
  893. struct automemberRegexRule *curr_rule = (struct automemberRegexRule *)list;
  894. /* Order rules by target group DN */
  895. if (slapi_sdn_compare(rule->target_group_dn, curr_rule->target_group_dn) < 0) {
  896. PR_INSERT_BEFORE(&(rule->list), list);
  897. rule = NULL;
  898. break;
  899. }
  900. list = PR_NEXT_LINK(list);
  901. /* If we hit the end of the list, add to the tail. */
  902. if ((PRCList *)config->inclusive_rules == list) {
  903. PR_INSERT_BEFORE(&(rule->list), list);
  904. rule = NULL;
  905. break;
  906. }
  907. }
  908. automember_free_regex_rule(rule);
  909. } else {
  910. /* Add to head of list */
  911. PR_INSERT_LINK(&(rule->list), (PRCList *)config->inclusive_rules);
  912. }
  913. } else {
  914. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  915. "automember_parse_regex_entry - Skipping invalid inclusive "
  916. "regex rule in rule entry \"%s\" (rule = \"%s\").\n",
  917. slapi_entry_get_ndn(e), values[i]);
  918. }
  919. }
  920. slapi_ch_array_free(values);
  921. values = NULL;
  922. }
  923. /* Load exclusive rules. */
  924. values = slapi_entry_attr_get_charray(e, AUTOMEMBER_EXC_REGEX_TYPE);
  925. if (values) {
  926. struct automemberRegexRule *rule = NULL;
  927. /* If we haven't loaded any exclusive rules for
  928. * this config definition yet, create a new list. */
  929. if (config->exclusive_rules == NULL) {
  930. /* Create a list to hold our regex rules */
  931. config->exclusive_rules = (struct automemberRegexRule *)slapi_ch_calloc(1, sizeof(struct automemberRegexRule));
  932. PR_INIT_CLIST((PRCList *)config->exclusive_rules);
  933. }
  934. for (i = 0; values && values[i]; ++i) {
  935. rule = automember_parse_regex_rule(values[i]);
  936. if (rule) {
  937. /* Fill in the target group. */
  938. rule->target_group_dn = slapi_sdn_new_normdn_byval(target_group);
  939. if (!PR_CLIST_IS_EMPTY((PRCList *)config->exclusive_rules)) {
  940. list = PR_LIST_HEAD((PRCList *)config->exclusive_rules);
  941. while (list != (PRCList *)config->exclusive_rules) {
  942. struct automemberRegexRule *curr_rule = (struct automemberRegexRule *)list;
  943. /* Order rules by target group DN */
  944. if (slapi_sdn_compare(rule->target_group_dn, curr_rule->target_group_dn) < 0) {
  945. PR_INSERT_BEFORE(&(rule->list), list);
  946. rule = NULL;
  947. break;
  948. }
  949. list = PR_NEXT_LINK(list);
  950. /* If we hit the end of the list, add to the tail. */
  951. if ((PRCList *)config->exclusive_rules == list) {
  952. PR_INSERT_BEFORE(&(rule->list), list);
  953. rule = NULL;
  954. break;
  955. }
  956. }
  957. automember_free_regex_rule(rule);
  958. } else {
  959. /* Add to head of list */
  960. PR_INSERT_LINK(&(rule->list), (PRCList *)config->exclusive_rules);
  961. }
  962. } else {
  963. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  964. "automember_parse_regex_entry - Skipping invalid exclusive "
  965. "regex rule in rule entry \"%s\" (rule = \"%s\").\n",
  966. slapi_entry_get_ndn(e), values[i]);
  967. }
  968. }
  969. slapi_ch_array_free(values);
  970. values = NULL;
  971. }
  972. bail:
  973. slapi_ch_free_string(&target_group);
  974. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  975. "<-- automember_parse_regex_entry\n");
  976. }
  977. /*
  978. * automember_parse_regex_rule()
  979. *
  980. * Parses a regex rule and returns a regex rule struct. The caller
  981. * will need to free this struct when it is finished with it. If
  982. * there is a problem parsing the regex rule, an error will be
  983. * logged and NULL will be returned.
  984. */
  985. static struct automemberRegexRule *
  986. automember_parse_regex_rule(char *rule_string)
  987. {
  988. struct automemberRegexRule *rule = NULL;
  989. char *attr = NULL;
  990. Slapi_Regex *regex = NULL;
  991. const char *recomp_result = NULL;
  992. char *p = NULL;
  993. char *p2 = NULL;
  994. /* A rule is in the form "attr=regex". */
  995. /* Find the comparison attribute name. */
  996. if ((p = strchr(rule_string, '=')) == NULL) {
  997. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  998. "automember_parse_regex_rule - Unable to parse "
  999. "regex rule (missing '=' delimeter).\n");
  1000. goto bail;
  1001. }
  1002. /* Make sure the attribute name is not empty. */
  1003. if (p == rule_string) {
  1004. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1005. "automember_parse_regex_rule - Unable to parse "
  1006. " regex rule (missing comparison attribute).\n");
  1007. goto bail;
  1008. }
  1009. if ((attr = strndup(rule_string, p - rule_string)) == NULL) {
  1010. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1011. "automember_parse_regex_rule - Unable to allocate "
  1012. "memory.\n");
  1013. goto bail;
  1014. }
  1015. /* Validate the attribute. */
  1016. for (p2 = attr; p2 && (*p2 != '\0'); p2++) {
  1017. if (!IS_ATTRDESC_CHAR(*p2)) {
  1018. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1019. "automember_parse_regex_rule - Invalid comparison "
  1020. "attribute name \"%s\".\n",
  1021. attr);
  1022. goto bail;
  1023. }
  1024. }
  1025. /* Find the regex. */
  1026. p++;
  1027. if (*p == '\0') {
  1028. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1029. "automember_parse_regex_rule - Unable to parse "
  1030. "regex rule (missing regex).\n");
  1031. goto bail;
  1032. }
  1033. /* Compile the regex to validate it. */
  1034. regex = slapi_re_comp(p, &recomp_result);
  1035. if (!regex) {
  1036. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1037. "automember_parse_regex_rule - Unable to parse "
  1038. "regex rule (invalid regex). Error \"%s\".\n",
  1039. recomp_result ? recomp_result : "unknown");
  1040. }
  1041. /* Validation has passed, so create the regex rule struct and fill it in.
  1042. * We hand off everything we have allocated. All of this will be free'd
  1043. * when the rule struct itself is freed. */
  1044. rule = (struct automemberRegexRule *)slapi_ch_calloc(1, sizeof(struct automemberRegexRule));
  1045. rule->attr = attr;
  1046. rule->regex_str = slapi_ch_strdup(p);
  1047. rule->regex = regex;
  1048. bail:
  1049. /* Cleanup if we didn't successfully create a rule. */
  1050. if (!rule) {
  1051. slapi_ch_free_string(&attr);
  1052. slapi_re_free(regex);
  1053. }
  1054. return rule;
  1055. }
  1056. /*
  1057. * automember_free_regex_rule()
  1058. *
  1059. * Frees a regex rule and all of it's contents from memory.
  1060. */
  1061. static void
  1062. automember_free_regex_rule(struct automemberRegexRule *rule)
  1063. {
  1064. if (rule) {
  1065. if (rule->target_group_dn) {
  1066. slapi_sdn_free(&(rule->target_group_dn));
  1067. }
  1068. if (rule->attr) {
  1069. slapi_ch_free_string(&(rule->attr));
  1070. }
  1071. if (rule->regex_str) {
  1072. slapi_ch_free_string(&(rule->regex_str));
  1073. }
  1074. if (rule->regex) {
  1075. slapi_re_free(rule->regex);
  1076. }
  1077. }
  1078. slapi_ch_free((void **)&rule);
  1079. }
  1080. /*
  1081. * automember_parse_grouping_attr()
  1082. *
  1083. * Parses a grouping attribute and grouping value from
  1084. * the passed in config string. Memory will be allocated
  1085. * for grouping_attr and grouping_value, so it is up to
  1086. * the called to free them when they are no longer needed.
  1087. * Returns 0 upon success and 1 upon failure.
  1088. */
  1089. static int
  1090. automember_parse_grouping_attr(char *value, char **grouping_attr, char **grouping_value)
  1091. {
  1092. int ret = 0;
  1093. char *p = NULL;
  1094. /* Clear out any existing type or value. */
  1095. slapi_ch_free_string(grouping_attr);
  1096. slapi_ch_free_string(grouping_value);
  1097. /* split out the type from the value (use the first ':') */
  1098. if ((p = strchr(value, ':')) == NULL) {
  1099. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1100. "automember_parse_grouping_attr - Value for grouping attribute "
  1101. "is not in the correct format. (value: \"%s\").\n",
  1102. value);
  1103. ret = 1;
  1104. goto bail;
  1105. }
  1106. /* Ensure the type is not empty. */
  1107. if (p == value) {
  1108. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1109. "automember_parse_grouping_attr - Value for grouping attribute "
  1110. "is not in the correct format. The grouping attribute is missing. "
  1111. "(value: \"%s\").\n",
  1112. value);
  1113. ret = 1;
  1114. goto bail;
  1115. }
  1116. /* Duplicate the type to be returned. */
  1117. *grouping_attr = strndup(value, p - value);
  1118. /* Advance p to point to the beginning of the value. */
  1119. p++;
  1120. while (*p == ' ') {
  1121. p++;
  1122. }
  1123. /* Ensure the value is not empty. */
  1124. if (*p == '\0') {
  1125. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1126. "automember_parse_grouping_attr - Value for grouping attribute "
  1127. "is not in the correct format. The grouping value is "
  1128. "missing. (value: \"%s\").\n",
  1129. value);
  1130. ret = 1;
  1131. goto bail;
  1132. }
  1133. /* Duplicate the value to be returned. */
  1134. *grouping_value = slapi_ch_strdup(p);
  1135. /* Ensure that memory was allocated successfully. */
  1136. if ((*grouping_attr == NULL) || (*grouping_value == NULL)) {
  1137. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1138. "automember_parse_grouping_attr - Error allocating memory.\n");
  1139. ret = 1;
  1140. goto bail;
  1141. }
  1142. /* Ensure that the grouping attr is a legal attr name. */
  1143. for (p = *grouping_attr; p && (*p != '\0'); p++) {
  1144. if (!IS_ATTRDESC_CHAR(*p)) {
  1145. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1146. "automember_parse_grouping_attr: Invalid value for "
  1147. "grouping attribute. The grouping attribute type is "
  1148. "illegal. (type: \"%s\").\n",
  1149. *grouping_attr);
  1150. ret = 1;
  1151. goto bail;
  1152. }
  1153. }
  1154. /* Ensure that the grouping value type is a legal attr name. */
  1155. for (p = *grouping_value; p && (*p != '\0'); p++) {
  1156. if (!IS_ATTRDESC_CHAR(*p)) {
  1157. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1158. "automember_parse_grouping_attr - Invalid value for "
  1159. "grouping attribute. The grouping value type is "
  1160. "illegal. (type: \"%s\").\n",
  1161. *grouping_value);
  1162. ret = 1;
  1163. goto bail;
  1164. }
  1165. }
  1166. bail:
  1167. if (ret != 0) {
  1168. slapi_ch_free_string(grouping_attr);
  1169. slapi_ch_free_string(grouping_value);
  1170. }
  1171. return ret;
  1172. }
  1173. /*
  1174. * automember_update_membership()
  1175. *
  1176. * Determines which target groups need to be updated according to
  1177. * the rules in config, then performs the updates.
  1178. */
  1179. static int
  1180. automember_update_membership(struct configEntry *config, Slapi_Entry *e, PRFileDesc *ldif_fd)
  1181. {
  1182. PRCList *rule = NULL;
  1183. struct automemberRegexRule *curr_rule = NULL;
  1184. PRCList exclusions;
  1185. PRCList targets;
  1186. struct automemberDNListItem *dnitem = NULL;
  1187. Slapi_DN *last = NULL;
  1188. PRCList *curr_exclusion = NULL;
  1189. char **vals = NULL;
  1190. int rc = 0;
  1191. int i = 0;
  1192. if (!config || !e) {
  1193. return -1;
  1194. }
  1195. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1196. "automember_update_membership - Processing \"%s\" "
  1197. "definition entry for candidate entry \"%s\".\n",
  1198. config->dn, slapi_entry_get_dn(e));
  1199. /* Initialize our lists that keep track of targets. */
  1200. PR_INIT_CLIST(&exclusions);
  1201. PR_INIT_CLIST(&targets);
  1202. /* Go through exclusive rules and build an exclusion list. */
  1203. if (config->exclusive_rules) {
  1204. if (!PR_CLIST_IS_EMPTY((PRCList *)config->exclusive_rules)) {
  1205. rule = PR_LIST_HEAD((PRCList *)config->exclusive_rules);
  1206. while (rule != (PRCList *)config->exclusive_rules) {
  1207. curr_rule = (struct automemberRegexRule *)rule;
  1208. /* Regex rules are sorted by the target group DN. This means
  1209. * we can skip all rules for the last target group DN that we
  1210. * added to the exclusions list. */
  1211. if ((last == NULL) || slapi_sdn_compare(last, curr_rule->target_group_dn) != 0) {
  1212. /* Get comparison attr and loop through values. */
  1213. vals = slapi_entry_attr_get_charray(e, curr_rule->attr);
  1214. for (i = 0; vals && vals[i]; ++i) {
  1215. /* Evaluate the regex. */
  1216. if (slapi_re_exec_nt(curr_rule->regex, vals[i]) == 1) {
  1217. /* Found a match. Add to end of the exclusion list
  1218. * and set last as a hint to ourselves. */
  1219. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1220. "automember_update_membership - Adding \"%s\" "
  1221. "to list of excluded groups for \"%s\" "
  1222. "(matched: \"%s=%s\").\n",
  1223. slapi_sdn_get_dn(curr_rule->target_group_dn),
  1224. slapi_entry_get_dn(e), curr_rule->attr,
  1225. curr_rule->regex_str);
  1226. dnitem = (struct automemberDNListItem *)slapi_ch_calloc(1,
  1227. sizeof(struct automemberDNListItem));
  1228. /* We are just referencing the dn from the regex rule. We
  1229. * will not free it when we clean up this list. This list
  1230. * is more short-lived than the regex rule list, so we can
  1231. * get away with this optimization. */
  1232. dnitem->dn = curr_rule->target_group_dn;
  1233. PR_APPEND_LINK(&(dnitem->list), &exclusions);
  1234. last = curr_rule->target_group_dn;
  1235. }
  1236. }
  1237. slapi_ch_array_free(vals);
  1238. vals = NULL;
  1239. }
  1240. rule = PR_NEXT_LINK(rule);
  1241. }
  1242. }
  1243. }
  1244. /* Go through inclusive rules and build the target list. */
  1245. if (config->inclusive_rules) {
  1246. if (!PR_CLIST_IS_EMPTY((PRCList *)config->inclusive_rules)) {
  1247. /* Clear out our last hint from processing exclusions. */
  1248. last = NULL;
  1249. /* Get the first excluded target for exclusion checking. */
  1250. if (!PR_CLIST_IS_EMPTY(&exclusions)) {
  1251. curr_exclusion = PR_LIST_HEAD(&exclusions);
  1252. }
  1253. rule = PR_LIST_HEAD((PRCList *)config->inclusive_rules);
  1254. while (rule != (PRCList *)config->inclusive_rules) {
  1255. curr_rule = (struct automemberRegexRule *)rule;
  1256. /* The excluded targets are stored in alphabetical order. Instead
  1257. * of going through the entire exclusion list for each inclusive
  1258. * rule, we can simply go through the exclusion list once and keep
  1259. * track of our position. If the curent exclusion comes after
  1260. * the target DN used in the current inclusive rule, it can't be
  1261. * excluded. If the current exclusion comes before the target
  1262. * in the current rule, we need to go through the exclusion list
  1263. * until we find a target that is the same or comes after the
  1264. * current rule. */
  1265. if (curr_exclusion) {
  1266. while ((curr_exclusion != &exclusions) && (slapi_sdn_compare(
  1267. ((struct automemberDNListItem *)curr_exclusion)->dn,
  1268. curr_rule->target_group_dn) < 0)) {
  1269. curr_exclusion = PR_NEXT_LINK(curr_exclusion);
  1270. }
  1271. }
  1272. /* Regex rules are sorted by the target group DN. This means
  1273. * we can skip all rules for the last target group DN that we
  1274. * added to the targets list. We also skip any rules for
  1275. * target groups that have been excluded by an exclusion rule. */
  1276. if (((curr_exclusion == NULL) || (curr_exclusion == &exclusions) ||
  1277. slapi_sdn_compare(((struct automemberDNListItem *)curr_exclusion)->dn,
  1278. curr_rule->target_group_dn) != 0) &&
  1279. ((last == NULL) ||
  1280. (slapi_sdn_compare(last, curr_rule->target_group_dn) != 0))) {
  1281. /* Get comparison attr and loop through values. */
  1282. vals = slapi_entry_attr_get_charray(e, curr_rule->attr);
  1283. for (i = 0; vals && vals[i]; ++i) {
  1284. /* Evaluate the regex. */
  1285. if (slapi_re_exec_nt(curr_rule->regex, vals[i]) == 1) {
  1286. /* Found a match. Add to the end of the targets list
  1287. * and set last as a hint to ourselves. */
  1288. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1289. "automember_update_membership - Adding \"%s\" "
  1290. "to list of target groups for \"%s\" "
  1291. "(matched: \"%s=%s\").\n",
  1292. slapi_sdn_get_dn(curr_rule->target_group_dn),
  1293. slapi_entry_get_dn(e), curr_rule->attr,
  1294. curr_rule->regex_str);
  1295. dnitem = (struct automemberDNListItem *)slapi_ch_calloc(1,
  1296. sizeof(struct automemberDNListItem));
  1297. /* We are just referencing the dn from the regex rule. We
  1298. * will not free it when we clean up this list. This list
  1299. * is more short-lived than the regex rule list, so we can
  1300. * get away with this optimization. */
  1301. dnitem->dn = curr_rule->target_group_dn;
  1302. PR_APPEND_LINK(&(dnitem->list), &targets);
  1303. last = curr_rule->target_group_dn;
  1304. }
  1305. }
  1306. slapi_ch_array_free(vals);
  1307. vals = NULL;
  1308. }
  1309. rule = PR_NEXT_LINK(rule);
  1310. }
  1311. }
  1312. }
  1313. /* If no targets, update default groups if set. Otherwise, update
  1314. * targets. Use a helper to do the actual updates. We can just pass an
  1315. * array of target group DNs along with our entry DN, the grouping attr,
  1316. * and the grouping value. */
  1317. if (PR_CLIST_IS_EMPTY(&targets)) {
  1318. /* Add to each default group. */
  1319. for (i = 0; config->default_groups && config->default_groups[i]; i++) {
  1320. if (automember_add_member_value(e, config->default_groups[i], config->grouping_attr,
  1321. config->grouping_value, ldif_fd)) {
  1322. rc = SLAPI_PLUGIN_FAILURE;
  1323. goto out;
  1324. }
  1325. }
  1326. } else {
  1327. /* Update the target groups. */
  1328. dnitem = (struct automemberDNListItem *)PR_LIST_HEAD(&targets);
  1329. while ((PRCList *)dnitem != &targets) {
  1330. if (automember_add_member_value(e, slapi_sdn_get_dn(dnitem->dn), config->grouping_attr,
  1331. config->grouping_value, ldif_fd)) {
  1332. rc = SLAPI_PLUGIN_FAILURE;
  1333. goto out;
  1334. }
  1335. dnitem = (struct automemberDNListItem *)PR_NEXT_LINK((PRCList *)dnitem);
  1336. }
  1337. }
  1338. /* Free the exclusions and targets lists. Remember that the DN's
  1339. * are not ours, so don't free them! */
  1340. while (!PR_CLIST_IS_EMPTY(&exclusions)) {
  1341. dnitem = (struct automemberDNListItem *)PR_LIST_HEAD(&exclusions);
  1342. PR_REMOVE_LINK((PRCList *)dnitem);
  1343. slapi_ch_free((void **)&dnitem);
  1344. }
  1345. while (!PR_CLIST_IS_EMPTY(&targets)) {
  1346. dnitem = (struct automemberDNListItem *)PR_LIST_HEAD(&targets);
  1347. PR_REMOVE_LINK((PRCList *)dnitem);
  1348. slapi_ch_free((void **)&dnitem);
  1349. }
  1350. out:
  1351. return rc;
  1352. }
  1353. /*
  1354. * automember_add_member_value()
  1355. *
  1356. * Adds a member entry to a group.
  1357. */
  1358. static int
  1359. automember_add_member_value(Slapi_Entry *member_e, const char *group_dn, char *grouping_attr, char *grouping_value, PRFileDesc *ldif_fd)
  1360. {
  1361. Slapi_PBlock *mod_pb = slapi_pblock_new();
  1362. int result = LDAP_SUCCESS;
  1363. LDAPMod mod;
  1364. LDAPMod *mods[2];
  1365. char *vals[2];
  1366. char *member_value = NULL;
  1367. int freeit = 0;
  1368. int rc = 0;
  1369. /* If grouping_value is dn, we need to fetch the dn instead. */
  1370. if (slapi_attr_type_cmp(grouping_value, "dn", SLAPI_TYPE_CMP_EXACT) == 0) {
  1371. member_value = slapi_entry_get_ndn(member_e);
  1372. } else {
  1373. member_value = slapi_entry_attr_get_charptr(member_e, grouping_value);
  1374. freeit = 1;
  1375. }
  1376. /*
  1377. * If ldif_fd is set, we are performing an export task. Write the changes to the
  1378. * file instead of performing them
  1379. */
  1380. if (ldif_fd) {
  1381. PR_fprintf(ldif_fd, "dn: %s\n", group_dn);
  1382. PR_fprintf(ldif_fd, "changetype: modify\n");
  1383. PR_fprintf(ldif_fd, "add: %s\n", grouping_attr);
  1384. PR_fprintf(ldif_fd, "%s: %s\n", grouping_attr, member_value);
  1385. PR_fprintf(ldif_fd, "\n");
  1386. goto out;
  1387. }
  1388. if (member_value) {
  1389. /* Set up the operation. */
  1390. vals[0] = member_value;
  1391. vals[1] = 0;
  1392. mod.mod_op = LDAP_MOD_ADD;
  1393. mod.mod_type = grouping_attr;
  1394. mod.mod_values = vals;
  1395. mods[0] = &mod;
  1396. mods[1] = 0;
  1397. /* Perform the modify operation. */
  1398. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1399. "automember_add_member_value - Adding \"%s\" as "
  1400. "a \"%s\" value to group \"%s\".\n",
  1401. member_value, grouping_attr, group_dn);
  1402. slapi_modify_internal_set_pb(mod_pb, group_dn,
  1403. mods, 0, 0, automember_get_plugin_id(), 0);
  1404. slapi_modify_internal_pb(mod_pb);
  1405. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
  1406. if ((result != LDAP_SUCCESS) && (result != LDAP_TYPE_OR_VALUE_EXISTS)) {
  1407. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1408. "automember_add_member_value - Unable to add \"%s\" as "
  1409. "a \"%s\" value to group \"%s\" (%s).\n",
  1410. member_value, grouping_attr, group_dn,
  1411. ldap_err2string(result));
  1412. rc = result;
  1413. }
  1414. } else {
  1415. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1416. "automember_add_member_value - Unable to find grouping "
  1417. "value attribute \"%s\" in entry \"%s\".\n",
  1418. grouping_value, slapi_entry_get_dn(member_e));
  1419. }
  1420. out:
  1421. /* Cleanup */
  1422. if (freeit) {
  1423. slapi_ch_free_string(&member_value);
  1424. }
  1425. slapi_pblock_destroy(mod_pb);
  1426. return rc;
  1427. }
  1428. /*
  1429. * Operation callback functions
  1430. */
  1431. /*
  1432. * automember_pre_op()
  1433. *
  1434. * Checks if an operation affects the auto membership
  1435. * config and validates the config changes.
  1436. */
  1437. static int
  1438. automember_pre_op(Slapi_PBlock *pb, int modop)
  1439. {
  1440. Slapi_DN *sdn = 0;
  1441. Slapi_Entry *e = 0;
  1442. Slapi_Mods *smods = 0;
  1443. LDAPMod **mods;
  1444. int free_entry = 0;
  1445. char *errstr = NULL;
  1446. int ret = SLAPI_PLUGIN_SUCCESS;
  1447. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1448. "--> automember_pre_op\n");
  1449. if (0 == (sdn = automember_get_sdn(pb)))
  1450. goto bail;
  1451. if (automember_dn_is_config(sdn)) {
  1452. /* Validate config changes, but don't apply them.
  1453. * This allows us to reject invalid config changes
  1454. * here at the pre-op stage. Applying the config
  1455. * needs to be done at the post-op stage. */
  1456. if (LDAP_CHANGETYPE_ADD == modop) {
  1457. slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
  1458. /* If the entry doesn't exist, just bail and
  1459. * let the server handle it. */
  1460. if (e == NULL) {
  1461. goto bail;
  1462. }
  1463. } else if (LDAP_CHANGETYPE_MODIFY == modop) {
  1464. /* Fetch the entry being modified so we can
  1465. * create the resulting entry for validation. */
  1466. if (sdn) {
  1467. slapi_search_internal_get_entry(sdn, 0, &e, automember_get_plugin_id());
  1468. free_entry = 1;
  1469. }
  1470. /* If the entry doesn't exist, just bail and
  1471. * let the server handle it. */
  1472. if (e == NULL) {
  1473. goto bail;
  1474. }
  1475. /* Grab the mods. */
  1476. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1477. smods = slapi_mods_new();
  1478. slapi_mods_init_byref(smods, mods);
  1479. /* Apply the mods to create the resulting entry. */
  1480. if (mods && (slapi_entry_apply_mods(e, mods) != LDAP_SUCCESS)) {
  1481. /* The mods don't apply cleanly, so we just let this op go
  1482. * to let the main server handle it. */
  1483. goto bailmod;
  1484. }
  1485. } else {
  1486. errstr = slapi_ch_smprintf("automember_pre_op - Invalid op type %d",
  1487. modop);
  1488. ret = LDAP_PARAM_ERROR;
  1489. goto bail;
  1490. }
  1491. if (automember_parse_config_entry(e, 0) != 0) {
  1492. /* Refuse the operation if config parsing failed. */
  1493. ret = LDAP_UNWILLING_TO_PERFORM;
  1494. if (LDAP_CHANGETYPE_ADD == modop) {
  1495. errstr = slapi_ch_smprintf("Not a valid auto membership configuration entry.");
  1496. } else {
  1497. errstr = slapi_ch_smprintf("Changes result in an invalid "
  1498. "auto membership configuration.");
  1499. }
  1500. }
  1501. }
  1502. bailmod:
  1503. /* Clean up smods. */
  1504. if (LDAP_CHANGETYPE_MODIFY == modop) {
  1505. slapi_mods_free(&smods);
  1506. }
  1507. bail:
  1508. if (free_entry && e)
  1509. slapi_entry_free(e);
  1510. if (ret) {
  1511. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1512. "automember_pre_op - Operation failure [%d]\n", ret);
  1513. slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL);
  1514. slapi_ch_free((void **)&errstr);
  1515. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
  1516. ret = SLAPI_PLUGIN_FAILURE;
  1517. }
  1518. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1519. "<-- automember_pre_op\n");
  1520. return ret;
  1521. }
  1522. static int
  1523. automember_add_pre_op(Slapi_PBlock *pb)
  1524. {
  1525. return automember_pre_op(pb, LDAP_CHANGETYPE_ADD);
  1526. }
  1527. static int
  1528. automember_mod_pre_op(Slapi_PBlock *pb)
  1529. {
  1530. return automember_pre_op(pb, LDAP_CHANGETYPE_MODIFY);
  1531. }
  1532. /*
  1533. * automember_mod_post_op()
  1534. *
  1535. * Reloads the auto membership config
  1536. * if config changes were made.
  1537. */
  1538. static int
  1539. automember_mod_post_op(Slapi_PBlock *pb)
  1540. {
  1541. Slapi_DN *sdn = NULL;
  1542. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1543. "--> automember_mod_post_op\n");
  1544. if (automember_oktodo(pb) && (sdn = automember_get_sdn(pb))) {
  1545. /* Check if the config is being modified and reload if so. */
  1546. if (automember_dn_is_config(sdn)) {
  1547. automember_load_config();
  1548. }
  1549. }
  1550. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1551. "<-- automember_mod_post_op\n");
  1552. return SLAPI_PLUGIN_SUCCESS;
  1553. }
  1554. static int
  1555. automember_add_post_op(Slapi_PBlock *pb)
  1556. {
  1557. Slapi_Entry *e = NULL;
  1558. Slapi_DN *sdn = NULL;
  1559. struct configEntry *config = NULL;
  1560. PRCList *list = NULL;
  1561. int rc = SLAPI_PLUGIN_SUCCESS;
  1562. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1563. "--> automember_add_post_op\n");
  1564. /* Reload config if a config entry was added. */
  1565. if ((sdn = automember_get_sdn(pb))) {
  1566. if (automember_dn_is_config(sdn)) {
  1567. automember_load_config();
  1568. }
  1569. } else {
  1570. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1571. "automember_add_post_op - Error retrieving dn\n");
  1572. rc = SLAPI_PLUGIN_FAILURE;
  1573. goto bail;
  1574. }
  1575. /* If replication, just bail. */
  1576. if (automember_isrepl(pb)) {
  1577. return SLAPI_PLUGIN_SUCCESS;
  1578. }
  1579. /* Get the newly added entry. */
  1580. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
  1581. if (e) {
  1582. /* If the entry is a tombstone, just bail. */
  1583. Slapi_Value *tombstone = slapi_value_new_string(SLAPI_ATTR_VALUE_TOMBSTONE);
  1584. int is_tombstone = slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS,
  1585. tombstone);
  1586. slapi_value_free(&tombstone);
  1587. if (is_tombstone) {
  1588. return SLAPI_PLUGIN_SUCCESS;
  1589. }
  1590. /* Check if a config entry applies
  1591. * to the entry being added. */
  1592. automember_config_read_lock();
  1593. if (!PR_CLIST_IS_EMPTY(g_automember_config)) {
  1594. list = PR_LIST_HEAD(g_automember_config);
  1595. while (list != g_automember_config) {
  1596. config = (struct configEntry *)list;
  1597. /* Does the entry meet scope and filter requirements? */
  1598. if (slapi_dn_issuffix(slapi_sdn_get_dn(sdn), config->scope) &&
  1599. (slapi_filter_test_simple(e, config->filter) == 0)) {
  1600. /* Find out what membership changes are needed and make them. */
  1601. if (automember_update_membership(config, e, NULL)) {
  1602. rc = SLAPI_PLUGIN_FAILURE;
  1603. break;
  1604. }
  1605. }
  1606. list = PR_NEXT_LINK(list);
  1607. }
  1608. }
  1609. automember_config_unlock();
  1610. } else {
  1611. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1612. "automember_add_post_op - Error "
  1613. "retrieving post-op entry %s\n",
  1614. slapi_sdn_get_dn(sdn));
  1615. }
  1616. bail:
  1617. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1618. "<-- automember_add_post_op (%d)\n", rc);
  1619. if (rc) {
  1620. char errtxt[SLAPI_DSE_RETURNTEXT_SIZE];
  1621. int result = LDAP_UNWILLING_TO_PERFORM;
  1622. PR_snprintf(errtxt, SLAPI_DSE_RETURNTEXT_SIZE, "Automember Plugin update unexpectedly failed.\n");
  1623. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &result);
  1624. slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, &errtxt);
  1625. }
  1626. return rc;
  1627. }
  1628. /*
  1629. * automember_del_post_op()
  1630. *
  1631. * Removes deleted config.
  1632. */
  1633. static int
  1634. automember_del_post_op(Slapi_PBlock *pb)
  1635. {
  1636. Slapi_DN *sdn = NULL;
  1637. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1638. "--> automember_del_post_op\n");
  1639. /* Reload config if a config entry was deleted. */
  1640. if ((sdn = automember_get_sdn(pb))) {
  1641. if (automember_dn_is_config(sdn))
  1642. automember_load_config();
  1643. } else {
  1644. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1645. "automember_del_post_op - Error retrieving dn\n");
  1646. }
  1647. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1648. "<-- automember_del_post_op\n");
  1649. return SLAPI_PLUGIN_SUCCESS;
  1650. }
  1651. typedef struct _task_data
  1652. {
  1653. char *filter_str;
  1654. char *ldif_out;
  1655. char *ldif_in;
  1656. Slapi_DN *base_dn;
  1657. char *bind_dn;
  1658. int scope;
  1659. } task_data;
  1660. static void
  1661. automember_task_destructor(Slapi_Task *task)
  1662. {
  1663. if (task) {
  1664. task_data *mydata = (task_data *)slapi_task_get_data(task);
  1665. while (slapi_task_get_refcount(task) > 0) {
  1666. /* Yield to wait for the fixup task finishes. */
  1667. DS_Sleep(PR_MillisecondsToInterval(100));
  1668. }
  1669. if (mydata) {
  1670. slapi_ch_free_string(&mydata->bind_dn);
  1671. slapi_sdn_free(&mydata->base_dn);
  1672. slapi_ch_free_string(&mydata->filter_str);
  1673. slapi_ch_free((void **)&mydata);
  1674. }
  1675. }
  1676. }
  1677. static void
  1678. automember_task_export_destructor(Slapi_Task *task)
  1679. {
  1680. if (task) {
  1681. task_data *mydata = (task_data *)slapi_task_get_data(task);
  1682. while (slapi_task_get_refcount(task) > 0) {
  1683. /* Yield to wait for the fixup task finishes. */
  1684. DS_Sleep(PR_MillisecondsToInterval(100));
  1685. }
  1686. if (mydata) {
  1687. slapi_ch_free_string(&mydata->ldif_out);
  1688. slapi_ch_free_string(&mydata->bind_dn);
  1689. slapi_sdn_free(&mydata->base_dn);
  1690. slapi_ch_free_string(&mydata->filter_str);
  1691. slapi_ch_free((void **)&mydata);
  1692. }
  1693. }
  1694. }
  1695. static void
  1696. automember_task_map_destructor(Slapi_Task *task)
  1697. {
  1698. if (task) {
  1699. task_data *mydata = (task_data *)slapi_task_get_data(task);
  1700. while (slapi_task_get_refcount(task) > 0) {
  1701. /* Yield to wait for the fixup task finishes. */
  1702. DS_Sleep(PR_MillisecondsToInterval(100));
  1703. }
  1704. if (mydata) {
  1705. slapi_ch_free_string(&mydata->ldif_out);
  1706. slapi_ch_free_string(&mydata->ldif_in);
  1707. slapi_ch_free_string(&mydata->bind_dn);
  1708. slapi_ch_free((void **)&mydata);
  1709. }
  1710. }
  1711. }
  1712. /*
  1713. * automember_task_add
  1714. *
  1715. * This task is designed to "retro-fit" entries that existed prior to
  1716. * enabling this plugin. This can be an expensive task to run, but it's
  1717. * better than processing every modify operation in an attempt to catch
  1718. * entries that have not been processed.
  1719. *
  1720. * task entry:
  1721. *
  1722. * dn: cn=my rebuild task, cn=automember rebuild membership,cn=tasks,cn=config
  1723. * objectClass: top
  1724. * objectClass: extensibleObject
  1725. * cn: my rebuild task
  1726. * basedn: dc=example,dc=com
  1727. * filter: (uid=*)
  1728. * scope: sub
  1729. *
  1730. * basedn and filter are required. If scope is omitted, the default is sub
  1731. */
  1732. static int
  1733. automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attribute__((unused)), int *returncode, char *returntext __attribute__((unused)), void *arg)
  1734. {
  1735. int rv = SLAPI_DSE_CALLBACK_OK;
  1736. task_data *mytaskdata = NULL;
  1737. Slapi_Task *task = NULL;
  1738. PRThread *thread = NULL;
  1739. char *bind_dn = NULL;
  1740. const char *base_dn;
  1741. const char *filter;
  1742. const char *scope;
  1743. *returncode = LDAP_SUCCESS;
  1744. /*
  1745. * Grab the task params
  1746. */
  1747. if ((base_dn = fetch_attr(e, "basedn", 0)) == NULL) {
  1748. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  1749. rv = SLAPI_DSE_CALLBACK_ERROR;
  1750. goto out;
  1751. }
  1752. if ((filter = fetch_attr(e, "filter", 0)) == NULL) {
  1753. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  1754. rv = SLAPI_DSE_CALLBACK_ERROR;
  1755. goto out;
  1756. }
  1757. scope = fetch_attr(e, "scope", "sub");
  1758. /*
  1759. * setup our task data
  1760. */
  1761. mytaskdata = (task_data *)slapi_ch_calloc(1, sizeof(task_data));
  1762. if (mytaskdata == NULL) {
  1763. *returncode = LDAP_OPERATIONS_ERROR;
  1764. rv = SLAPI_DSE_CALLBACK_ERROR;
  1765. goto out;
  1766. }
  1767. slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &bind_dn);
  1768. mytaskdata->bind_dn = slapi_ch_strdup(bind_dn);
  1769. mytaskdata->base_dn = slapi_sdn_new_dn_byval(base_dn);
  1770. mytaskdata->filter_str = slapi_ch_strdup(filter);
  1771. if (scope) {
  1772. if (strcasecmp(scope, "sub") == 0) {
  1773. mytaskdata->scope = 2;
  1774. } else if (strcasecmp(scope, "one") == 0) {
  1775. mytaskdata->scope = 1;
  1776. } else if (strcasecmp(scope, "base") == 0) {
  1777. mytaskdata->scope = 0;
  1778. } else {
  1779. /* Hmm, possible typo, use subtree */
  1780. mytaskdata->scope = 2;
  1781. }
  1782. } else {
  1783. /* subtree by default */
  1784. mytaskdata->scope = 2;
  1785. }
  1786. task = slapi_plugin_new_task(slapi_entry_get_ndn(e), arg);
  1787. slapi_task_set_destructor_fn(task, automember_task_destructor);
  1788. slapi_task_set_data(task, mytaskdata);
  1789. /*
  1790. * Start the task as a separate thread
  1791. */
  1792. thread = PR_CreateThread(PR_USER_THREAD, automember_rebuild_task_thread,
  1793. (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  1794. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  1795. if (thread == NULL) {
  1796. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1797. "automember_task_add - Unable to create task thread!\n");
  1798. *returncode = LDAP_OPERATIONS_ERROR;
  1799. slapi_task_finish(task, *returncode);
  1800. rv = SLAPI_DSE_CALLBACK_ERROR;
  1801. } else {
  1802. rv = SLAPI_DSE_CALLBACK_OK;
  1803. }
  1804. out:
  1805. return rv;
  1806. }
  1807. /*
  1808. * automember_rebuild_task_thread()
  1809. *
  1810. * Search using the basedn, filter, and scope provided from the task data.
  1811. * Then loop of each entry, and apply the membership if applicable.
  1812. */
  1813. void
  1814. automember_rebuild_task_thread(void *arg)
  1815. {
  1816. Slapi_Task *task = (Slapi_Task *)arg;
  1817. struct configEntry *config = NULL;
  1818. Slapi_PBlock *search_pb = NULL, *fixup_pb = NULL;
  1819. Slapi_Entry **entries = NULL;
  1820. task_data *td = NULL;
  1821. PRCList *list = NULL;
  1822. int result = 0;
  1823. int i = 0;
  1824. if (!task) {
  1825. return; /* no task */
  1826. }
  1827. slapi_task_inc_refcount(task);
  1828. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1829. "automember_rebuild_task_thread - Refcount incremented.\n");
  1830. /*
  1831. * Fetch our task data from the task
  1832. */
  1833. td = (task_data *)slapi_task_get_data(task);
  1834. slapi_task_begin(task, 1);
  1835. slapi_task_log_notice(task, "Automember rebuild task starting (base dn: (%s) filter (%s)...\n",
  1836. slapi_sdn_get_dn(td->base_dn), td->filter_str);
  1837. slapi_task_log_status(task, "Automember rebuild task starting (base dn: (%s) filter (%s)...\n",
  1838. slapi_sdn_get_dn(td->base_dn), td->filter_str);
  1839. /*
  1840. * Set the bind dn in the local thread data
  1841. */
  1842. slapi_td_set_dn(slapi_ch_strdup(td->bind_dn));
  1843. /*
  1844. * Search the database
  1845. */
  1846. search_pb = slapi_pblock_new();
  1847. slapi_search_internal_set_pb_ext(search_pb, td->base_dn, td->scope, td->filter_str, NULL,
  1848. 0, NULL, NULL, automember_get_plugin_id(), 0);
  1849. slapi_search_internal_pb(search_pb);
  1850. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
  1851. if (LDAP_SUCCESS != result) {
  1852. slapi_task_log_notice(task, "Automember rebuild membership task unable to search"
  1853. " on base (%s) filter (%s) error (%d)\n",
  1854. slapi_sdn_get_dn(td->base_dn),
  1855. td->filter_str, result);
  1856. slapi_task_log_status(task, "Automember rebuild membership task unable to search"
  1857. " on base (%s) filter (%s) error (%d)\n",
  1858. slapi_sdn_get_dn(td->base_dn),
  1859. td->filter_str, result);
  1860. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1861. "automember_rebuild_task_thread - Unable to search on base (%s) filter (%s) error (%d)\n",
  1862. slapi_sdn_get_dn(td->base_dn), td->filter_str, result);
  1863. goto out;
  1864. }
  1865. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  1866. /*
  1867. * If this is a backend txn plugin, start the transaction
  1868. */
  1869. if (plugin_is_betxn) {
  1870. Slapi_Backend *be = slapi_be_select(td->base_dn);
  1871. if (be) {
  1872. fixup_pb = slapi_pblock_new();
  1873. slapi_pblock_set(fixup_pb, SLAPI_BACKEND, be);
  1874. if (slapi_back_transaction_begin(fixup_pb) != LDAP_SUCCESS) {
  1875. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1876. "automember_rebuild_task_thread - Failed to start transaction\n");
  1877. }
  1878. } else {
  1879. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1880. "automember_rebuild_task_thread - Failed to get be backend from %s\n",
  1881. slapi_sdn_get_dn(td->base_dn));
  1882. }
  1883. }
  1884. /*
  1885. * Grab the config read lock, and loop over the entries
  1886. */
  1887. automember_config_read_lock();
  1888. for (i = 0; entries && (entries[i] != NULL); i++) {
  1889. if (!PR_CLIST_IS_EMPTY(g_automember_config)) {
  1890. list = PR_LIST_HEAD(g_automember_config);
  1891. while (list != g_automember_config) {
  1892. config = (struct configEntry *)list;
  1893. /* Does the entry meet scope and filter requirements? */
  1894. if (slapi_dn_issuffix(slapi_entry_get_dn(entries[i]), config->scope) &&
  1895. (slapi_filter_test_simple(entries[i], config->filter) == 0)) {
  1896. if (slapi_is_shutting_down() ||
  1897. automember_update_membership(config, entries[i], NULL)) {
  1898. result = SLAPI_PLUGIN_FAILURE;
  1899. automember_config_unlock();
  1900. goto out;
  1901. }
  1902. }
  1903. list = PR_NEXT_LINK(list);
  1904. }
  1905. }
  1906. }
  1907. automember_config_unlock();
  1908. out:
  1909. if (plugin_is_betxn && fixup_pb) {
  1910. if (i == 0 || result != 0) { /* no updates performed */
  1911. slapi_back_transaction_abort(fixup_pb);
  1912. } else {
  1913. slapi_back_transaction_commit(fixup_pb);
  1914. }
  1915. slapi_pblock_destroy(fixup_pb);
  1916. }
  1917. slapi_free_search_results_internal(search_pb);
  1918. slapi_pblock_destroy(search_pb);
  1919. if (result) {
  1920. /* error */
  1921. slapi_task_log_notice(task, "Automember rebuild task aborted. Error (%d)", result);
  1922. slapi_task_log_status(task, "Automember rebuild task aborted. Error (%d)", result);
  1923. } else {
  1924. slapi_task_log_notice(task, "Automember rebuild task finished. Processed (%d) entries.", i);
  1925. slapi_task_log_status(task, "Automember rebuild task finished. Processed (%d) entries.", i);
  1926. }
  1927. slapi_task_inc_progress(task);
  1928. slapi_task_finish(task, result);
  1929. slapi_task_dec_refcount(task);
  1930. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  1931. "automember_rebuild_task_thread - Refcount decremented.\n");
  1932. }
  1933. /*
  1934. * Export an ldif of the changes that would be made if we ran the automember rebuild membership task
  1935. *
  1936. * task entry:
  1937. *
  1938. * dn: cn=my export task, cn=automember export updates,cn=tasks,cn=config
  1939. * objectClass: top
  1940. * objectClass: extensibleObject
  1941. * cn: my export task
  1942. * basedn: dc=example,dc=com
  1943. * filter: (uid=*)
  1944. * scope: sub
  1945. * ldif: /tmp/automem-updates.ldif
  1946. */
  1947. static int
  1948. automember_task_add_export_updates(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attribute__((unused)), int *returncode, char *returntext __attribute__((unused)), void *arg)
  1949. {
  1950. int rv = SLAPI_DSE_CALLBACK_OK;
  1951. task_data *mytaskdata = NULL;
  1952. Slapi_Task *task = NULL;
  1953. PRThread *thread = NULL;
  1954. char *bind_dn = NULL;
  1955. const char *base_dn = NULL;
  1956. const char *filter = NULL;
  1957. const char *ldif = NULL;
  1958. const char *scope = NULL;
  1959. *returncode = LDAP_SUCCESS;
  1960. if ((ldif = fetch_attr(e, "ldif", 0)) == NULL) {
  1961. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  1962. rv = SLAPI_DSE_CALLBACK_ERROR;
  1963. goto out;
  1964. }
  1965. if ((base_dn = fetch_attr(e, "basedn", 0)) == NULL) {
  1966. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  1967. rv = SLAPI_DSE_CALLBACK_ERROR;
  1968. goto out;
  1969. }
  1970. if ((filter = fetch_attr(e, "filter", 0)) == NULL) {
  1971. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  1972. rv = SLAPI_DSE_CALLBACK_ERROR;
  1973. goto out;
  1974. }
  1975. scope = fetch_attr(e, "scope", "sub");
  1976. slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &bind_dn);
  1977. mytaskdata = (task_data *)slapi_ch_calloc(1, sizeof(task_data));
  1978. if (mytaskdata == NULL) {
  1979. *returncode = LDAP_OPERATIONS_ERROR;
  1980. rv = SLAPI_DSE_CALLBACK_ERROR;
  1981. goto out;
  1982. }
  1983. mytaskdata->bind_dn = slapi_ch_strdup(bind_dn);
  1984. mytaskdata->ldif_out = slapi_ch_strdup(ldif);
  1985. mytaskdata->base_dn = slapi_sdn_new_dn_byval(base_dn);
  1986. mytaskdata->filter_str = slapi_ch_strdup(filter);
  1987. if (scope) {
  1988. if (strcasecmp(scope, "sub") == 0) {
  1989. mytaskdata->scope = 2;
  1990. } else if (strcasecmp(scope, "one") == 0) {
  1991. mytaskdata->scope = 1;
  1992. } else if (strcasecmp(scope, "base") == 0) {
  1993. mytaskdata->scope = 0;
  1994. } else {
  1995. /* Hmm, possible typo, use subtree */
  1996. mytaskdata->scope = 2;
  1997. }
  1998. } else {
  1999. /* subtree by default */
  2000. mytaskdata->scope = 2;
  2001. }
  2002. task = slapi_plugin_new_task(slapi_entry_get_ndn(e), arg);
  2003. slapi_task_set_destructor_fn(task, automember_task_export_destructor);
  2004. slapi_task_set_data(task, mytaskdata);
  2005. /*
  2006. * Start the task as a separate thread
  2007. */
  2008. thread = PR_CreateThread(PR_USER_THREAD, automember_export_task_thread,
  2009. (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  2010. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  2011. if (thread == NULL) {
  2012. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2013. "automember_task_add_export_updates - Unable to create export task thread!\n");
  2014. *returncode = LDAP_OPERATIONS_ERROR;
  2015. rv = SLAPI_DSE_CALLBACK_ERROR;
  2016. slapi_task_finish(task, *returncode);
  2017. } else {
  2018. rv = SLAPI_DSE_CALLBACK_OK;
  2019. }
  2020. out:
  2021. return rv;
  2022. }
  2023. void
  2024. automember_export_task_thread(void *arg)
  2025. {
  2026. Slapi_Task *task = (Slapi_Task *)arg;
  2027. Slapi_PBlock *search_pb = NULL;
  2028. Slapi_Entry **entries = NULL;
  2029. int result = SLAPI_DSE_CALLBACK_OK;
  2030. struct configEntry *config = NULL;
  2031. PRCList *list = NULL;
  2032. task_data *td = NULL;
  2033. PRFileDesc *ldif_fd;
  2034. int i = 0;
  2035. int rc = 0;
  2036. if (!task) {
  2037. return; /* no task */
  2038. }
  2039. slapi_task_inc_refcount(task);
  2040. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2041. "automember_export_task_thread - Refcount incremented.\n");
  2042. td = (task_data *)slapi_task_get_data(task);
  2043. slapi_task_begin(task, 1);
  2044. slapi_task_log_notice(task, "Automember export task starting. Exporting changes to (%s)", td->ldif_out);
  2045. slapi_task_log_status(task, "Automember export task starting. Exporting changes to (%s)", td->ldif_out);
  2046. /* make sure we can open the ldif file */
  2047. if ((ldif_fd = PR_Open(td->ldif_out, PR_CREATE_FILE | PR_WRONLY, DEFAULT_FILE_MODE)) == NULL) {
  2048. rc = PR_GetOSError();
  2049. slapi_task_log_notice(task, "Automember export task could not open ldif file \"%s\" for writing, error %d (%s)\n",
  2050. td->ldif_out, rc, slapi_system_strerror(rc));
  2051. slapi_task_log_status(task, "Automember export task could not open ldif file \"%s\" for writing, error %d (%s)\n",
  2052. td->ldif_out, rc, slapi_system_strerror(rc));
  2053. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2054. "automember_export_task_thread - Could not open ldif file \"%s\" for writing, error %d (%s)\n",
  2055. td->ldif_out, rc, slapi_system_strerror(rc));
  2056. result = SLAPI_DSE_CALLBACK_ERROR;
  2057. goto out;
  2058. }
  2059. /*
  2060. * Set the bind dn in the local thread data
  2061. */
  2062. slapi_td_set_dn(slapi_ch_strdup(td->bind_dn));
  2063. /*
  2064. * Search the database
  2065. */
  2066. search_pb = slapi_pblock_new();
  2067. slapi_search_internal_set_pb_ext(search_pb, td->base_dn, td->scope, td->filter_str, NULL,
  2068. 0, NULL, NULL, automember_get_plugin_id(), 0);
  2069. slapi_search_internal_pb(search_pb);
  2070. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
  2071. if (LDAP_SUCCESS != result) {
  2072. slapi_task_log_notice(task, "Automember task failed to search on base (%s) filter (%s) error (%d)\n",
  2073. slapi_sdn_get_dn(td->base_dn), td->filter_str, result);
  2074. slapi_task_log_status(task, "Automember task failed to search on base (%s) filter (%s) error (%d)\n",
  2075. slapi_sdn_get_dn(td->base_dn), td->filter_str, result);
  2076. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2077. "automember_export_task_thread - Unable to search on base (%s) filter (%s) error (%d)\n",
  2078. slapi_sdn_get_dn(td->base_dn), td->filter_str, result);
  2079. goto out;
  2080. }
  2081. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  2082. /*
  2083. * Grab the config read lock, and loop over the entries
  2084. */
  2085. automember_config_read_lock();
  2086. for (i = 0; entries && (entries[i] != NULL); i++) {
  2087. if (!PR_CLIST_IS_EMPTY(g_automember_config)) {
  2088. list = PR_LIST_HEAD(g_automember_config);
  2089. while (list != g_automember_config) {
  2090. config = (struct configEntry *)list;
  2091. if (slapi_dn_issuffix(slapi_sdn_get_dn(td->base_dn), config->scope) &&
  2092. (slapi_filter_test_simple(entries[i], config->filter) == 0)) {
  2093. if (slapi_is_shutting_down() ||
  2094. automember_update_membership(config, entries[i], ldif_fd)) {
  2095. result = SLAPI_DSE_CALLBACK_ERROR;
  2096. automember_config_unlock();
  2097. goto out;
  2098. }
  2099. }
  2100. list = PR_NEXT_LINK(list);
  2101. }
  2102. }
  2103. }
  2104. automember_config_unlock();
  2105. out:
  2106. slapi_free_search_results_internal(search_pb);
  2107. slapi_pblock_destroy(search_pb);
  2108. if (ldif_fd) {
  2109. PR_Close(ldif_fd);
  2110. }
  2111. if (result) {
  2112. /* error */
  2113. slapi_task_log_notice(task, "Automember export task aborted. Error (%d)", result);
  2114. slapi_task_log_status(task, "Automember export task aborted. Error (%d)", result);
  2115. } else {
  2116. slapi_task_log_notice(task, "Automember export task finished. Processed (%d) entries.", i);
  2117. slapi_task_log_status(task, "Automember export task finished. Processed (%d) entries.", i);
  2118. }
  2119. slapi_task_inc_progress(task);
  2120. slapi_task_finish(task, result);
  2121. slapi_task_dec_refcount(task);
  2122. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2123. "automember_export_task_thread - Refcount decremented.\n");
  2124. }
  2125. /*
  2126. * Export an ldif of the changes that would be made from the entries
  2127. * in the provided ldif file
  2128. *
  2129. * task entry:
  2130. *
  2131. * dn: cn=my map task, cn=automember map updates,cn=tasks,cn=config
  2132. * objectClass: top
  2133. * objectClass: extensibleObject
  2134. * cn: my export task
  2135. * ldif_in: /tmp/entries.ldif
  2136. * ldif_out: /tmp/automem-updates.ldif
  2137. */
  2138. static int
  2139. automember_task_add_map_entries(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attribute__((unused)), int *returncode, char *returntext __attribute__((unused)), void *arg)
  2140. {
  2141. int rv = SLAPI_DSE_CALLBACK_OK;
  2142. task_data *mytaskdata = NULL;
  2143. Slapi_Task *task = NULL;
  2144. PRThread *thread = NULL;
  2145. char *bind_dn;
  2146. const char *ldif_out;
  2147. const char *ldif_in;
  2148. *returncode = LDAP_SUCCESS;
  2149. /*
  2150. * Get the params
  2151. */
  2152. if ((ldif_in = fetch_attr(e, "ldif_in", 0)) == NULL) {
  2153. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  2154. rv = SLAPI_DSE_CALLBACK_ERROR;
  2155. goto out;
  2156. }
  2157. if ((ldif_out = fetch_attr(e, "ldif_out", 0)) == NULL) {
  2158. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  2159. rv = SLAPI_DSE_CALLBACK_ERROR;
  2160. goto out;
  2161. }
  2162. /*
  2163. * Setup the task data
  2164. */
  2165. mytaskdata = (task_data *)slapi_ch_calloc(1, sizeof(task_data));
  2166. if (mytaskdata == NULL) {
  2167. *returncode = LDAP_OPERATIONS_ERROR;
  2168. rv = SLAPI_DSE_CALLBACK_ERROR;
  2169. goto out;
  2170. }
  2171. slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &bind_dn);
  2172. mytaskdata->bind_dn = slapi_ch_strdup(bind_dn);
  2173. mytaskdata->ldif_out = slapi_ch_strdup(ldif_out);
  2174. mytaskdata->ldif_in = slapi_ch_strdup(ldif_in);
  2175. task = slapi_plugin_new_task(slapi_entry_get_ndn(e), arg);
  2176. slapi_task_set_destructor_fn(task, automember_task_map_destructor);
  2177. slapi_task_set_data(task, mytaskdata);
  2178. /*
  2179. * Start the task as a separate thread
  2180. */
  2181. thread = PR_CreateThread(PR_USER_THREAD, automember_map_task_thread,
  2182. (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  2183. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  2184. if (thread == NULL) {
  2185. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2186. "automember_task_add_map_entries - Unable to create map task thread!\n");
  2187. *returncode = LDAP_OPERATIONS_ERROR;
  2188. rv = SLAPI_DSE_CALLBACK_ERROR;
  2189. slapi_task_finish(task, *returncode);
  2190. } else {
  2191. rv = SLAPI_DSE_CALLBACK_OK;
  2192. }
  2193. out:
  2194. return rv;
  2195. }
  2196. /*
  2197. * Read in the text entries from ldif_in, and convert them to slapi_entries.
  2198. * Then, write to ldif_out what the updates would be if these entries were added
  2199. */
  2200. void
  2201. automember_map_task_thread(void *arg)
  2202. {
  2203. Slapi_Task *task = (Slapi_Task *)arg;
  2204. Slapi_Entry *e = NULL;
  2205. int result = SLAPI_DSE_CALLBACK_OK;
  2206. struct configEntry *config = NULL;
  2207. PRCList *list = NULL;
  2208. task_data *td = NULL;
  2209. PRFileDesc *ldif_fd_out = NULL;
  2210. char *entrystr = NULL;
  2211. char *errstr = NULL;
  2212. #if defined(USE_OPENLDAP)
  2213. int buflen = 0;
  2214. LDIFFP *ldif_fd_in = NULL;
  2215. ldif_record_lineno_t lineno = 0;
  2216. #else
  2217. FILE *ldif_fd_in = NULL;
  2218. int lineno = 0;
  2219. #endif
  2220. int rc = 0;
  2221. if (!task) {
  2222. return; /* no task */
  2223. }
  2224. slapi_task_inc_refcount(task);
  2225. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2226. "automember_map_task_thread - Refcount incremented.\n");
  2227. td = (task_data *)slapi_task_get_data(task);
  2228. slapi_task_begin(task, 1);
  2229. slapi_task_log_notice(task, "Automember map task starting... Reading entries from (%s)"
  2230. " and writing the updates to (%s)",
  2231. td->ldif_in, td->ldif_out);
  2232. slapi_task_log_status(task, "Automember map task starting... Reading entries from (%s)"
  2233. " and writing the updates to (%s)",
  2234. td->ldif_in, td->ldif_out);
  2235. /* make sure we can open the ldif files */
  2236. if ((ldif_fd_out = PR_Open(td->ldif_out, PR_CREATE_FILE | PR_WRONLY, DEFAULT_FILE_MODE)) == NULL) {
  2237. rc = PR_GetOSError();
  2238. slapi_task_log_notice(task, "The ldif file %s could not be accessed, error %d (%s). Aborting task.\n",
  2239. td->ldif_out, rc, slapi_system_strerror(rc));
  2240. slapi_task_log_status(task, "The ldif file %s could not be accessed, error %d (%s). Aborting task.\n",
  2241. td->ldif_out, rc, slapi_system_strerror(rc));
  2242. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2243. "automember_map_task_thread - Could not open ldif file \"%s\" for writing, error %d (%s)\n",
  2244. td->ldif_out, rc, slapi_system_strerror(rc));
  2245. result = SLAPI_DSE_CALLBACK_ERROR;
  2246. goto out;
  2247. }
  2248. #if defined(USE_OPENLDAP)
  2249. if ((ldif_fd_in = ldif_open(td->ldif_in, "r")) == NULL) {
  2250. rc = errno;
  2251. errstr = strerror(rc);
  2252. #else
  2253. if ((ldif_fd_in = fopen(td->ldif_in, "r")) == NULL) {
  2254. rc = PR_GetOSError();
  2255. errstr = (char *)slapi_system_strerror(rc);
  2256. #endif
  2257. slapi_task_log_notice(task, "The ldif file %s could not be accessed, error %d (%s). Aborting task.\n",
  2258. td->ldif_in, rc, errstr);
  2259. slapi_task_log_status(task, "The ldif file %s could not be accessed, error %d (%s). Aborting task.\n",
  2260. td->ldif_in, rc, errstr);
  2261. slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2262. "automember_map_task_thread - Could not open ldif file \"%s\" for reading, error %d (%s)\n",
  2263. td->ldif_in, rc, errstr);
  2264. result = SLAPI_DSE_CALLBACK_ERROR;
  2265. goto out;
  2266. }
  2267. /*
  2268. * Convert each LDIF entry to a slapi_entry
  2269. */
  2270. automember_config_read_lock();
  2271. #if defined(USE_OPENLDAP)
  2272. while (ldif_read_record(ldif_fd_in, &lineno, &entrystr, &buflen)) {
  2273. buflen = 0;
  2274. #else
  2275. while ((entrystr = ldif_get_entry(ldif_fd_in, &lineno)) != NULL) {
  2276. #endif
  2277. e = slapi_str2entry(entrystr, 0);
  2278. if (e != NULL) {
  2279. if (!PR_CLIST_IS_EMPTY(g_automember_config)) {
  2280. list = PR_LIST_HEAD(g_automember_config);
  2281. while (list != g_automember_config) {
  2282. config = (struct configEntry *)list;
  2283. if (slapi_dn_issuffix(slapi_entry_get_dn_const(e), config->scope) &&
  2284. (slapi_filter_test_simple(e, config->filter) == 0)) {
  2285. if (slapi_is_shutting_down() ||
  2286. automember_update_membership(config, e, ldif_fd_out)) {
  2287. result = SLAPI_DSE_CALLBACK_ERROR;
  2288. slapi_entry_free(e);
  2289. slapi_ch_free_string(&entrystr);
  2290. automember_config_unlock();
  2291. goto out;
  2292. }
  2293. }
  2294. list = PR_NEXT_LINK(list);
  2295. }
  2296. }
  2297. slapi_entry_free(e);
  2298. } else {
  2299. /* invalid entry */
  2300. slapi_task_log_notice(task, "Automember map task, skipping invalid entry.");
  2301. slapi_task_log_status(task, "Automember map task, skipping invalid entry.");
  2302. }
  2303. slapi_ch_free_string(&entrystr);
  2304. }
  2305. automember_config_unlock();
  2306. out:
  2307. if (ldif_fd_out) {
  2308. PR_Close(ldif_fd_out);
  2309. }
  2310. if (ldif_fd_in) {
  2311. #if defined(USE_OPENLDAP)
  2312. ldif_close(ldif_fd_in);
  2313. #else
  2314. fclose(ldif_fd_in);
  2315. #endif
  2316. }
  2317. slapi_task_inc_progress(task);
  2318. slapi_task_finish(task, result);
  2319. slapi_task_dec_refcount(task);
  2320. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2321. "automember_map_task_thread - Refcount decremented.\n");
  2322. }
  2323. /*
  2324. * automember_modrdn_post_op()
  2325. *
  2326. * Reloads config if config entries move
  2327. * into or out of our config scope.
  2328. */
  2329. static int
  2330. automember_modrdn_post_op(Slapi_PBlock *pb)
  2331. {
  2332. Slapi_Entry *post_e = NULL;
  2333. Slapi_DN *old_sdn = NULL;
  2334. Slapi_DN *new_sdn = NULL;
  2335. struct configEntry *config = NULL;
  2336. PRCList *list = NULL;
  2337. int rc = SLAPI_PLUGIN_SUCCESS;
  2338. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2339. "--> automember_modrdn_post_op\n");
  2340. /* Just bail if we aren't ready to service requests yet. */
  2341. if (!automember_oktodo(pb)) {
  2342. return SLAPI_PLUGIN_SUCCESS;
  2343. }
  2344. /*
  2345. * Reload config if an existing config entry was renamed,
  2346. * or if the new dn brings an entry into the scope of the
  2347. * config entries.
  2348. */
  2349. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &post_e);
  2350. if (post_e) {
  2351. new_sdn = slapi_entry_get_sdn(post_e);
  2352. } else {
  2353. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2354. "automember_modrdn_post_op - Error "
  2355. "retrieving post-op entry\n");
  2356. return SLAPI_PLUGIN_FAILURE;
  2357. }
  2358. if ((old_sdn = automember_get_sdn(pb))) {
  2359. if (automember_dn_is_config(old_sdn) || automember_dn_is_config(new_sdn)) {
  2360. automember_load_config();
  2361. }
  2362. } else {
  2363. slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2364. "automember_modrdn_post_op - Error "
  2365. "retrieving dn\n");
  2366. return SLAPI_PLUGIN_FAILURE;
  2367. }
  2368. /* If replication, just bail. */
  2369. if (automember_isrepl(pb)) {
  2370. return SLAPI_PLUGIN_SUCCESS;
  2371. }
  2372. /*
  2373. * Check if a config entry applies to the entry(post modrdn)
  2374. */
  2375. automember_config_read_lock();
  2376. if (!PR_CLIST_IS_EMPTY(g_automember_config)) {
  2377. list = PR_LIST_HEAD(g_automember_config);
  2378. while (list != g_automember_config) {
  2379. config = (struct configEntry *)list;
  2380. /* Does the entry meet scope and filter requirements? */
  2381. if (slapi_dn_issuffix(slapi_sdn_get_dn(new_sdn), config->scope) &&
  2382. (slapi_filter_test_simple(post_e, config->filter) == 0)) {
  2383. /* Find out what membership changes are needed and make them. */
  2384. if (automember_update_membership(config, post_e, NULL)) {
  2385. rc = SLAPI_PLUGIN_FAILURE;
  2386. break;
  2387. }
  2388. }
  2389. list = PR_NEXT_LINK(list);
  2390. }
  2391. }
  2392. automember_config_unlock();
  2393. if (rc) {
  2394. char errtxt[SLAPI_DSE_RETURNTEXT_SIZE];
  2395. int result = LDAP_UNWILLING_TO_PERFORM;
  2396. PR_snprintf(errtxt, SLAPI_DSE_RETURNTEXT_SIZE, "Automember Plugin update unexpectedly failed. "
  2397. "Please see the server errors log for more information.\n");
  2398. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &result);
  2399. slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, &errtxt);
  2400. }
  2401. slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
  2402. "<-- automember_modrdn_post_op (%d)\n", rc);
  2403. return rc;
  2404. }