xref: /netbsd-src/external/bsd/openldap/dist/tests/progs/slapd-read.c (revision 9616dacfef448e70e3fbbd865bddf60d54b656c5)
1 /*	$NetBSD: slapd-read.c,v 1.1.1.4 2014/05/28 09:58:54 tron Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2014 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Kurt Spanier for inclusion
19  * in OpenLDAP Software.
20  */
21 
22 #include "portable.h"
23 
24 #include <stdio.h>
25 
26 #include "ac/stdlib.h"
27 
28 #include "ac/ctype.h"
29 #include "ac/param.h"
30 #include "ac/socket.h"
31 #include "ac/string.h"
32 #include "ac/unistd.h"
33 #include "ac/wait.h"
34 
35 #include "ldap.h"
36 #include "lutil.h"
37 
38 #include "ldap_pvt.h"
39 
40 #include "slapd-common.h"
41 
42 #define LOOPS	100
43 #define RETRIES	0
44 
45 static void
46 do_read( char *uri, char *manager, struct berval *passwd,
47 	char *entry, LDAP **ld,
48 	char **attrs, int noattrs, int nobind, int maxloop,
49 	int maxretries, int delay, int force, int chaserefs );
50 
51 static void
52 do_random( char *uri, char *manager, struct berval *passwd,
53 	char *sbase, char *filter, char **attrs, int noattrs, int nobind,
54 	int innerloop, int maxretries, int delay, int force, int chaserefs );
55 
56 static void
57 usage( char *name )
58 {
59         fprintf( stderr,
60 		"usage: %s "
61 		"-H <uri> | ([-h <host>] -p <port>) "
62 		"-D <manager> "
63 		"-w <passwd> "
64 		"-e <entry> "
65 		"[-A] "
66 		"[-C] "
67 		"[-F] "
68 		"[-N] "
69 		"[-f filter] "
70 		"[-i <ignore>] "
71 		"[-l <loops>] "
72 		"[-L <outerloops>] "
73 		"[-r <maxretries>] "
74 		"[-t <delay>] "
75 		"[-T <attrs>] "
76 		"[<attrs>] "
77 		"\n",
78 		name );
79 	exit( EXIT_FAILURE );
80 }
81 
82 /* -S: just send requests without reading responses
83  * -SS: send all requests asynchronous and immediately start reading responses
84  * -SSS: send all requests asynchronous; then read responses
85  */
86 static int swamp;
87 
88 int
89 main( int argc, char **argv )
90 {
91 	int		i;
92 	char		*uri = NULL;
93 	char		*host = "localhost";
94 	int		port = -1;
95 	char		*manager = NULL;
96 	struct berval	passwd = { 0, NULL };
97 	char		*entry = NULL;
98 	char		*filter  = NULL;
99 	int		loops = LOOPS;
100 	int		outerloops = 1;
101 	int		retries = RETRIES;
102 	int		delay = 0;
103 	int		force = 0;
104 	int		chaserefs = 0;
105 	char		*srchattrs[] = { "1.1", NULL };
106 	char		**attrs = srchattrs;
107 	int		noattrs = 0;
108 	int		nobind = 0;
109 
110 	tester_init( "slapd-read", TESTER_READ );
111 
112 	/* by default, tolerate referrals and no such object */
113 	tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
114 
115 	while ( (i = getopt( argc, argv, "ACD:e:Ff:H:h:i:L:l:p:r:St:T:w:" )) != EOF ) {
116 		switch ( i ) {
117 		case 'A':
118 			noattrs++;
119 			break;
120 
121 		case 'C':
122 			chaserefs++;
123 			break;
124 
125 		case 'H':		/* the server uri */
126 			uri = strdup( optarg );
127 			break;
128 
129 		case 'h':		/* the servers host */
130 			host = strdup( optarg );
131 			break;
132 
133 		case 'i':
134 			tester_ignore_str2errlist( optarg );
135 			break;
136 
137 		case 'N':
138 			nobind++;
139 			break;
140 
141 		case 'p':		/* the servers port */
142 			if ( lutil_atoi( &port, optarg ) != 0 ) {
143 				usage( argv[0] );
144 			}
145 			break;
146 
147 		case 'D':		/* the servers manager */
148 			manager = strdup( optarg );
149 			break;
150 
151 		case 'w':		/* the server managers password */
152 			passwd.bv_val = strdup( optarg );
153 			passwd.bv_len = strlen( optarg );
154 			memset( optarg, '*', passwd.bv_len );
155 			break;
156 
157 		case 'e':		/* DN to search for */
158 			entry = strdup( optarg );
159 			break;
160 
161 		case 'f':		/* the search request */
162 			filter = strdup( optarg );
163 			break;
164 
165 		case 'F':
166 			force++;
167 			break;
168 
169 		case 'l':		/* the number of loops */
170 			if ( lutil_atoi( &loops, optarg ) != 0 ) {
171 				usage( argv[0] );
172 			}
173 			break;
174 
175 		case 'L':		/* the number of outerloops */
176 			if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
177 				usage( argv[0] );
178 			}
179 			break;
180 
181 		case 'r':		/* the number of retries */
182 			if ( lutil_atoi( &retries, optarg ) != 0 ) {
183 				usage( argv[0] );
184 			}
185 			break;
186 
187 		case 'S':
188 			swamp++;
189 			break;
190 
191 		case 't':		/* delay in seconds */
192 			if ( lutil_atoi( &delay, optarg ) != 0 ) {
193 				usage( argv[0] );
194 			}
195 			break;
196 
197 		case 'T':
198 			attrs = ldap_str2charray( optarg, "," );
199 			if ( attrs == NULL ) {
200 				usage( argv[0] );
201 			}
202 			break;
203 
204 		default:
205 			usage( argv[0] );
206 			break;
207 		}
208 	}
209 
210 	if (( entry == NULL ) || ( port == -1 && uri == NULL ))
211 		usage( argv[0] );
212 
213 	if ( *entry == '\0' ) {
214 		fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
215 				argv[0] );
216 		exit( EXIT_FAILURE );
217 	}
218 
219 	if ( argv[optind] != NULL ) {
220 		attrs = &argv[optind];
221 	}
222 
223 	uri = tester_uri( uri, host, port );
224 
225 	for ( i = 0; i < outerloops; i++ ) {
226 		if ( filter != NULL ) {
227 			do_random( uri, manager, &passwd, entry, filter, attrs,
228 				noattrs, nobind, loops, retries, delay, force,
229 				chaserefs );
230 
231 		} else {
232 			do_read( uri, manager, &passwd, entry, NULL, attrs,
233 				noattrs, nobind, loops, retries, delay, force,
234 				chaserefs );
235 		}
236 	}
237 
238 	exit( EXIT_SUCCESS );
239 }
240 
241 static void
242 do_random( char *uri, char *manager, struct berval *passwd,
243 	char *sbase, char *filter, char **srchattrs, int noattrs, int nobind,
244 	int innerloop, int maxretries, int delay, int force, int chaserefs )
245 {
246 	LDAP	*ld = NULL;
247 	int  	i = 0, do_retry = maxretries;
248 	char	*attrs[ 2 ];
249 	int     rc = LDAP_SUCCESS;
250 	int	version = LDAP_VERSION3;
251 	int	nvalues = 0;
252 	char	**values = NULL;
253 	LDAPMessage *res = NULL, *e = NULL;
254 
255 	attrs[ 0 ] = LDAP_NO_ATTRS;
256 	attrs[ 1 ] = NULL;
257 
258 	ldap_initialize( &ld, uri );
259 	if ( ld == NULL ) {
260 		tester_perror( "ldap_initialize", NULL );
261 		exit( EXIT_FAILURE );
262 	}
263 
264 	(void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
265 	(void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
266 		chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
267 
268 	if ( do_retry == maxretries ) {
269 		fprintf( stderr, "PID=%ld - Read(%d): base=\"%s\", filter=\"%s\".\n",
270 				(long) pid, innerloop, sbase, filter );
271 	}
272 
273 	if ( nobind == 0 ) {
274 		rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
275 		if ( rc != LDAP_SUCCESS ) {
276 			tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
277 			switch ( rc ) {
278 			case LDAP_BUSY:
279 			case LDAP_UNAVAILABLE:
280 			/* fallthru */
281 			default:
282 				break;
283 			}
284 			exit( EXIT_FAILURE );
285 		}
286 	}
287 
288 	rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
289 		filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
290 	switch ( rc ) {
291 	case LDAP_SIZELIMIT_EXCEEDED:
292 	case LDAP_TIMELIMIT_EXCEEDED:
293 	case LDAP_SUCCESS:
294 		nvalues = ldap_count_entries( ld, res );
295 		if ( nvalues == 0 ) {
296 			if ( rc ) {
297 				tester_ldap_error( ld, "ldap_search_ext_s", NULL );
298 			}
299 			break;
300 		}
301 
302 		values = malloc( ( nvalues + 1 ) * sizeof( char * ) );
303 		for ( i = 0, e = ldap_first_entry( ld, res ); e != NULL; i++, e = ldap_next_entry( ld, e ) )
304 		{
305 			values[ i ] = ldap_get_dn( ld, e );
306 		}
307 		values[ i ] = NULL;
308 
309 		ldap_msgfree( res );
310 
311 		if ( do_retry == maxretries ) {
312 			fprintf( stderr, "  PID=%ld - Read base=\"%s\" filter=\"%s\" got %d values.\n",
313 				(long) pid, sbase, filter, nvalues );
314 		}
315 
316 		for ( i = 0; i < innerloop; i++ ) {
317 #if 0	/* use high-order bits for better randomness (Numerical Recipes in "C") */
318 			int	r = rand() % nvalues;
319 #endif
320 			int	r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
321 
322 			do_read( uri, manager, passwd, values[ r ], &ld,
323 				srchattrs, noattrs, nobind, 1, maxretries,
324 				delay, force, chaserefs );
325 		}
326 		free( values );
327 		break;
328 
329 	default:
330 		tester_ldap_error( ld, "ldap_search_ext_s", NULL );
331 		break;
332 	}
333 
334 	fprintf( stderr, "  PID=%ld - Read done (%d).\n", (long) pid, rc );
335 
336 	if ( ld != NULL ) {
337 		ldap_unbind_ext( ld, NULL, NULL );
338 	}
339 }
340 
341 static void
342 do_read( char *uri, char *manager, struct berval *passwd, char *entry,
343 	LDAP **ldp, char **attrs, int noattrs, int nobind, int maxloop,
344 	int maxretries, int delay, int force, int chaserefs )
345 {
346 	LDAP	*ld = ldp ? *ldp : NULL;
347 	int  	i = 0, do_retry = maxretries;
348 	int     rc = LDAP_SUCCESS;
349 	int		version = LDAP_VERSION3;
350 	int		*msgids = NULL, active = 0;
351 
352 	/* make room for msgid */
353 	if ( swamp > 1 ) {
354 		msgids = (int *)calloc( sizeof(int), maxloop );
355 	}
356 
357 retry:;
358 	if ( ld == NULL ) {
359 		ldap_initialize( &ld, uri );
360 		if ( ld == NULL ) {
361 			tester_perror( "ldap_initialize", NULL );
362 			exit( EXIT_FAILURE );
363 		}
364 
365 		(void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
366 		(void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
367 			chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
368 
369 		if ( do_retry == maxretries ) {
370 			fprintf( stderr, "PID=%ld - Read(%d): entry=\"%s\".\n",
371 				(long) pid, maxloop, entry );
372 		}
373 
374 		if ( nobind == 0 ) {
375 			rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
376 			if ( rc != LDAP_SUCCESS ) {
377 				tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
378 				switch ( rc ) {
379 				case LDAP_BUSY:
380 				case LDAP_UNAVAILABLE:
381 					if ( do_retry > 0 ) {
382 						ldap_unbind_ext( ld, NULL, NULL );
383 						ld = NULL;
384 						do_retry--;
385 						if ( delay != 0 ) {
386 						    sleep( delay );
387 						}
388 						goto retry;
389 					}
390 				/* fallthru */
391 				default:
392 					break;
393 				}
394 				exit( EXIT_FAILURE );
395 			}
396 		}
397 	}
398 
399 	if ( swamp > 1 ) {
400 		do {
401 			LDAPMessage *res = NULL;
402 			int j, msgid;
403 
404 			if ( i < maxloop ) {
405 				rc = ldap_search_ext( ld, entry, LDAP_SCOPE_BASE,
406 						NULL, attrs, noattrs, NULL, NULL,
407 						NULL, LDAP_NO_LIMIT, &msgids[i] );
408 
409 				active++;
410 #if 0
411 				fprintf( stderr,
412 					">>> PID=%ld - Read maxloop=%d cnt=%d active=%d msgid=%d: "
413 					"entry=\"%s\"\n",
414 					(long) pid, maxloop, i, active, msgids[i],
415 					entry );
416 #endif
417 				i++;
418 
419 				if ( rc ) {
420 					char buf[BUFSIZ];
421 					int first = tester_ignore_err( rc );
422 					/* if ignore.. */
423 					if ( first ) {
424 						/* only log if first occurrence */
425 						if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
426 							tester_ldap_error( ld, "ldap_search_ext", NULL );
427 						}
428 						continue;
429 					}
430 
431 					/* busy needs special handling */
432 					snprintf( buf, sizeof( buf ), "entry=\"%s\"\n", entry );
433 					tester_ldap_error( ld, "ldap_search_ext", buf );
434 					if ( rc == LDAP_BUSY && do_retry > 0 ) {
435 						ldap_unbind_ext( ld, NULL, NULL );
436 						ld = NULL;
437 						do_retry--;
438 						goto retry;
439 					}
440 					break;
441 				}
442 
443 				if ( swamp > 2 ) {
444 					continue;
445 				}
446 			}
447 
448 			rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res );
449 			switch ( rc ) {
450 			case -1:
451 				/* gone really bad */
452 #if 0
453 				fprintf( stderr,
454 					">>> PID=%ld - Read maxloop=%d cnt=%d active=%d: "
455 					"entry=\"%s\" ldap_result()=%d\n",
456 					(long) pid, maxloop, i, active, entry, rc );
457 #endif
458 				goto cleanup;
459 
460 			case 0:
461 				/* timeout (impossible) */
462 				break;
463 
464 			case LDAP_RES_SEARCH_ENTRY:
465 			case LDAP_RES_SEARCH_REFERENCE:
466 				/* ignore */
467 				break;
468 
469 			case LDAP_RES_SEARCH_RESULT:
470 				/* just remove, no error checking (TODO?) */
471 				msgid = ldap_msgid( res );
472 				ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 );
473 				res = NULL;
474 
475 				/* linear search, bah */
476 				for ( j = 0; j < i; j++ ) {
477 					if ( msgids[ j ] == msgid ) {
478 						msgids[ j ] = -1;
479 						active--;
480 #if 0
481 						fprintf( stderr,
482 							"<<< PID=%ld - ReadDone maxloop=%d cnt=%d active=%d msgid=%d: "
483 							"entry=\"%s\"\n",
484 							(long) pid, maxloop, j, active, msgid, entry );
485 #endif
486 						break;
487 					}
488 				}
489 				break;
490 
491 			default:
492 				/* other messages unexpected */
493 				fprintf( stderr,
494 					"### PID=%ld - Read(%d): "
495 					"entry=\"%s\" attrs=%s%s. unexpected response tag=%d\n",
496 					(long) pid, maxloop,
497 					entry, attrs[0], attrs[1] ? " (more...)" : "", rc );
498 				break;
499 			}
500 
501 			if ( res != NULL ) {
502 				ldap_msgfree( res );
503 			}
504 		} while ( i < maxloop || active > 0 );
505 
506 	} else {
507 		for ( ; i < maxloop; i++ ) {
508 			LDAPMessage *res = NULL;
509 
510 			if (swamp) {
511 				int msgid;
512 				rc = ldap_search_ext( ld, entry, LDAP_SCOPE_BASE,
513 						NULL, attrs, noattrs, NULL, NULL,
514 						NULL, LDAP_NO_LIMIT, &msgid );
515 				if ( rc == LDAP_SUCCESS ) continue;
516 				else break;
517 			}
518 
519 			rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE,
520 					NULL, attrs, noattrs, NULL, NULL, NULL,
521 					LDAP_NO_LIMIT, &res );
522 			if ( res != NULL ) {
523 				ldap_msgfree( res );
524 			}
525 
526 			if ( rc ) {
527 				int		first = tester_ignore_err( rc );
528 				char		buf[ BUFSIZ ];
529 
530 				snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
531 
532 				/* if ignore.. */
533 				if ( first ) {
534 					/* only log if first occurrence */
535 					if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
536 						tester_ldap_error( ld, buf, NULL );
537 					}
538 					continue;
539 				}
540 
541 				/* busy needs special handling */
542 				tester_ldap_error( ld, buf, NULL );
543 				if ( rc == LDAP_BUSY && do_retry > 0 ) {
544 					ldap_unbind_ext( ld, NULL, NULL );
545 					ld = NULL;
546 					do_retry--;
547 					goto retry;
548 				}
549 				break;
550 			}
551 		}
552 	}
553 
554 cleanup:;
555 	if ( msgids != NULL ) {
556 		free( msgids );
557 	}
558 
559 	if ( ldp != NULL ) {
560 		*ldp = ld;
561 
562 	} else {
563 		fprintf( stderr, "  PID=%ld - Read done (%d).\n", (long) pid, rc );
564 
565 		if ( ld != NULL ) {
566 			ldap_unbind_ext( ld, NULL, NULL );
567 		}
568 	}
569 }
570 
571