]> git.sur5r.net Git - openldap/blob - clients/tools/ldapdelete.c
4bcd7923b5919cfcee1f0faf19766f1b9d6789e5
[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", prog );
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", prog );
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", prog );
144                         return EXIT_FAILURE;
145                 }
146                 if( ldaphost != NULL ) {
147                         fprintf( stderr, "%s: -h previously specified\n", prog );
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", prog );
155                         return EXIT_FAILURE;
156                 }
157                 if( ldapport ) {
158                         fprintf( stderr, "%s: -H incompatible with -p\n", prog );
159                         return EXIT_FAILURE;
160                 }
161                 if( ldapuri != NULL ) {
162                         fprintf( stderr, "%s: -H previously specified\n", prog );
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", prog );
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", prog );
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", prog );
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", prog );
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", prog );
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", prog );
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: unrecognized 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
505                 ld = ldap_init( ldaphost, ldapport );
506                 if( ld == NULL ) {
507                         perror("ldapsearch: ldap_init");
508                         return EXIT_FAILURE;
509                 }
510
511         } else {
512                 if ( verbose ) {
513                         fprintf( stderr, "ldap_initialize( %s )\n",
514                                 ldapuri != NULL ? ldapuri : "<DEFAULT>" );
515                 }
516
517                 rc = ldap_initialize( &ld, ldapuri );
518                 if( rc != LDAP_SUCCESS ) {
519                         fprintf( stderr, "Could not create LDAP session handle (%d): %s\n",
520                                 rc, ldap_err2string(rc) );
521                         return EXIT_FAILURE;
522                 }
523         }
524
525         {
526                 /* this seems prudent for searches below */
527                 int deref = LDAP_DEREF_NEVER;
528                 ldap_set_option( ld, LDAP_OPT_DEREF, &deref );
529         }
530
531         /* chase referrals */
532         if( ldap_set_option( ld, LDAP_OPT_REFERRALS,
533                 referrals ? LDAP_OPT_ON : LDAP_OPT_OFF ) != LDAP_OPT_SUCCESS )
534         {
535                 fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
536                         referrals ? "on" : "off" );
537                 return EXIT_FAILURE;
538         }
539
540         if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version )
541                 != LDAP_OPT_SUCCESS )
542         {
543                 fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
544                         version );
545                 return EXIT_FAILURE;
546         }
547
548         if ( use_tls && ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
549                 ldap_perror( ld, "ldap_start_tls" );
550                 if ( use_tls > 1 ) {
551                         return EXIT_FAILURE;
552                 }
553         }
554
555         if (want_bindpw) {
556                 passwd.bv_val = getpassphrase("Enter LDAP Password: ");
557                 passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
558         }
559
560         if ( authmethod == LDAP_AUTH_SASL ) {
561 #ifdef HAVE_CYRUS_SASL
562                 void *defaults;
563
564                 if( sasl_secprops != NULL ) {
565                         rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
566                                 (void *) sasl_secprops );
567                         
568                         if( rc != LDAP_OPT_SUCCESS ) {
569                                 fprintf( stderr,
570                                         "Could not set LDAP_OPT_X_SASL_SECPROPS: %s\n",
571                                         sasl_secprops );
572                                 return( EXIT_FAILURE );
573                         }
574                 }
575                 
576                 defaults = lutil_sasl_defaults( ld,
577                         sasl_mech,
578                         sasl_realm,
579                         sasl_authc_id,
580                         passwd.bv_val,
581                         sasl_authz_id );
582
583                 rc = ldap_sasl_interactive_bind_s( ld, binddn,
584                         sasl_mech, NULL, NULL,
585                         sasl_flags, lutil_sasl_interact, defaults );
586
587                 if( rc != LDAP_SUCCESS ) {
588                         ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
589                         return( EXIT_FAILURE );
590                 }
591 #else
592                 fprintf( stderr, "%s: not compiled with SASL support\n",
593                         argv[0] );
594                 return( EXIT_FAILURE );
595 #endif
596         }
597         else {
598                 if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
599                                 != LDAP_SUCCESS ) {
600                         ldap_perror( ld, "ldap_bind" );
601                         return( EXIT_FAILURE );
602                 }
603         }
604
605         if ( manageDSAit ) {
606                 int err;
607                 LDAPControl c;
608                 LDAPControl *ctrls[2];
609                 ctrls[0] = &c;
610                 ctrls[1] = NULL;
611
612                 c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
613                 c.ldctl_value.bv_val = NULL;
614                 c.ldctl_value.bv_len = 0;
615                 c.ldctl_iscritical = manageDSAit > 1;
616
617                 err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, ctrls );
618
619                 if( err != LDAP_OPT_SUCCESS ) {
620                         fprintf( stderr, "Could not set ManageDSAit %scontrol\n",
621                                 c.ldctl_iscritical ? "critical " : "" );
622                         if( c.ldctl_iscritical ) {
623                                 exit( EXIT_FAILURE );
624                         }
625                 }
626         }
627
628         rc = 0;
629     if ( fp == NULL ) {
630         for ( ; optind < argc; ++optind ) {
631             rc = dodelete( ld, argv[ optind ] );
632         }
633     } else {
634         while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
635             buf[ strlen( buf ) - 1 ] = '\0';    /* remove trailing newline */
636             if ( *buf != '\0' ) {
637                 rc = dodelete( ld, buf );
638             }
639         }
640     }
641
642     ldap_unbind( ld );
643
644         return( rc );
645 }
646
647
648 static int dodelete(
649     LDAP        *ld,
650     const char  *dn)
651 {
652         int id;
653         int     rc, code;
654         char *matcheddn = NULL, *text = NULL, **refs = NULL;
655         LDAPMessage *res;
656
657         if ( verbose ) {
658                 printf( "%sdeleting entry \"%s\"\n",
659                         (not ? "!" : ""), dn );
660         }
661
662         if ( not ) {
663                 return LDAP_SUCCESS;
664         }
665
666         /* If prune is on, remove a whole subtree.  Delete the children of the
667          * DN recursively, then the DN requested.
668          */
669         if ( prune ) deletechildren( ld, dn );
670
671         rc = ldap_delete_ext( ld, dn, NULL, NULL, &id );
672         if ( rc != LDAP_SUCCESS ) {
673                 fprintf( stderr, "%s: ldap_delete_ext: %s (%d)\n",
674                         prog, ldap_err2string( rc ), rc );
675                 return rc;
676         }
677
678         rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res );
679         if ( rc < 0 ) {
680                 ldap_perror( ld, "ldapdelete: ldap_result" );
681                 return rc;
682         }
683
684         rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, NULL, 1 );
685
686         if( rc != LDAP_SUCCESS ) {
687                 fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
688                         prog, ldap_err2string( rc ), rc );
689                 return rc;
690         }
691
692         if( verbose || code != LDAP_SUCCESS ||
693                 (matcheddn && *matcheddn) || (text && *text) || (refs && *refs) )
694         {
695                 printf( "Delete Result: %s (%d)\n", ldap_err2string( code ), code );
696
697                 if( text && *text ) {
698                         printf( "Additional info: %s\n", text );
699                 }
700
701                 if( matcheddn && *matcheddn ) {
702                         printf( "Matched DN: %s\n", matcheddn );
703                 }
704
705                 if( refs ) {
706                         int i;
707                         for( i=0; refs[i]; i++ ) {
708                                 printf("Referral: %s\n", refs[i] );
709                         }
710                 }
711         }
712
713         ber_memfree( text );
714         ber_memfree( matcheddn );
715         ber_memvfree( (void **) refs );
716
717         return code;
718 }
719
720 /*
721  * Delete all the children of an entry recursively until leaf nodes are reached.
722  *
723  */
724 static int deletechildren(
725         LDAP *ld,
726         const char *dn )
727 {
728         LDAPMessage *res, *e;
729         int entries;
730         int rc;
731         static char *attrs[] = { "1.1", NULL };
732
733         if ( verbose ) printf ( "deleting children of: %s\n", dn );
734         /*
735          * Do a one level search at dn for children.  For each, delete its children.
736          */
737
738         rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
739                 NULL, NULL, NULL, -1, &res );
740         if ( rc != LDAP_SUCCESS ) {
741                 ldap_perror( ld, "ldap_search" );
742                 return( rc );
743         }
744
745         entries = ldap_count_entries( ld, res );
746
747         if ( entries > 0 ) {
748                 int i;
749
750                 for (e = ldap_first_entry( ld, res ), i = 0; e != NULL;
751                         e = ldap_next_entry( ld, e ), i++ )
752                 {
753                         char *dn = ldap_get_dn( ld, e );
754
755                         if( dn == NULL ) {
756                                 ldap_perror( ld, "ldap_prune" );
757                                 ldap_get_option( ld, LDAP_OPT_ERROR_NUMBER, &rc );
758                                 ber_memfree( dn );
759                                 return rc;
760                         }
761
762                         rc = deletechildren( ld, dn );
763                         if ( rc == -1 ) {
764                                 ldap_perror( ld, "ldap_prune" );
765                                 ber_memfree( dn );
766                                 return rc;
767                         }
768
769                         if ( verbose ) {
770                                 printf( "\tremoving %s\n", dn );
771                         }
772
773                         rc = ldap_delete_s( ld, dn );
774                         if ( rc == -1 ) {
775                                 ldap_perror( ld, "ldap_delete" );
776                                 ber_memfree( dn );
777                                 return rc;
778
779                         }
780                         
781                         if ( verbose ) {
782                                 printf( "\t%s removed\n", dn );
783                         }
784
785                         ber_memfree( dn );
786                 }
787         }
788
789         ldap_msgfree( res );
790         return rc;
791 }