summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/tools
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/slapd/tools
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/slapd/tools')
-rw-r--r--ldap/servers/slapd/tools/Makefile168
-rw-r--r--ldap/servers/slapd/tools/eggencode.c57
-rw-r--r--ldap/servers/slapd/tools/keyupg.c85
-rw-r--r--ldap/servers/slapd/tools/ldif.c128
-rw-r--r--ldap/servers/slapd/tools/migratecred.c154
-rw-r--r--ldap/servers/slapd/tools/mkdep.c335
-rw-r--r--ldap/servers/slapd/tools/mmldif.c1742
-rw-r--r--ldap/servers/slapd/tools/pwenc.c400
8 files changed, 3069 insertions, 0 deletions
diff --git a/ldap/servers/slapd/tools/Makefile b/ldap/servers/slapd/tools/Makefile
new file mode 100644
index 00000000..abd9fda1
--- /dev/null
+++ b/ldap/servers/slapd/tools/Makefile
@@ -0,0 +1,168 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# gnu makefile for LDAP Server tools.
+#
+
+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)/servers/tools/obj
+BINDIR = $(LDAP_SERVER_RELDIR)
+
+SLAPD_OBJDIR = $(LDAP_OBJDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+ifndef LDAP_USE_OLD_DB
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+INCLUDES+=-I$(DB_INCLUDE)
+else
+CFLAGS+=-DLDAP_USE_DB185
+endif
+
+SLAPDHDIR = ../
+
+ifeq ($(ARCH), OSF1)
+PLATFORM_SPECIFIC_EXTRA_LIBRARY = -lcxx
+else # OSF1
+# oems might need to edit this for their platform
+PLATFORM_SPECIFIC_EXTRA_LIBRARY =
+endif # OSF1
+
+INCLUDES += $(SSLINCLUDE)
+DEFS += $(SSL)
+
+OBJS1 += $(OBJDEST)/pwenc.o
+
+ifeq ($(USE_64), 1)
+ifeq ($(ARCH), HPUX)
+LDFLAGS += -lpthread +DA2.0W +DS2.0 +Z
+endif
+ifeq ($(ARCH), SOLARIS)
+LDFLAGS += -xarch=v9
+endif
+endif
+
+
+INCLUDES += -I$(SLAPDHDIR) -I$(LDAP_ADMINCDIR)
+INCLUDES += -I$(ACLINC)
+INCLUDES += -I ../../plugins/rever
+LDFLAGS += $(EXLDFLAGS) $(SSLLIBFLAG)
+
+ifeq ($(ARCH), WINNT)
+SUBSYSTEM=console
+endif
+
+DEPLIBS=
+
+EXTRA_LIBS_DEP = $(LDAPSDK_DEP) \
+ $(LDAP_LIBLDIF_DEP) \
+ $(LDAP_SLIBLCACHE_DEP) $(DB_LIB_DEP) $(LIBSLAPD_DEP) \
+ $(LDAP_COMMON_LIBS_DEP)
+
+EXTRA_LIBS = $(LDAPLINK) \
+ $(LDAP_SLIBLCACHE) $(DB_LIB) \
+ $(PLATFORM_SPECIFIC_EXTRA_LIBRARY) $(LIBSLAPD) $(LDAP_LIBLITEKEY) \
+ $(ALIBS) \
+ $(SECURITYLINK) $(DBMLINK) \
+ $(THREADSLIB) $(LDAP_COMMON_LIBS) $(NSPRLINK) $(SVRCORELINK)
+
+ifeq ($(ARCH), Linux)
+EXTRA_LIBS += -lcrypt
+endif
+
+
+KEYUPG_LIBS_DEP=
+KEYUPG_LIBS=$(LDAP_LIBLITEKEY)
+
+ifeq ($(ARCH), WINNT)
+KEYUPG_LIBS_DEP=$(LDAP_LIBUTIL_DEP)
+KEYUPG_LIBS += $(LDAP_LIBUTIL)
+endif
+
+ifdef HEAPAGENT
+CFLAGS+=-DPURIFYING
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+
+# It looks like all of the latest versions of Unix that we ship on
+# have a good enough heap implementations that they don't need
+# SmartHeap. We still need it on NT.
+ifneq ($(ARCH), WINNT)
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+
+# Don't use smartheap for debug builds on NT
+ifeq ($(ARCH), WINNT)
+ifeq ($(DEBUG), full)
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+endif
+
+ifndef LDAP_DONT_USE_SMARTHEAP
+include $(MCOM_ROOT)/ldapserver/ns_usesh.mk
+_smartheap_depend = $(SH_LIB_DEP)
+else
+CFLAGS+=-DLDAP_DONT_USE_SMARTHEAP
+endif
+
+
+TOOL_OBJS = ldif.o keyupg.o pwenc.o mmldif.o migratecred.o eggencode.o
+ALL_OBJS = $(addprefix $(OBJDEST)/, $(TOOL_OBJS))
+
+LDIF = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, ldif))
+PWDHASH = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, pwdhash))
+MIGRATECRED = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, migratecred))
+KEYUPG = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, keyupg))
+MMLDIF = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, mmldif))
+EGGENCODE = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, eggencode))
+
+BINS= $(LDIF) $(PWDHASH) $(KEYUPG) $(MMLDIF) $(MIGRATECRED)
+EXTRABINS= $(EGGENCODE)
+
+all: $(OBJDEST) $(BINDIR) $(LDAP_ADMIN_BIN_RELDIR) $(BINS)
+
+extras: $(OBJDEST) $(BINDIR) $(EGGENCODE)
+
+$(LDIF): $(OBJDEST)/ldif.o $(LDAP_LIBLDIF_DEP)
+ $(LINK_EXE) $< $(LDAP_LIBLDIF)
+
+$(PWDHASH): $(OBJS1) $(EXTRA_LIBS_DEP)
+ $(LINK_EXE) $(OBJS1) $(EXTRA_LIBS)
+
+$(MIGRATECRED): $(OBJDEST)/migratecred.o $(EXTRA_LIBS_DEP)
+ $(LINK_EXE) $(OBJDEST)/migratecred.o $(EXTRA_LIBS)
+
+$(KEYUPG): $(OBJDEST)/keyupg.o $(KEYUPG_LIBS_DEP)
+ $(LINK_EXE_NOLIBSOBJS) $< $(KEYUPG_LIBS)
+
+$(MMLDIF): $(OBJDEST)/mmldif.o $(EXTRA_LIBS_DEP)
+ $(LINK_EXE_NOLIBSOBJS) $(OBJDEST)/mmldif.o $(EXTRA_LIBS)
+
+$(EGGENCODE): $(OBJDEST)/eggencode.o
+ $(LINK_EXE_NOLIBSOBJS) $(OBJDEST)/eggencode.o
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+clean:
+ -$(RM) $(ALL_OBJS)
+ -$(RM) $(BINS) $(EXTRABINS)
+
diff --git a/ldap/servers/slapd/tools/eggencode.c b/ldap/servers/slapd/tools/eggencode.c
new file mode 100644
index 00000000..92b098ca
--- /dev/null
+++ b/ldap/servers/slapd/tools/eggencode.c
@@ -0,0 +1,57 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Easter egg encoder. See ../fedse.c:egg_decode() for the mirror image.
+ */
+#include <stdio.h>
+
+static unsigned char egg_nibble2char( int nibble );
+
+int
+main( int argc, char *argv[] )
+{
+ int c, colcount;
+ char outc;
+
+ if ( argc > 1 ) {
+ fprintf( stderr, "usage: %s < in > out\n", argv[0] );
+ return 2;
+ }
+
+ colcount = 0;
+ while (( c = getchar()) != EOF ) {
+ if ( 0 == colcount ) {
+ putchar( '"' );
+ }
+ c ^= 122;
+ outc = egg_nibble2char( (c & 0xF0) >> 4 );
+ putchar( outc );
+ ++colcount;
+ outc = egg_nibble2char( c & 0x0F );
+ putchar( outc );
+ ++colcount;
+ if ( colcount > 72 ) {
+ colcount = 0;
+ putchar( '"' );
+ putchar( '\n' );
+ }
+ }
+
+ if ( colcount > 0 ) {
+ putchar( '"' );
+ putchar( '\n' );
+ }
+
+ return 0;
+}
+
+
+static unsigned char
+egg_nibble2char( int nibble )
+{
+ return ( nibble < 10 ) ? nibble + '0' : ( nibble - 10 ) + 'A';
+}
diff --git a/ldap/servers/slapd/tools/keyupg.c b/ldap/servers/slapd/tools/keyupg.c
new file mode 100644
index 00000000..f1d9adc1
--- /dev/null
+++ b/ldap/servers/slapd/tools/keyupg.c
@@ -0,0 +1,85 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ *
+ * keyupg.c
+ *
+ * Upgrade the Key from Lite to normal ( only one way )
+ *
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#ifdef hpux
+#include <strings.h>
+#endif /* hpux */
+#ifdef LINUX
+#include <unistd.h> /* needed for getopt */
+#endif
+#if defined( _WIN32 )
+#include <windows.h>
+#include "proto-ntutil.h"
+#endif
+#include <stdlib.h>
+#include "litekey.h"
+
+
+#define BUFSIZE 800
+#define FILE_PATHSEP '/'
+
+int
+main (int argc, char **argv )
+{
+
+
+ char *keyfile = NULL;
+ int i, ikey, nkey;
+ FILE *fp = NULL;
+ int debug =0;
+
+
+ while ( (i = getopt( argc, argv, "k:f:dh" )) != EOF ) {
+ switch (i){
+ case 'f':
+ keyfile = strdup( optarg );
+ break;
+ case 'k':
+ ikey = atoi ( optarg );
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ }
+ }
+
+ if ( (NULL == keyfile ) || (!ikey)) {
+ fprintf (stderr, "usage:%s -k key -f key_file_path\n", argv[0]);
+ exit(1);
+
+ }
+
+ if (debug) printf ( "Key is :%d and file is in :%s\n", ikey, keyfile);
+
+ if ( ! is_key_validNormalKey ( ikey )) {
+ printf ( "Sorry. The input key is invalid\n" );
+ exit (1);
+ }
+
+
+ nkey = generate_directory_key ( DS_NORMAL_TYPE );
+
+ if ( (fp = fopen ( keyfile, "r+b")) == NULL ) {
+ printf ("KEYUPG Error: Could not open the the key file:%s\n", keyfile );
+ exit ( 1 );
+ }
+ fprintf (fp, "key: %d\n", nkey );
+ fclose ( fp );
+
+ printf ("Success: Your Directory Servers have been upgraded to the full version.\n");
+
+ return 0;
+}
diff --git a/ldap/servers/slapd/tools/ldif.c b/ldap/servers/slapd/tools/ldif.c
new file mode 100644
index 00000000..aa90a178
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldif.c
@@ -0,0 +1,128 @@
+/** 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 <memory.h>
+#include <sys/types.h>
+#if defined( _WINDOWS ) || defined( _WIN32 )
+#include <windows.h>
+#include <io.h>
+#include <fcntl.h>
+#else
+#include <unistd.h> /* for read() */
+#include <sys/socket.h>
+#endif
+#include "ldap.h"
+#include "ldif.h"
+
+int ldap_syslog;
+int ldap_syslog_level;
+
+
+static void
+display_usage( char *name )
+{
+ fprintf( stderr, "usage: %s [-b] <attrtype>\n", name );
+}
+
+int main( int argc, char **argv )
+{
+ char *type, *out;
+ int binary = 0;
+
+ if (argc < 2 || argc > 3 ) {
+ display_usage( argv[0] );
+ return( 1 );
+ }
+ if ( argc == 3 ) {
+ if ( strcmp( argv[1], "-b" ) != 0 ) {
+ display_usage( argv[0] );
+ return( 1 );
+ } else {
+ binary = 1;
+ type = argv[2];
+ }
+ } else {
+ if ( strcmp( argv[1], "-b" ) == 0 ) {
+ display_usage( argv[0] );
+ return( 1 );
+ }
+ type = argv[1];
+ }
+
+ /* if the -b flag was used, read single binary value from stdin */
+ if ( binary ) {
+ char buf[BUFSIZ];
+ char *val;
+ int nread, max, cur;
+#if defined( _WINDOWS ) || defined( _WIN32 )
+ _setmode( _fileno( stdin ), _O_BINARY );
+#endif
+
+ if (( val = (char *) malloc( BUFSIZ )) == NULL ) {
+ perror( "malloc" );
+ return( 1 );
+ }
+ max = BUFSIZ;
+ cur = 0;
+ while ( (nread = read( 0, buf, BUFSIZ )) != 0 ) {
+ if ( nread + cur > max ) {
+ max += BUFSIZ;
+ if (( val = (char *) realloc( val, max )) ==
+ NULL ) {
+ perror( "realloc" );
+ return( 1 );
+ }
+ }
+ memcpy( val + cur, buf, nread );
+ cur += nread;
+ }
+
+ if (( out = ldif_type_and_value( type, val, cur )) == NULL ) {
+ perror( "ldif_type_and_value" );
+ return( 1 );
+ }
+
+ fputs( out, stdout );
+ free( out );
+ free( val );
+ return( 0 );
+ } else {
+ /* not binary: one value per line... */
+ char *buf;
+ int curlen, maxlen = BUFSIZ;
+
+ if( (buf = malloc(BUFSIZ)) == NULL ) {
+ perror( "malloc" );
+ return( 1 );
+ }
+ while ( buf = fgets(buf, maxlen, stdin) ) {
+ /* if buffer was filled, expand and keep reading unless last char
+ is linefeed, in which case it is OK for buffer to be full */
+ while( ((curlen = strlen(buf)) == (maxlen - 1)) && buf[curlen-1] != '\n' ) {
+ maxlen *= 2;
+ if( (buf = (char *)realloc(buf, maxlen)) == NULL ) {
+ perror( "realloc" );
+ return( 1 );
+ }
+ fgets(buf+curlen, maxlen/2 + 1, stdin);
+ }
+ /* we have a full line, chop potential newline and turn into ldif */
+ if( buf[curlen-1] == '\n' )
+ buf[curlen-1]='\0';
+ if (( out = ldif_type_and_value( type, buf, strlen( buf ) ))
+ == NULL ) {
+ perror( "ldif_type_and_value" );
+ return( 1 );
+ }
+ fputs( out, stdout );
+ free( out );
+
+ }
+ free( buf );
+ }
+ return( 0 );
+}
diff --git a/ldap/servers/slapd/tools/migratecred.c b/ldap/servers/slapd/tools/migratecred.c
new file mode 100644
index 00000000..9d0d2c66
--- /dev/null
+++ b/ldap/servers/slapd/tools/migratecred.c
@@ -0,0 +1,154 @@
+/** 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 <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#ifndef _WIN32
+#include <sys/param.h> /* MAXPATHLEN */
+#endif
+
+#include "../plugins/rever/rever.h"
+#include "getopt_ext.h"
+
+static void usage(char *name)
+{
+ fprintf(stderr, "usage: %s -o 5.0InstancePath -n 5.1InstancePath -c 5.0Credential\n", name);
+ exit(1);
+}
+
+#ifdef _WIN32
+/* converts '\' chars to '/' */
+static void dostounixpath(char *szText)
+{
+ if(szText)
+ {
+ while(*szText)
+ {
+ if( *szText == '\\' )
+ *szText = '/';
+ szText++;
+ }
+ }
+}
+#endif
+
+/* Script used during 5.0 to 5.1 migration: replication and
+ chaining backend credentials must be converted.
+
+ Assumption: the built-in des-plugin.so lib has been used
+ in 5.0 and is used in 5.1
+
+ Usage: migrateCred
+ -o <5.0 instance path>
+ -n <5.1 instance path>
+ -c <5.0 credential, with prefix>
+
+ Return 5.1 credential with prefix
+*/
+
+int
+main( int argc, char **argv)
+{
+ char *cmd = argv[0];
+ char *oldpath = NULL;
+ char *newpath = NULL;
+ char *prefixCred = NULL;
+ char *cred = NULL;
+
+ char *newcred = NULL;
+ migrate_fn_type fct = NULL;
+ char libpath[MAXPATHLEN];
+ char *shared_lib;
+
+ char *opts = "o:n:c:";
+ int i;
+
+ while (( i = getopt( argc, argv, opts )) != EOF )
+ {
+ switch (i)
+ {
+ case 'o':
+ oldpath = strdup(optarg);
+#ifdef _WIN32
+ dostounixpath(oldpath);
+#endif /* _WIN32 */
+
+ break;
+ case 'n':
+ newpath = strdup(optarg);
+#ifdef _WIN32
+ dostounixpath(newpath);
+#endif /* _WIN32 */
+ break;
+ case 'c':
+ {
+ char *end = NULL;
+ int namelen;
+
+ /* cred has the prefix, remove it before decoding */
+ prefixCred = strdup(optarg);
+
+ if ((*prefixCred == PWD_HASH_PREFIX_START) &&
+ ((end = strchr(prefixCred, PWD_HASH_PREFIX_END)) != NULL) &&
+ ((namelen = end - prefixCred - 1 ) <= (3*PWD_MAX_NAME_LEN)) )
+ {
+ cred = prefixCred + namelen + 2;
+ }
+ else
+ {
+ fprintf(stderr, "Invalid -c argument: %s (wrong prefix?).\n", prefixCred);
+ }
+ }
+ break;
+ default:
+ usage(cmd);
+ }
+ }
+
+ if ( !oldpath || !newpath || !cred )
+ {
+ usage(cmd);
+ }
+
+
+#if defined( XP_WIN32 )
+ shared_lib = ".dll";
+#else
+#ifdef HPUX
+ shared_lib = ".sl";
+#else
+#ifdef AIX
+#if OSVERSION >= 4200
+ shared_lib = ".so";
+#else
+ shared_lib = "_shr.a";
+#endif
+#else
+ shared_lib = ".so";
+#endif
+#endif
+#endif
+
+ sprintf(libpath, "%s/../lib/des-plugin%s", newpath, shared_lib);
+
+ fct = (migrate_fn_type)sym_load(libpath, "migrateCredentials",
+ "DES Plugin", 1 /* report errors */ );
+ if ( fct == NULL )
+ {
+ return(1);
+ }
+
+ newcred = (fct)(oldpath, newpath, cred);
+
+ fprintf(stdout, "%s", newcred);
+
+ return(0);
+
+}
diff --git a/ldap/servers/slapd/tools/mkdep.c b/ldap/servers/slapd/tools/mkdep.c
new file mode 100644
index 00000000..469194fe
--- /dev/null
+++ b/ldap/servers/slapd/tools/mkdep.c
@@ -0,0 +1,335 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Originally by Linus Torvalds.
+ * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
+ * Lobotomized by Robey Pointer.
+ *
+ * Usage: mkdep file ...
+ *
+ * Read source files and output makefile dependency lines for them.
+ * I make simple dependency lines for #include "*.h".
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WINNT
+#include <windows.h>
+#include <winbase.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+
+
+char __depname[512] = "\n\t@touch ";
+#define depname (__depname+9)
+int hasdep;
+
+char *outdir = ".";
+
+struct path_struct {
+ int len;
+ char buffer[256-sizeof(int)];
+} path = { 0, "" };
+
+
+#ifdef WINNT
+#define EXISTS(_fn) _access(_fn, 00)
+#else
+#define EXISTS(_fn) access(_fn, F_OK)
+#endif
+
+/*
+ * Handle an #include line.
+ */
+void handle_include(const char * name, int len)
+{
+ memcpy(path.buffer+path.len, name, len);
+ path.buffer[path.len+len] = '\0';
+ if (EXISTS(path.buffer))
+ return;
+
+ if (!hasdep) {
+ hasdep = 1;
+ /* don't use outdir if it's a .h file */
+ if ((strlen(depname) > 2) &&
+ (strcmp(depname + strlen(depname) - 2, ".h") == 0)) {
+ /* skip using the outdir */
+ } else {
+ if (outdir)
+ printf("%s/", outdir);
+ }
+ printf("%s:", depname);
+ }
+ printf(" \\\n %s", path.buffer);
+}
+
+
+/* --- removed weird functions to try to emulate asm ---
+ * (turns out it's faster just to scan thru a char*)
+ */
+
+#define GETNEXT { current = *next++; if (next >= end) break; }
+
+/*
+ * State machine macros.
+ */
+#define CASE(c,label) if (current == c) goto label
+#define NOTCASE(c,label) if (current != c) goto label
+
+/*
+ * Yet another state machine speedup.
+ */
+#define MAX2(a,b) ((a)>(b)?(a):(b))
+#define MIN2(a,b) ((a)<(b)?(a):(b))
+#define MAX4(a,b,c,d) (MAX2(a,MAX2(b,MAX2(c,d))))
+#define MIN4(a,b,c,d) (MIN2(a,MIN2(b,MIN2(c,d))))
+
+
+
+/*
+ * The state machine looks for (approximately) these Perl regular expressions:
+ *
+ * m|\/\*.*?\*\/|
+ * m|'.*?'|
+ * m|".*?"|
+ * m|#\s*include\s*"(.*?)"|
+ *
+ * About 98% of the CPU time is spent here, and most of that is in
+ * the 'start' paragraph. Because the current characters are
+ * in a register, the start loop usually eats 4 or 8 characters
+ * per memory read. The MAX6 and MIN6 tests dispose of most
+ * input characters with 1 or 2 comparisons.
+ */
+void state_machine(const char * map, const char * end)
+{
+ register const char * next = map;
+ register const char * map_dot;
+ register unsigned char current;
+
+ for (;;) {
+start:
+ GETNEXT
+__start:
+ if (current > MAX4('/','\'','"','#')) goto start;
+ if (current < MIN4('/','\'','"','#')) goto start;
+ CASE('/', slash);
+ CASE('\'', squote);
+ CASE('"', dquote);
+ CASE('#', pound);
+ goto start;
+
+/* / */
+slash:
+ GETNEXT
+ NOTCASE('*', __start);
+slash_star_dot_star:
+ GETNEXT
+__slash_star_dot_star:
+ NOTCASE('*', slash_star_dot_star);
+ GETNEXT
+ NOTCASE('/', __slash_star_dot_star);
+ goto start;
+
+/* '.*?' */
+squote:
+ GETNEXT
+ CASE('\'', start);
+ NOTCASE('\\', squote);
+ GETNEXT
+ goto squote;
+
+/* ".*?" */
+dquote:
+ GETNEXT
+ CASE('"', start);
+ NOTCASE('\\', dquote);
+ GETNEXT
+ goto dquote;
+
+/* #\s* */
+pound:
+ GETNEXT
+ CASE(' ', pound);
+ CASE('\t', pound);
+ CASE('i', pound_i);
+ goto __start;
+
+/* #\s*i */
+pound_i:
+ GETNEXT NOTCASE('n', __start);
+ GETNEXT NOTCASE('c', __start);
+ GETNEXT NOTCASE('l', __start);
+ GETNEXT NOTCASE('u', __start);
+ GETNEXT NOTCASE('d', __start);
+ GETNEXT NOTCASE('e', __start);
+ goto pound_include;
+
+/* #\s*include\s* */
+pound_include:
+ GETNEXT
+ CASE(' ', pound_include);
+ CASE('\t', pound_include);
+ map_dot = next;
+ CASE('"', pound_include_dquote);
+ goto __start;
+
+/* #\s*include\s*"(.*)" */
+pound_include_dquote:
+ GETNEXT
+ CASE('\n', start);
+ NOTCASE('"', pound_include_dquote);
+ handle_include(map_dot, next - map_dot - 1);
+ goto start;
+
+ }
+}
+
+
+#ifdef WINNT
+
+/*
+ * Alternate implementation of do_depend() for NT
+ * (NT has its own wacky versions of open/mmap/close)
+ */
+void do_depend(const char *filename, const char *command)
+{
+ HANDLE fd, mapfd;
+ BY_HANDLE_FILE_INFORMATION st;
+ char *map;
+
+ fd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ if (fd == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "NT error opening '%s'\n", filename);
+ return;
+ }
+ if (! GetFileInformationByHandle(fd, &st)) {
+ fprintf(stderr, "NT error getting stat on '%s'\n", filename);
+ CloseHandle(fd);
+ return;
+ }
+ if (st.nFileSizeLow == 0) {
+ fprintf(stderr, "%s is empty\n", filename);
+ CloseHandle(fd);
+ return;
+ }
+
+ mapfd = CreateFileMapping(fd, NULL, PAGE_READONLY, st.nFileSizeHigh,
+ st.nFileSizeLow, NULL);
+ if (mapfd == NULL) {
+ fprintf(stderr, "NT error creating file mapping of '%s'\n",
+ filename);
+ CloseHandle(fd);
+ return;
+ }
+ map = MapViewOfFile(mapfd, FILE_MAP_READ, 0, 0, 0);
+ if (map == NULL) {
+ fprintf(stderr, "NT error creating mapped view of '%s'\n",
+ filename);
+ CloseHandle(mapfd);
+ CloseHandle(fd);
+ return;
+ }
+
+ hasdep = 0;
+ state_machine(map, map+st.nFileSizeLow);
+ if (hasdep)
+ puts(command);
+
+ UnmapViewOfFile(map);
+ CloseHandle(mapfd);
+ CloseHandle(fd);
+}
+
+#else
+
+/*
+ * Generate dependencies for one file.
+ */
+void do_depend(const char * filename, const char * command)
+{
+ int mapsize;
+ int pagesizem1 = getpagesize()-1;
+ int fd;
+ struct stat st;
+ char * map;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror(filename);
+ return;
+ }
+
+ fstat(fd, &st);
+ if (st.st_size == 0) {
+ fprintf(stderr,"%s is empty\n",filename);
+ close(fd);
+ return;
+ }
+
+ mapsize = st.st_size;
+ mapsize = (mapsize+pagesizem1) & ~pagesizem1;
+ map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
+ if ((long) map == -1) {
+ perror("mkdep: mmap");
+ close(fd);
+ return;
+ }
+ if ((unsigned long) map % sizeof(unsigned long) != 0)
+ {
+ fprintf(stderr, "do_depend: map not aligned\n");
+ exit(1);
+ }
+
+ hasdep = 0;
+ state_machine(map, map+st.st_size);
+ if (hasdep)
+ puts(command);
+
+ munmap(map, mapsize);
+ close(fd);
+}
+
+#endif
+
+
+/*
+ * Generate dependencies for all files.
+ */
+int main(int argc, char **argv)
+{
+ int len;
+
+ while (--argc > 0) {
+ const char *filename = *++argv;
+ const char *command = __depname;
+
+ if (strcmp(filename, "-o") == 0) {
+ outdir = *++argv;
+ argc--;
+ continue;
+ }
+ len = strlen(filename);
+ memcpy(depname, filename, len+1);
+ if (len > 2 && filename[len-2] == '.') {
+ if (filename[len-1] == 'c' || filename[len-1] == 'S') {
+ depname[len-1] = 'o';
+ command = "";
+ }
+ }
+ do_depend(filename, command);
+ }
+ return 0;
+}
diff --git a/ldap/servers/slapd/tools/mmldif.c b/ldap/servers/slapd/tools/mmldif.c
new file mode 100644
index 00000000..413c1b7d
--- /dev/null
+++ b/ldap/servers/slapd/tools/mmldif.c
@@ -0,0 +1,1742 @@
+/** 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 <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <ldap.h>
+#ifndef _WIN32
+# define stricmp strcasecmp
+#else
+# include <io.h>
+#endif
+
+#include <pk11func.h>
+
+#include <slap.h>
+#include <getopt_ext.h>
+#include <ldaplog.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef _WIN32
+int slapd_ldap_debug = 0;
+int *module_ldap_debug;
+#endif
+
+/*
+ * VSTRING was defined in PMDF headers.
+ */
+typedef struct vstring {
+ int length;
+ char body[252];
+} MM_VSTRING;
+
+/*
+ * Base64 declarations.
+ */
+
+typedef struct Enc64_s {
+ struct Enc64_s * next;
+ unsigned char * source;
+ int slen;
+} Enc64_t;
+
+typedef struct Dec64_s {
+ struct Dec64_s * next;
+ unsigned char * dest;
+ int maxlen;
+ int curlen;
+ int nextra;
+ unsigned char extra[3];
+} Dec64_t;
+
+Enc64_t * initEnc64(unsigned char * source, int slen);
+int Enc64(Enc64_t * this, unsigned char *dest, int maxlen, int *len);
+void freeEnc64(Enc64_t *this);
+Dec64_t * initDec64(unsigned char * dest, int maxlen);
+int freeDec64(Dec64_t *this);
+int Dec64(Dec64_t * this, unsigned char *source);
+
+/*
+ * License check declarations.
+ */
+
+int license_limit = -1;
+int license_count;
+
+/*
+ * Public declarations.(potentially).
+ */
+
+#define IDDS_MM_OK 0
+#define IDDS_MM_EOF -1
+#define IDDS_MM_ABSENT -2
+#define IDDS_MM_FIO -3
+#define IDDS_MM_BAD -4
+
+/* attrib_t is used to hold each record in memory. The emphasis here is
+ * on size, although compromising simplicity rather than speed. In reality
+ * the way this is used is that there is a block of bytes defined. within
+ * that block are a sequence of records each alligned on whatever is needed
+ * to read shorts happilly. each record consists of a name, a value and
+ * their lengths. The value length is first, because it has to be aligned
+ * then the name value, because we need it first, then the name, null
+ * terminated, then the value, null terminated. Thus if "thing" is a pointer
+ * to one of these things,
+ * thing->data is the name
+ * (thing->data + namelen + 1) is the value,
+ * (thing->data + ((namelen + 1 + valuelen + 1 + 3) & ~3) is the next one
+ * (if we're aligned on 4 byte boundaries)
+ */
+typedef int Boolean;
+typedef struct {
+ int valuelen;
+ char namelen;
+ char data[1];
+} attrib_t;
+
+#define attribname(thing) (thing)->data
+#define attribvalue(thing) ((thing)->data + (thing)->namelen + 1)
+#define attribalign 4
+#define attribsize(thing) (((thing)->namelen + (thing)->valuelen + 1 \
+ + attribalign) & ~(attribalign-1))
+#define attribnext(thing) (attrib_t *)(((char *)thing) \
+ + (((thing)->namelen + (thing)->valuelen \
+ + sizeof(int) + 2 + attribalign) & ~(attribalign-1)))
+
+/* record_t is used to hold a record once it had been squeezed
+ * obviously it has to be allocated carefully so that it is the right size
+ */
+typedef struct {
+ short nattrs;
+ attrib_t data;
+} record_t;
+
+/* attrib1_t is used to read in and sort a record */
+typedef struct attrib1_s {
+ struct attrib1_s *next;
+ char namelen;
+ char name[64];
+ int valuelen;
+ char value[0x20000];
+} attrib1_t;
+
+typedef struct ignore_s {
+ struct ignore_s *next;
+ char name[65];
+} ignore_t;
+
+/* entry_t is the structure used to carry the fingerprint in the hash table */
+typedef struct entry_s {
+ struct entry_s *overflow; /* we hash into buckets. This
+ * is the chain of entries */
+ char key[20]; /* this is the hash of the DN */
+ int present[4]; /* actually treated as a 128 bit array*/
+ /* this is the bitmap of which
+ * directories contain this DN */
+ int db; /* this is the directory number which
+ * provided the data for this entry */
+ record_t * first; /* this it the actual data */
+ char fingerprint[20];/* this is the hash of the data */
+ char flags; /* the status of this entry */
+#define EMPTY 0
+#define IDENTITY 1
+#define MODIFIED 2
+#define LOADED 0x10
+} entry_t;
+
+typedef struct {
+ time_t start_time;
+ int records;
+ int records_away;
+ time_t end_time;
+} cookstats_t;
+
+typedef struct {
+ cookstats_t cook;
+
+ time_t comb_start_time;
+ int authoritative_records;
+ time_t comb_end_time;
+
+ time_t diff_start_time;
+ int num_identities;
+ int num_unchanged;
+ int num_deletes;
+ int num_adds;
+ int num_modifies;
+ time_t diff_end_time;
+
+ cookstats_t uncook;
+} stats_t;
+
+extern int mm_init(int argc, char * argv[]);
+extern int mm_diff(stats_t *statsp);
+
+extern int mm_getvalue(
+ record_t *first,
+ attrib1_t *a,
+ int directory,
+ char *name,
+ char **value,
+ int *length
+);
+
+extern int mm_is_deleted(
+ record_t *first,
+ attrib1_t *a,
+ int directory
+);
+
+extern int mm_get_winner(record_t *first, attrib1_t *a);
+extern void mm_init_winner(void);
+extern void mm_fin_winner(void);
+
+/*
+ * Private declarations.
+ */
+
+#define log_write_error() fprintf(stderr, "error writing record\n")
+
+/*
+ * We need to maintain the order of entries read from input, so that
+ * we can maintain hierarchical ordering. The entryblock structure
+ * is used for that purpose. Memory for blocks of entries are allocated
+ * and strung in a linked list.
+ */
+struct entryblock {
+ entry_t *eb_block;
+ unsigned n;
+ struct entryblock *next;
+};
+
+static struct entryblock *eb_head = NULL, *eb_cur = NULL;
+
+entry_t *entryalloc(void)
+{
+ if (eb_head == NULL || eb_cur->n == 0x1000) {
+ struct entryblock *newblock;
+ newblock =
+ (struct entryblock *)calloc(1, sizeof(struct entryblock));
+ newblock->eb_block = (entry_t*)calloc(0x1000, sizeof(entry_t));
+ if (eb_head == NULL) {
+ eb_cur = eb_head = newblock;
+ } else {
+ eb_cur = eb_cur->next = newblock;
+ }
+ }
+ return &eb_cur->eb_block[eb_cur->n++];
+}
+
+typedef struct {
+ FILE * fp;
+ int end;
+} edfFILE;
+
+static int ndirectories;
+static edfFILE edfin[128];
+static FILE * edfout[128];
+static FILE * ofp;
+static char line[2048];
+static char seed;
+static int hashmask;
+static entry_t **hashtable;
+static int maxcount;
+static int emitchanges;
+
+static int readrec(edfFILE * edf1, attrib1_t ** attrib);
+static void freefreelist(attrib1_t * freelist);
+static void hashname(char seed, attrib1_t * attrib, char * hashkey);
+static void hashvalue(char seed, attrib1_t * attrib, char * fingerprint);
+static record_t * newrecord(attrib1_t * big);
+static int adddelete(FILE * edf3, attrib1_t * attrib);
+static int addnew(FILE * edf3, const char *changetype, record_t * first);
+static int addmodified(FILE * edf3, attrib1_t * attrib, record_t * first);
+static int simpletext(unsigned char * body, int length);
+static int simpletextbody(unsigned char * body, int length);
+static int putvalue(
+ FILE * fh,
+ const char *tag,
+ char * name,
+ int namelen,
+ char * value,
+ int valuelen
+);
+static int signedmemcmp(
+ unsigned char * a,
+ int lena,
+ unsigned char * b,
+ int lenb
+);
+static void makeupper(MM_VSTRING * v, char * body, int len);
+
+static void commententry(FILE *fp, attrib1_t *attrib);
+
+int mm_diff(stats_t *statsp)
+{
+ unsigned int h;
+ entry_t * overflow;
+ int i;
+ int pindex;
+ int pmask;
+ attrib1_t * attrib = 0;
+ entry_t * hashentry;
+ entry_t * hashentry2;
+ char fingerprint[16];
+ int stat;
+ int count;
+ int firsttime = TRUE;
+ int records = 0;
+ int added;
+ struct entryblock *block, *next;
+
+ union {
+ unsigned int key;
+ char data[16];
+ } hashkey;
+
+ unsigned int key;
+
+ time(&statsp->diff_start_time);
+ license_count = 0;
+
+/*
+ * read all entries from all directories hashing name and value, and make
+ * a bitmaps of who has each entry. Flag those entries where at least
+ * one directory differs from any other.
+ */
+ for (i = 0; i < ndirectories; i++) {
+ pindex = i / 32;
+ pmask = 1 << (i % 32);
+ LDAPDebug(LDAP_DEBUG_TRACE, "finger printing directory %d\n", i, 0, 0);
+ while (TRUE) {
+ stat = readrec(&edfin[i], &attrib);
+ if (stat == IDDS_MM_ABSENT) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "ignored: %s: %s\n",
+ attrib->name, attrib->value, 0);
+ continue;
+ }
+ if (stat == IDDS_MM_EOF)
+ break;
+ if (stat != IDDS_MM_OK) {
+ free(hashtable);
+ return stat;
+ }
+ records++;
+ LDAPDebug(LDAP_DEBUG_TRACE, "db%d: %s: %s\n",
+ i, attrib->name, attrib->value);
+ hashname(seed, attrib, hashkey.data);
+ key = hashkey.key & hashmask;
+ if (!hashtable[key]) {
+ hashentry = hashtable[key] = entryalloc();
+ } else {
+ hashentry = hashtable[key];
+ while (hashentry &&
+ memcmp(hashkey.data, hashentry->key, 16))
+ hashentry = hashentry->overflow;
+ if (hashentry != NULL) {
+ if (hashentry->present[pindex] & pmask) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "duplicate DN <%s=%s> (ignored)\n",
+ attrib->name, attrib->value, 0);
+ if (emitchanges) {
+ fprintf(edfout[i], "\n# Duplicate DN:\n");
+ commententry(edfout[i], attrib);
+ }
+ if (ofp != NULL) {
+ fprintf(ofp, "\n# Duplicate DN (in database %d):\n",
+ i);
+ commententry(ofp, attrib);
+ }
+ } else {
+ hashentry->present[pindex] |= pmask;
+ hashvalue(seed, attrib, fingerprint);
+ if (memcmp(fingerprint, hashentry->fingerprint, 16)) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "...data modified\n", key, 0, 0);
+ hashentry->flags = MODIFIED;
+ }
+ }
+ continue;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE, "overflow in key %u\n", key, 0, 0);
+ hashentry2 = entryalloc();
+ hashentry2->overflow = hashtable[key];
+ hashentry = hashtable[key] = hashentry2;
+ }
+ hashentry->present[pindex] |= pmask;
+ memcpy(hashentry->key, hashkey.data, 16);
+ hashentry->flags = IDENTITY;
+ statsp->num_identities++;
+ hashvalue(seed, attrib, hashentry->fingerprint);
+ }
+ if ((license_limit > 0) && (records > license_limit)) {
+ fprintf(stderr, "license exceeded\n");
+ free(hashtable);
+ return IDDS_MM_BAD;
+ }
+ if (records > license_count)
+ license_count = records;
+ records = 0;
+ }
+
+/*
+ * read all the directories again. This time we load the data into memory
+ * We use a fairly tight (and ugly) structure to hold the data.
+ * There are three possibilities to consider:
+ * 1. no data has yet been loaded for this entry (load it)
+ * 2. data is present, and the data is marked as an identity
+ * (skip it)
+ * 3. data is present, and the data differs in at least one
+ * directory. call out to see who wins.
+ */
+ for (i = 0; i < ndirectories; i++) {
+ rewind(edfin[i].fp);
+ edfin[i].end = FALSE;
+ pindex = i / 32;
+ pmask = 1 << (i % 32);
+
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "loading authoritative data from directory %d\n", i, 0, 0);
+ count = 0;
+ while (TRUE) {
+ stat = readrec(&edfin[i], &attrib);
+ if (stat == IDDS_MM_ABSENT) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "ignored: %s: %s\n",
+ attrib->name, attrib->value, 0);
+ continue;
+ }
+ if (stat == IDDS_MM_EOF)
+ break;
+ if (stat != IDDS_MM_OK) {
+ free(hashtable);
+ return stat;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE, "db%d: %s: %s\n",
+ i, attrib->name, attrib->value);
+ hashname(seed, attrib, hashkey.data);
+ key = hashkey.key & hashmask;
+ hashentry = hashtable[key];
+ while (hashentry &&
+ memcmp(hashentry->key, hashkey.data, 16))
+ hashentry = hashentry->overflow;
+ if (hashentry == NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "...hash entry not found\n", 0, 0, 0);
+ continue;
+ }
+ if (!(hashentry->flags & LOADED))
+ {
+ count++;
+ hashentry->first = newrecord(attrib);
+ hashentry->flags |= LOADED;
+ LDAPDebug(LDAP_DEBUG_TRACE, " ...data loaded\n", 0, 0, 0);
+ hashentry->db = i;
+ continue;
+ }
+ if (hashentry->flags & IDENTITY)
+ continue;
+ if (mm_get_winner(hashentry->first, attrib)) {
+ hashentry->flags |= LOADED;
+ LDAPDebug(LDAP_DEBUG_TRACE, " ...winner data loaded\n", 0, 0, 0);
+ hashentry->db = i;
+ free(hashentry->first);
+ hashentry->first = newrecord(attrib);
+ hashvalue(seed, attrib, hashentry->fingerprint);
+ /* must take new fingerprint */
+ continue;
+ }
+ }
+ }
+
+ if (!emitchanges) goto afterchanges;
+
+/*
+ * Now we have the "authoritative" data in memory. Hey, that's what
+ * VM is for. Now we are able to go through each directory (again)
+ * and generate the differences. There are a number of possibilities
+ * 1. the entry is marked as an identity. skip it
+ * 2. the entry is marked as originating from this directory
+ * skip it
+ * 3. the entry's finger print is unchanged. skip it
+ * 4. the entry has isDeleted set. emit a delete
+ * 5. otherwise emit a change record.
+ */
+ for (i = 0; i < ndirectories; i++) {
+ rewind(edfin[i].fp);
+ edfin[i].end = FALSE;
+ pindex = i / 32;
+ pmask = 1 << (i % 32);
+
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "generating differences for directory %d\n", i, 0, 0);
+ count = 0;
+ while (TRUE) {
+ stat = readrec(&edfin[i], &attrib);
+ if (stat == IDDS_MM_ABSENT) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "ignored: %s: %s\n",
+ attrib->name, attrib->value, 0);
+ continue;
+ }
+ if (stat == IDDS_MM_EOF)
+ break;
+ if (stat != IDDS_MM_OK) {
+ free(hashtable);
+ return stat;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE, "db%d: %s: %s\n",
+ i, attrib->name, attrib->value);
+ hashname(seed, attrib, hashkey.data);
+ key = hashkey.key & hashmask;
+ hashentry = hashtable[key];
+ while (hashentry &&
+ memcmp(hashentry->key, hashkey.data, 16))
+ hashentry = hashentry->overflow;
+ if (hashentry == NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "...hash entry not found\n", 0, 0, 0);
+ continue;
+ }
+ if (hashentry->flags & IDENTITY)
+ continue;
+ if (hashentry->db == i)
+ continue;
+ hashvalue(seed, attrib, fingerprint);
+ if (memcmp(fingerprint, hashentry->fingerprint, 16)) {
+ if (mm_is_deleted(hashentry->first, attrib, 0)) {
+ LDAPDebug(LDAP_DEBUG_TRACE, " ...deleted\n", 0, 0, 0);
+ adddelete(edfout[i], attrib);
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE, " ...modified\n", 0, 0, 0);
+ addmodified(edfout[i], attrib, hashentry->first);
+ }
+ }
+ }
+ }
+
+ afterchanges:
+
+/*
+ * Nearly done. Now we need to go through each entry in the hash table
+ * and for each directory check the "present" bit. If this is set
+ * no action is needed here. Otherwise we emit an add.
+ * we take this opportunity to free the memory.
+ */
+ LDAPDebug(LDAP_DEBUG_TRACE, "scanning db for new entries\n", 0, 0, 0);
+ for (h = 0; h < 0x1000; h++) {
+ for (hashentry = hashtable[h]; hashentry; hashentry = overflow) {
+ if (!hashentry->flags)
+ break;
+
+ for (i = 0, added = 0; i < ndirectories; i++) {
+ pindex = i / 32;
+ pmask = 1 << (i % 32);
+ if (hashentry->present[pindex] & pmask)
+ continue;
+ if (mm_is_deleted(hashentry->first, NULL, 0)) continue;
+ added++;
+ if (!emitchanges) continue;
+ LDAPDebug(LDAP_DEBUG_TRACE, " ...add new\n", 0, 0, 0);
+ addnew(edfout[i], "add", hashentry->first);
+ }
+
+ if (added) {
+ statsp->num_adds++;
+ } else if (hashentry->flags & MODIFIED) {
+ statsp->num_modifies++;
+ } else {
+ statsp->num_unchanged++;
+ }
+
+ overflow = hashentry->overflow;
+ }
+ }
+
+ /* output authoritative data and free data */
+ for (block = eb_head; block != NULL; block = next) {
+ entry_t *entry;
+ for (h = 0; h < block->n; h++) {
+ entry = &block->eb_block[h];
+ if (ofp != NULL) {
+ if (!mm_is_deleted(entry->first, NULL, 0)) {
+ addnew(ofp, NULL, entry->first);
+ }
+ }
+ free(entry->first);
+ }
+ next = block->next;
+ free(block->eb_block);
+ free(block);
+ }
+
+ free(hashtable);
+ time(&statsp->diff_end_time);
+ return IDDS_MM_OK;
+}
+
+static void usage(char *m)
+{
+ fprintf(stderr,"usage: mmldif [-c] [-D] [-o out.ldif] in1.ldif in2.ldif ...\n\n", m);
+ fprintf(stderr,"-c\tWrite a change file (.delta) for each input file\n");
+ fprintf(stderr,"-D\tPrint debugging information\n");
+ fprintf(stderr,"-o\tWrite authoritative data to this file\n");
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+int mm_init(int argc, char * argv[])
+{
+ char deltaname[255];
+ time_t tl;
+ int c;
+ char *ofn = NULL;
+ char *prog = argv[0];
+ char *tailorfile = NULL;
+
+ time(&tl);
+ seed = (char)tl;
+ maxcount = 10;
+ ndirectories = 0;
+ emitchanges = 0;
+ ofp = NULL;
+
+ mm_init_winner();
+
+ slapd_ldap_debug = 0;
+
+ while ((c = getopt(argc, argv, "cDho:")) != EOF) {
+ switch (c) {
+ case 'c':
+ emitchanges = 1;
+ break;
+ case 'D':
+ slapd_ldap_debug = 65535;
+ break;
+ case 'o':
+ ofn = strdup(optarg);
+ break;
+ case 'h':
+ default:
+ usage(prog);
+ break;
+ }
+ }
+
+#ifdef _WIN32
+ module_ldap_debug = &slapd_ldap_debug;
+ libldap_init_debug_level(&slapd_ldap_debug);
+#endif
+
+ if (ofn != NULL) {
+ ofp = fopen(ofn, "w");
+ if (ofp == NULL) {
+ perror(ofn);
+ return -1;
+ }
+ free(ofn);
+ ofn = NULL;
+ }
+
+ for (argv += optind; optind < argc; optind++, argv++) {
+ edfin[ndirectories].fp = fopen(*argv, "r");
+ if (edfin[ndirectories].fp == NULL) {
+ perror(*argv);
+ return -1;
+ }
+ edfin[ndirectories].end = FALSE;
+
+ if (emitchanges) {
+ strcpy(deltaname, *argv);
+ strcat(deltaname, ".delta");
+ edfout[ndirectories] = fopen(deltaname, "w");
+ if (edfout[ndirectories] == NULL) {
+ perror(deltaname);
+ return -1;
+ }
+ }
+ ndirectories++;
+ }
+
+ if (ndirectories == 0) {
+ fprintf(stderr, "\nno input files\n\n");
+ usage(prog);
+ return 0;
+ }
+
+ hashmask = 0xfff;
+ hashtable = (entry_t **)calloc(0x1000, sizeof(entry_t*));
+ if (tailorfile) free(tailorfile);
+ return 0;
+}
+
+/* this clears the attrib structure if there is one, and reads in the data
+ * sorting lines 2 to n by name, and eliminating comments
+ */
+static int
+readrec(edfFILE * edf1, attrib1_t ** attrib)
+{
+ Dec64_t * b64;
+ char * vptr;
+ char * lptr;
+ char * ptr;
+ int len;
+ int lookahead = 0;
+ int toolong = FALSE;
+ int rc;
+ int cmp;
+ attrib1_t * att;
+ attrib1_t ** prev;
+ attrib1_t * freelist = *attrib;
+ attrib1_t * newlist = NULL;
+ attrib1_t * a;
+ int ignore_rec = FALSE;
+
+ *attrib = NULL;
+ if (edf1->end) {
+ freefreelist(freelist);
+ return IDDS_MM_EOF;
+ }
+
+ while (TRUE) {
+ if (lookahead) {
+ if (lookahead == '\n') {
+ break; /* return */
+ }
+ line[0] = lookahead;
+ lptr = line+1;
+ lookahead = 0;
+ }
+ else
+ lptr = line;
+ if (!fgets(lptr, sizeof(line)-1, edf1->fp)) {
+ edf1->end = TRUE;
+ if (!newlist) {
+ /* that's for the case where the file */
+ /* has a trailing blank line */
+ freefreelist(freelist);
+ return IDDS_MM_EOF;
+ }
+ break; /* return */
+ }
+ if (line[0] == '\n') {
+ /* ignore empty lines at head of LDIF file */
+ if (newlist == NULL) {
+ continue;
+ }
+ break; /* an empty line terminates a record */
+ }
+ if (line[0] == '#')
+ continue; /* skip comment lines */
+
+ len = strlen(line);
+ for (lptr = line+len-1; len; len--, lptr--) {
+ if ((*lptr != '\n') && (*lptr != '\r'))
+ break;
+ *lptr = 0;
+ }
+ vptr = strchr(line, ':');
+ if (!vptr) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "%s\n invalid input line\n",
+ line, 0, 0);
+ continue; /* invalid line, but we'll just skip it */
+ }
+ *vptr = 0;
+ if (!stricmp(line, "authoritative"))
+ continue;
+ if (!freelist) {
+ att = (attrib1_t *)malloc(sizeof(attrib1_t));
+ } else {
+ att = freelist;
+ freelist = freelist->next;
+ }
+ att->namelen = vptr-line;
+
+ if (att->namelen > 63) {
+ att->namelen = 63;
+ *(line+64) = 0;
+ }
+
+ memcpy(att->name, line, att->namelen+1);
+ vptr++;
+ if (*vptr == ':') {
+ vptr++;
+ while (*vptr == ' ') vptr++; /* skip optional spaces */
+ b64 = initDec64((unsigned char *)att->value, 0x20000);
+ if (Dec64(b64, (unsigned char *) vptr)) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "%s\n invalid input line\n",
+ line, 0, 0);
+ continue; /* invalid line, but we'll just skip it */
+ }
+ toolong = FALSE;
+ while (TRUE) {
+ lookahead = fgetc(edf1->fp);
+ if (lookahead != ' ')
+ break;
+ fgets(line, sizeof(line), edf1->fp);
+ len = strlen(line);
+ for (lptr = line+len-1; len; len--, lptr--) {
+ if ((*lptr != '\n') && (*lptr != '\r'))
+ break;
+ *lptr = 0;
+ }
+ rc = Dec64(b64, (unsigned char *)line);
+ if (rc == -1)
+ {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "%s\n invalid input line\n", line, 0, 0);
+ continue; /* invalid line, but we'll just skip it */
+ }
+
+ if (rc) {
+ if (!toolong) {
+ toolong = TRUE;
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "%s\n line too long\n", line, 0, 0);
+ }
+ continue;
+ }
+ }
+ att->valuelen = freeDec64(b64);
+ } else {
+ if (!*vptr) {
+ att->valuelen = 0;
+ }
+ while (*vptr == ' ') vptr++; /* skip optional spaces */
+
+ att->valuelen = strlen(vptr);
+ memcpy(att->value, vptr, att->valuelen);
+ ptr = att->value + att->valuelen;
+ while (TRUE) {
+ lookahead = fgetc(edf1->fp);
+ if (lookahead != ' ')
+ break;
+ fgets(line, sizeof(line), edf1->fp);
+ len = strlen(line);
+ for (lptr = line+len-1; len; len--, lptr--) {
+ if ((*lptr != '\n') && (*lptr != '\r'))
+ break;
+ *lptr = 0;
+ }
+ memcpy(ptr, line, len);
+ att->valuelen += len;
+ ptr += len;
+ }
+ *ptr = 0;
+ }
+
+ if (newlist) {
+ if (newlist->next) {
+ for (a = newlist->next, prev = &(newlist->next);
+ a; prev=&(a->next), a = a->next) {
+ cmp = stricmp(a->name, att->name);
+ if (cmp > 0) {
+ att->next = *prev;
+ *prev = att;
+ goto f1;
+ }
+ if (cmp == 0) {
+ cmp = signedmemcmp((unsigned char *)a->value,
+ a->valuelen,
+ (unsigned char *)att->value,
+ att->valuelen);
+ if (cmp > 0) {
+ att->next = *prev;
+ *prev = att;
+ goto f1;
+ }
+ }
+ }
+ *prev = att;
+ att->next = NULL;
+ f1: ;
+ } else {
+ newlist->next = att;
+ att->next = NULL;
+ }
+ } else {
+ newlist = att;
+ att->next = NULL;
+ }
+ }
+ *attrib = newlist;
+ freefreelist(freelist);
+ if (ignore_rec)
+ return IDDS_MM_ABSENT;
+ return IDDS_MM_OK;
+}
+
+static void
+freefreelist(attrib1_t * freelist)
+{
+ attrib1_t * next;
+ for (;freelist; freelist = next) {
+ next = freelist->next;
+ free(freelist);
+ }
+}
+
+static void
+hashname(char seed, attrib1_t * attrib, char * hashkey)
+{
+ MM_VSTRING upper;
+ PK11Context *context;
+ unsigned int hashLen;
+
+/* we want the name to be case insensitive, and if the name DN, we want
+ * the value to be case insensitive. */
+/* this creates a hash key based on the first line in attrib */
+ makeupper(&upper, attrib->name, attrib->namelen);
+ context = PK11_CreateDigestContext(SEC_OID_MD5);
+ if (context != NULL) {
+ PK11_DigestBegin(context);
+ PK11_DigestOp(context, (unsigned char *)&seed, 1);
+ PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
+ PK11_DigestOp(context, (unsigned char *)"=", 1);
+ if (!memcmp(upper.body, "DN", 2)) {
+ makeupper(&upper, attrib->value, attrib->valuelen);
+ PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
+ } else
+ PK11_DigestOp(context, (unsigned char *)attrib->value, attrib->valuelen);
+ PK11_DigestFinal(context, (unsigned char *)hashkey, &hashLen, 16);
+ PK11_DestroyContext(context, PR_TRUE);
+ }
+ else { /* Probably desesperate but at least deterministic... */
+ memset(hashkey, 0, 16);
+ }
+}
+
+/* this creates a hash key base on all but the first line in attrib */
+static void
+hashvalue(char seed, attrib1_t * attrib, char * fingerprint)
+{
+ MM_VSTRING upper;
+ attrib1_t * a;
+ PK11Context *context;
+ unsigned int fgLen;
+
+ context = PK11_CreateDigestContext(SEC_OID_MD5);
+ if (context != NULL) {
+ PK11_DigestBegin(context);
+ PK11_DigestOp(context, (unsigned char *)&seed, 1);
+ for (a = attrib->next; a; a = a->next) {
+ if (!stricmp(a->name, "authoritative"))
+ continue;
+ /* we want the name to be case insensitive, and if the name DN, we want
+ * the value to be case insensitive. */
+ makeupper(&upper, a->name, a->namelen);
+ PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
+ PK11_DigestOp(context, (unsigned char *)"=", 1);
+ if (!memcmp(upper.body, "DN", 2)) {
+ makeupper(&upper, a->value, a->valuelen);
+ PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
+ } else
+ PK11_DigestOp(context, (unsigned char *)a->value, a->valuelen);
+ PK11_DigestOp(context, (unsigned char *)";", 1);
+ }
+ PK11_DigestFinal(context, (unsigned char *)fingerprint, &fgLen, 16);
+ PK11_DestroyContext(context, PR_TRUE);
+ }
+ else { /* Probably desesperate but at least deterministic... */
+ memset(fingerprint, 0, 16);
+ }
+}
+
+/* this writes a record deletion record based on the first line in attrib */
+static int
+adddelete(FILE * edf3, attrib1_t * attrib)
+{
+ if (!putvalue(edf3, NULL, attrib->name, attrib->namelen,
+ attrib->value, attrib->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ fprintf(edf3, "changetype: delete\n\n");
+ return IDDS_MM_OK;
+}
+
+/* this writes a record addition record based on attrib */
+static int
+addnew(FILE * edf3, const char *changetype, record_t * first)
+{
+ attrib_t * att;
+ int attnum;
+
+ for (attnum = 1, att = &first->data;
+ attnum <= first->nattrs;
+ attnum++, att = attribnext(att)) {
+ if (!stricmp(attribname(att), "modifytimestamp"))
+ continue;
+ if (!stricmp(attribname(att), "modifiersname"))
+ continue;
+ if (!putvalue(edf3, NULL, attribname(att), att->namelen,
+ attribvalue(att), att->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ if (attnum == 1 && changetype != NULL) {
+ fprintf(edf3, "changetype: %s\n", changetype);
+ }
+ }
+ if (fputs("\n", edf3) < 0) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ return IDDS_MM_OK;
+}
+
+/* this writes a record modification record based on the information in
+ * first and attrib
+ */
+static int
+addmodified(FILE * edf3, attrib1_t * attrib, record_t * first)
+{
+ attrib_t *b;
+ attrib1_t *a;
+ int num_b;
+ int tot_b;
+ int cmp;
+ char *attrname;
+
+ if (!putvalue(edf3, NULL, attrib->name, attrib->namelen,
+ attrib->value, attrib->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ if (fputs("changetype: modify\n", edf3) < 0) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+
+ tot_b = first->nattrs;
+ num_b = 1;
+ b = &first->data;
+
+ /* advance past dn attrs */
+ a = attrib->next;
+ b = attribnext(b); num_b++;
+
+ /*
+ * Lock-step through the two attr lists while there are still
+ * attrs remaining in either.
+ */
+ while (a != NULL || num_b <= tot_b) {
+ /* ignore operational attrs */
+ if (num_b <= tot_b &&
+ (stricmp(attribname(b), "modifytimestamp") == 0 ||
+ stricmp(attribname(b), "modifiersname") == 0)) {
+ b = attribnext(b); num_b++;
+ continue;
+ }
+ if (a != NULL &&
+ (stricmp(a->name, "modifytimestamp") == 0 ||
+ stricmp(a->name, "modifiersname") == 0)) {
+ a = a->next;
+ continue;
+ }
+
+ if (num_b > tot_b) {
+ cmp = -1;
+ } else if (a == NULL) {
+ cmp = 1;
+ } else {
+ cmp = stricmp(a->name, attribname(b));
+ }
+ if (cmp < 0) {
+ /* a < b: a is deleted */
+ attrname = a->name;
+ fprintf(edf3, "delete: %s\n-\n", attrname);
+ do {
+ a = a->next;
+ } while (a != NULL && stricmp(a->name, attrname) == 0);
+ continue;
+ } else if (cmp > 0) {
+ /* a > b: b is added */
+ attrname = attribname(b);
+ fprintf(edf3, "add: %s\n", attrname);
+ do {
+ if (!putvalue(edf3, NULL, attribname(b), b->namelen,
+ attribvalue(b), b->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ b = attribnext(b); num_b++;
+ } while (num_b <= tot_b && stricmp(attribname(b), attrname) == 0);
+ fprintf(edf3, "-\n");
+ continue;
+ } else {
+ /* a == b */
+ int nmods = 0;
+ attrib_t *begin_b = b;
+ attrib1_t *v_del = NULL;
+ attrib_t *v_add = NULL;
+ int begin_num_b = num_b;
+
+ /*
+ * Lock-step through the ordered values.
+ * Remember a maximum of one changed value.
+ * If we encounter more than one change then
+ * just issue a replace of the whole value.
+ */
+ attrname = a->name;
+ do {
+ if (num_b > tot_b || stricmp(attribname(b), attrname) != 0) {
+ cmp = -1;
+ } else if (a == NULL || stricmp(a->name, attrname) != 0) {
+ cmp = 1;
+ } else {
+ cmp = signedmemcmp((unsigned char *)a->value,
+ a->valuelen,
+ (unsigned char *)attribvalue(b),
+ b->valuelen);
+ }
+ if (cmp < 0) {
+ nmods++;
+ v_del = a;
+ a = a->next;
+ } else if (cmp > 0) {
+ nmods++;
+ v_add = b;
+ b = attribnext(b); num_b++;
+ } else {
+ a = a->next;
+ b = attribnext(b); num_b++;
+ }
+ } while ((a != NULL &&
+ stricmp(a->name, attrname) == 0) ||
+ (num_b <= tot_b &&
+ stricmp(attribname(b), attrname) == 0));
+ if (nmods == 1) {
+ if (v_add != NULL) {
+ if (!putvalue(edf3, "add",
+ attribname(v_add), v_add->namelen,
+ attribvalue(v_add), v_add->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ } else {
+ if (!putvalue(edf3, "delete",
+ v_del->name, v_del->namelen,
+ v_del->value, v_del->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ }
+ } else if (nmods > 1) {
+ fprintf(edf3, "replace: %s\n", attrname);
+ do {
+ if (!putvalue(edf3, NULL,
+ attribname(begin_b), begin_b->namelen,
+ attribvalue(begin_b), begin_b->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ begin_b = attribnext(begin_b); begin_num_b++;
+ } while (begin_num_b <= tot_b && begin_b != b);
+ fprintf(edf3, "-\n");
+ }
+ }
+ }
+
+ if (fputs("\n", edf3) < 0) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ return IDDS_MM_OK;
+}
+
+static record_t * newrecord(attrib1_t * big)
+{
+ record_t * smll;
+ attrib_t * b;
+ attrib1_t * a;
+ int len = 0;
+ int count = 0;
+
+ for (a=big; a; a = a->next) {
+ count++;
+ len += (a->namelen + a->valuelen + sizeof(attrib_t) + attribalign) &
+ ~ (attribalign-1);
+ }
+ len += sizeof(short);
+ smll = (record_t *)malloc(len);
+
+ for (a=big, b=&smll->data; a; a = a->next, b = attribnext(b)) {
+ b->valuelen = a->valuelen;
+ b->namelen = a->namelen;
+ memcpy(attribname(b), a->name, a->namelen+1);
+ memcpy(attribvalue(b), a->value, a->valuelen+1);
+ }
+ smll->nattrs = count;
+ return smll;
+}
+
+static int
+simpletextbody(unsigned char * body, int length)
+{
+ int i;
+ for (i = length; --i >= 0; body++) {
+ if ((*body < ' ') || (*body >= 0x7f))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static int
+simpletext(unsigned char * body, int length)
+{
+ if ((*body == ':') || (*body == '<') || (*body == ' '))
+ return FALSE;
+ return simpletextbody(body, length);
+}
+
+/* output a string value */
+static int
+putvalue(
+ FILE * fh,
+ const char * tag,
+ char * name,
+ int namelen,
+ char * value,
+ int valuelen
+)
+{
+ Enc64_t * b64;
+ char * lptr;
+ char line[255];
+ int return_code;
+ int len;
+ char * sptr;
+ int rc;
+ int simpletxt = TRUE;
+
+ lptr = line;
+ if (tag != NULL) {
+ sprintf(lptr, "%s: ", tag);
+ lptr += strlen(lptr);
+ memcpy(lptr, name, namelen);
+ lptr += namelen;
+ *lptr++ = '\n';
+ }
+
+ memcpy(lptr, name, namelen);
+ lptr += namelen;
+ *lptr++ = ':';
+
+ if (!valuelen) {
+ *lptr = '\n';
+ *(lptr+1) = 0;
+ return_code = fputs(line, fh);
+ goto return_bit;
+ }
+
+ if (simpletext((unsigned char *)value, valuelen)) {
+ *lptr = ' ';
+ if (valuelen + (lptr+1 - line) < 80) {
+ strcpy(lptr+1, value);
+ strcpy(lptr+1 + valuelen, "\n");
+ return_code = fputs(line, fh);
+ goto return_bit;
+ }
+ len = 80 - (lptr+1 - line);
+ memcpy(lptr+1, value, len);
+ line[80] = '\n';
+ line[81] = 0;
+ return_code = fputs(line, fh);
+ if (return_code < 0)
+ goto return_bit;
+ sptr = value + len;
+ len = valuelen - len;
+ line[0] = ' ';
+ while (len > 79) {
+ memcpy(line+1, sptr, 79);
+ return_code = fputs(line, fh);
+ if (return_code < 0)
+ goto return_bit;
+ sptr += 79;
+ len -= 79;
+ }
+ if (len) {
+ memcpy(line+1, sptr, len);
+ line[len+1] = '\n';
+ line[len+2] = 0;
+ return_code = fputs(line, fh);
+ }
+ goto return_bit;
+ }
+
+ b64 = initEnc64((unsigned char *)value, valuelen);
+ *lptr = ':';
+ *(lptr+1) = ' ';
+ rc = Enc64(b64, (unsigned char *)(lptr+2), 80-(lptr-line), &len);
+ *(lptr +len+2) = '\n';
+ *(lptr + len +3) = 0;
+ return_code = fputs(line, fh);
+ if (return_code < 0)
+ goto return_bit;
+ while (TRUE) {
+ line[0] = ' ';
+ rc = Enc64(b64, (unsigned char *)line+1, 79, &len);
+ if (rc)
+ break;
+ line[len+1] = '\n';
+ line[len+2] = 0;
+ return_code = fputs(line, fh);
+ if (return_code < 0)
+ goto return_bit;
+ }
+
+ return_bit:
+ if (tag != NULL) {
+ fputs("-\n", fh);
+ }
+ if (return_code < 0)
+ return FALSE;
+ return TRUE;
+}
+
+static int
+signedmemcmp(unsigned char * a, int lena, unsigned char * b, int lenb)
+{
+ int c;
+
+ for (;; a++, b++) {
+ if (!lenb)
+ return lena;
+ if (!lena)
+ return -1;
+ if (c=(int)*a - (int)*b)
+ return c;
+ lena--;
+ lenb--;
+ }
+}
+
+static void
+makeupper(MM_VSTRING * v, char * body, int len)
+{
+ char * vp;
+ v->length = len;
+ for (vp = v->body; len > 0; len--, vp++, body++)
+ *vp = toupper(*body);
+}
+
+int
+mm_getvalue(
+ record_t *first,
+ attrib1_t *a,
+ int directory,
+ char *name,
+ char **value,
+ int *length
+)
+{
+ int attnum;
+ attrib_t * att;
+ if (directory) {
+ for ( ; a; a = a->next) {
+ if (!stricmp(a->name, name)) {
+ if (!*value) {
+ *value = a->value;
+ *length = a->valuelen;
+ return TRUE;
+ } else {
+ if (*value == a->value)
+ *value = NULL;
+ }
+ }
+ }
+ return FALSE;
+ }
+
+ att = &first->data;
+
+ for (attnum = 1, att = &first->data;
+ attnum <= first->nattrs;
+ attnum++, att = attribnext(att)) {
+ if (!stricmp(attribname(att), name)) {
+ if (!*value) {
+ *value = attribvalue(att);
+ *length = att->valuelen;
+ return TRUE;
+ } else {
+ if (*value == attribvalue(att))
+ *value = NULL;
+ }
+ }
+ }
+ return FALSE;
+}
+
+int mm_is_deleted(
+ record_t *first,
+ attrib1_t *attrib,
+ int directory
+)
+{
+ char * value = NULL;
+ int len;
+
+ while (mm_getvalue(first, attrib, directory,
+ "objectclass",
+ &value, &len)) {
+ if (stricmp(value, "nsTombstone") == 0) {
+ return 1;
+ }
+ }
+
+ if (mm_getvalue(first, attrib, directory, "isdeleted", &value, &len)) {
+ if ((len == 1 && *value == '1') ||
+ (len == 4 && stricmp(value, "true") == 0)) {
+ return 1;
+ }
+ }
+
+ if (mm_getvalue(first, attrib, directory, "zombi", &value, &len)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static void commententry(FILE *fp, attrib1_t *attrib)
+{
+ attrib1_t *a;
+
+ if (attrib == NULL) return;
+
+ fprintf(fp, "# %s: %s\n", attrib->name, attrib->value);
+ for (a = attrib->next; a; a = a->next) {
+ if (simpletext((unsigned char *)a->value,
+ a->valuelen)) {
+ fprintf(fp, "# %*.*s: %*.*s\n",
+ a->namelen, a->namelen,
+ a->name,
+ a->valuelen, a->valuelen,
+ a->value);
+ }
+ }
+ fprintf(fp, "\n");
+}
+
+int main(int argc, char *argv[])
+{
+ stats_t stats;
+ int rc;
+ float difftime;
+
+ memset(&stats, 0, sizeof(stats));
+
+ if (rc = mm_init(argc, argv))
+ return rc;
+
+ if ((mm_diff(&stats) == IDDS_MM_OK)
+ && (license_limit > 0)) {
+ if (license_count > license_limit * 98.0 / 100)
+ fprintf(stderr, "That was over 98% of your license limit.\n");
+ else if (license_count > license_limit * 95.0 / 100)
+ fprintf(stderr, "That was over 95% of your license limit.\n");
+ else if (license_count > license_limit * 90.0 / 100)
+ fprintf(stderr, "That was over 90% of your license limit.\n");
+ }
+ mm_fin_winner();
+ printf("start time %s", ctime(&stats.diff_start_time));
+ printf("\nentry counts: unchanged=%d changed=%d new=%d total=%d\n\n",
+ stats.num_unchanged,
+ stats.num_modifies,
+ stats.num_adds,
+ stats.num_identities);
+ printf("end time %s", ctime(&stats.diff_end_time));
+
+ difftime = stats.diff_end_time - stats.diff_start_time;
+ if (difftime <= 1)
+ printf("differencing took <= 1 second\n");
+ else
+ printf("differencing took %u seconds, %u records per second\n",
+ (unsigned int)difftime,
+ (unsigned int)(stats.num_identities / difftime));
+ exit(0);
+}
+
+/*
+ * Conflict resolution.
+ */
+
+void mm_init_winner()
+{
+}
+
+void mm_fin_winner()
+{
+}
+
+int mm_get_winner(record_t * first, attrib1_t * a)
+{
+ int len;
+ char * modified0 = NULL;
+ char * modified1 = NULL;
+
+ mm_getvalue(first, a, 0, "modifytimestamp", &modified0, &len);
+ mm_getvalue(first, a, 1, "modifytimestamp", &modified1, &len);
+
+ if (!modified0) {
+ mm_getvalue(first, a, 0, "createtimestamp", &modified0, &len);
+ }
+
+ if (!modified1) {
+ mm_getvalue(first, a, 1, "createtimestamp", &modified1, &len);
+ }
+
+ if (!modified0) {
+ mm_getvalue(first, a, 0, "deletetimestamp", &modified0, &len);
+ }
+
+ if (!modified1) {
+ mm_getvalue(first, a, 1, "deletetimestamp", &modified1, &len);
+ }
+
+ if (!modified0)
+ return 1;
+ if (!modified1)
+ return 0;
+ return strcmp(modified0, modified1) <= 0;
+}
+
+/*
+ * Base64 Implementation.
+ */
+
+ /* 0123456789ABCDEF */
+static unsigned char b64[] = "ABCDEFGHIJKLMNOP"
+ "QRSTUVWXYZabcdef"
+ "ghijklmnopqrstuv"
+ "wxyz0123456789+/";
+
+static unsigned char ub64[] = {
+/* 0 1 2 3 4 5 6 7
+ * 8 9 A B C C E F
+ */
+/*0-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*0-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*1-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*1-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*2-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*2-*/ 0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63,
+/*3-*/ 52, 53, 54, 55, 56, 57, 58, 59,
+/*3-*/ 60, 61, 0xFF, 0xFF, 0xFF, 64, 0xFF, 0xFF,
+/*4-*/ 0xFF, 0, 1, 2, 3, 4, 5, 6,
+/*4-*/ 7, 8, 9, 10, 11, 12, 13, 14,
+/*5-*/ 15, 16, 17, 18, 19, 20, 21, 22,
+/*5-*/ 23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*6-*/ 0xFF, 26, 27, 28, 29, 30, 31, 32,
+/*6-*/ 33, 34, 35, 36, 37, 38, 39, 40,
+/*7-*/ 41, 42, 43, 44, 45, 46, 47, 48,
+/*7-*/ 49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*8-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*8-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*9-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*9-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*A-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*A-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*B-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*B-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*C-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*C-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*D-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*D-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*E-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*E-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*F-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*F-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+
+static Enc64_t * freeEnc64List = NULL;
+static Dec64_t * freeDec64List = NULL;
+
+Enc64_t *
+initEnc64(unsigned char * source, int slen)
+{
+ Enc64_t * this = freeEnc64List;
+ if (this)
+ freeEnc64List = freeEnc64List->next;
+ else
+ this = (Enc64_t *)malloc(sizeof(Enc64_t));
+ this->source = source;
+ this->slen = slen;
+ return this;
+ }
+
+int
+Enc64(Enc64_t * this, unsigned char *dest, int maxlen, int *len)
+{
+ /* returns 0 normally
+ * +1 on end of string
+ * -1 on badi
+ */
+ int l;
+ unsigned char * s;
+ unsigned char * d;
+ int reml;
+ int i;
+
+ if (!this->slen)
+ return 1;
+ l = this->slen / 3;
+ s = this->source;
+ if (l > maxlen / 4)
+ {
+ l = maxlen / 4;
+ this->slen -= l*3;
+ reml = 0;
+ this->source += l*3;
+ }
+ else
+ {
+ reml = this->slen % 3;
+ this->slen = 0;
+ }
+ for (d = dest, i = 0; i < l; i++)
+ {
+ *d++ = b64[(*s >> 2) & 0x3f];
+ *d++ = b64[((*s << 4) & 0x30) + ((*(s+1) >> 4) & 0x0f)];
+ s++;
+ *d++ = b64[((*s << 2) & 0x3c) + ((*(s+1) >> 6) & 0x03)];
+ s++;
+ *d++ = b64[*s & 0x3f];
+ s++;
+ }
+ if (reml--)
+ *d++ = b64[(*s >> 2) & 0x3f];
+ else
+ {
+ *d = 0;
+ *len = l*4;
+ return 0;
+ }
+ if (reml)
+ {
+ *d++ = b64[((*s << 4) & 0x30) + ((*(s+1) >> 4) & 0x0f)];
+ s++;
+ *d++ = b64[((*s << 2) & 0x3c)];
+ }
+ else
+ {
+ *d++ = b64[((*s << 4) & 0x30) + ((*(s+1) >> 4) & 0x0f)];
+ *d++ = '=';
+ }
+ *d++ = '=';
+ *d = 0;
+ *len = (l+1)*4;
+ return 0;
+ }
+
+void
+freeEnc64(Enc64_t *this)
+{
+ this->next = freeEnc64List;
+ freeEnc64List = this;
+ }
+
+Dec64_t *
+initDec64(unsigned char * dest, int maxlen)
+{
+ Dec64_t * this = freeDec64List;
+ if (this)
+ freeDec64List = freeDec64List->next;
+ else
+ this = (Dec64_t *)malloc(sizeof(Dec64_t));
+ this->dest = dest;
+ this->maxlen = maxlen;
+ this->curlen = 0;
+ this->nextra = 0;
+ return this;
+ }
+
+int
+freeDec64(Dec64_t *this)
+{
+ this->next = freeDec64List;
+ freeDec64List = this;
+ return this->curlen;
+ }
+
+int
+Dec64(Dec64_t * this, unsigned char *source)
+{
+ /* returns 0 normally
+ * -1 on badi
+ * 1 on too long
+ */
+ unsigned char * s;
+ unsigned char * d;
+ unsigned char * e;
+ unsigned char s1, s2, s3, s4;
+ int i;
+ int slen;
+ int len;
+ int nextra;
+ int newnextra;
+ unsigned char newextra[3];
+
+ nextra = this->nextra;
+ slen = strlen((char *)source);
+ len = (slen + nextra) / 4;
+ newnextra = (slen + nextra) - len * 4;
+ for (i = 0; i < newnextra; i++)
+ {
+ newextra[i] = source[slen-newnextra+i];
+ }
+
+ if (len * 3 > this->maxlen - this->curlen)
+ return 1;
+ for (d = this->dest + this->curlen, s = source, e = this->extra, i = 0;
+ i < len; i++)
+ {
+ if (nextra)
+ {
+ nextra--;
+ s1 = ub64[*e++];
+ }
+ else
+ s1 = ub64[*s++];
+ if (nextra)
+ {
+ nextra--;
+ s2 = ub64[*e++];
+ }
+ else
+ s2 = ub64[*s++];
+ if (nextra)
+ {
+ nextra--;
+ s3 = ub64[*e++];
+ }
+ else
+ s3 = ub64[*s++];
+ s4 = ub64[*s++];
+ if ((s1 | s2 | s3 | s4) & 0x80)
+ return -1;
+ *d++ = (s1 << 2) + (s2 >> 4);
+ this->curlen++;
+ if (s3 == 64)
+ break;
+ *d++ = (s2 << 4) + (s3 >> 2);
+ this->curlen++;
+ if (s4 == 64)
+ break;
+ *d++ = (s3 << 6) + s4;
+ this->curlen++;
+ }
+ this->nextra = newnextra;
+ memcpy(this->extra, newextra, 3);
+ return 0;
+ }
diff --git a/ldap/servers/slapd/tools/pwenc.c b/ldap/servers/slapd/tools/pwenc.c
new file mode 100644
index 00000000..7a150860
--- /dev/null
+++ b/ldap/servers/slapd/tools/pwenc.c
@@ -0,0 +1,400 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#if defined( _WIN32 )
+#include <sys/stat.h> /* for S_IREAD and S_IWRITE */
+#include <windows.h>
+#include <time.h>
+#include "proto-ntutil.h"
+#else
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#if defined(LINUX) /* I bet other Unix would like
+ * this flag. But don't want to
+ * break other builds so far */
+#include <unistd.h>
+#endif
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "ldap.h"
+#include "ldif.h"
+#include "../slapi-plugin.h"
+#include "../slap.h"
+#include <nspr.h>
+#include <nss.h>
+#include "../../plugins/pwdstorage/pwdstorage.h"
+
+int ldap_syslog;
+int ldap_syslog_level;
+int slapd_ldap_debug = LDAP_DEBUG_ANY;
+#ifdef _WIN32
+int *module_ldap_debug;
+#endif
+int detached;
+FILE *error_logfp;
+FILE *access_logfp;
+struct pw_scheme *pwdhashscheme;
+int heflag = 0;
+
+static int slapd_config(const char *configdir);
+static int entry_has_attr_and_value(Slapi_Entry *e, const char *attrname, char *value);
+
+static void
+usage( name )
+char *name;
+{
+ fprintf( stderr, "usage: %s -D instance-dir [-H] [-s scheme | -c comparepwd ] password...\n", name );
+ exit( 1 );
+}
+
+
+/*
+ * If global "heflag" is non-zero, un-hex-encode the string
+ * and return a decoded copy. Otherwise return a copy of the
+ * string.
+ */
+static char *
+decode( char *orig )
+{
+ char *r;
+
+ if ( NULL == orig ) {
+ return NULL;
+ }
+ r = calloc( 1, strlen( orig ) + 2 );
+ strcpy( r, orig );
+
+ if ( heflag ) {
+ char *s;
+
+ for ( s = r; *s != '\0'; ++s ) {
+ if ( *s == '%' && ldap_utf8isxdigit( s+1 ) && ldap_utf8isxdigit( s+2 )) {
+ memmove( s, s + 1, 2 );
+ s[ 2 ] = '\0';
+ *s = strtoul( s, NULL, 16 );
+ memmove( s + 1, s + 3, strlen( s + 3 ) + 1 );
+ }
+ }
+ }
+ return r;
+}
+
+
+int
+main( argc, argv )
+ int argc;
+ char *argv[];
+{
+ int i, rc;
+ char *enc, *cmp, *name;
+ struct pw_scheme *pwsp, *cmppwsp;
+ extern int optind;
+ char *cpwd = NULL; /* candidate password for comparison */
+ char errorbuf[BUFSIZ];
+ slapdFrontendConfig_t *slapdFrontendConfig = NULL;
+
+ char *opts = "Hs:c:D:";
+ char *instancedir = NULL;
+ name = argv[ 0 ];
+ pwsp = cmppwsp = NULL;
+
+#ifdef _WIN32
+ module_ldap_debug = &slapd_ldap_debug;
+ libldap_init_debug_level(&slapd_ldap_debug);
+#endif
+
+ PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 0 );
+
+ /* Initialize NSS to make ds_salted_sha1_pw_enc() work */
+ if (NSS_NoDB_Init(NULL) != SECSuccess) {
+ fprintf( stderr, "Fatal error: unable to initialize the NSS subcomponent." );
+ return( 1 );
+ }
+
+
+ while (( i = getopt( argc, argv, opts )) != EOF ) {
+ switch ( i ) {
+ case 'D':
+ /* kexcoff: quite the same as slapd_bootstrap_config */
+ FrontendConfig_init();
+
+ instancedir = rel2abspath( optarg );
+ if ( config_set_instancedir( "configdir (-D)", instancedir,
+ errorbuf, 1) != LDAP_SUCCESS ) {
+ fprintf( stderr, "%s\n", errorbuf );
+ return( 1 );
+ }
+ slapi_ch_free((void **)&instancedir);
+
+
+ slapdFrontendConfig = getFrontendConfig();
+ if (0 == slapd_config(slapdFrontendConfig->configdir)) {
+ fprintf(stderr,
+ "The configuration files in directory %s could not be read or were not found. Please refer to the error log or output for more information.\n",
+ slapdFrontendConfig->configdir);
+ return(1);
+ }
+ break;
+
+ case 's': /* set hash scheme */
+ if (!slapdFrontendConfig) {
+ usage( name );
+ return( 1 );
+ }
+ if (( pwsp = pw_name2scheme( optarg )) == NULL ) {
+ fprintf( stderr, "%s: unknown hash scheme \"%s\"\n", name,
+ optarg );
+ return( 1 );
+ }
+ break;
+
+ case 'c': /* compare encoded password to password */
+ if (!slapdFrontendConfig) {
+ usage( name );
+ return( 1 );
+ }
+ cpwd = optarg;
+ break;
+
+ case 'H': /* password(s) is(are) hex-encoded */
+ if (!slapdFrontendConfig) {
+ usage( name );
+ return( 1 );
+ }
+ heflag = 1;
+ break;
+
+ default:
+ usage( name );
+ }
+ }
+
+ if (!slapdFrontendConfig) {
+ usage( name );
+ return( 1 );
+ }
+
+ if ( cpwd != NULL ) {
+ cmppwsp = pw_val2scheme( decode( cpwd ), &cmp, 1 );
+ }
+
+ if ( cmppwsp != NULL && pwsp != NULL ) {
+ fprintf( stderr, "%s: do not use -s with -c\n", name );
+ usage( name );
+ }
+
+ if ( cmppwsp == NULL && pwsp == NULL ) {
+ pwsp = pw_name2scheme( SALTED_SHA1_SCHEME_NAME );
+ }
+
+ if ( argc <= optind ) {
+ usage( name );
+ }
+
+ if ( cmppwsp == NULL && pwsp->pws_enc == NULL ) {
+ fprintf( stderr,
+ "The scheme \"%s\" does not support password encoding.\n",
+ pwsp->pws_name );
+ return( 1 );
+ }
+
+ srand((int)time(NULL)); /* schemes such as crypt use random salt */
+
+ for ( rc = 0; optind < argc && rc == 0; ++optind ) {
+ if ( cmppwsp == NULL ) { /* encode passwords */
+ if (( enc = (*pwsp->pws_enc)( decode( argv[ optind ] ))) == NULL ) {
+ perror( name );
+ return( 1 );
+ }
+
+ puts( enc );
+ free( enc );
+ } else { /* compare passwords */
+ if (( rc = (*(cmppwsp->pws_cmp))( decode( argv[ optind ]), cmp )) == 0 ) {
+ printf( "%s: password ok.\n", name );
+ } else {
+ printf( "%s: password does not match.\n", name );
+ }
+ }
+ }
+
+ return( rc == 0 ? 0 : 1 );
+}
+
+/* -------------------------------------------------------------- */
+
+/*
+ kexcoff: quite similar to slapd_bootstrap_config() from the server,
+ but it only loads password storage scheme plugins
+ */
+static int
+slapd_config(const char *configdir)
+{
+ char configfile[MAXPATHLEN+1];
+ PRFileInfo prfinfo;
+ int rc = 0; /* Fail */
+ int done = 0;
+ PRInt32 nr = 0;
+ PRFileDesc *prfd = 0;
+ char *buf = 0;
+ char *lastp = 0;
+ char *entrystr = 0;
+
+ sprintf(configfile, "%s/%s", configdir, CONFIG_FILENAME);
+ if ( (rc = PR_GetFileInfo( configfile, &prfinfo )) != PR_SUCCESS )
+ {
+ fprintf(stderr,
+ "The given config file %s could not be accessed, error %d\n",
+ configfile, rc);
+ exit( 1 );
+ }
+ else if (( prfd = PR_Open( configfile, PR_RDONLY,
+ SLAPD_DEFAULT_FILE_MODE )) == NULL )
+ {
+ fprintf(stderr,
+ "The given config file %s could not be read\n",
+ configfile);
+ exit( 1 );
+ }
+ else
+ {
+ /* read the entire file into core */
+ buf = slapi_ch_malloc( prfinfo.size + 1 );
+ if (( nr = slapi_read_buffer( prfd, buf, prfinfo.size )) < 0 )
+ {
+ fprintf(stderr,
+ "Could only read %d of %d bytes from config file %s\n",
+ nr, prfinfo.size, configfile);
+ exit( 1 );
+ }
+
+ (void)PR_Close(prfd);
+ buf[ nr ] = '\0';
+
+ if(!done)
+ {
+ /* Convert LDIF to entry structures */
+ Slapi_DN plug_dn;
+ slapi_sdn_init_dn_byref(&plug_dn, PLUGIN_BASE_DN);
+ while ((entrystr = dse_read_next_entry(buf, &lastp)) != NULL)
+ {
+ /*
+ * XXXmcs: it would be better to also pass
+ * SLAPI_STR2ENTRY_REMOVEDUPVALS in the flags, but
+ * duplicate value checking requires that the syntax
+ * and schema subsystems be initialized... and they
+ * are not yet.
+ */
+ Slapi_Entry *e = slapi_str2entry(entrystr,
+ SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF);
+ if (e == NULL)
+ {
+ fprintf(stderr,
+ "The entry [%s] in the configfile %s was empty or could not be parsed\n",
+ entrystr, configfile);
+ continue;
+ }
+
+ /* see if the entry is a child of the plugin base dn */
+ if (slapi_sdn_isgrandparent(&plug_dn,
+ slapi_entry_get_sdn_const(e)))
+ {
+ if ( entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, "pwdstoragescheme"))
+ {
+ /* add the syntax/matching/pwd storage scheme rule plugin */
+ if (plugin_setup(e, 0, 0, 1))
+ {
+ fprintf(stderr,
+ "The plugin entry [%s] in the configfile %s was invalid\n",
+ slapi_entry_get_dn(e), configfile);
+ exit(1); /* yes this sucks, but who knows what else would go on if I did the right thing */
+ }
+ else
+ {
+ e = 0; /* successful plugin_setup consumes entry */
+ }
+ }
+ }
+
+ if (e)
+ slapi_entry_free(e);
+ }
+
+ /* kexcoff: initialize rootpwstoragescheme and pw_storagescheme
+ * if not explicilty set in the config file
+ */
+ config_set_storagescheme();
+
+ slapi_sdn_done(&plug_dn);
+ rc= 1; /* OK */
+ }
+
+ slapi_ch_free((void **)&buf);
+ }
+
+ return rc;
+}
+
+/*
+ kexcoff: direclty copied fron the server code
+ See if the given entry has an attribute with the given name and the
+ given value; if value is NULL, just test for the presence of the given
+ attribute; if value is an empty string (i.e. value[0] == 0),
+ the first value in the attribute will be copied into the given buffer
+ and returned
+*/
+static int
+entry_has_attr_and_value(Slapi_Entry *e, const char *attrname,
+ char *value)
+{
+ int retval = 0;
+ Slapi_Attr *attr = 0;
+ if (!e || !attrname)
+ return retval;
+
+ /* see if the entry has the specified attribute name */
+ if (!slapi_entry_attr_find(e, attrname, &attr) && attr)
+ {
+ /* if value is not null, see if the attribute has that
+ value */
+ if (!value)
+ {
+ retval = 1;
+ }
+ else
+ {
+ Slapi_Value *v = 0;
+ int index = 0;
+ for (index = slapi_attr_first_value(attr, &v);
+ v && (index != -1);
+ index = slapi_attr_next_value(attr, index, &v))
+ {
+ const char *s = slapi_value_get_string(v);
+ if (!s)
+ continue;
+
+ if (!*value)
+ {
+ strcpy(value, s);
+ retval = 1;
+ break;
+ }
+ else if (!strcasecmp(s, value))
+ {
+ retval = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+