1 /* $NetBSD: ldapmodify.c,v 1.1.1.3 2010/12/12 15:18:12 adam Exp $ */ 2 3 /* ldapmodify.c - generic program to modify or add entries using LDAP */ 4 /* OpenLDAP: pkg/ldap/clients/tools/ldapmodify.c,v 1.186.2.14 2010/04/15 22:16:50 quanah Exp */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2010 The OpenLDAP Foundation. 8 * Portions Copyright 2006 Howard Chu. 9 * Portions Copyright 1998-2003 Kurt D. Zeilenga. 10 * Portions Copyright 1998-2001 Net Boolean Incorporated. 11 * Portions Copyright 2001-2003 IBM Corporation. 12 * All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted only as authorized by the OpenLDAP 16 * Public License. 17 * 18 * A copy of this license is available in the file LICENSE in the 19 * top-level directory of the distribution or, alternatively, at 20 * <http://www.OpenLDAP.org/license.html>. 21 */ 22 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan. 23 * All rights reserved. 24 * 25 * Redistribution and use in source and binary forms are permitted 26 * provided that this notice is preserved and that due credit is given 27 * to the University of Michigan at Ann Arbor. The name of the 28 * University may not be used to endorse or promote products derived 29 * from this software without specific prior written permission. This 30 * software is provided ``as is'' without express or implied warranty. 31 */ 32 /* ACKNOWLEDGEMENTS: 33 * This work was originally developed by the University of Michigan 34 * (as part of U-MICH LDAP). Additional significant contributors 35 * include: 36 * Kurt D. Zeilenga 37 * Norbert Klasen 38 * Howard Chu 39 */ 40 41 #include "portable.h" 42 43 #include <stdio.h> 44 45 #include <ac/stdlib.h> 46 #include <ac/ctype.h> 47 #include <ac/string.h> 48 #include <ac/unistd.h> 49 #include <ac/socket.h> 50 #include <ac/time.h> 51 52 #ifdef HAVE_SYS_STAT_H 53 #include <sys/stat.h> 54 #endif 55 56 #ifdef HAVE_SYS_FILE_H 57 #include <sys/file.h> 58 #endif 59 #ifdef HAVE_FCNTL_H 60 #include <fcntl.h> 61 #endif 62 63 #include <ldap.h> 64 65 #include "lutil.h" 66 #include "lutil_ldap.h" 67 #include "ldif.h" 68 #include "ldap_defaults.h" 69 #include "ldap_log.h" 70 #include "ldap_pvt.h" 71 #include "lber_pvt.h" 72 73 #include "common.h" 74 75 static int ldapadd; 76 static char *rejfile = NULL; 77 static LDAP *ld = NULL; 78 79 #define M_SEP 0x7f 80 81 /* strings found in LDIF entries */ 82 static struct berval BV_VERSION = BER_BVC("version"); 83 static struct berval BV_DN = BER_BVC("dn"); 84 static struct berval BV_CONTROL = BER_BVC("control"); 85 static struct berval BV_CHANGETYPE = BER_BVC("changetype"); 86 static struct berval BV_ADDCT = BER_BVC("add"); 87 static struct berval BV_MODIFYCT = BER_BVC("modify"); 88 static struct berval BV_DELETECT = BER_BVC("delete"); 89 static struct berval BV_MODRDNCT = BER_BVC("modrdn"); 90 static struct berval BV_MODDNCT = BER_BVC("moddn"); 91 static struct berval BV_RENAMECT = BER_BVC("rename"); 92 static struct berval BV_MODOPADD = BER_BVC("add"); 93 static struct berval BV_MODOPREPLACE = BER_BVC("replace"); 94 static struct berval BV_MODOPDELETE = BER_BVC("delete"); 95 static struct berval BV_MODOPINCREMENT = BER_BVC("increment"); 96 static struct berval BV_NEWRDN = BER_BVC("newrdn"); 97 static struct berval BV_DELETEOLDRDN = BER_BVC("deleteoldrdn"); 98 static struct berval BV_NEWSUP = BER_BVC("newsuperior"); 99 100 #define BV_CASEMATCH(a, b) \ 101 ((a)->bv_len == (b)->bv_len && 0 == strcasecmp((a)->bv_val, (b)->bv_val)) 102 103 static int process_ldif_rec LDAP_P(( char *rbuf, int lineno )); 104 static int parse_ldif_control LDAP_P(( struct berval *val, LDAPControl ***pctrls )); 105 static int domodify LDAP_P(( 106 const char *dn, 107 LDAPMod **pmods, 108 LDAPControl **pctrls, 109 int newentry )); 110 static int dodelete LDAP_P(( 111 const char *dn, 112 LDAPControl **pctrls )); 113 static int dorename LDAP_P(( 114 const char *dn, 115 const char *newrdn, 116 const char *newsup, 117 int deleteoldrdn, 118 LDAPControl **pctrls )); 119 static int process_response( 120 LDAP *ld, 121 int msgid, 122 int res, 123 const char *dn ); 124 125 #ifdef LDAP_X_TXN 126 static int txn = 0; 127 static int txnabort = 0; 128 struct berval *txn_id = NULL; 129 #endif 130 131 void 132 usage( void ) 133 { 134 fprintf( stderr, _("Add or modify entries from an LDAP server\n\n")); 135 fprintf( stderr, _("usage: %s [options]\n"), prog); 136 fprintf( stderr, _(" The list of desired operations are read from stdin" 137 " or from the file\n")); 138 fprintf( stderr, _(" specified by \"-f file\".\n")); 139 fprintf( stderr, _("Add or modify options:\n")); 140 fprintf( stderr, _(" -a add values (%s)\n"), 141 (ldapadd ? _("default") : _("default is to replace"))); 142 fprintf( stderr, _(" -c continuous operation mode (do not stop on errors)\n")); 143 fprintf( stderr, _(" -E [!]ext=extparam modify extensions" 144 " (! indicate s criticality)\n")); 145 fprintf( stderr, _(" -f file read operations from `file'\n")); 146 fprintf( stderr, _(" -M enable Manage DSA IT control (-MM to make critical)\n")); 147 fprintf( stderr, _(" -P version protocol version (default: 3)\n")); 148 #ifdef LDAP_X_TXN 149 fprintf( stderr, 150 _(" [!]txn=<commit|abort> (transaction)\n")); 151 #endif 152 fprintf( stderr, _(" -S file write skipped modifications to `file'\n")); 153 154 tool_common_usage(); 155 exit( EXIT_FAILURE ); 156 } 157 158 159 const char options[] = "aE:rS:" 160 "cd:D:e:f:h:H:IMnNO:o:p:P:QR:U:vVw:WxX:y:Y:Z"; 161 162 int 163 handle_private_option( int i ) 164 { 165 char *control, *cvalue; 166 int crit; 167 168 switch ( i ) { 169 case 'E': /* modify extensions */ 170 if( protocol == LDAP_VERSION2 ) { 171 fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"), 172 prog, protocol ); 173 exit( EXIT_FAILURE ); 174 } 175 176 /* should be extended to support comma separated list of 177 * [!]key[=value] parameters, e.g. -E !foo,bar=567 178 */ 179 180 crit = 0; 181 cvalue = NULL; 182 if( optarg[0] == '!' ) { 183 crit = 1; 184 optarg++; 185 } 186 187 control = ber_strdup( optarg ); 188 if ( (cvalue = strchr( control, '=' )) != NULL ) { 189 *cvalue++ = '\0'; 190 } 191 192 #ifdef LDAP_X_TXN 193 if( strcasecmp( control, "txn" ) == 0 ) { 194 /* Transaction */ 195 if( txn ) { 196 fprintf( stderr, 197 _("txn control previously specified\n")); 198 exit( EXIT_FAILURE ); 199 } 200 if( cvalue != NULL ) { 201 if( strcasecmp( cvalue, "abort" ) == 0 ) { 202 txnabort=1; 203 } else if( strcasecmp( cvalue, "commit" ) != 0 ) { 204 fprintf( stderr, _("Invalid value for txn control, %s\n"), 205 cvalue ); 206 exit( EXIT_FAILURE ); 207 } 208 } 209 210 txn = 1 + crit; 211 } else 212 #endif 213 { 214 fprintf( stderr, _("Invalid modify extension name: %s\n"), 215 control ); 216 usage(); 217 } 218 break; 219 220 case 'a': /* add */ 221 ldapadd = 1; 222 break; 223 224 case 'r': /* replace (obsolete) */ 225 break; 226 227 case 'S': /* skipped modifications to file */ 228 if( rejfile != NULL ) { 229 fprintf( stderr, _("%s: -S previously specified\n"), prog ); 230 exit( EXIT_FAILURE ); 231 } 232 rejfile = ber_strdup( optarg ); 233 break; 234 235 default: 236 return 0; 237 } 238 return 1; 239 } 240 241 242 int 243 main( int argc, char **argv ) 244 { 245 char *rbuf = NULL, *rejbuf = NULL; 246 FILE *rejfp; 247 struct LDIFFP *ldiffp, ldifdummy = {0}; 248 char *matched_msg, *error_msg; 249 int rc, retval, ldifrc; 250 int len; 251 int i = 0; 252 int lineno, nextline = 0, lmax = 0; 253 LDAPControl c[1]; 254 255 prog = lutil_progname( "ldapmodify", argc, argv ); 256 257 /* strncmp instead of strcmp since NT binaries carry .exe extension */ 258 ldapadd = ( strncasecmp( prog, "ldapadd", sizeof("ldapadd")-1 ) == 0 ); 259 260 tool_init( ldapadd ? TOOL_ADD : TOOL_MODIFY ); 261 262 tool_args( argc, argv ); 263 264 if ( argc != optind ) usage(); 265 266 if ( rejfile != NULL ) { 267 if (( rejfp = fopen( rejfile, "w" )) == NULL ) { 268 perror( rejfile ); 269 return( EXIT_FAILURE ); 270 } 271 } else { 272 rejfp = NULL; 273 } 274 275 if ( infile != NULL ) { 276 if (( ldiffp = ldif_open( infile, "r" )) == NULL ) { 277 perror( infile ); 278 return( EXIT_FAILURE ); 279 } 280 } else { 281 ldifdummy.fp = stdin; 282 ldiffp = &ldifdummy; 283 } 284 285 if ( debug ) ldif_debug = debug; 286 287 ld = tool_conn_setup( dont, 0 ); 288 289 if ( !dont ) { 290 tool_bind( ld ); 291 } 292 293 #ifdef LDAP_X_TXN 294 if( txn ) { 295 /* start transaction */ 296 rc = ldap_txn_start_s( ld, NULL, NULL, &txn_id ); 297 if( rc != LDAP_SUCCESS ) { 298 tool_perror( "ldap_txn_start_s", rc, NULL, NULL, NULL, NULL ); 299 if( txn > 1 ) return EXIT_FAILURE; 300 txn = 0; 301 } 302 } 303 #endif 304 305 if ( 0 306 #ifdef LDAP_X_TXN 307 || txn 308 #endif 309 ) 310 { 311 #ifdef LDAP_X_TXN 312 if( txn ) { 313 c[i].ldctl_oid = LDAP_CONTROL_X_TXN_SPEC; 314 c[i].ldctl_value = *txn_id; 315 c[i].ldctl_iscritical = 1; 316 i++; 317 } 318 #endif 319 } 320 321 tool_server_controls( ld, c, i ); 322 323 rc = 0; 324 retval = 0; 325 lineno = 1; 326 while (( rc == 0 || contoper ) && ( ldifrc = ldif_read_record( ldiffp, &nextline, 327 &rbuf, &lmax )) > 0 ) 328 { 329 if ( rejfp ) { 330 len = strlen( rbuf ); 331 if (( rejbuf = (char *)ber_memalloc( len+1 )) == NULL ) { 332 perror( "malloc" ); 333 exit( EXIT_FAILURE ); 334 } 335 memcpy( rejbuf, rbuf, len+1 ); 336 } 337 338 rc = process_ldif_rec( rbuf, lineno ); 339 lineno = nextline+1; 340 341 if ( rc ) retval = rc; 342 if ( rc && rejfp ) { 343 fprintf(rejfp, _("# Error: %s (%d)"), ldap_err2string(rc), rc); 344 345 matched_msg = NULL; 346 ldap_get_option(ld, LDAP_OPT_MATCHED_DN, &matched_msg); 347 if ( matched_msg != NULL ) { 348 if ( *matched_msg != '\0' ) { 349 fprintf( rejfp, _(", matched DN: %s"), matched_msg ); 350 } 351 ldap_memfree( matched_msg ); 352 } 353 354 error_msg = NULL; 355 ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &error_msg); 356 if ( error_msg != NULL ) { 357 if ( *error_msg != '\0' ) { 358 fprintf( rejfp, _(", additional info: %s"), error_msg ); 359 } 360 ldap_memfree( error_msg ); 361 } 362 fprintf( rejfp, "\n%s\n", rejbuf ); 363 } 364 365 if (rejfp) ber_memfree( rejbuf ); 366 } 367 ber_memfree( rbuf ); 368 369 if ( ldifrc < 0 ) 370 retval = LDAP_OTHER; 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 && BV_CASEMATCH( 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 ( BV_CASEMATCH( 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 ( BV_CASEMATCH( 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 ( BV_CASEMATCH( 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 ( BV_CASEMATCH( vals+i, &BV_MODIFYCT )) { 537 new_entry = 0; 538 expect_modop = 1; 539 } else if ( BV_CASEMATCH( vals+i, &BV_ADDCT )) { 540 new_entry = 1; 541 modop = LDAP_MOD_ADD; 542 } else if ( BV_CASEMATCH( vals+i, &BV_MODRDNCT ) 543 || BV_CASEMATCH( vals+i, &BV_MODDNCT ) 544 || BV_CASEMATCH( vals+i, &BV_RENAMECT )) 545 { 546 i++; 547 if ( i >= lines ) 548 goto short_input; 549 if ( !BV_CASEMATCH( 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 ( !BV_CASEMATCH( 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 ( !BV_CASEMATCH( 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 ( BV_CASEMATCH( vals+i, &BV_DELETECT )) { 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 ( BV_CASEMATCH( 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 ( BV_CASEMATCH( 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 ( !BV_CASEMATCH( 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 ( BV_CASEMATCH( btype+i, &BV_MODOPADD )) { 698 modop = LDAP_MOD_ADD; 699 mops[i] = M_SEP; 700 nmods--; 701 } else if ( BV_CASEMATCH( btype+i, &BV_MODOPREPLACE )) { 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 ( BV_CASEMATCH( btype+i, &BV_MODOPDELETE )) { 711 modop = LDAP_MOD_DELETE; 712 mops[i] = modop | LDAP_MOD_BVALUES; 713 btype[i] = vals[i]; 714 } else if ( BV_CASEMATCH( btype+i, &BV_MODOPINCREMENT )) { 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 ( !BV_CASEMATCH( 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) 744 && BV_CASEMATCH( btype+i, btype+i-1 )) 745 { 746 mops[i-1] = M_SEP; 747 nmods--; 748 } 749 } 750 } 751 752 #if 0 /* we should faithfully encode the LDIF, not combine */ 753 /* Make sure all modops with multiple values are contiguous */ 754 for (i=idn; i<lines; i++) { 755 if ( mops[i] == M_SEP ) 756 continue; 757 for (j=i+1; j<lines; j++) { 758 if ( mops[j] == M_SEP || mops[i] != mops[j] ) 759 continue; 760 if ( BV_CASEMATCH( btype+i, btype+j )) { 761 nmods--; 762 /* out of order, move intervening attributes down */ 763 if ( j != i+1 ) { 764 int c; 765 struct berval bv; 766 char fv; 767 768 c = mops[j]; 769 bv = vals[j]; 770 fv = freeval[j]; 771 for (k=j; k>i; k--) { 772 btype[k] = btype[k-1]; 773 vals[k] = vals[k-1]; 774 freeval[k] = freeval[k-1]; 775 mops[k] = mops[k-1]; 776 } 777 k++; 778 btype[k] = btype[i]; 779 vals[k] = bv; 780 freeval[k] = fv; 781 mops[k] = c; 782 } 783 i++; 784 } 785 } 786 } 787 #endif 788 789 /* Allocate space for array of mods, array of pointers to mods, 790 * and array of pointers to values, allowing for NULL terminators 791 * for the pointer arrays... 792 */ 793 lm = ber_memalloc( nmods * sizeof(LDAPMod) + 794 (nmods+1) * sizeof(LDAPMod*) + 795 (lines + nmods - idn) * sizeof(struct berval *)); 796 pmods = (LDAPMod **)(lm+nmods); 797 bvl = (struct berval **)(pmods+nmods+1); 798 799 j = 0; 800 k = -1; 801 BER_BVZERO(&bv); 802 mops[idn-1] = M_SEP; 803 for (i=idn; i<lines; i++) { 804 if ( mops[i] == M_SEP ) 805 continue; 806 if ( mops[i] != mops[i-1] || !BV_CASEMATCH( btype+i, &bv )) { 807 bvl[k++] = NULL; 808 bv = btype[i]; 809 lm[j].mod_op = mops[i] | LDAP_MOD_BVALUES; 810 lm[j].mod_type = bv.bv_val; 811 if ( mops[i] & LDAP_MOD_BVALUES ) { 812 lm[j].mod_bvalues = NULL; 813 } else { 814 lm[j].mod_bvalues = bvl+k; 815 } 816 pmods[j] = lm+j; 817 j++; 818 } 819 bvl[k++] = vals+i; 820 } 821 bvl[k] = NULL; 822 pmods[j] = NULL; 823 824 doit: 825 /* If default controls are set (as with -M option) and controls are 826 specified in the LDIF file, we must add the default controls to 827 the list of controls sent with the ldap operation. 828 */ 829 if ( rc == 0 ) { 830 if (pctrls) { 831 LDAPControl **defctrls = NULL; /* Default server controls */ 832 LDAPControl **newctrls = NULL; 833 ldap_get_option(ld, LDAP_OPT_SERVER_CONTROLS, &defctrls); 834 if (defctrls) { 835 int npc=0; /* Num of LDIF controls */ 836 int ndefc=0; /* Num of default controls */ 837 while (pctrls[npc]) npc++; /* Count LDIF controls */ 838 while (defctrls[ndefc]) ndefc++; /* Count default controls */ 839 newctrls = ber_memrealloc(pctrls, 840 (npc+ndefc+1)*sizeof(LDAPControl*)); 841 842 if (newctrls == NULL) { 843 rc = LDAP_NO_MEMORY; 844 } else { 845 int i; 846 pctrls = newctrls; 847 for (i=npc; i<npc+ndefc; i++) { 848 pctrls[i] = ldap_control_dup(defctrls[i-npc]); 849 if (pctrls[i] == NULL) { 850 rc = LDAP_NO_MEMORY; 851 break; 852 } 853 } 854 pctrls[npc+ndefc] = NULL; 855 } 856 ldap_controls_free(defctrls); /* Must be freed by library */ 857 } 858 } 859 } 860 861 if ( rc == 0 ) { 862 if ( delete_entry ) { 863 rc = dodelete( dn, pctrls ); 864 } else if ( newrdn != NULL ) { 865 rc = dorename( dn, newrdn, newsup, deleteoldrdn, pctrls ); 866 } else { 867 rc = domodify( dn, pmods, pctrls, new_entry ); 868 } 869 870 if ( rc == LDAP_SUCCESS ) { 871 rc = 0; 872 } 873 } 874 875 leave: 876 if (pctrls != NULL) { 877 ldap_controls_free( pctrls ); 878 } 879 if ( lm != NULL ) { 880 ber_memfree( lm ); 881 } 882 if ( mops != NULL ) { 883 ber_memfree( mops ); 884 } 885 for (i=lines-1; i>=0; i--) 886 if ( freeval[i] ) ber_memfree( vals[i].bv_val ); 887 ber_memfree( btype ); 888 889 return( rc ); 890 } 891 892 /* Parse an LDIF control line of the form 893 control: oid [true/false] [: value] or 894 control: oid [true/false] [:: base64-value] or 895 control: oid [true/false] [:< url] 896 The control is added to the list of controls in *ppctrls. 897 */ 898 static int 899 parse_ldif_control( 900 struct berval *bval, 901 LDAPControl ***ppctrls ) 902 { 903 char *oid = NULL; 904 int criticality = 0; /* Default is false if not present */ 905 int i, rc=0; 906 char *s, *oidStart; 907 LDAPControl *newctrl = NULL; 908 LDAPControl **pctrls = NULL; 909 struct berval type, bv; 910 int freeval; 911 912 if (ppctrls) pctrls = *ppctrls; 913 /* OID should come first. Validate and extract it. */ 914 s = bval->bv_val; 915 if (*s == 0) return ( LDAP_PARAM_ERROR ); 916 oidStart = s; 917 while (isdigit((unsigned char)*s) || *s == '.') { 918 s++; /* OID should be digits or . */ 919 } 920 if (s == oidStart) { 921 return ( LDAP_PARAM_ERROR ); /* OID was not present */ 922 } 923 if (*s) { /* End of OID should be space or NULL */ 924 if (!isspace((unsigned char)*s)) { 925 return ( LDAP_PARAM_ERROR ); /* else OID contained invalid chars */ 926 } 927 *s++ = 0; /* Replace space with null to terminate */ 928 } 929 930 oid = ber_strdup(oidStart); 931 if (oid == NULL) return ( LDAP_NO_MEMORY ); 932 933 /* Optional Criticality field is next. */ 934 while (*s && isspace((unsigned char)*s)) { 935 s++; /* Skip white space before criticality */ 936 } 937 if (strncasecmp(s, "true", 4) == 0) { 938 criticality = 1; 939 s += 4; 940 } 941 else if (strncasecmp(s, "false", 5) == 0) { 942 criticality = 0; 943 s += 5; 944 } 945 946 /* Optional value field is next */ 947 while (*s && isspace((unsigned char)*s)) { 948 s++; /* Skip white space before value */ 949 } 950 if (*s) { 951 if (*s != ':') { /* If value is present, must start with : */ 952 rc = LDAP_PARAM_ERROR; 953 goto cleanup; 954 } 955 956 /* Back up so value is in the form 957 a: value 958 a:: base64-value 959 a:< url 960 Then we can use ldif_parse_line2 to extract and decode the value 961 */ 962 s--; 963 *s = 'a'; 964 965 rc = ldif_parse_line2(s, &type, &bv, &freeval); 966 if (rc < 0) { 967 rc = LDAP_PARAM_ERROR; 968 goto cleanup; 969 } 970 } 971 972 /* Create a new LDAPControl structure. */ 973 newctrl = (LDAPControl *)ber_memalloc(sizeof(LDAPControl)); 974 if ( newctrl == NULL ) { 975 rc = LDAP_NO_MEMORY; 976 goto cleanup; 977 } 978 newctrl->ldctl_oid = oid; 979 oid = NULL; 980 newctrl->ldctl_iscritical = criticality; 981 if ( freeval ) 982 newctrl->ldctl_value = bv; 983 else 984 ber_dupbv( &newctrl->ldctl_value, &bv ); 985 986 /* Add the new control to the passed-in list of controls. */ 987 i = 0; 988 if (pctrls) { 989 while ( pctrls[i] ) { /* Count the # of controls passed in */ 990 i++; 991 } 992 } 993 /* Allocate 1 more slot for the new control and 1 for the NULL. */ 994 pctrls = (LDAPControl **) ber_memrealloc(pctrls, 995 (i+2)*(sizeof(LDAPControl *))); 996 if (pctrls == NULL) { 997 rc = LDAP_NO_MEMORY; 998 goto cleanup; 999 } 1000 pctrls[i] = newctrl; 1001 newctrl = NULL; 1002 pctrls[i+1] = NULL; 1003 *ppctrls = pctrls; 1004 1005 cleanup: 1006 if (newctrl) { 1007 if (newctrl->ldctl_oid) ber_memfree(newctrl->ldctl_oid); 1008 if (newctrl->ldctl_value.bv_val) { 1009 ber_memfree(newctrl->ldctl_value.bv_val); 1010 } 1011 ber_memfree(newctrl); 1012 } 1013 if (oid) ber_memfree(oid); 1014 1015 return( rc ); 1016 } 1017 1018 1019 static int 1020 domodify( 1021 const char *dn, 1022 LDAPMod **pmods, 1023 LDAPControl **pctrls, 1024 int newentry ) 1025 { 1026 int rc, i, j, k, notascii, op; 1027 struct berval *bvp; 1028 1029 if ( dn == NULL ) { 1030 fprintf( stderr, _("%s: no DN specified\n"), prog ); 1031 return( LDAP_PARAM_ERROR ); 1032 } 1033 1034 if ( pmods == NULL ) { 1035 /* implement "touch" (empty sequence) 1036 * modify operation (note that there 1037 * is no symmetry with the UNIX command, 1038 * since \"touch\" on a non-existent entry 1039 * will fail)*/ 1040 printf( "warning: no attributes to %sadd (entry=\"%s\")\n", 1041 newentry ? "" : "change or ", dn ); 1042 1043 } else { 1044 for ( i = 0; pmods[ i ] != NULL; ++i ) { 1045 op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES; 1046 if( op == LDAP_MOD_ADD && ( pmods[i]->mod_bvalues == NULL )) { 1047 fprintf( stderr, 1048 _("%s: attribute \"%s\" has no values (entry=\"%s\")\n"), 1049 prog, pmods[i]->mod_type, dn ); 1050 return LDAP_PARAM_ERROR; 1051 } 1052 } 1053 1054 if ( verbose ) { 1055 for ( i = 0; pmods[ i ] != NULL; ++i ) { 1056 op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES; 1057 printf( "%s %s:\n", 1058 op == LDAP_MOD_REPLACE ? _("replace") : 1059 op == LDAP_MOD_ADD ? _("add") : 1060 op == LDAP_MOD_INCREMENT ? _("increment") : 1061 op == LDAP_MOD_DELETE ? _("delete") : 1062 _("unknown"), 1063 pmods[ i ]->mod_type ); 1064 1065 if ( pmods[ i ]->mod_bvalues != NULL ) { 1066 for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) { 1067 bvp = pmods[ i ]->mod_bvalues[ j ]; 1068 notascii = 0; 1069 for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) { 1070 if ( !isascii( bvp->bv_val[ k ] )) { 1071 notascii = 1; 1072 break; 1073 } 1074 } 1075 if ( notascii ) { 1076 printf( _("\tNOT ASCII (%ld bytes)\n"), bvp->bv_len ); 1077 } else { 1078 printf( "\t%s\n", bvp->bv_val ); 1079 } 1080 } 1081 } 1082 } 1083 } 1084 } 1085 1086 if ( newentry ) { 1087 printf( "%sadding new entry \"%s\"\n", dont ? "!" : "", dn ); 1088 } else { 1089 printf( "%smodifying entry \"%s\"\n", dont ? "!" : "", dn ); 1090 } 1091 1092 if ( !dont ) { 1093 int msgid; 1094 if ( newentry ) { 1095 rc = ldap_add_ext( ld, dn, pmods, pctrls, NULL, &msgid ); 1096 } else { 1097 rc = ldap_modify_ext( ld, dn, pmods, pctrls, NULL, &msgid ); 1098 } 1099 1100 if ( rc != LDAP_SUCCESS ) { 1101 /* print error message about failed update including DN */ 1102 fprintf( stderr, _("%s: update failed: %s\n"), prog, dn ); 1103 tool_perror( newentry ? "ldap_add" : "ldap_modify", 1104 rc, NULL, NULL, NULL, NULL ); 1105 goto done; 1106 } 1107 rc = process_response( ld, msgid, 1108 newentry ? LDAP_RES_ADD : LDAP_RES_MODIFY, dn ); 1109 1110 if ( verbose && rc == LDAP_SUCCESS ) { 1111 printf( _("modify complete\n") ); 1112 } 1113 1114 } else { 1115 rc = LDAP_SUCCESS; 1116 } 1117 1118 done: 1119 putchar( '\n' ); 1120 return rc; 1121 } 1122 1123 1124 static int 1125 dodelete( 1126 const char *dn, 1127 LDAPControl **pctrls ) 1128 { 1129 int rc; 1130 int msgid; 1131 1132 printf( _("%sdeleting entry \"%s\"\n"), dont ? "!" : "", dn ); 1133 if ( !dont ) { 1134 rc = ldap_delete_ext( ld, dn, pctrls, NULL, &msgid ); 1135 if ( rc != LDAP_SUCCESS ) { 1136 fprintf( stderr, _("%s: delete failed: %s\n"), prog, dn ); 1137 tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL ); 1138 goto done; 1139 } 1140 rc = process_response( ld, msgid, LDAP_RES_DELETE, dn ); 1141 1142 if ( verbose && rc == LDAP_SUCCESS ) { 1143 printf( _("delete complete\n") ); 1144 } 1145 } else { 1146 rc = LDAP_SUCCESS; 1147 } 1148 1149 done: 1150 putchar( '\n' ); 1151 return( rc ); 1152 } 1153 1154 1155 static int 1156 dorename( 1157 const char *dn, 1158 const char *newrdn, 1159 const char* newsup, 1160 int deleteoldrdn, 1161 LDAPControl **pctrls ) 1162 { 1163 int rc; 1164 int msgid; 1165 1166 printf( _("%smodifying rdn of entry \"%s\"\n"), dont ? "!" : "", dn ); 1167 if ( verbose ) { 1168 printf( _("\tnew RDN: \"%s\" (%skeep existing values)\n"), 1169 newrdn, deleteoldrdn ? _("do not ") : "" ); 1170 } 1171 if ( !dont ) { 1172 rc = ldap_rename( ld, dn, newrdn, newsup, deleteoldrdn, 1173 pctrls, NULL, &msgid ); 1174 if ( rc != LDAP_SUCCESS ) { 1175 fprintf( stderr, _("%s: rename failed: %s\n"), prog, dn ); 1176 tool_perror( "ldap_rename", rc, NULL, NULL, NULL, NULL ); 1177 goto done; 1178 } 1179 rc = process_response( ld, msgid, LDAP_RES_RENAME, dn ); 1180 1181 if ( verbose && rc == LDAP_SUCCESS ) { 1182 printf( _("rename complete\n") ); 1183 } 1184 } else { 1185 rc = LDAP_SUCCESS; 1186 } 1187 1188 done: 1189 putchar( '\n' ); 1190 return( rc ); 1191 } 1192 1193 static const char * 1194 res2str( int res ) { 1195 switch ( res ) { 1196 case LDAP_RES_ADD: 1197 return "ldap_add"; 1198 case LDAP_RES_DELETE: 1199 return "ldap_delete"; 1200 case LDAP_RES_MODIFY: 1201 return "ldap_modify"; 1202 case LDAP_RES_MODRDN: 1203 return "ldap_rename"; 1204 default: 1205 assert( 0 ); 1206 } 1207 1208 return "ldap_unknown"; 1209 } 1210 1211 static int process_response( 1212 LDAP *ld, 1213 int msgid, 1214 int op, 1215 const char *dn ) 1216 { 1217 LDAPMessage *res; 1218 int rc = LDAP_OTHER, msgtype; 1219 struct timeval tv = { 0, 0 }; 1220 int err; 1221 char *text = NULL, *matched = NULL, **refs = NULL; 1222 LDAPControl **ctrls = NULL; 1223 1224 for ( ; ; ) { 1225 tv.tv_sec = 0; 1226 tv.tv_usec = 100000; 1227 1228 rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res ); 1229 if ( tool_check_abandon( ld, msgid ) ) { 1230 return LDAP_CANCELLED; 1231 } 1232 1233 if ( rc == -1 ) { 1234 ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc ); 1235 tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL ); 1236 return rc; 1237 } 1238 1239 if ( rc != 0 ) { 1240 break; 1241 } 1242 } 1243 1244 msgtype = ldap_msgtype( res ); 1245 1246 rc = ldap_parse_result( ld, res, &err, &matched, &text, &refs, &ctrls, 1 ); 1247 if ( rc == LDAP_SUCCESS ) rc = err; 1248 1249 #ifdef LDAP_X_TXN 1250 if ( rc == LDAP_X_TXN_SPECIFY_OKAY ) { 1251 rc = LDAP_SUCCESS; 1252 } else 1253 #endif 1254 if ( rc != LDAP_SUCCESS ) { 1255 tool_perror( res2str( op ), rc, NULL, matched, text, refs ); 1256 } else if ( msgtype != op ) { 1257 fprintf( stderr, "%s: msgtype: expected %d got %d\n", 1258 res2str( op ), op, msgtype ); 1259 rc = LDAP_OTHER; 1260 } 1261 1262 if ( text ) ldap_memfree( text ); 1263 if ( matched ) ldap_memfree( matched ); 1264 if ( text ) ber_memvfree( (void **)refs ); 1265 1266 if ( ctrls ) { 1267 tool_print_ctrls( ld, ctrls ); 1268 ldap_controls_free( ctrls ); 1269 } 1270 1271 return rc; 1272 } 1273