slapd-search.c revision 1.1.1.2 1 /* $NetBSD: slapd-search.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $ */
2
3 /* OpenLDAP: pkg/ldap/tests/progs/slapd-search.c,v 1.41.2.11 2009/07/01 17:09:44 quanah Exp */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1999-2009 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 #include "ldap_pvt.h"
38
39 #include "slapd-common.h"
40
41 #define LOOPS 100
42 #define RETRIES 0
43
44 static void
45 do_search( char *uri, char *manager, struct berval *passwd,
46 char *sbase, int scope, char *filter, LDAP **ldp,
47 char **attrs, int noattrs, int nobind,
48 int innerloop, int maxretries, int delay, int force, int chaserefs );
49
50 static void
51 do_random( char *uri, char *manager, struct berval *passwd,
52 char *sbase, int scope, char *filter, char *attr,
53 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, char o )
58 {
59 if ( o != '\0' ) {
60 fprintf( stderr, "unknown/incorrect option \"%c\"\n", o );
61 }
62
63 fprintf( stderr,
64 "usage: %s "
65 "-H <uri> | ([-h <host>] -p <port>) "
66 "-D <manager> "
67 "-w <passwd> "
68 "-b <searchbase> "
69 "-s <scope> "
70 "-f <searchfilter> "
71 "[-a <attr>] "
72 "[-A] "
73 "[-C] "
74 "[-F] "
75 "[-N] "
76 "[-S] "
77 "[-i <ignore>] "
78 "[-l <loops>] "
79 "[-L <outerloops>] "
80 "[-r <maxretries>] "
81 "[-t <delay>] "
82 "[<attrs>] "
83 "\n",
84 name );
85 exit( EXIT_FAILURE );
86 }
87
88 /* Just send requests without reading responses */
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 *sbase = NULL;
101 int scope = LDAP_SCOPE_SUBTREE;
102 char *filter = NULL;
103 char *attr = NULL;
104 char *srchattrs[] = { "cn", "sn", NULL };
105 char **attrs = srchattrs;
106 int loops = LOOPS;
107 int outerloops = 1;
108 int retries = RETRIES;
109 int delay = 0;
110 int force = 0;
111 int chaserefs = 0;
112 int noattrs = 0;
113 int nobind = 0;
114
115 tester_init( "slapd-search", TESTER_SEARCH );
116
117 /* by default, tolerate referrals and no such object */
118 tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
119
120 while ( ( i = getopt( argc, argv, "Aa:b:CD:f:FH:h:i:l:L:Np:r:Ss:t:T:w:" ) ) != EOF )
121 {
122 switch ( i ) {
123 case 'A':
124 noattrs++;
125 break;
126
127 case 'C':
128 chaserefs++;
129 break;
130
131 case 'H': /* the server uri */
132 uri = strdup( optarg );
133 break;
134
135 case 'h': /* the servers host */
136 host = strdup( optarg );
137 break;
138
139 case 'i':
140 tester_ignore_str2errlist( optarg );
141 break;
142
143 case 'N':
144 nobind++;
145 break;
146
147 case 'p': /* the servers port */
148 if ( lutil_atoi( &port, optarg ) != 0 ) {
149 usage( argv[0], i );
150 }
151 break;
152
153 case 'D': /* the servers manager */
154 manager = strdup( optarg );
155 break;
156
157 case 'w': /* the server managers password */
158 passwd.bv_val = strdup( optarg );
159 passwd.bv_len = strlen( optarg );
160 memset( optarg, '*', passwd.bv_len );
161 break;
162
163 case 'a':
164 attr = strdup( optarg );
165 break;
166
167 case 'b': /* file with search base */
168 sbase = strdup( optarg );
169 break;
170
171 case 'f': /* the search request */
172 filter = strdup( optarg );
173 break;
174
175 case 'F':
176 force++;
177 break;
178
179 case 'l': /* number of loops */
180 if ( lutil_atoi( &loops, optarg ) != 0 ) {
181 usage( argv[0], i );
182 }
183 break;
184
185 case 'L': /* number of loops */
186 if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
187 usage( argv[0], i );
188 }
189 break;
190
191 case 'r': /* number of retries */
192 if ( lutil_atoi( &retries, optarg ) != 0 ) {
193 usage( argv[0], i );
194 }
195 break;
196
197 case 't': /* delay in seconds */
198 if ( lutil_atoi( &delay, optarg ) != 0 ) {
199 usage( argv[0], i );
200 }
201 break;
202
203 case 'T':
204 attrs = ldap_str2charray( optarg, "," );
205 if ( attrs == NULL ) {
206 usage( argv[0], i );
207 }
208 break;
209
210 case 'S':
211 swamp++;
212 break;
213
214 case 's':
215 scope = ldap_pvt_str2scope( optarg );
216 if ( scope == -1 ) {
217 usage( argv[0], i );
218 }
219 break;
220
221 default:
222 usage( argv[0], i );
223 break;
224 }
225 }
226
227 if (( sbase == NULL ) || ( filter == NULL ) || ( port == -1 && uri == NULL ))
228 usage( argv[0], '\0' );
229
230 if ( *filter == '\0' ) {
231
232 fprintf( stderr, "%s: invalid EMPTY search filter.\n",
233 argv[0] );
234 exit( EXIT_FAILURE );
235
236 }
237
238 if ( argv[optind] != NULL ) {
239 attrs = &argv[optind];
240 }
241
242 uri = tester_uri( uri, host, port );
243
244 for ( i = 0; i < outerloops; i++ ) {
245 if ( attr != NULL ) {
246 do_random( uri, manager, &passwd,
247 sbase, scope, filter, attr,
248 attrs, noattrs, nobind,
249 loops, retries, delay, force, chaserefs );
250
251 } else {
252 do_search( uri, manager, &passwd,
253 sbase, scope, filter, NULL,
254 attrs, noattrs, nobind,
255 loops, retries, delay, force, chaserefs );
256 }
257 }
258
259 exit( EXIT_SUCCESS );
260 }
261
262
263 static void
264 do_random( char *uri, char *manager, struct berval *passwd,
265 char *sbase, int scope, char *filter, char *attr,
266 char **srchattrs, int noattrs, int nobind,
267 int innerloop, int maxretries, int delay, int force, int chaserefs )
268 {
269 LDAP *ld = NULL;
270 int i = 0, do_retry = maxretries;
271 char *attrs[ 2 ];
272 int rc = LDAP_SUCCESS;
273 int version = LDAP_VERSION3;
274 int nvalues = 0;
275 char **values = NULL;
276 LDAPMessage *res = NULL, *e = NULL;
277
278 attrs[ 0 ] = attr;
279 attrs[ 1 ] = NULL;
280
281 ldap_initialize( &ld, uri );
282 if ( ld == NULL ) {
283 tester_perror( "ldap_initialize", NULL );
284 exit( EXIT_FAILURE );
285 }
286
287 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
288 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
289 chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
290
291 if ( do_retry == maxretries ) {
292 fprintf( stderr, "PID=%ld - Search(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n",
293 (long) pid, innerloop, sbase, filter, attr );
294 }
295
296 if ( nobind == 0 ) {
297 rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
298 if ( rc != LDAP_SUCCESS ) {
299 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
300 switch ( rc ) {
301 case LDAP_BUSY:
302 case LDAP_UNAVAILABLE:
303 /* fallthru */
304 default:
305 break;
306 }
307 exit( EXIT_FAILURE );
308 }
309 }
310
311 rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
312 filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
313 switch ( rc ) {
314 case LDAP_SIZELIMIT_EXCEEDED:
315 case LDAP_TIMELIMIT_EXCEEDED:
316 case LDAP_SUCCESS:
317 if ( ldap_count_entries( ld, res ) == 0 ) {
318 if ( rc ) {
319 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
320 }
321 break;
322 }
323
324 for ( e = ldap_first_entry( ld, res ); e != NULL; e = ldap_next_entry( ld, e ) )
325 {
326 struct berval **v = ldap_get_values_len( ld, e, attr );
327
328 if ( v != NULL ) {
329 int n = ldap_count_values_len( v );
330 int j;
331
332 values = realloc( values, ( nvalues + n + 1 )*sizeof( char * ) );
333 for ( j = 0; j < n; j++ ) {
334 values[ nvalues + j ] = strdup( v[ j ]->bv_val );
335 }
336 values[ nvalues + j ] = NULL;
337 nvalues += n;
338 ldap_value_free_len( v );
339 }
340 }
341
342 ldap_msgfree( res );
343
344 if ( !values ) {
345 fprintf( stderr, " PID=%ld - Search base=\"%s\" filter=\"%s\" got %d values.\n",
346 (long) pid, sbase, filter, nvalues );
347 exit(EXIT_FAILURE);
348 }
349
350 if ( do_retry == maxretries ) {
351 fprintf( stderr, " PID=%ld - Search base=\"%s\" filter=\"%s\" got %d values.\n",
352 (long) pid, sbase, filter, nvalues );
353 }
354
355 for ( i = 0; i < innerloop; i++ ) {
356 char buf[ BUFSIZ ];
357 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */
358 int r = rand() % nvalues;
359 #endif
360 int r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
361
362 snprintf( buf, sizeof( buf ), "(%s=%s)", attr, values[ r ] );
363
364 do_search( uri, manager, passwd,
365 sbase, scope, buf, &ld,
366 srchattrs, noattrs, nobind,
367 1, maxretries, delay, force, chaserefs );
368 }
369 break;
370
371 default:
372 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
373 break;
374 }
375
376 fprintf( stderr, " PID=%ld - Search done (%d).\n", (long) pid, rc );
377
378 if ( ld != NULL ) {
379 ldap_unbind_ext( ld, NULL, NULL );
380 }
381 }
382
383 static void
384 do_search( char *uri, char *manager, struct berval *passwd,
385 char *sbase, int scope, char *filter, LDAP **ldp,
386 char **attrs, int noattrs, int nobind,
387 int innerloop, int maxretries, int delay, int force, int chaserefs )
388 {
389 LDAP *ld = ldp ? *ldp : NULL;
390 int i = 0, do_retry = maxretries;
391 int rc = LDAP_SUCCESS;
392 int version = LDAP_VERSION3;
393 char buf[ BUFSIZ ];
394
395
396 retry:;
397 if ( ld == NULL ) {
398 ldap_initialize( &ld, uri );
399 if ( ld == NULL ) {
400 tester_perror( "ldap_initialize", NULL );
401 exit( EXIT_FAILURE );
402 }
403
404 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
405 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
406 chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
407
408 if ( do_retry == maxretries ) {
409 fprintf( stderr,
410 "PID=%ld - Search(%d): "
411 "base=\"%s\" scope=%s filter=\"%s\" "
412 "attrs=%s%s.\n",
413 (long) pid, innerloop,
414 sbase, ldap_pvt_scope2str( scope ), filter,
415 attrs[0], attrs[1] ? " (more...)" : "" );
416 }
417
418 if ( nobind == 0 ) {
419 rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
420 if ( rc != LDAP_SUCCESS ) {
421 snprintf( buf, sizeof( buf ),
422 "bindDN=\"%s\"", manager );
423 tester_ldap_error( ld, "ldap_sasl_bind_s", buf );
424 switch ( rc ) {
425 case LDAP_BUSY:
426 case LDAP_UNAVAILABLE:
427 if ( do_retry > 0 ) {
428 ldap_unbind_ext( ld, NULL, NULL );
429 ld = NULL;
430 do_retry--;
431 if ( delay != 0 ) {
432 sleep( delay );
433 }
434 goto retry;
435 }
436 /* fallthru */
437 default:
438 break;
439 }
440 exit( EXIT_FAILURE );
441 }
442 }
443 }
444
445 for ( ; i < innerloop; i++ ) {
446 LDAPMessage *res = NULL;
447
448 if (swamp) {
449 int msgid;
450 rc = ldap_search_ext( ld, sbase, scope,
451 filter, NULL, noattrs, NULL, NULL,
452 NULL, LDAP_NO_LIMIT, &msgid );
453 if ( rc == LDAP_SUCCESS ) continue;
454 else break;
455 }
456
457 rc = ldap_search_ext_s( ld, sbase, scope,
458 filter, attrs, noattrs, NULL, NULL,
459 NULL, LDAP_NO_LIMIT, &res );
460 if ( res != NULL ) {
461 ldap_msgfree( res );
462 }
463
464 if ( rc ) {
465 int first = tester_ignore_err( rc );
466 /* if ignore.. */
467 if ( first ) {
468 /* only log if first occurrence */
469 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
470 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
471 }
472 continue;
473 }
474
475 /* busy needs special handling */
476 snprintf( buf, sizeof( buf ),
477 "base=\"%s\" filter=\"%s\"\n",
478 sbase, filter );
479 tester_ldap_error( ld, "ldap_search_ext_s", buf );
480 if ( rc == LDAP_BUSY && do_retry > 0 ) {
481 ldap_unbind_ext( ld, NULL, NULL );
482 ld = NULL;
483 do_retry--;
484 goto retry;
485 }
486 break;
487 }
488 }
489
490 if ( ldp != NULL ) {
491 *ldp = ld;
492
493 } else {
494 fprintf( stderr, " PID=%ld - Search done (%d).\n", (long) pid, rc );
495
496 if ( ld != NULL ) {
497 ldap_unbind_ext( ld, NULL, NULL );
498 }
499 }
500 }
501