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