1 /* 2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * The contents of this file are subject to the Netscape Public 10 * License Version 1.1 (the "License"); you may not use this file 11 * except in compliance with the License. You may obtain a copy of 12 * the License at http://www.mozilla.org/NPL/ 13 * 14 * Software distributed under the License is distributed on an "AS 15 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 16 * implied. See the License for the specific language governing 17 * rights and limitations under the License. 18 * 19 * The Original Code is Mozilla Communicator client code, released 20 * March 31, 1998. 21 * 22 * The Initial Developer of the Original Code is Netscape 23 * Communications Corporation. Portions created by Netscape are 24 * Copyright (C) 1998-1999 Netscape Communications Corporation. All 25 * Rights Reserved. 26 * 27 * Contributor(s): 28 */ 29 30 /* ldapmodify.c - generic program to modify or add entries using LDAP */ 31 32 #include "ldaptool.h" 33 #include "fileurl.h" 34 35 #ifdef SOLARIS_LDAP_CMD 36 #include <locale.h> 37 #include "ldif.h" 38 #endif /* SOLARIS_LDAP_CMD */ 39 40 #ifndef SOLARIS_LDAP_CMD 41 #define gettext(s) s 42 #endif 43 44 static int newval, contoper, force, valsfromfiles, display_binary_values; 45 static int ldif_version = -1; /* -1 => unknown version */ 46 static char *rejfile = NULL; 47 static char *bulkimport_suffix = NULL; 48 static int ldapmodify_quiet = 0; 49 50 #ifdef SOLARIS_LDAP_CMD 51 static int error = 0, replace, nbthreads = 1; 52 static int thr_create_errors = 0; 53 static pthread_mutex_t read_mutex = {0}; 54 static pthread_mutex_t wait_mutex = {0}; 55 static pthread_cond_t wait_cond = {0}; 56 #else 57 /* 58 * For Solaris, ld is defined local to process() because 59 * multiple threads restricts Solaris from using a global 60 * ld variable. 61 * Solaris uses multiple threads to create multiple 62 * ldap connections if nbthreads > 1 (i.e -l option). 63 */ 64 static LDAP *ld; 65 #endif /* SOLARIS_LDAP_CMD */ 66 67 #define LDAPMOD_MAXLINE 4096 68 69 /* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */ 70 #define T_REPLICA_STR "replica" 71 #define T_DN_STR "dn" 72 #define T_VERSION_STR "version" 73 #define T_CHANGETYPESTR "changetype" 74 #define T_ADDCTSTR "add" 75 #define T_MODIFYCTSTR "modify" 76 #define T_DELETECTSTR "delete" 77 #define T_RENAMECTSTR "rename" /* non-standard */ 78 #define T_MODDNCTSTR "moddn" 79 #define T_MODRDNCTSTR "modrdn" 80 #define T_MODOPADDSTR "add" 81 #define T_MODOPREPLACESTR "replace" 82 #define T_MODOPDELETESTR "delete" 83 #define T_MODSEPSTR "-" 84 #define T_NEWRDNSTR "newrdn" 85 #define T_NEWSUPERIORSTR "newsuperior" 86 #define T_NEWPARENTSTR "newparent" 87 #define T_DELETEOLDRDNSTR "deleteoldrdn" 88 #define T_NEWSUPERIORSTR "newsuperior" 89 #define T_NEWPARENTSTR "newparent" /* non-standard */ 90 91 /* bulk import */ 92 #define BULKIMPORT_START_OID "2.16.840.1.113730.3.5.7" 93 #define BULKIMPORT_STOP_OID "2.16.840.1.113730.3.5.8" 94 95 static int process( void *arg ); 96 static void options_callback( int option, char *optarg ); 97 static void addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, 98 char *value, int vlen ); 99 static void freepmods( LDAPMod **pmods ); 100 static char *read_one_record( FILE *fp ); 101 static char *strdup_and_trim( char *s ); 102 103 #ifdef SOLARIS_LDAP_CMD 104 static int process_ldapmod_rec( LDAP *ld, char *rbuf ); 105 static int process_ldif_rec( LDAP *ld, char *rbuf ); 106 static int domodify( LDAP *ld, char *dn, LDAPMod **pmods, int newentry ); 107 static int dodelete( LDAP *ld, char *dn ); 108 static int dorename( LDAP *ld, char *dn, char *newrdn, char *newparent, 109 int deleteoldrdn ); 110 #else 111 static int process_ldapmod_rec( char *rbuf ); 112 static int process_ldif_rec( char *rbuf ); 113 static int domodify( char *dn, LDAPMod **pmods, int newentry ); 114 static int dodelete( char *dn ); 115 static int dorename( char *dn, char *newrdn, char *newparent, 116 int deleteoldrdn ); 117 #endif /* SOLARIS_LDAP_CMD */ 118 119 static void 120 usage( void ) 121 { 122 fprintf( stderr, gettext("usage: %s [options]\n"), ldaptool_progname ); 123 fprintf( stderr, gettext("options:\n") ); 124 ldaptool_common_usage( 0 ); 125 fprintf( stderr, gettext(" -c\t\tcontinuous mode (do not stop on errors)\n") ); 126 fprintf( stderr, gettext(" -A\t\tdisplay non-ASCII values in conjunction with -v\n") ); 127 fprintf( stderr, gettext(" -f file\tread modifications from file (default: standard input)\n") ); 128 if ( strcmp( ldaptool_progname, "ldapmodify" ) == 0 ){ 129 fprintf( stderr, gettext(" -a\t\tadd entries\n") ); 130 } 131 fprintf( stderr, gettext(" -b\t\tread values that start with / from files (for bin attrs)\n") ); 132 fprintf( stderr, gettext(" -F\t\tforce application of all changes, regardless of\n") ); 133 fprintf( stderr, gettext(" \t\treplica lines\n") ); 134 fprintf( stderr, gettext(" -e rejfile\tsave rejected entries in \"rejfile\"\n") ); 135 fprintf( stderr, gettext(" -B suffix\tbulk import to \"suffix\"\n")); 136 fprintf( stderr, gettext(" -q\t\tbe quiet when adding/modifying entries\n") ); 137 #ifdef SOLARIS_LDAP_CMD 138 fprintf( stderr, gettext(" -r\t\treplace values\n")); 139 fprintf( stderr, gettext(" -l nb-connections\tnumber of LDAP connections\n")); 140 #endif /* SOLARIS_LDAP_CMD */ 141 exit( LDAP_PARAM_ERROR ); 142 } 143 144 145 int 146 main( int argc, char **argv ) 147 { 148 int optind, i; 149 150 #ifdef SOLARIS_LDAP_CMD 151 char *locale = setlocale(LC_ALL, ""); 152 textdomain(TEXT_DOMAIN); 153 #endif 154 155 #ifdef notdef 156 #ifdef HPUX11 157 #ifndef __LP64__ 158 _main( argc, argv); 159 #endif /* __LP64_ */ 160 #endif /* HPUX11 */ 161 #endif 162 163 valsfromfiles = display_binary_values = 0; 164 165 #ifdef SOLARIS_LDAP_CMD 166 optind = ldaptool_process_args( argc, argv, "aAbcFe:B:qrl:", 0, 167 options_callback ); 168 #else 169 optind = ldaptool_process_args( argc, argv, "aAbcFe:B:q", 0, 170 options_callback ); 171 #endif /* SOLARIS_LDAP_CMD */ 172 173 174 if ( optind == -1 ) { 175 usage(); 176 } 177 178 if ( !newval && strcmp( ldaptool_progname, "ldapadd" ) == 0 ) { 179 newval = 1; 180 } 181 182 if ( ldaptool_fp == NULL ) { 183 ldaptool_fp = stdin; 184 } 185 186 if ( argc - optind != 0 ) { 187 usage(); 188 } 189 190 #ifdef SOLARIS_LDAP_CMD 191 /* trivial case */ 192 if ( nbthreads == 1 ) 193 return ( process(NULL) ); 194 195 for ( i=0; i<nbthreads; ++i ) { 196 if ( thr_create(NULL, 0, process, NULL, NULL, NULL) != 0 ) 197 ++thr_create_errors; 198 } 199 200 if ( thr_create_errors < nbthreads ) 201 while ( thr_join(0, NULL, NULL) == 0 ); 202 else 203 error = -1; 204 return ( error ); 205 #else 206 return ( process(NULL) ); 207 #endif /* SOLARIS_LDAP_CMD */ 208 } 209 210 #ifdef SOLARIS_LDAP_CMD 211 #define exit(a) \ 212 if (nbthreads > 1) { \ 213 mutex_lock(&read_mutex); \ 214 error |= a; \ 215 mutex_unlock(&read_mutex); \ 216 thr_exit(&error); \ 217 } else { \ 218 exit(a); \ 219 } 220 #endif /* SOLARIS_LDAP_CMD */ 221 222 static int 223 process( void *arg ) 224 { 225 char *rbuf, *saved_rbuf, *start, *p, *q; 226 FILE *rfp = NULL; 227 int rc, use_ldif, deref; 228 LDAPControl *ldctrl; 229 230 #ifdef SOLARIS_LDAP_CMD 231 LDAP *ld; 232 #endif /* SOLARIS_LDAP_CMD */ 233 234 ld = ldaptool_ldap_init( 0 ); 235 236 if ( !ldaptool_not ) { 237 deref = LDAP_DEREF_NEVER; /* this seems prudent */ 238 ldap_set_option( ld, LDAP_OPT_DEREF, &deref ); 239 } 240 241 ldaptool_bind( ld ); 242 243 if (( ldctrl = ldaptool_create_manage_dsait_control()) != NULL ) { 244 ldaptool_add_control_to_array( ldctrl, ldaptool_request_ctrls); 245 } 246 247 if ((ldctrl = ldaptool_create_proxyauth_control(ld)) !=NULL) { 248 ldaptool_add_control_to_array( ldctrl, ldaptool_request_ctrls); 249 } 250 251 rc = 0; 252 253 /* turn on bulk import?*/ 254 if (bulkimport_suffix) { 255 struct berval bv, *retdata; 256 char *retoid; 257 258 bv.bv_val = bulkimport_suffix; 259 bv.bv_len = strlen(bulkimport_suffix); 260 if ((rc = ldap_extended_operation_s(ld, 261 BULKIMPORT_START_OID, &bv, NULL, 262 NULL, &retoid, &retdata)) != 0) { 263 fprintf(stderr, gettext("Error: unable to service " 264 "extended operation request\n\t'%s' for " 265 "bulk import\n\t(error:%d:'%s')\n"), 266 BULKIMPORT_START_OID, rc, ldap_err2string(rc)); 267 return (rc); 268 } 269 if (retoid) 270 ldap_memfree(retoid); 271 if (retdata) 272 ber_bvfree(retdata); 273 } 274 275 while (( rc == 0 || contoper ) && 276 ( rbuf = read_one_record( ldaptool_fp )) != NULL ) { 277 /* 278 * we assume record is ldif/slapd.replog if the first line 279 * has a colon that appears to the left of any equal signs, OR 280 * if the first line consists entirely of digits (an entry id) 281 */ 282 use_ldif = ( p = strchr( rbuf, ':' )) != NULL && 283 ( q = strchr( rbuf, '\n' )) != NULL && p < q && 284 (( q = strchr( rbuf, '=' )) == NULL || p < q ); 285 286 start = rbuf; 287 saved_rbuf = strdup( rbuf ); 288 289 if ( !use_ldif && ( q = strchr( rbuf, '\n' )) != NULL ) { 290 for ( p = rbuf; p < q; ++p ) { 291 if ( !isdigit( *p )) { 292 break; 293 } 294 } 295 if ( p >= q ) { 296 use_ldif = 1; 297 start = q + 1; 298 } 299 } 300 301 #ifdef SOLARIS_LDAP_CMD 302 if ( use_ldif ) { 303 rc = process_ldif_rec( ld, start ); 304 } else { 305 rc = process_ldapmod_rec( ld, start ); 306 } 307 #else 308 if ( use_ldif ) { 309 rc = process_ldif_rec( start ); 310 } else { 311 rc = process_ldapmod_rec( start ); 312 } 313 #endif /* SOLARIS_LDAP_CMD */ 314 315 if ( rc != LDAP_SUCCESS && rejfile != NULL ) { 316 /* Write this record to the reject file */ 317 int newfile = 0; 318 struct stat stbuf; 319 if ( stat( rejfile, &stbuf ) < 0 ) { 320 if ( errno == ENOENT ) { 321 newfile = 1; 322 } 323 } 324 if (( rfp = ldaptool_open_file( rejfile, "a" )) == NULL ) { 325 fprintf( stderr, gettext("Cannot open error file \"%s\" - " 326 "erroneous entries will not be saved\n"), rejfile ); 327 rejfile = NULL; 328 } else { 329 if ( newfile == 0 ) { 330 fputs( "\n", rfp ); 331 } 332 fprintf( rfp, gettext("# Error: %s\n"), ldap_err2string( rc )); 333 fputs( saved_rbuf, rfp ); 334 fclose( rfp ); 335 rfp = NULL; 336 } 337 } 338 339 free( rbuf ); 340 free( saved_rbuf ); 341 } 342 ldaptool_reset_control_array( ldaptool_request_ctrls ); 343 344 /* turn off bulk import?*/ 345 if (bulkimport_suffix) { 346 struct berval bv, *retdata; 347 char *retoid; 348 349 bv.bv_val = ""; 350 bv.bv_len = 0; 351 if ((rc = ldap_extended_operation_s(ld, 352 BULKIMPORT_STOP_OID, &bv, NULL, 353 NULL, &retoid, &retdata)) != 0) { 354 355 fprintf(stderr, gettext("Error: unable to service " 356 "extended operation request\n\t '%s' for " 357 "bulk import\n\t(rc:%d:'%s')\n"), 358 BULKIMPORT_STOP_OID, rc, ldap_err2string(rc)); 359 return (rc); 360 } 361 if (retoid) 362 ldap_memfree(retoid); 363 if (retdata) 364 ber_bvfree(retdata); 365 } 366 367 #ifdef SOLARIS_LDAP_CMD 368 mutex_lock(&read_mutex); 369 #endif 370 ldaptool_cleanup( ld ); 371 #ifdef SOLARIS_LDAP_CMD 372 mutex_unlock(&read_mutex); 373 #endif 374 return( rc ); 375 } 376 377 378 static void 379 options_callback( int option, char *optarg ) 380 { 381 switch( option ) { 382 case 'a': /* add */ 383 newval = 1; 384 break; 385 case 'b': /* read values from files (for binary attributes) */ 386 valsfromfiles = 1; 387 break; 388 case 'A': /* display non-ASCII values when -v is used */ 389 display_binary_values = 1; 390 break; 391 case 'c': /* continuous operation */ 392 contoper = 1; 393 break; 394 case 'F': /* force all changes records to be used */ 395 force = 1; 396 break; 397 case 'e': 398 rejfile = strdup( optarg ); 399 break; 400 case 'B': /* bulk import option */ 401 bulkimport_suffix = strdup( optarg ); 402 break; 403 case 'q': /* quiet mode on add/modify operations */ 404 ldapmodify_quiet = 1; 405 break; 406 #ifdef SOLARIS_LDAP_CMD 407 case 'r': /* default is to replace rather than add values */ 408 replace = 1; 409 break; 410 case 'l': 411 nbthreads = atoi(optarg); 412 break; 413 #endif /* SOLARIS_LDAP_CMD */ 414 default: 415 usage(); 416 } 417 } 418 419 420 421 static int 422 #ifdef SOLARIS_LDAP_CMD 423 process_ldif_rec( LDAP *ld, char *rbuf ) 424 #else 425 process_ldif_rec( char *rbuf ) 426 #endif 427 { 428 char *line, *dn, *type, *value, *newrdn, *newparent, *p; 429 char *ctrl_oid=NULL, *ctrl_value=NULL; 430 int ctrl_criticality=1; 431 LDAPControl *ldctrl; 432 int rc, linenum, vlen, modop, replicaport; 433 int expect_modop, expect_sep, expect_chgtype_or_control, expect_newrdn; 434 int expect_deleteoldrdn, expect_newparent, rename, moddn; 435 int deleteoldrdn, saw_replica, use_record, new_entry, delete_entry; 436 int got_all, got_value; 437 LDAPMod **pmods; 438 439 new_entry = newval; 440 441 rc = got_all = saw_replica = delete_entry = expect_modop = 0; 442 expect_deleteoldrdn = expect_newrdn = expect_newparent = expect_sep = 0; 443 expect_chgtype_or_control = linenum = got_value = rename = moddn = 0; 444 deleteoldrdn = 1; 445 use_record = force; 446 pmods = NULL; 447 dn = newrdn = newparent = NULL; 448 449 #ifdef SOLARIS_LDAP_CMD 450 while ( rc == 0 && ( line = str_getline( &rbuf )) != NULL ) { 451 #else 452 while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) { 453 #endif /* SOLARIS_LDAP_CMD */ 454 ++linenum; 455 if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) { 456 expect_sep = 0; 457 expect_modop = 1; 458 459 /*If we see a separator in the input stream, 460 but we didn't get a value from the last modify 461 then we have to fill pmods with an empty value*/ 462 if (modop == LDAP_MOD_REPLACE && !got_value){ 463 addmodifyop( &pmods, modop, value, NULL, 0); 464 } 465 466 got_value = 0; 467 continue; 468 } 469 470 #ifdef SOLARIS_LDAP_CMD 471 if ( str_parse_line( line, &type, &value, &vlen ) < 0 ) { 472 #else 473 if ( ldif_parse_line( line, &type, &value, &vlen ) < 0 ) { 474 #endif /* SOLARIS_LDAP_CMD */ 475 fprintf( stderr, gettext("%s: invalid format (line %d of entry: %s)\n"), 476 ldaptool_progname, linenum, dn == NULL ? "" : dn ); 477 fprintf( stderr, gettext("%s: line contents: (%s)\n"), 478 ldaptool_progname, line ); 479 rc = LDAP_PARAM_ERROR; 480 break; 481 } 482 483 evaluate_line: 484 if ( dn == NULL ) { 485 if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) { 486 ++saw_replica; 487 if (( p = strchr( value, ':' )) == NULL ) { 488 replicaport = LDAP_PORT; 489 } else { 490 *p++ = '\0'; 491 replicaport = atoi( p ); 492 } 493 if ( strcasecmp( value, ldaptool_host ) == 0 && 494 replicaport == ldaptool_port ) { 495 use_record = 1; 496 } 497 498 } else if ( strcasecmp( type, T_DN_STR ) == 0 ) { 499 if (( dn = strdup( value )) == NULL ) { 500 perror( "strdup" ); 501 exit( LDAP_NO_MEMORY ); 502 } 503 expect_chgtype_or_control = 1; 504 505 } else if ( strcasecmp( type, T_VERSION_STR ) == 0 ) { 506 ldif_version = atoi( value ); 507 if ( ldif_version != LDIF_VERSION_ONE ) { 508 fprintf( stderr, gettext("%s: LDIF version %d is not supported;" 509 " use version: %d\n"), ldaptool_progname, ldif_version, 510 LDIF_VERSION_ONE ); 511 exit( LDAP_PARAM_ERROR ); 512 } 513 if ( ldaptool_verbose ) { 514 printf( gettext("Processing a version %d LDIF file...\n"), 515 ldif_version ); 516 } 517 518 /* Now check if there's something left to process */ 519 /* and if not, go get the new record, else continue */ 520 if ( *rbuf == '\0' ) { 521 return( 0 ); 522 } 523 524 } else if ( !saw_replica ) { 525 printf( gettext("%s: skipping change record: no dn: line\n"), 526 ldaptool_progname ); 527 return( 0 ); 528 } 529 530 continue; /* skip all lines until we see "dn:" */ 531 } 532 533 if ( expect_chgtype_or_control ) { 534 expect_chgtype_or_control = 0; 535 if ( !use_record && saw_replica ) { 536 printf( gettext("%s: skipping change record for entry: %s\n\t(LDAP host/port does not match replica: lines)\n"), 537 ldaptool_progname, dn ); 538 free( dn ); 539 return( 0 ); 540 } 541 542 #ifndef SOLARIS_LDAP_CMD 543 if ( strcasecmp( type, "control" ) == 0 ) { 544 value = strdup_and_trim( value ); 545 if (ldaptool_parse_ctrl_arg(value, ' ', &ctrl_oid, 546 &ctrl_criticality, &ctrl_value, &vlen)) { 547 usage(); 548 } 549 ldctrl = calloc(1,sizeof(LDAPControl)); 550 if (ctrl_value) { 551 rc = ldaptool_berval_from_ldif_value( ctrl_value, vlen, 552 &(ldctrl->ldctl_value), 553 1 /* recognize file URLs */, 0 /* always try file */, 554 1 /* report errors */ ); 555 if ((rc = ldaptool_fileurlerr2ldaperr( rc )) != LDAP_SUCCESS) { 556 fprintf( stderr, gettext("Unable to parse %s\n"), ctrl_value); 557 usage(); 558 } 559 } 560 ldctrl->ldctl_oid = ctrl_oid; 561 ldctrl->ldctl_iscritical = ctrl_criticality; 562 ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls); 563 expect_chgtype_or_control = 1; 564 continue; 565 } 566 #endif /* SOLARIS_LDAP_CMD */ 567 568 if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) { 569 value = strdup_and_trim( value ); 570 if ( strcasecmp( value, T_MODIFYCTSTR ) == 0 ) { 571 new_entry = 0; 572 expect_modop = 1; 573 } else if ( strcasecmp( value, T_ADDCTSTR ) == 0 ) { 574 new_entry = 1; 575 modop = LDAP_MOD_ADD; 576 } else if ( strcasecmp( value, T_MODRDNCTSTR ) == 0 ) { 577 expect_newrdn = 1; 578 moddn = 1; 579 } else if ( strcasecmp( value, T_MODDNCTSTR ) == 0 ) { 580 expect_newrdn = 1; 581 moddn = 1; 582 } else if ( strcasecmp( value, T_RENAMECTSTR ) == 0 ) { 583 expect_newrdn = 1; 584 rename = 1; 585 } else if ( strcasecmp( value, T_DELETECTSTR ) == 0 ) { 586 got_all = delete_entry = 1; 587 } else { 588 fprintf( stderr, 589 gettext("%s: unknown %s \"%s\" (line %d of entry: %s)\n"), 590 ldaptool_progname, T_CHANGETYPESTR, value, 591 linenum, dn ); 592 rc = LDAP_PARAM_ERROR; 593 } 594 free( value ); 595 continue; 596 } else if ( newval ) { /* missing changetype => add */ 597 new_entry = 1; 598 modop = LDAP_MOD_ADD; 599 } else { 600 /*The user MUST put in changetype: blah 601 unless adding a new entry with either -a or ldapadd*/ 602 fprintf(stderr, gettext("%s: Missing changetype operation specification.\n\tThe dn line must be followed by \"changetype: operation\"\n\t(unless ldapmodify is called with -a option)\n\twhere operation is add|delete|modify|modrdn|moddn|rename\n\t\"%s\" is not a valid changetype operation specification\n\t(line %d of entry %s)\n"), 603 ldaptool_progname, type, linenum, dn); 604 rc = LDAP_PARAM_ERROR; 605 /*expect_modop = 1; missing changetype => modify */ 606 } 607 } 608 609 if ( expect_modop ) { 610 expect_modop = 0; 611 expect_sep = 1; 612 if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) { 613 modop = LDAP_MOD_ADD; 614 continue; 615 } else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) { 616 modop = LDAP_MOD_REPLACE; 617 continue; 618 } else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) { 619 modop = LDAP_MOD_DELETE; 620 addmodifyop( &pmods, modop, value, NULL, 0 ); 621 continue; 622 #ifdef SOLARIS_LDAP_CMD 623 } else { /* no modify op: use default */ 624 modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD; 625 } 626 #else 627 } else { /*Bug 27479. Remove default add operation*/ 628 fprintf(stderr, gettext("%s: Invalid parameter \"%s\" specified for changetype modify (line %d of entry %s)\n"), 629 ldaptool_progname, type, linenum, dn); 630 rc = LDAP_PARAM_ERROR; 631 } 632 #endif /* SOLARIS_LDAP_CMD */ 633 634 } 635 636 if ( expect_newrdn ) { 637 if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) { 638 if ( *value == '\0' ) { 639 fprintf( stderr, 640 gettext("%s: newrdn value missing (line %d of entry: %s)\n"), 641 ldaptool_progname, linenum, dn == NULL ? "" : dn ); 642 rc = LDAP_PARAM_ERROR; 643 } else if (( newrdn = strdup( value )) == NULL ) { 644 perror( "strdup" ); 645 exit( LDAP_NO_MEMORY ); 646 } else { 647 expect_newrdn = 0; 648 if ( rename ) { 649 expect_newparent = 1; 650 } else { 651 expect_deleteoldrdn = 1; 652 } 653 } 654 } else { 655 fprintf( stderr, gettext("%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n"), 656 ldaptool_progname, T_NEWRDNSTR, type, linenum, dn ); 657 rc = LDAP_PARAM_ERROR; 658 } 659 } else if ( expect_newparent ) { 660 expect_newparent = 0; 661 if ( rename ) { 662 expect_deleteoldrdn = 1; 663 } 664 if ( strcasecmp( type, T_NEWPARENTSTR ) == 0 665 || strcasecmp( type, T_NEWSUPERIORSTR ) == 0 ) { 666 if (( newparent = strdup( value )) == NULL ) { 667 perror( "strdup" ); 668 exit( LDAP_NO_MEMORY ); 669 } 670 } else { 671 /* Since this is an optional argument for rename/moddn, cause 672 * the current line to be re-evaluated if newparent doesn't 673 * follow deleteoldrdn. 674 */ 675 newparent = NULL; 676 goto evaluate_line; 677 } 678 } else if ( expect_deleteoldrdn ) { 679 if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) { 680 if ( *value == '\0' ) { 681 fprintf( stderr, 682 gettext("%s: missing 0 or 1 (line %d of entry: %s)\n"), 683 ldaptool_progname, linenum, dn == NULL ? "" : dn ); 684 rc = LDAP_PARAM_ERROR; 685 } else { 686 deleteoldrdn = ( *value == '0' ) ? 0 : 1; 687 expect_deleteoldrdn = 0; 688 if ( moddn ) { 689 expect_newparent = 1; 690 } 691 } 692 } else { 693 fprintf( stderr, gettext("%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n"), 694 ldaptool_progname, T_DELETEOLDRDNSTR, type, linenum, 695 dn ); 696 rc = LDAP_PARAM_ERROR; 697 } 698 got_all = 1; 699 } else if ( got_all ) { 700 fprintf( stderr, 701 gettext("%s: extra lines at end (line %d of entry %s)\n"), 702 ldaptool_progname, linenum, dn ); 703 rc = LDAP_PARAM_ERROR; 704 got_all = 1; 705 } else { 706 addmodifyop( &pmods, modop, type, value, vlen ); 707 /*There was a value to replace*/ 708 got_value = 1; 709 710 } 711 } 712 713 if ( rc == 0 ) { 714 if ( delete_entry ) { 715 #ifdef SOLARIS_LDAP_CMD 716 rc = dodelete( ld, dn ); 717 #else 718 rc = dodelete( dn ); 719 #endif /* SOLARIS_LDAP_CMD */ 720 } else if ( newrdn != NULL ) { 721 #ifdef SOLARIS_LDAP_CMD 722 rc = dorename( ld, dn, newrdn, newparent, deleteoldrdn ); 723 #else 724 rc = dorename( dn, newrdn, newparent, deleteoldrdn ); 725 #endif /* SOLARIS_LDAP_CMD */ 726 rename = 0; 727 } else { 728 729 /*Patch to fix Bug 22183 730 If pmods is null, then there is no 731 attribute to replace, so we alloc 732 an empty pmods*/ 733 if (modop == LDAP_MOD_REPLACE && !got_value && expect_sep){ 734 addmodifyop( &pmods, modop, value, NULL, 0); 735 }/*End Patch*/ 736 737 738 #ifdef SOLARIS_LDAP_CMD 739 rc = domodify( ld, dn, pmods, new_entry ); 740 #else 741 rc = domodify( dn, pmods, new_entry ); 742 #endif /* SOLARIS_LDAP_CMD */ 743 } 744 745 if ( rc == LDAP_SUCCESS ) { 746 rc = 0; 747 } 748 } 749 750 if ( dn != NULL ) { 751 free( dn ); 752 } 753 if ( newrdn != NULL ) { 754 free( newrdn ); 755 } 756 if ( newparent != NULL ) { 757 free( newparent ); 758 } 759 if ( pmods != NULL ) { 760 freepmods( pmods ); 761 } 762 763 return( rc ); 764 } 765 766 767 static int 768 #ifdef SOLARIS_LDAP_CMD 769 process_ldapmod_rec( LDAP *ld, char *rbuf ) 770 #else 771 process_ldapmod_rec( char *rbuf ) 772 #endif /* SOLARIS_LDAP_CMD */ 773 { 774 char *line, *dn, *p, *q, *attr, *value; 775 int rc, linenum, modop; 776 LDAPMod **pmods; 777 778 pmods = NULL; 779 dn = NULL; 780 linenum = 0; 781 line = rbuf; 782 rc = 0; 783 784 while ( rc == 0 && rbuf != NULL && *rbuf != '\0' ) { 785 ++linenum; 786 if (( p = strchr( rbuf, '\n' )) == NULL ) { 787 rbuf = NULL; 788 } else { 789 if ( *(p-1) == '\\' ) { /* lines ending in '\' are continued */ 790 strcpy( p - 1, p ); 791 rbuf = p; 792 continue; 793 } 794 *p++ = '\0'; 795 rbuf = p; 796 } 797 798 if ( dn == NULL ) { /* first line contains DN */ 799 if (( dn = strdup( line )) == NULL ) { 800 perror( "strdup" ); 801 exit( LDAP_NO_MEMORY ); 802 } 803 } else { 804 if (( p = strchr( line, '=' )) == NULL ) { 805 value = NULL; 806 p = line + strlen( line ); 807 } else { 808 *p++ = '\0'; 809 value = p; 810 } 811 812 for ( attr = line; *attr != '\0' && isspace( *attr ); ++attr ) { 813 ; /* skip attribute leading white space */ 814 } 815 816 for ( q = p - 1; q > attr && isspace( *q ); --q ) { 817 *q = '\0'; /* remove attribute trailing white space */ 818 } 819 820 if ( value != NULL ) { 821 while ( isspace( *value )) { 822 ++value; /* skip value leading white space */ 823 } 824 for ( q = value + strlen( value ) - 1; q > value && 825 isspace( *q ); --q ) { 826 *q = '\0'; /* remove value trailing white space */ 827 } 828 if ( *value == '\0' ) { 829 value = NULL; 830 } 831 832 } 833 834 if ( value == NULL && newval ) { 835 fprintf( stderr, gettext("%s: missing value on line %d (attr is %s)\n"), 836 ldaptool_progname, linenum, attr ); 837 rc = LDAP_PARAM_ERROR; 838 } else { 839 switch ( *attr ) { 840 case '-': 841 modop = LDAP_MOD_DELETE; 842 ++attr; 843 break; 844 case '+': 845 modop = LDAP_MOD_ADD; 846 ++attr; 847 break; 848 default: 849 #ifdef SOLARIS_LDAP_CMD 850 modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD; 851 #else 852 /*Bug 27479. Remove the add default*/ 853 fprintf(stderr, gettext("%s: Invalid parameter specified for changetype modify (line %d of entry %s)\n"), 854 ldaptool_progname, linenum, dn); 855 rc = LDAP_PARAM_ERROR; 856 #endif /* SOLARIS_LDAP_CMD */ 857 } 858 859 addmodifyop( &pmods, modop, attr, value, 860 ( value == NULL ) ? 0 : strlen( value )); 861 } 862 } 863 864 line = rbuf; 865 } 866 867 if ( rc == 0 ) { 868 if ( dn == NULL ) { 869 rc = LDAP_PARAM_ERROR; 870 #ifdef SOLARIS_LDAP_CMD 871 } else if (( rc = domodify( ld, dn, pmods, newval )) == LDAP_SUCCESS ){ 872 #else 873 } else if (( rc = domodify( dn, pmods, newval )) == LDAP_SUCCESS ){ 874 #endif /* SOLARIS_LDAP_CMD */ 875 rc = 0; 876 } 877 } 878 879 if ( pmods != NULL ) { 880 freepmods( pmods ); 881 } 882 if ( dn != NULL ) { 883 free( dn ); 884 } 885 886 return( rc ); 887 } 888 889 890 static void 891 addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen ) 892 { 893 LDAPMod **pmods; 894 int i, j, rc; 895 struct berval *bvp; 896 897 pmods = *pmodsp; 898 modop |= LDAP_MOD_BVALUES; 899 900 i = 0; 901 if ( pmods != NULL ) { 902 for ( ; pmods[ i ] != NULL; ++i ) { 903 if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 && 904 pmods[ i ]->mod_op == modop ) { 905 break; 906 } 907 } 908 } 909 910 if ( pmods == NULL || pmods[ i ] == NULL ) { 911 if (( pmods = (LDAPMod **)LDAPTOOL_SAFEREALLOC( pmods, (i + 2) * 912 sizeof( LDAPMod * ))) == NULL ) { 913 perror( "realloc" ); 914 exit( LDAP_NO_MEMORY ); 915 } 916 *pmodsp = pmods; 917 pmods[ i + 1 ] = NULL; 918 if (( pmods[ i ] = (LDAPMod *)calloc( 1, sizeof( LDAPMod ))) 919 == NULL ) { 920 perror( "calloc" ); 921 exit( LDAP_NO_MEMORY ); 922 } 923 pmods[ i ]->mod_op = modop; 924 if (( pmods[ i ]->mod_type = strdup( attr )) == NULL ) { 925 perror( "strdup" ); 926 exit( LDAP_NO_MEMORY ); 927 } 928 } 929 930 if ( value != NULL ) { 931 j = 0; 932 if ( pmods[ i ]->mod_bvalues != NULL ) { 933 for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) { 934 ; 935 } 936 } 937 if (( pmods[ i ]->mod_bvalues = (struct berval **) 938 LDAPTOOL_SAFEREALLOC( pmods[ i ]->mod_bvalues, 939 (j + 2) * sizeof( struct berval * ))) == NULL ) { 940 perror( "realloc" ); 941 exit( LDAP_NO_MEMORY ); 942 } 943 pmods[ i ]->mod_bvalues[ j + 1 ] = NULL; 944 if (( bvp = (struct berval *)malloc( sizeof( struct berval ))) 945 == NULL ) { 946 perror( "malloc" ); 947 exit( LDAP_NO_MEMORY ); 948 } 949 pmods[ i ]->mod_bvalues[ j ] = bvp; 950 951 #ifdef notdef 952 if (ldaptool_verbose) { 953 printf(gettext("%s: value: %s vlen: %d\n"), "ldapmodify", value, vlen); 954 } 955 #endif 956 rc = ldaptool_berval_from_ldif_value( value, vlen, bvp, 957 ( ldif_version >= LDIF_VERSION_ONE ), valsfromfiles, 958 1 /* report errors */ ); 959 if ( rc != LDAPTOOL_FILEURL_SUCCESS ) { 960 exit( ldaptool_fileurlerr2ldaperr( rc )); 961 } 962 } 963 } 964 965 966 static int 967 #ifdef SOLARIS_LDAP_CMD 968 domodify( LDAP *ld, char *dn, LDAPMod **pmods, int newentry ) 969 #else 970 domodify( char *dn, LDAPMod **pmods, int newentry ) 971 #endif /* SOLARIS_LDAP_CMD */ 972 { 973 int i, j, notascii, op; 974 struct berval *bvp; 975 976 if ( pmods == NULL ) { 977 fprintf( stderr, gettext("%s: no attributes to change or add (entry %s)\n"), 978 ldaptool_progname, dn ); 979 return( LDAP_PARAM_ERROR ); 980 } 981 982 if ( ldaptool_verbose ) { 983 for ( i = 0; pmods[ i ] != NULL; ++i ) { 984 op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES; 985 printf( gettext("%s %s:\n"), op == LDAP_MOD_REPLACE ? 986 gettext("replace") : op == LDAP_MOD_ADD ? 987 gettext("add") : gettext("delete"), pmods[ i ]->mod_type ); 988 if ( pmods[ i ]->mod_bvalues != NULL ) { 989 for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) { 990 bvp = pmods[ i ]->mod_bvalues[ j ]; 991 notascii = 0; 992 if ( !display_binary_values ) { 993 notascii = !ldaptool_berval_is_ascii( bvp ); 994 } 995 if ( notascii ) { 996 printf( gettext("\tNOT ASCII (%ld bytes)\n"), bvp->bv_len ); 997 } else { 998 printf( "\t%s\n", bvp->bv_val ); 999 } 1000 } 1001 } 1002 } 1003 } 1004 1005 if ( !ldapmodify_quiet) { 1006 if ( newentry ) { 1007 printf( gettext("%sadding new entry %s\n"), 1008 ldaptool_not ? "!" : "", dn ); 1009 } else { 1010 printf( gettext("%smodifying entry %s\n"), 1011 ldaptool_not ? "!" : "", dn ); 1012 } 1013 } 1014 1015 if ( !ldaptool_not ) { 1016 if ( newentry ) { 1017 unsigned int sleep_interval = 2; /* seconds */ 1018 1019 #ifdef SOLARIS_LDAP_CMD 1020 /* Backward compatibility with old Solaris command */ 1021 unsigned int nb = 0; 1022 timestruc_t to; 1023 while ((i = ldaptool_add_ext_s( ld, dn, pmods, 1024 ldaptool_request_ctrls, NULL, "ldap_add" )) 1025 != LDAP_SUCCESS) { 1026 if (i == LDAP_BUSY) { 1027 if ( sleep_interval > 3600 ) { 1028 printf(gettext("ldap_add: Unable to complete " 1029 "request. Server is too " 1030 "busy servicing other " 1031 "requests\n")); 1032 break; 1033 } 1034 if ( !ldapmodify_quiet ) { 1035 printf(gettext("ldap_add: LDAP_BUSY returned " 1036 "by server. Will retry " 1037 "operation in %d seconds\n"), 1038 sleep_interval); 1039 } 1040 sleep( sleep_interval ); 1041 sleep_interval *= 2; 1042 } else if (i == LDAP_NO_SUCH_OBJECT) { 1043 /* 1044 * Wait for the parent entry to be created by 1045 * another thread. Do not retry more than the 1046 * number of threads. 1047 */ 1048 ++nb; 1049 if (nb >= nbthreads) 1050 break; 1051 mutex_lock(&wait_mutex); 1052 to.tv_sec = 5; 1053 to.tv_nsec = 0; 1054 if (cond_reltimedwait(&wait_cond, &wait_mutex, &to) 1055 == ETIME) { 1056 nb = nbthreads; /* last chance */ 1057 } 1058 mutex_unlock(&wait_mutex); 1059 } else { 1060 break; 1061 } 1062 } 1063 cond_broadcast(&wait_cond); 1064 #else 1065 while ((i = ldaptool_add_ext_s( ld, dn, pmods, 1066 ldaptool_request_ctrls, NULL, "ldap_add" )) 1067 == LDAP_BUSY) { 1068 if ( sleep_interval > 3600 ) { 1069 printf("ldap_add: Unable to complete request. "); 1070 printf("Server is too "); 1071 printf("busy servicing other requests\n"); 1072 break; 1073 } 1074 if ( !ldapmodify_quiet ) { 1075 printf("ldap_add: LDAP_BUSY returned by server. "); 1076 printf("Will retry operation "); 1077 printf("in %d seconds\n", sleep_interval); 1078 } 1079 sleep( sleep_interval ); 1080 sleep_interval *= 2; 1081 } 1082 #endif /* SOLARIS_LDAP_CMD */ 1083 } else { 1084 i = ldaptool_modify_ext_s( ld, dn, pmods, ldaptool_request_ctrls, 1085 NULL, "ldap_modify" ); 1086 } 1087 if ( i == LDAP_SUCCESS && ldaptool_verbose ) { 1088 printf( gettext("modify complete\n") ); 1089 } 1090 } else { 1091 i = LDAP_SUCCESS; 1092 } 1093 1094 if ( !ldapmodify_quiet) { 1095 putchar( '\n' ); 1096 } 1097 1098 return( i ); 1099 } 1100 1101 1102 static int 1103 #ifdef SOLARIS_LDAP_CMD 1104 dodelete( LDAP *ld, char *dn ) 1105 #else 1106 dodelete( char *dn ) 1107 #endif /* SOLARIS_LDAP_CMD */ 1108 { 1109 int rc; 1110 1111 printf( gettext("%sdeleting entry %s\n"), ldaptool_not ? "!" : "", dn ); 1112 if ( !ldaptool_not ) { 1113 if (( rc = ldaptool_delete_ext_s( ld, dn, ldaptool_request_ctrls, 1114 NULL, "ldap_delete" )) == LDAP_SUCCESS && ldaptool_verbose ) { 1115 printf( gettext("delete complete") ); 1116 } 1117 } else { 1118 rc = LDAP_SUCCESS; 1119 } 1120 1121 putchar( '\n' ); 1122 1123 return( rc ); 1124 } 1125 1126 1127 static int 1128 #ifdef SOLARIS_LDAP_CMD 1129 dorename( LDAP *ld, char *dn, char *newrdn, char *newparent, int deleteoldrdn ) 1130 #else 1131 dorename( char *dn, char *newrdn, char *newparent, int deleteoldrdn ) 1132 #endif /* SOLARIS_LDAP_CMD */ 1133 { 1134 int rc; 1135 1136 if ( ldaptool_verbose ) { 1137 if ( newparent == NULL ) { 1138 printf(deleteoldrdn ? 1139 gettext("new RDN: %s (do not keep existing values)\n"): 1140 gettext("new RDN: %s (keep existing values)\n")); 1141 } else { 1142 printf(deleteoldrdn ? 1143 gettext("new RDN: %s, new parent %s ( do not keep existing values)\n"): 1144 gettext("new RDN: %s, new parent %s ( keep existing values)\n")); 1145 } 1146 } 1147 1148 printf( gettext("%smodifying RDN of entry %s%s\n"), 1149 ldaptool_not ? "!" : "", dn, ( newparent == NULL ) ? "" : 1150 gettext(" and/or moving it beneath a new parent\n") ); 1151 1152 if ( !ldaptool_not ) { 1153 if (( rc = ldaptool_rename_s( ld, dn, newrdn, newparent, deleteoldrdn, 1154 ldaptool_request_ctrls, NULL, "ldap_rename" )) == LDAP_SUCCESS 1155 && ldaptool_verbose ) { 1156 printf( gettext("rename completed\n") ); 1157 } 1158 } else { 1159 rc = LDAP_SUCCESS; 1160 } 1161 1162 putchar( '\n' ); 1163 1164 return( rc ); 1165 } 1166 1167 1168 static void 1169 freepmods( LDAPMod **pmods ) 1170 { 1171 int i; 1172 1173 for ( i = 0; pmods[ i ] != NULL; ++i ) { 1174 if ( pmods[ i ]->mod_bvalues != NULL ) { 1175 ber_bvecfree( pmods[ i ]->mod_bvalues ); 1176 } 1177 if ( pmods[ i ]->mod_type != NULL ) { 1178 free( pmods[ i ]->mod_type ); 1179 } 1180 free( pmods[ i ] ); 1181 } 1182 free( pmods ); 1183 } 1184 1185 1186 static char * 1187 read_one_record( FILE *fp ) 1188 { 1189 int len, gotnothing; 1190 char *buf, line[ LDAPMOD_MAXLINE ]; 1191 int lcur, lmax; 1192 1193 lcur = lmax = 0; 1194 buf = NULL; 1195 gotnothing = 1; 1196 1197 #ifdef SOLARIS_LDAP_CMD 1198 mutex_lock(&read_mutex); 1199 1200 if (fp == NULL) { 1201 mutex_unlock(&read_mutex); 1202 return(NULL); 1203 } 1204 #endif 1205 1206 while ( fgets( line, sizeof(line), fp ) != NULL ) { 1207 if ( (len = strlen( line )) < 2 ) { 1208 if ( gotnothing ) { 1209 continue; 1210 } else { 1211 break; 1212 } 1213 } 1214 1215 /* Check if the blank line starts with '\r' (CR) */ 1216 if ( ((len = strlen( line )) == 2) && (line[0] == '\r') ) { 1217 if ( gotnothing ) { 1218 continue; 1219 } else { 1220 break; 1221 } 1222 } 1223 1224 if ( *line == '#' ) { 1225 continue; /* skip comment lines */ 1226 } 1227 1228 gotnothing = 0; 1229 if ( lcur + len + 1 > lmax ) { 1230 lmax = LDAPMOD_MAXLINE 1231 * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 ); 1232 if (( buf = (char *)LDAPTOOL_SAFEREALLOC( buf, lmax )) == NULL ) { 1233 perror( "realloc" ); 1234 #ifdef SOLARIS_LDAP_CMD 1235 mutex_unlock(&read_mutex); 1236 #endif 1237 exit( LDAP_NO_MEMORY ); 1238 } 1239 } 1240 strcpy( buf + lcur, line ); 1241 lcur += len; 1242 } 1243 1244 #ifdef SOLARIS_LDAP_CMD 1245 mutex_unlock(&read_mutex); 1246 #endif 1247 1248 return( buf ); 1249 } 1250 1251 1252 /* 1253 * strdup and trim trailing blanks 1254 */ 1255 static char * 1256 strdup_and_trim( char *s ) 1257 { 1258 char *p; 1259 1260 if (( s = strdup( s )) == NULL ) { 1261 perror( "strdup" ); 1262 exit( LDAP_NO_MEMORY ); 1263 } 1264 1265 p = s + strlen( s ) - 1; 1266 while ( p >= s && isspace( *p )) { 1267 --p; 1268 } 1269 *++p = '\0'; 1270 1271 return( s ); 1272 } 1273