]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-bind.c
allow to reuse the same connection for multiple binds
[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 );
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 [-h <host>] -p port (-D <dn>|-b <baseDN> [-f <searchfilter>]) -w <passwd> [-l <loops>] [-F] [-I]\n",
59                         name );
60         exit( EXIT_FAILURE );
61 }
62
63 static char *filter = "(objectClass=person)";
64
65 int
66 main( int argc, char **argv )
67 {
68         int             i;
69         char            *uri = NULL;
70         char            *host = "localhost";
71         char            *dn = NULL;
72         struct berval   base = { 0, NULL };
73         struct berval   pass = { 0, NULL };
74         int             port = -1;
75         int             loops = LOOPS;
76         int             force = 0;
77         int             noinit = 0;
78
79         tester_init( "slapd-bind" );
80
81         while ( (i = getopt( argc, argv, "b:H:h:p:D:w:l:f:FI" )) != EOF ) {
82                 switch( i ) {
83                         case 'b':               /* base DN of a tree of user DNs */
84                                 ber_str2bv( optarg, 0, 0, &base );
85                                 break;
86
87                         case 'H':               /* the server uri */
88                                 uri = strdup( optarg );
89                                 break;
90
91                         case 'h':               /* the servers host */
92                                 host = strdup( optarg );
93                                 break;
94
95                         case 'p':               /* the servers port */
96                                 if ( lutil_atoi( &port, optarg ) != 0 ) {
97                                         usage( argv[0] );
98                                 }
99                                 break;
100
101                         case 'D':
102                                 dn = strdup( optarg );
103                                 break;
104
105                         case 'w':
106                                 pass.bv_val = strdup( optarg );
107                                 pass.bv_len = strlen( optarg );
108                                 break;
109
110                         case 'l':               /* the number of loops */
111                                 if ( lutil_atoi( &loops, optarg ) != 0 ) {
112                                         usage( argv[0] );
113                                 }
114                                 break;
115
116                         case 'f':
117                                 filter = optarg;
118                                 break;
119
120                         case 'F':
121                                 force++;
122                                 break;
123
124                         case 'I':
125                                 /* reuse connection */
126                                 noinit++;
127                                 break;
128
129                         default:
130                                 usage( argv[0] );
131                                 break;
132                 }
133         }
134
135         if ( port == -1 && uri == NULL ) {
136                 usage( argv[0] );
137         }
138
139         uri = tester_uri( uri, host, port );
140
141         if ( base.bv_val != NULL ) {
142                 do_base( uri, &base, &pass, ( 20 * loops ), force, noinit );
143         } else {
144                 do_bind( uri, dn, &pass, ( 20 * loops ), force, noinit, NULL );
145         }
146         exit( EXIT_SUCCESS );
147 }
148
149
150 static int
151 do_bind( char *uri, char *dn, struct berval *pass, int maxloop, int force, int noinit, LDAP **ldp )
152 {
153         LDAP    *ld = ldp ? *ldp : NULL;
154         int     i, first = 1, rc = -1;
155         pid_t   pid = getpid();
156
157         if ( maxloop > 1 )
158                 fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n",
159                          (long) pid, maxloop, dn );
160
161         for ( i = 0; i < maxloop; i++ ) {
162                 if ( !noinit || ld == NULL ) {
163                         int version = LDAP_VERSION3;
164                         ldap_initialize( &ld, uri );
165                         if ( ld == NULL ) {
166                                 tester_perror( "ldap_initialize" );
167                                 rc = -1;
168                                 break;
169                         }
170
171                         (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
172                                 &version ); 
173                 }
174
175                 rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
176                 switch ( rc ) {
177                 case LDAP_SUCCESS:
178                         break;
179
180                 case LDAP_INVALID_CREDENTIALS:
181                         /* don't log: it's intended */
182                         if ( force >= 2 ) {
183                                 if ( !first ) {
184                                         break;
185                                 }
186                                 first = 0;
187                         }
188                         /* fallthru */
189
190                 default:
191                         tester_ldap_error( ld, "ldap_sasl_bind_s" );
192                 }
193
194                 if ( !noinit ) {
195                         ldap_unbind_ext( ld, NULL, NULL );
196                         ld = NULL;
197                 }
198                 if ( rc != LDAP_SUCCESS && !force ) {
199                         break;
200                 }
201         }
202
203         if ( maxloop > 1 ) {
204                 fprintf( stderr, " PID=%ld - Bind done.\n", (long) pid );
205         }
206
207         if ( ldp ) {
208                 *ldp = ld;
209
210         } else {
211                 ldap_unbind_ext( ld, NULL, NULL );
212         }
213
214         return rc;
215 }
216
217
218 static int
219 do_base( char *uri, struct berval *base, struct berval *pass, int maxloop, int force, int noinit )
220 {
221         LDAP    *ld = NULL;
222         int     i = 0;
223         pid_t   pid = getpid();
224         int     rc = LDAP_SUCCESS;
225         ber_int_t msgid;
226         LDAPMessage *res, *msg;
227         struct berval *rdns = NULL;
228         char *attrs[] = { LDAP_NO_ATTRS, NULL };
229         int nrdns = 0;
230 #ifdef _WIN32
231         DWORD beg, end;
232 #else
233         struct timeval beg, end;
234 #endif
235         int version = LDAP_VERSION3;
236         struct berval pw = { 0, NULL };
237
238         srand(pid);
239
240         ldap_initialize( &ld, uri );
241         if ( ld == NULL ) {
242                 tester_perror( "ldap_initialize" );
243                 exit( EXIT_FAILURE );
244         }
245
246         (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
247         (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
248
249         rc = ldap_sasl_bind_s( ld, NULL, LDAP_SASL_SIMPLE, &pw, NULL, NULL, NULL );
250         if ( rc != LDAP_SUCCESS ) {
251                 tester_ldap_error( ld, "ldap_sasl_bind_s" );
252                 exit( EXIT_FAILURE );
253         }
254
255         rc = ldap_search_ext( ld, base->bv_val, LDAP_SCOPE_ONE,
256                         filter, attrs, 0, NULL, NULL, 0, 0, &msgid );
257         if ( rc != LDAP_SUCCESS ) {
258                 tester_ldap_error( ld, "ldap_search_ext" );
259                 exit( EXIT_FAILURE );
260         }
261
262         while (( rc=ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res )) >0){
263                 BerElement *ber;
264                 struct berval bv;
265                 char *ptr;
266                 int done = 0;
267
268                 for (msg = ldap_first_message( ld, res ); msg;
269                         msg = ldap_next_message( ld, msg )) {
270                         switch ( ldap_msgtype( msg )) {
271                         case LDAP_RES_SEARCH_ENTRY:
272                                 rc = ldap_get_dn_ber( ld, msg, &ber, &bv );
273                                 ptr = strchr( bv.bv_val, ',');
274                                 assert( ptr != NULL );
275                                 bv.bv_len = ptr - bv.bv_val + 1;
276                                 rdns = realloc( rdns, (nrdns+1)*sizeof(struct berval));
277                                 ber_dupbv( &rdns[nrdns], &bv );
278                                 nrdns++;
279                                 ber_free( ber, 0 );
280                                 break;
281                         case LDAP_RES_SEARCH_RESULT:
282                                 done = 1;
283                                 break;
284                         }
285                         if ( done )
286                                 break;
287                 }
288                 ldap_msgfree( res );
289                 if ( done ) break;
290         }
291         ldap_unbind_ext( ld, NULL, NULL );
292         ld = NULL;
293
294 #ifdef _WIN32
295         beg = GetTickCount();
296 #else
297         gettimeofday( &beg, NULL );
298 #endif
299
300         if ( nrdns == 0 ) {
301                 tester_error( "No RDNs" );
302                 return 1;
303         }
304
305         /* Ok, got list of RDNs, now start binding to each */
306         for (i=0; i<maxloop; i++) {
307                 char dn[BUFSIZ], *ptr;
308                 int j, k;
309
310                 for ( k = 0; k < nrdns; k++) {
311                         j = rand() % nrdns;
312                         if ( base->bv_len + rdns[j].bv_len < sizeof( dn ) ) {
313                                 break;
314                         }
315                 }
316
317                 if ( k == nrdns ) {
318                         
319                 }
320                 
321                 ptr = lutil_strcopy(dn, rdns[j].bv_val);
322                 strcpy(ptr, base->bv_val);
323                 if ( do_bind( uri, dn, pass, 1, force, noinit, &ld ) && !force ) {
324                         break;
325                 }
326         }
327
328 #ifdef _WIN32
329         end = GetTickCount();
330         end -= beg;
331
332         fprintf( stderr, "Done %d Binds in %d.%03d seconds.\n", i,
333                 end / 1000, end % 1000 );
334 #else
335         gettimeofday( &end, NULL );
336         end.tv_usec -= beg.tv_usec;
337         if (end.tv_usec < 0 ) {
338                 end.tv_usec += 1000000;
339                 end.tv_sec -= 1;
340         }
341         end.tv_sec -= beg.tv_sec;
342
343         fprintf( stderr, "Done %d Binds in %ld.%06ld seconds.\n", i,
344                 (long) end.tv_sec, (long) end.tv_usec );
345 #endif
346         return 0;
347 }