referint.c 63 KB

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