1/* slapcommon.c - common routine for the slap tools */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 The OpenLDAP Foundation. 6 * Portions Copyright 1998-2003 Kurt D. Zeilenga. 7 * Portions Copyright 2003 IBM Corporation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18/* ACKNOWLEDGEMENTS: 19 * This work was initially developed by Kurt Zeilenga for inclusion 20 * in OpenLDAP Software. Additional signficant contributors include 21 * Jong Hyuk Choi 22 * Hallvard B. Furuseth 23 * Howard Chu 24 * Pierangelo Masarati 25 */ 26 27#include "portable.h" 28 29#include <stdio.h> 30 31#include <ac/stdlib.h> 32#include <ac/ctype.h> 33#include <ac/string.h> 34#include <ac/socket.h> 35#include <ac/unistd.h> 36 37#include "slapcommon.h" 38#include "lutil.h" 39#include "ldif.h" 40 41tool_vars tool_globals; 42 43#ifdef CSRIMALLOC 44static char *leakfilename; 45static FILE *leakfile; 46#endif 47 48static LDIFFP dummy; 49 50#if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG) 51int start_syslog; 52static char **syslog_unknowns; 53#ifdef LOG_LOCAL4 54static int syslogUser = SLAP_DEFAULT_SYSLOG_USER; 55#endif /* LOG_LOCAL4 */ 56#endif /* LDAP_DEBUG && LDAP_SYSLOG */ 57 58static void 59usage( int tool, const char *progname ) 60{ 61 char *options = NULL; 62 fprintf( stderr, 63 "usage: %s [-v] [-d debuglevel] [-f configfile] [-F configdir] [-o <name>[=<value>]]", 64 progname ); 65 66 switch( tool ) { 67 case SLAPACL: 68 options = "\n\t[-U authcID | -D authcDN] [-X authzID | -o authzDN=<DN>]" 69 "\n\t-b DN [-u] [attr[/access][:value]] [...]\n"; 70 break; 71 72 case SLAPADD: 73 options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]\n" 74 "\t[-l ldiffile] [-j linenumber] [-q] [-u] [-s] [-w]\n"; 75 break; 76 77 case SLAPAUTH: 78 options = "\n\t[-U authcID] [-X authzID] [-R realm] [-M mech] ID [...]\n"; 79 break; 80 81 case SLAPCAT: 82 options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]" 83 " [-l ldiffile] [-a filter] [-s subtree] [-H url]\n"; 84 break; 85 86 case SLAPDN: 87 options = "\n\t[-N | -P] DN [...]\n"; 88 break; 89 90 case SLAPINDEX: 91 options = " [-c]\n\t[-g] [-n databasenumber | -b suffix] [attr ...] [-q] [-t]\n"; 92 break; 93 94 case SLAPTEST: 95 options = " [-n databasenumber] [-u]\n"; 96 break; 97 98 case SLAPSCHEMA: 99 options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]" 100 " [-l errorfile] [-a filter] [-s subtree] [-H url]\n"; 101 break; 102 } 103 104 if ( options != NULL ) { 105 fputs( options, stderr ); 106 } 107 exit( EXIT_FAILURE ); 108} 109 110static int 111parse_slapopt( int tool, int *mode ) 112{ 113 size_t len = 0; 114 char *p; 115 116 p = strchr( optarg, '=' ); 117 if ( p != NULL ) { 118 len = p - optarg; 119 p++; 120 } 121 122 if ( strncasecmp( optarg, "sockurl", len ) == 0 ) { 123 if ( !BER_BVISNULL( &listener_url ) ) { 124 ber_memfree( listener_url.bv_val ); 125 } 126 ber_str2bv( p, 0, 1, &listener_url ); 127 128 } else if ( strncasecmp( optarg, "domain", len ) == 0 ) { 129 if ( !BER_BVISNULL( &peer_domain ) ) { 130 ber_memfree( peer_domain.bv_val ); 131 } 132 ber_str2bv( p, 0, 1, &peer_domain ); 133 134 } else if ( strncasecmp( optarg, "peername", len ) == 0 ) { 135 if ( !BER_BVISNULL( &peer_name ) ) { 136 ber_memfree( peer_name.bv_val ); 137 } 138 ber_str2bv( p, 0, 1, &peer_name ); 139 140 } else if ( strncasecmp( optarg, "sockname", len ) == 0 ) { 141 if ( !BER_BVISNULL( &sock_name ) ) { 142 ber_memfree( sock_name.bv_val ); 143 } 144 ber_str2bv( p, 0, 1, &sock_name ); 145 146 } else if ( strncasecmp( optarg, "ssf", len ) == 0 ) { 147 if ( lutil_atou( &ssf, p ) ) { 148 Debug( LDAP_DEBUG_ANY, "unable to parse ssf=\"%s\".\n", p, 0, 0 ); 149 return -1; 150 } 151 152 } else if ( strncasecmp( optarg, "transport_ssf", len ) == 0 ) { 153 if ( lutil_atou( &transport_ssf, p ) ) { 154 Debug( LDAP_DEBUG_ANY, "unable to parse transport_ssf=\"%s\".\n", p, 0, 0 ); 155 return -1; 156 } 157 158 } else if ( strncasecmp( optarg, "tls_ssf", len ) == 0 ) { 159 if ( lutil_atou( &tls_ssf, p ) ) { 160 Debug( LDAP_DEBUG_ANY, "unable to parse tls_ssf=\"%s\".\n", p, 0, 0 ); 161 return -1; 162 } 163 164 } else if ( strncasecmp( optarg, "sasl_ssf", len ) == 0 ) { 165 if ( lutil_atou( &sasl_ssf, p ) ) { 166 Debug( LDAP_DEBUG_ANY, "unable to parse sasl_ssf=\"%s\".\n", p, 0, 0 ); 167 return -1; 168 } 169 170 } else if ( strncasecmp( optarg, "authzDN", len ) == 0 ) { 171 ber_str2bv( p, 0, 1, &authzDN ); 172 173#if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG) 174 } else if ( strncasecmp( optarg, "syslog", len ) == 0 ) { 175 if ( parse_debug_level( p, &ldap_syslog, &syslog_unknowns ) ) { 176 return -1; 177 } 178 start_syslog = 1; 179 180 } else if ( strncasecmp( optarg, "syslog-level", len ) == 0 ) { 181 if ( parse_syslog_level( p, &ldap_syslog_level ) ) { 182 return -1; 183 } 184 start_syslog = 1; 185 186#ifdef LOG_LOCAL4 187 } else if ( strncasecmp( optarg, "syslog-user", len ) == 0 ) { 188 if ( parse_syslog_user( p, &syslogUser ) ) { 189 return -1; 190 } 191 start_syslog = 1; 192#endif /* LOG_LOCAL4 */ 193#endif /* LDAP_DEBUG && LDAP_SYSLOG */ 194 195 } else if ( strncasecmp( optarg, "schema-check", len ) == 0 ) { 196 switch ( tool ) { 197 case SLAPADD: 198 if ( strcasecmp( p, "yes" ) == 0 ) { 199 *mode &= ~SLAP_TOOL_NO_SCHEMA_CHECK; 200 } else if ( strcasecmp( p, "no" ) == 0 ) { 201 *mode |= SLAP_TOOL_NO_SCHEMA_CHECK; 202 } else { 203 Debug( LDAP_DEBUG_ANY, "unable to parse schema-check=\"%s\".\n", p, 0, 0 ); 204 return -1; 205 } 206 break; 207 208 default: 209 Debug( LDAP_DEBUG_ANY, "schema-check meaningless for tool.\n", 0, 0, 0 ); 210 break; 211 } 212 213 } else if ( strncasecmp( optarg, "value-check", len ) == 0 ) { 214 switch ( tool ) { 215 case SLAPADD: 216 if ( strcasecmp( p, "yes" ) == 0 ) { 217 *mode |= SLAP_TOOL_VALUE_CHECK; 218 } else if ( strcasecmp( p, "no" ) == 0 ) { 219 *mode &= ~SLAP_TOOL_VALUE_CHECK; 220 } else { 221 Debug( LDAP_DEBUG_ANY, "unable to parse value-check=\"%s\".\n", p, 0, 0 ); 222 return -1; 223 } 224 break; 225 226 default: 227 Debug( LDAP_DEBUG_ANY, "value-check meaningless for tool.\n", 0, 0, 0 ); 228 break; 229 } 230 231 } else if ( strncasecmp( optarg, "ldif-wrap", len ) == 0 ) { 232 switch ( tool ) { 233 case SLAPCAT: 234 if ( strcasecmp( p, "no" ) == 0 ) { 235 ldif_wrap = LDIF_LINE_WIDTH_MAX; 236 237 } else { 238 unsigned int u; 239 if ( lutil_atou( &u, p ) ) { 240 Debug( LDAP_DEBUG_ANY, "unable to parse ldif-wrap=\"%s\".\n", p, 0, 0 ); 241 return -1; 242 } 243 ldif_wrap = (ber_len_t)u; 244 } 245 break; 246 247 default: 248 Debug( LDAP_DEBUG_ANY, "value-check meaningless for tool.\n", 0, 0, 0 ); 249 break; 250 } 251 252 } else { 253 return -1; 254 } 255 256 return 0; 257} 258 259/* 260 * slap_tool_init - initialize slap utility, handle program options. 261 * arguments: 262 * name program name 263 * tool tool code 264 * argc, argv command line arguments 265 */ 266 267static int need_shutdown; 268 269void 270slap_tool_init( 271 const char* progname, 272 int tool, 273 int argc, char **argv ) 274{ 275 char *options; 276 char *conffile = NULL; 277 char *confdir = NULL; 278 struct berval base = BER_BVNULL; 279 char *filterstr = NULL; 280 char *subtree = NULL; 281 char *ldiffile = NULL; 282 char **debug_unknowns = NULL; 283 int rc, i; 284 int mode = SLAP_TOOL_MODE; 285 int truncatemode = 0; 286 int use_glue = 1; 287 int writer; 288 289#ifdef LDAP_DEBUG 290 /* tools default to "none", so that at least LDAP_DEBUG_ANY 291 * messages show up; use -d 0 to reset */ 292 slap_debug = LDAP_DEBUG_NONE; 293 ldif_debug = slap_debug; 294#endif 295 ldap_syslog = 0; 296 297#ifdef CSRIMALLOC 298 leakfilename = malloc( strlen( progname ) + STRLENOF( ".leak" ) + 1 ); 299 sprintf( leakfilename, "%s.leak", progname ); 300 if( ( leakfile = fopen( leakfilename, "w" )) == NULL ) { 301 leakfile = stderr; 302 } 303 free( leakfilename ); 304 leakfilename = NULL; 305#endif 306 307 ldif_wrap = LDIF_LINE_WIDTH; 308 309 scope = LDAP_SCOPE_DEFAULT; 310 311 switch( tool ) { 312 case SLAPADD: 313 options = "b:cd:f:F:gj:l:n:o:qsS:uvw"; 314 break; 315 316 case SLAPCAT: 317 options = "a:b:cd:f:F:gH:l:n:o:s:v"; 318 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 319 break; 320 321 case SLAPDN: 322 options = "d:f:F:No:Pv"; 323 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 324 break; 325 326 case SLAPSCHEMA: 327 options = "a:b:cd:f:F:gH:l:n:o:s:v"; 328 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 329 break; 330 331 case SLAPTEST: 332 options = "d:f:F:n:o:Quv"; 333 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 334 break; 335 336 case SLAPAUTH: 337 options = "d:f:F:M:o:R:U:vX:"; 338 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 339 break; 340 341 case SLAPINDEX: 342 options = "b:cd:f:F:gn:o:qtv"; 343 mode |= SLAP_TOOL_READMAIN; 344 break; 345 346 case SLAPACL: 347 options = "b:D:d:f:F:o:uU:vX:"; 348 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 349 break; 350 351 default: 352 fprintf( stderr, "%s: unknown tool mode (%d)\n", progname, tool ); 353 exit( EXIT_FAILURE ); 354 } 355 356 dbnum = -1; 357 while ( (i = getopt( argc, argv, options )) != EOF ) { 358 switch ( i ) { 359 case 'a': 360 filterstr = ch_strdup( optarg ); 361 break; 362 363 case 'b': 364 ber_str2bv( optarg, 0, 1, &base ); 365 break; 366 367 case 'c': /* enable continue mode */ 368 continuemode++; 369 break; 370 371 case 'd': { /* turn on debugging */ 372 int level = 0; 373 374 if ( parse_debug_level( optarg, &level, &debug_unknowns ) ) { 375 usage( tool, progname ); 376 } 377#ifdef LDAP_DEBUG 378 if ( level == 0 ) { 379 /* allow to reset log level */ 380 slap_debug = 0; 381 382 } else { 383 slap_debug |= level; 384 } 385#else 386 if ( level != 0 ) 387 fputs( "must compile with LDAP_DEBUG for debugging\n", 388 stderr ); 389#endif 390 } break; 391 392 case 'D': 393 ber_str2bv( optarg, 0, 1, &authcDN ); 394 break; 395 396 case 'f': /* specify a conf file */ 397 conffile = ch_strdup( optarg ); 398 break; 399 400 case 'F': /* specify a conf dir */ 401 confdir = ch_strdup( optarg ); 402 break; 403 404 case 'g': /* disable subordinate glue */ 405 use_glue = 0; 406 break; 407 408 case 'H': { 409 LDAPURLDesc *ludp; 410 int rc; 411 412 rc = ldap_url_parse_ext( optarg, &ludp, 413 LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_NOEMPTY_DN ); 414 if ( rc != LDAP_URL_SUCCESS ) { 415 usage( tool, progname ); 416 } 417 418 /* don't accept host, port, attrs, extensions */ 419 if ( ldap_pvt_url_scheme2proto( ludp->lud_scheme ) != LDAP_PROTO_TCP ) { 420 usage( tool, progname ); 421 } 422 423 if ( ludp->lud_host != NULL ) { 424 usage( tool, progname ); 425 } 426 427 if ( ludp->lud_port != 0 ) { 428 usage( tool, progname ); 429 } 430 431 if ( ludp->lud_attrs != NULL ) { 432 usage( tool, progname ); 433 } 434 435 if ( ludp->lud_exts != NULL ) { 436 usage( tool, progname ); 437 } 438 439 if ( ludp->lud_dn != NULL && ludp->lud_dn[0] != '\0' ) { 440 subtree = ludp->lud_dn; 441 ludp->lud_dn = NULL; 442 } 443 444 if ( ludp->lud_filter != NULL && ludp->lud_filter[0] != '\0' ) { 445 filterstr = ludp->lud_filter; 446 ludp->lud_filter = NULL; 447 } 448 449 scope = ludp->lud_scope; 450 451 ldap_free_urldesc( ludp ); 452 } break; 453 454 case 'j': /* jump to linenumber */ 455 if ( lutil_atoi( &jumpline, optarg ) ) { 456 usage( tool, progname ); 457 } 458 break; 459 460 case 'l': /* LDIF file */ 461 ldiffile = ch_strdup( optarg ); 462 break; 463 464 case 'M': 465 ber_str2bv( optarg, 0, 0, &mech ); 466 break; 467 468 case 'N': 469 if ( dn_mode && dn_mode != SLAP_TOOL_LDAPDN_NORMAL ) { 470 usage( tool, progname ); 471 } 472 dn_mode = SLAP_TOOL_LDAPDN_NORMAL; 473 break; 474 475 case 'n': /* which config file db to index */ 476 if ( lutil_atoi( &dbnum, optarg ) || dbnum < 0 ) { 477 usage( tool, progname ); 478 } 479 break; 480 481 case 'o': 482 if ( parse_slapopt( tool, &mode ) ) { 483 usage( tool, progname ); 484 } 485 break; 486 487 case 'P': 488 if ( dn_mode && dn_mode != SLAP_TOOL_LDAPDN_PRETTY ) { 489 usage( tool, progname ); 490 } 491 dn_mode = SLAP_TOOL_LDAPDN_PRETTY; 492 break; 493 494 case 'Q': 495 quiet++; 496 slap_debug = 0; 497 break; 498 499 case 'q': /* turn on quick */ 500 mode |= SLAP_TOOL_QUICK; 501 break; 502 503 case 'R': 504 realm = optarg; 505 break; 506 507 case 'S': 508 if ( lutil_atou( &csnsid, optarg ) 509 || csnsid > SLAP_SYNC_SID_MAX ) 510 { 511 usage( tool, progname ); 512 } 513 break; 514 515 case 's': 516 switch ( tool ) { 517 case SLAPADD: 518 /* no schema check */ 519 mode |= SLAP_TOOL_NO_SCHEMA_CHECK; 520 break; 521 522 case SLAPCAT: 523 case SLAPSCHEMA: 524 /* dump subtree */ 525 subtree = ch_strdup( optarg ); 526 break; 527 } 528 break; 529 530 case 't': /* turn on truncate */ 531 truncatemode++; 532 mode |= SLAP_TRUNCATE_MODE; 533 break; 534 535 case 'U': 536 ber_str2bv( optarg, 0, 0, &authcID ); 537 break; 538 539 case 'u': /* dry run */ 540 dryrun++; 541 break; 542 543 case 'v': /* turn on verbose */ 544 verbose++; 545 break; 546 547 case 'w': /* write context csn at the end */ 548 update_ctxcsn++; 549 break; 550 551 case 'X': 552 ber_str2bv( optarg, 0, 0, &authzID ); 553 break; 554 555 default: 556 usage( tool, progname ); 557 break; 558 } 559 } 560 561#if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG) 562 if ( start_syslog ) { 563 char *logName; 564#ifdef HAVE_EBCDIC 565 logName = ch_strdup( progname ); 566 __atoe( logName ); 567#else 568 logName = (char *)progname; 569#endif 570 571#ifdef LOG_LOCAL4 572 openlog( logName, OPENLOG_OPTIONS, syslogUser ); 573#elif defined LOG_DEBUG 574 openlog( logName, OPENLOG_OPTIONS ); 575#endif 576#ifdef HAVE_EBCDIC 577 free( logName ); 578 logName = NULL; 579#endif 580 } 581#endif /* LDAP_DEBUG && LDAP_SYSLOG */ 582 583 switch ( tool ) { 584 case SLAPCAT: 585 case SLAPSCHEMA: 586 writer = 1; 587 break; 588 589 default: 590 writer = 0; 591 break; 592 } 593 594 switch ( tool ) { 595 case SLAPADD: 596 case SLAPCAT: 597 case SLAPSCHEMA: 598 if ( ( argc != optind ) || (dbnum >= 0 && base.bv_val != NULL ) ) { 599 usage( tool, progname ); 600 } 601 602 break; 603 604 case SLAPINDEX: 605 if ( dbnum >= 0 && base.bv_val != NULL ) { 606 usage( tool, progname ); 607 } 608 609 break; 610 611 case SLAPDN: 612 if ( argc == optind ) { 613 usage( tool, progname ); 614 } 615 break; 616 617 case SLAPAUTH: 618 if ( argc == optind && BER_BVISNULL( &authcID ) ) { 619 usage( tool, progname ); 620 } 621 break; 622 623 case SLAPTEST: 624 if ( argc != optind ) { 625 usage( tool, progname ); 626 } 627 break; 628 629 case SLAPACL: 630 if ( !BER_BVISNULL( &authcDN ) && !BER_BVISNULL( &authcID ) ) { 631 usage( tool, progname ); 632 } 633 if ( BER_BVISNULL( &base ) ) { 634 usage( tool, progname ); 635 } 636 ber_dupbv( &baseDN, &base ); 637 break; 638 639 default: 640 break; 641 } 642 643 if ( ldiffile == NULL ) { 644 dummy.fp = writer ? stdout : stdin; 645 ldiffp = &dummy; 646 647 } else if ((ldiffp = ldif_open( ldiffile, writer ? "w" : "r" )) 648 == NULL ) 649 { 650 perror( ldiffile ); 651 exit( EXIT_FAILURE ); 652 } 653 654 /* 655 * initialize stuff and figure out which backend we're dealing with 656 */ 657 658 rc = slap_init( mode, progname ); 659 if ( rc != 0 ) { 660 fprintf( stderr, "%s: slap_init failed!\n", progname ); 661 exit( EXIT_FAILURE ); 662 } 663 664 rc = read_config( conffile, confdir ); 665 666 if ( rc != 0 ) { 667 fprintf( stderr, "%s: bad configuration %s!\n", 668 progname, confdir ? "directory" : "file" ); 669 exit( EXIT_FAILURE ); 670 } 671 672 if ( debug_unknowns ) { 673 rc = parse_debug_unknowns( debug_unknowns, &slap_debug ); 674 ldap_charray_free( debug_unknowns ); 675 debug_unknowns = NULL; 676 if ( rc ) 677 exit( EXIT_FAILURE ); 678 } 679 680#if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG) 681 if ( syslog_unknowns ) { 682 rc = parse_debug_unknowns( syslog_unknowns, &ldap_syslog ); 683 ldap_charray_free( syslog_unknowns ); 684 syslog_unknowns = NULL; 685 if ( rc ) 686 exit( EXIT_FAILURE ); 687 } 688#endif 689 690 at_oc_cache = 1; 691 692 switch ( tool ) { 693 case SLAPADD: 694 case SLAPCAT: 695 case SLAPINDEX: 696 case SLAPSCHEMA: 697 if ( !nbackends ) { 698 fprintf( stderr, "No databases found " 699 "in config file\n" ); 700 exit( EXIT_FAILURE ); 701 } 702 break; 703 704 default: 705 break; 706 } 707 708 if ( use_glue ) { 709 rc = glue_sub_attach( 0 ); 710 711 if ( rc != 0 ) { 712 fprintf( stderr, 713 "%s: subordinate configuration error\n", progname ); 714 exit( EXIT_FAILURE ); 715 } 716 } 717 718 rc = slap_schema_check(); 719 720 if ( rc != 0 ) { 721 fprintf( stderr, "%s: slap_schema_prep failed!\n", progname ); 722 exit( EXIT_FAILURE ); 723 } 724 725 switch ( tool ) { 726 case SLAPTEST: 727 if ( dbnum >= 0 ) 728 goto get_db; 729 /* FALLTHRU */ 730 case SLAPDN: 731 case SLAPAUTH: 732 be = NULL; 733 goto startup; 734 735 default: 736 break; 737 } 738 739 if( filterstr ) { 740 filter = str2filter( filterstr ); 741 742 if( filter == NULL ) { 743 fprintf( stderr, "Invalid filter '%s'\n", filterstr ); 744 exit( EXIT_FAILURE ); 745 } 746 747 ch_free( filterstr ); 748 filterstr = NULL; 749 } 750 751 if( subtree ) { 752 struct berval val; 753 ber_str2bv( subtree, 0, 0, &val ); 754 rc = dnNormalize( 0, NULL, NULL, &val, &sub_ndn, NULL ); 755 if( rc != LDAP_SUCCESS ) { 756 fprintf( stderr, "Invalid subtree DN '%s'\n", subtree ); 757 exit( EXIT_FAILURE ); 758 } 759 760 if ( BER_BVISNULL( &base ) && dbnum == -1 ) { 761 base = val; 762 } else { 763 free( subtree ); 764 subtree = NULL; 765 } 766 } 767 768 if( base.bv_val != NULL ) { 769 struct berval nbase; 770 771 rc = dnNormalize( 0, NULL, NULL, &base, &nbase, NULL ); 772 if( rc != LDAP_SUCCESS ) { 773 fprintf( stderr, "%s: slap_init invalid suffix (\"%s\")\n", 774 progname, base.bv_val ); 775 exit( EXIT_FAILURE ); 776 } 777 778 be = select_backend( &nbase, 0 ); 779 ber_memfree( nbase.bv_val ); 780 BER_BVZERO( &nbase ); 781 782 switch ( tool ) { 783 case SLAPACL: 784 goto startup; 785 786 default: 787 break; 788 } 789 790 if( be == NULL ) { 791 fprintf( stderr, "%s: slap_init no backend for \"%s\"\n", 792 progname, base.bv_val ); 793 exit( EXIT_FAILURE ); 794 } 795 /* If the named base is a glue master, operate on the 796 * entire context 797 */ 798 if ( SLAP_GLUE_INSTANCE( be ) ) { 799 nosubordinates = 1; 800 } 801 802 ch_free( base.bv_val ); 803 BER_BVZERO( &base ); 804 805 } else if ( dbnum == -1 ) { 806 /* no suffix and no dbnum specified, just default to 807 * the first available database 808 */ 809 if ( nbackends <= 0 ) { 810 fprintf( stderr, "No available databases\n" ); 811 exit( EXIT_FAILURE ); 812 } 813 LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { 814 dbnum++; 815 816 /* db #0 is cn=config, don't select it as a default */ 817 if ( dbnum < 1 ) continue; 818 819 if ( SLAP_MONITOR(be)) 820 continue; 821 822 /* If just doing the first by default and it is a 823 * glue subordinate, find the master. 824 */ 825 if ( SLAP_GLUE_SUBORDINATE(be) ) { 826 nosubordinates = 1; 827 continue; 828 } 829 break; 830 } 831 832 if ( !be ) { 833 fprintf( stderr, "Available database(s) " 834 "do not allow %s\n", progname ); 835 exit( EXIT_FAILURE ); 836 } 837 838 if ( nosubordinates == 0 && dbnum > 1 ) { 839 Debug( LDAP_DEBUG_ANY, 840 "The first database does not allow %s;" 841 " using the first available one (%d)\n", 842 progname, dbnum, 0 ); 843 } 844 845 } else if ( dbnum >= nbackends ) { 846 fprintf( stderr, 847 "Database number selected via -n is out of range\n" 848 "Must be in the range 0 to %d" 849 " (the number of configured databases)\n", 850 nbackends - 1 ); 851 exit( EXIT_FAILURE ); 852 853 } else { 854get_db: 855 LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { 856 if ( dbnum == 0 ) break; 857 dbnum--; 858 } 859 } 860 861 if ( scope != LDAP_SCOPE_DEFAULT && BER_BVISNULL( &sub_ndn ) ) { 862 if ( be && be->be_nsuffix ) { 863 ber_dupbv( &sub_ndn, be->be_nsuffix ); 864 865 } else { 866 fprintf( stderr, 867 "<scope> needs a DN or a valid database\n" ); 868 exit( EXIT_FAILURE ); 869 } 870 } 871 872startup:; 873 if ( be ) { 874 BackendDB *bdtmp; 875 876 dbnum = 0; 877 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) { 878 if ( bdtmp == be ) break; 879 dbnum++; 880 } 881 } 882 883#ifdef CSRIMALLOC 884 mal_leaktrace(1); 885#endif 886 887 if ( conffile != NULL ) { 888 ch_free( conffile ); 889 conffile = NULL; 890 } 891 892 if ( confdir != NULL ) { 893 ch_free( confdir ); 894 confdir = NULL; 895 } 896 897 if ( ldiffile != NULL ) { 898 ch_free( ldiffile ); 899 ldiffile = NULL; 900 } 901 902 /* slapdn doesn't specify a backend to startup */ 903 if ( !dryrun && tool != SLAPDN ) { 904 need_shutdown = 1; 905 906 if ( slap_startup( be ) ) { 907 switch ( tool ) { 908 case SLAPTEST: 909 fprintf( stderr, "slap_startup failed " 910 "(test would succeed using " 911 "the -u switch)\n" ); 912 break; 913 914 default: 915 fprintf( stderr, "slap_startup failed\n" ); 916 break; 917 } 918 919 exit( EXIT_FAILURE ); 920 } 921 } 922} 923 924int slap_tool_destroy( void ) 925{ 926 int rc = 0; 927 if ( !dryrun ) { 928 if ( need_shutdown ) { 929 if ( slap_shutdown( be )) 930 rc = EXIT_FAILURE; 931 } 932 if ( slap_destroy()) 933 rc = EXIT_FAILURE; 934 } 935#ifdef SLAPD_MODULES 936 if ( slapMode == SLAP_SERVER_MODE ) { 937 /* always false. just pulls in necessary symbol references. */ 938 lutil_uuidstr(NULL, 0); 939 } 940 module_kill(); 941#endif 942 schema_destroy(); 943#ifdef HAVE_TLS 944 ldap_pvt_tls_destroy(); 945#endif 946 config_destroy(); 947 948#ifdef CSRIMALLOC 949 mal_dumpleaktrace( leakfile ); 950#endif 951 952 if ( !BER_BVISNULL( &authcDN ) ) { 953 ch_free( authcDN.bv_val ); 954 BER_BVZERO( &authcDN ); 955 } 956 957 if ( ldiffp && ldiffp != &dummy ) { 958 ldif_close( ldiffp ); 959 } 960 return rc; 961} 962 963int 964slap_tool_update_ctxcsn( 965 const char *progname, 966 unsigned long sid, 967 struct berval *bvtext ) 968{ 969 struct berval ctxdn; 970 ID ctxcsn_id; 971 Entry *ctxcsn_e; 972 int rc = EXIT_SUCCESS; 973 974 if ( !(update_ctxcsn && !dryrun && sid != SLAP_SYNC_SID_MAX + 1) ) { 975 return rc; 976 } 977 978 if ( SLAP_SYNC_SUBENTRY( be )) { 979 build_new_dn( &ctxdn, &be->be_nsuffix[0], 980 (struct berval *)&slap_ldapsync_cn_bv, NULL ); 981 } else { 982 ctxdn = be->be_nsuffix[0]; 983 } 984 ctxcsn_id = be->be_dn2id_get( be, &ctxdn ); 985 if ( ctxcsn_id == NOID ) { 986 if ( SLAP_SYNC_SUBENTRY( be )) { 987 ctxcsn_e = slap_create_context_csn_entry( be, NULL ); 988 for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) { 989 if ( maxcsn[ sid ].bv_len ) { 990 attr_merge_one( ctxcsn_e, slap_schema.si_ad_contextCSN, 991 &maxcsn[ sid ], NULL ); 992 } 993 } 994 ctxcsn_id = be->be_entry_put( be, ctxcsn_e, bvtext ); 995 if ( ctxcsn_id == NOID ) { 996 fprintf( stderr, "%s: couldn't create context entry\n", progname ); 997 rc = EXIT_FAILURE; 998 } 999 } else { 1000 fprintf( stderr, "%s: context entry is missing\n", progname ); 1001 rc = EXIT_FAILURE; 1002 } 1003 } else { 1004 ctxcsn_e = be->be_entry_get( be, ctxcsn_id ); 1005 if ( ctxcsn_e != NULL ) { 1006 Entry *e = entry_dup( ctxcsn_e ); 1007 int change; 1008 Attribute *attr = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN ); 1009 if ( attr ) { 1010 int i; 1011 1012 change = 0; 1013 1014 for ( i = 0; !BER_BVISNULL( &attr->a_nvals[ i ] ); i++ ) { 1015 int rc_sid; 1016 int match; 1017 const char *text = NULL; 1018 1019 rc_sid = slap_parse_csn_sid( &attr->a_nvals[ i ] ); 1020 if ( rc_sid < 0 ) { 1021 Debug( LDAP_DEBUG_ANY, 1022 "%s: unable to extract SID " 1023 "from #%d contextCSN=%s\n", 1024 progname, i, 1025 attr->a_nvals[ i ].bv_val ); 1026 continue; 1027 } 1028 1029 assert( rc_sid <= SLAP_SYNC_SID_MAX ); 1030 1031 sid = (unsigned)rc_sid; 1032 1033 if ( maxcsn[ sid ].bv_len == 0 ) { 1034 match = -1; 1035 1036 } else { 1037 value_match( &match, slap_schema.si_ad_entryCSN, 1038 slap_schema.si_ad_entryCSN->ad_type->sat_ordering, 1039 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 1040 &maxcsn[ sid ], &attr->a_nvals[i], &text ); 1041 } 1042 1043 if ( match > 0 ) { 1044 change = 1; 1045 } else { 1046 AC_MEMCPY( maxcsn[ sid ].bv_val, 1047 attr->a_nvals[ i ].bv_val, 1048 attr->a_nvals[ i ].bv_len ); 1049 maxcsn[ sid ].bv_val[ attr->a_nvals[ i ].bv_len ] = '\0'; 1050 maxcsn[ sid ].bv_len = attr->a_nvals[ i ].bv_len; 1051 } 1052 } 1053 1054 if ( change ) { 1055 if ( attr->a_nvals != attr->a_vals ) { 1056 ber_bvarray_free( attr->a_nvals ); 1057 } 1058 attr->a_nvals = NULL; 1059 ber_bvarray_free( attr->a_vals ); 1060 attr->a_vals = NULL; 1061 attr->a_numvals = 0; 1062 } 1063 } else { 1064 change = 1; 1065 } 1066 1067 if ( change ) { 1068 for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) { 1069 if ( maxcsn[ sid ].bv_len ) { 1070 attr_merge_one( e, slap_schema.si_ad_contextCSN, 1071 &maxcsn[ sid], NULL ); 1072 } 1073 } 1074 1075 ctxcsn_id = be->be_entry_modify( be, e, bvtext ); 1076 if( ctxcsn_id == NOID ) { 1077 fprintf( stderr, "%s: could not modify ctxcsn (%s)\n", 1078 progname, bvtext->bv_val ? bvtext->bv_val : "" ); 1079 rc = EXIT_FAILURE; 1080 } else if ( verbose ) { 1081 fprintf( stderr, "modified: \"%s\" (%08lx)\n", 1082 e->e_dn, (long) ctxcsn_id ); 1083 } 1084 } 1085 entry_free( e ); 1086 } 1087 } 1088 1089 return rc; 1090} 1091 1092/* 1093 * return value: 1094 * -1: update_ctxcsn == 0 1095 * SLAP_SYNC_SID_MAX + 1: unable to extract SID 1096 * 0 <= SLAP_SYNC_SID_MAX: the SID 1097 */ 1098unsigned long 1099slap_tool_update_ctxcsn_check( 1100 const char *progname, 1101 Entry *e ) 1102{ 1103 if ( update_ctxcsn ) { 1104 unsigned long sid = SLAP_SYNC_SID_MAX + 1; 1105 int rc_sid; 1106 Attribute *attr; 1107 1108 attr = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ); 1109 assert( attr != NULL ); 1110 1111 rc_sid = slap_parse_csn_sid( &attr->a_nvals[ 0 ] ); 1112 if ( rc_sid < 0 ) { 1113 Debug( LDAP_DEBUG_ANY, "%s: could not " 1114 "extract SID from entryCSN=%s, entry dn=\"%s\"\n", 1115 progname, attr->a_nvals[ 0 ].bv_val, e->e_name.bv_val ); 1116 return (unsigned long)(-1); 1117 1118 } else { 1119 int match; 1120 const char *text = NULL; 1121 1122 assert( rc_sid <= SLAP_SYNC_SID_MAX ); 1123 1124 sid = (unsigned)rc_sid; 1125 if ( maxcsn[ sid ].bv_len != 0 ) { 1126 match = 0; 1127 value_match( &match, slap_schema.si_ad_entryCSN, 1128 slap_schema.si_ad_entryCSN->ad_type->sat_ordering, 1129 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 1130 &maxcsn[ sid ], &attr->a_nvals[0], &text ); 1131 } else { 1132 match = -1; 1133 } 1134 if ( match < 0 ) { 1135 strcpy( maxcsn[ sid ].bv_val, attr->a_nvals[0].bv_val ); 1136 maxcsn[ sid ].bv_len = attr->a_nvals[0].bv_len; 1137 } 1138 } 1139 } 1140 1141 return (unsigned long)(-1); 1142} 1143 1144int 1145slap_tool_update_ctxcsn_init(void) 1146{ 1147 if ( update_ctxcsn ) { 1148 unsigned long sid; 1149 maxcsn[ 0 ].bv_val = maxcsnbuf; 1150 for ( sid = 1; sid <= SLAP_SYNC_SID_MAX; sid++ ) { 1151 maxcsn[ sid ].bv_val = maxcsn[ sid - 1 ].bv_val + LDAP_PVT_CSNSTR_BUFSIZE; 1152 maxcsn[ sid ].bv_len = 0; 1153 } 1154 } 1155 1156 return 0; 1157} 1158 1159int 1160slap_tool_entry_check( 1161 const char *progname, 1162 Operation *op, 1163 Entry *e, 1164 int lineno, 1165 const char **text, 1166 char *textbuf, 1167 size_t textlen ) 1168{ 1169 /* NOTE: we may want to conditionally enable manage */ 1170 int manage = 0; 1171 1172 Attribute *oc = attr_find( e->e_attrs, 1173 slap_schema.si_ad_objectClass ); 1174 1175 if( oc == NULL ) { 1176 fprintf( stderr, "%s: dn=\"%s\" (line=%d): %s\n", 1177 progname, e->e_dn, lineno, 1178 "no objectClass attribute"); 1179 return LDAP_NO_SUCH_ATTRIBUTE; 1180 } 1181 1182 /* check schema */ 1183 op->o_bd = be; 1184 1185 if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) { 1186 int rc = entry_schema_check( op, e, NULL, manage, 1, NULL, 1187 text, textbuf, textlen ); 1188 1189 if( rc != LDAP_SUCCESS ) { 1190 fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n", 1191 progname, e->e_dn, lineno, rc, *text ); 1192 return rc; 1193 } 1194 textbuf[ 0 ] = '\0'; 1195 } 1196 1197 if ( (slapMode & SLAP_TOOL_VALUE_CHECK) != 0) { 1198 Modifications *ml = NULL; 1199 1200 int rc = slap_entry2mods( e, &ml, text, textbuf, textlen ); 1201 if ( rc != LDAP_SUCCESS ) { 1202 fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n", 1203 progname, e->e_dn, lineno, rc, *text ); 1204 return rc; 1205 } 1206 textbuf[ 0 ] = '\0'; 1207 1208 rc = slap_mods_check( op, ml, text, textbuf, textlen, NULL ); 1209 slap_mods_free( ml, 1 ); 1210 if ( rc != LDAP_SUCCESS ) { 1211 fprintf( stderr, "%s: dn=\"%s\" (line=%d): (%d) %s\n", 1212 progname, e->e_dn, lineno, rc, *text ); 1213 return rc; 1214 } 1215 textbuf[ 0 ] = '\0'; 1216 } 1217 1218 return LDAP_SUCCESS; 1219} 1220 1221