1 /* ldapdelete.c - simple program to delete an entry using LDAP */ 2 /* $OpenLDAP: pkg/ldap/clients/tools/ldapdelete.c,v 1.118.2.7 2008/02/12 00:32:01 quanah Exp $ */ 3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2008 The OpenLDAP Foundation. 6 * Portions Copyright 1998-2003 Kurt D. Zeilenga. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan. 18 * All rights reserved. 19 * 20 * Redistribution and use in source and binary forms are permitted 21 * provided that this notice is preserved and that due credit is given 22 * to the University of Michigan at Ann Arbor. The name of the 23 * University may not be used to endorse or promote products derived 24 * from this software without specific prior written permission. This 25 * software is provided ``as is'' without express or implied warranty. 26 */ 27 /* ACKNOWLEDGEMENTS: 28 * This work was originally developed by the University of Michigan 29 * (as part of U-MICH LDAP). Additional significant contributors 30 * include: 31 * Kurt D. Zeilenga 32 */ 33 34 #include "portable.h" 35 36 #include <stdio.h> 37 38 #include <ac/stdlib.h> 39 #include <ac/ctype.h> 40 #include <ac/string.h> 41 #include <ac/unistd.h> 42 #include <ac/socket.h> 43 #include <ac/time.h> 44 45 #include <ldap.h> 46 #include "lutil.h" 47 #include "lutil_ldap.h" 48 #include "ldap_defaults.h" 49 50 #include "common.h" 51 52 53 static int prune = 0; 54 static int sizelimit = -1; 55 56 57 static int dodelete LDAP_P(( 58 LDAP *ld, 59 const char *dn)); 60 61 static int deletechildren LDAP_P(( 62 LDAP *ld, 63 const char *dn, 64 int subentries )); 65 66 void 67 usage( void ) 68 { 69 fprintf( stderr, _("Delete entries from an LDAP server\n\n")); 70 fprintf( stderr, _("usage: %s [options] [dn]...\n"), prog); 71 fprintf( stderr, _(" dn: list of DNs to delete. If not given, it will be readed from stdin\n")); 72 fprintf( stderr, _(" or from the file specified with \"-f file\".\n")); 73 fprintf( stderr, _("Delete Options:\n")); 74 fprintf( stderr, _(" -r delete recursively\n")); 75 tool_common_usage(); 76 exit( EXIT_FAILURE ); 77 } 78 79 80 const char options[] = "r" 81 "cd:D:e:f:h:H:IMnO:o:p:P:QR:U:vVw:WxX:y:Y:z:Z"; 82 83 int 84 handle_private_option( int i ) 85 { 86 int ival; 87 char *next; 88 switch ( i ) { 89 #if 0 90 int crit; 91 char *control, *cvalue; 92 case 'E': /* delete extensions */ 93 if( protocol == LDAP_VERSION2 ) { 94 fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"), 95 prog, protocol ); 96 exit( EXIT_FAILURE ); 97 } 98 99 /* should be extended to support comma separated list of 100 * [!]key[=value] parameters, e.g. -E !foo,bar=567 101 */ 102 103 crit = 0; 104 cvalue = NULL; 105 if( optarg[0] == '!' ) { 106 crit = 1; 107 optarg++; 108 } 109 110 control = strdup( optarg ); 111 if ( (cvalue = strchr( control, '=' )) != NULL ) { 112 *cvalue++ = '\0'; 113 } 114 fprintf( stderr, _("Invalid delete extension name: %s\n"), control ); 115 usage(); 116 #endif 117 118 case 'r': 119 prune = 1; 120 break; 121 122 case 'z': /* size limit */ 123 if ( strcasecmp( optarg, "none" ) == 0 ) { 124 sizelimit = 0; 125 126 } else if ( strcasecmp( optarg, "max" ) == 0 ) { 127 sizelimit = LDAP_MAXINT; 128 129 } else { 130 ival = strtol( optarg, &next, 10 ); 131 if ( next == NULL || next[0] != '\0' ) { 132 fprintf( stderr, 133 _("Unable to parse size limit \"%s\"\n"), optarg ); 134 exit( EXIT_FAILURE ); 135 } 136 sizelimit = ival; 137 } 138 if( sizelimit < 0 || sizelimit > LDAP_MAXINT ) { 139 fprintf( stderr, _("%s: invalid sizelimit (%d) specified\n"), 140 prog, sizelimit ); 141 exit( EXIT_FAILURE ); 142 } 143 break; 144 145 default: 146 return 0; 147 } 148 return 1; 149 } 150 151 152 static void 153 private_conn_setup( LDAP *ld ) 154 { 155 /* this seems prudent for searches below */ 156 int deref = LDAP_DEREF_NEVER; 157 ldap_set_option( ld, LDAP_OPT_DEREF, &deref ); 158 } 159 160 161 int 162 main( int argc, char **argv ) 163 { 164 char buf[ 4096 ]; 165 FILE *fp; 166 LDAP *ld; 167 int rc, retval; 168 169 fp = NULL; 170 171 tool_init( TOOL_DELETE ); 172 prog = lutil_progname( "ldapdelete", argc, argv ); 173 174 tool_args( argc, argv ); 175 176 if ( infile != NULL ) { 177 if (( fp = fopen( infile, "r" )) == NULL ) { 178 perror( optarg ); 179 exit( EXIT_FAILURE ); 180 } 181 } else { 182 if ( optind >= argc ) { 183 fp = stdin; 184 } 185 } 186 187 ld = tool_conn_setup( 0, &private_conn_setup ); 188 189 if ( pw_file || want_bindpw ) { 190 if ( pw_file ) { 191 rc = lutil_get_filed_password( pw_file, &passwd ); 192 if( rc ) return EXIT_FAILURE; 193 } else { 194 passwd.bv_val = getpassphrase( _("Enter LDAP Password: ") ); 195 passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0; 196 } 197 } 198 199 tool_bind( ld ); 200 201 tool_server_controls( ld, NULL, 0 ); 202 203 retval = rc = 0; 204 205 if ( fp == NULL ) { 206 for ( ; optind < argc; ++optind ) { 207 rc = dodelete( ld, argv[ optind ] ); 208 209 /* Stop on error and no -c option */ 210 if( rc != 0 ) { 211 retval = rc; 212 if( contoper == 0 ) break; 213 } 214 } 215 } else { 216 while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) { 217 buf[ strlen( buf ) - 1 ] = '\0'; /* remove trailing newline */ 218 219 if ( *buf != '\0' ) { 220 rc = dodelete( ld, buf ); 221 if ( rc != 0 ) 222 retval = rc; 223 } 224 } 225 } 226 227 tool_unbind( ld ); 228 tool_destroy(); 229 return retval; 230 } 231 232 233 static int dodelete( 234 LDAP *ld, 235 const char *dn) 236 { 237 int id; 238 int rc, code; 239 char *matcheddn = NULL, *text = NULL, **refs = NULL; 240 LDAPControl **ctrls = NULL; 241 LDAPMessage *res; 242 int subentries = 0; 243 244 if ( verbose ) { 245 printf( _("%sdeleting entry \"%s\"\n"), 246 (dont ? "!" : ""), dn ); 247 } 248 249 if ( dont ) { 250 return LDAP_SUCCESS; 251 } 252 253 /* If prune is on, remove a whole subtree. Delete the children of the 254 * DN recursively, then the DN requested. 255 */ 256 if ( prune ) { 257 retry:; 258 deletechildren( ld, dn, subentries ); 259 } 260 261 rc = ldap_delete_ext( ld, dn, NULL, NULL, &id ); 262 if ( rc != LDAP_SUCCESS ) { 263 fprintf( stderr, "%s: ldap_delete_ext: %s (%d)\n", 264 prog, ldap_err2string( rc ), rc ); 265 return rc; 266 } 267 268 for ( ; ; ) { 269 struct timeval tv; 270 271 if ( tool_check_abandon( ld, id ) ) { 272 return LDAP_CANCELLED; 273 } 274 275 tv.tv_sec = 0; 276 tv.tv_usec = 100000; 277 278 rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res ); 279 if ( rc < 0 ) { 280 tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL ); 281 return rc; 282 } 283 284 if ( rc != 0 ) { 285 break; 286 } 287 } 288 289 rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 ); 290 291 switch ( rc ) { 292 case LDAP_SUCCESS: 293 break; 294 295 case LDAP_NOT_ALLOWED_ON_NONLEAF: 296 if ( prune && !subentries ) { 297 subentries = 1; 298 goto retry; 299 } 300 /* fallthru */ 301 302 default: 303 fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n", 304 prog, ldap_err2string( rc ), rc ); 305 return rc; 306 } 307 308 if( code != LDAP_SUCCESS ) { 309 tool_perror( "ldap_delete", code, NULL, matcheddn, text, refs ); 310 } else if ( verbose && 311 ((matcheddn && *matcheddn) || (text && *text) || (refs && *refs) )) 312 { 313 printf( _("Delete Result: %s (%d)\n"), 314 ldap_err2string( code ), code ); 315 316 if( text && *text ) { 317 printf( _("Additional info: %s\n"), text ); 318 } 319 320 if( matcheddn && *matcheddn ) { 321 printf( _("Matched DN: %s\n"), matcheddn ); 322 } 323 324 if( refs ) { 325 int i; 326 for( i=0; refs[i]; i++ ) { 327 printf(_("Referral: %s\n"), refs[i] ); 328 } 329 } 330 } 331 332 if (ctrls) { 333 tool_print_ctrls( ld, ctrls ); 334 ldap_controls_free( ctrls ); 335 } 336 337 ber_memfree( text ); 338 ber_memfree( matcheddn ); 339 ber_memvfree( (void **) refs ); 340 341 return code; 342 } 343 344 /* 345 * Delete all the children of an entry recursively until leaf nodes are reached. 346 */ 347 static int deletechildren( 348 LDAP *ld, 349 const char *base, 350 int subentries ) 351 { 352 LDAPMessage *res, *e; 353 int entries; 354 int rc = LDAP_SUCCESS, srch_rc; 355 static char *attrs[] = { LDAP_NO_ATTRS, NULL }; 356 LDAPControl c, *ctrls[2], **ctrlsp = NULL; 357 BerElement *ber = NULL; 358 359 if ( verbose ) printf ( _("deleting children of: %s\n"), base ); 360 361 if ( subentries ) { 362 /* 363 * Do a one level search at base for subentry children. 364 */ 365 366 if ((ber = ber_alloc_t(LBER_USE_DER)) == NULL) { 367 return EXIT_FAILURE; 368 } 369 rc = ber_printf( ber, "b", 1 ); 370 if ( rc == -1 ) { 371 ber_free( ber, 1 ); 372 fprintf( stderr, _("Subentries control encoding error!\n")); 373 return EXIT_FAILURE; 374 } 375 if ( ber_flatten2( ber, &c.ldctl_value, 0 ) == -1 ) { 376 return EXIT_FAILURE; 377 } 378 c.ldctl_oid = LDAP_CONTROL_SUBENTRIES; 379 c.ldctl_iscritical = 1; 380 ctrls[0] = &c; 381 ctrls[1] = NULL; 382 ctrlsp = ctrls; 383 } 384 385 /* 386 * Do a one level search at base for children. For each, delete its children. 387 */ 388 more:; 389 srch_rc = ldap_search_ext_s( ld, base, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1, 390 ctrlsp, NULL, NULL, sizelimit, &res ); 391 switch ( srch_rc ) { 392 case LDAP_SUCCESS: 393 case LDAP_SIZELIMIT_EXCEEDED: 394 break; 395 default: 396 tool_perror( "ldap_search", srch_rc, NULL, NULL, NULL, NULL ); 397 return( srch_rc ); 398 } 399 400 entries = ldap_count_entries( ld, res ); 401 402 if ( entries > 0 ) { 403 int i; 404 405 for (e = ldap_first_entry( ld, res ), i = 0; e != NULL; 406 e = ldap_next_entry( ld, e ), i++ ) 407 { 408 char *dn = ldap_get_dn( ld, e ); 409 410 if( dn == NULL ) { 411 ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc ); 412 tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL ); 413 ber_memfree( dn ); 414 return rc; 415 } 416 417 rc = deletechildren( ld, dn, 0 ); 418 if ( rc != LDAP_SUCCESS ) { 419 tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL ); 420 ber_memfree( dn ); 421 return rc; 422 } 423 424 if ( verbose ) { 425 printf( _("\tremoving %s\n"), dn ); 426 } 427 428 rc = ldap_delete_ext_s( ld, dn, NULL, NULL ); 429 if ( rc != LDAP_SUCCESS ) { 430 tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL ); 431 ber_memfree( dn ); 432 return rc; 433 434 } 435 436 if ( verbose ) { 437 printf( _("\t%s removed\n"), dn ); 438 } 439 440 ber_memfree( dn ); 441 } 442 } 443 444 ldap_msgfree( res ); 445 446 if ( srch_rc == LDAP_SIZELIMIT_EXCEEDED ) { 447 goto more; 448 } 449 450 return rc; 451 } 452