]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-bind.c
Happy New Year!
[openldap] / tests / progs / slapd-bind.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2017 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 #include "ldap_pvt.h"
39
40 #include "slapd-common.h"
41
42 #define LOOPS   100
43
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 );
48
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 );
53
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.
60  */
61 static void
62 usage( char *name, char opt )
63 {
64         if ( opt ) {
65                 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
66                         name, opt );
67         }
68
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 );
83 }
84
85 int
86 main( int argc, char **argv )
87 {
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;
103
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
114         };
115
116         LDAPURLDesc     *extra_ludp = NULL;
117
118         tester_init( "slapd-bind", TESTER_BIND );
119
120         /* by default, tolerate invalid credentials */
121         tester_ignore_str2errlist( "INVALID_CREDENTIALS" );
122
123         while ( ( i = getopt( argc, argv, "a:B:b:D:Ff:H:h:Ii:L:l:p:t:w:" ) ) != EOF )
124         {
125                 switch ( i ) {
126                 case 'a':
127                         pwattr = optarg;
128                         break;
129
130                 case 'b':               /* base DN of a tree of user DNs */
131                         base = optarg;
132                         break;
133
134                 case 'B':
135                         {
136                         int     c;
137
138                         for ( c = 0; type[c].bv_val; c++ ) {
139                                 if ( strncasecmp( optarg, type[c].bv_val, type[c].bv_len ) == 0 )
140                                 {
141                                         break;
142                                 }
143                         }
144
145                         if ( type[c].bv_val == NULL ) {
146                                 usage( argv[0], 'B' );
147                         }
148
149                         switch ( c ) {
150                         case TESTER_TESTER:
151                         case TESTER_BIND:
152                                 /* invalid */
153                                 usage( argv[0], 'B' );
154
155                         case TESTER_SEARCH:
156                                 {
157                                 if ( ldap_url_parse( &optarg[type[c].bv_len], &extra_ludp ) != LDAP_URL_SUCCESS )
158                                 {
159                                         usage( argv[0], 'B' );
160                                 }
161                                 } break;
162
163                         case TESTER_ADDEL:
164                         case TESTER_MODIFY:
165                         case TESTER_MODRDN:
166                         case TESTER_READ:
167                                 /* nothing to do */
168                                 break;
169
170                         default:
171                                 assert( 0 );
172                         }
173
174                         } break;
175
176                 case 'C':
177                         chaserefs++;
178                         break;
179
180                 case 'H':               /* the server uri */
181                         uri = optarg;
182                         break;
183
184                 case 'h':               /* the servers host */
185                         host = optarg;
186                         break;
187
188                 case 'i':
189                         tester_ignore_str2errlist( optarg );
190                         break;
191
192                 case 'p':               /* the servers port */
193                         if ( lutil_atoi( &port, optarg ) != 0 ) {
194                                 usage( argv[0], 'p' );
195                         }
196                         break;
197
198                 case 'D':
199                         dn = optarg;
200                         break;
201
202                 case 'w':
203                         ber_str2bv( optarg, 0, 1, &pass );
204                         memset( optarg, '*', pass.bv_len );
205                         break;
206
207                 case 'l':               /* the number of loops */
208                         if ( lutil_atoi( &loops, optarg ) != 0 ) {
209                                 usage( argv[0], 'l' );
210                         }
211                         break;
212
213                 case 'L':               /* the number of outerloops */
214                         if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
215                                 usage( argv[0], 'L' );
216                         }
217                         break;
218
219                 case 'f':
220                         filter = optarg;
221                         break;
222
223                 case 'F':
224                         force++;
225                         break;
226
227                 case 'I':
228                         /* reuse connection */
229                         noinit = 0;
230                         break;
231
232                 case 't':
233                         /* sleep between binds */
234                         if ( lutil_atoi( &delay, optarg ) != 0 ) {
235                                 usage( argv[0], 't' );
236                         }
237                         break;
238
239                 default:
240                         usage( argv[0], i );
241                         break;
242                 }
243         }
244
245         if ( port == -1 && uri == NULL ) {
246                 usage( argv[0], '\0' );
247         }
248
249         uri = tester_uri( uri, host, port );
250
251         for ( i = 0; i < outerloops; i++ ) {
252                 int rc;
253
254                 if ( base != NULL ) {
255                         rc = do_base( uri, dn, &pass, base, filter, pwattr, loops,
256                                 force, chaserefs, noinit, delay, -1, NULL );
257                 } else {
258                         rc = do_bind( uri, dn, &pass, loops,
259                                 force, chaserefs, noinit, NULL, -1, NULL );
260                 }
261                 if ( rc == LDAP_SERVER_DOWN )
262                         break;
263         }
264
265         exit( EXIT_SUCCESS );
266 }
267
268
269 static int
270 do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
271         int force, int chaserefs, int noinit, LDAP **ldp,
272         int action_type, void *action )
273 {
274         LDAP    *ld = ldp ? *ldp : NULL;
275         int     i, rc = -1;
276
277         /* for internal search */
278         int     timelimit = 0;
279         int     sizelimit = 0;
280
281         switch ( action_type ) {
282         case -1:
283                 break;
284
285         case TESTER_SEARCH:
286                 {
287                 LDAPURLDesc     *ludp = (LDAPURLDesc *)action;
288
289                 assert( action != NULL );
290
291                 if ( ludp->lud_exts != NULL ) {
292                         for ( i = 0; ludp->lud_exts[ i ] != NULL; i++ ) {
293                                 char    *ext = ludp->lud_exts[ i ];
294                                 int     crit = 0;
295
296                                 if (ext[0] == '!') {
297                                         crit++;
298                                         ext++;
299                                 }
300
301                                 if ( strncasecmp( ext, "x-timelimit=", STRLENOF( "x-timelimit=" ) ) == 0 ) {
302                                         if ( lutil_atoi( &timelimit, &ext[ STRLENOF( "x-timelimit=" ) ] ) && crit ) {
303                                                 tester_error( "unable to parse critical extension x-timelimit" );
304                                         }
305
306                                 } else if ( strncasecmp( ext, "x-sizelimit=", STRLENOF( "x-sizelimit=" ) ) == 0 ) {
307                                         if ( lutil_atoi( &sizelimit, &ext[ STRLENOF( "x-sizelimit=" ) ] ) && crit ) {
308                                                 tester_error( "unable to parse critical extension x-sizelimit" );
309                                         }
310
311                                 } else if ( crit ) {
312                                         tester_error( "unknown critical extension" );
313                                 }
314                         }
315                 }
316                 } break;
317
318         default:
319                 /* nothing to do yet */
320                 break;
321         }
322                         
323         if ( maxloop > 1 ) {
324                 fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n",
325                          (long) pid, maxloop, dn );
326         }
327
328         for ( i = 0; i < maxloop; i++ ) {
329                 if ( !noinit || ld == NULL ) {
330                         int version = LDAP_VERSION3;
331                         ldap_initialize( &ld, uri );
332                         if ( ld == NULL ) {
333                                 tester_perror( "ldap_initialize", NULL );
334                                 rc = -1;
335                                 break;
336                         }
337
338                         (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
339                                 &version ); 
340                         (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
341                                 chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );
342                 }
343
344                 rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
345                 if ( rc ) {
346                         int first = tester_ignore_err( rc );
347
348                         /* if ignore.. */
349                         if ( first ) {
350                                 /* only log if first occurrence */
351                                 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
352                                         tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
353                                 }
354                                 rc = LDAP_SUCCESS;
355
356                         } else {
357                                 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
358                         }
359                 }
360
361                 switch ( action_type ) {
362                 case -1:
363                         break;
364
365                 case TESTER_SEARCH:
366                         {
367                         LDAPURLDesc     *ludp = (LDAPURLDesc *)action;
368                         LDAPMessage     *res = NULL;
369                         struct timeval  tv = { 0 }, *tvp = NULL;
370
371                         if ( timelimit ) {
372                                 tv.tv_sec = timelimit;
373                                 tvp = &tv;
374                         }
375
376                         assert( action != NULL );
377
378                         rc = ldap_search_ext_s( ld,
379                                 ludp->lud_dn, ludp->lud_scope,
380                                 ludp->lud_filter, ludp->lud_attrs, 0,
381                                 NULL, NULL, tvp, sizelimit, &res );
382                         ldap_msgfree( res );
383                         } break;
384
385                 default:
386                         /* nothing to do yet */
387                         break;
388                 }
389                         
390                 if ( !noinit ) {
391                         ldap_unbind_ext( ld, NULL, NULL );
392                         ld = NULL;
393                 }
394
395                 if ( rc != LDAP_SUCCESS ) {
396                         break;
397                 }
398         }
399
400         if ( maxloop > 1 ) {
401                 fprintf( stderr, "  PID=%ld - Bind done (%d).\n", (long) pid, rc );
402         }
403
404         if ( ldp && noinit ) {
405                 *ldp = ld;
406
407         } else if ( ld != NULL ) {
408                 ldap_unbind_ext( ld, NULL, NULL );
409         }
410
411         return rc;
412 }
413
414
415 static int
416 do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr,
417         int maxloop, int force, int chaserefs, int noinit, int delay,
418         int action_type, void *action )
419 {
420         LDAP    *ld = NULL;
421         int     i = 0;
422         int     rc = LDAP_SUCCESS;
423         ber_int_t msgid;
424         LDAPMessage *res, *msg;
425         char **dns = NULL;
426         struct berval *creds = NULL;
427         char *attrs[] = { LDAP_NO_ATTRS, NULL };
428         int ndns = 0;
429 #ifdef _WIN32
430         DWORD beg, end;
431 #else
432         struct timeval beg, end;
433 #endif
434         int version = LDAP_VERSION3;
435         char *nullstr = "";
436
437         ldap_initialize( &ld, uri );
438         if ( ld == NULL ) {
439                 tester_perror( "ldap_initialize", NULL );
440                 exit( EXIT_FAILURE );
441         }
442
443         (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
444         (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
445                 chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );
446
447         rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
448         if ( rc != LDAP_SUCCESS ) {
449                 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
450                 exit( EXIT_FAILURE );
451         }
452
453         fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n",
454                         (long) pid, maxloop, base, filter, pwattr );
455
456         if ( pwattr != NULL ) {
457                 attrs[ 0 ] = pwattr;
458         }
459         rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE,
460                         filter, attrs, 0, NULL, NULL, 0, 0, &msgid );
461         if ( rc != LDAP_SUCCESS ) {
462                 tester_ldap_error( ld, "ldap_search_ext", NULL );
463                 exit( EXIT_FAILURE );
464         }
465
466         while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 )
467         {
468                 BerElement *ber;
469                 struct berval bv;
470                 int done = 0;
471
472                 for ( msg = ldap_first_message( ld, res ); msg;
473                         msg = ldap_next_message( ld, msg ) )
474                 {
475                         switch ( ldap_msgtype( msg ) ) {
476                         case LDAP_RES_SEARCH_ENTRY:
477                                 rc = ldap_get_dn_ber( ld, msg, &ber, &bv );
478                                 dns = realloc( dns, (ndns + 1)*sizeof(char *) );
479                                 dns[ndns] = ber_strdup( bv.bv_val );
480                                 if ( pwattr != NULL ) {
481                                         struct berval   **values = ldap_get_values_len( ld, msg, pwattr );
482
483                                         creds = realloc( creds, (ndns + 1)*sizeof(struct berval) );
484                                         if ( values == NULL ) {
485 novals:;
486                                                 creds[ndns].bv_len = 0;
487                                                 creds[ndns].bv_val = nullstr;
488
489                                         } else {
490                                                 static struct berval    cleartext = BER_BVC( "{CLEARTEXT} " );
491                                                 struct berval           value = *values[ 0 ];
492
493                                                 if ( value.bv_val[ 0 ] == '{' ) {
494                                                         char *end = ber_bvchr( &value, '}' );
495
496                                                         if ( end ) {
497                                                                 if ( ber_bvcmp( &value, &cleartext ) == 0 ) {
498                                                                         value.bv_val += cleartext.bv_len;
499                                                                         value.bv_len -= cleartext.bv_len;
500
501                                                                 } else {
502                                                                         ldap_value_free_len( values );
503                                                                         goto novals;
504                                                                 }
505                                                         }
506
507                                                 }
508
509                                                 ber_dupbv( &creds[ndns], &value );
510                                                 ldap_value_free_len( values );
511                                         }
512                                 }
513                                 ndns++;
514                                 ber_free( ber, 0 );
515                                 break;
516
517                         case LDAP_RES_SEARCH_RESULT:
518                                 done = 1;
519                                 break;
520                         }
521                         if ( done )
522                                 break;
523                 }
524                 ldap_msgfree( res );
525                 if ( done ) break;
526         }
527
528 #ifdef _WIN32
529         beg = GetTickCount();
530 #else
531         gettimeofday( &beg, NULL );
532 #endif
533
534         if ( ndns == 0 ) {
535                 tester_error( "No DNs" );
536                 return 1;
537         }
538
539         fprintf( stderr, "  PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n",
540                 (long) pid, base, filter, ndns );
541
542         /* Ok, got list of DNs, now start binding to each */
543         for ( i = 0; i < maxloop; i++ ) {
544                 int             j;
545                 struct berval   cred = { 0, NULL };
546
547
548 #if 0   /* use high-order bits for better randomness (Numerical Recipes in "C") */
549                 j = rand() % ndns;
550 #endif
551                 j = ((double)ndns)*rand()/(RAND_MAX + 1.0);
552
553                 if ( creds && !BER_BVISEMPTY( &creds[j] ) ) {
554                         cred = creds[j];
555                 }
556
557                 if ( do_bind( uri, dns[j], &cred, 1, force, chaserefs, noinit, &ld,
558                         action_type, action ) && !force )
559                 {
560                         break;
561                 }
562
563                 if ( delay ) {
564                         sleep( delay );
565                 }
566         }
567
568         if ( ld != NULL ) {
569                 ldap_unbind_ext( ld, NULL, NULL );
570                 ld = NULL;
571         }
572
573 #ifdef _WIN32
574         end = GetTickCount();
575         end -= beg;
576
577         fprintf( stderr, "  PID=%ld - Bind done %d in %d.%03d seconds.\n",
578                 (long) pid, i, end / 1000, end % 1000 );
579 #else
580         gettimeofday( &end, NULL );
581         end.tv_usec -= beg.tv_usec;
582         if (end.tv_usec < 0 ) {
583                 end.tv_usec += 1000000;
584                 end.tv_sec -= 1;
585         }
586         end.tv_sec -= beg.tv_sec;
587
588         fprintf( stderr, "  PID=%ld - Bind done %d in %ld.%06ld seconds.\n",
589                 (long) pid, i, (long) end.tv_sec, (long) end.tv_usec );
590 #endif
591
592         if ( dns ) {
593                 for ( i = 0; i < ndns; i++ ) {
594                         ber_memfree( dns[i] );
595                 }
596                 free( dns );
597         }
598
599         if ( creds ) {
600                 for ( i = 0; i < ndns; i++ ) {
601                         if ( creds[i].bv_val != nullstr ) {
602                                 ber_memfree( creds[i].bv_val );
603                         }
604                 }
605                 free( creds );
606         }
607
608         return 0;
609 }