1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1999-2011 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 Kurt Spanier for inclusion 17 * in OpenLDAP Software. 18 */ 19 20#include "portable.h" 21 22#include <stdio.h> 23 24#include "ac/stdlib.h" 25 26#include "ac/ctype.h" 27#include "ac/param.h" 28#include "ac/socket.h" 29#include "ac/string.h" 30#include "ac/unistd.h" 31#include "ac/wait.h" 32 33#include "ldap.h" 34#include "lutil.h" 35 36#include "slapd-common.h" 37 38#define LOOPS 100 39#define RETRIES 0 40 41static char * 42get_add_entry( char *filename, LDAPMod ***mods ); 43 44static void 45do_addel( char *uri, char *manager, struct berval *passwd, 46 char *dn, LDAPMod **attrs, int maxloop, int maxretries, int delay, 47 int friendly, int chaserefs ); 48 49static void 50usage( char *name ) 51{ 52 fprintf( stderr, 53 "usage: %s " 54 "-H <uri> | ([-h <host>] -p <port>) " 55 "-D <manager> " 56 "-w <passwd> " 57 "-f <addfile> " 58 "[-i <ignore>] " 59 "[-l <loops>] " 60 "[-L <outerloops>] " 61 "[-r <maxretries>] " 62 "[-t <delay>] " 63 "[-F] " 64 "[-C]\n", 65 name ); 66 exit( EXIT_FAILURE ); 67} 68 69int 70main( int argc, char **argv ) 71{ 72 int i; 73 char *host = "localhost"; 74 char *uri = NULL; 75 int port = -1; 76 char *manager = NULL; 77 struct berval passwd = { 0, NULL }; 78 char *filename = NULL; 79 char *entry = NULL; 80 int loops = LOOPS; 81 int outerloops = 1; 82 int retries = RETRIES; 83 int delay = 0; 84 int friendly = 0; 85 int chaserefs = 0; 86 LDAPMod **attrs = NULL; 87 88 tester_init( "slapd-addel", TESTER_ADDEL ); 89 90 while ( ( i = getopt( argc, argv, "CD:Ff:H:h:i:L:l:p:r:t:w:" ) ) != EOF ) 91 { 92 switch ( i ) { 93 case 'C': 94 chaserefs++; 95 break; 96 97 case 'F': 98 friendly++; 99 break; 100 101 case 'H': /* the server's URI */ 102 uri = strdup( optarg ); 103 break; 104 105 case 'h': /* the servers host */ 106 host = strdup( optarg ); 107 break; 108 109 case 'i': 110 /* ignored (!) by now */ 111 break; 112 113 case 'p': /* the servers port */ 114 if ( lutil_atoi( &port, optarg ) != 0 ) { 115 usage( argv[0] ); 116 } 117 break; 118 119 case 'D': /* the servers manager */ 120 manager = strdup( optarg ); 121 break; 122 123 case 'w': /* the server managers password */ 124 passwd.bv_val = strdup( optarg ); 125 passwd.bv_len = strlen( optarg ); 126 memset( optarg, '*', passwd.bv_len ); 127 break; 128 129 case 'f': /* file with entry search request */ 130 filename = strdup( optarg ); 131 break; 132 133 case 'l': /* the number of loops */ 134 if ( lutil_atoi( &loops, optarg ) != 0 ) { 135 usage( argv[0] ); 136 } 137 break; 138 139 case 'L': /* the number of outerloops */ 140 if ( lutil_atoi( &outerloops, optarg ) != 0 ) { 141 usage( argv[0] ); 142 } 143 break; 144 145 case 'r': /* number of retries */ 146 if ( lutil_atoi( &retries, optarg ) != 0 ) { 147 usage( argv[0] ); 148 } 149 break; 150 151 case 't': /* delay in seconds */ 152 if ( lutil_atoi( &delay, optarg ) != 0 ) { 153 usage( argv[0] ); 154 } 155 break; 156 157 default: 158 usage( argv[0] ); 159 break; 160 } 161 } 162 163 if (( filename == NULL ) || ( port == -1 && uri == NULL ) || 164 ( manager == NULL ) || ( passwd.bv_val == NULL )) 165 usage( argv[0] ); 166 167 entry = get_add_entry( filename, &attrs ); 168 if (( entry == NULL ) || ( *entry == '\0' )) { 169 170 fprintf( stderr, "%s: invalid entry DN in file \"%s\".\n", 171 argv[0], filename ); 172 exit( EXIT_FAILURE ); 173 174 } 175 176 if (( attrs == NULL ) || ( *attrs == '\0' )) { 177 178 fprintf( stderr, "%s: invalid attrs in file \"%s\".\n", 179 argv[0], filename ); 180 exit( EXIT_FAILURE ); 181 182 } 183 184 uri = tester_uri( uri, host, port ); 185 186 for ( i = 0; i < outerloops; i++ ) { 187 do_addel( uri, manager, &passwd, entry, attrs, 188 loops, retries, delay, friendly, chaserefs ); 189 } 190 191 exit( EXIT_SUCCESS ); 192} 193 194 195static void 196addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen ) 197{ 198 LDAPMod **pmods; 199 int i, j; 200 struct berval *bvp; 201 202 pmods = *pmodsp; 203 modop |= LDAP_MOD_BVALUES; 204 205 i = 0; 206 if ( pmods != NULL ) { 207 for ( ; pmods[ i ] != NULL; ++i ) { 208 if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 && 209 pmods[ i ]->mod_op == modop ) { 210 break; 211 } 212 } 213 } 214 215 if ( pmods == NULL || pmods[ i ] == NULL ) { 216 if (( pmods = (LDAPMod **)realloc( pmods, (i + 2) * 217 sizeof( LDAPMod * ))) == NULL ) { 218 tester_perror( "realloc", NULL ); 219 exit( EXIT_FAILURE ); 220 } 221 *pmodsp = pmods; 222 pmods[ i + 1 ] = NULL; 223 if (( pmods[ i ] = (LDAPMod *)calloc( 1, sizeof( LDAPMod ))) 224 == NULL ) { 225 tester_perror( "calloc", NULL ); 226 exit( EXIT_FAILURE ); 227 } 228 pmods[ i ]->mod_op = modop; 229 if (( pmods[ i ]->mod_type = strdup( attr )) == NULL ) { 230 tester_perror( "strdup", NULL ); 231 exit( EXIT_FAILURE ); 232 } 233 } 234 235 if ( value != NULL ) { 236 j = 0; 237 if ( pmods[ i ]->mod_bvalues != NULL ) { 238 for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) { 239 ; 240 } 241 } 242 if (( pmods[ i ]->mod_bvalues = 243 (struct berval **)ber_memrealloc( pmods[ i ]->mod_bvalues, 244 (j + 2) * sizeof( struct berval * ))) == NULL ) { 245 tester_perror( "ber_memrealloc", NULL ); 246 exit( EXIT_FAILURE ); 247 } 248 pmods[ i ]->mod_bvalues[ j + 1 ] = NULL; 249 if (( bvp = (struct berval *)ber_memalloc( sizeof( struct berval ))) 250 == NULL ) { 251 tester_perror( "ber_memalloc", NULL ); 252 exit( EXIT_FAILURE ); 253 } 254 pmods[ i ]->mod_bvalues[ j ] = bvp; 255 256 bvp->bv_len = vlen; 257 if (( bvp->bv_val = (char *)malloc( vlen + 1 )) == NULL ) { 258 tester_perror( "malloc", NULL ); 259 exit( EXIT_FAILURE ); 260 } 261 AC_MEMCPY( bvp->bv_val, value, vlen ); 262 bvp->bv_val[ vlen ] = '\0'; 263 } 264} 265 266 267static char * 268get_add_entry( char *filename, LDAPMod ***mods ) 269{ 270 FILE *fp; 271 char *entry = NULL; 272 273 if ( (fp = fopen( filename, "r" )) != NULL ) { 274 char line[BUFSIZ]; 275 276 if ( fgets( line, BUFSIZ, fp )) { 277 char *nl; 278 279 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' ))) 280 *nl = '\0'; 281 nl = line; 282 if ( !strncasecmp( nl, "dn: ", 4 )) 283 nl += 4; 284 entry = strdup( nl ); 285 286 } 287 288 while ( fgets( line, BUFSIZ, fp )) { 289 char *nl; 290 char *value; 291 292 if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' ))) 293 *nl = '\0'; 294 295 if ( *line == '\0' ) break; 296 if ( !( value = strchr( line, ':' ))) break; 297 298 *value++ = '\0'; 299 while ( *value && isspace( (unsigned char) *value )) 300 value++; 301 302 addmodifyop( mods, LDAP_MOD_ADD, line, value, strlen( value )); 303 304 } 305 fclose( fp ); 306 } 307 308 return( entry ); 309} 310 311 312static void 313do_addel( 314 char *uri, 315 char *manager, 316 struct berval *passwd, 317 char *entry, 318 LDAPMod **attrs, 319 int maxloop, 320 int maxretries, 321 int delay, 322 int friendly, 323 int chaserefs ) 324{ 325 LDAP *ld = NULL; 326 int i = 0, do_retry = maxretries; 327 int rc = LDAP_SUCCESS; 328 int version = LDAP_VERSION3; 329 330retry:; 331 ldap_initialize( &ld, uri ); 332 if ( ld == NULL ) { 333 tester_perror( "ldap_initialize", NULL ); 334 exit( EXIT_FAILURE ); 335 } 336 337 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 338 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, 339 chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); 340 341 if ( do_retry == maxretries ) { 342 fprintf( stderr, "PID=%ld - Add/Delete(%d): entry=\"%s\".\n", 343 (long) pid, maxloop, entry ); 344 } 345 346 rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); 347 if ( rc != LDAP_SUCCESS ) { 348 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); 349 switch ( rc ) { 350 case LDAP_BUSY: 351 case LDAP_UNAVAILABLE: 352 if ( do_retry > 0 ) { 353 do_retry--; 354 if ( delay != 0 ) { 355 sleep( delay ); 356 } 357 goto retry; 358 } 359 /* fallthru */ 360 default: 361 break; 362 } 363 exit( EXIT_FAILURE ); 364 } 365 366 for ( ; i < maxloop; i++ ) { 367 368 /* add the entry */ 369 rc = ldap_add_ext_s( ld, entry, attrs, NULL, NULL ); 370 if ( rc != LDAP_SUCCESS ) { 371 tester_ldap_error( ld, "ldap_add_ext_s", NULL ); 372 switch ( rc ) { 373 case LDAP_ALREADY_EXISTS: 374 /* NOTE: this likely means 375 * the delete failed 376 * during the previous round... */ 377 if ( !friendly ) { 378 goto done; 379 } 380 break; 381 382 case LDAP_BUSY: 383 case LDAP_UNAVAILABLE: 384 if ( do_retry > 0 ) { 385 do_retry--; 386 goto retry; 387 } 388 /* fall thru */ 389 390 default: 391 goto done; 392 } 393 } 394 395#if 0 396 /* wait a second for the add to really complete */ 397 /* This masks some race conditions though. */ 398 sleep( 1 ); 399#endif 400 401 /* now delete the entry again */ 402 rc = ldap_delete_ext_s( ld, entry, NULL, NULL ); 403 if ( rc != LDAP_SUCCESS ) { 404 tester_ldap_error( ld, "ldap_delete_ext_s", NULL ); 405 switch ( rc ) { 406 case LDAP_NO_SUCH_OBJECT: 407 /* NOTE: this likely means 408 * the add failed 409 * during the previous round... */ 410 if ( !friendly ) { 411 goto done; 412 } 413 break; 414 415 case LDAP_BUSY: 416 case LDAP_UNAVAILABLE: 417 if ( do_retry > 0 ) { 418 do_retry--; 419 goto retry; 420 } 421 /* fall thru */ 422 423 default: 424 goto done; 425 } 426 } 427 } 428 429done:; 430 fprintf( stderr, " PID=%ld - Add/Delete done (%d).\n", (long) pid, rc ); 431 432 ldap_unbind_ext( ld, NULL, NULL ); 433} 434 435 436