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