]> git.sur5r.net Git - openldap/blob - clients/tools/ldapdelete.c
ITS#6145
[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 = NULL;
166         LDAP            *ld;
167         int             rc, retval;
168
169         tool_init( TOOL_DELETE );
170     prog = lutil_progname( "ldapdelete", argc, argv );
171
172         tool_args( argc, argv );
173
174         if ( infile != NULL ) {
175                 if (( fp = fopen( infile, "r" )) == NULL ) {
176                         perror( optarg );
177                         exit( EXIT_FAILURE );
178             }
179         } else {
180                 if ( optind >= argc ) {
181                         fp = stdin;
182                 }
183     }
184
185         ld = tool_conn_setup( 0, &private_conn_setup );
186
187         if ( pw_file || want_bindpw ) {
188                 if ( pw_file ) {
189                         rc = lutil_get_filed_password( pw_file, &passwd );
190                         if( rc ) {
191                                 if ( fp && fp != stdin )
192                                         fclose( fp );
193                                 return EXIT_FAILURE;
194                         }
195                 } else {
196                         passwd.bv_val = getpassphrase( _("Enter LDAP Password: ") );
197                         passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
198                 }
199         }
200
201         tool_bind( ld );
202
203         tool_server_controls( ld, NULL, 0 );
204
205         retval = rc = 0;
206
207         if ( fp == NULL ) {
208                 for ( ; optind < argc; ++optind ) {
209                         rc = dodelete( ld, argv[ optind ] );
210
211                         /* Stop on error and no -c option */
212                         if( rc != 0 ) {
213                                 retval = rc;
214                                 if( contoper == 0 ) break;
215                         }
216                 }
217         } else {
218                 while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
219                         buf[ strlen( buf ) - 1 ] = '\0'; /* remove trailing newline */
220
221                         if ( *buf != '\0' ) {
222                                 rc = dodelete( ld, buf );
223                                 if ( rc != 0 )
224                                         retval = rc;
225                         }
226                 }
227                 if ( fp != stdin )
228                         fclose( fp );
229         }
230
231         tool_unbind( ld );
232         tool_destroy();
233     return retval;
234 }
235
236
237 static int dodelete(
238     LDAP        *ld,
239     const char  *dn)
240 {
241         int id;
242         int     rc, code;
243         char *matcheddn = NULL, *text = NULL, **refs = NULL;
244         LDAPControl **ctrls = NULL;
245         LDAPMessage *res;
246         int subentries = 0;
247
248         if ( verbose ) {
249                 printf( _("%sdeleting entry \"%s\"\n"),
250                         (dont ? "!" : ""), dn );
251         }
252
253         if ( dont ) {
254                 return LDAP_SUCCESS;
255         }
256
257         /* If prune is on, remove a whole subtree.  Delete the children of the
258          * DN recursively, then the DN requested.
259          */
260         if ( prune ) {
261 retry:;
262                 deletechildren( ld, dn, subentries );
263         }
264
265         rc = ldap_delete_ext( ld, dn, NULL, NULL, &id );
266         if ( rc != LDAP_SUCCESS ) {
267                 fprintf( stderr, "%s: ldap_delete_ext: %s (%d)\n",
268                         prog, ldap_err2string( rc ), rc );
269                 return rc;
270         }
271
272         for ( ; ; ) {
273                 struct timeval tv;
274
275                 if ( tool_check_abandon( ld, id ) ) {
276                         return LDAP_CANCELLED;
277                 }
278
279                 tv.tv_sec = 0;
280                 tv.tv_usec = 100000;
281
282                 rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
283                 if ( rc < 0 ) {
284                         tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
285                         return rc;
286                 }
287
288                 if ( rc != 0 ) {
289                         break;
290                 }
291         }
292
293         rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 );
294
295         switch ( rc ) {
296         case LDAP_SUCCESS:
297                 break;
298
299         case LDAP_NOT_ALLOWED_ON_NONLEAF:
300                 if ( prune && !subentries ) {
301                         subentries = 1;
302                         goto retry;
303                 }
304                 /* fallthru */
305
306         default:
307                 fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
308                         prog, ldap_err2string( rc ), rc );
309                 return rc;
310         }
311
312         if( code != LDAP_SUCCESS ) {
313                 tool_perror( "ldap_delete", code, NULL, matcheddn, text, refs );
314         } else if ( verbose && 
315                 ((matcheddn && *matcheddn) || (text && *text) || (refs && *refs) ))
316         {
317                 printf( _("Delete Result: %s (%d)\n"),
318                         ldap_err2string( code ), code );
319
320                 if( text && *text ) {
321                         printf( _("Additional info: %s\n"), text );
322                 }
323
324                 if( matcheddn && *matcheddn ) {
325                         printf( _("Matched DN: %s\n"), matcheddn );
326                 }
327
328                 if( refs ) {
329                         int i;
330                         for( i=0; refs[i]; i++ ) {
331                                 printf(_("Referral: %s\n"), refs[i] );
332                         }
333                 }
334         }
335
336         if (ctrls) {
337                 tool_print_ctrls( ld, ctrls );
338                 ldap_controls_free( ctrls );
339         }
340
341         ber_memfree( text );
342         ber_memfree( matcheddn );
343         ber_memvfree( (void **) refs );
344
345         return code;
346 }
347
348 /*
349  * Delete all the children of an entry recursively until leaf nodes are reached.
350  */
351 static int deletechildren(
352         LDAP *ld,
353         const char *base,
354         int subentries )
355 {
356         LDAPMessage *res, *e;
357         int entries;
358         int rc = LDAP_SUCCESS, srch_rc;
359         static char *attrs[] = { LDAP_NO_ATTRS, NULL };
360         LDAPControl c, *ctrls[2], **ctrlsp = NULL;
361         BerElement *ber = NULL;
362
363         if ( verbose ) printf ( _("deleting children of: %s\n"), base );
364
365         if ( subentries ) {
366                 /*
367                  * Do a one level search at base for subentry children.
368                  */
369
370                 if ((ber = ber_alloc_t(LBER_USE_DER)) == NULL) {
371                         return EXIT_FAILURE;
372                 }
373                 rc = ber_printf( ber, "b", 1 );
374                 if ( rc == -1 ) {
375                         ber_free( ber, 1 );
376                         fprintf( stderr, _("Subentries control encoding error!\n"));
377                         return EXIT_FAILURE;
378                 }
379                 if ( ber_flatten2( ber, &c.ldctl_value, 0 ) == -1 ) {
380                         return EXIT_FAILURE;
381                 }
382                 c.ldctl_oid = LDAP_CONTROL_SUBENTRIES;
383                 c.ldctl_iscritical = 1;
384                 ctrls[0] = &c;
385                 ctrls[1] = NULL;
386                 ctrlsp = ctrls;
387         }
388
389         /*
390          * Do a one level search at base for children.  For each, delete its children.
391          */
392 more:;
393         srch_rc = ldap_search_ext_s( ld, base, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
394                 ctrlsp, NULL, NULL, sizelimit, &res );
395         switch ( srch_rc ) {
396         case LDAP_SUCCESS:
397         case LDAP_SIZELIMIT_EXCEEDED:
398                 break;
399         default:
400                 tool_perror( "ldap_search", srch_rc, NULL, NULL, NULL, NULL );
401                 return( srch_rc );
402         }
403
404         entries = ldap_count_entries( ld, res );
405
406         if ( entries > 0 ) {
407                 int i;
408
409                 for (e = ldap_first_entry( ld, res ), i = 0; e != NULL;
410                         e = ldap_next_entry( ld, e ), i++ )
411                 {
412                         char *dn = ldap_get_dn( ld, e );
413
414                         if( dn == NULL ) {
415                                 ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc );
416                                 tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
417                                 ber_memfree( dn );
418                                 return rc;
419                         }
420
421                         rc = deletechildren( ld, dn, 0 );
422                         if ( rc != LDAP_SUCCESS ) {
423                                 tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
424                                 ber_memfree( dn );
425                                 return rc;
426                         }
427
428                         if ( verbose ) {
429                                 printf( _("\tremoving %s\n"), dn );
430                         }
431
432                         rc = ldap_delete_ext_s( ld, dn, NULL, NULL );
433                         if ( rc != LDAP_SUCCESS ) {
434                                 tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL );
435                                 ber_memfree( dn );
436                                 return rc;
437
438                         }
439                         
440                         if ( verbose ) {
441                                 printf( _("\t%s removed\n"), dn );
442                         }
443
444                         ber_memfree( dn );
445                 }
446         }
447
448         ldap_msgfree( res );
449
450         if ( srch_rc == LDAP_SIZELIMIT_EXCEEDED ) {
451                 goto more;
452         }
453
454         return rc;
455 }