linked_attrs.c 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2009 Red Hat, Inc.
  35. * All rights reserved.
  36. * END COPYRIGHT BLOCK **/
  37. #ifdef HAVE_CONFIG_H
  38. # include <config.h>
  39. #endif
  40. /*
  41. * Linked attributes plug-in
  42. */
  43. #include "linked_attrs.h"
  44. /*
  45. * Plug-in globals
  46. */
  47. static PRCList *g_link_config = NULL;
  48. static PRCList *g_managed_config_index = NULL;
  49. static Slapi_RWLock *g_config_lock;
  50. static void *_PluginID = NULL;
  51. static char *_PluginDN = NULL;
  52. int plugin_is_betxn = 0;
  53. /* For future use - enforce all linked attribute operations succeed */
  54. static int strict_results = 0;
  55. static Slapi_PluginDesc pdesc = { LINK_FEATURE_DESC,
  56. VENDOR,
  57. DS_PACKAGE_VERSION,
  58. LINK_PLUGIN_DESC };
  59. /*
  60. * Plug-in management functions
  61. */
  62. int linked_attrs_init(Slapi_PBlock * pb);
  63. static int linked_attrs_start(Slapi_PBlock * pb);
  64. static int linked_attrs_close(Slapi_PBlock * pb);
  65. static int linked_attrs_postop_init(Slapi_PBlock * pb);
  66. static int linked_attrs_internal_postop_init(Slapi_PBlock *pb);
  67. /*
  68. * Operation callbacks (where the real work is done)
  69. */
  70. static int linked_attrs_mod_post_op(Slapi_PBlock *pb);
  71. static int linked_attrs_add_post_op(Slapi_PBlock *pb);
  72. static int linked_attrs_del_post_op(Slapi_PBlock *pb);
  73. static int linked_attrs_modrdn_post_op(Slapi_PBlock *pb);
  74. static int linked_attrs_pre_op(Slapi_PBlock *pb, int modop);
  75. static int linked_attrs_mod_pre_op(Slapi_PBlock *pb);
  76. static int linked_attrs_add_pre_op(Slapi_PBlock *pb);
  77. /*
  78. * Config cache management functions
  79. */
  80. static int linked_attrs_load_config();
  81. static void linked_attrs_delete_config();
  82. static int linked_attrs_parse_config_entry(Slapi_Entry * e, int apply);
  83. static void linked_attrs_insert_config_index(struct configEntry *entry);
  84. static void linked_attrs_free_config_entry(struct configEntry ** entry);
  85. /*
  86. * helpers
  87. */
  88. static char *linked_attrs_get_dn(Slapi_PBlock * pb);
  89. static Slapi_DN *linked_attrs_get_sdn(Slapi_PBlock * pb);
  90. static int linked_attrs_dn_is_config(char *dn);
  91. static void linked_attrs_find_config(const char *dn, const char *type,
  92. struct configEntry **config);
  93. static void linked_attrs_find_config_reverse(const char *dn,
  94. const char *type, struct configEntry **config);
  95. static int linked_attrs_config_index_has_type(char *type);
  96. static int linked_attrs_config_exists(struct configEntry *entry);
  97. static int linked_attrs_config_exists_reverse(struct configEntry *entry);
  98. static int linked_attrs_oktodo(Slapi_PBlock *pb);
  99. void linked_attrs_load_array(Slapi_Value **array, Slapi_Attr *attr);
  100. int linked_attrs_compare(const void *a, const void *b);
  101. static int linked_attrs_add_backpointers(char *linkdn, struct configEntry *config,
  102. Slapi_Mod *smod);
  103. static int linked_attrs_del_backpointers(Slapi_PBlock *pb, char *linkdn,
  104. struct configEntry *config, Slapi_Mod *smod);
  105. static int linked_attrs_replace_backpointers(Slapi_PBlock *pb, char *linkdn,
  106. struct configEntry *config, Slapi_Mod *smod);
  107. static int linked_attrs_mod_backpointers(char *linkdn, char *type, char *scope,
  108. int modop, Slapi_ValueSet *targetvals);
  109. /*
  110. * Config cache locking functions
  111. */
  112. void
  113. linked_attrs_read_lock()
  114. {
  115. slapi_rwlock_rdlock(g_config_lock);
  116. }
  117. void
  118. linked_attrs_write_lock()
  119. {
  120. slapi_rwlock_wrlock(g_config_lock);
  121. }
  122. void
  123. linked_attrs_unlock()
  124. {
  125. slapi_rwlock_unlock(g_config_lock);
  126. }
  127. /*
  128. * Plugin identity functions
  129. */
  130. void
  131. linked_attrs_set_plugin_id(void *pluginID)
  132. {
  133. _PluginID = pluginID;
  134. }
  135. void *
  136. linked_attrs_get_plugin_id()
  137. {
  138. return _PluginID;
  139. }
  140. void
  141. linked_attrs_set_plugin_dn(const char *pluginDN)
  142. {
  143. _PluginDN = (char *)pluginDN;
  144. }
  145. char *
  146. linked_attrs_get_plugin_dn()
  147. {
  148. return _PluginDN;
  149. }
  150. /*
  151. * Plug-in initialization functions
  152. */
  153. int
  154. linked_attrs_init(Slapi_PBlock *pb)
  155. {
  156. int status = 0;
  157. char *plugin_identity = NULL;
  158. Slapi_Entry *plugin_entry = NULL;
  159. char *plugin_type = NULL;
  160. int preadd = SLAPI_PLUGIN_PRE_ADD_FN;
  161. int premod = SLAPI_PLUGIN_PRE_MODIFY_FN;
  162. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  163. "--> linked_attrs_init\n");
  164. if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
  165. plugin_entry &&
  166. (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
  167. plugin_type && strstr(plugin_type, "betxn")) {
  168. plugin_is_betxn = 1;
  169. preadd = SLAPI_PLUGIN_BE_TXN_PRE_ADD_FN;
  170. premod = SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN;
  171. }
  172. slapi_ch_free_string(&plugin_type);
  173. /* Store the plugin identity for later use.
  174. * Used for internal operations. */
  175. slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
  176. PR_ASSERT(plugin_identity);
  177. linked_attrs_set_plugin_id(plugin_identity);
  178. /* Register callbacks */
  179. if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  180. SLAPI_PLUGIN_VERSION_01) != 0 ||
  181. slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
  182. (void *) linked_attrs_start) != 0 ||
  183. slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
  184. (void *) linked_attrs_close) != 0 ||
  185. slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
  186. (void *) &pdesc) != 0 ||
  187. slapi_pblock_set(pb, premod, (void *) linked_attrs_mod_pre_op) != 0 ||
  188. slapi_pblock_set(pb, preadd, (void *) linked_attrs_add_pre_op) != 0) {
  189. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  190. "linked_attrs_init: failed to register plugin\n");
  191. status = -1;
  192. }
  193. if (!status && !plugin_is_betxn &&
  194. slapi_register_plugin("internalpostoperation", /* op type */
  195. 1, /* Enabled */
  196. "linked_attrs_init", /* this function desc */
  197. linked_attrs_internal_postop_init, /* init func */
  198. LINK_INT_POSTOP_DESC, /* plugin desc */
  199. NULL, /* ? */
  200. plugin_identity /* access control */
  201. )) {
  202. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  203. "linked_attrs_init: failed to register internalpostoperation plugin\n");
  204. status = -1;
  205. }
  206. if (!status) {
  207. plugin_type = "postoperation";
  208. if (plugin_is_betxn) {
  209. plugin_type = "betxnpostoperation";
  210. }
  211. if (slapi_register_plugin(plugin_type, /* op type */
  212. 1, /* Enabled */
  213. "linked_attrs_init", /* this function desc */
  214. linked_attrs_postop_init, /* init func for post op */
  215. LINK_POSTOP_DESC, /* plugin desc */
  216. NULL, /* ? */
  217. plugin_identity /* access control */
  218. )) {
  219. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  220. "linked_attrs_init: failed to register postop plugin\n");
  221. status = -1;
  222. }
  223. }
  224. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  225. "<-- linked_attrs_init\n");
  226. return status;
  227. }
  228. /* not used when using plugin as a betxn plugin - betxn plugins are called for both internal and external ops */
  229. static int
  230. linked_attrs_internal_postop_init(Slapi_PBlock *pb)
  231. {
  232. int status = 0;
  233. if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  234. SLAPI_PLUGIN_VERSION_01) != 0 ||
  235. slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
  236. (void *) &pdesc) != 0 ||
  237. slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN,
  238. (void *) linked_attrs_add_post_op) != 0 ||
  239. slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN,
  240. (void *) linked_attrs_del_post_op) != 0 ||
  241. slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN,
  242. (void *) linked_attrs_mod_post_op) != 0 ||
  243. slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN,
  244. (void *) linked_attrs_modrdn_post_op) != 0) {
  245. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  246. "linked_attrs_internal_postop_init: failed to register plugin\n");
  247. status = -1;
  248. }
  249. return status;
  250. }
  251. static int
  252. linked_attrs_postop_init(Slapi_PBlock *pb)
  253. {
  254. int status = 0;
  255. int addfn = SLAPI_PLUGIN_POST_ADD_FN;
  256. int delfn = SLAPI_PLUGIN_POST_DELETE_FN;
  257. int modfn = SLAPI_PLUGIN_POST_MODIFY_FN;
  258. int mdnfn = SLAPI_PLUGIN_POST_MODRDN_FN;
  259. if (plugin_is_betxn) {
  260. addfn = SLAPI_PLUGIN_BE_TXN_POST_ADD_FN;
  261. delfn = SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN;
  262. modfn = SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN;
  263. mdnfn = SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN;
  264. }
  265. if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
  266. SLAPI_PLUGIN_VERSION_01) != 0 ||
  267. slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
  268. (void *) &pdesc) != 0 ||
  269. slapi_pblock_set(pb, addfn, (void *) linked_attrs_add_post_op) != 0 ||
  270. slapi_pblock_set(pb, delfn, (void *) linked_attrs_del_post_op) != 0 ||
  271. slapi_pblock_set(pb, modfn, (void *) linked_attrs_mod_post_op) != 0 ||
  272. slapi_pblock_set(pb, mdnfn, (void *) linked_attrs_modrdn_post_op) != 0) {
  273. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  274. "linked_attrs_postop_init: failed to register plugin\n");
  275. status = -1;
  276. }
  277. return status;
  278. }
  279. /*
  280. * linked_attrs_start()
  281. *
  282. * Creates config lock and loads config cache.
  283. */
  284. static int
  285. linked_attrs_start(Slapi_PBlock * pb)
  286. {
  287. Slapi_DN *plugindn = NULL;
  288. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  289. "--> linked_attrs_start\n");
  290. g_config_lock = slapi_new_rwlock();
  291. if (!g_config_lock) {
  292. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  293. "linked_attrs_start: lock creation failed\n");
  294. return -1;
  295. }
  296. /*
  297. * Get the plug-in target dn from the system
  298. * and store it for future use. */
  299. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &plugindn);
  300. if (NULL == plugindn || 0 == slapi_sdn_get_ndn_len(plugindn)) {
  301. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  302. "linked_attrs_start: unable to retrieve plugin dn\n");
  303. return -1;
  304. }
  305. linked_attrs_set_plugin_dn(slapi_sdn_get_dn(plugindn));
  306. /*
  307. * Load the config cache
  308. */
  309. g_link_config = (PRCList *)slapi_ch_calloc(1, sizeof(struct configEntry));
  310. PR_INIT_CLIST(g_link_config);
  311. g_managed_config_index = (PRCList *)slapi_ch_calloc(1, sizeof(struct configIndex));
  312. PR_INIT_CLIST(g_managed_config_index);
  313. if (linked_attrs_load_config() != 0) {
  314. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  315. "linked_attrs_start: unable to load plug-in configuration\n");
  316. return -1;
  317. }
  318. /*
  319. * Register our task callback
  320. */
  321. slapi_plugin_task_register_handler("fixup linked attributes", linked_attrs_fixup_task_add, pb);
  322. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  323. "linked attributes plug-in: ready for service\n");
  324. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  325. "<-- linked_attrs_start\n");
  326. return 0;
  327. }
  328. /*
  329. * linked_attrs_close()
  330. *
  331. * Cleans up the config cache.
  332. */
  333. static int
  334. linked_attrs_close(Slapi_PBlock * pb)
  335. {
  336. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  337. "--> linked_attrs_close\n");
  338. slapi_plugin_task_unregister_handler("fixup linked attributes", linked_attrs_fixup_task_add);
  339. linked_attrs_delete_config();
  340. slapi_destroy_rwlock(g_config_lock);
  341. g_config_lock = NULL;
  342. slapi_ch_free((void **)&g_link_config);
  343. slapi_ch_free((void **)&g_managed_config_index);
  344. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  345. "<-- linked_attrs_close\n");
  346. return 0;
  347. }
  348. PRCList *
  349. linked_attrs_get_config()
  350. {
  351. return g_link_config;
  352. }
  353. /*
  354. * config looks like this
  355. * - cn=myplugin
  356. * --- cn=manager link
  357. * --- cn=owner link
  358. * --- cn=etc
  359. */
  360. static int
  361. linked_attrs_load_config()
  362. {
  363. int status = 0;
  364. int result;
  365. int i;
  366. Slapi_PBlock *search_pb;
  367. Slapi_Entry **entries = NULL;
  368. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  369. "--> linked_attrs_load_config\n");
  370. /* Clear out any old config. */
  371. linked_attrs_write_lock();
  372. linked_attrs_delete_config();
  373. /* Find the config entries beneath our plugin entry. */
  374. search_pb = slapi_pblock_new();
  375. slapi_search_internal_set_pb(search_pb, linked_attrs_get_plugin_dn(),
  376. LDAP_SCOPE_SUBTREE, "objectclass=*",
  377. NULL, 0, NULL, NULL, linked_attrs_get_plugin_id(), 0);
  378. slapi_search_internal_pb(search_pb);
  379. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
  380. if (LDAP_SUCCESS != result) {
  381. status = -1;
  382. goto cleanup;
  383. }
  384. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  385. &entries);
  386. if (NULL == entries || NULL == entries[0]) {
  387. /* If there are no config entries, we're done. */
  388. goto cleanup;
  389. }
  390. /* Loop through all of the entries we found and parse them. */
  391. for (i = 0; (entries[i] != NULL); i++) {
  392. /* We don't care about the status here because we may have
  393. * some invalid config entries, but we just want to continue
  394. * looking for valid ones. */
  395. linked_attrs_parse_config_entry(entries[i], 1);
  396. }
  397. cleanup:
  398. slapi_free_search_results_internal(search_pb);
  399. slapi_pblock_destroy(search_pb);
  400. linked_attrs_unlock();
  401. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  402. "<-- linked_attrs_load_config\n");
  403. return status;
  404. }
  405. /*
  406. * linked_attrs_parse_config_entry()
  407. *
  408. * Parses a single config entry. If apply is non-zero, then
  409. * we will load and start using the new config. You can simply
  410. * validate config without making any changes by setting apply
  411. * to 0.
  412. *
  413. * Returns 0 if the entry is valid and -1 if it is invalid.
  414. */
  415. static int
  416. linked_attrs_parse_config_entry(Slapi_Entry * e, int apply)
  417. {
  418. char *value;
  419. struct configEntry *entry = NULL;
  420. struct configEntry *config_entry;
  421. PRCList *list;
  422. int entry_added = 0;
  423. int ret = 0;
  424. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  425. "--> linked_attrs_parse_config_entry\n");
  426. /* If this is the main plug-in
  427. * config entry, just bail. */
  428. if (strcasecmp(linked_attrs_get_plugin_dn(), slapi_entry_get_ndn(e)) == 0) {
  429. ret = -1;
  430. goto bail;
  431. }
  432. entry = (struct configEntry *)slapi_ch_calloc(1, sizeof(struct configEntry));
  433. if (NULL == entry) {
  434. ret = -1;
  435. goto bail;
  436. }
  437. value = slapi_entry_get_ndn(e);
  438. if (value) {
  439. entry->dn = slapi_ch_strdup(value);
  440. } else {
  441. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  442. "linked_attrs_parse_config_entry: Error "
  443. "reading dn from config entry\n");
  444. ret = -1;
  445. goto bail;
  446. }
  447. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  448. "----------> dn [%s]\n", entry->dn);
  449. value = slapi_entry_attr_get_charptr(e, LINK_LINK_TYPE);
  450. if (value) {
  451. int not_dn_syntax = 0;
  452. char *syntaxoid = NULL;
  453. Slapi_Attr *attr = slapi_attr_new();
  454. /* Set this first so we free it if we encounter an error */
  455. entry->linktype = value;
  456. /* Gather some information about this attribute. */
  457. slapi_attr_init(attr, value);
  458. slapi_attr_get_syntax_oid_copy(attr, &syntaxoid );
  459. not_dn_syntax = strcmp(syntaxoid, DN_SYNTAX_OID);
  460. slapi_ch_free_string(&syntaxoid);
  461. slapi_attr_free(&attr);
  462. /* Check if the link type's syntax is Distinguished Name.
  463. * We only treat this as a warning. */
  464. if (not_dn_syntax) {
  465. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  466. "linked_attrs_parse_config_entry: The %s config "
  467. "setting must be set to an attribute with the "
  468. "Distinguished Name syntax for linked attribute "
  469. "pair \"%s\" attribute \"%s\".\n", LINK_LINK_TYPE, entry->dn, value);
  470. }
  471. } else {
  472. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  473. "linked_attrs_parse_config_entry: The %s config "
  474. "setting is required for linked attribute pair \"%s\".\n",
  475. LINK_LINK_TYPE, entry->dn);
  476. ret = -1;
  477. goto bail;
  478. }
  479. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  480. "----------> %s [%s]\n", LINK_LINK_TYPE, entry->linktype);
  481. value = slapi_entry_attr_get_charptr(e, LINK_MANAGED_TYPE);
  482. if (value) {
  483. int single_valued = 0;
  484. int not_dn_syntax = 0;
  485. char *syntaxoid = NULL;
  486. Slapi_Attr *attr = slapi_attr_new();
  487. /* Set this first so we free it if we encounter an error */
  488. entry->managedtype = value;
  489. /* Gather some information about this attribute. */
  490. slapi_attr_init(attr, value);
  491. slapi_attr_get_syntax_oid_copy(attr, &syntaxoid );
  492. not_dn_syntax = strcmp(syntaxoid, DN_SYNTAX_OID);
  493. single_valued = slapi_attr_flag_is_set(attr, SLAPI_ATTR_FLAG_SINGLE);
  494. slapi_ch_free_string(&syntaxoid);
  495. slapi_attr_free(&attr);
  496. /* Ensure that the managed type is a multi-valued attribute. */
  497. if (single_valued) {
  498. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  499. "linked_attrs_parse_config_entry: The %s config "
  500. "setting must be set to a multi-valued attribute "
  501. "for linked attribute pair \"%s\".\n",
  502. LINK_MANAGED_TYPE, entry->dn);
  503. ret = -1;
  504. goto bail;
  505. /* Check if the link type's syntax is Distinguished Name.
  506. * We only treat this as a warning. */
  507. } else if (not_dn_syntax) {
  508. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  509. "linked_attrs_parse_config_entry: The %s config "
  510. "setting must be set to an attribute with the "
  511. "Distinguished Name syntax for linked attribute "
  512. "pair \"%s\".\n", LINK_MANAGED_TYPE, entry->dn);
  513. }
  514. } else {
  515. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  516. "linked_attrs_parse_config_entry: The %s config "
  517. "setting is required for linked attribute pair \"%s\".\n",
  518. LINK_MANAGED_TYPE, entry->dn);
  519. ret = -1;
  520. goto bail;
  521. }
  522. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  523. "----------> %s [%s]\n", LINK_MANAGED_TYPE,
  524. entry->managedtype);
  525. /* A scope is not required. No scope means it
  526. * applies to any part of the DIT. */
  527. value = slapi_entry_attr_get_charptr(e, LINK_SCOPE);
  528. if (value) {
  529. entry->scope = value;
  530. }
  531. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  532. "----------> %s [%s]\n", LINK_SCOPE,
  533. entry->scope ? entry->scope : "NULL");
  534. /* Check if config already exists for
  535. * the link type at the same scope. */
  536. if (linked_attrs_config_exists(entry)) {
  537. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  538. "linked_attrs_parse_config_entry: A config "
  539. "entry for the link attribute %s already "
  540. "exists at a scope of \"%s\".\n", entry->linktype,
  541. entry->scope);
  542. ret = -1;
  543. goto bail;
  544. }
  545. /* Check if config already exists for
  546. * the managed type at the same scope. */
  547. if (linked_attrs_config_exists_reverse(entry)) {
  548. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  549. "linked_attrs_parse_config_entry: A config "
  550. "entry for the managed attribute %s already "
  551. "exists at a scope of \"%s\".\n", entry->managedtype,
  552. entry->scope);
  553. ret = -1;
  554. goto bail;
  555. }
  556. /* If we were only called to validate config, we can
  557. * just bail out before applying the config changes */
  558. if (apply == 0) {
  559. goto bail;
  560. }
  561. /* Create a lock for this attribute pair. */
  562. entry->lock = slapi_new_mutex();
  563. if (!entry->lock) {
  564. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  565. "linked_attrs_parse_config_entry: Unable to create "
  566. "lock for linked attribute pair \"%s\".\n", entry->dn);
  567. ret = -1;
  568. goto bail;
  569. }
  570. /* Add the entry to the list. We group by link type. We
  571. * also maintain a reverse list grouped by managed type. */
  572. if (!PR_CLIST_IS_EMPTY(g_link_config)) {
  573. list = PR_LIST_HEAD(g_link_config);
  574. while (list != g_link_config) {
  575. config_entry = (struct configEntry *) list;
  576. /* See if the types match. We want to group
  577. * entries for the same link type together. */
  578. if (slapi_attr_type_cmp(config_entry->linktype, entry->linktype, 1) == 0) {
  579. PR_INSERT_BEFORE(&(entry->list), list);
  580. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  581. "store [%s] before [%s] \n", entry->dn,
  582. config_entry->dn);
  583. /* add to managed type index */
  584. linked_attrs_insert_config_index(entry);
  585. entry_added = 1;
  586. break;
  587. }
  588. list = PR_NEXT_LINK(list);
  589. if (g_link_config == list) {
  590. /* add to tail */
  591. PR_INSERT_BEFORE(&(entry->list), list);
  592. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  593. "store [%s] at tail\n", entry->dn);
  594. /* add to managed type index */
  595. linked_attrs_insert_config_index(entry);
  596. entry_added = 1;
  597. break;
  598. }
  599. }
  600. } else {
  601. /* first entry */
  602. PR_INSERT_LINK(&(entry->list), g_link_config);
  603. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  604. "store [%s] at head \n", entry->dn);
  605. /* add to managed type index */
  606. linked_attrs_insert_config_index(entry);
  607. entry_added = 1;
  608. }
  609. bail:
  610. if (0 == entry_added) {
  611. /* Don't log error if we weren't asked to apply config */
  612. if ((apply != 0) && (entry != NULL)) {
  613. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  614. "linked_attrs_parse_config_entry: Invalid config entry "
  615. "[%s] skipped\n", entry->dn);
  616. }
  617. linked_attrs_free_config_entry(&entry);
  618. } else {
  619. ret = 0;
  620. }
  621. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  622. "<-- linked_attrs_parse_config_entry\n");
  623. return ret;
  624. }
  625. /*
  626. * linked_attrs_insert_config_index()
  627. *
  628. * Adds an entry to the ordered config index. We maintain
  629. * an list of pointers to the cached config entries that is
  630. * grouped by managed type. We use this index to find the
  631. * appropriate config entry when given a backpointer. This
  632. * is useful for the case where an entry with backpointers
  633. * is renamed and we need to updated the forward link.
  634. */
  635. static void
  636. linked_attrs_insert_config_index(struct configEntry *entry)
  637. {
  638. struct configEntry *config_entry = NULL;
  639. struct configIndex *index_entry = NULL;
  640. PRCList *list = PR_LIST_HEAD(g_managed_config_index);
  641. int inserted = 0;
  642. index_entry = (struct configIndex *)slapi_ch_calloc(1, sizeof(struct configIndex));
  643. index_entry->config = entry;
  644. if (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  645. while (list != g_managed_config_index) {
  646. config_entry = ((struct configIndex *)list)->config;
  647. /* See if the types match. */
  648. if (slapi_attr_type_cmp(config_entry->managedtype, entry->managedtype, 1) == 0) {
  649. PR_INSERT_BEFORE(&(index_entry->list), list);
  650. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  651. "store [%s] before [%s] \n", entry->dn,
  652. config_entry->dn);
  653. inserted = 1;
  654. break;
  655. }
  656. list = PR_NEXT_LINK(list);
  657. if (g_managed_config_index == list) {
  658. /* add to tail */
  659. PR_INSERT_BEFORE(&(index_entry->list), list);
  660. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  661. "store [%s] at tail\n", entry->dn);
  662. inserted = 1;
  663. break;
  664. }
  665. }
  666. } else {
  667. /* first entry */
  668. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  669. "store [%s] at head \n", entry->dn);
  670. PR_INSERT_LINK(&(index_entry->list), g_managed_config_index);
  671. inserted = 1;
  672. }
  673. if(!inserted){
  674. slapi_ch_free((void **)&index_entry);
  675. }
  676. }
  677. static void
  678. linked_attrs_free_config_entry(struct configEntry ** entry)
  679. {
  680. struct configEntry *e = *entry;
  681. if (e == NULL)
  682. return;
  683. if (e->dn) {
  684. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  685. "freeing config entry [%s]\n", e->dn);
  686. slapi_ch_free_string(&e->dn);
  687. }
  688. if (e->linktype)
  689. slapi_ch_free_string(&e->linktype);
  690. if (e->managedtype)
  691. slapi_ch_free_string(&e->managedtype);
  692. if (e->scope)
  693. slapi_ch_free_string(&e->scope);
  694. if (e->lock)
  695. slapi_destroy_mutex(e->lock);
  696. slapi_ch_free((void **) entry);
  697. }
  698. static void
  699. linked_attrs_delete_configEntry(PRCList *entry)
  700. {
  701. PR_REMOVE_LINK(entry);
  702. linked_attrs_free_config_entry((struct configEntry **) &entry);
  703. }
  704. static void
  705. linked_attrs_delete_config()
  706. {
  707. PRCList *list;
  708. /* Delete the config cache. */
  709. while (!PR_CLIST_IS_EMPTY(g_link_config)) {
  710. list = PR_LIST_HEAD(g_link_config);
  711. linked_attrs_delete_configEntry(list);
  712. }
  713. /* Delete the reverse index. */
  714. while (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  715. list = PR_LIST_HEAD(g_managed_config_index);
  716. PR_REMOVE_LINK(list);
  717. slapi_ch_free((void **)&list);
  718. }
  719. return;
  720. }
  721. /*
  722. * Helper functions
  723. */
  724. static char *
  725. linked_attrs_get_dn(Slapi_PBlock * pb)
  726. {
  727. const char *dn = 0;
  728. Slapi_DN *sdn = NULL;
  729. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  730. "--> linked_attrs_get_dn\n");
  731. if (slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn)) {
  732. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  733. "linked_attrs_get_dn: failed to get dn of changed entry");
  734. goto bail;
  735. }
  736. dn = slapi_sdn_get_dn(sdn);
  737. bail:
  738. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  739. "<-- linked_attrs_get_dn\n");
  740. return (char *)dn;
  741. }
  742. static Slapi_DN *
  743. linked_attrs_get_sdn(Slapi_PBlock * pb)
  744. {
  745. Slapi_DN *sdn = 0;
  746. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  747. "--> linked_attrs_get_sdn\n");
  748. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
  749. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  750. "<-- linked_attrs_get_sdn\n");
  751. return sdn;
  752. }
  753. /*
  754. * linked_attrs_dn_is_config()
  755. *
  756. * Checks if dn is a linked attribute config entry.
  757. */
  758. static int
  759. linked_attrs_dn_is_config(char *dn)
  760. {
  761. int ret = 0;
  762. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  763. "--> linked_attrs_dn_is_config\n");
  764. /* Return 1 if the passed in dn is a child of the main
  765. * plugin config entry. */
  766. if (slapi_dn_issuffix(dn, linked_attrs_get_plugin_dn()) &&
  767. strcasecmp(dn, linked_attrs_get_plugin_dn())) {
  768. ret = 1;
  769. }
  770. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  771. "<-- linked_attrs_dn_is_config\n");
  772. return ret;
  773. }
  774. /*
  775. * linked_attrs_find_config()
  776. *
  777. * Finds the appropriate config entry for a given dn and
  778. * link type. A read lock must be held on the config
  779. * before calling this function. The configEntry that is
  780. * returned is a pointer to the actual config entry in
  781. * the config cache. It should not be modified in any
  782. * way. The read lock should not be released until you
  783. * are finished with the config entry that is returned.
  784. * Returns NULL if no applicable config entry is found.
  785. */
  786. static void
  787. linked_attrs_find_config(const char *dn,
  788. const char *type, struct configEntry **config)
  789. {
  790. int found_type = 0;
  791. PRCList *list = NULL;
  792. *config = NULL;
  793. if (!PR_CLIST_IS_EMPTY(g_link_config)) {
  794. list = PR_LIST_HEAD(g_link_config);
  795. while (list != g_link_config) {
  796. if (slapi_attr_type_cmp(((struct configEntry *)list)->linktype,
  797. type, 1) == 0) {
  798. /* Set a flag indicating that we found a config entry
  799. * for this type. We use this flag so we can stop
  800. * processing early if we don't find a matching scope. */
  801. found_type = 1;
  802. /* Check if the dn is in the scope of this config
  803. * entry. If the config entry doesn't have a scope
  804. * (global), consider it a match. If we have a match,
  805. * we can stop processing the config. */
  806. if ((((struct configEntry *)list)->scope == NULL) ||
  807. (slapi_dn_issuffix(dn, ((struct configEntry *)list)->scope))) {
  808. *config = (struct configEntry *)list;
  809. break;
  810. }
  811. } else {
  812. /* If flag is set, we're done. We have configured links
  813. * for this type, but none of the scopes match. */
  814. if (found_type) {
  815. break;
  816. }
  817. }
  818. list = PR_NEXT_LINK(list);
  819. }
  820. }
  821. }
  822. /*
  823. * linked_attrs_find_config_reverse()
  824. *
  825. * Finds the appropriate config entry for a given dn and
  826. * managed type. A read lock must be held on the config
  827. * before calling this function. The configEntry that is
  828. * returned is a pointer to the actual config entry in
  829. * the config cache. It should not be modified in any
  830. * way. The read lock should not be released until you
  831. * are finished with the config entry that is returned.
  832. * Returns NULL if no applicable config entry is found.
  833. */
  834. static void
  835. linked_attrs_find_config_reverse(const char *dn,
  836. const char *type, struct configEntry **config)
  837. {
  838. int found_type = 0;
  839. PRCList *list = NULL;
  840. *config = NULL;
  841. if (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  842. list = PR_LIST_HEAD(g_managed_config_index);
  843. while (list != g_managed_config_index) {
  844. if (slapi_attr_type_cmp(((struct configIndex *)list)->config->managedtype,
  845. type, 1) == 0) {
  846. /* Set a flag indicating that we found a config entry
  847. * for this type. We use this flag so we can stop
  848. * processing early if we don't find a matching scope. */
  849. found_type = 1;
  850. /* Check if the dn is in the scope of this config
  851. * entry. If the config entry doesn't have a scope
  852. * (global), consider it a match. If we have a match,
  853. * we can stop processing the config. */
  854. if ((((struct configIndex *)list)->config->scope == NULL) ||
  855. (slapi_dn_issuffix(dn, ((struct configIndex *)list)->config->scope))) {
  856. *config = ((struct configIndex *)list)->config;
  857. break;
  858. }
  859. } else {
  860. /* If flag is set, we're done. We have configured links
  861. * for this type, but none of the scopes match. */
  862. if (found_type) {
  863. break;
  864. }
  865. }
  866. list = PR_NEXT_LINK(list);
  867. }
  868. }
  869. }
  870. /*
  871. * linked_attrs_config_index_has_type()
  872. *
  873. * Returns 1 if a config entry exists with the passed
  874. * in managed type.
  875. *
  876. * A read lock on the config must be held before calling
  877. * this function.
  878. */
  879. static int
  880. linked_attrs_config_index_has_type(char *type)
  881. {
  882. int rc = 0;
  883. PRCList *list = NULL;
  884. if (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  885. list = PR_LIST_HEAD(g_managed_config_index);
  886. while (list != g_managed_config_index) {
  887. if (slapi_attr_type_cmp(((struct configIndex *)list)->config->managedtype,
  888. type, 1) == 0) {
  889. rc = 1;
  890. break;
  891. }
  892. list = PR_NEXT_LINK(list);
  893. }
  894. }
  895. return rc;
  896. }
  897. /*
  898. * linked_attrs_config_exists()
  899. *
  900. * Returns 1 if a config entry exists in the cache
  901. * already for the given link type at the given scope.
  902. * This will detect if the cached config entry is really
  903. * the same one as the passed in entry by comparing the
  904. * dn of the config entry. We will still return 0 in
  905. * this case as it's one and the same config entry. We
  906. * really want to use this to prevent multiple config
  907. * entries for the same link type at the same scope.
  908. *
  909. * A read lock on the config must be held before calling
  910. * this function.
  911. */
  912. static int
  913. linked_attrs_config_exists(struct configEntry *entry)
  914. {
  915. int rc = 0;
  916. int found_type = 0;
  917. PRCList *list = NULL;
  918. if (!PR_CLIST_IS_EMPTY(g_link_config)) {
  919. list = PR_LIST_HEAD(g_link_config);
  920. while (list != g_link_config) {
  921. if (slapi_attr_type_cmp(((struct configEntry *)list)->linktype,
  922. entry->linktype, 1) == 0) {
  923. found_type = 1;
  924. /* We don't allow nested config for the same type. We
  925. * need to check for nesting in both directions here.
  926. * If no scope is set, we consider the entry global. */
  927. if ((((struct configEntry *)list)->scope == NULL) ||
  928. slapi_dn_issuffix(entry->scope, ((struct configEntry *)list)->scope) ||
  929. slapi_dn_issuffix(((struct configEntry *)list)->scope, entry->scope)) {
  930. /* Make sure that this isn't the same exact entry
  931. * in the list already. This can happen if a config
  932. * entry is being modified. Both of these were already
  933. * normalized when the config struct was filled in. */
  934. if (strcasecmp(entry->dn, ((struct configEntry *)list)->dn) != 0) {
  935. rc = 1;
  936. break;
  937. }
  938. }
  939. } else {
  940. if (found_type) {
  941. /* Since the list is sorted by link type, we
  942. * are finished if we get here since we found
  943. * the type but didn't match the scope. */
  944. break;
  945. }
  946. }
  947. list = PR_NEXT_LINK(list);
  948. }
  949. }
  950. return rc;
  951. }
  952. /*
  953. * linked_attrs_config_exists_reverse()
  954. *
  955. * Returns 1 if a config entry exists in the cache
  956. * already for the given managed type at the given scope.
  957. * This will detect if the cached config entry is really
  958. * the same one as the passed in entry by comparing the
  959. * dn of the config entry. We will still return 0 in
  960. * this case as it's one and the same config entry. We
  961. * really want to use this to prevent multiple config
  962. * entries for the same managed type at the same scope.
  963. *
  964. * A read lock on the config must be held before calling
  965. * this function.
  966. */
  967. static int
  968. linked_attrs_config_exists_reverse(struct configEntry *entry)
  969. {
  970. int rc = 0;
  971. int found_type = 0;
  972. PRCList *list = NULL;
  973. if (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  974. list = PR_LIST_HEAD(g_managed_config_index);
  975. while (list != g_managed_config_index) {
  976. if (slapi_attr_type_cmp(((struct configIndex *)list)->config->managedtype,
  977. entry->managedtype, 1) == 0) {
  978. found_type = 1;
  979. /* We don't allow nested config for the same type. We
  980. * need to check for nesting in both directions here. */
  981. if ((((struct configIndex *)list)->config->scope == NULL) ||
  982. slapi_dn_issuffix(entry->scope,
  983. ((struct configIndex *)list)->config->scope) ||
  984. slapi_dn_issuffix(((struct configIndex *)list)->config->scope,
  985. entry->scope)) {
  986. /* Make sure that this isn't the same exact entry
  987. * in the list already. This can happen if a config
  988. * entry is being modified. Both of these were already
  989. * normalized when the config struct was filled in. */
  990. if (strcasecmp(entry->dn, ((struct configIndex *)list)->config->dn) != 0) {
  991. rc = 1;
  992. break;
  993. }
  994. }
  995. } else {
  996. if (found_type) {
  997. /* Since the list is sorted by link type, we
  998. * are finished if we get here since we found
  999. * the type but didn't match the scope. */
  1000. break;
  1001. }
  1002. }
  1003. list = PR_NEXT_LINK(list);
  1004. }
  1005. }
  1006. return rc;
  1007. }
  1008. /*
  1009. * linked_attrs_oktodo()
  1010. *
  1011. * Check if we want to process this operation. We need to be
  1012. * sure that the operation succeeded. We also respond to replicated
  1013. * ops so we don't test for that. This does require that the managed
  1014. * attributes not be replicated.
  1015. */
  1016. static int
  1017. linked_attrs_oktodo(Slapi_PBlock *pb)
  1018. {
  1019. int ret = 1;
  1020. int oprc = 0;
  1021. slapi_log_error( SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1022. "--> linked_attrs_oktodo\n" );
  1023. if(slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
  1024. {
  1025. slapi_log_error( SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1026. "linked_attrs_oktodo: could not get parameters\n" );
  1027. ret = -1;
  1028. }
  1029. /* This plugin should only execute if the operation succeeded. */
  1030. if(oprc != 0)
  1031. {
  1032. ret = 0;
  1033. }
  1034. slapi_log_error( SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1035. "<-- linked_attrs_oktodo\n" );
  1036. return ret;
  1037. }
  1038. /* linked_attrs_load_array()
  1039. *
  1040. * put attribute values in array structure
  1041. */
  1042. void
  1043. linked_attrs_load_array(Slapi_Value **array, Slapi_Attr *attr)
  1044. {
  1045. Slapi_Value *val = 0;
  1046. int hint = slapi_attr_first_value(attr, &val);
  1047. while(val)
  1048. {
  1049. *array = val;
  1050. array++;
  1051. hint = slapi_attr_next_value(attr, hint, &val);
  1052. }
  1053. }
  1054. /* linked_attrs_compare()
  1055. *
  1056. * Compare two attr values using the DN syntax.
  1057. */
  1058. int
  1059. linked_attrs_compare(const void *a, const void *b)
  1060. {
  1061. Slapi_Value *val1;
  1062. Slapi_Value *val2;
  1063. Slapi_Attr *linkattr;
  1064. int rc = 0;
  1065. if(a == NULL && b != NULL){
  1066. return 1;
  1067. } else if(a != NULL && b == NULL){
  1068. return -1;
  1069. } else if(a == NULL && b == NULL){
  1070. return 0;
  1071. }
  1072. val1 = *((Slapi_Value **)a);
  1073. val2 = *((Slapi_Value **)b);
  1074. linkattr = slapi_attr_new();
  1075. slapi_attr_init(linkattr, "distinguishedName");
  1076. rc = slapi_attr_value_cmp(linkattr,
  1077. slapi_value_get_berval(val1),
  1078. slapi_value_get_berval(val2));
  1079. slapi_attr_free(&linkattr);
  1080. return rc;
  1081. }
  1082. /*
  1083. * linked_attrs_add_backpointers()
  1084. *
  1085. * Adds backpointers pointing to dn to the entries referred to
  1086. * by the values in smod.
  1087. */
  1088. static int
  1089. linked_attrs_add_backpointers(char *linkdn, struct configEntry *config,
  1090. Slapi_Mod *smod)
  1091. {
  1092. Slapi_ValueSet *vals = slapi_valueset_new();
  1093. int rc = LDAP_SUCCESS;
  1094. slapi_valueset_set_from_smod(vals, smod);
  1095. rc = linked_attrs_mod_backpointers(linkdn, config->managedtype, config->scope,
  1096. LDAP_MOD_ADD, vals);
  1097. slapi_valueset_free(vals);
  1098. return rc;
  1099. }
  1100. /*
  1101. * linked_attrs_del_backpointers()
  1102. *
  1103. * Remove backpointers pointing to linkdn in the entries referred
  1104. * to by the values in smod.
  1105. */
  1106. static int
  1107. linked_attrs_del_backpointers(Slapi_PBlock *pb, char *linkdn,
  1108. struct configEntry *config, Slapi_Mod *smod)
  1109. {
  1110. Slapi_ValueSet *vals = NULL;
  1111. int rc = LDAP_SUCCESS;
  1112. /* If no values are listed in the smod, we need to get
  1113. * a list of all of the values that were deleted by
  1114. * looking at the pre-op copy of the entry. */
  1115. if (slapi_mod_get_num_values(smod) == 0) {
  1116. Slapi_Entry *pre_e = NULL;
  1117. Slapi_Attr *pre_attr = NULL;
  1118. slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &pre_e );
  1119. slapi_entry_attr_find( pre_e, config->linktype, &pre_attr );
  1120. slapi_attr_get_valueset(pre_attr, &vals);
  1121. } else {
  1122. vals = slapi_valueset_new();
  1123. slapi_valueset_set_from_smod(vals, smod);
  1124. }
  1125. rc = linked_attrs_mod_backpointers(linkdn, config->managedtype, config->scope,
  1126. LDAP_MOD_DELETE, vals);
  1127. slapi_valueset_free(vals);
  1128. return rc;
  1129. }
  1130. /*
  1131. * linked_attrs_replace_backpointers()
  1132. *
  1133. * Remove backpointers pointing to linkdn from the entries
  1134. * whose values were deleted in smod and add backpointers
  1135. * for any new values that were added as a part of the
  1136. * replace operation.
  1137. */
  1138. static int
  1139. linked_attrs_replace_backpointers(Slapi_PBlock *pb, char *linkdn,
  1140. struct configEntry *config, Slapi_Mod *smod)
  1141. {
  1142. Slapi_Entry *pre_e = NULL;
  1143. Slapi_Entry *post_e = NULL;
  1144. Slapi_Attr *pre_attr = 0;
  1145. Slapi_Attr *post_attr = 0;
  1146. int rc = LDAP_SUCCESS;
  1147. /* Get the pre and post copy of the entry to see
  1148. * what values have been added and removed. */
  1149. slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &pre_e);
  1150. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &post_e);
  1151. if(pre_e && post_e) {
  1152. slapi_entry_attr_find(pre_e, config->linktype, &pre_attr);
  1153. slapi_entry_attr_find(post_e, config->linktype, &post_attr);
  1154. }
  1155. if(pre_attr || post_attr) {
  1156. int pre_total = 0;
  1157. int post_total = 0;
  1158. Slapi_Value **pre_array = 0;
  1159. Slapi_Value **post_array = 0;
  1160. int pre_index = 0;
  1161. int post_index = 0;
  1162. Slapi_ValueSet *addvals = NULL;
  1163. Slapi_ValueSet *delvals = NULL;
  1164. /* create arrays of values */
  1165. if(pre_attr) {
  1166. slapi_attr_get_numvalues(pre_attr, &pre_total);
  1167. }
  1168. if(post_attr) {
  1169. slapi_attr_get_numvalues(post_attr, &post_total);
  1170. }
  1171. if(pre_total) {
  1172. pre_array = (Slapi_Value**) slapi_ch_malloc(sizeof(Slapi_Value*)*pre_total);
  1173. linked_attrs_load_array(pre_array, pre_attr);
  1174. qsort(pre_array, pre_total, sizeof(Slapi_Value*), linked_attrs_compare);
  1175. }
  1176. if(post_total) {
  1177. post_array = (Slapi_Value**) slapi_ch_malloc(sizeof(Slapi_Value*)*post_total);
  1178. linked_attrs_load_array(post_array, post_attr);
  1179. qsort(post_array, post_total, sizeof(Slapi_Value*), linked_attrs_compare);
  1180. }
  1181. /* Work through arrays, following these rules:
  1182. * - in pre, in post, do nothing
  1183. * - in pre, not in post, delete from entry
  1184. * - not in pre, in post, add to entry
  1185. */
  1186. while(pre_index < pre_total || post_index < post_total) {
  1187. if(pre_index == pre_total) {
  1188. /* add the rest of post */
  1189. if (addvals == NULL) {
  1190. addvals = slapi_valueset_new();
  1191. }
  1192. slapi_valueset_add_value(addvals, post_array[post_index]);
  1193. post_index++;
  1194. } else if(post_index == post_total) {
  1195. /* delete the rest of pre */
  1196. if (delvals == NULL) {
  1197. delvals = slapi_valueset_new();
  1198. }
  1199. slapi_valueset_add_value(delvals, pre_array[pre_index]);
  1200. pre_index++;
  1201. } else {
  1202. /* decide what to do */
  1203. int cmp = linked_attrs_compare(&(pre_array[pre_index]),
  1204. &(post_array[post_index]));
  1205. if(cmp < 0) {
  1206. /* delete pre array */
  1207. if (delvals == NULL) {
  1208. delvals = slapi_valueset_new();
  1209. }
  1210. slapi_valueset_add_value(delvals, pre_array[pre_index]);
  1211. pre_index++;
  1212. } else if(cmp > 0) {
  1213. /* add post array */
  1214. if (addvals == NULL) {
  1215. addvals = slapi_valueset_new();
  1216. }
  1217. slapi_valueset_add_value(addvals, post_array[post_index]);
  1218. post_index++;
  1219. } else {
  1220. /* do nothing, advance */
  1221. pre_index++;
  1222. post_index++;
  1223. }
  1224. }
  1225. }
  1226. /* Perform the actual updates to the target entries. */
  1227. if (delvals) {
  1228. rc = linked_attrs_mod_backpointers(linkdn, config->managedtype,
  1229. config->scope, LDAP_MOD_DELETE, delvals);
  1230. slapi_valueset_free(delvals);
  1231. }
  1232. if (rc == LDAP_SUCCESS && addvals) {
  1233. rc = linked_attrs_mod_backpointers(linkdn, config->managedtype,
  1234. config->scope, LDAP_MOD_ADD, addvals);
  1235. slapi_valueset_free(addvals);
  1236. }
  1237. slapi_ch_free((void **)&pre_array);
  1238. slapi_ch_free((void **)&post_array);
  1239. }
  1240. return rc;
  1241. }
  1242. /*
  1243. * linked_attrs_mod_backpointers()
  1244. *
  1245. * Performs backpointer management.
  1246. */
  1247. static int
  1248. linked_attrs_mod_backpointers(char *linkdn, char *type,
  1249. char *scope, int modop, Slapi_ValueSet *targetvals)
  1250. {
  1251. char *val[2];
  1252. int i = 0;
  1253. Slapi_PBlock *mod_pb = slapi_pblock_new();
  1254. LDAPMod mod;
  1255. LDAPMod *mods[2];
  1256. Slapi_Value *targetval = NULL;
  1257. int rc = LDAP_SUCCESS;
  1258. /* Setup the modify operation. Only the target will
  1259. * change, so we only need to do this once. */
  1260. val[0] = linkdn;
  1261. val[1] = 0;
  1262. mod.mod_op = modop;
  1263. mod.mod_type = type;
  1264. mod.mod_values = val;
  1265. mods[0] = &mod;
  1266. mods[1] = 0;
  1267. i = slapi_valueset_first_value(targetvals, &targetval);
  1268. while(targetval)
  1269. {
  1270. int perform_update = 0;
  1271. const char *targetdn = slapi_value_get_string(targetval);
  1272. Slapi_DN *targetsdn = slapi_sdn_new_dn_byref(targetdn);
  1273. /* If we have a scope, only update the target if it is within
  1274. * the scope. If we don't have a scope, only update the target
  1275. * if it is in the same backend as the linkdn. */
  1276. if (scope) {
  1277. perform_update = slapi_dn_issuffix(targetdn, scope);
  1278. } else {
  1279. Slapi_Backend *be = NULL;
  1280. Slapi_DN *linksdn = slapi_sdn_new_normdn_byref(linkdn);
  1281. if ((be = slapi_be_select(linksdn))) {
  1282. perform_update = slapi_sdn_issuffix(targetsdn, slapi_be_getsuffix(be, 0));
  1283. }
  1284. slapi_sdn_free(&linksdn);
  1285. }
  1286. if (perform_update) {
  1287. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1288. "%s backpointer (%s) in entry (%s)\n",
  1289. (modop == LDAP_MOD_ADD) ? "Adding" : "Removing",
  1290. linkdn, targetdn);
  1291. /* Perform the modify operation. */
  1292. slapi_modify_internal_set_pb_ext(mod_pb, targetsdn, mods, 0, 0,
  1293. linked_attrs_get_plugin_id(), 0);
  1294. slapi_modify_internal_pb(mod_pb);
  1295. if (strict_results){
  1296. /* we are enforcing strict results, so return the error */
  1297. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1298. if(rc != LDAP_SUCCESS){
  1299. slapi_sdn_free(&targetsdn);
  1300. break;
  1301. }
  1302. }
  1303. /* Initialize the pblock so we can reuse it. */
  1304. slapi_pblock_init(mod_pb);
  1305. }
  1306. slapi_sdn_free(&targetsdn);
  1307. i = slapi_valueset_next_value(targetvals, i, &targetval);
  1308. }
  1309. slapi_pblock_destroy(mod_pb);
  1310. return rc;
  1311. }
  1312. /*
  1313. * Operation callback functions
  1314. */
  1315. /*
  1316. * linked_attrs_pre_op()
  1317. *
  1318. * Checks if an operation is modifying the linked
  1319. * attribute config and validates the config changes.
  1320. */
  1321. static int
  1322. linked_attrs_pre_op(Slapi_PBlock * pb, int modop)
  1323. {
  1324. char *dn = 0;
  1325. Slapi_Entry *e = 0;
  1326. LDAPMod **mods = NULL;
  1327. int free_entry = 0;
  1328. char *errstr = NULL;
  1329. int ret = SLAPI_PLUGIN_SUCCESS;
  1330. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1331. "--> linked_attrs_pre_op\n");
  1332. if (0 == (dn = linked_attrs_get_dn(pb)))
  1333. goto bail;
  1334. if (linked_attrs_dn_is_config(dn)) {
  1335. /* Validate config changes, but don't apply them.
  1336. * This allows us to reject invalid config changes
  1337. * here at the pre-op stage. Applying the config
  1338. * needs to be done at the post-op stage. */
  1339. if (LDAP_CHANGETYPE_ADD == modop) {
  1340. slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
  1341. } else {
  1342. /* Fetch the entry being modified so we can
  1343. * create the resulting entry for validation. */
  1344. /* int free_sdn = 0; */
  1345. Slapi_DN *tmp_dn = linked_attrs_get_sdn(pb);
  1346. if (tmp_dn) {
  1347. slapi_search_internal_get_entry(tmp_dn, 0, &e, linked_attrs_get_plugin_id());
  1348. free_entry = 1;
  1349. }
  1350. /* If the entry doesn't exist, just bail and
  1351. * let the server handle it. */
  1352. if (e == NULL) {
  1353. goto bail;
  1354. }
  1355. /* Grab the mods. */
  1356. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1357. /* Apply the mods to create the resulting entry. */
  1358. if (mods && (slapi_entry_apply_mods(e, mods) != LDAP_SUCCESS)) {
  1359. /* The mods don't apply cleanly, so we just let this op go
  1360. * to let the main server handle it. */
  1361. goto bail;
  1362. }
  1363. }
  1364. if (linked_attrs_parse_config_entry(e, 0) != 0) {
  1365. /* Refuse the operation if config parsing failed. */
  1366. ret = LDAP_UNWILLING_TO_PERFORM;
  1367. if (LDAP_CHANGETYPE_ADD == modop) {
  1368. errstr = slapi_ch_smprintf("Not a valid linked attribute configuration entry.");
  1369. } else {
  1370. errstr = slapi_ch_smprintf("Changes result in an invalid "
  1371. "linked attribute configuration.");
  1372. }
  1373. }
  1374. }
  1375. bail:
  1376. if (free_entry && e)
  1377. slapi_entry_free(e);
  1378. if (ret) {
  1379. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1380. "linked_attrs_pre_op: operation failure [%d]\n", ret);
  1381. slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL);
  1382. slapi_ch_free((void **)&errstr);
  1383. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
  1384. ret = SLAPI_PLUGIN_FAILURE;
  1385. }
  1386. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1387. "<-- linked_attrs_pre_op\n");
  1388. return ret;
  1389. }
  1390. static int
  1391. linked_attrs_add_pre_op(Slapi_PBlock * pb)
  1392. {
  1393. return linked_attrs_pre_op(pb, LDAP_CHANGETYPE_ADD);
  1394. }
  1395. static int
  1396. linked_attrs_mod_pre_op(Slapi_PBlock * pb)
  1397. {
  1398. return linked_attrs_pre_op(pb, LDAP_CHANGETYPE_MODIFY);
  1399. }
  1400. static int
  1401. linked_attrs_mod_post_op(Slapi_PBlock *pb)
  1402. {
  1403. Slapi_Mods *smods = NULL;
  1404. Slapi_Mod *smod = NULL;
  1405. LDAPMod **mods;
  1406. Slapi_Mod *next_mod = NULL;
  1407. char *dn = NULL;
  1408. struct configEntry *config = NULL;
  1409. void *caller_id = NULL;
  1410. int rc = SLAPI_PLUGIN_SUCCESS;
  1411. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1412. "--> linked_attrs_mod_post_op\n");
  1413. /* We don't want to process internal modify
  1414. * operations that originate from this plugin.
  1415. * Doing so could cause a deadlock. */
  1416. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &caller_id);
  1417. if (caller_id == linked_attrs_get_plugin_id()) {
  1418. /* Just return without processing */
  1419. return SLAPI_PLUGIN_SUCCESS;
  1420. }
  1421. if (linked_attrs_oktodo(pb) &&
  1422. (dn = linked_attrs_get_dn(pb))) {
  1423. /* First check if the config is being modified. */
  1424. if (linked_attrs_dn_is_config(dn)) {
  1425. linked_attrs_load_config();
  1426. }
  1427. /* get the mod set */
  1428. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1429. smods = slapi_mods_new();
  1430. slapi_mods_init_byref(smods, mods);
  1431. next_mod = slapi_mod_new();
  1432. smod = slapi_mods_get_first_smod(smods, next_mod);
  1433. while(smod) {
  1434. char *type = (char *)slapi_mod_get_type(smod);
  1435. /* See if there is an applicable link configured. */
  1436. linked_attrs_read_lock();
  1437. /* Bail out if the plug-in close function was just called. */
  1438. if (!slapi_plugin_running(pb)) {
  1439. linked_attrs_unlock();
  1440. return SLAPI_PLUGIN_SUCCESS;
  1441. }
  1442. linked_attrs_find_config(dn, type, &config);
  1443. /* If we have a matching config entry, we have
  1444. * work to do. If not, we can go to the next smod. */
  1445. if (config) {
  1446. int op = slapi_mod_get_operation(smod);
  1447. /* Prevent other threads from managing
  1448. * this specific link at the same time. */
  1449. slapi_lock_mutex(config->lock);
  1450. switch(op & ~LDAP_MOD_BVALUES) {
  1451. case LDAP_MOD_ADD:
  1452. /* Find the entries pointed to by the new
  1453. * values and add the backpointers. */
  1454. rc = linked_attrs_add_backpointers(dn, config, smod);
  1455. break;
  1456. case LDAP_MOD_DELETE:
  1457. /* Find the entries pointed to by the deleted
  1458. * values and remove the backpointers. */
  1459. rc = linked_attrs_del_backpointers(pb, dn, config, smod);
  1460. break;
  1461. case LDAP_MOD_REPLACE:
  1462. /* Find the entries pointed to by the deleted
  1463. * values and remove the backpointers. If
  1464. * any new values are being added, find those
  1465. * entries and add the backpointers. */
  1466. rc = linked_attrs_replace_backpointers(pb, dn, config, smod);
  1467. break;
  1468. default:
  1469. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1470. "linked_attrs_mod_post_op: unknown mod type\n" );
  1471. rc = SLAPI_PLUGIN_FAILURE;
  1472. break;
  1473. }
  1474. slapi_unlock_mutex(config->lock);
  1475. if(rc != LDAP_SUCCESS){
  1476. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1477. "linked_attrs_mod_post_op - update failed (%d)\n",rc);
  1478. linked_attrs_unlock();
  1479. slapi_mod_done(next_mod);
  1480. break;
  1481. }
  1482. }
  1483. config = NULL;
  1484. linked_attrs_unlock();
  1485. slapi_mod_done(next_mod);
  1486. smod = slapi_mods_get_next_smod(smods, next_mod);
  1487. }
  1488. slapi_mod_free(&next_mod);
  1489. slapi_mods_free(&smods);
  1490. }
  1491. if (rc) {
  1492. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
  1493. rc = SLAPI_PLUGIN_FAILURE;
  1494. }
  1495. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1496. "<-- linked_attrs_mod_post_op (%d)\n", rc);
  1497. return rc;
  1498. }
  1499. static int
  1500. linked_attrs_add_post_op(Slapi_PBlock *pb)
  1501. {
  1502. Slapi_Entry *e = NULL;
  1503. char *dn = NULL;
  1504. int rc = SLAPI_PLUGIN_SUCCESS;
  1505. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1506. "--> linked_attrs_add_post_op\n");
  1507. /* Reload config if a config entry was added. */
  1508. if ((dn = linked_attrs_get_dn(pb))) {
  1509. if (linked_attrs_dn_is_config(dn))
  1510. linked_attrs_load_config();
  1511. } else {
  1512. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1513. "linked_attrs_add_post_op: Error "
  1514. "retrieving dn\n");
  1515. }
  1516. /* Get the newly added entry. */
  1517. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
  1518. if (e) {
  1519. Slapi_Attr *attr = NULL;
  1520. char *type = NULL;
  1521. struct configEntry *config = NULL;
  1522. slapi_entry_first_attr(e, &attr);
  1523. while (attr) {
  1524. slapi_attr_get_type(attr, &type);
  1525. /* See if there is an applicable link configured. */
  1526. linked_attrs_read_lock();
  1527. /* Bail out if the plug-in close function was just called. */
  1528. if (!slapi_plugin_running(pb)) {
  1529. linked_attrs_unlock();
  1530. return SLAPI_PLUGIN_SUCCESS;
  1531. }
  1532. linked_attrs_find_config(dn, type, &config);
  1533. /* If config was found, add the backpointers to this entry. */
  1534. if (config) {
  1535. Slapi_ValueSet *vals = NULL;
  1536. slapi_attr_get_valueset(attr, &vals);
  1537. slapi_lock_mutex(config->lock);
  1538. rc = linked_attrs_mod_backpointers(dn, config->managedtype,
  1539. config->scope, LDAP_MOD_ADD, vals);
  1540. slapi_unlock_mutex(config->lock);
  1541. slapi_valueset_free(vals);
  1542. if(rc != LDAP_SUCCESS){
  1543. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1544. "linked_attrs_add_post_op: update failed (%d)\n",rc);
  1545. linked_attrs_unlock();
  1546. break;
  1547. }
  1548. }
  1549. config = NULL;
  1550. linked_attrs_unlock();
  1551. slapi_entry_next_attr(e, attr, &attr);
  1552. }
  1553. } else {
  1554. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1555. "linked_attrs_add_post_op: Error "
  1556. "retrieving post-op entry %s\n", dn);
  1557. }
  1558. if (rc) {
  1559. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
  1560. rc = SLAPI_PLUGIN_FAILURE;
  1561. }
  1562. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1563. "<-- linked_attrs_add_post_op\n");
  1564. return rc;
  1565. }
  1566. static int
  1567. linked_attrs_del_post_op(Slapi_PBlock *pb)
  1568. {
  1569. char *dn = NULL;
  1570. Slapi_Entry *e = NULL;
  1571. int rc = SLAPI_PLUGIN_SUCCESS;
  1572. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1573. "--> linked_attrs_del_post_op\n");
  1574. /* Just bail if we aren't ready to service requests yet. */
  1575. if (!linked_attrs_oktodo(pb)){
  1576. return rc;
  1577. }
  1578. /* Reload config if a config entry was deleted. */
  1579. if ((dn = linked_attrs_get_dn(pb))) {
  1580. if (linked_attrs_dn_is_config(dn))
  1581. linked_attrs_load_config();
  1582. } else {
  1583. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1584. "linked_attrs_del_post_op: Error "
  1585. "retrieving dn\n");
  1586. }
  1587. /* Get deleted entry, then go through types to find config. */
  1588. slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &e );
  1589. if (e) {
  1590. Slapi_Attr *attr = NULL;
  1591. char *type = NULL;
  1592. struct configEntry *config = NULL;
  1593. slapi_entry_first_attr(e, &attr);
  1594. while (attr) {
  1595. slapi_attr_get_type(attr, &type);
  1596. /* See if there is an applicable link configured. */
  1597. linked_attrs_read_lock();
  1598. /* Bail out if the plug-in close function was just called. */
  1599. if (!slapi_plugin_running(pb)) {
  1600. linked_attrs_unlock();
  1601. return rc;
  1602. }
  1603. linked_attrs_find_config(dn, type, &config);
  1604. /* If config was found, delete the backpointers to this entry. */
  1605. if (config) {
  1606. Slapi_ValueSet *vals = NULL;
  1607. slapi_attr_get_valueset(attr, &vals);
  1608. slapi_lock_mutex(config->lock);
  1609. rc = linked_attrs_mod_backpointers(dn, config->managedtype,
  1610. config->scope, LDAP_MOD_DELETE, vals);
  1611. slapi_unlock_mutex(config->lock);
  1612. slapi_valueset_free(vals);
  1613. if (rc != LDAP_SUCCESS){
  1614. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1615. "linked_attrs_del_post_op - update failed (%d)\n",rc);
  1616. linked_attrs_unlock();
  1617. break;
  1618. }
  1619. }
  1620. config = NULL;
  1621. /* See if any of the values for this attribute are managed
  1622. * backpointers. We need to remove the forward link if so. */
  1623. if (linked_attrs_config_index_has_type(type)) {
  1624. int hint = 0;
  1625. Slapi_Value *val = NULL;
  1626. /* Loop through values and see if we have matching config */
  1627. hint = slapi_attr_first_value(attr, &val);
  1628. while (val) {
  1629. linked_attrs_find_config_reverse(slapi_value_get_string(val),
  1630. type, &config);
  1631. if (config) {
  1632. Slapi_ValueSet *vals = slapi_valueset_new();
  1633. slapi_valueset_add_value(vals, val);
  1634. slapi_lock_mutex(config->lock);
  1635. /* Delete forward link value. */
  1636. rc = linked_attrs_mod_backpointers(dn, config->linktype,
  1637. config->scope, LDAP_MOD_DELETE, vals);
  1638. slapi_unlock_mutex(config->lock);
  1639. slapi_valueset_free(vals);
  1640. config = NULL;
  1641. if(rc != LDAP_SUCCESS){
  1642. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1643. "linked_attrs_del_post_op: update failed (%d)\n",rc);
  1644. linked_attrs_unlock();
  1645. goto bail;
  1646. }
  1647. }
  1648. hint = slapi_attr_next_value(attr, hint, &val);
  1649. }
  1650. }
  1651. linked_attrs_unlock();
  1652. slapi_entry_next_attr(e, attr, &attr);
  1653. }
  1654. } else {
  1655. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1656. "linked_attrs_del_post_op: Error "
  1657. "retrieving pre-op entry %s\n", dn);
  1658. rc = SLAPI_PLUGIN_FAILURE;
  1659. }
  1660. bail:
  1661. if (rc) {
  1662. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
  1663. rc = SLAPI_PLUGIN_FAILURE;
  1664. }
  1665. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1666. "<-- linked_attrs_del_post_op\n");
  1667. return rc;
  1668. }
  1669. static int
  1670. linked_attrs_modrdn_post_op(Slapi_PBlock *pb)
  1671. {
  1672. char *old_dn = NULL;
  1673. char *new_dn = NULL;
  1674. Slapi_Entry *post_e = NULL;
  1675. Slapi_Attr *attr = NULL;
  1676. char *type = NULL;
  1677. struct configEntry *config = NULL;
  1678. int rc = SLAPI_PLUGIN_SUCCESS;
  1679. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1680. "--> linked_attrs_modrdn_post_op\n");
  1681. /* Just bail if we aren't ready to service requests yet. */
  1682. if (!linked_attrs_oktodo(pb)) {
  1683. goto done;
  1684. }
  1685. /* Reload config if an existing config entry was renamed,
  1686. * or if the new dn brings an entry into the scope of the
  1687. * config entries. */
  1688. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &post_e);
  1689. if (post_e) {
  1690. new_dn = slapi_entry_get_ndn(post_e);
  1691. } else {
  1692. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1693. "linked_attrs_modrdn_post_op: Error "
  1694. "retrieving post-op entry\n");
  1695. rc = LDAP_OPERATIONS_ERROR;
  1696. goto done;
  1697. }
  1698. if ((old_dn = linked_attrs_get_dn(pb))) {
  1699. if (linked_attrs_dn_is_config(old_dn) || linked_attrs_dn_is_config(new_dn))
  1700. linked_attrs_load_config();
  1701. } else {
  1702. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1703. "linked_attrs_modrdn_post_op: Error "
  1704. "retrieving dn\n");
  1705. rc = LDAP_OPERATIONS_ERROR;
  1706. goto done;
  1707. }
  1708. /* Check if this operation requires any updates to links. */
  1709. slapi_entry_first_attr(post_e, &attr);
  1710. while (attr) {
  1711. slapi_attr_get_type(attr, &type);
  1712. /* See if there is an applicable link configured. */
  1713. linked_attrs_read_lock();
  1714. /* Bail out if the plug-in close function was just called. */
  1715. if (!slapi_plugin_running(pb)) {
  1716. linked_attrs_unlock();
  1717. return SLAPI_PLUGIN_SUCCESS;
  1718. }
  1719. linked_attrs_find_config(old_dn, type, &config);
  1720. /* If config was found for the old dn, delete the backpointers
  1721. * to this entry. */
  1722. if (config) {
  1723. Slapi_ValueSet *vals = NULL;
  1724. slapi_attr_get_valueset(attr, &vals);
  1725. slapi_lock_mutex(config->lock);
  1726. /* Delete old dn value. */
  1727. rc = linked_attrs_mod_backpointers(old_dn, config->managedtype,
  1728. config->scope, LDAP_MOD_DELETE, vals);
  1729. slapi_unlock_mutex(config->lock);
  1730. slapi_valueset_free(vals);
  1731. config = NULL;
  1732. if(rc != LDAP_SUCCESS){
  1733. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1734. "linked_attrs_modrdn_post_op: update failed(old type) (%d)\n",rc);
  1735. linked_attrs_unlock();
  1736. break;
  1737. }
  1738. }
  1739. linked_attrs_find_config(new_dn, type, &config);
  1740. /* If config was found for the new dn, add the backpointers
  1741. * to this entry. We do this separate check for both dn's
  1742. * to catch an entry that comes into or goes out of scope
  1743. * from the MODRDN operation. */
  1744. if (config) {
  1745. Slapi_ValueSet *vals = NULL;
  1746. slapi_attr_get_valueset(attr, &vals);
  1747. slapi_lock_mutex(config->lock);
  1748. /* Add new dn value. */
  1749. rc = linked_attrs_mod_backpointers(new_dn, config->managedtype,
  1750. config->scope, LDAP_MOD_ADD, vals);
  1751. slapi_unlock_mutex(config->lock);
  1752. slapi_valueset_free(vals);
  1753. config = NULL;
  1754. if(rc != LDAP_SUCCESS){
  1755. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1756. "linked_attrs_modrdn_post_op: update failed(new type) (%d)\n",rc);
  1757. linked_attrs_unlock();
  1758. break;
  1759. }
  1760. }
  1761. /* See if any of the values for this attribute are managed
  1762. * backpointers. We need to update the forward link if so. */
  1763. if (linked_attrs_config_index_has_type(type)) {
  1764. int hint = 0;
  1765. Slapi_Value *val = NULL;
  1766. /* Loop through values and see if we have matching config */
  1767. hint = slapi_attr_first_value(attr, &val);
  1768. while (val) {
  1769. linked_attrs_find_config_reverse(slapi_value_get_string(val),
  1770. type, &config);
  1771. /* If the new DN is within scope, we should fixup the forward links. */
  1772. if (config && slapi_dn_issuffix(new_dn, (config->scope))) {
  1773. Slapi_ValueSet *vals = slapi_valueset_new();
  1774. slapi_valueset_add_value(vals, val);
  1775. slapi_lock_mutex(config->lock);
  1776. /* Delete old dn value. */
  1777. rc = linked_attrs_mod_backpointers(old_dn, config->linktype,
  1778. config->scope, LDAP_MOD_DELETE, vals);
  1779. if(rc != LDAP_SUCCESS){
  1780. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1781. "linked_attrs_modrdn_post_op: update failed(old dn) (%d)\n",rc);
  1782. slapi_unlock_mutex(config->lock);
  1783. slapi_valueset_free(vals);
  1784. linked_attrs_unlock();
  1785. goto done;
  1786. }
  1787. /* Add new dn value. */
  1788. rc = linked_attrs_mod_backpointers(new_dn, config->linktype,
  1789. config->scope, LDAP_MOD_ADD, vals);
  1790. slapi_unlock_mutex(config->lock);
  1791. slapi_valueset_free(vals);
  1792. config = NULL;
  1793. if(rc != LDAP_SUCCESS){
  1794. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1795. "linked_attrs_modrdn_post_op: update failed(new dn) (%d)\n",rc);
  1796. linked_attrs_unlock();
  1797. goto done;
  1798. }
  1799. }
  1800. hint = slapi_attr_next_value(attr, hint, &val);
  1801. }
  1802. }
  1803. linked_attrs_unlock();
  1804. slapi_entry_next_attr(post_e, attr, &attr);
  1805. }
  1806. done:
  1807. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1808. "<-- linked_attrs_modrdn_post_op\n");
  1809. if (rc) {
  1810. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
  1811. rc = SLAPI_PLUGIN_FAILURE;
  1812. }
  1813. return rc;
  1814. }
  1815. /*
  1816. * Debug functions to print config
  1817. */
  1818. void
  1819. linked_attrs_dump_config()
  1820. {
  1821. PRCList *list;
  1822. linked_attrs_read_lock();
  1823. if (!PR_CLIST_IS_EMPTY(g_link_config)) {
  1824. list = PR_LIST_HEAD(g_link_config);
  1825. while (list != g_link_config) {
  1826. linked_attrs_dump_config_entry((struct configEntry *)list);
  1827. list = PR_NEXT_LINK(list);
  1828. }
  1829. }
  1830. linked_attrs_unlock();
  1831. }
  1832. void
  1833. linked_attrs_dump_config_index()
  1834. {
  1835. PRCList *list;
  1836. linked_attrs_read_lock();
  1837. if (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  1838. list = PR_LIST_HEAD(g_managed_config_index);
  1839. while (list != g_managed_config_index) {
  1840. linked_attrs_dump_config_entry(((struct configIndex *)list)->config);
  1841. list = PR_NEXT_LINK(list);
  1842. }
  1843. }
  1844. linked_attrs_unlock();
  1845. }
  1846. void
  1847. linked_attrs_dump_config_entry(struct configEntry * entry)
  1848. {
  1849. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1850. "<==== Linked Attribute Pair =====>\n");
  1851. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1852. "<---- config entry dn -----> %s\n", entry->dn);
  1853. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1854. "<---- link type -----------> %s\n", entry->linktype);
  1855. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1856. "<---- managed type --------> %s\n", entry->managedtype);
  1857. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1858. "<---- scope ---------------> %s\n", entry->scope);
  1859. }