]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-common.c
bb3eea1c47e99527113fc01abbb2ff889e577642
[openldap] / tests / progs / slapd-common.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/unistd.h"
26 #include "ac/string.h"
27 #include "ac/errno.h"
28
29 #include "ldap.h"
30
31 #include "lutil.h"
32 #include "lutil_ldap.h"
33 #include "ldap_pvt.h"
34 #include "slapd-common.h"
35
36 /* global vars */
37 pid_t pid;
38
39 /* static vars */
40 static char progname[ BUFSIZ ];
41 tester_t progtype;
42
43 /*
44  * ignore_count[] is indexed by result code:
45  * negative for OpenLDAP client-side errors, positive for protocol codes.
46  */
47 #define TESTER_CLIENT_FIRST     LDAP_REFERRAL_LIMIT_EXCEEDED /* negative */
48 #define TESTER_SERVER_LAST      LDAP_OTHER
49 static int ignore_base  [ -TESTER_CLIENT_FIRST + TESTER_SERVER_LAST + 1 ];
50 #define    ignore_count (ignore_base - TESTER_CLIENT_FIRST)
51
52 static const struct {
53         const char *name;
54         int     err;
55 } ignore_str2err[] = {
56         { "OPERATIONS_ERROR",           LDAP_OPERATIONS_ERROR },
57         { "PROTOCOL_ERROR",             LDAP_PROTOCOL_ERROR },
58         { "TIMELIMIT_EXCEEDED",         LDAP_TIMELIMIT_EXCEEDED },
59         { "SIZELIMIT_EXCEEDED",         LDAP_SIZELIMIT_EXCEEDED },
60         { "COMPARE_FALSE",              LDAP_COMPARE_FALSE },
61         { "COMPARE_TRUE",               LDAP_COMPARE_TRUE },
62         { "AUTH_METHOD_NOT_SUPPORTED",  LDAP_AUTH_METHOD_NOT_SUPPORTED },
63         { "STRONG_AUTH_NOT_SUPPORTED",  LDAP_STRONG_AUTH_NOT_SUPPORTED },
64         { "STRONG_AUTH_REQUIRED",       LDAP_STRONG_AUTH_REQUIRED },
65         { "STRONGER_AUTH_REQUIRED",     LDAP_STRONGER_AUTH_REQUIRED },
66         { "PARTIAL_RESULTS",            LDAP_PARTIAL_RESULTS },
67
68         { "REFERRAL",                   LDAP_REFERRAL },
69         { "ADMINLIMIT_EXCEEDED",        LDAP_ADMINLIMIT_EXCEEDED },
70         { "UNAVAILABLE_CRITICAL_EXTENSION", LDAP_UNAVAILABLE_CRITICAL_EXTENSION },
71         { "CONFIDENTIALITY_REQUIRED",   LDAP_CONFIDENTIALITY_REQUIRED },
72         { "SASL_BIND_IN_PROGRESS",      LDAP_SASL_BIND_IN_PROGRESS },
73
74         { "NO_SUCH_ATTRIBUTE",          LDAP_NO_SUCH_ATTRIBUTE },
75         { "UNDEFINED_TYPE",             LDAP_UNDEFINED_TYPE },
76         { "INAPPROPRIATE_MATCHING",     LDAP_INAPPROPRIATE_MATCHING },
77         { "CONSTRAINT_VIOLATION",       LDAP_CONSTRAINT_VIOLATION },
78         { "TYPE_OR_VALUE_EXISTS",       LDAP_TYPE_OR_VALUE_EXISTS },
79         { "INVALID_SYNTAX",             LDAP_INVALID_SYNTAX },
80
81         { "NO_SUCH_OBJECT",             LDAP_NO_SUCH_OBJECT },
82         { "ALIAS_PROBLEM",              LDAP_ALIAS_PROBLEM },
83         { "INVALID_DN_SYNTAX",          LDAP_INVALID_DN_SYNTAX },
84         { "IS_LEAF",                    LDAP_IS_LEAF },
85         { "ALIAS_DEREF_PROBLEM",        LDAP_ALIAS_DEREF_PROBLEM },
86
87         /* obsolete */
88         { "PROXY_AUTHZ_FAILURE",        LDAP_X_PROXY_AUTHZ_FAILURE },
89         { "INAPPROPRIATE_AUTH",         LDAP_INAPPROPRIATE_AUTH },
90         { "INVALID_CREDENTIALS",        LDAP_INVALID_CREDENTIALS },
91         { "INSUFFICIENT_ACCESS",        LDAP_INSUFFICIENT_ACCESS },
92
93         { "BUSY",                       LDAP_BUSY },
94         { "UNAVAILABLE",                LDAP_UNAVAILABLE },
95         { "UNWILLING_TO_PERFORM",       LDAP_UNWILLING_TO_PERFORM },
96         { "LOOP_DETECT",                LDAP_LOOP_DETECT },
97
98         { "NAMING_VIOLATION",           LDAP_NAMING_VIOLATION },
99         { "OBJECT_CLASS_VIOLATION",     LDAP_OBJECT_CLASS_VIOLATION },
100         { "NOT_ALLOWED_ON_NONLEAF",     LDAP_NOT_ALLOWED_ON_NONLEAF },
101         { "NOT_ALLOWED_ON_RDN",         LDAP_NOT_ALLOWED_ON_RDN },
102         { "ALREADY_EXISTS",             LDAP_ALREADY_EXISTS },
103         { "NO_OBJECT_CLASS_MODS",       LDAP_NO_OBJECT_CLASS_MODS },
104         { "RESULTS_TOO_LARGE",          LDAP_RESULTS_TOO_LARGE },
105         { "AFFECTS_MULTIPLE_DSAS",      LDAP_AFFECTS_MULTIPLE_DSAS },
106
107         { "OTHER",                      LDAP_OTHER },
108
109         { "SERVER_DOWN",                LDAP_SERVER_DOWN },
110         { "LOCAL_ERROR",                LDAP_LOCAL_ERROR },
111         { "ENCODING_ERROR",             LDAP_ENCODING_ERROR },
112         { "DECODING_ERROR",             LDAP_DECODING_ERROR },
113         { "TIMEOUT",                    LDAP_TIMEOUT },
114         { "AUTH_UNKNOWN",               LDAP_AUTH_UNKNOWN },
115         { "FILTER_ERROR",               LDAP_FILTER_ERROR },
116         { "USER_CANCELLED",             LDAP_USER_CANCELLED },
117         { "PARAM_ERROR",                LDAP_PARAM_ERROR },
118         { "NO_MEMORY",                  LDAP_NO_MEMORY },
119         { "CONNECT_ERROR",              LDAP_CONNECT_ERROR },
120         { "NOT_SUPPORTED",              LDAP_NOT_SUPPORTED },
121         { "CONTROL_NOT_FOUND",          LDAP_CONTROL_NOT_FOUND },
122         { "NO_RESULTS_RETURNED",        LDAP_NO_RESULTS_RETURNED },
123         { "MORE_RESULTS_TO_RETURN",     LDAP_MORE_RESULTS_TO_RETURN },
124         { "CLIENT_LOOP",                LDAP_CLIENT_LOOP },
125         { "REFERRAL_LIMIT_EXCEEDED",    LDAP_REFERRAL_LIMIT_EXCEEDED },
126
127         { NULL }
128 };
129
130 #define UNKNOWN_ERR     (1234567890)
131
132 #define RETRIES 0
133 #define LOOPS   100
134
135 static int
136 tester_ignore_str2err( const char *err )
137 {
138         int             i, ignore = 1;
139
140         if ( strcmp( err, "ALL" ) == 0 ) {
141                 for ( i = 0; ignore_str2err[ i ].name != NULL; i++ ) {
142                         ignore_count[ ignore_str2err[ i ].err ] = 1;
143                 }
144                 ignore_count[ LDAP_SUCCESS ] = 0;
145
146                 return 0;
147         }
148
149         if ( err[ 0 ] == '!' ) {
150                 ignore = 0;
151                 err++;
152
153         } else if ( err[ 0 ] == '*' ) {
154                 ignore = -1;
155                 err++;
156         }
157
158         for ( i = 0; ignore_str2err[ i ].name != NULL; i++ ) {
159                 if ( strcmp( err, ignore_str2err[ i ].name ) == 0 ) {
160                         int     err = ignore_str2err[ i ].err;
161
162                         if ( err != LDAP_SUCCESS ) {
163                                 ignore_count[ err ] = ignore;
164                         }
165
166                         return err;
167                 }
168         }
169
170         return UNKNOWN_ERR;
171 }
172
173 int
174 tester_ignore_str2errlist( const char *err )
175 {
176         int     i;
177         char    **errs = ldap_str2charray( err, "," );
178
179         for ( i = 0; errs[ i ] != NULL; i++ ) {
180                 /* TODO: allow <err>:<prog> to ignore <err> only when <prog> */
181                 (void)tester_ignore_str2err( errs[ i ] );
182         }
183
184         ldap_charray_free( errs );
185
186         return 0;
187 }
188
189 int
190 tester_ignore_err( int err )
191 {
192         int rc = 1;
193
194         if ( err && TESTER_CLIENT_FIRST <= err && err <= TESTER_SERVER_LAST ) {
195                 rc = ignore_count[ err ];
196                 if ( rc != 0 ) {
197                         ignore_count[ err ] = rc + (rc > 0 ? 1 : -1);
198                 }
199         }
200
201         /* SUCCESS is always "ignored" */
202         return rc;
203 }
204
205 struct tester_conn_args *
206 tester_init( const char *pname, tester_t ptype )
207 {
208         static struct tester_conn_args config = {
209                 .authmethod = -1,
210                 .retries = RETRIES,
211                 .loops = LOOPS,
212                 .outerloops = 1,
213
214                 .uri = NULL,
215                 .host = "localhost",
216                 .port = 389,
217         };
218
219         pid = getpid();
220         srand( pid );
221         snprintf( progname, sizeof( progname ), "%s PID=%d", pname, pid );
222         progtype = ptype;
223
224         return &config;
225 }
226
227 void
228 tester_ldap_error( LDAP *ld, const char *fname, const char *msg )
229 {
230         int             err;
231         char            *text = NULL;
232         LDAPControl     **ctrls = NULL;
233
234         ldap_get_option( ld, LDAP_OPT_RESULT_CODE, (void *)&err );
235         if ( err != LDAP_SUCCESS ) {
236                 ldap_get_option( ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void *)&text );
237         }
238
239         fprintf( stderr, "%s: %s: %s (%d) %s %s\n",
240                 progname, fname, ldap_err2string( err ), err,
241                 text == NULL ? "" : text,
242                 msg ? msg : "" );
243
244         if ( text ) {
245                 ldap_memfree( text );
246                 text = NULL;
247         }
248
249         ldap_get_option( ld, LDAP_OPT_MATCHED_DN, (void *)&text );
250         if ( text != NULL ) {
251                 if ( text[ 0 ] != '\0' ) {
252                         fprintf( stderr, "\tmatched: %s\n", text );
253                 }
254                 ldap_memfree( text );
255                 text = NULL;
256         }
257
258         ldap_get_option( ld, LDAP_OPT_SERVER_CONTROLS, (void *)&ctrls );
259         if ( ctrls != NULL ) {
260                 int     i;
261
262                 fprintf( stderr, "\tcontrols:\n" );
263                 for ( i = 0; ctrls[ i ] != NULL; i++ ) {
264                         fprintf( stderr, "\t\t%s\n", ctrls[ i ]->ldctl_oid );
265                 }
266                 ldap_controls_free( ctrls );
267                 ctrls = NULL;
268         }
269
270         if ( err == LDAP_REFERRAL ) {
271                 char **refs = NULL;
272
273                 ldap_get_option( ld, LDAP_OPT_REFERRAL_URLS, (void *)&refs );
274
275                 if ( refs ) {
276                         int     i;
277
278                         fprintf( stderr, "\treferral:\n" );
279                         for ( i = 0; refs[ i ] != NULL; i++ ) {
280                                 fprintf( stderr, "\t\t%s\n", refs[ i ] );
281                         }
282
283                         ber_memvfree( (void **)refs );
284                 }
285         }
286 }
287
288 void
289 tester_perror( const char *fname, const char *msg )
290 {
291         int     save_errno = errno;
292         char    buf[ BUFSIZ ];
293
294         fprintf( stderr, "%s: %s: (%d) %s %s\n",
295                         progname, fname, save_errno,
296                         AC_STRERROR_R( save_errno, buf, sizeof( buf ) ),
297                         msg ? msg : "" );
298 }
299
300 int
301 tester_config_opt( struct tester_conn_args *config, char opt, char *optarg )
302 {
303         switch ( opt ) {
304                 case 'C':
305                         config->chaserefs++;
306                         break;
307
308                 case 'D':
309                         config->binddn = strdup( optarg );
310                         break;
311
312                 case 'd':
313                         {
314                                 int debug;
315                                 if ( lutil_atoi( &debug, optarg ) != 0 ) {
316                                         return -1;
317                                 }
318
319                                 if ( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug )
320                                         != LBER_OPT_SUCCESS )
321                                 {
322                                         fprintf( stderr,
323                                                 "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
324                                 }
325
326                                 if ( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug )
327                                         != LDAP_OPT_SUCCESS )
328                                 {
329                                         fprintf( stderr,
330                                                 "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
331                                 }
332                                 break;
333                         }
334
335                 case 'H':
336                         config->uri = strdup( optarg );
337                         break;
338
339                 case 'h':
340                         config->host = strdup( optarg );
341                         break;
342
343                 case 'i':
344                         tester_ignore_str2errlist( optarg );
345                         break;
346
347                 case 'L':
348                         if ( lutil_atoi( &config->outerloops, optarg ) != 0 ) {
349                                 return -1;
350                         }
351                         break;
352
353                 case 'l':
354                         if ( lutil_atoi( &config->loops, optarg ) != 0 ) {
355                                 return -1;
356                         }
357                         break;
358
359 #ifdef HAVE_CYRUS_SASL
360                 case 'O':
361                         if ( config->secprops != NULL ) {
362                                 return -1;
363                         }
364                         if ( config->authmethod != -1 && config->authmethod != LDAP_AUTH_SASL ) {
365                                 return -1;
366                         }
367                         config->authmethod = LDAP_AUTH_SASL;
368                         config->secprops = ber_strdup( optarg );
369                         break;
370
371                 case 'R':
372                         if ( config->realm != NULL ) {
373                                 return -1;
374                         }
375                         if ( config->authmethod != -1 && config->authmethod != LDAP_AUTH_SASL ) {
376                                 return -1;
377                         }
378                         config->authmethod = LDAP_AUTH_SASL;
379                         config->realm = ber_strdup( optarg );
380                         break;
381
382                 case 'U':
383                         if ( config->authc_id != NULL ) {
384                                 return -1;
385                         }
386                         if ( config->authmethod != -1 && config->authmethod != LDAP_AUTH_SASL ) {
387                                 return -1;
388                         }
389                         config->authmethod = LDAP_AUTH_SASL;
390                         config->authc_id = ber_strdup( optarg );
391                         break;
392
393                 case 'X':
394                         if ( config->authz_id != NULL ) {
395                                 return -1;
396                         }
397                         if ( config->authmethod != -1 && config->authmethod != LDAP_AUTH_SASL ) {
398                                 return -1;
399                         }
400                         config->authmethod = LDAP_AUTH_SASL;
401                         config->authz_id = ber_strdup( optarg );
402                         break;
403
404                 case 'Y':
405                         if ( config->mech != NULL ) {
406                                 return -1;
407                         }
408                         if ( config->authmethod != -1 && config->authmethod != LDAP_AUTH_SASL ) {
409                                 return -1;
410                         }
411                         config->authmethod = LDAP_AUTH_SASL;
412                         config->mech = ber_strdup( optarg );
413                         break;
414 #endif
415
416                 case 'p':
417                         if ( lutil_atoi( &config->port, optarg ) != 0 ) {
418                                 return -1;
419                         }
420                         break;
421
422                 case 'r':
423                         if ( lutil_atoi( &config->retries, optarg ) != 0 ) {
424                                 return -1;
425                         }
426                         break;
427
428                 case 't':
429                         if ( lutil_atoi( &config->delay, optarg ) != 0 ) {
430                                 return -1;
431                         }
432                         break;
433
434                 case 'w':
435                         config->pass.bv_val = strdup( optarg );
436                         config->pass.bv_len = strlen( optarg );
437                         memset( optarg, '*', config->pass.bv_len );
438                         break;
439
440                 case 'x':
441                         if ( config->authmethod != -1 && config->authmethod != LDAP_AUTH_SIMPLE ) {
442                                 return -1;
443                         }
444                         config->authmethod = LDAP_AUTH_SIMPLE;
445                         break;
446
447                 default:
448                         return -1;
449         }
450
451         return LDAP_SUCCESS;
452 }
453
454 void
455 tester_config_finish( struct tester_conn_args *config )
456 {
457         if ( !config->uri ) {
458                 static char     uribuf[ BUFSIZ ];
459
460                 config->uri = uribuf;
461                 snprintf( uribuf, sizeof( uribuf ), "ldap://%s:%d",
462                                 config->host, config->port );
463         }
464
465         if ( config->authmethod == -1 ) {
466 #ifdef HAVE_CYRUS_SASL
467                 if ( config->binddn != NULL ) {
468                         config->authmethod = LDAP_AUTH_SIMPLE;
469                 } else {
470                         config->authmethod = LDAP_AUTH_SASL;
471                 }
472 #else
473                 config->authmethod = LDAP_AUTH_SIMPLE;
474 #endif
475         }
476
477 #ifdef HAVE_CYRUS_SASL
478         if ( config->authmethod == LDAP_AUTH_SASL ) {
479                 config->defaults = lutil_sasl_defaults( NULL,
480                         config->mech,
481                         config->realm,
482                         config->authc_id,
483                         config->pass.bv_val,
484                         config->authz_id );
485
486                 if ( config->defaults == NULL ) {
487                         tester_error( "unable to prepare SASL defaults" );
488                         exit( EXIT_FAILURE );
489                 }
490         }
491 #endif
492 }
493
494 void
495 tester_init_ld( LDAP **ldp, struct tester_conn_args *config, int flags )
496 {
497         LDAP *ld;
498         int rc, do_retry = config->retries;
499         int version = LDAP_VERSION3;
500
501 retry:;
502         ldap_initialize( &ld, config->uri );
503         if ( ld == NULL ) {
504                 tester_perror( "ldap_initialize", NULL );
505                 exit( EXIT_FAILURE );
506         }
507
508         (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
509         (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
510                 config->chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );
511
512         if ( !( flags & TESTER_INIT_ONLY ) ) {
513                 if ( config->authmethod == LDAP_AUTH_SASL ) {
514 #ifdef HAVE_CYRUS_SASL
515                         if ( config->secprops != NULL ) {
516                                 rc = ldap_set_option( ld,
517                                                 LDAP_OPT_X_SASL_SECPROPS, config->secprops );
518
519                                 if ( rc != LDAP_OPT_SUCCESS ) {
520                                         tester_ldap_error( ld, "ldap_set_option(SECPROPS)", NULL );
521                                         exit( EXIT_FAILURE );
522                                 }
523                         }
524
525                         rc = ldap_sasl_interactive_bind_s( ld,
526                                         config->binddn,
527                                         config->mech,
528                                         NULL, NULL,
529                                         LDAP_SASL_QUIET,
530                                         lutil_sasl_interact,
531                                         config->defaults );
532 #else /* HAVE_CYRUS_SASL */
533                         /* caller shouldn't have allowed this */
534                         assert(0);
535 #endif
536                 } else if ( config->authmethod == LDAP_AUTH_SIMPLE ) {
537                         rc = ldap_sasl_bind_s( ld,
538                                         config->binddn, LDAP_SASL_SIMPLE,
539                                         &config->pass, NULL, NULL, NULL );
540                 }
541
542                 if ( rc != LDAP_SUCCESS ) {
543                         tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
544                         switch ( rc ) {
545                                 case LDAP_BUSY:
546                                 case LDAP_UNAVAILABLE:
547                                         if ( do_retry > 0 ) {
548                                                 do_retry--;
549                                                 if ( config->delay > 0 ) {
550                                                         sleep( config->delay );
551                                                 }
552                                                 goto retry;
553                                         }
554                         }
555                         tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
556                         exit( EXIT_FAILURE );
557                 }
558         }
559
560         *ldp = ld;
561 }
562
563 void
564 tester_error( const char *msg )
565 {
566         fprintf( stderr, "%s: %s\n", progname, msg );
567 }