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