]> git.sur5r.net Git - openldap/blobdiff - tests/progs/slapd-bind.c
ITS#6003, #5916 fix ldap_back_entry_get_rw, no deref here
[openldap] / tests / progs / slapd-bind.c
index 5ede6aa934d48bb4c7f2187ea535e23b80540803..1b597f27f04b1063528a535992e2ee259bb15943 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1999-2006 The OpenLDAP Foundation.
+ * Copyright 1999-2009 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 #include <stdio.h>
 
-#include <ac/stdlib.h>
-#include <ac/time.h>
+#include "ac/stdlib.h"
+#include "ac/time.h"
 
-#include <ac/ctype.h>
-#include <ac/param.h>
-#include <ac/socket.h>
-#include <ac/string.h>
-#include <ac/unistd.h>
-#include <ac/wait.h>
-#include <ac/time.h>
+#include "ac/ctype.h"
+#include "ac/param.h"
+#include "ac/socket.h"
+#include "ac/string.h"
+#include "ac/unistd.h"
+#include "ac/wait.h"
+#include "ac/time.h"
 
-#include <ldap.h>
-#include <lutil.h>
-#include <lber_pvt.h>
+#include "ldap.h"
+#include "lutil.h"
+#include "lber_pvt.h"
+#include "ldap_pvt.h"
 
 #include "slapd-common.h"
 
 
 static int
 do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
-       int force, int chaserefs, int noinit, LDAP **ldp );
+       int force, int chaserefs, int noinit, LDAP **ldp,
+       int action_type, void *action );
 
 static int
-do_base( char *uri, struct berval *base, struct berval *pass, char *pwattr,
-       int maxloop, int force, int chaserefs, int noinit, int delay );
+do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr,
+       int maxloop, int force, int chaserefs, int noinit, int delay,
+       int action_type, void *action );
 
 /* This program can be invoked two ways: if -D is used to specify a Bind DN,
  * that DN will be used repeatedly for all of the Binds. If instead -b is used
@@ -56,24 +59,29 @@ do_base( char *uri, struct berval *base, struct berval *pass, char *pwattr,
  * assumed that the users are all onelevel children of the base.
  */
 static void
-usage( char *name )
+usage( char *name, char opt )
 {
+       if ( opt ) {
+               fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
+                       name, opt );
+       }
+
        fprintf( stderr, "usage: %s "
                "[-H uri | -h <host> [-p port]] "
                "[-D <dn> [-w <passwd>]] "
                "[-b <baseDN> [-f <searchfilter>] [-a pwattr]] "
                "[-l <loops>] "
                "[-L <outerloops>] "
+               "[-B <extra>[,...]] "
                "[-F] "
                "[-C] "
                "[-I] "
+               "[-i <ignore>] "
                "[-t delay]\n",
                name );
        exit( EXIT_FAILURE );
 }
 
