1 /* $NetBSD: slapd-modrdn.c,v 1.3 2021/08/14 16:15:03 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2021 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.3 2021/08/14 16:15:03 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( struct tester_conn_args *config, 48 char *entry, int friendly ); 49 50 static void 51 usage( char *name, char opt ) 52 { 53 if ( opt ) { 54 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n", 55 name, opt ); 56 } 57 58 fprintf( stderr, "usage: %s " TESTER_COMMON_HELP 59 "-e <entry> " 60 "[-F]\n", 61 name ); 62 exit( EXIT_FAILURE ); 63 } 64 65 int 66 main( int argc, char **argv ) 67 { 68 int i; 69 char *entry = NULL; 70 int friendly = 0; 71 struct tester_conn_args *config; 72 73 config = tester_init( "slapd-modrdn", TESTER_MODRDN ); 74 75 while ( ( i = getopt( argc, argv, TESTER_COMMON_OPTS "e:F" ) ) != EOF ) 76 { 77 switch ( i ) { 78 case 'F': 79 friendly++; 80 break; 81 82 case 'i': 83 /* ignored (!) by now */ 84 break; 85 86 case 'e': /* entry to rename */ 87 entry = optarg; 88 break; 89 90 default: 91 if ( tester_config_opt( config, i, optarg ) == LDAP_SUCCESS ) { 92 break; 93 } 94 usage( argv[0], i ); 95 break; 96 } 97 } 98 99 if ( entry == NULL ) 100 usage( argv[0], 0 ); 101 102 if ( *entry == '\0' ) { 103 104 fprintf( stderr, "%s: invalid EMPTY entry DN.\n", 105 argv[0] ); 106 exit( EXIT_FAILURE ); 107 108 } 109 110 tester_config_finish( config ); 111 112 for ( i = 0; i < config->outerloops; i++ ) { 113 do_modrdn( config, entry, friendly ); 114 } 115 116 exit( EXIT_SUCCESS ); 117 } 118 119 120 static void 121 do_modrdn( struct tester_conn_args *config, 122 char *entry, int friendly ) 123 { 124 LDAP *ld = NULL; 125 int i, do_retry = config->retries; 126 char *DNs[2]; 127 char *rdns[2]; 128 int rc = LDAP_SUCCESS; 129 char *p1, *p2; 130 131 DNs[0] = entry; 132 DNs[1] = strdup( entry ); 133 if ( DNs[1] == NULL ) { 134 tester_error( "strdup failed" ); 135 exit( EXIT_FAILURE ); 136 } 137 138 /* reverse the RDN, make new DN */ 139 p1 = strchr( entry, '=' ) + 1; 140 p2 = strchr( p1, ',' ); 141 142 *p2 = '\0'; 143 rdns[1] = strdup( entry ); 144 if ( rdns[1] == NULL ) { 145 tester_error( "strdup failed" ); 146 exit( EXIT_FAILURE ); 147 } 148 *p2-- = ','; 149 150 for (i = p1 - entry;p2 >= p1;) 151 DNs[1][i++] = *p2--; 152 153 DNs[1][i] = '\0'; 154 rdns[0] = strdup( DNs[1] ); 155 if ( rdns[0] == NULL ) { 156 tester_error( "strdup failed" ); 157 exit( EXIT_FAILURE ); 158 } 159 DNs[1][i] = ','; 160 161 i = 0; 162 163 retry:; 164 if ( ld == NULL ) { 165 tester_init_ld( &ld, config, 0 ); 166 } 167 168 if ( do_retry == config->retries ) { 169 fprintf( stderr, "PID=%ld - Modrdn(%d): entry=\"%s\".\n", 170 (long) pid, config->loops, entry ); 171 } 172 173 for ( ; i < config->loops; i++ ) { 174 rc = ldap_rename_s( ld, DNs[0], rdns[0], NULL, 0, NULL, NULL ); 175 if ( rc != LDAP_SUCCESS ) { 176 tester_ldap_error( ld, "ldap_rename_s", NULL ); 177 switch ( rc ) { 178 case LDAP_NO_SUCH_OBJECT: 179 /* NOTE: this likely means 180 * the second modrdn failed 181 * during the previous round... */ 182 if ( !friendly ) { 183 goto done; 184 } 185 break; 186 187 case LDAP_BUSY: 188 case LDAP_UNAVAILABLE: 189 if ( do_retry > 0 ) { 190 do_retry--; 191 goto retry; 192 } 193 /* fall thru */ 194 195 default: 196 goto done; 197 } 198 } 199 rc = ldap_rename_s( ld, DNs[1], rdns[1], NULL, 1, NULL, NULL ); 200 if ( rc != LDAP_SUCCESS ) { 201 tester_ldap_error( ld, "ldap_rename_s", NULL ); 202 switch ( rc ) { 203 case LDAP_NO_SUCH_OBJECT: 204 /* NOTE: this likely means 205 * the first modrdn failed 206 * during the previous round... */ 207 if ( !friendly ) { 208 goto done; 209 } 210 break; 211 212 case LDAP_BUSY: 213 case LDAP_UNAVAILABLE: 214 if ( do_retry > 0 ) { 215 do_retry--; 216 goto retry; 217 } 218 /* fall thru */ 219 220 default: 221 goto done; 222 } 223 } 224 } 225 226 done:; 227 fprintf( stderr, " PID=%ld - Modrdn done (%d).\n", (long) pid, rc ); 228 229 ldap_unbind_ext( ld, NULL, NULL ); 230 231 free( DNs[1] ); 232 free( rdns[0] ); 233 free( rdns[1] ); 234 } 235