]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-bind.c
don't chase referrals (essentially, because it may cause an endless loop in libldap...
[openldap] / tests / progs / slapd-bind.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2006 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
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.
10  *
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>.
14  */
15 /* ACKNOWLEDGEMENTS:
16  * This work was initially developed by Howard Chu for inclusion
17  * in OpenLDAP Software.
18  */
19
20 #include "portable.h"
21
22 #include <stdio.h>
23
24 #include <ac/stdlib.h>
25 #include <ac/time.h>
26
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>
34
35 #include <ldap.h>
36 #include <lutil.h>
37
38 #include "slapd-common.h"
39
40 #define LOOPS   100
41
42 static int
43 do_bind( char *uri, char *dn, struct berval *pass, int maxloop, int force, int noinit, LDAP **ldp );
44
45 static int
46 do_base( char *uri, struct berval *base, struct berval *pass, int maxloop, int force, int noinit, int delay );
47
48 /* This program can be invoked two ways: if -D is used to specify a Bind DN,
49  * that DN will be used repeatedly for all of the Binds. If instead -b is used
50  * to specify a base DN, a search will be done for all "person" objects under
51  * that base DN. Then DNs from this list will be randomly selected for each
52  * Bind request. All of the users must have identical passwords. Also it is
53  * assumed that the users are all onelevel children of the base.
54  */
55 static void
56 usage( char *name )
57 {
58         fprintf( stderr, "usage: %s "
59                 "[-h <host>] "
60                 "-p port "
61                 "(-D <dn>|-b <baseDN> [-f <searchfilter>]) "
62                 "-w <passwd> "
63                 "[-l <loops>] "
64                 "[-L <outerloops>] "
65                 "[-F] "
66                 "[-I] "
67                 "[-t delay]\n",
68                 name );
69         exit( EXIT_FAILURE );
70 }
71
72 static char *filter = "(objectClass=person)";
73
74 int
75 main( int argc, char **argv )
76 {
77         int             i;
78         char            *uri = NULL;
79         char            *host = "localhost";
80         char            *dn = NULL;
81         struct berval   base = { 0, NULL };
82         struct berval   pass = { 0, NULL };
83         int             port = -1;
84         int             loops = LOOPS;
85         int             outerloops = 1;
86         int             force = 0;
87         int             noinit = 0;
88         int             delay = 0;
89
90         tester_init( "slapd-bind" );
91
92         while ( (i = getopt( argc, argv, "b:H:h:p:D:w:l:L:f:FIt:" )) != EOF ) {
93                 switch( i ) {
94                         case 'b':               /* base DN of a tree of user DNs */
95                                 ber_str2bv( optarg, 0, 0, &base );
96                                 break;
97
98                         case 'H':               /* the server uri */
99                                 uri = strdup( optarg );
100                                 break;
101
102                         case 'h':               /* the servers host */
103                                 host = strdup( optarg );
104                                 break;
105
106                         case 'p':               /* the servers port */
107                                 if ( lutil_atoi( &port, optarg ) != 0 ) {
108                                         usage( argv[0] );
109                                 }
110                                 break;
111
112                         case 'D':
113                                 dn = strdup( optarg );
114                                 break;
115
116                         case 'w':
117                                 pass.bv_val = strdup( optarg );
118                                 pass.bv_len = strlen( optarg );
119                                 break;
120
121                         case 'l':               /* the number of loops */
122                                 if ( lutil_atoi( &loops, optarg ) != 0 ) {
123                                         usage( argv[0] );
124                                 }
125                                 break;
126
127                         case 'L':               /* the number of outerloops */
128                                 if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
129                                         usage( argv[0] );
130                                 }
131                                 break;
132
133                         case 'f':
134                                 filter = optarg;
135                                 break;
136
137                         case 'F':
138                                 force++;
139                                 break;
140
141                         case 'I':
142                                 /* reuse connection */
143                                 noinit++;
144                                 break;
145
146                         case 't':
147                                 /* sleep between binds */
148                                 if ( lutil_atoi( &delay, optarg ) != 0 ) {
149                                         usage( argv[0] );
150                                 }
151                                 break;
152
153                         default:
154                                 usage( argv[0] );
155                                 break;
156                 }
157         }
158
159         if ( port == -1 && uri == NULL ) {
160                 usage( argv[0] );
161         }
162
163         uri = tester_uri( uri, host, port );
164
165         for ( i = 0; i < outerloops; i++ ) {
166                 if ( base.bv_val != NULL ) {
167                         do_base( uri, &base, &pass, loops, force, noinit, delay );
168                 } else {
169                         do_bind( uri, dn, &pass, loops, force, noinit, NULL );
170                 }
171         }
172
173         exit( EXIT_SUCCESS );
174 }
175
176
177 static int
178 do_bind( char *uri, char *dn, struct berval *pass, int maxloop, int force, int noinit, LDAP **ldp )
179 {
180         LDAP    *ld = ldp ? *ldp : NULL;
181         int     i, first = 1, rc = -1;
182         pid_t   pid = getpid();
183
184         if ( maxloop > 1 )
185                 fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n",
186                          (long) pid, maxloop, dn );
187
188         for ( i = 0; i < maxloop; i++ ) {
189                 if ( !noinit || ld == NULL ) {
190                         int version = LDAP_VERSION3;
191                         ldap_initialize( &ld, uri );
192                         if ( ld == NULL ) {
193                                 tester_perror( "ldap_initialize" );
194                                 rc = -1;
195                                 break;
196                         }
197
198                         (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
199                                 &version ); 
200                         (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
201                                 LDAP_OPT_OFF );
202                 }
203
204                 rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
205                 switch ( rc ) {
206                 case LDAP_SUCCESS:
207                         break;
208
209                 case LDAP_INVALID_CREDENTIALS:
210                         /* don't log: it's intended */
211                         if ( force >= 2 ) {
212                                 if ( !first ) {
213                                         break;
214                                 }
215                                 first = 0;
216                         }
217                         /* fallthru */
218
219                 default:
220                         tester_ldap_error( ld, "ldap_sasl_bind_s" );
221                 }
222
223                 if ( !noinit ) {
224                         ldap_unbind_ext( ld, NULL, NULL );
225                         ld = NULL;
226                 }
227                 if ( rc != LDAP_SUCCESS && !force ) {
228                         break;
229                 }
230         }
231
232         if ( maxloop > 1 ) {
233                 fprintf( stderr, " PID=%ld - Bind done (%d).\n", (long) pid, rc );
234         }
235
236         if ( ldp ) {
237                 *ldp = ld;
238
239         } else if ( ld != NULL ) {
240                 ldap_unbind_ext( ld, NULL, NULL );
241         }
242
243         return rc;
244 }
245
246
247 static int
248 do_base( char *uri, struct berval *base, struct berval *pass, int maxloop, int force, int noinit, int delay )
249 {
250         LDAP    *ld = NULL;
251         int     i = 0;
252         pid_t   pid = getpid();
253         int     rc = LDAP_SUCCESS;
254         ber_int_t msgid;
255         LDAPMessage *res, *msg;
256         struct berval *rdns = NULL;
257         char *attrs[] = { LDAP_NO_ATTRS, NULL };
258         int nrdns = 0;
259 #ifdef _WIN32
260         DWORD beg, end;
261 #else
262         struct timeval beg, end;
263 #endif
264         int version = LDAP_VERSION3;
265         struct berval pw = { 0, NULL };
266
267         srand(pid);
268
269         ldap_initialize( &ld, uri );
270         if ( ld == NULL ) {
271                 tester_perror( "ldap_initialize" );
272                 exit( EXIT_FAILURE );
273         }
274
275         (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
276         (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
277
278         rc = ldap_sasl_bind_s( ld, NULL, LDAP_SASL_SIMPLE, &pw, NULL, NULL, NULL );
279         if ( rc != LDAP_SUCCESS ) {
280                 tester_ldap_error( ld, "ldap_sasl_bind_s" );
281                 exit( EXIT_FAILURE );
282         }
283
284         rc = ldap_search_ext( ld, base->bv_val, LDAP_SCOPE_ONE,
285                         filter, attrs, 0, NULL, NULL, 0, 0, &msgid );
286         if ( rc != LDAP_SUCCESS ) {
287                 tester_ldap_error( ld, "ldap_search_ext" );
288                 exit( EXIT_FAILURE );
289         }
290
291         while (( rc=ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res )) >0){
292                 BerElement *ber;
293                 struct berval bv;
294                 char *ptr;
295                 int done = 0;
296
297                 for (msg = ldap_first_message( ld, res ); msg;
298                         msg = ldap_next_message( ld, msg )) {
299                         switch ( ldap_msgtype( msg )) {
300                         case LDAP_RES_SEARCH_ENTRY:
301                                 rc = ldap_get_dn_ber( ld, msg, &ber, &bv );
302                                 ptr = strchr( bv.bv_val, ',');
303                                 assert( ptr != NULL );
304                                 bv.bv_len = ptr - bv.bv_val + 1;
305                                 rdns = realloc( rdns, (nrdns+1)*sizeof(struct berval));
306                                 ber_dupbv( &rdns[nrdns], &bv );
307                                 nrdns++;
308                                 ber_free( ber, 0 );
309                                 break;
310                         case LDAP_RES_SEARCH_RESULT:
311                                 done = 1;
312                                 break;
313                         }
314                         if ( done )
315                                 break;
316                 }
317                 ldap_msgfree( res );
318                 if ( done ) break;
319         }
320
321 #ifdef _WIN32
322         beg = GetTickCount();
323 #else
324         gettimeofday( &beg, NULL );
325 #endif
326
327         if ( nrdns == 0 ) {
328                 tester_error( "No RDNs" );
329                 return 1;
330         }
331
332         /* Ok, got list of RDNs, now start binding to each */
333         for ( i = 0; i < maxloop; i++ ) {
334                 char dn[BUFSIZ], *ptr;
335                 int j, k;
336
337                 for ( k = 0; k < nrdns; k++) {
338                         j = rand() % nrdns;
339                         if ( base->bv_len + rdns[j].bv_len < sizeof( dn ) ) {
340                                 break;
341                         }
342                 }
343
344                 if ( k == nrdns ) {
345                         
346                 }
347                 
348                 ptr = lutil_strcopy(dn, rdns[j].bv_val);
349                 strcpy(ptr, base->bv_val);
350                 if ( do_bind( uri, dn, pass, 1, force, noinit, &ld ) && !force ) {
351                         break;
352                 }
353
354                 if ( delay ) {
355                         sleep( delay );
356                 }
357         }
358
359         if ( ld != NULL ) {
360                 ldap_unbind_ext( ld, NULL, NULL );
361                 ld = NULL;
362         }
363
364 #ifdef _WIN32
365         end = GetTickCount();
366         end -= beg;
367
368         fprintf( stderr, "Done %d Binds in %d.%03d seconds.\n", i,
369                 end / 1000, end % 1000 );
370 #else
371         gettimeofday( &end, NULL );
372         end.tv_usec -= beg.tv_usec;
373         if (end.tv_usec < 0 ) {
374                 end.tv_usec += 1000000;
375                 end.tv_sec -= 1;
376         }
377         end.tv_sec -= beg.tv_sec;
378
379         fprintf( stderr, "Done %d Binds in %ld.%06ld seconds.\n", i,
380                 (long) end.tv_sec, (long) end.tv_usec );
381 #endif
382
383         if ( rdns ) {
384                 for ( i = 0; i < nrdns; i++ ) {
385                         free( rdns[i].bv_val );
386                 }
387                 free( rdns );
388         }
389
390         return 0;
391 }