Home | History | Annotate | Line # | Download | only in progs
slapd-addel.c revision 1.2
      1 /*	$NetBSD: slapd-addel.c,v 1.2 2020/08/11 13:15:42 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1999-2020 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.2 2020/08/11 13:15:42 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