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