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