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