1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2021 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 
41 static char *
42 get_add_entry( char *filename, LDAPMod ***mods );
43 
44 static void
45 do_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 
49 static void
usage(char * name)50 usage( 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 
69 int
main(int argc,char ** argv)70 main( 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 
195 static void
addmodifyop(LDAPMod *** pmodsp,int modop,char * attr,char * value,int vlen)196 addmodifyop( 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 
267 static char *
get_add_entry(char * filename,LDAPMod *** mods)268 get_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 
312 static void
do_addel(char * uri,char * manager,struct berval * passwd,char * entry,LDAPMod ** attrs,int maxloop,int maxretries,int delay,int friendly,int chaserefs)313 do_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 
330 retry:;
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 
429 done:;
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