-static char *filter = "(objectClass=person)";
-
 int
 main( int argc, char **argv )
 {
@@ -81,7 +89,8 @@ main( int argc, char **argv )
        char            *uri = NULL;
        char            *host = "localhost";
        char            *dn = NULL;
-       struct berval   base = { 0, NULL };
+       char            *base = NULL;
+       char            *filter = "(objectClass=person)";
        struct berval   pass = { 0, NULL };
        char            *pwattr = NULL;
        int             port = -1;
@@ -89,21 +98,81 @@ main( int argc, char **argv )
        int             outerloops = 1;
        int             force = 0;
        int             chaserefs = 0;
-       int             noinit = 0;
+       int             noinit = 1;
        int             delay = 0;
 
-       tester_init( "slapd-bind" );
+       /* extra action to do after bind... */
+       struct berval   type[] = {
+               BER_BVC( "tester=" ),
+               BER_BVC( "add=" ),
+               BER_BVC( "bind=" ),
+               BER_BVC( "modify=" ),
+               BER_BVC( "modrdn=" ),
+               BER_BVC( "read=" ),
+               BER_BVC( "search=" ),
+               BER_BVNULL
+       };
+
+       LDAPURLDesc     *extra_ludp = NULL;
 
-       while ( (i = getopt( argc, argv, "a:b:H:h:p:D:w:l:L:f:FIt:" )) != EOF ) {
-               switch( i ) {
+       tester_init( "slapd-bind", TESTER_BIND );
+
+       /* by default, tolerate invalid credentials */
+       tester_ignore_str2errlist( "INVALID_CREDENTIALS" );
+
+       while ( ( i = getopt( argc, argv, "a:B:b:D:Ff:H:h:Ii:L:l:p:t:w:" ) ) != EOF )
+       {
+               switch ( i ) {
                case 'a':
                        pwattr = optarg;
                        break;
 
                case 'b':               /* base DN of a tree of user DNs */
-                       ber_str2bv( optarg, 0, 0, &base );
+                       base = optarg;
                        break;
 
+               case 'B':
+                       {
+                       int     c;
+
+                       for ( c = 0; type[c].bv_val; c++ ) {
+                               if ( strncasecmp( optarg, type[c].bv_val, type[c].bv_len ) == 0 )
+                               {
+                                       break;
+                               }
+                       }
+
+                       if ( type[c].bv_val == NULL ) {
+                               usage( argv[0], 'B' );
+                       }
+
+                       switch ( c ) {
+                       case TESTER_TESTER:
+                       case TESTER_BIND:
+                               /* invalid */
+                               usage( argv[0], 'B' );
+
+                       case TESTER_SEARCH:
+                               {
+                               if ( ldap_url_parse( &optarg[type[c].bv_len], &extra_ludp ) != LDAP_URL_SUCCESS )
+                               {
+                                       usage( argv[0], 'B' );
+                               }
+                               } break;
+
+                       case TESTER_ADDEL:
+                       case TESTER_MODIFY:
+                       case TESTER_MODRDN:
+                       case TESTER_READ:
+                               /* nothing to do */
+                               break;
+
+                       default:
+                               assert( 0 );
+                       }
+
+                       } break;
+
                case 'C':
                        chaserefs++;
                        break;
@@ -116,9 +185,13 @@ main( int argc, char **argv )
                        host = optarg;
                        break;
 
+               case 'i':
+                       tester_ignore_str2errlist( optarg );
+                       break;
+
                case 'p':               /* the servers port */
                        if ( lutil_atoi( &port, optarg ) != 0 ) {
-                               usage( argv[0] );
+                               usage( argv[0], 'p' );
                        }
                        break;
 
@@ -127,18 +200,19 @@ main( int argc, char **argv )
                        break;
 
                case 'w':
-                       ber_str2bv( optarg, 0, 0, &pass );
+                       ber_str2bv( optarg, 0, 1, &pass );
+                       memset( optarg, '*', pass.bv_len );
                        break;
 
                case 'l':               /* the number of loops */
                        if ( lutil_atoi( &loops, optarg ) != 0 ) {
-                               usage( argv[0] );
+                               usage( argv[0], 'l' );
                        }
                        break;
 
                case 'L':               /* the number of outerloops */
                        if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
-                               usage( argv[0] );
+                               usage( argv[0], 'L' );
                        }
                        break;
 
@@ -152,36 +226,40 @@ main( int argc, char **argv )
 
                case 'I':
                        /* reuse connection */
-                       noinit++;
+                       noinit = 0;
                        break;
 
                case 't':
                        /* sleep between binds */
                        if ( lutil_atoi( &delay, optarg ) != 0 ) {
-                               usage( argv[0] );
+                               usage( argv[0], 't' );
                        }
                        break;
 
                default:
-                       usage( argv[0] );
+                       usage( argv[0], i );
                        break;
                }
        }
 
        if ( port == -1 && uri == NULL ) {
-               usage( argv[0] );
+               usage( argv[0], '\0' );
        }
 
        uri = tester_uri( uri, host, port );
 
        for ( i = 0; i < outerloops; i++ ) {
-               if ( base.bv_val != NULL ) {
-                       do_base( uri, &base, &pass, pwattr, loops,
-                               force, chaserefs, noinit, delay );
+               int rc;
+
+               if ( base != NULL ) {
+                       rc = do_base( uri, dn, &pass, base, filter, pwattr, loops,
+                               force, chaserefs, noinit, delay, -1, NULL );
                } else {
-                       do_bind( uri, dn, &pass, loops,
-                               force, chaserefs, noinit, NULL );
+                       rc = do_bind( uri, dn, &pass, loops,
+                               force, chaserefs, noinit, NULL, -1, NULL );
                }
+               if ( rc == LDAP_SERVER_DOWN )
+                       break;
        }
 
        exit( EXIT_SUCCESS );
@@ -190,15 +268,62 @@ main( int argc, char **argv )
 
 static int
 do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
-       int force, int chaserefs, int noinit, LDAP **ldp )
+       int force, int chaserefs, int noinit, LDAP **ldp,
+       int action_type, void *action )
 {
        LDAP    *ld = ldp ? *ldp : NULL;
-       int     i, first = 1, rc = -1;
-       pid_t   pid = getpid();
+       int     i, rc = -1;
+
+       /* for internal search */
+       int     timelimit = 0;
+       int     sizelimit = 0;
+
+       switch ( action_type ) {
+       case -1:
+               break;
+
+       case TESTER_SEARCH:
+               {
+               LDAPURLDesc     *ludp = (LDAPURLDesc *)action;
+
+               assert( action != NULL );
+
+               if ( ludp->lud_exts != NULL ) {
+                       for ( i = 0; ludp->lud_exts[ i ] != NULL; i++ ) {
+                               char    *ext = ludp->lud_exts[ i ];
+                               int     crit = 0;
+
+                               if (ext[0] == '!') {
+                                       crit++;
+                                       ext++;
+                               }
+
+                               if ( strncasecmp( ext, "x-timelimit=", STRLENOF( "x-timelimit=" ) ) == 0 ) {
+                                       if ( lutil_atoi( &timelimit, &ext[ STRLENOF( "x-timelimit=" ) ] ) && crit ) {
+                                               tester_error( "unable to parse critical extension x-timelimit" );
+                                       }
+
+                               } else if ( strncasecmp( ext, "x-sizelimit=", STRLENOF( "x-sizelimit=" ) ) == 0 ) {
+                                       if ( lutil_atoi( &sizelimit, &ext[ STRLENOF( "x-sizelimit=" ) ] ) && crit ) {
+                                               tester_error( "unable to parse critical extension x-sizelimit" );
+                                       }
+
+                               } else if ( crit ) {
+                                       tester_error( "unknown critical extension" );
+                               }
+                       }
+               }
+               } break;
 
-       if ( maxloop > 1 )
+       default:
+               /* nothing to do yet */
+               break;
+       }
+                       
+       if ( maxloop > 1 ) {
                fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n",
                         (long) pid, maxloop, dn );
+       }
 
        for ( i = 0; i < maxloop; i++ ) {
                if ( !noinit || ld == NULL ) {
@@ -217,35 +342,63 @@ do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
                }
 
                rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
-               switch ( rc ) {
-               case LDAP_SUCCESS:
+               if ( rc ) {
+                       int first = tester_ignore_err( rc );
+
+                       /* if ignore.. */
+                       if ( first ) {
+                               /* only log if first occurrence */
+                               if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
+                                       tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
+                               }
+                               rc = LDAP_SUCCESS;
+
+                       } else {
+                               tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
+                       }
+               }
+
+               switch ( action_type ) {
+               case -1:
                        break;
 
-               case LDAP_INVALID_CREDENTIALS:
-                       /* don't log: it's intended */
-                       if ( force >= 2 ) {
-                               if ( !first ) {
-                                       break;
-                               }
-                               first = 0;
+               case TESTER_SEARCH:
+                       {
+                       LDAPURLDesc     *ludp = (LDAPURLDesc *)action;
+                       LDAPMessage     *res = NULL;
+                       struct timeval  tv = { 0 }, *tvp = NULL;
+
+                       if ( timelimit ) {
+                               tv.tv_sec = timelimit;
+                               tvp = &tv;
                        }
-                       /* fallthru */
+
+                       assert( action != NULL );
+
+                       rc = ldap_search_ext_s( ld,
+                               ludp->lud_dn, ludp->lud_scope,
+                               ludp->lud_filter, ludp->lud_attrs, 0,
+                               NULL, NULL, tvp, sizelimit, &res );
+                       ldap_msgfree( res );
+                       } break;
 
                default:
-                       tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
+                       /* nothing to do yet */
+                       break;
                }
-
+                       
                if ( !noinit ) {
                        ldap_unbind_ext( ld, NULL, NULL );
                        ld = NULL;
                }
-               if ( rc != LDAP_SUCCESS && !force ) {
+
+               if ( rc != LDAP_SUCCESS ) {
                        break;
                }
        }
 
        if ( maxloop > 1 ) {
-               fprintf( stderr, " PID=%ld - Bind done (%d).\n", (long) pid, rc );
+               fprintf( stderr, "  PID=%ld - Bind done (%d).\n", (long) pid, rc );
        }
 
        if ( ldp && noinit ) {
@@ -260,12 +413,12 @@ do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
 
 
 static int
-do_base( char *uri, struct berval *base, struct berval *pass, char *pwattr,
-       int maxloop, int force, int chaserefs, int noinit, int delay )
+do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr,
+       int maxloop, int force, int chaserefs, int noinit, int delay,
+       int action_type, void *action )
 {
        LDAP    *ld = NULL;
        int     i = 0;
-       pid_t   pid = getpid();
        int     rc = LDAP_SUCCESS;
        ber_int_t msgid;
        LDAPMessage *res, *msg;
@@ -279,11 +432,8 @@ do_base( char *uri, struct berval *base, struct berval *pass, char *pwattr,
        struct timeval beg, end;
 #endif
        int version = LDAP_VERSION3;
-       struct berval pw = { 0, NULL };
        char *nullstr = "";
 
-       srand(pid);
-
        ldap_initialize( &ld, uri );
        if ( ld == NULL ) {
                tester_perror( "ldap_initialize", NULL );
@@ -294,19 +444,19 @@ do_base( char *uri, struct berval *base, struct berval *pass, char *pwattr,
        (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
                chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );
 
-       rc = ldap_sasl_bind_s( ld, NULL, LDAP_SASL_SIMPLE, &pw, NULL, NULL, NULL );
+       rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
        if ( rc != LDAP_SUCCESS ) {
                tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
                exit( EXIT_FAILURE );
        }
 
        fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n",
-                       (long) pid, maxloop, base->bv_val, filter, pwattr );
+                       (long) pid, maxloop, base, filter, pwattr );
 
        if ( pwattr != NULL ) {
                attrs[ 0 ] = pwattr;
        }
-       rc = ldap_search_ext( ld, base->bv_val, LDAP_SCOPE_SUBTREE,
+       rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE,
                        filter, attrs, 0, NULL, NULL, 0, 0, &msgid );
        if ( rc != LDAP_SUCCESS ) {
                tester_ldap_error( ld, "ldap_search_ext", NULL );
@@ -333,13 +483,8 @@ do_base( char *uri, struct berval *base, struct berval *pass, char *pwattr,
                                        creds = realloc( creds, (ndns + 1)*sizeof(struct berval) );
                                        if ( values == NULL ) {
 novals:;
-                                               if ( pass != NULL ) {
-                                                       ber_dupbv( &creds[ndns], pass );
-
-                                               } else {
-                                                       creds[ndns].bv_len = 0;
-                                                       creds[ndns].bv_val = nullstr;
-                                               }
+                                               creds[ndns].bv_len = 0;
+                                               creds[ndns].bv_val = nullstr;
 
                                        } else {
                                                static struct berval    cleartext = BER_BVC( "{CLEARTEXT} " );
@@ -387,26 +532,30 @@ novals:;
 #endif
 
        if ( ndns == 0 ) {
-               tester_error( "No RDNs" );
+               tester_error( "No DNs" );
                return 1;
        }
 
-       fprintf( stderr, "  PID=%ld - got %d values.\n", (long) pid, ndns );
+       fprintf( stderr, "  PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n",
+               (long) pid, base, filter, ndns );
 
-       /* Ok, got list of RDNs, now start binding to each */
+       /* Ok, got list of DNs, now start binding to each */
        for ( i = 0; i < maxloop; i++ ) {
-               int j, k;
-               struct berval *cred = pass;
+               int             j;
+               struct berval   cred = { 0, NULL };
 
-               for ( j = 0, k = 0; k < ndns; k++) {
-                       j = rand() % ndns;
-               }
+
+#if 0  /* use high-order bits for better randomness (Numerical Recipes in "C") */
+               j = rand() % ndns;
+#endif
+               j = ((double)ndns)*rand()/(RAND_MAX + 1.0);
 
                if ( creds && !BER_BVISEMPTY( &creds[j] ) ) {
-                       cred = &creds[j];
+                       cred = creds[j];
                }
-               if ( do_bind( uri, dns[j], cred, 1, force, chaserefs, noinit, &ld )
-                       && !force )
+
+               if ( do_bind( uri, dns[j], &cred, 1, force, chaserefs, noinit, &ld,
+                       action_type, action ) && !force )
                {
                        break;
                }
@@ -425,7 +574,7 @@ novals:;
        end = GetTickCount();
        end -= beg;
 
-       fprintf( stderr, " PID=%ld - Bind done %d in %d.%03d seconds.\n",
+       fprintf( stderr, "  PID=%ld - Bind done %d in %d.%03d seconds.\n",
                (long) pid, i, end / 1000, end % 1000 );
 #else
        gettimeofday( &end, NULL );
@@ -436,7 +585,7 @@ novals:;
        }
        end.tv_sec -= beg.tv_sec;
 
-       fprintf( stderr, " PID=%ld - Bind done %d in %ld.%06ld seconds.\n",
+       fprintf( stderr, "  PID=%ld - Bind done %d in %ld.%06ld seconds.\n",
                (long) pid, i, (long) end.tv_sec, (long) end.tv_usec );
 #endif