1/*	$NetBSD$	*/
2
3/* OpenLDAP: pkg/ldap/tests/progs/slapd-read.c,v 1.37.2.10 2010/04/13 20:23:58 kurt Exp */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1999-2010 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
45static void
46do_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
51static void
52do_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
56static void
57usage( 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
82int
83main( int argc, char **argv )
84{
85	int		i;
86	char		*uri = NULL;
87	char		*host = "localhost";
88	int		port = -1;
89	char		*manager = NULL;
90	struct berval	passwd = { 0, NULL };
91	char		*entry = NULL;
92	char		*filter  = NULL;
93	int		loops = LOOPS;
94	int		outerloops = 1;
95	int		retries = RETRIES;
96	int		delay = 0;
97	int		force = 0;
98	int		chaserefs = 0;
99	char		*srchattrs[] = { "1.1", NULL };
100	char		**attrs = srchattrs;
101	int		noattrs = 0;
102	int		nobind = 0;
103
104	tester_init( "slapd-read", TESTER_READ );
105
106	/* by default, tolerate referrals and no such object */
107	tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
108
109	while ( (i = getopt( argc, argv, "ACD:e:Ff:H:h:i:L:l:p:r:t:T:w:" )) != EOF ) {
110		switch ( i ) {
111		case 'A':
112			noattrs++;
113			break;
114
115		case 'C':
116			chaserefs++;
117			break;
118
119		case 'H':		/* the server uri */
120			uri = strdup( optarg );
121			break;
122
123		case 'h':		/* the servers host */
124			host = strdup( optarg );
125			break;
126
127		case 'i':
128			tester_ignore_str2errlist( optarg );
129			break;
130
131		case 'N':
132			nobind++;
133			break;
134
135		case 'p':		/* the servers port */
136			if ( lutil_atoi( &port, optarg ) != 0 ) {
137				usage( argv[0] );
138			}
139			break;
140
141		case 'D':		/* the servers manager */
142			manager = strdup( optarg );
143			break;
144
145		case 'w':		/* the server managers password */
146			passwd.bv_val = strdup( optarg );
147			passwd.bv_len = strlen( optarg );
148			memset( optarg, '*', passwd.bv_len );
149			break;
150
151		case 'e':		/* DN to search for */
152			entry = strdup( optarg );
153			break;
154
155		case 'f':		/* the search request */
156			filter = strdup( optarg );
157			break;
158
159		case 'F':
160			force++;
161			break;
162
163		case 'l':		/* the number of loops */
164			if ( lutil_atoi( &loops, optarg ) != 0 ) {
165				usage( argv[0] );
166			}
167			break;
168
169		case 'L':		/* the number of outerloops */
170			if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
171				usage( argv[0] );
172			}
173			break;
174
175		case 'r':		/* the number of retries */
176			if ( lutil_atoi( &retries, optarg ) != 0 ) {
177				usage( argv[0] );
178			}
179			break;
180
181		case 't':		/* delay in seconds */
182			if ( lutil_atoi( &delay, optarg ) != 0 ) {
183				usage( argv[0] );
184			}
185			break;
186
187		case 'T':
188			attrs = ldap_str2charray( optarg, "," );
189			if ( attrs == NULL ) {
190				usage( argv[0] );
191			}
192			break;
193
194		default:
195			usage( argv[0] );
196			break;
197		}
198	}
199
200	if (( entry == NULL ) || ( port == -1 && uri == NULL ))
201		usage( argv[0] );
202
203	if ( *entry == '\0' ) {
204		fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
205				argv[0] );
206		exit( EXIT_FAILURE );
207	}
208
209	if ( argv[optind] != NULL ) {
210		attrs = &argv[optind];
211	}
212
213	uri = tester_uri( uri, host, port );
214
215	for ( i = 0; i < outerloops; i++ ) {
216		if ( filter != NULL ) {
217			do_random( uri, manager, &passwd, entry, filter, attrs,
218				noattrs, nobind, loops, retries, delay, force,
219				chaserefs );
220
221		} else {
222			do_read( uri, manager, &passwd, entry, NULL, attrs,
223				noattrs, nobind, loops, retries, delay, force,
224				chaserefs );
225		}
226	}
227
228	exit( EXIT_SUCCESS );
229}
230
231static void
232do_random( char *uri, char *manager, struct berval *passwd,
233	char *sbase, char *filter, char **srchattrs, int noattrs, int nobind,
234	int innerloop, int maxretries, int delay, int force, int chaserefs )
235{
236	LDAP	*ld = NULL;
237	int  	i = 0, do_retry = maxretries;
238	char	*attrs[ 2 ];
239	int     rc = LDAP_SUCCESS;
240	int	version = LDAP_VERSION3;
241	int	nvalues = 0;
242	char	**values = NULL;
243	LDAPMessage *res = NULL, *e = NULL;
244
245	attrs[ 0 ] = LDAP_NO_ATTRS;
246	attrs[ 1 ] = NULL;
247
248	ldap_initialize( &ld, uri );
249	if ( ld == NULL ) {
250		tester_perror( "ldap_initialize", NULL );
251		exit( EXIT_FAILURE );
252	}
253
254	(void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
255	(void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
256		chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
257
258	if ( do_retry == maxretries ) {
259		fprintf( stderr, "PID=%ld - Read(%d): base=\"%s\", filter=\"%s\".\n",
260				(long) pid, innerloop, sbase, filter );
261	}
262
263	if ( nobind == 0 ) {
264		rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
265		if ( rc != LDAP_SUCCESS ) {
266			tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
267			switch ( rc ) {
268			case LDAP_BUSY:
269			case LDAP_UNAVAILABLE:
270			/* fallthru */
271			default:
272				break;
273			}
274			exit( EXIT_FAILURE );
275		}
276	}
277
278	rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
279		filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
280	switch ( rc ) {
281	case LDAP_SIZELIMIT_EXCEEDED:
282	case LDAP_TIMELIMIT_EXCEEDED:
283	case LDAP_SUCCESS:
284		nvalues = ldap_count_entries( ld, res );
285		if ( nvalues == 0 ) {
286			if ( rc ) {
287				tester_ldap_error( ld, "ldap_search_ext_s", NULL );
288			}
289			break;
290		}
291
292		values = malloc( ( nvalues + 1 ) * sizeof( char * ) );
293		for ( i = 0, e = ldap_first_entry( ld, res ); e != NULL; i++, e = ldap_next_entry( ld, e ) )
294		{
295			values[ i ] = ldap_get_dn( ld, e );
296		}
297		values[ i ] = NULL;
298
299		ldap_msgfree( res );
300
301		if ( do_retry == maxretries ) {
302			fprintf( stderr, "  PID=%ld - Read base=\"%s\" filter=\"%s\" got %d values.\n",
303				(long) pid, sbase, filter, nvalues );
304		}
305
306		for ( i = 0; i < innerloop; i++ ) {
307#if 0	/* use high-order bits for better randomness (Numerical Recipes in "C") */
308			int	r = rand() % nvalues;
309#endif
310			int	r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
311
312			do_read( uri, manager, passwd, values[ r ], &ld,
313				srchattrs, noattrs, nobind, 1, maxretries,
314				delay, force, chaserefs );
315		}
316		free( values );
317		break;
318
319	default:
320		tester_ldap_error( ld, "ldap_search_ext_s", NULL );
321		break;
322	}
323
324	fprintf( stderr, "  PID=%ld - Search done (%d).\n", (long) pid, rc );
325
326	if ( ld != NULL ) {
327		ldap_unbind_ext( ld, NULL, NULL );
328	}
329}
330
331static void
332do_read( char *uri, char *manager, struct berval *passwd, char *entry,
333	LDAP **ldp, char **attrs, int noattrs, int nobind, int maxloop,
334	int maxretries, int delay, int force, int chaserefs )
335{
336	LDAP	*ld = ldp ? *ldp : NULL;
337	int  	i = 0, do_retry = maxretries;
338	int     rc = LDAP_SUCCESS;
339	int	version = LDAP_VERSION3;
340
341retry:;
342	if ( ld == NULL ) {
343		ldap_initialize( &ld, uri );
344		if ( ld == NULL ) {
345			tester_perror( "ldap_initialize", NULL );
346			exit( EXIT_FAILURE );
347		}
348
349		(void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
350		(void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
351			chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
352
353		if ( do_retry == maxretries ) {
354			fprintf( stderr, "PID=%ld - Read(%d): entry=\"%s\".\n",
355				(long) pid, maxloop, entry );
356		}
357
358		if ( nobind == 0 ) {
359			rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
360			if ( rc != LDAP_SUCCESS ) {
361				tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
362				switch ( rc ) {
363				case LDAP_BUSY:
364				case LDAP_UNAVAILABLE:
365					if ( do_retry > 0 ) {
366						ldap_unbind_ext( ld, NULL, NULL );
367						ld = NULL;
368						do_retry--;
369						if ( delay != 0 ) {
370						    sleep( delay );
371						}
372						goto retry;
373					}
374				/* fallthru */
375				default:
376					break;
377				}
378				exit( EXIT_FAILURE );
379			}
380		}
381	}
382
383	for ( ; i < maxloop; i++ ) {
384		LDAPMessage *res = NULL;
385
386		rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE,
387				NULL, attrs, noattrs, NULL, NULL, NULL,
388				LDAP_NO_LIMIT, &res );
389		if ( res != NULL ) {
390			ldap_msgfree( res );
391		}
392
393		if ( rc ) {
394			int		first = tester_ignore_err( rc );
395			char		buf[ BUFSIZ ];
396
397			snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
398
399			/* if ignore.. */
400			if ( first ) {
401				/* only log if first occurrence */
402				if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
403					tester_ldap_error( ld, buf, NULL );
404				}
405				continue;
406			}
407
408			/* busy needs special handling */
409			tester_ldap_error( ld, buf, NULL );
410			if ( rc == LDAP_BUSY && do_retry > 0 ) {
411				ldap_unbind_ext( ld, NULL, NULL );
412				ld = NULL;
413				do_retry--;
414				goto retry;
415			}
416			break;
417		}
418	}
419
420	if ( ldp != NULL ) {
421		*ldp = ld;
422
423	} else {
424		fprintf( stderr, "  PID=%ld - Read done (%d).\n", (long) pid, rc );
425
426		if ( ld != NULL ) {
427			ldap_unbind_ext( ld, NULL, NULL );
428		}
429	}
430}
431
432