Back to index

openldap  2.4.31
ldapdelete.c
Go to the documentation of this file.
00001 /* ldapdelete.c - simple program to delete an entry using LDAP */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
00018  * All rights reserved.
00019  *
00020  * Redistribution and use in source and binary forms are permitted
00021  * provided that this notice is preserved and that due credit is given
00022  * to the University of Michigan at Ann Arbor.  The name of the
00023  * University may not be used to endorse or promote products derived
00024  * from this software without specific prior written permission.  This
00025  * software is provided ``as is'' without express or implied warranty.
00026  */
00027 /* ACKNOWLEDGEMENTS:
00028  * This work was originally developed by the University of Michigan
00029  * (as part of U-MICH LDAP).  Additional significant contributors
00030  * include:
00031  *   Kurt D. Zeilenga
00032  */
00033 
00034 #include "portable.h"
00035 
00036 #include <stdio.h>
00037 
00038 #include <ac/stdlib.h>
00039 #include <ac/ctype.h>
00040 #include <ac/string.h>
00041 #include <ac/unistd.h>
00042 #include <ac/socket.h>
00043 #include <ac/time.h>
00044 
00045 #include <ldap.h>
00046 #include "lutil.h"
00047 #include "lutil_ldap.h"
00048 #include "ldap_defaults.h"
00049 
00050 #include "common.h"
00051 
00052 
00053 static int    prune = 0;
00054 static int sizelimit = -1;
00055 
00056 
00057 static int dodelete LDAP_P((
00058     LDAP *ld,
00059     const char *dn));
00060 
00061 static int deletechildren LDAP_P((
00062        LDAP *ld,
00063        const char *dn,
00064        int subentries ));
00065 
00066 void
00067 usage( void )
00068 {
00069        fprintf( stderr, _("Delete entries from an LDAP server\n\n"));
00070        fprintf( stderr, _("usage: %s [options] [dn]...\n"), prog);
00071        fprintf( stderr, _(" dn: list of DNs to delete. If not given, it will be readed from stdin\n"));
00072        fprintf( stderr, _("     or from the file specified with \"-f file\".\n"));
00073        fprintf( stderr, _("Delete Options:\n"));
00074        fprintf( stderr, _("  -c         continuous operation mode (do not stop on errors)\n"));
00075        fprintf( stderr, _("  -f file    read operations from `file'\n"));
00076        fprintf( stderr, _("  -M         enable Manage DSA IT control (-MM to make critical)\n"));
00077        fprintf( stderr, _("  -P version protocol version (default: 3)\n"));
00078        fprintf( stderr, _("  -r         delete recursively\n"));
00079        tool_common_usage();
00080        exit( EXIT_FAILURE );
00081 }
00082 
00083 
00084 const char options[] = "r"
00085        "cd:D:e:f:h:H:IMnNO:o:p:P:QR:U:vVw:WxX:y:Y:z:Z";
00086 
00087 int
00088 handle_private_option( int i )
00089 {
00090        int ival;
00091        char *next;
00092        switch ( i ) {
00093 #if 0
00094               int crit;
00095               char *control, *cvalue;
00096        case 'E': /* delete extensions */
00097               if( protocol == LDAP_VERSION2 ) {
00098                      fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"),
00099                             prog, protocol );
00100                      exit( EXIT_FAILURE );
00101               }
00102 
00103               /* should be extended to support comma separated list of
00104                *     [!]key[=value] parameters, e.g.  -E !foo,bar=567
00105                */
00106 
00107               crit = 0;
00108               cvalue = NULL;
00109               if( optarg[0] == '!' ) {
00110                      crit = 1;
00111                      optarg++;
00112               }
00113 
00114               control = strdup( optarg );
00115               if ( (cvalue = strchr( control, '=' )) != NULL ) {
00116                      *cvalue++ = '\0';
00117               }
00118               fprintf( stderr, _("Invalid delete extension name: %s\n"), control );
00119               usage();
00120 #endif
00121 
00122        case 'r':
00123               prune = 1;
00124               break;
00125 
00126        case 'z':     /* size limit */
00127               if ( strcasecmp( optarg, "none" ) == 0 ) {
00128                      sizelimit = 0;
00129 
00130               } else if ( strcasecmp( optarg, "max" ) == 0 ) {
00131                      sizelimit = LDAP_MAXINT;
00132 
00133               } else {
00134                      ival = strtol( optarg, &next, 10 );
00135                      if ( next == NULL || next[0] != '\0' ) {
00136                             fprintf( stderr,
00137                                    _("Unable to parse size limit \"%s\"\n"), optarg );
00138                             exit( EXIT_FAILURE );
00139                      }
00140                      sizelimit = ival;
00141               }
00142               if( sizelimit < 0 || sizelimit > LDAP_MAXINT ) {
00143                      fprintf( stderr, _("%s: invalid sizelimit (%d) specified\n"),
00144                             prog, sizelimit );
00145                      exit( EXIT_FAILURE );
00146               }
00147               break;
00148 
00149        default:
00150               return 0;
00151        }
00152        return 1;
00153 }
00154 
00155 
00156 static void
00157 private_conn_setup( LDAP *ld )
00158 {
00159        /* this seems prudent for searches below */
00160        int deref = LDAP_DEREF_NEVER;
00161        ldap_set_option( ld, LDAP_OPT_DEREF, &deref );
00162 }
00163 
00164 
00165 int
00166 main( int argc, char **argv )
00167 {
00168        char          buf[ 4096 ];
00169        FILE          *fp = NULL;
00170        LDAP          *ld;
00171        int           rc, retval;
00172 
00173        tool_init( TOOL_DELETE );
00174     prog = lutil_progname( "ldapdelete", argc, argv );
00175 
00176        tool_args( argc, argv );
00177 
00178        if ( infile != NULL ) {
00179               if (( fp = fopen( infile, "r" )) == NULL ) {
00180                      perror( optarg );
00181                      exit( EXIT_FAILURE );
00182            }
00183        } else {
00184               if ( optind >= argc ) {
00185                      fp = stdin;
00186               }
00187        }
00188 
00189        ld = tool_conn_setup( 0, &private_conn_setup );
00190 
00191        tool_bind( ld );
00192 
00193        tool_server_controls( ld, NULL, 0 );
00194 
00195        retval = rc = 0;
00196 
00197        if ( fp == NULL ) {
00198               for ( ; optind < argc; ++optind ) {
00199                      rc = dodelete( ld, argv[ optind ] );
00200 
00201                      /* Stop on error and no -c option */
00202                      if( rc != 0 ) {
00203                             retval = rc;
00204                             if( contoper == 0 ) break;
00205                      }
00206               }
00207        } else {
00208               while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) {
00209                      buf[ strlen( buf ) - 1 ] = '\0'; /* remove trailing newline */
00210 
00211                      if ( *buf != '\0' ) {
00212                             rc = dodelete( ld, buf );
00213                             if ( rc != 0 )
00214                                    retval = rc;
00215                      }
00216               }
00217               if ( fp != stdin )
00218                      fclose( fp );
00219        }
00220 
00221        tool_exit( ld, retval );
00222 }
00223 
00224 
00225 static int dodelete(
00226     LDAP      *ld,
00227     const char       *dn)
00228 {
00229        int id;
00230        int    rc, code;
00231        char *matcheddn = NULL, *text = NULL, **refs = NULL;
00232        LDAPControl **ctrls = NULL;
00233        LDAPMessage *res;
00234        int subentries = 0;
00235 
00236        if ( verbose ) {
00237               printf( _("%sdeleting entry \"%s\"\n"),
00238                      (dont ? "!" : ""), dn );
00239        }
00240 
00241        if ( dont ) {
00242               return LDAP_SUCCESS;
00243        }
00244 
00245        /* If prune is on, remove a whole subtree.  Delete the children of the
00246         * DN recursively, then the DN requested.
00247         */
00248        if ( prune ) {
00249 retry:;
00250               deletechildren( ld, dn, subentries );
00251        }
00252 
00253        rc = ldap_delete_ext( ld, dn, NULL, NULL, &id );
00254        if ( rc != LDAP_SUCCESS ) {
00255               fprintf( stderr, "%s: ldap_delete_ext: %s (%d)\n",
00256                      prog, ldap_err2string( rc ), rc );
00257               return rc;
00258        }
00259 
00260        for ( ; ; ) {
00261               struct timeval tv;
00262 
00263               if ( tool_check_abandon( ld, id ) ) {
00264                      return LDAP_CANCELLED;
00265               }
00266 
00267               tv.tv_sec = 0;
00268               tv.tv_usec = 100000;
00269 
00270               rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
00271               if ( rc < 0 ) {
00272                      tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
00273                      return rc;
00274               }
00275 
00276               if ( rc != 0 ) {
00277                      break;
00278               }
00279        }
00280 
00281        rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 );
00282 
00283        switch ( rc ) {
00284        case LDAP_SUCCESS:
00285               break;
00286 
00287        case LDAP_NOT_ALLOWED_ON_NONLEAF:
00288               if ( prune && !subentries ) {
00289                      subentries = 1;
00290                      goto retry;
00291               }
00292               /* fallthru */
00293 
00294        default:
00295               fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
00296                      prog, ldap_err2string( rc ), rc );
00297               return rc;
00298        }
00299 
00300        if( code != LDAP_SUCCESS ) {
00301               tool_perror( "ldap_delete", code, NULL, matcheddn, text, refs );
00302        } else if ( verbose && 
00303               ((matcheddn && *matcheddn) || (text && *text) || (refs && *refs) ))
00304        {
00305               printf( _("Delete Result: %s (%d)\n"),
00306                      ldap_err2string( code ), code );
00307 
00308               if( text && *text ) {
00309                      printf( _("Additional info: %s\n"), text );
00310               }
00311 
00312               if( matcheddn && *matcheddn ) {
00313                      printf( _("Matched DN: %s\n"), matcheddn );
00314               }
00315 
00316               if( refs ) {
00317                      int i;
00318                      for( i=0; refs[i]; i++ ) {
00319                             printf(_("Referral: %s\n"), refs[i] );
00320                      }
00321               }
00322        }
00323 
00324        if (ctrls) {
00325               tool_print_ctrls( ld, ctrls );
00326               ldap_controls_free( ctrls );
00327        }
00328 
00329        ber_memfree( text );
00330        ber_memfree( matcheddn );
00331        ber_memvfree( (void **) refs );
00332 
00333        return code;
00334 }
00335 
00336 /*
00337  * Delete all the children of an entry recursively until leaf nodes are reached.
00338  */
00339 static int deletechildren(
00340        LDAP *ld,
00341        const char *base,
00342        int subentries )
00343 {
00344        LDAPMessage *res, *e;
00345        int entries;
00346        int rc = LDAP_SUCCESS, srch_rc;
00347        static char *attrs[] = { LDAP_NO_ATTRS, NULL };
00348        LDAPControl c, *ctrls[2], **ctrlsp = NULL;
00349        BerElement *ber = NULL;
00350 
00351        if ( verbose ) printf ( _("deleting children of: %s\n"), base );
00352 
00353        if ( subentries ) {
00354               /*
00355                * Do a one level search at base for subentry children.
00356                */
00357 
00358               if ((ber = ber_alloc_t(LBER_USE_DER)) == NULL) {
00359                      return EXIT_FAILURE;
00360               }
00361               rc = ber_printf( ber, "b", 1 );
00362               if ( rc == -1 ) {
00363                      ber_free( ber, 1 );
00364                      fprintf( stderr, _("Subentries control encoding error!\n"));
00365                      return EXIT_FAILURE;
00366               }
00367               if ( ber_flatten2( ber, &c.ldctl_value, 0 ) == -1 ) {
00368                      return EXIT_FAILURE;
00369               }
00370               c.ldctl_oid = LDAP_CONTROL_SUBENTRIES;
00371               c.ldctl_iscritical = 1;
00372               ctrls[0] = &c;
00373               ctrls[1] = NULL;
00374               ctrlsp = ctrls;
00375        }
00376 
00377        /*
00378         * Do a one level search at base for children.  For each, delete its children.
00379         */
00380 more:;
00381        srch_rc = ldap_search_ext_s( ld, base, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
00382               ctrlsp, NULL, NULL, sizelimit, &res );
00383        switch ( srch_rc ) {
00384        case LDAP_SUCCESS:
00385        case LDAP_SIZELIMIT_EXCEEDED:
00386               break;
00387        default:
00388               tool_perror( "ldap_search", srch_rc, NULL, NULL, NULL, NULL );
00389               return( srch_rc );
00390        }
00391 
00392        entries = ldap_count_entries( ld, res );
00393 
00394        if ( entries > 0 ) {
00395               int i;
00396 
00397               for (e = ldap_first_entry( ld, res ), i = 0; e != NULL;
00398                      e = ldap_next_entry( ld, e ), i++ )
00399               {
00400                      char *dn = ldap_get_dn( ld, e );
00401 
00402                      if( dn == NULL ) {
00403                             ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc );
00404                             tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
00405                             ber_memfree( dn );
00406                             return rc;
00407                      }
00408 
00409                      rc = deletechildren( ld, dn, 0 );
00410                      if ( rc != LDAP_SUCCESS ) {
00411                             tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
00412                             ber_memfree( dn );
00413                             return rc;
00414                      }
00415 
00416                      if ( verbose ) {
00417                             printf( _("\tremoving %s\n"), dn );
00418                      }
00419 
00420                      rc = ldap_delete_ext_s( ld, dn, NULL, NULL );
00421                      if ( rc != LDAP_SUCCESS ) {
00422                             tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL );
00423                             ber_memfree( dn );
00424                             return rc;
00425 
00426                      }
00427                      
00428                      if ( verbose ) {
00429                             printf( _("\t%s removed\n"), dn );
00430                      }
00431 
00432                      ber_memfree( dn );
00433               }
00434        }
00435 
00436        ldap_msgfree( res );
00437 
00438        if ( srch_rc == LDAP_SIZELIMIT_EXCEEDED ) {
00439               goto more;
00440        }
00441 
00442        return rc;
00443 }