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