diff options
| author | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
|---|---|---|
| committer | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
| commit | b2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch) | |
| tree | cf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/plugins/referint | |
| download | ds-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/Makefile | 72 | ||||
| -rw-r--r-- | ldap/servers/plugins/referint/dllmain.c | 95 | ||||
| -rw-r--r-- | ldap/servers/plugins/referint/referint.c | 808 | ||||
| -rw-r--r-- | ldap/servers/plugins/referint/referint.def | 12 |
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 |
