diff options
author | Noriko Hosoi <nhosoi@redhat.com> | 2006-01-11 01:54:47 +0000 |
---|---|---|
committer | Noriko Hosoi <nhosoi@redhat.com> | 2006-01-11 01:54:47 +0000 |
commit | 84a1a5302b42d43575922e65393668e03998d24b (patch) | |
tree | 6791a2768149bfc88f08f3a40300ab75418045dd | |
parent | 67385d898398f60886047b9239d027cf997f9433 (diff) | |
download | ds-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.
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 */ |