Back to index

openldap  2.4.31
slapd-bind.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1999-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* ACKNOWLEDGEMENTS:
00016  * This work was initially developed by Howard Chu for inclusion
00017  * in OpenLDAP Software.
00018  */
00019 
00020 #include "portable.h"
00021 
00022 #include <stdio.h>
00023 
00024 #include "ac/stdlib.h"
00025 #include "ac/time.h"
00026 
00027 #include "ac/ctype.h"
00028 #include "ac/param.h"
00029 #include "ac/socket.h"
00030 #include "ac/string.h"
00031 #include "ac/unistd.h"
00032 #include "ac/wait.h"
00033 #include "ac/time.h"
00034 
00035 #include "ldap.h"
00036 #include "lutil.h"
00037 #include "lber_pvt.h"
00038 #include "ldap_pvt.h"
00039 
00040 #include "slapd-common.h"
00041 
00042 #define LOOPS 100
00043 
00044 static int
00045 do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
00046        int force, int chaserefs, int noinit, LDAP **ldp,
00047        int action_type, void *action );
00048 
00049 static int
00050 do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr,
00051        int maxloop, int force, int chaserefs, int noinit, int delay,
00052        int action_type, void *action );
00053 
00054 /* This program can be invoked two ways: if -D is used to specify a Bind DN,
00055  * that DN will be used repeatedly for all of the Binds. If instead -b is used
00056  * to specify a base DN, a search will be done for all "person" objects under
00057  * that base DN. Then DNs from this list will be randomly selected for each
00058  * Bind request. All of the users must have identical passwords. Also it is
00059  * assumed that the users are all onelevel children of the base.
00060  */
00061 static void
00062 usage( char *name, char opt )
00063 {
00064        if ( opt ) {
00065               fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
00066                      name, opt );
00067        }
00068 
00069        fprintf( stderr, "usage: %s "
00070               "[-H uri | -h <host> [-p port]] "
00071               "[-D <dn> [-w <passwd>]] "
00072               "[-b <baseDN> [-f <searchfilter>] [-a pwattr]] "
00073               "[-l <loops>] "
00074               "[-L <outerloops>] "
00075               "[-B <extra>[,...]] "
00076               "[-F] "
00077               "[-C] "
00078               "[-I] "
00079               "[-i <ignore>] "
00080               "[-t delay]\n",
00081               name );
00082        exit( EXIT_FAILURE );
00083 }
00084 
00085 int
00086 main( int argc, char **argv )
00087 {
00088        int           i;
00089        char          *uri = NULL;
00090        char          *host = "localhost";
00091        char          *dn = NULL;
00092        char          *base = NULL;
00093        char          *filter = "(objectClass=person)";
00094        struct berval pass = { 0, NULL };
00095        char          *pwattr = NULL;
00096        int           port = -1;
00097        int           loops = LOOPS;
00098        int           outerloops = 1;
00099        int           force = 0;
00100        int           chaserefs = 0;
00101        int           noinit = 1;
00102        int           delay = 0;
00103 
00104        /* extra action to do after bind... */
00105        struct berval type[] = {
00106               BER_BVC( "tester=" ),
00107               BER_BVC( "add=" ),
00108               BER_BVC( "bind=" ),
00109               BER_BVC( "modify=" ),
00110               BER_BVC( "modrdn=" ),
00111               BER_BVC( "read=" ),
00112               BER_BVC( "search=" ),
00113               BER_BVNULL
00114        };
00115 
00116        LDAPURLDesc   *extra_ludp = NULL;
00117 
00118        tester_init( "slapd-bind", TESTER_BIND );
00119 
00120        /* by default, tolerate invalid credentials */
00121        tester_ignore_str2errlist( "INVALID_CREDENTIALS" );
00122 
00123        while ( ( i = getopt( argc, argv, "a:B:b:D:Ff:H:h:Ii:L:l:p:t:w:" ) ) != EOF )
00124        {
00125               switch ( i ) {
00126               case 'a':
00127                      pwattr = optarg;
00128                      break;
00129 
00130               case 'b':            /* base DN of a tree of user DNs */
00131                      base = optarg;
00132                      break;
00133 
00134               case 'B':
00135                      {
00136                      int    c;
00137 
00138                      for ( c = 0; type[c].bv_val; c++ ) {
00139                             if ( strncasecmp( optarg, type[c].bv_val, type[c].bv_len ) == 0 )
00140                             {
00141                                    break;
00142                             }
00143                      }
00144 
00145                      if ( type[c].bv_val == NULL ) {
00146                             usage( argv[0], 'B' );
00147                      }
00148 
00149                      switch ( c ) {
00150                      case TESTER_TESTER:
00151                      case TESTER_BIND:
00152                             /* invalid */
00153                             usage( argv[0], 'B' );
00154 
00155                      case TESTER_SEARCH:
00156                             {
00157                             if ( ldap_url_parse( &optarg[type[c].bv_len], &extra_ludp ) != LDAP_URL_SUCCESS )
00158                             {
00159                                    usage( argv[0], 'B' );
00160                             }
00161                             } break;
00162 
00163                      case TESTER_ADDEL:
00164                      case TESTER_MODIFY:
00165                      case TESTER_MODRDN:
00166                      case TESTER_READ:
00167                             /* nothing to do */
00168                             break;
00169 
00170                      default:
00171                             assert( 0 );
00172                      }
00173 
00174                      } break;
00175 
00176               case 'C':
00177                      chaserefs++;
00178                      break;
00179 
00180               case 'H':            /* the server uri */
00181                      uri = optarg;
00182                      break;
00183 
00184               case 'h':            /* the servers host */
00185                      host = optarg;
00186                      break;
00187 
00188               case 'i':
00189                      tester_ignore_str2errlist( optarg );
00190                      break;
00191 
00192               case 'p':            /* the servers port */
00193                      if ( lutil_atoi( &port, optarg ) != 0 ) {
00194                             usage( argv[0], 'p' );
00195                      }
00196                      break;
00197 
00198               case 'D':
00199                      dn = optarg;
00200                      break;
00201 
00202               case 'w':
00203                      ber_str2bv( optarg, 0, 1, &pass );
00204                      memset( optarg, '*', pass.bv_len );
00205                      break;
00206 
00207               case 'l':            /* the number of loops */
00208                      if ( lutil_atoi( &loops, optarg ) != 0 ) {
00209                             usage( argv[0], 'l' );
00210                      }
00211                      break;
00212 
00213               case 'L':            /* the number of outerloops */
00214                      if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
00215                             usage( argv[0], 'L' );
00216                      }
00217                      break;
00218 
00219               case 'f':
00220                      filter = optarg;
00221                      break;
00222 
00223               case 'F':
00224                      force++;
00225                      break;
00226 
00227               case 'I':
00228                      /* reuse connection */
00229                      noinit = 0;
00230                      break;
00231 
00232               case 't':
00233                      /* sleep between binds */
00234                      if ( lutil_atoi( &delay, optarg ) != 0 ) {
00235                             usage( argv[0], 't' );
00236                      }
00237                      break;
00238 
00239               default:
00240                      usage( argv[0], i );
00241                      break;
00242               }
00243        }
00244 
00245        if ( port == -1 && uri == NULL ) {
00246               usage( argv[0], '\0' );
00247        }
00248 
00249        uri = tester_uri( uri, host, port );
00250 
00251        for ( i = 0; i < outerloops; i++ ) {
00252               int rc;
00253 
00254               if ( base != NULL ) {
00255                      rc = do_base( uri, dn, &pass, base, filter, pwattr, loops,
00256                             force, chaserefs, noinit, delay, -1, NULL );
00257               } else {
00258                      rc = do_bind( uri, dn, &pass, loops,
00259                             force, chaserefs, noinit, NULL, -1, NULL );
00260               }
00261               if ( rc == LDAP_SERVER_DOWN )
00262                      break;
00263        }
00264 
00265        exit( EXIT_SUCCESS );
00266 }
00267 
00268 
00269 static int
00270 do_bind( char *uri, char *dn, struct berval *pass, int maxloop,
00271        int force, int chaserefs, int noinit, LDAP **ldp,
00272        int action_type, void *action )
00273 {
00274        LDAP   *ld = ldp ? *ldp : NULL;
00275        int    i, rc = -1;
00276 
00277        /* for internal search */
00278        int    timelimit = 0;
00279        int    sizelimit = 0;
00280 
00281        switch ( action_type ) {
00282        case -1:
00283               break;
00284 
00285        case TESTER_SEARCH:
00286               {
00287               LDAPURLDesc   *ludp = (LDAPURLDesc *)action;
00288 
00289               assert( action != NULL );
00290 
00291               if ( ludp->lud_exts != NULL ) {
00292                      for ( i = 0; ludp->lud_exts[ i ] != NULL; i++ ) {
00293                             char   *ext = ludp->lud_exts[ i ];
00294                             int    crit = 0;
00295 
00296                             if (ext[0] == '!') {
00297                                    crit++;
00298                                    ext++;
00299                             }
00300 
00301                             if ( strncasecmp( ext, "x-timelimit=", STRLENOF( "x-timelimit=" ) ) == 0 ) {
00302                                    if ( lutil_atoi( &timelimit, &ext[ STRLENOF( "x-timelimit=" ) ] ) && crit ) {
00303                                           tester_error( "unable to parse critical extension x-timelimit" );
00304                                    }
00305 
00306                             } else if ( strncasecmp( ext, "x-sizelimit=", STRLENOF( "x-sizelimit=" ) ) == 0 ) {
00307                                    if ( lutil_atoi( &sizelimit, &ext[ STRLENOF( "x-sizelimit=" ) ] ) && crit ) {
00308                                           tester_error( "unable to parse critical extension x-sizelimit" );
00309                                    }
00310 
00311                             } else if ( crit ) {
00312                                    tester_error( "unknown critical extension" );
00313                             }
00314                      }
00315               }
00316               } break;
00317 
00318        default:
00319               /* nothing to do yet */
00320               break;
00321        }
00322                      
00323        if ( maxloop > 1 ) {
00324               fprintf( stderr, "PID=%ld - Bind(%d): dn=\"%s\".\n",
00325                       (long) pid, maxloop, dn );
00326        }
00327 
00328        for ( i = 0; i < maxloop; i++ ) {
00329               if ( !noinit || ld == NULL ) {
00330                      int version = LDAP_VERSION3;
00331                      ldap_initialize( &ld, uri );
00332                      if ( ld == NULL ) {
00333                             tester_perror( "ldap_initialize", NULL );
00334                             rc = -1;
00335                             break;
00336                      }
00337 
00338                      (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
00339                             &version ); 
00340                      (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
00341                             chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );
00342               }
00343 
00344               rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
00345               if ( rc ) {
00346                      int first = tester_ignore_err( rc );
00347 
00348                      /* if ignore.. */
00349                      if ( first ) {
00350                             /* only log if first occurrence */
00351                             if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
00352                                    tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
00353                             }
00354                             rc = LDAP_SUCCESS;
00355 
00356                      } else {
00357                             tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
00358                      }
00359               }
00360 
00361               switch ( action_type ) {
00362               case -1:
00363                      break;
00364 
00365               case TESTER_SEARCH:
00366                      {
00367                      LDAPURLDesc   *ludp = (LDAPURLDesc *)action;
00368                      LDAPMessage   *res = NULL;
00369                      struct timeval       tv = { 0 }, *tvp = NULL;
00370 
00371                      if ( timelimit ) {
00372                             tv.tv_sec = timelimit;
00373                             tvp = &tv;
00374                      }
00375 
00376                      assert( action != NULL );
00377 
00378                      rc = ldap_search_ext_s( ld,
00379                             ludp->lud_dn, ludp->lud_scope,
00380                             ludp->lud_filter, ludp->lud_attrs, 0,
00381                             NULL, NULL, tvp, sizelimit, &res );
00382                      ldap_msgfree( res );
00383                      } break;
00384 
00385               default:
00386                      /* nothing to do yet */
00387                      break;
00388               }
00389                      
00390               if ( !noinit ) {
00391                      ldap_unbind_ext( ld, NULL, NULL );
00392                      ld = NULL;
00393               }
00394 
00395               if ( rc != LDAP_SUCCESS ) {
00396                      break;
00397               }
00398        }
00399 
00400        if ( maxloop > 1 ) {
00401               fprintf( stderr, "  PID=%ld - Bind done (%d).\n", (long) pid, rc );
00402        }
00403 
00404        if ( ldp && noinit ) {
00405               *ldp = ld;
00406 
00407        } else if ( ld != NULL ) {
00408               ldap_unbind_ext( ld, NULL, NULL );
00409        }
00410 
00411        return rc;
00412 }
00413 
00414 
00415 static int
00416 do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr,
00417        int maxloop, int force, int chaserefs, int noinit, int delay,
00418        int action_type, void *action )
00419 {
00420        LDAP   *ld = NULL;
00421        int    i = 0;
00422        int     rc = LDAP_SUCCESS;
00423        ber_int_t msgid;
00424        LDAPMessage *res, *msg;
00425        char **dns = NULL;
00426        struct berval *creds = NULL;
00427        char *attrs[] = { LDAP_NO_ATTRS, NULL };
00428        int ndns = 0;
00429 #ifdef _WIN32
00430        DWORD beg, end;
00431 #else
00432        struct timeval beg, end;
00433 #endif
00434        int version = LDAP_VERSION3;
00435        char *nullstr = "";
00436 
00437        ldap_initialize( &ld, uri );
00438        if ( ld == NULL ) {
00439               tester_perror( "ldap_initialize", NULL );
00440               exit( EXIT_FAILURE );
00441        }
00442 
00443        (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
00444        (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
00445               chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );
00446 
00447        rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
00448        if ( rc != LDAP_SUCCESS ) {
00449               tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
00450               exit( EXIT_FAILURE );
00451        }
00452 
00453        fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n",
00454                      (long) pid, maxloop, base, filter, pwattr );
00455 
00456        if ( pwattr != NULL ) {
00457               attrs[ 0 ] = pwattr;
00458        }
00459        rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE,
00460                      filter, attrs, 0, NULL, NULL, 0, 0, &msgid );
00461        if ( rc != LDAP_SUCCESS ) {
00462               tester_ldap_error( ld, "ldap_search_ext", NULL );
00463               exit( EXIT_FAILURE );
00464        }
00465 
00466        while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 )
00467        {
00468               BerElement *ber;
00469               struct berval bv;
00470               int done = 0;
00471 
00472               for ( msg = ldap_first_message( ld, res ); msg;
00473                      msg = ldap_next_message( ld, msg ) )
00474               {
00475                      switch ( ldap_msgtype( msg ) ) {
00476                      case LDAP_RES_SEARCH_ENTRY:
00477                             rc = ldap_get_dn_ber( ld, msg, &ber, &bv );
00478                             dns = realloc( dns, (ndns + 1)*sizeof(char *) );
00479                             dns[ndns] = ber_strdup( bv.bv_val );
00480                             if ( pwattr != NULL ) {
00481                                    struct berval **values = ldap_get_values_len( ld, msg, pwattr );
00482 
00483                                    creds = realloc( creds, (ndns + 1)*sizeof(struct berval) );
00484                                    if ( values == NULL ) {
00485 novals:;
00486                                           creds[ndns].bv_len = 0;
00487                                           creds[ndns].bv_val = nullstr;
00488 
00489                                    } else {
00490                                           static struct berval cleartext = BER_BVC( "{CLEARTEXT} " );
00491                                           struct berval        value = *values[ 0 ];
00492 
00493                                           if ( value.bv_val[ 0 ] == '{' ) {
00494                                                  char *end = ber_bvchr( &value, '}' );
00495 
00496                                                  if ( end ) {
00497                                                         if ( ber_bvcmp( &value, &cleartext ) == 0 ) {
00498                                                                value.bv_val += cleartext.bv_len;
00499                                                                value.bv_len -= cleartext.bv_len;
00500 
00501                                                         } else {
00502                                                                ldap_value_free_len( values );
00503                                                                goto novals;
00504                                                         }
00505                                                  }
00506 
00507                                           }
00508 
00509                                           ber_dupbv( &creds[ndns], &value );
00510                                           ldap_value_free_len( values );
00511                                    }
00512                             }
00513                             ndns++;
00514                             ber_free( ber, 0 );
00515                             break;
00516 
00517                      case LDAP_RES_SEARCH_RESULT:
00518                             done = 1;
00519                             break;
00520                      }
00521                      if ( done )
00522                             break;
00523               }
00524               ldap_msgfree( res );
00525               if ( done ) break;
00526        }
00527 
00528 #ifdef _WIN32
00529        beg = GetTickCount();
00530 #else
00531        gettimeofday( &beg, NULL );
00532 #endif
00533 
00534        if ( ndns == 0 ) {
00535               tester_error( "No DNs" );
00536               return 1;
00537        }
00538 
00539        fprintf( stderr, "  PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n",
00540               (long) pid, base, filter, ndns );
00541 
00542        /* Ok, got list of DNs, now start binding to each */
00543        for ( i = 0; i < maxloop; i++ ) {
00544               int           j;
00545               struct berval cred = { 0, NULL };
00546 
00547 
00548 #if 0  /* use high-order bits for better randomness (Numerical Recipes in "C") */
00549               j = rand() % ndns;
00550 #endif
00551               j = ((double)ndns)*rand()/(RAND_MAX + 1.0);
00552 
00553               if ( creds && !BER_BVISEMPTY( &creds[j] ) ) {
00554                      cred = creds[j];
00555               }
00556 
00557               if ( do_bind( uri, dns[j], &cred, 1, force, chaserefs, noinit, &ld,
00558                      action_type, action ) && !force )
00559               {
00560                      break;
00561               }
00562 
00563               if ( delay ) {
00564                      sleep( delay );
00565               }
00566        }
00567 
00568        if ( ld != NULL ) {
00569               ldap_unbind_ext( ld, NULL, NULL );
00570               ld = NULL;
00571        }
00572 
00573 #ifdef _WIN32
00574        end = GetTickCount();
00575        end -= beg;
00576 
00577        fprintf( stderr, "  PID=%ld - Bind done %d in %d.%03d seconds.\n",
00578               (long) pid, i, end / 1000, end % 1000 );
00579 #else
00580        gettimeofday( &end, NULL );
00581        end.tv_usec -= beg.tv_usec;
00582        if (end.tv_usec < 0 ) {
00583               end.tv_usec += 1000000;
00584               end.tv_sec -= 1;
00585        }
00586        end.tv_sec -= beg.tv_sec;
00587 
00588        fprintf( stderr, "  PID=%ld - Bind done %d in %ld.%06ld seconds.\n",
00589               (long) pid, i, (long) end.tv_sec, (long) end.tv_usec );
00590 #endif
00591 
00592        if ( dns ) {
00593               for ( i = 0; i < ndns; i++ ) {
00594                      ber_memfree( dns[i] );
00595               }
00596               free( dns );
00597        }
00598 
00599        if ( creds ) {
00600               for ( i = 0; i < ndns; i++ ) {
00601                      if ( creds[i].bv_val != nullstr ) {
00602                             ber_memfree( creds[i].bv_val );
00603                      }
00604               }
00605               free( creds );
00606        }
00607 
00608        return 0;
00609 }