]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-bind.c
further cleanup; fix filter specification for slapd-bind
[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 #include <lber_pvt.h>
38
39 #include "slapd-common.h"
40
41 #define LOOPS   100
42
43 static int
44 do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
45         int force, int chaserefs, int noinit, LDAP **ldp );
46
47 static int
48 do_base( char *uri, struct berval *base, struct berval *pass, char *pwattr,
49         int maxloop, int force, int chaserefs, int noinit, int delay );
50
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.
57  */
58 static void
59 usage( char *name )
60 {
61         fprintf( stderr, "usage: %s "
62                 "[-H uri | -h <host> [-p port]] "
63                 "[-D <dn> [-w <passwd>]] "
64                 "[-b <baseDN> [-f <searchfilter>] [-a pwattr]] "
65                 "[-l <loops>] "
66                 "[-L <outerloops>] "
67                 "[-F] "
68                 "[-C] "
69                 "[-I] "
70                 "[-i <ignore>] "
71                 "[-t delay]\n",
72                 name );
73         exit( EXIT_FAILURE );
74 }
75
76 static char *filter = "(objectClass=person)";
77
78 int
79 main( int argc, char **argv )
80 {
81         int             i;
82         char            *uri = NULL;
83         char            *host = "localhost";
84         char            *dn = NULL;
85         struct berval   base = { 0, NULL };
86         struct berval   pass = { 0, NULL };
87         char            *pwattr = NULL;
88         int             port = -1;
89         int             loops = LOOPS;
90         int             outerloops = 1;
91         int             force = 0;
92         int             chaserefs = 0;
93         int             noinit = 0;
94         int             delay = 0;
95
96         tester_init( "slapd-bind", TESTER_BIND );
97
98         /* by default, tolerate invalid credentials */
99         tester_ignore_str2errlist( "INVALID_CREDENTIALS" );
100
101         while ( (i = getopt( argc, argv, "a:b:H:h:i:p:D:w:l:L:f:FIt:" )) != EOF ) {
102                 switch( i ) {
103                 case 'a':
104                         pwattr = optarg;
105                         break;
106
107                 case 'b':               /* base DN of a tree of user DNs */
108                         ber_str2bv( optarg, 0, 0, &base );
109                         break;
110
111                 case 'C':
112                         chaserefs++;
113                         break;
114
115                 case 'H':               /* the server uri */
116                         uri = optarg;
117                         break;
118
119                 case 'h':               /* the servers host */
120                         host = optarg;
121                         break;
122
123                 case 'i':
124                         tester_ignore_str2errlist( optarg );
125                         break;
126
127                 case 'p':               /* the servers port */
128                         if ( lutil_atoi( &port, optarg ) != 0 ) {
129                                 usage( argv[0] );
130                         }
131                         break;
132
133                 case 'D':
134                         dn = optarg;
135                         break;
136
137                 case 'w':
138                         ber_str2bv( optarg, 0, 0, &pass );
139                         break;
140
141                 case 'l':               /* the number of loops */
142                         if ( lutil_atoi( &loops, optarg ) != 0 ) {
143                                 usage( argv[0] );
144                         }
145                         break;
146
147                 case 'L':               /* the number of outerloops */
148                         if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
149                                 usage( argv[0] );
150                         }
151                         break;
152
153                 case 'f':
154                         filter = optarg;
155                         break;
156
157                 case 'F':
158                         force++;
159                         break;
160
161                 case 'I':
162                         /* reuse connection */
163                         noinit++;
164                         break;
165
166                 case 't':
167                         /* sleep between binds */
168                         if ( lutil_atoi( &delay, optarg ) != 0 ) {
169                                 usage( argv[0] );
170                         }
171                         break;
172
173                 default:
174                         usage( argv[0] );
175                         break;
176                 }
177         }
178
179         if ( port == -1 && uri == NULL ) {
180                 usage( argv[0] );
181         }
182
183         uri = tester_uri( uri, host, port );
184
185         for ( i = 0; i < outerloops; i++ ) {
186                 if ( base.bv_val != NULL ) {
187                         do_base( uri, &base, &pass, pwattr, loops,
188                                 force, chaserefs, noinit, delay );
189                 } else {
190                         do_bind( uri, dn, &pass, loops,
191                                 force, chaserefs, noinit, NULL );
192                 }
193         }
194
195         exit( EXIT_SUCCESS );
196 }
197
198
199 static int
200 do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
201         int force, int chaserefs, int noinit, LDAP **ldp )
202 {
203         LDAP    *ld = ldp ? *ldp : NULL;
204         int     i, rc = -1;
205         pid_t   pid = getpid();
206
207         if ( maxloop > 1 )
208                 fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n",
209                          (long) pid, maxloop, dn );
210
211         for ( i = 0; i < maxloop; i++ ) {
212                 if ( !noinit || ld == NULL ) {
213                         int version = LDAP_VERSION3;
214                         ldap_initialize( &ld, uri );
215                         if ( ld == NULL ) {
216                                 tester_perror( "ldap_initialize", NULL );
217                                 rc = -1;
218                                 break;
219                         }
220
221                         (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
222                                 &version ); 
223                         (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
224                                 chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );
225                 }
226
227                 rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
228                 if ( rc ) {
229                         unsigned first = tester_ignore_err( rc );
230
231                         /* if ignore.. */
232                         if ( first ) {
233                                 /* only log if first occurrence */
234                                 if ( force < 2 || first == 1 ) {
235                                         tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
236                                 }
237                                 rc = LDAP_SUCCESS;
238
239                         } else {
240                                 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
241                         }
242                 }
243                         
244                 if ( !noinit ) {
245                         ldap_unbind_ext( ld, NULL, NULL );
246                         ld = NULL;
247                 }
248
249                 if ( rc != LDAP_SUCCESS ) {
250                         break;
251                 }
252         }
253
254         if ( maxloop > 1 ) {
255                 fprintf( stderr, " PID=%ld - Bind done (%d).\n", (long) pid, rc );
256         }
257
258         if ( ldp && noinit ) {
259                 *ldp = ld;
260
261         } else if ( ld != NULL ) {
262                 ldap_unbind_ext( ld, NULL, NULL );
263         }
264
265         return rc;
266 }
267
268
269 static int
270 do_base( char *uri, struct berval *base, struct berval *pass, char *pwattr,
271         int maxloop, int force, int chaserefs, int noinit, int delay )
272 {
273         LDAP    *ld = NULL;
274         int     i = 0;
275         pid_t   pid = getpid();
276         int     rc = LDAP_SUCCESS;
277         ber_int_t msgid;
278         LDAPMessage *res, *msg;
279         char **dns = NULL;
280         struct berval *creds = NULL;
281         char *attrs[] = { LDAP_NO_ATTRS, NULL };
282         int ndns = 0;
283 #ifdef _WIN32
284         DWORD beg, end;
285 #else
286         struct timeval beg, end;
287 #endif
288         int version = LDAP_VERSION3;
289         struct berval pw = { 0, NULL };
290         char *nullstr = "";
291
292         srand(pid);
293
294         ldap_initialize( &ld, uri );
295         if ( ld == NULL ) {
296                 tester_perror( "ldap_initialize", NULL );
297                 exit( EXIT_FAILURE );
298         }
299
300         (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
301         (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
302                 chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );
303
304         rc = ldap_sasl_bind_s( ld, NULL, LDAP_SASL_SIMPLE, &pw, NULL, NULL, NULL );
305         if ( rc != LDAP_SUCCESS ) {
306                 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
307                 exit( EXIT_FAILURE );
308         }
309
310         fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n",
311                         (long) pid, maxloop, base->bv_val, filter, pwattr );
312
313         if ( pwattr != NULL ) {
314                 attrs[ 0 ] = pwattr;
315         }
316         rc = ldap_search_ext( ld, base->bv_val, LDAP_SCOPE_SUBTREE,
317                         filter, attrs, 0, NULL, NULL, 0, 0, &msgid );
318         if ( rc != LDAP_SUCCESS ) {
319                 tester_ldap_error( ld, "ldap_search_ext", NULL );
320                 exit( EXIT_FAILURE );
321         }
322
323         while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 )
324         {
325                 BerElement *ber;
326                 struct berval bv;
327                 int done = 0;
328
329                 for ( msg = ldap_first_message( ld, res ); msg;
330                         msg = ldap_next_message( ld, msg ) )
331                 {
332                         switch ( ldap_msgtype( msg ) ) {
333                         case LDAP_RES_SEARCH_ENTRY:
334                                 rc = ldap_get_dn_ber( ld, msg, &ber, &bv );
335                                 dns = realloc( dns, (ndns + 1)*sizeof(char *) );
336                                 dns[ndns] = ber_strdup( bv.bv_val );
337                                 if ( pwattr != NULL ) {
338                                         struct berval   **values = ldap_get_values_len( ld, msg, pwattr );
339
340                                         creds = realloc( creds, (ndns + 1)*sizeof(struct berval) );
341                                         if ( values == NULL ) {
342 novals:;
343                                                 if ( pass != NULL ) {
344                                                         ber_dupbv( &creds[ndns], pass );
345
346                                                 } else {
347                                                         creds[ndns].bv_len = 0;
348                                                         creds[ndns].bv_val = nullstr;
349                                                 }
350
351                                         } else {
352                                                 static struct berval    cleartext = BER_BVC( "{CLEARTEXT} " );
353                                                 struct berval           value = *values[ 0 ];
354
355                                                 if ( value.bv_val[ 0 ] == '{' ) {
356                                                         char *end = ber_bvchr( &value, '}' );
357
358                                                         if ( end ) {
359                                                                 if ( ber_bvcmp( &value, &cleartext ) == 0 ) {
360                                                                         value.bv_val += cleartext.bv_len;
361                                                                         value.bv_len -= cleartext.bv_len;
362
363                                                                 } else {
364                                                                         ldap_value_free_len( values );
365                                                                         goto novals;
366                                                                 }
367                                                         }
368
369                                                 }
370
371                                                 ber_dupbv( &creds[ndns], &value );
372                                                 ldap_value_free_len( values );
373                                         }
374                                 }
375                                 ndns++;
376                                 ber_free( ber, 0 );
377                                 break;
378
379                         case LDAP_RES_SEARCH_RESULT:
380                                 done = 1;
381                                 break;
382                         }
383                         if ( done )
384                                 break;
385                 }
386                 ldap_msgfree( res );
387                 if ( done ) break;
388         }
389
390 #ifdef _WIN32
391         beg = GetTickCount();
392 #else
393         gettimeofday( &beg, NULL );
394 #endif
395
396         if ( ndns == 0 ) {
397                 tester_error( "No DNs" );
398                 return 1;
399         }
400
401         fprintf( stderr, "  PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n",
402                 (long) pid, base->bv_val, filter, ndns );
403
404         /* Ok, got list of DNs, now start binding to each */
405         for ( i = 0; i < maxloop; i++ ) {
406                 int j, k;
407                 struct berval *cred = pass;
408
409                 for ( j = 0, k = 0; k < ndns; k++) {
410                         j = rand() % ndns;
411                 }
412
413                 if ( creds && !BER_BVISEMPTY( &creds[j] ) ) {
414                         cred = &creds[j];
415                 }
416                 if ( do_bind( uri, dns[j], cred, 1, force, chaserefs, noinit, &ld )
417                         && !force )
418                 {
419                         break;
420                 }
421
422                 if ( delay ) {
423                         sleep( delay );
424                 }
425         }
426
427         if ( ld != NULL ) {
428                 ldap_unbind_ext( ld, NULL, NULL );
429                 ld = NULL;
430         }
431
432 #ifdef _WIN32
433         end = GetTickCount();
434         end -= beg;
435
436         fprintf( stderr, " PID=%ld - Bind done %d in %d.%03d seconds.\n",
437                 (long) pid, i, end / 1000, end % 1000 );
438 #else
439         gettimeofday( &end, NULL );
440         end.tv_usec -= beg.tv_usec;
441         if (end.tv_usec < 0 ) {
442                 end.tv_usec += 1000000;
443                 end.tv_sec -= 1;
444         }
445         end.tv_sec -= beg.tv_sec;
446
447         fprintf( stderr, " PID=%ld - Bind done %d in %ld.%06ld seconds.\n",
448                 (long) pid, i, (long) end.tv_sec, (long) end.tv_usec );
449 #endif
450
451         if ( dns ) {
452                 for ( i = 0; i < ndns; i++ ) {
453                         free( dns[i] );
454                 }
455                 free( dns );
456         }
457
458         if ( creds ) {
459                 for ( i = 0; i < ndns; i++ ) {
460                         if ( creds[i].bv_val != nullstr ) {
461                                 free( creds[i].bv_val );
462                         }
463                 }
464                 free( creds );
465         }
466
467         return 0;
468 }