]> git.sur5r.net Git - openldap/blobdiff - tests/progs/slapd-read.c
ITS#6003, #5916 fix ldap_back_entry_get_rw, no deref here
[openldap] / tests / progs / slapd-read.c
index 7b4887f0be94ed05f8ff0f7a1a6deb7e969373d8..35dcbe6f3aa9650001259e4cf9b7c5283e50ffd9 100644 (file)
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1999-2009 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Kurt Spanier for inclusion
+ * in OpenLDAP Software.
+ */
+
 #include "portable.h"
 
 #include <stdio.h>
 
-#include <ac/string.h>
-#include <ac/ctype.h>
-#include <ac/socket.h>
-#include <ac/unistd.h>
-#include <ac/wait.h>
+#include "ac/stdlib.h"
 
-#include <sys/param.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 "lber.h"
 #include "ldap.h"
+#include "lutil.h"
+
+#include "ldap_pvt.h"
+
+#include "slapd-common.h"
 
 #define LOOPS  100
+#define RETRIES        0
 
 static void
-do_read( char *host, int port, char *entry, int maxloop );
+do_read( char *uri, char *manager, struct berval *passwd,
+       char *entry, LDAP **ld,
+       char **attrs, int noattrs, int nobind, int maxloop,
+       int maxretries, int delay, int force, int chaserefs );
+
+static void
+do_random( char *uri, char *manager, struct berval *passwd,
+       char *sbase, char *filter, char **attrs, int noattrs, int nobind,
+       int innerloop, int maxretries, int delay, int force, int chaserefs );
 
 static void
 usage( char *name )
 {
-       fprintf( stderr, "usage: %s [-h <host>] -p port -e <entry> [-l <loops>]\n",
-                       name );
-       exit( 1 );
+        fprintf( stderr,
+               "usage: %s "
+               "-H <uri> | ([-h <host>] -p <port>) "
+               "-D <manager> "
+               "-w <passwd> "
+               "-e <entry> "
+               "[-A] "
+               "[-C] "
+               "[-F] "
+               "[-N] "
+               "[-f filter] "
+               "[-i <ignore>] "
+               "[-l <loops>] "
+               "[-L <outerloops>] "
+               "[-r <maxretries>] "
+               "[-t <delay>] "
+               "[-T <attrs>] "
+               "[<attrs>] "
+               "\n",
+               name );
+       exit( EXIT_FAILURE );
 }
 
 int
 main( int argc, char **argv )
 {
-       int             i, j;
-       char        *host = "localhost";
-       int                     port = -1;
+       int             i;
+       char            *uri = NULL;
+       char            *host = "localhost";
+       int             port = -1;
+       char            *manager = NULL;
+       struct berval   passwd = { 0, NULL };
        char            *entry = NULL;
-       int                     loops = LOOPS;
+       char            *filter  = NULL;
+       int             loops = LOOPS;
+       int             outerloops = 1;
+       int             retries = RETRIES;
+       int             delay = 0;
+       int             force = 0;
+       int             chaserefs = 0;
+       char            *srchattrs[] = { "1.1", NULL };
+       char            **attrs = srchattrs;
+       int             noattrs = 0;
+       int             nobind = 0;
+
+       tester_init( "slapd-read", TESTER_READ );
+
+       /* by default, tolerate referrals and no such object */
+       tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
+
+       while ( (i = getopt( argc, argv, "ACD:e:Ff:H:h:i:L:l:p:r:t:T:w:" )) != EOF ) {
+               switch ( i ) {
+               case 'A':
+                       noattrs++;
+                       break;
 
-       while ( (i = getopt( argc, argv, "h:p:e:l:" )) != EOF ) {
-               switch( i ) {
-                       case 'h':               /* the servers host */
-                               host = strdup( optarg );
+               case 'C':
+                       chaserefs++;
                        break;
 
-                       case 'p':               /* the servers port */
-                               port = atoi( optarg );
-                               break;
+               case 'H':               /* the server uri */
+                       uri = strdup( optarg );
+                       break;
 
-                       case 'e':               /* file with entry search request */
-                               entry = strdup( optarg );
-                               break;
+               case 'h':               /* the servers host */
+                       host = strdup( optarg );
+                       break;
 
-                       case 'l':               /* the number of loops */
-                               loops = atoi( optarg );
-                               break;
+               case 'i':
+                       tester_ignore_str2errlist( optarg );
+                       break;
 
-                       default:
+               case 'N':
+                       nobind++;
+                       break;
+
+               case 'p':               /* the servers port */
+                       if ( lutil_atoi( &port, optarg ) != 0 ) {
                                usage( argv[0] );
-                               break;
+                       }
+                       break;
+
+               case 'D':               /* the servers manager */
+                       manager = strdup( optarg );
+                       break;
+
+               case 'w':               /* the server managers password */
+                       passwd.bv_val = strdup( optarg );
+                       passwd.bv_len = strlen( optarg );
+                       memset( optarg, '*', passwd.bv_len );
+                       break;
+
+               case 'e':               /* DN to search for */
+                       entry = strdup( optarg );
+                       break;
+
+               case 'f':               /* the search request */
+                       filter = strdup( optarg );
+                       break;
+
+               case 'F':
+                       force++;
+                       break;
+
+               case 'l':               /* the number of loops */
+                       if ( lutil_atoi( &loops, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               case 'L':               /* the number of outerloops */
+                       if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               case 'r':               /* the number of retries */
+                       if ( lutil_atoi( &retries, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               case 't':               /* delay in seconds */
+                       if ( lutil_atoi( &delay, optarg ) != 0 ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               case 'T':
+                       attrs = ldap_str2charray( optarg, "," );
+                       if ( attrs == NULL ) {
+                               usage( argv[0] );
+                       }
+                       break;
+
+               default:
+                       usage( argv[0] );
+                       break;
                }
        }
 
-       if (( entry == NULL ) || ( port == -1 ))
+       if (( entry == NULL ) || ( port == -1 && uri == NULL ))
                usage( argv[0] );
 
        if ( *entry == '\0' ) {
-
                fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
                                argv[0] );
-               exit( 1 );
+               exit( EXIT_FAILURE );
+       }
 
+       if ( argv[optind] != NULL ) {
+               attrs = &argv[optind];
        }
 
-       do_read( host, port, entry, ( 4 * loops ));
+       uri = tester_uri( uri, host, port );
 
-       exit( 0 );
-}
+       for ( i = 0; i < outerloops; i++ ) {
+               if ( filter != NULL ) {
+                       do_random( uri, manager, &passwd, entry, filter, attrs,
+                               noattrs, nobind, loops, retries, delay, force,
+                               chaserefs );
 
+               } else {
+                       do_read( uri, manager, &passwd, entry, NULL, attrs,
+                               noattrs, nobind, loops, retries, delay, force,
+                               chaserefs );
+               }
+       }
+
+       exit( EXIT_SUCCESS );
+}
 
 static void
-do_read( char *host, int port, char *entry, int maxloop )
+do_random( char *uri, char *manager, struct berval *passwd,
+       char *sbase, char *filter, char **srchattrs, int noattrs, int nobind,
+       int innerloop, int maxretries, int delay, int force, int chaserefs )
 {
-       LDAP    *ld;
-       int     i;
-       char    *attrs[] = { "cn", "sn", NULL };
-       char    *filter = "(objectclass=*)";
-       pid_t   pid = getpid();
-
-       if (( ld = ldap_init( host, port )) == NULL ) {
-               perror( "ldap_init" );
-               exit( 1 );
+       LDAP    *ld = NULL;
+       int     i = 0, do_retry = maxretries;
+       char    *attrs[ 2 ];
+       int     rc = LDAP_SUCCESS;
+       int     version = LDAP_VERSION3;
+       int     nvalues = 0;
+       char    **values = NULL;
+       LDAPMessage *res = NULL, *e = NULL;
+
+       attrs[ 0 ] = LDAP_NO_ATTRS;
+       attrs[ 1 ] = NULL;
+
+       ldap_initialize( &ld, uri );
+       if ( ld == NULL ) {
+               tester_perror( "ldap_initialize", NULL );
+               exit( EXIT_FAILURE );
+       }
+
+       (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 
+       (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
+               chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
+
+       if ( do_retry == maxretries ) {
+               fprintf( stderr, "PID=%ld - Read(%d): base=\"%s\", filter=\"%s\".\n",
+                               (long) pid, innerloop, sbase, filter );
        }
 
-       if ( ldap_bind_s( ld, NULL, NULL, LDAP_AUTH_SIMPLE ) != LDAP_SUCCESS ) {
-               ldap_perror( ld, "ldap_bind" );
-                exit( 1 );
+       if ( nobind == 0 ) {
+               rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
+               if ( rc != LDAP_SUCCESS ) {
+                       tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
+                       switch ( rc ) {
+                       case LDAP_BUSY:
+                       case LDAP_UNAVAILABLE:
+                       /* fallthru */
+                       default:
+                               break;
+                       }
+                       exit( EXIT_FAILURE );
+               }
        }
 
+       rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
+               filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
+       switch ( rc ) {
+       case LDAP_SIZELIMIT_EXCEEDED:
+       case LDAP_TIMELIMIT_EXCEEDED:
+       case LDAP_SUCCESS:
+               nvalues = ldap_count_entries( ld, res );
+               if ( nvalues == 0 ) {
+                       if ( rc ) {
+                               tester_ldap_error( ld, "ldap_search_ext_s", NULL );
+                       }
+                       break;
+               }
 
-       fprintf( stderr, "PID=%ld - Read(%d): entry=\"%s\".\n",
-                (long) pid, maxloop, entry );
+               values = malloc( ( nvalues + 1 ) * sizeof( char * ) );
+               for ( i = 0, e = ldap_first_entry( ld, res ); e != NULL; i++, e = ldap_next_entry( ld, e ) )
+               {
+                       values[ i ] = ldap_get_dn( ld, e );
+               }
+               values[ i ] = NULL;
 
-       for ( i = 0; i < maxloop; i++ ) {
-               LDAPMessage *res;
-               int         rc;
+               ldap_msgfree( res );
 
-               if (( rc = ldap_search_s( ld, entry, LDAP_SCOPE_BASE,
-                               filter, attrs, 0, &res )) != LDAP_SUCCESS ) {
+               if ( do_retry == maxretries ) {
+                       fprintf( stderr, "  PID=%ld - Read base=\"%s\" filter=\"%s\" got %d values.\n",
+                               (long) pid, sbase, filter, nvalues );
+               }
 
-                       ldap_perror( ld, "ldap_read" );
-                       if ( rc != LDAP_NO_SUCH_OBJECT ) break;
-                       continue;
+               for ( i = 0; i < innerloop; i++ ) {
+#if 0  /* use high-order bits for better randomness (Numerical Recipes in "C") */
+                       int     r = rand() % nvalues;
+#endif
+                       int     r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
 
+                       do_read( uri, manager, passwd, values[ r ], &ld,
+                               srchattrs, noattrs, nobind, 1, maxretries,
+                               delay, force, chaserefs );
                }
+               free( values );
+               break;
 
-               ldap_msgfree( res );
+       default:
+               tester_ldap_error( ld, "ldap_search_ext_s", NULL );
+               break;
        }
 
-       fprintf( stderr, " PID=%ld - Read done.\n", (long) pid );
+       fprintf( stderr, "  PID=%ld - Search done (%d).\n", (long) pid, rc );
 
-       ldap_unbind( ld );
+       if ( ld != NULL ) {
+               ldap_unbind_ext( ld, NULL, NULL );
+       }
 }
 
+static void
+do_read( char *uri, char *manager, struct berval *passwd, char *entry,
+       LDAP **ldp, char **attrs, int noattrs, int nobind, int maxloop,
+       int maxretries, int delay, int force, int chaserefs )
+{
+       LDAP    *ld = ldp ? *ldp : NULL;
+       int     i = 0, do_retry = maxretries;
+       int     rc = LDAP_SUCCESS;
+       int     version = LDAP_VERSION3;
+
+retry:;
+       if ( ld == NULL ) {
+               ldap_initialize( &ld, uri );
+               if ( ld == NULL ) {
+                       tester_perror( "ldap_initialize", NULL );
+                       exit( EXIT_FAILURE );
+               }
+
+               (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 
+               (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
+                       chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
+
+               if ( do_retry == maxretries ) {
+                       fprintf( stderr, "PID=%ld - Read(%d): entry=\"%s\".\n",
+                               (long) pid, maxloop, entry );
+               }
+
+               if ( nobind == 0 ) {
+                       rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
+                       if ( rc != LDAP_SUCCESS ) {
+                               tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
+                               switch ( rc ) {
+                               case LDAP_BUSY:
+                               case LDAP_UNAVAILABLE:
+                                       if ( do_retry > 0 ) {
+                                               ldap_unbind_ext( ld, NULL, NULL );
+                                               ld = NULL;
+                                               do_retry--;
+                                               if ( delay != 0 ) {
+                                                   sleep( delay );
+                                               }
+                                               goto retry;
+                                       }
+                               /* fallthru */
+                               default:
+                                       break;
+                               }
+                               exit( EXIT_FAILURE );
+                       }
+               }
+       }
+
+       for ( ; i < maxloop; i++ ) {
+               LDAPMessage *res = NULL;
+
+               rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE,
+                               NULL, attrs, noattrs, NULL, NULL, NULL,
+                               LDAP_NO_LIMIT, &res );
+               if ( res != NULL ) {
+                       ldap_msgfree( res );
+               }
+
+               if ( rc ) {
+                       int             first = tester_ignore_err( rc );
+                       char            buf[ BUFSIZ ];
+
+                       snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
+
+                       /* if ignore.. */
+                       if ( first ) {
+                               /* only log if first occurrence */
+                               if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
+                                       tester_ldap_error( ld, buf, NULL );
+                               }
+                               continue;
+                       }
+
+                       /* busy needs special handling */
+                       tester_ldap_error( ld, buf, NULL );
+                       if ( rc == LDAP_BUSY && do_retry > 0 ) {
+                               ldap_unbind_ext( ld, NULL, NULL );
+                               ld = NULL;
+                               do_retry--;
+                               goto retry;
+                       }
+                       break;
+               }
+       }
+
+       if ( ldp != NULL ) {
+               *ldp = ld;
+
+       } else {
+               fprintf( stderr, "  PID=%ld - Read done (%d).\n", (long) pid, rc );
+
+               if ( ld != NULL ) {
+                       ldap_unbind_ext( ld, NULL, NULL );
+               }
+       }
+}