1/* $NetBSD$ */ 2 3/* OpenLDAP: pkg/ldap/tests/progs/slapd-search.c,v 1.41.2.12 2010/04/13 20:23:59 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#include "ldap_pvt.h" 38 39#include "slapd-common.h" 40 41#define LOOPS 100 42#define RETRIES 0 43 44static void 45do_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 50static void 51do_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 56static void 57usage( 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 */ 89static int swamp; 90 91int 92main( 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 263static void 264do_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 383static void 384do_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 396retry:; 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