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