Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / openldap / dist / tests / progs / slapd-bind.c
blobd6fba10bc85ede439ec258e5d710bcd975cfb863
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.
5 * All rights reserved.
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.
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>.
15 /* ACKNOWLEDGEMENTS:
16 * This work was initially developed by Howard Chu for inclusion
17 * in OpenLDAP Software.
20 #include "portable.h"
22 #include <stdio.h>
24 #include "ac/stdlib.h"
25 #include "ac/time.h"
27 #include "ac/ctype.h"
28 #include "ac/param.h"
29 #include "ac/socket.h"
30 #include "ac/string.h"
31 #include "ac/unistd.h"
32 #include "ac/wait.h"
33 #include "ac/time.h"
35 #include "ldap.h"
36 #include "lutil.h"
37 #include "lber_pvt.h"
38 #include "ldap_pvt.h"
40 #include "slapd-common.h"
42 #define LOOPS 100
44 static int
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 );
49 static int
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.
61 static void
62 usage( char *name, char opt )
64 if ( opt ) {
65 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
66 name, opt );
69 fprintf( stderr, "usage: %s "
70 "[-H uri | -h <host> [-p port]] "
71 "[-D <dn> [-w <passwd>]] "
72 "[-b <baseDN> [-f <searchfilter>] [-a pwattr]] "
73 "[-l <loops>] "
74 "[-L <outerloops>] "
75 "[-B <extra>[,...]] "
76 "[-F] "
77 "[-C] "
78 "[-I] "
79 "[-i <ignore>] "
80 "[-t delay]\n",
81 name );
82 exit( EXIT_FAILURE );
85 int
86 main( int argc, char **argv )
88 int i;
89 char *uri = NULL;
90 char *host = "localhost";
91 char *dn = NULL;
92 char *base = NULL;
93 char *filter = "(objectClass=person)";
94 struct berval pass = { 0, NULL };
95 char *pwattr = NULL;
96 int port = -1;
97 int loops = LOOPS;
98 int outerloops = 1;
99 int force = 0;
100 int chaserefs = 0;
101 int noinit = 1;
102 int delay = 0;
104 /* extra action to do after bind... */
105 struct berval type[] = {
106 BER_BVC( "tester=" ),
107 BER_BVC( "add=" ),
108 BER_BVC( "bind=" ),
109 BER_BVC( "modify=" ),
110 BER_BVC( "modrdn=" ),
111 BER_BVC( "read=" ),
112 BER_BVC( "search=" ),
113 BER_BVNULL
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 )
125 switch ( i ) {
126 case 'a':
127 pwattr = optarg;
128 break;
130 case 'b': /* base DN of a tree of user DNs */
131 base = optarg;
132 break;
134 case 'B':
136 int c;
138 for ( c = 0; type[c].bv_val; c++ ) {
139 if ( strncasecmp( optarg, type[c].bv_val, type[c].bv_len ) == 0 )
141 break;
145 if ( type[c].bv_val == NULL ) {
146 usage( argv[0], 'B' );
149 switch ( c ) {
150 case TESTER_TESTER:
151 case TESTER_BIND:
152 /* invalid */
153 usage( argv[0], 'B' );
155 case TESTER_SEARCH:
157 if ( ldap_url_parse( &optarg[type[c].bv_len], &extra_ludp ) != LDAP_URL_SUCCESS )
159 usage( argv[0], 'B' );
161 } break;
163 case TESTER_ADDEL:
164 case TESTER_MODIFY:
165 case TESTER_MODRDN:
166 case TESTER_READ:
167 /* nothing to do */
168 break;
170 default:
171 assert( 0 );
174 } break;
176 case 'C':
177 chaserefs++;
178 break;
180 case 'H': /* the server uri */
181 uri = optarg;
182 break;
184 case 'h': /* the servers host */
185 host = optarg;
186 break;
188 case 'i':
189 tester_ignore_str2errlist( optarg );
190 break;
192 case 'p': /* the servers port */
193 if ( lutil_atoi( &port, optarg ) != 0 ) {
194 usage( argv[0], 'p' );
196 break;
198 case 'D':
199 dn = optarg;
200 break;
202 case 'w':
203 ber_str2bv( optarg, 0, 1, &pass );
204 memset( optarg, '*', pass.bv_len );
205 break;
207 case 'l': /* the number of loops */
208 if ( lutil_atoi( &loops, optarg ) != 0 ) {
209 usage( argv[0], 'l' );
211 break;
213 case 'L': /* the number of outerloops */
214 if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
215 usage( argv[0], 'L' );
217 break;
219 case 'f':
220 filter = optarg;
221 break;
223 case 'F':
224 force++;
225 break;
227 case 'I':
228 /* reuse connection */
229 noinit = 0;
230 break;
232 case 't':
233 /* sleep between binds */
234 if ( lutil_atoi( &delay, optarg ) != 0 ) {
235 usage( argv[0], 't' );
237 break;
239 default:
240 usage( argv[0], i );
241 break;
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 );
255 } else {
256 do_bind( uri, dn, &pass, loops,
257 force, chaserefs, noinit, NULL, -1, NULL );
261 exit( EXIT_SUCCESS );
265 static int
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;
271 int i, rc = -1;
273 /* for internal search */
274 int timelimit = 0;
275 int sizelimit = 0;
277 switch ( action_type ) {
278 case -1:
279 break;
281 case TESTER_SEARCH:
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 ];
290 int crit = 0;
292 if (ext[0] == '!') {
293 crit++;
294 ext++;
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" );
307 } else if ( crit ) {
308 tester_error( "unknown critical extension" );
312 } break;
314 default:
315 /* nothing to do yet */
316 break;
319 if ( maxloop > 1 ) {
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 );
328 if ( ld == NULL ) {
329 tester_perror( "ldap_initialize", NULL );
330 rc = -1;
331 break;
334 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
335 &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 );
341 if ( rc ) {
342 unsigned first = tester_ignore_err( rc );
344 /* if ignore.. */
345 if ( first ) {
346 /* only log if first occurrence */
347 if ( force < 2 || first == 1 ) {
348 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
350 rc = LDAP_SUCCESS;
352 } else {
353 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
357 switch ( action_type ) {
358 case -1:
359 break;
361 case TESTER_SEARCH:
363 LDAPURLDesc *ludp = (LDAPURLDesc *)action;
364 LDAPMessage *res = NULL;
365 struct timeval tv = { 0 }, *tvp = NULL;
367 if ( timelimit ) {
368 tv.tv_sec = timelimit;
369 tvp = &tv;
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 );
378 ldap_msgfree( res );
379 } break;
381 default:
382 /* nothing to do yet */
383 break;
386 if ( !noinit ) {
387 ldap_unbind_ext( ld, NULL, NULL );
388 ld = NULL;
391 if ( rc != LDAP_SUCCESS ) {
392 break;
396 if ( maxloop > 1 ) {
397 fprintf( stderr, " PID=%ld - Bind done (%d).\n", (long) pid, rc );
400 if ( ldp && noinit ) {
401 *ldp = ld;
403 } else if ( ld != NULL ) {
404 ldap_unbind_ext( ld, NULL, NULL );
407 return rc;
411 static int
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 )
416 LDAP *ld = NULL;
417 int i = 0;
418 int rc = LDAP_SUCCESS;
419 ber_int_t msgid;
420 LDAPMessage *res, *msg;
421 char **dns = NULL;
422 struct berval *creds = NULL;
423 char *attrs[] = { LDAP_NO_ATTRS, NULL };
424 int ndns = 0;
425 #ifdef _WIN32
426 DWORD beg, end;
427 #else
428 struct timeval beg, end;
429 #endif
430 int version = LDAP_VERSION3;
431 char *nullstr = "";
433 ldap_initialize( &ld, uri );
434 if ( ld == NULL ) {
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 ) {
453 attrs[ 0 ] = pwattr;
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 )
464 BerElement *ber;
465 struct berval bv;
466 int done = 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 ) {
481 novals:;
482 creds[ndns].bv_len = 0;
483 creds[ndns].bv_val = nullstr;
485 } else {
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, '}' );
492 if ( end ) {
493 if ( ber_bvcmp( &value, &cleartext ) == 0 ) {
494 value.bv_val += cleartext.bv_len;
495 value.bv_len -= cleartext.bv_len;
497 } else {
498 ldap_value_free_len( values );
499 goto novals;
505 ber_dupbv( &creds[ndns], &value );
506 ldap_value_free_len( values );
509 ndns++;
510 ber_free( ber, 0 );
511 break;
513 case LDAP_RES_SEARCH_RESULT:
514 done = 1;
515 break;
517 if ( done )
518 break;
520 ldap_msgfree( res );
521 if ( done ) break;
524 #ifdef _WIN32
525 beg = GetTickCount();
526 #else
527 gettimeofday( &beg, NULL );
528 #endif
530 if ( ndns == 0 ) {
531 tester_error( "No DNs" );
532 return 1;
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++ ) {
540 int j;
541 struct berval cred = { 0, NULL };
544 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */
545 j = rand() % ndns;
546 #endif
547 j = ((double)ndns)*rand()/(RAND_MAX + 1.0);
549 if ( creds && !BER_BVISEMPTY( &creds[j] ) ) {
550 cred = creds[j];
553 if ( do_bind( uri, dns[j], &cred, 1, force, chaserefs, noinit, &ld,
554 action_type, action ) && !force )
556 break;
559 if ( delay ) {
560 sleep( delay );
564 if ( ld != NULL ) {
565 ldap_unbind_ext( ld, NULL, NULL );
566 ld = NULL;
569 #ifdef _WIN32
570 end = GetTickCount();
571 end -= beg;
573 fprintf( stderr, " PID=%ld - Bind done %d in %d.%03d seconds.\n",
574 (long) pid, i, end / 1000, end % 1000 );
575 #else
576 gettimeofday( &end, NULL );
577 end.tv_usec -= beg.tv_usec;
578 if (end.tv_usec < 0 ) {
579 end.tv_usec += 1000000;
580 end.tv_sec -= 1;
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 );
586 #endif
588 if ( dns ) {
589 for ( i = 0; i < ndns; i++ ) {
590 free( dns[i] );
592 free( dns );
595 if ( creds ) {
596 for ( i = 0; i < ndns; i++ ) {
597 if ( creds[i].bv_val != nullstr ) {
598 free( creds[i].bv_val );
601 free( creds );
604 return 0;