referint.c 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828
  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. /* Should we stop if one modify returns an error? */
  1144. }
  1145. }
  1146. }
  1147. } else {
  1148. if (isFatalSearchError(search_result)){
  1149. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1150. "update_integrity search (base=%s filter=%s) returned "
  1151. "error %d\n", search_base, filter, search_result);
  1152. rc = SLAPI_PLUGIN_FAILURE;
  1153. goto free_and_return;
  1154. }
  1155. }
  1156. slapi_ch_free_string(&filter);
  1157. }
  1158. slapi_free_search_results_internal(search_result_pb);
  1159. }
  1160. if (plugin_ContainerScope) {
  1161. /* at the moment only a single scope is supported
  1162. * so the loop ends after the first iteration
  1163. */
  1164. sdn = NULL;
  1165. } else {
  1166. sdn = slapi_get_next_suffix( &node, 0 );
  1167. }
  1168. }
  1169. /* if got here, then everything good rc = 0 */
  1170. rc = SLAPI_PLUGIN_SUCCESS;
  1171. free_and_return:
  1172. /* free filter and search_results_pb */
  1173. slapi_ch_free_string(&filter);
  1174. slapi_ch_array_free(membership_attrs);
  1175. slapi_pblock_destroy(mod_pb);
  1176. if (search_result_pb) {
  1177. slapi_free_search_results_internal(search_result_pb);
  1178. slapi_pblock_destroy(search_result_pb);
  1179. }
  1180. return(rc);
  1181. }
  1182. int referint_postop_start( Slapi_PBlock *pb)
  1183. {
  1184. Slapi_Entry *plugin_entry = NULL;
  1185. Slapi_Entry *config_e = NULL;
  1186. Slapi_PBlock *search_pb = NULL;
  1187. Slapi_Entry *e = NULL;
  1188. Slapi_DN *config_sdn = NULL;
  1189. char *config_area = NULL;
  1190. int result = 0;
  1191. int rc = 0;
  1192. if((config_rwlock = slapi_new_rwlock()) == NULL){
  1193. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_init failed to "
  1194. "create rwlock.\n" );
  1195. return ( -1 );
  1196. }
  1197. slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &plugin_entry );
  1198. /* Set the alternate config area if one is defined. */
  1199. slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_AREA, &config_area);
  1200. if (config_area)
  1201. {
  1202. rc = slapi_dn_syntax_check(pb, config_area, 1);
  1203. if (rc) { /* syntax check failed */
  1204. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_postop_start: "
  1205. "%s does not contain a valid DN (%s)\n",
  1206. SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_area);
  1207. rc = LDAP_INVALID_DN_SYNTAX;
  1208. goto bail;
  1209. }
  1210. config_sdn = slapi_sdn_new_dn_byval(config_area);
  1211. result = slapi_search_internal_get_entry(config_sdn, NULL, &e, referint_plugin_identity);
  1212. if (LDAP_SUCCESS != result) {
  1213. if (result == LDAP_NO_SUCH_OBJECT) {
  1214. /* log an error and use the plugin entry for the config */
  1215. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1216. "referint_postop_start: Config entry \"%s\" does "
  1217. "not exist.\n", config_area);
  1218. rc = -1;
  1219. goto bail;
  1220. }
  1221. } else {
  1222. if(e){
  1223. config_e = e;
  1224. } else {
  1225. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1226. "referint_postop_start: Config entry \"%s\" was not located.\n", config_area);
  1227. rc = -1;
  1228. goto bail;
  1229. }
  1230. }
  1231. } else {
  1232. config_e = plugin_entry;
  1233. }
  1234. if(load_config(pb, config_e, STARTUP) != LDAP_SUCCESS){
  1235. rc = -1;
  1236. goto bail;
  1237. }
  1238. referint_set_config_area(slapi_entry_get_sdn(config_e));
  1239. /*
  1240. * Only bother to start the thread if you are in delay mode.
  1241. * 0 = no delay,
  1242. * -1 = integrity off
  1243. */
  1244. if(referint_get_delay() > 0){
  1245. /* initialize the cv and lock */
  1246. if (!use_txn && (NULL == referint_mutex)) {
  1247. referint_mutex = PR_NewLock();
  1248. }
  1249. keeprunning_mutex = PR_NewLock();
  1250. keeprunning_cv = PR_NewCondVar(keeprunning_mutex);
  1251. keeprunning =1;
  1252. referint_tid = PR_CreateThread (PR_USER_THREAD,
  1253. referint_thread_func,
  1254. NULL,
  1255. PR_PRIORITY_NORMAL,
  1256. PR_GLOBAL_THREAD,
  1257. PR_UNJOINABLE_THREAD,
  1258. SLAPD_DEFAULT_THREAD_STACKSIZE);
  1259. if ( referint_tid == NULL ) {
  1260. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
  1261. "referint_postop_start PR_CreateThread failed\n" );
  1262. exit( 1 );
  1263. }
  1264. }
  1265. bail:
  1266. slapi_free_search_results_internal(search_pb);
  1267. slapi_pblock_destroy(search_pb);
  1268. slapi_sdn_free(&config_sdn);
  1269. slapi_entry_free(e);
  1270. return rc;
  1271. }
  1272. int referint_postop_close( Slapi_PBlock *pb)
  1273. {
  1274. /* signal the thread to exit */
  1275. if (NULL != keeprunning_mutex) {
  1276. PR_Lock(keeprunning_mutex);
  1277. keeprunning=0;
  1278. if (NULL != keeprunning_cv) {
  1279. PR_NotifyCondVar(keeprunning_cv);
  1280. }
  1281. PR_Unlock(keeprunning_mutex);
  1282. }
  1283. slapi_destroy_rwlock(config_rwlock);
  1284. config_rwlock = NULL;
  1285. slapi_ch_free_string(&config->logfile);
  1286. slapi_ch_array_free(config->attrs);
  1287. slapi_ch_free((void **)&config);
  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. goto bail;
  1602. }
  1603. } else if (slapi_sdn_compare(sdn, referint_get_plugin_area()) == 0){
  1604. /*
  1605. * Check if the plugin config area is set(verify it and load its config),
  1606. * otherwise reload the plugin entry config
  1607. */
  1608. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1609. smods = slapi_mods_new();
  1610. slapi_mods_init_byref(smods, mods);
  1611. /* Apply the mods to create the resulting entry. */
  1612. resulting_entry = slapi_entry_dup(pre_entry);
  1613. if (mods && (slapi_entry_apply_mods(resulting_entry, mods) != LDAP_SUCCESS)) {
  1614. /* we don't care about this, the update is invalid and will be caught later */
  1615. goto bail;
  1616. }
  1617. if((config_area = slapi_entry_attr_get_charptr(resulting_entry, SLAPI_PLUGIN_SHARED_CONFIG_AREA))){
  1618. rc = slapi_dn_syntax_check(pb, config_area, 1);
  1619. if (rc) { /* syntax check failed */
  1620. slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "referint_validate_config: "
  1621. "%s does not contain a valid DN (%s)\n",
  1622. SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_area);
  1623. rc = LDAP_INVALID_DN_SYNTAX;
  1624. goto bail;
  1625. }
  1626. config_sdn = slapi_sdn_new_dn_byval(config_area);
  1627. rc = slapi_search_internal_get_entry(config_sdn, NULL, &e, referint_plugin_identity);
  1628. if (LDAP_SUCCESS != rc) {
  1629. /* log an error and use the plugin entry for the config */
  1630. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1631. "referint_validate_config: Config entry \"%s\" couild not be found, error %d\n",
  1632. config_area, rc);
  1633. rc = LDAP_OPERATIONS_ERROR;
  1634. goto bail;
  1635. } else {
  1636. if(e){
  1637. config_e = e;
  1638. } else {
  1639. slapi_log_error(SLAPI_LOG_PLUGIN, REFERINT_PLUGIN_SUBSYSTEM,
  1640. "referint_validate_config: Config entry \"%s\" was not located.\n", config_area);
  1641. rc = LDAP_OPERATIONS_ERROR;
  1642. goto bail;
  1643. }
  1644. }
  1645. } else {
  1646. config_e = resulting_entry;
  1647. }
  1648. if(load_config(pb, config_e, 0) != LDAP_SUCCESS){
  1649. rc = LDAP_UNWILLING_TO_PERFORM;
  1650. goto bail;
  1651. }
  1652. referint_set_config_area(slapi_entry_get_sdn(config_e));
  1653. }
  1654. bail:
  1655. slapi_entry_free(e);
  1656. slapi_entry_free(resulting_entry);
  1657. slapi_sdn_free(&config_sdn);
  1658. slapi_ch_free_string(&config_area);
  1659. slapi_mods_free(&smods);
  1660. return rc;
  1661. }