referint.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205
  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_del, 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. Slapi_DN *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 *)slapi_sdn_get_dn(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, slapi_sdn_get_dn(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( slapi_sdn_get_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. slapi_sdn_get_dn(origDN));
  349. goto bail;
  350. }
  351. if (NULL == newRDN) {
  352. newRDN = dnParts[0];
  353. }
  354. if (newsuperior) {
  355. superior = newsuperior;
  356. } else {
  357. /* do not free superior */
  358. superior = slapi_dn_find_parent(slapi_sdn_get_dn(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, slapi_sdn_get_ndn(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. slapi_sdn_get_dn(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. Slapi_DN *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 *)slapi_sdn_get_dn(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, slapi_sdn_get_dn(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( slapi_sdn_get_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. slapi_sdn_get_dn(origDN));
  521. goto bail;
  522. }
  523. if (NULL == newRDN) {
  524. newRDN = dnParts[0];
  525. }
  526. if (newsuperior) {
  527. superior = newsuperior;
  528. } else {
  529. /* do not free superior */
  530. superior = slapi_dn_find_parent(slapi_sdn_get_dn(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, slapi_sdn_get_ndn(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, origSDN, 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, origSDN, 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. const char *newsuperiordn = NULL;
  987. size_t reqdn_len = 0;
  988. /* write this record to the file */
  989. /* use this lock to protect file data when update integrity is occuring */
  990. /* should hopefully not be a big issue on concurrency */
  991. PR_Lock(referint_mutex);
  992. if (( prfd = PR_Open( logfilename, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
  993. REFERINT_DEFAULT_FILE_MODE )) == NULL )
  994. {
  995. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  996. "referint_postop could not write integrity log \"%s\" "
  997. SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
  998. logfilename, PR_GetError(), slapd_pr_strerror(PR_GetError()) );
  999. PR_Unlock(referint_mutex);
  1000. return;
  1001. }
  1002. /* make sure we have enough room in our buffer
  1003. before trying to write it
  1004. */
  1005. /* add length of dn + 5(three tabs, a newline, and terminating \0) */
  1006. len_to_write = slapi_sdn_get_ndn_len(sdn) + 5;
  1007. if(newrdn == NULL)
  1008. {
  1009. /* add the length of "NULL" */
  1010. len_to_write += 4;
  1011. }else{
  1012. /* add the length of the newrdn */
  1013. len_to_write += strlen(newrdn);
  1014. }
  1015. newsuperiordn = slapi_sdn_get_dn(newsuperior);
  1016. if(NULL == newsuperiordn)
  1017. {
  1018. /* add the length of "NULL" */
  1019. len_to_write += 4;
  1020. }else{
  1021. /* add the length of the newsuperior */
  1022. len_to_write += slapi_sdn_get_ndn_len(newsuperior);
  1023. }
  1024. slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &requestordn);
  1025. if (requestorsdn && (requestordn = slapi_sdn_get_udn(requestorsdn)) &&
  1026. (reqdn_len = strlen(requestordn))) {
  1027. len_to_write += reqdn_len;
  1028. } else {
  1029. len_to_write += 4; /* "NULL" */
  1030. }
  1031. if(len_to_write > MAX_LINE )
  1032. {
  1033. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1034. "referint_postop could not write integrity log:"
  1035. " line length exceeded. It will not be able"
  1036. " to update references to this entry.\n");
  1037. }else{
  1038. PR_snprintf(buffer, MAX_LINE, "%s\t%s\t%s\t%s\t\n",
  1039. slapi_sdn_get_dn(sdn),
  1040. (newrdn != NULL) ? newrdn : "NULL",
  1041. (newsuperiordn != NULL) ? newsuperiordn : "NULL",
  1042. requestordn ? requestordn : "NULL");
  1043. if (PR_Write(prfd,buffer,strlen(buffer)) < 0){
  1044. slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
  1045. " writeintegritylog: PR_Write failed : The disk"
  1046. " may be full or the file is unwritable :: NSPR error - %d\n",
  1047. PR_GetError());
  1048. }
  1049. }
  1050. /* If file descriptor is closed successfully, PR_SUCCESS */
  1051. rc = PR_Close(prfd);
  1052. if (rc != PR_SUCCESS)
  1053. {
  1054. slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
  1055. " writeintegritylog: failed to close the file"
  1056. " descriptor prfd; NSPR error - %d\n",
  1057. PR_GetError());
  1058. }
  1059. PR_Unlock(referint_mutex);
  1060. }