referint.c 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  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) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. #include <stdio.h>
  42. #include <string.h>
  43. #include "portable.h"
  44. #include "slapi-plugin.h"
  45. #include "slap.h"
  46. /* include NSPR header files */
  47. #include "prthread.h"
  48. #include "prlock.h"
  49. #include "prerror.h"
  50. #include "prcvar.h"
  51. #include "prio.h"
  52. /* get file mode flags for unix */
  53. #ifndef _WIN32
  54. #include <sys/stat.h>
  55. #endif
  56. #define REFERINT_PLUGIN_SUBSYSTEM "referint-plugin" /* used for logging */
  57. #ifdef _WIN32
  58. #define REFERINT_DEFAULT_FILE_MODE 0
  59. #else
  60. #define REFERINT_DEFAULT_FILE_MODE S_IRUSR | S_IWUSR
  61. #endif
  62. #define MAX_LINE 2048
  63. #define READ_BUFSIZE 4096
  64. #define MY_EOF 0
  65. /* function prototypes */
  66. int referint_postop_init( Slapi_PBlock *pb );
  67. int referint_postop_del( Slapi_PBlock *pb );
  68. int referint_postop_modrdn( Slapi_PBlock *pb );
  69. int referint_postop_start( Slapi_PBlock *pb);
  70. int referint_postop_close( Slapi_PBlock *pb);
  71. int update_integrity(char **argv, Slapi_DN *sDN, char *newrDN, Slapi_DN *newsuperior, int logChanges);
  72. void referint_thread_func(void *arg);
  73. int GetNextLine(char *dest, int size_dest, PRFileDesc *stream);
  74. void writeintegritylog(Slapi_PBlock *pb, char *logfilename, Slapi_DN *sdn, char *newrdn, Slapi_DN *newsuperior, Slapi_DN *requestorsdn);
  75. int my_fgetc(PRFileDesc *stream);
  76. /* global thread control stuff */
  77. static PRLock *referint_mutex = NULL;
  78. static PRThread *referint_tid = NULL;
  79. int keeprunning = 0;
  80. static PRLock *keeprunning_mutex = NULL;
  81. static PRCondVar *keeprunning_cv = NULL;
  82. static Slapi_PluginDesc pdesc = { "referint", VENDOR, DS_PACKAGE_VERSION,
  83. "referential integrity plugin" };
  84. static void* referint_plugin_identity = NULL;
  85. #ifdef _WIN32
  86. int *module_ldap_debug = 0;
  87. void plugin_init_debug_level(int *level_ptr)
  88. {
  89. module_ldap_debug = level_ptr;
  90. }
  91. #endif
  92. int
  93. referint_postop_init( Slapi_PBlock *pb )
  94. {
  95. Slapi_Entry *plugin_entry = NULL;
  96. char *plugin_type = NULL;
  97. int delfn = SLAPI_PLUGIN_POST_DELETE_FN;
  98. int mdnfn = SLAPI_PLUGIN_POST_MODRDN_FN;
  99. /*
  100. * Get plugin identity and stored it for later use
  101. * Used for internal operations
  102. */
  103. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &referint_plugin_identity);
  104. PR_ASSERT (referint_plugin_identity);
  105. /* get args */
  106. if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
  107. plugin_entry &&
  108. (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
  109. plugin_type && strstr(plugin_type, "betxn")) {
  110. delfn = SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN;
  111. mdnfn = SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN;
  112. }
  113. slapi_ch_free_string(&plugin_type);
  114. if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
  115. SLAPI_PLUGIN_VERSION_01 ) != 0 ||
  116. slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
  117. (void *)&pdesc ) != 0 ||
  118. slapi_pblock_set( pb, delfn,
  119. (void *) referint_postop_del ) != 0 ||
  120. slapi_pblock_set( pb, mdnfn,
  121. (void *) referint_postop_modrdn ) != 0 ||
  122. slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
  123. (void *) referint_postop_start ) != 0 ||
  124. slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
  125. (void *) referint_postop_close ) != 0)
  126. {
  127. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  128. "referint_postop_init failed\n" );
  129. return( -1 );
  130. }
  131. return( 0 );
  132. }
  133. int
  134. referint_postop_del( Slapi_PBlock *pb )
  135. {
  136. Slapi_DN *sdn = NULL;
  137. int rc;
  138. int oprc;
  139. char **argv;
  140. int argc;
  141. int delay;
  142. int logChanges=0;
  143. int isrepop = 0;
  144. if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &isrepop ) != 0 ||
  145. slapi_pblock_get( pb, SLAPI_DELETE_TARGET_SDN, &sdn ) != 0 ||
  146. slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
  147. {
  148. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  149. "referint_postop_del: could not get parameters\n" );
  150. return( -1 );
  151. }
  152. /* this plugin should only execute if the delete was successful
  153. and this is not a replicated op
  154. */
  155. if(oprc != 0 || isrepop)
  156. {
  157. return( 0 );
  158. }
  159. /* get args */
  160. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0) {
  161. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  162. "referint_postop failed to get argc\n" );
  163. return( -1 );
  164. }
  165. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0) {
  166. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  167. "referint_postop failed to get argv\n" );
  168. return( -1 );
  169. }
  170. if(argv == NULL){
  171. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  172. "referint_postop_modrdn, args are NULL\n" );
  173. return( -1 );
  174. }
  175. if (argc >= 3) {
  176. /* argv[0] will be the delay */
  177. delay = atoi(argv[0]);
  178. /* argv[2] will be wether or not to log changes */
  179. logChanges = atoi(argv[2]);
  180. if(delay == -1){
  181. /* integrity updating is off */
  182. rc = 0;
  183. }else if(delay == 0){
  184. /* no delay */
  185. /* call function to update references to entry */
  186. rc = update_integrity(argv, sdn, NULL, NULL, logChanges);
  187. }else{
  188. /* write the entry to integrity log */
  189. writeintegritylog(pb, argv[1], sdn, NULL, NULL, NULL /* slapi_get_requestor_sdn(pb) */);
  190. rc = 0;
  191. }
  192. } else {
  193. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  194. "referint_postop insufficient arguments supplied\n" );
  195. return( -1 );
  196. }
  197. return( rc );
  198. }
  199. int
  200. referint_postop_modrdn( Slapi_PBlock *pb )
  201. {
  202. Slapi_DN *sdn = NULL;
  203. char *newrdn;
  204. Slapi_DN *newsuperior;
  205. int oprc;
  206. int rc;
  207. char **argv;
  208. int argc = 0;
  209. int delay;
  210. int logChanges=0;
  211. int isrepop = 0;
  212. if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &isrepop ) != 0 ||
  213. slapi_pblock_get( pb, SLAPI_MODRDN_TARGET_SDN, &sdn ) != 0 ||
  214. slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn ) != 0 ||
  215. slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperior ) != 0 ||
  216. slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 ){
  217. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  218. "referint_postop_modrdn: could not get parameters\n" );
  219. return( -1 );
  220. }
  221. /* this plugin should only execute if the delete was successful
  222. and this is not a replicated op
  223. */
  224. if(oprc != 0 || isrepop){
  225. return( 0 );
  226. }
  227. /* get args */
  228. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0) {
  229. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  230. "referint_postop failed to get argv\n" );
  231. return( -1 );
  232. }
  233. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0) {
  234. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  235. "referint_postop failed to get argv\n" );
  236. return( -1 );
  237. }
  238. if(argv == NULL){
  239. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  240. "referint_postop_modrdn, args are NULL\n" );
  241. return( -1 );
  242. }
  243. if (argc >= 3) {
  244. /* argv[0] will always be the delay */
  245. delay = atoi(argv[0]);
  246. /* argv[2] will be wether or not to log changes */
  247. logChanges = atoi(argv[2]);
  248. } else {
  249. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  250. "referint_postop_modrdn insufficient arguments supplied\n" );
  251. return( -1 );
  252. }
  253. if(delay == -1){
  254. /* integrity updating is off */
  255. rc = 0;
  256. }else if(delay == 0){
  257. /* no delay */
  258. /* call function to update references to entry */
  259. rc = update_integrity(argv, sdn, newrdn, newsuperior, logChanges);
  260. }else{
  261. /* write the entry to integrity log */
  262. writeintegritylog(pb, argv[1], sdn, newrdn, newsuperior, NULL /* slapi_get_requestor_sdn(pb) */);
  263. rc = 0;
  264. }
  265. return( rc );
  266. }
  267. int isFatalSearchError(int search_result)
  268. {
  269. /* Make sure search result is fatal
  270. * Some conditions that happen quite often are not fatal
  271. * for example if you have two suffixes and one is null, you will always
  272. * get no such object, howerever this is not a fatal error.
  273. * Add other conditions to the if statement as they are found
  274. */
  275. /* NPCTE fix for bugid 531225, esc 0. <P.R> <30-May-2001> */
  276. switch(search_result) {
  277. case LDAP_REFERRAL:
  278. case LDAP_NO_SUCH_OBJECT: return 0 ;
  279. }
  280. return 1;
  281. /* end of NPCTE fix for bugid 531225 */
  282. }
  283. static int
  284. _do_modify(Slapi_PBlock *mod_pb, Slapi_DN *entrySDN, LDAPMod **mods)
  285. {
  286. int rc = 0;
  287. slapi_pblock_init(mod_pb);
  288. /* Use internal operation API */
  289. slapi_modify_internal_set_pb_ext(mod_pb, entrySDN, mods, NULL, NULL,
  290. referint_plugin_identity, 0);
  291. slapi_modify_internal_pb(mod_pb);
  292. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  293. return rc;
  294. }
  295. /*
  296. * update one attribute value per _do_modify
  297. */
  298. static int
  299. _update_one_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */
  300. Slapi_Attr *attr, /* referred attribute */
  301. char *attrName,
  302. const char *origDN, /* original DN that was modified */
  303. char *newRDN, /* new RDN from modrdn */
  304. const char *newsuperior, /* new superior from modrdn */
  305. Slapi_PBlock *mod_pb)
  306. {
  307. LDAPMod *list_of_mods[3];
  308. char *values_del[2];
  309. char *values_add[2];
  310. char *newDN = NULL;
  311. char **dnParts = NULL;
  312. char *sval = NULL;
  313. char *newvalue = NULL;
  314. LDAPMod attribute1, attribute2;
  315. int rc = 0;
  316. if (NULL == newRDN && NULL == newsuperior) {
  317. /* in delete mode */
  318. /* delete old dn so set that up */
  319. values_del[0] = (char *)origDN;
  320. values_del[1] = NULL;
  321. attribute1.mod_type = attrName;
  322. attribute1.mod_op = LDAP_MOD_DELETE;
  323. attribute1.mod_values = values_del;
  324. list_of_mods[0] = &attribute1;
  325. /* terminate list of mods. */
  326. list_of_mods[1] = NULL;
  327. rc = _do_modify(mod_pb, entrySDN, list_of_mods);
  328. if (rc) {
  329. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  330. "_update_one_value: entry %s: deleting \"%s: %s\" failed (%d)"
  331. "\n", slapi_sdn_get_dn(entrySDN), attrName, origDN, rc);
  332. }
  333. } else {
  334. /* in modrdn mode */
  335. const char *superior = NULL;
  336. int nval = 0;
  337. Slapi_Value *v = NULL;
  338. if (NULL == origDN) {
  339. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  340. "_update_one_value: NULL dn was passed\n");
  341. goto bail;
  342. }
  343. /* need to put together rdn into a dn */
  344. dnParts = slapi_ldap_explode_dn( origDN, 0 );
  345. if (NULL == dnParts) {
  346. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  347. "_update_one_value: failed to explode dn %s\n",
  348. origDN);
  349. goto bail;
  350. }
  351. if (NULL == newRDN) {
  352. newRDN = dnParts[0];
  353. }
  354. if (newsuperior) {
  355. superior = newsuperior;
  356. } else {
  357. /* no need to free superior */
  358. superior = slapi_dn_find_parent(origDN);
  359. }
  360. /* newRDN and superior are already normalized. */
  361. newDN = slapi_ch_smprintf("%s,%s", newRDN, superior);
  362. slapi_dn_ignore_case(newDN);
  363. /*
  364. * Compare the modified dn with the value of
  365. * the target attribute of referint to find out
  366. * the modified dn is the ancestor (case 2) or
  367. * the value itself (case 1).
  368. *
  369. * E.g.,
  370. * (case 1)
  371. * modrdn: uid=A,ou=B,o=C --> uid=A',ou=B',o=C
  372. * (origDN) (newDN)
  373. * member: uid=A,ou=B,ou=C --> uid=A',ou=B',ou=C
  374. * (sval) (newDN)
  375. *
  376. * (case 2)
  377. * modrdn: ou=B,o=C --> ou=B',o=C
  378. * (origDN) (newDN)
  379. * member: uid=A,ou=B,ou=C --> uid=A,ou=B',ou=C
  380. * (sval) (sval' + newDN)
  381. */
  382. for (nval = slapi_attr_first_value(attr, &v);
  383. nval != -1;
  384. nval = slapi_attr_next_value(attr, nval, &v)) {
  385. char *p = NULL;
  386. size_t dnlen = 0;
  387. /* DN syntax, which should be a string */
  388. sval = slapi_ch_strdup(slapi_value_get_string(v));
  389. rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
  390. if (rc == 0) { /* sval is passed in; not terminated */
  391. *(p + dnlen) = '\0';
  392. sval = p;
  393. } else if (rc > 0) {
  394. slapi_ch_free_string(&sval);
  395. sval = p;
  396. }
  397. /* else: (rc < 0) Ignore the DN normalization error for now. */
  398. p = PL_strstr(sval, origDN);
  399. if (p == sval) {
  400. /* (case 1) */
  401. values_del[0] = sval;
  402. values_del[1] = NULL;
  403. attribute1.mod_type = attrName;
  404. attribute1.mod_op = LDAP_MOD_DELETE;
  405. attribute1.mod_values = values_del;
  406. list_of_mods[0] = &attribute1;
  407. values_add[0] = newDN;
  408. values_add[1] = NULL;
  409. attribute2.mod_type = attrName;
  410. attribute2.mod_op = LDAP_MOD_ADD;
  411. attribute2.mod_values = values_add;
  412. list_of_mods[1] = &attribute2;
  413. list_of_mods[2] = NULL;
  414. rc = _do_modify(mod_pb, entrySDN, list_of_mods);
  415. if (rc) {
  416. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  417. "_update_one_value: entry %s: replacing \"%s: %s\" "
  418. "with \"%s: %s\" failed (%d)\n",
  419. slapi_sdn_get_dn(entrySDN), attrName,
  420. origDN, attrName, newDN, rc);
  421. }
  422. } else if (p) {
  423. char bak;
  424. /* (case 2) */
  425. values_del[0] = sval;
  426. values_del[1] = NULL;
  427. attribute1.mod_type = attrName;
  428. attribute1.mod_op = LDAP_MOD_DELETE;
  429. attribute1.mod_values = values_del;
  430. list_of_mods[0] = &attribute1;
  431. bak = *p;
  432. *p = '\0';
  433. /* newRDN and superior are already normalized. */
  434. newvalue = slapi_ch_smprintf("%s%s", sval, newDN);
  435. *p = bak;
  436. values_add[0]=newvalue;
  437. values_add[1]=NULL;
  438. attribute2.mod_type = attrName;
  439. attribute2.mod_op = LDAP_MOD_ADD;
  440. attribute2.mod_values = values_add;
  441. list_of_mods[1] = &attribute2;
  442. list_of_mods[2] = NULL;
  443. rc = _do_modify(mod_pb, entrySDN, list_of_mods);
  444. if (rc) {
  445. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  446. "_update_one_value: entry %s: replacing \"%s: %s\" "
  447. "with \"%s: %s\" failed (%d)\n",
  448. slapi_sdn_get_dn(entrySDN), attrName, sval, attrName, newvalue, rc);
  449. }
  450. slapi_ch_free_string(&newvalue);
  451. }
  452. /* else: value does not include the modified DN. Ignore it. */
  453. slapi_ch_free_string(&sval);
  454. }
  455. /* cleanup memory allocated for dnParts and newDN */
  456. if (dnParts){
  457. slapi_ldap_value_free(dnParts);
  458. dnParts = NULL;
  459. }
  460. slapi_ch_free_string(&newDN);
  461. }
  462. bail:
  463. return rc;
  464. }
  465. /*
  466. * update multiple attribute values per _do_modify
  467. */
  468. static int
  469. _update_all_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */
  470. Slapi_Attr *attr, /* referred attribute */
  471. char *attrName,
  472. const char *origDN, /* original DN that was modified */
  473. char *newRDN, /* new RDN from modrdn */
  474. const char *newsuperior, /* new superior from modrdn */
  475. Slapi_PBlock *mod_pb)
  476. {
  477. Slapi_Mods *smods = NULL;
  478. char *newDN = NULL;
  479. char **dnParts = NULL;
  480. char *sval = NULL;
  481. char *newvalue = NULL;
  482. int rc = 0;
  483. int nval = 0;
  484. slapi_attr_get_numvalues(attr, &nval);
  485. if (NULL == newRDN && NULL == newsuperior) {
  486. /* in delete mode */
  487. LDAPMod *mods[2];
  488. char *values_del[2];
  489. LDAPMod attribute1;
  490. /* delete old dn so set that up */
  491. values_del[0] = (char *)origDN;
  492. values_del[1] = NULL;
  493. attribute1.mod_type = attrName;
  494. attribute1.mod_op = LDAP_MOD_DELETE;
  495. attribute1.mod_values = values_del;
  496. mods[0] = &attribute1;
  497. /* terminate list of mods. */
  498. mods[1] = NULL;
  499. rc = _do_modify(mod_pb, entrySDN, mods);
  500. if (rc) {
  501. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  502. "_update_all_per_mod: entry %s: deleting \"%s: %s\" failed (%d)"
  503. "\n", slapi_sdn_get_dn(entrySDN), attrName, origDN, rc);
  504. }
  505. } else {
  506. /* in modrdn mode */
  507. const char *superior = NULL;
  508. int nval = 0;
  509. Slapi_Value *v = NULL;
  510. if (NULL == origDN) {
  511. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  512. "_update_all_per_mod: NULL dn was passed\n");
  513. goto bail;
  514. }
  515. /* need to put together rdn into a dn */
  516. dnParts = slapi_ldap_explode_dn( origDN, 0 );
  517. if (NULL == dnParts) {
  518. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  519. "_update_all_per_mod: failed to explode dn %s\n",
  520. origDN);
  521. goto bail;
  522. }
  523. if (NULL == newRDN) {
  524. newRDN = dnParts[0];
  525. }
  526. if (newsuperior) {
  527. superior = newsuperior;
  528. } else {
  529. /* no need to free superior */
  530. superior = slapi_dn_find_parent(origDN);
  531. }
  532. /* newRDN and superior are already normalized. */
  533. newDN = slapi_ch_smprintf("%s,%s", newRDN, superior);
  534. slapi_dn_ignore_case(newDN);
  535. /*
  536. * Compare the modified dn with the value of
  537. * the target attribute of referint to find out
  538. * the modified dn is the ancestor (case 2) or
  539. * the value itself (case 1).
  540. *
  541. * E.g.,
  542. * (case 1)
  543. * modrdn: uid=A,ou=B,o=C --> uid=A',ou=B',o=C
  544. * (origDN) (newDN)
  545. * member: uid=A,ou=B,ou=C --> uid=A',ou=B',ou=C
  546. * (sval) (newDN)
  547. *
  548. * (case 2)
  549. * modrdn: ou=B,o=C --> ou=B',o=C
  550. * (origDN) (newDN)
  551. * member: uid=A,ou=B,ou=C --> uid=A,ou=B',ou=C
  552. * (sval) (sval' + newDN)
  553. */
  554. slapi_attr_get_numvalues(attr, &nval);
  555. smods = slapi_mods_new();
  556. slapi_mods_init(smods, 2 * nval + 1);
  557. for (nval = slapi_attr_first_value(attr, &v);
  558. nval != -1;
  559. nval = slapi_attr_next_value(attr, nval, &v)) {
  560. char *p = NULL;
  561. size_t dnlen = 0;
  562. /* DN syntax, which should be a string */
  563. sval = slapi_ch_strdup(slapi_value_get_string(v));
  564. rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
  565. if (rc == 0) { /* sval is passed in; not terminated */
  566. *(p + dnlen) = '\0';
  567. sval = p;
  568. } else if (rc > 0) {
  569. slapi_ch_free_string(&sval);
  570. sval = p;
  571. }
  572. /* else: (rc < 0) Ignore the DN normalization error for now. */
  573. p = PL_strstr(sval, origDN);
  574. if (p == sval) {
  575. /* (case 1) */
  576. slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval);
  577. slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newDN);
  578. } else if (p) {
  579. /* (case 2) */
  580. slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval);
  581. *p = '\0';
  582. newvalue = slapi_ch_smprintf("%s%s", sval, newDN);
  583. slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newvalue);
  584. slapi_ch_free_string(&newvalue);
  585. }
  586. /* else: value does not include the modified DN. Ignore it. */
  587. slapi_ch_free_string(&sval);
  588. }
  589. rc = _do_modify(mod_pb, entrySDN, slapi_mods_get_ldapmods_byref(smods));
  590. if (rc) {
  591. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  592. "_update_all_per_mod: entry %s failed (%d)\n",
  593. slapi_sdn_get_dn(entrySDN), rc);
  594. }
  595. /* cleanup memory allocated for dnParts and newDN */
  596. if (dnParts){
  597. slapi_ldap_value_free(dnParts);
  598. dnParts = NULL;
  599. }
  600. slapi_ch_free_string(&newDN);
  601. slapi_mods_free(&smods);
  602. }
  603. bail:
  604. return rc;
  605. }
  606. int
  607. update_integrity(char **argv, Slapi_DN *origSDN,
  608. char *newrDN, Slapi_DN *newsuperior,
  609. int logChanges)
  610. {
  611. Slapi_PBlock *search_result_pb = NULL;
  612. Slapi_PBlock *mod_pb = slapi_pblock_new();
  613. Slapi_Entry **search_entries = NULL;
  614. int search_result;
  615. Slapi_DN *sdn = NULL;
  616. void *node = NULL;
  617. char *filter = NULL;
  618. int i, j;
  619. const char *search_base = NULL;
  620. int rc;
  621. size_t len = slapi_sdn_get_ndn_len(origSDN);
  622. const char *origDN = slapi_sdn_get_dn(origSDN);
  623. if ( argv == NULL ) {
  624. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  625. "referint_postop required config file arguments missing\n" );
  626. rc = -1;
  627. goto free_and_return;
  628. }
  629. /* for now, just putting attributes to keep integrity on in conf file,
  630. until resolve the other timing mode issue */
  631. search_result_pb = slapi_pblock_new();
  632. /* Search each namingContext in turn */
  633. for ( sdn = slapi_get_first_suffix( &node, 0 ); sdn != NULL;
  634. sdn = slapi_get_next_suffix( &node, 0 ))
  635. {
  636. search_base = slapi_sdn_get_dn( sdn );
  637. for(i = 3; argv[i] != NULL; i++)
  638. {
  639. char buf[BUFSIZ];
  640. filter = slapi_ch_smprintf("(%s=*%s)", argv[i],
  641. escape_filter_value(origDN, len, buf));
  642. if ( filter ) {
  643. /* Need only the current attribute and its subtypes */
  644. char *attrs[2];
  645. attrs[0] = argv[i];
  646. attrs[1] = NULL;
  647. /* Use new search API */
  648. slapi_pblock_init(search_result_pb);
  649. slapi_search_internal_set_pb(search_result_pb, search_base,
  650. LDAP_SCOPE_SUBTREE, filter, attrs, 0 /* attrs only */,
  651. NULL, NULL, referint_plugin_identity, 0);
  652. slapi_search_internal_pb(search_result_pb);
  653. slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT,
  654. &search_result);
  655. /* if search successfull then do integrity update */
  656. if(search_result == LDAP_SUCCESS)
  657. {
  658. slapi_pblock_get(search_result_pb,
  659. SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  660. &search_entries);
  661. for(j=0; search_entries[j] != NULL; j++)
  662. {
  663. Slapi_Attr *attr = NULL;
  664. char *attrName = NULL;
  665. /* Loop over all the attributes of the entry and search
  666. * for the integrity attribute and its subtypes */
  667. for (slapi_entry_first_attr(search_entries[j], &attr); attr;
  668. slapi_entry_next_attr(search_entries[j], attr, &attr))
  669. {
  670. /* Take into account only the subtypes of the attribute
  671. * in argv[i] having the necessary value - origDN */
  672. slapi_attr_get_type(attr, &attrName);
  673. if (slapi_attr_type_cmp(argv[i], attrName,
  674. SLAPI_TYPE_CMP_SUBTYPE) == 0)
  675. {
  676. int nval = 0;
  677. slapi_attr_get_numvalues(attr, &nval);
  678. /*
  679. * We want to reduce the "modify" call as much as
  680. * possible. But if an entry contains 1000s of
  681. * attributes which need to be updated by the
  682. * referint plugin (e.g., a group containing 1000s
  683. * of members), we want to avoid to allocate too
  684. * many mods * in one "modify" call.
  685. * This is a compromise: If an attribute type has
  686. * more than 128 values, we update the attribute
  687. * value one by one. Otherwise, update all values
  688. * in one "modify" call.
  689. */
  690. if (nval > 128) {
  691. rc = _update_one_per_mod(
  692. slapi_entry_get_sdn(search_entries[j]),
  693. attr, attrName, origDN, newrDN,
  694. slapi_sdn_get_dn(newsuperior),
  695. mod_pb);
  696. } else {
  697. rc = _update_all_per_mod(
  698. slapi_entry_get_sdn(search_entries[j]),
  699. attr, attrName, origDN, newrDN,
  700. slapi_sdn_get_dn(newsuperior),
  701. mod_pb);
  702. }
  703. /* Should we stop if one modify returns an error? */
  704. }
  705. }
  706. }
  707. } else {
  708. if (isFatalSearchError(search_result))
  709. {
  710. /* NPCTE fix for bugid 531225, esc 0. <P.R> <30-May-2001> */
  711. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  712. "update_integrity search (base=%s filter=%s) returned "
  713. "error %d\n", search_base, filter, search_result);
  714. /* end of NPCTE fix for bugid 531225 */
  715. rc = -1;
  716. goto free_and_return;
  717. }
  718. }
  719. slapi_ch_free_string(&filter);
  720. }
  721. slapi_free_search_results_internal(search_result_pb);
  722. }
  723. }
  724. /* if got here, then everything good rc = 0 */
  725. rc = 0;
  726. free_and_return:
  727. /* free filter and search_results_pb */
  728. slapi_ch_free_string(&filter);
  729. slapi_pblock_destroy(mod_pb);
  730. if (search_result_pb) {
  731. slapi_free_search_results_internal(search_result_pb);
  732. slapi_pblock_destroy(search_result_pb);
  733. }
  734. return(rc);
  735. }
  736. int referint_postop_start( Slapi_PBlock *pb)
  737. {
  738. char **argv;
  739. int argc = 0;
  740. /* get args */
  741. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0 ) {
  742. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  743. "referint_postop failed to get argv\n" );
  744. return( -1 );
  745. }
  746. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
  747. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  748. "referint_postop failed to get argv\n" );
  749. return( -1 );
  750. }
  751. if(argv == NULL){
  752. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  753. "args were null in referint_postop_start\n" );
  754. return( -1 );
  755. }
  756. /* only bother to start the thread if you are in delay mode.
  757. 0 = no delay,
  758. -1 = integrity off */
  759. if (argc >= 1) {
  760. if(atoi(argv[0]) > 0){
  761. /* initialize cv and lock */
  762. referint_mutex = PR_NewLock();
  763. keeprunning_mutex = PR_NewLock();
  764. keeprunning_cv = PR_NewCondVar(keeprunning_mutex);
  765. keeprunning =1;
  766. referint_tid = PR_CreateThread (PR_USER_THREAD,
  767. referint_thread_func,
  768. (void *)argv,
  769. PR_PRIORITY_NORMAL,
  770. PR_GLOBAL_THREAD,
  771. PR_UNJOINABLE_THREAD,
  772. SLAPD_DEFAULT_THREAD_STACKSIZE);
  773. if ( referint_tid == NULL ) {
  774. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  775. "referint_postop_start PR_CreateThread failed\n" );
  776. exit( 1 );
  777. }
  778. }
  779. } else {
  780. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  781. "referint_postop_start insufficient arguments supplied\n" );
  782. return( -1 );
  783. }
  784. return(0);
  785. }
  786. int referint_postop_close( Slapi_PBlock *pb)
  787. {
  788. /* signal the thread to exit */
  789. if (NULL != keeprunning_mutex) {
  790. PR_Lock(keeprunning_mutex);
  791. keeprunning=0;
  792. if (NULL != keeprunning_cv) {
  793. PR_NotifyCondVar(keeprunning_cv);
  794. }
  795. PR_Unlock(keeprunning_mutex);
  796. }
  797. return(0);
  798. }
  799. void
  800. referint_thread_func(void *arg)
  801. {
  802. char **plugin_argv = (char **)arg;
  803. PRFileDesc *prfd;
  804. char *logfilename;
  805. char thisline[MAX_LINE];
  806. int delay;
  807. int no_changes;
  808. char delimiter[]="\t\n";
  809. char *ptoken;
  810. Slapi_DN *sdn = NULL;
  811. char *tmprdn;
  812. Slapi_DN *tmpsuperior = NULL;
  813. int logChanges=0;
  814. char * iter = NULL;
  815. if(plugin_argv == NULL){
  816. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  817. "referint_thread_func not get args \n" );
  818. return;
  819. }
  820. /* initialize the thread data index
  821. if(slapi_td_dn_init()){
  822. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,"Failed to create thread data index\n");
  823. } */
  824. delay = atoi(plugin_argv[0]);
  825. logfilename = plugin_argv[1];
  826. logChanges = atoi(plugin_argv[2]);
  827. /* keep running this thread until plugin is signalled to close */
  828. while(1){
  829. no_changes=1;
  830. while(no_changes){
  831. PR_Lock(keeprunning_mutex);
  832. if(keeprunning == 0){
  833. PR_Unlock(keeprunning_mutex);
  834. break;
  835. }
  836. PR_Unlock(keeprunning_mutex);
  837. PR_Lock(referint_mutex);
  838. if (( prfd = PR_Open( logfilename, PR_RDONLY,
  839. REFERINT_DEFAULT_FILE_MODE )) == NULL )
  840. {
  841. PR_Unlock(referint_mutex);
  842. /* go back to sleep and wait for this file */
  843. PR_Lock(keeprunning_mutex);
  844. PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
  845. PR_Unlock(keeprunning_mutex);
  846. }else{
  847. no_changes = 0;
  848. }
  849. }
  850. /* check keep running here, because after break out of no
  851. * changes loop on shutdown, also need to break out of this
  852. * loop before trying to do the changes. The server
  853. * will pick them up on next startup as file still exists
  854. */
  855. PR_Lock(keeprunning_mutex);
  856. if(keeprunning == 0){
  857. PR_Unlock(keeprunning_mutex);
  858. break;
  859. }
  860. PR_Unlock(keeprunning_mutex);
  861. while( GetNextLine(thisline, MAX_LINE, prfd) ){
  862. ptoken = ldap_utf8strtok_r(thisline, delimiter, &iter);
  863. sdn = slapi_sdn_new_normdn_byref(ptoken);
  864. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  865. if(!strcasecmp(ptoken, "NULL")) {
  866. tmprdn = NULL;
  867. } else {
  868. tmprdn = slapi_ch_smprintf("%s", ptoken);
  869. }
  870. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  871. if (!strcasecmp(ptoken, "NULL")) {
  872. tmpsuperior = NULL;
  873. } else {
  874. tmpsuperior = slapi_sdn_new_normdn_byref(ptoken);
  875. }
  876. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  877. if (strcasecmp(ptoken, "NULL") != 0) {
  878. /* Set the bind DN in the thread data */
  879. if(slapi_td_set_dn(slapi_ch_strdup(ptoken))){
  880. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,"Failed to set thread data\n");
  881. }
  882. }
  883. update_integrity(plugin_argv, sdn, tmprdn,
  884. tmpsuperior, logChanges);
  885. slapi_sdn_free(&sdn);
  886. slapi_ch_free_string(&tmprdn);
  887. slapi_sdn_free(&tmpsuperior);
  888. }
  889. PR_Close(prfd);
  890. /* remove the original file */
  891. if( PR_SUCCESS != PR_Delete(logfilename) )
  892. {
  893. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  894. "referint_postop_close could not delete \"%s\"\n",
  895. logfilename );
  896. }
  897. /* unlock and let other writers back at the file */
  898. PR_Unlock(referint_mutex);
  899. /* wait on condition here */
  900. PR_Lock(keeprunning_mutex);
  901. PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
  902. PR_Unlock(keeprunning_mutex);
  903. }
  904. /* cleanup resources allocated in start */
  905. if (NULL != keeprunning_mutex) {
  906. PR_DestroyLock(keeprunning_mutex);
  907. }
  908. if (NULL != referint_mutex) {
  909. PR_DestroyLock(referint_mutex);
  910. }
  911. if (NULL != keeprunning_cv) {
  912. PR_DestroyCondVar(keeprunning_cv);
  913. }
  914. }
  915. int my_fgetc(PRFileDesc *stream)
  916. {
  917. static char buf[READ_BUFSIZE] = "\0";
  918. static int position = READ_BUFSIZE;
  919. int retval;
  920. int err;
  921. /* check if we need to load the buffer */
  922. if( READ_BUFSIZE == position )
  923. {
  924. memset(buf, '\0', READ_BUFSIZE);
  925. if( ( err = PR_Read(stream, buf, READ_BUFSIZE) ) >= 0)
  926. {
  927. /* it read some data */;
  928. position = 0;
  929. }else{
  930. /* an error occurred */
  931. return err;
  932. }
  933. }
  934. /* try to read some data */
  935. if( '\0' == buf[position])
  936. {
  937. /* out of data, return eof */
  938. retval = MY_EOF;
  939. position = READ_BUFSIZE;
  940. }else{
  941. retval = buf[position];
  942. position++;
  943. }
  944. return retval;
  945. }
  946. int
  947. GetNextLine(char *dest, int size_dest, PRFileDesc *stream) {
  948. char nextchar ='\0';
  949. int done = 0;
  950. int i = 0;
  951. while(!done)
  952. {
  953. if( ( nextchar = my_fgetc(stream) ) != 0)
  954. {
  955. if( i < (size_dest - 1) )
  956. {
  957. dest[i] = nextchar;
  958. i++;
  959. if(nextchar == '\n')
  960. {
  961. /* end of line reached */
  962. done = 1;
  963. }
  964. }else{
  965. /* no more room in buffer */
  966. done = 1;
  967. }
  968. }else{
  969. /* error or end of file */
  970. done = 1;
  971. }
  972. }
  973. dest[i] = '\0';
  974. /* return size of string read */
  975. return i;
  976. }
  977. void
  978. writeintegritylog(Slapi_PBlock *pb, char *logfilename, Slapi_DN *sdn,
  979. char *newrdn, Slapi_DN *newsuperior, Slapi_DN *requestorsdn)
  980. {
  981. PRFileDesc *prfd;
  982. char buffer[MAX_LINE];
  983. int len_to_write = 0;
  984. int rc;
  985. const char *requestordn = NULL;
  986. size_t reqdn_len = 0;
  987. /* write this record to the file */
  988. /* use this lock to protect file data when update integrity is occuring */
  989. /* should hopefully not be a big issue on concurrency */
  990. PR_Lock(referint_mutex);
  991. if (( prfd = PR_Open( logfilename, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
  992. REFERINT_DEFAULT_FILE_MODE )) == NULL )
  993. {
  994. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  995. "referint_postop could not write integrity log \"%s\" "
  996. SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
  997. logfilename, PR_GetError(), slapd_pr_strerror(PR_GetError()) );
  998. PR_Unlock(referint_mutex);
  999. return;
  1000. }
  1001. /* make sure we have enough room in our buffer
  1002. before trying to write it
  1003. */
  1004. /* add length of dn + 5(three tabs, a newline, and terminating \0) */
  1005. len_to_write = slapi_sdn_get_ndn_len(sdn) + 5;
  1006. if(newrdn == NULL)
  1007. {
  1008. /* add the length of "NULL" */
  1009. len_to_write += 4;
  1010. }else{
  1011. /* add the length of the newrdn */
  1012. len_to_write += strlen(newrdn);
  1013. }
  1014. if(NULL == newsuperior)
  1015. {
  1016. /* add the length of "NULL" */
  1017. len_to_write += 4;
  1018. }else{
  1019. /* add the length of the newsuperior */
  1020. len_to_write += slapi_sdn_get_ndn_len(newsuperior);
  1021. }
  1022. slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &requestordn);
  1023. if (requestorsdn && (requestordn = slapi_sdn_get_udn(requestorsdn)) &&
  1024. (reqdn_len = strlen(requestordn))) {
  1025. len_to_write += reqdn_len;
  1026. } else {
  1027. len_to_write += 4; /* "NULL" */
  1028. }
  1029. if(len_to_write > MAX_LINE )
  1030. {
  1031. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1032. "referint_postop could not write integrity log:"
  1033. " line length exceeded. It will not be able"
  1034. " to update references to this entry.\n");
  1035. }else{
  1036. PR_snprintf(buffer, MAX_LINE, "%s\t%s\t%s\t%s\t\n",
  1037. slapi_sdn_get_dn(sdn),
  1038. (newrdn != NULL) ? newrdn : "NULL",
  1039. (newsuperior != NULL) ? slapi_sdn_get_dn(newsuperior) :
  1040. "NULL",
  1041. requestordn ? requestordn : "NULL");
  1042. if (PR_Write(prfd,buffer,strlen(buffer)) < 0){
  1043. slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
  1044. " writeintegritylog: PR_Write failed : The disk"
  1045. " may be full or the file is unwritable :: NSPR error - %d\n",
  1046. PR_GetError());
  1047. }
  1048. }
  1049. /* If file descriptor is closed successfully, PR_SUCCESS */
  1050. rc = PR_Close(prfd);
  1051. if (rc != PR_SUCCESS)
  1052. {
  1053. slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
  1054. " writeintegritylog: failed to close the file"
  1055. " descriptor prfd; NSPR error - %d\n",
  1056. PR_GetError());
  1057. }
  1058. PR_Unlock(referint_mutex);
  1059. }