]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-bind.c
541a473644b4c9a9b8c8dd897c2b376c0a1a06d3
[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 static int
43 do_bind( struct tester_conn_args *config, char *dn, int maxloop,
44         int force, int noinit, LDAP **ldp, int action_type, void *action );
45
46 static int
47 do_base( struct tester_conn_args *config, char *dn, char *base, char *filter, char *pwattr,
48         int force, int noinit, int action_type, void *action );
49
50 /* This program can be invoked two ways: if -D is used to specify a Bind DN,
51  * that DN will be used repeatedly for all of the Binds. If instead -b is used
52  * to specify a base DN, a search will be done for all "person" objects under
53  * that base DN. Then DNs from this list will be randomly selected for each
54  * Bind request. All of the users must have identical passwords. Also it is
55  * assumed that the users are all onelevel children of the base.
56  */
57 static void
58 usage( char *name, char opt )
59 {
60         if ( opt ) {
61                 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
62                         name, opt );
63         }
64
65         fprintf( stderr, "usage: %s " TESTER_COMMON_HELP
66                 "[-b <baseDN> [-f <searchfilter>] [-a pwattr]] "
67                 "[-B <extra>[,...]] "
68                 "[-F] "
69                 "[-I]\n",
70                 name );
71         exit( EXIT_FAILURE );
72 }
73
74 int
75 main( int argc, char **argv )
76 {
77         int             i;
78         char            *base = NULL;
79         char            *filter = "(objectClass=person)";
80         char            *pwattr = NULL;
81         int             force = 0;
82         int             noinit = 1;
83         struct tester_conn_args *config;
84
85         /* extra action to do after bind... */
86         struct berval   type[] = {
87                 BER_BVC( "tester=" ),
88                 BER_BVC( "add=" ),
89                 BER_BVC( "bind=" ),
90                 BER_BVC( "modify=" ),
91                 BER_BVC( "modrdn=" ),
92                 BER_BVC( "read=" ),
93                 BER_BVC( "search=" ),
94                 BER_BVNULL
95         };
96
97         LDAPURLDesc     *extra_ludp = NULL;
98
99         config = tester_init( "slapd-bind", TESTER_BIND );
100
101         /* by default, tolerate invalid credentials */
102         tester_ignore_str2errlist( "INVALID_CREDENTIALS" );
103
104         while ( ( i = getopt( argc, argv, TESTER_COMMON_OPTS "a:B:b:Ff:I" ) ) != EOF )
105         {
106                 switch ( i ) {
107                 case 'a':
108                         pwattr = optarg;
109                         break;
110
111                 case 'b':               /* base DN of a tree of user DNs */
112                         base = optarg;
113                         break;
114
115                 case 'B':
116                         {
117                         int     c;
118
119                         for ( c = 0; type[c].bv_val; c++ ) {
120                                 if ( strncasecmp( optarg, type[c].bv_val, type[c].bv_len ) == 0 )
121                                 {
122                                         break;
123                                 }
124                         }
125
126                         if ( type[c].bv_val == NULL ) {
127                                 usage( argv[0], 'B' );
128                         }
129
130                         switch ( c ) {
131                         case TESTER_TESTER:
132                         case TESTER_BIND:
133                                 /* invalid */
134                                 usage( argv[0], 'B' );
135
136                         case TESTER_SEARCH:
137                                 {
138                                 if ( ldap_url_parse( &optarg[type[c].bv_len], &extra_ludp ) != LDAP_URL_SUCCESS )
139                                 {
140                                         usage( argv[0], 'B' );
141                                 }
142                                 } break;
143
144                         case TESTER_ADDEL:
145                         case TESTER_MODIFY:
146                         case TESTER_MODRDN:
147                         case TESTER_READ:
148                                 /* nothing to do */
149                                 break;
150
151                         default:
152                                 assert( 0 );
153                         }
154
155                         } break;
156
157                 case 'f':
158                         filter = optarg;
159                         break;
160
161                 case 'F':
162                         force++;
163                         break;
164
165                 case 'I':
166                         /* reuse connection */
167                         noinit = 0;
168                         break;
169
170                 default:
171                         if ( tester_config_opt( config, i, optarg ) == LDAP_SUCCESS ) {
172                                 break;
173                         }
174                         usage( argv[0], i );
175                         break;
176                 }
177         }
178
179         tester_config_finish( config );
180
181         for ( i = 0; i < config->outerloops; i++ ) {
182                 int rc;
183
184                 if ( base != NULL ) {
185                         rc = do_base( config, config->binddn, base,
186                                 filter, pwattr, force, noinit, -1, NULL );
187                 } else {
188                         rc = do_bind( config, config->binddn,
189                                 config->loops, force, noinit, NULL, -1, NULL );
190                 }
191                 if ( rc == LDAP_SERVER_DOWN )
192                         break;
193         }
194
195         exit( EXIT_SUCCESS );
196 }
197
198
199 static int
200 do_bind( struct tester_conn_args *config, char *dn, int maxloop,
201         int force, int noinit, LDAP **ldp, int action_type, void *action )
202 {
203         LDAP    *ld = ldp ? *ldp : NULL;
204         int     i, rc = -1;
205
206         /* for internal search */
207         int     timelimit = 0;
208         int     sizelimit = 0;
209
210         switch ( action_type ) {
211         case -1:
212                 break;
213
214         case TESTER_SEARCH:
215                 {
216                 LDAPURLDesc     *ludp = (LDAPURLDesc *)action;
217
218                 assert( action != NULL );
219
220                 if ( ludp->lud_exts != NULL ) {
221                         for ( i = 0; ludp->lud_exts[ i ] != NULL; i++ ) {
222                                 char    *ext = ludp->lud_exts[ i ];
223                                 int     crit = 0;
224
225                                 if (ext[0] == '!') {
226                                         crit++;
227                                         ext++;
228                                 }
229
230                                 if ( strncasecmp( ext, "x-timelimit=", STRLENOF( "x-timelimit=" ) ) == 0 ) {
231                                         if ( lutil_atoi( &timelimit, &ext[ STRLENOF( "x-timelimit=" ) ] ) && crit ) {
232                                                 tester_error( "unable to parse critical extension x-timelimit" );
233                                         }
234
235                                 } else if ( strncasecmp( ext, "x-sizelimit=", STRLENOF( "x-sizelimit=" ) ) == 0 ) {
236                                         if ( lutil_atoi( &sizelimit, &ext[ STRLENOF( "x-sizelimit=" ) ] ) && crit ) {
237                                                 tester_error( "unable to parse critical extension x-sizelimit" );
238                                         }
239
240                                 } else if ( crit ) {
241                                         tester_error( "unknown critical extension" );
242                                 }
243                         }
244                 }
245                 } break;
246
247         default:
248                 /* nothing to do yet */
249                 break;
250         }
251                         
252         if ( maxloop > 1 ) {
253                 fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n",
254                          (long) pid, maxloop, dn );
255         }
256
257         for ( i = 0; i < maxloop; i++ ) {
258                 if ( !noinit || ld == NULL ) {
259                         tester_init_ld( &ld, config, TESTER_INIT_ONLY );
260                 }
261
262                 rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, &config->pass, NULL, NULL, NULL );
263                 if ( rc ) {
264                         int first = tester_ignore_err( rc );
265
266                         /* if ignore.. */
267                         if ( first ) {
268                                 /* only log if first occurrence */
269                                 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
270                                         tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
271                                 }
272                                 rc = LDAP_SUCCESS;
273
274                         } else {
275                                 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
276                         }
277                 }
278
279                 switch ( action_type ) {
280                 case -1:
281                         break;
282
283                 case TESTER_SEARCH:
284                         {
285                         LDAPURLDesc     *ludp = (LDAPURLDesc *)action;
286                         LDAPMessage     *res = NULL;
287                         struct timeval  tv = { 0 }, *tvp = NULL;
288
289                         if ( timelimit ) {
290                                 tv.tv_sec = timelimit;
291                                 tvp = &tv;
292                         }
293
294                         assert( action != NULL );
295
296                         rc = ldap_search_ext_s( ld,
297                                 ludp->lud_dn, ludp->lud_scope,
298                                 ludp->lud_filter, ludp->lud_attrs, 0,
299                                 NULL, NULL, tvp, sizelimit, &res );
300                         ldap_msgfree( res );
301                         } break;
302
303                 default:
304                         /* nothing to do yet */
305                         break;
306                 }
307                         
308                 if ( !noinit ) {
309                         ldap_unbind_ext( ld, NULL, NULL );
310                         ld = NULL;
311                 }
312
313                 if ( rc != LDAP_SUCCESS ) {
314                         break;
315                 }
316         }
317
318         if ( maxloop > 1 ) {
319                 fprintf( stderr, "  PID=%ld - Bind done (%d).\n", (long) pid, rc );
320         }
321
322         if ( ldp && noinit ) {
323                 *ldp = ld;
324
325         } else if ( ld != NULL ) {
326                 ldap_unbind_ext( ld, NULL, NULL );
327         }
328
329         return rc;
330 }
331
332
333 static int
334 do_base( struct tester_conn_args *config, char *dn, char *base, char *filter, char *pwattr,
335         int force, int noinit, int action_type, void *action )
336 {
337         LDAP    *ld = NULL;
338         int     i = 0;
339         int     rc = LDAP_SUCCESS;
340         ber_int_t msgid;
341         LDAPMessage *res, *msg;
342         char **dns = NULL;
343         struct berval *creds = NULL;
344         char *attrs[] = { LDAP_NO_ATTRS, NULL };
345         int ndns = 0;
346 #ifdef _WIN32
347         DWORD beg, end;
348 #else
349         struct timeval beg, end;
350 #endif
351         char *nullstr = "";
352
353         tester_init_ld( &ld, config, 0 );
354
355         fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n",
356                         (long) pid, config->loops, base, filter, pwattr );
357
358         if ( pwattr != NULL ) {
359                 attrs[ 0 ] = pwattr;
360         }
361         rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE,
362                         filter, attrs, 0, NULL, NULL, 0, 0, &msgid );
363         if ( rc != LDAP_SUCCESS ) {
364                 tester_ldap_error( ld, "ldap_search_ext", NULL );
365                 exit( EXIT_FAILURE );
366         }
367
368         while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 )
369         {
370                 BerElement *ber;
371                 struct berval bv;
372                 int done = 0;
373
374                 for ( msg = ldap_first_message( ld, res ); msg;
375                         msg = ldap_next_message( ld, msg ) )
376                 {
377                         switch ( ldap_msgtype( msg ) ) {
378                         case LDAP_RES_SEARCH_ENTRY:
379                                 rc = ldap_get_dn_ber( ld, msg, &ber, &bv );
380                                 dns = realloc( dns, (ndns + 1)*sizeof(char *) );
381                                 dns[ndns] = ber_strdup( bv.bv_val );
382                                 if ( pwattr != NULL ) {
383                                         struct berval   **values = ldap_get_values_len( ld, msg, pwattr );
384
385                                         creds = realloc( creds, (ndns + 1)*sizeof(struct berval) );
386                                         if ( values == NULL ) {
387 novals:;
388                                                 creds[ndns].bv_len = 0;
389                                                 creds[ndns].bv_val = nullstr;
390
391                                         } else {
392                                                 static struct berval    cleartext = BER_BVC( "{CLEARTEXT} " );
393                                                 struct berval           value = *values[ 0 ];
394
395                                                 if ( value.bv_val[ 0 ] == '{' ) {
396                                                         char *end = ber_bvchr( &value, '}' );
397
398                                                         if ( end ) {
399                                                                 if ( ber_bvcmp( &value, &cleartext ) == 0 ) {
400                                                                         value.bv_val += cleartext.bv_len;
401                                                                         value.bv_len -= cleartext.bv_len;
402
403                                                                 } else {
404                                                                         ldap_value_free_len( values );
405                                                                         goto novals;
406                                                                 }
407                                                         }
408
409                                                 }
410
411                                                 ber_dupbv( &creds[ndns], &value );
412                                                 ldap_value_free_len( values );
413                                         }
414                                 }
415                                 ndns++;
416                                 ber_free( ber, 0 );
417                                 break;
418
419                         case LDAP_RES_SEARCH_RESULT:
420                                 done = 1;
421                                 break;
422                         }
423                         if ( done )
424                                 break;
425                 }
426                 ldap_msgfree( res );
427                 if ( done ) break;
428         }
429
430 #ifdef _WIN32
431         beg = GetTickCount();
432 #else
433         gettimeofday( &beg, NULL );
434 #endif
435
436         if ( ndns == 0 ) {
437                 tester_error( "No DNs" );
438                 return 1;
439         }
440
441         fprintf( stderr, "  PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n",
442                 (long) pid, base, filter, ndns );
443
444         /* Ok, got list of DNs, now start binding to each */
445         for ( i = 0; i < config->loops; i++ ) {
446                 int             j;
447
448 #if 0   /* use high-order bits for better randomness (Numerical Recipes in "C") */
449                 j = rand() % ndns;
450 #endif
451                 j = ((double)ndns)*rand()/(RAND_MAX + 1.0);
452
453                 if ( creds && !BER_BVISEMPTY( &creds[j] ) ) {
454                         config->pass = creds[j];
455                 }
456
457                 if ( do_bind( config, dns[j], 1, force, noinit, &ld,
458                         action_type, action ) && !force )
459                 {
460                         break;
461                 }
462
463                 if ( config->delay ) {
464                         sleep( config->delay );
465                 }
466         }
467
468         if ( ld != NULL ) {
469                 ldap_unbind_ext( ld, NULL, NULL );
470                 ld = NULL;
471         }
472
473 #ifdef _WIN32
474         end = GetTickCount();
475         end -= beg;
476
477         fprintf( stderr, "  PID=%ld - Bind done %d in %d.%03d seconds.\n",
478                 (long) pid, i, end / 1000, end % 1000 );
479 #else
480         gettimeofday( &end, NULL );
481         end.tv_usec -= beg.tv_usec;
482         if (end.tv_usec < 0 ) {
483                 end.tv_usec += 1000000;
484                 end.tv_sec -= 1;
485         }
486         end.tv_sec -= beg.tv_sec;
487
488         fprintf( stderr, "  PID=%ld - Bind done %d in %ld.%06ld seconds.\n",
489                 (long) pid, i, (long) end.tv_sec, (long) end.tv_usec );
490 #endif
491
492         if ( dns ) {
493                 for ( i = 0; i < ndns; i++ ) {
494                         ber_memfree( dns[i] );
495                 }
496                 free( dns );
497         }
498
499         if ( creds ) {
500                 for ( i = 0; i < ndns; i++ ) {
501                         if ( creds[i].bv_val != nullstr ) {
502                                 ber_memfree( creds[i].bv_val );
503                         }
504                 }
505                 free( creds );
506         }
507
508         return 0;
509 }