referint.c 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202
  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,
  260. newsuperior, logChanges);
  261. }else{
  262. /* write the entry to integrity log */
  263. writeintegritylog(pb, argv[1], sdn, newrdn, newsuperior, NULL /* slapi_get_requestor_sdn(pb) */);
  264. rc = 0;
  265. }
  266. return( rc );
  267. }
  268. int isFatalSearchError(int search_result)
  269. {
  270. /* Make sure search result is fatal
  271. * Some conditions that happen quite often are not fatal
  272. * for example if you have two suffixes and one is null, you will always
  273. * get no such object, howerever this is not a fatal error.
  274. * Add other conditions to the if statement as they are found
  275. */
  276. /* NPCTE fix for bugid 531225, esc 0. <P.R> <30-May-2001> */
  277. switch(search_result) {
  278. case LDAP_REFERRAL:
  279. case LDAP_NO_SUCH_OBJECT: return 0 ;
  280. }
  281. return 1;
  282. /* end of NPCTE fix for bugid 531225 */
  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. /* Use internal operation API */
  290. slapi_modify_internal_set_pb_ext(mod_pb, entrySDN, mods, NULL, NULL,
  291. referint_plugin_identity, 0);
  292. slapi_modify_internal_pb(mod_pb);
  293. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  294. return rc;
  295. }
  296. /*
  297. * update one attribute value per _do_modify
  298. */
  299. static int
  300. _update_one_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */
  301. Slapi_Attr *attr, /* referred attribute */
  302. char *attrName,
  303. const char *origDN, /* original DN that was modified */
  304. char *newRDN, /* new RDN from modrdn */
  305. const char *newsuperior, /* new superior from modrdn */
  306. Slapi_PBlock *mod_pb)
  307. {
  308. LDAPMod *list_of_mods[3];
  309. char *values_del[2];
  310. char *values_add[2];
  311. char *newDN = NULL;
  312. char **dnParts = NULL;
  313. char *sval = NULL;
  314. char *newvalue = NULL;
  315. LDAPMod attribute1, attribute2;
  316. int rc = 0;
  317. if (NULL == newRDN && NULL == newsuperior) {
  318. /* in delete mode */
  319. /* delete old dn so set that up */
  320. values_del[0] = (char *)origDN;
  321. values_del[1] = NULL;
  322. attribute1.mod_type = attrName;
  323. attribute1.mod_op = LDAP_MOD_DELETE;
  324. attribute1.mod_values = values_del;
  325. list_of_mods[0] = &attribute1;
  326. /* terminate list of mods. */
  327. list_of_mods[1] = NULL;
  328. rc = _do_modify(mod_pb, entrySDN, list_of_mods);
  329. if (rc) {
  330. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  331. "_update_one_value: entry %s: deleting \"%s: %s\" failed (%d)"
  332. "\n", slapi_sdn_get_dn(entrySDN), attrName, origDN, rc);
  333. }
  334. } else {
  335. /* in modrdn mode */
  336. const char *superior = NULL;
  337. int nval = 0;
  338. Slapi_Value *v = NULL;
  339. if (NULL == origDN) {
  340. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  341. "_update_one_value: NULL dn was passed\n");
  342. goto bail;
  343. }
  344. /* need to put together rdn into a dn */
  345. dnParts = slapi_ldap_explode_dn( origDN, 0 );
  346. if (NULL == dnParts) {
  347. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  348. "_update_one_value: failed to explode dn %s\n",
  349. origDN);
  350. goto bail;
  351. }
  352. if (NULL == newRDN) {
  353. newRDN = dnParts[0];
  354. }
  355. if (newsuperior) {
  356. superior = newsuperior;
  357. } else {
  358. /* no need to free superior */
  359. superior = slapi_dn_find_parent(origDN);
  360. }
  361. /* newRDN and superior are already normalized. */
  362. newDN = slapi_ch_smprintf("%s,%s", newRDN, superior);
  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. newDN = slapi_ch_smprintf("%s,%s", newRDN, superior);
  533. /*
  534. * Compare the modified dn with the value of
  535. * the target attribute of referint to find out
  536. * the modified dn is the ancestor (case 2) or
  537. * the value itself (case 1).
  538. *
  539. * E.g.,
  540. * (case 1)
  541. * modrdn: uid=A,ou=B,o=C --> uid=A',ou=B',o=C
  542. * (origDN) (newDN)
  543. * member: uid=A,ou=B,ou=C --> uid=A',ou=B',ou=C
  544. * (sval) (newDN)
  545. *
  546. * (case 2)
  547. * modrdn: ou=B,o=C --> ou=B',o=C
  548. * (origDN) (newDN)
  549. * member: uid=A,ou=B,ou=C --> uid=A,ou=B',ou=C
  550. * (sval) (sval' + newDN)
  551. */
  552. slapi_attr_get_numvalues(attr, &nval);
  553. smods = slapi_mods_new();
  554. slapi_mods_init(smods, 2 * nval + 1);
  555. for (nval = slapi_attr_first_value(attr, &v);
  556. nval != -1;
  557. nval = slapi_attr_next_value(attr, nval, &v)) {
  558. char *p = NULL;
  559. size_t dnlen = 0;
  560. /* DN syntax, which should be a string */
  561. sval = slapi_ch_strdup(slapi_value_get_string(v));
  562. rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
  563. if (rc == 0) { /* sval is passed in; not terminated */
  564. *(p + dnlen) = '\0';
  565. sval = p;
  566. } else if (rc > 0) {
  567. slapi_ch_free_string(&sval);
  568. sval = p;
  569. }
  570. /* else: (rc < 0) Ignore the DN normalization error for now. */
  571. p = PL_strstr(sval, origDN);
  572. if (p == sval) {
  573. /* (case 1) */
  574. slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval);
  575. slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newDN);
  576. } else if (p) {
  577. /* (case 2) */
  578. slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval);
  579. *p = '\0';
  580. newvalue = slapi_ch_smprintf("%s%s", sval, newDN);
  581. slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newvalue);
  582. slapi_ch_free_string(&newvalue);
  583. }
  584. /* else: value does not include the modified DN. Ignore it. */
  585. slapi_ch_free_string(&sval);
  586. }
  587. rc = _do_modify(mod_pb, entrySDN, slapi_mods_get_ldapmods_byref(smods));
  588. if (rc) {
  589. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  590. "_update_all_per_mod: entry %s failed (%d)\n",
  591. slapi_sdn_get_dn(entrySDN), rc);
  592. }
  593. /* cleanup memory allocated for dnParts and newDN */
  594. if (dnParts){
  595. slapi_ldap_value_free(dnParts);
  596. dnParts = NULL;
  597. }
  598. slapi_ch_free_string(&newDN);
  599. slapi_mods_free(&smods);
  600. }
  601. bail:
  602. return rc;
  603. }
  604. int
  605. update_integrity(char **argv, Slapi_DN *origSDN,
  606. char *newrDN, Slapi_DN *newsuperior,
  607. int logChanges)
  608. {
  609. Slapi_PBlock *search_result_pb = NULL;
  610. Slapi_PBlock *mod_pb = slapi_pblock_new();
  611. Slapi_Entry **search_entries = NULL;
  612. int search_result;
  613. Slapi_DN *sdn = NULL;
  614. void *node = NULL;
  615. char *filter = NULL;
  616. int i, j;
  617. const char *search_base = NULL;
  618. int rc;
  619. size_t len = slapi_sdn_get_ndn_len(origSDN);
  620. const char *origDN = slapi_sdn_get_dn(origSDN);
  621. if ( argv == NULL ) {
  622. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  623. "referint_postop required config file arguments missing\n" );
  624. rc = -1;
  625. goto free_and_return;
  626. }
  627. /* for now, just putting attributes to keep integrity on in conf file,
  628. until resolve the other timing mode issue */
  629. search_result_pb = slapi_pblock_new();
  630. /* Search each namingContext in turn */
  631. for ( sdn = slapi_get_first_suffix( &node, 0 ); sdn != NULL;
  632. sdn = slapi_get_next_suffix( &node, 0 ))
  633. {
  634. search_base = slapi_sdn_get_dn( sdn );
  635. for(i = 3; argv[i] != NULL; i++)
  636. {
  637. char buf[BUFSIZ];
  638. filter = slapi_ch_smprintf("(%s=*%s)", argv[i],
  639. escape_filter_value(origDN, len, buf));
  640. if ( filter ) {
  641. /* Need only the current attribute and its subtypes */
  642. char *attrs[2];
  643. attrs[0] = argv[i];
  644. attrs[1] = NULL;
  645. /* Use new search API */
  646. slapi_pblock_init(search_result_pb);
  647. slapi_search_internal_set_pb(search_result_pb, search_base,
  648. LDAP_SCOPE_SUBTREE, filter, attrs, 0 /* attrs only */,
  649. NULL, NULL, referint_plugin_identity, 0);
  650. slapi_search_internal_pb(search_result_pb);
  651. slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT,
  652. &search_result);
  653. /* if search successfull then do integrity update */
  654. if(search_result == LDAP_SUCCESS)
  655. {
  656. slapi_pblock_get(search_result_pb,
  657. SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  658. &search_entries);
  659. for(j=0; search_entries[j] != NULL; j++)
  660. {
  661. Slapi_Attr *attr = NULL;
  662. char *attrName = NULL;
  663. /* Loop over all the attributes of the entry and search
  664. * for the integrity attribute and its subtypes */
  665. for (slapi_entry_first_attr(search_entries[j], &attr); attr;
  666. slapi_entry_next_attr(search_entries[j], attr, &attr))
  667. {
  668. /* Take into account only the subtypes of the attribute
  669. * in argv[i] having the necessary value - origDN */
  670. slapi_attr_get_type(attr, &attrName);
  671. if (slapi_attr_type_cmp(argv[i], attrName,
  672. SLAPI_TYPE_CMP_SUBTYPE) == 0)
  673. {
  674. int nval = 0;
  675. slapi_attr_get_numvalues(attr, &nval);
  676. /*
  677. * We want to reduce the "modify" call as much as
  678. * possible. But if an entry contains 1000s of
  679. * attributes which need to be updated by the
  680. * referint plugin (e.g., a group containing 1000s
  681. * of members), we want to avoid to allocate too
  682. * many mods * in one "modify" call.
  683. * This is a compromise: If an attribute type has
  684. * more than 128 values, we update the attribute
  685. * value one by one. Otherwise, update all values
  686. * in one "modify" call.
  687. */
  688. if (nval > 128) {
  689. rc = _update_one_per_mod(
  690. slapi_entry_get_sdn(search_entries[j]),
  691. attr, attrName, origDN, newrDN,
  692. slapi_sdn_get_dn(newsuperior),
  693. mod_pb);
  694. } else {
  695. rc = _update_all_per_mod(
  696. slapi_entry_get_sdn(search_entries[j]),
  697. attr, attrName, origDN, newrDN,
  698. slapi_sdn_get_dn(newsuperior),
  699. mod_pb);
  700. }
  701. /* Should we stop if one modify returns an error? */
  702. }
  703. }
  704. }
  705. } else {
  706. if (isFatalSearchError(search_result))
  707. {
  708. /* NPCTE fix for bugid 531225, esc 0. <P.R> <30-May-2001> */
  709. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  710. "update_integrity search (base=%s filter=%s) returned "
  711. "error %d\n", search_base, filter, search_result);
  712. /* end of NPCTE fix for bugid 531225 */
  713. rc = -1;
  714. goto free_and_return;
  715. }
  716. }
  717. slapi_ch_free_string(&filter);
  718. }
  719. slapi_free_search_results_internal(search_result_pb);
  720. }
  721. }
  722. /* if got here, then everything good rc = 0 */
  723. rc = 0;
  724. free_and_return:
  725. /* free filter and search_results_pb */
  726. slapi_ch_free_string(&filter);
  727. slapi_pblock_destroy(mod_pb);
  728. if (search_result_pb) {
  729. slapi_free_search_results_internal(search_result_pb);
  730. slapi_pblock_destroy(search_result_pb);
  731. }
  732. return(rc);
  733. }
  734. int referint_postop_start( Slapi_PBlock *pb)
  735. {
  736. char **argv;
  737. int argc = 0;
  738. /* get args */
  739. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0 ) {
  740. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  741. "referint_postop failed to get argv\n" );
  742. return( -1 );
  743. }
  744. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
  745. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  746. "referint_postop failed to get argv\n" );
  747. return( -1 );
  748. }
  749. if(argv == NULL){
  750. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  751. "args were null in referint_postop_start\n" );
  752. return( -1 );
  753. }
  754. /* only bother to start the thread if you are in delay mode.
  755. 0 = no delay,
  756. -1 = integrity off */
  757. if (argc >= 1) {
  758. if(atoi(argv[0]) > 0){
  759. /* initialize cv and lock */
  760. referint_mutex = PR_NewLock();
  761. keeprunning_mutex = PR_NewLock();
  762. keeprunning_cv = PR_NewCondVar(keeprunning_mutex);
  763. keeprunning =1;
  764. referint_tid = PR_CreateThread (PR_USER_THREAD,
  765. referint_thread_func,
  766. (void *)argv,
  767. PR_PRIORITY_NORMAL,
  768. PR_GLOBAL_THREAD,
  769. PR_UNJOINABLE_THREAD,
  770. SLAPD_DEFAULT_THREAD_STACKSIZE);
  771. if ( referint_tid == NULL ) {
  772. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  773. "referint_postop_start PR_CreateThread failed\n" );
  774. exit( 1 );
  775. }
  776. }
  777. } else {
  778. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  779. "referint_postop_start insufficient arguments supplied\n" );
  780. return( -1 );
  781. }
  782. return(0);
  783. }
  784. int referint_postop_close( Slapi_PBlock *pb)
  785. {
  786. /* signal the thread to exit */
  787. if (NULL != keeprunning_mutex) {
  788. PR_Lock(keeprunning_mutex);
  789. keeprunning=0;
  790. if (NULL != keeprunning_cv) {
  791. PR_NotifyCondVar(keeprunning_cv);
  792. }
  793. PR_Unlock(keeprunning_mutex);
  794. }
  795. return(0);
  796. }
  797. void
  798. referint_thread_func(void *arg)
  799. {
  800. char **plugin_argv = (char **)arg;
  801. PRFileDesc *prfd;
  802. char *logfilename;
  803. char thisline[MAX_LINE];
  804. int delay;
  805. int no_changes;
  806. char delimiter[]="\t\n";
  807. char *ptoken;
  808. Slapi_DN *sdn = NULL;
  809. char *tmprdn;
  810. Slapi_DN *tmpsuperior = NULL;
  811. int logChanges=0;
  812. char * iter = NULL;
  813. if(plugin_argv == NULL){
  814. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  815. "referint_thread_func not get args \n" );
  816. return;
  817. }
  818. /* initialize the thread data index
  819. if(slapi_td_dn_init()){
  820. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,"Failed to create thread data index\n");
  821. } */
  822. delay = atoi(plugin_argv[0]);
  823. logfilename = plugin_argv[1];
  824. logChanges = atoi(plugin_argv[2]);
  825. /* keep running this thread until plugin is signalled to close */
  826. while(1){
  827. no_changes=1;
  828. while(no_changes){
  829. PR_Lock(keeprunning_mutex);
  830. if(keeprunning == 0){
  831. PR_Unlock(keeprunning_mutex);
  832. break;
  833. }
  834. PR_Unlock(keeprunning_mutex);
  835. PR_Lock(referint_mutex);
  836. if (( prfd = PR_Open( logfilename, PR_RDONLY,
  837. REFERINT_DEFAULT_FILE_MODE )) == NULL )
  838. {
  839. PR_Unlock(referint_mutex);
  840. /* go back to sleep and wait for this file */
  841. PR_Lock(keeprunning_mutex);
  842. PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
  843. PR_Unlock(keeprunning_mutex);
  844. }else{
  845. no_changes = 0;
  846. }
  847. }
  848. /* check keep running here, because after break out of no
  849. * changes loop on shutdown, also need to break out of this
  850. * loop before trying to do the changes. The server
  851. * will pick them up on next startup as file still exists
  852. */
  853. PR_Lock(keeprunning_mutex);
  854. if(keeprunning == 0){
  855. PR_Unlock(keeprunning_mutex);
  856. break;
  857. }
  858. PR_Unlock(keeprunning_mutex);
  859. while( GetNextLine(thisline, MAX_LINE, prfd) ){
  860. ptoken = ldap_utf8strtok_r(thisline, delimiter, &iter);
  861. sdn = slapi_sdn_new_normdn_byref(ptoken);
  862. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  863. if(!strcasecmp(ptoken, "NULL")) {
  864. tmprdn = NULL;
  865. } else {
  866. tmprdn = slapi_ch_smprintf("%s", ptoken);
  867. }
  868. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  869. if (!strcasecmp(ptoken, "NULL")) {
  870. tmpsuperior = NULL;
  871. } else {
  872. tmpsuperior = slapi_sdn_new_normdn_byref(ptoken);
  873. }
  874. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  875. if (strcasecmp(ptoken, "NULL") != 0) {
  876. /* Set the bind DN in the thread data */
  877. if(slapi_td_set_dn(slapi_ch_strdup(ptoken))){
  878. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,"Failed to set thread data\n");
  879. }
  880. }
  881. update_integrity(plugin_argv, sdn, tmprdn,
  882. tmpsuperior, logChanges);
  883. slapi_sdn_free(&sdn);
  884. slapi_ch_free_string(&tmprdn);
  885. slapi_sdn_free(&tmpsuperior);
  886. }
  887. PR_Close(prfd);
  888. /* remove the original file */
  889. if( PR_SUCCESS != PR_Delete(logfilename) )
  890. {
  891. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  892. "referint_postop_close could not delete \"%s\"\n",
  893. logfilename );
  894. }
  895. /* unlock and let other writers back at the file */
  896. PR_Unlock(referint_mutex);
  897. /* wait on condition here */
  898. PR_Lock(keeprunning_mutex);
  899. PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
  900. PR_Unlock(keeprunning_mutex);
  901. }
  902. /* cleanup resources allocated in start */
  903. if (NULL != keeprunning_mutex) {
  904. PR_DestroyLock(keeprunning_mutex);
  905. }
  906. if (NULL != referint_mutex) {
  907. PR_DestroyLock(referint_mutex);
  908. }
  909. if (NULL != keeprunning_cv) {
  910. PR_DestroyCondVar(keeprunning_cv);
  911. }
  912. }
  913. int my_fgetc(PRFileDesc *stream)
  914. {
  915. static char buf[READ_BUFSIZE] = "\0";
  916. static int position = READ_BUFSIZE;
  917. int retval;
  918. int err;
  919. /* check if we need to load the buffer */
  920. if( READ_BUFSIZE == position )
  921. {
  922. memset(buf, '\0', READ_BUFSIZE);
  923. if( ( err = PR_Read(stream, buf, READ_BUFSIZE) ) >= 0)
  924. {
  925. /* it read some data */;
  926. position = 0;
  927. }else{
  928. /* an error occurred */
  929. return err;
  930. }
  931. }
  932. /* try to read some data */
  933. if( '\0' == buf[position])
  934. {
  935. /* out of data, return eof */
  936. retval = MY_EOF;
  937. position = READ_BUFSIZE;
  938. }else{
  939. retval = buf[position];
  940. position++;
  941. }
  942. return retval;
  943. }
  944. int
  945. GetNextLine(char *dest, int size_dest, PRFileDesc *stream) {
  946. char nextchar ='\0';
  947. int done = 0;
  948. int i = 0;
  949. while(!done)
  950. {
  951. if( ( nextchar = my_fgetc(stream) ) != 0)
  952. {
  953. if( i < (size_dest - 1) )
  954. {
  955. dest[i] = nextchar;
  956. i++;
  957. if(nextchar == '\n')
  958. {
  959. /* end of line reached */
  960. done = 1;
  961. }
  962. }else{
  963. /* no more room in buffer */
  964. done = 1;
  965. }
  966. }else{
  967. /* error or end of file */
  968. done = 1;
  969. }
  970. }
  971. dest[i] = '\0';
  972. /* return size of string read */
  973. return i;
  974. }
  975. void
  976. writeintegritylog(Slapi_PBlock *pb, char *logfilename, Slapi_DN *sdn,
  977. char *newrdn, Slapi_DN *newsuperior, Slapi_DN *requestorsdn)
  978. {
  979. PRFileDesc *prfd;
  980. char buffer[MAX_LINE];
  981. int len_to_write = 0;
  982. int rc;
  983. const char *requestordn = NULL;
  984. size_t reqdn_len = 0;
  985. /* write this record to the file */
  986. /* use this lock to protect file data when update integrity is occuring */
  987. /* should hopefully not be a big issue on concurrency */
  988. PR_Lock(referint_mutex);
  989. if (( prfd = PR_Open( logfilename, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
  990. REFERINT_DEFAULT_FILE_MODE )) == NULL )
  991. {
  992. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  993. "referint_postop could not write integrity log \"%s\" "
  994. SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
  995. logfilename, PR_GetError(), slapd_pr_strerror(PR_GetError()) );
  996. PR_Unlock(referint_mutex);
  997. return;
  998. }
  999. /* make sure we have enough room in our buffer
  1000. before trying to write it
  1001. */
  1002. /* add length of dn + 5(three tabs, a newline, and terminating \0) */
  1003. len_to_write = slapi_sdn_get_ndn_len(sdn) + 5;
  1004. if(newrdn == NULL)
  1005. {
  1006. /* add the length of "NULL" */
  1007. len_to_write += 4;
  1008. }else{
  1009. /* add the length of the newrdn */
  1010. len_to_write += strlen(newrdn);
  1011. }
  1012. if(NULL == newsuperior)
  1013. {
  1014. /* add the length of "NULL" */
  1015. len_to_write += 4;
  1016. }else{
  1017. /* add the length of the newsuperior */
  1018. len_to_write += slapi_sdn_get_ndn_len(newsuperior);
  1019. }
  1020. slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &requestordn);
  1021. if (requestorsdn && (requestordn = slapi_sdn_get_udn(requestorsdn)) &&
  1022. (reqdn_len = strlen(requestordn))) {
  1023. len_to_write += reqdn_len;
  1024. } else {
  1025. len_to_write += 4; /* "NULL" */
  1026. }
  1027. if(len_to_write > MAX_LINE )
  1028. {
  1029. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1030. "referint_postop could not write integrity log:"
  1031. " line length exceeded. It will not be able"
  1032. " to update references to this entry.\n");
  1033. }else{
  1034. PR_snprintf(buffer, MAX_LINE, "%s\t%s\t%s\t%s\t\n",
  1035. slapi_sdn_get_dn(sdn),
  1036. (newrdn != NULL) ? newrdn : "NULL",
  1037. (newsuperior != NULL) ? slapi_sdn_get_dn(newsuperior) :
  1038. "NULL",
  1039. requestordn ? requestordn : "NULL");
  1040. if (PR_Write(prfd,buffer,strlen(buffer)) < 0){
  1041. slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
  1042. " writeintegritylog: PR_Write failed : The disk"
  1043. " may be full or the file is unwritable :: NSPR error - %d\n",
  1044. PR_GetError());
  1045. }
  1046. }
  1047. /* If file descriptor is closed successfully, PR_SUCCESS */
  1048. rc = PR_Close(prfd);
  1049. if (rc != PR_SUCCESS)
  1050. {
  1051. slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
  1052. " writeintegritylog: failed to close the file"
  1053. " descriptor prfd; NSPR error - %d\n",
  1054. PR_GetError());
  1055. }
  1056. PR_Unlock(referint_mutex);
  1057. }