ldapdelete.c 9.32 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* ldapdelete.c - simple program to delete an entry using LDAP */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 1998-2006 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 * Portions Copyright 1998-2003 Kurt D. Zeilenga.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of Michigan at Ann Arbor.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.  This
 * software is provided ``as is'' without express or implied warranty.
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
27
28
/* ACKNOWLEDGEMENTS:
 * This work was originally developed by the University of Michigan
Kurt Zeilenga's avatar
Kurt Zeilenga committed
29
30
31
 * (as part of U-MICH LDAP).  Additional significant contributors
 * include:
 *   Kurt D. Zeilenga
Kurt Zeilenga's avatar
Kurt Zeilenga committed
32
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
33

Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
35
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
36
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
37
38
39

#include <ac/stdlib.h>
#include <ac/ctype.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
40
#include <ac/string.h>
41
#include <ac/unistd.h>
42
#include <ac/time.h>
43

Kurt Zeilenga's avatar
Kurt Zeilenga committed
44
#include <ldap.h>
45
#include "lutil.h"
46
#include "lutil_ldap.h"
47
#include "ldap_defaults.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
48

49
50
51
#include "common.h"


52
static int	prune = 0;
53

Kurt Zeilenga's avatar
Kurt Zeilenga committed
54

Kurt Zeilenga's avatar
Kurt Zeilenga committed
55
static int dodelete LDAP_P((
Kurt Zeilenga's avatar
Kurt Zeilenga committed
56
57
    LDAP *ld,
    const char *dn));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
58

Kurt Zeilenga's avatar
Kurt Zeilenga committed
59
60
61
static int deletechildren LDAP_P((
	LDAP *ld,
	const char *dn ));
62

63
64
void
usage( void )
65
{
66
67
68
69
70
71
	fprintf( stderr, _("Delete entries from an LDAP server\n\n"));
	fprintf( stderr, _("usage: %s [options] [dn]...\n"), prog);
	fprintf( stderr, _("	dn: list of DNs to delete. If not given, it will be readed from stdin\n"));
	fprintf( stderr, _("	    or from the file specified with \"-f file\".\n"));
	fprintf( stderr, _("Delete Options:\n"));
	fprintf( stderr, _("  -r         delete recursively\n"));
72
	tool_common_usage();
73
74
75
76
	exit( EXIT_FAILURE );
}


77
const char options[] = "r"
78
	"cd:D:e:f:h:H:IkKMnO:p:P:QR:U:vVw:WxX:y:Y:Z";
79

Hallvard Furuseth's avatar
Hallvard Furuseth committed
80
int
81
handle_private_option( int i )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
82
{
83
84
85
86
	switch ( i ) {
#if 0
		int crit;
		char *control, *cvalue;
87
	case 'E': /* delete extensions */
88
		if( protocol == LDAP_VERSION2 ) {
89
			fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"),
90
				prog, protocol );
91
			exit( EXIT_FAILURE );
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
		}

		/* should be extended to support comma separated list of
		 *	[!]key[=value] parameters, e.g.  -E !foo,bar=567
		 */

		crit = 0;
		cvalue = NULL;
		if( optarg[0] == '!' ) {
			crit = 1;
			optarg++;
		}

		control = strdup( optarg );
		if ( (cvalue = strchr( control, '=' )) != NULL ) {
			*cvalue++ = '\0';
		}
109
		fprintf( stderr, _("Invalid delete extension name: %s\n"), control );
110
111
112
		usage();
#endif

113
114
115
116
	case 'r':
		prune = 1;
		break;

117
118
119
120
121
	default:
		return 0;
	}
	return 1;
}
122

123

124
125
126
127
128
129
130
static void
private_conn_setup( LDAP *ld )
{
	/* this seems prudent for searches below */
	int deref = LDAP_DEREF_NEVER;
	ldap_set_option( ld, LDAP_OPT_DEREF, &deref );
}
131
132


