referint.c 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include "portable.h"
  15. #include "slapi-plugin.h"
  16. #include "slap.h"
  17. #include "prthread.h"
  18. #include "prlock.h"
  19. #include "prerror.h"
  20. #include "prcvar.h"
  21. #include "prio.h"
  22. #include <sys/stat.h>
  23. #define REFERINT_DEFAULT_FILE_MODE S_IRUSR | S_IWUSR
  24. #define REFERINT_PLUGIN_SUBSYSTEM "referint-plugin" /* used for logging */
  25. #define REFERINT_PREOP_DESC "referint preop plugin"
  26. #define REFERINT_ATTR_DELAY "referint-update-delay"
  27. #define REFERINT_ATTR_LOGCHANGES "referint-logchanges"
  28. #define REFERINT_ATTR_LOGFILE "referint-logfile"
  29. #define REFERINT_ATTR_MEMBERSHIP "referint-membership-attr"
  30. #define MAX_LINE 2048
  31. #define READ_BUFSIZE 4096
  32. #define MY_EOF 0
  33. #define STARTUP 2
  34. typedef struct referint_config {
  35. int delay;
  36. char *logfile;
  37. int logchanges;
  38. char **attrs;
  39. } referint_config;
  40. Slapi_RWLock *config_rwlock = NULL;
  41. /* function prototypes */
  42. int referint_postop_init( Slapi_PBlock *pb );
  43. int referint_postop_del( Slapi_PBlock *pb );
  44. int referint_postop_modrdn( Slapi_PBlock *pb );
  45. int referint_postop_start( Slapi_PBlock *pb);
  46. int referint_postop_close( Slapi_PBlock *pb);
  47. int update_integrity(Slapi_DN *sDN, char *newrDN, Slapi_DN *newsuperior, int logChanges);
  48. int GetNextLine(char *dest, int size_dest, PRFileDesc *stream);
  49. int my_fgetc(PRFileDesc *stream);
  50. void referint_thread_func(void *arg);
  51. void writeintegritylog(Slapi_PBlock *pb, char *logfilename, Slapi_DN *sdn, char *newrdn, Slapi_DN *newsuperior, Slapi_DN *requestorsdn);
  52. int load_config(Slapi_PBlock *pb, Slapi_Entry *config_entry, int apply);
  53. int referint_get_delay();
  54. int referint_get_logchanges();
  55. char *referint_get_logfile();
  56. char **referint_get_attrs();
  57. int referint_postop_modify(Slapi_PBlock *pb);
  58. int referint_validate_config(Slapi_PBlock *pb);
  59. static int referint_preop_init(Slapi_PBlock *pb);
  60. void referint_set_config_area(Slapi_DN *dn);
  61. Slapi_DN *referint_get_config_area();
  62. void referint_set_plugin_area(Slapi_DN *sdn);
  63. Slapi_DN *referint_get_plugin_area();
  64. int referint_sdn_config_cmp(Slapi_DN *sdn);
  65. void referint_get_config(int *delay, int *logchanges, char **logfile);
  66. /* global thread control stuff */
  67. static PRLock *referint_mutex = NULL;
  68. static PRThread *referint_tid = NULL;
  69. static PRLock *keeprunning_mutex = NULL;
  70. static PRCondVar *keeprunning_cv = NULL;
  71. static int keeprunning = 0;
  72. static referint_config *config = NULL;
  73. static Slapi_DN* _ConfigAreaDN = NULL;
  74. static Slapi_DN* _pluginDN = NULL;
  75. static Slapi_PluginDesc pdesc = { "referint", VENDOR, DS_PACKAGE_VERSION, "referential integrity plugin" };
  76. static int allow_repl = 0;
  77. static Slapi_DN **plugin_EntryScope = NULL;
  78. static Slapi_DN *plugin_ExcludeEntryScope = NULL;
  79. static Slapi_DN *plugin_ContainerScope = NULL;
  80. static void* referint_plugin_identity = NULL;
  81. static int use_txn = 0;
  82. static int premodfn = SLAPI_PLUGIN_PRE_MODIFY_FN;
  83. static void
  84. referint_lock()
  85. {
  86. if (use_txn) { /* no lock if betxn is enabled */
  87. return;
  88. }
  89. if (NULL == referint_mutex) {
  90. referint_mutex = PR_NewLock();
  91. }
  92. if (referint_mutex) {
  93. PR_Lock(referint_mutex);
  94. }
  95. }
  96. static void
  97. referint_unlock()
  98. {
  99. if (use_txn) { /* no lock if betxn is enabled */
  100. return;
  101. }
  102. if (referint_mutex) {
  103. PR_Unlock(referint_mutex);
  104. }
  105. }
  106. void
  107. referint_set_config_area(Slapi_DN *dn)
  108. {
  109. slapi_rwlock_wrlock(config_rwlock);
  110. slapi_sdn_free(&_ConfigAreaDN);
  111. _ConfigAreaDN = slapi_sdn_dup(dn);
  112. slapi_rwlock_unlock(config_rwlock);
  113. }
  114. /*
  115. * No need to lock here, because this only called from referint_sdn_config_cmp()
  116. * which does take the lock.
  117. */
  118. Slapi_DN *
  119. referint_get_config_area()
  120. {
  121. return _ConfigAreaDN;
  122. }
  123. /* no locking needed for the plugin DN because it is set at initialization */
  124. void
  125. referint_set_plugin_area(Slapi_DN *sdn)
  126. {
  127. slapi_sdn_free(&_pluginDN);
  128. _pluginDN = slapi_sdn_dup(sdn);
  129. }
  130. Slapi_DN *
  131. referint_get_plugin_area()
  132. {
  133. return _pluginDN;
  134. }
  135. int
  136. referint_postop_init( Slapi_PBlock *pb )
  137. {
  138. Slapi_Entry *plugin_entry = NULL;
  139. char *plugin_type = NULL;
  140. int delfn = SLAPI_PLUGIN_POST_DELETE_FN;
  141. int mdnfn = SLAPI_PLUGIN_POST_MODRDN_FN;
  142. int modfn = SLAPI_PLUGIN_POST_MODIFY_FN; /* for config changes */
  143. char *preop_plugin_type = "preoperation";
  144. /*
  145. * Get plugin identity and stored it for later use.
  146. * Used for internal operations.
  147. */
  148. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &referint_plugin_identity);
  149. PR_ASSERT (referint_plugin_identity);
  150. if((config = (referint_config *)slapi_ch_calloc (1, sizeof (referint_config))) == NULL){
  151. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_init failed to "
  152. "allocate configuration\n" );
  153. return ( -1 );
  154. }
  155. /* get the args */
  156. if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
  157. plugin_entry &&
  158. (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
  159. plugin_type && strstr(plugin_type, "betxn"))
  160. {
  161. delfn = SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN;
  162. mdnfn = SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN;
  163. modfn = SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN;
  164. preop_plugin_type = "betxnpreoperation";
  165. premodfn = SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN;
  166. use_txn = 1;
  167. }
  168. slapi_ch_free_string(&plugin_type);
  169. if(plugin_entry){
  170. char *plugin_attr_value;
  171. char **plugin_attr_values;
  172. plugin_attr_value = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginAllowReplUpdates");
  173. if(plugin_attr_value && strcasecmp(plugin_attr_value,"on")==0){
  174. allow_repl = 1;
  175. }
  176. slapi_ch_free_string(&plugin_attr_value);
  177. plugin_attr_values = slapi_entry_attr_get_charray(plugin_entry, "nsslapd-pluginEntryScope");
  178. if(plugin_attr_values) {
  179. int i,j=0;;
  180. for (i=0; plugin_attr_values[i];i++);
  181. plugin_EntryScope = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),i+1);
  182. for (i=0; plugin_attr_values[i];i++) {
  183. if (slapi_dn_syntax_check(NULL, plugin_attr_values[i], 1) == 1) {
  184. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  185. "Error: Ignoring invalid DN used as plugin entry scope: [%s]\n",
  186. plugin_attr_values[i]);
  187. slapi_ch_free_string(&plugin_attr_values[i]);
  188. } else {
  189. plugin_EntryScope[j++] = slapi_sdn_new_dn_passin(plugin_attr_values[i]);
  190. }
  191. }
  192. slapi_ch_free((void**)&plugin_attr_values);
  193. }
  194. plugin_attr_value = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginExcludeEntryScope");
  195. if(plugin_attr_value) {
  196. if (slapi_dn_syntax_check(NULL, plugin_attr_value, 1) == 1) {
  197. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  198. "Error: Ignoring invalid DN used as plugin exclude entry scope: [%s]\n",
  199. plugin_attr_value);
  200. slapi_ch_free_string(&plugin_attr_value);
  201. } else {
  202. plugin_ExcludeEntryScope = slapi_sdn_new_dn_passin(plugin_attr_value);
  203. }
  204. }
  205. plugin_attr_value = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginContainerScope");
  206. if(plugin_attr_value) {
  207. if (slapi_dn_syntax_check(NULL, plugin_attr_value, 1) == 1) {
  208. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  209. "Error: Ignoring invalid DN used as plugin container scope: [%s]\n",
  210. plugin_attr_value);
  211. slapi_ch_free_string(&plugin_attr_value);
  212. } else {
  213. plugin_ContainerScope = slapi_sdn_new_dn_passin(plugin_attr_value);
  214. }
  215. }
  216. referint_set_plugin_area(slapi_entry_get_sdn(plugin_entry));
  217. }
  218. if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
  219. slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&pdesc ) != 0 ||
  220. slapi_pblock_set( pb, delfn, (void *) referint_postop_del ) != 0 ||
  221. slapi_pblock_set( pb, mdnfn, (void *) referint_postop_modrdn ) != 0 ||
  222. slapi_pblock_set( pb, modfn, (void *) (void *)referint_postop_modify ) != 0 ||
  223. slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) referint_postop_start ) != 0 ||
  224. slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) referint_postop_close ) != 0)
  225. {
  226. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_init failed\n" );
  227. return( -1 );
  228. }
  229. /*
  230. * Setup the preop plugin for config validation
  231. */
  232. if (slapi_register_plugin(preop_plugin_type, /* op type */
  233. 1, /* Enabled */
  234. "referint_preop_init", /* this function desc */
  235. referint_preop_init, /* init func */
  236. REFERINT_PREOP_DESC, /* plugin desc */
  237. NULL, /* ? */
  238. referint_plugin_identity /* access control */))
  239. {
  240. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_preop_init failed\n" );
  241. return ( -1 );
  242. }
  243. return( 0 );
  244. }
  245. /*
  246. * referint-update-delay: 0
  247. * referint-logfile: /var/log/dirsrv/slapd-localhost/referint
  248. * referint-logchanges: 0
  249. * referint-membership-attr: member
  250. * referint-membership-attr: uniquemember
  251. * referint-membership-attr: owner
  252. * referint-membership-attr: seeAlso
  253. *
  254. *
  255. * Need to lock this!
  256. */
  257. int
  258. load_config(Slapi_PBlock *pb, Slapi_Entry *config_entry, int apply)
  259. {
  260. referint_config *tmp_config = NULL;
  261. char *value = NULL;
  262. char **attrs = NULL;
  263. char **argv = NULL;
  264. int new_config_present = 0;
  265. int argc = 0;
  266. int rc = SLAPI_PLUGIN_SUCCESS;
  267. if(config_entry == NULL){
  268. return rc;
  269. }
  270. slapi_rwlock_wrlock(config_rwlock);
  271. if(config == NULL){
  272. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  273. "load_config: config is NULL\n" );
  274. rc = SLAPI_PLUGIN_FAILURE;
  275. goto done;
  276. }
  277. if((tmp_config = (referint_config *)slapi_ch_calloc (1, sizeof (referint_config))) == NULL){
  278. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "load_config failed to "
  279. "allocate configuration\n" );
  280. rc = SLAPI_PLUGIN_FAILURE;
  281. goto done;
  282. } else {
  283. /* set these to -1 for config validation */
  284. tmp_config->delay = -1;
  285. tmp_config->logchanges = -1;
  286. }
  287. if((value = slapi_entry_attr_get_charptr(config_entry, REFERINT_ATTR_DELAY))){
  288. tmp_config->delay = atoi(value);
  289. slapi_ch_free_string(&value);
  290. new_config_present = 1;
  291. }
  292. if((value = slapi_entry_attr_get_charptr(config_entry, REFERINT_ATTR_LOGFILE))){
  293. tmp_config->logfile = value;
  294. new_config_present = 1;
  295. }
  296. if((value = slapi_entry_attr_get_charptr(config_entry, REFERINT_ATTR_LOGCHANGES))){
  297. tmp_config->logchanges = atoi(value);
  298. slapi_ch_free_string(&value);
  299. new_config_present = 1;
  300. }
  301. if((attrs = slapi_entry_attr_get_charray(config_entry, REFERINT_ATTR_MEMBERSHIP))){
  302. tmp_config->attrs = attrs;
  303. new_config_present = 1;
  304. }
  305. if(new_config_present){
  306. /* Verify we have everything we need */
  307. if(tmp_config->delay == -1){
  308. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "Plugin configuration is missing %s\n",
  309. REFERINT_ATTR_DELAY);
  310. rc = SLAPI_PLUGIN_FAILURE;
  311. } else if (!tmp_config->logfile){
  312. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "Plugin configuration is missing %s\n",
  313. REFERINT_ATTR_LOGFILE);
  314. rc = SLAPI_PLUGIN_FAILURE;
  315. } else if (tmp_config->logchanges == -1){
  316. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "Plugin configuration is missing %s\n",
  317. REFERINT_ATTR_LOGCHANGES);
  318. rc = SLAPI_PLUGIN_FAILURE;
  319. } else if (!tmp_config->attrs){
  320. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "Plugin configuration is missing %s\n",
  321. REFERINT_ATTR_MEMBERSHIP);
  322. rc = SLAPI_PLUGIN_FAILURE;
  323. }
  324. } else{
  325. /*
  326. * We are using the old plugin arg configuration, get the args
  327. */
  328. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0) {
  329. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  330. "referint_postop failed to get argc\n" );
  331. rc = SLAPI_PLUGIN_FAILURE;
  332. goto done;
  333. }
  334. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0) {
  335. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  336. "referint_postop failed to get argv\n" );
  337. rc = SLAPI_PLUGIN_FAILURE;
  338. goto done;
  339. }
  340. if(argv == NULL){
  341. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  342. "referint_postop_del, args are NULL\n" );
  343. rc = SLAPI_PLUGIN_FAILURE;
  344. goto done;
  345. }
  346. /*
  347. * Load the args and set the config struct
  348. */
  349. if (argc >= 3) {
  350. int i;
  351. tmp_config->delay = atoi(argv[0]);
  352. tmp_config->logfile = slapi_ch_strdup(argv[1]);
  353. tmp_config->logchanges = atoi(argv[2]);
  354. for(i = 3; argv[i] != NULL; i++){
  355. slapi_ch_array_add(&tmp_config->attrs, slapi_ch_strdup(argv[i]));
  356. }
  357. } else {
  358. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  359. "referint_postop insufficient arguments supplied\n" );
  360. rc = SLAPI_PLUGIN_FAILURE;
  361. goto done;
  362. }
  363. }
  364. done:
  365. if(apply && rc == SLAPI_PLUGIN_SUCCESS){
  366. slapi_ch_free_string(&config->logfile);
  367. slapi_ch_array_free(config->attrs);
  368. slapi_ch_free((void **)&config);
  369. config = tmp_config;
  370. } else if(tmp_config){
  371. slapi_ch_free_string(&tmp_config->logfile);
  372. slapi_ch_array_free(tmp_config->attrs);
  373. slapi_ch_free((void **)&tmp_config);
  374. }
  375. slapi_rwlock_unlock(config_rwlock);
  376. return rc;
  377. }
  378. int
  379. referint_postop_modify(Slapi_PBlock *pb)
  380. {
  381. Slapi_Entry *entry = NULL, *e = NULL;
  382. Slapi_Entry *config_e = NULL;
  383. Slapi_DN *config_sdn = NULL;
  384. Slapi_DN *sdn = NULL;
  385. char *config_area = NULL;
  386. int result = 0;
  387. int rc = SLAPI_PLUGIN_SUCCESS;
  388. /* check if we are updating the shared config entry */
  389. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
  390. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &entry);
  391. if (referint_sdn_config_cmp(sdn) == 0 && slapi_sdn_compare(sdn, referint_get_plugin_area()))
  392. {
  393. if( SLAPI_PLUGIN_FAILURE == load_config(pb, entry, 1)){
  394. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "Failed to update configuration.\n");
  395. return SLAPI_PLUGIN_FAILURE;
  396. }
  397. } else if (slapi_sdn_compare(sdn, referint_get_plugin_area()) == 0){
  398. /*
  399. * Check if the plugin config area is set(verify it and load its config),
  400. * otherwise reload the plugin entry config
  401. */
  402. if((config_area = slapi_entry_attr_get_charptr(entry, SLAPI_PLUGIN_SHARED_CONFIG_AREA))){
  403. rc = slapi_dn_syntax_check(pb, config_area, 1);
  404. if (rc) { /* syntax check failed */
  405. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_modify: "
  406. "%s does not contain a valid DN (%s)\n",
  407. SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_area);
  408. rc = LDAP_INVALID_DN_SYNTAX;
  409. goto bail;
  410. }
  411. config_sdn = slapi_sdn_new_dn_byval(config_area);
  412. result = slapi_search_internal_get_entry(config_sdn, NULL, &e, referint_plugin_identity);
  413. if (LDAP_SUCCESS != result) {
  414. if (result == LDAP_NO_SUCH_OBJECT) {
  415. /* log an error and use the plugin entry for the config */
  416. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  417. "referint_postop_modify: Config entry \"%s\" does "
  418. "not exist.\n", config_area);
  419. rc = LDAP_OPERATIONS_ERROR;
  420. goto bail;
  421. }
  422. } else {
  423. if(e){
  424. config_e = e;
  425. } else {
  426. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  427. "referint_postop_modify: Config entry \"%s\" was not located.\n", config_area);
  428. rc = LDAP_OPERATIONS_ERROR;
  429. goto bail;
  430. }
  431. }
  432. } else {
  433. config_e = entry;
  434. }
  435. if(load_config(pb, config_e, 1) != LDAP_SUCCESS){
  436. rc = LDAP_UNWILLING_TO_PERFORM;
  437. goto bail;
  438. }
  439. referint_set_config_area(slapi_entry_get_sdn(config_e));
  440. }
  441. bail:
  442. slapi_ch_free_string(&config_area);
  443. slapi_sdn_free(&config_sdn);
  444. slapi_entry_free(e);
  445. return rc;
  446. }
  447. int
  448. referint_get_delay()
  449. {
  450. int delay;
  451. slapi_rwlock_rdlock(config_rwlock);
  452. delay = config->delay;
  453. slapi_rwlock_unlock(config_rwlock);
  454. return delay;
  455. }
  456. int
  457. referint_get_logchanges()
  458. {
  459. int log_changes;
  460. slapi_rwlock_rdlock(config_rwlock);
  461. log_changes = config->logchanges;
  462. slapi_rwlock_unlock(config_rwlock);
  463. return log_changes;
  464. }
  465. char *
  466. referint_get_logfile()
  467. {
  468. char *log_file;
  469. slapi_rwlock_rdlock(config_rwlock);
  470. log_file = slapi_ch_strdup(config->logfile);
  471. slapi_rwlock_unlock(config_rwlock);
  472. return log_file;
  473. }
  474. void
  475. referint_get_config(int *delay, int *logchanges, char **logfile)
  476. {
  477. slapi_rwlock_rdlock(config_rwlock);
  478. if(delay){
  479. *delay = config->delay;
  480. }
  481. if(logchanges){
  482. *logchanges = config->logchanges;
  483. }
  484. if(logfile){
  485. *logfile = slapi_ch_strdup(config->logfile);
  486. }
  487. slapi_rwlock_unlock(config_rwlock);
  488. }
  489. /*
  490. * might need to find an alternate option instead of copying
  491. */
  492. char **
  493. referint_get_attrs()
  494. {
  495. char **attrs = NULL;
  496. slapi_rwlock_rdlock(config_rwlock);
  497. attrs = slapi_ch_array_dup(config->attrs);
  498. slapi_rwlock_unlock(config_rwlock);
  499. return attrs;
  500. }
  501. int
  502. referint_sdn_config_cmp(Slapi_DN *sdn)
  503. {
  504. int rc = 0;
  505. slapi_rwlock_rdlock(config_rwlock);
  506. rc = slapi_sdn_compare(sdn, referint_get_config_area());
  507. slapi_rwlock_unlock(config_rwlock);
  508. return rc;
  509. }
  510. int
  511. referint_sdn_in_container_scope(Slapi_DN *sdn)
  512. {
  513. if (plugin_ContainerScope == NULL) {
  514. return(1);
  515. } else {
  516. return(slapi_sdn_issuffix(sdn, plugin_ContainerScope));
  517. }
  518. }
  519. int
  520. referint_sdn_in_entry_scope(Slapi_DN *sdn)
  521. {
  522. int rc = 0;
  523. if (plugin_ExcludeEntryScope && slapi_sdn_issuffix(sdn, plugin_ExcludeEntryScope))
  524. return (0);
  525. if (plugin_EntryScope == NULL) {
  526. /* no scope defined, all sdns match */
  527. return(1);
  528. } else {
  529. int i = 0;
  530. while (plugin_EntryScope[i]) {
  531. if (slapi_sdn_issuffix(sdn, plugin_EntryScope[i]) ) {
  532. rc = 1;
  533. break;
  534. } else {
  535. i++;
  536. }
  537. }
  538. }
  539. return (rc);
  540. }
  541. int
  542. referint_postop_del( Slapi_PBlock *pb )
  543. {
  544. Slapi_DN *sdn = NULL;
  545. char *logfile = NULL;
  546. int delay;
  547. int logChanges=0;
  548. int isrepop = 0;
  549. int oprc;
  550. int rc = SLAPI_PLUGIN_SUCCESS;
  551. if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &isrepop ) != 0 ||
  552. slapi_pblock_get( pb, SLAPI_DELETE_TARGET_SDN, &sdn ) != 0 ||
  553. slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
  554. {
  555. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  556. "referint_postop_del: could not get parameters\n" );
  557. return SLAPI_PLUGIN_FAILURE;
  558. }
  559. /*
  560. * This plugin should only execute if the delete was successful
  561. * and this is not a replicated op(unless its allowed)
  562. */
  563. if(oprc != 0 || (isrepop && !allow_repl)){
  564. return SLAPI_PLUGIN_SUCCESS;
  565. }
  566. referint_get_config(&delay, &logChanges, NULL);
  567. if(delay == -1){
  568. /* integrity updating is off */
  569. rc = SLAPI_PLUGIN_SUCCESS;
  570. } else if(delay == 0){ /* no delay */
  571. /* call function to update references to entry */
  572. if (referint_sdn_in_entry_scope(sdn)) {
  573. rc = update_integrity(sdn, NULL, NULL, logChanges);
  574. }
  575. } else {
  576. /* write the entry to integrity log */
  577. logfile = referint_get_logfile();
  578. writeintegritylog(pb, logfile, sdn, NULL, NULL, NULL /* slapi_get_requestor_sdn(pb) */);
  579. rc = SLAPI_PLUGIN_SUCCESS;
  580. }
  581. slapi_ch_free_string(&logfile);
  582. return( rc );
  583. }
  584. int
  585. referint_postop_modrdn( Slapi_PBlock *pb )
  586. {
  587. Slapi_DN *sdn = NULL;
  588. Slapi_DN *newsuperior;
  589. char *logfile = NULL;
  590. char *newrdn;
  591. int oprc;
  592. int rc = SLAPI_PLUGIN_SUCCESS;
  593. int delay;
  594. int logChanges=0;
  595. int isrepop = 0;
  596. if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &isrepop ) != 0 ||
  597. slapi_pblock_get( pb, SLAPI_MODRDN_TARGET_SDN, &sdn ) != 0 ||
  598. slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn ) != 0 ||
  599. slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperior ) != 0 ||
  600. slapi_pblock_get( pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 )
  601. {
  602. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  603. "referint_postop_modrdn: could not get parameters\n" );
  604. return SLAPI_PLUGIN_FAILURE;
  605. }
  606. /*
  607. * This plugin should only execute if the delete was successful
  608. * and this is not a replicated op (unless its allowed)
  609. */
  610. if(oprc != 0 || (isrepop && !allow_repl)){
  611. return SLAPI_PLUGIN_SUCCESS;
  612. }
  613. referint_get_config(&delay, &logChanges, NULL);
  614. if(delay == -1){
  615. /* integrity updating is off */
  616. rc = SLAPI_PLUGIN_SUCCESS;
  617. } else if(delay == 0){ /* no delay */
  618. /* call function to update references to entry */
  619. if (!plugin_EntryScope && !plugin_ExcludeEntryScope) {
  620. /* no scope defined, default always process referint */
  621. rc = update_integrity(sdn, newrdn, newsuperior, logChanges);
  622. } else {
  623. const char *newsuperiordn = slapi_sdn_get_dn(newsuperior);
  624. if ( (newsuperiordn == NULL && referint_sdn_in_entry_scope(sdn)) ||
  625. ( newsuperiordn && referint_sdn_in_entry_scope(newsuperior)))
  626. {
  627. /*
  628. * It is a modrdn inside the scope or into the scope,
  629. * process normal modrdn
  630. */
  631. rc = update_integrity(sdn, newrdn, newsuperior, logChanges);
  632. } else if (referint_sdn_in_entry_scope(sdn)) {
  633. /* the entry is moved out of scope, treat as delete */
  634. rc = update_integrity(sdn, NULL, NULL, logChanges);
  635. }
  636. }
  637. } else {
  638. /* write the entry to integrity log */
  639. logfile = referint_get_logfile();
  640. writeintegritylog(pb, logfile, sdn, newrdn, newsuperior, NULL /* slapi_get_requestor_sdn(pb) */);
  641. rc = SLAPI_PLUGIN_SUCCESS;
  642. }
  643. slapi_ch_free_string(&logfile);
  644. return( rc );
  645. }
  646. int isFatalSearchError(int search_result)
  647. {
  648. /* Make sure search result is fatal
  649. * Some conditions that happen quite often are not fatal
  650. * for example if you have two suffixes and one is null, you will always
  651. * get no such object, however this is not a fatal error.
  652. * Add other conditions to the if statement as they are found
  653. */
  654. switch(search_result) {
  655. case LDAP_REFERRAL:
  656. case LDAP_NO_SUCH_OBJECT: return 0 ;
  657. }
  658. return 1;
  659. }
  660. static int
  661. _do_modify(Slapi_PBlock *mod_pb, Slapi_DN *entrySDN, LDAPMod **mods)
  662. {
  663. int rc = 0;
  664. slapi_pblock_init(mod_pb);
  665. if(allow_repl){
  666. /* Must set as a replicated operation */
  667. slapi_modify_internal_set_pb_ext(mod_pb, entrySDN, mods, NULL, NULL,
  668. referint_plugin_identity, OP_FLAG_REPLICATED);
  669. } else {
  670. slapi_modify_internal_set_pb_ext(mod_pb, entrySDN, mods, NULL, NULL,
  671. referint_plugin_identity, 0);
  672. }
  673. slapi_modify_internal_pb(mod_pb);
  674. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  675. return rc;
  676. }
  677. /*
  678. * update one attribute value per _do_modify
  679. */
  680. static int
  681. _update_one_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */
  682. Slapi_Attr *attr, /* referred attribute */
  683. char *attrName,
  684. Slapi_DN *origDN, /* original DN that was modified */
  685. char *newRDN, /* new RDN from modrdn */
  686. const char *newsuperior, /* new superior from modrdn */
  687. Slapi_PBlock *mod_pb)
  688. {
  689. LDAPMod attribute1, attribute2;
  690. LDAPMod *list_of_mods[3];
  691. char *values_del[2];
  692. char *values_add[2];
  693. char *newDN = NULL;
  694. char **dnParts = NULL;
  695. char *sval = NULL;
  696. char *newvalue = NULL;
  697. char *p = NULL;
  698. size_t dnlen = 0;
  699. int rc = 0;
  700. if (NULL == newRDN && NULL == newsuperior) {
  701. /* in delete mode */
  702. /* delete old dn so set that up */
  703. values_del[0] = (char *)slapi_sdn_get_dn(origDN);
  704. values_del[1] = NULL;
  705. attribute1.mod_type = attrName;
  706. attribute1.mod_op = LDAP_MOD_DELETE;
  707. attribute1.mod_values = values_del;
  708. list_of_mods[0] = &attribute1;
  709. /* terminate list of mods. */
  710. list_of_mods[1] = NULL;
  711. rc = _do_modify(mod_pb, entrySDN, list_of_mods);
  712. if (rc) {
  713. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  714. "_update_one_value: entry %s: deleting \"%s: %s\" failed (%d)"
  715. "\n", slapi_sdn_get_dn(entrySDN), attrName, slapi_sdn_get_dn(origDN), rc);
  716. }
  717. } else {
  718. /* in modrdn mode */
  719. const char *superior = NULL;
  720. int nval = 0;
  721. Slapi_Value *v = NULL;
  722. if (NULL == origDN) {
  723. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  724. "_update_one_value: NULL dn was passed\n");
  725. goto bail;
  726. }
  727. /* need to put together rdn into a dn */
  728. dnParts = slapi_ldap_explode_dn( slapi_sdn_get_dn(origDN), 0 );
  729. if (NULL == dnParts) {
  730. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  731. "_update_one_value: failed to explode dn %s\n",
  732. slapi_sdn_get_dn(origDN));
  733. goto bail;
  734. }
  735. if (NULL == newRDN) {
  736. newRDN = dnParts[0];
  737. }
  738. if (newsuperior) {
  739. superior = newsuperior;
  740. } else {
  741. /* do not free superior */
  742. superior = slapi_dn_find_parent(slapi_sdn_get_dn(origDN));
  743. }
  744. /* newRDN and superior are already normalized. */
  745. newDN = slapi_ch_smprintf("%s,%s", newRDN, superior);
  746. slapi_dn_ignore_case(newDN);
  747. /*
  748. * Compare the modified dn with the value of
  749. * the target attribute of referint to find out
  750. * the modified dn is the ancestor (case 2) or
  751. * the value itself (case 1).
  752. *
  753. * E.g.,
  754. * (case 1)
  755. * modrdn: uid=A,ou=B,o=C --> uid=A',ou=B',o=C
  756. * (origDN) (newDN)
  757. * member: uid=A,ou=B,ou=C --> uid=A',ou=B',ou=C
  758. * (sval) (newDN)
  759. *
  760. * (case 2)
  761. * modrdn: ou=B,o=C --> ou=B',o=C
  762. * (origDN) (newDN)
  763. * member: uid=A,ou=B,ou=C --> uid=A,ou=B',ou=C
  764. * (sval) (sval' + newDN)
  765. */
  766. for (nval = slapi_attr_first_value(attr, &v); nval != -1;
  767. nval = slapi_attr_next_value(attr, nval, &v)) {
  768. p = NULL;
  769. dnlen = 0;
  770. /* DN syntax, which should be a string */
  771. sval = slapi_ch_strdup(slapi_value_get_string(v));
  772. rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
  773. if (rc == 0) { /* sval is passed in; not terminated */
  774. *(p + dnlen) = '\0';
  775. sval = p;
  776. } else if (rc > 0) {
  777. slapi_ch_free_string(&sval);
  778. sval = p;
  779. }
  780. /* else: (rc < 0) Ignore the DN normalization error for now. */
  781. p = PL_strstr(sval, slapi_sdn_get_ndn(origDN));
  782. if (p == sval) {
  783. /* (case 1) */
  784. values_del[0] = sval;
  785. values_del[1] = NULL;
  786. attribute1.mod_type = attrName;
  787. attribute1.mod_op = LDAP_MOD_DELETE;
  788. attribute1.mod_values = values_del;
  789. list_of_mods[0] = &attribute1;
  790. values_add[0] = newDN;
  791. values_add[1] = NULL;
  792. attribute2.mod_type = attrName;
  793. attribute2.mod_op = LDAP_MOD_ADD;
  794. attribute2.mod_values = values_add;
  795. list_of_mods[1] = &attribute2;
  796. list_of_mods[2] = NULL;
  797. rc = _do_modify(mod_pb, entrySDN, list_of_mods);
  798. if (rc) {
  799. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  800. "_update_one_value: entry %s: replacing \"%s: %s\" "
  801. "with \"%s: %s\" failed (%d)\n",
  802. slapi_sdn_get_dn(entrySDN), attrName,
  803. slapi_sdn_get_dn(origDN), attrName, newDN, rc);
  804. }
  805. } else if (p) {
  806. char bak;
  807. /* (case 2) */
  808. values_del[0] = sval;
  809. values_del[1] = NULL;
  810. attribute1.mod_type = attrName;
  811. attribute1.mod_op = LDAP_MOD_DELETE;
  812. attribute1.mod_values = values_del;
  813. list_of_mods[0] = &attribute1;
  814. bak = *p;
  815. *p = '\0';
  816. /* newRDN and superior are already normalized. */
  817. newvalue = slapi_ch_smprintf("%s%s", sval, newDN);
  818. *p = bak;
  819. values_add[0]=newvalue;
  820. values_add[1]=NULL;
  821. attribute2.mod_type = attrName;
  822. attribute2.mod_op = LDAP_MOD_ADD;
  823. attribute2.mod_values = values_add;
  824. list_of_mods[1] = &attribute2;
  825. list_of_mods[2] = NULL;
  826. rc = _do_modify(mod_pb, entrySDN, list_of_mods);
  827. if (rc) {
  828. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  829. "_update_one_value: entry %s: replacing \"%s: %s\" "
  830. "with \"%s: %s\" failed (%d)\n",
  831. slapi_sdn_get_dn(entrySDN), attrName, sval, attrName, newvalue, rc);
  832. }
  833. slapi_ch_free_string(&newvalue);
  834. }
  835. /* else: value does not include the modified DN. Ignore it. */
  836. slapi_ch_free_string(&sval);
  837. }
  838. /* cleanup memory allocated for dnParts and newDN */
  839. if (dnParts){
  840. slapi_ldap_value_free(dnParts);
  841. dnParts = NULL;
  842. }
  843. slapi_ch_free_string(&newDN);
  844. }
  845. bail:
  846. return rc;
  847. }
  848. /*
  849. * update multiple attribute values per _do_modify
  850. */
  851. static int
  852. _update_all_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */
  853. Slapi_Attr *attr, /* referred attribute */
  854. char *attrName,
  855. Slapi_DN *origDN, /* original DN that was modified */
  856. char *newRDN, /* new RDN from modrdn */
  857. const char *newsuperior, /* new superior from modrdn */
  858. Slapi_PBlock *mod_pb)
  859. {
  860. Slapi_Mods *smods = NULL;
  861. char *newDN = NULL;
  862. char **dnParts = NULL;
  863. char *sval = NULL;
  864. char *newvalue = NULL;
  865. char *p = NULL;
  866. size_t dnlen = 0;
  867. int rc = 0;
  868. int nval = 0;
  869. slapi_attr_get_numvalues(attr, &nval);
  870. if (NULL == newRDN && NULL == newsuperior) {
  871. /* in delete mode */
  872. LDAPMod *mods[2];
  873. char *values_del[2];
  874. LDAPMod attribute1;
  875. /* delete old dn so set that up */
  876. values_del[0] = (char *)slapi_sdn_get_dn(origDN);
  877. values_del[1] = NULL;
  878. attribute1.mod_type = attrName;
  879. attribute1.mod_op = LDAP_MOD_DELETE;
  880. attribute1.mod_values = values_del;
  881. mods[0] = &attribute1;
  882. /* terminate list of mods. */
  883. mods[1] = NULL;
  884. rc = _do_modify(mod_pb, entrySDN, mods);
  885. if (rc) {
  886. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  887. "_update_all_per_mod: entry %s: deleting \"%s: %s\" failed (%d)"
  888. "\n", slapi_sdn_get_dn(entrySDN), attrName, slapi_sdn_get_dn(origDN), rc);
  889. }
  890. } else {
  891. /* in modrdn mode */
  892. const char *superior = NULL;
  893. int nval = 0;
  894. Slapi_Value *v = NULL;
  895. if (NULL == origDN) {
  896. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  897. "_update_all_per_mod: NULL dn was passed\n");
  898. goto bail;
  899. }
  900. /* need to put together rdn into a dn */
  901. dnParts = slapi_ldap_explode_dn( slapi_sdn_get_dn(origDN), 0 );
  902. if (NULL == dnParts) {
  903. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  904. "_update_all_per_mod: failed to explode dn %s\n",
  905. slapi_sdn_get_dn(origDN));
  906. goto bail;
  907. }
  908. if (NULL == newRDN) {
  909. newRDN = dnParts[0];
  910. }
  911. if (newsuperior) {
  912. superior = newsuperior;
  913. } else {
  914. /* do not free superior */
  915. superior = slapi_dn_find_parent(slapi_sdn_get_dn(origDN));
  916. }
  917. /* newRDN and superior are already normalized. */
  918. newDN = slapi_ch_smprintf("%s,%s", newRDN, superior);
  919. slapi_dn_ignore_case(newDN);
  920. /*
  921. * Compare the modified dn with the value of
  922. * the target attribute of referint to find out
  923. * the modified dn is the ancestor (case 2) or
  924. * the value itself (case 1).
  925. *
  926. * E.g.,
  927. * (case 1)
  928. * modrdn: uid=A,ou=B,o=C --> uid=A',ou=B',o=C
  929. * (origDN) (newDN)
  930. * member: uid=A,ou=B,ou=C --> uid=A',ou=B',ou=C
  931. * (sval) (newDN)
  932. *
  933. * (case 2)
  934. * modrdn: ou=B,o=C --> ou=B',o=C
  935. * (origDN) (newDN)
  936. * member: uid=A,ou=B,ou=C --> uid=A,ou=B',ou=C
  937. * (sval) (sval' + newDN)
  938. */
  939. slapi_attr_get_numvalues(attr, &nval);
  940. smods = slapi_mods_new();
  941. slapi_mods_init(smods, 2 * nval + 1);
  942. for (nval = slapi_attr_first_value(attr, &v);
  943. nval != -1;
  944. nval = slapi_attr_next_value(attr, nval, &v)) {
  945. p = NULL;
  946. dnlen = 0;
  947. /* DN syntax, which should be a string */
  948. sval = slapi_ch_strdup(slapi_value_get_string(v));
  949. rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
  950. if (rc == 0) { /* sval is passed in; not terminated */
  951. *(p + dnlen) = '\0';
  952. sval = p;
  953. } else if (rc > 0) {
  954. slapi_ch_free_string(&sval);
  955. sval = p;
  956. }
  957. /* else: (rc < 0) Ignore the DN normalization error for now. */
  958. p = PL_strstr(sval, slapi_sdn_get_ndn(origDN));
  959. if (p == sval) {
  960. /* (case 1) */
  961. slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval);
  962. slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newDN);
  963. } else if (p) {
  964. /* (case 2) */
  965. slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval);
  966. *p = '\0';
  967. newvalue = slapi_ch_smprintf("%s%s", sval, newDN);
  968. slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newvalue);
  969. slapi_ch_free_string(&newvalue);
  970. }
  971. /* else: value does not include the modified DN. Ignore it. */
  972. slapi_ch_free_string(&sval);
  973. }
  974. rc = _do_modify(mod_pb, entrySDN, slapi_mods_get_ldapmods_byref(smods));
  975. if (rc) {
  976. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  977. "_update_all_per_mod: entry %s failed (%d)\n",
  978. slapi_sdn_get_dn(entrySDN), rc);
  979. }
  980. /* cleanup memory allocated for dnParts and newDN */
  981. if (dnParts){
  982. slapi_ldap_value_free(dnParts);
  983. dnParts = NULL;
  984. }
  985. slapi_ch_free_string(&newDN);
  986. slapi_mods_free(&smods);
  987. }
  988. bail:
  989. return rc;
  990. }
  991. int
  992. update_integrity(Slapi_DN *origSDN,
  993. char *newrDN, Slapi_DN *newsuperior,
  994. int logChanges)
  995. {
  996. Slapi_PBlock *search_result_pb = NULL;
  997. Slapi_PBlock *mod_pb = slapi_pblock_new();
  998. Slapi_Entry **search_entries = NULL;
  999. Slapi_DN *sdn = NULL;
  1000. Slapi_Attr *attr = NULL;
  1001. void *node = NULL;
  1002. const char *origDN = slapi_sdn_get_dn(origSDN);
  1003. const char *search_base = NULL;
  1004. char *attrName = NULL;
  1005. char *filter = NULL;
  1006. char *attrs[2];
  1007. char **membership_attrs = NULL;
  1008. int search_result;
  1009. int nval = 0;
  1010. int i, j;
  1011. int rc = SLAPI_PLUGIN_SUCCESS;
  1012. membership_attrs = referint_get_attrs();
  1013. /*
  1014. * For now, just putting attributes to keep integrity on in conf file,
  1015. * until resolve the other timing mode issue
  1016. */
  1017. search_result_pb = slapi_pblock_new();
  1018. /* Search each namingContext in turn
  1019. * or use the defined scope(s)
  1020. */
  1021. if (plugin_ContainerScope) {
  1022. sdn = plugin_ContainerScope;
  1023. } else {
  1024. sdn = slapi_get_first_suffix( &node, 0 );
  1025. }
  1026. while (sdn)
  1027. {
  1028. Slapi_Backend *be = slapi_be_select(sdn);
  1029. search_base = slapi_sdn_get_dn( sdn );
  1030. for(i = 0; membership_attrs[i] != NULL; i++){
  1031. if(newrDN){
  1032. /* we need to check the children of the old dn, so use a wildcard */
  1033. filter = slapi_filter_sprintf("(%s=*%s%s)", membership_attrs[i], ESC_NEXT_VAL, origDN);
  1034. } else {
  1035. filter = slapi_filter_sprintf("(%s=%s%s)", membership_attrs[i], ESC_NEXT_VAL, origDN);
  1036. }
  1037. if ( filter ) {
  1038. /* Need only the current attribute and its subtypes */
  1039. attrs[0] = membership_attrs[i];
  1040. attrs[1] = NULL;
  1041. /* Use new search API */
  1042. slapi_pblock_init(search_result_pb);
  1043. slapi_pblock_set(search_result_pb, SLAPI_BACKEND, be);
  1044. slapi_search_internal_set_pb(search_result_pb, search_base,
  1045. LDAP_SCOPE_SUBTREE, filter, attrs, 0 /* attrs only */,
  1046. NULL, NULL, referint_plugin_identity, 0);
  1047. slapi_search_internal_pb(search_result_pb);
  1048. slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
  1049. /* if search successfull then do integrity update */
  1050. if(search_result == LDAP_SUCCESS)
  1051. {
  1052. slapi_pblock_get(search_result_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  1053. &search_entries);
  1054. for(j = 0; search_entries[j] != NULL; j++){
  1055. attr = NULL;
  1056. attrName = NULL;
  1057. /*
  1058. * Loop over all the attributes of the entry and search
  1059. * for the integrity attribute and its subtypes
  1060. */
  1061. for (slapi_entry_first_attr(search_entries[j], &attr); attr;
  1062. slapi_entry_next_attr(search_entries[j], attr, &attr))
  1063. {
  1064. /*
  1065. * Take into account only the subtypes of the attribute
  1066. * in argv[i] having the necessary value - origDN
  1067. */
  1068. slapi_attr_get_type(attr, &attrName);
  1069. if (slapi_attr_type_cmp(membership_attrs[i], attrName,
  1070. SLAPI_TYPE_CMP_SUBTYPE) == 0)
  1071. {
  1072. nval = 0;
  1073. slapi_attr_get_numvalues(attr, &nval);
  1074. /*
  1075. * We want to reduce the "modify" call as much as
  1076. * possible. But if an entry contains 1000s of
  1077. * attributes which need to be updated by the
  1078. * referint plugin (e.g., a group containing 1000s
  1079. * of members), we want to avoid to allocate too
  1080. * many mods * in one "modify" call.
  1081. * This is a compromise: If an attribute type has
  1082. * more than 128 values, we update the attribute
  1083. * value one by one. Otherwise, update all values
  1084. * in one "modify" call.
  1085. */
  1086. if (nval > 128) {
  1087. rc = _update_one_per_mod(
  1088. slapi_entry_get_sdn(search_entries[j]),
  1089. attr, attrName, origSDN, newrDN,
  1090. slapi_sdn_get_dn(newsuperior),
  1091. mod_pb);
  1092. } else {
  1093. rc = _update_all_per_mod(
  1094. slapi_entry_get_sdn(search_entries[j]),
  1095. attr, attrName, origSDN, newrDN,
  1096. slapi_sdn_get_dn(newsuperior),
  1097. mod_pb);
  1098. }
  1099. if (rc) {
  1100. if (use_txn) {
  1101. /*
  1102. * We're using backend transactions,
  1103. * so we need to stop on failure.
  1104. */
  1105. rc = SLAPI_PLUGIN_FAILURE;
  1106. goto free_and_return;
  1107. } else {
  1108. rc = SLAPI_PLUGIN_SUCCESS;
  1109. }
  1110. }
  1111. }
  1112. }
  1113. }
  1114. } else {
  1115. if (isFatalSearchError(search_result)){
  1116. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1117. "update_integrity search (base=%s filter=%s) returned "
  1118. "error %d\n", search_base, filter, search_result);
  1119. rc = SLAPI_PLUGIN_FAILURE;
  1120. goto free_and_return;
  1121. }
  1122. }
  1123. slapi_ch_free_string(&filter);
  1124. }
  1125. slapi_free_search_results_internal(search_result_pb);
  1126. }
  1127. if (plugin_ContainerScope) {
  1128. /* at the moment only a single scope is supported
  1129. * so the loop ends after the first iteration
  1130. */
  1131. sdn = NULL;
  1132. } else {
  1133. sdn = slapi_get_next_suffix( &node, 0 );
  1134. }
  1135. }
  1136. free_and_return:
  1137. /* free filter and search_results_pb */
  1138. slapi_ch_free_string(&filter);
  1139. slapi_ch_array_free(membership_attrs);
  1140. slapi_pblock_destroy(mod_pb);
  1141. if (search_result_pb) {
  1142. slapi_free_search_results_internal(search_result_pb);
  1143. slapi_pblock_destroy(search_result_pb);
  1144. }
  1145. return(rc);
  1146. }
  1147. int referint_postop_start( Slapi_PBlock *pb)
  1148. {
  1149. Slapi_Entry *plugin_entry = NULL;
  1150. Slapi_Entry *config_e = NULL;
  1151. Slapi_PBlock *search_pb = NULL;
  1152. Slapi_Entry *e = NULL;
  1153. Slapi_DN *config_sdn = NULL;
  1154. char *config_area = NULL;
  1155. int result = 0;
  1156. int rc = 0;
  1157. if((config_rwlock = slapi_new_rwlock()) == NULL){
  1158. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_init failed to "
  1159. "create rwlock.\n" );
  1160. return ( -1 );
  1161. }
  1162. slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &plugin_entry );
  1163. /* Set the alternate config area if one is defined. */
  1164. slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_AREA, &config_area);
  1165. if (config_area)
  1166. {
  1167. rc = slapi_dn_syntax_check(pb, config_area, 1);
  1168. if (rc) { /* syntax check failed */
  1169. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_start: "
  1170. "%s does not contain a valid DN (%s)\n",
  1171. SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_area);
  1172. rc = LDAP_INVALID_DN_SYNTAX;
  1173. goto bail;
  1174. }
  1175. config_sdn = slapi_sdn_new_dn_byval(config_area);
  1176. result = slapi_search_internal_get_entry(config_sdn, NULL, &e, referint_plugin_identity);
  1177. if (LDAP_SUCCESS != result) {
  1178. if (result == LDAP_NO_SUCH_OBJECT) {
  1179. /* log an error and use the plugin entry for the config */
  1180. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1181. "referint_postop_start: Config entry \"%s\" does "
  1182. "not exist.\n", config_area);
  1183. rc = -1;
  1184. goto bail;
  1185. }
  1186. } else {
  1187. if(e){
  1188. config_e = e;
  1189. } else {
  1190. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1191. "referint_postop_start: Config entry \"%s\" was not located.\n", config_area);
  1192. rc = -1;
  1193. goto bail;
  1194. }
  1195. }
  1196. } else {
  1197. config_e = plugin_entry;
  1198. }
  1199. if(load_config(pb, config_e, STARTUP) != LDAP_SUCCESS){
  1200. rc = -1;
  1201. goto bail;
  1202. }
  1203. referint_set_config_area(slapi_entry_get_sdn(config_e));
  1204. /*
  1205. * Only bother to start the thread if you are in delay mode.
  1206. * 0 = no delay,
  1207. * -1 = integrity off
  1208. */
  1209. if(referint_get_delay() > 0){
  1210. /* initialize the cv and lock */
  1211. if (!use_txn && (NULL == referint_mutex)) {
  1212. referint_mutex = PR_NewLock();
  1213. }
  1214. keeprunning_mutex = PR_NewLock();
  1215. keeprunning_cv = PR_NewCondVar(keeprunning_mutex);
  1216. keeprunning =1;
  1217. referint_tid = PR_CreateThread (PR_USER_THREAD,
  1218. referint_thread_func,
  1219. NULL,
  1220. PR_PRIORITY_NORMAL,
  1221. PR_GLOBAL_THREAD,
  1222. PR_UNJOINABLE_THREAD,
  1223. SLAPD_DEFAULT_THREAD_STACKSIZE);
  1224. if ( referint_tid == NULL ) {
  1225. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1226. "referint_postop_start PR_CreateThread failed\n" );
  1227. exit( 1 );
  1228. }
  1229. }
  1230. bail:
  1231. slapi_free_search_results_internal(search_pb);
  1232. slapi_pblock_destroy(search_pb);
  1233. slapi_sdn_free(&config_sdn);
  1234. slapi_entry_free(e);
  1235. return rc;
  1236. }
  1237. int referint_postop_close( Slapi_PBlock *pb)
  1238. {
  1239. /* signal the thread to exit */
  1240. if (NULL != keeprunning_mutex) {
  1241. PR_Lock(keeprunning_mutex);
  1242. keeprunning=0;
  1243. if (NULL != keeprunning_cv) {
  1244. PR_NotifyCondVar(keeprunning_cv);
  1245. }
  1246. PR_Unlock(keeprunning_mutex);
  1247. }
  1248. slapi_destroy_rwlock(config_rwlock);
  1249. config_rwlock = NULL;
  1250. slapi_ch_free_string(&config->logfile);
  1251. slapi_ch_array_free(config->attrs);
  1252. slapi_ch_free((void **)&config);
  1253. return(0);
  1254. }
  1255. void
  1256. referint_thread_func(void *arg)
  1257. {
  1258. PRFileDesc *prfd = NULL;
  1259. char *logfilename = NULL;
  1260. char thisline[MAX_LINE];
  1261. char delimiter[]="\t\n";
  1262. char *ptoken;
  1263. char *tmprdn;
  1264. char *iter = NULL;
  1265. Slapi_DN *sdn = NULL;
  1266. Slapi_DN *tmpsuperior = NULL;
  1267. int logChanges = 0;
  1268. int delay;
  1269. int no_changes;
  1270. /*
  1271. * keep running this thread until plugin is signaled to close
  1272. */
  1273. while(1){
  1274. /* refresh the config */
  1275. slapi_ch_free_string(&logfilename);
  1276. referint_get_config(&delay, &logChanges, &logfilename);
  1277. no_changes=1;
  1278. while(no_changes){
  1279. PR_Lock(keeprunning_mutex);
  1280. if(keeprunning == 0){
  1281. PR_Unlock(keeprunning_mutex);
  1282. break;
  1283. }
  1284. PR_Unlock(keeprunning_mutex);
  1285. referint_lock();
  1286. if (( prfd = PR_Open( logfilename, PR_RDONLY, REFERINT_DEFAULT_FILE_MODE )) == NULL ){
  1287. referint_unlock();
  1288. /* go back to sleep and wait for this file */
  1289. PR_Lock(keeprunning_mutex);
  1290. PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
  1291. PR_Unlock(keeprunning_mutex);
  1292. } else {
  1293. no_changes = 0;
  1294. }
  1295. }
  1296. /*
  1297. * Check keep running here, because after break out of no
  1298. * changes loop on shutdown, also need to break out of this
  1299. * loop before trying to do the changes. The server
  1300. * will pick them up on next startup as file still exists
  1301. */
  1302. PR_Lock(keeprunning_mutex);
  1303. if(keeprunning == 0){
  1304. PR_Unlock(keeprunning_mutex);
  1305. break;
  1306. }
  1307. PR_Unlock(keeprunning_mutex);
  1308. while( GetNextLine(thisline, MAX_LINE, prfd) ){
  1309. ptoken = ldap_utf8strtok_r(thisline, delimiter, &iter);
  1310. sdn = slapi_sdn_new_normdn_byref(ptoken);
  1311. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  1312. if(!strcasecmp(ptoken, "NULL")) {
  1313. tmprdn = NULL;
  1314. } else {
  1315. tmprdn = slapi_ch_smprintf("%s", ptoken);
  1316. }
  1317. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  1318. if (!strcasecmp(ptoken, "NULL")) {
  1319. tmpsuperior = NULL;
  1320. } else {
  1321. tmpsuperior = slapi_sdn_new_normdn_byref(ptoken);
  1322. }
  1323. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  1324. if (strcasecmp(ptoken, "NULL") != 0) {
  1325. /* Set the bind DN in the thread data */
  1326. if(slapi_td_set_dn(slapi_ch_strdup(ptoken))){
  1327. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,"Failed to set thread data\n");
  1328. }
  1329. }
  1330. update_integrity(sdn, tmprdn, tmpsuperior, logChanges);
  1331. slapi_sdn_free(&sdn);
  1332. slapi_ch_free_string(&tmprdn);
  1333. slapi_sdn_free(&tmpsuperior);
  1334. }
  1335. PR_Close(prfd);
  1336. /* remove the original file */
  1337. if( PR_SUCCESS != PR_Delete(logfilename) ){
  1338. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1339. "referint_postop_close could not delete \"%s\"\n", logfilename );
  1340. }
  1341. /* unlock and let other writers back at the file */
  1342. referint_unlock();
  1343. /* wait on condition here */
  1344. PR_Lock(keeprunning_mutex);
  1345. PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
  1346. PR_Unlock(keeprunning_mutex);
  1347. }
  1348. /* cleanup resources allocated in start */
  1349. if (NULL != keeprunning_mutex) {
  1350. PR_DestroyLock(keeprunning_mutex);
  1351. }
  1352. if (NULL != referint_mutex) {
  1353. PR_DestroyLock(referint_mutex);
  1354. }
  1355. if (NULL != keeprunning_cv) {
  1356. PR_DestroyCondVar(keeprunning_cv);
  1357. }
  1358. slapi_ch_free_string(&logfilename);
  1359. }
  1360. int my_fgetc(PRFileDesc *stream)
  1361. {
  1362. static char buf[READ_BUFSIZE] = "\0";
  1363. static int position = READ_BUFSIZE;
  1364. int retval;
  1365. int err;
  1366. /* check if we need to load the buffer */
  1367. if( READ_BUFSIZE == position )
  1368. {
  1369. memset(buf, '\0', READ_BUFSIZE);
  1370. if( ( err = PR_Read(stream, buf, READ_BUFSIZE) ) >= 0)
  1371. {
  1372. /* it read some data */;
  1373. position = 0;
  1374. }else{
  1375. /* an error occurred */
  1376. return err;
  1377. }
  1378. }
  1379. /* try to read some data */
  1380. if( '\0' == buf[position])
  1381. {
  1382. /* out of data, return eof */
  1383. retval = MY_EOF;
  1384. position = READ_BUFSIZE;
  1385. }else{
  1386. retval = buf[position];
  1387. position++;
  1388. }
  1389. return retval;
  1390. }
  1391. int
  1392. GetNextLine(char *dest, int size_dest, PRFileDesc *stream) {
  1393. char nextchar ='\0';
  1394. int done = 0;
  1395. int i = 0;
  1396. while(!done){
  1397. if( ( nextchar = my_fgetc(stream) ) != 0){
  1398. if( i < (size_dest - 1) ){
  1399. dest[i] = nextchar;
  1400. i++;
  1401. if(nextchar == '\n'){
  1402. /* end of line reached */
  1403. done = 1;
  1404. }
  1405. } else {
  1406. /* no more room in buffer */
  1407. done = 1;
  1408. }
  1409. } else {
  1410. /* error or end of file */
  1411. done = 1;
  1412. }
  1413. }
  1414. dest[i] = '\0';
  1415. /* return size of string read */
  1416. return i;
  1417. }
  1418. /*
  1419. * Write this record to the log file
  1420. */
  1421. void
  1422. writeintegritylog(Slapi_PBlock *pb, char *logfilename, Slapi_DN *sdn,
  1423. char *newrdn, Slapi_DN *newsuperior, Slapi_DN *requestorsdn)
  1424. {
  1425. PRFileDesc *prfd;
  1426. char buffer[MAX_LINE];
  1427. int len_to_write = 0;
  1428. int rc;
  1429. const char *requestordn = NULL;
  1430. const char *newsuperiordn = NULL;
  1431. size_t reqdn_len = 0;
  1432. if (!(referint_sdn_in_entry_scope(sdn) ||
  1433. (newsuperior && referint_sdn_in_entry_scope(newsuperior)))) {
  1434. return;
  1435. }
  1436. /*
  1437. * Use this lock to protect file data when update integrity is occuring.
  1438. * If betxn is enabled, this mutex is ignored; transaction itself takes
  1439. * the role.
  1440. */
  1441. referint_lock();
  1442. if (( prfd = PR_Open( logfilename, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
  1443. REFERINT_DEFAULT_FILE_MODE )) == NULL )
  1444. {
  1445. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1446. "referint_postop could not write integrity log \"%s\" "
  1447. SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
  1448. logfilename, PR_GetError(), slapd_pr_strerror(PR_GetError()) );
  1449. PR_Unlock(referint_mutex);
  1450. referint_unlock();
  1451. return;
  1452. }
  1453. /*
  1454. * Make sure we have enough room in our buffer before trying to write it.
  1455. * add length of dn + 5(three tabs, a newline, and terminating \0)
  1456. */
  1457. len_to_write = slapi_sdn_get_ndn_len(sdn) + 5;
  1458. newsuperiordn = slapi_sdn_get_dn(newsuperior);
  1459. if (newsuperiordn &&
  1460. !referint_sdn_in_entry_scope(newsuperior)) {
  1461. /* this is a modrdn which moves the entry out of scope, handle like a delete */
  1462. newsuperiordn = NULL;
  1463. newrdn = NULL;
  1464. }
  1465. if(newrdn == NULL){
  1466. /* add the length of "NULL" */
  1467. len_to_write += 4;
  1468. } else {
  1469. /* add the length of the newrdn */
  1470. len_to_write += strlen(newrdn);
  1471. }
  1472. if(NULL == newsuperiordn)
  1473. {
  1474. /* add the length of "NULL" */
  1475. len_to_write += 4;
  1476. } else {
  1477. /* add the length of the newsuperior */
  1478. len_to_write += slapi_sdn_get_ndn_len(newsuperior);
  1479. }
  1480. slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &requestordn);
  1481. if (requestorsdn && (requestordn = slapi_sdn_get_udn(requestorsdn)) &&
  1482. (reqdn_len = strlen(requestordn))) {
  1483. len_to_write += reqdn_len;
  1484. } else {
  1485. len_to_write += 4; /* "NULL" */
  1486. }
  1487. if(len_to_write > MAX_LINE ){
  1488. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1489. "referint_postop could not write integrity log:"
  1490. " line length exceeded. It will not be able"
  1491. " to update references to this entry.\n");
  1492. } else {
  1493. PR_snprintf(buffer, MAX_LINE, "%s\t%s\t%s\t%s\t\n", slapi_sdn_get_dn(sdn),
  1494. (newrdn != NULL) ? newrdn : "NULL",
  1495. (newsuperiordn != NULL) ? newsuperiordn : "NULL",
  1496. requestordn ? requestordn : "NULL");
  1497. if (PR_Write(prfd,buffer,strlen(buffer)) < 0){
  1498. slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
  1499. " writeintegritylog: PR_Write failed : The disk"
  1500. " may be full or the file is unwritable :: NSPR error - %d\n",
  1501. PR_GetError());
  1502. }
  1503. }
  1504. /* If file descriptor is closed successfully, PR_SUCCESS */
  1505. rc = PR_Close(prfd);
  1506. if (rc != PR_SUCCESS){
  1507. slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
  1508. " writeintegritylog: failed to close the file descriptor prfd; NSPR error - %d\n",
  1509. PR_GetError());
  1510. }
  1511. referint_unlock();
  1512. }
  1513. static int
  1514. referint_preop_init(Slapi_PBlock *pb)
  1515. {
  1516. int status = 0;
  1517. if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) != 0 ||
  1518. slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &pdesc) != 0 ||
  1519. slapi_pblock_set(pb, premodfn, (void *)referint_validate_config) != 0)
  1520. {
  1521. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1522. "referint_preop_init: failed to register plugin\n");
  1523. status = -1;
  1524. }
  1525. return status;
  1526. }
  1527. /*
  1528. * This is our preop function to validate a config update, postop modify
  1529. * will apply the config change.
  1530. */
  1531. int
  1532. referint_validate_config(Slapi_PBlock *pb)
  1533. {
  1534. Slapi_Entry *config_e = NULL, *e = NULL;
  1535. Slapi_Entry *pre_entry = NULL;
  1536. Slapi_Entry *resulting_entry = NULL;
  1537. Slapi_DN *config_sdn = NULL;
  1538. Slapi_DN *sdn = NULL;
  1539. Slapi_Mods *smods = NULL;
  1540. LDAPMod **mods = NULL;
  1541. char *config_area = NULL;
  1542. int rc = SLAPI_PLUGIN_SUCCESS;
  1543. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
  1544. slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &pre_entry);
  1545. if (!pre_entry) {
  1546. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_validate_config: Null pre op entry.\n");
  1547. rc = LDAP_OPERATIONS_ERROR;
  1548. goto bail;
  1549. }
  1550. if (referint_sdn_config_cmp(sdn) == 0 && slapi_sdn_compare(sdn, referint_get_plugin_area()) ){
  1551. /*
  1552. * This is the shared config entry. Apply the mods and set/validate
  1553. * the config
  1554. */
  1555. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1556. smods = slapi_mods_new();
  1557. slapi_mods_init_byref(smods, mods);
  1558. /*
  1559. * Create a copy of the entry and apply the
  1560. * mods to create the resulting entry.
  1561. */
  1562. resulting_entry = slapi_entry_dup(pre_entry);
  1563. if (mods && (slapi_entry_apply_mods(resulting_entry, mods) != LDAP_SUCCESS)) {
  1564. /* we don't care about this, the update is invalid and will be caught later */
  1565. goto bail;
  1566. }
  1567. if ( SLAPI_PLUGIN_FAILURE == load_config(pb, resulting_entry, 0)) {
  1568. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_validate_config: "
  1569. "configuration validation failed.\n");
  1570. rc = LDAP_UNWILLING_TO_PERFORM;
  1571. goto bail;
  1572. }
  1573. } else if (slapi_sdn_compare(sdn, referint_get_plugin_area()) == 0){
  1574. /*
  1575. * Check if the plugin config area is set(verify it and load its config),
  1576. * otherwise reload the plugin entry config
  1577. */
  1578. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1579. smods = slapi_mods_new();
  1580. slapi_mods_init_byref(smods, mods);
  1581. /* Apply the mods to create the resulting entry. */
  1582. resulting_entry = slapi_entry_dup(pre_entry);
  1583. if (mods && (slapi_entry_apply_mods(resulting_entry, mods) != LDAP_SUCCESS)) {
  1584. /* we don't care about this, the update is invalid and will be caught later */
  1585. goto bail;
  1586. }
  1587. if((config_area = slapi_entry_attr_get_charptr(resulting_entry, SLAPI_PLUGIN_SHARED_CONFIG_AREA))){
  1588. rc = slapi_dn_syntax_check(pb, config_area, 1);
  1589. if (rc) { /* syntax check failed */
  1590. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_validate_config: "
  1591. "%s does not contain a valid DN (%s)\n",
  1592. SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_area);
  1593. rc = LDAP_INVALID_DN_SYNTAX;
  1594. goto bail;
  1595. }
  1596. config_sdn = slapi_sdn_new_dn_byval(config_area);
  1597. rc = slapi_search_internal_get_entry(config_sdn, NULL, &e, referint_plugin_identity);
  1598. if (LDAP_SUCCESS != rc) {
  1599. /* log an error and use the plugin entry for the config */
  1600. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1601. "referint_validate_config: Config entry \"%s\" couild not be found, error %d\n",
  1602. config_area, rc);
  1603. rc = LDAP_OPERATIONS_ERROR;
  1604. goto bail;
  1605. } else {
  1606. if(e){
  1607. config_e = e;
  1608. } else {
  1609. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1610. "referint_validate_config: Config entry \"%s\" was not located.\n", config_area);
  1611. rc = LDAP_OPERATIONS_ERROR;
  1612. goto bail;
  1613. }
  1614. }
  1615. } else {
  1616. config_e = resulting_entry;
  1617. }
  1618. if(load_config(pb, config_e, 0) != LDAP_SUCCESS){
  1619. rc = LDAP_UNWILLING_TO_PERFORM;
  1620. goto bail;
  1621. }
  1622. referint_set_config_area(slapi_entry_get_sdn(config_e));
  1623. }
  1624. bail:
  1625. slapi_entry_free(e);
  1626. slapi_entry_free(resulting_entry);
  1627. slapi_sdn_free(&config_sdn);
  1628. slapi_ch_free_string(&config_area);
  1629. slapi_mods_free(&smods);
  1630. return rc;
  1631. }