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