referint.c 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838
  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 REFERINT_PREOP_DESC "referint preop plugin"
  63. #define REFERINT_ATTR_DELAY "referint-update-delay"
  64. #define REFERINT_ATTR_LOGCHANGES "referint-logchanges"
  65. #define REFERINT_ATTR_LOGFILE "referint-logfile"
  66. #define REFERINT_ATTR_MEMBERSHIP "referint-membership-attr"
  67. #define MAX_LINE 2048
  68. #define READ_BUFSIZE 4096
  69. #define MY_EOF 0
  70. #define STARTUP 2
  71. typedef struct referint_config {
  72. int delay;
  73. char *logfile;
  74. int logchanges;
  75. char **attrs;
  76. } referint_config;
  77. Slapi_RWLock *config_rwlock = NULL;
  78. /* function prototypes */
  79. int referint_postop_init( Slapi_PBlock *pb );
  80. int referint_postop_del( Slapi_PBlock *pb );
  81. int referint_postop_modrdn( Slapi_PBlock *pb );
  82. int referint_postop_start( Slapi_PBlock *pb);
  83. int referint_postop_close( Slapi_PBlock *pb);
  84. int update_integrity(Slapi_DN *sDN, char *newrDN, Slapi_DN *newsuperior, int logChanges);
  85. int GetNextLine(char *dest, int size_dest, PRFileDesc *stream);
  86. int my_fgetc(PRFileDesc *stream);
  87. void referint_thread_func(void *arg);
  88. void writeintegritylog(Slapi_PBlock *pb, char *logfilename, Slapi_DN *sdn, char *newrdn, Slapi_DN *newsuperior, Slapi_DN *requestorsdn);
  89. int load_config(Slapi_PBlock *pb, Slapi_Entry *config_entry, int apply);
  90. int referint_get_delay();
  91. int referint_get_logchanges();
  92. char *referint_get_logfile();
  93. char **referint_get_attrs();
  94. int referint_postop_modify(Slapi_PBlock *pb);
  95. int referint_validate_config(Slapi_PBlock *pb);
  96. static int referint_preop_init(Slapi_PBlock *pb);
  97. void referint_set_config_area(Slapi_DN *dn);
  98. Slapi_DN *referint_get_config_area();
  99. void referint_set_plugin_area(Slapi_DN *sdn);
  100. Slapi_DN *referint_get_plugin_area();
  101. int referint_sdn_config_cmp(Slapi_DN *sdn);
  102. void referint_get_config(int *delay, int *logchanges, char **logfile);
  103. /* global thread control stuff */
  104. static PRLock *referint_mutex = NULL;
  105. static PRThread *referint_tid = NULL;
  106. static PRLock *keeprunning_mutex = NULL;
  107. static PRCondVar *keeprunning_cv = NULL;
  108. static int keeprunning = 0;
  109. static referint_config *config = NULL;
  110. static Slapi_DN* _ConfigAreaDN = NULL;
  111. static Slapi_DN* _pluginDN = NULL;
  112. static Slapi_PluginDesc pdesc = { "referint", VENDOR, DS_PACKAGE_VERSION, "referential integrity plugin" };
  113. static int allow_repl = 0;
  114. static Slapi_DN **plugin_EntryScope = NULL;
  115. static Slapi_DN *plugin_ExcludeEntryScope = NULL;
  116. static Slapi_DN *plugin_ContainerScope = NULL;
  117. static void* referint_plugin_identity = NULL;
  118. static int use_txn = 0;
  119. static int premodfn = SLAPI_PLUGIN_PRE_MODIFY_FN;
  120. #ifdef _WIN32
  121. int *module_ldap_debug = 0;
  122. void plugin_init_debug_level(int *level_ptr)
  123. {
  124. module_ldap_debug = level_ptr;
  125. }
  126. #endif
  127. static void
  128. referint_lock()
  129. {
  130. if (use_txn) { /* no lock if betxn is enabled */
  131. return;
  132. }
  133. if (NULL == referint_mutex) {
  134. referint_mutex = PR_NewLock();
  135. }
  136. if (referint_mutex) {
  137. PR_Lock(referint_mutex);
  138. }
  139. }
  140. static void
  141. referint_unlock()
  142. {
  143. if (use_txn) { /* no lock if betxn is enabled */
  144. return;
  145. }
  146. if (referint_mutex) {
  147. PR_Unlock(referint_mutex);
  148. }
  149. }
  150. void
  151. referint_set_config_area(Slapi_DN *dn)
  152. {
  153. slapi_rwlock_wrlock(config_rwlock);
  154. slapi_sdn_free(&_ConfigAreaDN);
  155. _ConfigAreaDN = slapi_sdn_dup(dn);
  156. slapi_rwlock_unlock(config_rwlock);
  157. }
  158. /*
  159. * No need to lock here, because this only called from referint_sdn_config_cmp()
  160. * which does take the lock.
  161. */
  162. Slapi_DN *
  163. referint_get_config_area()
  164. {
  165. return _ConfigAreaDN;
  166. }
  167. /* no locking needed for the plugin DN because it is set at initialization */
  168. void
  169. referint_set_plugin_area(Slapi_DN *sdn)
  170. {
  171. slapi_sdn_free(&_pluginDN);
  172. _pluginDN = slapi_sdn_dup(sdn);
  173. }
  174. Slapi_DN *
  175. referint_get_plugin_area()
  176. {
  177. return _pluginDN;
  178. }
  179. int
  180. referint_postop_init( Slapi_PBlock *pb )
  181. {
  182. Slapi_Entry *plugin_entry = NULL;
  183. char *plugin_type = NULL;
  184. int delfn = SLAPI_PLUGIN_POST_DELETE_FN;
  185. int mdnfn = SLAPI_PLUGIN_POST_MODRDN_FN;
  186. int modfn = SLAPI_PLUGIN_POST_MODIFY_FN; /* for config changes */
  187. char *preop_plugin_type = "preoperation";
  188. /*
  189. * Get plugin identity and stored it for later use.
  190. * Used for internal operations.
  191. */
  192. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &referint_plugin_identity);
  193. PR_ASSERT (referint_plugin_identity);
  194. if((config = (referint_config *)slapi_ch_calloc (1, sizeof (referint_config))) == NULL){
  195. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_init failed to "
  196. "allocate configuration\n" );
  197. return ( -1 );
  198. }
  199. /* get the args */
  200. if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
  201. plugin_entry &&
  202. (plugin_type = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype")) &&
  203. plugin_type && strstr(plugin_type, "betxn"))
  204. {
  205. delfn = SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN;
  206. mdnfn = SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN;
  207. modfn = SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN;
  208. preop_plugin_type = "betxnpreoperation";
  209. premodfn = SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN;
  210. use_txn = 1;
  211. }
  212. slapi_ch_free_string(&plugin_type);
  213. if(plugin_entry){
  214. char *plugin_attr_value;
  215. char **plugin_attr_values;
  216. plugin_attr_value = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginAllowReplUpdates");
  217. if(plugin_attr_value && strcasecmp(plugin_attr_value,"on")==0){
  218. allow_repl = 1;
  219. }
  220. slapi_ch_free_string(&plugin_attr_value);
  221. plugin_attr_values = slapi_entry_attr_get_charray(plugin_entry, "nsslapd-pluginEntryScope");
  222. if(plugin_attr_values) {
  223. int i,j=0;;
  224. for (i=0; plugin_attr_values[i];i++);
  225. plugin_EntryScope = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),i+1);
  226. for (i=0; plugin_attr_values[i];i++) {
  227. if (slapi_dn_syntax_check(NULL, plugin_attr_values[i], 1) == 1) {
  228. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  229. "Error: Ignoring invalid DN used as plugin entry scope: [%s]\n",
  230. plugin_attr_values[i]);
  231. slapi_ch_free_string(&plugin_attr_values[i]);
  232. } else {
  233. plugin_EntryScope[j++] = slapi_sdn_new_dn_passin(plugin_attr_values[i]);
  234. }
  235. }
  236. slapi_ch_free((void**)&plugin_attr_values);
  237. }
  238. plugin_attr_value = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginExcludeEntryScope");
  239. if(plugin_attr_value) {
  240. if (slapi_dn_syntax_check(NULL, plugin_attr_value, 1) == 1) {
  241. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  242. "Error: Ignoring invalid DN used as plugin exclude entry scope: [%s]\n",
  243. plugin_attr_value);
  244. slapi_ch_free_string(&plugin_attr_value);
  245. } else {
  246. plugin_ExcludeEntryScope = slapi_sdn_new_dn_passin(plugin_attr_value);
  247. }
  248. }
  249. plugin_attr_value = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginContainerScope");
  250. if(plugin_attr_value) {
  251. if (slapi_dn_syntax_check(NULL, plugin_attr_value, 1) == 1) {
  252. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  253. "Error: Ignoring invalid DN used as plugin container scope: [%s]\n",
  254. plugin_attr_value);
  255. slapi_ch_free_string(&plugin_attr_value);
  256. } else {
  257. plugin_ContainerScope = slapi_sdn_new_dn_passin(plugin_attr_value);
  258. }
  259. }
  260. referint_set_plugin_area(slapi_entry_get_sdn(plugin_entry));
  261. }
  262. if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
  263. slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&pdesc ) != 0 ||
  264. slapi_pblock_set( pb, delfn, (void *) referint_postop_del ) != 0 ||
  265. slapi_pblock_set( pb, mdnfn, (void *) referint_postop_modrdn ) != 0 ||
  266. slapi_pblock_set( pb, modfn, (void *) (void *)referint_postop_modify ) != 0 ||
  267. slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) referint_postop_start ) != 0 ||
  268. slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) referint_postop_close ) != 0)
  269. {
  270. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_init failed\n" );
  271. return( -1 );
  272. }
  273. /*
  274. * Setup the preop plugin for config validation
  275. */
  276. if (slapi_register_plugin(preop_plugin_type, /* op type */
  277. 1, /* Enabled */
  278. "referint_preop_init", /* this function desc */
  279. referint_preop_init, /* init func */
  280. REFERINT_PREOP_DESC, /* plugin desc */
  281. NULL, /* ? */
  282. referint_plugin_identity /* access control */))
  283. {
  284. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_preop_init failed\n" );
  285. return ( -1 );
  286. }
  287. return( 0 );
  288. }
  289. /*
  290. * referint-update-delay: 0
  291. * referint-logfile: /var/log/dirsrv/slapd-localhost/referint
  292. * referint-logchanges: 0
  293. * referint-membership-attr: member
  294. * referint-membership-attr: uniquemember
  295. * referint-membership-attr: owner
  296. * referint-membership-attr: seeAlso
  297. *
  298. *
  299. * Need to lock this!
  300. */
  301. int
  302. load_config(Slapi_PBlock *pb, Slapi_Entry *config_entry, int apply)
  303. {
  304. referint_config *tmp_config = NULL;
  305. char *value = NULL;
  306. char **attrs = NULL;
  307. char **argv = NULL;
  308. int new_config_present = 0;
  309. int argc = 0;
  310. int rc = SLAPI_PLUGIN_SUCCESS;
  311. if(config_entry == NULL){
  312. return rc;
  313. }
  314. slapi_rwlock_wrlock(config_rwlock);
  315. if(config == NULL){
  316. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  317. "load_config: config is NULL\n" );
  318. rc = SLAPI_PLUGIN_FAILURE;
  319. goto done;
  320. }
  321. if((tmp_config = (referint_config *)slapi_ch_calloc (1, sizeof (referint_config))) == NULL){
  322. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "load_config failed to "
  323. "allocate configuration\n" );
  324. rc = SLAPI_PLUGIN_FAILURE;
  325. goto done;
  326. } else {
  327. /* set these to -1 for config validation */
  328. tmp_config->delay = -1;
  329. tmp_config->logchanges = -1;
  330. }
  331. if((value = slapi_entry_attr_get_charptr(config_entry, REFERINT_ATTR_DELAY))){
  332. tmp_config->delay = atoi(value);
  333. slapi_ch_free_string(&value);
  334. new_config_present = 1;
  335. }
  336. if((value = slapi_entry_attr_get_charptr(config_entry, REFERINT_ATTR_LOGFILE))){
  337. tmp_config->logfile = value;
  338. new_config_present = 1;
  339. }
  340. if((value = slapi_entry_attr_get_charptr(config_entry, REFERINT_ATTR_LOGCHANGES))){
  341. tmp_config->logchanges = atoi(value);
  342. slapi_ch_free_string(&value);
  343. new_config_present = 1;
  344. }
  345. if((attrs = slapi_entry_attr_get_charray(config_entry, REFERINT_ATTR_MEMBERSHIP))){
  346. tmp_config->attrs = attrs;
  347. new_config_present = 1;
  348. }
  349. if(new_config_present){
  350. /* Verify we have everything we need */
  351. if(tmp_config->delay == -1){
  352. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "Plugin configuration is missing %s\n",
  353. REFERINT_ATTR_DELAY);
  354. rc = SLAPI_PLUGIN_FAILURE;
  355. } else if (!tmp_config->logfile){
  356. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "Plugin configuration is missing %s\n",
  357. REFERINT_ATTR_LOGFILE);
  358. rc = SLAPI_PLUGIN_FAILURE;
  359. } else if (tmp_config->logchanges == -1){
  360. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "Plugin configuration is missing %s\n",
  361. REFERINT_ATTR_LOGCHANGES);
  362. rc = SLAPI_PLUGIN_FAILURE;
  363. } else if (!tmp_config->attrs){
  364. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "Plugin configuration is missing %s\n",
  365. REFERINT_ATTR_MEMBERSHIP);
  366. rc = SLAPI_PLUGIN_FAILURE;
  367. }
  368. } else{
  369. /*
  370. * We are using the old plugin arg configuration, get the args
  371. */
  372. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0) {
  373. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  374. "referint_postop failed to get argc\n" );
  375. rc = SLAPI_PLUGIN_FAILURE;
  376. goto done;
  377. }
  378. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0) {
  379. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  380. "referint_postop failed to get argv\n" );
  381. rc = SLAPI_PLUGIN_FAILURE;
  382. goto done;
  383. }
  384. if(argv == NULL){
  385. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  386. "referint_postop_del, args are NULL\n" );
  387. rc = SLAPI_PLUGIN_FAILURE;
  388. goto done;
  389. }
  390. /*
  391. * Load the args and set the config struct
  392. */
  393. if (argc >= 3) {
  394. int i;
  395. tmp_config->delay = atoi(argv[0]);
  396. tmp_config->logfile = slapi_ch_strdup(argv[1]);
  397. tmp_config->logchanges = atoi(argv[2]);
  398. for(i = 3; argv[i] != NULL; i++){
  399. slapi_ch_array_add(&tmp_config->attrs, slapi_ch_strdup(argv[i]));
  400. }
  401. } else {
  402. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  403. "referint_postop insufficient arguments supplied\n" );
  404. rc = SLAPI_PLUGIN_FAILURE;
  405. goto done;
  406. }
  407. }
  408. done:
  409. if(apply && rc == SLAPI_PLUGIN_SUCCESS){
  410. slapi_ch_free_string(&config->logfile);
  411. slapi_ch_array_free(config->attrs);
  412. slapi_ch_free((void **)&config);
  413. config = tmp_config;
  414. } else if(tmp_config){
  415. slapi_ch_free_string(&tmp_config->logfile);
  416. slapi_ch_array_free(tmp_config->attrs);
  417. slapi_ch_free((void **)&tmp_config);
  418. }
  419. slapi_rwlock_unlock(config_rwlock);
  420. return rc;
  421. }
  422. int
  423. referint_postop_modify(Slapi_PBlock *pb)
  424. {
  425. Slapi_Entry *entry = NULL, *e = NULL;
  426. Slapi_Entry *config_e = NULL;
  427. Slapi_DN *config_sdn = NULL;
  428. Slapi_DN *sdn = NULL;
  429. char *config_area = NULL;
  430. int result = 0;
  431. int rc = SLAPI_PLUGIN_SUCCESS;
  432. /* check if we are updating the shared config entry */
  433. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
  434. slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &entry);
  435. if (referint_sdn_config_cmp(sdn) == 0 && slapi_sdn_compare(sdn, referint_get_plugin_area()))
  436. {
  437. if( SLAPI_PLUGIN_FAILURE == load_config(pb, entry, 1)){
  438. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "Failed to update configuration.\n");
  439. return SLAPI_PLUGIN_FAILURE;
  440. }
  441. } else if (slapi_sdn_compare(sdn, referint_get_plugin_area()) == 0){
  442. /*
  443. * Check if the plugin config area is set(verify it and load its config),
  444. * otherwise reload the plugin entry config
  445. */
  446. if((config_area = slapi_entry_attr_get_charptr(entry, SLAPI_PLUGIN_SHARED_CONFIG_AREA))){
  447. rc = slapi_dn_syntax_check(pb, config_area, 1);
  448. if (rc) { /* syntax check failed */
  449. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_modify: "
  450. "%s does not contain a valid DN (%s)\n",
  451. SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_area);
  452. rc = LDAP_INVALID_DN_SYNTAX;
  453. goto bail;
  454. }
  455. config_sdn = slapi_sdn_new_dn_byval(config_area);
  456. result = slapi_search_internal_get_entry(config_sdn, NULL, &e, referint_plugin_identity);
  457. if (LDAP_SUCCESS != result) {
  458. if (result == LDAP_NO_SUCH_OBJECT) {
  459. /* log an error and use the plugin entry for the config */
  460. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  461. "referint_postop_modify: Config entry \"%s\" does "
  462. "not exist.\n", config_area);
  463. rc = LDAP_OPERATIONS_ERROR;
  464. goto bail;
  465. }
  466. } else {
  467. if(e){
  468. config_e = e;
  469. } else {
  470. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  471. "referint_postop_modify: Config entry \"%s\" was not located.\n", config_area);
  472. rc = LDAP_OPERATIONS_ERROR;
  473. goto bail;
  474. }
  475. }
  476. } else {
  477. config_e = entry;
  478. }
  479. if(load_config(pb, config_e, 1) != LDAP_SUCCESS){
  480. rc = LDAP_UNWILLING_TO_PERFORM;
  481. goto bail;
  482. }
  483. referint_set_config_area(slapi_entry_get_sdn(config_e));
  484. }
  485. bail:
  486. slapi_ch_free_string(&config_area);
  487. slapi_sdn_free(&config_sdn);
  488. slapi_entry_free(e);
  489. return rc;
  490. }
  491. int
  492. referint_get_delay()
  493. {
  494. int delay;
  495. slapi_rwlock_rdlock(config_rwlock);
  496. delay = config->delay;
  497. slapi_rwlock_unlock(config_rwlock);
  498. return delay;
  499. }
  500. int
  501. referint_get_logchanges()
  502. {
  503. int log_changes;
  504. slapi_rwlock_rdlock(config_rwlock);
  505. log_changes = config->logchanges;
  506. slapi_rwlock_unlock(config_rwlock);
  507. return log_changes;
  508. }
  509. char *
  510. referint_get_logfile()
  511. {
  512. char *log_file;
  513. slapi_rwlock_rdlock(config_rwlock);
  514. log_file = slapi_ch_strdup(config->logfile);
  515. slapi_rwlock_unlock(config_rwlock);
  516. return log_file;
  517. }
  518. void
  519. referint_get_config(int *delay, int *logchanges, char **logfile)
  520. {
  521. slapi_rwlock_rdlock(config_rwlock);
  522. if(delay){
  523. *delay = config->delay;
  524. }
  525. if(logchanges){
  526. *logchanges = config->logchanges;
  527. }
  528. if(logfile){
  529. *logfile = slapi_ch_strdup(config->logfile);
  530. }
  531. slapi_rwlock_unlock(config_rwlock);
  532. }
  533. /*
  534. * might need to find an alternate option instead of copying
  535. */
  536. char **
  537. referint_get_attrs()
  538. {
  539. char **attrs = NULL;
  540. slapi_rwlock_rdlock(config_rwlock);
  541. attrs = slapi_ch_array_dup(config->attrs);
  542. slapi_rwlock_unlock(config_rwlock);
  543. return attrs;
  544. }
  545. int
  546. referint_sdn_config_cmp(Slapi_DN *sdn)
  547. {
  548. int rc = 0;
  549. slapi_rwlock_rdlock(config_rwlock);
  550. rc = slapi_sdn_compare(sdn, referint_get_config_area());
  551. slapi_rwlock_unlock(config_rwlock);
  552. return rc;
  553. }
  554. int
  555. referint_sdn_in_container_scope(Slapi_DN *sdn)
  556. {
  557. if (plugin_ContainerScope == NULL) {
  558. return(1);
  559. } else {
  560. return(slapi_sdn_issuffix(sdn, plugin_ContainerScope));
  561. }
  562. }
  563. int
  564. referint_sdn_in_entry_scope(Slapi_DN *sdn)
  565. {
  566. int rc = 0;
  567. if (plugin_ExcludeEntryScope && slapi_sdn_issuffix(sdn, plugin_ExcludeEntryScope))
  568. return (0);
  569. if (plugin_EntryScope == NULL) {
  570. /* no scope defined, all sdns match */
  571. return(1);
  572. } else {
  573. int i = 0;
  574. while (plugin_EntryScope[i]) {
  575. if (slapi_sdn_issuffix(sdn, plugin_EntryScope[i]) ) {
  576. rc = 1;
  577. break;
  578. } else {
  579. i++;
  580. }
  581. }
  582. }
  583. return (rc);
  584. }
  585. int
  586. referint_postop_del( Slapi_PBlock *pb )
  587. {
  588. Slapi_DN *sdn = NULL;
  589. char *logfile = NULL;
  590. int delay;
  591. int logChanges=0;
  592. int isrepop = 0;
  593. int oprc;
  594. int rc = SLAPI_PLUGIN_SUCCESS;
  595. if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &isrepop ) != 0 ||
  596. slapi_pblock_get( pb, SLAPI_DELETE_TARGET_SDN, &sdn ) != 0 ||
  597. slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
  598. {
  599. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  600. "referint_postop_del: could not get parameters\n" );
  601. return SLAPI_PLUGIN_FAILURE;
  602. }
  603. /*
  604. * This plugin should only execute if the delete was successful
  605. * and this is not a replicated op(unless its allowed)
  606. */
  607. if(oprc != 0 || (isrepop && !allow_repl)){
  608. return SLAPI_PLUGIN_SUCCESS;
  609. }
  610. referint_get_config(&delay, &logChanges, NULL);
  611. if(delay == -1){
  612. /* integrity updating is off */
  613. rc = SLAPI_PLUGIN_SUCCESS;
  614. } else if(delay == 0){ /* no delay */
  615. /* call function to update references to entry */
  616. if (referint_sdn_in_entry_scope(sdn)) {
  617. rc = update_integrity(sdn, NULL, NULL, logChanges);
  618. }
  619. } else {
  620. /* write the entry to integrity log */
  621. logfile = referint_get_logfile();
  622. writeintegritylog(pb, logfile, sdn, NULL, NULL, NULL /* slapi_get_requestor_sdn(pb) */);
  623. rc = SLAPI_PLUGIN_SUCCESS;
  624. }
  625. slapi_ch_free_string(&logfile);
  626. return( rc );
  627. }
  628. int
  629. referint_postop_modrdn( Slapi_PBlock *pb )
  630. {
  631. Slapi_DN *sdn = NULL;
  632. Slapi_DN *newsuperior;
  633. char *logfile = NULL;
  634. char *newrdn;
  635. int oprc;
  636. int rc = SLAPI_PLUGIN_SUCCESS;
  637. int delay;
  638. int logChanges=0;
  639. int isrepop = 0;
  640. if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &isrepop ) != 0 ||
  641. slapi_pblock_get( pb, SLAPI_MODRDN_TARGET_SDN, &sdn ) != 0 ||
  642. slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn ) != 0 ||
  643. slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperior ) != 0 ||
  644. slapi_pblock_get( pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 )
  645. {
  646. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  647. "referint_postop_modrdn: could not get parameters\n" );
  648. return SLAPI_PLUGIN_FAILURE;
  649. }
  650. /*
  651. * This plugin should only execute if the delete was successful
  652. * and this is not a replicated op (unless its allowed)
  653. */
  654. if(oprc != 0 || (isrepop && !allow_repl)){
  655. return SLAPI_PLUGIN_SUCCESS;
  656. }
  657. referint_get_config(&delay, &logChanges, NULL);
  658. if(delay == -1){
  659. /* integrity updating is off */
  660. rc = SLAPI_PLUGIN_SUCCESS;
  661. } else if(delay == 0){ /* no delay */
  662. /* call function to update references to entry */
  663. if (!plugin_EntryScope && !plugin_ExcludeEntryScope) {
  664. /* no scope defined, default always process referint */
  665. rc = update_integrity(sdn, newrdn, newsuperior, logChanges);
  666. } else {
  667. const char *newsuperiordn = slapi_sdn_get_dn(newsuperior);
  668. if ( (newsuperiordn == NULL && referint_sdn_in_entry_scope(sdn)) ||
  669. ( newsuperiordn && referint_sdn_in_entry_scope(newsuperior)))
  670. {
  671. /*
  672. * It is a modrdn inside the scope or into the scope,
  673. * process normal modrdn
  674. */
  675. rc = update_integrity(sdn, newrdn, newsuperior, logChanges);
  676. } else if (referint_sdn_in_entry_scope(sdn)) {
  677. /* the entry is moved out of scope, treat as delete */
  678. rc = update_integrity(sdn, NULL, NULL, logChanges);
  679. }
  680. }
  681. } else {
  682. /* write the entry to integrity log */
  683. logfile = referint_get_logfile();
  684. writeintegritylog(pb, logfile, sdn, newrdn, newsuperior, NULL /* slapi_get_requestor_sdn(pb) */);
  685. rc = SLAPI_PLUGIN_SUCCESS;
  686. }
  687. slapi_ch_free_string(&logfile);
  688. return( rc );
  689. }
  690. int isFatalSearchError(int search_result)
  691. {
  692. /* Make sure search result is fatal
  693. * Some conditions that happen quite often are not fatal
  694. * for example if you have two suffixes and one is null, you will always
  695. * get no such object, however this is not a fatal error.
  696. * Add other conditions to the if statement as they are found
  697. */
  698. switch(search_result) {
  699. case LDAP_REFERRAL:
  700. case LDAP_NO_SUCH_OBJECT: return 0 ;
  701. }
  702. return 1;
  703. }
  704. static int
  705. _do_modify(Slapi_PBlock *mod_pb, Slapi_DN *entrySDN, LDAPMod **mods)
  706. {
  707. int rc = 0;
  708. slapi_pblock_init(mod_pb);
  709. if(allow_repl){
  710. /* Must set as a replicated operation */
  711. slapi_modify_internal_set_pb_ext(mod_pb, entrySDN, mods, NULL, NULL,
  712. referint_plugin_identity, OP_FLAG_REPLICATED);
  713. } else {
  714. slapi_modify_internal_set_pb_ext(mod_pb, entrySDN, mods, NULL, NULL,
  715. referint_plugin_identity, 0);
  716. }
  717. slapi_modify_internal_pb(mod_pb);
  718. slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  719. return rc;
  720. }
  721. /*
  722. * update one attribute value per _do_modify
  723. */
  724. static int
  725. _update_one_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */
  726. Slapi_Attr *attr, /* referred attribute */
  727. char *attrName,
  728. Slapi_DN *origDN, /* original DN that was modified */
  729. char *newRDN, /* new RDN from modrdn */
  730. const char *newsuperior, /* new superior from modrdn */
  731. Slapi_PBlock *mod_pb)
  732. {
  733. LDAPMod attribute1, attribute2;
  734. LDAPMod *list_of_mods[3];
  735. char *values_del[2];
  736. char *values_add[2];
  737. char *newDN = NULL;
  738. char **dnParts = NULL;
  739. char *sval = NULL;
  740. char *newvalue = NULL;
  741. char *p = NULL;
  742. size_t dnlen = 0;
  743. int rc = 0;
  744. if (NULL == newRDN && NULL == newsuperior) {
  745. /* in delete mode */
  746. /* delete old dn so set that up */
  747. values_del[0] = (char *)slapi_sdn_get_dn(origDN);
  748. values_del[1] = NULL;
  749. attribute1.mod_type = attrName;
  750. attribute1.mod_op = LDAP_MOD_DELETE;
  751. attribute1.mod_values = values_del;
  752. list_of_mods[0] = &attribute1;
  753. /* terminate list of mods. */
  754. list_of_mods[1] = NULL;
  755. rc = _do_modify(mod_pb, entrySDN, list_of_mods);
  756. if (rc) {
  757. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  758. "_update_one_value: entry %s: deleting \"%s: %s\" failed (%d)"
  759. "\n", slapi_sdn_get_dn(entrySDN), attrName, slapi_sdn_get_dn(origDN), rc);
  760. }
  761. } else {
  762. /* in modrdn mode */
  763. const char *superior = NULL;
  764. int nval = 0;
  765. Slapi_Value *v = NULL;
  766. if (NULL == origDN) {
  767. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  768. "_update_one_value: NULL dn was passed\n");
  769. goto bail;
  770. }
  771. /* need to put together rdn into a dn */
  772. dnParts = slapi_ldap_explode_dn( slapi_sdn_get_dn(origDN), 0 );
  773. if (NULL == dnParts) {
  774. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  775. "_update_one_value: failed to explode dn %s\n",
  776. slapi_sdn_get_dn(origDN));
  777. goto bail;
  778. }
  779. if (NULL == newRDN) {
  780. newRDN = dnParts[0];
  781. }
  782. if (newsuperior) {
  783. superior = newsuperior;
  784. } else {
  785. /* do not free superior */
  786. superior = slapi_dn_find_parent(slapi_sdn_get_dn(origDN));
  787. }
  788. /* newRDN and superior are already normalized. */
  789. newDN = slapi_ch_smprintf("%s,%s", newRDN, superior);
  790. slapi_dn_ignore_case(newDN);
  791. /*
  792. * Compare the modified dn with the value of
  793. * the target attribute of referint to find out
  794. * the modified dn is the ancestor (case 2) or
  795. * the value itself (case 1).
  796. *
  797. * E.g.,
  798. * (case 1)
  799. * modrdn: uid=A,ou=B,o=C --> uid=A',ou=B',o=C
  800. * (origDN) (newDN)
  801. * member: uid=A,ou=B,ou=C --> uid=A',ou=B',ou=C
  802. * (sval) (newDN)
  803. *
  804. * (case 2)
  805. * modrdn: ou=B,o=C --> ou=B',o=C
  806. * (origDN) (newDN)
  807. * member: uid=A,ou=B,ou=C --> uid=A,ou=B',ou=C
  808. * (sval) (sval' + newDN)
  809. */
  810. for (nval = slapi_attr_first_value(attr, &v); nval != -1;
  811. nval = slapi_attr_next_value(attr, nval, &v)) {
  812. p = NULL;
  813. dnlen = 0;
  814. /* DN syntax, which should be a string */
  815. sval = slapi_ch_strdup(slapi_value_get_string(v));
  816. rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
  817. if (rc == 0) { /* sval is passed in; not terminated */
  818. *(p + dnlen) = '\0';
  819. sval = p;
  820. } else if (rc > 0) {
  821. slapi_ch_free_string(&sval);
  822. sval = p;
  823. }
  824. /* else: (rc < 0) Ignore the DN normalization error for now. */
  825. p = PL_strstr(sval, slapi_sdn_get_ndn(origDN));
  826. if (p == sval) {
  827. /* (case 1) */
  828. values_del[0] = sval;
  829. values_del[1] = NULL;
  830. attribute1.mod_type = attrName;
  831. attribute1.mod_op = LDAP_MOD_DELETE;
  832. attribute1.mod_values = values_del;
  833. list_of_mods[0] = &attribute1;
  834. values_add[0] = newDN;
  835. values_add[1] = NULL;
  836. attribute2.mod_type = attrName;
  837. attribute2.mod_op = LDAP_MOD_ADD;
  838. attribute2.mod_values = values_add;
  839. list_of_mods[1] = &attribute2;
  840. list_of_mods[2] = NULL;
  841. rc = _do_modify(mod_pb, entrySDN, list_of_mods);
  842. if (rc) {
  843. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  844. "_update_one_value: entry %s: replacing \"%s: %s\" "
  845. "with \"%s: %s\" failed (%d)\n",
  846. slapi_sdn_get_dn(entrySDN), attrName,
  847. slapi_sdn_get_dn(origDN), attrName, newDN, rc);
  848. }
  849. } else if (p) {
  850. char bak;
  851. /* (case 2) */
  852. values_del[0] = sval;
  853. values_del[1] = NULL;
  854. attribute1.mod_type = attrName;
  855. attribute1.mod_op = LDAP_MOD_DELETE;
  856. attribute1.mod_values = values_del;
  857. list_of_mods[0] = &attribute1;
  858. bak = *p;
  859. *p = '\0';
  860. /* newRDN and superior are already normalized. */
  861. newvalue = slapi_ch_smprintf("%s%s", sval, newDN);
  862. *p = bak;
  863. values_add[0]=newvalue;
  864. values_add[1]=NULL;
  865. attribute2.mod_type = attrName;
  866. attribute2.mod_op = LDAP_MOD_ADD;
  867. attribute2.mod_values = values_add;
  868. list_of_mods[1] = &attribute2;
  869. list_of_mods[2] = NULL;
  870. rc = _do_modify(mod_pb, entrySDN, list_of_mods);
  871. if (rc) {
  872. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  873. "_update_one_value: entry %s: replacing \"%s: %s\" "
  874. "with \"%s: %s\" failed (%d)\n",
  875. slapi_sdn_get_dn(entrySDN), attrName, sval, attrName, newvalue, rc);
  876. }
  877. slapi_ch_free_string(&newvalue);
  878. }
  879. /* else: value does not include the modified DN. Ignore it. */
  880. slapi_ch_free_string(&sval);
  881. }
  882. /* cleanup memory allocated for dnParts and newDN */
  883. if (dnParts){
  884. slapi_ldap_value_free(dnParts);
  885. dnParts = NULL;
  886. }
  887. slapi_ch_free_string(&newDN);
  888. }
  889. bail:
  890. return rc;
  891. }
  892. /*
  893. * update multiple attribute values per _do_modify
  894. */
  895. static int
  896. _update_all_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */
  897. Slapi_Attr *attr, /* referred attribute */
  898. char *attrName,
  899. Slapi_DN *origDN, /* original DN that was modified */
  900. char *newRDN, /* new RDN from modrdn */
  901. const char *newsuperior, /* new superior from modrdn */
  902. Slapi_PBlock *mod_pb)
  903. {
  904. Slapi_Mods *smods = NULL;
  905. char *newDN = NULL;
  906. char **dnParts = NULL;
  907. char *sval = NULL;
  908. char *newvalue = NULL;
  909. char *p = NULL;
  910. size_t dnlen = 0;
  911. int rc = 0;
  912. int nval = 0;
  913. slapi_attr_get_numvalues(attr, &nval);
  914. if (NULL == newRDN && NULL == newsuperior) {
  915. /* in delete mode */
  916. LDAPMod *mods[2];
  917. char *values_del[2];
  918. LDAPMod attribute1;
  919. /* delete old dn so set that up */
  920. values_del[0] = (char *)slapi_sdn_get_dn(origDN);
  921. values_del[1] = NULL;
  922. attribute1.mod_type = attrName;
  923. attribute1.mod_op = LDAP_MOD_DELETE;
  924. attribute1.mod_values = values_del;
  925. mods[0] = &attribute1;
  926. /* terminate list of mods. */
  927. mods[1] = NULL;
  928. rc = _do_modify(mod_pb, entrySDN, mods);
  929. if (rc) {
  930. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  931. "_update_all_per_mod: entry %s: deleting \"%s: %s\" failed (%d)"
  932. "\n", slapi_sdn_get_dn(entrySDN), attrName, slapi_sdn_get_dn(origDN), rc);
  933. }
  934. } else {
  935. /* in modrdn mode */
  936. const char *superior = NULL;
  937. int nval = 0;
  938. Slapi_Value *v = NULL;
  939. if (NULL == origDN) {
  940. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  941. "_update_all_per_mod: NULL dn was passed\n");
  942. goto bail;
  943. }
  944. /* need to put together rdn into a dn */
  945. dnParts = slapi_ldap_explode_dn( slapi_sdn_get_dn(origDN), 0 );
  946. if (NULL == dnParts) {
  947. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  948. "_update_all_per_mod: failed to explode dn %s\n",
  949. slapi_sdn_get_dn(origDN));
  950. goto bail;
  951. }
  952. if (NULL == newRDN) {
  953. newRDN = dnParts[0];
  954. }
  955. if (newsuperior) {
  956. superior = newsuperior;
  957. } else {
  958. /* do not free superior */
  959. superior = slapi_dn_find_parent(slapi_sdn_get_dn(origDN));
  960. }
  961. /* newRDN and superior are already normalized. */
  962. newDN = slapi_ch_smprintf("%s,%s", newRDN, superior);
  963. slapi_dn_ignore_case(newDN);
  964. /*
  965. * Compare the modified dn with the value of
  966. * the target attribute of referint to find out
  967. * the modified dn is the ancestor (case 2) or
  968. * the value itself (case 1).
  969. *
  970. * E.g.,
  971. * (case 1)
  972. * modrdn: uid=A,ou=B,o=C --> uid=A',ou=B',o=C
  973. * (origDN) (newDN)
  974. * member: uid=A,ou=B,ou=C --> uid=A',ou=B',ou=C
  975. * (sval) (newDN)
  976. *
  977. * (case 2)
  978. * modrdn: ou=B,o=C --> ou=B',o=C
  979. * (origDN) (newDN)
  980. * member: uid=A,ou=B,ou=C --> uid=A,ou=B',ou=C
  981. * (sval) (sval' + newDN)
  982. */
  983. slapi_attr_get_numvalues(attr, &nval);
  984. smods = slapi_mods_new();
  985. slapi_mods_init(smods, 2 * nval + 1);
  986. for (nval = slapi_attr_first_value(attr, &v);
  987. nval != -1;
  988. nval = slapi_attr_next_value(attr, nval, &v)) {
  989. p = NULL;
  990. dnlen = 0;
  991. /* DN syntax, which should be a string */
  992. sval = slapi_ch_strdup(slapi_value_get_string(v));
  993. rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
  994. if (rc == 0) { /* sval is passed in; not terminated */
  995. *(p + dnlen) = '\0';
  996. sval = p;
  997. } else if (rc > 0) {
  998. slapi_ch_free_string(&sval);
  999. sval = p;
  1000. }
  1001. /* else: (rc < 0) Ignore the DN normalization error for now. */
  1002. p = PL_strstr(sval, slapi_sdn_get_ndn(origDN));
  1003. if (p == sval) {
  1004. /* (case 1) */
  1005. slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval);
  1006. slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newDN);
  1007. } else if (p) {
  1008. /* (case 2) */
  1009. slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval);
  1010. *p = '\0';
  1011. newvalue = slapi_ch_smprintf("%s%s", sval, newDN);
  1012. slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newvalue);
  1013. slapi_ch_free_string(&newvalue);
  1014. }
  1015. /* else: value does not include the modified DN. Ignore it. */
  1016. slapi_ch_free_string(&sval);
  1017. }
  1018. rc = _do_modify(mod_pb, entrySDN, slapi_mods_get_ldapmods_byref(smods));
  1019. if (rc) {
  1020. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1021. "_update_all_per_mod: entry %s failed (%d)\n",
  1022. slapi_sdn_get_dn(entrySDN), rc);
  1023. }
  1024. /* cleanup memory allocated for dnParts and newDN */
  1025. if (dnParts){
  1026. slapi_ldap_value_free(dnParts);
  1027. dnParts = NULL;
  1028. }
  1029. slapi_ch_free_string(&newDN);
  1030. slapi_mods_free(&smods);
  1031. }
  1032. bail:
  1033. return rc;
  1034. }
  1035. int
  1036. update_integrity(Slapi_DN *origSDN,
  1037. char *newrDN, Slapi_DN *newsuperior,
  1038. int logChanges)
  1039. {
  1040. Slapi_PBlock *search_result_pb = NULL;
  1041. Slapi_PBlock *mod_pb = slapi_pblock_new();
  1042. Slapi_Entry **search_entries = NULL;
  1043. Slapi_DN *sdn = NULL;
  1044. Slapi_Attr *attr = NULL;
  1045. void *node = NULL;
  1046. const char *origDN = slapi_sdn_get_dn(origSDN);
  1047. const char *search_base = NULL;
  1048. char *attrName = NULL;
  1049. char *filter = NULL;
  1050. char *attrs[2];
  1051. char **membership_attrs = NULL;
  1052. int search_result;
  1053. int nval = 0;
  1054. int i, j;
  1055. int rc = SLAPI_PLUGIN_SUCCESS;
  1056. membership_attrs = referint_get_attrs();
  1057. /*
  1058. * For now, just putting attributes to keep integrity on in conf file,
  1059. * until resolve the other timing mode issue
  1060. */
  1061. search_result_pb = slapi_pblock_new();
  1062. /* Search each namingContext in turn
  1063. * or use the defined scope(s)
  1064. */
  1065. if (plugin_ContainerScope) {
  1066. sdn = plugin_ContainerScope;
  1067. } else {
  1068. sdn = slapi_get_first_suffix( &node, 0 );
  1069. }
  1070. while (sdn)
  1071. {
  1072. Slapi_Backend *be = slapi_be_select(sdn);
  1073. search_base = slapi_sdn_get_dn( sdn );
  1074. for(i = 0; membership_attrs[i] != NULL; i++){
  1075. if(newrDN){
  1076. /* we need to check the children of the old dn, so use a wildcard */
  1077. filter = slapi_filter_sprintf("(%s=*%s%s)", membership_attrs[i], ESC_NEXT_VAL, origDN);
  1078. } else {
  1079. filter = slapi_filter_sprintf("(%s=%s%s)", membership_attrs[i], ESC_NEXT_VAL, origDN);
  1080. }
  1081. if ( filter ) {
  1082. /* Need only the current attribute and its subtypes */
  1083. attrs[0] = membership_attrs[i];
  1084. attrs[1] = NULL;
  1085. /* Use new search API */
  1086. slapi_pblock_init(search_result_pb);
  1087. slapi_pblock_set(search_result_pb, SLAPI_BACKEND, be);
  1088. slapi_search_internal_set_pb(search_result_pb, search_base,
  1089. LDAP_SCOPE_SUBTREE, filter, attrs, 0 /* attrs only */,
  1090. NULL, NULL, referint_plugin_identity, 0);
  1091. slapi_search_internal_pb(search_result_pb);
  1092. slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
  1093. /* if search successfull then do integrity update */
  1094. if(search_result == LDAP_SUCCESS)
  1095. {
  1096. slapi_pblock_get(search_result_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
  1097. &search_entries);
  1098. for(j = 0; search_entries[j] != NULL; j++){
  1099. attr = NULL;
  1100. attrName = NULL;
  1101. /*
  1102. * Loop over all the attributes of the entry and search
  1103. * for the integrity attribute and its subtypes
  1104. */
  1105. for (slapi_entry_first_attr(search_entries[j], &attr); attr;
  1106. slapi_entry_next_attr(search_entries[j], attr, &attr))
  1107. {
  1108. /*
  1109. * Take into account only the subtypes of the attribute
  1110. * in argv[i] having the necessary value - origDN
  1111. */
  1112. slapi_attr_get_type(attr, &attrName);
  1113. if (slapi_attr_type_cmp(membership_attrs[i], attrName,
  1114. SLAPI_TYPE_CMP_SUBTYPE) == 0)
  1115. {
  1116. nval = 0;
  1117. slapi_attr_get_numvalues(attr, &nval);
  1118. /*
  1119. * We want to reduce the "modify" call as much as
  1120. * possible. But if an entry contains 1000s of
  1121. * attributes which need to be updated by the
  1122. * referint plugin (e.g., a group containing 1000s
  1123. * of members), we want to avoid to allocate too
  1124. * many mods * in one "modify" call.
  1125. * This is a compromise: If an attribute type has
  1126. * more than 128 values, we update the attribute
  1127. * value one by one. Otherwise, update all values
  1128. * in one "modify" call.
  1129. */
  1130. if (nval > 128) {
  1131. rc = _update_one_per_mod(
  1132. slapi_entry_get_sdn(search_entries[j]),
  1133. attr, attrName, origSDN, newrDN,
  1134. slapi_sdn_get_dn(newsuperior),
  1135. mod_pb);
  1136. } else {
  1137. rc = _update_all_per_mod(
  1138. slapi_entry_get_sdn(search_entries[j]),
  1139. attr, attrName, origSDN, newrDN,
  1140. slapi_sdn_get_dn(newsuperior),
  1141. mod_pb);
  1142. }
  1143. if (rc) {
  1144. if (use_txn) {
  1145. /*
  1146. * We're using backend transactions,
  1147. * so we need to stop on failure.
  1148. */
  1149. rc = SLAPI_PLUGIN_FAILURE;
  1150. goto free_and_return;
  1151. } else {
  1152. rc = SLAPI_PLUGIN_SUCCESS;
  1153. }
  1154. }
  1155. }
  1156. }
  1157. }
  1158. } else {
  1159. if (isFatalSearchError(search_result)){
  1160. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1161. "update_integrity search (base=%s filter=%s) returned "
  1162. "error %d\n", search_base, filter, search_result);
  1163. rc = SLAPI_PLUGIN_FAILURE;
  1164. goto free_and_return;
  1165. }
  1166. }
  1167. slapi_ch_free_string(&filter);
  1168. }
  1169. slapi_free_search_results_internal(search_result_pb);
  1170. }
  1171. if (plugin_ContainerScope) {
  1172. /* at the moment only a single scope is supported
  1173. * so the loop ends after the first iteration
  1174. */
  1175. sdn = NULL;
  1176. } else {
  1177. sdn = slapi_get_next_suffix( &node, 0 );
  1178. }
  1179. }
  1180. free_and_return:
  1181. /* free filter and search_results_pb */
  1182. slapi_ch_free_string(&filter);
  1183. slapi_ch_array_free(membership_attrs);
  1184. slapi_pblock_destroy(mod_pb);
  1185. if (search_result_pb) {
  1186. slapi_free_search_results_internal(search_result_pb);
  1187. slapi_pblock_destroy(search_result_pb);
  1188. }
  1189. return(rc);
  1190. }
  1191. int referint_postop_start( Slapi_PBlock *pb)
  1192. {
  1193. Slapi_Entry *plugin_entry = NULL;
  1194. Slapi_Entry *config_e = NULL;
  1195. Slapi_PBlock *search_pb = NULL;
  1196. Slapi_Entry *e = NULL;
  1197. Slapi_DN *config_sdn = NULL;
  1198. char *config_area = NULL;
  1199. int result = 0;
  1200. int rc = 0;
  1201. if((config_rwlock = slapi_new_rwlock()) == NULL){
  1202. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_init failed to "
  1203. "create rwlock.\n" );
  1204. return ( -1 );
  1205. }
  1206. slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &plugin_entry );
  1207. /* Set the alternate config area if one is defined. */
  1208. slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_AREA, &config_area);
  1209. if (config_area)
  1210. {
  1211. rc = slapi_dn_syntax_check(pb, config_area, 1);
  1212. if (rc) { /* syntax check failed */
  1213. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_start: "
  1214. "%s does not contain a valid DN (%s)\n",
  1215. SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_area);
  1216. rc = LDAP_INVALID_DN_SYNTAX;
  1217. goto bail;
  1218. }
  1219. config_sdn = slapi_sdn_new_dn_byval(config_area);
  1220. result = slapi_search_internal_get_entry(config_sdn, NULL, &e, referint_plugin_identity);
  1221. if (LDAP_SUCCESS != result) {
  1222. if (result == LDAP_NO_SUCH_OBJECT) {
  1223. /* log an error and use the plugin entry for the config */
  1224. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1225. "referint_postop_start: Config entry \"%s\" does "
  1226. "not exist.\n", config_area);
  1227. rc = -1;
  1228. goto bail;
  1229. }
  1230. } else {
  1231. if(e){
  1232. config_e = e;
  1233. } else {
  1234. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1235. "referint_postop_start: Config entry \"%s\" was not located.\n", config_area);
  1236. rc = -1;
  1237. goto bail;
  1238. }
  1239. }
  1240. } else {
  1241. config_e = plugin_entry;
  1242. }
  1243. if(load_config(pb, config_e, STARTUP) != LDAP_SUCCESS){
  1244. rc = -1;
  1245. goto bail;
  1246. }
  1247. referint_set_config_area(slapi_entry_get_sdn(config_e));
  1248. /*
  1249. * Only bother to start the thread if you are in delay mode.
  1250. * 0 = no delay,
  1251. * -1 = integrity off
  1252. */
  1253. if(referint_get_delay() > 0){
  1254. /* initialize the cv and lock */
  1255. if (!use_txn && (NULL == referint_mutex)) {
  1256. referint_mutex = PR_NewLock();
  1257. }
  1258. keeprunning_mutex = PR_NewLock();
  1259. keeprunning_cv = PR_NewCondVar(keeprunning_mutex);
  1260. keeprunning =1;
  1261. referint_tid = PR_CreateThread (PR_USER_THREAD,
  1262. referint_thread_func,
  1263. NULL,
  1264. PR_PRIORITY_NORMAL,
  1265. PR_GLOBAL_THREAD,
  1266. PR_UNJOINABLE_THREAD,
  1267. SLAPD_DEFAULT_THREAD_STACKSIZE);
  1268. if ( referint_tid == NULL ) {
  1269. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1270. "referint_postop_start PR_CreateThread failed\n" );
  1271. exit( 1 );
  1272. }
  1273. }
  1274. bail:
  1275. slapi_free_search_results_internal(search_pb);
  1276. slapi_pblock_destroy(search_pb);
  1277. slapi_sdn_free(&config_sdn);
  1278. slapi_entry_free(e);
  1279. return rc;
  1280. }
  1281. int referint_postop_close( Slapi_PBlock *pb)
  1282. {
  1283. /* signal the thread to exit */
  1284. if (NULL != keeprunning_mutex) {
  1285. PR_Lock(keeprunning_mutex);
  1286. keeprunning=0;
  1287. if (NULL != keeprunning_cv) {
  1288. PR_NotifyCondVar(keeprunning_cv);
  1289. }
  1290. PR_Unlock(keeprunning_mutex);
  1291. }
  1292. slapi_destroy_rwlock(config_rwlock);
  1293. config_rwlock = NULL;
  1294. slapi_ch_free_string(&config->logfile);
  1295. slapi_ch_array_free(config->attrs);
  1296. slapi_ch_free((void **)&config);
  1297. return(0);
  1298. }
  1299. void
  1300. referint_thread_func(void *arg)
  1301. {
  1302. PRFileDesc *prfd = NULL;
  1303. char *logfilename = NULL;
  1304. char thisline[MAX_LINE];
  1305. char delimiter[]="\t\n";
  1306. char *ptoken;
  1307. char *tmprdn;
  1308. char *iter = NULL;
  1309. Slapi_DN *sdn = NULL;
  1310. Slapi_DN *tmpsuperior = NULL;
  1311. int logChanges = 0;
  1312. int delay;
  1313. int no_changes;
  1314. /*
  1315. * keep running this thread until plugin is signaled to close
  1316. */
  1317. while(1){
  1318. /* refresh the config */
  1319. slapi_ch_free_string(&logfilename);
  1320. referint_get_config(&delay, &logChanges, &logfilename);
  1321. no_changes=1;
  1322. while(no_changes){
  1323. PR_Lock(keeprunning_mutex);
  1324. if(keeprunning == 0){
  1325. PR_Unlock(keeprunning_mutex);
  1326. break;
  1327. }
  1328. PR_Unlock(keeprunning_mutex);
  1329. referint_lock();
  1330. if (( prfd = PR_Open( logfilename, PR_RDONLY, REFERINT_DEFAULT_FILE_MODE )) == NULL ){
  1331. referint_unlock();
  1332. /* go back to sleep and wait for this file */
  1333. PR_Lock(keeprunning_mutex);
  1334. PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
  1335. PR_Unlock(keeprunning_mutex);
  1336. } else {
  1337. no_changes = 0;
  1338. }
  1339. }
  1340. /*
  1341. * Check keep running here, because after break out of no
  1342. * changes loop on shutdown, also need to break out of this
  1343. * loop before trying to do the changes. The server
  1344. * will pick them up on next startup as file still exists
  1345. */
  1346. PR_Lock(keeprunning_mutex);
  1347. if(keeprunning == 0){
  1348. PR_Unlock(keeprunning_mutex);
  1349. break;
  1350. }
  1351. PR_Unlock(keeprunning_mutex);
  1352. while( GetNextLine(thisline, MAX_LINE, prfd) ){
  1353. ptoken = ldap_utf8strtok_r(thisline, delimiter, &iter);
  1354. sdn = slapi_sdn_new_normdn_byref(ptoken);
  1355. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  1356. if(!strcasecmp(ptoken, "NULL")) {
  1357. tmprdn = NULL;
  1358. } else {
  1359. tmprdn = slapi_ch_smprintf("%s", ptoken);
  1360. }
  1361. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  1362. if (!strcasecmp(ptoken, "NULL")) {
  1363. tmpsuperior = NULL;
  1364. } else {
  1365. tmpsuperior = slapi_sdn_new_normdn_byref(ptoken);
  1366. }
  1367. ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
  1368. if (strcasecmp(ptoken, "NULL") != 0) {
  1369. /* Set the bind DN in the thread data */
  1370. if(slapi_td_set_dn(slapi_ch_strdup(ptoken))){
  1371. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,"Failed to set thread data\n");
  1372. }
  1373. }
  1374. update_integrity(sdn, tmprdn, tmpsuperior, logChanges);
  1375. slapi_sdn_free(&sdn);
  1376. slapi_ch_free_string(&tmprdn);
  1377. slapi_sdn_free(&tmpsuperior);
  1378. }
  1379. PR_Close(prfd);
  1380. /* remove the original file */
  1381. if( PR_SUCCESS != PR_Delete(logfilename) ){
  1382. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1383. "referint_postop_close could not delete \"%s\"\n", logfilename );
  1384. }
  1385. /* unlock and let other writers back at the file */
  1386. referint_unlock();
  1387. /* wait on condition here */
  1388. PR_Lock(keeprunning_mutex);
  1389. PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
  1390. PR_Unlock(keeprunning_mutex);
  1391. }
  1392. /* cleanup resources allocated in start */
  1393. if (NULL != keeprunning_mutex) {
  1394. PR_DestroyLock(keeprunning_mutex);
  1395. }
  1396. if (NULL != referint_mutex) {
  1397. PR_DestroyLock(referint_mutex);
  1398. }
  1399. if (NULL != keeprunning_cv) {
  1400. PR_DestroyCondVar(keeprunning_cv);
  1401. }
  1402. slapi_ch_free_string(&logfilename);
  1403. }
  1404. int my_fgetc(PRFileDesc *stream)
  1405. {
  1406. static char buf[READ_BUFSIZE] = "\0";
  1407. static int position = READ_BUFSIZE;
  1408. int retval;
  1409. int err;
  1410. /* check if we need to load the buffer */
  1411. if( READ_BUFSIZE == position )
  1412. {
  1413. memset(buf, '\0', READ_BUFSIZE);
  1414. if( ( err = PR_Read(stream, buf, READ_BUFSIZE) ) >= 0)
  1415. {
  1416. /* it read some data */;
  1417. position = 0;
  1418. }else{
  1419. /* an error occurred */
  1420. return err;
  1421. }
  1422. }
  1423. /* try to read some data */
  1424. if( '\0' == buf[position])
  1425. {
  1426. /* out of data, return eof */
  1427. retval = MY_EOF;
  1428. position = READ_BUFSIZE;
  1429. }else{
  1430. retval = buf[position];
  1431. position++;
  1432. }
  1433. return retval;
  1434. }
  1435. int
  1436. GetNextLine(char *dest, int size_dest, PRFileDesc *stream) {
  1437. char nextchar ='\0';
  1438. int done = 0;
  1439. int i = 0;
  1440. while(!done){
  1441. if( ( nextchar = my_fgetc(stream) ) != 0){
  1442. if( i < (size_dest - 1) ){
  1443. dest[i] = nextchar;
  1444. i++;
  1445. if(nextchar == '\n'){
  1446. /* end of line reached */
  1447. done = 1;
  1448. }
  1449. } else {
  1450. /* no more room in buffer */
  1451. done = 1;
  1452. }
  1453. } else {
  1454. /* error or end of file */
  1455. done = 1;
  1456. }
  1457. }
  1458. dest[i] = '\0';
  1459. /* return size of string read */
  1460. return i;
  1461. }
  1462. /*
  1463. * Write this record to the log file
  1464. */
  1465. void
  1466. writeintegritylog(Slapi_PBlock *pb, char *logfilename, Slapi_DN *sdn,
  1467. char *newrdn, Slapi_DN *newsuperior, Slapi_DN *requestorsdn)
  1468. {
  1469. PRFileDesc *prfd;
  1470. char buffer[MAX_LINE];
  1471. int len_to_write = 0;
  1472. int rc;
  1473. const char *requestordn = NULL;
  1474. const char *newsuperiordn = NULL;
  1475. size_t reqdn_len = 0;
  1476. if (!(referint_sdn_in_entry_scope(sdn) ||
  1477. (newsuperior && referint_sdn_in_entry_scope(newsuperior)))) {
  1478. return;
  1479. }
  1480. /*
  1481. * Use this lock to protect file data when update integrity is occuring.
  1482. * If betxn is enabled, this mutex is ignored; transaction itself takes
  1483. * the role.
  1484. */
  1485. referint_lock();
  1486. if (( prfd = PR_Open( logfilename, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
  1487. REFERINT_DEFAULT_FILE_MODE )) == NULL )
  1488. {
  1489. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1490. "referint_postop could not write integrity log \"%s\" "
  1491. SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
  1492. logfilename, PR_GetError(), slapd_pr_strerror(PR_GetError()) );
  1493. PR_Unlock(referint_mutex);
  1494. referint_unlock();
  1495. return;
  1496. }
  1497. /*
  1498. * Make sure we have enough room in our buffer before trying to write it.
  1499. * add length of dn + 5(three tabs, a newline, and terminating \0)
  1500. */
  1501. len_to_write = slapi_sdn_get_ndn_len(sdn) + 5;
  1502. newsuperiordn = slapi_sdn_get_dn(newsuperior);
  1503. if (newsuperiordn &&
  1504. !referint_sdn_in_entry_scope(newsuperior)) {
  1505. /* this is a modrdn which moves the entry out of scope, handle like a delete */
  1506. newsuperiordn = NULL;
  1507. newrdn = NULL;
  1508. }
  1509. if(newrdn == NULL){
  1510. /* add the length of "NULL" */
  1511. len_to_write += 4;
  1512. } else {
  1513. /* add the length of the newrdn */
  1514. len_to_write += strlen(newrdn);
  1515. }
  1516. if(NULL == newsuperiordn)
  1517. {
  1518. /* add the length of "NULL" */
  1519. len_to_write += 4;
  1520. } else {
  1521. /* add the length of the newsuperior */
  1522. len_to_write += slapi_sdn_get_ndn_len(newsuperior);
  1523. }
  1524. slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &requestordn);
  1525. if (requestorsdn && (requestordn = slapi_sdn_get_udn(requestorsdn)) &&
  1526. (reqdn_len = strlen(requestordn))) {
  1527. len_to_write += reqdn_len;
  1528. } else {
  1529. len_to_write += 4; /* "NULL" */
  1530. }
  1531. if(len_to_write > MAX_LINE ){
  1532. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1533. "referint_postop could not write integrity log:"
  1534. " line length exceeded. It will not be able"
  1535. " to update references to this entry.\n");
  1536. } else {
  1537. PR_snprintf(buffer, MAX_LINE, "%s\t%s\t%s\t%s\t\n", slapi_sdn_get_dn(sdn),
  1538. (newrdn != NULL) ? newrdn : "NULL",
  1539. (newsuperiordn != NULL) ? newsuperiordn : "NULL",
  1540. requestordn ? requestordn : "NULL");
  1541. if (PR_Write(prfd,buffer,strlen(buffer)) < 0){
  1542. slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
  1543. " writeintegritylog: PR_Write failed : The disk"
  1544. " may be full or the file is unwritable :: NSPR error - %d\n",
  1545. PR_GetError());
  1546. }
  1547. }
  1548. /* If file descriptor is closed successfully, PR_SUCCESS */
  1549. rc = PR_Close(prfd);
  1550. if (rc != PR_SUCCESS){
  1551. slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
  1552. " writeintegritylog: failed to close the file descriptor prfd; NSPR error - %d\n",
  1553. PR_GetError());
  1554. }
  1555. referint_unlock();
  1556. }
  1557. static int
  1558. referint_preop_init(Slapi_PBlock *pb)
  1559. {
  1560. int status = 0;
  1561. if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) != 0 ||
  1562. slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &pdesc) != 0 ||
  1563. slapi_pblock_set(pb, premodfn, (void *)referint_validate_config) != 0)
  1564. {
  1565. slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1566. "referint_preop_init: failed to register plugin\n");
  1567. status = -1;
  1568. }
  1569. return status;
  1570. }
  1571. /*
  1572. * This is our preop function to validate a config update, postop modify
  1573. * will apply the config change.
  1574. */
  1575. int
  1576. referint_validate_config(Slapi_PBlock *pb)
  1577. {
  1578. Slapi_Entry *config_e = NULL, *e = NULL;
  1579. Slapi_Entry *pre_entry = NULL;
  1580. Slapi_Entry *resulting_entry = NULL;
  1581. Slapi_DN *config_sdn = NULL;
  1582. Slapi_DN *sdn = NULL;
  1583. Slapi_Mods *smods = NULL;
  1584. LDAPMod **mods = NULL;
  1585. char *config_area = NULL;
  1586. int rc = SLAPI_PLUGIN_SUCCESS;
  1587. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
  1588. slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &pre_entry);
  1589. if (referint_sdn_config_cmp(sdn) == 0 && slapi_sdn_compare(sdn, referint_get_plugin_area()) ){
  1590. /*
  1591. * This is the shared config entry. Apply the mods and set/validate
  1592. * the config
  1593. */
  1594. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1595. smods = slapi_mods_new();
  1596. slapi_mods_init_byref(smods, mods);
  1597. /*
  1598. * Create a copy of the entry and apply the
  1599. * mods to create the resulting entry.
  1600. */
  1601. resulting_entry = slapi_entry_dup(pre_entry);
  1602. if (mods && (slapi_entry_apply_mods(resulting_entry, mods) != LDAP_SUCCESS)) {
  1603. /* we don't care about this, the update is invalid and will be caught later */
  1604. goto bail;
  1605. }
  1606. if ( SLAPI_PLUGIN_FAILURE == load_config(pb, resulting_entry, 0)) {
  1607. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_validate_config: "
  1608. "configuration validation failed.\n");
  1609. rc = LDAP_UNWILLING_TO_PERFORM;
  1610. goto bail;
  1611. }
  1612. } else if (slapi_sdn_compare(sdn, referint_get_plugin_area()) == 0){
  1613. /*
  1614. * Check if the plugin config area is set(verify it and load its config),
  1615. * otherwise reload the plugin entry config
  1616. */
  1617. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1618. smods = slapi_mods_new();
  1619. slapi_mods_init_byref(smods, mods);
  1620. /* Apply the mods to create the resulting entry. */
  1621. resulting_entry = slapi_entry_dup(pre_entry);
  1622. if (mods && (slapi_entry_apply_mods(resulting_entry, mods) != LDAP_SUCCESS)) {
  1623. /* we don't care about this, the update is invalid and will be caught later */
  1624. goto bail;
  1625. }
  1626. if((config_area = slapi_entry_attr_get_charptr(resulting_entry, SLAPI_PLUGIN_SHARED_CONFIG_AREA))){
  1627. rc = slapi_dn_syntax_check(pb, config_area, 1);
  1628. if (rc) { /* syntax check failed */
  1629. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_validate_config: "
  1630. "%s does not contain a valid DN (%s)\n",
  1631. SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_area);
  1632. rc = LDAP_INVALID_DN_SYNTAX;
  1633. goto bail;
  1634. }
  1635. config_sdn = slapi_sdn_new_dn_byval(config_area);
  1636. rc = slapi_search_internal_get_entry(config_sdn, NULL, &e, referint_plugin_identity);
  1637. if (LDAP_SUCCESS != rc) {
  1638. /* log an error and use the plugin entry for the config */
  1639. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1640. "referint_validate_config: Config entry \"%s\" couild not be found, error %d\n",
  1641. config_area, rc);
  1642. rc = LDAP_OPERATIONS_ERROR;
  1643. goto bail;
  1644. } else {
  1645. if(e){
  1646. config_e = e;
  1647. } else {
  1648. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1649. "referint_validate_config: Config entry \"%s\" was not located.\n", config_area);
  1650. rc = LDAP_OPERATIONS_ERROR;
  1651. goto bail;
  1652. }
  1653. }
  1654. } else {
  1655. config_e = resulting_entry;
  1656. }
  1657. if(load_config(pb, config_e, 0) != LDAP_SUCCESS){
  1658. rc = LDAP_UNWILLING_TO_PERFORM;
  1659. goto bail;
  1660. }
  1661. referint_set_config_area(slapi_entry_get_sdn(config_e));
  1662. }
  1663. bail:
  1664. slapi_entry_free(e);
  1665. slapi_entry_free(resulting_entry);
  1666. slapi_sdn_free(&config_sdn);
  1667. slapi_ch_free_string(&config_area);
  1668. slapi_mods_free(&smods);
  1669. return rc;
  1670. }