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