1 /* $OpenLDAP: pkg/ldap/tests/progs/slapd-search.c,v 1.41.2.7 2008/02/11 23:26:50 kurt Exp $ */ 2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1999-2008 The OpenLDAP Foundation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15 /* ACKNOWLEDGEMENTS: 16 * This work was initially developed by Kurt Spanier for inclusion 17 * in OpenLDAP Software. 18 */ 19 20 #include "portable.h" 21 22 #include <stdio.h> 23 24 #include "ac/stdlib.h" 25 26 #include "ac/ctype.h" 27 #include "ac/param.h" 28 #include "ac/socket.h" 29 #include "ac/string.h" 30 #include "ac/unistd.h" 31 #include "ac/wait.h" 32 33 #include "ldap.h" 34 #include "lutil.h" 35 #include "ldap_pvt.h" 36 37 #include "slapd-common.h" 38 39 #define LOOPS 100 40 #define RETRIES 0 41 42 static void 43 do_search( char *uri, char *manager, struct berval *passwd, 44 char *sbase, int scope, char *filter, LDAP **ldp, 45 char **attrs, int noattrs, int nobind, 46 int innerloop, int maxretries, int delay, int force, int chaserefs ); 47 48 static void 49 do_random( char *uri, char *manager, struct berval *passwd, 50 char *sbase, int scope, char *filter, char *attr, 51 char **attrs, int noattrs, int nobind, 52 int innerloop, int maxretries, int delay, int force, int chaserefs ); 53 54 static void 55 usage( char *name, char o ) 56 { 57 if ( o != '\0' ) { 58 fprintf( stderr, "unknown/incorrect option \"%c\"\n", o ); 59 } 60 61 fprintf( stderr, 62 "usage: %s " 63 "-H <uri> | ([-h <host>] -p <port>) " 64 "-D <manager> " 65 "-w <passwd> " 66 "-b <searchbase> " 67 "-s <scope> " 68 "-f <searchfilter> " 69 "[-a <attr>] " 70 "[-A] " 71 "[-C] " 72 "[-F] " 73 "[-N] " 74 "[-i <ignore>] " 75 "[-l <loops>] " 76 "[-L <outerloops>] " 77 "[-r <maxretries>] " 78 "[-t <delay>] " 79 "[<attrs>] " 80 "\n", 81 name ); 82 exit( EXIT_FAILURE ); 83 } 84 85 int 86 main( int argc, char **argv ) 87 { 88 int i; 89 char *uri = NULL; 90 char *host = "localhost"; 91 int port = -1; 92 char *manager = NULL; 93 struct berval passwd = { 0, NULL }; 94 char *sbase = NULL; 95 int scope = LDAP_SCOPE_SUBTREE; 96 char *filter = NULL; 97 char *attr = NULL; 98 char *srchattrs[] = { "cn", "sn", NULL }; 99 char **attrs = srchattrs; 100 int loops = LOOPS; 101 int outerloops = 1; 102 int retries = RETRIES; 103 int delay = 0; 104 int force = 0; 105 int chaserefs = 0; 106 int noattrs = 0; 107 int nobind = 0; 108 109 tester_init( "slapd-search", TESTER_SEARCH ); 110 111 /* by default, tolerate referrals and no such object */ 112 tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" ); 113 114 while ( ( i = getopt( argc, argv, "Aa:b:CD:f:FH:h:i:l:L:Np:r:s:t:T:w:" ) ) != EOF ) 115 { 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], i ); 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 'a': 158 attr = strdup( optarg ); 159 break; 160 161 case 'b': /* file with search base */ 162 sbase = strdup( optarg ); 163 break; 164 165 case 'f': /* the search request */ 166 filter = strdup( optarg ); 167 break; 168 169 case 'F': 170 force++; 171 break; 172 173 case 'l': /* number of loops */ 174 if ( lutil_atoi( &loops, optarg ) != 0 ) { 175 usage( argv[0], i ); 176 } 177 break; 178 179 case 'L': /* number of loops */ 180 if ( lutil_atoi( &outerloops, optarg ) != 0 ) { 181 usage( argv[0], i ); 182 } 183 break; 184 185 case 'r': /* number of retries */ 186 if ( lutil_atoi( &retries, optarg ) != 0 ) { 187 usage( argv[0], i ); 188 } 189 break; 190 191 case 't': /* delay in seconds */ 192 if ( lutil_atoi( &delay, optarg ) != 0 ) { 193 usage( argv[0], i ); 194 } 195 break; 196 197 case 'T': 198 attrs = ldap_str2charray( optarg, "," ); 199 if ( attrs == NULL ) { 200 usage( argv[0], i ); 201 } 202 break; 203 204 case 's': 205 scope = ldap_pvt_str2scope( optarg ); 206 if ( scope == -1 ) { 207 usage( argv[0], i ); 208 } 209 break; 210 211 default: 212 usage( argv[0], i ); 213 break; 214 } 215 } 216 217 if (( sbase == NULL ) || ( filter == NULL ) || ( port == -1 && uri == NULL )) 218 usage( argv[0], '\0' ); 219 220 if ( *filter == '\0' ) { 221 222 fprintf( stderr, "%s: invalid EMPTY search filter.\n", 223 argv[0] ); 224 exit( EXIT_FAILURE ); 225 226 } 227 228 if ( argv[optind] != NULL ) { 229 attrs = &argv[optind]; 230 } 231 232 uri = tester_uri( uri, host, port ); 233 234 for ( i = 0; i < outerloops; i++ ) { 235 if ( attr != NULL ) { 236 do_random( uri, manager, &passwd, 237 sbase, scope, filter, attr, 238 attrs, noattrs, nobind, 239 loops, retries, delay, force, chaserefs ); 240 241 } else { 242 do_search( uri, manager, &passwd, 243 sbase, scope, filter, NULL, 244 attrs, noattrs, nobind, 245 loops, retries, delay, force, chaserefs ); 246 } 247 } 248 249 exit( EXIT_SUCCESS ); 250 } 251 252 253 static void 254 do_random( char *uri, char *manager, struct berval *passwd, 255 char *sbase, int scope, char *filter, char *attr, 256 char **srchattrs, int noattrs, int nobind, 257 int innerloop, int maxretries, int delay, int force, int chaserefs ) 258 { 259 LDAP *ld = NULL; 260 int i = 0, do_retry = maxretries; 261 char *attrs[ 2 ]; 262 int rc = LDAP_SUCCESS; 263 int version = LDAP_VERSION3; 264 int nvalues = 0; 265 char **values = NULL; 266 LDAPMessage *res = NULL, *e = NULL; 267 268 attrs[ 0 ] = attr; 269 attrs[ 1 ] = NULL; 270 271 ldap_initialize( &ld, uri ); 272 if ( ld == NULL ) { 273 tester_perror( "ldap_initialize", NULL ); 274 exit( EXIT_FAILURE ); 275 } 276 277 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 278 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, 279 chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); 280 281 if ( do_retry == maxretries ) { 282 fprintf( stderr, "PID=%ld - Search(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n", 283 (long) pid, innerloop, sbase, filter, attr ); 284 } 285 286 if ( nobind == 0 ) { 287 rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); 288 if ( rc != LDAP_SUCCESS ) { 289 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); 290 switch ( rc ) { 291 case LDAP_BUSY: 292 case LDAP_UNAVAILABLE: 293 /* fallthru */ 294 default: 295 break; 296 } 297 exit( EXIT_FAILURE ); 298 } 299 } 300 301 rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE, 302 filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); 303 switch ( rc ) { 304 case LDAP_SIZELIMIT_EXCEEDED: 305 case LDAP_TIMELIMIT_EXCEEDED: 306 case LDAP_SUCCESS: 307 if ( ldap_count_entries( ld, res ) == 0 ) { 308 if ( rc ) { 309 tester_ldap_error( ld, "ldap_search_ext_s", NULL ); 310 } 311 break; 312 } 313 314 for ( e = ldap_first_entry( ld, res ); e != NULL; e = ldap_next_entry( ld, e ) ) 315 { 316 struct berval **v = ldap_get_values_len( ld, e, attr ); 317 318 if ( v != NULL ) { 319 int n = ldap_count_values_len( v ); 320 int j; 321 322 values = realloc( values, ( nvalues + n + 1 )*sizeof( char * ) ); 323 for ( j = 0; j < n; j++ ) { 324 values[ nvalues + j ] = strdup( v[ j ]->bv_val ); 325 } 326 values[ nvalues + j ] = NULL; 327 nvalues += n; 328 ldap_value_free_len( v ); 329 } 330 } 331 332 ldap_msgfree( res ); 333 334 if ( !values ) { 335 fprintf( stderr, " PID=%ld - Search base=\"%s\" filter=\"%s\" got %d values.\n", 336 (long) pid, sbase, filter, nvalues ); 337 exit(EXIT_FAILURE); 338 } 339 340 if ( do_retry == maxretries ) { 341 fprintf( stderr, " PID=%ld - Search base=\"%s\" filter=\"%s\" got %d values.\n", 342 (long) pid, sbase, filter, nvalues ); 343 } 344 345 for ( i = 0; i < innerloop; i++ ) { 346 char buf[ BUFSIZ ]; 347 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */ 348 int r = rand() % nvalues; 349 #endif 350 int r = ((double)nvalues)*rand()/(RAND_MAX + 1.0); 351 352 snprintf( buf, sizeof( buf ), "(%s=%s)", attr, values[ r ] ); 353 354 do_search( uri, manager, passwd, 355 sbase, scope, buf, &ld, 356 srchattrs, noattrs, nobind, 357 1, maxretries, delay, force, chaserefs ); 358 } 359 break; 360 361 default: 362 tester_ldap_error( ld, "ldap_search_ext_s", NULL ); 363 break; 364 } 365 366 fprintf( stderr, " PID=%ld - Search done (%d).\n", (long) pid, rc ); 367 368 if ( ld != NULL ) { 369 ldap_unbind_ext( ld, NULL, NULL ); 370 } 371 } 372 373 static void 374 do_search( char *uri, char *manager, struct berval *passwd, 375 char *sbase, int scope, char *filter, LDAP **ldp, 376 char **attrs, int noattrs, int nobind, 377 int innerloop, int maxretries, int delay, int force, int chaserefs ) 378 { 379 LDAP *ld = ldp ? *ldp : NULL; 380 int i = 0, do_retry = maxretries; 381 int rc = LDAP_SUCCESS; 382 int version = LDAP_VERSION3; 383 char buf[ BUFSIZ ]; 384 385 386 retry:; 387 if ( ld == NULL ) { 388 ldap_initialize( &ld, uri ); 389 if ( ld == NULL ) { 390 tester_perror( "ldap_initialize", NULL ); 391 exit( EXIT_FAILURE ); 392 } 393 394 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 395 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, 396 chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); 397 398 if ( do_retry == maxretries ) { 399 fprintf( stderr, 400 "PID=%ld - Search(%d): " 401 "base=\"%s\" scope=%s filter=\"%s\" " 402 "attrs=%s%s.\n", 403 (long) pid, innerloop, 404 sbase, ldap_pvt_scope2str( scope ), filter, 405 attrs[0], attrs[1] ? " (more...)" : "" ); 406 } 407 408 if ( nobind == 0 ) { 409 rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); 410 if ( rc != LDAP_SUCCESS ) { 411 snprintf( buf, sizeof( buf ), 412 "bindDN=\"%s\"", manager ); 413 tester_ldap_error( ld, "ldap_sasl_bind_s", buf ); 414 switch ( rc ) { 415 case LDAP_BUSY: 416 case LDAP_UNAVAILABLE: 417 if ( do_retry > 0 ) { 418 ldap_unbind_ext( ld, NULL, NULL ); 419 ld = NULL; 420 do_retry--; 421 if ( delay != 0 ) { 422 sleep( delay ); 423 } 424 goto retry; 425 } 426 /* fallthru */ 427 default: 428 break; 429 } 430 exit( EXIT_FAILURE ); 431 } 432 } 433 } 434 435 for ( ; i < innerloop; i++ ) { 436 LDAPMessage *res = NULL; 437 438 rc = ldap_search_ext_s( ld, sbase, scope, 439 filter, attrs, noattrs, NULL, NULL, 440 NULL, LDAP_NO_LIMIT, &res ); 441 if ( res != NULL ) { 442 ldap_msgfree( res ); 443 } 444 445 if ( rc ) { 446 unsigned first = tester_ignore_err( rc ); 447 /* if ignore.. */ 448 if ( first ) { 449 /* only log if first occurrence */ 450 if ( force < 2 || first == 1 ) { 451 tester_ldap_error( ld, "ldap_search_ext_s", NULL ); 452 } 453 continue; 454 } 455 456 /* busy needs special handling */ 457 snprintf( buf, sizeof( buf ), 458 "base=\"%s\" filter=\"%s\"\n", 459 sbase, filter ); 460 tester_ldap_error( ld, "ldap_search_ext_s", buf ); 461 if ( rc == LDAP_BUSY && do_retry > 0 ) { 462 ldap_unbind_ext( ld, NULL, NULL ); 463 ld = NULL; 464 do_retry--; 465 goto retry; 466 } 467 break; 468 } 469 } 470 471 if ( ldp != NULL ) { 472 *ldp = ld; 473 474 } else { 475 fprintf( stderr, " PID=%ld - Search done (%d).\n", (long) pid, rc ); 476 477 if ( ld != NULL ) { 478 ldap_unbind_ext( ld, NULL, NULL ); 479 } 480 } 481 } 482