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