linked_attrs.c 72 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180
  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. linked_attrs_delete_config();
  339. slapi_destroy_rwlock(g_config_lock);
  340. g_config_lock = NULL;
  341. slapi_ch_free((void **)&g_link_config);
  342. slapi_ch_free((void **)&g_managed_config_index);
  343. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  344. "<-- linked_attrs_close\n");
  345. return 0;
  346. }
  347. PRCList *
  348. linked_attrs_get_config()
  349. {
  350. return g_link_config;
  351. }
  352. /*
  353. * config looks like this
  354. * - cn=myplugin
  355. * --- cn=manager link
  356. * --- cn=owner link
  357. * --- cn=etc
  358. */
  359. static int
  360. linked_attrs_load_config()
  361. {
  362. int status = 0;
  363. int result;
  364. int i;
  365. Slapi_PBlock *search_pb;
  366. Slapi_Entry **entries = NULL;
  367. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  368. "--> linked_attrs_load_config\n");
  369. /* Clear out any old config. */
  370. linked_attrs_write_lock();
  371. linked_attrs_delete_config();
  372. /* Find the config entries beneath our plugin entry. */
  373. search_pb = slapi_pblock_new();
  374. slapi_search_internal_set_pb(search_pb, linked_attrs_get_plugin_dn(),
  375. LDAP_SCOPE_SUBTREE, "objectclass=*",
  376. NULL, 0, NULL, NULL, linked_attrs_get_plugin_id(), 0);
  377. slapi_search_internal_pb(search_pb);
  378. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
  379. if (LDAP_SUCCESS != result) {
  380. status = -1;
  381. goto cleanup;
  382. }
  383. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  384. &entries);
  385. if (NULL == entries || NULL == entries[0]) {
  386. /* If there are no config entries, we're done. */
  387. goto cleanup;
  388. }
  389. /* Loop through all of the entries we found and parse them. */
  390. for (i = 0; (entries[i] != NULL); i++) {
  391. /* We don't care about the status here because we may have
  392. * some invalid config entries, but we just want to continue
  393. * looking for valid ones. */
  394. linked_attrs_parse_config_entry(entries[i], 1);
  395. }
  396. cleanup:
  397. slapi_free_search_results_internal(search_pb);
  398. slapi_pblock_destroy(search_pb);
  399. linked_attrs_unlock();
  400. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  401. "<-- linked_attrs_load_config\n");
  402. return status;
  403. }
  404. /*
  405. * linked_attrs_parse_config_entry()
  406. *
  407. * Parses a single config entry. If apply is non-zero, then
  408. * we will load and start using the new config. You can simply
  409. * validate config without making any changes by setting apply
  410. * to 0.
  411. *
  412. * Returns 0 if the entry is valid and -1 if it is invalid.
  413. */
  414. static int
  415. linked_attrs_parse_config_entry(Slapi_Entry * e, int apply)
  416. {
  417. char *value;
  418. struct configEntry *entry = NULL;
  419. struct configEntry *config_entry;
  420. PRCList *list;
  421. int entry_added = 0;
  422. int ret = 0;
  423. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  424. "--> linked_attrs_parse_config_entry\n");
  425. /* If this is the main plug-in
  426. * config entry, just bail. */
  427. if (strcasecmp(linked_attrs_get_plugin_dn(), slapi_entry_get_ndn(e)) == 0) {
  428. ret = -1;
  429. goto bail;
  430. }
  431. entry = (struct configEntry *)slapi_ch_calloc(1, sizeof(struct configEntry));
  432. if (NULL == entry) {
  433. ret = -1;
  434. goto bail;
  435. }
  436. value = slapi_entry_get_ndn(e);
  437. if (value) {
  438. entry->dn = slapi_ch_strdup(value);
  439. } else {
  440. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  441. "linked_attrs_parse_config_entry: Error "
  442. "reading dn from config entry\n");
  443. ret = -1;
  444. goto bail;
  445. }
  446. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  447. "----------> dn [%s]\n", entry->dn);
  448. value = slapi_entry_attr_get_charptr(e, LINK_LINK_TYPE);
  449. if (value) {
  450. int not_dn_syntax = 0;
  451. char *syntaxoid = NULL;
  452. Slapi_Attr *attr = slapi_attr_new();
  453. /* Set this first so we free it if we encounter an error */
  454. entry->linktype = value;
  455. /* Gather some information about this attribute. */
  456. slapi_attr_init(attr, value);
  457. slapi_attr_get_syntax_oid_copy(attr, &syntaxoid );
  458. not_dn_syntax = strcmp(syntaxoid, DN_SYNTAX_OID);
  459. slapi_ch_free_string(&syntaxoid);
  460. slapi_attr_free(&attr);
  461. /* Check if the link type's syntax is Distinguished Name.
  462. * We only treat this as a warning. */
  463. if (not_dn_syntax) {
  464. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  465. "linked_attrs_parse_config_entry: The %s config "
  466. "setting must be set to an attribute with the "
  467. "Distinguished Name syntax for linked attribute "
  468. "pair \"%s\" attribute \"%s\".\n", LINK_LINK_TYPE, entry->dn, value);
  469. }
  470. } else {
  471. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  472. "linked_attrs_parse_config_entry: The %s config "
  473. "setting is required for linked attribute pair \"%s\".\n",
  474. LINK_LINK_TYPE, entry->dn);
  475. ret = -1;
  476. goto bail;
  477. }
  478. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  479. "----------> %s [%s]\n", LINK_LINK_TYPE, entry->linktype);
  480. value = slapi_entry_attr_get_charptr(e, LINK_MANAGED_TYPE);
  481. if (value) {
  482. int single_valued = 0;
  483. int not_dn_syntax = 0;
  484. char *syntaxoid = NULL;
  485. Slapi_Attr *attr = slapi_attr_new();
  486. /* Set this first so we free it if we encounter an error */
  487. entry->managedtype = value;
  488. /* Gather some information about this attribute. */
  489. slapi_attr_init(attr, value);
  490. slapi_attr_get_syntax_oid_copy(attr, &syntaxoid );
  491. not_dn_syntax = strcmp(syntaxoid, DN_SYNTAX_OID);
  492. single_valued = slapi_attr_flag_is_set(attr, SLAPI_ATTR_FLAG_SINGLE);
  493. slapi_ch_free_string(&syntaxoid);
  494. slapi_attr_free(&attr);
  495. /* Ensure that the managed type is a multi-valued attribute. */
  496. if (single_valued) {
  497. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  498. "linked_attrs_parse_config_entry: The %s config "
  499. "setting must be set to a multi-valued attribute "
  500. "for linked attribute pair \"%s\".\n",
  501. LINK_MANAGED_TYPE, entry->dn);
  502. ret = -1;
  503. goto bail;
  504. /* Check if the link type's syntax is Distinguished Name.
  505. * We only treat this as a warning. */
  506. } else if (not_dn_syntax) {
  507. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  508. "linked_attrs_parse_config_entry: The %s config "
  509. "setting must be set to an attribute with the "
  510. "Distinguished Name syntax for linked attribute "
  511. "pair \"%s\".\n", LINK_MANAGED_TYPE, entry->dn);
  512. }
  513. } else {
  514. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  515. "linked_attrs_parse_config_entry: The %s config "
  516. "setting is required for linked attribute pair \"%s\".\n",
  517. LINK_MANAGED_TYPE, entry->dn);
  518. ret = -1;
  519. goto bail;
  520. }
  521. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  522. "----------> %s [%s]\n", LINK_MANAGED_TYPE,
  523. entry->managedtype);
  524. /* A scope is not required. No scope means it
  525. * applies to any part of the DIT. */
  526. value = slapi_entry_attr_get_charptr(e, LINK_SCOPE);
  527. if (value) {
  528. entry->scope = value;
  529. }
  530. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  531. "----------> %s [%s]\n", LINK_SCOPE,
  532. entry->scope ? entry->scope : "NULL");
  533. /* Check if config already exists for
  534. * the link type at the same scope. */
  535. if (linked_attrs_config_exists(entry)) {
  536. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  537. "linked_attrs_parse_config_entry: A config "
  538. "entry for the link attribute %s already "
  539. "exists at a scope of \"%s\".\n", entry->linktype,
  540. entry->scope);
  541. ret = -1;
  542. goto bail;
  543. }
  544. /* Check if config already exists for
  545. * the managed type at the same scope. */
  546. if (linked_attrs_config_exists_reverse(entry)) {
  547. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  548. "linked_attrs_parse_config_entry: A config "
  549. "entry for the managed attribute %s already "
  550. "exists at a scope of \"%s\".\n", entry->managedtype,
  551. entry->scope);
  552. ret = -1;
  553. goto bail;
  554. }
  555. /* If we were only called to validate config, we can
  556. * just bail out before applying the config changes */
  557. if (apply == 0) {
  558. goto bail;
  559. }
  560. /* Create a lock for this attribute pair. */
  561. entry->lock = slapi_new_mutex();
  562. if (!entry->lock) {
  563. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  564. "linked_attrs_parse_config_entry: Unable to create "
  565. "lock for linked attribute pair \"%s\".\n", entry->dn);
  566. ret = -1;
  567. goto bail;
  568. }
  569. /* Add the entry to the list. We group by link type. We
  570. * also maintain a reverse list grouped by managed type. */
  571. if (!PR_CLIST_IS_EMPTY(g_link_config)) {
  572. list = PR_LIST_HEAD(g_link_config);
  573. while (list != g_link_config) {
  574. config_entry = (struct configEntry *) list;
  575. /* See if the types match. We want to group
  576. * entries for the same link type together. */
  577. if (slapi_attr_type_cmp(config_entry->linktype, entry->linktype, 1) == 0) {
  578. PR_INSERT_BEFORE(&(entry->list), list);
  579. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  580. "store [%s] before [%s] \n", entry->dn,
  581. config_entry->dn);
  582. /* add to managed type index */
  583. linked_attrs_insert_config_index(entry);
  584. entry_added = 1;
  585. break;
  586. }
  587. list = PR_NEXT_LINK(list);
  588. if (g_link_config == list) {
  589. /* add to tail */
  590. PR_INSERT_BEFORE(&(entry->list), list);
  591. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  592. "store [%s] at tail\n", entry->dn);
  593. /* add to managed type index */
  594. linked_attrs_insert_config_index(entry);
  595. entry_added = 1;
  596. break;
  597. }
  598. }
  599. } else {
  600. /* first entry */
  601. PR_INSERT_LINK(&(entry->list), g_link_config);
  602. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  603. "store [%s] at head \n", entry->dn);
  604. /* add to managed type index */
  605. linked_attrs_insert_config_index(entry);
  606. entry_added = 1;
  607. }
  608. bail:
  609. if (0 == entry_added) {
  610. /* Don't log error if we weren't asked to apply config */
  611. if ((apply != 0) && (entry != NULL)) {
  612. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  613. "linked_attrs_parse_config_entry: Invalid config entry "
  614. "[%s] skipped\n", entry->dn);
  615. }
  616. linked_attrs_free_config_entry(&entry);
  617. } else {
  618. ret = 0;
  619. }
  620. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  621. "<-- linked_attrs_parse_config_entry\n");
  622. return ret;
  623. }
  624. /*
  625. * linked_attrs_insert_config_index()
  626. *
  627. * Adds an entry to the ordered config index. We maintain
  628. * an list of pointers to the cached config entries that is
  629. * grouped by managed type. We use this index to find the
  630. * appropriate config entry when given a backpointer. This
  631. * is useful for the case where an entry with backpointers
  632. * is renamed and we need to updated the forward link.
  633. */
  634. static void
  635. linked_attrs_insert_config_index(struct configEntry *entry)
  636. {
  637. struct configEntry *config_entry = NULL;
  638. struct configIndex *index_entry = NULL;
  639. PRCList *list = PR_LIST_HEAD(g_managed_config_index);
  640. int inserted = 0;
  641. index_entry = (struct configIndex *)slapi_ch_calloc(1, sizeof(struct configIndex));
  642. index_entry->config = entry;
  643. if (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  644. while (list != g_managed_config_index) {
  645. config_entry = ((struct configIndex *)list)->config;
  646. /* See if the types match. */
  647. if (slapi_attr_type_cmp(config_entry->managedtype, entry->managedtype, 1) == 0) {
  648. PR_INSERT_BEFORE(&(index_entry->list), list);
  649. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  650. "store [%s] before [%s] \n", entry->dn,
  651. config_entry->dn);
  652. inserted = 1;
  653. break;
  654. }
  655. list = PR_NEXT_LINK(list);
  656. if (g_managed_config_index == list) {
  657. /* add to tail */
  658. PR_INSERT_BEFORE(&(index_entry->list), list);
  659. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  660. "store [%s] at tail\n", entry->dn);
  661. inserted = 1;
  662. break;
  663. }
  664. }
  665. } else {
  666. /* first entry */
  667. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  668. "store [%s] at head \n", entry->dn);
  669. PR_INSERT_LINK(&(index_entry->list), g_managed_config_index);
  670. inserted = 1;
  671. }
  672. if(!inserted){
  673. slapi_ch_free((void **)&index_entry);
  674. }
  675. }
  676. static void
  677. linked_attrs_free_config_entry(struct configEntry ** entry)
  678. {
  679. struct configEntry *e = *entry;
  680. if (e == NULL)
  681. return;
  682. if (e->dn) {
  683. slapi_log_error(SLAPI_LOG_CONFIG, LINK_PLUGIN_SUBSYSTEM,
  684. "freeing config entry [%s]\n", e->dn);
  685. slapi_ch_free_string(&e->dn);
  686. }
  687. if (e->linktype)
  688. slapi_ch_free_string(&e->linktype);
  689. if (e->managedtype)
  690. slapi_ch_free_string(&e->managedtype);
  691. if (e->scope)
  692. slapi_ch_free_string(&e->scope);
  693. if (e->lock)
  694. slapi_destroy_mutex(e->lock);
  695. slapi_ch_free((void **) entry);
  696. }
  697. static void
  698. linked_attrs_delete_configEntry(PRCList *entry)
  699. {
  700. PR_REMOVE_LINK(entry);
  701. linked_attrs_free_config_entry((struct configEntry **) &entry);
  702. }
  703. static void
  704. linked_attrs_delete_config()
  705. {
  706. PRCList *list;
  707. /* Delete the config cache. */
  708. while (!PR_CLIST_IS_EMPTY(g_link_config)) {
  709. list = PR_LIST_HEAD(g_link_config);
  710. linked_attrs_delete_configEntry(list);
  711. }
  712. /* Delete the reverse index. */
  713. while (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  714. list = PR_LIST_HEAD(g_managed_config_index);
  715. PR_REMOVE_LINK(list);
  716. slapi_ch_free((void **)&list);
  717. }
  718. return;
  719. }
  720. /*
  721. * Helper functions
  722. */
  723. static char *
  724. linked_attrs_get_dn(Slapi_PBlock * pb)
  725. {
  726. const char *dn = 0;
  727. Slapi_DN *sdn = NULL;
  728. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  729. "--> linked_attrs_get_dn\n");
  730. if (slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn)) {
  731. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  732. "linked_attrs_get_dn: failed to get dn of changed entry");
  733. goto bail;
  734. }
  735. dn = slapi_sdn_get_dn(sdn);
  736. bail:
  737. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  738. "<-- linked_attrs_get_dn\n");
  739. return (char *)dn;
  740. }
  741. static Slapi_DN *
  742. linked_attrs_get_sdn(Slapi_PBlock * pb)
  743. {
  744. Slapi_DN *sdn = 0;
  745. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  746. "--> linked_attrs_get_sdn\n");
  747. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
  748. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  749. "<-- linked_attrs_get_sdn\n");
  750. return sdn;
  751. }
  752. /*
  753. * linked_attrs_dn_is_config()
  754. *
  755. * Checks if dn is a linked attribute config entry.
  756. */
  757. static int
  758. linked_attrs_dn_is_config(char *dn)
  759. {
  760. int ret = 0;
  761. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  762. "--> linked_attrs_dn_is_config\n");
  763. /* Return 1 if the passed in dn is a child of the main
  764. * plugin config entry. */
  765. if (slapi_dn_issuffix(dn, linked_attrs_get_plugin_dn()) &&
  766. strcasecmp(dn, linked_attrs_get_plugin_dn())) {
  767. ret = 1;
  768. }
  769. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  770. "<-- linked_attrs_dn_is_config\n");
  771. return ret;
  772. }
  773. /*
  774. * linked_attrs_find_config()
  775. *
  776. * Finds the appropriate config entry for a given dn and
  777. * link type. A read lock must be held on the config
  778. * before calling this function. The configEntry that is
  779. * returned is a pointer to the actual config entry in
  780. * the config cache. It should not be modified in any
  781. * way. The read lock should not be released until you
  782. * are finished with the config entry that is returned.
  783. * Returns NULL if no applicable config entry is found.
  784. */
  785. static void
  786. linked_attrs_find_config(const char *dn,
  787. const char *type, struct configEntry **config)
  788. {
  789. int found_type = 0;
  790. PRCList *list = NULL;
  791. *config = NULL;
  792. if (!PR_CLIST_IS_EMPTY(g_link_config)) {
  793. list = PR_LIST_HEAD(g_link_config);
  794. while (list != g_link_config) {
  795. if (slapi_attr_type_cmp(((struct configEntry *)list)->linktype,
  796. type, 1) == 0) {
  797. /* Set a flag indicating that we found a config entry
  798. * for this type. We use this flag so we can stop
  799. * processing early if we don't find a matching scope. */
  800. found_type = 1;
  801. /* Check if the dn is in the scope of this config
  802. * entry. If the config entry doesn't have a scope
  803. * (global), consider it a match. If we have a match,
  804. * we can stop processing the config. */
  805. if ((((struct configEntry *)list)->scope == NULL) ||
  806. (slapi_dn_issuffix(dn, ((struct configEntry *)list)->scope))) {
  807. *config = (struct configEntry *)list;
  808. break;
  809. }
  810. } else {
  811. /* If flag is set, we're done. We have configured links
  812. * for this type, but none of the scopes match. */
  813. if (found_type) {
  814. break;
  815. }
  816. }
  817. list = PR_NEXT_LINK(list);
  818. }
  819. }
  820. }
  821. /*
  822. * linked_attrs_find_config_reverse()
  823. *
  824. * Finds the appropriate config entry for a given dn and
  825. * managed type. A read lock must be held on the config
  826. * before calling this function. The configEntry that is
  827. * returned is a pointer to the actual config entry in
  828. * the config cache. It should not be modified in any
  829. * way. The read lock should not be released until you
  830. * are finished with the config entry that is returned.
  831. * Returns NULL if no applicable config entry is found.
  832. */
  833. static void
  834. linked_attrs_find_config_reverse(const char *dn,
  835. const char *type, struct configEntry **config)
  836. {
  837. int found_type = 0;
  838. PRCList *list = NULL;
  839. *config = NULL;
  840. if (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  841. list = PR_LIST_HEAD(g_managed_config_index);
  842. while (list != g_managed_config_index) {
  843. if (slapi_attr_type_cmp(((struct configIndex *)list)->config->managedtype,
  844. type, 1) == 0) {
  845. /* Set a flag indicating that we found a config entry
  846. * for this type. We use this flag so we can stop
  847. * processing early if we don't find a matching scope. */
  848. found_type = 1;
  849. /* Check if the dn is in the scope of this config
  850. * entry. If the config entry doesn't have a scope
  851. * (global), consider it a match. If we have a match,
  852. * we can stop processing the config. */
  853. if ((((struct configIndex *)list)->config->scope == NULL) ||
  854. (slapi_dn_issuffix(dn, ((struct configIndex *)list)->config->scope))) {
  855. *config = ((struct configIndex *)list)->config;
  856. break;
  857. }
  858. } else {
  859. /* If flag is set, we're done. We have configured links
  860. * for this type, but none of the scopes match. */
  861. if (found_type) {
  862. break;
  863. }
  864. }
  865. list = PR_NEXT_LINK(list);
  866. }
  867. }
  868. }
  869. /*
  870. * linked_attrs_config_index_has_type()
  871. *
  872. * Returns 1 if a config entry exists with the passed
  873. * in managed type.
  874. *
  875. * A read lock on the config must be held before calling
  876. * this function.
  877. */
  878. static int
  879. linked_attrs_config_index_has_type(char *type)
  880. {
  881. int rc = 0;
  882. PRCList *list = NULL;
  883. if (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  884. list = PR_LIST_HEAD(g_managed_config_index);
  885. while (list != g_managed_config_index) {
  886. if (slapi_attr_type_cmp(((struct configIndex *)list)->config->managedtype,
  887. type, 1) == 0) {
  888. rc = 1;
  889. break;
  890. }
  891. list = PR_NEXT_LINK(list);
  892. }
  893. }
  894. return rc;
  895. }
  896. /*
  897. * linked_attrs_config_exists()
  898. *
  899. * Returns 1 if a config entry exists in the cache
  900. * already for the given link type at the given scope.
  901. * This will detect if the cached config entry is really
  902. * the same one as the passed in entry by comparing the
  903. * dn of the config entry. We will still return 0 in
  904. * this case as it's one and the same config entry. We
  905. * really want to use this to prevent multiple config
  906. * entries for the same link type at the same scope.
  907. *
  908. * A read lock on the config must be held before calling
  909. * this function.
  910. */
  911. static int
  912. linked_attrs_config_exists(struct configEntry *entry)
  913. {
  914. int rc = 0;
  915. int found_type = 0;
  916. PRCList *list = NULL;
  917. if (!PR_CLIST_IS_EMPTY(g_link_config)) {
  918. list = PR_LIST_HEAD(g_link_config);
  919. while (list != g_link_config) {
  920. if (slapi_attr_type_cmp(((struct configEntry *)list)->linktype,
  921. entry->linktype, 1) == 0) {
  922. found_type = 1;
  923. /* We don't allow nested config for the same type. We
  924. * need to check for nesting in both directions here.
  925. * If no scope is set, we consider the entry global. */
  926. if ((((struct configEntry *)list)->scope == NULL) ||
  927. slapi_dn_issuffix(entry->scope, ((struct configEntry *)list)->scope) ||
  928. slapi_dn_issuffix(((struct configEntry *)list)->scope, entry->scope)) {
  929. /* Make sure that this isn't the same exact entry
  930. * in the list already. This can happen if a config
  931. * entry is being modified. Both of these were already
  932. * normalized when the config struct was filled in. */
  933. if (strcasecmp(entry->dn, ((struct configEntry *)list)->dn) != 0) {
  934. rc = 1;
  935. break;
  936. }
  937. }
  938. } else {
  939. if (found_type) {
  940. /* Since the list is sorted by link type, we
  941. * are finished if we get here since we found
  942. * the type but didn't match the scope. */
  943. break;
  944. }
  945. }
  946. list = PR_NEXT_LINK(list);
  947. }
  948. }
  949. return rc;
  950. }
  951. /*
  952. * linked_attrs_config_exists_reverse()
  953. *
  954. * Returns 1 if a config entry exists in the cache
  955. * already for the given managed type at the given scope.
  956. * This will detect if the cached config entry is really
  957. * the same one as the passed in entry by comparing the
  958. * dn of the config entry. We will still return 0 in
  959. * this case as it's one and the same config entry. We
  960. * really want to use this to prevent multiple config
  961. * entries for the same managed type at the same scope.
  962. *
  963. * A read lock on the config must be held before calling
  964. * this function.
  965. */
  966. static int
  967. linked_attrs_config_exists_reverse(struct configEntry *entry)
  968. {
  969. int rc = 0;
  970. int found_type = 0;
  971. PRCList *list = NULL;
  972. if (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  973. list = PR_LIST_HEAD(g_managed_config_index);
  974. while (list != g_managed_config_index) {
  975. if (slapi_attr_type_cmp(((struct configIndex *)list)->config->managedtype,
  976. entry->managedtype, 1) == 0) {
  977. found_type = 1;
  978. /* We don't allow nested config for the same type. We
  979. * need to check for nesting in both directions here. */
  980. if ((((struct configIndex *)list)->config->scope == NULL) ||
  981. slapi_dn_issuffix(entry->scope,
  982. ((struct configIndex *)list)->config->scope) ||
  983. slapi_dn_issuffix(((struct configIndex *)list)->config->scope,
  984. entry->scope)) {
  985. /* Make sure that this isn't the same exact entry
  986. * in the list already. This can happen if a config
  987. * entry is being modified. Both of these were already
  988. * normalized when the config struct was filled in. */
  989. if (strcasecmp(entry->dn, ((struct configIndex *)list)->config->dn) != 0) {
  990. rc = 1;
  991. break;
  992. }
  993. }
  994. } else {
  995. if (found_type) {
  996. /* Since the list is sorted by link type, we
  997. * are finished if we get here since we found
  998. * the type but didn't match the scope. */
  999. break;
  1000. }
  1001. }
  1002. list = PR_NEXT_LINK(list);
  1003. }
  1004. }
  1005. return rc;
  1006. }
  1007. /*
  1008. * linked_attrs_oktodo()
  1009. *
  1010. * Check if we want to process this operation. We need to be
  1011. * sure that the operation succeeded. We also respond to replicated
  1012. * ops so we don't test for that. This does require that the managed
  1013. * attributes not be replicated.
  1014. */
  1015. static int
  1016. linked_attrs_oktodo(Slapi_PBlock *pb)
  1017. {
  1018. int ret = 1;
  1019. int oprc = 0;
  1020. slapi_log_error( SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1021. "--> linked_attrs_oktodo\n" );
  1022. if(slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
  1023. {
  1024. slapi_log_error( SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1025. "linked_attrs_oktodo: could not get parameters\n" );
  1026. ret = -1;
  1027. }
  1028. /* This plugin should only execute if the operation succeeded. */
  1029. if(oprc != 0)
  1030. {
  1031. ret = 0;
  1032. }
  1033. slapi_log_error( SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1034. "<-- linked_attrs_oktodo\n" );
  1035. return ret;
  1036. }
  1037. /* linked_attrs_load_array()
  1038. *
  1039. * put attribute values in array structure
  1040. */
  1041. void
  1042. linked_attrs_load_array(Slapi_Value **array, Slapi_Attr *attr)
  1043. {
  1044. Slapi_Value *val = 0;
  1045. int hint = slapi_attr_first_value(attr, &val);
  1046. while(val)
  1047. {
  1048. *array = val;
  1049. array++;
  1050. hint = slapi_attr_next_value(attr, hint, &val);
  1051. }
  1052. }
  1053. /* linked_attrs_compare()
  1054. *
  1055. * Compare two attr values using the DN syntax.
  1056. */
  1057. int
  1058. linked_attrs_compare(const void *a, const void *b)
  1059. {
  1060. Slapi_Value *val1;
  1061. Slapi_Value *val2;
  1062. Slapi_Attr *linkattr;
  1063. int rc = 0;
  1064. if(a == NULL && b != NULL){
  1065. return 1;
  1066. } else if(a != NULL && b == NULL){
  1067. return -1;
  1068. } else if(a == NULL && b == NULL){
  1069. return 0;
  1070. }
  1071. val1 = *((Slapi_Value **)a);
  1072. val2 = *((Slapi_Value **)b);
  1073. linkattr = slapi_attr_new();
  1074. slapi_attr_init(linkattr, "distinguishedName");
  1075. rc = slapi_attr_value_cmp(linkattr,
  1076. slapi_value_get_berval(val1),
  1077. slapi_value_get_berval(val2));
  1078. slapi_attr_free(&linkattr);
  1079. return rc;
  1080. }
  1081. /*
  1082. * linked_attrs_add_backpointers()
  1083. *
  1084. * Adds backpointers pointing to dn to the entries referred to
  1085. * by the values in smod.
  1086. */
  1087. static int
  1088. linked_attrs_add_backpointers(char *linkdn, struct configEntry *config,
  1089. Slapi_Mod *smod)
  1090. {
  1091. Slapi_ValueSet *vals = slapi_valueset_new();
  1092. int rc = LDAP_SUCCESS;
  1093. slapi_valueset_set_from_smod(vals, smod);
  1094. rc = linked_attrs_mod_backpointers(linkdn, config->managedtype, config->scope,
  1095. LDAP_MOD_ADD, vals);
  1096. slapi_valueset_free(vals);
  1097. return rc;
  1098. }
  1099. /*
  1100. * linked_attrs_del_backpointers()
  1101. *
  1102. * Remove backpointers pointing to linkdn in the entries referred
  1103. * to by the values in smod.
  1104. */
  1105. static int
  1106. linked_attrs_del_backpointers(Slapi_PBlock *pb, char *linkdn,
  1107. struct configEntry *config, Slapi_Mod *smod)
  1108. {
  1109. Slapi_ValueSet *vals = NULL;
  1110. int rc = LDAP_SUCCESS;
  1111. /* If no values are listed in the smod, we need to get
  1112. * a list of all of the values that were deleted by
  1113. * looking at the pre-op copy of the entry. */
  1114. if (slapi_mod_get_num_values(smod) == 0) {
  1115. Slapi_Entry *pre_e = NULL;
  1116. Slapi_Attr *pre_attr = NULL;
  1117. slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &pre_e );
  1118. slapi_entry_attr_find( pre_e, config->linktype, &pre_attr );
  1119. slapi_attr_get_valueset(pre_attr, &vals);
  1120. } else {
  1121. vals = slapi_valueset_new();
  1122. slapi_valueset_set_from_smod(vals, smod);
  1123. }
  1124. rc = linked_attrs_mod_backpointers(linkdn, config->managedtype, config->scope,
  1125. LDAP_MOD_DELETE, vals);
  1126. slapi_valueset_free(vals);
  1127. return rc;
  1128. }
  1129. /*
  1130. * linked_attrs_replace_backpointers()
  1131. *
  1132. * Remove backpointers pointing to linkdn from the entries
  1133. * whose values were deleted in smod and add backpointers
  1134. * for any new values that were added as a part of the
  1135. * replace operation.
  1136. */
  1137. static int
  1138. linked_attrs_replace_backpointers(Slapi_PBlock *pb, char *linkdn,
  1139. struct configEntry *config, Slapi_Mod *smod)
  1140. {
  1141. Slapi_Entry *pre_e = NULL;
  1142. Slapi_Entry *post_e = NULL;
  1143. Slapi_Attr *pre_attr = 0;
  1144. Slapi_Attr *post_attr = 0;
  1145. int rc = LDAP_SUCCESS;
  1146. /* Get the pre and post copy of the entry to see
  1147. * what values have been added and removed. */
  1148. slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &pre_e);
  1149. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &post_e);
  1150. if(pre_e && post_e) {
  1151. slapi_entry_attr_find(pre_e, config->linktype, &pre_attr);
  1152. slapi_entry_attr_find(post_e, config->linktype, &post_attr);
  1153. }
  1154. if(pre_attr || post_attr) {
  1155. int pre_total = 0;
  1156. int post_total = 0;
  1157. Slapi_Value **pre_array = 0;
  1158. Slapi_Value **post_array = 0;
  1159. int pre_index = 0;
  1160. int post_index = 0;
  1161. Slapi_ValueSet *addvals = NULL;
  1162. Slapi_ValueSet *delvals = NULL;
  1163. /* create arrays of values */
  1164. if(pre_attr) {
  1165. slapi_attr_get_numvalues(pre_attr, &pre_total);
  1166. }
  1167. if(post_attr) {
  1168. slapi_attr_get_numvalues(post_attr, &post_total);
  1169. }
  1170. if(pre_total) {
  1171. pre_array = (Slapi_Value**) slapi_ch_malloc(sizeof(Slapi_Value*)*pre_total);
  1172. linked_attrs_load_array(pre_array, pre_attr);
  1173. qsort(pre_array, pre_total, sizeof(Slapi_Value*), linked_attrs_compare);
  1174. }
  1175. if(post_total) {
  1176. post_array = (Slapi_Value**) slapi_ch_malloc(sizeof(Slapi_Value*)*post_total);
  1177. linked_attrs_load_array(post_array, post_attr);
  1178. qsort(post_array, post_total, sizeof(Slapi_Value*), linked_attrs_compare);
  1179. }
  1180. /* Work through arrays, following these rules:
  1181. * - in pre, in post, do nothing
  1182. * - in pre, not in post, delete from entry
  1183. * - not in pre, in post, add to entry
  1184. */
  1185. while(pre_index < pre_total || post_index < post_total) {
  1186. if(pre_index == pre_total) {
  1187. /* add the rest of post */
  1188. if (addvals == NULL) {
  1189. addvals = slapi_valueset_new();
  1190. }
  1191. slapi_valueset_add_value(addvals, post_array[post_index]);
  1192. post_index++;
  1193. } else if(post_index == post_total) {
  1194. /* delete the rest of pre */
  1195. if (delvals == NULL) {
  1196. delvals = slapi_valueset_new();
  1197. }
  1198. slapi_valueset_add_value(delvals, pre_array[pre_index]);
  1199. pre_index++;
  1200. } else {
  1201. /* decide what to do */
  1202. int cmp = linked_attrs_compare(&(pre_array[pre_index]),
  1203. &(post_array[post_index]));
  1204. if(cmp < 0) {
  1205. /* delete pre array */
  1206. if (delvals == NULL) {
  1207. delvals = slapi_valueset_new();
  1208. }
  1209. slapi_valueset_add_value(delvals, pre_array[pre_index]);
  1210. pre_index++;
  1211. } else if(cmp > 0) {
  1212. /* add post array */
  1213. if (addvals == NULL) {
  1214. addvals = slapi_valueset_new();
  1215. }
  1216. slapi_valueset_add_value(addvals, post_array[post_index]);
  1217. post_index++;
  1218. } else {
  1219. /* do nothing, advance */
  1220. pre_index++;
  1221. post_index++;
  1222. }
  1223. }
  1224. }
  1225. /* Perform the actual updates to the target entries. */
  1226. if (delvals) {
  1227. rc = linked_attrs_mod_backpointers(linkdn, config->managedtype,
  1228. config->scope, LDAP_MOD_DELETE, delvals);
  1229. slapi_valueset_free(delvals);
  1230. }
  1231. if (rc == LDAP_SUCCESS && addvals) {
  1232. rc = linked_attrs_mod_backpointers(linkdn, config->managedtype,
  1233. config->scope, LDAP_MOD_ADD, addvals);
  1234. slapi_valueset_free(addvals);
  1235. }
  1236. slapi_ch_free((void **)&pre_array);
  1237. slapi_ch_free((void **)&post_array);
  1238. }
  1239. return rc;
  1240. }
  1241. /*
  1242. * linked_attrs_mod_backpointers()
  1243. *
  1244. * Performs backpointer management.
  1245. */
  1246. static int
  1247. linked_attrs_mod_backpointers(char *linkdn, char *type,
  1248. char *scope, int modop, Slapi_ValueSet *targetvals)
  1249. {
  1250. char *val[2];
  1251. int i = 0;
  1252. Slapi_PBlock *mod_pb = slapi_pblock_new();
  1253. LDAPMod mod;
  1254. LDAPMod *mods[2];
  1255. Slapi_Value *targetval = NULL;
  1256. int rc = LDAP_SUCCESS;
  1257. /* Setup the modify operation. Only the target will
  1258. * change, so we only need to do this once. */
  1259. val[0] = linkdn;
  1260. val[1] = 0;
  1261. mod.mod_op = modop;
  1262. mod.mod_type = type;
  1263. mod.mod_values = val;
  1264. mods[0] = &mod;
  1265. mods[1] = 0;
  1266. i = slapi_valueset_first_value(targetvals, &targetval);
  1267. while(targetval)
  1268. {
  1269. int perform_update = 0;
  1270. const char *targetdn = slapi_value_get_string(targetval);
  1271. Slapi_DN *targetsdn = slapi_sdn_new_dn_byref(targetdn);
  1272. /* If we have a scope, only update the target if it is within
  1273. * the scope. If we don't have a scope, only update the target
  1274. * if it is in the same backend as the linkdn. */
  1275. if (scope) {
  1276. perform_update = slapi_dn_issuffix(targetdn, scope);
  1277. } else {
  1278. Slapi_Backend *be = NULL;
  1279. Slapi_DN *linksdn = slapi_sdn_new_normdn_byref(linkdn);
  1280. if ((be = slapi_be_select(linksdn))) {
  1281. perform_update = slapi_sdn_issuffix(targetsdn, slapi_be_getsuffix(be, 0));
  1282. }
  1283. slapi_sdn_free(&linksdn);
  1284. }
  1285. if (perform_update) {
  1286. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1287. "%s backpointer (%s) in entry (%s)\n",
  1288. (modop == LDAP_MOD_ADD) ? "Adding" : "Removing",
  1289. linkdn, targetdn);
  1290. /* Perform the modify operation. */
  1291. slapi_modify_internal_set_pb_ext(mod_pb, targetsdn, mods, 0, 0,
  1292. linked_attrs_get_plugin_id(), 0);
  1293. slapi_modify_internal_pb(mod_pb);
  1294. if (strict_results){
  1295. /* we are enforcing strict results, so return the error */
  1296. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1297. if(rc != LDAP_SUCCESS){
  1298. slapi_sdn_free(&targetsdn);
  1299. break;
  1300. }
  1301. }
  1302. /* Initialize the pblock so we can reuse it. */
  1303. slapi_pblock_init(mod_pb);
  1304. }
  1305. slapi_sdn_free(&targetsdn);
  1306. i = slapi_valueset_next_value(targetvals, i, &targetval);
  1307. }
  1308. slapi_pblock_destroy(mod_pb);
  1309. return rc;
  1310. }
  1311. /*
  1312. * Operation callback functions
  1313. */
  1314. /*
  1315. * linked_attrs_pre_op()
  1316. *
  1317. * Checks if an operation is modifying the linked
  1318. * attribute config and validates the config changes.
  1319. */
  1320. static int
  1321. linked_attrs_pre_op(Slapi_PBlock * pb, int modop)
  1322. {
  1323. char *dn = 0;
  1324. Slapi_Entry *e = 0;
  1325. LDAPMod **mods = NULL;
  1326. int free_entry = 0;
  1327. char *errstr = NULL;
  1328. int ret = SLAPI_PLUGIN_SUCCESS;
  1329. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1330. "--> linked_attrs_pre_op\n");
  1331. if (0 == (dn = linked_attrs_get_dn(pb)))
  1332. goto bail;
  1333. if (linked_attrs_dn_is_config(dn)) {
  1334. /* Validate config changes, but don't apply them.
  1335. * This allows us to reject invalid config changes
  1336. * here at the pre-op stage. Applying the config
  1337. * needs to be done at the post-op stage. */
  1338. if (LDAP_CHANGETYPE_ADD == modop) {
  1339. slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
  1340. } else {
  1341. /* Fetch the entry being modified so we can
  1342. * create the resulting entry for validation. */
  1343. /* int free_sdn = 0; */
  1344. Slapi_DN *tmp_dn = linked_attrs_get_sdn(pb);
  1345. if (tmp_dn) {
  1346. slapi_search_internal_get_entry(tmp_dn, 0, &e, linked_attrs_get_plugin_id());
  1347. free_entry = 1;
  1348. }
  1349. /* If the entry doesn't exist, just bail and
  1350. * let the server handle it. */
  1351. if (e == NULL) {
  1352. goto bail;
  1353. }
  1354. /* Grab the mods. */
  1355. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1356. /* Apply the mods to create the resulting entry. */
  1357. if (mods && (slapi_entry_apply_mods(e, mods) != LDAP_SUCCESS)) {
  1358. /* The mods don't apply cleanly, so we just let this op go
  1359. * to let the main server handle it. */
  1360. goto bail;
  1361. }
  1362. }
  1363. if (linked_attrs_parse_config_entry(e, 0) != 0) {
  1364. /* Refuse the operation if config parsing failed. */
  1365. ret = LDAP_UNWILLING_TO_PERFORM;
  1366. if (LDAP_CHANGETYPE_ADD == modop) {
  1367. errstr = slapi_ch_smprintf("Not a valid linked attribute configuration entry.");
  1368. } else {
  1369. errstr = slapi_ch_smprintf("Changes result in an invalid "
  1370. "linked attribute configuration.");
  1371. }
  1372. }
  1373. }
  1374. bail:
  1375. if (free_entry && e)
  1376. slapi_entry_free(e);
  1377. if (ret) {
  1378. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1379. "linked_attrs_pre_op: operation failure [%d]\n", ret);
  1380. slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL);
  1381. slapi_ch_free((void **)&errstr);
  1382. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
  1383. ret = SLAPI_PLUGIN_FAILURE;
  1384. }
  1385. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1386. "<-- linked_attrs_pre_op\n");
  1387. return ret;
  1388. }
  1389. static int
  1390. linked_attrs_add_pre_op(Slapi_PBlock * pb)
  1391. {
  1392. return linked_attrs_pre_op(pb, LDAP_CHANGETYPE_ADD);
  1393. }
  1394. static int
  1395. linked_attrs_mod_pre_op(Slapi_PBlock * pb)
  1396. {
  1397. return linked_attrs_pre_op(pb, LDAP_CHANGETYPE_MODIFY);
  1398. }
  1399. static int
  1400. linked_attrs_mod_post_op(Slapi_PBlock *pb)
  1401. {
  1402. Slapi_Mods *smods = NULL;
  1403. Slapi_Mod *smod = NULL;
  1404. LDAPMod **mods;
  1405. Slapi_Mod *next_mod = NULL;
  1406. char *dn = NULL;
  1407. struct configEntry *config = NULL;
  1408. void *caller_id = NULL;
  1409. int rc = SLAPI_PLUGIN_SUCCESS;
  1410. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1411. "--> linked_attrs_mod_post_op\n");
  1412. /* We don't want to process internal modify
  1413. * operations that originate from this plugin.
  1414. * Doing so could cause a deadlock. */
  1415. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &caller_id);
  1416. if (caller_id == linked_attrs_get_plugin_id()) {
  1417. /* Just return without processing */
  1418. return SLAPI_PLUGIN_SUCCESS;
  1419. }
  1420. if (linked_attrs_oktodo(pb) &&
  1421. (dn = linked_attrs_get_dn(pb))) {
  1422. /* First check if the config is being modified. */
  1423. if (linked_attrs_dn_is_config(dn)) {
  1424. linked_attrs_load_config();
  1425. }
  1426. /* get the mod set */
  1427. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1428. smods = slapi_mods_new();
  1429. slapi_mods_init_byref(smods, mods);
  1430. next_mod = slapi_mod_new();
  1431. smod = slapi_mods_get_first_smod(smods, next_mod);
  1432. while(smod) {
  1433. char *type = (char *)slapi_mod_get_type(smod);
  1434. /* See if there is an applicable link configured. */
  1435. linked_attrs_read_lock();
  1436. /* Bail out if the plug-in close function was just called. */
  1437. if (!slapi_plugin_running(pb)) {
  1438. linked_attrs_unlock();
  1439. return SLAPI_PLUGIN_SUCCESS;
  1440. }
  1441. linked_attrs_find_config(dn, type, &config);
  1442. /* If we have a matching config entry, we have
  1443. * work to do. If not, we can go to the next smod. */
  1444. if (config) {
  1445. int op = slapi_mod_get_operation(smod);
  1446. /* Prevent other threads from managing
  1447. * this specific link at the same time. */
  1448. slapi_lock_mutex(config->lock);
  1449. switch(op & ~LDAP_MOD_BVALUES) {
  1450. case LDAP_MOD_ADD:
  1451. /* Find the entries pointed to by the new
  1452. * values and add the backpointers. */
  1453. rc = linked_attrs_add_backpointers(dn, config, smod);
  1454. break;
  1455. case LDAP_MOD_DELETE:
  1456. /* Find the entries pointed to by the deleted
  1457. * values and remove the backpointers. */
  1458. rc = linked_attrs_del_backpointers(pb, dn, config, smod);
  1459. break;
  1460. case LDAP_MOD_REPLACE:
  1461. /* Find the entries pointed to by the deleted
  1462. * values and remove the backpointers. If
  1463. * any new values are being added, find those
  1464. * entries and add the backpointers. */
  1465. rc = linked_attrs_replace_backpointers(pb, dn, config, smod);
  1466. break;
  1467. default:
  1468. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1469. "linked_attrs_mod_post_op: unknown mod type\n" );
  1470. rc = SLAPI_PLUGIN_FAILURE;
  1471. break;
  1472. }
  1473. slapi_unlock_mutex(config->lock);
  1474. if(rc != LDAP_SUCCESS){
  1475. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1476. "linked_attrs_mod_post_op - update failed (%d)\n",rc);
  1477. linked_attrs_unlock();
  1478. slapi_mod_done(next_mod);
  1479. break;
  1480. }
  1481. }
  1482. config = NULL;
  1483. linked_attrs_unlock();
  1484. slapi_mod_done(next_mod);
  1485. smod = slapi_mods_get_next_smod(smods, next_mod);
  1486. }
  1487. slapi_mod_free(&next_mod);
  1488. slapi_mods_free(&smods);
  1489. }
  1490. if (rc) {
  1491. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
  1492. rc = SLAPI_PLUGIN_FAILURE;
  1493. }
  1494. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1495. "<-- linked_attrs_mod_post_op (%d)\n", rc);
  1496. return rc;
  1497. }
  1498. static int
  1499. linked_attrs_add_post_op(Slapi_PBlock *pb)
  1500. {
  1501. Slapi_Entry *e = NULL;
  1502. char *dn = NULL;
  1503. int rc = SLAPI_PLUGIN_SUCCESS;
  1504. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1505. "--> linked_attrs_add_post_op\n");
  1506. /* Reload config if a config entry was added. */
  1507. if ((dn = linked_attrs_get_dn(pb))) {
  1508. if (linked_attrs_dn_is_config(dn))
  1509. linked_attrs_load_config();
  1510. } else {
  1511. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1512. "linked_attrs_add_post_op: Error "
  1513. "retrieving dn\n");
  1514. }
  1515. /* Get the newly added entry. */
  1516. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
  1517. if (e) {
  1518. Slapi_Attr *attr = NULL;
  1519. char *type = NULL;
  1520. struct configEntry *config = NULL;
  1521. slapi_entry_first_attr(e, &attr);
  1522. while (attr) {
  1523. slapi_attr_get_type(attr, &type);
  1524. /* See if there is an applicable link configured. */
  1525. linked_attrs_read_lock();
  1526. /* Bail out if the plug-in close function was just called. */
  1527. if (!slapi_plugin_running(pb)) {
  1528. linked_attrs_unlock();
  1529. return SLAPI_PLUGIN_SUCCESS;
  1530. }
  1531. linked_attrs_find_config(dn, type, &config);
  1532. /* If config was found, add the backpointers to this entry. */
  1533. if (config) {
  1534. Slapi_ValueSet *vals = NULL;
  1535. slapi_attr_get_valueset(attr, &vals);
  1536. slapi_lock_mutex(config->lock);
  1537. rc = linked_attrs_mod_backpointers(dn, config->managedtype,
  1538. config->scope, LDAP_MOD_ADD, vals);
  1539. slapi_unlock_mutex(config->lock);
  1540. slapi_valueset_free(vals);
  1541. if(rc != LDAP_SUCCESS){
  1542. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1543. "linked_attrs_add_post_op: update failed (%d)\n",rc);
  1544. linked_attrs_unlock();
  1545. break;
  1546. }
  1547. }
  1548. config = NULL;
  1549. linked_attrs_unlock();
  1550. slapi_entry_next_attr(e, attr, &attr);
  1551. }
  1552. } else {
  1553. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1554. "linked_attrs_add_post_op: Error "
  1555. "retrieving post-op entry %s\n", dn);
  1556. }
  1557. if (rc) {
  1558. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
  1559. rc = SLAPI_PLUGIN_FAILURE;
  1560. }
  1561. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1562. "<-- linked_attrs_add_post_op\n");
  1563. return rc;
  1564. }
  1565. static int
  1566. linked_attrs_del_post_op(Slapi_PBlock *pb)
  1567. {
  1568. char *dn = NULL;
  1569. Slapi_Entry *e = NULL;
  1570. int rc = SLAPI_PLUGIN_SUCCESS;
  1571. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1572. "--> linked_attrs_del_post_op\n");
  1573. /* Just bail if we aren't ready to service requests yet. */
  1574. if (!linked_attrs_oktodo(pb)){
  1575. return rc;
  1576. }
  1577. /* Reload config if a config entry was deleted. */
  1578. if ((dn = linked_attrs_get_dn(pb))) {
  1579. if (linked_attrs_dn_is_config(dn))
  1580. linked_attrs_load_config();
  1581. } else {
  1582. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1583. "linked_attrs_del_post_op: Error "
  1584. "retrieving dn\n");
  1585. }
  1586. /* Get deleted entry, then go through types to find config. */
  1587. slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &e );
  1588. if (e) {
  1589. Slapi_Attr *attr = NULL;
  1590. char *type = NULL;
  1591. struct configEntry *config = NULL;
  1592. slapi_entry_first_attr(e, &attr);
  1593. while (attr) {
  1594. slapi_attr_get_type(attr, &type);
  1595. /* See if there is an applicable link configured. */
  1596. linked_attrs_read_lock();
  1597. /* Bail out if the plug-in close function was just called. */
  1598. if (!slapi_plugin_running(pb)) {
  1599. linked_attrs_unlock();
  1600. return rc;
  1601. }
  1602. linked_attrs_find_config(dn, type, &config);
  1603. /* If config was found, delete the backpointers to this entry. */
  1604. if (config) {
  1605. Slapi_ValueSet *vals = NULL;
  1606. slapi_attr_get_valueset(attr, &vals);
  1607. slapi_lock_mutex(config->lock);
  1608. rc = linked_attrs_mod_backpointers(dn, config->managedtype,
  1609. config->scope, LDAP_MOD_DELETE, vals);
  1610. slapi_unlock_mutex(config->lock);
  1611. slapi_valueset_free(vals);
  1612. if (rc != LDAP_SUCCESS){
  1613. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1614. "linked_attrs_del_post_op - update failed (%d)\n",rc);
  1615. linked_attrs_unlock();
  1616. break;
  1617. }
  1618. }
  1619. config = NULL;
  1620. /* See if any of the values for this attribute are managed
  1621. * backpointers. We need to remove the forward link if so. */
  1622. if (linked_attrs_config_index_has_type(type)) {
  1623. int hint = 0;
  1624. Slapi_Value *val = NULL;
  1625. /* Loop through values and see if we have matching config */
  1626. hint = slapi_attr_first_value(attr, &val);
  1627. while (val) {
  1628. linked_attrs_find_config_reverse(slapi_value_get_string(val),
  1629. type, &config);
  1630. if (config) {
  1631. Slapi_ValueSet *vals = slapi_valueset_new();
  1632. slapi_valueset_add_value(vals, val);
  1633. slapi_lock_mutex(config->lock);
  1634. /* Delete forward link value. */
  1635. rc = linked_attrs_mod_backpointers(dn, config->linktype,
  1636. config->scope, LDAP_MOD_DELETE, vals);
  1637. slapi_unlock_mutex(config->lock);
  1638. slapi_valueset_free(vals);
  1639. config = NULL;
  1640. if(rc != LDAP_SUCCESS){
  1641. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1642. "linked_attrs_del_post_op: update failed (%d)\n",rc);
  1643. linked_attrs_unlock();
  1644. goto bail;
  1645. }
  1646. }
  1647. hint = slapi_attr_next_value(attr, hint, &val);
  1648. }
  1649. }
  1650. linked_attrs_unlock();
  1651. slapi_entry_next_attr(e, attr, &attr);
  1652. }
  1653. } else {
  1654. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1655. "linked_attrs_del_post_op: Error "
  1656. "retrieving pre-op entry %s\n", dn);
  1657. rc = SLAPI_PLUGIN_FAILURE;
  1658. }
  1659. bail:
  1660. if (rc) {
  1661. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
  1662. rc = SLAPI_PLUGIN_FAILURE;
  1663. }
  1664. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1665. "<-- linked_attrs_del_post_op\n");
  1666. return rc;
  1667. }
  1668. static int
  1669. linked_attrs_modrdn_post_op(Slapi_PBlock *pb)
  1670. {
  1671. char *old_dn = NULL;
  1672. char *new_dn = NULL;
  1673. Slapi_Entry *post_e = NULL;
  1674. Slapi_Attr *attr = NULL;
  1675. char *type = NULL;
  1676. struct configEntry *config = NULL;
  1677. int rc = SLAPI_PLUGIN_SUCCESS;
  1678. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1679. "--> linked_attrs_modrdn_post_op\n");
  1680. /* Just bail if we aren't ready to service requests yet. */
  1681. if (!linked_attrs_oktodo(pb)) {
  1682. goto done;
  1683. }
  1684. /* Reload config if an existing config entry was renamed,
  1685. * or if the new dn brings an entry into the scope of the
  1686. * config entries. */
  1687. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &post_e);
  1688. if (post_e) {
  1689. new_dn = slapi_entry_get_ndn(post_e);
  1690. } else {
  1691. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1692. "linked_attrs_modrdn_post_op: Error "
  1693. "retrieving post-op entry\n");
  1694. rc = LDAP_OPERATIONS_ERROR;
  1695. goto done;
  1696. }
  1697. if ((old_dn = linked_attrs_get_dn(pb))) {
  1698. if (linked_attrs_dn_is_config(old_dn) || linked_attrs_dn_is_config(new_dn))
  1699. linked_attrs_load_config();
  1700. } else {
  1701. slapi_log_error(SLAPI_LOG_PLUGIN, LINK_PLUGIN_SUBSYSTEM,
  1702. "linked_attrs_modrdn_post_op: Error "
  1703. "retrieving dn\n");
  1704. rc = LDAP_OPERATIONS_ERROR;
  1705. goto done;
  1706. }
  1707. /* Check if this operation requires any updates to links. */
  1708. slapi_entry_first_attr(post_e, &attr);
  1709. while (attr) {
  1710. slapi_attr_get_type(attr, &type);
  1711. /* See if there is an applicable link configured. */
  1712. linked_attrs_read_lock();
  1713. /* Bail out if the plug-in close function was just called. */
  1714. if (!slapi_plugin_running(pb)) {
  1715. linked_attrs_unlock();
  1716. return SLAPI_PLUGIN_SUCCESS;
  1717. }
  1718. linked_attrs_find_config(old_dn, type, &config);
  1719. /* If config was found for the old dn, delete the backpointers
  1720. * to this entry. */
  1721. if (config) {
  1722. Slapi_ValueSet *vals = NULL;
  1723. slapi_attr_get_valueset(attr, &vals);
  1724. slapi_lock_mutex(config->lock);
  1725. /* Delete old dn value. */
  1726. rc = linked_attrs_mod_backpointers(old_dn, config->managedtype,
  1727. config->scope, LDAP_MOD_DELETE, vals);
  1728. slapi_unlock_mutex(config->lock);
  1729. slapi_valueset_free(vals);
  1730. config = NULL;
  1731. if(rc != LDAP_SUCCESS){
  1732. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1733. "linked_attrs_modrdn_post_op: update failed(old type) (%d)\n",rc);
  1734. linked_attrs_unlock();
  1735. break;
  1736. }
  1737. }
  1738. linked_attrs_find_config(new_dn, type, &config);
  1739. /* If config was found for the new dn, add the backpointers
  1740. * to this entry. We do this separate check for both dn's
  1741. * to catch an entry that comes into or goes out of scope
  1742. * from the MODRDN operation. */
  1743. if (config) {
  1744. Slapi_ValueSet *vals = NULL;
  1745. slapi_attr_get_valueset(attr, &vals);
  1746. slapi_lock_mutex(config->lock);
  1747. /* Add new dn value. */
  1748. rc = linked_attrs_mod_backpointers(new_dn, config->managedtype,
  1749. config->scope, LDAP_MOD_ADD, vals);
  1750. slapi_unlock_mutex(config->lock);
  1751. slapi_valueset_free(vals);
  1752. config = NULL;
  1753. if(rc != LDAP_SUCCESS){
  1754. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1755. "linked_attrs_modrdn_post_op: update failed(new type) (%d)\n",rc);
  1756. linked_attrs_unlock();
  1757. break;
  1758. }
  1759. }
  1760. /* See if any of the values for this attribute are managed
  1761. * backpointers. We need to update the forward link if so. */
  1762. if (linked_attrs_config_index_has_type(type)) {
  1763. int hint = 0;
  1764. Slapi_Value *val = NULL;
  1765. /* Loop through values and see if we have matching config */
  1766. hint = slapi_attr_first_value(attr, &val);
  1767. while (val) {
  1768. linked_attrs_find_config_reverse(slapi_value_get_string(val),
  1769. type, &config);
  1770. /* If the new DN is within scope, we should fixup the forward links. */
  1771. if (config && slapi_dn_issuffix(new_dn, (config->scope))) {
  1772. Slapi_ValueSet *vals = slapi_valueset_new();
  1773. slapi_valueset_add_value(vals, val);
  1774. slapi_lock_mutex(config->lock);
  1775. /* Delete old dn value. */
  1776. rc = linked_attrs_mod_backpointers(old_dn, config->linktype,
  1777. config->scope, LDAP_MOD_DELETE, vals);
  1778. if(rc != LDAP_SUCCESS){
  1779. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1780. "linked_attrs_modrdn_post_op: update failed(old dn) (%d)\n",rc);
  1781. slapi_unlock_mutex(config->lock);
  1782. slapi_valueset_free(vals);
  1783. linked_attrs_unlock();
  1784. goto done;
  1785. }
  1786. /* Add new dn value. */
  1787. rc = linked_attrs_mod_backpointers(new_dn, config->linktype,
  1788. config->scope, LDAP_MOD_ADD, vals);
  1789. slapi_unlock_mutex(config->lock);
  1790. slapi_valueset_free(vals);
  1791. config = NULL;
  1792. if(rc != LDAP_SUCCESS){
  1793. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1794. "linked_attrs_modrdn_post_op: update failed(new dn) (%d)\n",rc);
  1795. linked_attrs_unlock();
  1796. goto done;
  1797. }
  1798. }
  1799. hint = slapi_attr_next_value(attr, hint, &val);
  1800. }
  1801. }
  1802. linked_attrs_unlock();
  1803. slapi_entry_next_attr(post_e, attr, &attr);
  1804. }
  1805. done:
  1806. slapi_log_error(SLAPI_LOG_TRACE, LINK_PLUGIN_SUBSYSTEM,
  1807. "<-- linked_attrs_modrdn_post_op\n");
  1808. if (rc) {
  1809. slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc);
  1810. rc = SLAPI_PLUGIN_FAILURE;
  1811. }
  1812. return rc;
  1813. }
  1814. /*
  1815. * Debug functions to print config
  1816. */
  1817. void
  1818. linked_attrs_dump_config()
  1819. {
  1820. PRCList *list;
  1821. linked_attrs_read_lock();
  1822. if (!PR_CLIST_IS_EMPTY(g_link_config)) {
  1823. list = PR_LIST_HEAD(g_link_config);
  1824. while (list != g_link_config) {
  1825. linked_attrs_dump_config_entry((struct configEntry *)list);
  1826. list = PR_NEXT_LINK(list);
  1827. }
  1828. }
  1829. linked_attrs_unlock();
  1830. }
  1831. void
  1832. linked_attrs_dump_config_index()
  1833. {
  1834. PRCList *list;
  1835. linked_attrs_read_lock();
  1836. if (!PR_CLIST_IS_EMPTY(g_managed_config_index)) {
  1837. list = PR_LIST_HEAD(g_managed_config_index);
  1838. while (list != g_managed_config_index) {
  1839. linked_attrs_dump_config_entry(((struct configIndex *)list)->config);
  1840. list = PR_NEXT_LINK(list);
  1841. }
  1842. }
  1843. linked_attrs_unlock();
  1844. }
  1845. void
  1846. linked_attrs_dump_config_entry(struct configEntry * entry)
  1847. {
  1848. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1849. "<==== Linked Attribute Pair =====>\n");
  1850. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1851. "<---- config entry dn -----> %s\n", entry->dn);
  1852. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1853. "<---- link type -----------> %s\n", entry->linktype);
  1854. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1855. "<---- managed type --------> %s\n", entry->managedtype);
  1856. slapi_log_error(SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM,
  1857. "<---- scope ---------------> %s\n", entry->scope);
  1858. }