1 /* $OpenLDAP: pkg/ldap/tests/progs/slapd-bind.c,v 1.18.2.7 2008/02/11 23:26:50 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2008 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:D:Ff:H:h:Ii:L:l:p:t:w:" ) ) != EOF
)
130 case 'b': /* base DN of a tree of user DNs */
138 for ( c
= 0; type
[c
].bv_val
; c
++ ) {
139 if ( strncasecmp( optarg
, type
[c
].bv_val
, type
[c
].bv_len
) == 0 )
145 if ( type
[c
].bv_val
== NULL
) {
146 usage( argv
[0], 'B' );
153 usage( argv
[0], 'B' );
157 if ( ldap_url_parse( &optarg
[type
[c
].bv_len
], &extra_ludp
) != LDAP_URL_SUCCESS
)
159 usage( argv
[0], 'B' );
180 case 'H': /* the server uri */
184 case 'h': /* the servers host */
189 tester_ignore_str2errlist( optarg
);
192 case 'p': /* the servers port */
193 if ( lutil_atoi( &port
, optarg
) != 0 ) {
194 usage( argv
[0], 'p' );
203 ber_str2bv( optarg
, 0, 1, &pass
);
204 memset( optarg
, '*', pass
.bv_len
);
207 case 'l': /* the number of loops */
208 if ( lutil_atoi( &loops
, optarg
) != 0 ) {
209 usage( argv
[0], 'l' );
213 case 'L': /* the number of outerloops */
214 if ( lutil_atoi( &outerloops
, optarg
) != 0 ) {
215 usage( argv
[0], 'L' );
228 /* reuse connection */
233 /* sleep between binds */
234 if ( lutil_atoi( &delay
, optarg
) != 0 ) {
235 usage( argv
[0], 't' );
245 if ( port
== -1 && uri
== NULL
) {
246 usage( argv
[0], '\0' );
249 uri
= tester_uri( uri
, host
, port
);
251 for ( i
= 0; i
< outerloops
; i
++ ) {
252 if ( base
!= NULL
) {
253 do_base( uri
, dn
, &pass
, base
, filter
, pwattr
, loops
,
254 force
, chaserefs
, noinit
, delay
, -1, NULL
);
256 do_bind( uri
, dn
, &pass
, loops
,
257 force
, chaserefs
, noinit
, NULL
, -1, NULL
);
261 exit( EXIT_SUCCESS
);
266 do_bind( char *uri
, char *dn
, struct berval
*pass
, int maxloop
,
267 int force
, int chaserefs
, int noinit
, LDAP
**ldp
,
268 int action_type
, void *action
)
270 LDAP
*ld
= ldp
? *ldp
: NULL
;
273 /* for internal search */
277 switch ( action_type
) {
283 LDAPURLDesc
*ludp
= (LDAPURLDesc
*)action
;
285 assert( action
!= NULL
);
287 if ( ludp
->lud_exts
!= NULL
) {
288 for ( i
= 0; ludp
->lud_exts
[ i
] != NULL
; i
++ ) {
289 char *ext
= ludp
->lud_exts
[ i
];
297 if ( strncasecmp( ext
, "x-timelimit=", STRLENOF( "x-timelimit=" ) ) == 0 ) {
298 if ( lutil_atoi( &timelimit
, &ext
[ STRLENOF( "x-timelimit=" ) ] ) && crit
) {
299 tester_error( "unable to parse critical extension x-timelimit" );
302 } else if ( strncasecmp( ext
, "x-sizelimit=", STRLENOF( "x-sizelimit=" ) ) == 0 ) {
303 if ( lutil_atoi( &sizelimit
, &ext
[ STRLENOF( "x-sizelimit=" ) ] ) && crit
) {
304 tester_error( "unable to parse critical extension x-sizelimit" );
308 tester_error( "unknown critical extension" );
315 /* nothing to do yet */
320 fprintf( stderr
, "PID=%ld - Bind(%d): dn=\"%s\".\n",
321 (long) pid
, maxloop
, dn
);
324 for ( i
= 0; i
< maxloop
; i
++ ) {
325 if ( !noinit
|| ld
== NULL
) {
326 int version
= LDAP_VERSION3
;
327 ldap_initialize( &ld
, uri
);
329 tester_perror( "ldap_initialize", NULL
);
334 (void) ldap_set_option( ld
, LDAP_OPT_PROTOCOL_VERSION
,
336 (void) ldap_set_option( ld
, LDAP_OPT_REFERRALS
,
337 chaserefs
? LDAP_OPT_ON
: LDAP_OPT_OFF
);
340 rc
= ldap_sasl_bind_s( ld
, dn
, LDAP_SASL_SIMPLE
, pass
, NULL
, NULL
, NULL
);
342 unsigned first
= tester_ignore_err( rc
);
346 /* only log if first occurrence */
347 if ( force
< 2 || first
== 1 ) {
348 tester_ldap_error( ld
, "ldap_sasl_bind_s", NULL
);
353 tester_ldap_error( ld
, "ldap_sasl_bind_s", NULL
);
357 switch ( action_type
) {
363 LDAPURLDesc
*ludp
= (LDAPURLDesc
*)action
;
364 LDAPMessage
*res
= NULL
;
365 struct timeval tv
= { 0 }, *tvp
= NULL
;
368 tv
.tv_sec
= timelimit
;
372 assert( action
!= NULL
);
374 rc
= ldap_search_ext_s( ld
,
375 ludp
->lud_dn
, ludp
->lud_scope
,
376 ludp
->lud_filter
, ludp
->lud_attrs
, 0,
377 NULL
, NULL
, tvp
, sizelimit
, &res
);
382 /* nothing to do yet */
387 ldap_unbind_ext( ld
, NULL
, NULL
);
391 if ( rc
!= LDAP_SUCCESS
) {
397 fprintf( stderr
, " PID=%ld - Bind done (%d).\n", (long) pid
, rc
);
400 if ( ldp
&& noinit
) {
403 } else if ( ld
!= NULL
) {
404 ldap_unbind_ext( ld
, NULL
, NULL
);
412 do_base( char *uri
, char *dn
, struct berval
*pass
, char *base
, char *filter
, char *pwattr
,
413 int maxloop
, int force
, int chaserefs
, int noinit
, int delay
,
414 int action_type
, void *action
)
418 int rc
= LDAP_SUCCESS
;
420 LDAPMessage
*res
, *msg
;
422 struct berval
*creds
= NULL
;
423 char *attrs
[] = { LDAP_NO_ATTRS
, NULL
};
428 struct timeval beg
, end
;
430 int version
= LDAP_VERSION3
;
433 ldap_initialize( &ld
, uri
);
435 tester_perror( "ldap_initialize", NULL
);
436 exit( EXIT_FAILURE
);
439 (void) ldap_set_option( ld
, LDAP_OPT_PROTOCOL_VERSION
, &version
);
440 (void) ldap_set_option( ld
, LDAP_OPT_REFERRALS
,
441 chaserefs
? LDAP_OPT_ON
: LDAP_OPT_OFF
);
443 rc
= ldap_sasl_bind_s( ld
, dn
, LDAP_SASL_SIMPLE
, pass
, NULL
, NULL
, NULL
);
444 if ( rc
!= LDAP_SUCCESS
) {
445 tester_ldap_error( ld
, "ldap_sasl_bind_s", NULL
);
446 exit( EXIT_FAILURE
);
449 fprintf( stderr
, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n",
450 (long) pid
, maxloop
, base
, filter
, pwattr
);
452 if ( pwattr
!= NULL
) {
455 rc
= ldap_search_ext( ld
, base
, LDAP_SCOPE_SUBTREE
,
456 filter
, attrs
, 0, NULL
, NULL
, 0, 0, &msgid
);
457 if ( rc
!= LDAP_SUCCESS
) {
458 tester_ldap_error( ld
, "ldap_search_ext", NULL
);
459 exit( EXIT_FAILURE
);
462 while ( ( rc
= ldap_result( ld
, LDAP_RES_ANY
, LDAP_MSG_ONE
, NULL
, &res
) ) > 0 )
468 for ( msg
= ldap_first_message( ld
, res
); msg
;
469 msg
= ldap_next_message( ld
, msg
) )
471 switch ( ldap_msgtype( msg
) ) {
472 case LDAP_RES_SEARCH_ENTRY
:
473 rc
= ldap_get_dn_ber( ld
, msg
, &ber
, &bv
);
474 dns
= realloc( dns
, (ndns
+ 1)*sizeof(char *) );
475 dns
[ndns
] = ber_strdup( bv
.bv_val
);
476 if ( pwattr
!= NULL
) {
477 struct berval
**values
= ldap_get_values_len( ld
, msg
, pwattr
);
479 creds
= realloc( creds
, (ndns
+ 1)*sizeof(struct berval
) );
480 if ( values
== NULL
) {
482 creds
[ndns
].bv_len
= 0;
483 creds
[ndns
].bv_val
= nullstr
;
486 static struct berval cleartext
= BER_BVC( "{CLEARTEXT} " );
487 struct berval value
= *values
[ 0 ];
489 if ( value
.bv_val
[ 0 ] == '{' ) {
490 char *end
= ber_bvchr( &value
, '}' );
493 if ( ber_bvcmp( &value
, &cleartext
) == 0 ) {
494 value
.bv_val
+= cleartext
.bv_len
;
495 value
.bv_len
-= cleartext
.bv_len
;
498 ldap_value_free_len( values
);
505 ber_dupbv( &creds
[ndns
], &value
);
506 ldap_value_free_len( values
);
513 case LDAP_RES_SEARCH_RESULT
:
525 beg
= GetTickCount();
527 gettimeofday( &beg
, NULL
);
531 tester_error( "No DNs" );
535 fprintf( stderr
, " PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n",
536 (long) pid
, base
, filter
, ndns
);
538 /* Ok, got list of DNs, now start binding to each */
539 for ( i
= 0; i
< maxloop
; i
++ ) {
541 struct berval cred
= { 0, NULL
};
544 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */
547 j
= ((double)ndns
)*rand()/(RAND_MAX
+ 1.0);
549 if ( creds
&& !BER_BVISEMPTY( &creds
[j
] ) ) {
553 if ( do_bind( uri
, dns
[j
], &cred
, 1, force
, chaserefs
, noinit
, &ld
,
554 action_type
, action
) && !force
)
565 ldap_unbind_ext( ld
, NULL
, NULL
);
570 end
= GetTickCount();
573 fprintf( stderr
, " PID=%ld - Bind done %d in %d.%03d seconds.\n",
574 (long) pid
, i
, end
/ 1000, end
% 1000 );
576 gettimeofday( &end
, NULL
);
577 end
.tv_usec
-= beg
.tv_usec
;
578 if (end
.tv_usec
< 0 ) {
579 end
.tv_usec
+= 1000000;
582 end
.tv_sec
-= beg
.tv_sec
;
584 fprintf( stderr
, " PID=%ld - Bind done %d in %ld.%06ld seconds.\n",
585 (long) pid
, i
, (long) end
.tv_sec
, (long) end
.tv_usec
);
589 for ( i
= 0; i
< ndns
; i
++ ) {
596 for ( i
= 0; i
< ndns
; i
++ ) {
597 if ( creds
[i
].bv_val
!= nullstr
) {
598 free( creds
[i
].bv_val
);