xref: /netbsd-src/external/bsd/openldap/dist/clients/tools/ldapdelete.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: ldapdelete.c,v 1.1.1.4 2014/05/28 09:58:20 tron Exp $	*/
2 
3 /* ldapdelete.c - simple program to delete an entry using LDAP */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2014 The OpenLDAP Foundation.
8  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
20  * All rights reserved.
21  *
22  * Redistribution and use in source and binary forms are permitted
23  * provided that this notice is preserved and that due credit is given
24  * to the University of Michigan at Ann Arbor.  The name of the
25  * University may not be used to endorse or promote products derived
26  * from this software without specific prior written permission.  This
27  * software is provided ``as is'' without express or implied warranty.
28  */
29 /* ACKNOWLEDGEMENTS:
30  * This work was originally developed by the University of Michigan
31  * (as part of U-MICH LDAP).  Additional significant contributors
32  * include:
33  *   Kurt D. Zeilenga
34  */
35 
36 #include "portable.h"
37 
38 #include <stdio.h>
39 
40 #include <ac/stdlib.h>
41 #include <ac/ctype.h>
42 #include <ac/string.h>
43 #include <ac/unistd.h>
44 #include <ac/socket.h>
45 #include <ac/time.h>
46 
47 #include <ldap.h>
48 #include "lutil.h"
49 #include "lutil_ldap.h"
50 #include "ldap_defaults.h"
51 
52 #include "common.h"
53 
54 
55 static int	prune = 0;
56 static int sizelimit = -1;
57 
58 
59 static int dodelete LDAP_P((
60     LDAP *ld,
61     const char *dn));
62 
63 static int deletechildren LDAP_P((
64 	LDAP *ld,
65 	const char *dn,
66 	int subentries ));
67 
68 void
69 usage( void )
70 {
71 	fprintf( stderr, _("Delete entries from an LDAP server\n\n"));
72 	fprintf( stderr, _("usage: %s [options] [dn]...\n"), prog);
73 	fprintf( stderr, _("	dn: list of DNs to delete. If not given, it will be readed from stdin\n"));
74 	fprintf( stderr, _("	    or from the file specified with \"-f file\".\n"));
75 	fprintf( stderr, _("Delete Options:\n"));
76 	fprintf( stderr, _("  -c         continuous operation mode (do not stop on errors)\n"));
77 	fprintf( stderr, _("  -f file    read operations from `file'\n"));
78 	fprintf( stderr, _("  -M         enable Manage DSA IT control (-MM to make critical)\n"));
79 	fprintf( stderr, _("  -P version protocol version (default: 3)\n"));
80 	fprintf( stderr, _("  -r         delete recursively\n"));
81 	tool_common_usage();
82 	exit( EXIT_FAILURE );
83 }
84 
85 
86 const char options[] = "r"
87 	"cd:D:e:f:h:H:IMnNO:o:p:P:QR:U:vVw:WxX:y:Y:z:Z";
88 
89 int
90 handle_private_option( int i )
91 {
92 	int ival;
93 	char *next;
94 	switch ( i ) {
95 #if 0
96 		int crit;
97 		char *control, *cvalue;
98 	case 'E': /* delete extensions */
99 		if( protocol == LDAP_VERSION2 ) {
100 			fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"),
101 				prog, protocol );
102 			exit( EXIT_FAILURE );
103 		}
104 
105 		/* should be extended to support comma separated list of
106 		 *	[!]key[=value] parameters, e.g.  -E !foo,bar=567
107 		 */
108 
109 		crit = 0;
110 		cvalue = NULL;
111 		if( optarg[0] == '!' ) {
112 			crit = 1;
113 			optarg++;
114 		}
115 
116 		control = strdup( optarg );
117 		if ( (cvalue = strchr( control, '=' )) != NULL ) {
118 			*cvalue++ = '\0';
119 		}
120 		fprintf( stderr, _("Invalid delete extension name: %s\n"), control );
121 		usage();
122 #endif
123 
124 	case 'r':
125 		prune = 1;
126 		break;
127 
128 	case 'z':	/* size limit */
129 		if ( strcasecmp( optarg, "none" ) == 0 ) {
130 			sizelimit = 0;
131 
132 		} else if ( strcasecmp( optarg, "max" ) == 0 ) {
133 			sizelimit = LDAP_MAXINT;
134 
135 		} else {
136 			ival = strtol( optarg, &next, 10 );
137 			if ( next == NULL || next[0] != '\0' ) {
138 				fprintf( stderr,
139 					_("Unable to parse size limit \"%s\"\n"), optarg );
140 				exit( EXIT_FAILURE );
141 			}
142 			sizelimit = ival;
143 		}
144 		if( sizelimit < 0 || sizelimit > LDAP_MAXINT ) {
145 			fprintf( stderr, _("%s: invalid sizelimit (%d) specified\n"),
146 				prog, sizelimit );
147 			exit( EXIT_FAILURE );
148 		}
149 		break;
150 
151 	default:
152 		return 0;
153 	}
154 	return 1;
155 }
156 
157 
158 static void
159 private_conn_setup( LDAP *ld )
160 {
161 	/* this seems prudent for searches below */
162 	int deref = LDAP_DEREF_NEVER;
163 	ldap_set_option( ld, LDAP_OPT_DEREF, &deref );
164 }
165 
166 
167 int
168 main( int argc, char **argv )
169 {
170 	char		buf[ 4096 ];
171 	FILE		*fp = NULL;
172 	LDAP		*ld;
173 	int		rc, retval;
174 
175 	tool_init( TOOL_DELETE );
176     prog = lutil_progname( "ldapdelete", argc, argv );
177 
178 	tool_args( argc, argv );
179 
180 	if ( infile != NULL ) {
181 		if (( fp = fopen( infile, "r" )) == NULL ) {
182 			perror( optarg );
183 			exit( EXIT_FAILURE );
184 	    }
185 	} else {
186 		if ( optind >= argc ) {
187 			fp = stdin;
188 		}
189 	}
190 
191 	ld = tool_conn_setup( 0, &private_conn_setup );
192 
193 	tool_bind( ld );
194 
195 	tool_server_controls( ld, NULL, 0 );
196 
197 	retval = rc = 0;
198 
199 	if ( fp == NULL ) {
200 		for ( ; optind < argc; ++optind ) {
201 			rc = dodelete( ld, argv[ optind ] );
202 
203 			/* Stop on error and no -c option */
204 			if( rc != 0 ) {
205 				retval = rc;
206 				if( contoper == 0 ) break;
207 			}
208 		}
209 	} else {
210 		while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
211 			buf[ strlen( buf ) - 1 ] = '\0'; /* remove trailing newline */
212 
213 			if ( *buf != '\0' ) {
214 				rc = dodelete( ld, buf );
215 				if ( rc != 0 )
216 					retval = rc;
217 			}
218 		}
219 		if ( fp != stdin )
220 			fclose( fp );
221 	}
222 
223 	tool_exit( ld, retval );
224 }
225 
226 
227 static int dodelete(
228     LDAP	*ld,
229     const char	*dn)
230 {
231 	int id;
232 	int	rc, code;
233 	char *matcheddn = NULL, *text = NULL, **refs = NULL;
234 	LDAPControl **ctrls = NULL;
235 	LDAPMessage *res;
236 	int subentries = 0;
237 
238 	if ( verbose ) {
239 		printf( _("%sdeleting entry \"%s\"\n"),
240 			(dont ? "!" : ""), dn );
241 	}
242 
243 	if ( dont ) {
244 		return LDAP_SUCCESS;
245 	}
246 
247 	/* If prune is on, remove a whole subtree.  Delete the children of the
248 	 * DN recursively, then the DN requested.
249 	 */
250 	if ( prune ) {
251 retry:;
252 		deletechildren( ld, dn, subentries );
253 	}
254 
255 	rc = ldap_delete_ext( ld, dn, NULL, NULL, &id );
256 	if ( rc != LDAP_SUCCESS ) {
257 		fprintf( stderr, "%s: ldap_delete_ext: %s (%d)\n",
258 			prog, ldap_err2string( rc ), rc );
259 		return rc;
260 	}
261 
262 	for ( ; ; ) {
263 		struct timeval tv;
264 
265 		if ( tool_check_abandon( ld, id ) ) {
266 			return LDAP_CANCELLED;
267 		}
268 
269 		tv.tv_sec = 0;
270 		tv.tv_usec = 100000;
271 
272 		rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
273 		if ( rc < 0 ) {
274 			tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
275 			return rc;
276 		}
277 
278 		if ( rc != 0 ) {
279 			break;
280 		}
281 	}
282 
283 	rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 );
284 
285 	switch ( rc ) {
286 	case LDAP_SUCCESS:
287 		break;
288 
289 	case LDAP_NOT_ALLOWED_ON_NONLEAF:
290 		if ( prune && !subentries ) {
291 			subentries = 1;
292 			goto retry;
293 		}
294 		/* fallthru */
295 
296 	default:
297 		fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
298 			prog, ldap_err2string( rc ), rc );
299 		return rc;
300 	}
301 
302 	if( code != LDAP_SUCCESS ) {
303 		tool_perror( "ldap_delete", code, NULL, matcheddn, text, refs );
304 	} else if ( verbose &&
305 		((matcheddn && *matcheddn) || (text && *text) || (refs && *refs) ))
306 	{
307 		printf( _("Delete Result: %s (%d)\n"),
308 			ldap_err2string( code ), code );
309 
310 		if( text && *text ) {
311 			printf( _("Additional info: %s\n"), text );
312 		}
313 
314 		if( matcheddn && *matcheddn ) {
315 			printf( _("Matched DN: %s\n"), matcheddn );
316 		}
317 
318 		if( refs ) {
319 			int i;
320 			for( i=0; refs[i]; i++ ) {
321 				printf(_("Referral: %s\n"), refs[i] );
322 			}
323 		}
324 	}
325 
326 	if (ctrls) {
327 		tool_print_ctrls( ld, ctrls );
328 		ldap_controls_free( ctrls );
329 	}
330 
331 	ber_memfree( text );
332 	ber_memfree( matcheddn );
333 	ber_memvfree( (void **) refs );
334 
335 	return code;
336 }
337 
338 /*
339  * Delete all the children of an entry recursively until leaf nodes are reached.
340  */
341 static int deletechildren(
342 	LDAP *ld,
343 	const char *base,
344 	int subentries )
345 {
346 	LDAPMessage *res, *e;
347 	int entries;
348 	int rc = LDAP_SUCCESS, srch_rc;
349 	static char *attrs[] = { LDAP_NO_ATTRS, NULL };
350 	LDAPControl c, *ctrls[2], **ctrlsp = NULL;
351 	BerElement *ber = NULL;
352 
353 	if ( verbose ) printf ( _("deleting children of: %s\n"), base );
354 
355 	if ( subentries ) {
356 		/*
357 		 * Do a one level search at base for subentry children.
358 		 */
359 
360 		if ((ber = ber_alloc_t(LBER_USE_DER)) == NULL) {
361 			return EXIT_FAILURE;
362 		}
363 		rc = ber_printf( ber, "b", 1 );
364 		if ( rc == -1 ) {
365 			ber_free( ber, 1 );
366 			fprintf( stderr, _("Subentries control encoding error!\n"));
367 			return EXIT_FAILURE;
368 		}
369 		if ( ber_flatten2( ber, &c.ldctl_value, 0 ) == -1 ) {
370 			return EXIT_FAILURE;
371 		}
372 		c.ldctl_oid = LDAP_CONTROL_SUBENTRIES;
373 		c.ldctl_iscritical = 1;
374 		ctrls[0] = &c;
375 		ctrls[1] = NULL;
376 		ctrlsp = ctrls;
377 	}
378 
379 	/*
380 	 * Do a one level search at base for children.  For each, delete its children.
381 	 */
382 more:;
383 	srch_rc = ldap_search_ext_s( ld, base, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
384 		ctrlsp, NULL, NULL, sizelimit, &res );
385 	switch ( srch_rc ) {
386 	case LDAP_SUCCESS:
387 	case LDAP_SIZELIMIT_EXCEEDED:
388 		break;
389 	default:
390 		tool_perror( "ldap_search", srch_rc, NULL, NULL, NULL, NULL );
391 		return( srch_rc );
392 	}
393 
394 	entries = ldap_count_entries( ld, res );
395 
396 	if ( entries > 0 ) {
397 		int i;
398 
399 		for (e = ldap_first_entry( ld, res ), i = 0; e != NULL;
400 			e = ldap_next_entry( ld, e ), i++ )
401 		{
402 			char *dn = ldap_get_dn( ld, e );
403 
404 			if( dn == NULL ) {
405 				ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc );
406 				tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
407 				ber_memfree( dn );
408 				return rc;
409 			}
410 
411 			rc = deletechildren( ld, dn, 0 );
412 			if ( rc != LDAP_SUCCESS ) {
413 				tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
414 				ber_memfree( dn );
415 				return rc;
416 			}
417 
418 			if ( verbose ) {
419 				printf( _("\tremoving %s\n"), dn );
420 			}
421 
422 			rc = ldap_delete_ext_s( ld, dn, NULL, NULL );
423 			if ( rc != LDAP_SUCCESS ) {
424 				tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL );
425 				ber_memfree( dn );
426 				return rc;
427 
428 			}
429 
430 			if ( verbose ) {
431 				printf( _("\t%s removed\n"), dn );
432 			}
433 
434 			ber_memfree( dn );
435 		}
436 	}
437 
438 	ldap_msgfree( res );
439 
440 	if ( srch_rc == LDAP_SIZELIMIT_EXCEEDED ) {
441 		goto more;
442 	}
443 
444 	return rc;
445 }
446