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