1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1999-2011 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
10 *
11 * A copy of this license is available in file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
14 */
15/* ACKNOWLEDGEMENTS:
16 * This work was initially developed by Kurt Spanier for inclusion
17 * in OpenLDAP Software.
18 */
19
20#include "portable.h"
21
22#include <stdio.h>
23
24#include "ac/stdlib.h"
25
26#include "ac/ctype.h"
27#include "ac/param.h"
28#include "ac/socket.h"
29#include "ac/string.h"
30#include "ac/unistd.h"
31#include "ac/wait.h"
32
33#include "ldap.h"
34#include "lutil.h"
35
36#include "slapd-common.h"
37
38#define LOOPS	100
39#define RETRIES	0
40
41static char *
42get_add_entry( char *filename, LDAPMod ***mods );
43
44static void
45do_addel( char *uri, char *manager, struct berval *passwd,
46	char *dn, LDAPMod **attrs, int maxloop, int maxretries, int delay,
47	int friendly, int chaserefs );
48
49static void
50usage( char *name )
51{
52        fprintf( stderr,
53		"usage: %s "
54		"-H <uri> | ([-h <host>] -p <port>) "
55		"-D <manager> "
56		"-w <passwd> "
57		"-f <addfile> "
58		"[-i <ignore>] "
59		"[-l <loops>] "
60		"[-L <outerloops>] "
61		"[-r <maxretries>] "
62		"[-t <delay>] "
63		"[-F] "
64		"[-C]\n",
65			name );
66	exit( EXIT_FAILURE );
67}
68
69int
70main( int argc, char **argv )
71{
72	int		i;
73	char		*host = "localhost";
74	char		*uri = NULL;
75	int		port = -1;
76	char		*manager = NULL;
77	struct berval	passwd = { 0, NULL };
78	char		*filename = NULL;
79	char		*entry = NULL;
80	int		loops = LOOPS;
81	int		outerloops = 1;
82	int		retries = RETRIES;
83	int		delay = 0;
84	int		friendly = 0;
85	int		chaserefs = 0;
86	LDAPMod		**attrs = NULL;
87
88	tester_init( "slapd-addel", TESTER_ADDEL );
89
90	while ( ( i = getopt( argc, argv, "CD:Ff:H:h:i:L:l:p:r:t:w:" ) ) != EOF )
91	{
92		switch ( i ) {
93		case 'C':
94			chaserefs++;
95			break;
96
97		case 'F':
98			friendly++;
99			break;
100
101		case 'H':		/* the server's URI */
102			uri = strdup( optarg );
103			break;
104
105		case 'h':		/* the servers host */
106			host = strdup( optarg );
107			break;
108
109		case 'i':
110			/* ignored (!) by now */
111			break;
112
113		case 'p':		/* the servers port */
114			if ( lutil_atoi( &port, optarg ) != 0 ) {
115				usage( argv[0] );
116			}
117			break;
118
119		case 'D':		/* the servers manager */
120			manager = strdup( optarg );
121			break;
122
123		case 'w':		/* the server managers password */
124			passwd.bv_val = strdup( optarg );
125			passwd.bv_len = strlen( optarg );
126			memset( optarg, '*', passwd.bv_len );
127			break;
128
129		case 'f':		/* file with entry search request */
130			filename = strdup( optarg );
131			break;
132
133		case 'l':		/* the number of loops */
134			if ( lutil_atoi( &loops, optarg ) != 0 ) {
135				usage( argv[0] );
136			}
137			break;
138
139		case 'L':		/* the number of outerloops */
140			if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
141				usage( argv[0] );
142			}
143			break;
144
145		case 'r':		/* number of retries */
146			if ( lutil_atoi( &retries, optarg ) != 0 ) {
147				usage( argv[0] );
148			}
149			break;
150
151		case 't':		/* delay in seconds */
152			if ( lutil_atoi( &delay, optarg ) != 0 ) {
153				usage( argv[0] );
154			}
155			break;
156
157		default:
158			usage( argv[0] );
159			break;
160		}
161	}
162
163	if (( filename == NULL ) || ( port == -1 && uri == NULL ) ||
164				( manager == NULL ) || ( passwd.bv_val == NULL ))
165		usage( argv[0] );
166
167	entry = get_add_entry( filename, &attrs );
168	if (( entry == NULL ) || ( *entry == '\0' )) {
169
170		fprintf( stderr, "%s: invalid entry DN in file \"%s\".\n",
171				argv[0], filename );
172		exit( EXIT_FAILURE );
173
174	}
175
176	if (( attrs == NULL ) || ( *attrs == '\0' )) {
177
178		fprintf( stderr, "%s: invalid attrs in file \"%s\".\n",
179				argv[0], filename );
180		exit( EXIT_FAILURE );
181
182	}
183
184	uri = tester_uri( uri, host, port );
185
186	for ( i = 0; i < outerloops; i++ ) {
187		do_addel( uri, manager, &passwd, entry, attrs,
188				loops, retries, delay, friendly, chaserefs );
189	}
190
191	exit( EXIT_SUCCESS );
192}
193
194
195static void
196addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen )
197{
198    LDAPMod		**pmods;
199    int			i, j;
200    struct berval	*bvp;
201
202    pmods = *pmodsp;
203    modop |= LDAP_MOD_BVALUES;
204
205    i = 0;
206    if ( pmods != NULL ) {
207		for ( ; pmods[ i ] != NULL; ++i ) {
208	    	if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
209		    	pmods[ i ]->mod_op == modop ) {
210				break;
211	    	}
212		}
213    }
214
215    if ( pmods == NULL || pmods[ i ] == NULL ) {
216		if (( pmods = (LDAPMod **)realloc( pmods, (i + 2) *
217			sizeof( LDAPMod * ))) == NULL ) {
218	    		tester_perror( "realloc", NULL );
219	    		exit( EXIT_FAILURE );
220		}
221		*pmodsp = pmods;
222		pmods[ i + 1 ] = NULL;
223		if (( pmods[ i ] = (LDAPMod *)calloc( 1, sizeof( LDAPMod )))
224			== NULL ) {
225	    		tester_perror( "calloc", NULL );
226	    		exit( EXIT_FAILURE );
227		}
228		pmods[ i ]->mod_op = modop;
229		if (( pmods[ i ]->mod_type = strdup( attr )) == NULL ) {
230	    	tester_perror( "strdup", NULL );
231	    	exit( EXIT_FAILURE );
232		}
233    }
234
235    if ( value != NULL ) {
236		j = 0;
237		if ( pmods[ i ]->mod_bvalues != NULL ) {
238	    	for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
239				;
240	    	}
241		}
242		if (( pmods[ i ]->mod_bvalues =
243			(struct berval **)ber_memrealloc( pmods[ i ]->mod_bvalues,
244			(j + 2) * sizeof( struct berval * ))) == NULL ) {
245	    		tester_perror( "ber_memrealloc", NULL );
246	    		exit( EXIT_FAILURE );
247		}
248		pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
249		if (( bvp = (struct berval *)ber_memalloc( sizeof( struct berval )))
250			== NULL ) {
251	    		tester_perror( "ber_memalloc", NULL );
252	    		exit( EXIT_FAILURE );
253		}
254		pmods[ i ]->mod_bvalues[ j ] = bvp;
255
256	    bvp->bv_len = vlen;
257	    if (( bvp->bv_val = (char *)malloc( vlen + 1 )) == NULL ) {
258			tester_perror( "malloc", NULL );
259			exit( EXIT_FAILURE );
260	    }
261	    AC_MEMCPY( bvp->bv_val, value, vlen );
262	    bvp->bv_val[ vlen ] = '\0';
263    }
264}
265
266
267static char *
268get_add_entry( char *filename, LDAPMod ***mods )
269{
270	FILE    *fp;
271	char    *entry = NULL;
272
273	if ( (fp = fopen( filename, "r" )) != NULL ) {
274		char  line[BUFSIZ];
275
276		if ( fgets( line, BUFSIZ, fp )) {
277			char *nl;
278
279			if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
280				*nl = '\0';
281			nl = line;
282			if ( !strncasecmp( nl, "dn: ", 4 ))
283				nl += 4;
284			entry = strdup( nl );
285
286		}
287
288		while ( fgets( line, BUFSIZ, fp )) {
289			char	*nl;
290			char	*value;
291
292			if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
293				*nl = '\0';
294
295			if ( *line == '\0' ) break;
296			if ( !( value = strchr( line, ':' ))) break;
297
298			*value++ = '\0';
299			while ( *value && isspace( (unsigned char) *value ))
300				value++;
301
302			addmodifyop( mods, LDAP_MOD_ADD, line, value, strlen( value ));
303
304		}
305		fclose( fp );
306	}
307
308	return( entry );
309}
310
311
312static void
313do_addel(
314	char *uri,
315	char *manager,
316	struct berval *passwd,
317	char *entry,
318	LDAPMod **attrs,
319	int maxloop,
320	int maxretries,
321	int delay,
322	int friendly,
323	int chaserefs )
324{
325	LDAP	*ld = NULL;
326	int  	i = 0, do_retry = maxretries;
327	int	rc = LDAP_SUCCESS;
328	int	version = LDAP_VERSION3;
329
330retry:;
331	ldap_initialize( &ld, uri );
332	if ( ld == NULL ) {
333		tester_perror( "ldap_initialize", NULL );
334		exit( EXIT_FAILURE );
335	}
336
337	(void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
338	(void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
339		chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
340
341	if ( do_retry == maxretries ) {
342		fprintf( stderr, "PID=%ld - Add/Delete(%d): entry=\"%s\".\n",
343			(long) pid, maxloop, entry );
344	}
345
346	rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
347	if ( rc != LDAP_SUCCESS ) {
348		tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
349		switch ( rc ) {
350		case LDAP_BUSY:
351		case LDAP_UNAVAILABLE:
352			if ( do_retry > 0 ) {
353				do_retry--;
354				if ( delay != 0 ) {
355				    sleep( delay );
356				}
357				goto retry;
358			}
359		/* fallthru */
360		default:
361			break;
362		}
363		exit( EXIT_FAILURE );
364	}
365
366	for ( ; i < maxloop; i++ ) {
367
368		/* add the entry */
369		rc = ldap_add_ext_s( ld, entry, attrs, NULL, NULL );
370		if ( rc != LDAP_SUCCESS ) {
371			tester_ldap_error( ld, "ldap_add_ext_s", NULL );
372			switch ( rc ) {
373			case LDAP_ALREADY_EXISTS:
374				/* NOTE: this likely means
375				 * the delete failed
376				 * during the previous round... */
377				if ( !friendly ) {
378					goto done;
379				}
380				break;
381
382			case LDAP_BUSY:
383			case LDAP_UNAVAILABLE:
384				if ( do_retry > 0 ) {
385					do_retry--;
386					goto retry;
387				}
388				/* fall thru */
389
390			default:
391				goto done;
392			}
393		}
394
395#if 0
396		/* wait a second for the add to really complete */
397		/* This masks some race conditions though. */
398		sleep( 1 );
399#endif
400
401		/* now delete the entry again */
402		rc = ldap_delete_ext_s( ld, entry, NULL, NULL );
403		if ( rc != LDAP_SUCCESS ) {
404			tester_ldap_error( ld, "ldap_delete_ext_s", NULL );
405			switch ( rc ) {
406			case LDAP_NO_SUCH_OBJECT:
407				/* NOTE: this likely means
408				 * the add failed
409				 * during the previous round... */
410				if ( !friendly ) {
411					goto done;
412				}
413				break;
414
415			case LDAP_BUSY:
416			case LDAP_UNAVAILABLE:
417				if ( do_retry > 0 ) {
418					do_retry--;
419					goto retry;
420				}
421				/* fall thru */
422
423			default:
424				goto done;
425			}
426		}
427	}
428
429done:;
430	fprintf( stderr, "  PID=%ld - Add/Delete done (%d).\n", (long) pid, rc );
431
432	ldap_unbind_ext( ld, NULL, NULL );
433}
434
435
436