xref: /netbsd-src/external/bsd/openldap/dist/tests/progs/slapd-modrdn.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
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