1 /* $NetBSD: slapd-modify.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 18 #include <sys/cdefs.h> 19 __RCSID("$NetBSD: slapd-modify.c,v 1.2 2020/08/11 13:15:42 christos Exp $"); 20 21 #include "portable.h" 22 23 #include <stdio.h> 24 25 #include "ac/stdlib.h" 26 27 #include "ac/ctype.h" 28 #include "ac/param.h" 29 #include "ac/socket.h" 30 #include "ac/string.h" 31 #include "ac/unistd.h" 32 #include "ac/wait.h" 33 34 #include "ldap.h" 35 #include "lutil.h" 36 37 #include "slapd-common.h" 38 39 #define LOOPS 100 40 #define RETRIES 0 41 42 static void 43 do_modify( char *uri, char *manager, struct berval *passwd, 44 char *entry, char *attr, char *value, int maxloop, 45 int maxretries, int delay, int friendly, int chaserefs ); 46 47 48 static void 49 usage( char *name ) 50 { 51 fprintf( stderr, 52 "usage: %s " 53 "-H <uri> | ([-h <host>] -p <port>) " 54 "-D <manager> " 55 "-w <passwd> " 56 "-e <entry> " 57 "[-i <ignore>] " 58 "[-l <loops>] " 59 "[-L <outerloops>] " 60 "[-r <maxretries>] " 61 "[-t <delay>] " 62 "[-F] " 63 "[-C]\n", 64 name ); 65 exit( EXIT_FAILURE ); 66 } 67 68 int 69 main( int argc, char **argv ) 70 { 71 int i; 72 char *uri = NULL; 73 char *host = "localhost"; 74 int port = -1; 75 char *manager = NULL; 76 struct berval passwd = { 0, NULL }; 77 char *entry = NULL; 78 char *ava = NULL; 79 char *value = 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 87 tester_init( "slapd-modify", TESTER_MODIFY ); 88 89 while ( ( i = getopt( argc, argv, "a:CD:e:FH:h:i:L:l:p:r:t:w:" ) ) != EOF ) 90 { 91 switch ( i ) { 92 case 'C': 93 chaserefs++; 94 break; 95 96 case 'F': 97 friendly++; 98 break; 99 100 case 'H': /* the server uri */ 101 uri = strdup( optarg ); 102 break; 103 104 case 'h': /* the servers host */ 105 host = strdup( optarg ); 106 break; 107 108 case 'i': 109 /* ignored (!) by now */ 110 break; 111 112 case 'p': /* the servers port */ 113 if ( lutil_atoi( &port, optarg ) != 0 ) { 114 usage( argv[0] ); 115 } 116 break; 117 118 case 'D': /* the servers manager */ 119 manager = strdup( optarg ); 120 break; 121 122 case 'w': /* the server managers password */ 123 passwd.bv_val = strdup( optarg ); 124 passwd.bv_len = strlen( optarg ); 125 memset( optarg, '*', passwd.bv_len ); 126 break; 127 128 case 'e': /* entry to modify */ 129 entry = strdup( optarg ); 130 break; 131 132 case 'a': 133 ava = strdup( optarg ); 134 break; 135 136 case 'l': /* the number of loops */ 137 if ( lutil_atoi( &loops, optarg ) != 0 ) { 138 usage( argv[0] ); 139 } 140 break; 141 142 case 'L': /* the number of outerloops */ 143 if ( lutil_atoi( &outerloops, optarg ) != 0 ) { 144 usage( argv[0] ); 145 } 146 break; 147 148 case 'r': /* number of retries */ 149 if ( lutil_atoi( &retries, optarg ) != 0 ) { 150 usage( argv[0] ); 151 } 152 break; 153 154 case 't': /* delay in seconds */ 155 if ( lutil_atoi( &delay, optarg ) != 0 ) { 156 usage( argv[0] ); 157 } 158 break; 159 160 default: 161 usage( argv[0] ); 162 break; 163 } 164 } 165 166 if (( entry == NULL ) || ( ava == NULL ) || ( port == -1 && uri == NULL )) 167 usage( argv[0] ); 168 169 if ( *entry == '\0' ) { 170 171 fprintf( stderr, "%s: invalid EMPTY entry DN.\n", 172 argv[0] ); 173 exit( EXIT_FAILURE ); 174 175 } 176 if ( *ava == '\0' ) { 177 fprintf( stderr, "%s: invalid EMPTY AVA.\n", 178 argv[0] ); 179 exit( EXIT_FAILURE ); 180 } 181 182 if ( !( value = strchr( ava, ':' ))) { 183 fprintf( stderr, "%s: invalid AVA.\n", 184 argv[0] ); 185 exit( EXIT_FAILURE ); 186 } 187 *value++ = '\0'; 188 while ( *value && isspace( (unsigned char) *value )) 189 value++; 190 191 uri = tester_uri( uri, host, port ); 192 193 for ( i = 0; i < outerloops; i++ ) { 194 do_modify( uri, manager, &passwd, entry, ava, value, 195 loops, retries, delay, friendly, chaserefs ); 196 } 197 198 exit( EXIT_SUCCESS ); 199 } 200 201 202 static void 203 do_modify( char *uri, char *manager, 204 struct berval *passwd, char *entry, char* attr, char* value, 205 int maxloop, int maxretries, int delay, int friendly, int chaserefs ) 206 { 207 LDAP *ld = NULL; 208 int i = 0, do_retry = maxretries; 209 int rc = LDAP_SUCCESS; 210 211 struct ldapmod mod; 212 struct ldapmod *mods[2]; 213 char *values[2]; 214 int version = LDAP_VERSION3; 215 216 values[0] = value; 217 values[1] = NULL; 218 mod.mod_op = LDAP_MOD_ADD; 219 mod.mod_type = attr; 220 mod.mod_values = values; 221 mods[0] = &mod; 222 mods[1] = NULL; 223 224 retry:; 225 ldap_initialize( &ld, uri ); 226 if ( ld == NULL ) { 227 tester_perror( "ldap_initialize", NULL ); 228 exit( EXIT_FAILURE ); 229 } 230 231 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 232 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, 233 chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); 234 235 if ( do_retry == maxretries ) { 236 fprintf( stderr, "PID=%ld - Modify(%d): entry=\"%s\".\n", 237 (long) pid, maxloop, entry ); 238 } 239 240 rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); 241 if ( rc != LDAP_SUCCESS ) { 242 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); 243 switch ( rc ) { 244 case LDAP_BUSY: 245 case LDAP_UNAVAILABLE: 246 if ( do_retry > 0 ) { 247 do_retry--; 248 if ( delay > 0 ) { 249 sleep( delay ); 250 } 251 goto retry; 252 } 253 /* fallthru */ 254 default: 255 break; 256 } 257 exit( EXIT_FAILURE ); 258 } 259 260 for ( ; i < maxloop; i++ ) { 261 mod.mod_op = LDAP_MOD_ADD; 262 rc = ldap_modify_ext_s( ld, entry, mods, NULL, NULL ); 263 if ( rc != LDAP_SUCCESS ) { 264 tester_ldap_error( ld, "ldap_modify_ext_s", NULL ); 265 switch ( rc ) { 266 case LDAP_TYPE_OR_VALUE_EXISTS: 267 /* NOTE: this likely means 268 * the second modify failed 269 * during the previous round... */ 270 if ( !friendly ) { 271 goto done; 272 } 273 break; 274 275 case LDAP_BUSY: 276 case LDAP_UNAVAILABLE: 277 if ( do_retry > 0 ) { 278 do_retry--; 279 goto retry; 280 } 281 /* fall thru */ 282 283 default: 284 goto done; 285 } 286 } 287 288 mod.mod_op = LDAP_MOD_DELETE; 289 rc = ldap_modify_ext_s( ld, entry, mods, NULL, NULL ); 290 if ( rc != LDAP_SUCCESS ) { 291 tester_ldap_error( ld, "ldap_modify_ext_s", NULL ); 292 switch ( rc ) { 293 case LDAP_NO_SUCH_ATTRIBUTE: 294 /* NOTE: this likely means 295 * the first modify failed 296 * during the previous round... */ 297 if ( !friendly ) { 298 goto done; 299 } 300 break; 301 302 case LDAP_BUSY: 303 case LDAP_UNAVAILABLE: 304 if ( do_retry > 0 ) { 305 do_retry--; 306 goto retry; 307 } 308 /* fall thru */ 309 310 default: 311 goto done; 312 } 313 } 314 315 } 316 317 done:; 318 fprintf( stderr, " PID=%ld - Modify done (%d).\n", (long) pid, rc ); 319 320 ldap_unbind_ext( ld, NULL, NULL ); 321 } 322 323 324