1 /* $NetBSD: slapd-modrdn.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 Howard Chu, based in part 19 * on other OpenLDAP test tools, for inclusion in OpenLDAP Software. 20 */ 21 22 #include <sys/cdefs.h> 23 __RCSID("$NetBSD: slapd-modrdn.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 void 47 do_modrdn( char *uri, char *manager, struct berval *passwd, 48 char *entry, 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 "-e <entry> " 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 *uri = NULL; 76 char *host = "localhost"; 77 int port = -1; 78 char *manager = NULL; 79 struct berval passwd = { 0, NULL }; 80 char *entry = NULL; 81 int loops = LOOPS; 82 int outerloops = 1; 83 int retries = RETRIES; 84 int delay = 0; 85 int friendly = 0; 86 int chaserefs = 0; 87 88 tester_init( "slapd-modrdn", TESTER_MODRDN ); 89 90 while ( ( i = getopt( argc, argv, "CD:e:FH: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 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 'e': /* entry to rename */ 130 entry = 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': /* the 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 (( entry == NULL ) || ( port == -1 && uri == NULL )) 164 usage( argv[0] ); 165 166 if ( *entry == '\0' ) { 167 168 fprintf( stderr, "%s: invalid EMPTY entry DN.\n", 169 argv[0] ); 170 exit( EXIT_FAILURE ); 171 172 } 173 174 uri = tester_uri( uri, host, port ); 175 176 for ( i = 0; i < outerloops; i++ ) { 177 do_modrdn( uri, manager, &passwd, entry, 178 loops, retries, delay, friendly, chaserefs ); 179 } 180 181 exit( EXIT_SUCCESS ); 182 } 183 184 185 static void 186 do_modrdn( char *uri, char *manager, 187 struct berval *passwd, char *entry, int maxloop, int maxretries, 188 int delay, int friendly, int chaserefs ) 189 { 190 LDAP *ld = NULL; 191 int i, do_retry = maxretries; 192 char *DNs[2]; 193 char *rdns[2]; 194 int rc = LDAP_SUCCESS; 195 char *p1, *p2; 196 int version = LDAP_VERSION3; 197 198 DNs[0] = entry; 199 DNs[1] = strdup( entry ); 200 201 /* reverse the RDN, make new DN */ 202 p1 = strchr( entry, '=' ) + 1; 203 p2 = strchr( p1, ',' ); 204 205 *p2 = '\0'; 206 rdns[1] = strdup( entry ); 207 *p2-- = ','; 208 209 for (i = p1 - entry;p2 >= p1;) 210 DNs[1][i++] = *p2--; 211 212 DNs[1][i] = '\0'; 213 rdns[0] = strdup( DNs[1] ); 214 DNs[1][i] = ','; 215 216 i = 0; 217 218 retry:; 219 ldap_initialize( &ld, uri ); 220 if ( ld == NULL ) { 221 tester_perror( "ldap_initialize", NULL ); 222 exit( EXIT_FAILURE ); 223 } 224 225 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 226 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS, 227 chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF ); 228 229 if ( do_retry == maxretries ) { 230 fprintf( stderr, "PID=%ld - Modrdn(%d): entry=\"%s\".\n", 231 (long) pid, maxloop, entry ); 232 } 233 234 rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL ); 235 if ( rc != LDAP_SUCCESS ) { 236 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL ); 237 switch ( rc ) { 238 case LDAP_BUSY: 239 case LDAP_UNAVAILABLE: 240 if ( do_retry > 0 ) { 241 do_retry--; 242 if ( delay > 0) { 243 sleep( delay ); 244 } 245 goto retry; 246 } 247 /* fallthru */ 248 default: 249 break; 250 } 251 exit( EXIT_FAILURE ); 252 } 253 254 for ( ; i < maxloop; i++ ) { 255 rc = ldap_rename_s( ld, DNs[0], rdns[0], NULL, 0, NULL, NULL ); 256 if ( rc != LDAP_SUCCESS ) { 257 tester_ldap_error( ld, "ldap_rename_s", NULL ); 258 switch ( rc ) { 259 case LDAP_NO_SUCH_OBJECT: 260 /* NOTE: this likely means 261 * the second modrdn failed 262 * during the previous round... */ 263 if ( !friendly ) { 264 goto done; 265 } 266 break; 267 268 case LDAP_BUSY: 269 case LDAP_UNAVAILABLE: 270 if ( do_retry > 0 ) { 271 do_retry--; 272 goto retry; 273 } 274 /* fall thru */ 275 276 default: 277 goto done; 278 } 279 } 280 rc = ldap_rename_s( ld, DNs[1], rdns[1], NULL, 1, NULL, NULL ); 281 if ( rc != LDAP_SUCCESS ) { 282 tester_ldap_error( ld, "ldap_rename_s", NULL ); 283 switch ( rc ) { 284 case LDAP_NO_SUCH_OBJECT: 285 /* NOTE: this likely means 286 * the first modrdn failed 287 * during the previous round... */ 288 if ( !friendly ) { 289 goto done; 290 } 291 break; 292 293 case LDAP_BUSY: 294 case LDAP_UNAVAILABLE: 295 if ( do_retry > 0 ) { 296 do_retry--; 297 goto retry; 298 } 299 /* fall thru */ 300 301 default: 302 goto done; 303 } 304 } 305 } 306 307 done:; 308 fprintf( stderr, " PID=%ld - Modrdn done (%d).\n", (long) pid, rc ); 309 310 ldap_unbind_ext( ld, NULL, NULL ); 311 312 free( DNs[1] ); 313 free( rdns[0] ); 314 free( rdns[1] ); 315 } 316