summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoriko Hosoi <nhosoi@redhat.com>2006-01-11 01:54:47 +0000
committerNoriko Hosoi <nhosoi@redhat.com>2006-01-11 01:54:47 +0000
commit84a1a5302b42d43575922e65393668e03998d24b (patch)
tree6791a2768149bfc88f08f3a40300ab75418045dd
parent67385d898398f60886047b9239d027cf997f9433 (diff)
downloadds-84a1a5302b42d43575922e65393668e03998d24b.tar.gz
ds-84a1a5302b42d43575922e65393668e03998d24b.tar.xz
ds-84a1a5302b42d43575922e65393668e03998d24b.zip
[164596] LDCLT distributed with Directory Server
integrated ldclt from DSRK into the DS source tree.
-rw-r--r--ldap/servers/slapd/tools/Makefile5
-rw-r--r--ldap/servers/slapd/tools/ldclt/Makefile134
-rw-r--r--ldap/servers/slapd/tools/ldclt/README1
-rw-r--r--ldap/servers/slapd/tools/ldclt/data.c525
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/001/add.ksh55
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/001/add_incr.ksh58
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/001/config.ksh56
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/001/delete.ksh56
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/001/env.ksh51
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/001/search.ksh56
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/002/add.ksh59
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/002/config.ksh57
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/002/env.ksh51
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/002/ldif01.ksh60
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/002/ldif02.ksh60
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/002/ldif03.ksh60
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/002/ofile12
-rw-r--r--ldap/servers/slapd/tools/ldclt/examples/README52
-rw-r--r--ldap/servers/slapd/tools/ldclt/ldap-private.h321
-rw-r--r--ldap/servers/slapd/tools/ldclt/ldapfct.c3506
-rw-r--r--ldap/servers/slapd/tools/ldclt/ldclt.c3066
-rw-r--r--ldap/servers/slapd/tools/ldclt/ldclt.h739
-rw-r--r--ldap/servers/slapd/tools/ldclt/ldclt.man754
-rw-r--r--ldap/servers/slapd/tools/ldclt/ldclt.use86
-rw-r--r--ldap/servers/slapd/tools/ldclt/ldcltU.c224
-rw-r--r--ldap/servers/slapd/tools/ldclt/opCheck.c1012
-rw-r--r--ldap/servers/slapd/tools/ldclt/parser.c618
-rw-r--r--ldap/servers/slapd/tools/ldclt/port.c321
-rw-r--r--ldap/servers/slapd/tools/ldclt/port.h130
-rw-r--r--ldap/servers/slapd/tools/ldclt/remote.h87
-rw-r--r--ldap/servers/slapd/tools/ldclt/repcheck.c162
-rw-r--r--ldap/servers/slapd/tools/ldclt/repslave.c342
-rw-r--r--ldap/servers/slapd/tools/ldclt/scalab01.c1193
-rw-r--r--ldap/servers/slapd/tools/ldclt/scalab01.h120
-rw-r--r--ldap/servers/slapd/tools/ldclt/srv.c123
-rw-r--r--ldap/servers/slapd/tools/ldclt/threadMain.c1198
-rw-r--r--ldap/servers/slapd/tools/ldclt/utils.c337
-rw-r--r--ldap/servers/slapd/tools/ldclt/utils.h76
-rw-r--r--ldap/servers/slapd/tools/ldclt/version.c1
-rw-r--r--ldap/servers/slapd/tools/ldclt/workarounds.c110
40 files changed, 15933 insertions, 1 deletions
diff --git a/ldap/servers/slapd/tools/Makefile b/ldap/servers/slapd/tools/Makefile
index dae1b414..55c483f0 100644
--- a/ldap/servers/slapd/tools/Makefile
+++ b/ldap/servers/slapd/tools/Makefile
@@ -171,7 +171,7 @@ DBSCAN = $(addsuffix $(EXE_SUFFIX), \
BINS= $(LDIF) $(PWDHASH) $(KEYUPG) $(MMLDIF) $(MIGRATECRED) $(DBSCAN)
EXTRABINS= $(EGGENCODE)
-all: $(OBJDEST) $(BINDIR) $(LDAP_ADMIN_BIN_RELDIR) $(BINS) buildRsearch
+all: $(OBJDEST) $(BINDIR) $(LDAP_ADMIN_BIN_RELDIR) $(BINS) buildRsearch buildLdclt
extras: $(OBJDEST) $(BINDIR) $(EGGENCODE)
@@ -202,6 +202,9 @@ $(OBJDEST):
buildRsearch:
cd rsearch; $(MAKE)
+buildLdclt:
+ cd ldclt; $(MAKE)
+
clean:
-$(RM) $(ALL_OBJS)
-$(RM) $(BINS) $(EXTRABINS)
diff --git a/ldap/servers/slapd/tools/ldclt/Makefile b/ldap/servers/slapd/tools/ldclt/Makefile
new file mode 100644
index 00000000..995e865a
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/Makefile
@@ -0,0 +1,134 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# This Makefile is targetted to build the ldclt tool. This tool is a
+# multithreaded ldap client, specially targetted to ensure good
+# reliability of the product under test.
+#
+# -----------------------------------------------------------------------------
+
+LDAP_SRC = ../../../..
+BUILD_ROOT = ../../../../..
+
+OBJDEST = $(OBJDIR)/servers/tools/obj
+BINDIR = $(RELDIR)/shared/bin
+DATDIR = $(RELDIR)/shared/data
+
+include $(BUILD_ROOT)/nsdefs.mk
+include $(BUILD_ROOT)/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(OS_ARCH), WINNT)
+OBJEXT =.obj
+else
+OBJEXT =.o
+endif
+
+EXTRA_LIBS_DEP = $(LDAPSDK_DEP) $(DB_LIB_DEP) $(LDAP_COMMON_LIBS_DEP)
+
+EXTRA_LIBS += $(LDAPLINK) $(DB_LIB) \
+ $(PLATFORM_SPECIFIC_EXTRA_LIBRARY) \
+ $(ALIBS) $(NSPRLINK) $(SECURITYLINK) \
+ $(THREADSLIB) $(LDAP_COMMON_LIBS)
+
+LDCLTSRC = \
+ data.c \
+ ldapfct.c \
+ ldclt.c \
+ ldcltU.c \
+ parser.c \
+ port.c \
+ scalab01.c \
+ threadMain.c \
+ utils.c \
+ version.c \
+ workarounds.c
+
+#ifdef SUN_DS_3_X_SUPPORT
+LDCLTSRC += opCheck.c
+#endif
+
+LDCLTOBJS = $(addprefix $(OBJDEST)/, $(LDCLTSRC:.c=$(OBJEXT)))
+
+HDIR = $(LDAP_SRC)/include
+
+LDCLTBIN = $(addsuffix $(EXE_SUFFIX), $(addprefix $(BINDIR)/, ldclt))
+
+INC_FILES = \
+ ldclt.h \
+ port.h \
+ utils.h \
+ remote.h
+
+INC_PLUGINS = \
+ scalab01.h
+
+ADDLIBS = $(LDAPLIBS) $(SPEC_LIBS) $(SYSTEM_LIBS) $(END)
+
+CFLAGS+=-DLDAP_DONT_USE_SMARTHEAP
+
+EXTRA_LIBS_DEP = $(LDAPSDK_DEP) $(DB_LIB_DEP) $(LDAP_COMMON_LIBS_DEP)
+
+EXTRA_LIBS += $(LDAPLINK) $(DB_LIB) \
+ $(PLATFORM_SPECIFIC_EXTRA_LIBRARY) \
+ $(ALIBS) $(NSPRLINK) $(SECURITYLINK) \
+ $(THREADSLIB) $(LDAP_COMMON_LIBS)
+
+##########################################################################
+
+all: $(OBJDEST) $(BINDIR) $(LDCLTBIN)
+
+clean:
+ -$(RM) $(LDCLTOBJS) $(LDCLTBIN)
+
+$(OBJDEST):
+ if [ ! -d $(OBJDEST) ]; then \
+ $(MKDIR) $(OBJDEST); \
+ fi
+
+$(BINDIR):
+ if [ ! -d $(BINDIR) ]; then \
+ $(MKDIR) $(BINDIR); \
+ fi
+
+$(LDCLTBIN): $(LDCLTOBJS)
+ $(LINK_EXE) $(LDCLTOBJS) $(EXTRA_LIBS)
+ -chmod 755 $(LDCLTBIN)
+
diff --git a/ldap/servers/slapd/tools/ldclt/README b/ldap/servers/slapd/tools/ldclt/README
new file mode 100644
index 00000000..6bd67574
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/README
@@ -0,0 +1 @@
+CVS snapshot in sync with ldclt 4.23
diff --git a/ldap/servers/slapd/tools/ldclt/data.c b/ldap/servers/slapd/tools/ldclt/data.c
new file mode 100644
index 00000000..73b2c238
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/data.c
@@ -0,0 +1,525 @@
+#ident "ldclt @(#)data.c 1.8 01/03/23"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : data.c
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 11 January 1999
+ DESCRIPTION :
+ This file implements the management of the data that
+ are manipulated by ldclt.
+ It is targetted to contain all the functions needed for
+ the images, etc...
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+11/01/99 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+06/03/00 | JL Schwing | 1.2 : Test malloc() return value.
+---------+--------------+------------------------------------------------------
+28/11/00 | JL Schwing | 1.3 : Port on NT 4.
+---------+--------------+------------------------------------------------------
+30/11/00 | JL Schwing | 1.4 : Implement loadImages for NT.
+---------+--------------+------------------------------------------------------
+30/11/00 | JL Schwing | 1.5 : Port on OSF1.
+---------+--------------+------------------------------------------------------
+01/12/00 | JL Schwing | 1.6 : Port on Linux.
+---------+--------------+------------------------------------------------------
+06/03/01 | JL Schwing | 1.7 : Better error messages if images not found.
+---------+--------------+------------------------------------------------------
+23/03/01 | JL Schwing | 1.8 : Implements data file list support in variants.
+---------+--------------+------------------------------------------------------
+*/
+
+#include <stdio.h> /* printf(), etc... */
+#include <stdlib.h> /* realloc(), etc... */
+#include <string.h> /* strlen(), etc... */
+#include <errno.h> /* errno, etc... */ /*JLS 06-03-00*/
+#include <sys/types.h> /* Misc types... */
+#include <sys/stat.h> /* stat(), etc... */
+#include <fcntl.h> /* open(), etc... */
+#include <lber.h> /* ldap C-API BER declarations */
+#include <ldap.h> /* ldap C-API declarations */
+#ifndef _WIN32 /*JLS 28-11-00*/
+#include <unistd.h> /* close(), etc... */
+#include <dirent.h> /* opendir(), etc... */
+#include <pthread.h> /* pthreads(), etc... */
+#include <sys/mman.h> /* mmap(), etc... */
+#endif /*JLS 28-11-00*/
+
+#include "port.h" /* Portability definitions */ /*JLS 28-11-00*/
+#include "ldclt.h" /* This tool's include file */
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : getExtend
+ PURPOSE : Get the extension of the given string, i.e. the part
+ that is after the last '.'
+ INPUT : str = string to process
+ OUTPUT : None.
+ RETURN : The extension.
+ DESCRIPTION :
+ *****************************************************************************/
+char *getExtend (
+ char *str)
+{
+ int i;
+ for (i=strlen(str)-1; (i>=0) && (str[i]!='.') ; i--);
+ return (&(str[i+1]));
+}
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : loadImages
+ PURPOSE : Load the images from the given directory.
+ INPUT : dirpath = directory where the images are located.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int loadImages (
+ char *dirpath)
+{
+#ifdef _WIN32
+ WIN32_FIND_DATA fileData; /* Current file */
+ HANDLE dirContext; /* Directory context */
+ char *findPath; /* To build the find path */
+ char *pt; /* To read the images */
+#else /* _WIN32 */
+ DIR *dirp; /* Directory data */
+ struct dirent *direntp; /* Directory entry */
+#endif /* _WIN32 */
+ char *fileName; /* As read from the system */
+ char name [1024]; /* To build the full path */
+ struct stat stat_buf; /* To read the image size */
+ int fd; /* To open the image */
+ int ret; /* Return value */
+
+ /*
+ * Initialization
+ */
+ mctx.images = NULL;
+ mctx.imagesNb = 0;
+ mctx.imagesLast = -1;
+
+ if ((ret = ldclt_mutex_init(&(mctx.imagesLast_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (ret));
+ fprintf (stderr, "Error: cannot initiate imagesLast_mutex\n");
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Open the directory
+ */
+#ifdef _WIN32
+ findPath = (char *) malloc (strlen (dirpath) + 5);
+ strcpy (findPath, dirpath);
+ strcat (findPath, "/*.*");
+ dirContext = FindFirstFile (findPath, &fileData);
+ if (dirContext == INVALID_HANDLE_VALUE)
+ {
+ fprintf (stderr, "ldlct: cannot load images from %s\n", dirpath);
+ fprintf (stderr, "ldclt: try using -e imagesdir=path\n"); /*JLS 06-03-01*/
+ fflush (stderr);
+ free (findPath);
+ return (-1);
+ }
+#else /* _WIN32 */
+ dirp = opendir (dirpath);
+ if (dirp == NULL)
+ {
+ perror (dirpath);
+ fprintf (stderr, "ldlct: cannot load images from %s\n", dirpath);
+ fprintf (stderr, "ldclt: try using -e imagesdir=path\n"); /*JLS 06-03-01*/
+ fflush (stderr);
+ return (-1);
+ }
+#endif /* _WIN32 */
+
+ /*
+ * Process the directory.
+ * We will only accept the .jpg files, as stated by the RFC.
+ */
+#ifdef _WIN32
+ fileName = fileData.cFileName;
+ do
+ {
+#else
+ while ((direntp = readdir (dirp)) != NULL)
+ {
+ fileName = direntp->d_name;
+#endif
+ if (!strcmp (getExtend (fileName), "jpg"))
+ {
+ /*
+ * Allocate a new image, and initiates with its name.
+ */
+ mctx.imagesNb++;
+ mctx.images =
+ (image *) realloc (mctx.images, mctx.imagesNb * sizeof (image));
+ if (mctx.images == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Error: cannot realloc(mctx.images), error=%d (%s)\n",
+ errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ mctx.images[mctx.imagesNb-1].name =
+ (char *) malloc (strlen(fileName) + 1);
+ if (mctx.images[mctx.imagesNb-1].name == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Error: cannot malloc(mctx.images[%d]).name, error=%d (%s)\n",
+ mctx.imagesNb-1, errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ strcpy (mctx.images[mctx.imagesNb-1].name, fileName);
+
+ /*
+ * Read the image size
+ */
+ strcpy (name, dirpath);
+ strcat (name, "/");
+ strcat (name, fileName);
+ if (stat (name, &stat_buf) < 0)
+ {
+ perror (name);
+ fprintf (stderr, "Cannot stat(%s)\n", name);
+ fflush (stderr);
+ return (-1);
+ }
+ mctx.images[mctx.imagesNb-1].length = stat_buf.st_size;
+
+ /*
+ * Open the image
+ */
+ fd = open (name, O_RDONLY);
+ if (fd < 0)
+ {
+ perror (name);
+ fprintf (stderr, "Cannot open(%s)\n", name);
+ fflush (stderr);
+ return (-1);
+ }
+
+#ifdef _WIN32
+ /*
+ * Allocate buffer and read the data :-(
+ */
+ mctx.images[mctx.imagesNb-1].data = (char *) malloc (stat_buf.st_size);
+ if (mctx.images[mctx.imagesNb-1].data == NULL)
+ {
+ fprintf (stderr, "Cannot malloc(%d) to load %s\n",
+ stat_buf.st_size, name);
+ fflush (stderr);
+ return (-1);
+ }
+ if (read (fd, mctx.images[mctx.imagesNb-1].data, stat_buf.st_size) < 0)
+ {
+ perror (name);
+ fprintf (stderr, "Cannot read(%s)\n", name);
+ fflush (stderr);
+ return (-1);
+ }
+#else /* _WIN32 */
+ /*
+ * mmap() the image
+ */
+ mctx.images[mctx.imagesNb-1].data = mmap (0, stat_buf.st_size,
+ PROT_READ, MAP_SHARED, fd, 0);
+ if (mctx.images[mctx.imagesNb-1].data == (char *)MAP_FAILED)
+ {
+ perror (name);
+ fprintf (stderr, "Cannot mmap(%s)\n", name);
+ fflush (stderr);
+ return (-1);
+ }
+#endif /* _WIN32 */
+
+ /*
+ * Close the image. The mmap() will remain available, and this
+ * close() will save file descriptors.
+ */
+ if (close (fd) < 0)
+ {
+ perror (name);
+ fprintf (stderr, "Cannot close(%s)\n", name);
+ fflush (stderr);
+ return (-1);
+ }
+ }
+#ifdef _WIN32
+ } while (FindNextFile(dirContext, &fileData) == TRUE);
+#else
+ } /* while ((direntp = readdir (dirp)) != NULL) */
+#endif
+
+ /*
+ * Close the directory
+ */
+#ifndef _WIN32
+ if (closedir (dirp) < 0)
+ {
+ perror (dirpath);
+ fprintf (stderr, "Cannot closedir(%s)\n", dirpath);
+ fflush (stderr);
+ return (-1);
+ }
+#endif
+
+ /*
+ * Normal end
+ */
+#ifdef _WIN32
+ free (findPath);
+#endif
+ return (0);
+}
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : getImage
+ PURPOSE : Add a random image to the given attribute.
+ INPUT : None.
+ OUTPUT : attribute = the attribute where the image should
+ be added.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int getImage (
+ LDAPMod *attribute)
+{
+ int imageNumber; /* The image we will select */
+ int ret; /* Return value */
+
+ /*
+ * Select the next image
+ */
+ if ((ret = ldclt_mutex_lock (&(mctx.imagesLast_mutex))) != 0) /*JLS 29-11-00*/
+ {
+ fprintf (stderr,
+ "Cannot mutex_lock(imagesLast_mutex), error=%d (%s)\n",
+ ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+ mctx.imagesLast++;
+ if (mctx.imagesLast == mctx.imagesNb)
+ mctx.imagesLast = 0;
+ imageNumber = mctx.imagesLast;
+ if ((ret = ldclt_mutex_unlock (&(mctx.imagesLast_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "Cannot mutex_unlock(imagesLast_mutex), error=%d (%s)\n",
+ ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Create the data structure required
+ */
+ attribute->mod_bvalues = (struct berval **)
+ malloc (2 * sizeof (struct berval *));
+ if (attribute->mod_bvalues == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Error: cannot malloc(attribute->mod_bvalues), error=%d (%s)\n",
+ errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ attribute->mod_bvalues[0] = (struct berval *) malloc (sizeof (struct berval));
+ if (attribute->mod_bvalues[0] == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Error: cannot malloc(attribute->mod_bvalues[0]), error=%d (%s)\n",
+ errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ attribute->mod_bvalues[1] = NULL;
+
+ /*
+ * Fill the bvalue with the image data
+ */
+ attribute->mod_bvalues[0]->bv_len = mctx.images[imageNumber].length;
+ attribute->mod_bvalues[0]->bv_val = mctx.images[imageNumber].data;
+
+ /*
+ * Normal end
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+ /* New */ /*JLS 23-03-01*/
+/* ****************************************************************************
+ FUNCTION : loadDataListFile
+ PURPOSE : Load the data list file given in argument.
+ INPUT : dlf->fname = file to process
+ OUTPUT : dlf = file read
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+loadDataListFile (
+ data_list_file *dlf)
+{
+ FILE *ifile; /* Input file */
+ char line[MAX_FILTER]; /* To read ifile */
+
+ /*
+ * Open the file
+ */
+ ifile = fopen (dlf->fname, "r");
+ if (ifile == NULL)
+ {
+ perror (dlf->fname);
+ fprintf (stderr, "Error: cannot open file \"%s\"\n", dlf->fname);
+ return (-1);
+ }
+
+ /*
+ * Count the entries.
+ * Allocate the array.
+ * Rewind the file.
+ */
+ for (dlf->strNb=0 ; fgets(line, MAX_FILTER, ifile) != NULL ; dlf->strNb++);
+ dlf->str = (char **) malloc (dlf->strNb * sizeof (char *));
+ if (fseek (ifile, 0, SEEK_SET) != 0)
+ {
+ perror (dlf->fname);
+ fprintf (stderr, "Error: cannot rewind file \"%s\"\n", dlf->fname);
+ return (-1);
+ }
+
+ /*
+ * Read all the entries from this file
+ */
+ dlf->strNb=0;
+ while (fgets(line, MAX_FILTER, ifile) != NULL)
+ {
+ if ((strlen (line) > 0) && (line[strlen(line)-1]=='\n'))
+ line[strlen(line)-1] = '\0';
+ dlf->str[dlf->strNb] = strdup (line);
+ dlf->strNb++;
+ }
+
+ /*
+ * Close the file
+ */
+ if (fclose (ifile) != 0)
+ {
+ perror (dlf->fname);
+ fprintf (stderr, "Error: cannot fclose file \"%s\"\n", dlf->fname);
+ return (-1);
+ }
+ return (0);
+}
+
+
+
+
+
+
+
+ /* New */ /*JLS 23-03-01*/
+/* ****************************************************************************
+ FUNCTION : dataListFile
+ PURPOSE : Find the given data_list_file either in the list of
+ files already loaded, either load it.
+ INPUT : fname = file name.
+ OUTPUT : None.
+ RETURN : NULL if error, else the requested file.
+ DESCRIPTION :
+ *****************************************************************************/
+data_list_file *
+dataListFile (
+ char *fname)
+{
+ data_list_file *dlf; /* To process the request */
+
+ /*
+ * Maybe we already have loaded this file ?
+ */
+ for (dlf=mctx.dlf ; dlf != NULL ; dlf=dlf->next)
+ if (!strcmp (fname, dlf->fname))
+ return (dlf);
+
+ /*
+ * Well, it looks like we should load a new file ;-)
+ * Allocate a new data structure, chain it in mctx and load the file.
+ */
+ dlf = (data_list_file *) malloc (sizeof (data_list_file));
+ dlf->next = mctx.dlf;
+ mctx.dlf = dlf;
+ dlf->fname = strdup (fname);
+ if (loadDataListFile (dlf) < 0)
+ return (NULL);
+
+ /*
+ * Loaded...
+ */
+ return (dlf);
+}
+
+
+
+
+
+
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/examples/001/add.ksh b/ldap/servers/slapd/tools/ldclt/examples/001/add.ksh
new file mode 100644
index 00000000..57359af9
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/001/add.ksh
@@ -0,0 +1,55 @@
+#!/bin/ksh -p
+#ident "ldclt @(#)add.ksh 1.2 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+# This script will add random entries in the database.
+
+. env.ksh
+
+ldclt \
+ -h $Host -p $Port \
+ -D "$UserDN" -w "$UserPassword" \
+ -e add,person,random \
+ -e imagedir=../../../data/ldclt/images \
+ -r0 -R1000000 \
+ -I68 \
+ -n50 \
+ -f cn=mrXXXXXXXXX -b o=data,$BaseDN \
+ -v -q
diff --git a/ldap/servers/slapd/tools/ldclt/examples/001/add_incr.ksh b/ldap/servers/slapd/tools/ldclt/examples/001/add_incr.ksh
new file mode 100644
index 00000000..57a141a5
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/001/add_incr.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#ident "ldclt @(#)add_incr.ksh 1.2 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+# Sequential add of entries.
+# This script will add entries from 0 to 1000000 and exit. All the
+# threads will share the same counter, i.e. each entry will be added
+# only one time.
+
+. env.ksh
+
+ldclt \
+ -h $Host -p $Port \
+ -D "$UserDN" -w "$UserPassword" \
+ -e add,person,incr,commoncounter,noloop \
+ -e imagedir=../../../data/ldclt/images \
+ -r0 -R1000000 \
+ -I68 \
+ -n5 \
+ -f cn=mrXXXXXXXXX -b o=data,$BaseDN \
+ -v -q
diff --git a/ldap/servers/slapd/tools/ldclt/examples/001/config.ksh b/ldap/servers/slapd/tools/ldclt/examples/001/config.ksh
new file mode 100644
index 00000000..96af408c
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/001/config.ksh
@@ -0,0 +1,56 @@
+#!/bin/ksh -p
+#ident "ldclt @(#)config.ksh 1.2 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+. env.ksh
+
+ldapmodify -D"$RootDN" -w"$RootPasswd" -h$Host -p$Port <<-EOD
+dn: $UserDN
+changetype: add
+objectclass: person
+sn: test user
+userpassword: $UserPassword
+
+dn: $BaseDN
+changetype: modify
+add : aci
+aci: (targetattr = "*") (version 3.0;acl "test user";allow (all)(userdn = "ldap:///$UserDN");)
+
+EOD
diff --git a/ldap/servers/slapd/tools/ldclt/examples/001/delete.ksh b/ldap/servers/slapd/tools/ldclt/examples/001/delete.ksh
new file mode 100644
index 00000000..e0bdd6ce
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/001/delete.ksh
@@ -0,0 +1,56 @@
+#!/bin/ksh -p
+#ident "ldclt @(#)delete.ksh 1.2 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+# This script will delete random entries in the database.
+
+. env.ksh
+
+ldclt \
+ -h $Host -p $Port \
+ -D "$UserDN" -w "$UserPassword" \
+ -e delete,random \
+ -e imagedir=../../../data/ldclt/images \
+ -r0 -R1000000 \
+ -I32 \
+ -n50 \
+ -f cn=mrXXXXXXXXX -b o=data,$BaseDN \
+ -v -q
+
diff --git a/ldap/servers/slapd/tools/ldclt/examples/001/env.ksh b/ldap/servers/slapd/tools/ldclt/examples/001/env.ksh
new file mode 100644
index 00000000..f6029819
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/001/env.ksh
@@ -0,0 +1,51 @@
+#ident "ldclt @(#)env.ksh 1.2 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+Host=localhost
+Port=1389
+
+BaseDN=o=test.com
+
+RootDN="cn=directory manager"
+RootPasswd=secret12
+
+UserRDN="cn=test"
+UserDN="$UserRDN,$BaseDN"
+UserPassword=testpassword
diff --git a/ldap/servers/slapd/tools/ldclt/examples/001/search.ksh b/ldap/servers/slapd/tools/ldclt/examples/001/search.ksh
new file mode 100644
index 00000000..591c2d71
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/001/search.ksh
@@ -0,0 +1,56 @@
+#!/bin/ksh -p
+#ident "ldclt @(#)search.ksh 1.2 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+# This script will search random entries in the database.
+
+. env.ksh
+
+ldclt \
+ -h $Host -p $Port \
+ -D "$UserDN" -w "$UserPassword" \
+ -e esearch,random \
+ -e imagedir=../../../data/ldclt/images \
+ -r0 -R1000000 \
+ -I32 \
+ -n200 \
+ -f cn=mrXXXXXXXXX -b o=data,$BaseDN \
+ -v -q
+
diff --git a/ldap/servers/slapd/tools/ldclt/examples/002/add.ksh b/ldap/servers/slapd/tools/ldclt/examples/002/add.ksh
new file mode 100644
index 00000000..6fd4b5fc
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/002/add.ksh
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#ident "ldclt @(#)add.ksh 1.1 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+# Add 500 entries with strings randomly selected from Lastname.txt
+#
+
+. env.ksh
+
+echo "dn: $BaseDN
+objectclass: organization
+" > /tmp/ldif01.ldif
+
+ldclt \
+ -h $Host -p $Port \
+ -D "$UserDN" -w "$UserPassword" \
+ -q -v -n10 \
+ -e object=ofile \
+ -e add,commoncounter \
+ -e -e imagedir=../../../data/ldclt/images \
+ -b $BaseDN -e rdn='cn:blob [C=RNDFROMFILE(../../../data/ldclt/names/Lastname.txt)] [D=RNDN(3;11;5)] [E=INCRNNOLOOP(1;500;3)]'
+
diff --git a/ldap/servers/slapd/tools/ldclt/examples/002/config.ksh b/ldap/servers/slapd/tools/ldclt/examples/002/config.ksh
new file mode 100644
index 00000000..bc4a5978
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/002/config.ksh
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#ident "ldclt @(#)config.ksh 1.1 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+. env.ksh
+
+ldapmodify -D"$RootDN" -w"$RootPasswd" -h$Host -p$Port <<-EOD
+dn: $UserDN
+changetype: add
+objectclass: person
+sn: test user
+userpassword: $UserPassword
+
+dn: $BaseDN
+changetype: modify
+add : aci
+aci: (targetattr = "*") (version 3.0;acl "test user";allow (all)(userdn = "ldap:///$UserDN");)
+
+EOD
+
diff --git a/ldap/servers/slapd/tools/ldclt/examples/002/env.ksh b/ldap/servers/slapd/tools/ldclt/examples/002/env.ksh
new file mode 100644
index 00000000..d2b1c477
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/002/env.ksh
@@ -0,0 +1,51 @@
+#ident "ldclt @(#)env.ksh 1.1 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+Host=localhost
+Port=1389
+
+BaseDN=o=test.com
+
+RootDN="cn=directory manager"
+RootPasswd=secret12
+
+UserRDN="cn=test"
+UserDN="$UserRDN,$BaseDN"
+UserPassword=testpassword
diff --git a/ldap/servers/slapd/tools/ldclt/examples/002/ldif01.ksh b/ldap/servers/slapd/tools/ldclt/examples/002/ldif01.ksh
new file mode 100644
index 00000000..9df09eeb
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/002/ldif01.ksh
@@ -0,0 +1,60 @@
+#!/bin/ksh -p
+#ident "ldclt @(#)ldif01.ksh 1.1 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+# Create ldif file with incremental strings from file.
+# Will create one entry for each line in Lastname.txt
+#
+
+. env.ksh
+
+echo "dn: $BaseDN
+objectclass: organization
+" > /tmp/ldif01.ldif
+
+ldclt \
+ -h $Host -p $Port \
+ -D "$UserDN" -w "$UserPassword" \
+ -q -v -n1 \
+ -e object=ofile \
+ -e append,genldif=/tmp/ldif01.ldif \
+ -e imagedir=../../../data/ldclt/images \
+ -b $BaseDN -e rdn='cn:blob [C=INCRFROMFILENOLOOP(../../../data/ldclt/names/Lastname.txt)] [D=RNDN(3;11;5)] [E=INCRNNOLOOP(1;150000;6)]'
+
diff --git a/ldap/servers/slapd/tools/ldclt/examples/002/ldif02.ksh b/ldap/servers/slapd/tools/ldclt/examples/002/ldif02.ksh
new file mode 100644
index 00000000..8d854096
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/002/ldif02.ksh
@@ -0,0 +1,60 @@
+#!/bin/ksh -p
+#ident "ldclt @(#)ldif02.ksh 1.1 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+# Create ldif file with incremental strings from file.
+# Will create 150k entries
+#
+
+. env.ksh
+
+echo "dn: $BaseDN
+objectclass: organization
+" > /tmp/ldif02.ldif
+
+ldclt \
+ -h $Host -p $Port \
+ -D "$UserDN" -w "$UserPassword" \
+ -q -v -n1 \
+ -e object=ofile \
+ -e append,genldif=/tmp/ldif02.ldif \
+ -e imagedir=../../../data/ldclt/images \
+ -b $BaseDN -e rdn='cn:blob [C=INCRFROMFILE(../../../data/ldclt/names/Lastname.txt)] [D=RNDN(3;11;5)] [E=INCRNNOLOOP(1;150000;6)]'
+
diff --git a/ldap/servers/slapd/tools/ldclt/examples/002/ldif03.ksh b/ldap/servers/slapd/tools/ldclt/examples/002/ldif03.ksh
new file mode 100644
index 00000000..acc480a7
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/002/ldif03.ksh
@@ -0,0 +1,60 @@
+#!/bin/ksh -p
+#ident "ldclt @(#)ldif03.ksh 1.1 01/04/11"
+
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2006 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+
+# Create ldif file with random strings from file.
+# Will create 150k entries
+#
+
+. env.ksh
+
+echo "dn: $BaseDN
+objectclass: organization
+" > /tmp/ldif03.ldif
+
+ldclt \
+ -h $Host -p $Port \
+ -D "$UserDN" -w "$UserPassword" \
+ -q -v -n1 \
+ -e object=ofile \
+ -e append,genldif=/tmp/ldif03.ldif \
+ -e imagedir=../../../data/ldclt/images \
+ -b $BaseDN -e rdn='cn:blob [C=RNDFROMFILE(../../../data/ldclt/names/Lastname.txt)] [D=RNDN(3;11;5)] [E=INCRNNOLOOP(1;150000;6)]'
+
diff --git a/ldap/servers/slapd/tools/ldclt/examples/002/ofile b/ldap/servers/slapd/tools/ldclt/examples/002/ofile
new file mode 100644
index 00000000..2816dcc1
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/002/ofile
@@ -0,0 +1,12 @@
+#ident "ldclt @(#)ofile 1.1 01/04/11"
+#
+objectclass: person
+sn: mr [A=RNDS(12)] final [RNDN(1;5;6)]
+description: blob [RNDN(1;5;6)] blib
+description: [A]
+description: [A=RNDFROMFILE(../../../data/ldclt/names/Firstname.txt)].[B=RNDFROMFILE(../../../data/ldclt/names/Lastname.txt)]
+description: A = [A]
+description: B = [B]
+description: C = [C]
+description: D = [D]
+description: E = [E]
diff --git a/ldap/servers/slapd/tools/ldclt/examples/README b/ldap/servers/slapd/tools/ldclt/examples/README
new file mode 100644
index 00000000..5ade39ed
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/examples/README
@@ -0,0 +1,52 @@
+#ident "ldclt @(#)README 1.1 01/04/11"
+
+ ldclt examples README
+
+Introduction
+
+ The examples provided in this directory are delivered "as it" and
+ may not be 100% accurate from the last releases of ldclt. They have
+ been tested when added to the package, but are not meant to be
+ maintained.
+
+ Compatibility or stability of the examples from one version to another
+ is not a target : examples may be removed or changed in any way at any
+ time.
+
+ To know when they were introduced or updated, please read the release
+ notes in the file ../History
+
+ Please report any comment, suggestion, error, new example, whatever
+ to ldclt@france.sun.com.
+
+001
+ This one is a very basic example of use of ldclt. It is based for
+ the configuration part, on iPlanet DS 5.0 but should work with any
+ kind of ldap server.
+
+ - env.ksh Environment and parameters.
+ - config.ksh Configure the server (create user and aci).
+ - add.ksh Add random entries.
+ - add_incr.ksh Add sequentialy numbered entries.
+ - delete.ksh Delete random entries.
+ - search.ksh Search random entries.
+
+002
+ Using the advanced feature of ldclt allowing to specify very complex
+ objects, we will generate ldif files or add/search complex objects.
+ * Use the name files delivered with ldclt.
+
+ - env.ksh Environment and parameters.
+ - config.ksh Configure the server (create user and aci, modify
+ schema).
+ - ofile Description of the object that will be created.
+ - ldif01.ksh Create ldif file with incremental strings from file,
+ one entry per line in the file Lastname.txt
+ - ldif02.ksh Create ldif file with incremental strings from file,
+ 150k entries in total.
+ - ldif03.ksh Create ldif file with random strings from file,
+ 150k entries in total.
+ - add.ksh Add 500 entries with random strings from file.
+
+
+# End of file
diff --git a/ldap/servers/slapd/tools/ldclt/ldap-private.h b/ldap/servers/slapd/tools/ldclt/ldap-private.h
new file mode 100644
index 00000000..7db687d9
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/ldap-private.h
@@ -0,0 +1,321 @@
+#ident "@(#)ldap-private.h 1.6 06/10/98 SMI"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _LDAP_PRIVATE_H
+#define _LDAP_PRIVATE_H
+
+#ifdef _REENTRANT
+#ifndef MAX_THREAD_ID
+#define MAX_THREAD_ID 500
+#endif /* MAX_THREAD_ID */
+#else /* _REENTRANT */
+#ifndef MAX_THREAD_ID
+#define MAX_THREAD_ID 1
+#endif /* MAX_THREAD_ID */
+#endif /* _REENTRANT */
+
+#define COMPAT20
+#define COMPAT30
+#if defined(COMPAT20) || defined(COMPAT30)
+#define COMPAT
+#endif
+
+#ifdef LDAP_DNS
+#define LDAP_OPT_DNS 0x00000001 /* use DN & DNS */
+#endif /* LDAP_DNS */
+
+/*
+#define DBG_LOCK1(st) printf("%d> %s %d:%s\n", _thr_self(), st, __LINE__, __FILE__);
+#define DBG_LOCK2(ld,st) printf("%d> %s ld_lockcount=%d %d:%s\n", _thr_self(), st, (ld)->ld_lockcount, __LINE__, __FILE__);
+*/
+#define DBG_LOCK1(st)
+#define DBG_LOCK2(ld,st)
+
+#define LOCK_RESPONSE(ld) \
+ if ((ld)->ld_response_lockthread != _thr_self()) { \
+ DBG_LOCK1("waiting for response lock") \
+ pthread_mutex_lock( &((ld)->ld_response_mutex) ); \
+ DBG_LOCK1("got response lock") \
+ (ld)->ld_response_lockthread = _thr_self(); \
+ } else { \
+ (ld)->ld_response_lockcount++; \
+ DBG_LOCK2(ld, "fake ldap lock") \
+ }
+
+#define UNLOCK_RESPONSE(ld) \
+ if ((ld)->ld_response_lockcount==0) { \
+ (ld)->ld_response_lockthread = 0; \
+ pthread_mutex_unlock( &((ld)->ld_response_mutex) ); \
+ DBG_LOCK1("freed response lock") \
+ } else { \
+ (ld)->ld_response_lockcount--; \
+ DBG_LOCK2(ld, "fake ldap unlock") \
+ }
+
+#define LOCK_LDAP(ld) \
+ if ((ld)->ld_lockthread != _thr_self()) { \
+ DBG_LOCK1("waiting for ldap lock") \
+ pthread_mutex_lock( &((ld)->ld_ldap_mutex) ); \
+ DBG_LOCK1("got ldap lock") \
+ (ld)->ld_lockthread = _thr_self(); \
+ } else { \
+ (ld)->ld_lockcount++; \
+ DBG_LOCK2(ld, "fake ldap lock") \
+ }
+
+#define UNLOCK_LDAP(ld) \
+ if ((ld)->ld_lockcount==0) { \
+ (ld)->ld_lockthread = 0; \
+ pthread_mutex_unlock( &((ld)->ld_ldap_mutex) ); \
+ DBG_LOCK1("freed ldap lock") \
+ } else { \
+ (ld)->ld_lockcount--; \
+ DBG_LOCK2(ld, "fake ldap unlock") \
+ }
+
+#define LOCK_POLL(ld) pthread_mutex_lock( &ld->ld_poll_mutex )
+#define UNLOCK_POLL(ld) pthread_mutex_unlock( &ld->ld_poll_mutex )
+
+/*
+ * This structure represents both ldap messages and ldap responses.
+ * These are really the same, except in the case of search responses,
+ * where a response has multiple messages.
+ */
+typedef struct ldapmsg {
+ int lm_msgid; /* the message id */
+ int lm_msgtype; /* the message type */
+ BerElement *lm_ber; /* the ber encoded message contents */
+ struct ldapmsg *lm_chain; /* for search - next msg in the resp */
+ struct ldapmsg *lm_next; /* next response */
+ unsigned long lm_time; /* used to maintain cache */
+} _struct_LDAPMessage;
+
+typedef struct ldap_filt_list {
+ char *lfl_tag;
+ char *lfl_pattern;
+ char *lfl_delims;
+ LDAPFiltInfo *lfl_ilist;
+ struct ldap_filt_list *lfl_next;
+} _struct_FiltList;
+
+typedef struct ldap_filt_desc {
+ LDAPFiltList *lfd_filtlist;
+ LDAPFiltInfo *lfd_curfip;
+ LDAPFiltInfo lfd_retfi;
+ char lfd_filter[ LDAP_FILT_MAXSIZ ];
+ char *lfd_curval;
+ char *lfd_curvalcopy;
+ char **lfd_curvalwords;
+ char *lfd_filtprefix;
+ char *lfd_filtsuffix;
+} _struct_FiltDesc;
+
+/*
+ * structure for tracking LDAP server host, ports, DNs, etc.
+ */
+typedef struct ldap_server {
+ char *lsrv_host;
+ char *lsrv_dn; /* if NULL, use default */
+ int lsrv_port;
+ struct ldap_server *lsrv_next;
+} LDAPServer;
+
+
+/*
+ * structure for representing an LDAP server connection
+ */
+typedef struct ldap_conn {
+ Sockbuf *lconn_sb;
+ int lconn_refcnt;
+ unsigned long lconn_lastused; /* time */
+ int lconn_status;
+#define LDAP_CONNST_NEEDSOCKET 1
+#define LDAP_CONNST_CONNECTING 2
+#define LDAP_CONNST_CONNECTED 3
+ LDAPServer *lconn_server;
+ char *lconn_krbinstance;
+ struct ldap_conn *lconn_next;
+} LDAPConn;
+
+/*
+ * Structure used to keep track of search references
+ */
+typedef struct ldap_reference {
+ char ** lref_refs;
+ struct ldap_reference *lref_next;
+} LDAPRef;
+
+/*
+ * structure used to track outstanding requests
+ */
+typedef struct ldapreq {
+ int lr_msgid; /* the message id */
+ int lr_status; /* status of request */
+#define LDAP_REQST_INPROGRESS 1
+#define LDAP_REQST_CHASINGREFS 2
+#define LDAP_REQST_NOTCONNECTED 3
+#define LDAP_REQST_WRITING 4
+ int lr_outrefcnt; /* count of outstanding referrals */
+ int lr_origid; /* original request's message id */
+ int lr_parentcnt; /* count of parent requests */
+ int lr_res_msgtype; /* result message type */
+ int lr_res_errno; /* result LDAP errno */
+ char *lr_res_error; /* result error string */
+ char *lr_res_matched;/* result matched DN string */
+ BerElement *lr_ber; /* ber encoded request contents */
+ LDAPConn *lr_conn; /* connection used to send request */
+ LDAPRef *lr_references;
+ char **lr_ref_followed; /* referral being followed */
+ char **lr_ref_unfollowed; /* Not being followed */
+ char **lr_ref_tofollow; /* referral to follow if the one being
+ followed fails. */
+ struct ldapreq *lr_parent; /* request that spawned this referral */
+ struct ldapreq *lr_refnext; /* next referral spawned */
+ struct ldapreq *lr_prev; /* previous request */
+ struct ldapreq *lr_next; /* next request */
+} LDAPRequest;
+
+/*
+ * structure for client cache
+ */
+#define LDAP_CACHE_BUCKETS 31 /* cache hash table size */
+typedef struct ldapcache {
+ LDAPMessage *lc_buckets[LDAP_CACHE_BUCKETS];/* hash table */
+ LDAPMessage *lc_requests; /* unfulfilled reqs */
+ long lc_timeout; /* request timeout */
+ long lc_maxmem; /* memory to use */
+ long lc_memused; /* memory in use */
+ int lc_enabled; /* enabled? */
+ unsigned long lc_options; /* options */
+#define LDAP_CACHE_OPT_CACHENOERRS 0x00000001
+#define LDAP_CACHE_OPT_CACHEALLERRS 0x00000002
+} LDAPCache;
+#define NULLLDCACHE ((LDAPCache *)NULL)
+
+/*
+ * structure representing an ldap connection
+ */
+typedef struct ldap {
+ Sockbuf ld_sb; /* socket descriptor & buffer */
+ char *ld_host;
+ int ld_version;
+ char ld_lberoptions;
+ int ld_deref;
+
+ int ld_timelimit;
+ int ld_sizelimit;
+
+ LDAPFiltDesc *ld_filtd; /* from getfilter for ufn searches */
+ char *ld_ufnprefix; /* for incomplete ufn's */
+
+ int ld_errno[MAX_THREAD_ID]; /* thread-specific */
+#define ld_errno ld_errno[ldap_thr_index()]
+ char *ld_error[MAX_THREAD_ID]; /* thread-specific */
+#define ld_error ld_error[ldap_thr_index()]
+ char *ld_matched[MAX_THREAD_ID]; /* thread-specific */
+#define ld_matched ld_matched[ldap_thr_index()]
+ char **ld_referrals[MAX_THREAD_ID]; /* thread-specific */
+#define ld_referrals ld_referrals[ldap_thr_index()]
+ LDAPControl **ld_ret_ctrls[MAX_THREAD_ID]; /* thread-specific */
+#define ld_ret_ctrls ld_ret_ctrls[ldap_thr_index()]
+ int ld_msgid;
+
+ int ld_follow_referral; /* flag set to true if lib follow referrals */
+ LDAPRequest *ld_requests; /* list of outstanding requests -- referrals*/
+
+ LDAPMessage *ld_responses; /* list of outstanding responses */
+ int *ld_abandoned; /* array of abandoned requests */
+
+ pthread_mutex_t ld_response_mutex; /* mutex for responses part of structure */
+ pthread_t ld_response_lockthread; /* thread which currently holds the response lock */
+ int ld_response_lockcount; /* response lock depth */
+
+ char *ld_attrbuffer[MAX_THREAD_ID];
+#define ld_attrbuffer ld_attrbuffer[ldap_thr_index()]
+ LDAPCache *ld_cache; /* non-null if cache is initialized */
+ char *ld_cldapdn; /* DN used in connectionless search */
+
+ /* it is OK to change these next four values directly */
+ int ld_cldaptries; /* connectionless search retry count */
+ int ld_cldaptimeout;/* time between retries */
+ int ld_refhoplimit; /* limit on referral nesting */
+ int ld_restart; /* Decide if continue after interruption */
+#ifdef LDAP_SSL
+ int ld_use_ssl;
+ char *ld_ssl_key;
+#endif
+ unsigned long ld_options; /* boolean options */
+
+ /* do not mess with the rest though */
+ char *ld_defhost; /* full name of default server */
+ int ld_defport; /* port of default server */
+ BERTranslateProc ld_lber_encode_translate_proc;
+ BERTranslateProc ld_lber_decode_translate_proc;
+
+ LDAPConn *ld_defconn; /* default connection */
+ LDAPConn *ld_conns; /* list of server connections */
+ void *ld_selectinfo; /* platform specifics for select */
+
+ LDAP_REBIND_FUNCTION *ld_rebindproc;
+ void *ld_rebind_extra_arg;
+/* int (*ld_rebindproc)( struct ldap *ld, char **dnp, */
+/* char **passwdp, int *authmethodp, int freeit ); */
+ /* routine to get info needed for re-bind */
+
+ pthread_mutex_t ld_ldap_mutex; /* mutex for thread dependent part of struct */
+ pthread_t ld_lockthread; /* thread which currently holds the lock */
+ int ld_lockcount; /* lock depth */
+ pthread_mutex_t ld_poll_mutex; /* a seperate lock for polling */
+
+ LDAPControl **ld_srvctrls; /* Controls used by ldap and server */
+ LDAPControl **ld_cltctrls; /* Client side controls */
+
+/* KE: Lists of unsolicited notifications */
+ LDAPMessage *ld_notifs[MAX_THREAD_ID];
+#define ld_notifs ld_notifs[ldap_thr_index()]
+} _struct_LDAP;
+
+/*
+ * handy macro to check whether LDAP struct is set up for CLDAP or not
+ */
+#define LDAP_IS_CLDAP( ld ) ( ld->ld_sb.sb_naddr > 0 )
+
+
+#endif /* _LDAP_PRIVATE_H */
diff --git a/ldap/servers/slapd/tools/ldclt/ldapfct.c b/ldap/servers/slapd/tools/ldclt/ldapfct.c
new file mode 100644
index 00000000..213569d2
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/ldapfct.c
@@ -0,0 +1,3506 @@
+#ident "ldclt @(#)ldapfct.c 1.68 01/05/04"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : ldapfct.c
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 04 December 1998
+ DESCRIPTION :
+ This file contains the ldap part of this tool.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+04/12/98 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+09/12/98 | JL Schwing | 1.2 : Forget to free ldap returned data.
+---------+--------------+------------------------------------------------------
+10/12/98 | JL Schwing | 1.3 : Add nb of errors statistics.
+---------+--------------+------------------------------------------------------
+10/12/98 | JL Schwing | 1.4 : Implement asynchronous mode.
+---------+--------------+------------------------------------------------------
+11/12/98 | JL Schwing | 1.5 : fflush(stdout) after each printf.
+---------+--------------+------------------------------------------------------
+14/12/98 | JL Schwing | 1.6 : Implement "-e close".
+ | New function my_ldap_err2string() to prevent crashes.
+---------+--------------+------------------------------------------------------
+16/12/98 | JL Schwing | 1.7 : Implement "-e add" and "-e delete".
+ | Create separate functions for connection operations.
+---------+--------------+------------------------------------------------------
+23/12/98 | JL Schwing | 1.8 : Factorise the doXxxx() functions.
+ | Fix SIGSEGV in ldap_parse_result().
+ | Implement result decoding in doAddEntry().
+---------+--------------+------------------------------------------------------
+24/12/98 | JL Schwing | 1.9 : Bug fix - should support no message in async.
+ | Bug fix - forget to check mctx.asyncMax !!!
+ | Modify the getPending() algorythm to empty the queue
+ | (if possible).
+---------+--------------+------------------------------------------------------
+29/12/98 | JL Schwing | 1.10: Implement -Q.
+ | Bug fix mode -q when asynchronous.
+---------+--------------+------------------------------------------------------
+11/01/99 | JL Schwing | 1.11: Implement "-e emailPerson".
+ | Bug fix - bad building of rdn in buildNewEntry().
+---------+--------------+------------------------------------------------------
+13/01/99 | JL Schwing | 1.12: Implement "-e string".
+---------+--------------+------------------------------------------------------
+14/01/99 | JL Schwing | 1.13: Implement "-s <scope>".
+---------+--------------+------------------------------------------------------
+15/01/99 | JL Schwing | 1.14: Create automatically the missing nodes.
+---------+--------------+------------------------------------------------------
+18/01/99 | JL Schwing | 1.15: Implements "-e randombase".
+---------+--------------+------------------------------------------------------
+18/01/99 | JL Schwing | 1.16: Implements "-e v2".
+---------+--------------+------------------------------------------------------
+20/01/99 | JL Schwing | 1.17: Bug fix - should'nt fail in createMissingNodes()
+ | if error 68 (Already exists).
+ | Increment counter for intermediate node(s) too.
+---------+--------------+------------------------------------------------------
+23/01/99 | JL Schwing | 1.18: Improve traces.
+ | Bug fix - remove leading spaces from rdn.
+---------+--------------+------------------------------------------------------
+26/01/99 | JL Schwing | 1.19: Implement "-e noloop".
+---------+--------------+------------------------------------------------------
+01/02/99 | JL Schwing | 1.20: Create *all* the nodes in createMissingNodes()
+---------+--------------+------------------------------------------------------
+03/02/99 | JL Schwing | 1.21: Create the leaf entry after createMissingNodes()
+---------+--------------+------------------------------------------------------
+26/02/99 | JL Schwing | 1.22: Detect "\," in createMissingNodes().
+---------+--------------+------------------------------------------------------
+04/05/99 | JL Schwing | 1.23: Add call to opAdd().
+---------+--------------+------------------------------------------------------
+04/05/99 | JL Schwing | 1.24: Forget some calls to opAdd().
+---------+--------------+------------------------------------------------------
+04/05/99 | JL Schwing | 1.25: Too many calls to opAdd() !!!
+---------+--------------+------------------------------------------------------
+19/05/99 | JL Schwing | 1.27: Implements doRename().
+ | Do not print messages about intermediate nodes created
+ | in quiet mode.
+ | MOdify getPending()to support rename operations.
+---------+--------------+------------------------------------------------------
+06/03/00 | JL Schwing | 1.28: Test malloc() return value.
+---------+--------------+------------------------------------------------------
+06/03/00 | A. Hornik | 1.29: Bug fix - SEGV if no passwd provided.
+---------+--------------+------------------------------------------------------
+03/08/00 | JL Schwing | 1.30: Improve errors decoding. This improvement
+ | is to retrieve the additional error string that
+ | is returned by the server. This is implemented for
+ | the asynchronous operations and for the synchronous
+ | search only, because for the other synchronous ops
+ | we should use ldap_get_lderrno() that is not
+ | implement in Solaris's libldap.
+ | Add new function printErrorFromLdap().
+---------+--------------+------------------------------------------------------
+03/08/00 | JL Schwing | 1.31: Fix SIGSEGV in printErrorFromLdap().
+---------+--------------+------------------------------------------------------
+11/08/00 | JL Schwing | 1.32: Improve error decoding.
+---------+--------------+------------------------------------------------------
+18/08/00 | JL Schwing | 1.33: Print begin and end dates.
+---------+--------------+------------------------------------------------------
+25/08/00 | JL Schwing | 1.34: Implement consistent exit status...
+---------+--------------+------------------------------------------------------
+11/10/00 | B Kolics | 1.35: Added SSL connection initialization to
+ | | connectToServer, createMissingNodes
+---------+--------------+------------------------------------------------------
+26/10/00 | B Kolics | 1.36: Moved SSL client initialization to basicInit
+-------------------------------------------------------------------------------
+07/11/00 | JL Schwing | 1.37: Implements dynamic load of ssl-related
+ | functions.
+---------+--------------+------------------------------------------------------
+07/11/00 | JL Schwing | 1.38: Implement "-e inetOrgPerson".
+ | Add new error message in createMissingNodes().
+---------+--------------+------------------------------------------------------
+13/11/00 | JL Schwing | 1.39: Add new options "-e randombaselow and ...high"
+---------+--------------+------------------------------------------------------
+14/11/00 | JL Schwing | 1.40: Will now use utils.c functions.
+---------+--------------+------------------------------------------------------
+14/11/00 | JL Schwing | 1.41 : Port on AIX.
+---------+--------------+------------------------------------------------------
+21/11/00 | JL Schwing | 1.42: Implement "-e attreplace=name:mask"
+ | Add new function buildNewModAttrib().
+---------+--------------+------------------------------------------------------
+24/11/00 | B Kolics | 1.43: Added SSL client authentication
+---------+--------------+------------------------------------------------------
+29/11/00 | JL Schwing | 1.44: Port on NT 4.
+---------+--------------+------------------------------------------------------
+01/12/00 | JL Schwing | 1.45: Port on Linux.
+---------+--------------+------------------------------------------------------
+14/12/00 | JL Schwing | 1.46: Add more trace in VERY_VERBOSE mode.
+ | Fix some trace messages.
+ | Add new function dnFromMessage().
+---------+--------------+------------------------------------------------------
+15/12/00 | JL Schwing | 1.47: Implement "-e counteach".
+ | Implement "-e withnewparent" - cf bug Scopus 526148
+---------+--------------+------------------------------------------------------
+18/12/00 | JL Schwing | 1.48: Add new exit status EXIT_RESSOURCE.
+---------+--------------+------------------------------------------------------
+18/12/00 | JL Schwing | 1.49: Bug fix when -e rename,counteach
+---------+--------------+------------------------------------------------------
+18/12/00 | JL Schwing | 1.50: Bug fix - support errors the user wants to
+ | ignore in connectToServer().
+ | Also a bug fix in tttctx->exitStatus management.
+---------+--------------+------------------------------------------------------
+03/01/01 | JL Schwing | 1.51: Implement "-e attrsonly=value".
+---------+--------------+------------------------------------------------------
+05/01/01 | JL Schwing | 1.52: Implement "-e randombinddn" and associated
+ | "-e randombinddnlow/high"
+ | Add new function buildNewBindDN().
+---------+--------------+------------------------------------------------------
+05/03/01 | JL Schwing | 1.53: Fix the "anonymous" mode.
+---------+--------------+------------------------------------------------------
+08/03/01 | JL Schwing | 1.54: Change referrals handling.
+ | Add new functions refRebindProc() and referralSetup().
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.55: Implement "-e commoncounter"
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.56: Lint cleanup.
+ | Port on _WIN32.
+---------+--------------+------------------------------------------------------
+15/03/01 | JL Schwing | 1.57: Implement "-e attrlist=name:name:name"
+ | Implement "-e randomattrlist=name:name:name"
+---------+--------------+------------------------------------------------------
+19/03/01 | JL Schwing | 1.58: Implement "-e object=filename".
+ | Implement "-e genldif=filename".
+ | Add new functions buildVersatileObject() doGenldif()
+---------+--------------+------------------------------------------------------
+21/03/01 | JL Schwing | 1.59: Implements variables in "-e object=filename"
+---------+--------------+------------------------------------------------------
+23/03/01 | JL Schwing | 1.60: Implements data file list support in variants.
+ | Implements "-e rdn=value".
+---------+--------------+------------------------------------------------------
+28/03/01 | JL Schwing | 1.61: Fix traces.
+---------+--------------+------------------------------------------------------
+28/03/01 | JL Schwing | 1.62: Support -e commoncounter with -e rdn/object
+ | Increment counters in doGenldif().
+ | Perfs tunning in doGenldif().
+---------+--------------+------------------------------------------------------
+02/04/01 | JL Schwing | 1.63: Bug fix : large files support for -e genldif.
+ | Add new function ldclt_write_genldif().
+---------+--------------+------------------------------------------------------
+11/04/01 | JL Schwing | 1.64: Implement [INCRFROMFILE<NOLOOP>(myfile)]
+---------+--------------+------------------------------------------------------
+11/04/01 | JL Schwing | 1.65: Bug fix - should not crash if variable not set.
+---------+--------------+------------------------------------------------------
+03/05/01 | JL Schwing | 1.66: Implement -e randombinddnfromfile=filename.
+ | Add new function getBindAndPasswdFromFile().
+---------+--------------+------------------------------------------------------
+04/05/01 | JL Schwing | 1.67: Implement -e bindonly.
+ | Add new function doBindOnly().
+---------+--------------+------------------------------------------------------
+04/05/01 | JL Schwing | 1.68: Lint cleanup.
+---------+--------------+------------------------------------------------------
+*/
+
+
+#include <stdio.h> /* printf(), etc... */
+#include <string.h> /* strcpy(), etc... */
+#include <errno.h> /* errno, etc... */
+#include <stdlib.h> /* malloc(), etc... */
+#include <lber.h> /* ldap C-API BER declarations */
+#include <ldap.h> /* ldap C-API declarations */
+#ifdef LDAP_H_FROM_QA_WKA
+#include <proto-ldap.h> /* ldap C-API prototypes */
+#endif
+#ifndef _WIN32 /*JLS 29-11-00*/
+#include <unistd.h> /* close(), etc... */
+#include <pthread.h> /* pthreads(), etc... */
+#endif /*JLS 29-11-00*/
+
+#include "port.h" /* Portability definitions */ /*JLS 29-11-00*/
+#include "ldclt.h" /* This tool's include file */
+#include "utils.h" /* Utilities functions */ /*JLS 14-11-00*/
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : my_ldap_err2string
+ PURPOSE : This function is targetted to encapsulate the standard
+ function ldap_err2string(), that sometimes returns
+ a NULL pointer and thus crashes the appicaliton :-(
+ INPUT : err = error to decode
+ OUTPUT : None.
+ RETURN : A string that describes the error.
+ DESCRIPTION :
+ *****************************************************************************/
+char *
+my_ldap_err2string (
+ int err)
+{
+ if (ldap_err2string (err) == NULL)
+ return ("ldap_err2string() returns a NULL pointer !!!");
+ else
+ return (ldap_err2string(err));
+}
+
+
+
+
+
+
+
+ /* New function */ /*JLS 14-12-00*/
+/* ****************************************************************************
+ FUNCTION : dnFromMessage
+ PURPOSE : Extract the matcheddnp value from an LDAP (error)
+ message.
+ INPUT : tttctx = thread context.
+ res = result to parse
+ OUTPUT : None.
+ RETURN : The matcheddnp or an error string.
+ DESCRIPTION :
+ *****************************************************************************/
+char *
+dnFromMessage (
+ thread_context *tttctx,
+ LDAPMessage *res)
+{
+ static char *notFound = "*** not found by ldclt ***";
+ int ret;
+ int errcodep;
+
+ /*
+ * Maybe a previous call to free...
+ */
+ if (tttctx->matcheddnp)
+ ldap_memfree (tttctx->matcheddnp);
+
+ /*
+ * Get the requested information
+ */
+ ret = ldap_parse_result (tttctx->ldapCtx, res, &errcodep,
+ &(tttctx->matcheddnp), NULL, NULL, NULL, 0);
+ switch (ret)
+ {
+ case LDAP_SUCCESS:
+ case LDAP_MORE_RESULTS_TO_RETURN:
+ return (tttctx->matcheddnp);
+ case LDAP_NO_RESULTS_RETURNED:
+ case LDAP_DECODING_ERROR:
+ case LDAP_PARAM_ERROR:
+ case LDAP_NO_MEMORY:
+ default:
+ tttctx->matcheddnp = NULL;
+ printf ("ldclt[%d]: T%03d: Cannot ldap_parse_result(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ return (notFound);
+ }
+}
+
+ /* New function */ /*JLS 03-05-01*/
+/* ****************************************************************************
+ FUNCTION : getBindAndPasswdFromFile
+ PURPOSE : Get the new bindDN and passwd to use from a dlf.
+ INPUT : tttctx = this thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+getBindAndPasswdFromFile (
+ thread_context *tttctx)
+{
+ int num; /* Temp. number */
+ int i; /* For the loops */
+
+ /*
+ * The bind DN is before the first '\t'
+ */
+ num = (lrand48() % mctx.rndBindDlf->strNb);
+ for (i=0 ; mctx.rndBindDlf->str[num][i]!='\0' &&
+ mctx.rndBindDlf->str[num][i]!='\t' ; i++);
+ if (mctx.rndBindDlf->str[num][i] == '\0')
+ {
+ printf ("ldclt[%d]: %s: No bind DN find line %d of %s\n",
+ mctx.pid, tttctx->thrdId, num+1, mctx.rndBindFname);
+ return (-1);
+ }
+ strncpy (tttctx->bufBindDN, mctx.rndBindDlf->str[num], i);
+ tttctx->bufBindDN[i] = '\0';
+
+ /*
+ * Skip the '\t' to find the password.
+ * The password is from this place up to the end of the line.
+ */
+ while (mctx.rndBindDlf->str[num][i]!='\0' &&
+ mctx.rndBindDlf->str[num][i]=='\t')
+ i++;
+ if (mctx.rndBindDlf->str[num][i] == '\0')
+ {
+ printf ("ldclt[%d]: %s: No password find line %d of %s\n",
+ mctx.pid, tttctx->thrdId, num+1, mctx.rndBindFname);
+ return (-1);
+ }
+ strcpy (tttctx->bufPasswd, &(mctx.rndBindDlf->str[num][i]));
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+ /* New function */ /*JLS 05-01-01*/
+/* ****************************************************************************
+ FUNCTION : buildNewBindDN
+ PURPOSE : Purpose of the fct
+ INPUT : tttctx = this thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+buildNewBindDN (
+ thread_context *tttctx)
+{
+ /*
+ * Maybe we should get the bindDN and passwd from a file ?
+ */
+ if (mctx.mod2 & M2_RNDBINDFILE)
+ return (getBindAndPasswdFromFile (tttctx));
+
+ /*
+ * If we shouldn't operate with a variable bind DN, then the buffers
+ * are already initiated with the fixed values...
+ */
+ if (!(mctx.mode & RANDOM_BINDDN))
+ return (0);
+
+ /*
+ * Generate the random value we will use for both the bind DN
+ * and the password.
+ */
+ if (mctx.mode & STRING)
+ (void) randomString (tttctx, mctx.bindDNNbDigit);
+ else
+ rnd (tttctx->buf2, mctx.bindDNLow, mctx.bindDNHigh, mctx.bindDNNbDigit);
+
+ /*
+ * First, randomize the bind DN.
+ */
+ strncpy (&(tttctx->bufBindDN[tttctx->startBindDN]), tttctx->buf2,
+ mctx.bindDNNbDigit);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: bind DN=\"%s\"\n",
+ mctx.pid, tttctx->thrdNum, tttctx->bufBindDN);
+
+ /*
+ * Second, randomize the bind password.
+ */
+ strncpy (&(tttctx->bufPasswd[tttctx->startPasswd]), tttctx->buf2,
+ mctx.passwdNbDigit);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: bind passwd=\"%s\"\n",
+ mctx.pid, tttctx->thrdNum, tttctx->bufPasswd);
+
+ /*
+ * No problem found.
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+ /* New function */ /*JLS 08-03-01*/
+/* ****************************************************************************
+ FUNCTION : refRebindProc
+ PURPOSE : This function is intended to perform the rebind when
+ a referral requires it.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : Always LDAP_SUCCESS for the moment...
+ DESCRIPTION :
+ *****************************************************************************/
+int
+refRebindProc (
+ LDAP *ldapCtx,
+ char **dnp,
+ char **passwdp,
+ int *authmethodp,
+ int freeit,
+ void *arg)
+{
+ thread_context *tttctx;
+
+ tttctx = (thread_context *)arg;
+
+ /*
+ * We will assume here that the same DN and passwd will be used to
+ * bind to the referred server, so we will just get the values used
+ * previously from the thread's context.
+ */
+ *dnp = tttctx->bufBindDN;
+ *passwdp = tttctx->bufPasswd;
+ *authmethodp = LDAP_AUTH_SIMPLE;
+
+ /*
+ * What should we do with the "freeit" argument ? I do not have any
+ * memory to free, so let's just ignore it.
+ */
+
+ return (LDAP_SUCCESS);
+}
+
+
+
+
+
+
+
+ /* New function */ /*JLS 08-03-01*/
+/* ****************************************************************************
+ FUNCTION : referralSetup
+ PURPOSE : Initiates referral features. This function is called
+ once after the ldap_init().
+ INPUT : tttctx = this thread's thread_context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+referralSetup (
+ thread_context *tttctx)
+{
+ int ret; /* Return value */
+ void *ref; /* Referral settings */
+
+ /*
+ * Set the referral options...
+ */
+ if (mctx.referral == REFERRAL_OFF)
+ ref = LDAP_OPT_OFF;
+ else
+ ref = LDAP_OPT_ON;
+
+ ret = ldap_set_option (tttctx->ldapCtx, LDAP_OPT_REFERRALS, &ref);
+ if (ret < 0)
+ {
+ printf ("ldclt[%d]: %s: Cannot ldap_set_option(LDAP_OPT_REFERRALS)\n",
+ mctx.pid, tttctx->thrdId);
+ fflush (stdout);
+ return (-1);
+ }
+
+ /*
+ * Maybe the user would like to have an authenticated referral rebind ?
+ * Note : at 09-03-01 ldap_set_rebind_proc() is a void return function
+ * Note : cannot compile on _WIN32 without the cast... even if I cast to
+ * the same thing !!!!
+ */
+ if (mctx.referral == REFERRAL_REBIND)
+#ifdef _WIN32 /*JLS 14-03-01*/
+ ldap_set_rebind_proc (tttctx->ldapCtx, /*JLS 14-03-01*/
+ (LDAP_REBINDPROC_CALLBACK *)refRebindProc, /*JLS 14-03-01*/
+ (void *)tttctx); /*JLS 14-03-01*/
+#else /*JLS 14-03-01*/
+ ldap_set_rebind_proc (tttctx->ldapCtx, refRebindProc, (void *)tttctx);
+#endif /*JLS 14-03-01*/
+
+ /*
+ * Normal end
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : connectToServer
+ PURPOSE : Realise the connection to the server.
+ If requested by the user, it also realize the
+ disconnection prior to connect.
+ INPUT : tttctx = this thread's thread_context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+connectToServer (
+ thread_context *tttctx)
+{
+ int ret; /* Return value */
+ int fd; /* LDAP cnx's fd */
+ int v2v3; /* LDAP version used */
+
+ /*
+ * Maybe close the connection ?
+ * We will do this *here* to keep the cnx the longest time open.
+ */
+ if ((mctx.mode & BIND_EACH_OPER) && (tttctx->ldapCtx != NULL))
+ {
+ /*
+ * Maybe the user want the connection to be *closed* rather than
+ * being kindly unbinded ?
+ */
+ if (mctx.mode & CLOSE_FD)
+ {
+ /*
+ * Get the corresponding fd
+ */
+#ifdef WORKAROUND_4197228
+ if (getFdFromLdapSession (tttctx->ldapCtx, &fd) < 0)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot extract fd from ldap session\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ return (-1);
+ }
+#else
+ ret = ldap_get_option (tttctx->ldapCtx, LDAP_OPT_DESC, &fd);
+ if (ret < 0)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_get_option(LDAP_OPT_DESC)\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ return (-1);
+ }
+#endif
+#ifdef TRACE_FD_GET_OPTION_BUG
+ printf ("ldclt[%d]: T%03d: fd=%d\n", mctx.pid, tttctx->thrdNum, fd);
+#endif
+ if (close (fd) < 0)
+ {
+ perror ("ldctx");
+ printf ("ldclt[%d]: T%03d: cannot close(fd=%d), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, fd, errno, strerror (errno));
+ return (-1);
+ }
+ }
+
+ /*
+ * Ok, anyway, we must ldap_unbind() to release our contextes
+ * at the client side, otherwise this process will rocket through
+ * the ceiling.
+ * But don't be afraid, the UNBIND operation never reach the
+ * server that will only see a suddent socket disconnection.
+ */
+ ret = ldap_unbind (tttctx->ldapCtx);
+ if (ret != LDAP_SUCCESS)
+ {
+ fprintf (stderr, "ldclt[%d]: T%03d: cannot ldap_unbind(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret,strerror (ret));
+ fflush (stderr);
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ return (-1);
+ }
+ tttctx->ldapCtx = NULL;
+ }
+
+ /*
+ * Maybe create the LDAP context ?
+ */
+ if (tttctx->ldapCtx == NULL)
+ {
+#ifdef LDCLTSSL
+ /*
+ * SSL is enabled ?
+ */
+ if (mctx.mode & SSL)
+ {
+ /*
+ * LDAP session initialization in SSL mode
+ * added by: B Kolics (11/10/00)
+ */
+ tttctx->ldapCtx = (LDAP *)(*(mctx.sslctx.ldapssl_init)) /*JLS 07-11-00*/
+ (mctx.hostname, mctx.port, 1);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: After ldapssl_init (%s, %d), ldapCtx=0x%08x\n",
+ mctx.pid, tttctx->thrdNum, mctx.hostname, mctx.port,
+ (unsigned int)tttctx->ldapCtx);
+ if (tttctx->ldapCtx == NULL)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldapssl_init (%s, %d), errno=%d\n",
+ mctx.pid, tttctx->thrdNum, mctx.hostname, mctx.port, errno);
+ fflush (stdout);
+ return (-1);
+ }
+ /*
+ * Client authentication is used ?
+ */
+ if (mctx.mode & CLTAUTH)
+ {
+ ret = (int)(*(mctx.sslctx.ldapssl_enable_clientauth))
+ (tttctx->ldapCtx, "", mctx.keydbpin, mctx.cltcertname);
+ if (mctx.mode & VERY_VERBOSE)
+ printf
+ ("ldclt[%d]: T%03d: After ldapssl_enable_clientauth (ldapCtx=0x%08x, %s, %s)",
+ mctx.pid, tttctx->thrdNum, (unsigned int)tttctx->ldapCtx, mctx.keydbpin,
+ mctx.cltcertname);
+ if (ret < 0)
+ {
+ printf
+ ("ldclt[%d]: T%03d: Cannot ldapssl_enable_clientauth (ldapCtx=0x%08x, %s, %s)",
+ mctx.pid, tttctx->thrdNum, (unsigned int)tttctx->ldapCtx, mctx.keydbpin,
+ mctx.cltcertname);
+ ldap_perror(tttctx->ldapCtx, "ldapssl_enable_clientauth");
+ fflush (stdout);
+ return (-1);
+ }
+ }
+ } else {
+#endif
+ /*
+ * connection initialization in normal, unencrypted mode
+ */
+ tttctx->ldapCtx = ldap_init (mctx.hostname, mctx.port);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: After ldap_init (%s, %d), ldapCtx=0x%08x\n",
+ mctx.pid, tttctx->thrdNum, mctx.hostname, mctx.port,
+ (unsigned int)tttctx->ldapCtx);
+ if (tttctx->ldapCtx == NULL)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_init (%s, %d), errno=%d\n",
+ mctx.pid, tttctx->thrdNum, mctx.hostname, mctx.port, errno);
+ fflush (stdout);
+ return (-1);
+ }
+#ifdef LDCLTSSL
+ }
+#endif
+
+ if (mctx.mode & LDAP_V2)
+ v2v3 = LDAP_VERSION2;
+ else
+ v2v3 = LDAP_VERSION3;
+
+ ret = ldap_set_option (tttctx->ldapCtx, LDAP_OPT_PROTOCOL_VERSION, &v2v3);
+ if (ret < 0)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_set_option(LDAP_OPT_PROTOCOL_VERSION)\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ return (-1);
+ }
+
+ /*
+ * Set the referral options...
+ */
+ if (referralSetup (tttctx) < 0)
+ return (-1);
+ }
+
+ /*
+ * Let's save some time here... If no bindDN is provided, the tool is
+ * working in anonymous mode, i.e. we may consider it is always
+ * binded.
+ * NOTE : maybe some cleanup is needed with the tests mctx.bindDN!=NULL
+ * below in this function ?
+ * 03-05-01 : no cleanup I think, cf M2_RNDBINDFILE
+ */
+ if ((mctx.bindDN == NULL) && (!(mctx.mod2 & M2_RNDBINDFILE))) /*JLS 03-05-01*/
+ { /*JLS 05-03-01*/
+ tttctx->binded = 1; /*JLS 05-03-01*/
+ return (0); /*JLS 05-03-01*/
+ } /*JLS 05-03-01*/
+
+ /*
+ * Maybe we should bind ?
+ */
+#ifdef LDCLTSSL
+ /*
+ * for SSL client authentication, SASL BIND is used
+ */
+ if ((mctx.mode & CLTAUTH) && ((!(tttctx->binded)) ||
+ (mctx.mode & BIND_EACH_OPER)))
+ {
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: Before ldap_sasl_bind_s\n",
+ mctx.pid, tttctx->thrdNum);
+ ret = ldap_sasl_bind_s (tttctx->ldapCtx, "", "EXTERNAL", NULL, NULL, NULL,
+ NULL);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: After ldap_sasl_bind_s\n",
+ mctx.pid, tttctx->thrdNum);
+ if (ret == LDAP_SUCCESS) /*JLS 18-12-00*/
+ tttctx->binded = 1; /*JLS 18-12-00*/
+ else /*JLS 18-12-00*/
+ { /*JLS 18-12-00*/
+ tttctx->binded = 0; /*JLS 18-12-00*/
+ if (ignoreError (ret)) /*JLS 18-12-00*/
+ { /*JLS 18-12-00*/
+ if (!(mctx.mode & QUIET)) /*JLS 18-12-00*/
+ { /*JLS 18-12-00*/
+ printf ("ldclt[%d]: T%03d: Cannot ldap_sasl_bind_s, error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout); /*JLS 18-12-00*/
+ } /*JLS 18-12-00*/
+ if (addErrorStat (ret) < 0) /*JLS 18-12-00*/
+ return (-1); /*JLS 18-12-00*/
+ return (0); /*JLS 18-12-00*/
+ } /*JLS 18-12-00*/
+ else /*JLS 18-12-00*/
+ { /*JLS 18-12-00*/
+ printf ("ldclt[%d]: T%03d: Cannot ldap_sasl_bind_s, error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout); /*JLS 18-12-00*/
+ tttctx->exitStatus = EXIT_NOBIND; /*JLS 18-12-00*/
+ if (addErrorStat (ret) < 0) /*JLS 18-12-00*/
+ return (-1); /*JLS 18-12-00*/
+ return (-1); /*JLS 18-12-00*/
+ } /*JLS 18-12-00*/
+ }
+ }
+ else
+ {
+#endif /* LDCLTSSL */
+ if (((mctx.bindDN != NULL) || (mctx.mod2 & M2_RNDBINDFILE)) && /*03-05-01*/
+ ((!(tttctx->binded)) || (mctx.mode & BIND_EACH_OPER)))
+ {
+ if (buildNewBindDN (tttctx) < 0) /*JLS 05-01-01*/
+ return (-1); /*JLS 05-01-01*/
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: Before ldap_simple_bind_s (%s, %s)\n",
+ mctx.pid, tttctx->thrdNum, tttctx->bufBindDN,
+ mctx.passwd?tttctx->bufPasswd:"NO PASSWORD PROVIDED");
+ ret = ldap_simple_bind_s (tttctx->ldapCtx,
+ tttctx->bufBindDN, /*JLS 05-01-01*/
+ mctx.passwd?tttctx->bufPasswd:"NO PASSWORD PROVIDED");
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: After ldap_simple_bind_s (%s, %s)\n",
+ mctx.pid, tttctx->thrdNum, tttctx->bufBindDN,
+ mctx.passwd?tttctx->bufPasswd:"NO PASSWORD PROVIDED");
+ if (ret == LDAP_SUCCESS) /*JLS 18-12-00*/
+ tttctx->binded = 1; /*JLS 18-12-00*/
+ else /*JLS 18-12-00*/
+ { /*JLS 18-12-00*/
+ tttctx->binded = 0; /*JLS 18-12-00*/
+ if (ignoreError (ret)) /*JLS 18-12-00*/
+ { /*JLS 18-12-00*/
+ if (!(mctx.mode & QUIET)) /*JLS 18-12-00*/
+ { /*JLS 18-12-00*/
+ printf("ldclt[%d]: T%03d: Cannot ldap_simple_bind_s (%s, %s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, tttctx->bufBindDN,
+ mctx.passwd?tttctx->bufPasswd:"NO PASSWORD PROVIDED",
+ ret, my_ldap_err2string (ret));
+ fflush (stdout); /*JLS 18-12-00*/
+ } /*JLS 18-12-00*/
+ if (addErrorStat (ret) < 0) /*JLS 18-12-00*/
+ return (-1); /*JLS 18-12-00*/
+ return (0); /*JLS 18-12-00*/
+ } /*JLS 18-12-00*/
+ else /*JLS 18-12-00*/
+ { /*JLS 18-12-00*/
+ printf ("ldclt[%d]: T%03d: Cannot ldap_simple_bind_s (%s, %s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, tttctx->bufBindDN,
+ mctx.passwd?tttctx->bufPasswd:"NO PASSWORD PROVIDED",
+ ret, my_ldap_err2string (ret));
+ fflush (stdout); /*JLS 18-12-00*/
+ tttctx->exitStatus = EXIT_NOBIND; /*JLS 18-12-00*/
+ if (addErrorStat (ret) < 0) /*JLS 18-12-00*/
+ return (-1); /*JLS 18-12-00*/
+ return (-1); /*JLS 18-12-00*/
+ } /*JLS 18-12-00*/
+ }
+ }
+#ifdef LDCLTSSL
+ }
+#endif
+
+ /*
+ * Normal end
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : buildVersatileAttribute
+ PURPOSE : Build a new attribute value using the definitions of
+ the parameters.
+ The pointer returned is always to a safe buffer inside
+ the attribute.
+ INPUT : tttctx = thread context
+ object = object definition
+ attrib = attribute to build
+ OUTPUT : None.
+ RETURN : NULL if error, pointer to the new value else.
+ DESCRIPTION :
+ *****************************************************************************/
+char *
+buildVersatileAttribute (
+ thread_context *tttctx,
+ vers_object *object,
+ vers_attribute *attrib)
+{
+ vers_field *field; /* To parse the fields */
+ int num; /* Temp. number */
+
+ /*
+ * Maybe this attribute has a constant value ?
+ * (i.e. only one field, constant value)
+ */
+ if (attrib->buf == NULL)
+ return (attrib->field->cst);
+
+ /*
+ * Well, it looks like we will have to build the new value
+ */
+ attrib->buf[0] = '\0'; /* No field yet */
+ for (field=attrib->field ; field!=NULL ; field=field->next)
+ {
+ switch (field->how)
+ {
+ case HOW_CONSTANT:
+ strcat (attrib->buf, field->cst);
+ break;
+ case HOW_INCR_FROM_FILE:
+ if (mctx.mode & COMMON_COUNTER)
+ {
+ num = incrementCommonCounterObject (tttctx, field->commonField);
+ if (num < 0)
+ return (NULL);
+ }
+ else
+ {
+ if (field->cnt > field->high)
+ field->cnt = field->low;
+ num = field->cnt;
+ field->cnt++; /* Next value for next loop */
+ }
+ strcat (attrib->buf, field->dlf->str[num]);
+ if (field->var != -1)
+ strcpy (object->var[field->var], field->dlf->str[num]);
+ break;
+ case HOW_INCR_FROM_FILE_NL:
+ if (mctx.mode & COMMON_COUNTER)
+ {
+ num = incrementCommonCounterObject (tttctx, field->commonField);
+ if (num < 0)
+ return (NULL);
+ }
+ else
+ {
+ if (field->cnt > field->high)
+ {
+ printf ("ldclt[%d]: %s: Hit top incrementeal value\n",
+ mctx.pid, tttctx->thrdId);
+ return(NULL);
+ }
+ num = field->cnt;
+ field->cnt++; /* Next value for next loop */
+ }
+ strcat (attrib->buf, field->dlf->str[num]);
+ if (field->var != -1)
+ strcpy (object->var[field->var], tttctx->buf2);
+ break;
+ case HOW_INCR_NB:
+ if (mctx.mode & COMMON_COUNTER)
+ {
+ num = incrementCommonCounterObject (tttctx, field->commonField);
+ if (num < 0)
+ return (NULL);
+ }
+ else
+ {
+ if (field->cnt > field->high)
+ field->cnt = field->low;
+ num = field->cnt;
+ field->cnt++; /* Next value for next loop */
+ }
+ sprintf (tttctx->buf2, "%0*d", field->nb, num);
+ strcat (attrib->buf, tttctx->buf2);
+ if (field->var != -1)
+ strcpy (object->var[field->var], tttctx->buf2);
+ break;
+ case HOW_INCR_NB_NOLOOP:
+ if (mctx.mode & COMMON_COUNTER)
+ {
+ num = incrementCommonCounterObject (tttctx, field->commonField);
+ if (num < 0)
+ return (NULL);
+ }
+ else
+ {
+ if (field->cnt > field->high)
+ {
+ printf ("ldclt[%d]: %s: Hit top incrementeal value\n",
+ mctx.pid, tttctx->thrdId);
+ return(NULL);
+ }
+ num = field->cnt;
+ field->cnt++; /* Next value for next loop */
+ }
+ sprintf (tttctx->buf2, "%0*d", field->nb, num);
+ strcat (attrib->buf, tttctx->buf2);
+ if (field->var != -1)
+ strcpy (object->var[field->var], tttctx->buf2);
+ break;
+ case HOW_RND_FROM_FILE:
+ num = (lrand48() % field->dlf->strNb);
+ strcat (attrib->buf, field->dlf->str[num]);
+ if (field->var != -1)
+ strcpy (object->var[field->var], field->dlf->str[num]);
+ break;
+ case HOW_RND_NUMBER:
+ rnd (tttctx->buf2, field->low, field->high, field->nb);
+ strcat (attrib->buf, tttctx->buf2);
+ if (field->var != -1)
+ strcpy (object->var[field->var], tttctx->buf2);
+ break;
+ case HOW_RND_STRING:
+ (void) randomString (tttctx, field->nb);
+ strcat (attrib->buf, tttctx->buf2);
+ if (field->var != -1)
+ strcpy (object->var[field->var], tttctx->buf2);
+ break;
+ case HOW_VARIABLE:
+ if (object->var[field->var] == NULL) /*JLS 11-04-01*/
+ { /*JLS 11-04-01*/
+ printf ("ldclt[%d]: %s: Error : unset variable %c in %s\n",
+ mctx.pid, tttctx->thrdId,
+ 'A'+field->var, attrib->src); /*JLS 11-04-01*/
+ return(NULL); /*JLS 11-04-01*/
+ } /*JLS 11-04-01*/
+ strcat (attrib->buf, object->var[field->var]);
+ break;
+ default:
+ /*
+ * Should not happen, unless new variant parsed and not
+ * integrated here, or "jardinage"....
+ */
+ field = NULL;
+ field->how = 22; /* Crash !!! */
+ break;
+ }
+ }
+
+ /*
+ * Return the new value.
+ */
+ return (attrib->buf);
+}
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : buildRandomRdnOrFilter
+ PURPOSE : This function will build a random string (rdn or filter)
+ to be used by ldap_search() or ldap_add() or etc...
+ The result is in tttctx->bufFilter
+ INPUT : tttctx = thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+buildRandomRdnOrFilter (
+ thread_context *tttctx)
+{
+
+ /*
+ * Maybe we will operate with a variable base DN ?
+ */
+ if (mctx.mode & RANDOM_BASE)
+ {
+ if (mctx.mode & STRING)
+ (void) randomString (tttctx, mctx.baseDNNbDigit);
+ else
+ rnd (tttctx->buf2, mctx.baseDNLow, mctx.baseDNHigh, /*JLS 14-11-00*/
+ mctx.baseDNNbDigit); /*JLS 14-11-00*/
+ strncpy (&(tttctx->bufBaseDN[tttctx->startBaseDN]),
+ tttctx->buf2, mctx.baseDNNbDigit);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: base DN=\"%s\"\n",
+ mctx.pid, tttctx->thrdNum, tttctx->bufBaseDN);
+ }
+
+ /*
+ * Maybe we must build a random attribute value ?
+ * We only support random string generation here.
+ */
+ if (mctx.mode & ATTR_REPLACE) /*JLS 21-11-00*/
+ { /*JLS 21-11-00*/
+ (void) randomString (tttctx, mctx.attrplNbDigit); /*JLS 21-11-00*/
+ strncpy (&(tttctx->bufAttrpl[tttctx->startAttrpl]), /*JLS 21-11-00*/
+ tttctx->buf2, mctx.attrplNbDigit); /*JLS 21-11-00*/
+ if (mctx.mode & VERY_VERBOSE) /*JLS 21-11-00*/
+ printf ("ldclt[%d]: T%03d: attrib=\"%s\"\n",
+ mctx.pid, tttctx->thrdNum, tttctx->bufAttrpl);
+ } /*JLS 21-11-00*/
+
+ /*
+ * Maybe we must use a variant-rdn style ?
+ */
+ if (mctx.mod2 & M2_RDN_VALUE) /*JLS 23-03-01*/
+ { /*JLS 23-03-01*/
+ char *buf; /* Temp for new value */ /*JLS 23-03-01*/
+ /*JLS 23-03-01*/
+ buf = buildVersatileAttribute (tttctx, /*JLS 23-03-01*/
+ tttctx->object, tttctx->object->rdn); /*JLS 23-03-01*/
+ if (buf == NULL) /*JLS 23-03-01*/
+ return (-1); /*JLS 23-03-01*/
+ strcpy (tttctx->bufFilter, tttctx->object->rdnName); /*JLS 23-03-01*/
+ strcat (tttctx->bufFilter, "="); /*JLS 23-03-01*/
+ strcat (tttctx->bufFilter, buf); /*JLS 23-03-01*/
+ if (mctx.mode & VERY_VERBOSE) /*JLS 28-03-01*/
+ printf ("ldclt[%d]: %s: rdn variant mode:filter=\"%s\"\n",
+ mctx.pid, tttctx->thrdId, tttctx->bufFilter);
+ } /*JLS 23-03-01*/
+ else /*JLS 23-03-01*/
+ { /*JLS 23-03-01*/
+ /*
+ * Build the new filter string
+ */
+ if (mctx.mode & RANDOM)
+ {
+ if (mctx.mode & STRING)
+ (void) randomString (tttctx, mctx.randomNbDigit);
+ else
+ rnd (tttctx->buf2, mctx.randomLow, mctx.randomHigh, /*JLS 14-11-00*/
+ mctx.randomNbDigit); /*JLS 14-11-00*/
+ strncpy (&(tttctx->bufFilter[tttctx->startRandom]),
+ tttctx->buf2, mctx.randomNbDigit);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: %s: random mode:filter=\"%s\"\n",
+ mctx.pid, tttctx->thrdId, tttctx->bufFilter);
+ }
+ if (mctx.mode & INCREMENTAL)
+ {
+ if (mctx.mode & COMMON_COUNTER) /*JLS 14-03-01*/
+ { /*JLS 14-03-01*/
+ int val; /*JLS 14-03-01*/
+ val = incrementCommonCounter (tttctx); /*JLS 14-03-01*/
+ if (val == -1) /*JLS 14-03-01*/
+ return (-1); /*JLS 14-03-01*/
+ sprintf (tttctx->buf2, "%0*d", mctx.randomNbDigit, val);/*JLS 14-03-01*/
+ } /*JLS 14-03-01*/
+ else /*JLS 14-03-01*/
+ { /*JLS 14-03-01*/
+ tttctx->lastVal++;
+ if (tttctx->lastVal > mctx.randomHigh)
+ {
+ if (!(mctx.mode & NOLOOP))
+ tttctx->lastVal = mctx.randomLow;
+ else
+ {
+ /*
+ * Well, there is no clean way to exit. Let's use the error
+ * condition and hope all will be ok.
+ */
+ printf ("ldclt[%d]: %s: Hit top incrementeal value\n",
+ mctx.pid, tttctx->thrdId);
+ return (-1);
+ }
+ }
+ sprintf (tttctx->buf2, "%0*d", mctx.randomNbDigit, tttctx->lastVal);
+ } /*JLS 14-03-01*/
+
+ strncpy (&(tttctx->bufFilter[tttctx->startRandom]), tttctx->buf2,
+ mctx.randomNbDigit);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: %s: incremental mode:filter=\"%s\"\n",
+ mctx.pid, tttctx->thrdId, tttctx->bufFilter);
+ }
+ } /*JLS 23-03-01*/
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : addAttrib
+ PURPOSE : Add a new attribute to the given LDAPMod array
+ INPUT : attrs = existing LDAPMod array
+ nb = number of entries in the array
+ newattr = new attribute to add to the list
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION : Important note: the first time this function is called,
+ it must be with nb==0.
+ *****************************************************************************/
+int
+addAttrib (
+ LDAPMod **attrs,
+ int nb,
+ LDAPMod *newattr)
+{
+ attrs[nb] = (LDAPMod *) malloc (sizeof (LDAPMod));
+ if (attrs[nb] == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("ldclt[%d]: Txxx: cannot malloc(attrs[%d]), error=%d (%s)\n",
+ mctx.pid, nb, errno, strerror (errno));
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ memcpy (attrs[nb], newattr, sizeof (LDAPMod));
+ attrs[nb+1] = NULL;
+ return (0);
+}
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : freeAttrib
+ PURPOSE : Free an array of addAttrib.
+ INPUT : attrs = LDAPMod array to free
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+freeAttrib (
+ LDAPMod **attrs)
+{
+ int i;
+ for (i=0 ; attrs[i]!=NULL ; i++)
+ {
+ if (attrs[i]->mod_op & LDAP_MOD_BVALUES)
+ {
+ free (attrs[i]->mod_bvalues[0]);
+ free (attrs[i]->mod_bvalues);
+ }
+ else
+ free (attrs[i]->mod_values);
+ free (attrs[i]);
+ }
+ return (0);
+}
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : strList1
+ PURPOSE : Create a list (array) of two strings
+ INPUT : str1 = the first string.
+ OUTPUT : None.
+ RETURN : Pointer to the char *str[2]
+ DESCRIPTION :
+ *****************************************************************************/
+char **
+strList1 (
+ char *str1)
+{
+ char **p;
+ p = (char **) malloc (2 * sizeof (char *));
+ if (p == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("ldclt[%d]: Txxx: cannot malloc(p), error=%d (%s)\n",
+ mctx.pid, errno, strerror (errno));
+ ldcltExit (EXIT_RESSOURCE); /*JLS 18-12-00*/
+ } /*JLS 06-03-00*/
+ p[0] = str1;
+ p[1] = NULL;
+ return (p);
+}
+
+
+
+
+
+
+
+
+
+
+
+ /* New function */ /*JLS 03-08-00*/
+/* ****************************************************************************
+ FUNCTION : printErrorFromLdap
+ PURPOSE : Print the error message returned by ldap.
+ INPUT : tttctx = thread context
+ res = LDAP result
+ errcode = error code
+ errmsg = error message
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+printErrorFromLdap (
+ thread_context *tttctx,
+ LDAPMessage *res,
+ int errcode,
+ char *errmsg)
+{
+ int ret; /* Return value */
+ char *addErrMsg; /* Additional error msg */
+ int errcodep; /* Async error code */ /*JLS 11-08-00*/
+
+ /*
+ * Print the error message and error code
+ */
+ printf ("ldclt[%d]: T%03d: %s, error=%d (%s",
+ mctx.pid, tttctx->thrdNum, errmsg,
+ errcode, my_ldap_err2string (errcode));
+
+ /*
+ * See if there is an additional error message...
+ */
+ ret = ldap_parse_result (tttctx->ldapCtx, res, &errcodep, /*JLS 11-08-00*/
+ NULL, &addErrMsg, NULL, NULL, 0);
+ if (ret != LDAP_SUCCESS)
+ {
+ printf (")\n");
+ printf ("ldclt[%d]: T%03d: errcodep = %d\n",
+ mctx.pid, tttctx->thrdNum, errcodep);
+ printf ("ldclt[%d]: T%03d: Cannot ldap_parse_result(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ return (-1);
+ }
+
+ /*
+ * Ok, we were able to retrieve more information...
+ * Well, the errcodep is the error of the operation parsed by
+ * ldap_parse_result(), so we will print it if different from
+ * the one given in argument to this function...
+ */
+ if (errcodep != errcode) /*JLS 11-08-00*/
+ printf ("ldclt[%d]: errcodep=%d (%s)",
+ mctx.pid, errcodep, my_ldap_err2string (errcodep));
+ if ((addErrMsg != NULL) && (*addErrMsg != '\0'))
+ {
+ printf (" - %s", addErrMsg);
+ ldap_memfree (addErrMsg);
+ }
+ printf (")\n");
+
+ /*
+ * Don't forget to flush !
+ */
+ fflush (stdout);
+ return (0);
+}
+
+
+
+
+
+ /* New function */ /*JLS 21-11-00*/
+/* ****************************************************************************
+ FUNCTION : buildNewModAttrib
+ PURPOSE : Build a new (random or incremental) target DN and the
+ corresponding LDAPMod for attribute modification.
+ INPUT : tttctx = thread context
+ OUTPUT : newDN = DN of the new entry
+ attrs = attributes for the ldap_modify
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+buildNewModAttrib (
+ thread_context *tttctx,
+ char *newDn,
+ LDAPMod **attrs)
+{
+ int nbAttribs; /* Nb of attributes */
+ LDAPMod attribute; /* To build the attributes */
+
+ /*
+ * Build the new DN
+ * We will assume that the filter (-f argument) is set to use it
+ * to build the rdn of the new entry.
+ * Note that the random new attribute is also build by this function.
+ */
+ if (buildRandomRdnOrFilter (tttctx) < 0)
+ return (-1);
+ strcpy (newDn, tttctx->bufFilter);
+ strcat (newDn, ",");
+ strcat (newDn, tttctx->bufBaseDN);
+
+ /*
+ * Build the attributes modification
+ */
+ attrs[0] = NULL; /* No attributes yet */
+ nbAttribs = 0; /* No attributes yet */
+ attribute.mod_op = LDAP_MOD_REPLACE;
+ attribute.mod_type = mctx.attrplName;
+ attribute.mod_values = strList1 (tttctx->bufAttrpl);
+ if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+ return (-1);
+
+ /*
+ * Normal end
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /* New */ /*JLS 19-03-01*/
+/* ****************************************************************************
+ FUNCTION : buildVersatileObject
+ PURPOSE : Build a new entry using the definitions in the object
+ given in parameter.
+ INPUT : tttctx = thread context
+ object = object definition
+ OUTPUT : attrs = resulting attributes.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+buildVersatileObject (
+ thread_context *tttctx,
+ vers_object *object,
+ LDAPMod **attrs)
+{
+ int nbAttribs; /* Nb of attributes */
+ LDAPMod attribute; /* To build the attributes */
+ int i; /* For the loop */
+ char *newValue; /* New values for the attributes */
+
+ /*
+ * Initialization
+ */
+ attrs[0] = NULL; /* No attributes yet */
+ nbAttribs = 0; /* No attributes yet */
+
+ /*
+ * What is sure is that ttctx->bufFilter contains the rdn of the new entry !
+ * This rdn is build from the filter, and is independant from the
+ * object class.
+ */
+ for (i=0 ; tttctx->bufFilter[i] != '=' ; i++)
+ tttctx->buf2[i] = tttctx->bufFilter[i];
+ tttctx->buf2[i] = '\0';
+ strcpy (tttctx->bufObject1, tttctx->buf2);
+ attribute.mod_op = LDAP_MOD_ADD;
+ attribute.mod_type = tttctx->bufObject1;
+ attribute.mod_values = strList1 (&(tttctx->bufFilter[i+1]));
+ if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+ return (-1);
+
+ /*
+ * We are certain that there is enough space in attrs
+ */
+ for (i=0 ; i<object->attribsNb ; i++)
+ {
+ attribute.mod_op = LDAP_MOD_ADD;
+ attribute.mod_type = object->attribs[i].name;
+
+ newValue = buildVersatileAttribute (tttctx, object, &(object->attribs[i]));
+ if (newValue == NULL)
+ return (-1);
+
+ attribute.mod_values = strList1 (newValue);
+ if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : buildNewEntry
+ PURPOSE : Build a new (random or incremental) entry, to be used
+ for ldap_add() or ldap_modify() operations.
+ INPUT : tttctx = thread context
+ OUTPUT : newDn = DN of the new entry
+ attrs = attributes of the new entry
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+buildNewEntry (
+ thread_context *tttctx,
+ char *newDn,
+ LDAPMod **attrs)
+{
+ int nbAttribs; /* Nb of attributes */
+ LDAPMod attribute; /* To build the attributes */
+ int i; /* To loop */
+
+ /*
+ * Build the new DN
+ * We will assume that the filter (-f argument) is set to use it
+ * to build the rdn of the new entry.
+ */
+ if (buildRandomRdnOrFilter (tttctx) < 0)
+ return (-1);
+ strcpy (newDn, tttctx->bufFilter);
+ strcat (newDn, ",");
+ strcat (newDn, tttctx->bufBaseDN);
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: %s: tttctx->bufFilter=\"%s\"\n",
+ mctx.pid, tttctx->thrdId, tttctx->bufFilter);
+
+ /*
+ * Maybe we are using the new versatile object definition ?
+ */
+ if (mctx.mod2 & M2_OBJECT) /*JLS 19-03-01*/
+ { /*JLS 19-03-01*/
+ if (buildVersatileObject(tttctx, tttctx->object, attrs) < 0)/*JLS 19-03-01*/
+ return (-1); /*JLS 19-03-01*/
+ if (mctx.mode & VERY_VERBOSE) /*JLS 19-03-01*/
+ { /*JLS 19-03-01*/
+ for (i=0 ; attrs[i] != NULL ; i++) /*JLS 19-03-01*/
+ printf ("ldclt[%d]: %s: attrs[%d]=(\"%s\" , \"%s\")\n",
+ mctx.pid, tttctx->thrdId, i,
+ attrs[i]->mod_type, attrs[i]->mod_values[0]); /*JLS 19-03-01*/
+ } /*JLS 19-03-01*/
+ return (0); /*JLS 19-03-01*/
+ } /*JLS 19-03-01*/
+
+ /*
+ * Build the attributes
+ * First, the class...
+ * The classe depends of course on the user's choice.
+ * Up to now, we only accept person, or one of its subclasses, emailPerson.
+ * The difference is that emailPerson contains no other mandatory attributes,
+ * but an optionnal one caled "jpegPhoto". This one will be added at the end
+ * of this function.
+ * NOTE: When other classes will be managed, this function will be splitted
+ * to do this.
+ */
+ attrs[0] = NULL; /* No attributes yet */
+ nbAttribs = 0; /* No attributes yet */
+ attribute.mod_op = LDAP_MOD_ADD;
+ attribute.mod_type = "objectclass";
+ if (mctx.mode & OC_PERSON)
+ attribute.mod_values = strList1 ("person");
+ if (mctx.mode & OC_EMAILPERSON)
+ attribute.mod_values = strList1 ("emailPerson");
+ if (mctx.mode & OC_INETORGPRSON) /*JLS 07-11-00*/
+ attribute.mod_values = strList1 ("inetOrgPerson"); /*JLS 07-11-00*/
+ if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+ return (-1);
+
+ /*
+ * What is sure is that ttctx->bufFilter contains the rdn of the new entry !
+ * This rdn is build from the filter, and is independant from the
+ * object class.
+ */
+ for (i=0 ; tttctx->bufFilter[i] != '=' ; i++)
+ tttctx->buf2[i] = tttctx->bufFilter[i];
+ tttctx->buf2[i] = '\0';
+ attribute.mod_op = LDAP_MOD_ADD;
+ attribute.mod_type = tttctx->buf2;
+ attribute.mod_values = strList1 (&(tttctx->bufFilter[i+1]));
+ if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+ return (-1);
+
+ /*
+ * The other attributes...
+ */
+ if (mctx.mode & (OC_PERSON|OC_EMAILPERSON|OC_INETORGPRSON)) /*JLS 07-11-00*/
+ {
+ if (strcmp (tttctx->buf2, "cn"))
+ {
+ attribute.mod_op = LDAP_MOD_ADD;
+ attribute.mod_type = "cn";
+ attribute.mod_values = strList1 ("toto cn");
+ if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+ return (-1);
+ }
+ if (strcmp (tttctx->buf2, "sn"))
+ {
+ attribute.mod_op = LDAP_MOD_ADD;
+ attribute.mod_type = "sn";
+ attribute.mod_values = strList1 ("toto sn");
+ if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+ return (-1);
+ }
+ }
+
+ /*
+ * This object class is used because it contains an attribute photo...
+ */
+ if (mctx.mode & (OC_EMAILPERSON|OC_INETORGPRSON)) /*JLS 07-11-00*/
+ {
+ attribute.mod_op = (LDAP_MOD_ADD|LDAP_MOD_BVALUES);
+ attribute.mod_type = "jpegPhoto";
+ if (getImage (&attribute) < 0)
+ return (-1);
+ if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+ return (-1);
+ }
+
+
+ /*
+ * No more attributes. Dump the attributes...
+ */
+ if (mctx.mode & VERY_VERBOSE)
+ {
+ for (i=0 ; attrs[i] != NULL ; i++)
+ printf ("ldclt[%d]: T%03d: attrs[%d]=(\"%s\" , \"%s\")\n",
+ mctx.pid, tttctx->thrdNum, i,
+ attrs[i]->mod_type, attrs[i]->mod_values[0]);
+ }
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : createMissingNodes
+ PURPOSE : Create the missing intermediate nodes.
+ INPUT : tttctx = thread context
+ newDN = new DN that was rejected due to error 32
+ LDAP_NO_SUCH_OBJECT
+ cnx = ldap connection. NULL if not connected.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION : This function will call itself recursively while it is
+ impossible to create the node, as long as the error is
+ LDAP_NO_SUCH_OBJECT (aka 32).
+ This function connects to the server to perform its
+ task, using the same DN and passwd as in the mctx, i.e.
+ the same as the rest of this tool. Hence it is possible
+ that it is impossible to initiate a database if the
+ user is not cn=admin and the database is empty, because
+ only cn=admin may create the root entry.
+ *****************************************************************************/
+int
+createMissingNodes (
+ thread_context *tttctx,
+ char *newDN,
+ LDAP *cnx)
+{
+ int i, j; /* For the loops */
+ int ret; /* Return value */
+ char *nodeDN; /* Node to create */
+ char attrName[256]; /* nodeDN's rdn attribute name */
+ char attrVal[256]; /* nodeDN's rdn attribute value */
+ char *objClass; /* Object class to create */
+ int nbAttribs; /* Nb of attributes */
+ LDAPMod attribute; /* To build the attributes */
+ LDAPMod *attrs[4]; /* Attributes of this entry */
+ int v2v3; /* LDAP version used */
+
+ /*
+ * Skip the rdn of the given newDN, that was rejected.
+ * Don't forget to skip the leading spaces...
+ */
+ nodeDN=newDN;
+ while (*nodeDN != '\0')
+ {
+ if (*nodeDN == ',')
+ break;
+ if (*nodeDN == '\\')
+ {
+ nodeDN++;
+ if (*nodeDN == '\0')
+ break;
+ }
+ nodeDN++;
+ }
+ if (*nodeDN == ',')
+ nodeDN++; /* Skip the ',' */
+ while ((*nodeDN == ' ') && (*nodeDN != '\0'))
+ nodeDN++;
+ if (*nodeDN == '\0')
+ {
+ printf ("ldclt[%d]: T%03d: Reach top of DN for %s\n",
+ mctx.pid, tttctx->thrdNum, newDN);
+ fflush (stdout);
+ return (-1);
+ }
+
+ if (mctx.mode & VERY_VERBOSE) /*JLS 14-12-00*/
+ printf ("ldclt[%d]: T%03d: nodeDN: %s\n",
+ mctx.pid, tttctx->thrdNum, nodeDN);
+
+ /*
+ * Found the naming attribute used for nodeDN's rdn.
+ */
+ for (i=0 ; (nodeDN[i] != '=') && (nodeDN[i] != '\0') ; i++);
+ if (nodeDN[i] == '\0')
+ {
+ printf ("ldclt[%d]: T%03d: Cannot extract naming attribute from %s\n",
+ mctx.pid, tttctx->thrdNum, nodeDN);
+ fflush (stdout);
+ return (-1);
+ }
+ strncpy (attrName, nodeDN, i);
+ attrName[i] = '\0';
+
+ /*
+ * Get the value of this rdn
+ */
+ for (j=i ; (nodeDN[j] != ',') && (nodeDN[j] != '\0') ; j++);
+ if (nodeDN[j] == '\0')
+ {
+ printf ("ldclt[%d]: T%03d: Cannot extract naming attribute from %s\n",
+ mctx.pid, tttctx->thrdNum, nodeDN);
+ fflush (stdout);
+ return (-1);
+ }
+ strncpy (attrVal, nodeDN+i+1, j-i-1);
+ attrVal[j-i-1] = '\0';
+
+ /*
+ * What kind of entry should be create ?
+ */
+ if (!strcmp (attrName, "o"))
+ objClass = "organization";
+ else if (!strcmp (attrName, "ou"))
+ objClass = "organizationalUnit";
+ else if (!strcmp (attrName, "cn"))
+ objClass = "organizationalRole";
+ else
+ {
+ printf ("ldclt[%d]: T%03d: Don't know how to create entry when rdn is \"%s=%s\"\n",
+ mctx.pid, tttctx->thrdNum, attrName, attrVal);
+ fflush (stdout);
+ return (-1);
+ }
+
+ /*
+ * Maybe connect to the server ?
+ */
+ if (cnx == NULL)
+ {
+ if (mctx.mode & VERY_VERBOSE) /*JLS 14-12-00*/
+ printf ("ldclt[%d]: T%03d: must connect to the server.\n",
+ mctx.pid, tttctx->thrdNum);
+#ifdef LDCLTSSL
+ /*
+ * SSL is enabled ?
+ */
+ if (mctx.mode & SSL)
+ {
+ /*
+ * LDAP session initialization in SSL mode
+ * added by: B Kolics (11/10/00)
+ */
+ tttctx->ldapCtx = (LDAP *)(*(mctx.sslctx.ldapssl_init)) /*JLS 07-11-00*/
+ (mctx.hostname, mctx.port, 1);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: After ldapssl_init (%s, %d), ldapCtx=0x%08x\n",
+ mctx.pid, tttctx->thrdNum, mctx.hostname, mctx.port,
+ (unsigned int)tttctx->ldapCtx);
+ if (tttctx->ldapCtx == NULL)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldapssl_init (%s, %d), errno=%d\n",
+ mctx.pid, tttctx->thrdNum, mctx.hostname, mctx.port, errno);
+ fflush (stdout);
+ return (-1);
+ }
+ /*
+ * Client authentication is used ?
+ */
+ if (mctx.mode & CLTAUTH)
+ {
+ ret = (int)(*(mctx.sslctx.ldapssl_enable_clientauth))
+ (tttctx->ldapCtx, "", mctx.keydbpin, mctx.cltcertname);
+ if (mctx.mode & VERY_VERBOSE)
+ printf
+ ("ldclt[%d]: T%03d: After ldapssl_enable_clientauth (ldapCtx=0x%08x, %s, %s)",
+ mctx.pid, tttctx->thrdNum, (unsigned int)tttctx->ldapCtx, mctx.keydbpin,
+ mctx.cltcertname);
+ if (ret < 0)
+ {
+ printf
+ ("ldclt[%d]: T%03d: Cannot ldapssl_enable_clientauth (ldapCtx=0x%08x, %s, %s)",
+ mctx.pid, tttctx->thrdNum, (unsigned int)tttctx->ldapCtx, mctx.keydbpin,
+ mctx.cltcertname);
+ fflush (stdout);
+ return (-1);
+ }
+ }
+ } else {
+#endif
+ /*
+ * connection initialization in normal, unencrypted mode
+ */
+ cnx = ldap_init (mctx.hostname, mctx.port);
+ if (cnx == NULL)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_init (%s, %d), errno=%d\n",
+ mctx.pid, tttctx->thrdNum, mctx.hostname, mctx.port, errno);
+ fflush (stdout);
+ return (-1);
+ }
+#ifdef LDCLTSSL
+ }
+#endif
+
+ if (mctx.mode & LDAP_V2)
+ v2v3 = LDAP_VERSION2;
+ else
+ v2v3 = LDAP_VERSION3;
+
+ ret = ldap_set_option (cnx, LDAP_OPT_PROTOCOL_VERSION, &v2v3);
+ if (ret < 0)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_set_option(LDAP_OPT_PROTOCOL_VERSION)\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ return (-1);
+ }
+
+ /*
+ * Bind to the server
+ */
+#ifdef LDCLTSSL
+ /*
+ * for SSL client authentication, SASL BIND is used
+ */
+ if (mctx.mode & CLTAUTH)
+ {
+ ret = ldap_sasl_bind_s (tttctx->ldapCtx, "", "EXTERNAL", NULL, NULL, NULL,
+ NULL);
+ if (ret != LDAP_SUCCESS)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_sasl_bind_s, error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ tttctx->exitStatus = EXIT_NOBIND;
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ return (-1);
+ }
+ } else {
+#endif
+ ret = ldap_simple_bind_s (cnx, tttctx->bufBindDN, tttctx->bufPasswd);
+ if (ret != LDAP_SUCCESS)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_simple_bind_s (%s, %s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum,
+ tttctx->bufBindDN, tttctx->bufPasswd,
+ ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ tttctx->exitStatus = EXIT_NOBIND; /*JLS 25-08-00*/
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ return (-1);
+ }
+ }
+#ifdef LDCLTSSL
+ }
+#endif
+
+ /*
+ * Create the entry
+ */
+ attrs[0] = NULL; /* No attributes yet */
+ nbAttribs = 0; /* No attributes yet */
+ attribute.mod_op = LDAP_MOD_ADD;
+ attribute.mod_type = "objectclass";
+ attribute.mod_values = strList1 (objClass);
+ if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+ return (-1);
+ attribute.mod_op = LDAP_MOD_ADD;
+ attribute.mod_type = attrName;
+ attribute.mod_values = strList1 (attrVal);
+ if (addAttrib (attrs, nbAttribs++, &attribute) < 0)
+ return (-1);
+
+ /*
+ * Add the entry
+ * If it doesn't work, we will recurse on the nodeDN
+ */
+ ret = ldap_add_s (cnx, nodeDN, attrs);
+ if ((ret != LDAP_SUCCESS) && (ret != LDAP_ALREADY_EXISTS))
+ {
+ if (ret == LDAP_NO_SUCH_OBJECT)
+ { /*JLS 07-11-00*/
+ printf ("ldclt[%d]: T%03d: Parent of %s doesn't exist, looping\n",
+ mctx.pid, tttctx->thrdNum, nodeDN);
+ if (createMissingNodes (tttctx, nodeDN, cnx) < 0)
+ return (-1);
+ else
+ {
+ /*
+ * Well, the upper node is created. Maybe we should now
+ * create the node requested for this instance of the function.
+ * Two solutions, retry a ldap_add_s() or recursive call to
+ * createMissingNodes()... Let's be simple and recurse ;-)
+ * Don't forget that the cnx was released in the previous call.
+ */
+ cnx = NULL;
+ return (createMissingNodes (tttctx, newDN, cnx));
+ }
+ } /*JLS 07-11-00*/
+
+ /*
+ * Well, looks like it is more serious !
+ */
+ printf ("ldclt[%d]: T%03d: Cannot add (%s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, nodeDN, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ return (-1);
+ }
+
+ /*
+ * Note that error this node may exist, i.e. being just created
+ * by another thread !
+ * Memorize this operation only if the entry was really created.
+ * Maybe we run in check mode, so be carreful...
+ */
+ if (ret != LDAP_ALREADY_EXISTS)
+ {
+ if (incrementNbOpers (tttctx) < 0)
+ return (-1);
+#ifdef SOLARIS /*JLS 14-11-00*/
+ if (mctx.slavesNb > 0)
+ if (opAdd (tttctx, LDAP_REQ_ADD, nodeDN, attrs, NULL, NULL) < 0)
+ return (-1);
+#endif /*JLS 14-11-00*/
+ }
+ else /*JLS 15-12-00*/
+ if ((mctx.mode & COUNT_EACH) & (ret == LDAP_ALREADY_EXISTS))/*JLS 15-12-00*/
+ { /*JLS 15-12-00*/
+ if (incrementNbOpers (tttctx) < 0) /*JLS 15-12-00*/
+ return (-1); /*JLS 15-12-00*/
+ } /*JLS 15-12-00*/
+
+ /*
+ * Ok, we succeed to create the entry ! or it already exist.
+ * Don't forget to free the attributes and to release the cnx !!
+ */
+ if (freeAttrib (attrs) < 0)
+ return (-1);
+
+ ret = ldap_unbind (cnx);
+ if (ret != LDAP_SUCCESS)
+ {
+ fprintf (stderr, "ldclt[%d]: T%03d: cannot ldap_unbind(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ return (-1);
+ }
+
+ /*
+ * Ouf ! End of this function.
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : getPending
+ PURPOSE : Get the pending results, and perform some basic controls
+ on them.
+ INPUT : tttctx = thread context
+ timeout = how many times wait for a result.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+getPending (
+ thread_context *tttctx,
+ struct timeval *timeout)
+{
+ LDAPMessage *res; /* LDAP async results */
+ int ret; /* Return values */
+ int expected; /* Expect this type */
+ char *verb; /* LDAP verb expected */
+ int type; /* Message type */
+ int errcodep; /* Async error code */
+ int msgid; /* Async message id */
+ int msgOk; /* Message read. */
+ char *addErrMsg; /* Additional error msg */ /*JLS 03-08-00*/
+
+ /*
+ * Initialization
+ */
+ msgOk = 0; /* No message received */
+ if (tttctx->mode & ADD_ENTRIES)
+ {
+ expected = LDAP_RES_ADD;
+ verb = "ldap_add";
+ }
+ else
+ if (tttctx->mode & DELETE_ENTRIES)
+ {
+ expected = LDAP_RES_DELETE;
+ verb = "ldap_delete";
+ }
+ else
+ if (tttctx->mode & RENAME_ENTRIES)
+ {
+ expected = LDAP_RES_MODRDN;
+ verb = "ldap_rename";
+ }
+ else /*JLS 21-11-00*/
+ if (tttctx->mode & ATTR_REPLACE) /*JLS 21-11-00*/
+ { /*JLS 21-11-00*/
+ expected = LDAP_RES_MODIFY; /*JLS 21-11-00*/
+ verb = "ldap_modify"; /*JLS 21-11-00*/
+ } /*JLS 21-11-00*/
+
+ /*
+ * Here, we are in asynchronous mode...
+ * Too bad, lot of things to do here.
+ * First, let's see if we are above the reading threshold.
+ * This function may be called recursivelly to empty the input queue. When
+ * it is used this way, the timeout is set to zero.
+ */
+ if ((timeout == &(mctx.timevalZero)) ||
+ (tttctx->pendingNb >= mctx.asyncMin))
+ {
+ /*
+ * Retrieve the next pending request
+ * The result of ldap_result() may be -1 (error), 0 (timeout).
+ * If timeout, well... let's ignore it and continue.
+ */
+ ret = ldap_result (tttctx->ldapCtx, LDAP_RES_ANY, 1, timeout, &res);
+ if (ret != 0)
+ {
+ msgOk = 1;
+ if (ret < 0)
+ {
+ if (!ignoreError (ret))
+ {
+ msgOk = 0;
+ if (!(mctx.mode & QUIET))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_result(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ }
+ else
+ {
+ /*
+ * Ensure it is what we expect to see...
+ */
+ type = ldap_msgtype (res);
+ msgid = ldap_msgid (res);
+ if (type != expected)
+ {
+ msgOk = 0;
+ printf ("ldclt[%d]: T%03d: bad result type 0x%02x\n",
+ mctx.pid, tttctx->thrdNum, type);
+ fflush (stdout);
+ if (msgIdDel (tttctx, msgid, 1) < 0)
+ return (-1);
+ return (0);
+ }
+
+ /*
+ * Parse the result
+ */
+ addErrMsg = NULL; /*JLS 03-08-00*/
+ ret = ldap_parse_result (tttctx->ldapCtx, res, &errcodep,
+ NULL, &addErrMsg, NULL, NULL, 0); /*JLS 03-08-00*/
+ if (ret < 0)
+ {
+ if (!ignoreError (ret))
+ {
+ msgOk = 0;
+ if (!(mctx.mode & QUIET))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_parse_result(%s), error=%d (%s",
+ mctx.pid, tttctx->thrdNum, msgIdStr (tttctx, msgid),
+ ret, my_ldap_err2string (ret));
+ if ((addErrMsg != NULL) && (*addErrMsg != '\0')) /*JLS 03-08-00*/
+ { /*JLS 03-08-00*/
+ printf (" - %s", addErrMsg); /*JLS 03-08-00*/
+ ldap_memfree (addErrMsg); /*JLS 03-08-00*/
+ } /*JLS 03-08-00*/
+ printf (")\n"); /*JLS 03-08-00*/
+ fflush (stdout);
+ }
+ }
+ if (msgIdDel (tttctx, msgid, 1) < 0)
+ return (-1);
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ }
+
+ /*
+ * Ensure the operation was well performed
+ * Note that an error to be ignored should be considered as
+ * a good message received (cf boolean msgOk).
+ */
+ if (errcodep != LDAP_SUCCESS)
+ {
+ if (!ignoreError (ret))
+ {
+ msgOk = 0;
+ if (!(mctx.mode & QUIET))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot %s(%s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, verb, msgIdStr (tttctx, msgid),
+ errcodep, my_ldap_err2string (errcodep));
+ fflush (stdout);
+ }
+ }
+
+ /*
+ * Maybe we must create the intermediate nodes ?
+ */
+ if (((expected == LDAP_RES_ADD) || (expected == LDAP_RES_MODRDN)) &&
+ (errcodep == LDAP_NO_SUCH_OBJECT))
+ {
+ /*
+ * Attention, for the rename operation we will memorize the new
+ * parent node and not the entry itself.
+ */
+ if (createMissingNodes (tttctx, msgIdStr (tttctx, msgid), NULL) < 0)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot create the intermediate nodes for %s\n",
+ mctx.pid, tttctx->thrdNum, msgIdStr (tttctx, msgid));
+ fflush (stdout);
+ return (-1);
+ }
+ if ((mctx.mode & VERBOSE) && (!(mctx.mode & QUIET)))
+ {
+ printf ("ldclt[%d]: T%03d: Intermediate nodes created for %s\n",
+ mctx.pid, tttctx->thrdNum, msgIdStr (tttctx, msgid));
+ fflush (stdout);
+ }
+ }
+
+ /*
+ * Free the message's data
+ */
+ if (msgIdDel (tttctx, msgid, 1) < 0)
+ return (-1);
+ if (addErrorStat (errcodep) < 0)
+ return (-1);
+ }
+ else
+ {
+ /*
+ * Ok, the operation is well performed !
+ * Maybe we are running in check mode ?
+ */
+ if (mctx.slavesNb == 0)
+ {
+ if (msgIdDel (tttctx, msgid, 1) < 0)
+ return (-1);
+ }
+#ifdef SOLARIS /*JLS 14-11-00*/
+ else
+ {
+ switch (expected)
+ {
+ case LDAP_RES_ADD:
+ if (opAdd (tttctx, LDAP_REQ_ADD, msgIdDN(tttctx, msgid),
+ msgIdAttribs(tttctx, msgid), NULL, NULL) < 0)
+ return (-1);
+ break;
+ case LDAP_RES_DELETE:
+ if (opAdd (tttctx, LDAP_REQ_DELETE, msgIdDN(tttctx, msgid),
+ NULL, NULL, NULL) < 0)
+ return (-1);
+ break;
+ case LDAP_RES_MODRDN:
+ if (opAdd (tttctx, LDAP_REQ_DELETE, msgIdDN(tttctx, msgid),
+ NULL, NULL, NULL) < 0)
+/*
+ TBC : memorize the newRdn and newParent
+ */
+ return (-1);
+ break;
+ }
+ if (msgIdDel (tttctx, msgid, 1) < 0)
+ return (-1);
+ }
+#endif /* SOLARIS */ /*JLS 14-11-00*/
+ }
+
+ /*
+ * Ok, it is a "SUCCESS" message.
+ * Don't forget to free the returned message !
+ */
+ tttctx->pendingNb--;
+ if ((ret = ldap_msgfree (res)) < 0)
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_msgfree(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ }
+ }
+ }
+ }
+
+ /*
+ * Maybe recurse to read the next message ?
+ */
+ if (msgOk)
+ return (getPending (tttctx, &(mctx.timevalZero)));
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : doRename
+ PURPOSE : Perform an ldap_rename() operation.
+ INPUT : tttctx = thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+doRename (
+ thread_context *tttctx)
+{
+ char oldDn[MAX_DN_LENGTH]; /* DN of the entry to rename */
+ int ret; /* Return values */
+ int retry; /* Retry after createMissingNodes() */
+ int retryed; /* If already retryed */
+ int msgid; /* For asynchronous mode */
+
+ /*
+ * Connection to the server
+ * The function connectToServer() will take care of the various connection/
+ * disconnection, bind/unbind/close etc... requested by the user.
+ * The cost is one more function call in this application, but the
+ * resulting source code will be much more easiest to maintain.
+ */
+ if (connectToServer (tttctx) < 0) /*JLS 18-12-00*/
+ return (-1); /*JLS 18-12-00*/
+ if (!(tttctx->binded)) /*JLS 18-12-00*/
+ return (0); /*JLS 18-12-00*/
+
+ /*
+ * Build a random entry name. Of course, we are not sure it exist
+ * but there is no other simple solution...
+ * Anyway, the result is: tttctx->bufFilter , tttctx->bufBaseDN
+ */
+ if (buildRandomRdnOrFilter (tttctx) < 0)
+ return (-1);
+ strcpy (oldDn, tttctx->bufFilter);
+ strcat (oldDn, ",");
+ strcat (oldDn, tttctx->bufBaseDN);
+
+ /*
+ * Now, build a random new name for this entry
+ */
+ if (buildRandomRdnOrFilter (tttctx) < 0)
+ return (-1);
+
+ /*
+ * Do the rename
+ * Maybe we are in synchronous mode ?
+ * We won't try to recover from errors in this function, because the
+ * way the library will tell the application that the target parent
+ * (tttctx->bufBaseDN) doesn't exist is LDAP_PROTOCOL_ERROR that may
+ * report as well three other problems.
+ */
+ if (!(mctx.mode & ASYNC))
+ {
+ /*
+ * We will retry with this entry...
+ * We need to memorize we have already retry to add an entry, because
+ * ldap_rename_s() returns LDAP_PROTOCOL_ERROR if the randomly chosen
+ * entry we try to rename does not exist ! If we don't, the program will
+ * loop infinitely on this.
+ * The only way is to decide that LDAP_PROTOCOL_ERROR is not a *real*
+ * error, that is detailed below :
+ * The possible meanings of LDAP_PROTOCOL_ERROR are :
+ * - BER problem, unlike to happen
+ * - newrdn is invalid, also unlike to happen
+ * - ldclt is not running ldap v3 - ok, we could leave with this.
+ * - the newparent is invalid. I thing that we could take this for
+ * "doesn't exist"...
+ */
+ retry = 1;
+ retryed = 0;
+ while (retry && !retryed)
+ {
+ if (mctx.mode & WITH_NEWPARENT) /*JLS 15-12-00*/
+ ret = ldap_rename_s (tttctx->ldapCtx, oldDn,
+ tttctx->bufFilter, tttctx->bufBaseDN, 1, NULL, NULL);
+ else /*JLS 15-12-00*/
+ ret = ldap_rename_s (tttctx->ldapCtx, oldDn, /*JLS 15-12-00*/
+ tttctx->bufFilter, NULL, 1, NULL, NULL);/*JLS 15-12-00*/
+ if (ret == LDAP_SUCCESS) /*JLS 15-12-00*/
+ {
+ retry = 0;
+ if (incrementNbOpers (tttctx) < 0) /* Memorize operation */
+ return (-1);
+#ifdef SOLARIS /*JLS 14-11-00*/
+ if (mctx.slavesNb > 0)
+ if (opAdd (tttctx, LDAP_REQ_MODRDN, oldDn, NULL,
+ tttctx->bufFilter, tttctx->bufBaseDN) < 0)
+ return (-1);
+#endif /*JLS 14-11-00*/
+ }
+ else /* Error */
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot rename (%s, %s, %s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, oldDn, tttctx->bufFilter, tttctx->bufBaseDN,
+ ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+
+ /*
+ * Check what to do depending on the error.
+ * From the c-sdk function description, if the parent node of the
+ * new dn (i.e. tttctx->bufBaseDN) doesn't exist, the error returned
+ * is LDAP_PROTOCOL_ERROR that may report as well three other problems.
+ * See discussion above.
+ */
+
+ /*
+ * Maybe we should count each operation ?
+ */
+ if ((mctx.mode & COUNT_EACH) && /*JLS 18-12-00*/
+ ((ret == LDAP_PROTOCOL_ERROR) || /*JLS 18-12-00*/
+ (ret == LDAP_NO_SUCH_OBJECT) || /*JLS 18-12-00*/
+ (ret == LDAP_ALREADY_EXISTS))) /*JLS 18-12-00*/
+ { /*JLS 18-12-00*/
+ if (incrementNbOpers (tttctx) < 0) /*JLS 18-12-00*/
+ return (-1); /*JLS 18-12-00*/
+ } /*JLS 18-12-00*/
+
+ /*
+ * Maybe we must create the intermediate nodes ?
+ */
+ if (ret != LDAP_PROTOCOL_ERROR) /*JLS 15-12-00*/
+ retry = 0;
+ else
+ {
+ if (createMissingNodes (tttctx, tttctx->bufBaseDN, NULL) < 0)
+ {
+ retry = 0;
+ printf ("ldclt[%d]: T%03d: Cannot create the intermediate nodes for %s\n",
+ mctx.pid, tttctx->thrdNum, tttctx->bufBaseDN);
+ fflush (stdout);
+ return (-1);
+ }
+ if ((mctx.mode & VERBOSE) && (!(mctx.mode & QUIET)))
+ {
+ printf ("ldclt[%d]: T%03d: Intermediate nodes created for %s\n",
+ mctx.pid, tttctx->thrdNum, tttctx->bufBaseDN);
+ fflush (stdout);
+ }
+ retryed = 1;
+ }
+ }
+ }
+
+ /*
+ * End of synchronous operations
+ */
+ return (0);
+ }
+
+ /*
+ * Here, we are in asynchronous mode...
+ * Too bad, lot of things to do here.
+ * First, let's see if we are above the reading threshold.
+ */
+ if (getPending (tttctx, &(mctx.timeval)) < 0)
+ return (-1);
+
+ /*
+ * Maybe we may send another request ?
+ * Well... there is no proper way to retrieve the error number for
+ * this, so I guess I may use direct access to the ldap context
+ * to read the field ld_errno.
+ */
+ if (tttctx->pendingNb > mctx.asyncMax)
+ {
+ if ((mctx.mode & VERBOSE) &&
+ (tttctx->asyncHit == 1) &&
+ (!(mctx.mode & SUPER_QUIET)))
+ {
+ tttctx->asyncHit = 1;
+ printf ("ldclt[%d]: T%03d: Max pending request hit.\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ }
+ }
+ else
+ {
+ if ((mctx.mode & VERBOSE) &&
+ (tttctx->asyncHit == 1) &&
+ (!(mctx.mode & SUPER_QUIET)))
+ {
+ tttctx->asyncHit = 0;
+ printf ("ldclt[%d]: T%03d: Restart sending.\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ }
+
+ if (mctx.mode & WITH_NEWPARENT) /*JLS 15-12-00*/
+ ret = ldap_rename (tttctx->ldapCtx, oldDn,
+ tttctx->bufFilter, tttctx->bufBaseDN,
+ 1, NULL, NULL, &msgid);
+ else /*JLS 15-12-00*/
+ ret = ldap_rename (tttctx->ldapCtx, oldDn, /*JLS 15-12-00*/
+ tttctx->bufFilter, NULL, /*JLS 15-12-00*/
+ 1, NULL, NULL, &msgid); /*JLS 15-12-00*/
+ if (ret < 0)
+ {
+ if (ldap_get_option (tttctx->ldapCtx, LDAP_OPT_ERROR_NUMBER, &ret) < 0)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_get_option(LDAP_OPT_ERROR_NUMBER)\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ return (-1);
+ }
+ else
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot rename (%s, %s, %s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, oldDn, tttctx->bufFilter, tttctx->bufBaseDN,
+ ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+
+ /*
+ * Maybe we should count each operation ?
+ */
+ if ((mctx.mode & COUNT_EACH) && /*JLS 18-12-00*/
+ ((ret == LDAP_PROTOCOL_ERROR) || /*JLS 18-12-00*/
+ (ret == LDAP_NO_SUCH_OBJECT) || /*JLS 18-12-00*/
+ (ret == LDAP_ALREADY_EXISTS))) /*JLS 18-12-00*/
+ { /*JLS 18-12-00*/
+ if (incrementNbOpers (tttctx) < 0) /*JLS 18-12-00*/
+ return (-1); /*JLS 18-12-00*/
+ } /*JLS 18-12-00*/
+
+ /*
+ * Maybe we must create the intermediate nodes ?
+ * Question: is it likely probable that such error is returned
+ * by the server on a *asynchornous* operation ?
+ * See discussion about the error returned in the synchronous section
+ * of this function.
+ */
+ if (ret == LDAP_PROTOCOL_ERROR) /*JLS 15-12-00*/
+ { /*JLS 15-12-00*/
+ if (createMissingNodes (tttctx, tttctx->bufBaseDN, NULL) < 0)
+ return (-1);
+ } /*JLS 15-12-00*/
+ }
+ }
+ else
+ {
+ /*
+ * Memorize the operation
+ */
+/*
+ TBC : I'm not sure what will happen if we call msgIdAdd() with a NULL
+ pointer as attribs !!!!!
+ */
+ if (msgIdAdd (tttctx, msgid, tttctx->bufBaseDN, oldDn, NULL) < 0)
+ return (-1);
+ if (incrementNbOpers (tttctx) < 0)
+ return (-1);
+ tttctx->pendingNb++;
+ }
+ }
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: pendingNb=%d\n",
+ mctx.pid, tttctx->thrdNum, tttctx->pendingNb);
+
+ /*
+ * End of asynchronous operation... and also end of function.
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+ /* New */ /*JLS 02-04-01*/
+/* ****************************************************************************
+ FUNCTION : ldclt_write_genldif
+ PURPOSE : Implements buffered write to speed up -e genldif
+ implementation.
+ INPUT : str = string to write.
+ lgth = length of this string.
+ OUTPUT : None.
+ RETURN : None.
+ DESCRIPTION : Usual write() function is unbuffered on Solaris and
+ thus really slow down the whole process. Using this
+ function allow ldclt to perform 8 times faster.
+ We cannot use fprintf() because of portability issues
+ regarding large files support.
+ *****************************************************************************/
+char *ldclt_write_genldif_buf = NULL;
+char *ldclt_write_genldif_pt;
+int ldclt_write_genldif_nb;
+
+void
+ldclt_flush_genldif (void)
+{
+ write (mctx.genldifFile, ldclt_write_genldif_buf, ldclt_write_genldif_nb);
+ ldclt_write_genldif_pt = ldclt_write_genldif_buf;
+ ldclt_write_genldif_nb = 0;
+}
+
+void
+ldclt_write_genldif (
+ char *str,
+ int lgth)
+{
+ /*
+ * First call ?
+ */
+ if (ldclt_write_genldif_buf == NULL)
+ {
+ ldclt_write_genldif_buf = (char *) malloc (65536);
+ ldclt_write_genldif_pt = ldclt_write_genldif_buf;
+ ldclt_write_genldif_nb = 0;
+ }
+
+ /*
+ * Buffer full ?
+ */
+ if (ldclt_write_genldif_nb + lgth >= 65536)
+ ldclt_flush_genldif();
+
+ /*
+ * Add to the buffer
+ */
+ strncpy (ldclt_write_genldif_pt, str, lgth);
+ ldclt_write_genldif_pt += lgth;
+ ldclt_write_genldif_nb += lgth;
+}
+
+
+
+
+
+
+
+
+
+ /* New */ /*JLS 19-03-01*/
+/* ****************************************************************************
+ FUNCTION : doGenldif
+ PURPOSE : Create a ldif file from the given parameters.
+ INPUT : tttctx = thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+doGenldif (
+ thread_context *tttctx)
+{
+ char newDn[MAX_DN_LENGTH]; /* DN of the new entry */
+ LDAPMod *attrs[MAX_ATTRIBS]; /* Attributes of this entry */
+ int i; /* For the loop */
+
+ /*
+ * Build a new entry
+ */
+ if (buildNewEntry (tttctx, newDn, attrs) < 0)
+ return (-1);
+
+ /*
+ * Dump this entry.
+ * Using a buffer speeds writes 3 times faster.
+ */
+ ldclt_write_genldif ("dn: ", 4); /*JLS 02-04-01*/
+ ldclt_write_genldif (newDn, strlen (newDn)); /*JLS 02-04-01*/
+ ldclt_write_genldif ("\n", 1); /*JLS 02-04-01*/
+ for (i=0 ; attrs[i]!=NULL ; i++) /*JLS 02-04-01*/
+ { /*JLS 02-04-01*/
+ ldclt_write_genldif (attrs[i]->mod_type, /*JLS 02-04-01*/
+ strlen (attrs[i]->mod_type)); /*JLS 02-04-01*/
+ ldclt_write_genldif (": ", 2); /*JLS 02-04-01*/
+ ldclt_write_genldif (attrs[i]->mod_values[0], /*JLS 02-04-01*/
+ strlen (attrs[i]->mod_values[0])); /*JLS 02-04-01*/
+ ldclt_write_genldif ("\n", 1); /*JLS 02-04-01*/
+ } /*JLS 02-04-01*/
+ ldclt_write_genldif ("\n", 1); /*JLS 02-04-01*/
+
+ /*
+ * Increment counters
+ */
+ if (incrementNbOpers (tttctx) < 0) /*JLS 28-03-01*/
+ return (-1); /*JLS 28-03-01*/
+
+ /*
+ * Free the memory and return
+ */
+ if (freeAttrib (attrs) < 0)
+ return (-1);
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : doAddEntry
+ PURPOSE : Perform an ldap_add() operation.
+ INPUT : tttctx = thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+doAddEntry (
+ thread_context *tttctx)
+{
+ char newDn[MAX_DN_LENGTH]; /* DN of the new entry */
+ LDAPMod *attrs[MAX_ATTRIBS]; /* Attributes of this entry */
+ int ret; /* Return values */
+ int retry; /* Retry after createMissingNodes() */
+
+ /*
+ * Connection to the server
+ * The function connectToServer() will take care of the various connection/
+ * disconnection, bind/unbind/close etc... requested by the user.
+ * The cost is one more function call in this application, but the
+ * resulting source code will be much more easiest to maintain.
+ */
+ if (connectToServer (tttctx) < 0)
+ return (-1);
+ if (!(tttctx->binded)) /*JLS 18-12-00*/
+ return (0); /*JLS 18-12-00*/
+
+ /*
+ * Do the add
+ * Maybe we are in synchronous mode ?
+ */
+ if (!(mctx.mode & ASYNC))
+ {
+ /*
+ * Build the new entry
+ */
+ if (buildNewEntry (tttctx, newDn, attrs) < 0)
+ return (-1);
+
+ /*
+ * We will retry with this entry...
+ */
+ retry = 1;
+ while (retry)
+ {
+ ret = ldap_add_s (tttctx->ldapCtx, newDn, attrs);
+ if (ret != LDAP_SUCCESS)
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot add (%s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, newDn, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+
+ /*
+ * Maybe we must create the intermediate nodes ?
+ */
+ if (ret != LDAP_NO_SUCH_OBJECT)
+ {
+ if ((ret == LDAP_ALREADY_EXISTS) && /*JLS 15-12-00*/
+ (mctx.mode & COUNT_EACH)) /*JLS 15-12-00*/
+ { /*JLS 15-12-00*/
+ if (incrementNbOpers (tttctx) < 0) /*JLS 15-12-00*/
+ return (-1); /*JLS 15-12-00*/
+ } /*JLS 15-12-00*/
+ retry = 0;
+ }
+ else
+ {
+ if (createMissingNodes (tttctx, newDn, NULL) < 0)
+ {
+ retry = 0;
+ printf ("ldclt[%d]: T%03d: Cannot create the intermediate nodes for %s\n",
+ mctx.pid, tttctx->thrdNum, newDn);
+ fflush (stdout);
+ return (-1);
+ }
+ if ((mctx.mode & VERBOSE) && (!(mctx.mode & QUIET)))
+ {
+ printf ("ldclt[%d]: T%03d: Intermediate nodes created for %s\n",
+ mctx.pid, tttctx->thrdNum, newDn);
+ fflush (stdout);
+ }
+ }
+ }
+ else
+ {
+ retry = 0;
+ if (incrementNbOpers (tttctx) < 0) /* Memorize operation */
+ return (-1);
+#ifdef SOLARIS /*JLS 14-11-00*/
+ if (mctx.slavesNb > 0)
+ if (opAdd (tttctx, LDAP_REQ_ADD, newDn, attrs, NULL, NULL) < 0)
+ return (-1);
+#endif /*JLS 14-11-00*/
+ }
+ }
+
+ /*
+ * Free the attributes
+ */
+ if (freeAttrib (attrs) < 0)
+ return (-1);
+
+ /*
+ * End of synchronous operations
+ */
+ return (0);
+ }
+
+ /*
+ * Here, we are in asynchronous mode...
+ * Too bad, lot of things to do here.
+ * First, let's see if we are above the reading threshold.
+ */
+ if (getPending (tttctx, &(mctx.timeval)) < 0)
+ return (-1);
+
+ /*
+ * Maybe we may send another request ?
+ * Well... there is no proper way to retrieve the error number for
+ * this, so I guess I may use direct access to the ldap context
+ * to read the field ld_errno.
+ */
+ if (tttctx->pendingNb > mctx.asyncMax)
+ {
+ if ((mctx.mode & VERBOSE) &&
+ (tttctx->asyncHit == 1) &&
+ (!(mctx.mode & SUPER_QUIET)))
+ {
+ tttctx->asyncHit = 1;
+ printf ("ldclt[%d]: T%03d: Max pending request hit.\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ }
+ }
+ else
+ {
+ if ((mctx.mode & VERBOSE) &&
+ (tttctx->asyncHit == 1) &&
+ (!(mctx.mode & SUPER_QUIET)))
+ {
+ tttctx->asyncHit = 0;
+ printf ("ldclt[%d]: T%03d: Restart sending.\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ }
+
+ /*
+ * Build the new entry
+ */
+ if (buildNewEntry (tttctx, newDn, attrs) < 0)
+ return (-1);
+
+ ret = ldap_add (tttctx->ldapCtx, newDn, attrs);
+ if (ret < 0)
+ {
+ if (ldap_get_option (tttctx->ldapCtx, LDAP_OPT_ERROR_NUMBER, &ret) < 0)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_get_option(LDAP_OPT_ERROR_NUMBER)\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ return (-1);
+ }
+ else
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot add(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+
+ /*
+ * Maybe we must create the intermediate nodes ?
+ * Question: is it likely probable that sush error is returned
+ * by the server on a *asynchornous* operation ?
+ */
+ if (ret == LDAP_NO_SUCH_OBJECT)
+ if (createMissingNodes (tttctx, newDn, NULL) < 0)
+ return (-1);
+ if ((ret == LDAP_ALREADY_EXISTS) && /*JLS 15-12-00*/
+ (mctx.mode & COUNT_EACH)) /*JLS 15-12-00*/
+ { /*JLS 15-12-00*/
+ if (incrementNbOpers (tttctx) < 0) /*JLS 15-12-00*/
+ return (-1); /*JLS 15-12-00*/
+ } /*JLS 15-12-00*/
+ }
+ }
+ else
+ {
+ /*
+ * Memorize the operation
+ */
+ if (msgIdAdd (tttctx, ret, newDn, newDn, attrs) < 0)
+ return (-1);
+ if (incrementNbOpers (tttctx) < 0)
+ return (-1);
+ tttctx->pendingNb++;
+ }
+ }
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: pendingNb=%d\n",
+ mctx.pid, tttctx->thrdNum, tttctx->pendingNb);
+
+ /*
+ * End of asynchronous operation... and also end of function.
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : doAttrReplace
+ PURPOSE : Perform an ldap_modify() operation, to replace an
+ attribute of the entry.
+ INPUT : tttctx = thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+doAttrReplace (
+ thread_context *tttctx)
+{
+ char newDn[MAX_DN_LENGTH]; /* DN of the new entry */
+ LDAPMod *attrs[MAX_ATTRIBS]; /* Attributes of this entry */
+ int ret; /* Return values */
+ int msgid; /* For asynchronous mode */
+
+ /*
+ * Connection to the server
+ * The function connectToServer() will take care of the various connection/
+ * disconnection, bind/unbind/close etc... requested by the user.
+ * The cost is one more function call in this application, but the
+ * resulting source code will be much more easiest to maintain.
+ */
+ if (connectToServer (tttctx) < 0)
+ return (-1);
+ if (!(tttctx->binded)) /*JLS 18-12-00*/
+ return (0); /*JLS 18-12-00*/
+
+ /*
+ * Do the modify
+ * Maybe we are in synchronous mode ?
+ */
+ if (!(mctx.mode & ASYNC))
+ {
+ /*
+ * Build the new entry
+ */
+ if (buildNewModAttrib (tttctx, newDn, attrs) < 0)
+ return (-1);
+
+ /*
+ * We will modify this entry
+ */
+ ret = ldap_modify_ext_s (tttctx->ldapCtx, newDn, attrs, NULL, NULL);
+ if (ret != LDAP_SUCCESS)
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot modify (%s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, newDn, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ }
+ else
+ {
+ if (incrementNbOpers (tttctx) < 0) /* Memorize operation */
+ return (-1);
+ }
+
+ /*
+ * Free the attributes
+ */
+ if (freeAttrib (attrs) < 0)
+ return (-1);
+
+ /*
+ * End of synchronous operations
+ */
+ return (0);
+ }
+
+ /*
+ * Here, we are in asynchronous mode...
+ * Too bad, lot of things to do here.
+ * First, let's see if we are above the reading threshold.
+ */
+ if (getPending (tttctx, &(mctx.timeval)) < 0)
+ return (-1);
+
+ /*
+ * Maybe we may send another request ?
+ * Well... there is no proper way to retrieve the error number for
+ * this, so I guess I may use direct access to the ldap context
+ * to read the field ld_errno.
+ */
+ if (tttctx->pendingNb > mctx.asyncMax)
+ {
+ if ((mctx.mode & VERBOSE) &&
+ (tttctx->asyncHit == 1) &&
+ (!(mctx.mode & SUPER_QUIET)))
+ {
+ tttctx->asyncHit = 1;
+ printf ("ldclt[%d]: T%03d: Max pending request hit.\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ }
+ }
+ else
+ {
+ if ((mctx.mode & VERBOSE) &&
+ (tttctx->asyncHit == 1) &&
+ (!(mctx.mode & SUPER_QUIET)))
+ {
+ tttctx->asyncHit = 0;
+ printf ("ldclt[%d]: T%03d: Restart sending.\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ }
+
+ /*
+ * Build the new entry
+ */
+ if (buildNewModAttrib (tttctx, newDn, attrs) < 0)
+ return (-1);
+
+ ret = ldap_modify_ext (tttctx->ldapCtx, newDn, attrs, NULL, NULL, &msgid);
+ if (ret != LDAP_SUCCESS)
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot modify(%s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, newDn, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ }
+ else
+ {
+ /*
+ * Memorize the operation
+ */
+ if (msgIdAdd (tttctx, msgid, newDn, newDn, attrs) < 0)
+ return (-1);
+ if (incrementNbOpers (tttctx) < 0)
+ return (-1);
+ tttctx->pendingNb++;
+ }
+ }
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: pendingNb=%d\n",
+ mctx.pid, tttctx->thrdNum, tttctx->pendingNb);
+
+ /*
+ * End of asynchronous operation... and also end of function.
+ */
+ return (0);
+}
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : doDeleteEntry
+ PURPOSE : Perform an ldap_delete() operation.
+ INPUT : tttctx = thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+doDeleteEntry (
+ thread_context *tttctx)
+{
+ int ret; /* Return values */
+ char delDn[MAX_DN_LENGTH]; /* The entry to delete */
+
+ /*
+ * Connection to the server
+ * The function connectToServer() will take care of the various connection/
+ * disconnection, bind/unbind/close etc... requested by the user.
+ * The cost is one more function call in this application, but the
+ * resulting source code will be much more easiest to maintain.
+ */
+ if (connectToServer (tttctx) < 0)
+ return (-1);
+ if (!(tttctx->binded)) /*JLS 18-12-00*/
+ return (0); /*JLS 18-12-00*/
+
+ /*
+ * Do the delete
+ * Maybe we are in synchronous mode ?
+ */
+ if (!(mctx.mode & ASYNC))
+ {
+ /*
+ * Random (or incremental) creation of the rdn to delete.
+ * The resulting rdn is in tttctx->bufFilter.
+ */
+ if (buildRandomRdnOrFilter (tttctx) < 0)
+ return (-1);
+ strcpy (delDn, tttctx->bufFilter);
+ strcat (delDn, ",");
+ strcat (delDn, tttctx->bufBaseDN);
+
+ ret = ldap_delete_s (tttctx->ldapCtx, delDn);
+ if (ret != LDAP_SUCCESS)
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_delete (%s), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, delDn, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ if ((ret == LDAP_NO_SUCH_OBJECT) && /*JLS 15-12-00*/
+ (mctx.mode & COUNT_EACH)) /*JLS 15-12-00*/
+ { /*JLS 15-12-00*/
+ if (incrementNbOpers (tttctx) < 0) /*JLS 15-12-00*/
+ return (-1); /*JLS 15-12-00*/
+ } /*JLS 15-12-00*/
+ }
+ else
+ {
+ if (incrementNbOpers (tttctx) < 0) /* Memorize operation */
+ return (-1);
+#ifdef SOLARIS /*JLS 14-11-00*/
+ if (mctx.slavesNb > 0)
+ if (opAdd (tttctx, LDAP_REQ_DELETE, delDn, NULL, NULL, NULL) < 0)
+ return (-1);
+#endif /*JLS 14-11-00*/
+ }
+
+ /*
+ * End of synchronous operations
+ */
+ return (0);
+ }
+
+ /*
+ * Here, we are in asynchronous mode...
+ * Too bad, lot of things to do here.
+ * First, let's see if we are above the reading threshold.
+ */
+ if (getPending (tttctx, &(mctx.timeval)) < 0)
+ return (-1);
+
+ /*
+ * Maybe we may send another request ?
+ * Well... there is no proper way to retrieve the error number for
+ * this, so I guess I may use direct access to the ldap context
+ * to read the field ld_errno.
+ */
+ if (tttctx->pendingNb > mctx.asyncMax)
+ {
+ if ((mctx.mode & VERBOSE) &&
+ (tttctx->asyncHit == 1) &&
+ (!(mctx.mode & SUPER_QUIET)))
+ {
+ tttctx->asyncHit = 1;
+ printf ("ldclt[%d]: T%03d: Max pending request hit.\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ }
+ }
+ else
+ {
+ if ((mctx.mode & VERBOSE) &&
+ (tttctx->asyncHit == 1) &&
+ (!(mctx.mode & SUPER_QUIET)))
+ {
+ tttctx->asyncHit = 0;
+ printf ("ldclt[%d]: T%03d: Restart sending.\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ }
+
+ /*
+ * Random (or incremental) creation of the rdn to delete.
+ * The resulting rdn is in tttctx->bufFilter.
+ */
+ if (buildRandomRdnOrFilter (tttctx) < 0)
+ return (-1);
+ strcpy (delDn, tttctx->bufFilter);
+ strcat (delDn, ",");
+ strcat (delDn, tttctx->bufBaseDN);
+
+ ret = ldap_delete (tttctx->ldapCtx, delDn);
+ if (ret < 0)
+ {
+ if (ldap_get_option (tttctx->ldapCtx, LDAP_OPT_ERROR_NUMBER, &ret) < 0)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_get_option(LDAP_OPT_ERROR_NUMBER)\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ return (-1);
+ }
+ else
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_delete(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ if ((ret == LDAP_NO_SUCH_OBJECT) && /*JLS 15-12-00*/
+ (mctx.mode & COUNT_EACH)) /*JLS 15-12-00*/
+ { /*JLS 15-12-00*/
+ if (incrementNbOpers (tttctx) < 0) /*JLS 15-12-00*/
+ return (-1); /*JLS 15-12-00*/
+ } /*JLS 15-12-00*/
+ }
+ }
+ else
+ {
+ /*
+ * Memorize the operation
+ */
+ if (incrementNbOpers (tttctx) < 0)
+ return (-1);
+ tttctx->pendingNb++;
+ }
+ }
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: pendingNb=%d\n",
+ mctx.pid, tttctx->thrdNum, tttctx->pendingNb);
+
+ /*
+ * End of asynchronous operation... and also end of doDeleteEntry().
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+ /* New function */ /*JLS 04-05-01*/
+/* ****************************************************************************
+ FUNCTION : doBindOnly
+ PURPOSE : Perform only bind/unbind operations.
+ INPUT : tttctx = thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+doBindOnly (
+ thread_context *tttctx)
+{
+ /*
+ * Connection to the server
+ * The function connectToServer() will take care of the various connection/
+ * disconnection, bind/unbind/close etc... requested by the user.
+ * The cost is one more function call in this application, but the
+ * resulting source code will be much more easiest to maintain.
+ */
+ if (connectToServer (tttctx) < 0)
+ return (-1);
+ if (!(tttctx->binded))
+ return (0);
+
+ if (incrementNbOpers (tttctx) < 0)
+ return (-1);
+
+ return (0);
+}
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : doExactSearch
+ PURPOSE : Perform one exact search operation.
+ INPUT : tttctx = thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+doExactSearch (
+ thread_context *tttctx)
+{
+ int ret; /* Return value */
+ LDAPMessage *res; /* LDAP results */
+ char **attrlist; /* Attribs list */ /*JLS 15-03-01*/
+
+ /*
+ * Connection to the server
+ * The function connectToServer() will take care of the various connection/
+ * disconnection, bind/unbind/close etc... requested by the user.
+ * The cost is one more function call in this application, but the
+ * resulting source code will be much more easiest to maintain.
+ */
+ if (connectToServer (tttctx) < 0) /*JLS 18-12-00*/
+ return (-1); /*JLS 18-12-00*/
+ if (!(tttctx->binded)) /*JLS 18-12-00*/
+ return (0); /*JLS 18-12-00*/
+
+ /*
+ * Build the filter
+ */
+ if (buildRandomRdnOrFilter (tttctx) < 0)
+ return (-1);
+
+ /*
+ * Prepear the attribute list
+ */
+ if (mctx.attrlistNb == 0) /*JLS 15-03-01*/
+ attrlist = NULL; /*JLS 15-03-01*/
+ else /*JLS 15-03-01*/
+ if (mctx.mode & RANDOM_ATTRLIST) /*JLS 15-03-01*/
+ attrlist = selectRandomAttrList (tttctx); /*JLS 15-03-01*/
+ else /*JLS 15-03-01*/
+ attrlist = mctx.attrlist; /*JLS 15-03-01*/
+
+ /*
+ * Do the search
+ * Maybe we are in synchronous mode ? I hope so, it is really
+ * much simple ;-)
+ */
+ if (!(mctx.mode & ASYNC))
+ {
+ ret = ldap_search_s (tttctx->ldapCtx, tttctx->bufBaseDN, mctx.scope,
+ tttctx->bufFilter, attrlist, /*JLS 15-03-01*/
+ mctx.attrsonly, &res); /*JLS 03-01-01*/
+ if (ret != LDAP_SUCCESS)
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ (void) printErrorFromLdap (tttctx, res, ret, /*JLS 03-08-00*/
+ "Cannot ldap_search()"); /*JLS 03-08-00*/
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ if ((ret == LDAP_NO_SUCH_OBJECT) && /*JLS 15-12-00*/
+ (mctx.mode & COUNT_EACH)) /*JLS 15-12-00*/
+ { /*JLS 15-12-00*/
+ if (incrementNbOpers (tttctx) < 0) /*JLS 15-12-00*/
+ return (-1); /*JLS 15-12-00*/
+ } /*JLS 15-12-00*/
+ }
+ else
+ {
+ if (incrementNbOpers (tttctx) < 0)/* Memorize operation */
+ return (-1);
+
+ /*
+ * Don't forget to free the returned message !
+ */
+ if ((ret = ldap_msgfree (res)) < 0)
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_msgfree(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ }
+ }
+
+ /*
+ * End of synchronous operation
+ */
+ return (0);
+ }
+
+ /*
+ * Here, we are in asynchronous mode...
+ * Too bad, lot of things to do here.
+ * First, let's see if we are above the reading threshold.
+ */
+ if (tttctx->pendingNb >= mctx.asyncMin)
+ {
+ /*
+ * Retrieve the next pending request
+ */
+ ret = ldap_result (tttctx->ldapCtx, LDAP_RES_ANY, 1, &(mctx.timeval), &res);
+ if (ret < 0)
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ (void) printErrorFromLdap (tttctx, res, ret, /*JLS 03-08-00*/
+ "Cannot ldap_result()"); /*JLS 03-08-00*/
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ }
+ else
+ {
+ tttctx->pendingNb--;
+
+ /*
+ * Don't forget to free the returned message !
+ */
+ if ((ret = ldap_msgfree (res)) < 0)
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_msgfree(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ }
+ }
+ }
+
+ /*
+ * Maybe we may send another request ?
+ * Well... there is no proper way to retrieve the error number for
+ * this, so I guess I may use direct access to the ldap context
+ * to read the field ld_errno.
+ */
+ if (tttctx->pendingNb > mctx.asyncMax)
+ {
+ if ((mctx.mode & VERBOSE) &&
+ (tttctx->asyncHit == 1) &&
+ (!(mctx.mode & SUPER_QUIET)))
+ {
+ tttctx->asyncHit = 1;
+ printf ("ldclt[%d]: T%03d: Max pending request hit.\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ }
+ }
+ else
+ {
+ if ((mctx.mode & VERBOSE) &&
+ (tttctx->asyncHit == 1) &&
+ (!(mctx.mode & SUPER_QUIET)))
+ {
+ tttctx->asyncHit = 0;
+ printf ("ldclt[%d]: T%03d: Restart sending.\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ }
+
+ ret = ldap_search (tttctx->ldapCtx, tttctx->bufBaseDN, mctx.scope,
+ tttctx->bufFilter, attrlist, /*JLS 15-03-01*/
+ mctx.attrsonly); /*JLS 03-01-01*/
+ if (ret < 0)
+ {
+ if (ldap_get_option (tttctx->ldapCtx, LDAP_OPT_ERROR_NUMBER, &ret) < 0)
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_get_option(LDAP_OPT_ERROR_NUMBER)\n",
+ mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ return (-1);
+ }
+ else
+ {
+ if (!((mctx.mode & QUIET) && ignoreError (ret)))
+ {
+ printf ("ldclt[%d]: T%03d: Cannot ldap_search(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ }
+ if (addErrorStat (ret) < 0)
+ return (-1);
+ if ((ret == LDAP_NO_SUCH_OBJECT) && /*JLS 15-12-00*/
+ (mctx.mode & COUNT_EACH)) /*JLS 15-12-00*/
+ { /*JLS 15-12-00*/
+ if (incrementNbOpers (tttctx) < 0) /*JLS 15-12-00*/
+ return (-1); /*JLS 15-12-00*/
+ } /*JLS 15-12-00*/
+ }
+ }
+ else
+ {
+ /*
+ * Memorize the operation
+ */
+ if (incrementNbOpers (tttctx) < 0)
+ return (-1);
+ tttctx->pendingNb++;
+ }
+ }
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: pendingNb=%d\n",
+ mctx.pid, tttctx->thrdNum, tttctx->pendingNb);
+
+ /*
+ * End of asynchronous operation... and also end of function.
+ */
+ return (0);
+}
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/ldclt.c b/ldap/servers/slapd/tools/ldclt/ldclt.c
new file mode 100644
index 00000000..95b0982f
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/ldclt.c
@@ -0,0 +1,3066 @@
+#ident "ldclt @(#)ldclt.c 1.89 01/06/19"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : ldclt.c
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 03 December 1998
+ DESCRIPTION :
+ This file is the main file of the ldclt tool. This tool
+ is targetted to be a multi-threaded ldap client,
+ specially designed to ensure good reliability of both
+ the basic ldap server purpose, and the replication
+ processes. It is *not* targetted against the
+ functionnality aspect of the product, but rather on the
+ stress and long-term operation.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+03/12/98 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+10/12/98 | JL Schwing | 1.2 : Add statistics report when exiting.
+---------+--------------+------------------------------------------------------
+10/12/98 | JL Schwing | 1.3 : Trap SIGQUIL to issue statistics without exit.
+ | Bug fix - call ldap_err2string() to decode ldap errs.
+---------+--------------+------------------------------------------------------
+11/12/98 | JL Schwing | 1.4 : Implement max errors threshold.
+ | fflush(stdout) after each printf.
+ | Will exit(0) on SIGINT
+---------+--------------+------------------------------------------------------
+14/12/98 | JL Schwing | 1.5 : Implement "-e close".
+ | Ensure thread not dead prior to issue "no activity"
+ | Add statts for the number of dead threads.
+---------+--------------+------------------------------------------------------
+16/12/98 | JL Schwing | 1.6 : Implement "-e add" and "-e delete".
+ | Improve printout of options.
+---------+--------------+------------------------------------------------------
+24/12/98 | JL Schwing | 1.7 : Fix memory problem.
+---------+--------------+------------------------------------------------------
+28/12/98 | JL Schwing | 1.8 : Add more statistics.
+---------+--------------+------------------------------------------------------
+29/12/98 | JL Schwing | 1.9 : Implement -Q.
+---------+--------------+------------------------------------------------------
+29/12/98 | JL Schwing | 1.10: Don't print pending stats if not asynchronous.
+---------+--------------+------------------------------------------------------
+29/12/98 | JL Schwing | 1.11: Fix typo.
+---------+--------------+------------------------------------------------------
+30/12/98 | JL Schwing | 1.12: Protect messages "no activity for %d seconds"
+ | by SUPER_QUIET mode.
+---------+--------------+------------------------------------------------------
+11/01/99 | JL Schwing | 1.13: Implement "-e emailPerson".
+---------+--------------+------------------------------------------------------
+13/01/99 | JL Schwing | 1.14: Implement "-e string".
+---------+--------------+------------------------------------------------------
+14/01/99 | JL Schwing | 1.15: Implement "-s <scope>".
+---------+--------------+------------------------------------------------------
+18/01/99 | JL Schwing | 1.16: Implement "-e randombase".
+---------+--------------+------------------------------------------------------
+18/01/99 | JL Schwing | 1.17: Implement "-e v2".
+---------+--------------+------------------------------------------------------
+21/01/99 | JL Schwing | 1.18: Implement "-e ascii".
+---------+--------------+------------------------------------------------------
+26/01/99 | JL Schwing | 1.19: Implement "-e noloop".
+---------+--------------+------------------------------------------------------
+28/01/99 | JL Schwing | 1.20: Implement "-T <total>".
+---------+--------------+------------------------------------------------------
+04/05/99 | JL Schwing | 1.21: Implement operations list.
+---------+--------------+------------------------------------------------------
+06/05/99 | JL Schwing | 1.25: Add proper shutdwon (wait for check threads).
+ | Implement "-P <master port>".
+---------+--------------+------------------------------------------------------
+06/05/99 | JL Schwing | 1.26: Implement "-e modrdn".
+---------+--------------+------------------------------------------------------
+06/05/99 | F. Pistolesi | 1.27: Some fixes.
+---------+--------------+------------------------------------------------------
+07/05/99 | JL Schwing | 1.28: Some fixes.
+---------+--------------+------------------------------------------------------
+19/05/99 | JL Schwing | 1.30: Implement "-e rename".
+ | Set the threads status to DEAD when nb of opers done.
+ | Lint-cleanup.
+---------+--------------+------------------------------------------------------
+21/05/99 | JL Schwing | 1.31: Fix Unitialized Memory Read for head's mutex.
+---------+--------------+------------------------------------------------------
+27/05/99 | JL Schwing | 1.32 : Add statistics to check threads.
+---------+--------------+------------------------------------------------------
+28/05/99 | JL Schwing | 1.33 : Add new option -W (wait).
+---------+--------------+------------------------------------------------------
+02/06/99 | JL Schwing | 1.34 : Add flag in main ctx to know if slave was
+ | connected or not.
+ | Add counter of operations received in check threads.
+---------+--------------+------------------------------------------------------
+06/03/00 | JL Schwing | 1.35: Test malloc() and strdup() return value.
+---------+--------------+------------------------------------------------------
+04/08/00 | JL Schwing | 1.36: Add stats on nb inactivity per thread.
+---------+--------------+------------------------------------------------------
+08/08/00 | JL Schwing | 1.37: Print global statistics every 1000 loops.
+---------+--------------+------------------------------------------------------
+18/08/00 | JL Schwing | 1.38: Print global statistics every 90 loops.
+ | Bug fix in this new feature.
+ | Print ldclt version.
+ | Print date of begin and of end.
+ | Add new function ldcltExit().
+---------+--------------+------------------------------------------------------
+25/08/00 | JL Schwing | 1.39: Implement consistent exit status...
+---------+--------------+------------------------------------------------------
+25/08/00 | JL Schwing | 1.40: Will only load images if -e emailPerson
+---------+--------------+------------------------------------------------------
+11/10/00 | B Kolics | 1.41: Implement "-Z certfile".
+---------+--------------+------------------------------------------------------
+26/10/00 | B Kolics | 1.42: Move SSL client initialization to basicInit()
+-------------------------------------------------------------------------------
+07/11/00 | JL Schwing | 1.43: Add handlers for dynamic load of ssl-related
+ | functions.
+ | Add new function sslDynLoadInit().
+-----------------------------------------------------------------------------
+07/11/00 | JL Schwing | 1.44: Implement "-e inetOrgPerson".
+---------+--------------+------------------------------------------------------
+08/11/00 | JL Schwing | 1.45: Improve error message when initiating ssl.
+---------+--------------+------------------------------------------------------
+13/11/00 | JL Schwing | 1.46: Add new options "-e randombaselow and ...high"
+ | Made use of exit (EXIT_PARAMS) in main().
+---------+--------------+------------------------------------------------------
+14/11/00 | JL Schwing | 1.47: Port on AIX.
+---------+--------------+------------------------------------------------------
+16/11/00 | JL Schwing | 1.48: Implement "-e imagesdir=path".
+---------+--------------+------------------------------------------------------
+17/11/00 | JL Schwing | 1.49: Implement "-e smoothshutdown".
+ | Forget to add mode decoding.
+ | Add new function shutdownThreads().
+---------+--------------+------------------------------------------------------
+21/11/00 | JL Schwing | 1.50: Implement "-e attreplace=name:mask"
+ | Add new function parseFilter().
+---------+--------------+------------------------------------------------------
+22/11/00 | JL Schwing | 1.51: Will now use LD_LIBRARY_PATH to load libssl.
+---------+--------------+------------------------------------------------------
+24/11/00 | B Kolics | 1.52: Added SSL client authentication
+---------+--------------+------------------------------------------------------
+29/11/00 | JL Schwing | 1.53: Port on NT 4.
+---------+--------------+------------------------------------------------------
+30/11/00 | JL Schwing | 1.54: Bug fix - bad error message if -eimagesdir=path
+---------+--------------+------------------------------------------------------
+01/12/00 | JL Schwing | 1.55: Port on Linux.
+---------+--------------+------------------------------------------------------
+01/12/00 | JL Schwing | 1.56: Port on HP-UX.
+---------+--------------+------------------------------------------------------
+07/12/00 | JL Schwing | 1.57: Bug fix - crash SIGBUS in main:1840 if no
+ | filter is provided to the tool.
+ | Build the argv list before parsing.
+---------+--------------+------------------------------------------------------
+15/12/00 | JL Schwing | 1.58: Implement "-e counteach".
+ | Implement "-e withnewparent".
+---------+--------------+------------------------------------------------------
+18/12/00 | JL Schwing | 1.59: Fix an exit status problem.
+---------+--------------+------------------------------------------------------
+18/12/00 | JL Schwing | 1.60: Minor fix/improvement in -I management.
+---------+--------------+------------------------------------------------------
+19/12/00 | JL Schwing | 1.61: Implement "-e noglobalstats".
+---------+--------------+------------------------------------------------------
+19/12/00 | JL Schwing | 1.62: Add comments.
+---------+--------------+------------------------------------------------------
+03/01/01 | JL Schwing | 1.63: Implement "-e attrsonly=value".
+---------+--------------+------------------------------------------------------
+05/01/01 | JL Schwing | 1.64: Implement "-e randombinddn" and associated
+ | "-e randombinddnlow/high"
+---------+--------------+------------------------------------------------------
+08/01/01 | JL Schwing | 1.65: Implement "-e scalab01".
+ | Replace all exit() by ldcltExit()
+---------+--------------+------------------------------------------------------
+12/01/01 | JL Schwing | 1.66: Second set of options for -e scalab01
+ | Sanity check in decodeExecParams().
+---------+--------------+------------------------------------------------------
+26/02/01 | JL Schwing | 1.67: Use ldclt_sleep() not sleep() (NT issue).
+---------+--------------+------------------------------------------------------
+08/03/01 | JL Schwing | 1.68: Change referrals handling.
+ | Use a static char[] to store ldclt version.
+ | Add new function decodeReferralParams().
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.69: Implement "-e commoncounter"
+ | Add a control for referral mode.
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.70: Implement "-e dontsleeponserverdown".
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.71: Misc fixes for HP-UX compilation.
+---------+--------------+------------------------------------------------------
+15/03/01 | JL Schwing | 1.72: Implement "-e attrlist=name:name:name"
+ | Implement "-e randomattrlist=name:name:name"
+---------+--------------+------------------------------------------------------
+19/03/01 | JL Schwing | 1.73: Implement "-e object=filename"
+ | Bug fix - understand EXIT_INIT in ldcltExit().
+ | Implement "-e genldif=filename"
+ | Add new function tttctxInit().
+---------+--------------+------------------------------------------------------
+21/03/01 | JL Schwing | 1.74: Implements variables in "-e object=filename"
+ | Add new function copyVersObject().
+---------+--------------+------------------------------------------------------
+23/03/01 | JL Schwing | 1.75: Implements data file list support in variants.
+ | Implements "-e rdn=value".
+ | Add new functions copyVersAttribute() decodeRdnParam()
+---------+--------------+------------------------------------------------------
+28/03/01 | JL Schwing | 1.76: Update options checking for "-e rdn=value".
+---------+--------------+------------------------------------------------------
+28/03/01 | JL Schwing | 1.77: Support -e commoncounter with -e rdn/object
+ | Remove MAX_ATTRLIST - use MAX_ATTRIBS.
+ | Bug fix - forget to initiate some fields in -e rdn=
+---------+--------------+------------------------------------------------------
+02/04/01 | JL Schwing | 1.78: Bug fix : large files support for -e genldif.
+---------+--------------+------------------------------------------------------
+03/04/01 | JL Schwing | 1.79: Port on _WIN32 and OSF1.
+---------+--------------+------------------------------------------------------
+05/04/01 | JL Schwing | 1.80: Bug fix - forget to print genldif file name.
+---------+--------------+------------------------------------------------------
+05/04/01 | JL Schwing | 1.81: Implement -e append.
+---------+--------------+------------------------------------------------------
+11/04/01 | JL Schwing | 1.82: Bug fix in -e append.
+---------+--------------+------------------------------------------------------
+23/04/01 | JL Schwing | 1.83: Improved arguments print at startup.
+ | Add new function buildArgListString().
+---------+--------------+------------------------------------------------------
+23/04/01 | JL Schwing | 1.84: Exit on error 2 if extra arguments provided.
+---------+--------------+------------------------------------------------------
+03/05/01 | JL Schwing | 1.85: Implement -e randombinddnfromfile=filename.
+---------+--------------+------------------------------------------------------
+04/05/01 | JL Schwing | 1.86: Implement -e bindonly.
+---------+--------------+------------------------------------------------------
+04/05/01 | JL Schwing | 1.87: Fix options check.
+---------+--------------+------------------------------------------------------
+16/06/01 | JL Schwing | 1.89: Allow SSL for HP-UX.
+---------+--------------+------------------------------------------------------
+*/
+
+#include <stdlib.h> /* exit(), etc... */
+#include <stdio.h> /* printf(), etc... */
+#include <signal.h> /* sigset(), etc... */
+#include <string.h> /* strerror(), etc... */
+#include <errno.h> /* errno, etc... */ /*JLS 06-03-00*/
+#include <fcntl.h> /* O_RDONLY, etc... */ /*JLS 02-04-01*/
+#include <time.h> /* ctime(), etc... */ /*JLS 18-08-00*/
+#include <lber.h> /* ldap C-API BER decl. */
+#include <ldap.h> /* ldap C-API decl. */
+#ifdef LDAP_H_FROM_QA_WKA
+#include <proto-ldap.h> /* ldap C-API prototypes */
+#endif
+#ifdef _WIN32 /*JLS 29-11-00*/
+#include <ldap_ssl.h> /* ldapssl_init(), etc... */ /*JLS 29-11-00*/
+#else
+#include <pthread.h> /* pthreads(), etc... */
+#include <unistd.h> /* close(), etc... */
+#include <dlfcn.h> /* dlopen(), etc... */ /*JLS 07-11-00*/
+#include <sys/resource.h> /* setrlimit(), etc... */
+#include <sys/time.h> /* struct rlimit, etc... */
+#endif
+#ifdef HPUX /*JLS 19-06-01*/
+#include <ldap_ssl.h> /* ldapssl_init(), etc... */ /*JLS 19-06-01*/
+#endif /*JLS 19-06-01*/
+
+#include "port.h" /* Portability definitions */ /*JLS 29-11-00*/
+#include "ldclt.h" /* This tool's include file */
+#include "utils.h" /* Utilities functions */ /*JLS 16-11-00*/
+#include "scalab01.h" /* Scalab01 specific */ /*JLS 12-01-01*/
+
+
+
+/*
+ * Global variables
+ */
+main_context mctx; /* Main context */
+thread_context tctx [MAX_THREADS]; /* Threads contextes */
+check_context cctx [MAX_SLAVES]; /* Check threads contextes */
+int masterPort=16000;
+
+extern char *ldcltVersion; /* ldclt version */ /*JLS 18-08-00*/
+
+
+
+
+
+
+
+
+
+
+ /* New function */ /*JLS 18-08-00*/
+/* ****************************************************************************
+ FUNCTION : ldcltExit
+ PURPOSE : Print the last data then exit the process.
+ INPUT : status = exit status
+ OUTPUT : None.
+ RETURN : None.
+ DESCRIPTION :
+ *****************************************************************************/
+void
+ldcltExit (
+ int status)
+{
+ time_t tim;
+
+ tim = time (NULL);
+ printf ("ldclt[%d]: Ending at %s", mctx.pid, ctime (&tim));
+ printf ("ldclt[%d]: Exit status %d - ", mctx.pid, status);
+ switch (status) /*JLS 25-08-00*/
+ { /*JLS 25-08-00*/
+ case EXIT_OK: /*JLS 25-08-00*/
+ printf ("No problem during execution.\n"); /*JLS 25-08-00*/
+ break; /*JLS 25-08-00*/
+ case EXIT_PARAMS: /*JLS 25-08-00*/
+ printf ("Error in parameters.\n"); /*JLS 25-08-00*/
+ break; /*JLS 25-08-00*/
+ case EXIT_MAX_ERRORS: /*JLS 25-08-00*/
+ printf ("Max errors reached.\n"); /*JLS 25-08-00*/
+ break; /*JLS 25-08-00*/
+ case EXIT_NOBIND: /*JLS 25-08-00*/
+ printf ("Cannot bind.\n"); /*JLS 25-08-00*/
+ break; /*JLS 25-08-00*/
+ case EXIT_LOADSSL: /*JLS 07-11-00*/
+ printf ("Cannot load libssl.\n"); /*JLS 07-11-00*/
+ break; /*JLS 07-11-00*/
+ case EXIT_INIT: /*JLS 19-03-01*/
+ printf ("Cannot initialize ldclt.\n"); /*JLS 19-03-01*/
+ break; /*JLS 19-03-01*/
+ case EXIT_OTHER: /*JLS 25-08-00*/
+ printf ("Other kind of error.\n"); /*JLS 25-08-00*/
+ break; /*JLS 25-08-00*/
+ default: /*JLS 25-08-00*/
+ printf ("Undocumented error - update source code.\n"); /*JLS 25-08-00*/
+ break; /*JLS 25-08-00*/
+ } /*JLS 25-08-00*/
+ exit (status);
+}
+
+
+
+
+
+
+#ifdef LDCLT_NO_DLOPEN /*JLS 01-12-00*/
+int /*JLS 29-11-00*/
+sslDynLoadInit (void) /*JLS 29-11-00*/
+{ /*JLS 29-11-00*/
+ mctx.sslctx.ldapssl_init = ldapssl_init;
+ mctx.sslctx.ldapssl_client_init = ldapssl_client_init;
+ mctx.sslctx.ldapssl_clientauth_init = ldapssl_clientauth_init;
+ mctx.sslctx.ldapssl_enable_clientauth = ldapssl_enable_clientauth;
+ return (0); /*JLS 29-11-00*/
+} /*JLS 29-11-00*/
+#else /*JLS 29-11-00*/
+ /* New function */ /*JLS 07-11-00*/
+/* ****************************************************************************
+ FUNCTION : sslDynLoadInit
+ PURPOSE : Initiates the dynamic load of ssl library.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+sslDynLoadInit (void)
+{
+ char *buf; /*JLS 22-11-00*/
+
+ /*
+ * Open the shared library...
+ * Will try to load the hard-coded PATH if not in the PATH.
+ */
+ mctx.sslctx.libssl = dlopen (SSL_LIB, RTLD_LAZY);
+ if (mctx.sslctx.libssl == NULL)
+ {
+ buf = (char *) malloc (strlen (SSL_LIB) + strlen (SSL_LIB_PATH) + 2);
+ strcat (buf, SSL_LIB_PATH);
+ strcat (buf, "/");
+ strcat (buf, SSL_LIB);
+
+ mctx.sslctx.libssl = dlopen (buf, RTLD_LAZY);
+ if (mctx.sslctx.libssl == NULL)
+ {
+ printf ("Cannot dlopen (%s) : %s\n", SSL_LIB, dlerror());
+ return (-1);
+ }
+ }
+
+ /*
+ * Find the address of function and data objects
+ */
+ mctx.sslctx.ldapssl_init = (LDAP *(*)(const char *, int, int))
+ dlsym (mctx.sslctx.libssl, "ldapssl_init");
+ if (mctx.sslctx.ldapssl_init == NULL)
+ {
+ printf ("Cannot dlsym (ldapssl_init) : %s\n", dlerror());
+ return (-1);
+ }
+
+ /*
+ * Next function...
+ */
+ mctx.sslctx.ldapssl_client_init = (int (*)(const char*, void*))
+ dlsym (mctx.sslctx.libssl, "ldapssl_client_init");
+ if (mctx.sslctx.ldapssl_client_init == NULL)
+ {
+ printf ("Cannot dlsym (ldapssl_client_init) : %s\n", dlerror());
+ return (-1);
+ }
+
+ /*
+ * Next function...
+ */
+ mctx.sslctx.ldapssl_clientauth_init =
+ (int (*)(char *, void *, int, char *, void *))
+ dlsym (mctx.sslctx.libssl, "ldapssl_clientauth_init");
+ if (mctx.sslctx.ldapssl_clientauth_init == NULL)
+ {
+ printf ("Cannot dlsym (ldapssl_enable_clientauth): %s\n", dlerror());
+ return (-1);
+ }
+
+ /*
+ * Next function...
+ */
+ mctx.sslctx.ldapssl_enable_clientauth =
+ (int (*)(LDAP *, char *, char *, char *))
+ dlsym (mctx.sslctx.libssl, "ldapssl_enable_clientauth");
+ if (mctx.sslctx.ldapssl_enable_clientauth == NULL)
+ {
+ printf ("Cannot dlsym (ldapssl_enable_clientauth): %s\n", dlerror());
+ return (-1);
+ }
+
+ return (0);
+}
+#endif /* LDCLT_NO_DLOPEN */ /*JLS 29-11-00*/
+
+
+
+
+
+
+
+
+ /* New */ /*JLS 23-03-01*/
+/* ****************************************************************************
+ FUNCTION : copyVersAttribute
+ PURPOSE : Copy a versatile object's attribute
+ INPUT : srcattr = source attribute
+ OUTPUT : dstattr = destination attribute
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+copyVersAttribute (
+ vers_attribute *srcattr,
+ vers_attribute *dstattr)
+{
+ vers_field *src; /* Source field */
+ vers_field *dst; /* Destination field */
+
+ dstattr->name = srcattr->name;
+ dstattr->src = srcattr->src;
+ dstattr->field = (vers_field *) malloc (sizeof (vers_field));
+
+ /*
+ * Copy each field of the attribute
+ */
+ src = srcattr->field;
+ dst = dstattr->field;
+ while (src != NULL)
+ {
+ memcpy (dst, src, sizeof (vers_field));
+ dst->commonField = src; /*JLS 28-03-01*/
+ if ((src = src->next) != NULL)
+ {
+ dst->next = (vers_field *) malloc (sizeof (vers_field));
+ dst = dst->next;
+ }
+ }
+
+ /*
+ * Do we need a buffer ?
+ */
+ if (srcattr->buf == NULL) /*JLS 28-03-01*/
+ dstattr->buf = NULL; /*JLS 28-03-01*/
+ else /*JLS 28-03-01*/
+ dstattr->buf = (char *) malloc (MAX_FILTER);
+
+ /*
+ * End of function
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+ /* New */ /*JLS 21-03-01*/
+/* ****************************************************************************
+ FUNCTION : copyVersObject
+ PURPOSE : Copy a versatile object.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : NULL if error, copy of the object else.
+ DESCRIPTION :
+ *****************************************************************************/
+vers_object *
+copyVersObject (
+ vers_object *srcobj)
+{
+ vers_object *newobj; /* New object */
+ int i; /* For the loops */
+
+ /*
+ * Copy the object and initiates the buffers...
+ */
+ newobj = (vers_object *) malloc (sizeof (vers_object));
+ newobj->attribsNb = srcobj->attribsNb;
+ newobj->fname = srcobj->fname;
+
+ /*
+ * Initiates the variables
+ */
+ for (i=0 ; i+VAR_MIN < VAR_MAX ; i++)
+ if (srcobj->var[i] == NULL)
+ newobj->var[i] = NULL;
+ else
+ newobj->var[i] = (char *) malloc (MAX_FILTER);
+
+ /*
+ * Maybe copy the rdn ?
+ */
+ if (srcobj->rdn != NULL)
+ {
+ newobj->rdnName = strdup (srcobj->rdnName);
+ newobj->rdn = (vers_attribute *) malloc (sizeof (vers_attribute));
+ if (copyVersAttribute (srcobj->rdn, newobj->rdn) < 0)
+ return (NULL);
+ }
+
+ /*
+ * Copy each attribute
+ */
+ for (i=0 ; i < srcobj->attribsNb ; i++)
+ if (copyVersAttribute (&(srcobj->attribs[i]), &(newobj->attribs[i])) < 0)
+ return (NULL);
+
+ /*
+ * Return the new object
+ */
+ return (newobj);
+}
+
+
+
+
+
+
+
+
+
+
+ /* New */ /*JLS 19-03-01*/
+/* ****************************************************************************
+ FUNCTION : tttctxInit
+ PURPOSE : Initiates the thread context
+ INPUT : num = thread number
+ OUTPUT : tttctx = initiates context
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+tttctxInit (
+ int num,
+ thread_context *tttctx)
+{
+ int ret; /* ldclt_mutex_init() return value */
+
+ /*
+ * Initialize data for this thread
+ */
+ tttctx->active = mctx.inactivMax + 1;
+ tttctx->attrlist[0] = NULL;
+ tttctx->exitStatus = EXIT_OK;
+ tttctx->nbInactRow = 0;
+ tttctx->nbInactTot = 0;
+ tttctx->mode = mctx.mode;
+ tttctx->status = FREE;
+ tttctx->thrdNum = num;
+ tttctx->totalReq = mctx.totalReq;
+ sprintf (tttctx->thrdId, "T%03d", tttctx->thrdNum);
+
+ if (mctx.mod2 & M2_OBJECT)
+ {
+ tttctx->bufObject1 = (char *) malloc (MAX_FILTER);
+ if ((tttctx->object = copyVersObject (&(mctx.object))) == NULL)
+ return(-1);
+ }
+
+ /*
+ * Initiate the mutexes that protect the private data structures.
+ */
+ if ((ret = ldclt_mutex_init(&(tttctx->nbOpers_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (ret));
+ fprintf (stderr,"Error: cannot initiate nbOpers_mutex %s\n",tttctx->thrdId);
+ fflush (stderr);
+ return (-1);
+ }
+ if ((ret = ldclt_mutex_init (&(tttctx->status_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (ret));
+ fprintf (stderr, "Error: cannot initiate status_mutex %s\n",tttctx->thrdId);
+ fflush (stderr);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : runThem
+ PURPOSE : This function implements the launching of the threads.
+ The monitoring will be realized in monitorIt().
+ This function also create the check threads if needed.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+runThem (void)
+{
+ int i; /* For the loops */ /*JLS 23-03-01*/
+ int ret; /* pthread_xxx() return value */
+
+
+#ifdef SOLARIS /*JLS 17-11-00*/
+ /*
+ * Maybe create the check operation threads.
+ */
+ if (mctx.slavesNb > 0)
+ {
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ {
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: Creating thread C%03d\n", mctx.pid, i);
+
+ /*
+ * Initiate context for this thread
+ */
+ cctx[i].headListOp = mctx.opListTail;
+ cctx[i].status = DEAD;
+ cctx[i].thrdNum = i;
+ cctx[i].calls = 0;
+ cctx[i].slaveName = NULL;
+ cctx[i].nbEarly = 0;
+ cctx[i].nbLate = 0;
+ cctx[i].nbLostOp = 0;
+ cctx[i].nbNotOnList = 0;
+ cctx[i].nbOpRecv = 0;
+ cctx[i].nbRepFail32 = 0;
+ cctx[i].nbRepFail68 = 0;
+ cctx[i].nbRepFailX = 0;
+ cctx[i].nbStillOnQ = 0;
+ }
+
+ /*
+ * Create the main (aka monitoring) check operation thread.
+ */
+ if ((ret = ldclt_thread_create (NULL, opCheckMain, NULL)) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s\n", mctx.pid, strerror (ret));
+ fprintf (stderr, "ldclt[%d]: Error: cannot create thread C%03d\n", mctx.pid, i);
+ fflush (stderr);
+ return (-1);
+ }
+ }
+#endif /* SOLARIS */ /*JLS 14-11-00*/
+
+ /*
+ * Maybe we need to start a special control thread ?
+ */
+ if (mctx.mode & SCALAB01) /*JLS 08-01-01*/
+ { /*JLS 08-01-01*/
+ ldclt_tid dummy; /* Don't need tid */ /*JLS 14-03-01*/
+ /*JLS 08-01-01*/
+ if ((ret = ldclt_thread_create (&dummy, /*JLS 08-01-01*/
+ scalab01_control, (void *)NULL)) != 0) /*JLS 08-01-01*/
+ { /*JLS 08-01-01*/
+ fprintf (stderr, "ldclt[%d]: %s\n", mctx.pid, strerror (ret)); /*JLS 08-01-01*/
+ fprintf (stderr, "ldclt[%d]: Error: cannot create thread scalab01_control\n", mctx.pid);
+ fflush (stderr); /*JLS 08-01-01*/
+ return (-1); /*JLS 08-01-01*/
+ } /*JLS 08-01-01*/
+ ldclt_sleep (2); /* Time to initialize */ /*JLS 26-02-01*/
+ } /*JLS 08-01-01*/
+
+ /*
+ * Ok, the check operation threads are now created (if needed).
+ * Let's create the (working) ldap client threads.
+ */
+ for (i=0 ; i<mctx.nbThreads ; i++)
+ {
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: Creating thread T%03d\n", mctx.pid, i);
+ if (tttctxInit (i, &(tctx[i])) < 0) /*JLS 19-03-01*/
+ return (-1); /*JLS 19-03-01*/
+
+ /*
+ * Create the thread
+ */
+ if ((ret = ldclt_thread_create (&(tctx[i].tid),
+ threadMain, (void *)&(tctx[i]))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s\n", mctx.pid, strerror (ret));
+ fprintf (stderr, "ldclt[%d]: Error: cannot create thread T%03d\n", mctx.pid, i);
+ fflush (stderr);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+ /* New function */ /*JLS 17-11-00*/
+/* ****************************************************************************
+ FUNCTION : shutdownThreads
+ PURPOSE : This function is targetted to shutdown the threads.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+shutdownThreads (void)
+{
+ int i; /* To process the threads */
+ int status; /* Thread's status */
+ int allDead; /* All threads are dead */
+ int maxLoops; /* Max loops waiting for DEAD */
+ int ret; /* Return code */
+
+ /*
+ * Command all the threads to shutdown.
+ * Must set to MUST_SHUTDOWN only if not dead, hence need to
+ * expose the mutex here...
+ */
+ for (i=0 ; i<mctx.nbThreads ; i++)
+ {
+ if ((ret = ldclt_mutex_lock (&(tctx[i].status_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "Cannot mutex_lock(T%03d), error=%d (%s)\n",
+ tctx[i].thrdNum, ret, strerror (ret));
+ printf ("Cannot command shutdwon to thread %d\n", tctx[i].thrdNum);
+ return (-1);
+ }
+ if (tctx[i].status != DEAD)
+ tctx[i].status = MUST_SHUTDOWN;
+ if ((ret = ldclt_mutex_unlock (&(tctx[i].status_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "Cannot mutex_unlock(T%03d), error=%d (%s)\n",
+ tctx[i].thrdNum, ret, strerror (ret));
+ printf ("Cannot command shutdwon to thread %d\n", tctx[i].thrdNum);
+ return (-1);
+ }
+ }
+
+ /*
+ * Wait (maybe ?) for the thread to actually die...
+ */
+ if (mctx.mode & SMOOTHSHUTDOWN)
+ {
+ int alivecnt;
+ allDead = 0;
+ maxLoops = 20;
+ while (maxLoops && !allDead)
+ {
+ allDead = 1;
+ alivecnt = 0;
+ for (i=0 ; i<mctx.nbThreads ; i++)
+ {
+ if (getThreadStatus (&(tctx[i]), &status) < 0)
+ {
+ printf ("Cannot command shutdown to thread %d\n", tctx[i].thrdNum);
+ return (-1);
+ }
+ if (status != DEAD)
+ {
+ allDead = 0;
+ alivecnt++;
+ }
+ }
+ maxLoops--;
+ if (!allDead)
+ ldclt_sleep (1);
+ }
+
+ if (!maxLoops)
+ {
+ printf ("%d thread(s) don't die...\n", alivecnt);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : monitorThem
+ PURPOSE : This function will monitor all the client threads.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+monitorThem (void)
+{
+ int i; /* To parse the threads */
+ int ret; /* Return value */
+ int nbOpers; /* This thread nb of operations */
+ int nbOpersTot; /* Total nb of operations */
+ int allDead = 0; /* All threads are dead */
+ int status; /* Thread's status */ /*JLS 17-11-00*/
+
+ while (!allDead)
+ {
+ ldclt_sleep (mctx.sampling);
+ nbOpersTot = 0;
+ allDead = 1; /* Assume all threads are dead */
+
+ /*
+ * Parse all the threads
+ */
+ for (i=0 ; i<mctx.nbThreads ; i++)
+ {
+ status = RUNNING;
+ if ((ret = ldclt_mutex_lock (&(tctx[i].nbOpers_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "ldclt[%d]: Cannot mutex_lock(T%03d), error=%d (%s)\n",
+ mctx.pid, tctx[i].thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+ nbOpers = tctx[i].nbOpers;
+ tctx[i].nbOpers = 0;
+ if ((ret = ldclt_mutex_unlock (&(tctx[i].nbOpers_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "ldclt[%d]: Cannot mutex_unlock(T%03d), error=%d (%s)\n",
+ mctx.pid, tctx[i].thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Report results, and check activity
+ */
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: nbOpers = %d\n", mctx.pid, tctx[i].thrdNum, nbOpers);
+ if (nbOpers != 0)
+ {
+ tctx[i].active = mctx.inactivMax + 1;
+ tctx[i].nbInactRow = 0; /*JLS 04-08-00*/
+ nbOpersTot += nbOpers;
+ }
+ else
+ {
+ tctx[i].active--;
+ if (getThreadStatus (&(tctx[i]), &status) < 0) /*JLS 17-11-00*/
+ { /*JLS 17-11-00*/
+ printf ("ldclt[%d]: T%03d: Cannot get status\n", mctx.pid, tctx[i].thrdNum);
+ status = RUNNING; /* Be conservative */ /*JLS 17-11-00*/
+ } /*JLS 17-11-00*/
+ if ((!(tctx[i].active)) && (status != DEAD)) /*JLS 17-11-00*/
+ {
+ tctx[i].nbInactRow++; /*JLS 04-08-00*/
+ tctx[i].nbInactTot++; /*JLS 04-08-00*/
+ if (!(mctx.mode & SUPER_QUIET))
+ {
+ printf ("ldclt[%d]: T%03d: No activity for %d seconds"
+ " -- %5d in row, total %5d\n", /*JLS 04-08-00*/
+ mctx.pid, tctx[i].thrdNum,
+ (mctx.inactivMax + 1) * mctx.sampling,
+ tctx[i].nbInactRow, tctx[i].nbInactTot);/*JLS 08-08-00*/
+ fflush (stdout);
+ }
+ tctx[i].active = mctx.inactivMax + 1;
+ mctx.nbNoActivity++;
+ }
+ }
+
+ if (status != DEAD) /*JLS 17-11-00*/
+ allDead = 0;
+ } /* For each thread */
+
+ /*
+ * Summary of operations
+ */
+ printf ("ldclt[%d]: Average rate: %7.2f/thr (%7.2f/sec), total: %6d\n",
+ mctx.pid, (float)nbOpersTot/(float)mctx.nbThreads,
+ (float)nbOpersTot/(float)mctx.sampling, nbOpersTot);
+ fflush (stdout);
+
+ /*
+ * Gather global statistics
+ */
+ mctx.totNbOpers += nbOpersTot;
+ mctx.totNbSamples++;
+
+ /*
+ * Maybe the number of samples is achieved ?
+ */
+ mctx.nbSamples--;
+ if (mctx.nbSamples == 0)
+ {
+ if (shutdownThreads() < 0) /*JLS 17-11-00*/
+ printf ("ldclt[%d]: Problem while shutting down threads,\n", mctx.pid);
+ allDead = 1;
+ printf ("ldclt[%d]: Number of samples achieved. Bye-bye...\n", mctx.pid);
+ }
+
+ /*
+ * Maybe global statistics to print ?
+ * Keep this at the end of the loop !!!
+ */
+ if ((!allDead) && (!(--mctx.globStatsCnt))) /*JLS 18-08-00*/
+ { /*JLS 08-08-00*/
+ if (printGlobalStatistics() < 0) /*JLS 08-08-00*/
+ { /*JLS 08-08-00*/
+ printf ("ldclt[%d]: Cannot print global statistics...\n", mctx.pid);
+ printf ("ldclt[%d]: Bye-bye...", mctx.pid);
+ ldcltExit (EXIT_OTHER); /*JLS 25-08-00*/
+ } /*JLS 08-08-00*/
+ mctx.globStatsCnt = DEF_GLOBAL_NB; /*JLS 08-08-00*/
+ } /*JLS 08-08-00*/
+ } /* while (!allDead) */
+
+#ifdef SOLARIS /*JLS 17-11-00*/
+ /*
+ * Well, all the productors are dead.
+ * Let's wait for the consumers (aka ckeck threads)
+ */
+ allDead = 0;
+ if (mctx.slavesNb > 0)
+ while (!allDead)
+ {
+ allDead=1;
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ if (cctx[i].status != DEAD)
+ allDead = 0;
+ if (!allDead)
+ ldclt_sleep (1);
+ }
+#endif /*JLS 17-11-00*/
+
+ /*
+ * Check the exit status of the threads
+ */
+ for (i=0 ; i<mctx.nbThreads ; i++) /*JLS 08-08-00*/
+ if (tctx[i].exitStatus > mctx.exitStatus) /*JLS 08-08-00*/
+ mctx.exitStatus = tctx[i].exitStatus; /*JLS 08-08-00*/
+
+ /*
+ * If there, all threads are dead
+ */
+ printf ("ldclt[%d]: All threads are dead - exit.\n", mctx.pid);
+ fflush (stdout);
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : printGlobalStatistics
+ PURPOSE : This function will print the global statistics numbers.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+printGlobalStatistics (void)
+{
+ int i; /* For the loops */
+ char buf[256]; /* To build the error strings */
+ int found; /* Something was found */
+ int total; /* Total statistics */
+
+ /*
+ * Pending operations statistics
+ */
+ if (mctx.mode & ASYNC)
+ {
+ total = 0;
+ for (i=0 ; i<mctx.nbThreads ; i++)
+ {
+ printf ("ldclt[%d]: T%03d: pendingNb=%d\n", mctx.pid, tctx[i].thrdNum, tctx[i].pendingNb);
+ total += tctx[i].pendingNb;
+ }
+ printf ("ldclt[%d]: Global total pending operations: %d\n", mctx.pid, total);
+ }
+
+ /*
+ * Operations statistics
+ */
+ printf ("ldclt[%d]: Global average rate: %7.2f/thr (%6.2f/sec), total: %6d\n",
+ mctx.pid, (float)mctx.totNbOpers/(float)mctx.nbThreads,
+ (float)mctx.totNbOpers/(float)(mctx.sampling*mctx.totNbSamples),
+ mctx.totNbOpers);
+
+ /*
+ * No activity reports.
+ */
+ if (mctx.nbNoActivity == 0)
+ printf ("ldclt[%d]: Global number times \"no activity\" reports: never\n", mctx.pid);
+ else
+ printf ("ldclt[%d]: Global number times \"no activity\" reports: %d\n",
+ mctx.pid, mctx.nbNoActivity);
+
+ /*
+ * Dead threads statistics
+ */
+ total = 0;
+ for (i=0 ; i<mctx.nbThreads ; i++)
+ if (tctx[i].status == DEAD)
+ total++;
+ if (total != 0)
+ printf ("ldclt[%d]: Global number of dead threads: %d\n", mctx.pid, total);
+
+ /*
+ * Errors statistics
+ * No mutex because this function is called at exit
+ * Note: Maybe implement a way to stop the running threads ?
+ */
+ found = 0;
+ for (i=0 ; i<MAX_ERROR_NB ; i++)
+ if (mctx.errors[i] > 0)
+ {
+ found = 1;
+ sprintf (buf, "(%s)", my_ldap_err2string (i));
+ printf ("ldclt[%d]: Global error %2d %s occurs %5d times\n",
+ mctx.pid, i, buf, mctx.errors[i]);
+ }
+ if (mctx.errorsBad > 0)
+ {
+ found = 1;
+ printf ("ldclt[%d]: Global illegal errors (codes not in [0, %d]) occurs %5d times\n",
+ mctx.pid, MAX_ERROR_NB-1, mctx.errorsBad);
+ }
+ if (!found)
+ printf ("ldclt[%d]: Global no error occurs during this session.\n", mctx.pid);
+
+ /*
+ * Check threads statistics
+ */
+ if (mctx.slavesNb > 0)
+ {
+ if (!(mctx.slaveConn))
+ printf ("ldclt[%d]: Problem: slave never connected !!!!\n", mctx.pid);
+ else
+ {
+ total = 0;
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ total += cctx[i].nbOpRecv;
+ printf ("ldclt[%d]: Global number of replication operations received: %5d\n",
+ mctx.pid, total);
+
+ total = 0;
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ total += cctx[i].nbEarly;
+ printf ("ldclt[%d]: Global number of early replication: %5d\n",
+ mctx.pid, total);
+
+ total = 0;
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ total += cctx[i].nbLate;
+ printf ("ldclt[%d]: Global number of late replication: %5d\n",
+ mctx.pid, total);
+
+ total = 0;
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ total += cctx[i].nbLostOp;
+ printf ("ldclt[%d]: Global number of lost operation: %5d\n",
+ mctx.pid, total);
+
+ total = 0;
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ total += cctx[i].nbNotOnList;
+ printf ("ldclt[%d]: Global number of not on list replication op.: %5d\n",
+ mctx.pid, total);
+
+ total = 0;
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ total += cctx[i].nbRepFail32;
+ printf ("ldclt[%d]: Global number of repl failed LDAP_NO_SUCH_OBJECT: %5d\n",
+ mctx.pid, total);
+
+ total = 0;
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ total += cctx[i].nbRepFail68;
+ printf ("ldclt[%d]: Global number of repl failed LDAP_ALREADY_EXISTS: %5d\n",
+ mctx.pid, total);
+
+ total = 0;
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ total += cctx[i].nbRepFailX;
+ printf ("ldclt[%d]: Global number of repl failed other error: %5d\n",
+ mctx.pid, total);
+
+ total = 0;
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ total += cctx[i].nbStillOnQ;
+ printf ("ldclt[%d]: Global number of repl still on Queue: %5d\n",
+ mctx.pid, total);
+ }
+ }
+
+ /*
+ * Normal end
+ */
+ fflush (stdout);
+ return (0);
+}
+
+
+
+
+
+
+
+#ifndef _WIN32 /*JLS 29-11-00*/
+/* ****************************************************************************
+ FUNCTION : trapVector
+ PURPOSE : Interruption vector for SIGINT and SIGQUIT
+ INPUT : sig = the signal
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION : Issue statistics report. If SIGINT, exit the tool.
+ The other signal (SIGQUIT) will only issue statistics.
+ *****************************************************************************/
+void
+trapVector (
+ int sig,
+ siginfo_t *siginfo,
+ void *truc)
+{
+ printf ("\n"); /* Jump over the ^C or ^\ */
+ (void) printGlobalStatistics();
+ if (sig == SIGINT)
+ {
+ printf ("Catch SIGINT - exit...\n");
+ fflush (stdout);
+ ldcltExit (mctx.exitStatus); /*JLS 25-08-00*/
+ }
+ return;
+}
+#endif /* _WIN32 */ /*JLS 29-11-00*/
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : initMainThread
+ PURPOSE : Initiates the main thread
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+initMainThread (void)
+{
+#ifndef _WIN32 /*JLS 29-11-00*/
+ struct sigaction act;
+
+ /*
+ * Trap SIGINT.
+ */
+#ifdef LDCLT_CAST_SIGACTION /*JLS 01-12-00*/
+ act.sa_handler = (void(*)(int)) trapVector; /*JLS 14-11-00*/
+#else /*JLS 14-11-00*/
+ act.sa_handler = trapVector;
+#endif /*JLS 14-11-00*/
+ act.sa_sigaction = trapVector;
+ act.sa_flags = SA_NODEFER;
+ sigemptyset (&(act.sa_mask));
+ sigaddset (&(act.sa_mask), SIGINT);
+ sigfillset (&(act.sa_mask));
+ if (sigaction (SIGINT, &act, NULL) < 0)
+ {
+ perror ("ldclt");
+ fprintf (stderr, "ldclt[%d]: Error: cannot sigaction(SIGINT)\n", mctx.pid);
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Trap SIGQUIT.
+ */
+#ifdef LDCLT_CAST_SIGACTION /*JLS 01-12-00*/
+ act.sa_handler = (void(*)(int)) trapVector; /*JLS 14-11-00*/
+#else /*JLS 14-11-00*/
+ act.sa_handler = trapVector;
+#endif /*JLS 14-11-00*/
+ act.sa_sigaction = trapVector;
+ act.sa_flags = SA_NODEFER;
+ sigemptyset (&(act.sa_mask));
+ sigaddset (&(act.sa_mask), SIGQUIT);
+ sigfillset (&(act.sa_mask));
+ if (sigaction (SIGQUIT, &act, NULL) < 0)
+ {
+ perror ("ldclt");
+ fprintf (stderr, "ldclt[%d]: Error: cannot sigaction(SIGQUIT)\n", mctx.pid);
+ fflush (stderr);
+ return (-1);
+ }
+#endif /* _WIN32 */ /*JLS 29-11-00*/
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+ /* New function */ /*JLS 21-11-00*/
+/* ****************************************************************************
+ FUNCTION : parseFilter
+ PURPOSE : This function parse a string in the form abcXXXdef
+ and returns the head, tail and number of digits for
+ the XXX part.
+ INPUT : src = source string
+ OUTPUT : head = head ==> abc
+ tail = tail ==> def
+ ndigits = number of digits
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+parseFilter (
+ char *src,
+ char **head,
+ char **tail,
+ int *ndigits)
+{
+ int i, j;
+
+ for (i=0 ; (i<strlen(src)) && (src[i]!='X') ; i++);
+ *head = (char *)malloc(i+1);
+ if (*head == NULL)
+ {
+ printf ("Error: cannot malloc(*head), error=%d (%s)\n",
+ errno, strerror (errno));
+ return (-1);
+ }
+ strncpy (*head, src, i);
+ (*head)[i] = '\0';
+
+ for (j=i ; (i<strlen(src)) && (src[j]=='X') ; j++);
+ *tail = (char *)malloc(strlen(src)-j+1);
+ if (*tail == NULL)
+ {
+ printf ("Error: cannot malloc(*tail), error=%d (%s)\n",
+ errno, strerror (errno));
+ return (-1);
+ }
+ strcpy (*tail, &(src[j]));
+
+ *ndigits = j-i;
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : basicInit
+ PURPOSE : This function performs the basic initializations of
+ this tool, as soon as all the options are decoded.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+basicInit (void)
+{
+#ifndef _WIN32 /*JLS 29-11-00*/
+ struct rlimit rlp; /* For setrlimit() */
+#endif /* _WIN32 */ /*JLS 29-11-00*/
+ int i; /* For the loops */ /*JLS 21-11-00*/
+ int ret; /* Return value */
+ int oflags;/* open() flags */ /*JLS 05-04-01*/
+
+ /*
+ * Misc inits
+ */
+ mctx.timeval.tv_sec = mctx.timeout;
+ mctx.timeval.tv_usec = 0;
+ mctx.timevalZero.tv_sec = 0;
+ mctx.timevalZero.tv_usec = 0;
+
+ /*
+ * Initiate the utilities
+ */
+ if (utilsInit() < 0) /*JLS 14-11-00*/
+ { /*JLS 14-11-00*/
+ fprintf (stderr, "Cannot initialize utilities.\n"); /*JLS 14-11-00*/
+ return (-1); /*JLS 14-11-00*/
+ } /*JLS 14-11-00*/
+
+ /*
+ * Maybe random data to be read from file ?
+ */
+ if (mctx.mod2 & M2_RNDBINDFILE) /*JLS 03-05-01*/
+ { /*JLS 03-05-01*/
+ mctx.rndBindDlf = dataListFile (mctx.rndBindFname); /*JLS 03-05-01*/
+ if (mctx.rndBindDlf == NULL) /*JLS 03-05-01*/
+ { /*JLS 03-05-01*/
+ fprintf (stderr, "Error : cannot read %s\n", /*JLS 03-05-01*/
+ mctx.rndBindFname); /*JLS 03-05-01*/
+ fflush (stderr); /*JLS 03-05-01*/
+ return (-1); /*JLS 03-05-01*/
+ } /*JLS 03-05-01*/
+ } /*JLS 03-05-01*/
+
+ /*
+ * Genldif output file ?
+ * This file should not already exist.
+ */
+ if (mctx.mod2 & M2_GENLDIF) /*JLS 19-03-01*/
+ { /*JLS 19-03-01*/
+ if (!(mctx.mod2 & M2_APPEND)) /*JLS 11-04-01*/
+ { /*JLS 11-04-01*/
+ mctx.genldifFile = open (mctx.genldifName, O_RDONLY); /*JLS 02-04-01*/
+ if (mctx.genldifFile != -1) /*JLS 02-04-01*/
+ { /*JLS 19-03-01*/
+ fprintf (stderr,"Error: File exits %s\n", /*JLS 19-03-01*/
+ mctx.genldifName); /*JLS 19-03-01*/
+ fflush (stderr); /*JLS 19-03-01*/
+ return (-1); /*JLS 19-03-01*/
+ } /*JLS 19-03-01*/
+ } /*JLS 11-04-01*/
+ if (mctx.mod2 & M2_APPEND) /*JLS 05-04-01*/
+ oflags = O_APPEND|O_WRONLY|O_CREAT; /*JLS 05-04-01*/
+ else /*JLS 05-04-01*/
+ oflags = O_EXCL|O_WRONLY|O_CREAT; /*JLS 05-04-01*/
+#if !defined(_WIN32) && !defined(OSF1) && !defined(__LP64__) && !defined(_LP64) /*JLS 05-04-01*/
+ oflags |= O_LARGEFILE; /*JLS 05-04-01*/
+#endif /*JLS 03-04-01*/
+ mctx.genldifFile = open (mctx.genldifName, oflags, 0666); /*JLS 05-04-01*/
+ if (mctx.genldifFile == -1) /*JLS 02-04-01*/
+ { /*JLS 19-03-01*/
+ fprintf (stderr, "ldclt: %s\n", strerror (errno)); /*JLS 19-03-01*/
+ fprintf (stderr,"Error: cannot create %s\n", /*JLS 19-03-01*/
+ mctx.genldifName); /*JLS 19-03-01*/
+ fflush (stderr); /*JLS 19-03-01*/
+ return (-1); /*JLS 19-03-01*/
+ } /*JLS 19-03-01*/
+ mctx.nbThreads = 1; /*JLS 19-03-01*/
+ } /*JLS 19-03-01*/
+
+ /*
+ * Maybe common counter ?
+ */
+ if ((mctx.mode & COMMON_COUNTER) &&(!(mctx.mod2 & M2_OBJECT)))/*JLS 28-03-01*/
+ { /*JLS 14-03-01*/
+ if ((ret = ldclt_mutex_init(&(mctx.lastVal_mutex))) != 0) /*JLS 14-03-01*/
+ { /*JLS 14-03-01*/
+ fprintf (stderr, "ldclt: %s\n", strerror (ret)); /*JLS 14-03-01*/
+ fprintf (stderr,"Error: cannot initiate lastVal_mutex\n");/*JLS 14-03-01*/
+ fflush (stderr); /*JLS 14-03-01*/
+ return (-1); /*JLS 14-03-01*/
+ } /*JLS 14-03-01*/
+ mctx.lastVal = mctx.randomLow-1; /*JLS 14-03-01*/
+ } /*JLS 14-03-01*/
+
+ /*
+ * Set appropriate number of files...
+ */
+#ifndef _WIN32 /*JLS 29-11-00*/
+ if (mctx.nbThreads > 54)
+ {
+ if (getrlimit (RLIMIT_NOFILE, &rlp) < 0)
+ {
+ perror ("ldclt");
+ fprintf (stderr, "Error: cannot getrlimit()\n");
+ fflush (stderr);
+ return (-1);
+ }
+ rlp.rlim_cur = rlp.rlim_max;
+ if (setrlimit (RLIMIT_NOFILE, &rlp) < 0)
+ {
+ perror ("ldclt");
+ fprintf (stderr, "Error: cannot setrlimit()\n");
+ fflush (stderr);
+ return (-1);
+ }
+ if (mctx.mode & VERBOSE)
+ printf ("Set file number to %u\n", (unsigned int)rlp.rlim_max);
+ }
+#endif /* _WIN32 */ /*JLS 29-11-00*/
+
+ /*
+ * Maybe an object to read ?
+ */
+ if (mctx.mod2 & M2_OBJECT) /*JLS 19-03-01*/
+ if (readObject (&(mctx.object)) < 0) /*JLS 19-03-01*/
+ { /*JLS 19-03-01*/
+ printf ("Error: cannot parse %s\n", mctx.object.fname); /*JLS 19-03-01*/
+ return (-1); /*JLS 19-03-01*/
+ } /*JLS 19-03-01*/
+
+ /*
+ * Maybe random filter to prepear ?
+ */
+ if ((mctx.mode & (RANDOM | INCREMENTAL)) &&
+ (!(mctx.mod2 & M2_RDN_VALUE))) /*JLS 23-03-01*/
+ {
+ if (parseFilter (mctx.filter, &(mctx.randomHead), /*JLS 21-11-00*/
+ &(mctx.randomTail), &(mctx.randomNbDigit)) < 0) /*JLS 21-11-00*/
+ { /*JLS 21-11-00*/
+ printf ("Error: cannot parse filter...\n"); /*JLS 21-11-00*/
+ return (-1); /*JLS 21-11-00*/
+ } /*JLS 21-11-00*/
+ }
+
+ /*
+ * Maybe random base DN to prepear ?
+ */
+ if (mctx.mode & RANDOM_BASE)
+ {
+ if (parseFilter (mctx.baseDN, &(mctx.baseDNHead), /*JLS 21-11-00*/
+ &(mctx.baseDNTail), &(mctx.baseDNNbDigit)) < 0) /*JLS 21-11-00*/
+ { /*JLS 21-11-00*/
+ printf ("Error: cannot parse base DN...\n"); /*JLS 21-11-00*/
+ return (-1); /*JLS 21-11-00*/
+ } /*JLS 21-11-00*/
+ }
+
+ /*
+ * Maybe random bind DN to prepear ?
+ */
+ if (mctx.mode & RANDOM_BINDDN) /*JLS 05-01-01*/
+ { /*JLS 05-01-01*/
+ if (parseFilter (mctx.bindDN, &(mctx.bindDNHead), /*JLS 05-01-01*/
+ &(mctx.bindDNTail), &(mctx.bindDNNbDigit)) < 0) /*JLS 05-01-01*/
+ { /*JLS 05-01-01*/
+ printf ("Error: cannot parse bind DN...\n"); /*JLS 05-01-01*/
+ return (-1); /*JLS 05-01-01*/
+ } /*JLS 05-01-01*/
+ if (parseFilter (mctx.passwd, &(mctx.passwdHead), /*JLS 05-01-01*/
+ &(mctx.passwdTail), &(mctx.passwdNbDigit)) < 0) /*JLS 05-01-01*/
+ { /*JLS 05-01-01*/
+ printf ("Error: cannot parse password...\n"); /*JLS 05-01-01*/
+ return (-1); /*JLS 05-01-01*/
+ } /*JLS 05-01-01*/
+ } /*JLS 05-01-01*/
+
+ /*
+ * Maybe an attribute replacement to prepear ?
+ */
+ if (mctx.mode & ATTR_REPLACE) /*JLS 21-11-00*/
+ { /*JLS 21-11-00*/
+ /*
+ * Find the attribute name
+ */
+ for (i=0 ; (i<strlen(mctx.attrpl)) && /*JLS 21-11-00*/
+ (mctx.attrpl[i]!=':') ; i++); /*JLS 21-11-00*/
+ mctx.attrplName = (char *)malloc(i+1); /*JLS 21-11-00*/
+ strncpy (mctx.attrplName, mctx.attrpl, i); /*JLS 21-11-00*/
+ mctx.attrplName[i] = '\0'; /*JLS 21-11-00*/
+
+ /*
+ * Parse the attribute value
+ */
+ if (parseFilter (mctx.attrpl+i+1, &(mctx.attrplHead), /*JLS 21-11-00*/
+ &(mctx.attrplTail), &(mctx.attrplNbDigit)) < 0) /*JLS 21-11-00*/
+ { /*JLS 21-11-00*/
+ printf ("Error: cannot parse attreplace...\n"); /*JLS 21-11-00*/
+ return (-1); /*JLS 21-11-00*/
+ } /*JLS 21-11-00*/
+ } /*JLS 21-11-00*/
+
+
+ /*
+ * Initiates statistics fields
+ */
+ mctx.totNbOpers = 0;
+ mctx.totNbSamples = 0;
+ mctx.errorsBad = 0;
+ for (i=0 ; i<MAX_ERROR_NB ; i++)
+ mctx.errors[i] = 0;
+
+ /*
+ * Initiate the mutex that protect the errors statistics
+ */
+ if ((ret = ldclt_mutex_init(&(mctx.errors_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (ret));
+ fprintf (stderr, "Error: cannot initiate errors_mutex\n");
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Load the images
+ */
+ if (mctx.mode & (OC_EMAILPERSON|OC_INETORGPRSON)) /*JLS 07-11-00*/
+ if (loadImages (mctx.imagesDir) < 0) /*JLS 16-11-00*/
+ return (-1);
+
+ /*
+ * Maybe we should initiate the operation list mutex and other check-related
+ * thing...
+ */
+ if (mctx.slavesNb > 0)
+ {
+ /*
+ * Initiates the mutex
+ */
+ if ((ret = ldclt_mutex_init(&(mctx.opListTail_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (ret));
+ fprintf (stderr, "Error: cannot initiate opListTail_mutex\n");
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Initiates the first operation with empty dummy values
+ * We need to initiate this entry to dummy values because some opXyz()
+ * functions will access this entry careless.
+ */
+ mctx.opListTail = (oper *) malloc (sizeof (oper));
+ if (mctx.opListTail == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Error: cannot malloc(mctx.opListTail), error=%d (%s)\n",
+ errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ mctx.opListTail->dn = strdup("Dummy initial dn");
+ if (mctx.opListTail->dn == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Error: cannot strdup(mctx.opListTail->dn), error=%d (%s)\n",
+ errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ mctx.opListTail->attribs[0].type = NULL;
+ mctx.opListTail->newRdn = NULL;
+ mctx.opListTail->newParent = NULL;
+ mctx.opListTail->skipped = 0;
+ mctx.opListTail->next = NULL;
+ if ((ret=ldclt_mutex_init(&(mctx.opListTail->skipped_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (ret));
+ fprintf (stderr, "Error: cannot initiate opListTail->skipped_mutex\n");
+ fflush (stderr);
+ return (-1);
+ }
+ }
+
+#ifdef LDCLTSSL
+ /*
+ * SSL is enabled ?
+ */
+ if (mctx.mode & SSL)
+ {
+ /*
+ * The initialization of certificate based and basic authentication differs
+ * B Kolics 23-11-00
+ */
+ if (mctx.mode & CLTAUTH)
+ {
+ if ((*(mctx.sslctx.ldapssl_clientauth_init))
+ (mctx.certfile, NULL, 1, mctx.keydbfile, NULL) < 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (errno));
+ fprintf (stderr, "Cannot ldapssl_clientauth_init (%s,%s)\n",
+ mctx.certfile, mctx.keydbfile);
+ fflush (stderr);
+ return (-1);
+ }
+ } else {
+ if ((*(mctx.sslctx.ldapssl_client_init)) /*JLS 07-11-00*/
+ (mctx.certfile, NULL) < 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (errno));
+ fprintf (stderr, "Cannot ldapssl_client_init (%s)\n", /*JLS 08-11-00*/
+ mctx.certfile); /*JLS 08-11-00*/
+ fflush (stderr);
+ return (-1);
+ }
+ }
+ }
+#endif /* LDCLTSSL */
+
+ /*
+ * Specific scenarios initialization...
+ */
+ if (mctx.mode & SCALAB01) /*JLS 08-01-01*/
+ if (scalab01_init() < 0) /*JLS 08-01-01*/
+ { /*JLS 08-01-01*/
+ fprintf (stderr, "ldclt: cannot init scalab01\n"); /*JLS 08-01-01*/
+ fflush (stderr); /*JLS 08-01-01*/
+ return (-1); /*JLS 08-01-01*/
+ } /*JLS 08-01-01*/
+
+ /*
+ * Normal end
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : printModeValues
+ PURPOSE : This function is targetted to print the bits mask of
+ the mode field.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : None.
+ DESCRIPTION :
+ *****************************************************************************/
+void
+dumpModeValues (void)
+{
+ if (mctx.mode & QUIET)
+ printf (" quiet");
+ if (mctx.mode & SUPER_QUIET)
+ printf (" super_quiet");
+ if (mctx.mode & VERBOSE)
+ printf (" verbose");
+ if (mctx.mode & VERY_VERBOSE)
+ printf (" very_verbose");
+ if (mctx.mode & COUNT_EACH) /*JLS 15-12-00*/
+ printf (" counteach"); /*JLS 15-12-00*/
+ if (mctx.mode & LDAP_V2)
+ printf (" v2");
+ if (mctx.mode & ASYNC)
+ printf (" asynchronous");
+ if (mctx.mode & INCREMENTAL)
+ printf (" incremental");
+ if (mctx.mode & COMMON_COUNTER) /*JLS 14-03-01*/
+ printf (" commoncounter"); /*JLS 14-03-01*/
+ if (mctx.mode & NOLOOP)
+ printf (" noloop");
+ if (mctx.mode & RANDOM)
+ printf (" random");
+ if (mctx.mode & RANDOM_BASE)
+ printf (" randombase");
+ if (mctx.mode & RANDOM_BINDDN) /*JLS 05-01-01*/
+ printf (" randombinddn"); /*JLS 05-01-01*/
+ if (mctx.mode & STRING)
+ printf (" string");
+ if (mctx.mode & ASCII_7BITS)
+ printf (" ascii");
+ if (mctx.mode & CLOSE_FD)
+ printf (" close_fd");
+ if (mctx.mode & BIND_EACH_OPER)
+ printf (" bind_each_operation");
+ if (mctx.mode & SSL)
+ printf (" ssl");
+ if (mctx.mode & CLTAUTH)
+ printf (" ssl_with_client_authentication"); /* BK 23-11-00*/
+ if (mctx.mode & SMOOTHSHUTDOWN) /*JLS 17-11-00*/
+ printf (" smoothshutdown"); /*JLS 17-11-00*/
+ if (mctx.mode & DONT_SLEEP_DOWN) /*JLS 14-03-01*/
+ printf (" dontsleeponserverdown"); /*JLS 14-03-01*/
+
+ if (mctx.mode & ADD_ENTRIES)
+ printf (" add");
+ if (mctx.mode & ATTR_REPLACE) /*JLS 21-11-00*/
+ printf (" attrib_replace"); /*JLS 21-11-00*/
+ if (mctx.mod2 & M2_BINDONLY) /*JLS 04-05-01*/
+ printf (" bindonly"); /*JLS 04-05-01*/
+ if (mctx.mode & DELETE_ENTRIES)
+ printf (" delete");
+ if (mctx.mode & EXACT_SEARCH)
+ printf (" exact_search");
+ if (mctx.mode & RANDOM_ATTRLIST) /*JLS 15-03-01*/
+ printf (" randomattrlist"); /*JLS 15-03-01*/
+ if (mctx.mode & RENAME_ENTRIES)
+ printf (" rename");
+ if (mctx.mode & WITH_NEWPARENT) /*JLS 15-12-00*/
+ printf (" withnewparent"); /*JLS 15-12-00*/
+
+ if (mctx.mod2 & M2_GENLDIF) /*JLS 08-01-01*/
+ printf (" genldif=%s", mctx.genldifName); /*JLS 05-04-01*/
+ if (mctx.mode & SCALAB01) /*JLS 08-01-01*/
+ printf (" scalab01"); /*JLS 08-01-01*/
+
+ if (mctx.mode & OC_EMAILPERSON)
+ printf (" class=emailPerson");
+ if (mctx.mode & OC_PERSON)
+ printf (" class=person");
+ if (mctx.mode & OC_INETORGPRSON) /*JLS 07-11-00*/
+ printf (" class=inetOrgPerson"); /*JLS 07-11-00*/
+ if (mctx.mod2 & M2_OBJECT) /*JLS 19-03-01*/
+ printf (" object=%s", mctx.object.fname); /*JLS 19-03-01*/
+ if (mctx.mod2 & M2_RNDBINDFILE) /*JLS 04-05-01*/
+ printf (" randombinddnfromfile=%s", mctx.rndBindFname); /*JLS 04-05-01*/
+ return;
+}
+
+
+
+
+
+
+
+
+/*
+ * Scope parameters (-s sub-options)
+ */
+char *scopeParams[] = {
+#define SP_ONE 0
+ "one",
+#define SP_SUBTREE 1
+ "subtree",
+#define SP_BASE 2
+ "base",
+ NULL
+};
+
+/* ****************************************************************************
+ FUNCTION : decodeScopeParams
+ PURPOSE : Decode the scope parameters (ak asub-options of the
+ option -s).
+ INPUT : optarg = argument to decode
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+decodeScopeParams (
+ char *optarg)
+{
+ char *suboptions; /* To parse optarg */
+ char *subvalue; /* Current sub-option */
+
+ suboptions = optarg;
+ while (*suboptions != '\0')
+ {
+ switch (getsubopt (&suboptions, scopeParams, &subvalue))
+ {
+ case SP_BASE:
+ mctx.scope = LDAP_SCOPE_BASE;
+ break;
+ case SP_ONE:
+ mctx.scope = LDAP_SCOPE_ONELEVEL;
+ break;
+ case SP_SUBTREE:
+ mctx.scope = LDAP_SCOPE_SUBTREE;
+ break;
+ default:
+ fprintf (stderr, "Error: illegal option -s %s\n", subvalue);
+ return (-1);
+ break;
+ }
+ }
+ return (0);
+}
+
+
+
+
+
+
+ /* New function */ /*JLS 08-03-01*/
+/* ****************************************************************************
+ FUNCTION : decodeReferralParams
+ PURPOSE : Decode -e referral params.
+ INPUT : val = value to decode
+ OUTPUT : None.
+ RETURN : -1 if error, decoded value otherwise.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+decodeReferralParams (
+ char *val)
+{
+ if (val == NULL)
+ {
+ fprintf (stderr, "Error: missing arg referral\n");
+ return (-1);
+ }
+ if (!strcmp (val, "on"))
+ return (REFERRAL_ON);
+ if (!strcmp (val, "off"))
+ return (REFERRAL_OFF);
+ if (!strcmp (val, "rebind"))
+ return (REFERRAL_REBIND);
+
+ fprintf (stderr, "Error: illegal arg %s for referral\n", val);
+ return (-1);
+}
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : addAttrToList
+ PURPOSE : Add attributes in the attribute list.
+ INPUT : list = list to process.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+addAttrToList (
+ char *list)
+{
+ int start; /* Start of the attr name */
+ int end; /* End of the attr name */
+
+ /*
+ * Sanity check
+ */
+ if ((list == NULL) || (!(strlen(list))))
+ {
+ fprintf (stderr, "Error: missing attrlist\n");
+ return (-1);
+ }
+
+ /*
+ * The main loop.
+ */
+ start = 0;
+ while (start < strlen (list))
+ {
+ /*
+ * Maybe no more room in the structures ?
+ */
+ if ((mctx.attrlistNb+1) == MAX_ATTRIBS)
+ {
+ fprintf (stderr, "Error : too many attributes in attrlist\n");
+ return (-1);
+ }
+
+ for (end=start ; (list[end]!='\0') && (list[end]!=':') ; end++);
+ mctx.attrlist[mctx.attrlistNb] = (char *) malloc (1+end-start);
+ strncpy (mctx.attrlist[mctx.attrlistNb], &(list[start]), end-start);
+ mctx.attrlist[mctx.attrlistNb][end-start] = '\0';
+ mctx.attrlistNb++;
+ start = end+1;
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+ /* New */ /*JLS 23-03-01*/
+/* ****************************************************************************
+ FUNCTION : decodeRdnParam
+ PURPOSE : Decodes a -e rdn=value parameter.
+ INPUT : value = value to decode.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+decodeRdnParam (
+ char *value)
+{
+ int i; /* For the loops */
+
+ /*
+ * Note : ldclt does allow parameters overload. Ideally, we should
+ * free memory if a rdn has already been provided, but let's
+ * simply lost this data...
+ * Anyway, there is not a lot of memory used here...
+ */
+ mctx.object.rdn = (vers_attribute *) malloc (sizeof (vers_attribute));
+ mctx.object.rdn->buf = NULL; /*JLS 28-03-01*/
+
+ /*
+ * Find this attribute's name
+ */
+ for (i=0 ; (value[i] != '\0') && (value[i] != ':') ; i++);
+ if (value[i] == '\0')
+ {
+ fprintf (stderr, "Error: missing rdn attribute name\n");
+ return (-1);
+ }
+ mctx.object.rdnName = (char *) malloc (i+1);
+ strncpy (mctx.object.rdnName, value, i);
+ mctx.object.rdnName[i] = '\0';
+
+ /*
+ * Decode the value
+ */
+ if (parseAttribValue ("-e rdn=", &(mctx.object),
+ value+i+1, mctx.object.rdn) < 0)
+ return (-1);
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ * Exec params (-e sub-options)
+ */
+char *execParams[] = {
+#define EP_EXACT_SEARCH 0
+ "esearch",
+#define EP_BIND_EACH_OPER 1
+ "bindeach",
+#define EP_RANDOM 2
+ "random",
+#define EP_CLOSE_FD 3
+ "close",
+#define EP_INCREMENTAL 4
+ "incr",
+#define EP_ADD_ENTRIES 5
+ "add",
+#define EP_OC_PERSON 6
+ "person",
+#define EP_DELETE_ENTRIES 7
+ "delete",
+#define EP_OC_EMAILPERSON 8
+ "emailPerson",
+#define EP_STRING 9
+ "string",
+#define EP_RANDOM_BASE 10
+ "randombase",
+#define EP_LDAP_V2 11
+ "v2",
+#define EP_ASCII_7BITS 12
+ "ascii",
+#define EP_NOLOOP 13
+ "noloop",
+#define EP_RENAME 14
+ "rename",
+#define EP_OC_INETORGPRSON 15 /*JLS 07-11-00*/
+ "inetOrgPerson", /*JLS 07-11-00*/
+#define EP_RANDOM_BASE_LOW 16 /*JLS 13-11-00*/
+ "randombaselow", /*JLS 13-11-00*/
+#define EP_RANDOM_BASE_HIGH 17 /*JLS 13-11-00*/
+ "randombasehigh", /*JLS 13-11-00*/
+#define EP_IMAGES_DIR 18 /*JLS 16-11-00*/
+ "imagesdir", /*JLS 16-11-00*/
+#define EP_SMOOTH_SHUTDOWN 19 /*JLS 17-11-00*/
+ "smoothshutdown", /*JLS 17-11-00*/
+#define EP_ATT_REPLACE 20 /*JLS 21-11-00*/
+ "attreplace", /*JLS 21-11-00*/
+#define EP_CLTCERT_NAME 21 /* BK 23-11-00*/
+ "cltcertname", /* BK 23-11-00*/
+#define EP_KEYDB_FILE 22 /* BK 23-11-00*/
+ "keydbfile", /* BK 23-11-00*/
+#define EP_KEYDB_PIN 23 /* BK 23-11-00*/
+ "keydbpin", /* BK 23-11-00*/
+#define EP_COUNT_EACH 24 /*JLS 15-12-00*/
+ "counteach", /*JLS 15-12-00*/
+#define EP_WITH_NEWPARENT 25 /*JLS 15-12-00*/
+ "withnewparent", /*JLS 15-12-00*/
+#define EP_NO_GLOBAL_STATS 26 /*JLS 19-12-00*/
+ "noglobalstats", /*JLS 19-12-00*/
+#define EP_ATTRSONLY 27 /*JLS 03-01-01*/
+ "attrsonly", /*JLS 03-01-01*/
+#define EP_RANDOMBINDDN 28 /*JLS 05-01-01*/
+ "randombinddn", /*JLS 05-01-01*/
+#define EP_RANDOMBINDDNHIGH 29 /*JLS 05-01-01*/
+ "randombinddnhigh", /*JLS 05-01-01*/
+#define EP_RANDOMBINDDNLOW 30 /*JLS 05-01-01*/
+ "randombinddnlow", /*JLS 05-01-01*/
+#define EP_SCALAB01 31 /*JLS 08-01-01*/
+ "scalab01", /*JLS 08-01-01*/
+#define EP_SCALAB01_CNXDURATION 32 /*JLS 12-01-01*/
+ "scalab01_cnxduration", /*JLS 12-01-01*/
+#define EP_SCALAB01_WAIT 33 /*JLS 12-01-01*/
+ "scalab01_wait", /*JLS 12-01-01*/
+#define EP_SCALAB01_MAXCNXNB 34 /*JLS 12-01-01*/
+ "scalab01_maxcnxnb", /*JLS 12-01-01*/
+#define EP_REFERRAL 35 /*JLS 08-03-01*/
+ "referral", /*JLS 08-03-01*/
+#define EP_COMMONCOUNTER 36 /*JLS 14-03-01*/
+ "commoncounter", /*JLS 14-03-01*/
+#define EP_DONTSLEEPONSERVERDOWN 37 /*JLS 14-03-01*/
+ "dontsleeponserverdown", /*JLS 14-03-01*/
+#define EP_ATTRLIST 38 /*JLS 15-03-01*/
+ "attrlist", /*JLS 15-03-01*/
+#define EP_RANDOMATTRLIST 39 /*JLS 15-03-01*/
+ "randomattrlist", /*JLS 15-03-01*/
+#define EP_OBJECT 40 /*JLS 19-03-01*/
+ "object", /*JLS 19-03-01*/
+#define EP_GENLDIF 41 /*JLS 19-03-01*/
+ "genldif", /*JLS 19-03-01*/
+#define EP_RDN 42 /*JLS 23-03-01*/
+ "rdn", /*JLS 23-03-01*/
+#define EP_APPEND 43 /*JLS 05-04-01*/
+ "append", /*JLS 05-04-01*/
+#define EP_RANDOMBINDDNFROMFILE 44 /*JLS 03-05-01*/
+ "randombinddnfromfile", /*JLS 03-05-01*/
+#define EP_BINDONLY 45 /*JLS 04-05-01*/
+ "bindonly", /*JLS 04-05-01*/
+ NULL
+};
+
+/* ****************************************************************************
+ FUNCTION : decodeExecParams
+ PURPOSE : Decode the execution parameters (aka sub-options of the
+ option -e).
+ INPUT : optarg = argument to decode.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+decodeExecParams (
+ char *optarg)
+{
+ char *suboptions; /* To parse optarg */
+ char *subvalue; /* Current sub-option */
+
+ suboptions = optarg;
+ while (*suboptions != '\0')
+ {
+ switch (getsubopt (&suboptions, execParams, &subvalue))
+ {
+ case EP_ADD_ENTRIES:
+ mctx.mode |= ADD_ENTRIES;
+ break;
+ case EP_APPEND: /*JLS 05-04-01*/
+ mctx.mod2 |= M2_APPEND; /*JLS 05-04-01*/
+ break; /*JLS 05-04-01*/
+ case EP_ASCII_7BITS:
+ mctx.mode |= ASCII_7BITS;
+ break;
+ case EP_ATT_REPLACE: /*JLS 21-11-00*/
+ mctx.mode |= ATTR_REPLACE; /*JLS 21-11-00*/
+ if (subvalue == NULL) /*JLS 21-11-00*/
+ { /*JLS 21-11-00*/
+ fprintf (stderr, "Error: missing arg attreplace\n"); /*JLS 21-11-00*/
+ return (-1); /*JLS 21-11-00*/
+ } /*JLS 21-11-00*/
+ mctx.attrpl = strdup (subvalue); /*JLS 21-11-00*/
+ break; /*JLS 21-11-00*/
+ case EP_ATTRLIST: /*JLS 15-03-01*/
+ return (addAttrToList (subvalue)); /*JLS 15-03-01*/
+ break; /*JLS 15-03-01*/
+ case EP_ATTRSONLY: /*JLS 03-01-01*/
+ if (subvalue == NULL) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf (stderr, "Error: missing arg attrsonly\n"); /*JLS 12-01-01*/
+ return (-1); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ mctx.attrsonly = atoi (subvalue); /*JLS 03-01-01*/
+ break; /*JLS 03-01-01*/
+ case EP_BIND_EACH_OPER:
+ mctx.mode |= BIND_EACH_OPER;
+ break;
+ case EP_BINDONLY: /*JLS 04-05-01*/
+ mctx.mod2 |= M2_BINDONLY; /*JLS 04-05-01*/
+ break; /*JLS 04-05-01*/
+ case EP_CLOSE_FD:
+ mctx.mode |= CLOSE_FD;
+ break;
+ case EP_CLTCERT_NAME: /* BK 23-11-00*/
+ mctx.mode |= CLTAUTH; /* BK 23-11-00*/
+ if (subvalue == NULL) /* BK 23-11-00*/
+ { /* BK 23-11-00*/
+ fprintf (stderr,"Error: missing arg for cltcertname\n");
+ /* BK 23-11-00*/
+ return (-1); /* BK 23-11-00*/
+ } /* BK 23-11-00*/
+ mctx.cltcertname = strdup (subvalue); /* BK 23-11-00*/
+ break; /* BK 23-11-00*/
+ case EP_COMMONCOUNTER: /*JLS 14-03-01*/
+ mctx.mode |= COMMON_COUNTER; /*JLS 14-03-01*/
+ break; /*JLS 14-03-01*/
+ case EP_COUNT_EACH: /*JLS 15-12-00*/
+ mctx.mode |= COUNT_EACH; /*JLS 15-12-00*/
+ break; /*JLS 15-12-00*/
+ case EP_DELETE_ENTRIES:
+ mctx.mode |= DELETE_ENTRIES;
+ break;
+ case EP_DONTSLEEPONSERVERDOWN: /*JLS 14-03-01*/
+ mctx.mode |= DONT_SLEEP_DOWN; /*JLS 14-03-01*/
+ break; /*JLS 14-03-01*/
+ case EP_EXACT_SEARCH:
+ mctx.mode |= EXACT_SEARCH;
+ break;
+ case EP_IMAGES_DIR: /*JLS 16-11-00*/
+ if (subvalue == NULL) /*JLS 16-11-00*/
+ { /*JLS 16-11-00*/
+ fprintf(stderr,"Error: missing arg for imagesdir\n"); /*JLS 16-11-00*/
+ return (-1); /*JLS 16-11-00*/
+ } /*JLS 16-11-00*/
+ mctx.imagesDir = strdup (subvalue); /*JLS 16-11-00*/
+ break; /*JLS 16-11-00*/
+ case EP_INCREMENTAL:
+ mctx.mode |= INCREMENTAL;
+ break;
+ case EP_KEYDB_FILE: /* BK 23-11-00*/
+ mctx.mode |= CLTAUTH; /* BK 23-11-00*/
+ if (subvalue == NULL) /* BK 23-11-00*/
+ { /* BK 23-11-00*/
+ fprintf (stderr,"Error: missing arg for keydbfile\n");/* BK 23-11-00*/
+ return (-1); /* BK 23-11-00*/
+ } /* BK 23-11-00*/
+ mctx.keydbfile = strdup (subvalue); /* BK 23-11-00*/
+ break; /* BK 23-11-00*/
+ case EP_KEYDB_PIN: /* BK 23-11-00*/
+ mctx.mode |= CLTAUTH; /* BK 23-11-00*/
+ if (subvalue == NULL) /* BK 23-11-00*/
+ { /* BK 23-11-00*/
+ fprintf (stderr,"Error: missing arg for keydbpin\n"); /* BK 23-11-00*/
+ return (-1); /* BK 23-11-00*/
+ } /* BK 23-11-00*/
+ mctx.keydbpin = strdup (subvalue); /* BK 23-11-00*/
+ break; /* BK 23-11-00*/
+ case EP_LDAP_V2:
+ mctx.mode |= LDAP_V2;
+ break;
+ case EP_NO_GLOBAL_STATS: /*JLS 19-12-00*/
+ mctx.globStatsCnt = -1; /*JLS 19-12-00*/
+ break; /*JLS 19-12-00*/
+ case EP_NOLOOP:
+ mctx.mode |= NOLOOP;
+ break;
+ case EP_OBJECT: /*JLS 19-03-01*/
+ mctx.mod2 |= M2_OBJECT; /*JLS 19-03-01*/
+ if (subvalue == NULL) /*JLS 19-03-01*/
+ { /*JLS 19-03-01*/
+ fprintf (stderr, "Error: missing object filename\n"); /*JLS 19-03-01*/
+ return (-1); /*JLS 19-03-01*/
+ } /*JLS 19-03-01*/
+ mctx.object.fname = strdup (subvalue); /*JLS 19-03-01*/
+ break; /*JLS 19-03-01*/
+ case EP_OC_EMAILPERSON:
+ mctx.mode |= OC_EMAILPERSON;
+ break;
+ case EP_GENLDIF: /*JLS 19-03-01*/
+ mctx.mod2 |= M2_GENLDIF; /*JLS 19-03-01*/
+ if (subvalue == NULL) /*JLS 19-03-01*/
+ { /*JLS 19-03-01*/
+ fprintf (stderr, "Error: missing genldif filename\n");/*JLS 19-03-01*/
+ return (-1); /*JLS 19-03-01*/
+ } /*JLS 19-03-01*/
+ mctx.genldifName = strdup (subvalue); /*JLS 19-03-01*/
+ break; /*JLS 19-03-01*/
+ case EP_OC_INETORGPRSON: /*JLS 07-11-00*/
+ mctx.mode |= OC_INETORGPRSON; /*JLS 07-11-00*/
+ break; /*JLS 07-11-00*/
+ case EP_OC_PERSON:
+ mctx.mode |= OC_PERSON;
+ break;
+ case EP_RANDOM:
+ mctx.mode |= RANDOM;
+ break;
+ case EP_RANDOM_BASE:
+ mctx.mode |= RANDOM_BASE;
+ break;
+ case EP_RANDOM_BASE_HIGH: /*JLS 13-11-00*/
+ mctx.mode |= RANDOM_BASE; /*JLS 13-11-00*/
+ if (subvalue == NULL) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf(stderr,"Error: missing arg randombasehigh\n");/*JLS 12-01-01*/
+ return (-1); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ mctx.baseDNHigh = atoi (subvalue); /*JLS 13-11-00*/
+ break; /*JLS 13-11-00*/
+ case EP_RANDOM_BASE_LOW: /*JLS 13-11-00*/
+ mctx.mode |= RANDOM_BASE; /*JLS 13-11-00*/
+ if (subvalue == NULL) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf(stderr, "Error: missing arg randombaselow\n");/*JLS 12-01-01*/
+ return (-1); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ mctx.baseDNLow = atoi (subvalue); /*JLS 13-11-00*/
+ break; /*JLS 13-11-00*/
+ case EP_RANDOMATTRLIST: /*JLS 15-03-01*/
+ mctx.mode |= RANDOM_ATTRLIST; /*JLS 15-03-01*/
+ return (addAttrToList (subvalue)); /*JLS 15-03-01*/
+ break; /*JLS 15-03-01*/
+ case EP_RANDOMBINDDN: /*JLS 05-01-01*/
+ mctx.mode |= RANDOM_BINDDN; /*JLS 05-01-01*/
+ break; /*JLS 05-01-01*/
+ case EP_RANDOMBINDDNFROMFILE: /*JLS 03-05-01*/
+ mctx.mod2 |= M2_RNDBINDFILE; /*JLS 03-05-01*/
+ if (subvalue == NULL) /*JLS 03-05-01*/
+ { /*JLS 03-05-01*/
+ fprintf(stderr,"Error: missing file name for randombinddnfromfile\n");
+ return (-1); /*JLS 03-05-01*/
+ } /*JLS 03-05-01*/
+ mctx.rndBindFname = strdup (subvalue); /*JLS 03-05-01*/
+ break; /*JLS 03-05-01*/
+ case EP_RANDOMBINDDNHIGH: /*JLS 05-01-01*/
+ mctx.mode |= RANDOM_BINDDN; /*JLS 05-01-01*/
+ if (subvalue == NULL) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf(stderr,"Error: missing arg randombindhigh\n");/*JLS 12-01-01*/
+ return (-1); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ mctx.bindDNHigh = atoi (subvalue); /*JLS 05-01-01*/
+ break; /*JLS 05-01-01*/
+ case EP_RANDOMBINDDNLOW: /*JLS 05-01-01*/
+ mctx.mode |= RANDOM_BINDDN; /*JLS 05-01-01*/
+ if (subvalue == NULL) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf(stderr, "Error: missing arg randombindlow\n");/*JLS 12-01-01*/
+ return (-1); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ mctx.bindDNLow = atoi (subvalue); /*JLS 05-01-01*/
+ break; /*JLS 05-01-01*/
+ case EP_RDN: /*JLS 23-03-01*/
+ if (decodeRdnParam (subvalue) < 0) /*JLS 23-03-01*/
+ return (-1); /*JLS 23-03-01*/
+ mctx.mod2 |= M2_RDN_VALUE; /*JLS 23-03-01*/
+ break; /*JLS 23-03-01*/
+ case EP_REFERRAL: /*JLS 08-03-01*/
+ if ((mctx.referral=decodeReferralParams(subvalue))<0) /*JLS 08-03-01*/
+ return (-1); /*JLS 08-03-01*/
+ break; /*JLS 08-03-01*/
+ case EP_RENAME:
+ mctx.mode |= RENAME_ENTRIES;
+ break;
+ case EP_SCALAB01: /*JLS 08-01-01*/
+ mctx.mode |= SCALAB01; /*JLS 08-01-01*/
+ break; /*JLS 08-01-01*/
+ case EP_SCALAB01_CNXDURATION: /*JLS 12-01-01*/
+ mctx.mode |= SCALAB01; /*JLS 12-01-01*/
+ if (subvalue == NULL) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf (stderr, "Error: missing arg scalab01_cnxduration\n");
+ return (-1); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ s1ctx.cnxduration = atoi (subvalue); /*JLS 12-01-01*/
+ break; /*JLS 12-01-01*/
+ case EP_SCALAB01_MAXCNXNB: /*JLS 12-01-01*/
+ mctx.mode |= SCALAB01; /*JLS 12-01-01*/
+ if (subvalue == NULL) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf (stderr, "Error: missing arg scalab01_maxcnxnb\n");
+ return (-1); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ s1ctx.maxcnxnb = atoi (subvalue); /*JLS 12-01-01*/
+ break; /*JLS 12-01-01*/
+ case EP_SCALAB01_WAIT: /*JLS 12-01-01*/
+ mctx.mode |= SCALAB01; /*JLS 12-01-01*/
+ if (subvalue == NULL) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf(stderr, "Error: missing arg scalab01_wait\n");/*JLS 12-01-01*/
+ return (-1); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ s1ctx.wait = atoi (subvalue); /*JLS 12-01-01*/
+ break; /*JLS 12-01-01*/
+ case EP_SMOOTH_SHUTDOWN: /*JLS 17-11-00*/
+ mctx.mode |= SMOOTHSHUTDOWN; /*JLS 17-11-00*/
+ break; /*JLS 17-11-00*/
+ case EP_STRING:
+ mctx.mode |= STRING;
+ break;
+ case EP_WITH_NEWPARENT: /*JLS 15-12-00*/
+ mctx.mode |= WITH_NEWPARENT; /*JLS 15-12-00*/
+ break; /*JLS 15-12-00*/
+ default:
+ fprintf (stderr, "Error: illegal option -e %s\n", subvalue);
+ return (-1);
+ break;
+ }
+ }
+ /*
+ * SSL client authentication is only supported in LDAP_V3, because we have
+ * to perform a SASL BIND operation in this case, and it is V3 specific
+ */
+ if ((mctx.mode & LDAP_V2) && (mctx.mode & CLTAUTH))
+ {
+ fprintf
+ (stderr,"Error: SSL client authentication is supported in LDAPv3 only");
+ return (-1);
+ }
+ return (0);
+}
+
+
+
+
+
+
+ /* New function */ /*JLS 23-04-01*/
+/* ****************************************************************************
+ FUNCTION : buildArgListString
+ PURPOSE : Saved the arguments of ldclt into a string.
+ INPUT : argc, argv
+ OUTPUT : None.
+ RETURN : The resulting string.
+ DESCRIPTION :
+ *****************************************************************************/
+char *
+buildArgListString (
+ int argc,
+ char **argv)
+{
+ char *argvList; /* Arg list */
+ int lgth; /* Length of argv list */
+ int i; /* For the loops */
+
+ /*
+ * Compute the length
+ */
+ lgth = 0;
+ for (i=0 ; i<argc ; i++)
+ {
+ lgth += strlen (argv[i]) + 1;
+ if ((strchr (argv[i], ' ') != NULL) || (strchr (argv[i], '\t') != NULL))
+ lgth += 2;
+ }
+ argvList = (char *) malloc (lgth);
+ argvList[0] = '\0';
+ strcat (argvList, argv[0]);
+ for (i=1 ; i<argc ; i++)
+ {
+ strcat (argvList, " ");
+ if ((strchr (argv[i], ' ') == NULL) && (strchr (argv[i], '\t') == NULL))
+ strcat (argvList, argv[i]);
+ else
+ {
+ strcat (argvList, "\"");
+ strcat (argvList, argv[i]);
+ strcat (argvList, "\"");
+ }
+ }
+
+
+ return (argvList);
+}
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : main
+ PURPOSE : Main function of ldclt
+ INPUT : argc, argv = see man page
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+main (
+ int argc,
+ char **argv)
+{
+ int opt_ret; /* For getopt() */
+ int i; /* For the loops */
+ time_t tim; /* For time() */ /*JLS 18-08-00*/
+ char *argvList; /* To keep track in core files */ /*JLS 07-12-00*/
+ int found; /* General purpose variable */ /*JLS 18-12-00*/
+ char verStr[40]; /* Version string */ /*JLS 13-03-01*/
+
+ /*
+ * Build the argv list to keep track of it...
+ * Print version.
+ * We are using a string variable to keep the version in the core files.
+ */
+ argvList = buildArgListString (argc, argv); /*JLS 23-04-01*/
+ sprintf (verStr, "ldclt version %s", ldcltVersion); /*JLS 13-03-01*/
+ printf ("%s\n", verStr); /*JLS 13-03-01*/
+
+ /*
+ * Initialization
+ */
+ mctx.attrlistNb = 0; /*JLS 15-03-01*/
+ mctx.attrsonly = DEF_ATTRSONLY; /*JLS 03-01-01*/
+ mctx.baseDN = "o=sun,c=us";
+ mctx.baseDNLow = -1; /*JLS 13-11-00*/
+ mctx.baseDNHigh = -1; /*JLS 13-11-00*/
+ mctx.bindDN = NULL;
+ mctx.bindDNLow = -1; /*JLS 05-01-01*/
+ mctx.bindDNHigh = -1; /*JLS 05-01-01*/
+ mctx.dlf = NULL; /*JLS 23-03-01*/
+ mctx.exitStatus = EXIT_OK; /*JLS 25-08-00*/
+ mctx.filter = NULL;
+ mctx.globStatsCnt = DEF_GLOBAL_NB; /*JLS 08-08-00*/
+ mctx.hostname = "localhost";
+ mctx.ignErrNb = 0;
+ mctx.images = NULL; /*JLS 17-11-00*/
+ mctx.imagesDir = DEF_IMAGES_PATH; /*JLS 16-11-00*/
+ mctx.inactivMax = DEF_INACTIV_MAX;
+ mctx.maxErrors = DEF_MAX_ERRORS;
+ mctx.mode = NOTHING;
+ mctx.mod2 = NOTHING;
+ mctx.nbNoActivity = 0;
+ mctx.nbSamples = -1;
+ mctx.nbThreads = DEF_NB_THREADS;
+ mctx.opListTail = NULL;
+ mctx.passwd = NULL;
+ mctx.pid = getpid();
+ mctx.port = DEF_PORT;
+ mctx.randomLow = -1;
+ mctx.randomHigh = -1;
+ mctx.referral = DEF_REFERRAL; /*JLS 08-03-01*/
+ mctx.sampling = DEF_SAMPLING;
+ mctx.scope = DEF_SCOPE;
+ mctx.slaveConn = 0;
+ mctx.slavesNb = 0;
+ mctx.timeout = DEF_TIMEOUT;
+ mctx.totalReq = -1;
+ mctx.waitSec = 0;
+ s1ctx.cnxduration = SCALAB01_DEF_CNX_DURATION; /*JLS 12-01-01*/
+ s1ctx.maxcnxnb = SCALAB01_DEF_MAX_CNX; /*JLS 12-01-01*/
+ s1ctx.wait = SCALAB01_DEF_WAIT_TIME; /*JLS 12-01-01*/
+
+ /*
+ * Initiates the object *NOW*
+ * It is mandatory to do it *NOW* because of -e rdn option.
+ */
+ mctx.object.attribsNb = 0; /*JLS 23-03-01*/
+ mctx.object.rdn = NULL; /*JLS 23-03-01*/
+ for (i=0 ; i+VAR_MIN < VAR_MAX ; i++) /*JLS 23-03-01*/
+ mctx.object.var[i] = NULL; /*JLS 23-03-01*/
+
+ /*
+ * Get options
+ */
+ while ((opt_ret = getopt (argc, argv,
+ "a:b:D:e:E:f:h:i:I:n:N:p:qQr:R:s:S:t:T:vVw:W:Z:H")) != EOF)
+ switch (opt_ret)
+ {
+ case 'a':
+ mctx.mode |= ASYNC;
+ mctx.asyncMax = atoi (optarg);
+ mctx.asyncMin = mctx.asyncMax / 2;
+ break;
+ case 'b':
+ mctx.baseDN = optarg;
+ break;
+ case 'D':
+ mctx.bindDN = optarg;
+ break;
+ case 'e':
+ if (decodeExecParams (optarg) < 0)
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ break;
+ case 'E':
+ mctx.maxErrors = atoi (optarg);
+ break;
+ case 'f':
+ mctx.filter = optarg;
+ break;
+ case 'h':
+ mctx.hostname = optarg;
+ break;
+ case 'i':
+ mctx.inactivMax = atoi (optarg);
+ break;
+ case 'I':
+ found = 0; /*JLS 18-12-00*/
+ for (i=0 ; i<mctx.ignErrNb ; i++) /*JLS 18-12-00*/
+ if (mctx.ignErr[i] == atoi (optarg)) /*JLS 18-12-00*/
+ found = 1; /*JLS 18-12-00*/
+ if (found) /*JLS 18-12-00*/
+ break; /*JLS 18-12-00*/
+ if (mctx.ignErrNb == MAX_IGN_ERRORS)
+ {
+ fprintf (stderr, "Error: too many errors to ignore.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ mctx.ignErr[mctx.ignErrNb++] = atoi (optarg);
+ break;
+ case 'n':
+ mctx.nbThreads = atoi (optarg);
+ break;
+ case 'N':
+ mctx.nbSamples = atoi (optarg);
+ break;
+ case 'p':
+ mctx.port = atoi (optarg);
+ break;
+ case 'P':
+ masterPort = atoi (optarg);
+ break;
+ case 'q':
+ mctx.mode |= QUIET;
+ break;
+ case 'Q':
+ mctx.mode |= QUIET;
+ mctx.mode |= SUPER_QUIET;
+ break;
+ case 'r':
+ mctx.randomLow = atoi (optarg);
+ break;
+ case 'R':
+ mctx.randomHigh = atoi (optarg);
+ break;
+ case 's':
+ if (decodeScopeParams (optarg) < 0)
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ break;
+ case 't':
+ mctx.timeout = atoi (optarg);
+ break;
+ case 'S':
+ mctx.slaves[mctx.slavesNb] = optarg;
+ mctx.slavesNb++;
+ break;
+ case 'T':
+ mctx.totalReq = atoi (optarg);
+ break;
+ case 'v':
+ mctx.mode |= VERBOSE;
+ break;
+ case 'V':
+ mctx.mode |= VERBOSE;
+ mctx.mode |= VERY_VERBOSE;
+ break;
+ case 'w':
+ mctx.passwd = optarg;
+ break;
+ case 'W':
+ mctx.waitSec = atoi (optarg);
+ break;
+ case 'Z':
+ mctx.mode |= SSL;
+ mctx.certfile = optarg;
+ break;
+ case 'H':
+ usage ();
+ ldcltExit (EXIT_OK); /*JLS 18-12-00*/
+ break;
+ case '?':
+ usage ();
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ break;
+ }
+
+ /*
+ * It should not be any extra argument.
+ */
+ if (optind != argc) /*JLS 23-04-01*/
+ { /*JLS 23-04-01*/
+ fprintf (stderr, "Error: unexpected extra arguments.\n"); /*JLS 23-04-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 23-04-01*/
+ } /*JLS 23-04-01*/
+
+ /*
+ * If scalab01 is set, then some other features are automatically enabled.
+ */
+ if (mctx.mode & SCALAB01) /*JLS 08-01-01*/
+ { /*JLS 08-01-01*/
+ mctx.mode |= BIND_EACH_OPER; /*JLS 08-01-01*/
+ mctx.mode |= RANDOM_BINDDN; /*JLS 08-01-01*/
+ } /*JLS 08-01-01*/
+
+ /*
+ * Check coherency
+ */
+ if (mctx.nbThreads <= 0)
+ {
+ fprintf (stderr, "Error: it must be at least 1 thread, not \"%d\"\n",
+ mctx.nbThreads);
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if (mctx.nbThreads > MAX_THREADS)
+ {
+ fprintf (stderr, "Error: too many threads %d, maximum is %d\n",
+ mctx.nbThreads, MAX_THREADS);
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if ((!(mctx.mode & VALID_OPERS)) &&
+ (!(mctx.mod2 & M2_VALID_OPERS))) /*JLS 04-05-01*/
+ {
+ fprintf (stderr, "Error: don't know what to do...\n");
+ fprintf (stderr, "Error: please use option -e for this purpose.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if ((mctx.mod2 & M2_APPEND) && (!(mctx.mod2 & M2_GENLDIF))) /*JLS 05-04-01*/
+ { /*JLS 05-04-01*/
+ fprintf (stderr, "Error: -e append requires -e genldif.\n");/*JLS 05-04-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 05-04-01*/
+ } /*JLS 05-04-01*/
+ if ((mctx.filter != NULL) && (mctx.mod2 & M2_RDN_VALUE)) /*JLS 23-03-01*/
+ { /*JLS 23-03-01*/
+ fprintf (stderr, "Error: -f and -e rdn= are exclusive.\n"); /*JLS 23-03-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 23-03-01*/
+ } /*JLS 23-03-01*/
+ if ((mctx.mod2 & M2_RDN_VALUE) && (mctx.mode & RANDOM)) /*JLS 28-03-01*/
+ { /*JLS 28-03-01*/
+ fprintf (stderr, "Error: exclusive -e random and -e rdn\n");/*JLS 28-03-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 28-03-01*/
+ } /*JLS 28-03-01*/
+ if ((mctx.mod2 & M2_RDN_VALUE) && (mctx.mode & INCREMENTAL)) /*JLS 28-03-01*/
+ { /*JLS 28-03-01*/
+ fprintf (stderr, "Error: exclusive -e incr and -e rdn\n"); /*JLS 28-03-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 28-03-01*/
+ } /*JLS 28-03-01*/
+ if ((mctx.mode & NEED_FILTER) &&
+ ((mctx.filter == NULL) && (!(mctx.mod2 & M2_RDN_VALUE)))) /*JLS 23-03-01*/
+ {
+ fprintf (stderr, "Error: missing filter...\n");
+ fprintf (stderr, "Error: use -f or -e rdn=value for this purpose.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if ((!((mctx.mode & NEED_FILTER) || (mctx.mod2 & M2_GENLDIF)))/*JLS 04-05-01*/
+ && (mctx.filter != NULL)) /*JLS 04-05-01*/
+ { /*JLS 04-05-01*/
+ fprintf (stderr, "Error: do not need filter -f\n"); /*JLS 04-05-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 04-05-01*/
+ } /*JLS 04-05-01*/
+ if ((!((mctx.mode & NEED_FILTER) || (mctx.mod2 & M2_GENLDIF)))/*JLS 04-05-01*/
+ && (mctx.mod2 & M2_RDN_VALUE)) /*JLS 04-05-01*/
+ { /*JLS 04-05-01*/
+ fprintf (stderr, "Error: do not need -e rdn=value\n"); /*JLS 04-05-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 04-05-01*/
+ } /*JLS 04-05-01*/
+ if ((mctx.mod2 & M2_RDN_VALUE) && /*JLS 28-03-01*/
+ ((mctx.randomLow >= 0) || (mctx.randomHigh > 0))) /*JLS 28-03-01*/
+ { /*JLS 28-03-01*/
+ fprintf (stderr, "Error: -e rdn exclusive with -r or -R\n");/*JLS 28-03-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 28-03-01*/
+ } /*JLS 28-03-01*/
+ if (mctx.mode & NEED_RANGE) /*JLS 28-03-01*/
+ { /*JLS 28-03-01*/
+ if (((mctx.randomLow >= 0) && (mctx.randomHigh < 0)) ||
+ ((mctx.randomLow < 0) && (mctx.randomHigh > 0)) ||
+ (mctx.randomLow > mctx.randomHigh))
+ {
+ fprintf (stderr, "Error: invalid random levels %d and %d\n",
+ mctx.randomLow, mctx.randomHigh);
+ fprintf (stderr, "Error: use both options -r and -R for this purpose.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if ((mctx.randomLow < 0) && (mctx.randomHigh < 0)) /*JLS 28-03-01*/
+ {
+ fprintf (stderr, "Error: missing values range.\n");
+ fprintf (stderr, "Error: use both options -r and -R for this purpose.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ } /*JLS 28-03-01*/
+ if (mctx.inactivMax < 0)
+ {
+ fprintf (stderr, "Error: max times inactivity should not be negative.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if (mctx.maxErrors < 0)
+ {
+ fprintf (stderr, "Error: max allowed errors should not be negative.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if ((mctx.mode & INCREMENTAL) && (mctx.mode & RANDOM))
+ {
+ fprintf (stderr, "Error: modes -e incr and -e random are exclusive.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if ((mctx.mode & NOLOOP) && (!(mctx.mode & INCREMENTAL)))
+ {
+ fprintf (stderr, "Error: mode -e noloop requires mode -e incr.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if ((mctx.mode & NEED_RND_INCR) &&
+ (!((mctx.mode & (RANDOM|INCREMENTAL)) || (mctx.mod2 & M2_RDN_VALUE))))
+ {
+ fprintf (stderr, "Error: -e add requires either -e incr/random/rdn\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if (mctx.filter != NULL) /*JLS 07-12-00*/
+ { /*JLS 07-12-00*/
+ for (i=0 ; (mctx.filter[i] != '\0') && (mctx.filter[i] != '=') ; i++);
+ if (mctx.filter[i] != '=')
+ {
+ fprintf (stderr, "Error: filter must be \"attrib=value\", not \"%s\"\n",
+ mctx.filter);
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ } /*JLS 07-12-00*/
+ if ((mctx.mode & NEED_CLASSES) &&
+ (!((mctx.mode & THE_CLASSES) || (mctx.mod2 & M2_OBJECT))))
+ {
+ fprintf (stderr, "Error: missing classes (option -e)\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if ((mctx.mode & STRING) && (!(mctx.mode & RANDOM)))
+ {
+ fprintf (stderr, "Error: -e string is only valid with -e random.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if (mctx.waitSec < 0)
+ {
+ fprintf (stderr, "Error: -W should have a positive value.\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ }
+ if ((mctx.mode & RANDOM_BASE) && /*JLS 13-11-00*/
+ ((mctx.baseDNLow < 0) || (mctx.baseDNHigh < 0))) /*JLS 13-11-00*/
+ { /*JLS 13-11-00*/
+ fprintf (stderr, "Error: missing ranges for randombase.\n");/*JLS 13-11-00*/
+ fprintf (stderr, "Error: use option -e randombaselow=\n"); /*JLS 13-11-00*/
+ fprintf (stderr, "Error: use option -e randombasehigh=\n"); /*JLS 13-11-00*/
+ ldcltExit (EXIT_PARAMS); /*JLS 13-11-00*/
+ } /*JLS 13-11-00*/
+ if ((mctx.mod2 & M2_RNDBINDFILE) && /*JLS 03-05-01*/
+ (mctx.mode & RANDOM_BINDDN)) /*JLS 03-05-01*/
+ { /*JLS 03-05-01*/
+ fprintf (stderr, /*JLS 03-05-01*/
+ "Error : exclusive -e randombinddn and -e randombinddnfromfile\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 03-05-01*/
+ } /*JLS 03-05-01*/
+ if ((mctx.mode & RANDOM_BINDDN) && /*JLS 05-01-01*/
+ ((mctx.bindDNLow < 0) || (mctx.bindDNHigh < 0))) /*JLS 05-01-01*/
+ { /*JLS 05-01-01*/
+ fprintf(stderr,"Error: missing ranges for randombinddn.\n");/*JLS 05-01-01*/
+ fprintf(stderr,"Error: use option -e randombinddnlow=\n"); /*JLS 05-01-01*/
+ fprintf(stderr,"Error: use option -e randombinddnhigh=\n"); /*JLS 05-01-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 05-01-01*/
+ } /*JLS 05-01-01*/
+ if (mctx.mode & CLTAUTH) /* BK 23-11-00*/
+ { /* BK 23-11-00*/
+ if (!(mctx.mode & SSL)) /* BK 23-11-00*/
+ { /* BK 23-11-00*/
+ fprintf (stderr, "Error: no certificate DB specified.\n");/* BK 23-11-00*/
+ fprintf (stderr, "Error: use -Z certfile.\n"); /* BK 23-11-00*/
+ ldcltExit (EXIT_PARAMS); /* BK 23-11-00*/
+ } /* BK 23-11-00*/
+ if (mctx.cltcertname == NULL) /* BK 23-11-00*/
+ { /* BK 23-11-00*/
+ fprintf (stderr, "Error: no client certificate name specified.\n");
+ /* BK 23-11-00*/
+ fprintf (stderr, "Error: use option -e cltcertname=\n"); /* BK 23-11-00*/
+ ldcltExit (EXIT_PARAMS); /* BK 23-11-00*/
+ } /* BK 23-11-00*/
+ if (mctx.keydbfile == NULL) /* BK 23-11-00*/
+ { /* BK 23-11-00*/
+ fprintf (stderr, "Error: no key database file specified.\n");
+ /* BK 23-11-00*/
+ fprintf (stderr, "Error: use option -e keydbfile=\n"); /* BK 23-11-00*/
+ ldcltExit (EXIT_PARAMS); /* BK 23-11-00*/
+ } /* BK 23-11-00*/
+ if (mctx.keydbpin == NULL) /* BK 23-11-00*/
+ { /* BK 23-11-00*/
+ fprintf (stderr, "Error: no key database password specified.\n");
+ /* BK 23-11-00*/
+ fprintf (stderr, "Error: use option -e keydbpin=\n"); /* BK 23-11-00*/
+ ldcltExit (EXIT_PARAMS); /* BK 23-11-00*/
+ } /* BK 23-11-00*/
+ }
+ if ((mctx.mode & WITH_NEWPARENT) && /*JLS 15-12-00*/
+ (!(mctx.mode & RENAME_ENTRIES))) /*JLS 15-12-00*/
+ { /*JLS 15-12-00*/
+ fprintf (stderr, "Error : option -e withnewparent needs -e rename\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 15-12-00*/
+ } /*JLS 15-12-00*/
+ if ((mctx.attrsonly != 0) && (mctx.attrsonly != 1)) /*JLS 03-01-01*/
+ { /*JLS 03-01-01*/
+ fprintf (stderr, "Error : option -e attrsonly=%d not 0|1\n",/*JLS 03-01-01*/
+ mctx.attrsonly); /*JLS 03-01-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 03-01-01*/
+ } /*JLS 03-01-01*/
+ if (mctx.mode & SCALAB01) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ if (s1ctx.cnxduration <= 0) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf (stderr, "Error : -e scalab01_cnxduration=%d <= 0\n",
+ s1ctx.cnxduration); /*JLS 12-01-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ if (s1ctx.maxcnxnb <= 0) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf (stderr, "Error : -e scalab01_maxcnxnb=%d <= 0\n",/*JLS 12-01-01*/
+ s1ctx.maxcnxnb); /*JLS 12-01-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ if (s1ctx.wait <= 0) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ fprintf (stderr, "Error : -e scalab01_wait=%d <= 0\n", /*JLS 12-01-01*/
+ s1ctx.wait); /*JLS 12-01-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ if ((mctx.referral == REFERRAL_REBIND) && /*JLS 14-03-01*/
+ ((mctx.bindDN == NULL) || (mctx.passwd == NULL))) /*JLS 14-03-01*/
+ { /*JLS 14-03-01*/
+ fprintf (stderr, "Error: -e referral=rebind needs -D and -w\n");/*14-03-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 14-03-01*/
+ } /*JLS 14-03-01*/
+ if ((mctx.mode & COMMON_COUNTER) && /*JLS 14-03-01*/
+ (!((mctx.mode & INCREMENTAL) || (mctx.mod2 & M2_OBJECT))))/*JLS 28-03-01*/
+ { /*JLS 14-03-01*/
+ fprintf (stderr, "Error: -e commoncounter needs -e incr or -e object\n");
+ ldcltExit (EXIT_PARAMS); /*JLS 14-03-01*/
+ } /*JLS 14-03-01*/
+ if ((mctx.attrlistNb != 0) && (!(mctx.mode & EXACT_SEARCH))) /*JLS 15-03-01*/
+ { /*JLS 15-03-01*/
+ fprintf(stderr,"Error : -e attrlist requires -e esearch\n");/*JLS 15-03-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 15-03-01*/
+ } /*JLS 15-03-01*/
+ if ((mctx.mod2 & M2_GENLDIF) && (mctx.mode & VALID_OPERS)) /*JLS 19-03-01*/
+ { /*JLS 19-03-01*/
+ fprintf(stderr,"Error : -e genldif is exclusive.\n"); /*JLS 19-03-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 19-03-01*/
+ } /*JLS 19-03-01*/
+ if ((mctx.mod2 & M2_RDN_VALUE) && (!(mctx.mod2 & M2_OBJECT))) /*JLS 23-03-01*/
+ { /*JLS 23-03-01*/
+ fprintf(stderr,"Error : -e rdn needs -e object.\n"); /*JLS 23-03-01*/
+ ldcltExit (EXIT_PARAMS); /*JLS 23-03-01*/
+ } /*JLS 23-03-01*/
+
+ /*
+ * Maybe we should load ssl library ?
+ */
+ if (mctx.mode & SSL) /*JLS 07-11-00*/
+ if (sslDynLoadInit() < 0) /*JLS 07-11-00*/
+ ldcltExit (EXIT_LOADSSL); /*JLS 07-11-00*/
+
+ /*
+ * Basic initialization from the user's parameters/options
+ */
+ if (basicInit() < 0)
+ ldcltExit (EXIT_INIT); /*JLS 18-12-00*/
+
+ /*
+ * What are we doing now...
+ */
+ if (mctx.mode & VERBOSE)
+ {
+ printf ("%s\n", argvList); /*JLS 07-12-00*/
+ printf ("Process ID = %d\n", mctx.pid);
+ printf ("Host to connect = %s\n", mctx.hostname);
+ printf ("Port number = %d\n", mctx.port);
+ if (mctx.bindDN == NULL)
+ printf ("Bind DN = NULL\n");
+ else
+ printf ("Bind DN = %s\n", mctx.bindDN);
+ if (mctx.passwd == NULL)
+ printf ("Passwd = NULL\n");
+ else
+ printf ("Passwd = %s\n", mctx.passwd);
+ switch (mctx.referral) /*JLS 08-03-01*/
+ { /*JLS 08-03-01*/
+ case REFERRAL_OFF: /*JLS 08-03-01*/
+ printf ("Referral = off\n"); /*JLS 08-03-01*/
+ break; /*JLS 08-03-01*/
+ case REFERRAL_ON: /*JLS 08-03-01*/
+ printf ("Referral = on\n"); /*JLS 08-03-01*/
+ break; /*JLS 08-03-01*/
+ case REFERRAL_REBIND: /*JLS 08-03-01*/
+ printf ("Referral = rebind\n"); /*JLS 08-03-01*/
+ break; /*JLS 08-03-01*/
+ } /*JLS 08-03-01*/
+ printf ("Base DN = %s\n", mctx.baseDN);
+ if (mctx.filter == NULL)
+ printf ("Filter = NULL\n");
+ else
+ printf ("Filter = \"%s\"\n", mctx.filter);
+ if (mctx.attrlistNb > 0) /*JLS 15-03-01*/
+ { /*JLS 15-03-01*/
+ printf ("Attributes list ="); /*JLS 15-03-01*/
+ for (i=0 ; i<mctx.attrlistNb ; i++) /*JLS 15-03-01*/
+ printf (" %s", mctx.attrlist[i]); /*JLS 15-03-01*/
+ printf ("\n"); /*JLS 15-03-01*/
+ } /*JLS 15-03-01*/
+ printf ("Max times inactive = %d\n", mctx.inactivMax);
+ printf ("Max allowed errors = %d\n", mctx.maxErrors);
+ printf ("Number of samples = %d\n", mctx.nbSamples);
+ printf ("Number of threads = %d\n", mctx.nbThreads);
+ printf ("Total op. req. = %d\n", mctx.totalReq);
+ printf ("Running mode = 0x%08x\n", mctx.mode);
+ printf ("Running mode =");
+ dumpModeValues (); /*JLS 19-03-01*/
+ printf ("\n");
+ if (mctx.mode & SCALAB01) /*JLS 12-01-01*/
+ { /*JLS 12-01-01*/
+ printf("Scalab01 cnx dur. = %d sec\n",s1ctx.cnxduration);/*JLS 12-01-01*/
+ printf ("Scalab01 max nb cnx= %d\n", s1ctx.maxcnxnb); /*JLS 12-01-01*/
+ printf ("Scalab01 wait time = %d sec\n", s1ctx.wait); /*JLS 12-01-01*/
+ } /*JLS 12-01-01*/
+ printf ("LDAP oper. timeout = %d sec\n", mctx.timeout);
+ printf ("Sampling interval = %d sec\n", mctx.sampling);
+ if (mctx.mode & EXACT_SEARCH)
+ { /*JLS 03-01-01*/
+ switch (mctx.scope)
+ {
+ case LDAP_SCOPE_BASE:
+ printf ("Scope = base\n");
+ break;
+ case LDAP_SCOPE_ONELEVEL:
+ printf ("Scope = one level\n");
+ break;
+ case LDAP_SCOPE_SUBTREE:
+ printf ("Scope = subtree\n");
+ break;
+ }
+ printf ("Attrsonly = %d\n", mctx.attrsonly); /*JLS 03-01-01*/
+ } /*JLS 03-01-01*/
+ if (mctx.images != NULL) /*JLS 17-11-00*/
+ printf ("Images directory = %s\n", mctx.imagesDir); /*JLS 17-11-00*/
+ if ((mctx.mode & NEED_RANGE) && (mctx.randomLow >= 0)) /*JLS 28-03-01*/
+ printf ("Values range = [%d , %d]\n",
+ mctx.randomLow, mctx.randomHigh);
+ if ((mctx.mode & (RANDOM | INCREMENTAL)) &&
+ (!(mctx.mod2 & M2_RDN_VALUE))) /*JLS 23-03-01*/
+ {
+ printf ("Filter's head = \"%s\"\n", mctx.randomHead);
+ printf ("Filter's tail = \"%s\"\n", mctx.randomTail);
+ }
+ if (mctx.mode & RANDOM_BASE)
+ {
+ printf ("Base DN's head = \"%s\"\n", mctx.baseDNHead);
+ printf ("Base DN's tail = \"%s\"\n", mctx.baseDNTail);
+ printf ("Base DN's range = [%d , %d]\n", /*JLS 13-11-00*/
+ mctx.baseDNLow, mctx.baseDNHigh); /*JLS 13-11-00*/
+ }
+ if (mctx.mode & RANDOM_BINDDN) /*JLS 05-01-01*/
+ { /*JLS 05-01-01*/
+ printf ("Bind DN's head = \"%s\"\n", mctx.bindDNHead);/*JLS 05-01-01*/
+ printf ("Bind DN's tail = \"%s\"\n", mctx.bindDNTail);/*JLS 05-01-01*/
+ printf ("Bind DN's range = [%d , %d]\n", /*JLS 05-01-01*/
+ mctx.bindDNLow, mctx.bindDNHigh); /*JLS 05-01-01*/
+ printf ("Bind passwd's head = \"%s\"\n", mctx.passwdHead);/*JLS 05-01-01*/
+ printf ("Bind passwd's tail = \"%s\"\n", mctx.passwdTail);/*JLS 05-01-01*/
+ } /*JLS 05-01-01*/
+ if (mctx.mode & ATTR_REPLACE) /*JLS 21-11-00*/
+ { /*JLS 21-11-00*/
+ printf ("Attribute's head = \"%s\"\n", mctx.attrplHead);/*JLS 21-11-00*/
+ printf ("Attribute's tail = \"%s\"\n", mctx.attrplTail);/*JLS 21-11-00*/
+ } /*JLS 21-11-00*/
+ if (mctx.mode & ASYNC)
+ {
+ printf ("Async max pending = %d\n", mctx.asyncMax);
+ printf ("Async min pending = %d\n", mctx.asyncMin);
+ }
+ for (i=0 ; i<mctx.ignErrNb ; i++)
+ printf ("Ignore error = %d (%s)\n",
+ mctx.ignErr[i], my_ldap_err2string (mctx.ignErr[i]));
+ fflush (stdout);
+ if (mctx.slavesNb > 0)
+ {
+ printf ("Slave(s) to check =");
+ for (i=0 ; i<mctx.slavesNb ; i++)
+ printf (" %s", mctx.slaves[i]);
+ printf ("\n");
+ }
+ }
+
+ /*
+ * Let's go!
+ */
+ tim = time(NULL);
+ printf ("ldclt[%d]: Starting at %s\n", mctx.pid, ctime (&tim)); /*JLS 18-08-00*/
+ if (runThem() < 0)
+ ldcltExit (EXIT_OTHER); /*JLS 25-08-00*/
+ if (initMainThread() < 0)
+ ldcltExit (EXIT_OTHER); /*JLS 25-08-00*/
+ if (monitorThem() < 0)
+ ldcltExit (EXIT_OTHER); /*JLS 25-08-00*/
+ if (printGlobalStatistics() < 0)
+ ldcltExit (EXIT_OTHER); /*JLS 25-08-00*/
+
+ ldcltExit (mctx.exitStatus); /*JLS 25-08-00*/
+}
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/ldclt.h b/ldap/servers/slapd/tools/ldclt/ldclt.h
new file mode 100644
index 00000000..f4262e64
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/ldclt.h
@@ -0,0 +1,739 @@
+#ident "ldclt @(#)ldclt.h 1.66 01/05/04"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : ldclt.h
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 03 December 1998
+ DESCRIPTION :
+ This file is the main include file of the tool named
+ "ldclt"
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+03/12/98 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+10/12/98 | JL Schwing | 1.2 : Add stats numbers in main_context.
+---------+--------------+------------------------------------------------------
+10/12/98 | JL Schwing | 1.3 : Implement asynchronous mode.
+---------+--------------+------------------------------------------------------
+11/12/98 | JL Schwing | 1.4 : Implement max errors threshold.
+---------+--------------+------------------------------------------------------
+14/12/98 | JL Schwing | 1.5 : Implement "-e close".
+---------+--------------+------------------------------------------------------
+16/12/98 | JL Schwing | 1.6 : Implement "-e add" and "-e delete".
+ | Add counter nb timeouts (no activity).
+---------+--------------+------------------------------------------------------
+28/12/98 | JL Schwing | 1.7 : Add tag asyncHit.
+---------+--------------+------------------------------------------------------
+29/12/98 | JL Schwing | 1.8 : Implement -Q.
+---------+--------------+------------------------------------------------------
+11/01/99 | JL Schwing | 1.9 : Implement "-e emailPerson".
+---------+--------------+------------------------------------------------------
+13/01/99 | JL Schwing | 1.10: Implement "-e string".
+---------+--------------+------------------------------------------------------
+14/01/99 | JL Schwing | 1.11: Implement "-s <scope>".
+---------+--------------+------------------------------------------------------
+18/01/99 | JL Schwing | 1.12: Implement "-e randombase".
+---------+--------------+------------------------------------------------------
+18/01/99 | JL Schwing | 1.13: Implement "-e v2".
+---------+--------------+------------------------------------------------------
+21/01/99 | JL Schwing | 1.14: Implement "-e ascii".
+---------+--------------+------------------------------------------------------
+26/01/99 | JL Schwing | 1.15: Implement "-e noloop".
+---------+--------------+------------------------------------------------------
+28/01/99 | JL Schwing | 1.16: Implement "-T <total>".
+---------+--------------+------------------------------------------------------
+04/05/99 | JL Schwing | 1.17: Implement operations list.
+---------+--------------+------------------------------------------------------
+06/05/99 | JL Schwing | 1.22: Implement "-e modrdn".
+---------+--------------+------------------------------------------------------
+19/05/99 | JL Schwing | 1.25: Implement "-e rename".
+---------+--------------+------------------------------------------------------
+27/05/99 | JL Schwing | 1.26 : Add statistics to check threads.
+---------+--------------+------------------------------------------------------
+28/05/99 | JL Schwing | 1.27 : Add new option -W (wait).
+---------+--------------+------------------------------------------------------
+02/06/99 | JL Schwing | 1.28 : Add flag in main ctx to know if slave was
+ | connected or not.
+ | Add counter of operations received in check threads.
+---------+--------------+------------------------------------------------------
+04/08/00 | JL Schwing | 1.29: Add stats on nb inactivity per thread.
+---------+--------------+------------------------------------------------------
+08/08/00 | JL Schwing | 1.30: Print global statistics every 1000 loops.
+---------+--------------+------------------------------------------------------
+18/08/00 | JL Schwing | 1.31: Print global statistics every 15'
+ | Print begin and end dates.
+---------+--------------+------------------------------------------------------
+25/08/00 | JL Schwing | 1.32: Implement consistent exit status...
+---------+--------------+------------------------------------------------------
+19/09/00 | JL Schwing | 1.33: Port on Netscape's libldap. This is realized in
+ | such a way that this library become the default
+ | way so a ifdef for Solaris will be used...
+---------+--------------+----------------------------------------------------
+11/10/00 | B Kolics | 1.34: Added 'SSL' to the list of running modes and
+ | | certfile to main_context structure
+---------+--------------+------------------------------------------------------
+07/11/00 | JL Schwing | 1.35: Add handlers for dynamic load of ssl-related
+ | functions.
+-----------------------------------------------------------------------------
+07/11/00 | JL Schwing | 1.36: Implement "-e inetOrgPerson".
+---------+--------------+------------------------------------------------------
+13/11/00 | JL Schwing | 1.37: Add new options "-e randombaselow and ...high"
+---------+--------------+------------------------------------------------------
+16/11/00 | JL Schwing | 1.38: Implement "-e imagesdir=path".
+ | lint-cleanup.
+---------+--------------+------------------------------------------------------
+17/11/00 | JL Schwing | 1.39: Implement "-e smoothshutdown".
+---------+--------------+------------------------------------------------------
+21/11/00 | JL Schwing | 1.40: Implement "-e attreplace=name:mask"
+ | Increase max number of threads from 512 to 1000.
+---------+--------------+------------------------------------------------------
+22/11/00 | JL Schwing | 1.41: Will now use LD_LIBRARY_PATH to load libssl.
+---------+--------------+------------------------------------------------------
+24/11/00 | JL Schwing | 1.41: Added SSL client authentication
+---------+--------------+------------------------------------------------------
+28/11/00 | JL Schwing | 1.43: Port on NT 4.
+---------+--------------+------------------------------------------------------
+15/12/00 | JL Schwing | 1.44: Add more trace in VERY_VERBOSE mode.
+---------+--------------+------------------------------------------------------
+15/12/00 | JL Schwing | 1.45: Implement "-e counteach".
+ | Implement "-e withnewparent".
+---------+--------------+------------------------------------------------------
+18/12/00 | JL Schwing | 1.46: Add exit status EXIT_INIT and EXIT_RESSOURCE.
+---------+--------------+------------------------------------------------------
+03/01/01 | JL Schwing | 1.47: Implement "-e attrsonly=value".
+---------+--------------+------------------------------------------------------
+05/01/01 | JL Schwing | 1.48: Implement "-e randombinddn" and associated
+ | "-e randombinddnlow/high"
+---------+--------------+------------------------------------------------------
+08/01/01 | JL Schwing | 1.49: Implement "-e scalab01".
+---------+--------------+------------------------------------------------------
+12/01/01 | JL Schwing | 1.50: Second set of options for -e scalab01
+---------+--------------+------------------------------------------------------
+06/03/01 | JL Schwing | 1.51: Change DEF_ATTRSONLY from 1 to 0
+---------+--------------+------------------------------------------------------
+08/03/01 | JL Schwing | 1.52: Change referrals handling.
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.53: Implement "-e commoncounter"
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.54: Implement "-e dontsleeponserverdown".
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.55: Lint cleanup.
+---------+--------------+------------------------------------------------------
+15/03/01 | JL Schwing | 1.56: Implement "-e attrlist=name:name:name"
+ | Implement "-e randomattrlist=name:name:name"
+---------+--------------+------------------------------------------------------
+19/03/01 | JL Schwing | 1.57: Implement "-e object=filename"
+ | Implement "-e genldif=filename"
+---------+--------------+------------------------------------------------------
+21/03/01 | JL Schwing | 1.58: Implements variables in "-e object=filename"
+---------+--------------+------------------------------------------------------
+23/03/01 | JL Schwing | 1.59: Implements data file list support in variants.
+ | Implements "-e rdn=value".
+---------+--------------+------------------------------------------------------
+28/03/01 | JL Schwing | 1.60: Update options checking for "-e rdn=value".
+---------+--------------+------------------------------------------------------
+28/03/01 | JL Schwing | 1.61: Support -e commoncounter with -e rdn/object
+ | Increase MAX_ATTRIBS from 20 to 40
+ | Remove MAX_ATTRLIST - use MAX_ATTRIBS.
+---------+--------------+------------------------------------------------------
+02/04/01 | JL Schwing | 1.62: Bug fix : large files support for -e genldif.
+---------+--------------+------------------------------------------------------
+05/04/01 | JL Schwing | 1.63: Implement -e append.
+---------+--------------+------------------------------------------------------
+11/04/01 | JL Schwing | 1.64: Implement [INCRFROMFILE<NOLOOP>(myfile)]
+---------+--------------+------------------------------------------------------
+03/05/01 | JL Schwing | 1.64: Implement -e randombinddnfromfile=filename.
+---------+--------------+------------------------------------------------------
+04/05/01 | JL Schwing | 1.65: Implement -e bindonly.
+---------+--------------+------------------------------------------------------
+*/
+
+#ifndef LDCLT_H
+#define LDCLT_H
+
+/*
+ * Misc constant definitions
+ */
+#define DEF_ATTRSONLY 0 /* ldap_search() default */ /*JLS 06-03-01*/
+#define DEF_GLOBAL_NB 90 /* Prt glob stats every 15' */ /*JLS 18-08-00*/
+#define DEF_INACTIV_MAX 3 /* Inactivity max nb times */
+#define DEF_MAX_ERRORS 1000 /* Max errors before exit */
+#define DEF_NB_THREADS 10 /* Nb client threads */
+#define DEF_PORT 389 /* Ldap server port */
+#define DEF_SAMPLING 10 /* Default sampling rate */
+#define DEF_TIMEOUT 30 /* Ldap operations timeout */
+#define DEF_PORT_CHECK 16000 /* Port used for check processing */
+#define MAX_ATTRIBS 40 /* Max number of attributes */ /*JLS 28-03-01*/
+#define MAX_DN_LENGTH 1024 /* Max length for a DN */
+#define MAX_ERROR_NB 0x62 /* Max ldap err number + 1 */
+#define MAX_IGN_ERRORS 20 /* Max errors ignored */
+#define MAX_FILTER 512 /* Max filters length */
+#define MAX_THREADS 1000 /* Max number of threads */ /*JLS 21-11-00*/
+#define MAX_SLAVES 20 /* Max number of slaves */
+
+#define DEF_IMAGES_PATH "../../data/ldclt/images"
+#define DEF_REFERRAL REFERRAL_ON /*JLS 08-03-01*/
+#define DEF_SCOPE LDAP_SCOPE_SUBTREE /* Default for -s */
+
+#ifndef SSL_LIB
+#define SSL_LIB "libldapssl41.so"
+#endif
+#ifndef SSL_LIB_PATH
+#define SSL_LIB_PATH "/qa/ldap/tools/ldclt/src/lib-sparc/ldapcsdk"
+#endif
+
+/*
+ * Referral choices...
+ */
+#define REFERRAL_OFF 0 /*JLS 08-03-01*/
+#define REFERRAL_ON 1 /*JLS 08-03-01*/
+#define REFERRAL_REBIND 2 /*JLS 08-03-01*/
+
+/*
+ * Running modes
+ * Will be used as well for main_context and for thread_context
+ * Don't forget to update dumpModeValues().
+ */
+#define NOTHING 0x00000000 /* Nothing special */
+#define VERBOSE 0x00000001 /* -v : verbose */
+#define VERY_VERBOSE 0x00000002 /* -V : very verbose */
+#define ASYNC 0x00000004 /* -a : asynchonous mode */
+#define QUIET 0x00000008 /* -q : quiet */
+#define SUPER_QUIET 0x00000010 /* -Q : super quiet */
+#define SSL 0x00000020 /* -Z certfile :SSL enabled *//*BK 11-10-00*/
+#define CLTAUTH 0x00000040 /* .... */ /* BK 23-11-00*/
+/**/
+#define RANDOM_ATTRLIST 0x00000080 /* -e randomattrlist*/ /*JLS 15-03-01*/
+#define DONT_SLEEP_DOWN 0x00000100 /* -e dontsleeponserverdown*//*JLS 14-03-01*/
+#define COMMON_COUNTER 0x00000200 /* -e commoncounter */ /*JLS 14-03-01*/
+#define SCALAB01 0x00000400 /* -e scalab01 */ /*JLS 08-01-01*/
+#define RANDOM_BINDDN 0x00000800 /* -e randombinddn */ /*JLS 05-01-01*/
+#define WITH_NEWPARENT 0x00001000 /* -e withnewparent */ /*JLS 15-12-00*/
+#define COUNT_EACH 0x00002000 /* -e counteach */ /*JLS 15-12-00*/
+#define ATTR_REPLACE 0x00004000 /* -e attreplace */ /*JLS 21-11-00*/
+#define SMOOTHSHUTDOWN 0x00008000 /* -e smoothshutdown */ /*JLS 17-11-00*/
+#define OC_INETORGPRSON 0x00010000 /* -e inetOrgPerson : oc= */ /*JLS 07-11-00*/
+#define RENAME_ENTRIES 0x00020000 /* -e rename : rename entries */
+#define NOLOOP 0x00040000 /* -e noloop : don't loop nb */
+#define ASCII_7BITS 0x00080000 /* -e ascii : ascii 7bits */
+#define LDAP_V2 0x00100000 /* -e v2 : ldap v2 */
+#define RANDOM_BASE 0x00200000 /* -e randombase : string mode */
+#define STRING 0x00400000 /* -e string : string mode */
+#define OC_EMAILPERSON 0x00800000 /* -e emailPerson : oc = person */
+#define DELETE_ENTRIES 0x01000000 /* -e delete : delete */
+#define OC_PERSON 0x02000000 /* -e person : oc = person */
+#define ADD_ENTRIES 0x04000000 /* -e add : add entries */
+#define INCREMENTAL 0x08000000 /* -e incr : incremental */
+#define CLOSE_FD 0x10000000 /* -e close : close fd */
+#define RANDOM 0x20000000 /* -e random : rnd values */
+#define BIND_EACH_OPER 0x40000000 /* -e bindeach : bnd each op */
+#define EXACT_SEARCH 0x80000000 /* -e esearch : exact srch */
+
+#define M2_OBJECT 0x00000001 /* -e object */ /*JLS 19-03-01*/
+#define M2_GENLDIF 0x00000002 /* -e genldif */ /*JLS 19-03-01*/
+#define M2_RDN_VALUE 0x00000004 /* -e rdn */ /*JLS 23-03-01*/
+#define M2_APPEND 0x00000008 /* -e append */ /*JLS 05-04-01*/
+#define M2_RNDBINDFILE 0x00000010 /* -e randombinddnfromfile *//*JLS 03-05-01*/
+#define M2_BINDONLY 0x00000020 /* -e bindonly */ /*JLS 04-05-01*/
+
+/*
+ * Combinatory defines
+ * - NEED_FILTER : filter required
+ * - NEED_RANGE : -r and -R required
+ * - NEED_RND_INCR : need entry generator
+ * - VALID_OPERS : valid operations
+ */
+#define NEED_FILTER (ADD_ENTRIES|DELETE_ENTRIES|EXACT_SEARCH|RENAME_ENTRIES|ATTR_REPLACE|SCALAB01)
+#define NEED_RANGE (INCREMENTAL|RANDOM)
+#define NEED_RND_INCR (ADD_ENTRIES|DELETE_ENTRIES|RENAME_ENTRIES)
+#define VALID_OPERS (ADD_ENTRIES|DELETE_ENTRIES|EXACT_SEARCH|RENAME_ENTRIES|ATTR_REPLACE|SCALAB01)
+#define M2_VALID_OPERS (M2_GENLDIF|M2_BINDONLY)
+#define NEED_CLASSES (ADD_ENTRIES)
+#define THE_CLASSES (OC_PERSON|OC_EMAILPERSON|OC_INETORGPRSON)
+
+/*
+ * The threads status - check thread_context.status
+ */
+#define FREE -1 /* Slot is free */
+#define CREATED 0 /* Just created */
+#define INITIATED 1 /* Initiated */
+#define RUNNING 2 /* Doing it's job */
+#define DEAD 9 /* Thread is dead */
+#define MUST_SHUTDOWN 10 /* Monitor command this */ /*JLS 17-11-00*/
+
+/*
+ * Exit status
+ * The biggest is the number, the higher priority is.
+ * Cf the end of monitorThem().
+ */
+#define EXIT_OK 0 /* No problem during execution */ /*JLS 25-08-00*/
+#define EXIT_PARAMS 2 /* Error in parameters */ /*JLS 25-08-00*/
+#define EXIT_MAX_ERRORS 3 /* Max errors reached */ /*JLS 25-08-00*/
+#define EXIT_NOBIND 4 /* Cannot bind */ /*JLS 25-08-00*/
+#define EXIT_LOADSSL 5 /* Cannot load libssl */ /*JLS 07-11-00*/
+#define EXIT_MUTEX 6 /* Mutex error */ /*JLS 17-11-00*/
+#define EXIT_INIT 7 /* Initialization error */ /*JLS 18-12-00*/
+#define EXIT_RESSOURCE 8 /* Ressource limitation */ /*JLS 18-12-00*/
+#define EXIT_OTHER 99 /* Other kind of error */ /*JLS 25-08-00*/
+
+/*
+ * Some constants from Sun's ldap.h are not provided by
+ * Netscape implementation...
+ */
+#ifdef SOLARIS_LIBLDAP /*JLS 19-09-00*/
+#define WORKAROUND_4197228 1 /*JLS 19-09-00*/
+#else /*JLS 19-09-00*/
+#define LDAP_REQ_BIND 0x60 /*JLS 19-09-00*/
+#define LDAP_REQ_UNBIND 0x42 /*JLS 19-09-00*/
+#define LDAP_REQ_SEARCH 0x63 /*JLS 19-09-00*/
+#define LDAP_REQ_MODIFY 0x66 /*JLS 19-09-00*/
+#define LDAP_REQ_ADD 0x68 /*JLS 19-09-00*/
+#define LDAP_REQ_DELETE 0x4a /*JLS 19-09-00*/
+#define LDAP_REQ_MODRDN 0x6c /*JLS 19-09-00*/
+#define LDAP_REQ_COMPARE 0x6e /*JLS 19-09-00*/
+#define LDAP_REQ_ABANDON 0x50 /*JLS 19-09-00*/
+#define LDAP_REQ_EXTENDED 0x77 /*JLS 19-09-00*/
+#define LDAP_REQ_UNBIND_30 0x62 /*JLS 19-09-00*/
+#define LDAP_REQ_DELETE_30 0x6a /*JLS 19-09-00*/
+#define LDAP_REQ_ABANDON_30 0x70 /*JLS 19-09-00*/
+#endif /*JLS 19-09-00*/
+
+/*
+ * This structure is the internal representation of an image
+ */
+typedef struct image {
+ char *name;
+ int length;
+ char *data;
+} image;
+
+/*
+ * Internal representation of a data list file
+ */
+typedef struct data_list_file { /*JLS 23-03-01*/
+ char *fname; /* File name */
+ char **str; /* Strings array */
+ int strNb; /* Nb of strings */
+ struct data_list_file *next; /* Next file */
+} data_list_file;
+
+/*
+ * This structure is the internal representation of an LDAP attribute
+ */
+typedef struct {
+ char *type; /* e.g. "objectclass" or "cn" */
+ int length; /* Length of the value */
+ char *value; /* The attribute value */
+ int dontFree; /* Don't free the value */
+} attribute;
+
+/*
+ * This structure is used to memorize an operation successfully
+ * performed by the tool in order to be checked later on.
+ * The operation type is a LDAP constant LDAP_REQ_ADD, etc...
+ * ATTENTION: don't forget to maintain in sync with the struct thoper below.
+ */
+typedef struct oper {
+ int type; /* Operation type */
+ char *dn; /* Target's DN */
+ attribute attribs[MAX_ATTRIBS]; /* Attributes to check */
+ /* attribs[i].type == NULL marks the */
+ /* end of the attributes */
+ char *newRdn; /* For rename operation */
+ char *newParent; /* For rename operation */
+ int skipped; /* Thread that skipped it */
+ ldclt_mutex_t skipped_mutex; /* Protect skipped */ /*JLS 28-11-00*/
+ struct oper *next; /* Next operation */
+} oper;
+
+/*
+ * Same as before, but this is a per thread "lost" operation list
+ */
+typedef struct _simpl_op {
+ int type;
+ int first; /* Keeps in order replies */
+ char *dn;
+ attribute attribs[MAX_ATTRIBS];
+ char *newRdn;
+ char *newParent;
+ struct _simpl_op *next;
+} thoper;
+
+/*
+ * This structure will allow to manage the handlers for ssl-related
+ * dynamic loaded functions.
+ */
+typedef struct ssl_context { /*JLS 07-11-00*/
+#ifndef _WIN32
+ void *libssl; /* lib ssl handler */ /*JLS 07-11-00*/
+ LDAP *(*ldapssl_init)(const char *, int, int); /*JLS 07-11-00*/
+ int (*ldapssl_client_init)(const char*, void*); /*JLS 07-11-00*/
+ int (*ldapssl_clientauth_init)(char *, void *, int, char *, void*);
+ /* BK 23-11-00*/
+ int (*ldapssl_enable_clientauth)(LDAP *, char *, char *, char *);
+ /* BK 22-11-00*/
+#else /* _WIN32 */
+ LDAP * (LDAP_CALL *ldapssl_init)(const char *, int, int);
+ int (LDAP_CALL *ldapssl_client_init)(const char*, void*);
+ int (LDAP_CALL *ldapssl_clientauth_init)(char *, void *, int, char *, void*);
+ int (LDAP_CALL *ldapssl_enable_clientauth)(LDAP *, char *, char *, char *);
+#endif /* _WIN32 */
+} ssl_context; /*JLS 07-11-00*/
+
+/*
+ * Versatile object attribute's field
+ * - If ldclt should use a common counter, then this counter will
+ * be in the mctx structure and will be found by the commonField
+ * pointer.
+ */
+#define HOW_CONSTANT 0 /* Constant value */
+#define HOW_INCR_FROM_FILE 1 /* Increment string from file *//*JLS 11-04-01*/
+#define HOW_INCR_FROM_FILE_NL 2 /* Incr string file noloop*/ /*JLS 11-04-01*/
+#define HOW_INCR_NB 3 /* Increment number */ /*JLS 23-03-01*/
+#define HOW_INCR_NB_NOLOOP 4 /* Increment number no loop */ /*JLS 23-03-01*/
+#define HOW_RND_FROM_FILE 5 /* Random string from file */ /*JLS 23-03-01*/
+#define HOW_RND_NUMBER 6 /* Random number */
+#define HOW_RND_STRING 7 /* Random string */
+#define HOW_VARIABLE 8 /* Retrieve variable value */ /*JLS 21-03-01*/
+typedef struct vers_field { /*JLS 21-03-01*/
+ int how; /* How to build this field */
+ int cnt; /* Counter */ /*JLS 23-03-01*/
+ ldclt_mutex_t cnt_mutex; /* Protect cnt */ /*JLS 28-03-01*/
+ struct vers_field *commonField; /* Common field */ /*JLS 28-03-01*/
+ char *cst; /* Constant field */
+ data_list_file *dlf; /* Data list file */ /*JLS 23-03-01*/
+ int high; /* High value */
+ int low; /* Low value */
+ int nb; /* Number of items */
+ int var; /* Variable number */
+ struct vers_field *next; /* Next field */
+} vers_field;
+
+/*
+ * Versatile object's attribute
+ */
+typedef struct vers_attribute { /*JLS 19-03-01*/
+ char *buf; /* Store the generated value */ /*JLS 21-03-01*/
+ char *name; /* Attribute name */
+ char *src; /* Source line */
+ vers_field *field; /* First field */ /*JLS 21-03-01*/
+} vers_attribute;
+
+/*
+ * This structure contains the definitions related to the versatile
+ * object classes managed by ldclt.
+ * The field 'rdn' of vers_object is a trick we will use to be
+ * able to support the same random mechanism for the entry's rdn
+ * generation than for the attributes themselves.
+ */
+#define VAR_MIN 'A' /*JLS 21-03-01*/
+#define VAR_MAX 'H' /*JLS 21-03-01*/
+typedef struct vers_object { /*JLS 19-03-01*/
+ vers_attribute attribs[MAX_ATTRIBS];
+ int attribsNb;
+ vers_attribute *rdn; /* Object's rdn */ /*JLS 23-03-01*/
+ char *rdnName; /* Attrib. name */ /*JLS 23-03-01*/
+ char *var[VAR_MAX-VAR_MIN]; /*JLS 21-03-01*/
+ char *fname; /* Object definition */
+} vers_object;
+
+/*
+ * This structure contain the *process* context, used only by the
+ * main thread(s).
+ * Another dedicated structure is used by each test thread.
+ */
+typedef struct main_context {
+ int asyncMin; /* Min pend for read */
+ int asyncMax; /* Max async pending */
+ char *attrlist[MAX_ATTRIBS]; /*JLS 15-03-01*/
+ int attrlistNb; /* Nb attrib in list */ /*JLS 15-03-01*/
+ char *attrpl; /* Attrib argument */ /*JLS 21-11-00*/
+ char *attrplHead; /* Attrib value head */ /*JLS 21-11-00*/
+ char *attrplName; /* Attrib name */ /*JLS 21-11-00*/
+ int attrplNbDigit; /* Attrib nb digits */ /*JLS 21-11-00*/
+ char *attrplTail; /* Attrib value tail */ /*JLS 21-11-00*/
+ int attrsonly; /* search() param. */ /*JLS 03-01-01*/
+ char *baseDN; /* Base DN to use */
+ int baseDNLow; /* Base DN's low val */ /*JLS 13-11-00*/
+ int baseDNHigh; /* Base DN's high val *//*JLS 13-11-00*/
+ int baseDNNbDigit; /* Base DN's nb of digits */
+ char *baseDNHead; /* Base DN's head string */
+ char *baseDNTail; /* Base DN's tail string */
+ char *bindDN; /* Bind DN */
+ int bindDNLow; /* Bind DN's low val */ /*JLS 05-01-01*/
+ int bindDNHigh; /* Bind DN's high val *//*JLS 05-01-01*/
+ int bindDNNbDigit; /* Bind DN's ndigits */ /*JLS 05-01-01*/
+ char *bindDNHead; /* Bind DN's head */ /*JLS 05-01-01*/
+ char *bindDNTail; /* Bind DN's tail */ /*JLS 05-01-01*/
+ char *certfile; /* certificate file */ /* BK 11-10-00 */
+ char *cltcertname; /* client cert name */ /* BK 23 11-00 */
+ data_list_file *dlf; /* Data list files */ /*JLS 23-03-01*/
+ int errors[MAX_ERROR_NB]; /* Err stats */
+ int errorsBad; /* Bad errors */
+ ldclt_mutex_t errors_mutex; /* Protect errors */ /*JLS 28-11-00*/
+ int exitStatus; /* Exit status */ /*JLS 25-08-00*/
+ char *filter; /* Filter for req. */
+ char *genldifName; /* Where to put ldif */ /*JLS 19-03-01*/
+ int genldifFile; /* Where to put ldif */ /*JLS 19-03-01*/
+ char *hostname; /* Host to connect */
+ int globStatsCnt; /* Global stats loop */ /*JLS 08-08-00*/
+ int ignErr[MAX_IGN_ERRORS]; /* Err ignor */
+ int ignErrNb; /* Nb err ignored */
+ image *images; /* The images */
+ char *imagesDir; /* Where are images */ /*JLS 16-11-00*/
+ int imagesNb; /* Nb of images */
+ int imagesLast; /* Last selected image */
+ ldclt_mutex_t imagesLast_mutex; /* Protect imagesLast */
+ int inactivMax; /* Allowed inactivity */
+ char *keydbfile; /* key DB file */ /* BK 23-11-00*/
+ char *keydbpin; /* key DB password */ /* BK 23-11-00*/
+ int lastVal; /* To build filters */ /*JLS 14-03-01*/
+ ldclt_mutex_t lastVal_mutex; /* Protect lastVal */ /*JLS 14-03-01*/
+ int maxErrors; /* Max allowed errors */
+ unsigned int mode; /* Running mode */
+ unsigned int mod2; /* Running mode - 2 */ /*JLS 19-03-01*/
+ int nbNoActivity; /* Nb times no activ. */
+ int nbSamples; /* Samples to get */
+ int nbThreads; /* Nb of client */
+ vers_object object; /* Object to generate *//*JLS 19-03-01*/
+ oper *opListTail; /* Tail of operation list */
+ ldclt_mutex_t opListTail_mutex; /* Protect opListTail */
+ char *passwd; /* Bind passwd */
+ int passwdNbDigit; /* Passwd's ndigits */ /*JLS 05-01-01*/
+ char *passwdHead; /* Passwd's head */ /*JLS 05-01-01*/
+ char *passwdTail; /* Passwd's tail */ /*JLS 05-01-01*/
+ int pid; /* Process ID */
+ int port; /* Port to use */
+ int randomLow; /* Rnd's low value */
+ int randomHigh; /* Rnd's high val */
+ int randomNbDigit; /* Rnd's nb of digits */
+ char *randomHead; /* Rnd's head string */
+ char *randomTail; /* Rnd's tail string */
+ data_list_file *rndBindDlf; /* Rnd bind file data *//*JLS 03-05-01*/
+ char *rndBindFname; /* Rnd bind file name *//*JLS 03-05-01*/
+ int referral; /* Referral followed */ /*JLS 08-03-01*/
+ int sampling; /* Sampling frequency */
+ int scope; /* Searches scope */
+ int slaveConn; /* Slave has connected */
+ char *slaves[MAX_SLAVES]; /* Slaves list */
+ int slavesNb; /* Number of slaves */
+ ssl_context sslctx; /* SSL dyn. load ctx */ /*JSL 07-11-00*/
+ int timeout; /* LDAP op. t.o. */
+ struct timeval timeval; /* Timeval structure */
+ struct timeval timevalZero; /* Timeout of zero */
+ int totalReq; /* Total requested */
+ int totNbOpers; /* Total opers number */
+ int totNbSamples; /* Total samples nb */
+ int waitSec; /* Wait between two operations */
+} main_context;
+
+
+/*
+ * This structure is aimed to ease the managing of asynchronous
+ * operations, keeping in memory the msgid returned by the library and
+ * a free string meaning something for the user.
+ * It is targetted that this string is something like a DN, and is
+ * locally managed by the list functions.
+ */
+typedef struct msgid_cell {
+ LDAPMod **attribs; /* Attributes */
+ char dn[MAX_DN_LENGTH]; /* entry's dn */
+ int msgid; /* msg id */
+ char str[MAX_DN_LENGTH]; /* free str */
+ struct msgid_cell *next; /* next cell */
+} msgid_cell;
+
+/*
+ * This structure contain the context associated with each thread.
+ * It is targetted to be initiated by the main thread, and maintained
+ * by each thread.
+ */
+typedef struct thread_context {
+ int active; /* thread is active */
+ int asyncHit; /* async max hit */
+ char *attrlist[MAX_ATTRIBS]; /*JLS 15-03-01*/
+ int binded; /* thread is binded */
+ int exitStatus; /* Exit status */ /*JLS 25-08-00*/
+ int fd; /* fd to the server */
+ int lastVal; /* To build filters */
+ LDAP *ldapCtx; /* LDAP context */
+ unsigned int mode; /* Running mode */
+ int nbInactRow; /* Nb inactive in row *//*JLS 04-08-00*/
+ int nbInactTot; /* Nb inactive total */ /*JLS 04-08-00*/
+ int nbOpers; /* Nb of operations */
+ ldclt_mutex_t nbOpers_mutex; /* Protect nbOpers */ /*JLS 28-11-00*/
+ vers_object *object; /* Template */ /*JLS 21-03-01*/
+ int pendingNb; /* Pending opers */
+ int status; /* Status */
+ ldclt_mutex_t status_mutex; /* Protect status */ /*JLS 28-11-00*/
+ ldclt_tid tid; /* Thread's id */ /*JLS 28-11-00*/
+ char thrdId[8]; /* This thread ident */ /*JLS 08-01-01*/
+ int thrdNum; /* This thread number */
+ int totOpers; /* Total nb operations */
+ int totalReq; /* Total nb operations requested */
+ /*
+ * Now some convenient buffers ;-)
+ */
+ char buf2 [MAX_FILTER];
+ char *bufObject1; /*JLS 19-03-01*/
+ char *bufAttrpl; /* Attribute replace */ /*JLS 21-11-00*/
+ char *bufBaseDN; /* Base DN to use */
+ char *bufBindDN; /* Bind DN to use */ /*JLS 05-01-01*/
+ char *bufFilter; /* Filter to use */
+ char *bufPasswd; /* Bind passwd to use *//*JLS 05-01-01*/
+ /*
+ * Note about matcheddnp management. This pointer is managed by the
+ * function dnFromMessage() that need it to free or remember the string
+ * returned by the library. DO NOT manage this field another way.
+ */
+ char *matcheddnp; /* See above */ /*JLS 15-12-00*/
+ int startAttrpl; /* Insert random here *//*JLS 21-11-00*/
+ int startBaseDN; /* Insert random here */
+ int startBindDN; /* Insert random here *//*JLS 05-01-01*/
+ int startPasswd; /* Insert random here *//*JLS 05-01-01*/
+ int startRandom; /* Insert random here */
+ msgid_cell *firstMsgId; /* pending messages */
+ msgid_cell *lastMsgId; /* last one */
+} thread_context;
+
+/*
+ * This structure gather the information used by a check thread
+ */
+typedef struct check_context {
+ oper *headListOp; /* Head list of operation */
+ thoper *dcOper; /* Double check operation list */
+ char *slaveName; /* Name of the slave */
+ int sockfd; /* Socket fd after accept() */
+ int status; /* Status */
+ int thrdNum; /* Thread number */
+ int calls; /* Number of timeouts */
+ ldclt_tid tid; /* Thread's id */ /*JLS 28-11-00*/
+ int nbEarly; /* err = Early */
+ int nbLate; /* err = Late replica */
+ int nbLostOp; /* err = Lost op */
+ int nbNotOnList; /* err = Not on list */
+ int nbOpRecv; /* Nb operations received */
+ int nbRepFail32; /* err = Replica failed err=32 */
+ int nbRepFail68; /* err = Replica failed err=68 */
+ int nbRepFailX; /* err = Replica failed err=X */
+ int nbStillOnQ; /* err = still on Queue */
+} check_context;
+
+
+
+/*
+ * Extern declarations of global variables.
+ */
+extern main_context mctx; /* Main context */
+extern thread_context tctx[]; /* Thread contextes */
+extern check_context cctx[]; /* Check thread contextes */
+
+
+/*
+ * Extern functions prototypes (for exported functions)
+ */
+ /* From ldclt.c */
+extern void ldcltExit (int status); /*JLS 18-08-00*/
+extern int printGlobalStatistics (void); /*JLS 16-11-00*/
+ /* From ldcltU.c */
+extern void usage (void);
+ /* From threadMain.c */
+extern int addErrorStat (int err);
+extern int getThreadStatus (thread_context *tttctx, /*JLS 17-11-00*/
+ int *status); /*JLS 17-11-00*/
+extern int ignoreError (int err);
+extern int incrementCommonCounter (thread_context *tttctx); /*14-03-01*/
+extern int incrementCommonCounterObject ( /*JLS 28-03-01*/
+ thread_context *tttctx, /*JLS 28-03-01*/
+ vers_field *field); /*JLS 28-03-01*/
+extern int incrementNbOpers (thread_context *tttctx);
+extern int msgIdAdd (thread_context *tttctx, int msgid, char *str,
+ char *dn, LDAPMod **attribs);
+extern LDAPMod **msgIdAttribs (thread_context *tttctx, int msgid);
+extern int msgIdDel (thread_context *tttctx, int msgid, int freeAttr);
+extern char *msgIdDN (thread_context *tttctx, int msgid);
+extern char *msgIdStr (thread_context *tttctx, int msgid);
+extern int randomString (thread_context *tttctx, int nbDigits);
+extern char **selectRandomAttrList (thread_context *tttctx); /*JLS 15-03-01*/
+extern int setThreadStatus (thread_context *tttctx, /*JLS 17-11-00*/
+ int status); /*JLS 17-11-00*/
+extern void *threadMain (void *);
+ /* From ldapfct.c */
+extern int connectToServer (thread_context *tttctx); /*JLS 14-03-01*/
+extern char *dnFromMessage (thread_context *tttctx, LDAPMessage *res);
+extern int doAddEntry (thread_context *tttctx);
+extern int doAttrReplace (thread_context *tttctx); /*JLS 21-11-00*/
+extern int doBindOnly (thread_context *tttctx); /*JLS 04-05-01*/
+extern int doDeleteEntry (thread_context *tttctx);
+extern int doExactSearch (thread_context *tttctx);
+extern int doGenldif (thread_context *tttctx); /*JLS 19-03-01*/
+extern int doRename (thread_context *tttctx);
+extern int freeAttrib (LDAPMod **attrs);
+extern void ldclt_flush_genldif (void); /*JLS 02-04-01*/
+extern char *my_ldap_err2string (int err);
+extern char **strList1 (char *str1); /*JLS 08-01-01*/
+ /* From data.c */
+extern data_list_file *dataListFile (char *fname); /*JLS 23-03-01*/
+extern int getImage (LDAPMod *attribute);
+extern int loadImages (char *dirpath);
+ /* From workarounds.c */
+extern int getFdFromLdapSession (LDAP *ld, int *fd);
+ /* From opCheck.c */
+extern int opAdd (thread_context *tttctx, int type, char *dn,
+ LDAPMod **attribs, char *newRdn, char *newParent);
+extern void *opCheckMain (void *);
+extern void *opCheckLoop (void *);
+extern int opNext (check_context *ctctx, oper **op);
+extern int opRead (check_context *ctctx, int num, oper **op);
+ /* From parser.c */
+extern int parseAttribValue (char *fname, /*JLS 23-03-01*/
+ vers_object *obj, char *line, /*JLS 23-03-01*/
+ vers_attribute *attrib); /*JLS 23-03-01*/
+extern int readObject (vers_object *obj); /*JLS 19-03-01*/
+
+
+#endif /* LDCLT_H */
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/ldclt.man b/ldap/servers/slapd/tools/ldclt/ldclt.man
new file mode 100644
index 00000000..088e9048
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/ldclt.man
@@ -0,0 +1,754 @@
+#ident "ldclt @(#)ldclt.man 1.56 01/05/04"
+
+ldclt(1) SUNQAldap ldclt(1)
+
+NAME
+ ldclt - ldap client for stress and reliability testing.
+
+SYNOPSIS
+ ldclt [-qQvV] [-e <execParams>] [-t <timeout>]
+ [-b <base DN>] [-h <host>] [-p <port>]
+ [-D <bind DN>] [-w <passwd>]
+ [-n <nb threads>] [-i <nb times>] [-N <nb samples>]
+ [-r <low> -R <high>]
+ [-a <max pending>] [-E <max errors>]
+ [-I <ignored error>] [-T <total>]
+ [-f <filter>] [-s <scope>]
+ [-S <slave>] [-P<master port>]
+ [-W <waitsec>] [-Z <certfile>]
+
+AVAILABILITY
+ SUNQAldap
+
+DESCRIPTION
+ ldclt is a multi-threaded test tool targetted to stress a
+ ldap server with multiple simultaneous requests.
+
+ The tool automatically set its ulimit parameters to fit
+ with the options.
+
+ The tool uses a minimum of 16Mo of memory, and maybe more
+ depending on the operations requested.
+
+ A summary of global statistics regarding the operations
+ performed, and the errors that occurs, is printed at the
+ exit of the tool, as well as every 90 loops (15 minutes).
+
+ http://www-icnc.france/~jls/icnc_qa_lab_faq_05.html#ldclt
+
+ Mailing list : ldclt@france.sun.com
+
+ Referrals
+ By default, ldclt will let the ldap library try to follow
+ referrals as anonymous. The option "-e referral=value"
+ allows to change this behaviour :
+ on : (default) follow as anonymous.
+ off : do not follow.
+ rebind : try to rebind with the same binDN and passwd.
+
+ Search operation
+ The option -e attrsonly=value is used to request or not
+ the attributes values. It is recommanded to use ldclt
+ with the the default value (== 0) of this option.
+ Extract from the C-SDK documentation :
+ 0 : both attribute types and attribute values are
+ returned.
+ 1 : only attribute types are returned.
+
+ The options -e attrlist=name:name:name and similar option
+ -e randomattrlist=name:name:name allows to specify which
+ attributes are retrieved from the server.
+
+ Error decoding
+ The tool try to decode the error as much as possible, but
+ sometimes not enough information is send back to the
+ client. This happen if chaining the backend feature of
+ DS 5.0 or more is used, when one of the farm servers is
+ stopped. The error returned is "Operations error" without
+ any more information in synchronous mode (except for the
+ search).
+
+ This is a problem resides in the libldap implementation
+ of Solaris.
+
+ Implementation note : This improvement is to retrieve the
+ additional error string that is returned by the server.
+ This is implemented for the asynchronous operations and
+ for the synchronous search only, because for the other
+ synchronous ops we should use ldap_get_lderrno() that is
+ not implement in Solaris's libldap.
+
+ Missing nodes
+ The tool automatically create the missing nodes. These
+ nodes are created using the DN and passwd given in argu-
+ ments to ldclt, and thus it may be possible that the tool
+ cannot initiate an empty database if it is not cn=admin,
+ because only cn=admin may create the root entry.
+
+ Note that when it occurs, the tool doesn't retry to
+ create the original entry IF running *asynchronously*.
+
+ Special consideration about rename entries : from the
+ c-sdk function description, if the parent node of the new
+ dn doesn't exist, the error returned LDAP_PROTOCOL_ERROR
+ may report as well three other problems :
+ - BER problem, unlike to happen
+ - newrdn is invalid, also unlike to happen
+ - ldclt is not running ldap v3 - ok, we could leave with
+ this issue.
+ - the newparent is invalid. I thing that we could take
+ this for "doesn't exist"...
+
+ The current version of this tool recognize the following
+ naming attributes:
+ cn organizationalRole
+ o organization
+ ou organizationalUnit
+
+ Close(fd) vs ldap_unbind(ld)
+ The option "-e bindeach" made the tool to release the
+ connection to the server after each operation being
+ processed. This is intended to simulate many clients
+ doing quick operations.
+
+ Without any other option, the connection is properly
+ released with a ldap_unbind(ld), but if the additional
+ option "-e close" is used, the socket with the server is
+ close() simulating a suddent exit of the client process.
+
+ Random
+ This feature is activated by the option "-e random". When
+ used with filters, the tool will seek the given filters
+ for the first sequence of 'X' and will take this as the
+ place where the random numbers should be put. The span of
+ the random numbers generated is given by the options -r
+ and -R.
+
+ For example, if the tool is called with the options:
+
+ -f mail=a0000XXXXXX@sympatico.ca -e random -r0 \
+ -R 9000000
+
+ the following filters will be generated:
+
+ mail=a0000492027@sympatico.ca
+ mail=a0000001941@sympatico.ca
+ mail=a0000075117@sympatico.ca
+ mail=a0000589623@sympatico.ca
+ mail=a0000283543@sympatico.ca
+ mail=a0000051688@sympatico.ca
+ etc...
+
+ The same feature may be applied to the base DN, and is
+ activated by the options "-e randombase",
+ "-e randombaselow=value" and "-e randombasehigh=value".
+
+ The same feature may be applied to the bind DN, and is
+ activated by the options "-e randombinddn",
+ "-e randombinddnlow=value", "-e randombinddnhigh=value".
+
+ Incremental
+ This feature is activated by the option "-e incr", and is
+ similar to the "Random" feature described above. It will
+ replace the 'X' partern by incremental numbers starting
+ by the value of "-r" and ending with "-R". When the top
+ value is reached, return back to the lower value.
+
+ The option "-e noloop" will prevent ldclt from looping
+ the numbers: when the -R value is reached, the thread
+ dies.
+
+ The option "-e commoncounter" will made all the threads
+ use the same counter rather than each thread having its
+ own private counter. This may be used for example to have
+ many threads adding entries without "collisions".
+
+ String
+ This feature is activated by the option "-e string", and
+ will make this tool generates random strings for the 'X'
+ partern rather than random numbers.
+
+ This option is only valid with the mode "-e random", and
+ will be applied as well to the base DN if "-e randombase"
+ is set, and to the bind DN and bind password if the
+ option "-e randombinddn" is set.
+
+ The option "-e ascii" will produce characters less than
+ 0x7f, otherwise UTF-8 will be produced.
+
+ Signals
+ The signal SIGINT (^C or kill -2) is trapped to perform a
+ smooth exit of the tool, with statistics report.
+
+ The signal SIGQUIT (^\ or kill -3) is trapped to issue
+ the current statistics numbers, but without exiting the
+ tool.
+
+ Entry generator
+ If you do not want to use the hard-coded object classes
+ person/emailPerson/inetOrgPerson (see below), you may use
+ the option "-e object=filename" to give ldclt a template
+ to build the entries.
+
+ The same syntax may be used for the option "-e rdn=value"
+ including variables. The RDN is build first and you may
+ retrieve the variables you defined in it for the object.
+
+ You could use the option -e commoncounter with the entry
+ generator. When used, all the variants INCRNNOLOOP or
+ INCRN will share the same counter (if you are using three
+ times one of these variants, three different counters
+ will be used).
+
+ The option -e commoncounter is also compatible with the
+ variants INCRFROMFILE and INCRFROMFILENOLOOP.
+
+ File grammar :
+
+ # Comment start with a '#'
+ #
+ LINE = ATTRIBUTE_NAME: FIELD+
+ ATTRIBUTE_NAME = constant_string
+ FIELD = constant_string | VARIANT
+ VARIANT = [VAR=VDEF] | [VAR] | [VDEF]
+ VAR = letter A to H
+ VDEF = see below
+
+ The keywords and associated args are listed below. Note
+ that the separator is ';' and not ','.
+
+ INCRFROMFILE(file_name)
+ Will select each entry of file_name in sequence.
+ After the last entry, will reset the index for
+ to process again the first entry.
+ INCRFROMFILENOLOOP(file_name)
+ Will select each entry of file_name in sequence.
+ After the last entry, the thread will exit.
+ INCRN(low;hign;nb)
+ Increment a counter that will go from low to
+ high, and will loop to restart with low. This
+ counter is VARIANT-specific.
+ Similar to "-e incr".
+ INCRNNOLOOP(low;high;nb)
+ Same as INCRN, except that the thread will exit
+ when reaching the value high (after processing
+ of this value).
+ Similar to "-e incr,noloop".
+ RNDFROMFILE(file_name)
+ Select a random string from the file. One entry
+ per line is expected.
+ RNDN(low;high;length)
+ Build a random number of length digits, value
+ selected from low to high.
+ RNDS(lenght)
+ Build a random string.
+
+ Here is an example of template file :
+
+ # Example.
+ #
+ objectclass: person
+ sn: mr [RNDS(12)] final
+ description: blob [RNDN(1,5,6)] blib
+
+ Resulting entries :
+
+ dn: cn=mr00000,ou=object,o=test.com
+ cn: mr00000
+ objectclass: person
+ sn: mr 2[kK-:9)_(qv final
+ description: blob 000005 blib
+
+ dn: cn=mr00001,ou=object,o=test.com
+ cn: mr00001
+ objectclass: person
+ sn: mr Jwf01XrZs.mt final
+ description: blob 000002 blib
+
+ Person
+ Activated by "-e person" and valid only for the "-e add"
+ feature, the new entries are of the objectclass=person
+ as described here:
+
+ EmailPerson
+ Activated by "-e emailPerson" and valid only for the "-e
+ add" feature, the new entries are of the objectclass=
+ emailPerson as described here. These entries contain a
+ jpegPhoto attribute, and thus are very big entries. The
+ jpeg image itself is randomly (in fact: sequencially)
+ selected from /opt/SUNQA/ldap/lib/images/*.jpg or in the
+ directory specified by -e imagesdir=path.
+
+ InetOrgPerson
+ Activated by "-e inetOrgPerson", it is the Netscape
+ version of emailPerson.
+
+ Scalab01 scenario
+ This scenario is activated by the "-e scalab01" and is
+ a special evolution of ldclt for the purpose of the
+ system tests "scalab01". This scenario simulates a modem
+ pool that uses LDAP to store information about users, as
+ well as to autheticate them by binding.
+
+ The associated options are :
+ -e scalab01
+ Activate this scenario.
+
+ -e scalab01_cnxduration
+ Specifies the maximum cnx duration in seconds.
+ Default value is 3600 seconds.
+
+ -e scalab01_maxcnxnb
+ Modem pool size. Default size if 5000.
+
+ -e scalab01_wait
+ Sleep() in seconds while to attempts to connect.
+ Default value is 10 seconds.
+
+OPTIONS
+ The valid options are:
+
+ -a <number>
+ Asynchronous mode. When used, the tool will issue
+ asynchronous requests, with a maximum number of
+ pending requests (aka results non-read). There is
+ a threshold at "max pending / 2" giving the
+ minimum number of pending operations needed to
+ read the answers from the server.
+
+ Each thread will process with the same algorythm,
+ each having the same thresholds.
+
+ -b <DN> Specify the base DN to use. Default "o=sun,c=us".
+
+ -D <DN> Bind DN. See -w for the password. You could use
+ the option "-e randombinddn" to randomize the
+ bind DN. Read below in -e options for the
+ details.
+
+ -e <parm1,parm2,etc...>
+ Execution parameters. This option is used to
+ select the kind of tests that should be run. It
+ is possible to specify more than one value (see
+ example below). The valid values are:
+
+ add
+ Add entries.
+
+ append
+ Append new entries to genldif file.
+ See also -e genldif.
+
+ ascii
+ Ascii 7-bits strings.
+
+ attreplace=name:mask
+ Will replace the attribute "name" with a
+ random string value build using the mask
+ i.e. :
+ attreplace=sn:"mr XXXX Jr"
+ Note : You DO NOT need to use -e random
+ nor -e string with this option.
+
+ attrlist=name:name:name
+ Specify the list of attributes to
+ retrieve.
+ See also -e randomattrlist.
+
+ attrsonly=0|1
+ This ldap_search() parameter means : 0
+ specifies that both attribute types and
+ attribute values are returned and 1
+ specifies that only attribute types are
+ returned.
+ Default value : 0
+
+ bindeach
+ Bind for each operation.
+
+ bindonly
+ ldclt will only perform ldap_bind() and
+ ldap_unbind() or close() depending on
+ the options.
+ See also -e close.
+
+ close
+ Will disconnect from the server by a
+ close() on the fd, rather than by a
+ ldap_unbind().
+
+ cltcertname=certificate_name
+ Use certificate_name for SSL client
+ authentication. The certificate database
+ is specified with the -Z option.
+ SSL client authentication requires the
+ option -Z and cltcertname, keydbfile,
+ keydbpin execution parameters to be
+ specified.
+
+ commoncounter
+ Valid only with -e incr or -e object.
+ All the threads will use the same
+ counter, i.e. T000 will process entry n,
+ T001 entry n+1, etc...
+ When used with an object (-e object) or
+ within a rdn (-e rdn), a common counter
+ will be used for each variant field
+ INCRN or INCRNNOLOOP. Each field will
+ have its own common counter.
+
+ counteach
+ To count each operation, and not only
+ the ones that succeed. Without this
+ option, an add request with result
+ 68==LDAP_ALREADY_EXISTS is not counted,
+ that may mislead the statistics about
+ the thread's activity.
+ The changes are that we will count as a
+ valid request :
+ - add ==> LDAP_ALREADY_EXISTS
+ - delete ==> LDAP_NO_SUCH_OBJECT
+ - rename ==> LDAP_ALREADY_EXISTS
+ LDAP_NO_SUCH_OBJECT
+ LDAP_PROTOCOL_ERROR
+ - search ==> LDAP_NO_SUCH_OBJECT
+
+ delete
+ ldap_delete() entries.
+
+ dontsleeponserverdown
+ By default, ldclt sleep 1 second when
+ occurs an error like 81 or 91 (i.e.
+ server down). This should avoid ldclt
+ looping when server is down, otherwise it
+ may take 100% of all 10 CPUs of a E6000.
+ Basically, the client machine is down if
+ this happen.
+
+ emailPerson
+ The new entries objectclass is
+ emailPerson. See details above in
+ DESCRIPTION.
+
+ esearch
+ Exact search. No wildcards expected in
+ the filter.
+
+ genldif=filename
+ Create a ldif file using ldclt entry
+ generator.
+ See also -e append.
+
+ imagesdir=<path>
+ The images are taken from the given path
+ rather than from the default directory :
+ /opt/SUNQA/ldap/lib/images
+
+ incr
+ Incremental values, from -r to -R values
+ When -R is reached, go back to -r.
+ See also -e commoncounter.
+
+ inetOrgPerson
+ The new entries objectclass is
+ inetOrgPerson. See details above in
+ DESCRIPTION.
+
+ keydbfile=key_DB_filename
+ The file name of the key database.
+ SSL client authentication requires the
+ option -Z and cltcertname, keydbfile,
+ keydbpin execution parameters to be
+ specified.
+
+ keydbpin=key_DB_password
+ Password required for accessing the key
+ database specified in keydbfile
+ execution parameter.
+ SSL client authentication requires the
+ option -Z and cltcertname, keydbfile,
+ keydbpin execution parameters to be
+ specified.
+
+ noglobalstats
+ Don't print the periodical global stats
+ (by default : every 90 loops).
+
+ noloop
+ Does not loop the numbers. Cf the option
+ "-e incr".
+
+ object=filename
+ Entries will be created using template
+ from the given file. See details above
+ in DESCRIPTION.
+ See "-e rdn=attrname:value".
+
+ person
+ The new entries objectclass is person.
+ See details in DESCRIPTION.
+
+ random
+ Random filters, etc... generation. See
+ details above in this tool description.
+
+ randomattrlist=name:name:name
+ Specify the list of attributes from
+ which ldclt will randomly select one to
+ be retrieved.
+ See also -e attrlist.
+
+ randombase
+ Random base DN generation.
+
+ randombaselow=<number>
+ Low value range for random base DN.
+
+ randombasehigh=<number>
+ High value range for random base DN.
+
+ randombinddn
+ Random bind DN and bind password
+ generation. When used, this option will
+ produce a random value that will be used
+ to randomize the bind DN and password
+ with the same random value. e.g. cn=m123
+ and passwd123 will be generated.
+ If you want to have fix password (the
+ same password) for each bind DN, just no
+ 'X' in the password.
+
+ randombinddnfromfile=filename
+ A bind DN and its corresponding password
+ will be randomly selected from the given
+ file. Each line must contain the bind DN
+ and password, separated by one or more
+ tabs. Leading & trailing spaces are not
+ ignored.
+ Exclusive with -e randombinddn and with
+ -D / -w.
+
+ randombinddnlow=<number>
+ Low value range for random bind DN.
+
+ randombinddnhigh=<number>
+ High value range for random bind DN.
+
+ rdn=attrname:value
+ Similar to the option "-f filterspec",
+ this feature allow to use the full power
+ of the entry generator (see DESCRIPTION)
+ to build the rdn of the entry that will
+ be processed.
+ Requires "-e object=".
+ Exclusive with -f.
+
+ referral=value
+ Change referral behaviour. See details
+ above in the DESCRIPTION section.
+
+ rename
+ Rename entries (aka modrdn). See also
+ -e withnewparent.
+
+ scalab01
+ Activates the scalab01 scenario. Please
+ read the corresponding section above for
+ the other associated options and
+ behaviour.
+
+ string
+ Will generate random strings rather than
+ numbers. See details above in the string
+ sub-section.
+
+ v2
+ Ldap v2 mode.
+
+ withnewparent
+ The ldap_rename() will be called with a
+ newparent argument. By default, only the
+ new rdn is specified. This option is
+ valid only with -e rename.
+
+ -E <number>
+ Specify the maximum number of times one error
+ may occur. It is usefull to detect a big problem
+ on the server side, and to exit the tool. The
+ default value is 1000.
+
+ -f <filter>
+ Filter for searches. The syntax is the same as
+ specified in ldap's RFCs.
+ See option "-e rdn=attrname:value".
+
+ -h <hostname>
+ Host to connect. Default "localhost".
+
+ -i <number of 10 seconds>
+ Number of times inactivity allowed. The tool
+ ensure that no thread is starving, i.e. expect
+ that all the threads should perform at least one
+ operation every 10 seconds. This parameter gives
+ the number of times a thread may be starving
+ before releasing an alert message. The default
+ value is 3 (30 seconds).
+
+ -I <error number>
+ The tool will ignore the errors the same number
+ as the ones specified with -I. These errors may
+ be for example:
+ 32 : No such object - when -e random,delete
+ 68 : Already exists - when -e random,add
+
+ When used, this option will configure ldclt to
+ ignore/support these errors during the ldap_bind
+ to the server. Otherwise, any error that happen
+ during the connection is a fatal error for the
+ thread where it occurs.
+
+ Note that although ldclt support a certain level
+ of errors during connection, any error that
+ happen while creating missing nodes is a fatal
+ error.
+
+ -n <number>
+ Number of threads. Each thread is a ldap client
+ for the ldap server under test. The maximum
+ number of threads is system-dependand, and is of
+ 1000 threads. The default number is 10 threads.
+
+ -N <number>
+ Number of samples (10 seconds each). It is the
+ time the tool should run. A value of 360 means
+ 360 samples of 10 seconds, i.e. 3600 seconds of
+ testing (one hour). Default infinite.
+
+ -p <port number>
+ Server port. Default port 389.
+
+ -P <master port number>
+ This is the port used to communicate with the
+ slaves in order to check the replication.
+
+ -q Quiet mode. When used, the errors of the option
+ -I are not printed. The messages "Intermediate
+ nodes created for xxx" are not printed either.
+
+ -Q Super quiet mode. In addition to -q, the
+ following messages are not printed:
+ Max pending request hit.
+ No activity for %d seconds.
+ Restart sending.
+
+ -r <number>
+ Range's low value.
+
+ -R <number>
+ Range's high value.
+
+ -s <scope>
+ Valid only for searches. May be base, subtree
+ or one. The default value is subtree.
+
+ -S <slave>
+ The slave host given in argument will be under
+ monitoring to ensure that the operations
+ performed on the server are well realized on
+ the given slave. This option may be used more
+ than one time to indicate more than one slave.
+
+ -t <seconds>
+ LDAP operations timeout. Default 30 seconds.
+
+ -T <total>
+ Total number of operations requested per thread
+ before exit. When used, this parameter will
+ cause each thread to exit when this number of
+ operations is reached.
+
+ -v Verbose.
+
+ -V Very verbose.
+
+ -w <password>
+ Bind passwd. See option -D.
+
+ -W <wait seconds>
+ Wait between two operations. Default=0 seconds.
+
+ -Z <certfile>
+ Establish secure communication with the server
+ over SSL using certfile as the certificate
+ database.
+
+EXIT STATUS
+
+ ldclt exit status may be :
+
+ 0 : no problem during execution.
+ 1 : please report this to me - shouldn't happen !!
+ 2 : error in parameters.
+ 3 : max errors reached.
+ 4 : cannot bind.
+ 5 : cannot load libssl.
+ 6 : mutex error.
+ 7 : initialization problem.
+ 8 : ressource limitation (malloc, etc...).
+ 99 : other kind of error - please report to me.
+
+EXAMPLES
+ jls@chronos$ ldclt -v \
+ -h aegir -e esearch,random \
+ -r0 -R900000 \
+ -bo=Sympatico,c=CA \
+ -fmail=a0000XXXXXX@sympatico.ca \
+ -ebindeach -n230 -i6
+ Host to connect = aegir
+ Port number = 389
+ Bind DN = NULL
+ Passwd = NULL
+ Base DN = o=Sympatico,c=CA
+ Filter = mail=a0000XXXXXX@sympatico.ca
+ Max times inactive = 6
+ Number of samples = 20
+ Number of threads = 5
+ Running mode = 0x0000001d
+ Sampling interval = 10 sec
+ Random range = [0 , 900000]
+ Filter's head = mail=a0000
+ Filter's tail = @sympatico.ca
+ Average rate: 9.98/thr (229.50/sec), total: 2295
+ Average rate: 10.13/thr (233.00/sec), total: 2330
+ Average rate: 10.05/thr (231.10/sec), total: 2311
+ Average rate: 10.17/thr (233.80/sec), total: 2338
+ Average rate: 9.99/thr (229.80/sec), total: 2298
+ ^CCatch SIGINT - exit...
+ jls@chronos$
+
+NOTES
+ This tool doesn't retry to create the original entry when
+ the creation of the missing nodes is activated. This is a
+ known missing feature of the asynchronous mode.
+
+ Please read the file "History" delivered with this tool
+ for more information about new features, todo list, etc.
+
+ IMPORTANT NOTE : you may specify a filter that return lot
+ of entries (e.g. : -f "cn=*") but you should then know
+ that such filters leads to retrieve a lot of data from
+ the server. These data are malloc() and free() by ldclt
+ and the ldap C library, but as you may have many threads
+ running at the same time in ldclt, you will have many
+ times these data allocated, leading to a *very) big ldclt
+ process, even more than 1Gb. It is not a memory leak but
+ rather allocation of lot of data. If you want the server
+ to retrieve a lot of data from its database and however
+ limit the ressources required by ldclt, use the option
+ "-e attrsonly=1".
+
+AUTHORS
+ Jean-Luc Schwing
+ Fabio Pistolesi : replication check.
+ Bertold Kolics : SSL.
+
diff --git a/ldap/servers/slapd/tools/ldclt/ldclt.use b/ldap/servers/slapd/tools/ldclt/ldclt.use
new file mode 100644
index 00000000..37ebe05e
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/ldclt.use
@@ -0,0 +1,86 @@
+usage: ldclt [-qQvV] [-E <max errors>]
+ [-b <base DN>] [-h <host>] [-p <port>] [-t <timeout>]
+ [-D <bind DN>] [-w <passwd>]
+ [-e <execParams>] [-a <max pending>]
+ [-n <nb threads>] [-i <nb times>] [-N <nb samples>]
+ [-I <err number>] [-T <total>]
+ [-r <low> -R <high>]
+ [-f <filter>] [-s <scope>]
+ [-S <slave>] [-P<master port>]
+ [-W <waitsec>] [-Z <certfile>]
+
+ This tool is a ldap client targetted to validate the reliability of
+ the product under test under hard use.
+
+ The valid options are:
+ -a Asynchronous mode, with max pending operations.
+ -b Give the base DN to use. Default "o=sun,c=us".
+ -D Bind DN. See -w
+ -E Max errors allowed. Default 1000.
+ -e Execution parameters:
+ add : ldap_add() entries.
+ append : append entries to the genldif file.
+ ascii : ascii 7-bits strings.
+ attreplace=name:mask : replace attribute of existing entry.
+ attrlist=name:name:name : specify list of attribs to retrieve
+ attrsonly=0|1 : ldap_search() parameter. Set 0 to read values.
+ bindeach : ldap_bind() for each operation.
+ bindonly : only bind/unbind, no other operation is performed.
+ close : will close() the fd, rather than ldap_unbind().
+ cltcertname=name : name of the SSL client certificate
+ commoncounter : all threads share the same counter.
+ counteach : count each operation not only successful ones.
+ delete : ldap_delete() entries.
+ dontsleeponserverdown : will loop very fast if server down.
+ emailPerson : objectclass=emailPerson (-e add only).
+ esearch : exact search.
+ genldif=filename : generates a ldif file
+ imagesdir=path : specify where are the images.
+ incr : incremental values.
+ inetOrgPerson : objectclass=inetOrgPerson (-e add only).
+ keydbfile=file : filename of the key database
+ keydbpin=password : password for accessing the key database
+ noglobalstats : don't print periodical global statistics
+ noloop : does not loop the incremental numbers.
+ object=filename : build object from input file
+ person : objectclass=person (-e add only).
+ random : random filters, etc...
+ randomattrlist=name:name:name : random select attrib in the list
+ randombase : random base DN.
+ randombaselow=value : low value for random generator.
+ randombasehigh=value : high value for random generator.
+ randombinddn : random bind DN.
+ randombinddnfromfile=fine : retrieve bind DN & passwd from file
+ randombinddnlow=value : low value for random generator.
+ randombinddnhigh=value : high value for random generator.
+ rdn=attrname:value : alternate for -f.
+ referral=on|off|rebind : change referral behaviour.
+ scalab01 : activates scalab01 scenario.
+ scalab01_cnxduration : maximum connection duration.
+ scalab01_maxcnxnb : modem pool size.
+ scalab01_wait : sleep() between 2 attempts to connect.
+ string : create random strings rather than random numbers.
+ v2 : ldap v2.
+ withnewparent : rename with newparent specified as argument.
+ -f Filter for searches.
+ -h Host to connect. Default "localhost".
+ -i Number of times inactivity allowed. Default 3 (30 seconds)
+ -I Ignore errors (cf. -E). Default none.
+ -n Number of threads. Default 10.
+ -N Number of samples (10 seconds each). Default infinite.
+ -p Server port. Default 389.
+ -P Master port (to check replication). Default 16000.
+ -q Quiet mode. See option -I.
+ -Q Super quiet mode.
+ -r Range's low value.
+ -R Range's high value.
+ -s Scope. May be base, subtree or one. Default subtree.
+ -S Slave to check.
+ -t LDAP operations timeout. Default 30 seconds.
+ -T Total number of operations per thread. Default infinite.
+ -v Verbose.
+ -V Very verbose.
+ -w Bind passwd. See -D.
+ -W Wait between two operations. Default 0 seconds.
+ -Z certfile. Turn on SSL and use certfile as the certificate DB
+
diff --git a/ldap/servers/slapd/tools/ldclt/ldcltU.c b/ldap/servers/slapd/tools/ldclt/ldcltU.c
new file mode 100644
index 00000000..8c72be92
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/ldcltU.c
@@ -0,0 +1,224 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <stdio.h>
+
+
+/*
+ * usage: ldclt [-qQvV] [-E <max errors>]
+ * [-b <base DN>] [-h <host>] [-p <port>] [-t <timeout>]
+ * [-D <bind DN>] [-w <passwd>]
+ * [-e <execParams>] [-a <max pending>]
+ * [-n <nb threads>] [-i <nb times>] [-N <nb samples>]
+ * [-I <err number>] [-T <total>]
+ * [-r <low> -R <high>]
+ * [-f <filter>] [-s <scope>]
+ * [-S <slave>] [-P<master port>]
+ * [-W <waitsec>] [-Z <certfile>]
+ *
+ * This tool is a ldap client targetted to validate the reliability of
+ * the product under test under hard use.
+ *
+ * The valid options are:
+ * -a Asynchronous mode, with max pending operations.
+ * -b Give the base DN to use. Default "o=sun,c=us".
+ * -D Bind DN. See -w
+ * -E Max errors allowed. Default 1000.
+ * -e Execution parameters:
+ * add : ldap_add() entries.
+ * append : append entries to the genldif file.
+ * ascii : ascii 7-bits strings.
+ * attreplace=name:mask : replace attribute of existing entry.
+ * attrlist=name:name:name : specify list of attribs to retrieve
+ * attrsonly=0|1 : ldap_search() parameter. Set 0 to read values.
+ * bindeach : ldap_bind() for each operation.
+ * bindonly : only bind/unbind, no other operation is performed.
+ * close : will close() the fd, rather than ldap_unbind().
+ * cltcertname=name : name of the SSL client certificate
+ * commoncounter : all threads share the same counter.
+ * counteach : count each operation not only successful ones.
+ * delete : ldap_delete() entries.
+ * dontsleeponserverdown : will loop very fast if server down.
+ * emailPerson : objectclass=emailPerson (-e add only).
+ * esearch : exact search.
+ * genldif=filename : generates a ldif file
+ * imagesdir=path : specify where are the images.
+ * incr : incremental values.
+ * inetOrgPerson : objectclass=inetOrgPerson (-e add only).
+ * keydbfile=file : filename of the key database
+ * keydbpin=password : password for accessing the key database
+ * noglobalstats : don't print periodical global statistics
+ * noloop : does not loop the incremental numbers.
+ * object=filename : build object from input file
+ * person : objectclass=person (-e add only).
+ * random : random filters, etc...
+ * randomattrlist=name:name:name : random select attrib in the list
+ * randombase : random base DN.
+ * randombaselow=value : low value for random generator.
+ * randombasehigh=value : high value for random generator.
+ * randombinddn : random bind DN.
+ * randombinddnfromfile=fine : retrieve bind DN & passwd from file
+ * randombinddnlow=value : low value for random generator.
+ * randombinddnhigh=value : high value for random generator.
+ * rdn=attrname:value : alternate for -f.
+ * referral=on|off|rebind : change referral behaviour.
+ * scalab01 : activates scalab01 scenario.
+ * scalab01_cnxduration : maximum connection duration.
+ * scalab01_maxcnxnb : modem pool size.
+ * scalab01_wait : sleep() between 2 attempts to connect.
+ * smoothshutdown : main thread waits till the worker threads exit.
+ * string : create random strings rather than random numbers.
+ * v2 : ldap v2.
+ * withnewparent : rename with newparent specified as argument.
+ * -f Filter for searches.
+ * -h Host to connect. Default "localhost".
+ * -i Number of times inactivity allowed. Default 3 (30 seconds)
+ * -I Ignore errors (cf. -E). Default none.
+ * -n Number of threads. Default 10.
+ * -N Number of samples (10 seconds each). Default infinite.
+ * -p Server port. Default 389.
+ * -P Master port (to check replication). Default 16000.
+ * -q Quiet mode. See option -I.
+ * -Q Super quiet mode.
+ * -r Range's low value.
+ * -R Range's high value.
+ * -s Scope. May be base, subtree or one. Default subtree.
+ * -S Slave to check.
+ * -t LDAP operations timeout. Default 30 seconds.
+ * -T Total number of operations per thread. Default infinite.
+ * -v Verbose.
+ * -V Very verbose.
+ * -w Bind passwd. See -D.
+ * -W Wait between two operations. Default 0 seconds.
+ * -Z certfile. Turn on SSL and use certfile as the certificate DB
+ */
+void usage ()
+{
+ (void) printf ("\n");
+ (void) printf ("usage: ldclt [-qQvV] [-E <max errors>]\n");
+ (void) printf (" [-b <base DN>] [-h <host>] [-p <port>] [-t <timeout>]\n");
+ (void) printf (" [-D <bind DN>] [-w <passwd>]\n");
+ (void) printf (" [-e <execParams>] [-a <max pending>]\n");
+ (void) printf (" [-n <nb threads>] [-i <nb times>] [-N <nb samples>]\n");
+ (void) printf (" [-I <err number>] [-T <total>]\n");
+ (void) printf (" [-r <low> -R <high>]\n");
+ (void) printf (" [-f <filter>] [-s <scope>]\n");
+ (void) printf (" [-S <slave>] [-P<master port>]\n");
+ (void) printf (" [-W <waitsec>] [-Z <certfile>]\n");
+ (void) printf ("\n");
+ (void) printf (" This tool is a ldap client targetted to validate the reliability of\n");
+ (void) printf (" the product under test under hard use.\n");
+ (void) printf ("\n");
+ (void) printf (" The valid options are:\n");
+ (void) printf (" -a Asynchronous mode, with max pending operations.\n");
+ (void) printf (" -b Give the base DN to use. Default \"o=sun,c=us\".\n");
+ (void) printf (" -D Bind DN. See -w\n");
+ (void) printf (" -E Max errors allowed. Default 1000.\n");
+ (void) printf (" -e Execution parameters:\n");
+ (void) printf (" add : ldap_add() entries.\n");
+ (void) printf (" append : append entries to the genldif file.\n");
+ (void) printf (" ascii : ascii 7-bits strings.\n");
+ (void) printf (" attreplace=name:mask : replace attribute of existing entry.\n");
+ (void) printf (" attrlist=name:name:name : specify list of attribs to retrieve\n");
+ (void) printf (" attrsonly=0|1 : ldap_search() parameter. Set 0 to read values.\n");
+ (void) printf (" bindeach : ldap_bind() for each operation.\n");
+ (void) printf (" bindonly : only bind/unbind, no other operation is performed.\n");
+ (void) printf (" close : will close() the fd, rather than ldap_unbind().\n");
+ (void) printf (" cltcertname=name : name of the SSL client certificate\n");
+ (void) printf (" commoncounter : all threads share the same counter.\n");
+ (void) printf (" counteach : count each operation not only successful ones.\n");
+ (void) printf (" delete : ldap_delete() entries.\n");
+ (void) printf (" dontsleeponserverdown : will loop very fast if server down.\n");
+ (void) printf (" emailPerson : objectclass=emailPerson (-e add only).\n");
+ (void) printf (" esearch : exact search.\n");
+ (void) printf (" genldif=filename : generates a ldif file\n");
+ (void) printf (" imagesdir=path : specify where are the images.\n");
+ (void) printf (" incr : incremental values.\n");
+ (void) printf (" inetOrgPerson : objectclass=inetOrgPerson (-e add only).\n");
+ (void) printf (" keydbfile=file : filename of the key database\n");
+ (void) printf (" keydbpin=password : password for accessing the key database\n");
+ (void) printf (" noglobalstats : don't print periodical global statistics\n");
+ (void) printf (" noloop : does not loop the incremental numbers.\n");
+ (void) printf (" object=filename : build object from input file\n");
+ (void) printf (" person : objectclass=person (-e add only).\n");
+ (void) printf (" random : random filters, etc...\n");
+ (void) printf (" randomattrlist=name:name:name : random select attrib in the list\n");
+ (void) printf (" randombase : random base DN.\n");
+ (void) printf (" randombaselow=value : low value for random generator.\n");
+ (void) printf (" randombasehigh=value : high value for random generator.\n");
+ (void) printf (" randombinddn : random bind DN.\n");
+ (void) printf (" randombinddnfromfile=fine : retrieve bind DN & passwd from file\n");
+ (void) printf (" randombinddnlow=value : low value for random generator.\n");
+ (void) printf (" randombinddnhigh=value : high value for random generator.\n");
+ (void) printf (" rdn=attrname:value : alternate for -f.\n");
+ (void) printf (" referral=on|off|rebind : change referral behaviour.\n");
+ (void) printf (" scalab01 : activates scalab01 scenario.\n");
+ (void) printf (" scalab01_cnxduration : maximum connection duration.\n");
+ (void) printf (" scalab01_maxcnxnb : modem pool size.\n");
+ (void) printf (" scalab01_wait : sleep() between 2 attempts to connect.\n");
+ (void) printf (" smoothshutdown : main thread waits till the worker threads exit.\n");
+ (void) printf (" string : create random strings rather than random numbers.\n");
+ (void) printf (" v2 : ldap v2.\n");
+ (void) printf (" withnewparent : rename with newparent specified as argument.\n");
+ (void) printf (" -f Filter for searches.\n");
+ (void) printf (" -h Host to connect. Default \"localhost\".\n");
+ (void) printf (" -i Number of times inactivity allowed. Default 3 (30 seconds)\n");
+ (void) printf (" -I Ignore errors (cf. -E). Default none.\n");
+ (void) printf (" -n Number of threads. Default 10.\n");
+ (void) printf (" -N Number of samples (10 seconds each). Default infinite.\n");
+ (void) printf (" -p Server port. Default 389.\n");
+ (void) printf (" -P Master port (to check replication). Default 16000.\n");
+ (void) printf (" -q Quiet mode. See option -I.\n");
+ (void) printf (" -Q Super quiet mode.\n");
+ (void) printf (" -r Range's low value.\n");
+ (void) printf (" -R Range's high value.\n");
+ (void) printf (" -s Scope. May be base, subtree or one. Default subtree.\n");
+ (void) printf (" -S Slave to check.\n");
+ (void) printf (" -t LDAP operations timeout. Default 30 seconds.\n");
+ (void) printf (" -T Total number of operations per thread. Default infinite.\n");
+ (void) printf (" -v Verbose.\n");
+ (void) printf (" -V Very verbose.\n");
+ (void) printf (" -w Bind passwd. See -D.\n");
+ (void) printf (" -W Wait between two operations. Default 0 seconds.\n");
+ (void) printf (" -Z certfile. Turn on SSL and use certfile as the certificate DB\n");
+ (void) printf ("\n");
+} /* usage() */
+
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/opCheck.c b/ldap/servers/slapd/tools/ldclt/opCheck.c
new file mode 100644
index 00000000..b9c200c0
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/opCheck.c
@@ -0,0 +1,1012 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : opCheck.c
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 04 May 1999
+ DESCRIPTION :
+ This file contains the functions used to manage and
+ check the operations performed by the tool.
+ These functions manages the operation list
+ "mctx.opListTail", match an entry retrieved from the
+ server to the attributes memorized for one operation,
+ etc...
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+04/05/99 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+05/05/99 | F. Pistolesi | 1.8 : Add communication with remote host.
+ | Implement operations check.
+---------+--------------+------------------------------------------------------
+06/05/99 | JL Schwing | 1.10: Implements opDecOper().
+ | Add more traces in VERY_VERBOSE
+---------+--------------+------------------------------------------------------
+20/05/99 | JL Schwing | 1.18: Add params (newRdn and newParent) to opAdd()
+ | Decode operations in Cnnn messages.
+ | No more exit on EINTR in accept()
+ | Fix memory leak in thOperFree()
+---------+--------------+------------------------------------------------------
+21/05/99 | JL Schwing | 1.19: Minor fixes in messages.
+ | Purify cleanup - Free memory read in opCheckLoop()
+ | Fix thOperFree() - pb when head of list to delete
+ | Fix memory leak in opNext().
+---------+--------------+------------------------------------------------------
+26/05/99 | JL Schwing | 1.21: Bug fix - return(-1) bad place in opNext().
+ | Minor fixes in messages.
+---------+--------------+------------------------------------------------------
+27/05/99 | JL Schwing | 1.22 : Add statistics to check threads.
+---------+--------------+------------------------------------------------------
+27/05/99 | F. Pistolesi | 1.23 : Fix statistics and other algorythms.
+---------+--------------+------------------------------------------------------
+31/05/99 | JL Schwing | 1.25 : Bug fix - should test opRead() returned pointer
+---------+--------------+------------------------------------------------------
+02/06/99 | JL Schwing | 1.26 : Add flag in main ctx to know if slave was
+ | connected or not.
+ | Add counter of operations received in check threads.
+---------+--------------+------------------------------------------------------
+06/03/00 | JL Schwing | 1.27: Test malloc() return value.
+---------+--------------+------------------------------------------------------
+18/08/00 | JL Schwing | 1.28: Print begin and end dates.
+---------+--------------+------------------------------------------------------
+17/11/00 | JL Schwing | 1.29: Implement "-e smoothshutdown".
+---------+--------------+------------------------------------------------------
+29/11/00 | JL Schwing | 1.30: Port on NT 4.
+---------+--------------+------------------------------------------------------
+*/
+
+#include <pthread.h> /* Posix threads */
+#include <errno.h> /* errno, etc... */
+#include <stdlib.h> /* exit(), etc... */
+#include <unistd.h> /* sleep(), etc... */
+#include <stdio.h> /* printf(), etc... */
+#include <signal.h> /* sigset(), etc... */
+#include <string.h> /* strerror(), etc... */
+#include <sys/resource.h> /* setrlimit(), etc... */
+#include <lber.h> /* ldap C-API BER decl. */
+#include <ldap.h> /* ldap C-API decl. */
+#include <sys/poll.h> /* djani : while porting */
+#include <sys/socket.h> /* djani : while porting */
+#include <sys/types.h> /* djani : while porting */
+#include <netdb.h> /* djani : while porting */
+#include <netinet/in.h> /* djani : while porting */
+#ifdef LDAP_H_FROM_QA_WKA
+#include <proto-ldap.h> /* ldap C-API prototypes */
+#endif
+#include "port.h" /* Portability definitions */ /*JLS 29-11-00*/
+#include "ldclt.h" /* This tool's include file */
+#include "remote.h" /* Definitions common with the slave */
+
+enum {SINGLE=0,FIRST,MIDDLE,LAST};
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : opDecOper
+ PURPOSE : This function decodes an LDAP operation and return a
+ printable string.
+ INPUT : op = operation to decode
+ OUTPUT : None.
+ RETURN : The decoded string.
+ DESCRIPTION :
+ *****************************************************************************/
+char *
+opDecOper (
+ int op)
+{
+ switch (op)
+ {
+ case LDAP_REQ_MODIFY: return ("modify"); break;
+ case LDAP_REQ_ADD: return ("add"); break;
+ case LDAP_REQ_DELETE: return ("delete"); break;
+ case LDAP_REQ_MODRDN: return ("modrdn"); break;
+ default: return ("??unknown??"); break;
+ }
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : LDAPMod2attributes
+ PURPOSE : Convert a LDAPMod-like array of attributes to the
+ internal attributes array.
+ INPUT : mods = LDAPMod array. If NULL, attribs[] is
+ initiated as an empty array.
+ OUTPUT : attribs = struct attribute array. This array is of
+ MAX_ATTRIBS length.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+LDAPMod2attributes (
+ LDAPMod **mods,
+ attribute *attribs)
+{
+ int i; /* For the loop */
+
+ /*
+ * Maybe there is no mods ?? This occurs for rename operation, for example.
+ */
+ if (mods == NULL)
+ {
+ attribs[0].type = NULL;
+ return (0);
+ }
+
+ /*
+ * Process each entry
+ */
+ for (i=0 ; i< MAX_ATTRIBS && mods[i] != NULL ; i++)
+ {
+ attribs[i].type = strdup (mods[i]->mod_type);
+ if (attribs[i].type == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Error: cannot strdup(attribs[%d].type), error=%d (%s)\n",
+ i, errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+
+ /*
+ * Well, if it is a binary value, it is most likely an image
+ * that is read by mmap and always available. Thus there is no reason
+ * to copy it, just modify the pointers.
+ */
+ if (mods[i]->mod_op & LDAP_MOD_BVALUES)
+ {
+ attribs[i].dontFree = 1;
+ attribs[i].length = mods[i]->mod_bvalues[0]->bv_len;
+ attribs[i].value = mods[i]->mod_bvalues[0]->bv_val;
+ }
+ else
+ {
+ attribs[i].dontFree = 0;
+ attribs[i].length = strlen (mods[i]->mod_values[0]);
+ attribs[i].value = strdup (mods[i]->mod_values[0]);
+ if (attribs[i].value == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Error: cannot strdup(attribs[%d].value), error=%d (%s)\n",
+ i, errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ }
+ }
+
+ /*
+ * Don't forget to mark the end !
+ */
+ if (i<MAX_ATTRIBS)
+ attribs[i].type = NULL;
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : freeAttributesArray
+ PURPOSE : This function is targetted to free an array of
+ struct attribute. It does not free the array itself,
+ but only the types and values memorized in it.
+ INPUT : attribs = array to free.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+freeAttributesArray (
+ attribute *attribs)
+{
+ int i; /* For the loop */
+
+ for (i=0;i<MAX_ATTRIBS&&attribs[i].type != NULL;i++)
+ {
+ free (attribs[i].type);
+ if (!(attribs[i].dontFree))
+ free (attribs[i].value);
+ }
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : opAdd
+ PURPOSE : Add a new operation to the list.
+ INPUT : tttctx = thread context
+ type = operation type
+ dn = target's DN
+ attribs = operation attributes
+ newRdn = new rdn (valid for rename only)
+ newParent = new parent (valid for rename only)
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION : Note that the attributes given in argument are
+ directly memorized (i.e. no copy), hence they should
+ *not* be freed by the calling function.
+ *****************************************************************************/
+int
+opAdd (
+ thread_context *tttctx,
+ int type,
+ char *dn,
+ LDAPMod **attribs,
+ char *newRdn,
+ char *newParent)
+{
+ int ret; /* Return value */
+ oper *newOper; /* New operation to memorize */
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("T%03d: opAdd (%s, %s)\n", tttctx->thrdNum, opDecOper(type), dn);
+
+
+ /*
+ * Go to protected section. This will enforce the correct sequencing
+ * of the operations performed because the whole function is lock
+ * for the threads.
+ * Note: Maybe reduce the size of this section ? To be checked.
+ */
+ if ((ret = pthread_mutex_lock (&(mctx.opListTail_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "T%03d: cannot pthread_mutex_lock(opListTail), error=%d (%s)\n",
+ tttctx->thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Create the new cell
+ */
+ newOper = (oper *) malloc (sizeof (oper));
+ if (newOper == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("T%03d: cannot malloc(newOper), error=%d (%s)\n", /*JLS 06-03-00*/
+ tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ newOper->next = NULL;
+ newOper->type = type;
+ newOper->skipped = mctx.slavesNb;
+ newOper->dn = strdup (dn);
+ if (newOper->dn == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf("T%03d: cannot strdup(newOper->dn), error=%d (%s)\n",/*JLS 06-03-00*/
+ tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ newOper->newRdn = (newRdn == NULL ? NULL : strdup (newRdn));
+ if (newOper->newRdn == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("T%03d: cannot strdup(newOper->newRdn), error=%d (%s)\n",
+ tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ newOper->newParent = (newParent == NULL ? NULL : strdup (newParent));
+ if (newOper->newParent == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("T%03d: cannot strdup(newOper->newParent), error=%d (%s)\n",
+ tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ if (LDAPMod2attributes (attribs, newOper->attribs) < 0)
+ return (-1);
+
+ /*
+ * Don't forget to initiate this cell's mutex !
+ */
+ if ((ret = pthread_mutex_init(&(newOper->skipped_mutex), NULL)) != 0)
+ {
+ fprintf (stderr,
+ "T%03d: cannot initiate skipped_mutex error=%d (%s)\n",
+ tttctx->thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Link the cell
+ */
+ mctx.opListTail->next = newOper;
+ mctx.opListTail = newOper;
+
+ /*
+ * Release the mutex
+ */
+ if ((ret = pthread_mutex_unlock (&(mctx.opListTail_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "T%03d: cannot pthread_mutex_unlock(opListTail), error=%d (%s)\n",
+ tttctx->thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : opNext
+ PURPOSE : Return the next available operation. May return NULL
+ if no operation available.
+ INPUT : ctctx = thread context
+ OUTPUT : op = next operation. May be NULL.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+opNext (
+ check_context *ctctx,
+ oper **op)
+{
+ int ret; /* Return value */
+ oper *newHead; /* The new head operation */
+
+ /*
+ * Maybe there is no new operation ?
+ */
+ if (ctctx->headListOp->next == NULL)
+ {
+ *op = NULL;
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("C%03d: opNext --> NULL\n", ctctx->thrdNum);
+ return (0);
+ }
+
+ /*
+ * Ok, there is one new operation. Let's skip the head and
+ * go to the new operation...
+ */
+ if ((ret = pthread_mutex_lock (&(ctctx->headListOp->skipped_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "C%03d: cannot pthread_mutex_lock(skipped_mutex), error=%d (%s)\n",
+ ctctx->thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+ newHead = ctctx->headListOp->next;
+ ctctx->headListOp->skipped--;
+
+ /*
+ * If there is another thread that has not skipped, let's move to the
+ * next operation and unlock the counter.
+ */
+ if (ctctx->headListOp->skipped != 0)
+ {
+ if ((ret = pthread_mutex_unlock (&(ctctx->headListOp->skipped_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "C%03d: cannot pthread_mutex_unlock(skipped_mutex), error=%d (%s)\n",
+ ctctx->thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+ }
+ else
+ {
+ /*
+ * Well, looks like we are the last thread to skip.... Let's free this
+ * operation. BTW, there is no reason to unlock/release the mutex because
+ * it will be destroyed !
+ * Note: may be NULL when LDAP_REQ_DELETE for example.
+ */
+ if (ctctx->headListOp->attribs != NULL)
+ if (freeAttributesArray (ctctx->headListOp->attribs) < 0)
+ return (-1);
+ if (ctctx->headListOp->dn != NULL)
+ free (ctctx->headListOp->dn);
+ if (ctctx->headListOp->newRdn != NULL)
+ free (ctctx->headListOp->newRdn);
+ if (ctctx->headListOp->newParent != NULL)
+ free (ctctx->headListOp->newParent);
+ free (ctctx->headListOp);
+ }
+
+ /*
+ * End of function
+ */
+ *op = ctctx->headListOp = newHead;
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("C%03d: opNext --> (%s, %s)\n",
+ ctctx->thrdNum, opDecOper ((*op)->type), (*op)->dn);
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : opRead
+ PURPOSE : Read the n'th operation from the head.
+ INPUT : ctctx = thread context
+ num = number of the operation to retrieve
+ OUTPUT : op = returned operation. May be NULL.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+opRead (
+ check_context *ctctx,
+ int num,
+ oper **op)
+{
+ *op = ctctx->headListOp;
+ while (num != 0)
+ {
+ /*
+ * Maybe not enough entries in the list ?
+ */
+ if (*op == NULL)
+ return (0);
+ *op = (*op)->next;
+ num--;
+ }
+
+ /*
+ * If there, we got it :-)
+ */
+ return (0);
+}
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : thOperAdd
+ PURPOSE : This function copies an operation to the late
+ operation list
+ INPUT : head list and operation to copy
+ OUTPUT : None.
+ RETURN : New head
+ DESCRIPTION :
+ *****************************************************************************/
+thoper *
+thOperAdd ( thoper *head, oper *elem, int f)
+{
+ thoper *new,*t=head;
+ int i;
+
+ new=malloc(sizeof(thoper));
+ if (new == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Txxx: cannot malloc(new), error=%d (%s)\n", /*JLS 06-03-00*/
+ errno, strerror (errno)); /*JLS 06-03-00*/
+ ldcltExit (1); /*JLS 18-08-00*/
+ } /*JLS 06-03-00*/
+ new->next=NULL;
+ new->first=f;
+ new->type=elem->type;
+ new->dn=strdup(elem->dn);
+ if (elem->newRdn != NULL)
+ new->newRdn=strdup(elem->newRdn);
+ if (elem->newParent != NULL)
+ new->newParent=strdup(elem->newParent);
+ for(i=0;i<MAX_ATTRIBS&&elem->attribs[i].type;i++)
+ {
+ new->attribs[i].type=strdup(elem->attribs[i].type);
+ if (new->attribs[i].type == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Txxx: cannot strdup(new->attribs[%d].type), error=%d (%s)\n",
+ errno, i, strerror (errno)); /*JLS 06-03-00*/
+ ldcltExit (1); /*JLS 18-08-00*/
+ } /*JLS 06-03-00*/
+ new->attribs[i].length = elem->attribs[i].length;
+ if((new->attribs[i].dontFree=elem->attribs[i].dontFree))
+ new->attribs[i].value = elem->attribs[i].value;
+ else
+ {
+ new->attribs[i].value = strdup(elem->attribs[i].value);
+ if (new->attribs[i].value == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("Txxx: cannot strdup(new->attribs[%d].value), error=%d (%s)\n",
+ errno, i, strerror (errno)); /*JLS 06-03-00*/
+ ldcltExit (1); /*JLS 18-08-00*/
+ } /*JLS 06-03-00*/
+ }
+ }
+ if(i<MAX_ATTRIBS)
+ new->attribs[i].type=NULL;
+ if(head==NULL)
+ return new;
+ for(t=head;t->next;)
+ t=t->next;
+ t->next=new;
+ return head;
+}
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : thOperFree
+ PURPOSE : This function frees memory for a late operation
+ INPUT : Head of list and operation to delete
+ OUTPUT : None.
+ RETURN : new head
+ DESCRIPTION :
+ *****************************************************************************/
+thoper *
+thOperFree (thoper *head, thoper *elem)
+{
+ thoper *t;
+
+ freeAttributesArray(elem->attribs);
+ free (elem->dn);
+ if (elem->newRdn != NULL)
+ free (elem->newRdn);
+ if (elem->newParent != NULL)
+ free (elem->newParent);
+ if(head!=elem)
+ {
+ for(t=head;t->next!=elem;)
+ t=t->next;
+ t->next=t->next->next;
+ }
+ else
+ head = head->next;
+ free(elem);
+ return head;
+}
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : opCheckLoop
+ PURPOSE : This function is the per slave check function
+ INPUT : arg = this check thread's check_context
+ OUTPUT : None.
+ RETURN : None.
+ DESCRIPTION :
+ *****************************************************************************/
+void *
+opCheckLoop ( void* arg)
+{
+ struct check_context *cctx=(struct check_context *)arg;
+ struct pollfd pfd;
+ repconfirm *recOper;
+ oper *myop;
+ thoper *t;
+ unsigned char recbuf[1500];
+ int ret,i,timeout;
+ int cnt; /* To count loops for timeout purpose */
+ int fndlt; /* Found late operation */
+ int nbRead; /* Nb char read() */
+ int status; /* Thread status */ /*JLS 17-11-00*/
+
+ recOper=(repconfirm*)recbuf;
+ pfd.fd=cctx->sockfd;
+ pfd.events=(POLLIN|POLLPRI);
+ pfd.revents=0;
+ cctx->status=INITIATED;
+ if((timeout=mctx.timeout)<30)
+ timeout=30;
+ /*
+ * First time in here?
+ */
+ if(cctx->calls==1)
+ cctx->dcOper=NULL;
+
+ while((ret=poll(&pfd,1,500))>=0)
+ {
+ if(ret)
+ {
+ /*
+ * Exit if read error on the net
+ */
+ if ((nbRead = read (pfd.fd,recOper,sizeof(repconfirm)))<0)
+ break;
+ if (nbRead != sizeof(repconfirm))
+ printf ("C%03d(%s): Partial header read %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, sizeof(repconfirm));
+ recOper->type=ntohl(recOper->type);
+ recOper->res=ntohl(recOper->res);
+ recOper->dnSize=ntohl(recOper->dnSize);
+ /*
+ * Beware of structure alignment
+ */
+ if((nbRead=read(pfd.fd,recOper->dn+sizeof(recOper->dn),recOper->dnSize))<0)
+ break;
+ if (nbRead != recOper->dnSize)
+ printf ("C%03d(%s): Partial dn read %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, recOper->dnSize);
+ if (nbRead > (1500 - sizeof(repconfirm)))
+ printf ("C%03d(%s): Read too much %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, 1500 - sizeof(repconfirm));
+ cnt=0;
+ cctx->nbOpRecv++;
+ if(mctx.mode&VERY_VERBOSE)
+ {
+ printf("C%03d(%s): Rec %s\n",cctx->thrdNum,cctx->slaveName,recOper->dn);
+ for(myop=cctx->headListOp->next;myop;myop=myop->next)
+ printf("C%03d(%s): IN : %s\n",cctx->thrdNum,cctx->slaveName,myop->dn);
+ for(t=cctx->dcOper;t;t=t->next)
+ printf("C%03d(%s): LATE : %s\n",cctx->thrdNum,cctx->slaveName,t->dn);
+ }
+ /*
+ * Do not tell me there was an error during replica...
+ */
+ if(recOper->res)
+ {
+ printf("C%03d(%s): Replica failed, op:%d(%s), dn=\"%s\" res=%d\n",
+ cctx->thrdNum, cctx->slaveName,
+ recOper->type, opDecOper(recOper->type),
+ recOper->dn, recOper->res );
+ switch (recOper->res)
+ {
+ case 32: cctx->nbRepFail32++ ; break;
+ case 68: cctx->nbRepFail68++ ; break;
+ default: cctx->nbRepFailX++ ; break;
+ }
+ }
+ /*
+ * Is this a late operation?
+ */
+ fndlt=0;
+ if(cctx->dcOper)
+ {
+ for (i=1,t = cctx->dcOper;t;i++)
+ if ((recOper->type!=t->type) || strcmp(recOper->dn,t->dn))
+ t = t->next;
+ else
+ {
+ /*
+ * if this is a single operation: 132456
+ */
+ if(t->first==SINGLE)
+ {
+ /*
+ * error.
+ */
+ printf("C%03d(%s): Late replica: op:%d(%s), dn=\"%s\"\n",
+ cctx->thrdNum, cctx->slaveName,
+ t->type, opDecOper(t->type), t->dn );
+ cctx->nbLate++;
+ } else if (t->first==MIDDLE)
+ {
+ /*
+ * Middle of a series : 23546
+ */
+ printf("C%03d(%s): Early (%3d) op:%d(%s), dn=\"%s\"\n",
+ cctx->thrdNum, cctx->slaveName,i,
+ t->type, opDecOper(t->type), t->dn );
+ cctx->nbEarly++;
+
+ } else if(t->next)
+ {
+ /*
+ * else maybe we are in a re-corrected situation.
+ * we should receive the next one, now.
+ */
+ if(t->next->first!=LAST)
+ t->next->first=FIRST;
+ }
+ cctx->dcOper = thOperFree (cctx->dcOper, t);
+ fndlt=1;
+ break;
+ }
+ }
+ if(!fndlt)
+ {
+ /*
+ * See if the operation we received is the same as the head
+ */
+ opRead(cctx,1,&myop);
+ if (myop != NULL &&
+ recOper->type==myop->type &&
+ strcmp(recOper->dn,myop->dn) == 0)
+ opNext(cctx,&myop);
+ else
+ {
+ /*
+ * Nope, look for it
+ */
+ for(i=2;opRead(cctx,i,&myop)==0;i++)
+ if(myop)
+ {
+ if(recOper->type==myop->type &&
+ strcmp(recOper->dn,myop->dn) == 0)
+ {
+ /*
+ * Skip all between current head and this one
+ */
+ printf("C%03d(%s): Early (%3d) op:%d(%s), dn=\"%s\"\n", cctx->thrdNum,cctx->slaveName, i-1, recOper->type, opDecOper(recOper->type), recOper->dn );
+ cctx->nbEarly++;
+ opNext(cctx,&myop);
+ /*
+ * mark the first of the series as leader
+ */
+ cctx->dcOper=thOperAdd(cctx->dcOper,myop,
+ i==2?SINGLE:FIRST);
+ for(;i>2;i--)
+ {
+ opNext(cctx,&myop);
+ /*
+ * copy up until one before last
+ */
+ if(myop)
+ thOperAdd(cctx->dcOper,myop,
+ i==3?LAST:MIDDLE);
+ }
+ opNext(cctx,&myop);
+ break;
+ }
+ } else break;
+ if(!myop)
+ {
+ printf("C%03d(%s): Not on list op:%d(%s), dn=\"%s\"\n", cctx->thrdNum,cctx->slaveName, recOper->type, opDecOper(recOper->type), recOper->dn );
+ cctx->nbNotOnList++;
+ }
+ }
+ }
+ }
+ pfd.events=(POLLIN|POLLPRI);
+ pfd.revents=0;
+ /*
+ * operations threads still running?
+ */
+ for(i=0;i<mctx.nbThreads;i++)
+ { /*JLS 17-11-00*/
+ if (getThreadStatus (&(tctx[i]), &status) < 0) /*JLS 17-11-00*/
+ break; /*JLS 17-11-00*/
+ if(status != DEAD) /*JLS 17-11-00*/
+ {
+ cnt=0;
+ break;
+ }
+ } /*JLS 17-11-00*/
+ /*
+ * twice half a second...
+ */
+ if(++cnt>timeout*2)
+ break;
+ }
+ if(mctx.mode&VERY_VERBOSE)
+ printf("C%03d(%s): Exiting\n",cctx->thrdNum,cctx->slaveName);
+ /*
+ * Any operation left?
+ */
+ for(opNext(cctx,&myop);myop;opNext(cctx,&myop))
+ {
+ printf("Operation %d(%s) still on Queue for %s (%s)\n",myop->type,opDecOper(myop->type),cctx->slaveName,myop->dn);
+ cctx->nbStillOnQ++;
+ }
+ for(t=cctx->dcOper;t;t=t->next)
+ {
+ printf("Lost op %d(%s) on %s (%s)\n",t->type,opDecOper(t->type),cctx->slaveName,t->dn);
+ cctx->nbLostOp++;
+ }
+ close(cctx->sockfd);
+ cctx->status=DEAD;
+ pthread_exit(NULL);
+}
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : opCheckMain
+ PURPOSE : This function is the main function of the check
+ operation threads,
+ INPUT : arg = NULL
+ OUTPUT : None.
+ RETURN : None.
+ DESCRIPTION :
+ *****************************************************************************/
+void *
+opCheckMain (
+ void *arg)
+{
+ struct sockaddr_in srvsaddr,claddr;
+ struct hostent cltaddr;
+#ifdef LINUX
+ struct hostent *stupidlinux=NULL;
+#endif
+#ifdef AIX
+ struct hostent_data stupidaix;
+#endif
+ struct linger lopt;
+ uint32_t ipaddr;
+ int newfd,sockfd,ncctx,i,err;
+ char buffer[128];
+ int retry; /* To retry on EINTR */
+
+ /*
+ * Initialization
+ */
+
+ srvsaddr.sin_addr.s_addr=htonl(INADDR_ANY);
+ srvsaddr.sin_family=AF_INET;
+ srvsaddr.sin_port=htons(masterPort);
+
+ /*
+ * Let's go !!!
+ */
+
+ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
+ {
+ perror("Socket");
+ ldcltExit(1); /*JLS 18-08-00*/
+ }
+ i=1;
+ if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void *)&i,sizeof(int))!=0)
+ perror("Sockopt");
+ if(bind(sockfd,(struct sockaddr*)&srvsaddr,sizeof(struct sockaddr))!=0)
+ {
+ perror("Bind");
+ ldcltExit(1); /*JLS 18-08-00*/
+ }
+ if(listen(sockfd,1)!=0)
+ perror("listen");
+ for(ncctx=0;;)
+ {
+ i=sizeof(claddr);
+ retry = 1;
+ while (retry)
+ {
+#ifdef AIX
+ if ((newfd=accept(sockfd,(struct sockaddr *)&claddr,(unsigned long *)&i))>=0)
+#else
+ if ((newfd=accept(sockfd,(struct sockaddr *)&claddr,&i))>=0)
+#endif
+ retry = 0;
+ else
+ if (errno != EINTR)
+ {
+ perror("Accept");
+ ldcltExit(1); /*JLS 18-08-00*/
+ }
+ }
+ /*
+ * get client's name
+ */
+ ipaddr=ntohl(claddr.sin_addr.s_addr);
+
+#ifdef AIX
+ gethostbyaddr_r((char*)&ipaddr,sizeof(ipaddr),AF_INET,&cltaddr,
+ &stupidaix);
+#else
+#ifdef LINUX
+ gethostbyaddr_r((char*)&ipaddr,sizeof(ipaddr),AF_INET,&cltaddr,
+ buffer,128, &stupidlinux, &err);
+#else
+#if defined(HPUX) && defined(__LP64__)
+ gethostbyaddr((char*)&ipaddr,sizeof(ipaddr),AF_INET);
+#else
+ gethostbyaddr_r((char*)&ipaddr,sizeof(ipaddr),AF_INET,&cltaddr,
+ buffer,128,&err);
+#endif
+#endif
+#endif
+
+ i=1;
+ if(setsockopt(newfd,IPPROTO_TCP, TCP_NODELAY,(void *)&i,sizeof(int))!=0)
+ perror("Nagle");
+ /*
+ * Linger: when connection ends, send an RST instead of a FIN
+ * This way the client will have a fail on the first write instead of
+ * the second
+ */
+ lopt.l_onoff=1;
+ lopt.l_linger=0;
+ if(setsockopt(newfd,SOL_SOCKET,SO_LINGER,(void*)&lopt,sizeof(struct linger))<0)
+ perror("Linger");
+ /*
+ * Search for an empty client slot. If a client reconnects, use the
+ * same slot
+ */
+ for(i=0;i<mctx.slavesNb;i++)
+ {
+ if(cctx[i].calls==0)
+ {
+ i=ncctx++;
+ break;
+ }
+ if(cctx[i].slaveName&&cctx[i].status==DEAD)
+ if(strcmp(cctx[i].slaveName,cltaddr.h_name)==0)
+ break;
+ }
+ if(i>=mctx.slavesNb)
+ {
+ fprintf (stderr, "ldclt: Too many slaves %s\n",cltaddr.h_name);
+ close(newfd);
+ continue;
+ }
+
+ cctx[i].sockfd=newfd;
+ cctx[i].calls++;
+ cctx[i].slaveName=strdup(cltaddr.h_name);
+ if ((err = pthread_create (&(cctx[i].tid), NULL,
+ opCheckLoop, (void *)&(cctx[i]))) != 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (err));
+ fprintf (stderr, "Error: cannot create thread opCheck for %s\n",
+ cltaddr.h_name);
+ fflush (stderr);
+ }
+ else
+ mctx.slaveConn = 1;
+ }
+ close(sockfd);
+}
+
+
+
+
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/parser.c b/ldap/servers/slapd/tools/ldclt/parser.c
new file mode 100644
index 00000000..84f574f0
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/parser.c
@@ -0,0 +1,618 @@
+#ident "@(#)parser.c 1.5 01/04/11"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : parser.c
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 19 March 2001
+ DESCRIPTION :
+ This file contains the parser functions of ldclt
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+19/03/01 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+21/03/01 | JL Schwing | 1.2 : Implements variables in "-e object=filename"
+---------+--------------+------------------------------------------------------
+23/03/01 | JL Schwing | 1.3 : Implements data file list support in variants.
+ | Bug fix : close the file !
+ | Implements "-e rdn=value".
+---------+--------------+------------------------------------------------------
+28/03/01 | JL Schwing | 1.4 : Support -e commoncounter with -e rdn/object
+---------+--------------+------------------------------------------------------
+11/04/01 | JL Schwing | 1.5 : Implement [INCRFROMFILE<NOLOOP>(myfile)]
+ | Improved error message.
+---------+--------------+------------------------------------------------------
+*/
+
+
+#include <stdio.h> /* printf(), etc... */
+#include <string.h> /* strcpy(), etc... */
+#include <errno.h> /* errno, etc... */
+#include <stdlib.h> /* malloc(), etc... */
+#include <lber.h> /* ldap C-API BER declarations */
+#include <ldap.h> /* ldap C-API declarations */
+#ifdef LDAP_H_FROM_QA_WKA
+#include <proto-ldap.h> /* ldap C-API prototypes */
+#endif
+#ifndef _WIN32
+#include <unistd.h> /* close(), etc... */
+#include <pthread.h> /* pthreads(), etc... */
+#endif
+
+#include "port.h" /* Portability definitions */
+#include "ldclt.h" /* This tool's include file */
+#include "utils.h" /* Utilities functions */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : decodeHow
+ PURPOSE : Decode the how field
+ INPUT : how = field to decode
+ OUTPUT : None.
+ RETURN : -1 if error, how value else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+decodeHow (
+ char *how)
+{
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("decodeHow: how=\"%s\"\n", how);
+
+ if (!strcmp (how, "INCRFROMFILE")) return (HOW_INCR_FROM_FILE);
+ if (!strcmp (how, "INCRFROMFILENOLOOP")) return (HOW_INCR_FROM_FILE_NL);
+ if (!strcmp (how, "INCRN")) return (HOW_INCR_NB);
+ if (!strcmp (how, "INCRNNOLOOP")) return (HOW_INCR_NB_NOLOOP);
+ if (!strcmp (how, "RNDFROMFILE")) return (HOW_RND_FROM_FILE);
+ if (!strcmp (how, "RNDN")) return (HOW_RND_NUMBER);
+ if (!strcmp (how, "RNDS")) return (HOW_RND_STRING);
+ return (-1);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : parseVariant
+ PURPOSE : Parse a variant definition.
+ INPUT : variant = string to parse
+ fname = file name
+ line = source line
+ obj = object we are parsing and building
+ OUTPUT : field = field parsed
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+parseVariant (
+ char *variant,
+ char *fname,
+ char *line,
+ vers_object *obj,
+ vers_field *field)
+{
+ int start, end; /* For the loops */
+ char how[MAX_FILTER]; /* To parse the variant : */
+ char first[MAX_FILTER]; /* how(first) */
+ char second[MAX_FILTER]; /* how(first,second) */
+ char third[MAX_FILTER]; /* how(first,second,third) */
+ int ret; /* ldclt_mutex_init() return value */
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("parseVariant: variant=\"%s\"\n", variant);
+
+ /*
+ * Maybe a variable ?
+ */
+ if (variant[1] == '\0')
+ {
+ if ((variant[0] < VAR_MIN) || (variant[0] > VAR_MAX))
+ {
+ fprintf (stderr, "Error: bad variable in %s : \"%s\"\n", fname, line);
+ fprintf (stderr, "Error: must be in [%c-%c]\n", VAR_MIN, VAR_MAX);
+ return (-1);
+ }
+ field->how = HOW_VARIABLE;
+ field->var = variant[0] - VAR_MIN;
+ return (0);
+ }
+
+ /*
+ * Maybe a variable definition ?
+ */
+ if (variant[1] != '=')
+ field->var = -1;
+ else
+ {
+ if ((variant[0] < VAR_MIN) || (variant[0] > VAR_MAX))
+ {
+ fprintf (stderr, "Error: bad variable in %s : \"%s\"\n", fname, line);
+ fprintf (stderr, "Error: must be in [%c-%c]\n", VAR_MIN, VAR_MAX);
+ return (-1);
+ }
+ field->var = variant[0] - VAR_MIN;
+ variant++; /* Skip variable name */
+ variant++; /* Skip '=' */
+
+ /*
+ * We need a variable !
+ */
+ if (obj->var[field->var] == NULL)
+ obj->var[field->var] = (char *) malloc (MAX_FILTER);
+ }
+
+ /*
+ * Find how definition
+ */
+ for (end=0 ; (variant[end]!='\0') && (variant[end]!='(') ; end++);
+ if (variant[end]=='\0')
+ {
+ fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
+ fprintf (stderr, "Error: missing '('\n");
+ return (-1);
+ }
+ strncpy (how, variant, end);
+ how[end] = '\0';
+
+ /*
+ * Parse the first parameter
+ */
+ end++; /* Skip '(' */
+ for (start=end ; (variant[end]!='\0') && (variant[end]!=';')
+ && (variant[end]!=')') ; end++);
+ if (variant[end]=='\0')
+ {
+ fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
+ fprintf (stderr, "Error: missing ')'\n");
+ return (-1);
+ }
+ strncpy (first, variant+start, end-start);
+ first[end-start] = '\0';
+
+ /*
+ * Parse the second parameter
+ */
+ if (variant[end] == ')')
+ second[0] = '\0';
+ else
+ {
+ end++; /* Skip ';' */
+ for (start=end ; (variant[end]!='\0') && (variant[end]!=';')
+ && (variant[end]!=')') ; end++);
+ if (variant[end]=='\0')
+ {
+ fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
+ fprintf (stderr, "Error: missing ')'\n");
+ return (-1);
+ }
+ strncpy (second, variant+start, end-start);
+ second[end-start] = '\0';
+ }
+
+ /*
+ * Parse the third parameter
+ */
+ if (variant[end]==')')
+ third[0]='\0';
+ else
+ {
+ end++; /* Skip ';' */
+ for (start=end ; (variant[end]!='\0') && (variant[end]!=')') ; end++);
+ if (variant[end]=='\0')
+ {
+ fprintf (stderr, "Error: bad variant in %s : \"%s\"\n", fname, line);
+ fprintf (stderr, "Error: missing ')'\n");
+ return (-1);
+ }
+ strncpy (third, variant+start, end-start);
+ third[end-start] = '\0';
+ }
+
+ /*
+ * Analyse it
+ * Note : first parameter always exist (detected when parsing) while
+ * second and third may not have been provided by the user.
+ */
+ switch (field->how = decodeHow (how))
+ {
+ case HOW_INCR_FROM_FILE:
+ case HOW_INCR_FROM_FILE_NL:
+ case HOW_RND_FROM_FILE:
+ if ((field->dlf = dataListFile (first)) == NULL)
+ {
+ fprintf (stderr, "Error : bad file in %s : \"%s\"\n", fname, line);
+ return (-1);
+ }
+
+ /*
+ * Useless for HOW_RND_FROM_FILE
+ */
+ field->cnt = 0;
+ field->low = 0;
+ field->high = field->dlf->strNb - 1;
+
+ /*
+ * Maybe common counter ?
+ */
+ if ((mctx.mode & COMMON_COUNTER) &&
+ ((field->how == HOW_INCR_FROM_FILE) ||
+ (field->how == HOW_INCR_FROM_FILE_NL)))
+ {
+ if ((ret = ldclt_mutex_init (&(field->cnt_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (ret));
+ fprintf (stderr, "Error: cannot initiate cnt_mutex in %s for %s\n",
+ fname, line);
+ fflush (stderr);
+ return (-1);
+ }
+ }
+ break;
+ case HOW_INCR_NB:
+ case HOW_INCR_NB_NOLOOP:
+ case HOW_RND_NUMBER:
+ if (third[0] == '\0')
+ {
+ fprintf (stderr, "Error : missing parameters in %s : \"%s\"\n",
+ fname, line);
+ return (-1);
+ }
+ field->cnt = atoi (first);
+ field->low = atoi (first);
+ field->high = atoi (second);
+ field->nb = atoi (third);
+
+ /*
+ * Maybe common counter ?
+ */
+ if ((mctx.mode & COMMON_COUNTER) &&
+ ((field->how == HOW_INCR_NB) || (field->how == HOW_INCR_NB_NOLOOP)))
+ {
+ if ((ret = ldclt_mutex_init (&(field->cnt_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt: %s\n", strerror (ret));
+ fprintf (stderr, "Error: cannot initiate cnt_mutex in %s for %s\n",
+ fname, line);
+ fflush (stderr);
+ return (-1);
+ }
+ }
+ break;
+ case HOW_RND_STRING:
+ field->nb = atoi (first);
+ break;
+ case -1:
+ fprintf (stderr, "Error: illegal keyword \"%s\" in %s : \"%s\"\n",
+ how, fname, line);
+ return (-1);
+ break;
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : parseAttribValue
+ PURPOSE : Parse the right part of attribname: attribvalue.
+ INPUT : fname = file name
+ obj = object where variables are.
+ line = value to parse.
+ OUTPUT : attrib = attribute where the value should be stored
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+parseAttribValue (
+ char *fname,
+ vers_object *obj,
+ char *line,
+ vers_attribute *attrib)
+{
+ char variant[MAX_FILTER]; /* To process the variant */
+ int start, end; /* For the loops */
+ vers_field *field; /* To build the fields */
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("parseAttribValue: line=\"%s\"\n", line);
+
+ /*
+ * We will now parse this line for the different fields.
+ */
+ field = NULL;
+ end = start = 0;
+ while (line[end]!='\0')
+ {
+ /*
+ * Allocate a new field
+ */
+ if (field == NULL)
+ {
+ field = (vers_field *) malloc (sizeof (vers_field));
+ field->next = NULL;
+ attrib->field = field;
+ }
+ else
+ {
+ field->next = (vers_field *) malloc (sizeof (vers_field));
+ field = field->next;
+ field->next = NULL;
+ }
+
+ /*
+ * Is it a variant field ?
+ */
+ if (line[end] == '[')
+ {
+ /*
+ * Extract the variant definition
+ */
+ end++; /* Skip '[' */
+ for (start=end ; (line[end]!='\0') && (line[end]!=']') ; end++);
+ strncpy (variant, line+start, end-start);
+ variant[end-start] = '\0';
+ if (line[end]=='\0')
+ {
+ fprintf (stderr, "Error: missing ']' in %s : \"%s\"\n", fname, line);
+ return (-1);
+ }
+ if (parseVariant (variant, fname, line, obj, field) < 0)
+ return (-1);
+ end++; /* Skip ']' */
+
+ /*
+ * We need to allocate a buffer in this attribute !
+ */
+ if (attrib->buf == NULL)
+ {
+ attrib->buf = (char *) malloc (MAX_FILTER);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("parseAttribValue: buffer allocated\n");
+ }
+ }
+ else
+ {
+ /*
+ * It is a constant field. Find the end : [ or \0
+ */
+ for (start=end ; (line[end]!='\0') && (line[end]!='[') ; end++);
+ field->how = HOW_CONSTANT;
+ field->cst = (char *) malloc (1+end-start);
+ strncpy (field->cst, line+start, end-start);
+ field->cst[end-start] = '\0';
+ }
+ }
+
+ /*
+ * Attribute value is parsed !
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : parseLine
+ PURPOSE : Parse the given line to find an attribute definition.
+ INPUT : line = line to parse
+ fname = file name
+ OUTPUT : obj = object where the attribute should be added
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+parseLine (
+ char *line,
+ char *fname,
+ vers_object *obj)
+{
+ int end; /* For the loops */
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("parseLine: line=\"%s\"\n", line);
+
+ /*
+ * Empty line ? Comment ?
+ * No more place for new attributes ?
+ */
+ if ((line[0]=='\0') || (line[0]=='#'))
+ return (0);
+ if (obj->attribsNb == MAX_ATTRIBS)
+ {
+ fprintf (stderr, "Error: too many attributes in %s, max is %d\n",
+ fname, MAX_ATTRIBS);
+ return (-1);
+ }
+
+ /*
+ * Find the attribute name
+ * name:
+ */
+ for (end=0 ; (line[end]!='\0') && (line[end]!=':') ; end++);
+ if (line[end]!=':')
+ {
+ fprintf (stderr, "Error: can't find attribute name in %s : \"%s\"\n",
+ fname, line);
+ return (-1);
+ }
+
+ /*
+ * Initiate the attribute
+ */
+ obj->attribs[obj->attribsNb].buf = NULL;
+ obj->attribs[obj->attribsNb].src = strdup (line);
+ obj->attribs[obj->attribsNb].name = (char *) malloc (1+end);
+ strncpy (obj->attribs[obj->attribsNb].name, line, end);
+ obj->attribs[obj->attribsNb].name[end] = '\0';
+ for (end++ ; line[end]==' ' ; end++); /* Skip the leading ' ' */
+
+ /*
+ * We will now parse the value of this attribute
+ */
+ if (parseAttribValue(fname,obj, line+end, &(obj->attribs[obj->attribsNb]))<0)
+ return (-1);
+
+ /*
+ * Do not forget to increment attributes number !
+ */
+ obj->attribsNb++;
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : readObject
+ PURPOSE : This function will read an object description from the
+ file given in argument.
+ The object should be already initiated !!!
+ INPUT : None.
+ OUTPUT : obj = parsed object.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+readObject (
+ vers_object *obj)
+{
+ FILE *ifile; /* The file that contains the object to read */
+ char line[MAX_FILTER]; /* To read ifile */
+
+ /*
+ * Open the file
+ */
+ ifile = fopen (obj->fname, "r");
+ if (ifile == NULL)
+ {
+ perror (obj->fname);
+ fprintf (stderr, "Error: cannot open file \"%s\"\n", obj->fname);
+ return (-1);
+ }
+
+ /*
+ * Process each line of the input file.
+ * Reminder : the object is initiated by the calling function !
+ */
+ while (fgets (line, MAX_FILTER, ifile) != NULL)
+ {
+ if ((strlen (line) > 0) && (line[strlen(line)-1]=='\n'))
+ line[strlen(line)-1] = '\0';
+ if (parseLine (line, obj->fname, obj) < 0)
+ return (-1);
+ }
+
+ /*
+ * Do not forget to close the file !
+ */
+ if (fclose (ifile) != 0)
+ {
+ perror (obj->fname);
+ fprintf (stderr, "Error: cannot fclose file \"%s\"\n", obj->fname);
+ return (-1);
+ }
+
+ /*
+ * End of function
+ */
+ if (obj->attribsNb == 0)
+ {
+ fprintf (stderr, "Error: no object found in \"%s\"\n", obj->fname);
+ return (-1);
+ }
+ return (0);
+}
+
+
+
+
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/port.c b/ldap/servers/slapd/tools/ldclt/port.c
new file mode 100644
index 00000000..0b1ddb09
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/port.c
@@ -0,0 +1,321 @@
+#ident "ldclt @(#)port.c 1.2 01/03/14"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : port.c
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 28 November 2000
+ DESCRIPTION :
+ This file contains platform-independant version of
+ common (unix) functions in order to have portable
+ source code for either unix and windows platforms.
+ It is greatly inspired from iPlanet DS 5.0 workspace.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+28/11/00 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.2 : Lint cleanup.
+---------+--------------+------------------------------------------------------
+*/
+
+
+#include <stdio.h> /* EOF, etc... */
+
+#ifdef _WIN32
+#include <windows.h>
+#include <winbase.h>
+#else
+#include <unistd.h> /* sleep(), etc... */ /*JLS 14-03-01*/
+#include <pthread.h> /* pthreads(), etc... */
+#endif
+
+#include "port.h"
+
+/************************************************************************/
+/************************************************************************/
+/**************** NT section ***********************/
+/************************************************************************/
+/************************************************************************/
+
+#ifdef _WIN32
+
+int
+ldclt_mutex_init (
+ ldclt_mutex_t *mutex)
+{
+ InitializeCriticalSection (mutex);
+ return (0);
+}
+
+int
+ldclt_mutex_lock (
+ ldclt_mutex_t *mutex)
+{
+ EnterCriticalSection(mutex);
+ return (0);
+}
+
+int
+ldclt_mutex_unlock (
+ ldclt_mutex_t *mutex)
+{
+ LeaveCriticalSection (mutex);
+ return (0);
+}
+
+void
+ldclt_sleep (
+ int nseconds)
+{
+ Sleep (1000 * nseconds);
+}
+
+int
+ldclt_thread_create (
+ ldclt_tid *tid,
+ void *fct,
+ void *param)
+{
+ CreateThread (NULL, 0, fct, param, 0, tid);
+ return (0);
+}
+
+long
+lrand48 (void)
+{
+ return ((rand()<<8)+rand());
+}
+
+/*
+ * Implements the Unix getopt function for NT systems
+ */
+char *optarg;
+int optind;
+int
+getopt (
+ int argc,
+ char **argv,
+ char *optstring)
+{
+ static char **prevArgv = NULL; /* Memorize argv to parse */
+ static int inOption; /* In option parsing ? */
+ static int cNum; /* Current char num */
+ int c; /* Current char */
+ int i; /* Loops */
+
+ /*
+ * Initialization - maybe the first time this function is called ?
+ */
+ if (prevArgv != argv)
+ {
+ prevArgv = argv;
+ optind = 0;
+ inOption = 0;
+ }
+
+ /*
+ * Maybe we processed the last chars of the option in the previous call
+ */
+ if (inOption)
+ {
+ if (argv[optind][cNum] == '\0')
+ inOption = 0;
+ }
+
+ /*
+ * Maybe we should look for '-'
+ */
+ if (!inOption)
+ {
+ optind++; /* Next option */
+ if (optind == argc) /* No more option */
+ return (EOF);
+ if (argv[optind][0] != '-') /* Not an option */
+ return (EOF);
+ if (argv[optind][1] == '\0') /* Only '-' */
+ return (EOF);
+ cNum = 1; /* Next char to process */
+ inOption = 0; /* We are in an option */
+ }
+
+ /*
+ * See if this is a valid option
+ */
+ c = argv[optind][cNum];
+ for (i=0 ; (i<strlen(optstring)) && (c!=optstring[i]) ; i++);
+ if (c != optstring[i]) /* Not an option */
+ return ('?');
+ cNum++; /* Next char */
+
+ /*
+ * Check if this option requires an argument
+ * Note that for the last char of optstring, it is a valid '\0' != ':'
+ */
+ if (optstring[i+1] != ':') /* No argument */
+ return (c);
+
+ /*
+ * Need an argument...
+ * The argument is either the end of argv[optind] or argv[++optind]
+ */
+ if (argv[optind][cNum] == '\0') /* Must return next argument */
+ {
+ optind++; /* Next argument */
+ if (optind == argc) /* There is no next argument */
+ {
+ printf ("%s: option requires an argument -- %c\n", argv[0], c);
+ return ('?');
+ }
+ optarg = argv[optind]; /* Set optarg to teh argument argv[] */
+ inOption = 0; /* No more in option... */
+ return (c);
+ }
+
+ /*
+ * Return the end of the current argv[optind]
+ */
+ optarg = &(argv[optind][cNum]); /* End of argv[optind] */
+ inOption = 0; /* No more in option */
+ return (c);
+}
+
+
+/*
+ * Implement the Unix getsubopt function for NT systems
+ */
+int
+getsubopt(
+ char **optionp,
+ char **tokens,
+ char **valuep)
+{
+ int i; /* Loops */
+ char *curOpt; /* Current optionp */
+
+ curOpt = *optionp; /* Begin of current option */
+
+ /*
+ * Find the end of the current option
+ */
+ for (i=0 ; (curOpt[i]!='\0') && (curOpt[i]!=',') ; i++);
+ if (curOpt[i] == '\0')
+ *optionp = &(curOpt[i]);
+ else
+ *optionp = &(curOpt[i+1]);
+ curOpt[i] = '\0'; /* Do not forget to end this string */
+
+ /*
+ * Find if there is a subvalue for this option
+ */
+ for (i=0 ; (curOpt[i]!='\0') && (curOpt[i]!='=') ; i++);
+ if (curOpt[i] == '\0')
+ *valuep = &(curOpt[i]);
+ else
+ *valuep = &(curOpt[i+1]);
+ curOpt[i] = '\0'; /* Do not forget to end this string */
+
+ /*
+ * Find if this option is valid...
+ */
+ for (i=0 ; tokens[i] != NULL ; i++)
+ if (!strcmp (curOpt, tokens[i]))
+ return (i);
+
+ /*
+ * Not found...
+ */
+ return (-1);
+}
+
+
+#else /* NT 4 */
+
+/************************************************************************/
+/************************************************************************/
+/**************** Unix section ***********************/
+/************************************************************************/
+/************************************************************************/
+
+int
+ldclt_mutex_init (
+ ldclt_mutex_t *mutex)
+{
+ return (pthread_mutex_init (mutex, NULL));
+}
+
+int
+ldclt_mutex_lock (
+ ldclt_mutex_t *mutex)
+{
+ return (pthread_mutex_lock (mutex));
+}
+
+int
+ldclt_mutex_unlock (
+ ldclt_mutex_t *mutex)
+{
+ return (pthread_mutex_unlock (mutex));
+}
+
+void
+ldclt_sleep (
+ int nseconds)
+{
+ sleep (nseconds);
+}
+
+int
+ldclt_thread_create (
+ ldclt_tid *tid,
+ void *(*fct)(void *),
+ void *param)
+{
+ return (pthread_create (tid, NULL, fct, param));
+}
+
+#endif /* _WIN32 */
+
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/port.h b/ldap/servers/slapd/tools/ldclt/port.h
new file mode 100644
index 00000000..de3c4e03
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/port.h
@@ -0,0 +1,130 @@
+#ident "ldclt @(#)port.h 1.4 01/04/03"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : port.h
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 28 November 2000
+ DESCRIPTION :
+ This file contains the include (interface) definitions
+ of port.c
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+28/11/00 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+01/12/00 | JL Schwing | 1.2 : Port on Linux.
+---------+--------------+------------------------------------------------------
+01/12/00 | JL Schwing | 1.3 : Port on HP-UX.
+---------+--------------+------------------------------------------------------
+03/04/01 | JL Schwing | 1.4 : Linux large file issue...
+---------+--------------+------------------------------------------------------
+*/
+
+/*
+ * Tuning of the code
+ */
+#ifdef AIX /*JLS 01-12-00*/
+#define LDCLT_CAST_SIGACTION 1 /*JLS 01-12-00*/
+#endif /*JLS 01-12-00*/
+
+#ifdef HPUX /*JLS 01-12-00*/
+#define LDCLT_CAST_SIGACTION 1 /*JLS 01-12-00*/
+#define LDCLT_NO_DLOPEN 1 /*JLS 01-12-00*/
+#endif /*JLS 01-12-00*/
+
+#ifdef LINUX /*JLS 01-12-00*/
+#define LDCLT_CAST_SIGACTION 1 /*JLS 01-12-00*/
+#ifndef O_LARGEFILE /*JLS 03-04-01*/
+# define O_LARGEFILE 0100000 /*JLS 03-04-01*/
+#endif /*JLS 03-04-01*/
+#endif /*JLS 01-12-00*/
+
+#ifdef _WIN32 /*JLS 01-12-00*/
+#define LDCLT_NO_DLOPEN 1 /*JLS 01-12-00*/
+#endif /*JLS 01-12-00*/
+
+
+/************************************************************************/
+/************************************************************************/
+/**************** NT section ***********************/
+/************************************************************************/
+/************************************************************************/
+
+#ifdef _WIN32
+
+typedef CRITICAL_SECTION ldclt_mutex_t;
+typedef DWORD ldclt_tid;
+
+extern int getopt (int argc, char **argv, char *optstring);
+extern int getsubopt(char **optionp, char **tokens, char **valuep);
+extern long lrand48 (void);
+extern char *optarg;
+extern int optind;
+
+#else /* _WIN32 */
+
+extern int getsubopt(char **optionp, char **tokens, char **valuep);
+
+/************************************************************************/
+/************************************************************************/
+/**************** Unix section ***********************/
+/************************************************************************/
+/************************************************************************/
+
+typedef pthread_mutex_t ldclt_mutex_t;
+typedef pthread_t ldclt_tid;
+
+#endif /* _WIN32 */
+
+
+/*
+ * Portability functions common to all platforms
+ */
+extern int ldclt_mutex_init (ldclt_mutex_t *mutex);
+extern int ldclt_mutex_lock (ldclt_mutex_t *mutex);
+extern int ldclt_mutex_unlock (ldclt_mutex_t *mutex);
+extern void ldclt_sleep (int nseconds);
+extern int ldclt_thread_create (ldclt_tid *tid, void *(*fct)(void *), void *param);
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/remote.h b/ldap/servers/slapd/tools/ldclt/remote.h
new file mode 100644
index 00000000..1a99fba1
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/remote.h
@@ -0,0 +1,87 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : remote.h
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 04 May 1999
+ DESCRIPTION :
+ This file contains the definitions used by the remote
+ control module of ldclt.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+04/05/99 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+05/05/99 | F. Pistolesi | 1.3 : Implements communication with remote part.
+---------+--------------+------------------------------------------------------
+06/05/99 | JL Schwing | 1.4 : Port on Solaris 2.5.1
+---------+--------------+------------------------------------------------------
+*/
+
+/*
+ * Network includes
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#ifdef OSF1
+#ifndef _UINT32_T
+#define _UINT32_T
+typedef unsigned long uint32_t;
+#endif /* _UINT32_T */
+#else /* OS_RELEASE */
+#include <inttypes.h>
+#endif /* OS_RELEASE */
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+typedef struct {
+ uint32_t type,res,dnSize;
+ char dn[sizeof(uint32_t)];
+} repconfirm;
+
+extern int masterPort;
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/repcheck.c b/ldap/servers/slapd/tools/ldclt/repcheck.c
new file mode 100644
index 00000000..6967e708
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/repcheck.c
@@ -0,0 +1,162 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <signal.h>
+#include "remote.h"
+#include "lber.h"
+#include "ldap.h"
+
+enum {ADD,DELETE,MODRDN,MODIFY,RESULT};
+
+typedef struct {
+ int conn,op,type;
+ char *dn;
+ } Optype;
+
+Optype *pendops;
+int npend,maxop,connected;
+char *ldap_ops[]={"ADD","DEL","MODRDN","MOD ","RESULT",NULL};
+int ldap_val[]={LDAP_REQ_ADD,LDAP_REQ_DELETE,LDAP_REQ_MODRDN,LDAP_REQ_MODIFY};
+
+get_op_par(char *s,Optype *op)
+{
+ char *t;
+ int i;
+
+ t=strstr(s,"conn=");
+ for(t+=5,op->conn=0;isdigit(*t);t++)
+ op->conn=op->conn*10+*t-'0';
+ t=strstr(s,"op=");
+ for(t+=3,op->op=0;isdigit(*t);t++)
+ op->op=op->op*10+*t-'0';
+ if(t=strstr(s,"dn="))
+ op->dn=strdup(t+3);
+}
+
+send_op(char* s,int sfd)
+{
+ int sz,i;
+ Optype tmp;
+ repconfirm *result;
+ char *t;
+
+ get_op_par(s,&tmp);
+ for(i=0;i<maxop;i++)
+ if(pendops[i].op==tmp.op && pendops[i].conn==tmp.conn){
+ t=strstr(s,"err=");
+ sz=strlen(pendops[i].dn);
+ result=(repconfirm*)malloc(sizeof(repconfirm)+sz);
+ for(t+=4,result->res=0;isdigit(*t);t++)
+ result->res=result->res*10+*t-'0';
+ result->type=htonl(ldap_val[pendops[i].type]);
+ strcpy(result->dn,pendops[i].dn);
+ result->dnSize=htonl(sz);
+ result->res=htonl(result->res);
+ if(write(sfd,result,sizeof(repconfirm)+sz)<=0){
+ close(sfd);
+ memset(pendops,0,maxop*sizeof(Optype));
+ maxop=npend=connected=0;
+ return;
+ }
+ if(i!=maxop)
+ pendops[i]=pendops[maxop];
+ else memset(pendops+i,0,sizeof(Optype));
+ return;
+ }
+}
+
+main(int argc, char**argv)
+{
+ int i,port=16000;
+ int sockfd;
+ static char logline[512];
+ char **tmp;
+ struct hostent *serveraddr;
+ struct sockaddr_in srvsaddr;
+
+ while((i=getopt(argc,argv,"p:"))!=EOF){
+ switch(i){
+ case 'p': port=atoi(optarg);
+ break;
+ }
+ }
+ serveraddr=gethostbyname(argv[optind]);
+ srvsaddr.sin_addr.s_addr=htonl(*((u_long*)(serveraddr->h_addr_list[0])));
+ srvsaddr.sin_family=AF_INET;
+ srvsaddr.sin_port=htons(port);
+ maxop=npend=0;
+ pendops=(Optype*)malloc(sizeof(Optype)*20);
+ sigset(SIGPIPE,SIG_IGN);
+ while(gets(logline)){
+ if(!connected){
+ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
+ perror(argv[0]);
+ exit(1);
+ }
+ i=1;
+ if(setsockopt(sockfd,IPPROTO_TCP, TCP_NODELAY,&i,sizeof(int))!=0)
+ perror("Nagle");
+ if(connect(sockfd,(struct sockaddr*)&srvsaddr,sizeof(struct sockaddr))!=-1)
+ connected=1;
+ else {
+ close(sockfd);
+ continue;
+ }
+ }
+ for(tmp=ldap_ops,i=0;tmp[i];i++)
+ if(strstr(logline,tmp[i]))
+ break;
+ if(i<RESULT){
+ get_op_par(logline,&pendops[maxop]);
+ pendops[maxop].type=i;
+ if(++maxop>npend)
+ npend=maxop;
+ if(!(npend%20)){
+ pendops=(Optype*)realloc(pendops,sizeof(Optype)*(npend+20));
+ memset(pendops+npend,0,sizeof(Optype)*20);
+ }
+ }
+ if(i==RESULT)
+ send_op(logline,sockfd);
+ }
+ close(sockfd);
+}
+
diff --git a/ldap/servers/slapd/tools/ldclt/repslave.c b/ldap/servers/slapd/tools/ldclt/repslave.c
new file mode 100644
index 00000000..952d91a3
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/repslave.c
@@ -0,0 +1,342 @@
+#ident "@(#)repslave.c 1.15 99/06/09"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : repslave.c
+ AUTHOR : Fabio Pistolesi
+ VERSION : 1.0
+ DATE : 05 May 1999
+ DESCRIPTION :
+ This file contains the implementation of the slave part
+ of ldclt tool. This slave is intended to scan the logs
+ of the ldap server and to communicate the operations
+ logged to the master ldclt, to be checked against the
+ memorized operations performed on the master ldap
+ server.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+05/05/99 | F. Pistolesi | Creation
+---------+--------------+------------------------------------------------------
+06/05/99 | JL Schwing | 1.2 : Port on Solaris 2.5.1
+---------+--------------+------------------------------------------------------
+10/05/99 | F. Pistolesi | Added multiple filtered servers to send results to.
+---------+--------------+------------------------------------------------------
+18/05/99 | JL Schwing | 1.8 : Port on 2.5.1
+---------+--------------+------------------------------------------------------
+26/05/99 | F. Pistolesi | 1.10: Bug fix - missing free()
+---------+--------------+------------------------------------------------------
+27/05/99 | F. Pistolesi | 1.11: Add new option -d (debug)
+---------+--------------+------------------------------------------------------
+29/05/99 | F. Pistolesi | 1.12: Add new option -t (log)
+---------+--------------+------------------------------------------------------
+09/06/99 | JL Schwing | 1.14: Bug fix - crash in send_op() if tmp.dn==NULL
+---------+--------------+------------------------------------------------------
+09/06/99 | F. Pistolesi | 1.15: Fix the fix above.
+---------+--------------+------------------------------------------------------
+*/
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <signal.h>
+#include <libgen.h>
+#if OS_RELEASE == 551
+#include <re_comp.h>
+#endif
+#include "remote.h"
+#include "lber.h"
+#include "ldap.h"
+
+/*
+ * Enumeration for internal list
+ */
+enum {ADD,DELETE,MODRDN,MODIFY,RESULT,LAST};
+
+/*
+ * internal list
+ */
+typedef struct {
+ int conn,op,type;
+ char *dn;
+ } Optype;
+
+typedef struct {
+ int fd;
+ char *filter,*hname;
+ struct sockaddr_in addr;
+ } Towho;
+
+Optype *pendops;
+Towho *srvlist;
+int npend,maxop,connected,nsrv,debug;
+char *ldap_ops[]={"ADD","DEL","MODRDN","MOD ","RESULT","NONE",NULL};
+/*
+ * To map internal values to LDAP_REQ
+ */
+int ldap_val[]={LDAP_REQ_ADD,LDAP_REQ_DELETE,LDAP_REQ_MODRDN,LDAP_REQ_MODIFY};
+
+get_op_par(char *s,Optype *op)
+{
+ char *t;
+ int i;
+
+ /*
+ * Provided they do not change dsservd's log format, this should work
+ * Magic numbers are the length of the lookup string
+ */
+ t=strstr(s,"conn=");
+ for(t+=5,op->conn=0;isdigit(*t);t++)
+ op->conn=op->conn*10+*t-'0';
+ t=strstr(s,"op=");
+ for(t+=3,op->op=0;isdigit(*t);t++)
+ op->op=op->op*10+*t-'0';
+ if(t=strstr(s,"dn="))
+ op->dn=strdup(t+3);
+}
+
+open_cnx(struct sockaddr *srv)
+{
+ int i,sockfd;
+
+ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
+ {
+ perror("Slave");
+ exit(1);
+ }
+ i=1;
+ /*
+ * Disable TCP's Nagle algorithm
+ */
+ if(setsockopt(sockfd,IPPROTO_TCP, TCP_NODELAY,(void *)&i,sizeof(int))!=0)
+ perror("Nagle");
+ if(connect(sockfd,srv,sizeof(struct sockaddr))!=-1)
+ return sockfd;
+ else close(sockfd);
+ return -1;
+}
+
+send_op(char* s)
+{
+ int sz,i,j,ret;
+ Optype tmp;
+ repconfirm *result;
+ char *t;
+ struct pollfd pfd;
+
+ get_op_par(s,&tmp);
+ for(i=0;i<maxop;i++)
+ /*
+ * got a RESULT string. Try to match with known operations.
+ */
+ if(pendops[i].op==tmp.op && pendops[i].conn==tmp.conn)
+ {
+ sz=strlen(pendops[i].dn);
+ result=(repconfirm*)malloc(sizeof(repconfirm)+sz);
+ t=strstr(s,"err=");
+ for(t+=4,result->res=0;isdigit(*t);t++)
+ result->res=result->res*10+*t-'0';
+ /*
+ * Build packet
+ */
+ result->type=htonl(ldap_val[pendops[i].type]);
+ strcpy(result->dn,pendops[i].dn+1);
+ sz-=2;
+ result->dn[sz]='\0';
+ result->dnSize=htonl(sz);
+ if(debug)
+ printf("Sending %d %d %s\n",ntohl(result->type),result->res,result->dn);
+ result->res=htonl(result->res);
+ /*
+ * find which filter applies. Note that if no filter applies, no
+ * packets are sent
+ */
+ for(j=0;j<nsrv;j++)
+ {
+ /*
+ * Suppose a NULL filter means everything
+ */
+ if(srvlist[j].filter)
+ if(regex(srvlist[j].filter,result->dn)==NULL)
+ continue;
+ /*
+ * try to write. This works if server set SO_LINGER option
+ * with parameters l_onoff=1,l_linger=0. This means terminate
+ * the connection sending an RST instead of FIN, so that
+ * write() will fail on first attempt instead of second.
+ */
+ if(write(srvlist[j].fd,result,sizeof(repconfirm)+sz)<=0)
+ {
+ /*
+ * socket was closed by peer. try again
+ */
+ close(srvlist[j].fd);
+ if((srvlist[j].fd=connected=open_cnx((struct sockaddr*)&srvlist[j].addr))==-1)
+ /*
+ * OK, server disconnected for good
+ */
+ continue;
+ if((ret=write(srvlist[j].fd,result,sizeof(repconfirm)+sz))<=0)
+ puts("Porc!");
+ }
+ }
+ /*
+ * Copy over the operation at the end
+ */
+ free(pendops[i].dn);
+ maxop--;
+ pendops[i]=pendops[maxop];
+ free(result);
+ break;
+ }
+ if (tmp.dn != NULL)
+ free(tmp.dn);
+}
+
+main(int argc, char**argv)
+{
+ int i,port=16000;
+ int sockfd,log=0;
+ static char logline[512];
+ char **tmp,*hn,*hp,*hf;
+ struct hostent *serveraddr;
+
+ while((i=getopt(argc,argv,"tdP:s:"))!=EOF)
+ {
+ switch(i)
+ {
+ case 't': log=1;
+ break;
+ case 'd': debug=1;
+ break;
+ case 'P':
+ port=atoi(optarg);
+ break;
+ case 's':
+ /*
+ * pointers to hostname, host port, filter
+ */
+ hn=strtok(optarg,",");
+ hp=strtok(NULL,",");
+ hf=strtok(NULL,",");
+ if(hf==NULL&&hp)
+ if(*hp<'0' || *hp >'9')
+ hf=hp;
+ if(hn==NULL||hf==NULL)
+ {
+ puts("Missing parameter\n");
+ break;
+ }
+ /*
+ * Get master address, just the first.
+ */
+ if((serveraddr=gethostbyname(hn))==NULL)
+ {
+ printf("Unknown host %s\n",hn);
+ break;
+ }
+ srvlist=(Towho*)realloc(srvlist,(nsrv+1)*sizeof(Towho));
+ srvlist[nsrv].addr.sin_addr.s_addr=htonl(*((u_long*)(serveraddr->h_addr_list[0])));
+ srvlist[nsrv].addr.sin_family=AF_INET;
+ srvlist[nsrv].addr.sin_port=htonl((hp==hf?port:atoi(hp)));
+ if((srvlist[nsrv].filter=regcmp(hf,NULL))==NULL)
+ printf("Wrong REX: %s\n",hf);
+ srvlist[nsrv].fd=open_cnx((struct sockaddr*)&srvlist[nsrv].addr);
+ srvlist[nsrv].hname=strdup(hn);
+ nsrv++;
+ break;
+ }
+ }
+ if(!nsrv)
+ {
+ if(!argv[optind])
+ {
+ printf("Usage: %s [-td] -P port <hostname>\n\tor %s [-td] -s <host>,[<port>,]<REGEX>\n",argv[0],argv[0]);
+ printf("\t-t\tprints input on stdout.\n\t-d\tdebug mode.\n");
+ exit(1);
+ }
+ srvlist=(Towho*)malloc(sizeof(Towho));
+ if((serveraddr=gethostbyname(argv[optind]))==NULL)
+ {
+ printf("Unknown host %s\n",argv[optind]);
+ exit(1);
+ }
+ srvlist[nsrv].addr.sin_addr.s_addr=htonl(*((u_long*)(serveraddr->h_addr_list[0])));
+ srvlist[nsrv].addr.sin_family=AF_INET;
+ srvlist[nsrv].addr.sin_port=htons(port);
+ srvlist[nsrv].filter=NULL;
+ srvlist[nsrv].fd=open_cnx((struct sockaddr*)&srvlist[nsrv].addr);
+ srvlist[nsrv].hname=strdup(argv[optind]);
+ nsrv++;
+ }
+ maxop=npend=0;
+ pendops=(Optype*)malloc(sizeof(Optype)*20);
+ /*
+ * Ignore SIGPIPE during write()
+ */
+ sigset(SIGPIPE,SIG_IGN);
+ while(gets(logline))
+ {
+ if(log)
+ puts(logline);
+ for(tmp=ldap_ops,i=0;tmp[i];i++)
+ if(strstr(logline,tmp[i]))
+ break;
+ if(i<RESULT)
+ {
+ get_op_par(logline,&pendops[maxop]);
+ pendops[maxop].type=i;
+ if(++maxop>npend)
+ npend=maxop;
+ if(!(npend%20))
+ {
+ pendops=(Optype*)realloc(pendops,sizeof(Optype)*(npend+20));
+ memset(pendops+npend,0,sizeof(Optype)*20);
+ }
+ }
+ if(i==RESULT)
+ send_op(logline);
+ }
+}
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/scalab01.c b/ldap/servers/slapd/tools/ldclt/scalab01.c
new file mode 100644
index 00000000..2d0074ee
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/scalab01.c
@@ -0,0 +1,1193 @@
+#ident "ldclt @(#)scalab01.c 1.8 01/05/03"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : scalab01.c
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 08 January 2001
+ DESCRIPTION :
+ This file contains the implmentation of the specific
+ scenario scalab01 of ldclt.
+ I implement this set of functions in a separate file to
+ reduce the interconnection(s) between the main ldclt
+ and the add-ons, keeping in mind the possibility to use
+ a dynamic load of plugins for a future release.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+08/01/01 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+12/01/01 | JL Schwing | 1.2 : Second set of options for -e scalab01
+---------+--------------+------------------------------------------------------
+29/01/01 | B Kolics | 1.3 : readAttrValue() uses filter of requested attr
+---------+--------------+------------------------------------------------------
+01/02/01 | JL Schwing | 1.4 : Protect against multiple choice of same user.
+---------+--------------+------------------------------------------------------
+26/02/01 | JL Schwing | 1.5 : Port on non-solaris platforms...
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.6 : Lint cleanup.
+ | Bug fix : forget to set ldap protocol version.
+---------+--------------+------------------------------------------------------
+26/04/01 | B Kolics | 1.7 : in case of lock failure, thread is not aborted
+---------+--------------+------------------------------------------------------
+03/05/01 | B Kolics | 1.8 : bug fix - forget to release more line.
+---------+--------------+------------------------------------------------------
+*/
+
+
+
+#include <stdio.h> /* printf(), etc... */
+#include <stdlib.h> /* malloc(), etc... */
+#include <string.h> /* strcpy(), etc... */
+#include <errno.h> /* perror(), etc... */
+#ifndef _WIN32
+#include <pthread.h> /* pthreads(), etc... */
+#endif
+
+#include <lber.h> /* ldap C-API BER declarations */
+#include <ldap.h> /* ldap C-API declarations */
+
+#include "port.h" /* Portability definitions */
+#include "ldclt.h" /* This tool's include file */
+#include "utils.h" /* Utilities functions */
+#include "scalab01.h" /* Scalab01 specific definitions */
+
+
+
+
+
+/*
+ * Private data structures.
+ */
+scalab01_context s1ctx;
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : scalab01_init
+ PURPOSE : Initiates the scalab01 scenario.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+scalab01_init (void)
+{
+ int ret; /* Return value */
+
+ s1ctx.nbcnx = 0; /* No connection yet */
+ s1ctx.list = NULL; /* No record yet */
+ s1ctx.lockingMax = 0; /* No locking yet */
+
+ /*
+ * Initiates mutexes
+ */
+ if ((ret = ldclt_mutex_init (&(s1ctx.list_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s\n", mctx.pid, strerror (ret));
+ fprintf (stderr, "ldclt[%d]: Error: cannot initiate s1ctx.list_mutex\n", mctx.pid);
+ fflush (stderr);
+ return (-1);
+ }
+ if ((ret = ldclt_mutex_init (&(s1ctx.locking_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s\n", mctx.pid, strerror (ret));
+ fprintf (stderr, "ldclt[%d]: Error: cannot initiate s1ctx.locking_mutex\n", mctx.pid);
+ fflush (stderr);
+ return (-1);
+ }
+ if ((ret = ldclt_mutex_init (&(s1ctx.nbcnx_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s\n", mctx.pid, strerror (ret));
+ fprintf (stderr, "ldclt[%d]: Error: cannot initiate s1ctx.nbcnx_mutex\n", mctx.pid);
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * No error
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : scalab01Lock
+ PURPOSE : Lock for single user trying to connect.
+ INPUT : tttctx = thread context.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 cannot lock, 1 if could lock.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+scalab01Lock (
+ thread_context *tttctx)
+{
+ int i; /* For the loop */
+ int ret; /* Return code */
+ int res; /* Result of this function */
+
+ /*
+ * Get secure access to the common data structure.
+ */
+ if ((ret = ldclt_mutex_lock (&(s1ctx.locking_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdId, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Is it locked ?
+ */
+ res = 1;
+ for (i=0 ; i<s1ctx.lockingMax ; i++)
+ if ((s1ctx.locking[i] != NULL) &&
+ (!strcmp (s1ctx.locking[i], tttctx->bufBindDN)))
+ {
+ res = 0;
+ break;
+ }
+ if (res == 1)
+ {
+ for (i=0 ; (i<s1ctx.lockingMax) && (s1ctx.locking[i] != NULL) ; i++);
+ if (i == s1ctx.lockingMax)
+ {
+ if (s1ctx.lockingMax == SCALAB01_MAX_LOCKING)
+ res = 0;
+ else
+ s1ctx.lockingMax++;
+ }
+ if (res != 0)
+ s1ctx.locking[i] = tttctx->bufBindDN;
+ }
+
+ /*
+ * Free mutex
+ */
+ if ((ret = ldclt_mutex_unlock (&(s1ctx.locking_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_unlock(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdId, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ return (res);
+}
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : scalab01Unlock
+ PURPOSE : Unlock for single user trying to connect.
+ INPUT : tttctx = thread context.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+scalab01Unlock (
+ thread_context *tttctx)
+{
+ int i; /* For the loop */
+ int ret; /* Return code */
+
+ /*
+ * Get secure access to the common data structure.
+ */
+ if ((ret = ldclt_mutex_lock (&(s1ctx.locking_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdId, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Find the entry and unlock it.
+ */
+ for (i=0 ; i<s1ctx.lockingMax ; i++)
+ if ((s1ctx.locking[i] != NULL) &&
+ (!strcmp (s1ctx.locking[i], tttctx->bufBindDN)))
+ {
+ s1ctx.locking[i] = NULL;
+ break;
+ }
+
+ /*
+ * Free mutex
+ */
+ if ((ret = ldclt_mutex_unlock (&(s1ctx.locking_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_unlock(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdId, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : scalab01_modemIncr
+ PURPOSE : Increments the modem nb of cnx
+ INPUT : ident = thread identifier
+ OUTPUT : None.
+ RETURN : -1 if error
+ 0 if no modem available
+ 1 if modem available
+ DESCRIPTION :
+ *****************************************************************************/
+int
+scalab01_modemIncr (
+ char *ident)
+{
+ int ret; /* Return value */
+ int res; /* Result of this function */
+
+ /*
+ * Get secure access to the common data structure.
+ */
+ if ((ret = ldclt_mutex_lock (&(s1ctx.nbcnx_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(), error=%d (%s)\n",
+ mctx.pid, ident, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ if (s1ctx.nbcnx >= s1ctx.maxcnxnb)
+ res = 0;
+ else
+ {
+ res = 1;
+ s1ctx.nbcnx++;
+ }
+
+ /*
+ * Free mutex
+ */
+ if ((ret = ldclt_mutex_unlock (&(s1ctx.nbcnx_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_unlock(), error=%d (%s)\n",
+ mctx.pid, ident, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ return (res);
+}
+
+
+/* ****************************************************************************
+ FUNCTION : scalab01_modemDecr
+ PURPOSE : Decrements the modem nb of cnx
+ INPUT : ident = thread identifier
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+scalab01_modemDecr (
+ char *ident)
+{
+ int ret; /* Return value */
+
+ /*
+ * Get secure access to the common data structure.
+ */
+ if ((ret = ldclt_mutex_lock (&(s1ctx.nbcnx_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(), error=%d (%s)\n",
+ mctx.pid, ident, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ s1ctx.nbcnx--;
+
+ /*
+ * Free mutex
+ */
+ if ((ret = ldclt_mutex_unlock (&(s1ctx.nbcnx_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_unlock(), error=%d (%s)\n",
+ mctx.pid, ident, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : scalab01_addLogin
+ PURPOSE : Add a new user login to the s1ctx structure.
+ INPUT : tttctx = thread context.
+ dn = user's dn.
+ duration = duration of the connection.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+scalab01_addLogin (
+ thread_context *tttctx,
+ char *dn,
+ int duration)
+{
+ int ret; /* Return value */
+ isp_user *new; /* New entry */
+ isp_user *cur; /* Current entry */
+
+ /*
+ * Create the new record.
+ */
+ new = (isp_user *) malloc (sizeof (isp_user));
+ strcpy (new->dn, dn);
+ new->cost = new->counter = duration;
+ new->next = NULL;
+
+ /*
+ * Get secure access to the common data structure.
+ * Note : it should be possible to reduce the "size" of this critical
+ * section but I am not 100% certain this won't mess up all things.
+ */
+ if ((ret = ldclt_mutex_lock (&(s1ctx.list_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdId, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Maybe this is the first entry of the list ?
+ */
+ if (s1ctx.list == NULL)
+ s1ctx.list = new;
+ else
+ {
+ /*
+ * Check with the list's head
+ */
+ if (s1ctx.list->counter >= duration)
+ {
+ new->next = s1ctx.list;
+ s1ctx.list = new;
+ }
+ else
+ {
+ cur = s1ctx.list;
+ while (cur != NULL)
+ {
+ if (cur->next == NULL)
+ {
+ cur->next = new;
+ cur = NULL; /* Exit loop */
+ }
+ else
+ if (cur->next->counter >= duration)
+ {
+ new->next = cur->next;
+ cur->next = new;
+ cur = NULL; /* Exit loop */
+ }
+ else
+ cur = cur->next;
+ }
+ }
+ }
+
+ /*
+ * Free mutex
+ */
+ if ((ret = ldclt_mutex_unlock (&(s1ctx.list_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_unlock(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdId, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : scalab01_connectSuperuser
+ PURPOSE : Purpose of the fct
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+scalab01_connectSuperuser (void)
+{
+ int ret; /* Return value */
+ int v2v3; /* LDAP version used */
+ char bindDN [MAX_DN_LENGTH]; /* To bind */
+
+ /*
+ * Create the LDAP context
+ */
+#ifdef LDCLTSSL
+ /*
+ * SSL is enabled ?
+ */
+ if (mctx.mode & SSL)
+ {
+ /*
+ * LDAP session initialization in SSL mode
+ */
+ s1ctx.ldapCtx = (LDAP *)(*(mctx.sslctx.ldapssl_init))
+ (mctx.hostname, mctx.port, 1);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: ctrl: ldapssl_init (%s, %d), ldapCtx=0x%08x\n",
+ mctx.pid, mctx.hostname, mctx.port, (unsigned int)s1ctx.ldapCtx);
+ if (s1ctx.ldapCtx == NULL)
+ {
+ printf ("ldclt[%d]: ctrl: Cannot ldapssl_init (%s, %d), errno=%d\n",
+ mctx.pid, mctx.hostname, mctx.port, errno);
+ fflush (stdout);
+ return (-1);
+ }
+ /*
+ * Client authentication is used ?
+ */
+ if (mctx.mode & CLTAUTH)
+ {
+ ret = (int)(*(mctx.sslctx.ldapssl_enable_clientauth))
+ (s1ctx.ldapCtx, "", mctx.keydbpin, mctx.cltcertname);
+ if (mctx.mode & VERY_VERBOSE)
+ printf
+ ("ldclt[%d]: ctrl: After ldapssl_enable_clientauth (ldapCtx=0x%08x, %s, %s)",
+ mctx.pid, (unsigned int)s1ctx.ldapCtx, mctx.keydbpin, mctx.cltcertname);
+ if (ret < 0)
+ {
+ printf
+ ("ldclt[%d]: ctrl: Cannot ldapssl_enable_clientauth (ldapCtx=0x%08x, %s, %s)",
+ mctx.pid, (unsigned int)s1ctx.ldapCtx, mctx.keydbpin, mctx.cltcertname);
+ ldap_perror(s1ctx.ldapCtx, "ldapssl_enable_clientauth");
+ fflush (stdout);
+ return (-1);
+ }
+ }
+ }
+ else
+ {
+#endif
+ /*
+ * Connection initialization in normal, unencrypted mode
+ */
+ s1ctx.ldapCtx = ldap_init (mctx.hostname, mctx.port);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: ctrl: After ldap_init (%s, %d), ldapCtx=0x%08x\n",
+ mctx.pid, mctx.hostname, mctx.port, (unsigned int)s1ctx.ldapCtx);
+ if (s1ctx.ldapCtx == NULL)
+ {
+ printf ("ldclt[%d]: ctrl: Cannot ldap_init (%s, %d), errno=%d\n",
+ mctx.pid, mctx.hostname, mctx.port, errno);
+ fflush (stdout);
+ return (-1);
+ }
+#ifdef LDCLTSSL
+ }
+#endif
+
+ /*
+ * Set the LDAP version and other options...
+ */
+ if (mctx.mode & LDAP_V2)
+ v2v3 = LDAP_VERSION2;
+ else
+ v2v3 = LDAP_VERSION3;
+
+ ret = ldap_set_option (s1ctx.ldapCtx, LDAP_OPT_PROTOCOL_VERSION, &v2v3);
+ if (ret < 0) /*JLS 14-03-01*/
+ { /*JLS 14-03-01*/
+ printf ("ldclt[%d]: ctrl: Cannot ldap_set_option(LDAP_OPT_PROTOCOL_VERSION)\n",
+ mctx.pid);
+ fflush (stdout); /*JLS 14-03-01*/
+ return (-1); /*JLS 14-03-01*/
+ } /*JLS 14-03-01*/
+
+
+ /*
+ * Now we could bind
+ */
+#ifdef LDCLTSSL
+ /*
+ * for SSL client authentication, SASL BIND is used
+ */
+ if (mctx.mode & CLTAUTH)
+ {
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: ctrl: Before ldap_sasl_bind_s\n", mctx.pid);
+ ret = ldap_sasl_bind_s (s1ctx.ldapCtx, "", "EXTERNAL", NULL, NULL, NULL,
+ NULL);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: ctrl: After ldap_sasl_bind_s\n", mctx.pid);
+ if (ret != LDAP_SUCCESS)
+ {
+ printf ("ldclt[%d]: ctrl: Cannot ldap_sasl_bind_s, error=%d (%s)\n",
+ mctx.pid, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ return (-1);
+ }
+ }
+ else
+ {
+#endif /* LDCLTSSL */
+ strcpy (bindDN, SCALAB01_SUPER_USER_RDN);
+ strcat (bindDN, ",");
+ strcat (bindDN, mctx.baseDN);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: ctrl: Before ldap_simple_bind_s (%s , %s)\n",
+ mctx.pid, bindDN, SCALAB01_SUPER_USER_PASSWORD);
+ ret = ldap_simple_bind_s (s1ctx.ldapCtx,
+ bindDN, SCALAB01_SUPER_USER_PASSWORD);
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: ctrl: After ldap_simple_bind_s (%s, %s)\n",
+ mctx.pid, bindDN, SCALAB01_SUPER_USER_PASSWORD);
+ if (ret != LDAP_SUCCESS)
+ {
+ printf("ldclt[%d]: ctrl: Cannot ldap_simple_bind_s (%s, %s), error=%d (%s)\n",
+ mctx.pid, bindDN, SCALAB01_SUPER_USER_PASSWORD,
+ ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ return (-1);
+ }
+#ifdef LDCLTSSL
+ }
+#endif
+
+ /*
+ * Normal end...
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : readAttrValue
+ PURPOSE : This function will ldap_search the given entry for the
+ value of the given attribute.
+ INPUT : ident = thread identifier
+ ldapCtx = LDAP context
+ dn = dn of the entry to process
+ attname = attribute name
+ OUTPUT : value = attribute value. This buffer must be
+ initiated with enough memory.
+ value[0] == '\0' if not find.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+readAttrValue (
+ LDAP *ldapCtx,
+ char *ident,
+ char *dn,
+ char *attname,
+ char *value)
+{
+ int ret; /* Return value */
+ char *attrs[2]; /* Attribute to retrieve */
+ LDAPMessage *res; /* LDAP responses */
+ LDAPMessage *cur; /* Current message */
+ BerElement *ber; /* To decode the response */
+ char *aname; /* Current attribute name */
+ char **vals; /* Attribute value returned */
+ char *filter; /* Filter used for searching */
+
+ /*
+ * First, ldap_search() the entry.
+ */
+ attrs[0] = attname;
+ attrs[1] = NULL;
+ filter = (char *)malloc((4+strlen(attname))*sizeof(char));
+ sprintf(filter, "(%s=*)", attname);
+ ret = ldap_search_s (ldapCtx, dn, LDAP_SCOPE_BASE,
+ filter, attrs, 0, &res);
+ if (filter != NULL) free(filter);
+ if (ret != LDAP_SUCCESS)
+ {
+ printf ("ldclt[%d]: %s: Cannot ldap_search (%s in %s), error=%d (%s)\n",
+ mctx.pid, ident, attname, dn, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ return (-1);
+ }
+
+ /*
+ * Decode the response
+ */
+ value[0] = '\0'; /* Not find yet */
+ cur = ldap_first_entry (ldapCtx, res);
+ while ((!value[0]) && (cur != NULL))
+ {
+ aname = ldap_first_attribute (ldapCtx, cur, &ber);
+ while ((!value[0]) && (aname != NULL))
+ {
+ /*
+ * We expect this attribute to be single-valued.
+ */
+ if (!strcmp (aname, attname))
+ {
+ vals = ldap_get_values (ldapCtx, cur, aname);
+ if (vals == NULL)
+ {
+ printf ("ldclt[%d]: %s: no value for %s in %s\n",
+ mctx.pid, ident, dn, attname);
+ fflush (stdout);
+ return (-1);
+ }
+ strcpy (value, vals[0]);
+ ldap_value_free (vals);
+ }
+
+ /*
+ * Next attribute
+ */
+ ldap_memfree (aname);
+ if (!value[0])
+ aname = ldap_next_attribute (ldapCtx, cur, ber);
+ }
+
+ /*
+ * Next entry - shouldn't happen in theory
+ */
+ if (ber != NULL)
+ ldap_ber_free (ber, 0);
+ cur = ldap_next_entry (ldapCtx, cur);
+ }
+ ldap_msgfree (res); /* Free the response */
+
+ return (0);
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : writeAttrValue
+ PURPOSE : This function will ldap_modify the given entry to
+ replace the value of the given attribute.
+ INPUT : ident = thread identifier
+ ldapCtx = LDAP context
+ dn = dn of the entry to process
+ attname = attribute name
+ value = attribute value
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+writeAttrValue (
+ LDAP *ldapCtx,
+ char *ident,
+ char *dn,
+ char *attname,
+ char *value)
+{
+ int ret; /* Return value */
+ LDAPMod attribute; /* To build the attributes */
+ LDAPMod *attrsmod[2]; /* Modify attributes */
+ char *pvalues[2]; /* To build the values list */
+
+ /*
+ * Prepear the data to be written
+ */
+ pvalues[0] = value;
+ pvalues[1] = NULL;
+ attribute.mod_op = LDAP_MOD_REPLACE;
+ attribute.mod_type = attname;
+ attribute.mod_values = pvalues;
+ attrsmod[0] = &attribute;
+ attrsmod[1] = NULL;
+
+ /*
+ * Store the data in the directory.
+ */
+ ret = ldap_modify_ext_s (ldapCtx, dn, attrsmod, NULL, NULL);
+ if (ret != LDAP_SUCCESS)
+ {
+ printf ("ldclt[%d]: %s: Cannot ldap_modify_ext_s (%s in %s), error=%d (%s)\n",
+ mctx.pid, ident, attname, dn, ret, my_ldap_err2string (ret));
+ fflush (stdout);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : scalab01_unlock
+ PURPOSE : Unlock the user given in argument.
+ INPUT : entry = entry to unlock.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+scalab01_unlock (
+ isp_user *user)
+{
+ int account; /* Accounting value */
+ char buf[20]; /* To read/write attribute */
+
+ /*
+ * Increment accounting counters
+ * First, read the current value.
+ */
+ if (readAttrValue (s1ctx.ldapCtx,"ctrl",user->dn,SCALAB01_ACC_ATTRIB,buf) < 0)
+ {
+ printf ("ldclt[%d]: ctrl: Cannot read accounting attribute of %s\n",
+ mctx.pid, user->dn);
+ fflush (stdout);
+ return (-1);
+ }
+
+ /*
+ * If this attribute has no value (doesn't exist) we assume it is 0.
+ */
+ if (buf[0] != '\0')
+ account = atoi (buf);
+ else
+ {
+ printf ("ldclt[%d]: ctrl: No accounting attribute for %s - assume it is 0\n",
+ mctx.pid, user->dn);
+ fflush (stdout);
+ account = 0;
+ }
+
+ /*
+ * Compute the new value and store it in the directory.
+ */
+ sprintf (buf, "%d", account + user->cost);
+ if (writeAttrValue (s1ctx.ldapCtx,"ctrl",user->dn,SCALAB01_ACC_ATTRIB,buf) <0)
+ {
+ printf ("ldclt[%d]: ctrl: Cannot write accounting attribute of %s\n",
+ mctx.pid, user->dn);
+ fflush (stdout);
+ return (-1);
+ }
+
+ /*
+ * Unlock the user
+ */
+ if (writeAttrValue (s1ctx.ldapCtx, "ctrl", user->dn,
+ SCALAB01_LOCK_ATTRIB, SCALAB01_VAL_UNLOCKED) < 0)
+ {
+ printf ("ldclt[%d]: ctrl: Cannot write lock (unlock) attribute of %s\n",
+ mctx.pid, user->dn);
+ fflush (stdout);
+ return (-1);
+ }
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: ctrl: entry %s unlocked\n",
+ mctx.pid, user->dn);
+
+ /*
+ * Decrement modem pool usage...
+ */
+ if (scalab01_modemDecr ("ctrl") < 0)
+ return (-1);
+
+ /*
+ * Normal end
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : scalab01_control
+ PURPOSE : This function implements the control loop/thread of
+ the scalab01 scenario. Its main target is to manage
+ the counters of each "connection" and to unlock the
+ entry when time is reached.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+void *
+scalab01_control (
+ void *arg)
+{
+ isp_user *cur; /* Current entry */
+ isp_user *head; /* Head of entries to process */
+ int ret; /* Return value */
+ int nbTot; /* Total nb entries locked */
+ int nbU; /* Number unlocked */
+
+ /*
+ * Initialization
+ * Failure to connect is a critical error...
+ */
+ if (scalab01_connectSuperuser () < 0)
+ ldcltExit (EXIT_NOBIND);
+
+ /*
+ * Main loop
+ */
+ while (1 /*CONSTCOND*/) /*JLS 14-03-01*/
+ {
+ ldclt_sleep (1); /* Poll the connections every second */
+ nbTot = nbU = 0; /* No entries processed yet */
+
+ /*
+ * Get protected access to the entries
+ */
+ if ((ret = ldclt_mutex_lock (&(s1ctx.list_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: ctrl: cannot mutex_lock(), error=%d (%s)\n",
+ mctx.pid, ret, strerror (ret));
+ fflush (stderr);
+ ldcltExit (EXIT_OTHER);
+ }
+
+ /*
+ * Decrement all counters
+ */
+ for (cur=s1ctx.list ; cur!=NULL ; cur=cur->next)
+ {
+ cur->counter--;
+ nbTot++;
+ }
+
+ /*
+ * Find the entries to process.
+ */
+ if ((s1ctx.list == NULL) || (s1ctx.list->counter > 0))
+ head = NULL;
+ else
+ {
+ head = cur = s1ctx.list;
+ while ((cur != NULL) && (cur->counter == 0))
+ cur = cur->next;
+ s1ctx.list = cur;
+ }
+
+ /*
+ * Release mutex
+ */
+ if ((ret = ldclt_mutex_unlock (&(s1ctx.list_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: ctrl: cannot mutex_unlock(), error=%d (%s)\n",
+ mctx.pid, ret, strerror (ret));
+ fflush (stderr);
+ ldcltExit (EXIT_OTHER);
+ }
+
+ /*
+ * Now, we have "head" that points either to NULL or to a list of
+ * entries to process.
+ * Attention, this list of entries is not terminated by NULL, but
+ * we must rather check the field head->next->counter" for the last
+ * entry...
+ *
+ * NOTE : implements this section as a separate thread to keep the
+ * general timer working...
+ */
+ while (head != NULL)
+ {
+ if (scalab01_unlock (head) < 0)
+ {
+ printf ("ldclt[%d]: ctrl: cannot unlock %s\n", mctx.pid, head->dn);
+ ldcltExit (EXIT_OTHER);
+ }
+ nbU++; /* One more entry unlocked */
+
+ /*
+ * Next entry...
+ */
+ cur = head;
+ if (head->next == NULL)
+ head = NULL;
+ else
+ if (head->next->counter != 0)
+ head = NULL;
+ else
+ head = head->next;
+
+ free (cur);
+ } /* while (head =! NULL) */
+
+ /*
+ * Print some stats...
+ */
+ if (mctx.mode & VERBOSE)
+ printf ("ldclt[%d]: ctrl: nb entries unlocked / total : %3d / %5d\n",
+ mctx.pid, nbU, nbTot);
+ } /* Main loop */
+
+ /*
+ * End of thread
+ */
+ return (arg);
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : doScalab01
+ PURPOSE : Implements the client part of the scalab01 scenario.
+ INPUT : tttctx = this thread context
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+doScalab01 (
+ thread_context *tttctx)
+{
+ char buf[32]; /* To read attributes value */
+ int duration; /* Use a variable for trace purpose */
+ int res; /* Result of cnx to modem pool */
+ int doloop; /* To know if we should loop */
+
+ /*
+ * Simulate connection to the modem pool.
+ */
+ while ((res = scalab01_modemIncr(tttctx->thrdId)) != 1)
+ switch (res)
+ {
+ case 0:
+ ldclt_sleep (s1ctx.wait==0?SCALAB01_DEF_WAIT_TIME:rndlim(0,s1ctx.wait));
+ break;
+ case -1:
+ return (-1);
+ break;
+ }
+
+ /*
+ * Connection to the server
+ * The function connectToServer() will take care of the various connection/
+ * disconnection, bind/unbind/close etc... requested by the user.
+ * The cost is one more function call in this application, but the
+ * resulting source code will be much more easiest to maintain.
+ */
+ if (connectToServer (tttctx) < 0)
+ return (-1);
+ if (!(tttctx->binded))
+ return (0);
+
+ /*
+ * Check that no other thread is using the same identity...
+ */
+ doloop = 1;
+ while (doloop)
+ {
+ switch (scalab01Lock (tttctx))
+ {
+ case 0:
+ ldclt_sleep (1);
+ break;
+ case 1:
+ doloop = 0;
+ break;
+ case -1:
+ return (-1);
+ break;
+ }
+ }
+
+ /*
+ * Ok, we are now binded. Great ;-)
+ * The DN we used to bind is available in tttctx->bufBindDN
+ * Read lock attribute
+ */
+ if (readAttrValue (tttctx->ldapCtx, tttctx->thrdId, tttctx->bufBindDN,
+ SCALAB01_LOCK_ATTRIB, buf) < 0)
+ {
+ printf ("ldclt[%d]: %s: Cannot read lock attribute of %s\n",
+ mctx.pid, tttctx->thrdId, tttctx->bufBindDN);
+ fflush (stdout);
+ (void) scalab01_modemDecr (tttctx->thrdId);
+ return (-1);
+ }
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: %s: entry %s lock read\n",
+ mctx.pid, tttctx->thrdId, tttctx->bufBindDN);
+
+ /*
+ * If locked, then we cannot login now...
+ */
+ if (!strcmp (buf, SCALAB01_VAL_LOCKED))
+ {
+ if (scalab01_modemDecr (tttctx->thrdId) < 0)
+ return (-1);
+ return (0);
+ }
+
+ /*
+ * If not locked :
+ * - lock the user
+ * - decide how many times will be connected
+ * - add information to the list of connected
+ */
+ if (writeAttrValue (tttctx->ldapCtx, tttctx->thrdId, tttctx->bufBindDN,
+ SCALAB01_LOCK_ATTRIB, SCALAB01_VAL_LOCKED) < 0)
+ {
+ printf ("ldclt[%d]: %s: Cannot write lock attribute of %s\n",
+ mctx.pid, tttctx->thrdId, tttctx->bufBindDN);
+ fflush (stdout);
+ /*
+ * It can still happen that two threads write this attribute at the same
+ * time, so there can be failure in one of the threads
+ * in this case just return
+ */
+ if (scalab01_modemDecr (tttctx->thrdId) < 0) /*JLS 03-05-01*/
+ return (-1); /*JLS 03-05-01*/
+ return (0); /*BK 26-04-01*/
+ }
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: %s: entry %s lock written\n",
+ mctx.pid, tttctx->thrdId, tttctx->bufBindDN);
+
+ if (scalab01Unlock (tttctx) < 0)
+ return (-1);
+
+ duration = rndlim (1, s1ctx.cnxduration);
+ if (scalab01_addLogin (tttctx, tttctx->bufBindDN, duration) < 0)
+ {
+ printf ("ldclt[%d]: %s: Cannot memorize new login of %s\n",
+ mctx.pid, tttctx->thrdId, tttctx->bufBindDN);
+ fflush (stdout);
+ return (-1);
+ }
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: %s: entry %s login added duration %6d\n",
+ mctx.pid, tttctx->thrdId, tttctx->bufBindDN, duration);
+
+ /*
+ * Memorize the operation
+ */
+ if (incrementNbOpers (tttctx) < 0)
+ return (-1);
+
+ /*
+ * Wait before next operation...
+ */
+ if (s1ctx.wait > 0)
+ ldclt_sleep (rndlim (0,s1ctx.wait));
+
+ /*
+ * Unbind
+ */
+/*
+TBC - this is done in the next loop... - cf connectToServer()
+*/
+
+ return (0);
+}
+
+
+
+
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/scalab01.h b/ldap/servers/slapd/tools/ldclt/scalab01.h
new file mode 100644
index 00000000..381c8bab
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/scalab01.h
@@ -0,0 +1,120 @@
+#ident "ldclt @(#)scalab01.h 1.3 01/03/14"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : scalab01.h
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 12 January 2001
+ DESCRIPTION :
+ This file contains the definitions related to the
+ scenario scalab01 of ldclt.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+12/01/01 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+01/02/01 | JL Schwing | 1.2 : Protect against multiple choice of same user.
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.3 : Lint cleanup.
+---------+--------------+------------------------------------------------------
+*/
+
+
+#ifndef SCALAB01_H
+#define SCALAB01_H
+
+
+/*
+ * Default values for scalab01
+ */
+#define SCALAB01_ACC_ATTRIB "ntUserUnitsPerWeek"
+#define SCALAB01_DEF_MAX_CNX 5000
+#define SCALAB01_DEF_CNX_DURATION 3600
+#define SCALAB01_DEF_WAIT_TIME 10
+#define SCALAB01_LOCK_ATTRIB "ntUserFlags"
+#define SCALAB01_SUPER_USER_RDN "cn=super user"
+#define SCALAB01_SUPER_USER_PASSWORD "super user password"
+#define SCALAB01_VAL_LOCKED "1"
+#define SCALAB01_VAL_UNLOCKED "0"
+#define SCALAB01_MAX_LOCKING 4096
+
+/*
+ * This structure is intended to memorize the information about
+ * the "ISP" users connected.
+ * Uses mainly static size data to save malloc()/free() calls.
+ */
+typedef struct isp_user {
+ char dn[MAX_DN_LENGTH]; /* User's DN */
+ int cost; /* Cnx cost */
+ int counter; /* To free it */
+ struct isp_user *next; /* Next entry */
+} isp_user;
+
+/*
+ * This is the scalab01 context structure.
+ */
+typedef struct scalab01_context {
+ int cnxduration; /* Max cnx duration */
+ LDAP *ldapCtx; /* LDAP context */
+ isp_user *list; /* ISP users list */
+ ldclt_mutex_t list_mutex; /* Protect list */
+ char *locking[SCALAB01_MAX_LOCKING];
+ ldclt_mutex_t locking_mutex;
+ int lockingMax;
+ int maxcnxnb; /* Modem pool size */
+ int nbcnx; /* Nb cnx to the modem */
+ ldclt_mutex_t nbcnx_mutex; /* Protect nbcnx */
+ int wait; /* Retry every this time */
+} scalab01_context;
+
+/*
+ * Exported functions and structures
+ */
+extern int doScalab01 (thread_context *tttctx);
+extern scalab01_context s1ctx;
+extern void *scalab01_control (void *);
+extern int scalab01_init (void); /*JLS 14-03-01*/
+
+#endif /* SCALAB01_H */
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/srv.c b/ldap/servers/slapd/tools/ldclt/srv.c
new file mode 100644
index 00000000..80c2608a
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/srv.c
@@ -0,0 +1,123 @@
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/inttypes.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include "remote.h"
+#include "lber.h"
+#include "ldap.h"
+
+enum {ADD,DELETE,MODRDN,MODIFY,RESULT};
+
+typedef struct {
+ int conn,op,type;
+ char *dn;
+ } Optype;
+
+Optype *pendops;
+int npend=-1,maxop;
+char *ldap_ops[]={"ADD","DEL","MODRDN","MOD ","RESULT",NULL};
+int ldap_val[]={LDAP_REQ_ADD,LDAP_REQ_DELETE,LDAP_REQ_MODRDN,LDAP_REQ_MODIFY};
+
+print_packet(repconfirm *op)
+{
+ int i;
+ printf("type=%d, res=%d, dnlen=%d, dN: %s\n",op->type,op->res,op->dnSize,op->dn);
+
+}
+
+main(int argc, char**argv)
+{
+ int i,port=16000;
+ int sockfd,newfd;
+ static char buff[512];
+ char **tmp;
+ struct sockaddr_in srvsaddr,claddr;
+ struct hostent *cltaddr;
+ uint32_t ipaddr;
+
+ while((i=getopt(argc,argv,"p:"))!=EOF){
+ switch(i){
+ case 'p': port=atoi(optarg);
+ break;
+ }
+ }
+ srvsaddr.sin_addr.s_addr=htonl(INADDR_ANY);
+ srvsaddr.sin_family=AF_INET;
+ srvsaddr.sin_port=htons(port);
+ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
+ perror("Socket");
+ exit(1);
+ }
+ i=1;
+ if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int))!=0)
+ perror("Sockopt");
+ if(bind(sockfd,(struct sockaddr*)&srvsaddr,sizeof(struct sockaddr))!=0){
+ perror("Bind");
+ exit(1);
+ }
+ if(listen(sockfd,1)!=0)
+ perror("listen");
+ for(;;){
+ i=sizeof(claddr);
+ if((newfd=accept(sockfd,(struct sockaddr *)&claddr,&i))<0){
+ perror("Accept");
+ exit(1);
+ }
+ ipaddr=ntohl(claddr.sin_addr.s_addr);
+ cltaddr=gethostbyaddr((char*)&ipaddr,sizeof(ipaddr),AF_INET);
+ printf("Accepting from %s\n",cltaddr->h_name);
+ while(read(newfd,buff,512)>0){
+ print_packet((repconfirm*) buff);
+ memset(buff,0,512);
+ }
+ close(newfd);
+ }
+ close(sockfd);
+}
+
diff --git a/ldap/servers/slapd/tools/ldclt/threadMain.c b/ldap/servers/slapd/tools/ldclt/threadMain.c
new file mode 100644
index 00000000..f2f23725
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/threadMain.c
@@ -0,0 +1,1198 @@
+#ident "ldclt @(#)threadMain.c 1.40 01/05/04"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : threadMain.c
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 04 December 1998
+ DESCRIPTION :
+ This file implements the main/core part of the
+ threads. The ldap part is in another source file.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+04/12/98 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+10/12/98 | JL Schwing | 1.2 : Add nb of errors statistics.
+---------+--------------+------------------------------------------------------
+10/12/98 | JL Schwing | 1.3 : Implement asynchronous mode.
+---------+--------------+------------------------------------------------------
+11/12/98 | JL Schwing | 1.4 : Implement max errors threshold.
+ | fflush(stdout) after each printf.
+---------+--------------+------------------------------------------------------
+14/12/98 | JL Schwing | 1.5 : Implement "-e close".
+ | Add "thread is dead" message.
+---------+--------------+------------------------------------------------------
+16/12/98 | JL Schwing | 1.6 : Implement "-e add" and "-e delete".
+---------+--------------+------------------------------------------------------
+23/12/98 | JL Schwing | 1.7 : bug fix - crash in msgIdDel().
+---------+--------------+------------------------------------------------------
+28/12/98 | JL Schwing | 1.8 : Add tag asyncHit.
+---------+--------------+------------------------------------------------------
+13/01/99 | JL Schwing | 1.9 : Implement "-e string".
+---------+--------------+------------------------------------------------------
+18/01/99 | JL Schwing | 1.10: Implement "-e randombase".
+---------+--------------+------------------------------------------------------
+21/01/99 | JL Schwing | 1.11: Implement "-e ascii".
+---------+--------------+------------------------------------------------------
+26/02/99 | JL Schwing | 1.12: Improve strict ascii: reject more characters.
+---------+--------------+------------------------------------------------------
+26/02/99 | JL Schwing | 1.13: Quote (aka \) characters rather than reject.
+---------+--------------+------------------------------------------------------
+04/05/99 | JL Schwing | 1.14: Modify msgId*() to memorize attribs as well.
+---------+--------------+------------------------------------------------------
+19/05/99 | JL Schwing | 1.15: Implement "-e rename".
+ | Exit the thread if status==DEAD
+---------+--------------+------------------------------------------------------
+28/05/99 | JL Schwing | 1.16: Add new option -W (wait).
+---------+--------------+------------------------------------------------------
+06/03/00 | JL Schwing | 1.17: Test malloc() return value.
+---------+--------------+------------------------------------------------------
+18/08/00 | JL Schwing | 1.18: Print begin and end dates.
+---------+--------------+------------------------------------------------------
+25/08/00 | JL Schwing | 1.19: Implement consistent exit status...
+ | Fix some old legacy code.
+---------+--------------+------------------------------------------------------
+14/11/00 | JL Schwing | 1.20: Will now use utils.c functions.
+---------+--------------+------------------------------------------------------
+17/11/00 | JL Schwing | 1.21: Implement "-e smoothshutdown".
+ | Add new functions setThreadStatus() getThreadStatus().
+---------+--------------+------------------------------------------------------
+21/11/00 | JL Schwing | 1.22: Implement "-e attreplace=name:mask"
+---------+--------------+------------------------------------------------------
+29/11/00 | JL Schwing | 1.23: Port on NT 4.
+---------+--------------+------------------------------------------------------
+01/12/00 | JL Schwing | 1.24: Port on Linux.
+---------+--------------+------------------------------------------------------
+15/12/00 | JL Schwing | 1.25: Add more trace in VERY_VERBOSE mode.
+---------+--------------+------------------------------------------------------
+18/12/00 | JL Schwing | 1.26: Add new exit status EXIT_INIT.
+---------+--------------+------------------------------------------------------
+05/01/01 | JL Schwing | 1.27: Implement "-e randombinddn" and associated
+ | "-e randombinddnlow/high"
+---------+--------------+------------------------------------------------------
+08/01/01 | JL Schwing | 1.28: Implement "-e scalab01".
+---------+--------------+------------------------------------------------------
+12/01/01 | JL Schwing | 1.29: Include scalab01.h
+---------+--------------+------------------------------------------------------
+05/03/01 | JL Schwing | 1.30: Bug fix - crash SIGSEGV if no binDN provided.
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.31: Implement "-e commoncounter"
+ | Add new function incrementCommonCounter().
+---------+--------------+------------------------------------------------------
+14/03/01 | JL Schwing | 1.32: Implement "-e dontsleeponserverdown".
+---------+--------------+------------------------------------------------------
+15/03/01 | JL Schwing | 1.33: Implement "-e randomattrlist=name:name:name"
+ | Add new function selectRandomAttrList().
+---------+--------------+------------------------------------------------------
+19/03/01 | JL Schwing | 1.34: Implement "-e genldif=filename"
+---------+--------------+------------------------------------------------------
+23/03/01 | JL Schwing | 1.35: Implements "-e rdn=value".
+---------+--------------+------------------------------------------------------
+28/03/01 | JL Schwing | 1.36: Support -e commoncounter with -e rdn/object
+ | Add new function incrementCommonCounterObject().
+---------+--------------+------------------------------------------------------
+02/04/01 | JL Schwing | 1.37: Bug fix : large files support for -e genldif.
+---------+--------------+------------------------------------------------------
+11/04/01 | JL Schwing | 1.38: Implement [INCRFROMFILE<NOLOOP>(myfile)]
+---------+--------------+------------------------------------------------------
+03/05/01 | JL Schwing | 1.39: Implement -e randombinddnfromfile=filename.
+---------+--------------+------------------------------------------------------
+04/05/01 | JL Schwing | 1.40: Implement -e bindonly.
+---------+--------------+------------------------------------------------------
+*/
+
+#include <stdio.h> /* printf(), etc... */
+#include <string.h> /* strerror(), etc... */
+#include <stdlib.h> /* exit(), etc... */
+#include <ctype.h> /* isascii(), etc... */
+#include <errno.h> /* errno, etc... */ /*JLS 06-03-00*/
+#include <lber.h> /* ldap C-API BER declarations */
+#include <ldap.h> /* ldap C-API declarations */
+#ifndef _WIN32 /*JLS 29-11-00*/
+#include <unistd.h> /* close(), etc... */
+#include <pthread.h> /* pthreads(), etc... */
+#include <signal.h> /* sigfillset(), etc... */
+#endif /*JLS 29-11-00*/
+
+#include "port.h" /* Portability definitions */ /*JLS 29-11-00*/
+#include "ldclt.h" /* This tool's include file */
+#include "utils.h" /* Utilities functions */ /*JLS 14-11-00*/
+#include "scalab01.h" /* Scalab01 specific */ /*JLS 12-01-01*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /* New */ /*JLS 15-03-01*/
+/* ****************************************************************************
+ FUNCTION : selectRandomAttrList
+ PURPOSE : Select a random attr list.
+ INPUT : tttctx = this thread context
+ OUTPUT : None.
+ RETURN : The random list.
+ DESCRIPTION :
+ *****************************************************************************/
+char **
+selectRandomAttrList (
+ thread_context *tttctx)
+{
+ tttctx->attrlist[0] = mctx.attrlist[rndlim(0,mctx.attrlistNb-1)];
+ return (tttctx->attrlist);
+}
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : randomString
+ PURPOSE : Return a random string, of length nbDigits.
+ The string is returned in tttctx->buf2.
+ INPUT : tttctx = thread context.
+ nbDigits = number of digits required.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+randomString (
+ thread_context *tttctx,
+ int nbDigits)
+{
+ rndstr (tttctx->buf2, nbDigits); /*JLS 14-11-00*/
+ return (0);
+}
+
+
+
+
+
+
+
+ /* New */ /*JLS 28-03-01*/
+/* ****************************************************************************
+ FUNCTION : incrementCommonCounterObject
+ PURPOSE : Purpose of the fct
+ INPUT : tttctx = thread context
+ field = field to process
+ OUTPUT : None.
+ RETURN : -1 if error or end of loop (no_loop), new value else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+incrementCommonCounterObject (
+ thread_context *tttctx,
+ vers_field *field)
+{
+ int ret; /* Return value */
+ int val; /* New value */
+
+ /*
+ * Get mutex
+ */
+ if ((ret = ldclt_mutex_lock (&(field->cnt_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(field->cnt_mutex), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdId, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Compute next value
+ */
+ switch (field->how)
+ {
+ case HOW_INCR_FROM_FILE:
+ case HOW_INCR_NB:
+ if (field->cnt <= field->high) /* Limit not reached */
+ {
+ val = field->cnt;
+ field->cnt++;
+ }
+ else
+ {
+ val = field->low;
+ field->cnt = field->low + 1;
+ }
+ break;
+ case HOW_INCR_FROM_FILE_NL:
+ case HOW_INCR_NB_NOLOOP:
+ if (field->cnt <= field->high) /* Limit not reached */
+ {
+ val = field->cnt;
+ field->cnt++;
+ }
+ else
+ val = -1; /* Exit thread */
+ break;
+ default:
+ printf ("ldclt[%d]: %s: Illegal how=%d in incrementCommonCounterObject()\n",
+ mctx.pid, tttctx->thrdId, field->how);
+ val = -1;
+ break;
+ }
+
+ /*
+ * Free mutex
+ */
+ if ((ret = ldclt_mutex_unlock (&(field->cnt_mutex))) != 0)
+ {
+ fprintf(stderr,"ldclt[%d]: %s: cannot mutex_unlock(field->cnt_mutex), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdId, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Maybe a message to print ?
+ */
+ if (val < 0)
+ printf ("ldclt[%d]: %s: Hit top incrementeal value\n", mctx.pid, tttctx->thrdId);
+
+ return (val);
+}
+
+
+
+
+
+
+ /* New */ /*JLS 14-03-01*/
+/* ****************************************************************************
+ FUNCTION : incrementCommonCounter
+ PURPOSE : Purpose of the fct
+ INPUT : tttctx = thread context
+ OUTPUT : None.
+ RETURN : -1 if error or end of loop (no_loop), new value else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+incrementCommonCounter (
+ thread_context *tttctx)
+{
+ int ret; /* Return value */
+ int val; /* New value */
+
+ /*
+ * Get mutex
+ */
+ if ((ret = ldclt_mutex_lock (&(mctx.lastVal_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: T%03d: cannot mutex_lock(lastVal_mutex), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Compute next value
+ */
+ if ((mctx.mode & NOLOOP) && (mctx.lastVal == mctx.randomHigh))
+ val = -1;
+ else
+ {
+ mctx.lastVal++;
+ if (mctx.lastVal > mctx.randomHigh)
+ {
+ if (mctx.mode & NOLOOP)
+ val = -1;
+ else
+ mctx.lastVal = mctx.randomLow;
+ }
+ val = mctx.lastVal;
+ }
+
+ /*
+ * Free mutex
+ */
+ if ((ret = ldclt_mutex_unlock (&(mctx.lastVal_mutex))) != 0)
+ {
+ fprintf(stderr,"ldclt[%d]: T%03d: cannot mutex_unlock(lastVal_mutex), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Maybe a message to print ?
+ */
+ if (val < 0)
+ printf ("ldclt[%d]: T%03d: Hit top incrementeal value\n", mctx.pid, tttctx->thrdNum);
+
+ return (val);
+}
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : incrementNbOpers
+ PURPOSE : Increment the counters tttctx->nbOpers and
+ tttctx->totOpers of the given thread.
+ INPUT : tttctx = thread context.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+incrementNbOpers (
+ thread_context *tttctx)
+{
+ int ret; /* Return value */
+
+ /*
+ * Get mutex
+ */
+ if ((ret = ldclt_mutex_lock (&(tttctx->nbOpers_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: T%03d: cannot mutex_lock(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Increment counter
+ */
+ tttctx->nbOpers++;
+
+ /*
+ * Free mutex
+ */
+ if ((ret = ldclt_mutex_unlock (&(tttctx->nbOpers_mutex))) != 0)
+ {
+ fprintf (stderr, "ldclt[%d]: T%03d: cannot mutex_unlock(), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Increment total and check if max value reached
+ */
+ tttctx->totOpers++;
+ if(tttctx->totalReq > -1) {
+ if (tttctx->totOpers >= tttctx->totalReq) {
+ if (setThreadStatus(tttctx, MUST_SHUTDOWN) < 0) {
+ tttctx->status = DEAD; /* Force thread to die! */
+ }
+ }
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : ignoreError
+ PURPOSE : Returns true or false depending on the given error
+ should be ignored or not (option -I).
+ We will sleep() if an error about server down is to be
+ ignored.
+ INPUT : err = error number
+ OUTPUT : None.
+ RETURN : 1 if should be ignored, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+ignoreError (
+ int err)
+{
+ int i;
+ for (i=0 ; i<mctx.ignErrNb ; i++)
+ if (mctx.ignErr[i] == err)
+ { /*JLS 14-03-01*/
+ if ((!(mctx.mode & DONT_SLEEP_DOWN)) && /*JLS 14-03-01*/
+ ((err == LDAP_SERVER_DOWN) || /*JLS 14-03-01*/
+ (err == LDAP_CONNECT_ERROR))) /*JLS 14-03-01*/
+ ldclt_sleep (1); /*JLS 14-03-01*/
+ return (1);
+ } /*JLS 14-03-01*/
+ return (0);
+}
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : addErrorStat
+ PURPOSE : Add the given error number to the statistics.
+ INPUT : err = error number
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+addErrorStat (
+ int err)
+{
+ int ret; /* Return value */
+
+ /*
+ * Get mutex
+ */
+ if ((ret = ldclt_mutex_lock (&(mctx.errors_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "ldclt[%d]: Cannot mutex_lock(errors_mutex), error=%d (%s)\n",
+ mctx.pid, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Update the counters
+ */
+ if ((err <= 0) || (err >= MAX_ERROR_NB))
+ {
+ fprintf (stderr, "ldclt[%d]: Illegal error number %d\n", mctx.pid, err);
+ fflush (stderr);
+ mctx.errorsBad++;
+ }
+ else
+ mctx.errors[err]++;
+
+ /*
+ * Release the mutex
+ */
+ if ((ret = ldclt_mutex_unlock (&(mctx.errors_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "ldclt[%d]: Cannot mutex_unlock(errors_mutex), error=%d (%s)\n",
+ mctx.pid, ret, strerror (ret));
+ fflush (stderr);
+ return (-1);
+ }
+
+ /*
+ * Maybe we should ignore this error ?
+ */
+ if (!(ignoreError (err)))
+ {
+ /*
+ * Ok, we should not ignore this error...
+ * Maybe the limit is reached ?
+ */
+ if ((err <= 0) || (err >= MAX_ERROR_NB))
+ {
+ if (mctx.errorsBad > mctx.maxErrors)
+ {
+ printf ("ldclt[%d]: Max error limit reached - exiting.\n", mctx.pid);
+ (void) printGlobalStatistics(); /*JLS 25-08-00*/
+ fflush (stdout);
+ ldclt_sleep (5);
+ ldcltExit (EXIT_MAX_ERRORS); /*JLS 25-08-00*/
+ }
+ }
+ else
+ if (mctx.errors[err] > mctx.maxErrors)
+ {
+ printf ("ldclt[%d]: Max error limit reached - exiting.\n", mctx.pid);
+ (void) printGlobalStatistics(); /*JLS 25-08-00*/
+ fflush (stdout);
+ ldclt_sleep (5);
+ ldcltExit (EXIT_MAX_ERRORS); /*JLS 25-08-00*/
+ }
+ }
+
+ /*
+ * Normal end
+ */
+ return (0);
+}
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : msgIdAdd
+ PURPOSE : Add a new message id to the pending ones.
+ INPUT : tttctx = thread's context.
+ msgid = message id.
+ str = free string.
+ dn = dn of the entry
+ attribs = attributes
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+msgIdAdd (
+ thread_context *tttctx,
+ int msgid,
+ char *str,
+ char *dn,
+ LDAPMod **attribs)
+{
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: msgIdAdd (%d, %s)\n", mctx.pid, tttctx->thrdNum, msgid, str);
+
+ /*
+ * Add the new cell
+ */
+ if (tttctx->firstMsgId == NULL)
+ {
+ tttctx->firstMsgId = (msgid_cell *) malloc (sizeof (msgid_cell));
+ if (tttctx->firstMsgId == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->firstMsgId), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, errno, strerror (errno));
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ tttctx->lastMsgId = tttctx->firstMsgId;
+ }
+ else
+ {
+ tttctx->lastMsgId->next = (msgid_cell *) malloc (sizeof (msgid_cell));
+ if (tttctx->lastMsgId->next == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->lastMsgId->next), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, errno, strerror (errno));
+ return (-1); /*JLS 06-03-00*/
+ } /*JLS 06-03-00*/
+ tttctx->lastMsgId = tttctx->lastMsgId->next;
+ }
+
+ /*
+ * Memorize the information
+ */
+ tttctx->lastMsgId->next = NULL;
+ tttctx->lastMsgId->msgid = msgid;
+ strcpy (tttctx->lastMsgId->str, str);
+ strcpy (tttctx->lastMsgId->dn, dn);
+ tttctx->lastMsgId->attribs = attribs;
+
+ return (0);
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : msgIdAttribs
+ PURPOSE : Found the requested message id in the pending list.
+ INPUT : tttctx = thread's context
+ msgid = message id
+ OUTPUT : None
+ RETURN : The associated attributes, or NULL.
+ DESCRIPTION :
+ *****************************************************************************/
+LDAPMod **
+msgIdAttribs (
+ thread_context *tttctx,
+ int msgid)
+{
+ msgid_cell *pt;
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: msgIdAttribs (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
+
+ for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
+ if (pt->msgid == msgid)
+ return (pt->attribs);
+
+ return (NULL);
+}
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : msgIdDN
+ PURPOSE : Found the requested message id in the pending list.
+ INPUT : tttctx = thread's context
+ msgid = message id
+ OUTPUT : None
+ RETURN : The associated DN, or NULL.
+ DESCRIPTION :
+ *****************************************************************************/
+char *
+msgIdDN (
+ thread_context *tttctx,
+ int msgid)
+{
+ msgid_cell *pt;
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: msgIdDN (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
+
+ for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
+ if (pt->msgid == msgid)
+ return (pt->dn);
+
+ return (NULL);
+}
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : msgIdStr
+ PURPOSE : Found the requested message id in the pending list.
+ INPUT : tttctx = thread's context
+ msgid = message id
+ OUTPUT : None
+ RETURN : The associated str, or an error message string.
+ DESCRIPTION :
+ *****************************************************************************/
+char *
+msgIdStr (
+ thread_context *tttctx,
+ int msgid)
+{
+ msgid_cell *pt;
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: msgIdStr (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
+
+ for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
+ if (pt->msgid == msgid)
+ return (pt->str);
+
+ return ("Error: msgid not found");
+}
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : msgIdDel
+ PURPOSE : Delete a message id from the pending ones.
+ INPUT : tttctx = thread's context
+ msgid = message id.
+ freeAttr= true or false depending on freing the attribs
+ OUTPUT : None.
+ RETURN : -1 if not found, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+msgIdDel (
+ thread_context *tttctx,
+ int msgid,
+ int freeAttr)
+{
+ msgid_cell *pt; /* For the loop */
+ msgid_cell *ptToFree; /* The cell to free */
+
+ if (mctx.mode & VERY_VERBOSE)
+ printf ("ldclt[%d]: T%03d: msgIdDel (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
+
+ /*
+ * Make sure there is a list !
+ */
+ if (tttctx->firstMsgId != NULL)
+ {
+ /*
+ * Maybe it is the first one ?
+ */
+ if (tttctx->firstMsgId->msgid == msgid)
+ {
+ ptToFree = tttctx->firstMsgId;
+ tttctx->firstMsgId = tttctx->firstMsgId->next;
+ if (tttctx->firstMsgId == NULL)
+ tttctx->lastMsgId = NULL;
+ free (ptToFree);
+ return (0);
+ }
+
+ /*
+ * Let's go through the whole list
+ */
+ for (pt = tttctx->firstMsgId ; pt->next != NULL ; pt = pt->next)
+ if (pt->next->msgid == msgid)
+ {
+ /*
+ * Be carrefull if it is the last element of the list
+ */
+ if (pt->next->next == NULL)
+ tttctx->lastMsgId = pt;
+ ptToFree = pt->next;
+ pt->next = ptToFree->next;
+ if (freeAttr)
+ if (freeAttrib (ptToFree->attribs) < 0)
+ return (-1);
+
+ /*
+ * Free the pointer itself
+ */
+ free (ptToFree);
+ return (0);
+ }
+ }
+
+ /*
+ * Not found
+ */
+ printf ("ldclt[%d]: T%03d: message %d not found.\n", mctx.pid, tttctx->thrdNum, msgid);
+ fflush (stdout);
+ return (-1);
+}
+
+
+
+
+
+
+
+
+ /* New function */ /*JLS 17-11-00*/
+/* ****************************************************************************
+ FUNCTION : getThreadStatus
+ PURPOSE : Get the value of a given thread's status.
+ INPUT : tttctx = thread context
+ OUTPUT : status = the thread's status
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+getThreadStatus (
+ thread_context *tttctx,
+ int *status)
+{
+ int ret; /* Return code */
+
+ if ((ret = ldclt_mutex_lock (&(tttctx->status_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "ldclt[%d]: Cannot mutex_lock(T%03d), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, strerror (ret));
+ fprintf (stderr, "ldclt[%d]: Problem in getThreadStatus()\n", mctx.pid);
+ fflush (stderr);
+ return (-1);
+ }
+ *status = tttctx->status;
+ if ((ret = ldclt_mutex_unlock (&(tttctx->status_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "ldclt[%d]: Cannot mutex_unlock(T%03d), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, strerror (ret));
+ fprintf (stderr, "ldclt[%d]: Problem in getThreadStatus()\n", mctx.pid);
+ fflush (stderr);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+
+
+
+ /* New function */ /*JLS 17-11-00*/
+/* ****************************************************************************
+ FUNCTION : setThreadStatus
+ PURPOSE : Set the value of a given thread's status.
+ INPUT : tttctx = thread context
+ status = new status
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+setThreadStatus (
+ thread_context *tttctx,
+ int status)
+{
+ int ret; /* Return code */
+
+ if ((ret = ldclt_mutex_lock (&(tttctx->status_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "ldclt[%d]: Cannot mutex_lock(T%03d), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, strerror (ret));
+ fprintf (stderr, "ldclt[%d]: Problem in setThreadStatus()\n", mctx.pid);
+ fflush (stderr);
+ return (-1);
+ }
+ tttctx->status = status;
+ if ((ret = ldclt_mutex_unlock (&(tttctx->status_mutex))) != 0)
+ {
+ fprintf (stderr,
+ "ldclt[%d]: Cannot mutex_unlock(T%03d), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, ret, strerror (ret));
+ fprintf (stderr, "ldclt[%d]: Problem in setThreadStatus()\n", mctx.pid);
+ fflush (stderr);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : threadMain
+ PURPOSE : This function is the main function of the client threads
+ part of this tool.
+ INPUT : arg = this thread's thread_context
+ OUTPUT : None.
+ RETURN : None.
+ DESCRIPTION :
+ *****************************************************************************/
+void *
+threadMain (
+ void *arg)
+{
+ thread_context *tttctx; /* This thread's context */
+ int go = 1; /* Thread must continue */
+ int status; /* Thread's status */ /*JLS 17-11-00*/
+
+ /*
+ * Initialization
+ */
+ tttctx = (thread_context *) arg;
+ if (setThreadStatus (tttctx, CREATED) < 0) /*JLS 17-11-00*/
+ { /*JLS 17-11-00*/
+ tttctx->status = DEAD; /*JLS 17-11-00*/
+ return NULL; /*JLS 17-11-00*/
+ } /*JLS 17-11-00*/
+ tttctx->asyncHit = 0;
+ tttctx->binded = 0;
+ tttctx->fd = -1;
+ tttctx->lastVal = mctx.randomLow-1;
+ tttctx->ldapCtx = NULL;
+ tttctx->matcheddnp = NULL; /*JLS 15-12-00*/
+ tttctx->nbOpers = 0;
+ tttctx->totOpers = 0;
+ tttctx->pendingNb = 0;
+ tttctx->firstMsgId = NULL;
+ tttctx->lastMsgId = NULL;
+
+ /*
+ * Don't forget the buffers !!
+ * This should save time while redoing random values
+ */
+ if ((mctx.mode & NEED_FILTER) || (mctx.mod2 & M2_GENLDIF)) /*JLS 19-03-01*/
+ {
+ if (mctx.mod2 & M2_RDN_VALUE) /*JLS 23-03-01*/
+ tttctx->bufFilter = (char *) malloc (MAX_FILTER); /*JLS 23-03-01*/
+ else /*JLS 23-03-01*/
+ { /*JLS 23-03-01*/
+ /*
+ * Variable filter ?
+ */
+ tttctx->bufFilter = (char *) malloc (strlen (mctx.filter) + 1);
+ if (tttctx->bufFilter == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("ldclt[%d]: %s: cannot malloc(tttctx->bufFilter), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdId, errno, strerror (errno));
+ ldcltExit (EXIT_INIT); /*JLS 18-12-00*/
+ } /*JLS 06-03-00*/
+ if (!(mctx.mode & (RANDOM | INCREMENTAL)))
+ strcpy (tttctx->bufFilter, mctx.filter);
+ else
+ {
+ tttctx->startRandom = strlen (mctx.randomHead);
+ strcpy (tttctx->bufFilter, mctx.randomHead);
+ strcpy (&(tttctx->bufFilter[tttctx->startRandom+mctx.randomNbDigit]),
+ mctx.randomTail);
+ if (mctx.mode & VERY_VERBOSE)
+ {
+ printf ("ldclt[%d]: %s: startRandom = %d\n",
+ mctx.pid, tttctx->thrdId, tttctx->startRandom);
+ printf ("ldclt[%d]: %s: randomHead = \"%s\", randomTail = \"%s\"\n",
+ mctx.pid, tttctx->thrdId, mctx.randomHead, mctx.randomTail);
+ }
+ }
+ } /*JLS 23-03-01*/
+
+ /*
+ * Variable base DN ?
+ */
+ tttctx->bufBaseDN = (char *) malloc (strlen (mctx.baseDN) + 1);
+ if (tttctx->bufBaseDN == NULL) /*JLS 06-03-00*/
+ { /*JLS 06-03-00*/
+ printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufBaseDN), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, errno, strerror (errno));
+ ldcltExit (EXIT_INIT); /*JLS 18-12-00*/
+ } /*JLS 06-03-00*/
+ if (!(mctx.mode & RANDOM_BASE))
+ strcpy (tttctx->bufBaseDN, mctx.baseDN);
+ else
+ {
+ tttctx->startBaseDN = strlen (mctx.baseDNHead);
+ strcpy (tttctx->bufBaseDN, mctx.baseDNHead);
+ strcpy (&(tttctx->bufBaseDN[tttctx->startBaseDN+mctx.baseDNNbDigit]),
+ mctx.baseDNTail);
+ }
+
+ /*
+ * Variable bind DN ?
+ * Do not forget the random bind password below that is activated
+ * at the same time as the random bind DN.
+ */
+ if (mctx.bindDN != NULL) /*JLS 05-03-01*/
+ { /*JLS 05-03-01*/
+ tttctx->bufBindDN = (char *) malloc (strlen (mctx.bindDN) + 1);
+ if (tttctx->bufBindDN == NULL)
+ {
+ printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufBindDN), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, errno, strerror (errno));
+ ldcltExit (EXIT_INIT);
+ }
+ if (!(mctx.mode & RANDOM_BINDDN))
+ strcpy (tttctx->bufBindDN, mctx.bindDN);
+ else
+ {
+ tttctx->startBindDN = strlen (mctx.bindDNHead);
+ strcpy (tttctx->bufBindDN, mctx.bindDNHead);
+ strcpy (&(tttctx->bufBindDN[tttctx->startBindDN+mctx.bindDNNbDigit]),
+ mctx.bindDNTail);
+ }
+ } /*JLS 05-03-01*/
+
+ /*
+ * Variable bind password ?
+ * Remember that the random bind password feature is activated
+ * by the same option as the random bind DN, but has here its own
+ * code section for the ease of coding.
+ */
+ if (mctx.passwd != NULL) /*JLS 05-03-01*/
+ { /*JLS 05-03-01*/
+ tttctx->bufPasswd = (char *) malloc (strlen (mctx.passwd) + 1);
+ if (tttctx->bufPasswd == NULL)
+ {
+ printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufPasswd), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, errno, strerror (errno));
+ ldcltExit (EXIT_INIT);
+ }
+ if (!(mctx.mode & RANDOM_BINDDN))
+ strcpy (tttctx->bufPasswd, mctx.passwd);
+ else
+ {
+ tttctx->startPasswd = strlen (mctx.passwdHead);
+ strcpy (tttctx->bufPasswd, mctx.passwdHead);
+ strcpy (&(tttctx->bufPasswd[tttctx->startPasswd+mctx.passwdNbDigit]),
+ mctx.passwdTail);
+ }
+ }
+ } /*JLS 05-03-01*/
+
+ /*
+ * Bind DN from a file ?
+ * The trick (mctx.passwd = "foo bar"; ) is needed to
+ * simplify the code, because in many places we check
+ * if mctx.passwd exist before sending password.
+ */
+ if (mctx.mod2 & M2_RNDBINDFILE) /*JLS 03-05-01*/
+ { /*JLS 03-05-01*/
+ tttctx->bufBindDN = (char *) malloc (MAX_DN_LENGTH); /*JLS 03-05-01*/
+ tttctx->bufPasswd = (char *) malloc (MAX_DN_LENGTH); /*JLS 03-05-01*/
+ mctx.passwd = "foo bar"; /* trick... */ /*JLS 03-05-01*/
+ } /*JLS 03-05-01*/
+
+ /*
+ * Initiates the attribute replace buffers
+ */
+ if (mctx.mode & ATTR_REPLACE) /* New */ /*JLS 21-11-00*/
+ {
+ tttctx->bufAttrpl = (char *) malloc (strlen (mctx.attrpl) + 1);
+ if (tttctx->bufAttrpl == NULL)
+ {
+ printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufAttrpl), error=%d (%s)\n",
+ mctx.pid, tttctx->thrdNum, errno, strerror (errno));
+ ldcltExit (EXIT_INIT); /*JLS 18-12-00*/
+ }
+ tttctx->startAttrpl = strlen (mctx.attrplHead);
+ strcpy (tttctx->bufAttrpl, mctx.attrplHead);
+ strcpy (&(tttctx->bufAttrpl[tttctx->startAttrpl+mctx.attrplNbDigit]),
+ mctx.attrplTail);
+ }
+
+ /*
+ * We are ready to go !
+ */
+ status = RUNNING; /*JLS 17-11-00*/
+ if (setThreadStatus (tttctx, RUNNING) < 0) /*JLS 17-11-00*/
+ status = DEAD; /*JLS 17-11-00*/
+
+ /*
+ * Let's go !
+ */
+ while (go && (status != DEAD) && (status != MUST_SHUTDOWN)) /*JLS 17-11-00*/
+ {
+ if (mctx.waitSec > 0)
+ { /*JLS 17-11-00*/
+ ldclt_sleep (mctx.waitSec);
+
+ /*
+ * Maybe we should shutdown ?
+ */
+ if (getThreadStatus (tttctx, &status) < 0) /*JLS 17-11-00*/
+ break; /*JLS 17-11-00*/
+ if (status == MUST_SHUTDOWN) /*JLS 17-11-00*/
+ break; /*JLS 17-11-00*/
+ } /*JLS 17-11-00*/
+
+ /*
+ * Do a LDAP request
+ */
+ if (tttctx->mode & ADD_ENTRIES)
+ if (doAddEntry (tttctx) < 0)
+ {
+ go = 0;
+ continue;
+ }
+ if (tttctx->mode & ATTR_REPLACE) /*JLS 21-11-00*/
+ if (doAttrReplace (tttctx) < 0) /*JLS 21-11-00*/
+ { /*JLS 21-11-00*/
+ go = 0; /*JLS 21-11-00*/
+ continue; /*JLS 21-11-00*/
+ } /*JLS 21-11-00*/
+ if (tttctx->mode & DELETE_ENTRIES)
+ if (doDeleteEntry (tttctx) < 0)
+ {
+ go = 0;
+ continue;
+ }
+ if (mctx.mod2 & M2_BINDONLY) /*JLS 04-05-01*/
+ if (doBindOnly (tttctx) < 0) /*JLS 04-05-01*/
+ { /*JLS 04-05-01*/
+ go = 0; /*JLS 04-05-01*/
+ continue; /*JLS 04-05-01*/
+ } /*JLS 04-05-01*/
+ if (tttctx->mode & EXACT_SEARCH)
+ if (doExactSearch (tttctx) < 0)
+ {
+ go = 0;
+ continue;
+ }
+ if (tttctx->mode & RENAME_ENTRIES)
+ if (doRename (tttctx) < 0)
+ {
+ go = 0;
+ continue;
+ }
+
+ /*
+ * Maybe a specific scenario ?
+ */
+ if (tttctx->mode & SCALAB01) /*JLS 08-01-01*/
+ if (doScalab01 (tttctx) < 0) /*JLS 08-01-01*/
+ { /*JLS 08-01-01*/
+ go = 0; /*JLS 08-01-01*/
+ continue; /*JLS 08-01-01*/
+ } /*JLS 08-01-01*/
+
+ /*
+ * Maybe genldif mode ?
+ */
+ if (mctx.mod2 & M2_GENLDIF) /*JLS 19-03-01*/
+ if (doGenldif (tttctx) < 0) /*JLS 19-03-01*/
+ { /*JLS 19-03-01*/
+ ldclt_flush_genldif(); /*JLS 02-04-01*/
+ go = 0; /*JLS 19-03-01*/
+ continue; /*JLS 19-03-01*/
+ } /*JLS 19-03-01*/
+
+ /*
+ * Check the thread's status
+ */
+ if (getThreadStatus (tttctx, &status) < 0) /*JLS 17-11-00*/
+ break; /*JLS 17-11-00*/
+ }
+
+ /*
+ * End of thread
+ */
+ /* [156984] once setting "DEAD", nothing should be done in the context */
+ /* moved the dead message above setThreadStatus(DEAD) */
+ printf ("ldclt[%d]: T%03d: thread is dead.\n", mctx.pid, tttctx->thrdNum);
+ fflush (stdout);
+ if (setThreadStatus (tttctx, DEAD) < 0) /*JLS 17-11-00*/
+ { /*JLS 17-11-00*/
+ ldclt_sleep (1); /*JLS 17-11-00*/
+ tttctx->status = DEAD; /* Force it !!! */ /*JLS 17-11-00*/
+ } /*JLS 17-11-00*/
+ return (arg);
+}
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/utils.c b/ldap/servers/slapd/tools/ldclt/utils.c
new file mode 100644
index 00000000..54b6c150
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/utils.c
@@ -0,0 +1,337 @@
+#ident "ldclt @(#)utils.c 1.4 01/01/11"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : utils.c
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 14 November 2000
+ DESCRIPTION :
+ This file contains the utilities functions that will be
+ used as well by ldclt and by the genldif command, e.g.
+ the random generator functions, etc...
+ The main target/reason for creating this file is to be
+ able to easely separate these functions from ldclt's
+ framework and data structures, and thus to provide a
+ kind of library suitable for any command.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+14/11/00 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+14/11/00 | JL Schwing | 1.2 : Port on AIX.
+---------+--------------+------------------------------------------------------
+16/11/00 | JL Schwing | 1.3 : lint cleanup.
+---------+--------------+------------------------------------------------------
+11/01/01 | JL Schwing | 1.4 : Add new function rndlim().
+---------+--------------+------------------------------------------------------
+*/
+
+#include "utils.h" /* Basic definitions for this file */
+#include <stdio.h> /* sprintf(), etc... */
+#include <stdlib.h> /* lrand48(), etc... */
+#include <ctype.h> /* isascii(), etc... */ /*JLS 16-11-00*/
+#include <string.h> /* strerror(), etc... */ /*JLS 14-11-00*/
+
+
+/*
+ * Some global variables...
+ */
+#ifdef AIX
+pthread_mutex_t ldcltrand48_mutex; /* ldcltrand48() */ /*JLS 14-11-00*/
+#endif
+
+
+#ifdef AIX /* New */ /*JLS 14-11-00*/
+/* ****************************************************************************
+ FUNCTION : ldcltrand48
+ PURPOSE : Implement a thread-save version of lrand48()
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : A random value.
+ DESCRIPTION :
+ *****************************************************************************/
+long int
+ldcltrand48 (void)
+{
+ long int val;
+ int ret;
+
+ if ((ret = pthread_mutex_lock (&ldcltrand48_mutex)) != 0)
+ {
+ fprintf (stderr,
+ "Cannot pthread_mutex_lock(ldcltrand48_mutex), error=%d (%s)\n",
+ ret, strerror (ret));
+ fflush (stderr);
+ ldcltExit (99);
+ }
+ val = lrand48();
+ if ((ret = pthread_mutex_unlock (&ldcltrand48_mutex)) != 0)
+ {
+ fprintf (stderr,
+ "Cannot pthread_mutex_unlock(ldcltrand48_mutex), error=%d (%s)\n",
+ ret, strerror (ret));
+ fflush (stderr);
+ ldcltExit (99);
+ }
+
+ return (val);
+}
+
+#else /* AIX */
+#define ldcltrand48() lrand48()
+#endif /* AIX */
+
+
+/* ****************************************************************************
+ FUNCTION : utilsInit
+ PURPOSE : Initiates the utilities functions.
+ INPUT : None.
+ OUTPUT : None.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+utilsInit (void)
+{
+#ifdef AIX /*JLS 14-11-00*/
+ int ret; /*JLS 14-11-00*/
+
+ /*
+ * Initiate the mutex that protect ldcltrand48()
+ */
+ if ((ret = pthread_mutex_init(&ldcltrand48_mutex, NULL)) != 0)/*JLS 14-11-00*/
+ { /*JLS 14-11-00*/
+ fprintf (stderr, "ldclt: %s\n", strerror (ret)); /*JLS 14-11-00*/
+ fprintf (stderr, /*JLS 14-11-00*/
+ "Error: cannot initiate ldcltrand48_mutex\n"); /*JLS 14-11-00*/
+ fflush (stderr); /*JLS 14-11-00*/
+ return (-1); /*JLS 14-11-00*/
+ } /*JLS 14-11-00*/
+#endif /*JLS 14-11-00*/
+
+ /*
+ * No error
+ */
+ return (0);
+}
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : rndlim
+ PURPOSE : Returns a random number between the given limits.
+ INPUT : low = low limit
+ high = high limit
+ OUTPUT : None.
+ RETURN : The random value.
+ DESCRIPTION :
+ *****************************************************************************/
+int
+rndlim (
+ int low,
+ int high)
+{
+ return (low + ldcltrand48() % (high-low+1));
+}
+
+
+
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : rnd
+ PURPOSE : Creates a random number string between the given
+ arguments. The string is returned in the buffer.
+ INPUT : low = low limit
+ high = high limit
+ ndigits = number of digits
+ OUTPUT : buf = buffer to write the random string. Note that
+ it is generated with fixed number of digits,
+ completed with leading '0'.
+ RETURN : None.
+ DESCRIPTION :
+ *****************************************************************************/
+void
+rnd (
+ char *buf,
+ int low,
+ int high,
+ int ndigits)
+{
+ sprintf (buf, "%0*d", ndigits,
+ (int)(low + (ldcltrand48() % (high-low+1)))); /*JLS 14-11-00*/
+}
+
+
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : rndstr
+ PURPOSE : Return a random string, of length ndigits. The string
+ is returned in the buf.
+ INPUT : ndigits = number of digits required.
+ OUTPUT : buf = the buf must be long enough to contain the
+ requested string.
+ RETURN : None.
+ DESCRIPTION :
+ *****************************************************************************/
+void
+rndstr (
+ char *buf,
+ int ndigits)
+{
+ unsigned int rndNum; /* The random value */
+ int charNum; /* Random char in buf */
+ int byteNum; /* Byte in rndNum */
+ char newChar; /* The new byte as a char */
+ char *rndArray; /* To cast the rndNum into chars */
+
+ charNum = 0;
+ byteNum = 4;
+ rndArray = (char *)(&rndNum);
+ while (charNum < ndigits)
+ {
+ /*
+ * Maybe we should generate a new random number ?
+ */
+ if (byteNum == 4)
+ {
+ rndNum = ldcltrand48(); /*JLS 14-11-00*/
+ byteNum = 0;
+ }
+
+ /*
+ * Is it a valid char ?
+ */
+ newChar = rndArray[byteNum];
+
+ /*
+ * The last char must not be a '\' nor a space.
+ */
+ if (!(((charNum+1) == ndigits) &&
+ ((newChar == '\\') || (newChar == ' '))))
+ {
+ /*
+ * First, there are some special characters that have a meaning for
+ * LDAP, and thus that must be quoted. What LDAP's rfc1779 means by
+ * "to quote" may be translated by "to antislash"
+ * Note: we do not check the \ because in this way, it leads to randomly
+ * quote some valid characters.
+ */
+ if ((newChar == '=') || (newChar == ';') || (newChar == ',') ||
+ (newChar == '+') || (newChar == '"') || (newChar == '<') ||
+ (newChar == '>') || (newChar == '#'))
+ {
+ /*
+ * Ensure that the previous char is *not* a \ otherwise
+ * it will result in a \\, rather than a \,
+ * If it is the case, add one more \ to have \\\,
+ */
+ if ((charNum > 0) && (buf[charNum-1] == '\\'))
+ {
+ if ((charNum+3) < ndigits)
+ {
+ buf[charNum++] = '\\';
+ buf[charNum++] = '\\';
+ buf[charNum++] = newChar;
+ }
+ }
+ else
+ {
+ if ((charNum+2) < ndigits)
+ {
+ buf[charNum++] = '\\';
+ buf[charNum++] = newChar;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Maybe strict ascii required ?
+ */
+ if (1)
+ {
+ if (isascii (newChar) && !iscntrl(newChar))
+ buf[charNum++] = newChar;
+ }
+ else
+ {
+ if (((newChar >= 0x30) && (newChar <= 0x7a)) ||
+ ((newChar >= 0xc0) && (newChar <= 0xf6)))
+ buf[charNum++] = newChar;
+ }
+ }
+ }
+
+ /*
+ * Next byte of the random value.
+ */
+ byteNum++;
+ }
+
+ /*
+ * End of function
+ */
+ buf[charNum] = '\0';
+}
+
+
+
+
+
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/utils.h b/ldap/servers/slapd/tools/ldclt/utils.h
new file mode 100644
index 00000000..37f7a934
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/utils.h
@@ -0,0 +1,76 @@
+#ident "ldclt @(#)utils.h 1.3 01/01/11"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : utils.h
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 14 November 2000
+ DESCRIPTION :
+ This files contians the prototypes and other
+ definitions related to utils.c, utilities functions
+ that will be used as well by ldclt and by the genldif
+ command.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+14/11/00 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+16/11/00 | JL Schwing | 1.2 : Fix typo.
+---------+--------------+------------------------------------------------------
+11/01/01 | JL Schwing | 1.3 : Add new function rndlim().
+---------+--------------+------------------------------------------------------
+*/
+
+
+
+
+/*
+ * Functions exported by utils.c
+ */
+extern void rnd (char *buf, int low, int high, int ndigits);
+extern int rndlim (int low, int high);
+extern void rndstr (char *buf, int ndigits);
+extern int utilsInit (void);
+
+
+/* End of file */
diff --git a/ldap/servers/slapd/tools/ldclt/version.c b/ldap/servers/slapd/tools/ldclt/version.c
new file mode 100644
index 00000000..0c74d631
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/version.c
@@ -0,0 +1 @@
+char *ldcltVersion="4.23";
diff --git a/ldap/servers/slapd/tools/ldclt/workarounds.c b/ldap/servers/slapd/tools/ldclt/workarounds.c
new file mode 100644
index 00000000..85d96dea
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldclt/workarounds.c
@@ -0,0 +1,110 @@
+#ident "ldclt @(#)workarounds.c 1.5 00/12/01"
+
+/** BEGIN COPYRIGHT BLOCK
+ * This Program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * In addition, as a special exception, Red Hat, Inc. gives You the additional
+ * right to link the code of this Program with code not covered under the GNU
+ * General Public License ("Non-GPL Code") and to distribute linked combinations
+ * including the two, subject to the limitations in this paragraph. Non-GPL Code
+ * permitted under this exception must only link to the code of this Program
+ * through those well defined interfaces identified in the file named EXCEPTION
+ * found in the source code files (the "Approved Interfaces"). The files of
+ * Non-GPL Code may instantiate templates or use macros or inline functions from
+ * the Approved Interfaces without causing the resulting work to be covered by
+ * the GNU General Public License. Only Red Hat, Inc. may make changes or
+ * additions to the list of Approved Interfaces. You must obey the GNU General
+ * Public License in all respects for all of the Program code and other code used
+ * in conjunction with the Program except the Non-GPL Code covered by this
+ * exception. If you modify this file, you may extend this exception to your
+ * version of the file, but you are not obligated to do so. If you do not wish to
+ * provide this exception without modification, you must delete this exception
+ * statement from your version and license this file solely under the GPL without
+ * exception.
+ *
+ *
+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+ * Copyright (C) 2006 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ FILE : workarounds.c
+ AUTHOR : Jean-Luc SCHWING
+ VERSION : 1.0
+ DATE : 15 December 1998
+ DESCRIPTION :
+ This file contains special work-arounds targetted to
+ fix, or work-around, the various bugs that may appear
+ in Solaris 2.7 libldap.
+ LOCAL : None.
+ HISTORY :
+---------+--------------+------------------------------------------------------
+dd/mm/yy | Author | Comments
+---------+--------------+------------------------------------------------------
+15/12/98 | JL Schwing | Creation
+---------+--------------+------------------------------------------------------
+19/09/00 | JL Schwing | 1.2: Port on Netscape's libldap. This is realized in
+ | such a way that this library become the default
+ | way so a ifdef for Solaris will be used...
+---------+--------------+------------------------------------------------------
+16/11/00 | JL Schwing | 1.3 : lint cleanup.
+-----------------------------------------------------------------------------
+29/11/00 | JL Schwing | 1.4 : Port on NT 4.
+---------+--------------+------------------------------------------------------
+01/12/00 | JL Schwing | 1.5 : Port on Linux.
+---------+--------------+------------------------------------------------------
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h> /* exit(), ... */ /*JLS 16-11-00*/
+#include "lber.h"
+#include "ldap.h"
+#ifdef SOLARIS_LIBLDAP /*JLS 19-09-00*/
+#include "ldap-private.h"
+#else /*JLS 19-09-00*/
+#ifndef _WIN32 /*JLS 01-12-00*/
+#include <pthread.h> /*JLS 01-12-00*/
+#endif /*JLS 01-12-00*/
+#include "port.h" /* Portability definitions */ /*JLS 29-11-00*/
+#include "ldclt.h" /*JLS 19-09-00*/
+#endif /*JLS 19-09-00*/
+
+
+
+
+/* ****************************************************************************
+ FUNCTION : getFdFromLdapSession
+ PURPOSE : This function is a work-around for the bug 4197228
+ that is not expected to be fixed soon...
+ INPUT : ld = ldap session to process.
+ OUTPUT : fd = the corresponding fd.
+ RETURN : -1 if error, 0 else.
+ DESCRIPTION :
+ *****************************************************************************/
+int getFdFromLdapSession (
+ LDAP *ld,
+ int *fd)
+{
+#ifdef SOLARIS_LIBLDAP /*JLS 19-09-00*/
+ *fd = ld->ld_sb.sb_sd;
+ return (0);
+#else /*JLS 19-09-00*/
+ printf("Error : getFdFromLdapSession() not implemented...\n");/*JLS 19-09-00*/
+ exit (EXIT_OTHER); /*JLS 19-09-00*/
+#endif /*JLS 19-09-00*/
+}
+
+
+/* End of file */