133
134
135
136
137
138
139
int
main( int argc, char **argv )
{
	char		buf[ 4096 ];
	FILE		*fp;
	LDAP		*ld;
	int		rc, retval;
140

141
    fp = NULL;
142

143
	tool_init( TOOL_DELETE );
144
    prog = lutil_progname( "ldapdelete", argc, argv );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
145

146
	tool_args( argc, argv );
147

148
149
150
151
152
153
	if ( infile != NULL ) {
		if (( fp = fopen( infile, "r" )) == NULL ) {
			perror( optarg );
			exit( EXIT_FAILURE );
	    }
	} else {
154
155
156
157
	if ( optind >= argc ) {
	    fp = stdin;
	}
    }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
158

159
	ld = tool_conn_setup( 0, &private_conn_setup );
160

161
162
163
164
165
	if ( pw_file || want_bindpw ) {
		if ( pw_file ) {
			rc = lutil_get_filed_password( pw_file, &passwd );
			if( rc ) return EXIT_FAILURE;
		} else {
166
			passwd.bv_val = getpassphrase( _("Enter LDAP Password: ") );
167
168
			passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
169
	}
170

171
	tool_bind( ld );
172

173
	tool_server_controls( ld, NULL, 0 );
174

175
	retval = rc = 0;
176

177
	if ( fp == NULL ) {
178
179
180
181
		for ( ; optind < argc; ++optind ) {
			rc = dodelete( ld, argv[ optind ] );

			/* Stop on error and no -c option */
182
183
184
185
			if( rc != 0 ) {
				retval = rc;
				if( contoper == 0 ) break;
			}
186
187
188
189
190
191
192
		}
	} else {
		while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
			buf[ strlen( buf ) - 1 ] = '\0'; /* remove trailing newline */

			if ( *buf != '\0' ) {
				rc = dodelete( ld, buf );
193
194
				if ( rc != 0 )
					retval = rc;
195
196
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
197
198
	}

199
200
201
	tool_unbind( ld );
	tool_destroy();
    return retval;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
202
203
}

204
205

static int dodelete(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
206
    LDAP	*ld,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
207
    const char	*dn)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
208
{
209
210
211
212
	int id;
	int	rc, code;
	char *matcheddn = NULL, *text = NULL, **refs = NULL;
	LDAPMessage *res;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
213

Kurt Zeilenga's avatar
Kurt Zeilenga committed
214
	if ( verbose ) {
215
		printf( _("%sdeleting entry \"%s\"\n"),
216
			(dont ? "!" : ""), dn );
217
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
218

219
	if ( dont ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
220
221
222
223
224
225
226
227
		return LDAP_SUCCESS;
	}

	/* If prune is on, remove a whole subtree.  Delete the children of the
	 * DN recursively, then the DN requested.
	 */
	if ( prune ) deletechildren( ld, dn );

228
	rc = ldap_delete_ext( ld, dn, NULL, NULL, &id );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
229
	if ( rc != LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
230
231
		fprintf( stderr, "%s: ldap_delete_ext: %s (%d)\n",
			prog, ldap_err2string( rc ), rc );
232
		return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
233
234
	}

235
	for ( ; ; ) {
236
		struct timeval tv;
237
238
239
240
241
242
243
244
245
246

		if ( tool_check_abandon( ld, id ) ) {
			return LDAP_CANCELLED;
		}

		tv.tv_sec = 0;
		tv.tv_usec = 100000;

		rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
		if ( rc < 0 ) {
247
			tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
248
249
250
251
252
253
			return rc;
		}

		if ( rc != 0 ) {
			break;
		}
254
255
256
257
258
	}

	rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 1 );

	if( rc != LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
259
260
		fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
			prog, ldap_err2string( rc ), rc );
261
		return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
262
263
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
264
265
266
267
	if( code != LDAP_SUCCESS ) {
		tool_perror( "ldap_delete", code, NULL, matcheddn, text, refs );
	} else if ( verbose && 
		((matcheddn && *matcheddn) || (text && *text) || (refs && *refs) ))
268
	{
269
270
		printf( _("Delete Result: %s (%d)\n"),
			ldap_err2string( code ), code );
271
272

		if( text && *text ) {
273
			printf( _("Additional info: %s\n"), text );
274
275
276
		}

		if( matcheddn && *matcheddn ) {
277
			printf( _("Matched DN: %s\n"), matcheddn );
278
279
280
281
282
		}

		if( refs ) {
			int i;
			for( i=0; refs[i]; i++ ) {
283
				printf(_("Referral: %s\n"), refs[i] );
284
285
286
287
288
289
			}
		}
	}

	ber_memfree( text );
	ber_memfree( matcheddn );
290
	ber_memvfree( (void **) refs );
291
292

	return code;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
293
}
294
295
296
297

/*
 * Delete all the children of an entry recursively until leaf nodes are reached.
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
298
299
300
static int deletechildren(
	LDAP *ld,
	const char *dn )
301
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
302
303
304
	LDAPMessage *res, *e;
	int entries;
	int rc;
Kurt Zeilenga's avatar
Cleanup    
Kurt Zeilenga committed
305
	static char *attrs[] = { LDAP_NO_ATTRS, NULL };
306
307
308
	LDAPControl c, *ctrls[2];
	BerElement *ber = NULL;
	LDAPMessage *res_se;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
309

310
	if ( verbose ) printf ( _("deleting children of: %s\n"), dn );
311

Kurt Zeilenga's avatar
Kurt Zeilenga committed
312
313
314
315
316
317
318
	/*
	 * Do a one level search at dn for children.  For each, delete its children.
	 */

	rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
		NULL, NULL, NULL, -1, &res );
	if ( rc != LDAP_SUCCESS ) {
319
		tool_perror( "ldap_search", rc, NULL, NULL, NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
320
321
		return( rc );
	}
322

Kurt Zeilenga's avatar
Kurt Zeilenga committed
323
324
325
326
327
328
329
330
331
332
333
334
	entries = ldap_count_entries( ld, res );

	if ( entries > 0 ) {
		int i;

		for (e = ldap_first_entry( ld, res ), i = 0; e != NULL;
			e = ldap_next_entry( ld, e ), i++ )
		{
			char *dn = ldap_get_dn( ld, e );

			if( dn == NULL ) {
				ldap_get_option( ld, LDAP_OPT_ERROR_NUMBER, &rc );
335
				tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
336
337
338
339
340
341
				ber_memfree( dn );
				return rc;
			}

			rc = deletechildren( ld, dn );
			if ( rc == -1 ) {
342
				tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
343
344
345
346
347
				ber_memfree( dn );
				return rc;
			}

			if ( verbose ) {
348
				printf( _("\tremoving %s\n"), dn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
349
350
			}

351
			rc = ldap_delete_ext_s( ld, dn, NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
352
			if ( rc == -1 ) {
353
				tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
354
355
356
357
358
359
				ber_memfree( dn );
				return rc;

			}
			
			if ( verbose ) {
360
				printf( _("\t%s removed\n"), dn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
361
362
363
364
365
366
367
			}

			ber_memfree( dn );
		}
	}

	ldap_msgfree( res );
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392

	/*
	 * Do a one level search at dn for subentry children.
	 */

	if ((ber = ber_alloc_t(LBER_USE_DER)) == NULL) {
		return EXIT_FAILURE;
	}
	rc = ber_printf( ber, "b", 1 );
	if ( rc == -1 ) {
		ber_free( ber, 1 );
		fprintf( stderr, _("Subentries control encoding error!\n"));
		return EXIT_FAILURE;
	}
	if ( ber_flatten2( ber, &c.ldctl_value, 0 ) == -1 ) {
		return EXIT_FAILURE;
	}
	c.ldctl_oid = LDAP_CONTROL_SUBENTRIES;
	c.ldctl_iscritical = 1;
	ctrls[0] = &c;
	ctrls[1] = NULL;

	rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
		ctrls, NULL, NULL, -1, &res_se );
	if ( rc != LDAP_SUCCESS ) {
393
		tool_perror( "ldap_search", rc, NULL, NULL, NULL, NULL );
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
		return( rc );
	}
	ber_free( ber, 1 );

	entries = ldap_count_entries( ld, res_se );

	if ( entries > 0 ) {
		int i;

		for (e = ldap_first_entry( ld, res_se ), i = 0; e != NULL;
			e = ldap_next_entry( ld, e ), i++ )
		{
			char *dn = ldap_get_dn( ld, e );

			if( dn == NULL ) {
				ldap_get_option( ld, LDAP_OPT_ERROR_NUMBER, &rc );
410
				tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
411
412
413
414
415
416
417
418
				ber_memfree( dn );
				return rc;
			}

			if ( verbose ) {
				printf( _("\tremoving %s\n"), dn );
			}

419
			rc = ldap_delete_ext_s( ld, dn, NULL, NULL );
420
			if ( rc == -1 ) {
421
				tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL );
422
423
424
425
426
427
428
429
430
431
432
433
434
435
				ber_memfree( dn );
				return rc;

			}
			
			if ( verbose ) {
				printf( _("\t%s removed\n"), dn );
			}

			ber_memfree( dn );
		}
	}

	ldap_msgfree( res_se );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
436
	return rc;
437
}