2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2006 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
16 * This work was initially developed by Howard Chu for inclusion
17 * in OpenLDAP Software.
24 #include <ac/stdlib.h>
29 #include <ac/socket.h>
30 #include <ac/string.h>
31 #include <ac/unistd.h>
40 #include "slapd-common.h"
45 do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
46 int force, int chaserefs, int noinit, LDAP **ldp,
47 int action_type, void *action );
50 do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr,
51 int maxloop, int force, int chaserefs, int noinit, int delay,
52 int action_type, void *action );
54 /* This program can be invoked two ways: if -D is used to specify a Bind DN,
55 * that DN will be used repeatedly for all of the Binds. If instead -b is used
56 * to specify a base DN, a search will be done for all "person" objects under
57 * that base DN. Then DNs from this list will be randomly selected for each
58 * Bind request. All of the users must have identical passwords. Also it is
59 * assumed that the users are all onelevel children of the base.
62 usage( char *name, char opt )
65 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
69 fprintf( stderr, "usage: %s "
70 "[-H uri | -h <host> [-p port]] "
71 "[-D <dn> [-w <passwd>]] "
72 "[-b <baseDN> [-f <searchfilter>] [-a pwattr]] "
86 main( int argc, char **argv )
90 char *host = "localhost";
93 char *filter = "(objectClass=person)";
94 struct berval pass = { 0, NULL };
104 /* extra action to do after bind... */
105 struct berval type[] = {
106 BER_BVC( "tester=" ),
109 BER_BVC( "modify=" ),
110 BER_BVC( "modrdn=" ),
112 BER_BVC( "search=" ),
116 LDAPURLDesc *extra_ludp = NULL;
118 tester_init( "slapd-bind", TESTER_BIND );
120 /* by default, tolerate invalid credentials */
121 tester_ignore_str2errlist( "INVALID_CREDENTIALS" );
123 while ( (i = getopt( argc, argv, "a:b:B:H:h:i:p:D:w:l:L:f:FIt:" )) != EOF ) {
129 case 'b': /* base DN of a tree of user DNs */
137 for ( c = 0; type[c].bv_val; c++ ) {
138 if ( strncasecmp( optarg, type[c].bv_val, type[c].bv_len ) == 0 )
144 if ( type[c].bv_val == NULL ) {
145 usage( argv[0], 'B' );
152 usage( argv[0], 'B' );
156 if ( ldap_url_parse( &optarg[type[c].bv_len], &extra_ludp ) != LDAP_URL_SUCCESS )
158 usage( argv[0], 'B' );
179 case 'H': /* the server uri */
183 case 'h': /* the servers host */
188 tester_ignore_str2errlist( optarg );
191 case 'p': /* the servers port */
192 if ( lutil_atoi( &port, optarg ) != 0 ) {
193 usage( argv[0], 'p' );
202 ber_str2bv( optarg, 0, 1, &pass );
203 memset( optarg, '*', pass.bv_len );
206 case 'l': /* the number of loops */
207 if ( lutil_atoi( &loops, optarg ) != 0 ) {
208 usage( argv[0], 'l' );
212 case 'L': /* the number of outerloops */
213 if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
214 usage( argv[0], 'L' );
227 /* reuse connection */
232 /* sleep between binds */
233 if ( lutil_atoi( &delay, optarg ) != 0 ) {
234 usage( argv[0], 't' );
244 if ( port == -1 && uri == NULL ) {
245 usage( argv[0], '\0' );
248 uri = tester_uri( uri, host, port );
250 for ( i = 0; i < outerloops; i++ ) {
251 if ( base != NULL ) {
252 do_base( uri, dn, &pass, base, filter, pwattr, loops,
253 force, chaserefs, noinit, delay, -1, NULL );
255 do_bind( uri, dn, &pass, loops,
256 force, chaserefs, noinit, NULL, -1, NULL );
260 exit( EXIT_SUCCESS );
265 do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
266 int force, int chaserefs, int noinit, LDAP **ldp,
267 int action_type, void *action )
269 LDAP *ld = ldp ? *ldp : NULL;
272 /* for internal search */
276 switch ( action_type ) {
282 LDAPURLDesc *ludp = (LDAPURLDesc *)action;
284 assert( action != NULL );
286 if ( ludp->lud_exts != NULL ) {
287 for ( i = 0; ludp->lud_exts[ i ] != NULL; i++ ) {
288 char *ext = ludp->lud_exts[ i ];
296 if ( strncasecmp( ext, "x-timelimit=", STRLENOF( "x-timelimit=" ) ) == 0 ) {
297 if ( lutil_atoi( &timelimit, &ext[ STRLENOF( "x-timelimit=" ) ] ) && crit ) {
298 tester_error( "unable to parse critical extension x-timelimit" );
301 } else if ( strncasecmp( ext, "x-sizelimit=", STRLENOF( "x-sizelimit=" ) ) == 0 ) {
302 if ( lutil_atoi( &sizelimit, &ext[ STRLENOF( "x-sizelimit=" ) ] ) && crit ) {
303 tester_error( "unable to parse critical extension x-sizelimit" );
307 tester_error( "unknown critical extension" );
314 /* nothing to do yet */
319 fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n",
320 (long) pid, maxloop, dn );
323 for ( i = 0; i < maxloop; i++ ) {
324 if ( !noinit || ld == NULL ) {
325 int version = LDAP_VERSION3;
326 ldap_initialize( &ld, uri );
328 tester_perror( "ldap_initialize", NULL );
333 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
335 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
336 chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );
339 rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
341 unsigned first = tester_ignore_err( rc );
345 /* only log if first occurrence */
346 if ( force < 2 || first == 1 ) {
347 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
352 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
356 switch ( action_type ) {
362 LDAPURLDesc *ludp = (LDAPURLDesc *)action;
363 LDAPMessage *res = NULL;
364 struct timeval tv = { 0 }, *tvp = NULL;
367 tv.tv_sec = timelimit;
371 assert( action != NULL );
373 rc = ldap_search_ext_s( ld,
374 ludp->lud_dn, ludp->lud_scope,
375 ludp->lud_filter, ludp->lud_attrs, 0,
376 NULL, NULL, tvp, sizelimit, &res );
381 /* nothing to do yet */
386 ldap_unbind_ext( ld, NULL, NULL );
390 if ( rc != LDAP_SUCCESS ) {
396 fprintf( stderr, " PID=%ld - Bind done (%d).\n", (long) pid, rc );
399 if ( ldp && noinit ) {
402 } else if ( ld != NULL ) {
403 ldap_unbind_ext( ld, NULL, NULL );
411 do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr,
412 int maxloop, int force, int chaserefs, int noinit, int delay,
413 int action_type, void *action )
417 int rc = LDAP_SUCCESS;
419 LDAPMessage *res, *msg;
421 struct berval *creds = NULL;
422 char *attrs[] = { LDAP_NO_ATTRS, NULL };
427 struct timeval beg, end;
429 int version = LDAP_VERSION3;
432 ldap_initialize( &ld, uri );
434 tester_perror( "ldap_initialize", NULL );
435 exit( EXIT_FAILURE );
438 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
439 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
440 chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );
442 rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
443 if ( rc != LDAP_SUCCESS ) {
444 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
445 exit( EXIT_FAILURE );
448 fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n",
449 (long) pid, maxloop, base, filter, pwattr );
451 if ( pwattr != NULL ) {
454 rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE,
455 filter, attrs, 0, NULL, NULL, 0, 0, &msgid );
456 if ( rc != LDAP_SUCCESS ) {
457 tester_ldap_error( ld, "ldap_search_ext", NULL );
458 exit( EXIT_FAILURE );
461 while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 )
467 for ( msg = ldap_first_message( ld, res ); msg;
468 msg = ldap_next_message( ld, msg ) )
470 switch ( ldap_msgtype( msg ) ) {
471 case LDAP_RES_SEARCH_ENTRY:
472 rc = ldap_get_dn_ber( ld, msg, &ber, &bv );
473 dns = realloc( dns, (ndns + 1)*sizeof(char *) );
474 dns[ndns] = ber_strdup( bv.bv_val );
475 if ( pwattr != NULL ) {
476 struct berval **values = ldap_get_values_len( ld, msg, pwattr );
478 creds = realloc( creds, (ndns + 1)*sizeof(struct berval) );
479 if ( values == NULL ) {
481 creds[ndns].bv_len = 0;
482 creds[ndns].bv_val = nullstr;
485 static struct berval cleartext = BER_BVC( "{CLEARTEXT} " );
486 struct berval value = *values[ 0 ];
488 if ( value.bv_val[ 0 ] == '{' ) {
489 char *end = ber_bvchr( &value, '}' );
492 if ( ber_bvcmp( &value, &cleartext ) == 0 ) {
493 value.bv_val += cleartext.bv_len;
494 value.bv_len -= cleartext.bv_len;
497 ldap_value_free_len( values );
504 ber_dupbv( &creds[ndns], &value );
505 ldap_value_free_len( values );
512 case LDAP_RES_SEARCH_RESULT:
524 beg = GetTickCount();
526 gettimeofday( &beg, NULL );
530 tester_error( "No DNs" );
534 fprintf( stderr, " PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n",
535 (long) pid, base, filter, ndns );
537 /* Ok, got list of DNs, now start binding to each */
538 for ( i = 0; i < maxloop; i++ ) {
540 struct berval cred = { 0, NULL };
543 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */
546 j = ((double)ndns)*rand()/(RAND_MAX + 1.0);
548 if ( creds && !BER_BVISEMPTY( &creds[j] ) ) {
552 if ( do_bind( uri, dns[j], &cred, 1, force, chaserefs, noinit, &ld,
553 action_type, action ) && !force )
564 ldap_unbind_ext( ld, NULL, NULL );
569 end = GetTickCount();
572 fprintf( stderr, " PID=%ld - Bind done %d in %d.%03d seconds.\n",
573 (long) pid, i, end / 1000, end % 1000 );
575 gettimeofday( &end, NULL );
576 end.tv_usec -= beg.tv_usec;
577 if (end.tv_usec < 0 ) {
578 end.tv_usec += 1000000;
581 end.tv_sec -= beg.tv_sec;
583 fprintf( stderr, " PID=%ld - Bind done %d in %ld.%06ld seconds.\n",
584 (long) pid, i, (long) end.tv_sec, (long) end.tv_usec );
588 for ( i = 0; i < ndns; i++ ) {
595 for ( i = 0; i < ndns; i++ ) {
596 if ( creds[i].bv_val != nullstr ) {
597 free( creds[i].bv_val );