summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/referint
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/plugins/referint
downloadds-ldapserver7x.tar.gz
ds-ldapserver7x.tar.xz
ds-ldapserver7x.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/plugins/referint')
-rw-r--r--ldap/servers/plugins/referint/Makefile72
-rw-r--r--ldap/servers/plugins/referint/dllmain.c95
-rw-r--r--ldap/servers/plugins/referint/referint.c808
-rw-r--r--ldap/servers/plugins/referint/referint.def12
4 files changed, 987 insertions, 0 deletions
diff --git a/ldap/servers/plugins/referint/Makefile b/ldap/servers/plugins/referint/Makefile
new file mode 100644
index 00000000..acf09c42
--- /dev/null
+++ b/ldap/servers/plugins/referint/Makefile
@@ -0,0 +1,72 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+LDAP_SRC = ../../..
+MCOM_ROOT = ../../../../..
+
+NOSTDCLEAN=true # don't let nsconfig.mk define target clean
+NOSTDSTRIP=true # don't let nsconfig.mk define target strip
+NSPR20=true # probably should be defined somewhere else (not sure where)
+
+OBJDEST = $(OBJDIR)/lib/referint-plugin
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./referint.def
+endif
+
+REFERINT_OBJS = referint.o
+OBJS = $(addprefix $(OBJDEST)/, $(REFERINT_OBJS))
+
+INCLUDES += -I../../slapd -I../../../include
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPLINK_DEP) $(NSPRLINK_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAPLINK) $(NSPRLINK)
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(SECURITY_DEP)
+EXTRA_LIBS += $(SECURITYLINK)
+endif
+
+ifeq ($(ARCH), WINNT)
+REFERINT_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+ifeq ($(ARCH), AIX)
+LD=ld
+endif
+
+REFERINT= $(addprefix $(LIBDIR)/, $(REFERINT_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(REFERINT)
+
+ifeq ($(ARCH), WINNT)
+$(REFERINT): $(OBJS) $(REFERINT_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(REFERINT_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+$(REFERINT): $(OBJS) $(REFERINT_DLL_OBJ)
+ $(LINK_DLL) $(REFERINT_DLL_OBJ) $(EXTRA_LIBS)
+endif
+
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(REFERINT_DLL_OBJ)
+endif
+ $(RM) $(REFERINT)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
diff --git a/ldap/servers/plugins/referint/dllmain.c b/ldap/servers/plugins/referint/dllmain.c
new file mode 100644
index 00000000..96bfcbb0
--- /dev/null
+++ b/ldap/servers/plugins/referint/dllmain.c
@@ -0,0 +1,95 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "ldap.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/referint/referint.c b/ldap/servers/plugins/referint/referint.c
new file mode 100644
index 00000000..e0ad15fd
--- /dev/null
+++ b/ldap/servers/plugins/referint/referint.c
@@ -0,0 +1,808 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdio.h>
+#include <string.h>
+#include "portable.h"
+#include "slapi-plugin.h"
+#include "slap.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+
+/* include NSPR header files */
+#include "prthread.h"
+#include "prlock.h"
+#include "prerror.h"
+#include "prcvar.h"
+#include "prio.h"
+
+/* get file mode flags for unix */
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+#define REFERINT_PLUGIN_SUBSYSTEM "referint-plugin" /* used for logging */
+
+#ifdef _WIN32
+#define REFERINT_DEFAULT_FILE_MODE 0
+#else
+#define REFERINT_DEFAULT_FILE_MODE S_IRUSR | S_IWUSR
+#endif
+
+
+#define MAX_LINE 2048
+#define READ_BUFSIZE 4096
+#define MY_EOF 0
+
+/* function prototypes */
+int referint_postop_init( Slapi_PBlock *pb );
+int referint_postop_del( Slapi_PBlock *pb );
+int referint_postop_modrdn( Slapi_PBlock *pb );
+int referint_postop_start( Slapi_PBlock *pb);
+int referint_postop_close( Slapi_PBlock *pb);
+int update_integrity(char **argv, char *origDN, char *newrDN, int logChanges);
+void referint_thread_func(void *arg);
+int GetNextLine(char *dest, int size_dest, PRFileDesc *stream);
+void writeintegritylog(char *logfilename, char *dn, char *newrdn);
+int my_fgetc(PRFileDesc *stream);
+
+/* global thread control stuff */
+
+static PRLock *referint_mutex = NULL;
+static PRThread *referint_tid = NULL;
+int keeprunning = 0;
+
+static PRLock *keeprunning_mutex = NULL;
+static PRCondVar *keeprunning_cv = NULL;
+
+static Slapi_PluginDesc pdesc = { "referint", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "referential integrity plugin" };
+
+static void* referint_plugin_identity = NULL;
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+int
+referint_postop_init( Slapi_PBlock *pb )
+{
+
+ /*
+ * Get plugin identity and stored it for later use
+ * Used for internal operations
+ */
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &referint_plugin_identity);
+ PR_ASSERT (referint_plugin_identity);
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_DELETE_FN,
+ (void *) referint_postop_del ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODRDN_FN,
+ (void *) referint_postop_modrdn ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+ (void *) referint_postop_start ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) referint_postop_close ) != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_init failed\n" );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+int
+referint_postop_del( Slapi_PBlock *pb )
+{
+ char *dn;
+ int rc;
+ int oprc;
+ char **argv;
+ int argc;
+ int delay;
+ int logChanges=0;
+ int isrepop = 0;
+
+ if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &isrepop ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_DELETE_TARGET, &dn ) != 0 ||
+ slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_del: could not get parameters\n" );
+ return( -1 );
+ }
+
+ /* this plugin should only execute if the delete was successful
+ and this is not a replicated op
+ */
+ if(oprc != 0 || isrepop)
+ {
+ return( 0 );
+ }
+ /* get args */
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argc\n" );
+ return( -1 );
+ }
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argv\n" );
+ return( -1 );
+ }
+
+ if(argv == NULL){
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_modrdn, args are NULL\n" );
+ return( -1 );
+ }
+
+ if (argc >= 3) {
+ /* argv[0] will be the delay */
+ delay = atoi(argv[0]);
+
+ /* argv[2] will be wether or not to log changes */
+ logChanges = atoi(argv[2]);
+
+ if(delay == -1){
+ /* integrity updating is off */
+ rc = 0;
+ }else if(delay == 0){
+ /* no delay */
+ /* call function to update references to entry */
+ rc = update_integrity(argv, dn, NULL, logChanges);
+ }else{
+ /* write the entry to integrity log */
+ writeintegritylog(argv[1],dn, NULL);
+ rc = 0;
+ }
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop insufficient arguments supplied\n" );
+ return( -1 );
+ }
+
+ return( rc );
+
+}
+
+int
+referint_postop_modrdn( Slapi_PBlock *pb )
+{
+ char *dn;
+ char *newrdn;
+ int oprc;
+ int rc;
+ char **argv;
+ int argc = 0;
+ int delay;
+ int logChanges=0;
+ int isrepop = 0;
+
+ if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &isrepop ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_MODRDN_TARGET, &dn ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn ) != 0 ||
+ slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 ){
+
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_modrdn: could not get parameters\n" );
+ return( -1 );
+ }
+
+ /* this plugin should only execute if the delete was successful
+ and this is not a replicated op
+ */
+ if(oprc != 0 || isrepop){
+ return( 0 );
+ }
+ /* get args */
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argv\n" );
+ return( -1 );
+ }
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argv\n" );
+ return( -1 );
+ }
+
+ if(argv == NULL){
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_modrdn, args are NULL\n" );
+ return( -1 );
+ }
+
+ if (argc >= 3) {
+ /* argv[0] will always be the delay */
+ delay = atoi(argv[0]);
+
+ /* argv[2] will be wether or not to log changes */
+ logChanges = atoi(argv[2]);
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_modrdn insufficient arguments supplied\n" );
+ return( -1 );
+ }
+
+ if(delay == -1){
+ /* integrity updating is off */
+ rc = 0;
+ }else if(delay == 0){
+ /* no delay */
+ /* call function to update references to entry */
+ rc = update_integrity(argv, dn, newrdn, logChanges);
+ }else{
+ /* write the entry to integrity log */
+ writeintegritylog(argv[1],dn, newrdn);
+ rc = 0;
+ }
+
+ return( rc );
+}
+
+int isFatalSearchError(int search_result)
+{
+
+ /* Make sure search result is fatal
+ * Some conditions that happen quite often are not fatal
+ * for example if you have two suffixes and one is null, you will always
+ * get no such object, howerever this is not a fatal error.
+ * Add other conditions to the if statement as they are found
+ */
+
+ /* NPCTE fix for bugid 531225, esc 0. <P.R> <30-May-2001> */
+ switch(search_result) {
+ case LDAP_REFERRAL:
+ case LDAP_NO_SUCH_OBJECT: return 0 ;
+ }
+ return 1;
+ /* end of NPCTE fix for bugid 531225 */
+
+}
+
+int update_integrity(char **argv, char *origDN, char *newrDN, int logChanges){
+
+ Slapi_PBlock *search_result_pb = NULL;
+ Slapi_PBlock *mod_result_pb = NULL;
+ Slapi_Entry **search_entries = NULL;
+ int search_result;
+ Slapi_DN *sdn = NULL;
+ void *node = NULL;
+ LDAPMod attribute1, attribute2;
+ const LDAPMod *list_of_mods[3];
+ char *values_del[2];
+ char *values_add[2];
+ char *filter = NULL;
+ int i, j;
+ const char *search_base = NULL;
+ char *newDN=NULL;
+ char **dnParts=NULL;
+ int dnsize;
+ int x;
+ int rc;
+ int valcount = 0;
+
+ if ( argv == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop required config file arguments missing\n" );
+ rc = -1;
+ goto free_and_return;
+ }
+
+ /* for now, just putting attributes to keep integrity on in conf file,
+ until resolve the other timing mode issue */
+
+ /* Search each namingContext in turn */
+ for ( sdn = slapi_get_first_suffix( &node, 0 ); sdn != NULL;
+ sdn = slapi_get_next_suffix( &node, 0 ))
+ {
+ search_base = slapi_sdn_get_dn( sdn );
+
+
+ for(i=3; argv[i] != NULL; i++)
+ {
+ unsigned long filtlen = strlen(argv[i]) + (strlen(origDN) * 3 ) + 4;
+ filter = (char *)slapi_ch_calloc( filtlen, sizeof(char ));
+ if (( search_result = ldap_create_filter( filter, filtlen, "(%a=%e)",
+ NULL, NULL, argv[i], origDN, NULL )) == LDAP_SUCCESS ) {
+
+ /* Don't need any attribute */
+ char * attrs[2];
+ attrs[0]="1.1";
+ attrs[1]=NULL;
+
+ /* Use new search API */
+ search_result_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(search_result_pb, search_base, LDAP_SCOPE_SUBTREE,
+ filter, attrs, 0 /* attrs only */, NULL,NULL,referint_plugin_identity,0);
+ slapi_search_internal_pb(search_result_pb);
+
+ slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
+ }
+
+
+ /* if search successfull then do integrity update */
+ if(search_result == 0)
+ {
+ slapi_pblock_get( search_result_pb,SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+ &search_entries);
+
+ for(j=0; search_entries[j] != NULL; j++)
+ {
+ /* no matter what mode in always going to delete old dn so set that up */
+ values_del[0]= origDN;
+ values_del[1]= NULL;
+ attribute1.mod_type = argv[i];
+ attribute1.mod_op = LDAP_MOD_DELETE;
+ attribute1.mod_values = values_del;
+ list_of_mods[0] = &attribute1;
+
+ if(newrDN == NULL){
+ /* in delete mode so terminate list of mods cause this is the only one */
+ list_of_mods[1] = NULL;
+ }else if(newrDN != NULL){
+ /* in modrdn mode */
+
+ /* need to put together rdn into a dn */
+ dnParts = ldap_explode_dn( origDN, 0 );
+
+ /* skip original rdn so start at 1*/
+ dnsize = 0;
+ for(x=1; dnParts[x] != NULL; x++)
+ {
+ /* +2 for space and comma adding later */
+ dnsize += strlen(dnParts[x]) + 2;
+ }
+ /* add the newrDN length */
+ dnsize += strlen(newrDN) + 1;
+
+ newDN = slapi_ch_calloc(dnsize, sizeof(char));
+ strcat(newDN, newrDN);
+ for(x=1; dnParts[x] != NULL; x++)
+ {
+ strcat(newDN, ", ");
+ strcat(newDN, dnParts[x]);
+ }
+
+ values_add[0]=newDN;
+ values_add[1]=NULL;
+ attribute2.mod_type = argv[i];
+ attribute2.mod_op = LDAP_MOD_ADD;
+ attribute2.mod_values = values_add;
+
+ /* add the new dn to list of mods and terminate list of mods */
+ list_of_mods[1] = &attribute2;
+ list_of_mods[2] = NULL;
+
+ }
+
+ /* try to cleanup entry */
+
+ /* Use new internal operation API */
+ mod_result_pb=slapi_pblock_new();
+ slapi_modify_internal_set_pb(mod_result_pb,slapi_entry_get_dn(search_entries[j]),
+ (LDAPMod **)list_of_mods,NULL,NULL,referint_plugin_identity,0);
+ slapi_modify_internal_pb(mod_result_pb);
+
+ /* could check the result code here if want to log it or something later
+ for now, continue no matter what result is */
+
+ slapi_pblock_destroy(mod_result_pb);
+
+ /* cleanup memory allocated for dnParts and newDN */
+ if(dnParts != NULL){
+ for(x=0; dnParts[x] != NULL; x++)
+ {
+ free(dnParts[x]);
+ }
+ free(dnParts);
+ }
+ if(newDN != NULL){
+ slapi_ch_free((void**)&newDN);
+ }
+
+ }
+
+
+
+ }else{
+ if(isFatalSearchError(search_result))
+ {
+ /* NPCTE fix for bugid 531225, esc 0. <P.R> <30-May-2001> */
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop search (base=%s filter=%s) returned error %d\n", search_base,filter,search_result );
+ /* end of NPCTE fix for bugid 531225 */
+ rc = -1;
+ goto free_and_return;
+ }
+
+ }
+
+ slapi_ch_free((void**)&filter);
+
+ if(search_result_pb != NULL){
+ slapi_free_search_results_internal(search_result_pb);
+ slapi_pblock_destroy(search_result_pb);
+ search_result_pb= NULL;
+ }
+
+ }
+ }
+ /* if got here, then everything good rc = 0 */
+ rc = 0;
+
+free_and_return:
+
+ /* free filter and search_results_pb */
+ if(filter != NULL)
+ {
+ free(filter);
+ }
+
+ if(search_result_pb != NULL)
+ {
+ slapi_free_search_results_internal(search_result_pb);
+ free(search_result_pb);
+ }
+
+ return(rc);
+}
+
+int referint_postop_start( Slapi_PBlock *pb)
+{
+
+ char **argv;
+ int argc = 0;
+
+ /* get args */
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argv\n" );
+ return( -1 );
+ }
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argv\n" );
+ return( -1 );
+ }
+
+ if(argv == NULL){
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "args were null in referint_postop_start\n" );
+ return( -1 );
+ }
+
+ /* only bother to start the thread if you are in delay mode.
+ 0 = no delay,
+ -1 = integrity off */
+
+ if (argc >= 1) {
+ if(atoi(argv[0]) > 0){
+
+ /* initialize cv and lock */
+
+ referint_mutex = PR_NewLock();
+ keeprunning_mutex = PR_NewLock();
+ keeprunning_cv = PR_NewCondVar(keeprunning_mutex);
+ keeprunning =1;
+
+ if (( referint_tid = PR_CreateThread (PR_USER_THREAD,
+ referint_thread_func,
+ (void *)argv,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_start PR_CreateThread failed\n" );
+ exit( 1 );
+ }
+ }
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_start insufficient arguments supplied\n" );
+ return( -1 );
+ }
+
+ return(0);
+
+}
+
+int referint_postop_close( Slapi_PBlock *pb)
+{
+
+ /* signal the thread to exit */
+ if (NULL != keeprunning_mutex) {
+ PR_Lock(keeprunning_mutex);
+ keeprunning=0;
+ if (NULL != keeprunning_cv) {
+ PR_NotifyCondVar(keeprunning_cv);
+ }
+ PR_Unlock(keeprunning_mutex);
+ }
+
+ return(0);
+}
+
+void referint_thread_func(void *arg){
+
+ char **plugin_argv = (char **)arg;
+ PRFileDesc *prfd;
+ char *logfilename;
+ char thisline[MAX_LINE];
+ int delay;
+ int no_changes;
+ char delimiter[]="\t\n";
+ char *ptoken;
+ char *tmpdn, *tmprdn;
+ int logChanges=0;
+ char * iter = NULL;
+
+ if(plugin_argv == NULL){
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_thread_func not get args \n" );
+ return;
+ }
+
+
+ delay = atoi(plugin_argv[0]);
+ logfilename = plugin_argv[1];
+ logChanges = atoi(plugin_argv[2]);
+
+ /* keep running this thread until plugin is signalled to close */
+
+ while(1){
+
+ no_changes=1;
+
+ while(no_changes){
+
+ PR_Lock(keeprunning_mutex);
+ if(keeprunning == 0){
+ PR_Unlock(keeprunning_mutex);
+ break;
+ }
+ PR_Unlock(keeprunning_mutex);
+
+
+ PR_Lock(referint_mutex);
+ if (( prfd = PR_Open( logfilename, PR_RDONLY,
+ REFERINT_DEFAULT_FILE_MODE )) == NULL )
+ {
+ PR_Unlock(referint_mutex);
+ /* go back to sleep and wait for this file */
+ PR_Lock(keeprunning_mutex);
+ PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
+ PR_Unlock(keeprunning_mutex);
+ }else{
+ no_changes = 0;
+ }
+ }
+
+ /* check keep running here, because after break out of no
+ * changes loop on shutdown, also need to break out of this
+ * loop before trying to do the changes. The server
+ * will pick them up on next startup as file still exists
+ */
+ PR_Lock(keeprunning_mutex);
+ if(keeprunning == 0){
+ PR_Unlock(keeprunning_mutex);
+ break;
+ }
+ PR_Unlock(keeprunning_mutex);
+
+
+ while( GetNextLine(thisline, MAX_LINE, prfd) ){
+ ptoken = ldap_utf8strtok_r(thisline, delimiter, &iter);
+ tmpdn = slapi_ch_calloc(strlen(ptoken) + 1, sizeof(char));
+ strcpy(tmpdn, ptoken);
+
+ ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
+ if(!strcasecmp(ptoken, "NULL")){
+ tmprdn = NULL;
+ }else{
+ tmprdn = slapi_ch_calloc(strlen(ptoken) + 1, sizeof(char));
+ strcpy(tmprdn, ptoken);
+ }
+
+
+ update_integrity(plugin_argv, tmpdn, tmprdn, logChanges);
+
+ slapi_ch_free((void **) &tmpdn);
+ slapi_ch_free((void **) &tmprdn);
+ }
+
+ PR_Close(prfd);
+
+ /* remove the original file */
+ if( PR_SUCCESS != PR_Delete(logfilename) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_close could not delete \"%s\"\n",
+ logfilename );
+ }
+
+ /* unlock and let other writers back at the file */
+ PR_Unlock(referint_mutex);
+
+ /* wait on condition here */
+ PR_Lock(keeprunning_mutex);
+ PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
+ PR_Unlock(keeprunning_mutex);
+ }
+
+ /* cleanup resources allocated in start */
+ if (NULL != keeprunning_mutex) {
+ PR_DestroyLock(keeprunning_mutex);
+ }
+ if (NULL != referint_mutex) {
+ PR_DestroyLock(referint_mutex);
+ }
+ if (NULL != keeprunning_cv) {
+ PR_DestroyCondVar(keeprunning_cv);
+ }
+
+
+}
+
+int my_fgetc(PRFileDesc *stream)
+{
+ static char buf[READ_BUFSIZE] = "\0";
+ static int position = READ_BUFSIZE;
+ int retval;
+ int err;
+
+ /* check if we need to load the buffer */
+
+ if( READ_BUFSIZE == position )
+ {
+ memset(buf, '\0', READ_BUFSIZE);
+ if( ( err = PR_Read(stream, buf, READ_BUFSIZE) ) >= 0)
+ {
+ /* it read some data */;
+ position = 0;
+ }else{
+ /* an error occurred */
+ return err;
+ }
+ }
+
+ /* try to read some data */
+ if( '\0' == buf[position])
+ {
+ /* out of data, return eof */
+ retval = MY_EOF;
+ position = READ_BUFSIZE;
+ }else{
+ retval = buf[position];
+ position++;
+ }
+
+ return retval;
+
+}
+
+int
+GetNextLine(char *dest, int size_dest, PRFileDesc *stream) {
+
+ char nextchar ='\0';
+ int done = 0;
+ int i = 0;
+
+ while(!done)
+ {
+ if( ( nextchar = my_fgetc(stream) ) != 0)
+ {
+ if( i < (size_dest - 1) )
+ {
+ dest[i] = nextchar;
+ i++;
+
+ if(nextchar == '\n')
+ {
+ /* end of line reached */
+ done = 1;
+ }
+
+ }else{
+ /* no more room in buffer */
+ done = 1;
+ }
+
+ }else{
+ /* error or end of file */
+ done = 1;
+ }
+ }
+
+ dest[i] = '\0';
+
+ /* return size of string read */
+ return i;
+}
+
+void writeintegritylog(char *logfilename, char *dn, char *newrdn){
+ PRFileDesc *prfd;
+ char buffer[MAX_LINE];
+ int len_to_write = 0;
+ int rc;
+ /* write this record to the file */
+
+ /* use this lock to protect file data when update integrity is occuring */
+ /* should hopefully not be a big issue on concurrency */
+
+ PR_Lock(referint_mutex);
+ if (( prfd = PR_Open( logfilename, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
+ REFERINT_DEFAULT_FILE_MODE )) == NULL )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop could not write integrity log \"%s\" "
+ SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
+ logfilename, PR_GetError(), slapd_pr_strerror(PR_GetError()) );
+
+ PR_Unlock(referint_mutex);
+ return;
+ }
+
+ /* make sure we have enough room in our buffer
+ before trying to write it
+ */
+
+ /* add length of dn + 4(two tabs, a newline, and terminating \0) */
+ len_to_write = strlen(dn) + 4;
+
+ if(newrdn == NULL)
+ {
+ /* add the length of "NULL" */
+ len_to_write += 4;
+ }else{
+ /* add the length of the newrdn */
+ len_to_write += strlen(newrdn);
+ }
+
+ if(len_to_write > MAX_LINE )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop could not write integrity log:"
+ " line length exceeded. It will not be able"
+ " to update references to this entry.\n");
+ }else{
+ PRInt32 rv;
+ sprintf(buffer, "%s\t%s\t\n",
+ dn,
+ (newrdn != NULL) ? newrdn : "NULL");
+ if ((rv = PR_Write(prfd,buffer,strlen(buffer))) < 0){
+ slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
+ " writeintegritylog: PR_Write failed : The disk"
+ " may be full or the file is unwritable :: NSPR error - %d\n",
+ PR_GetError());
+ }
+ }
+
+ /* If file descriptor is closed successfully, PR_SUCCESS */
+
+ rc = PR_Close(prfd);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
+ " writeintegritylog: failed to close the file"
+ " descriptor prfd; NSPR error - %d\n",
+ PR_GetError());
+ }
+ PR_Unlock(referint_mutex);
+ }
diff --git a/ldap/servers/plugins/referint/referint.def b/ldap/servers/plugins/referint/referint.def
new file mode 100644
index 00000000..75861791
--- /dev/null
+++ b/ldap/servers/plugins/referint/referint.def
@@ -0,0 +1,12 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Netscape Directory Server 7 Referint Plugin'
+CODE SHARED READ EXECUTE
+DATA SHARED READ WRITE
+EXPORTS
+ referint_postop_init @2
+ plugin_init_debug_level @3