1 /* $NetBSD: ldapmodify.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $ */ 2 3 /* ldapmodify.c - generic program to modify or add entries using LDAP */ 4 /* OpenLDAP: pkg/ldap/clients/tools/ldapmodify.c,v 1.186.2.12 2009/08/13 00:55:07 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 2006 Howard Chu. 9 * Portions Copyright 1998-2003 Kurt D. Zeilenga. 10 * Portions Copyright 1998-2001 Net Boolean Incorporated. 11 * Portions Copyright 2001-2003 IBM Corporation. 12 * All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted only as authorized by the OpenLDAP 16 * Public License. 17 * 18 * A copy of this license is available in the file LICENSE in the 19 * top-level directory of the distribution or, alternatively, at 20 * <http://www.OpenLDAP.org/license.html>. 21 */ 22 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan. 23 * All rights reserved. 24 * 25 * Redistribution and use in source and binary forms are permitted 26 * provided that this notice is preserved and that due credit is given 27 * to the University of Michigan at Ann Arbor. The name of the 28 * University may not be used to endorse or promote products derived 29 * from this software without specific prior written permission. This 30 * software is provided ``as is'' without express or implied warranty. 31 */ 32 /* ACKNOWLEDGEMENTS: 33 * This work was originally developed by the University of Michigan 34 * (as part of U-MICH LDAP). Additional significant contributors 35 * include: 36 * Kurt D. Zeilenga 37 * Norbert Klasen 38 * Howard Chu 39 */ 40 41 #include "portable.h" 42 43 #include <stdio.h> 44 45 #include <ac/stdlib.h> 46 #include <ac/ctype.h> 47 #include <ac/string.h> 48 #include <ac/unistd.h> 49 #include <ac/socket.h> 50 #include <ac/time.h> 51 52 #ifdef HAVE_SYS_STAT_H 53 #include <sys/stat.h> 54 #endif 55 56 #ifdef HAVE_SYS_FILE_H 57 #include <sys/file.h> 58 #endif 59 #ifdef HAVE_FCNTL_H 60 #include <fcntl.h> 61 #endif 62 63 #include <ldap.h> 64 65 #include "lutil.h" 66 #include "lutil_ldap.h" 67 #include "ldif.h" 68 #include "ldap_defaults.h" 69 #include "ldap_log.h" 70 #include "ldap_pvt.h" 71 #include "lber_pvt.h" 72 73 #include "common.h" 74 75 static int ldapadd; 76 static char *rejfile = NULL; 77 static LDAP *ld = NULL; 78 79 #define M_SEP 0x7f 80 81 /* strings found in LDIF entries */ 82 static struct berval BV_VERSION = BER_BVC("version"); 83 static struct berval BV_DN = BER_BVC("dn"); 84 static struct berval BV_CONTROL = BER_BVC("control"); 85 static struct berval BV_CHANGETYPE = BER_BVC("changetype"); 86 static struct berval BV_ADDCT = BER_BVC("add"); 87 static struct berval BV_MODIFYCT = BER_BVC("modify"); 88 static struct berval BV_DELETECT = BER_BVC("delete"); 89 static struct berval BV_MODRDNCT = BER_BVC("modrdn"); 90 static struct berval BV_MODDNCT = BER_BVC("moddn"); 91 static struct berval BV_RENAMECT = BER_BVC("rename"); 92 static struct berval BV_MODOPADD = BER_BVC("add"); 93 static struct berval BV_MODOPREPLACE = BER_BVC("replace"); 94 static struct berval BV_MODOPDELETE = BER_BVC("delete"); 95 static struct berval BV_MODOPINCREMENT = BER_BVC("increment"); 96 static struct berval BV_NEWRDN = BER_BVC("newrdn"); 97 static struct berval BV_DELETEOLDRDN = BER_BVC("deleteoldrdn"); 98 static struct berval BV_NEWSUP = BER_BVC("newsuperior"); 99 100 #define BV_CASEMATCH(a, b) \ 101 ((a)->bv_len == (b)->bv_len && 0 == strcasecmp((a)->bv_val, (b)->bv_val)) 102 103 static int process_ldif_rec LDAP_P(( char *rbuf, int lineno )); 104 static int parse_ldif_control LDAP_P(( struct berval *val, LDAPControl ***pctrls )); 105 static int domodify LDAP_P(( 106 const char *dn, 107 LDAPMod **pmods, 108 LDAPControl **pctrls, 109 int newentry )); 110 static int dodelete LDAP_P(( 111 const char *dn, 112 LDAPControl **pctrls )); 113 static int dorename LDAP_P(( 114 const char *dn, 115 const char *newrdn, 116 const char *newsup, 117 int deleteoldrdn, 118 LDAPControl **pctrls )); 119 static int process_response( 120 LDAP *ld, 121 int msgid, 122 int res, 123 const char *dn ); 124 125 #ifdef LDAP_X_TXN 126 static int txn = 0; 127 static int txnabort = 0; 128 struct berval *txn_id = NULL; 129 #endif 130 131 void 132 usage( void ) 133 { 134 fprintf( stderr, _("Add or modify entries from an LDAP server\n\n")); 135 fprintf( stderr, _("usage: %s [options]\n"), prog); 136 fprintf( stderr, _(" The list of desired operations are read from stdin" 137 " or from the file\n")); 138 fprintf( stderr, _(" specified by \"-f file\".\n")); 139 fprintf( stderr, _("Add or modify options:\n")); 140 fprintf( stderr, _(" -a add values (%s)\n"), 141 (ldapadd ? _("default") : _("default is to replace"))); 142 fprintf( stderr, _(" -c continuous operation mode (do not stop on errors)\n")); 143 fprintf( stderr, _(" -E [!]ext=extparam modify extensions" 144 " (! indicate s criticality)\n")); 145 fprintf( stderr, _(" -f file read operations from `file'\n")); 146 fprintf( stderr, _(" -M enable Manage DSA IT control (-MM to make critical)\n")); 147 fprintf( stderr, _(" -P version protocol version (default: 3)\n")); 148 #ifdef LDAP_X_TXN 149 fprintf( stderr, 150 _(" [!]txn=<commit|abort> (transaction)\n")); 151 #endif 152 fprintf( stderr, _(" -S file write skipped modifications to `file'\n")); 153 154 tool_common_usage(); 155 exit( EXIT_FAILURE ); 156 } 157 158 159 const char options[] = "aE:rS:" 160 "cd:D:e:f:h:H:IMnNO:o:p:P:QR:U:vVw:WxX:y:Y:Z"; 161 162 int 163 handle_private_option( int i ) 164 { 165 char *control, *cvalue; 166 int crit; 167 168 switch ( i ) { 169 case 'E': /* modify extensions */ 170 if( protocol == LDAP_VERSION2 ) { 171 fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"), 172 prog, protocol ); 173 exit( EXIT_FAILURE ); 174 } 175 176 /* should be extended to support comma separated list of 177 * [!]key[=value] parameters, e.g. -E !foo,bar=567 178 */ 179 180 crit = 0; 181 cvalue = NULL; 182 if( optarg[0] == '!' ) { 183 crit = 1; 184 optarg++; 185 } 186 187 control = ber_strdup( optarg ); 188 if ( (cvalue = strchr( control, '=' )) != NULL ) { 189 *cvalue++ = '\0'; 190 } 191 192 #ifdef LDAP_X_TXN 193 if( strcasecmp( control, "txn" ) == 0 ) { 194 /* Transaction */ 195 if( txn ) { 196 fprintf( stderr, 197 _("txn control previously specified\n")); 198 exit( EXIT_FAILURE ); 199 } 200 if( cvalue != NULL ) { 201 if( strcasecmp( cvalue, "abort" ) == 0 ) { 202 txnabort=1; 203 } else if( strcasecmp( cvalue, "commit" ) != 0 ) { 204 fprintf( stderr, _("Invalid value for txn control, %s\n"), 205 cvalue ); 206 exit( EXIT_FAILURE ); 207 } 208 } 209 210 txn = 1 + crit; 211 } else 212 #endif 213 { 214 fprintf( stderr, _("Invalid modify extension name: %s\n"), 215 control ); 216 usage(); 217 } 218 break; 219 220 case 'a': /* add */ 221 ldapadd = 1; 222 break; 223 224 case 'r': /* replace (obsolete) */ 225 break; 226 227 case 'S': /* skipped modifications to file */ 228 if( rejfile != NULL ) { 229 fprintf( stderr, _("%s: -S previously specified\n"), prog ); 230 exit( EXIT_FAILURE ); 231 } 232 rejfile = ber_strdup( optarg ); 233 break; 234 235 default: 236 return 0; 237 } 238 return 1; 239 } 240 241 242 int 243 main( int argc, char **argv ) 244 { 245 char *rbuf = NULL, *rejbuf = NULL; 246 FILE *rejfp; 247 struct LDIFFP *ldiffp, ldifdummy = {0}; 248 char *matched_msg, *error_msg; 249 int rc, retval, ldifrc; 250 int len; 251 int i = 0; 252 int lineno, nextline = 0, lmax = 0; 253 LDAPControl c[1]; 254 255 prog = lutil_progname( "ldapmodify", argc, argv ); 256 257 /* strncmp instead of strcmp since NT binaries carry .exe extension */ 258 ldapadd = ( strncasecmp( prog, "ldapadd", sizeof("ldapadd")-1 ) == 0 ); 259 260 tool_init( ldapadd ? TOOL_ADD : TOOL_MODIFY ); 261 262 tool_args( argc, argv ); 263 264 if ( argc != optind ) usage(); 265 266 if ( rejfile != NULL ) { 267 if (( rejfp = fopen( rejfile, "w" )) == NULL ) { 268 perror( rejfile ); 269 return( EXIT_FAILURE ); 270 } 271 } else { 272 rejfp = NULL; 273 } 274 275 if ( infile != NULL ) { 276 if (( ldiffp = ldif_open( infile, "r" )) == NULL ) { 277 perror( infile ); 278 return( EXIT_FAILURE ); 279 } 280 } else { 281 ldifdummy.fp = stdin; 282 ldiffp = &ldifdummy; 283 } 284 285 if ( debug ) ldif_debug = debug; 286 287 ld = tool_conn_setup( dont, 0 ); 288 289 if ( !dont ) { 290 if ( pw_file || want_bindpw ) { 291 if ( pw_file ) { 292 rc = lutil_get_filed_password( pw_file, &passwd ); 293 if( rc ) return EXIT_FAILURE; 294 } else { 295 passwd.bv_val = getpassphrase( _("Enter LDAP Password: ") ); 296 passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0; 297 } 298 } 299 tool_bind( ld ); 300 } 301 302 #ifdef LDAP_X_TXN 303 if( txn ) { 304 /* start transaction */ 305 rc = ldap_txn_start_s( ld, NULL, NULL, &txn_id ); 306 if( rc != LDAP_SUCCESS ) { 307 tool_perror( "ldap_txn_start_s", rc, NULL, NULL, NULL, NULL ); 308 if( txn > 1 ) return EXIT_FAILURE; 309 txn = 0; 310 } 311 } 312 #endif 313 314 if ( 0 315 #ifdef LDAP_X_TXN 316 || txn 317 #endif 318 ) 319 { 320 #ifdef LDAP_X_TXN 321 if( txn ) { 322 c[i].ldctl_oid = LDAP_CONTROL_X_TXN_SPEC; 323 c[i].ldctl_value = *txn_id; 324 c[i].ldctl_iscritical = 1; 325 i++; 326 } 327 #endif 328 } 329 330 tool_server_controls( ld, c, i ); 331 332 rc = 0; 333 retval = 0; 334 lineno = 1; 335 while (( rc == 0 || contoper ) && ( ldifrc = ldif_read_record( ldiffp, &nextline, 336 &rbuf, &lmax )) > 0 ) 337 { 338 if ( rejfp ) { 339 len = strlen( rbuf ); 340 if (( rejbuf = (char *)ber_memalloc( len+1 )) == NULL ) { 341 perror( "malloc" ); 342 exit( EXIT_FAILURE ); 343 } 344 memcpy( rejbuf, rbuf, len+1 ); 345 } 346 347 rc = process_ldif_rec( rbuf, lineno ); 348 lineno = nextline+1; 349 350 if ( rc ) retval = rc; 351 if ( rc && rejfp ) { 352 fprintf(rejfp, _("# Error: %s (%d)"), ldap_err2string(rc), rc); 353 354 matched_msg = NULL; 355 ldap_get_option(ld, LDAP_OPT_MATCHED_DN, &matched_msg); 356 if ( matched_msg != NULL ) { 357 if ( *matched_msg != '\0' ) { 358 fprintf( rejfp, _(", matched DN: %s"), matched_msg ); 359 } 360 ldap_memfree( matched_msg ); 361 } 362 363 error_msg = NULL; 364 ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &error_msg); 365 if ( error_msg != NULL ) { 366 if ( *error_msg != '\0' ) { 367 fprintf( rejfp, _(", additional info: %s"), error_msg ); 368 } 369 ldap_memfree( error_msg ); 370 } 371 fprintf( rejfp, "\n%s\n", rejbuf ); 372 } 373 374 if (rejfp) ber_memfree( rejbuf ); 375 } 376 ber_memfree( rbuf ); 377 378 if ( ldifrc < 0 ) 379 retval = LDAP_OTHER; 380 381 #ifdef LDAP_X_TXN 382 if( retval == 0 && txn ) { 383 rc = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, NULL ); 384 if ( rc != LDAP_OPT_SUCCESS ) { 385 fprintf( stderr, "Could not unset controls for ldap_txn_end\n"); 386 } 387 388 /* create transaction */ 389 rc = ldap_txn_end_s( ld, !txnabort, txn_id, NULL, NULL, NULL ); 390 if( rc != LDAP_SUCCESS ) { 391 tool_perror( "ldap_txn_end_s", rc, NULL, NULL, NULL, NULL ); 392 retval = rc; 393 } 394 } 395 #endif 396 397 if ( !dont ) { 398 tool_unbind( ld ); 399 } 400 401 if ( rejfp != NULL ) { 402 fclose( rejfp ); 403 } 404 405 tool_destroy(); 406 return( retval ); 407 } 408 409 410 static int 411 process_ldif_rec( char *rbuf, int linenum ) 412 { 413 char *line, *dn, *newrdn, *newsup; 414 int rc, modop; 415 int expect_modop, expect_sep; 416 int deleteoldrdn; 417 int new_entry, delete_entry, got_all; 418 LDAPMod **pmods, *lm = NULL; 419 int version; 420 LDAPControl **pctrls; 421 int i, j, k, lines, idn, nmods; 422 struct berval *btype, *vals, **bvl, bv; 423 char *freeval; 424 unsigned char *mops = NULL; 425 426 new_entry = ldapadd; 427 428 rc = got_all = delete_entry = modop = expect_modop = 0; 429 expect_sep = 0; 430 version = 0; 431 deleteoldrdn = 1; 432 pmods = NULL; 433 pctrls = NULL; 434 dn = newrdn = newsup = NULL; 435 436 lines = ldif_countlines( rbuf ); 437 btype = ber_memcalloc( 1, (lines+1)*2*sizeof(struct berval)+lines ); 438 if ( !btype ) 439 return LDAP_NO_MEMORY; 440 441 vals = btype+lines+1; 442 freeval = (char *)(vals+lines+1); 443 i = -1; 444 445 while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) { 446 int freev; 447 448 if ( *line == '\n' || *line == '\0' ) { 449 break; 450 } 451 452 ++i; 453 454 if ( line[0] == '-' && !line[1] ) { 455 BER_BVZERO( btype+i ); 456 freeval[i] = 0; 457 continue; 458 } 459 460 if ( ( rc = ldif_parse_line2( line, btype+i, vals+i, &freev ) ) < 0 ) { 461 fprintf( stderr, _("%s: invalid format (line %d) entry: \"%s\"\n"), 462 prog, linenum+i, dn == NULL ? "" : dn ); 463 rc = LDAP_PARAM_ERROR; 464 break; 465 } 466 freeval[i] = freev; 467 468 if ( dn == NULL ) { 469 if ( linenum+i == 1 && BV_CASEMATCH( btype+i, &BV_VERSION )) { 470 int v; 471 if( vals[i].bv_len == 0 || lutil_atoi( &v, vals[i].bv_val) != 0 || v != 1 ) { 472 fprintf( stderr, 473 _("%s: invalid version %s, line %d (ignored)\n"), 474 prog, vals[i].bv_val, linenum ); 475 } 476 version++; 477 478 } else if ( BV_CASEMATCH( btype+i, &BV_DN )) { 479 dn = vals[i].bv_val; 480 idn = i; 481 } 482 /* skip all lines until we see "dn:" */ 483 } 484 } 485 486 /* check to make sure there was a dn: line */ 487 if ( !dn ) { 488 rc = 0; 489 goto leave; 490 } 491 492 lines = i+1; 493 494 if( lines == 0 ) { 495 rc = 0; 496 goto leave; 497 } 498 499 if( version && lines == 1 ) { 500 rc = 0; 501 goto leave; 502 } 503 504 i = idn+1; 505 /* Check for "control" tag after dn and before changetype. */ 506 if ( BV_CASEMATCH( btype+i, &BV_CONTROL )) { 507 /* Parse and add it to the list of controls */ 508 rc = parse_ldif_control( vals+i, &pctrls ); 509 if (rc != 0) { 510 fprintf( stderr, 511 _("%s: Error processing %s line, line %d: %s\n"), 512 prog, BV_CONTROL.bv_val, linenum+i, ldap_err2string(rc) ); 513 } 514 i++; 515 if ( i>= lines ) { 516 short_input: 517 fprintf( stderr, 518 _("%s: Expecting more input after %s line, line %d\n"), 519 prog, btype[i-1].bv_val, linenum+i ); 520 521 rc = LDAP_PARAM_ERROR; 522 goto leave; 523 } 524 } 525 526 /* Check for changetype */ 527 if ( BV_CASEMATCH( btype+i, &BV_CHANGETYPE )) { 528 #ifdef LIBERAL_CHANGETYPE_MODOP 529 /* trim trailing spaces (and log warning ...) */ 530 int icnt; 531 for ( icnt = vals[i].bv_len; --icnt > 0; ) { 532 if ( !isspace( (unsigned char) vals[i].bv_val[icnt] ) ) { 533 break; 534 } 535 } 536 537 if ( ++icnt != vals[i].bv_len ) { 538 fprintf( stderr, _("%s: illegal trailing space after" 539 " \"%s: %s\" trimmed (line %d, entry \"%s\")\n"), 540 prog, BV_CHANGETYPE.bv_val, vals[i].bv_val, linenum+i, dn ); 541 vals[i].bv_val[icnt] = '\0'; 542 } 543 #endif /* LIBERAL_CHANGETYPE_MODOP */ 544 545 if ( BV_CASEMATCH( vals+i, &BV_MODIFYCT )) { 546 new_entry = 0; 547 expect_modop = 1; 548 } else if ( BV_CASEMATCH( vals+i, &BV_ADDCT )) { 549 new_entry = 1; 550 modop = LDAP_MOD_ADD; 551 } else if ( BV_CASEMATCH( vals+i, &BV_MODRDNCT ) 552 || BV_CASEMATCH( vals+i, &BV_MODDNCT ) 553 || BV_CASEMATCH( vals+i, &BV_RENAMECT )) 554 { 555 i++; 556 if ( i >= lines ) 557 goto short_input; 558 if ( !BV_CASEMATCH( btype+i, &BV_NEWRDN )) { 559 fprintf( stderr, _("%s: expecting \"%s:\" but saw" 560 " \"%s:\" (line %d, entry \"%s\")\n"), 561 prog, BV_NEWRDN.bv_val, btype[i].bv_val, linenum+i, dn ); 562 rc = LDAP_PARAM_ERROR; 563 goto leave; 564 } 565 newrdn = vals[i].bv_val; 566 i++; 567 if ( i >= lines ) 568 goto short_input; 569 if ( !BV_CASEMATCH( btype+i, &BV_DELETEOLDRDN )) { 570 fprintf( stderr, _("%s: expecting \"%s:\" but saw" 571 " \"%s:\" (line %d, entry \"%s\")\n"), 572 prog, BV_DELETEOLDRDN.bv_val, btype[i].bv_val, linenum+i, dn ); 573 rc = LDAP_PARAM_ERROR; 574 goto leave; 575 } 576 deleteoldrdn = ( vals[i].bv_val[0] == '0' ) ? 0 : 1; 577 i++; 578 if ( i < lines ) { 579 if ( !BV_CASEMATCH( btype+i, &BV_NEWSUP )) { 580 fprintf( stderr, _("%s: expecting \"%s:\" but saw" 581 " \"%s:\" (line %d, entry \"%s\")\n"), 582 prog, BV_NEWSUP.bv_val, btype[i].bv_val, linenum+i, dn ); 583 rc = LDAP_PARAM_ERROR; 584 goto leave; 585 } 586 newsup = vals[i].bv_val; 587 i++; 588 } 589 got_all = 1; 590 } else if ( BV_CASEMATCH( vals+i, &BV_DELETECT )) { 591 got_all = delete_entry = 1; 592 } else { 593 fprintf( stderr, 594 _("%s: unknown %s \"%s\" (line %d, entry \"%s\")\n"), 595 prog, BV_CHANGETYPE.bv_val, vals[i].bv_val, linenum+i, dn ); 596 rc = LDAP_PARAM_ERROR; 597 goto leave; 598 } 599 i++; 600 } else if ( ldapadd ) { /* missing changetype => add */ 601 new_entry = 1; 602 modop = LDAP_MOD_ADD; 603 } else { 604 expect_modop = 1; /* missing changetype => modify */ 605 } 606 607 if ( got_all ) { 608 if ( i < lines ) { 609 fprintf( stderr, 610 _("%s: extra lines at end (line %d, entry \"%s\")\n"), 611 prog, linenum+i, dn ); 612 rc = LDAP_PARAM_ERROR; 613 goto leave; 614 } 615 goto doit; 616 } 617 618 nmods = lines - i; 619 idn = i; 620 621 if ( new_entry ) { 622 int fv; 623 624 /* Make sure all attributes with multiple values are contiguous */ 625 for (; i<lines; i++) { 626 for (j=i+1; j<lines; j++) { 627 if ( BV_CASEMATCH( btype+i, btype+j )) { 628 nmods--; 629 /* out of order, move intervening attributes down */ 630 if ( j != i+1 ) { 631 bv = vals[j]; 632 fv = freeval[j]; 633 for (k=j; k>i; k--) { 634 btype[k] = btype[k-1]; 635 vals[k] = vals[k-1]; 636 freeval[k] = freeval[k-1]; 637 } 638 k++; 639 btype[k] = btype[i]; 640 vals[k] = bv; 641 freeval[k] = fv; 642 } 643 i++; 644 } 645 } 646 } 647 /* Allocate space for array of mods, array of pointers to mods, 648 * and array of pointers to values, allowing for NULL terminators 649 * for the pointer arrays... 650 */ 651 lm = ber_memalloc( nmods * sizeof(LDAPMod) + 652 (nmods+1) * sizeof(LDAPMod*) + 653 (lines + nmods - idn) * sizeof(struct berval *)); 654 pmods = (LDAPMod **)(lm+nmods); 655 bvl = (struct berval **)(pmods+nmods+1); 656 657 j = 0; 658 k = -1; 659 BER_BVZERO(&bv); 660 for (i=idn; i<lines; i++) { 661 if ( BV_CASEMATCH( btype+i, &BV_DN )) { 662 fprintf( stderr, _("%s: attributeDescription \"%s\":" 663 " (possible missing newline" 664 " after line %d, entry \"%s\"?)\n"), 665 prog, btype[i].bv_val, linenum+i - 1, dn ); 666 } 667 if ( !BV_CASEMATCH( btype+i, &bv )) { 668 bvl[k++] = NULL; 669 bv = btype[i]; 670 lm[j].mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES; 671 lm[j].mod_type = bv.bv_val; 672 lm[j].mod_bvalues = bvl+k; 673 pmods[j] = lm+j; 674 j++; 675 } 676 bvl[k++] = vals+i; 677 } 678 bvl[k] = NULL; 679 pmods[j] = NULL; 680 goto doit; 681 } 682 683 mops = ber_memalloc( lines+1 ); 684 mops[lines] = M_SEP; 685 mops[i-1] = M_SEP; 686 687 for ( ; i<lines; i++ ) { 688 if ( expect_modop ) { 689 #ifdef LIBERAL_CHANGETYPE_MODOP 690 /* trim trailing spaces (and log warning ...) */ 691 int icnt; 692 for ( icnt = vals[i].bv_len; --icnt > 0; ) { 693 if ( !isspace( (unsigned char) vals[i].bv_val[icnt] ) ) break; 694 } 695 696 if ( ++icnt != vals[i].bv_len ) { 697 fprintf( stderr, _("%s: illegal trailing space after" 698 " \"%s: %s\" trimmed (line %d, entry \"%s\")\n"), 699 prog, type, vals[i].bv_val, linenum+i, dn ); 700 vals[i].bv_val[icnt] = '\0'; 701 } 702 #endif /* LIBERAL_CHANGETYPE_MODOP */ 703 704 expect_modop = 0; 705 expect_sep = 1; 706 if ( BV_CASEMATCH( btype+i, &BV_MODOPADD )) { 707 modop = LDAP_MOD_ADD; 708 mops[i] = M_SEP; 709 nmods--; 710 } else if ( BV_CASEMATCH( btype+i, &BV_MODOPREPLACE )) { 711 /* defer handling these since they might have no values. 712 * Use the BVALUES flag to signal that these were 713 * deferred. If values are provided later, this 714 * flag will be switched off. 715 */ 716 modop = LDAP_MOD_REPLACE; 717 mops[i] = modop | LDAP_MOD_BVALUES; 718 btype[i] = vals[i]; 719 } else if ( BV_CASEMATCH( btype+i, &BV_MODOPDELETE )) { 720 modop = LDAP_MOD_DELETE; 721 mops[i] = modop | LDAP_MOD_BVALUES; 722 btype[i] = vals[i]; 723 } else if ( BV_CASEMATCH( btype+i, &BV_MODOPINCREMENT )) { 724 modop = LDAP_MOD_INCREMENT; 725 mops[i] = M_SEP; 726 nmods--; 727 } else { /* no modify op: invalid LDIF */ 728 fprintf( stderr, _("%s: modify operation type is missing at" 729 " line %d, entry \"%s\"\n"), 730 prog, linenum+i, dn ); 731 rc = LDAP_PARAM_ERROR; 732 goto leave; 733 } 734 bv = vals[i]; 735 } else if ( expect_sep && BER_BVISEMPTY( btype+i )) { 736 mops[i] = M_SEP; 737 expect_sep = 0; 738 expect_modop = 1; 739 nmods--; 740 } else { 741 if ( !BV_CASEMATCH( btype+i, &bv )) { 742 fprintf( stderr, _("%s: wrong attributeType at" 743 " line %d, entry \"%s\"\n"), 744 prog, linenum+i, dn ); 745 rc = LDAP_PARAM_ERROR; 746 goto leave; 747 } 748 mops[i] = modop; 749 /* If prev op was deferred and matches this type, 750 * clear the flag 751 */ 752 if ( (mops[i-1] & LDAP_MOD_BVALUES) 753 && BV_CASEMATCH( btype+i, btype+i-1 )) 754 { 755 mops[i-1] = M_SEP; 756 nmods--; 757 } 758 } 759 } 760 761 #if 0 /* we should faithfully encode the LDIF, not combine */ 762 /* Make sure all modops with multiple values are contiguous */ 763 for (i=idn; i<lines; i++) { 764 if ( mops[i] == M_SEP ) 765 continue; 766 for (j=i+1; j<lines; j++) { 767 if ( mops[j] == M_SEP || mops[i] != mops[j] ) 768 continue; 769 if ( BV_CASEMATCH( btype+i, btype+j )) { 770 nmods--; 771 /* out of order, move intervening attributes down */ 772 if ( j != i+1 ) { 773 int c; 774 struct berval bv; 775 char fv; 776 777 c = mops[j]; 778 bv = vals[j]; 779 fv = freeval[j]; 780 for (k=j; k>i; k--) { 781 btype[k] = btype[k-1]; 782 vals[k] = vals[k-1]; 783 freeval[k] = freeval[k-1]; 784 mops[k] = mops[k-1]; 785 } 786 k++; 787 btype[k] = btype[i]; 788 vals[k] = bv; 789 freeval[k] = fv; 790 mops[k] = c; 791 } 792 i++; 793 } 794 } 795 } 796 #endif 797 798 /* Allocate space for array of mods, array of pointers to mods, 799 * and array of pointers to values, allowing for NULL terminators 800 * for the pointer arrays... 801 */ 802 lm = ber_memalloc( nmods * sizeof(LDAPMod) + 803 (nmods+1) * sizeof(LDAPMod*) + 804 (lines + nmods - idn) * sizeof(struct berval *)); 805 pmods = (LDAPMod **)(lm+nmods); 806 bvl = (struct berval **)(pmods+nmods+1); 807 808 j = 0; 809 k = -1; 810 BER_BVZERO(&bv); 811 mops[idn-1] = M_SEP; 812 for (i=idn; i<lines; i++) { 813 if ( mops[i] == M_SEP ) 814 continue; 815 if ( mops[i] != mops[i-1] || !BV_CASEMATCH( btype+i, &bv )) { 816 bvl[k++] = NULL; 817 bv = btype[i]; 818 lm[j].mod_op = mops[i] | LDAP_MOD_BVALUES; 819 lm[j].mod_type = bv.bv_val; 820 if ( mops[i] & LDAP_MOD_BVALUES ) { 821 lm[j].mod_bvalues = NULL; 822 } else { 823 lm[j].mod_bvalues = bvl+k; 824 } 825 pmods[j] = lm+j; 826 j++; 827 } 828 bvl[k++] = vals+i; 829 } 830 bvl[k] = NULL; 831 pmods[j] = NULL; 832 833 doit: 834 /* If default controls are set (as with -M option) and controls are 835 specified in the LDIF file, we must add the default controls to 836 the list of controls sent with the ldap operation. 837 */ 838 if ( rc == 0 ) { 839 if (pctrls) { 840 LDAPControl **defctrls = NULL; /* Default server controls */ 841 LDAPControl **newctrls = NULL; 842 ldap_get_option(ld, LDAP_OPT_SERVER_CONTROLS, &defctrls); 843 if (defctrls) { 844 int npc=0; /* Num of LDIF controls */ 845 int ndefc=0; /* Num of default controls */ 846 while (pctrls[npc]) npc++; /* Count LDIF controls */ 847 while (defctrls[ndefc]) ndefc++; /* Count default controls */ 848 newctrls = ber_memrealloc(pctrls, 849 (npc+ndefc+1)*sizeof(LDAPControl*)); 850 851 if (newctrls == NULL) { 852 rc = LDAP_NO_MEMORY; 853 } else { 854 int i; 855 pctrls = newctrls; 856 for (i=npc; i<npc+ndefc; i++) { 857 pctrls[i] = ldap_control_dup(defctrls[i-npc]); 858 if (pctrls[i] == NULL) { 859 rc = LDAP_NO_MEMORY; 860 break; 861 } 862 } 863 pctrls[npc+ndefc] = NULL; 864 } 865 ldap_controls_free(defctrls); /* Must be freed by library */ 866 } 867 } 868 } 869 870 if ( rc == 0 ) { 871 if ( delete_entry ) { 872 rc = dodelete( dn, pctrls ); 873 } else if ( newrdn != NULL ) { 874 rc = dorename( dn, newrdn, newsup, deleteoldrdn, pctrls ); 875 } else { 876 rc = domodify( dn, pmods, pctrls, new_entry ); 877 } 878 879 if ( rc == LDAP_SUCCESS ) { 880 rc = 0; 881 } 882 } 883 884 leave: 885 if (pctrls != NULL) { 886 ldap_controls_free( pctrls ); 887 } 888 if ( lm != NULL ) { 889 ber_memfree( lm ); 890 } 891 if ( mops != NULL ) { 892 ber_memfree( mops ); 893 } 894 for (i=lines-1; i>=0; i--) 895 if ( freeval[i] ) ber_memfree( vals[i].bv_val ); 896 ber_memfree( btype ); 897 898 return( rc ); 899 } 900 901 /* Parse an LDIF control line of the form 902 control: oid [true/false] [: value] or 903 control: oid [true/false] [:: base64-value] or 904 control: oid [true/false] [:< url] 905 The control is added to the list of controls in *ppctrls. 906 */ 907 static int 908 parse_ldif_control( 909 struct berval *bval, 910 LDAPControl ***ppctrls ) 911 { 912 char *oid = NULL; 913 int criticality = 0; /* Default is false if not present */ 914 int i, rc=0; 915 char *s, *oidStart; 916 LDAPControl *newctrl = NULL; 917 LDAPControl **pctrls = NULL; 918 struct berval type, bv; 919 int freeval; 920 921 if (ppctrls) pctrls = *ppctrls; 922 /* OID should come first. Validate and extract it. */ 923 s = bval->bv_val; 924 if (*s == 0) return ( LDAP_PARAM_ERROR ); 925 oidStart = s; 926 while (isdigit((unsigned char)*s) || *s == '.') { 927 s++; /* OID should be digits or . */ 928 } 929 if (s == oidStart) { 930 return ( LDAP_PARAM_ERROR ); /* OID was not present */ 931 } 932 if (*s) { /* End of OID should be space or NULL */ 933 if (!isspace((unsigned char)*s)) { 934 return ( LDAP_PARAM_ERROR ); /* else OID contained invalid chars */ 935 } 936 *s++ = 0; /* Replace space with null to terminate */ 937 } 938 939 oid = ber_strdup(oidStart); 940 if (oid == NULL) return ( LDAP_NO_MEMORY ); 941 942 /* Optional Criticality field is next. */ 943 while (*s && isspace((unsigned char)*s)) { 944 s++; /* Skip white space before criticality */ 945 } 946 if (strncasecmp(s, "true", 4) == 0) { 947 criticality = 1; 948 s += 4; 949 } 950 else if (strncasecmp(s, "false", 5) == 0) { 951 criticality = 0; 952 s += 5; 953 } 954 955 /* Optional value field is next */ 956 while (*s && isspace((unsigned char)*s)) { 957 s++; /* Skip white space before value */ 958 } 959 if (*s) { 960 if (*s != ':') { /* If value is present, must start with : */ 961 rc = LDAP_PARAM_ERROR; 962 goto cleanup; 963 } 964 965 /* Back up so value is in the form 966 a: value 967 a:: base64-value 968 a:< url 969 Then we can use ldif_parse_line2 to extract and decode the value 970 */ 971 s--; 972 *s = 'a'; 973 974 rc = ldif_parse_line2(s, &type, &bv, &freeval); 975 if (rc < 0) { 976 rc = LDAP_PARAM_ERROR; 977 goto cleanup; 978 } 979 } 980 981 /* Create a new LDAPControl structure. */ 982 newctrl = (LDAPControl *)ber_memalloc(sizeof(LDAPControl)); 983 if ( newctrl == NULL ) { 984 rc = LDAP_NO_MEMORY; 985 goto cleanup; 986 } 987 newctrl->ldctl_oid = oid; 988 oid = NULL; 989 newctrl->ldctl_iscritical = criticality; 990 if ( freeval ) 991 newctrl->ldctl_value = bv; 992 else 993 ber_dupbv( &newctrl->ldctl_value, &bv ); 994 995 /* Add the new control to the passed-in list of controls. */ 996 i = 0; 997 if (pctrls) { 998 while ( pctrls[i] ) { /* Count the # of controls passed in */ 999 i++; 1000 } 1001 } 1002 /* Allocate 1 more slot for the new control and 1 for the NULL. */ 1003 pctrls = (LDAPControl **) ber_memrealloc(pctrls, 1004 (i+2)*(sizeof(LDAPControl *))); 1005 if (pctrls == NULL) { 1006 rc = LDAP_NO_MEMORY; 1007 goto cleanup; 1008 } 1009 pctrls[i] = newctrl; 1010 newctrl = NULL; 1011 pctrls[i+1] = NULL; 1012 *ppctrls = pctrls; 1013 1014 cleanup: 1015 if (newctrl) { 1016 if (newctrl->ldctl_oid) ber_memfree(newctrl->ldctl_oid); 1017 if (newctrl->ldctl_value.bv_val) { 1018 ber_memfree(newctrl->ldctl_value.bv_val); 1019 } 1020 ber_memfree(newctrl); 1021 } 1022 if (oid) ber_memfree(oid); 1023 1024 return( rc ); 1025 } 1026 1027 1028 static int 1029 domodify( 1030 const char *dn, 1031 LDAPMod **pmods, 1032 LDAPControl **pctrls, 1033 int newentry ) 1034 { 1035 int rc, i, j, k, notascii, op; 1036 struct berval *bvp; 1037 1038 if ( dn == NULL ) { 1039 fprintf( stderr, _("%s: no DN specified\n"), prog ); 1040 return( LDAP_PARAM_ERROR ); 1041 } 1042 1043 if ( pmods == NULL ) { 1044 /* implement "touch" (empty sequence) 1045 * modify operation (note that there 1046 * is no symmetry with the UNIX command, 1047 * since \"touch\" on a non-existent entry 1048 * will fail)*/ 1049 printf( "warning: no attributes to %sadd (entry=\"%s\")\n", 1050 newentry ? "" : "change or ", dn ); 1051 1052 } else { 1053 for ( i = 0; pmods[ i ] != NULL; ++i ) { 1054 op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES; 1055 if( op == LDAP_MOD_ADD && ( pmods[i]->mod_bvalues == NULL )) { 1056 fprintf( stderr, 1057 _("%s: attribute \"%s\" has no values (entry=\"%s\")\n"), 1058 prog, pmods[i]->mod_type, dn ); 1059 return LDAP_PARAM_ERROR; 1060 } 1061 } 1062 1063 if ( verbose ) { 1064 for ( i = 0; pmods[ i ] != NULL; ++i ) { 1065 op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES; 1066 printf( "%s %s:\n", 1067 op == LDAP_MOD_REPLACE ? _("replace") : 1068 op == LDAP_MOD_ADD ? _("add") : 1069 op == LDAP_MOD_INCREMENT ? _("increment") : 1070 op == LDAP_MOD_DELETE ? _("delete") : 1071 _("unknown"), 1072 pmods[ i ]->mod_type ); 1073 1074 if ( pmods[ i ]->mod_bvalues != NULL ) { 1075 for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) { 1076 bvp = pmods[ i ]->mod_bvalues[ j ]; 1077 notascii = 0; 1078 for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) { 1079 if ( !isascii( bvp->bv_val[ k ] )) { 1080 notascii = 1; 1081 break; 1082 } 1083 } 1084 if ( notascii ) { 1085 printf( _("\tNOT ASCII (%ld bytes)\n"), bvp->bv_len ); 1086 } else { 1087 printf( "\t%s\n", bvp->bv_val ); 1088 } 1089 } 1090 } 1091 } 1092 } 1093 } 1094 1095 if ( newentry ) { 1096 printf( "%sadding new entry \"%s\"\n", dont ? "!" : "", dn ); 1097 } else { 1098 printf( "%smodifying entry \"%s\"\n", dont ? "!" : "", dn ); 1099 } 1100 1101 if ( !dont ) { 1102 int msgid; 1103 if ( newentry ) { 1104 rc = ldap_add_ext( ld, dn, pmods, pctrls, NULL, &msgid ); 1105 } else { 1106 rc = ldap_modify_ext( ld, dn, pmods, pctrls, NULL, &msgid ); 1107 } 1108 1109 if ( rc != LDAP_SUCCESS ) { 1110 /* print error message about failed update including DN */ 1111 fprintf( stderr, _("%s: update failed: %s\n"), prog, dn ); 1112 tool_perror( newentry ? "ldap_add" : "ldap_modify", 1113 rc, NULL, NULL, NULL, NULL ); 1114 goto done; 1115 } 1116 rc = process_response( ld, msgid, 1117 newentry ? LDAP_RES_ADD : LDAP_RES_MODIFY, dn ); 1118 1119 if ( verbose && rc == LDAP_SUCCESS ) { 1120 printf( _("modify complete\n") ); 1121 } 1122 1123 } else { 1124 rc = LDAP_SUCCESS; 1125 } 1126 1127 done: 1128 putchar( '\n' ); 1129 return rc; 1130 } 1131 1132 1133 static int 1134 dodelete( 1135 const char *dn, 1136 LDAPControl **pctrls ) 1137 { 1138 int rc; 1139 int msgid; 1140 1141 printf( _("%sdeleting entry \"%s\"\n"), dont ? "!" : "", dn ); 1142 if ( !dont ) { 1143 rc = ldap_delete_ext( ld, dn, pctrls, NULL, &msgid ); 1144 if ( rc != LDAP_SUCCESS ) { 1145 fprintf( stderr, _("%s: delete failed: %s\n"), prog, dn ); 1146 tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL ); 1147 goto done; 1148 } 1149 rc = process_response( ld, msgid, LDAP_RES_DELETE, dn ); 1150 1151 if ( verbose && rc == LDAP_SUCCESS ) { 1152 printf( _("delete complete\n") ); 1153 } 1154 } else { 1155 rc = LDAP_SUCCESS; 1156 } 1157 1158 done: 1159 putchar( '\n' ); 1160 return( rc ); 1161 } 1162 1163 1164 static int 1165 dorename( 1166 const char *dn, 1167 const char *newrdn, 1168 const char* newsup, 1169 int deleteoldrdn, 1170 LDAPControl **pctrls ) 1171 { 1172 int rc; 1173 int msgid; 1174 1175 printf( _("%smodifying rdn of entry \"%s\"\n"), dont ? "!" : "", dn ); 1176 if ( verbose ) { 1177 printf( _("\tnew RDN: \"%s\" (%skeep existing values)\n"), 1178 newrdn, deleteoldrdn ? _("do not ") : "" ); 1179 } 1180 if ( !dont ) { 1181 rc = ldap_rename( ld, dn, newrdn, newsup, deleteoldrdn, 1182 pctrls, NULL, &msgid ); 1183 if ( rc != LDAP_SUCCESS ) { 1184 fprintf( stderr, _("%s: rename failed: %s\n"), prog, dn ); 1185 tool_perror( "ldap_rename", rc, NULL, NULL, NULL, NULL ); 1186 goto done; 1187 } 1188 rc = process_response( ld, msgid, LDAP_RES_RENAME, dn ); 1189 1190 if ( verbose && rc == LDAP_SUCCESS ) { 1191 printf( _("rename complete\n") ); 1192 } 1193 } else { 1194 rc = LDAP_SUCCESS; 1195 } 1196 1197 done: 1198 putchar( '\n' ); 1199 return( rc ); 1200 } 1201 1202 static const char * 1203 res2str( int res ) { 1204 switch ( res ) { 1205 case LDAP_RES_ADD: 1206 return "ldap_add"; 1207 case LDAP_RES_DELETE: 1208 return "ldap_delete"; 1209 case LDAP_RES_MODIFY: 1210 return "ldap_modify"; 1211 case LDAP_RES_MODRDN: 1212 return "ldap_rename"; 1213 default: 1214 assert( 0 ); 1215 } 1216 1217 return "ldap_unknown"; 1218 } 1219 1220 static int process_response( 1221 LDAP *ld, 1222 int msgid, 1223 int op, 1224 const char *dn ) 1225 { 1226 LDAPMessage *res; 1227 int rc = LDAP_OTHER, msgtype; 1228 struct timeval tv = { 0, 0 }; 1229 int err; 1230 char *text = NULL, *matched = NULL, **refs = NULL; 1231 LDAPControl **ctrls = NULL; 1232 1233 for ( ; ; ) { 1234 tv.tv_sec = 0; 1235 tv.tv_usec = 100000; 1236 1237 rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res ); 1238 if ( tool_check_abandon( ld, msgid ) ) { 1239 return LDAP_CANCELLED; 1240 } 1241 1242 if ( rc == -1 ) { 1243 ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc ); 1244 tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL ); 1245 return rc; 1246 } 1247 1248 if ( rc != 0 ) { 1249 break; 1250 } 1251 } 1252 1253 msgtype = ldap_msgtype( res ); 1254 1255 rc = ldap_parse_result( ld, res, &err, &matched, &text, &refs, &ctrls, 1 ); 1256 if ( rc == LDAP_SUCCESS ) rc = err; 1257 1258 #ifdef LDAP_X_TXN 1259 if ( rc == LDAP_X_TXN_SPECIFY_OKAY ) { 1260 rc = LDAP_SUCCESS; 1261 } else 1262 #endif 1263 if ( rc != LDAP_SUCCESS ) { 1264 tool_perror( res2str( op ), rc, NULL, matched, text, refs ); 1265 } else if ( msgtype != op ) { 1266 fprintf( stderr, "%s: msgtype: expected %d got %d\n", 1267 res2str( op ), op, msgtype ); 1268 rc = LDAP_OTHER; 1269 } 1270 1271 if ( text ) ldap_memfree( text ); 1272 if ( matched ) ldap_memfree( matched ); 1273 if ( text ) ber_memvfree( (void **)refs ); 1274 1275 if ( ctrls ) { 1276 tool_print_ctrls( ld, ctrls ); 1277 ldap_controls_free( ctrls ); 1278 } 1279 1280 return rc; 1281 } 1282