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