referint.c 41 KB

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