]> git.sur5r.net Git - openldap/blob - clients/tools/ldapdelete.c
bc04de2b5b0462e3ff33f41b5a3647ee778c5e18
[openldap] / clients / tools / ldapdelete.c
1 /* ldapdelete.c - simple program to delete an entry using LDAP */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/stdlib.h>
13 #include <ac/ctype.h>
14
15 #include <ac/signal.h>
16 #include <ac/string.h>
17 #include <ac/unistd.h>
18
19 #include <ldap.h>
20 #include "lutil.h"
21 #include "lutil_ldap.h"
22 #include "ldap_defaults.h"
23
24 static char     *prog;
25 static char     *binddn = NULL;
26 static struct berval passwd = { 0, NULL };
27 static char *ldapuri = NULL;
28 static char     *ldaphost = NULL;
29 static int      ldapport = 0;
30 static int      prune = 0;
31 #ifdef HAVE_CYRUS_SASL
32 static unsigned sasl_flags = LDAP_SASL_AUTOMATIC;
33 static char     *sasl_mech = NULL;
34 static char *sasl_realm = NULL;
35 static char     *sasl_authc_id = NULL;
36 static char     *sasl_authz_id = NULL;
37 static char     *sasl_secprops = NULL;
38 #endif
39 static int      use_tls = 0;
40 static int      not, verbose, contoper;
41 static LDAP     *ld = NULL;
42
43 static int dodelete LDAP_P((
44     LDAP *ld,
45     const char *dn));
46
47 static int deletechildren LDAP_P((
48         LDAP *ld,
49         const char *dn ));
50
51 static void
52 usage( const char *s )
53 {
54         fprintf( stderr,
55 "Delete entries from an LDAP server\n\n"
56 "usage: %s [options] [dn]...\n"
57 "       dn: list of DNs to delete. If not given, it will be readed from stdin\n"
58 "           or from the file specified with \"-f file\".\n"
59 "Delete Options:\n"
60 "  -r         delete recursively\n"
61
62 "Common options:\n"
63 "  -d level   set LDAP debugging level to `level'\n"
64 "  -D binddn  bind DN\n"
65 "  -f file    read operations from `file'\n"
66 "  -h host    LDAP server\n"
67 "  -H URI     LDAP Uniform Resource Indentifier(s)\n"
68 "  -I         use SASL Interactive mode\n"
69 "  -k         use Kerberos authentication\n"
70 "  -K         like -k, but do only step 1 of the Kerberos bind\n"
71 "  -M         enable Manage DSA IT control (-MM to make critical)\n"
72 "  -n         show what would be done but don't actually do it\n"
73 "  -O props   SASL security properties\n"
74 "  -p port    port on LDAP server\n"
75 "  -P version procotol version (default: 3)\n"
76 "  -Q         use SASL Quiet mode\n"
77 "  -R realm   SASL realm\n"
78 "  -U authcid SASL authentication identity\n"
79 "  -v         run in verbose mode (diagnostics to standard output)\n"
80 "  -w passwd  bind passwd (for simple authentication)\n"
81 "  -W         prompt for bind passwd\n"
82 "  -x         Simple authentication\n"
83 "  -X authzid SASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
84 "  -Y mech    SASL mechanism\n"
85 "  -Z         Start TLS request (-ZZ to require successful response)\n"
86 ,               s );
87
88         exit( EXIT_FAILURE );
89 }
90
91
92 int
93 main( int argc, char **argv )
94 {
95         char            buf[ 4096 ];
96         FILE            *fp;
97         int             i, rc, authmethod, referrals, want_bindpw, version, debug, manageDSAit;
98
99     not = verbose = contoper = want_bindpw = debug = manageDSAit = referrals = 0;
100     fp = NULL;
101     authmethod = -1;
102         version = -1;
103
104     prog = lutil_progname( "ldapdelete", argc, argv );
105
106     while (( i = getopt( argc, argv, "cf:r"
107                 "Cd:D:h:H:IkKMnO:p:P:QR:U:vw:WxX:Y:Z" )) != EOF )
108         {
109         switch( i ) {
110         /* Delete Specific Options */
111         case 'c':       /* continuous operation mode */
112             ++contoper;
113             break;
114         case 'f':       /* read DNs from a file */
115                 if( fp != NULL ) {
116                         fprintf( stderr, "%s: -f previously specified\n", prog );
117                         return EXIT_FAILURE;
118                 }
119             if (( fp = fopen( optarg, "r" )) == NULL ) {
120                 perror( optarg );
121                 exit( EXIT_FAILURE );
122             }
123             break;
124         case 'r':
125                 prune = 1;
126                 break;
127
128         /* Common Options */
129         case 'C':
130                 referrals++;
131                 break;
132         case 'd':
133             debug |= atoi( optarg );
134             break;
135         case 'D':       /* bind DN */
136                 if( binddn != NULL ) {
137                         fprintf( stderr, "%s: -D previously specified\n", prog );
138                         return EXIT_FAILURE;
139                 }
140             binddn = strdup( optarg );
141             break;
142         case 'h':       /* ldap host */
143                 if( ldapuri != NULL ) {
144                         fprintf( stderr, "%s: -h incompatible with -H\n", prog );
145                         return EXIT_FAILURE;
146                 }
147                 if( ldaphost != NULL ) {
148                         fprintf( stderr, "%s: -h previously specified\n", prog );
149                         return EXIT_FAILURE;
150                 }
151             ldaphost = strdup( optarg );
152             break;
153         case 'H':       /* ldap URI */
154                 if( ldaphost != NULL ) {
155                         fprintf( stderr, "%s: -H incompatible with -h\n", prog );
156                         return EXIT_FAILURE;
157                 }
158                 if( ldapport ) {
159                         fprintf( stderr, "%s: -H incompatible with -p\n", prog );
160                         return EXIT_FAILURE;
161                 }
162                 if( ldapuri != NULL ) {
163                         fprintf( stderr, "%s: -H previously specified\n", prog );
164                         return EXIT_FAILURE;
165                 }
166             ldapuri = strdup( optarg );
167             break;
168         case 'I':
169 #ifdef HAVE_CYRUS_SASL
170                 if( version == LDAP_VERSION2 ) {
171                         fprintf( stderr, "%s: -I incompatible with version %d\n",
172                                 prog, version );
173                         return EXIT_FAILURE;
174                 }
175                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
176                         fprintf( stderr, "%s: incompatible previous "
177                                 "authentication choice\n",
178                                 prog );
179                         return EXIT_FAILURE;
180                 }
181                 authmethod = LDAP_AUTH_SASL;
182                 version = LDAP_VERSION3;
183                 sasl_flags = LDAP_SASL_INTERACTIVE;
184                 break;
185 #else
186                 fprintf( stderr, "%s: was not compiled with SASL support\n",
187                         prog );
188                 return( EXIT_FAILURE );
189 #endif
190         case 'k':       /* kerberos bind */
191 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
192                 if( version > LDAP_VERSION2 ) {
193                         fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
194                                 prog, version );
195                         return EXIT_FAILURE;
196                 }
197
198                 if( authmethod != -1 ) {
199                         fprintf( stderr, "%s: -k incompatible with previous "
200                                 "authentication choice\n", prog );
201                         return EXIT_FAILURE;
202                 }
203                         
204                 authmethod = LDAP_AUTH_KRBV4;
205 #else
206                 fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
207                 return EXIT_FAILURE;
208 #endif
209             break;
210         case 'K':       /* kerberos bind, part one only */
211 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
212                 if( version > LDAP_VERSION2 ) {
213                         fprintf( stderr, "%s: -k incompatible with LDAPv%d\n",
214                                 prog, version );
215                         return EXIT_FAILURE;
216                 }
217                 if( authmethod != -1 ) {
218                         fprintf( stderr, "%s: incompatible with previous "
219                                 "authentication choice\n", prog );
220                         return EXIT_FAILURE;
221                 }
222
223                 authmethod = LDAP_AUTH_KRBV41;
224 #else
225                 fprintf( stderr, "%s: not compiled with Kerberos support\n", prog );
226                 return( EXIT_FAILURE );
227 #endif
228             break;
229         case 'M':
230                 /* enable Manage DSA IT */
231                 if( version == LDAP_VERSION2 ) {
232                         fprintf( stderr, "%s: -M incompatible with LDAPv%d\n",
233                                 prog, version );
234                         return EXIT_FAILURE;
235                 }
236                 manageDSAit++;
237                 version = LDAP_VERSION3;
238                 break;
239         case 'n':       /* print deletes, don't actually do them */
240             ++not;
241             break;
242         case 'O':
243 #ifdef HAVE_CYRUS_SASL
244                 if( sasl_secprops != NULL ) {
245                         fprintf( stderr, "%s: -O previously specified\n", prog );
246                         return EXIT_FAILURE;
247                 }
248                 if( version == LDAP_VERSION2 ) {
249                         fprintf( stderr, "%s: -O incompatible with LDAPv%d\n",
250                                 prog, version );
251                         return EXIT_FAILURE;
252                 }
253                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
254                         fprintf( stderr, "%s: incompatible previous "
255                                 "authentication choice\n", prog );
256                         return EXIT_FAILURE;
257                 }
258                 authmethod = LDAP_AUTH_SASL;
259                 version = LDAP_VERSION3;
260                 sasl_secprops = strdup( optarg );
261 #else
262                 fprintf( stderr, "%s: not compiled with SASL support\n",
263                         prog );
264                 return( EXIT_FAILURE );
265 #endif
266                 break;
267         case 'p':
268                 if( ldapport ) {
269                         fprintf( stderr, "%s: -p previously specified\n", prog );
270                         return EXIT_FAILURE;
271                 }
272             ldapport = atoi( optarg );
273             break;
274         case 'P':
275                 switch( atoi(optarg) ) {
276                 case 2:
277                         if( version == LDAP_VERSION3 ) {
278                                 fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
279                                         prog, version );
280                                 return EXIT_FAILURE;
281                         }
282                         version = LDAP_VERSION2;
283                         break;
284                 case 3:
285                         if( version == LDAP_VERSION2 ) {
286                                 fprintf( stderr, "%s: -P 2 incompatible with version %d\n",
287                                         prog, version );
288                                 return EXIT_FAILURE;
289                         }
290                         version = LDAP_VERSION3;
291                         break;
292                 default:
293                         fprintf( stderr, "%s: protocol version should be 2 or 3\n",
294                                 prog );
295                         usage( prog );
296                         return( EXIT_FAILURE );
297                 } break;
298         case 'Q':
299 #ifdef HAVE_CYRUS_SASL
300                 if( version == LDAP_VERSION2 ) {
301                         fprintf( stderr, "%s: -Q incompatible with version %d\n",
302                                 prog, version );
303                         return EXIT_FAILURE;
304                 }
305                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
306                         fprintf( stderr, "%s: incompatible previous "
307                                 "authentication choice\n",
308                                 prog );
309                         return EXIT_FAILURE;
310                 }
311                 authmethod = LDAP_AUTH_SASL;
312                 version = LDAP_VERSION3;
313                 sasl_flags = LDAP_SASL_QUIET;
314                 break;
315 #else
316                 fprintf( stderr, "%s: not compiled with SASL support\n",
317                         prog );
318                 return( EXIT_FAILURE );
319 #endif
320         case 'R':
321 #ifdef HAVE_CYRUS_SASL
322                 if( sasl_realm != NULL ) {
323                         fprintf( stderr, "%s: -R previously specified\n", prog );
324                         return EXIT_FAILURE;
325                 }
326                 if( version == LDAP_VERSION2 ) {
327                         fprintf( stderr, "%s: -R incompatible with version %d\n",
328                                 prog, version );
329                         return EXIT_FAILURE;
330                 }
331                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
332                         fprintf( stderr, "%s: incompatible previous "
333                                 "authentication choice\n",
334                                 prog );
335                         return EXIT_FAILURE;
336                 }
337                 authmethod = LDAP_AUTH_SASL;
338                 version = LDAP_VERSION3;
339                 sasl_realm = strdup( optarg );
340 #else
341                 fprintf( stderr, "%s: not compiled with SASL support\n",
342                         prog );
343                 return( EXIT_FAILURE );
344 #endif
345                 break;
346         case 'U':
347 #ifdef HAVE_CYRUS_SASL
348                 if( sasl_authc_id != NULL ) {
349                         fprintf( stderr, "%s: -U previously specified\n", prog );
350                         return EXIT_FAILURE;
351                 }
352                 if( version == LDAP_VERSION2 ) {
353                         fprintf( stderr, "%s: -U incompatible with version %d\n",
354                                 prog, version );
355                         return EXIT_FAILURE;
356                 }
357                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
358                         fprintf( stderr, "%s: incompatible previous "
359                                 "authentication choice\n",
360                                 prog );
361                         return EXIT_FAILURE;
362                 }
363                 authmethod = LDAP_AUTH_SASL;
364                 version = LDAP_VERSION3;
365                 sasl_authc_id = strdup( optarg );
366 #else
367                 fprintf( stderr, "%s: not compiled with SASL support\n",
368                         prog );
369                 return( EXIT_FAILURE );
370 #endif
371                 break;
372         case 'v':       /* verbose mode */
373             verbose++;
374             break;
375         case 'w':       /* password */
376             passwd.bv_val = strdup( optarg );
377                 {
378                         char* p;
379
380                         for( p = optarg; *p != '\0'; p++ ) {
381                                 *p = '\0';
382                         }
383                 }
384                 passwd.bv_len = strlen( passwd.bv_val );
385             break;
386         case 'W':
387                 want_bindpw++;
388                 break;
389         case 'Y':
390 #ifdef HAVE_CYRUS_SASL
391                 if( sasl_mech != NULL ) {
392                         fprintf( stderr, "%s: -Y previously specified\n", prog );
393                         return EXIT_FAILURE;
394                 }
395                 if( version == LDAP_VERSION2 ) {
396                         fprintf( stderr, "%s: -Y incompatible with version %d\n",
397                                 prog, version );
398                         return EXIT_FAILURE;
399                 }
400                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
401                         fprintf( stderr, "%s: incompatible with authentication choice\n", prog );
402                         return EXIT_FAILURE;
403                 }
404                 authmethod = LDAP_AUTH_SASL;
405                 version = LDAP_VERSION3;
406                 sasl_mech = strdup( optarg );
407 #else
408                 fprintf( stderr, "%s: not compiled with SASL support\n",
409                         prog );
410                 return( EXIT_FAILURE );
411 #endif
412                 break;
413         case 'x':
414                 if( authmethod != -1 && authmethod != LDAP_AUTH_SIMPLE ) {
415                         fprintf( stderr, "%s: incompatible with previous "
416                                 "authentication choice\n", prog );
417                         return EXIT_FAILURE;
418                 }
419                 authmethod = LDAP_AUTH_SIMPLE;
420                 break;
421         case 'X':
422 #ifdef HAVE_CYRUS_SASL
423                 if( sasl_authz_id != NULL ) {
424                         fprintf( stderr, "%s: -X previously specified\n", prog );
425                         return EXIT_FAILURE;
426                 }
427                 if( version == LDAP_VERSION2 ) {
428                         fprintf( stderr, "%s: -X incompatible with LDAPv%d\n",
429                                 prog, version );
430                         return EXIT_FAILURE;
431                 }
432                 if( authmethod != -1 && authmethod != LDAP_AUTH_SASL ) {
433                         fprintf( stderr, "%s: -X incompatible with "
434                                 "authentication choice\n", prog );
435                         return EXIT_FAILURE;
436                 }
437                 authmethod = LDAP_AUTH_SASL;
438                 version = LDAP_VERSION3;
439                 sasl_authz_id = strdup( optarg );
440 #else
441                 fprintf( stderr, "%s: not compiled with SASL support\n",
442                         prog );
443                 return( EXIT_FAILURE );
444 #endif
445                 break;
446         case 'Z':
447 #ifdef HAVE_TLS
448                 if( version == LDAP_VERSION2 ) {
449                         fprintf( stderr, "%s: -Z incompatible with version %d\n",
450                                 prog, version );
451                         return EXIT_FAILURE;
452                 }
453                 version = LDAP_VERSION3;
454                 use_tls++;
455 #else
456                 fprintf( stderr, "%s: not compiled with TLS support\n",
457                         prog );
458                 return( EXIT_FAILURE );
459 #endif
460                 break;
461         default:
462                 fprintf( stderr, "%s: unrecognized option -%c\n",
463                         prog, optopt );
464                 usage( prog );
465                 return( EXIT_FAILURE );
466         }
467     }
468
469         if (version == -1) {
470                 version = LDAP_VERSION3;
471         }
472         if (authmethod == -1 && version > LDAP_VERSION2) {
473 #ifdef HAVE_CYRUS_SASL
474                 authmethod = LDAP_AUTH_SASL;
475 #else
476                 authmethod = LDAP_AUTH_SIMPLE;
477 #endif
478         }
479
480     if ( fp == NULL ) {
481         if ( optind >= argc ) {
482             fp = stdin;
483         }
484     }
485
486         if ( debug ) {
487                 if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
488                         fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
489                 }
490                 if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
491                         fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
492                 }
493         }
494
495 #ifdef SIGPIPE
496         (void) SIGNAL( SIGPIPE, SIG_IGN );
497 #endif
498
499         if( ( ldaphost != NULL || ldapport ) && ( ldapuri == NULL ) ) {
500                 if ( verbose ) {
501                         fprintf( stderr, "ldap_init( %s, %d )\n",
502                                 ldaphost != NULL ? ldaphost : "<DEFAULT>",
503                                 ldapport );
504                 }
505
506                 ld = ldap_init( ldaphost, ldapport );
507                 if( ld == NULL ) {
508                         perror("ldapdelete: ldap_init");
509                         return EXIT_FAILURE;
510                 }
511
512         } else {
513                 if ( verbose ) {
514                         fprintf( stderr, "ldap_initialize( %s )\n",
515                                 ldapuri != NULL ? ldapuri : "<DEFAULT>" );
516                 }
517
518                 rc = ldap_initialize( &ld, ldapuri );
519                 if( rc != LDAP_SUCCESS ) {
520                         fprintf( stderr, "Could not create LDAP session handle (%d): %s\n",
521                                 rc, ldap_err2string(rc) );
522                         return EXIT_FAILURE;
523                 }
524         }
525
526         {
527                 /* this seems prudent for searches below */
528                 int deref = LDAP_DEREF_NEVER;
529                 ldap_set_option( ld, LDAP_OPT_DEREF, &deref );
530         }
531
532         /* chase referrals */
533         if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
534                 referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
535         {
536                 fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
537                         referrals ? "on" : "off" );
538                 return EXIT_FAILURE;
539         }
540
541         if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version )
542                 != LDAP_OPT_SUCCESS )
543         {
544                 fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
545                         version );
546                 return EXIT_FAILURE;
547         }
548
549         if ( use_tls && ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS )) {
550                 ldap_perror( ld, "ldap_start_tls" );
551                 if ( use_tls > 1 ) {
552                         return EXIT_FAILURE;
553                 }
554         }
555
556         if (want_bindpw) {
557                 passwd.bv_val = getpassphrase("Enter LDAP Password: ");
558                 passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
559         }
560
561         if ( authmethod == LDAP_AUTH_SASL ) {
562 #ifdef HAVE_CYRUS_SASL
563                 void *defaults;
564
565                 if( sasl_secprops != NULL ) {
566                         rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
567                                 (void *) sasl_secprops );
568                         
569                         if( rc != LDAP_OPT_SUCCESS ) {
570                                 fprintf( stderr,
571                                         "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
572                                         sasl_secprops );
573                                 return( EXIT_FAILURE );
574                         }
575                 }
576                 
577                 defaults = lutil_sasl_defaults( ld,
578                         sasl_mech,
579                         sasl_realm,
580                         sasl_authc_id,
581                         passwd.bv_val,
582                         sasl_authz_id );
583
584                 rc = ldap_sasl_interactive_bind_s( ld, binddn,
585                         sasl_mech, NULL, NULL,
586                         sasl_flags, lutil_sasl_interact, defaults );
587
588                 if( rc != LDAP_SUCCESS ) {
589                         ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
590                         return( EXIT_FAILURE );
591                 }
592 #else
593                 fprintf( stderr, "%s: not compiled with SASL support\n",
594                         prog );
595                 return( EXIT_FAILURE );
596 #endif
597         }
598         else {
599                 if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
600                                 != LDAP_SUCCESS ) {
601                         ldap_perror( ld, "ldap_bind" );
602                         return( EXIT_FAILURE );
603                 }
604         }
605
606         if ( manageDSAit ) {
607                 int err;
608                 LDAPControl c;
609                 LDAPControl *ctrls[2];
610                 ctrls[0] = &c;
611                 ctrls[1] = NULL;
612
613                 c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
614                 c.ldctl_value.bv_val = NULL;
615                 c.ldctl_value.bv_len = 0;
616                 c.ldctl_iscritical = manageDSAit > 1;
617
618                 err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
619
620                 if( err != LDAP_OPT_SUCCESS ) {
621                         fprintf( stderr, "Could not set ManageDSAit %scontrol\n",
622                                 c.ldctl_iscritical ? "critical " : "" );
623                         if( c.ldctl_iscritical ) {
624                                 exit( EXIT_FAILURE );
625                         }
626                 }
627         }
628
629         rc = 0;
630
631     if ( fp == NULL ) {
632                 for ( ; optind < argc; ++optind ) {
633                         rc = dodelete( ld, argv[ optind ] );
634
635                         /* Stop on error and no -c option */
636                         if( rc != 0 && contoper == 0) break;
637                 }
638         } else {
639                 while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
640                         buf[ strlen( buf ) - 1 ] = '\0'; /* remove trailing newline */
641
642                         if ( *buf != '\0' ) {
643                                 rc = dodelete( ld, buf );
644                         }
645                 }
646         }
647
648     ldap_unbind( ld );
649
650         return( rc );
651 }
652
653
654 static int dodelete(
655     LDAP        *ld,
656     const char  *dn)
657 {
658         int id;
659         int     rc, code;
660         char *matcheddn = NULL, *text = NULL, **refs = NULL;
661         LDAPMessage *res;
662
663         if ( verbose ) {
664                 printf( "%sdeleting entry \"%s\"\n",
665                         (not ? "!" : ""), dn );
666         }
667
668         if ( not ) {
669                 return LDAP_SUCCESS;
670         }
671
672         /* If prune is on, remove a whole subtree.  Delete the children of the
673          * DN recursively, then the DN requested.
674          */
675         if ( prune ) deletechildren( ld, dn );
676
677         rc = ldap_delete_ext( ld, dn, NULL, NULL, &id );
678         if ( rc != LDAP_SUCCESS ) {
679                 fprintf( stderr, "%s: ldap_delete_ext: %s (%d)\n",
680                         prog, ldap_err2string( rc ), rc );
681                 return rc;
682         }
683
684         rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res );
685         if ( rc < 0 ) {
686                 ldap_perror( ld, "ldapdelete: ldap_result" );
687                 return rc;
688         }
689
690         rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 1 );
691
692         if( rc != LDAP_SUCCESS ) {
693                 fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
694                         prog, ldap_err2string( rc ), rc );
695                 return rc;
696         }
697
698         if( verbose || code != LDAP_SUCCESS ||
699                 (matcheddn && *matcheddn) || (text && *text) || (refs && *refs) )
700         {
701                 printf( "Delete Result: %s (%d)\n", ldap_err2string( code ), code );
702
703                 if( text && *text ) {
704                         printf( "Additional info: %s\n", text );
705                 }
706
707                 if( matcheddn && *matcheddn ) {
708                         printf( "Matched DN: %s\n", matcheddn );
709                 }
710
711                 if( refs ) {
712                         int i;
713                         for( i=0; refs[i]; i++ ) {
714                                 printf("Referral: %s\n", refs[i] );
715                         }
716                 }
717         }
718
719         ber_memfree( text );
720         ber_memfree( matcheddn );
721         ber_memvfree( (void **) refs );
722
723         return code;
724 }
725
726 /*
727  * Delete all the children of an entry recursively until leaf nodes are reached.
728  *
729  */
730 static int deletechildren(
731         LDAP *ld,
732         const char *dn )
733 {
734         LDAPMessage *res, *e;
735         int entries;
736         int rc;
737         static char *attrs[] = { "1.1", NULL };
738
739         if ( verbose ) printf ( "deleting children of: %s\n", dn );
740         /*
741          * Do a one level search at dn for children.  For each, delete its children.
742          */
743
744         rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
745                 NULL, NULL, NULL, -1, &res );
746         if ( rc != LDAP_SUCCESS ) {
747                 ldap_perror( ld, "ldap_search" );
748                 return( rc );
749         }
750
751         entries = ldap_count_entries( ld, res );
752
753         if ( entries > 0 ) {
754                 int i;
755
756                 for (e = ldap_first_entry( ld, res ), i = 0; e != NULL;
757                         e = ldap_next_entry( ld, e ), i++ )
758                 {
759                         char *dn = ldap_get_dn( ld, e );
760
761                         if( dn == NULL ) {
762                                 ldap_perror( ld, "ldap_prune" );
763                                 ldap_get_option( ld, LDAP_OPT_ERROR_NUMBER, &rc );
764                                 ber_memfree( dn );
765                                 return rc;
766                         }
767
768                         rc = deletechildren( ld, dn );
769                         if ( rc == -1 ) {
770                                 ldap_perror( ld, "ldap_prune" );
771                                 ber_memfree( dn );
772                                 return rc;
773                         }
774
775                         if ( verbose ) {
776                                 printf( "\tremoving %s\n", dn );
777                         }
778
779                         rc = ldap_delete_s( ld, dn );
780                         if ( rc == -1 ) {
781                                 ldap_perror( ld, "ldap_delete" );
782                                 ber_memfree( dn );
783                                 return rc;
784
785                         }
786                         
787                         if ( verbose ) {
788                                 printf( "\t%s removed\n", dn );
789                         }
790
791                         ber_memfree( dn );
792                 }
793         }
794
795         ldap_msgfree( res );
796         return rc;
797 }