1 /* $NetBSD: slapd-bind.c,v 1.1.1.3 2010/12/12 15:24:16 adam Exp $ */ 2 3 /* OpenLDAP: pkg/ldap/tests/progs/slapd-bind.c,v 1.18.2.12 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 Howard Chu for inclusion 19 * in OpenLDAP Software. 20 */ 21 22 #include "portable.h" 23 24 #include <stdio.h> 25 26 #include "ac/stdlib.h" 27 #include "ac/time.h" 28 29 #include "ac/ctype.h" 30 #include "ac/param.h" 31 #include "ac/socket.h" 32 #include "ac/string.h" 33 #include "ac/unistd.h" 34 #include "ac/wait.h" 35 #include "ac/time.h" 36 37 #include "ldap.h" 38 #include "lutil.h" 39 #include "lber_pvt.h" 40 #include "ldap_pvt.h" 41 42 #include "slapd-common.h" 43 44 #define LOOPS 100 45 46 static int 47 do_bind( char *uri, char *dn, struct berval *pass, int maxloop, 48 int force, int chaserefs, int noinit, LDAP **ldp, 49 int action_type, void *action ); 50 51 static int 52 do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr, 53 int maxloop, int force, int chaserefs, int noinit, int delay, 54 int action_type, void *action ); 55 56 /* This program can be invoked two ways: if -D is used to specify a Bind DN, 57 * that DN will be used repeatedly for all of the Binds. If instead -b is used 58 * to specify a base DN, a search will be done for all "person" objects under 59 * that base DN. Then DNs from this list will be randomly selected for each 60 * Bind request. All of the users must have identical passwords. Also it is 61 * assumed that the users are all onelevel children of the base. 62 */ 63 static void 64 usage( char *name, char opt ) 65 { 66 if ( opt ) { 67 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n", 68 name, opt ); 69 } 70 71 fprintf( stderr, "usage: %s " 72 "[-H uri | -h <host> [-p port]] " 73 "[-D <dn> [-w <passwd>]] " 74 "[-b <baseDN> [-f <searchfilter>] [-a pwattr]] " 75 "[-l <loops>] " 76 "[-L <outerloops>] " 77 "[-B <extra>[,...]] " 78 "[-F] " 79 "[-C] " 80 "[-I] " 81 "[-i <ignore>] " 82 "[-t delay]\n", 83 name ); 84 exit( EXIT_FAILURE ); 85 } 86 87 int 88 main( int argc, char **argv ) 89 { 90 int i; 91 char *uri = NULL; 92 char *host = "localhost"; 93 char *dn = NULL; 94 char *base = NULL; 95 char *filter = "(objectClass=person)"; 96 struct berval pass = { 0, NULL }; 97 char *pwattr = NULL; 98 int port = -1; 99 int loops = LOOPS; 100 int outerloops = 1; 101 int force = 0; 102 int chaserefs = 0; 103 int noinit = 1; 104 int delay = 0; 105 106 /* extra action to do after bind... */ 107 struct berval type[] = { 108 BER_BVC( "tester=" ), 109 BER_BVC( "add=" ), 110 BER_BVC( "bind=" ), 111 BER_BVC( "modify=" ), 112 BER_BVC( "modrdn=" ), 113 BER_BVC( "read=" ), 114 BER_BVC( "search=" ), 115 BER_BVNULL 116 }; 117 118 LDAPURLDesc *extra_ludp = NULL; 119 120 tester_init( "slapd-bind", TESTER_BIND ); 121 122 /* by default, tolerate invalid credentials */ 123 tester_ignore_str2errlist( "INVALID_CREDENTIALS" ); 124 125 while ( ( i = getopt( argc, argv, "a:B:b:D:Ff:H:h:Ii:L:l:p:t:w:" ) ) != EOF ) 126 { 127 switch ( i ) { 128 case 'a': 129 pwattr = optarg; 130 break; 131 132 case 'b': /* base DN of a tree of user DNs */ 133 base = optarg; 134 break; 135 136 case 'B': 137 { 138 int c; 139 140 for ( c = 0; type[c].bv_val; c++ ) { 141 if ( strncasecmp( optarg, type[c].bv_val, type[c].bv_len ) == 0 ) 142 { 143 break; 144 } 145 } 146 147 if ( type[c].bv_val == NULL ) { 148 usage( argv[0], 'B' ); 149 } 150 151 switch ( c ) { 152 case TESTER_TESTER: 153 case TESTER_BIND: 154 /* invalid */ 155 usage( argv[0], 'B' ); 156 157 case TESTER_SEARCH: 158 { 159 if ( ldap_url_parse( &optarg[type[c].bv_len], &extra_ludp ) != LDAP_URL_SUCCESS ) 160 { 161 usage( argv[0], 'B' ); 162 } 163 } break; 164 165 case TESTER_ADDEL: 166 case TESTER_MODIFY: 167 case TESTER_MODRDN: 168 case TESTER_READ: 169 /* nothing to do */ 170 break; 171 172 default: 173 assert( 0 ); 174 } 175 176 } break; 177 178 case 'C': 179 chaserefs++; 180 break; 181 182 case 'H': /* the server uri */ 183 uri = optarg; 184 break; 185 186 case 'h': /* the servers host */ 187 host = optarg; 188 break; 189 190 case 'i': 191 tester_ignore_str2errlist( optarg ); 192 break; 193 194 case 'p': /* the servers port */ 195 if ( lutil_atoi( &port, optarg ) != 0 ) { 196 usage( argv[0], 'p' ); 197 } 198 break; 199 200 case 'D': 201 dn = optarg; 202 break; 203 204 case 'w': 205 ber_str2bv( optarg, 0, 1, &pass ); 206 memset( optarg, '*', pass.bv_len ); 207 break; 208 209 case 'l': /* the number of loops */ 210 if ( lutil_atoi( &loops, optarg ) != 0 ) { 211 usage( argv[0], 'l' ); 212 } 213 break; 214 215 case 'L': /* the number of outerloops */ 216 if ( lutil_atoi( &outerloops, optarg ) != 0 ) { 217 usage( argv[0], 'L' ); 218 } 219 break; 220 221 case 'f': 222 filter = optarg; 223 break; 224 225 case 'F': 226 force++; 227 break; 228 229 case 'I': 230 /* reuse connection */ 231 noinit = 0; 232 break; 233 234 case 't': 235 /* sleep between binds */ 236 if ( lutil_atoi( &delay, optarg ) != 0 ) { 237 usage( argv[0], 't' ); 238 } 239 break; 240 241 default: 242 usage( argv[0], i ); 243 break; 244 } 245 } 246 247 if ( port == -1 && uri == NULL ) { 248 usage( argv[0], '\0' ); 249 } 250 251 uri = tester_uri( uri, host, port ); 252 253 for ( i = 0; i < outerloops; i++ ) { 254 int rc; 255 256 if ( base != NULL ) { 257 rc = do_base( uri, dn, &pass, base, filter, pwattr, loops, 258 force, chaserefs, noinit, delay, -1, NULL ); 259 } else { 260 rc = do_bind( uri, dn, &pass, loops, 261 force, chaserefs, noinit, NULL, -1, NULL ); 262 } 263 if ( rc == LDAP_SERVER_DOWN ) 264 break; 265 } 266 267 exit( EXIT_SUCCESS ); 268 } 269 270 271 static int 272 do_bind( char *uri, char *dn, struct berval *pass, int maxloop, 273 int force, int chaserefs, int noinit, LDAP **ldp, 274 int action_type, void *action ) 275 { 276 LDAP *ld = ldp ? *ldp : NULL; 277 int i, rc = -1; 278 279 /* for internal search */ 280 int timelimit = 0; 281 int sizelimit = 0; 282 283 switch ( action_type ) { 284 case -1: 285 break; 286 287 case TESTER_SEARCH: 288 { 289 LDAPURLDesc *ludp = (LDAPURLDesc *)action; 290 291 assert( action != NULL ); 292 293 if ( ludp->lud_exts != NULL ) { 294 for ( i = 0; ludp->lud_exts[ i ] != NULL; i++ ) { 295 char *ext = ludp->lud_exts[ i ]; 296 int crit = 0; 297 298 if (ext[0] == '!') { 299 crit++; 300 ext++; 301 } 302 303 if ( strncasecmp( ext, "x-timelimit=", STRLENOF( "x-timelimit=" ) ) == 0 ) { 304 if ( lutil_atoi( &timelimit, &ext[ STRLENOF( "x-timelimit=" ) ] ) && crit ) { 305 tester_error( "unable to parse critical extension x-timelimit" ); 306 } 307 308 } else if ( strncasecmp( ext, "x-sizelimit=", STRLENOF( "x-sizelimit=" ) ) == 0 ) { 309 if ( lutil_atoi( &sizelimit, &ext[ STRLENOF( "x-sizelimit=" ) ] ) && crit ) { 310 tester_error( "unable to parse critical extension x-sizelimit" ); 311 } 312 313 } else if ( crit ) { 314 tester_error( "unknown critical extension" ); 315 } 316 } 317 } 318 } break; 319 320 default: 321 /* nothing to do yet */ 322 break; 323 } 324 325 if ( maxloop > 1 ) { 326 fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n", 327 (long) pid, maxloop, dn ); 328 } 329 330 for ( i = 0; i < maxloop; i++ ) { 331 if ( !noinit || ld == NULL ) { 332 int version = LDAP_VERSION3; 333 ldap_initialize( &ld, uri ); 334 if ( ld == NULL ) { 335 tester_perror( "ldap_initialize", NULL ); 336 rc = -1; 337 break; 338 } 339 340 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, 341 &version ); 342 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, 343 chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF ); 344 } 345 346 rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL ); 347 if ( rc ) { 348 int first = tester_ignore_err( rc ); 349 350 /* if ignore.. */ 351 if ( first ) { 352 /* only log if first occurrence */ 353 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) { 354 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); 355 } 356 rc = LDAP_SUCCESS; 357 358 } else { 359 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); 360 } 361 } 362 363 switch ( action_type ) { 364 case -1: 365 break; 366 367 case TESTER_SEARCH: 368 { 369 LDAPURLDesc *ludp = (LDAPURLDesc *)action; 370 LDAPMessage *res = NULL; 371 struct timeval tv = { 0 }, *tvp = NULL; 372 373 if ( timelimit ) { 374 tv.tv_sec = timelimit; 375 tvp = &tv; 376 } 377 378 assert( action != NULL ); 379 380 rc = ldap_search_ext_s( ld, 381 ludp->lud_dn, ludp->lud_scope, 382 ludp->lud_filter, ludp->lud_attrs, 0, 383 NULL, NULL, tvp, sizelimit, &res ); 384 ldap_msgfree( res ); 385 } break; 386 387 default: 388 /* nothing to do yet */ 389 break; 390 } 391 392 if ( !noinit ) { 393 ldap_unbind_ext( ld, NULL, NULL ); 394 ld = NULL; 395 } 396 397 if ( rc != LDAP_SUCCESS ) { 398 break; 399 } 400 } 401 402 if ( maxloop > 1 ) { 403 fprintf( stderr, " PID=%ld - Bind done (%d).\n", (long) pid, rc ); 404 } 405 406 if ( ldp && noinit ) { 407 *ldp = ld; 408 409 } else if ( ld != NULL ) { 410 ldap_unbind_ext( ld, NULL, NULL ); 411 } 412 413 return rc; 414 } 415 416 417 static int 418 do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr, 419 int maxloop, int force, int chaserefs, int noinit, int delay, 420 int action_type, void *action ) 421 { 422 LDAP *ld = NULL; 423 int i = 0; 424 int rc = LDAP_SUCCESS; 425 ber_int_t msgid; 426 LDAPMessage *res, *msg; 427 char **dns = NULL; 428 struct berval *creds = NULL; 429 char *attrs[] = { LDAP_NO_ATTRS, NULL }; 430 int ndns = 0; 431 #ifdef _WIN32 432 DWORD beg, end; 433 #else 434 struct timeval beg, end; 435 #endif 436 int version = LDAP_VERSION3; 437 char *nullstr = ""; 438 439 ldap_initialize( &ld, uri ); 440 if ( ld == NULL ) { 441 tester_perror( "ldap_initialize", NULL ); 442 exit( EXIT_FAILURE ); 443 } 444 445 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 446 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, 447 chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF ); 448 449 rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL ); 450 if ( rc != LDAP_SUCCESS ) { 451 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); 452 exit( EXIT_FAILURE ); 453 } 454 455 fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n", 456 (long) pid, maxloop, base, filter, pwattr ); 457 458 if ( pwattr != NULL ) { 459 attrs[ 0 ] = pwattr; 460 } 461 rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE, 462 filter, attrs, 0, NULL, NULL, 0, 0, &msgid ); 463 if ( rc != LDAP_SUCCESS ) { 464 tester_ldap_error( ld, "ldap_search_ext", NULL ); 465 exit( EXIT_FAILURE ); 466 } 467 468 while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 ) 469 { 470 BerElement *ber; 471 struct berval bv; 472 int done = 0; 473 474 for ( msg = ldap_first_message( ld, res ); msg; 475 msg = ldap_next_message( ld, msg ) ) 476 { 477 switch ( ldap_msgtype( msg ) ) { 478 case LDAP_RES_SEARCH_ENTRY: 479 rc = ldap_get_dn_ber( ld, msg, &ber, &bv ); 480 dns = realloc( dns, (ndns + 1)*sizeof(char *) ); 481 dns[ndns] = ber_strdup( bv.bv_val ); 482 if ( pwattr != NULL ) { 483 struct berval **values = ldap_get_values_len( ld, msg, pwattr ); 484 485 creds = realloc( creds, (ndns + 1)*sizeof(struct berval) ); 486 if ( values == NULL ) { 487 novals:; 488 creds[ndns].bv_len = 0; 489 creds[ndns].bv_val = nullstr; 490 491 } else { 492 static struct berval cleartext = BER_BVC( "{CLEARTEXT} " ); 493 struct berval value = *values[ 0 ]; 494 495 if ( value.bv_val[ 0 ] == '{' ) { 496 char *end = ber_bvchr( &value, '}' ); 497 498 if ( end ) { 499 if ( ber_bvcmp( &value, &cleartext ) == 0 ) { 500 value.bv_val += cleartext.bv_len; 501 value.bv_len -= cleartext.bv_len; 502 503 } else { 504 ldap_value_free_len( values ); 505 goto novals; 506 } 507 } 508 509 } 510 511 ber_dupbv( &creds[ndns], &value ); 512 ldap_value_free_len( values ); 513 } 514 } 515 ndns++; 516 ber_free( ber, 0 ); 517 break; 518 519 case LDAP_RES_SEARCH_RESULT: 520 done = 1; 521 break; 522 } 523 if ( done ) 524 break; 525 } 526 ldap_msgfree( res ); 527 if ( done ) break; 528 } 529 530 #ifdef _WIN32 531 beg = GetTickCount(); 532 #else 533 gettimeofday( &beg, NULL ); 534 #endif 535 536 if ( ndns == 0 ) { 537 tester_error( "No DNs" ); 538 return 1; 539 } 540 541 fprintf( stderr, " PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n", 542 (long) pid, base, filter, ndns ); 543 544 /* Ok, got list of DNs, now start binding to each */ 545 for ( i = 0; i < maxloop; i++ ) { 546 int j; 547 struct berval cred = { 0, NULL }; 548 549 550 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */ 551 j = rand() % ndns; 552 #endif 553 j = ((double)ndns)*rand()/(RAND_MAX + 1.0); 554 555 if ( creds && !BER_BVISEMPTY( &creds[j] ) ) { 556 cred = creds[j]; 557 } 558 559 if ( do_bind( uri, dns[j], &cred, 1, force, chaserefs, noinit, &ld, 560 action_type, action ) && !force ) 561 { 562 break; 563 } 564 565 if ( delay ) { 566 sleep( delay ); 567 } 568 } 569 570 if ( ld != NULL ) { 571 ldap_unbind_ext( ld, NULL, NULL ); 572 ld = NULL; 573 } 574 575 #ifdef _WIN32 576 end = GetTickCount(); 577 end -= beg; 578 579 fprintf( stderr, " PID=%ld - Bind done %d in %d.%03d seconds.\n", 580 (long) pid, i, end / 1000, end % 1000 ); 581 #else 582 gettimeofday( &end, NULL ); 583 end.tv_usec -= beg.tv_usec; 584 if (end.tv_usec < 0 ) { 585 end.tv_usec += 1000000; 586 end.tv_sec -= 1; 587 } 588 end.tv_sec -= beg.tv_sec; 589 590 fprintf( stderr, " PID=%ld - Bind done %d in %ld.%06ld seconds.\n", 591 (long) pid, i, (long) end.tv_sec, (long) end.tv_usec ); 592 #endif 593 594 if ( dns ) { 595 for ( i = 0; i < ndns; i++ ) { 596 ber_memfree( dns[i] ); 597 } 598 free( dns ); 599 } 600 601 if ( creds ) { 602 for ( i = 0; i < ndns; i++ ) { 603 if ( creds[i].bv_val != nullstr ) { 604 ber_memfree( creds[i].bv_val ); 605 } 606 } 607 free( creds ); 608 } 609 610 return 0; 611 } 612