2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2017 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"
37 #include "lutil_ldap.h"
41 #include "slapd-common.h"
44 do_bind( struct tester_conn_args *config, char *dn, int maxloop,
45 int force, int noinit, LDAP **ldp, int action_type, void *action );
48 do_base( struct tester_conn_args *config, char *dn, char *base, char *filter, char *pwattr,
49 int force, int noinit, int action_type, void *action );
51 /* This program can be invoked two ways: if -D is used to specify a Bind DN,
52 * that DN will be used repeatedly for all of the Binds. If instead -b is used
53 * to specify a base DN, a search will be done for all "person" objects under
54 * that base DN. Then DNs from this list will be randomly selected for each
55 * Bind request. All of the users must have identical passwords. Also it is
56 * assumed that the users are all onelevel children of the base.
59 usage( char *name, char opt )
62 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
66 fprintf( stderr, "usage: %s " TESTER_COMMON_HELP
67 "[-b <baseDN> [-f <searchfilter>] [-a pwattr]] "
76 main( int argc, char **argv )
80 char *filter = "(objectClass=person)";
84 struct tester_conn_args *config;
86 /* extra action to do after bind... */
87 struct berval type[] = {
98 LDAPURLDesc *extra_ludp = NULL;
100 config = tester_init( "slapd-bind", TESTER_BIND );
102 /* by default, tolerate invalid credentials */
103 tester_ignore_str2errlist( "INVALID_CREDENTIALS" );
105 while ( ( i = getopt( argc, argv, TESTER_COMMON_OPTS "a:B:b:Ff:I" ) ) != EOF )
112 case 'b': /* base DN of a tree of user DNs */
120 for ( c = 0; type[c].bv_val; c++ ) {
121 if ( strncasecmp( optarg, type[c].bv_val, type[c].bv_len ) == 0 )
127 if ( type[c].bv_val == NULL ) {
128 usage( argv[0], 'B' );
135 usage( argv[0], 'B' );
139 if ( ldap_url_parse( &optarg[type[c].bv_len], &extra_ludp ) != LDAP_URL_SUCCESS )
141 usage( argv[0], 'B' );
167 /* reuse connection */
172 if ( tester_config_opt( config, i, optarg ) == LDAP_SUCCESS ) {
180 tester_config_finish( config );
182 for ( i = 0; i < config->outerloops; i++ ) {
185 if ( base != NULL ) {
186 rc = do_base( config, config->binddn, base,
187 filter, pwattr, force, noinit, -1, NULL );
189 rc = do_bind( config, config->binddn,
190 config->loops, force, noinit, NULL, -1, NULL );
192 if ( rc == LDAP_SERVER_DOWN )
196 exit( EXIT_SUCCESS );
201 do_bind( struct tester_conn_args *config, char *dn, int maxloop,
202 int force, int noinit, LDAP **ldp, int action_type, void *action )
204 LDAP *ld = ldp ? *ldp : NULL;
205 char *bindfunc = "ldap_sasl_bind_s";
208 /* for internal search */
212 switch ( action_type ) {
218 LDAPURLDesc *ludp = (LDAPURLDesc *)action;
220 assert( action != NULL );
222 if ( ludp->lud_exts != NULL ) {
223 for ( i = 0; ludp->lud_exts[ i ] != NULL; i++ ) {
224 char *ext = ludp->lud_exts[ i ];
232 if ( strncasecmp( ext, "x-timelimit=", STRLENOF( "x-timelimit=" ) ) == 0 ) {
233 if ( lutil_atoi( &timelimit, &ext[ STRLENOF( "x-timelimit=" ) ] ) && crit ) {
234 tester_error( "unable to parse critical extension x-timelimit" );
237 } else if ( strncasecmp( ext, "x-sizelimit=", STRLENOF( "x-sizelimit=" ) ) == 0 ) {
238 if ( lutil_atoi( &sizelimit, &ext[ STRLENOF( "x-sizelimit=" ) ] ) && crit ) {
239 tester_error( "unable to parse critical extension x-sizelimit" );
243 tester_error( "unknown critical extension" );
250 /* nothing to do yet */
255 fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n",
256 (long) pid, maxloop, dn );
259 for ( i = 0; i < maxloop; i++ ) {
260 if ( !noinit || ld == NULL ) {
261 tester_init_ld( &ld, config, TESTER_INIT_ONLY );
263 #ifdef HAVE_CYRUS_SASL
264 if ( config->secprops != NULL ) {
265 rc = ldap_set_option( ld,
266 LDAP_OPT_X_SASL_SECPROPS, config->secprops );
268 if( rc != LDAP_OPT_SUCCESS ) {
269 tester_ldap_error( ld, "ldap_set_option(SECPROPS)", NULL );
270 exit( EXIT_FAILURE );
276 if ( config->authmethod == LDAP_AUTH_SASL ) {
277 #ifdef HAVE_CYRUS_SASL
278 bindfunc = "ldap_sasl_interactive_bind_s";
279 rc = ldap_sasl_interactive_bind_s( ld,
286 #else /* HAVE_CYRUS_SASL */
287 /* caller shouldn't have allowed this */
290 } else if ( config->authmethod == LDAP_AUTH_SIMPLE ) {
291 bindfunc = "ldap_sasl_bind_s";
292 rc = ldap_sasl_bind_s( ld,
293 config->binddn, LDAP_SASL_SIMPLE,
294 &config->pass, NULL, NULL, NULL );
298 int first = tester_ignore_err( rc );
302 /* only log if first occurrence */
303 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
304 tester_ldap_error( ld, bindfunc, NULL );
309 tester_ldap_error( ld, bindfunc, NULL );
313 switch ( action_type ) {
319 LDAPURLDesc *ludp = (LDAPURLDesc *)action;
320 LDAPMessage *res = NULL;
321 struct timeval tv = { 0 }, *tvp = NULL;
324 tv.tv_sec = timelimit;
328 assert( action != NULL );
330 rc = ldap_search_ext_s( ld,
331 ludp->lud_dn, ludp->lud_scope,
332 ludp->lud_filter, ludp->lud_attrs, 0,
333 NULL, NULL, tvp, sizelimit, &res );
338 /* nothing to do yet */
343 ldap_unbind_ext( ld, NULL, NULL );
347 if ( rc != LDAP_SUCCESS ) {
353 fprintf( stderr, " PID=%ld - Bind done (%d).\n", (long) pid, rc );
356 if ( ldp && noinit ) {
359 } else if ( ld != NULL ) {
360 ldap_unbind_ext( ld, NULL, NULL );
368 do_base( struct tester_conn_args *config, char *dn, char *base, char *filter, char *pwattr,
369 int force, int noinit, int action_type, void *action )
373 int rc = LDAP_SUCCESS;
375 LDAPMessage *res, *msg;
377 struct berval *creds = NULL;
378 char *attrs[] = { LDAP_NO_ATTRS, NULL };
383 struct timeval beg, end;
387 tester_init_ld( &ld, config, 0 );
389 fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n",
390 (long) pid, config->loops, base, filter, pwattr );
392 if ( pwattr != NULL ) {
395 rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE,
396 filter, attrs, 0, NULL, NULL, 0, 0, &msgid );
397 if ( rc != LDAP_SUCCESS ) {
398 tester_ldap_error( ld, "ldap_search_ext", NULL );
399 exit( EXIT_FAILURE );
402 while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 )
408 for ( msg = ldap_first_message( ld, res ); msg;
409 msg = ldap_next_message( ld, msg ) )
411 switch ( ldap_msgtype( msg ) ) {
412 case LDAP_RES_SEARCH_ENTRY:
413 rc = ldap_get_dn_ber( ld, msg, &ber, &bv );
414 dns = realloc( dns, (ndns + 1)*sizeof(char *) );
415 dns[ndns] = ber_strdup( bv.bv_val );
416 if ( pwattr != NULL ) {
417 struct berval **values = ldap_get_values_len( ld, msg, pwattr );
419 creds = realloc( creds, (ndns + 1)*sizeof(struct berval) );
420 if ( values == NULL ) {
422 creds[ndns].bv_len = 0;
423 creds[ndns].bv_val = nullstr;
426 static struct berval cleartext = BER_BVC( "{CLEARTEXT} " );
427 struct berval value = *values[ 0 ];
429 if ( value.bv_val[ 0 ] == '{' ) {
430 char *end = ber_bvchr( &value, '}' );
433 if ( ber_bvcmp( &value, &cleartext ) == 0 ) {
434 value.bv_val += cleartext.bv_len;
435 value.bv_len -= cleartext.bv_len;
438 ldap_value_free_len( values );
445 ber_dupbv( &creds[ndns], &value );
446 ldap_value_free_len( values );
453 case LDAP_RES_SEARCH_RESULT:
465 beg = GetTickCount();
467 gettimeofday( &beg, NULL );
471 tester_error( "No DNs" );
475 fprintf( stderr, " PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n",
476 (long) pid, base, filter, ndns );
478 /* Ok, got list of DNs, now start binding to each */
479 for ( i = 0; i < config->loops; i++ ) {
482 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */
485 j = ((double)ndns)*rand()/(RAND_MAX + 1.0);
487 if ( creds && !BER_BVISEMPTY( &creds[j] ) ) {
488 config->pass = creds[j];
491 if ( do_bind( config, dns[j], 1, force, noinit, &ld,
492 action_type, action ) && !force )
497 if ( config->delay ) {
498 sleep( config->delay );
503 ldap_unbind_ext( ld, NULL, NULL );
508 end = GetTickCount();
511 fprintf( stderr, " PID=%ld - Bind done %d in %d.%03d seconds.\n",
512 (long) pid, i, end / 1000, end % 1000 );
514 gettimeofday( &end, NULL );
515 end.tv_usec -= beg.tv_usec;
516 if (end.tv_usec < 0 ) {
517 end.tv_usec += 1000000;
520 end.tv_sec -= beg.tv_sec;
522 fprintf( stderr, " PID=%ld - Bind done %d in %ld.%06ld seconds.\n",
523 (long) pid, i, (long) end.tv_sec, (long) end.tv_usec );
527 for ( i = 0; i < ndns; i++ ) {
528 ber_memfree( dns[i] );
534 for ( i = 0; i < ndns; i++ ) {
535 if ( creds[i].bv_val != nullstr ) {
536 ber_memfree( creds[i].bv_val );