1/* $NetBSD: slapcommon.c,v 1.3 2021/08/14 16:14: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-2021 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 significant 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.3 2021/08/14 16:14: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 46tool_vars tool_globals; 47enum slaptool slapTool; 48 49#ifdef CSRIMALLOC 50static char *leakfilename; 51static FILE *leakfile; 52#endif 53 54static LDIFFP dummy; 55 56#if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG) 57int start_syslog; 58static char **syslog_unknowns; 59#ifdef LOG_LOCAL4 60static int syslogUser = SLAP_DEFAULT_SYSLOG_USER; 61#endif /* LOG_LOCAL4 */ 62#endif /* LDAP_DEBUG && LDAP_SYSLOG */ 63 64static void 65usage( int tool, const char *progname ) 66{ 67 char *options = NULL; 68 fprintf( stderr, 69 "usage: %s [-v] [-d debuglevel] [-f configfile] [-F configdir] [-o <name>[=<value>]]", 70 progname ); 71 72 switch( tool ) { 73 case SLAPACL: 74 options = "\n\t[-U authcID | -D authcDN] [-X authzID | -o authzDN=<DN>]" 75 "\n\t-b DN [-u] [attr[/access][:value]] [...]\n"; 76 break; 77 78 case SLAPADD: 79 options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]\n" 80 "\t[-l ldiffile] [-j linenumber] [-q] [-u] [-s] [-w]\n"; 81 break; 82 83 case SLAPAUTH: 84 options = "\n\t[-U authcID] [-X authzID] [-R realm] [-M mech] ID [...]\n"; 85 break; 86 87 case SLAPCAT: 88 options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]" 89 " [-l ldiffile] [-a filter] [-s subtree] [-H url]\n"; 90 break; 91 92 case SLAPDN: 93 options = "\n\t[-N | -P] DN [...]\n"; 94 break; 95 96 case SLAPINDEX: 97 options = " [-c]\n\t[-g] [-n databasenumber | -b suffix] [attr ...] [-q] [-t]\n"; 98 break; 99 100 case SLAPMODIFY: 101 options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]\n" 102 "\t[-l ldiffile] [-j linenumber] [-q] [-u] [-s] [-w]\n"; 103 break; 104 105 case SLAPTEST: 106 options = " [-n databasenumber] [-u] [-Q]\n"; 107 break; 108 109 case SLAPSCHEMA: 110 options = " [-c]\n\t[-g] [-n databasenumber | -b suffix]" 111 " [-l errorfile] [-a filter] [-s subtree] [-H url]\n"; 112 break; 113 } 114 115 if ( options != NULL ) { 116 fputs( options, stderr ); 117 } 118 exit( EXIT_FAILURE ); 119} 120 121static int 122parse_slapopt( int tool, int *mode ) 123{ 124 size_t len = 0; 125 char *p; 126 127 p = strchr( optarg, '=' ); 128 if ( p != NULL ) { 129 len = p - optarg; 130 p++; 131 } 132 133 if ( strncasecmp( optarg, "sockurl", len ) == 0 ) { 134 if ( !BER_BVISNULL( &listener_url ) ) { 135 ber_memfree( listener_url.bv_val ); 136 } 137 ber_str2bv( p, 0, 1, &listener_url ); 138 139 } else if ( strncasecmp( optarg, "domain", len ) == 0 ) { 140 if ( !BER_BVISNULL( &peer_domain ) ) { 141 ber_memfree( peer_domain.bv_val ); 142 } 143 ber_str2bv( p, 0, 1, &peer_domain ); 144 145 } else if ( strncasecmp( optarg, "peername", len ) == 0 ) { 146 if ( !BER_BVISNULL( &peer_name ) ) { 147 ber_memfree( peer_name.bv_val ); 148 } 149 ber_str2bv( p, 0, 1, &peer_name ); 150 151 } else if ( strncasecmp( optarg, "sockname", len ) == 0 ) { 152 if ( !BER_BVISNULL( &sock_name ) ) { 153 ber_memfree( sock_name.bv_val ); 154 } 155 ber_str2bv( p, 0, 1, &sock_name ); 156 157 } else if ( strncasecmp( optarg, "ssf", len ) == 0 ) { 158 if ( lutil_atou( &ssf, p ) ) { 159 Debug( LDAP_DEBUG_ANY, "unable to parse ssf=\"%s\".\n", p ); 160 return -1; 161 } 162 163 } else if ( strncasecmp( optarg, "transport_ssf", len ) == 0 ) { 164 if ( lutil_atou( &transport_ssf, p ) ) { 165 Debug( LDAP_DEBUG_ANY, "unable to parse transport_ssf=\"%s\".\n", p ); 166 return -1; 167 } 168 169 } else if ( strncasecmp( optarg, "tls_ssf", len ) == 0 ) { 170 if ( lutil_atou( &tls_ssf, p ) ) { 171 Debug( LDAP_DEBUG_ANY, "unable to parse tls_ssf=\"%s\".\n", p ); 172 return -1; 173 } 174 175 } else if ( strncasecmp( optarg, "sasl_ssf", len ) == 0 ) { 176 if ( lutil_atou( &sasl_ssf, p ) ) { 177 Debug( LDAP_DEBUG_ANY, "unable to parse sasl_ssf=\"%s\".\n", p ); 178 return -1; 179 } 180 181 } else if ( strncasecmp( optarg, "authzDN", len ) == 0 ) { 182 ber_str2bv( p, 0, 1, &authzDN ); 183 184#if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG) 185 } else if ( strncasecmp( optarg, "syslog", len ) == 0 ) { 186 if ( parse_debug_level( p, &ldap_syslog, &syslog_unknowns ) ) { 187 return -1; 188 } 189 start_syslog = 1; 190 191 } else if ( strncasecmp( optarg, "syslog-level", len ) == 0 ) { 192 if ( parse_syslog_level( p, &ldap_syslog_level ) ) { 193 return -1; 194 } 195 start_syslog = 1; 196 197#ifdef LOG_LOCAL4 198 } else if ( strncasecmp( optarg, "syslog-user", len ) == 0 ) { 199 if ( parse_syslog_user( p, &syslogUser ) ) { 200 return -1; 201 } 202 start_syslog = 1; 203#endif /* LOG_LOCAL4 */ 204#endif /* LDAP_DEBUG && LDAP_SYSLOG */ 205 206 } else if ( strncasecmp( optarg, "schema-check", len ) == 0 ) { 207 switch ( tool ) { 208 case SLAPADD: 209 if ( strcasecmp( p, "yes" ) == 0 ) { 210 *mode &= ~SLAP_TOOL_NO_SCHEMA_CHECK; 211 } else if ( strcasecmp( p, "no" ) == 0 ) { 212 *mode |= SLAP_TOOL_NO_SCHEMA_CHECK; 213 } else { 214 Debug( LDAP_DEBUG_ANY, "unable to parse schema-check=\"%s\".\n", p ); 215 return -1; 216 } 217 break; 218 219 default: 220 Debug( LDAP_DEBUG_ANY, "schema-check meaningless for tool.\n" ); 221 break; 222 } 223 224 } else if ( strncasecmp( optarg, "value-check", len ) == 0 ) { 225 switch ( tool ) { 226 case SLAPADD: 227 if ( strcasecmp( p, "yes" ) == 0 ) { 228 *mode |= SLAP_TOOL_VALUE_CHECK; 229 } else if ( strcasecmp( p, "no" ) == 0 ) { 230 *mode &= ~SLAP_TOOL_VALUE_CHECK; 231 } else { 232 Debug( LDAP_DEBUG_ANY, "unable to parse value-check=\"%s\".\n", p ); 233 return -1; 234 } 235 break; 236 237 default: 238 Debug( LDAP_DEBUG_ANY, "value-check meaningless for tool.\n" ); 239 break; 240 } 241 242 } else if ( ( strncasecmp( optarg, "ldif_wrap", len ) == 0 ) || 243 ( strncasecmp( optarg, "ldif-wrap", len ) == 0 ) ) { 244 switch ( tool ) { 245 case SLAPCAT: 246 if ( strcasecmp( p, "no" ) == 0 ) { 247 ldif_wrap = LDIF_LINE_WIDTH_MAX; 248 249 } else { 250 unsigned int u; 251 if ( lutil_atou( &u, p ) ) { 252 Debug( LDAP_DEBUG_ANY, "unable to parse ldif_wrap=\"%s\".\n", p ); 253 return -1; 254 } 255 ldif_wrap = (ber_len_t)u; 256 } 257 break; 258 259 default: 260 Debug( LDAP_DEBUG_ANY, "ldif-wrap meaningless for tool.\n" ); 261 break; 262 } 263 264 } else { 265 return -1; 266 } 267 268 return 0; 269} 270 271/* 272 * slap_tool_init - initialize slap utility, handle program options. 273 * arguments: 274 * name program name 275 * tool tool code 276 * argc, argv command line arguments 277 */ 278 279static int need_shutdown; 280 281void 282slap_tool_init( 283 const char* progname, 284 int tool, 285 int argc, char **argv ) 286{ 287 char *options; 288 char *conffile = NULL; 289 char *confdir = NULL; 290 struct berval base = BER_BVNULL; 291 char *filterstr = NULL; 292 char *subtree = NULL; 293 char *ldiffile = NULL; 294 char **debug_unknowns = NULL; 295 int rc, i; 296 int mode = SLAP_TOOL_MODE; 297 int truncatemode = 0; 298 int use_glue = 1; 299 int writer; 300 301#ifdef LDAP_DEBUG 302 /* tools default to "none", so that at least LDAP_DEBUG_ANY 303 * messages show up; use -d 0 to reset */ 304 slap_debug = LDAP_DEBUG_NONE; 305 ldif_debug = slap_debug; 306#endif 307 ldap_syslog = 0; 308 /* make sure libldap gets init'd */ 309 ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug ); 310 311#ifdef CSRIMALLOC 312 leakfilename = malloc( strlen( progname ) + STRLENOF( ".leak" ) + 1 ); 313 sprintf( leakfilename, "%s.leak", progname ); 314 if( ( leakfile = fopen( leakfilename, "w" )) == NULL ) { 315 leakfile = stderr; 316 } 317 free( leakfilename ); 318 leakfilename = NULL; 319#endif 320 321 ldif_wrap = LDIF_LINE_WIDTH; 322 323 scope = LDAP_SCOPE_DEFAULT; 324 325 switch( tool ) { 326 case SLAPADD: 327 options = "b:cd:f:F:gj:l:n:o:qsS:uvw"; 328 break; 329 330 case SLAPCAT: 331 options = "a:b:cd:f:F:gH:l:n:o:s:v"; 332 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 333 break; 334 335 case SLAPDN: 336 options = "d:f:F:No:Pv"; 337 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 338 break; 339 340 case SLAPMODIFY: 341 options = "b:cd:f:F:gj:l:n:o:qsS:uvw"; 342 break; 343 344 case SLAPSCHEMA: 345 options = "a:b:cd:f:F:gH:l:n:o:s:v"; 346 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 347 break; 348 349 case SLAPTEST: 350 options = "d:f:F:n:o:Quv"; 351 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 352 break; 353 354 case SLAPAUTH: 355 options = "d:f:F:M:o:R:U:vX:"; 356 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 357 break; 358 359 case SLAPINDEX: 360 options = "b:cd:f:F:gn:o:qtv"; 361 mode |= SLAP_TOOL_READMAIN; 362 break; 363 364 case SLAPACL: 365 options = "b:D:d:f:F:o:uU:vX:"; 366 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY; 367 break; 368 369 default: 370 fprintf( stderr, "%s: unknown tool mode (%d)\n", progname, tool ); 371 exit( EXIT_FAILURE ); 372 } 373 374 dbnum = -1; 375 while ( (i = getopt( argc, argv, options )) != EOF ) { 376 switch ( i ) { 377 case 'a': 378 filterstr = optarg; 379 break; 380 381 case 'b': 382 ber_str2bv( optarg, 0, 1, &base ); 383 break; 384 385 case 'c': /* enable continue mode */ 386 continuemode++; 387 break; 388 389 case 'd': { /* turn on debugging */ 390 int level = 0; 391 392 if ( parse_debug_level( optarg, &level, &debug_unknowns ) ) { 393 usage( tool, progname ); 394 } 395#ifdef LDAP_DEBUG 396 if ( level == 0 ) { 397 /* allow to reset log level */ 398 slap_debug = 0; 399 400 } else { 401 slap_debug |= level; 402 } 403#else 404 if ( level != 0 ) 405 fputs( "must compile with LDAP_DEBUG for debugging\n", 406 stderr ); 407#endif 408 } break; 409 410 case 'D': 411 ber_str2bv( optarg, 0, 1, &authcDN ); 412 break; 413 414 case 'f': /* specify a conf file */ 415 conffile = optarg; 416 break; 417 418 case 'F': /* specify a conf dir */ 419 confdir = optarg; 420 break; 421 422 case 'g': /* disable subordinate glue */ 423 use_glue = 0; 424 break; 425 426 case 'H': { 427 LDAPURLDesc *ludp; 428 int rc; 429 430 rc = ldap_url_parse_ext( optarg, &ludp, 431 LDAP_PVT_URL_PARSE_NOEMPTY_HOST | LDAP_PVT_URL_PARSE_NOEMPTY_DN ); 432 if ( rc != LDAP_URL_SUCCESS ) { 433 usage( tool, progname ); 434 } 435 436 /* don't accept host, port, attrs, extensions */ 437 if ( ldap_pvt_url_scheme2proto( ludp->lud_scheme ) != LDAP_PROTO_TCP ) { 438 usage( tool, progname ); 439 } 440 441 if ( ludp->lud_host != NULL ) { 442 usage( tool, progname ); 443 } 444 445 if ( ludp->lud_port != 0 ) { 446 usage( tool, progname ); 447 } 448 449 if ( ludp->lud_attrs != NULL ) { 450 usage( tool, progname ); 451 } 452 453 if ( ludp->lud_exts != NULL ) { 454 usage( tool, progname ); 455 } 456 457 if ( ludp->lud_dn != NULL && ludp->lud_dn[0] != '\0' ) { 458 ch_free( subtree ); 459 subtree = ludp->lud_dn; 460 ludp->lud_dn = NULL; 461 } 462 463 if ( ludp->lud_filter != NULL && ludp->lud_filter[0] != '\0' ) { 464 filterstr = ludp->lud_filter; 465 ludp->lud_filter = NULL; 466 } 467 468 scope = ludp->lud_scope; 469 470 ldap_free_urldesc( ludp ); 471 } break; 472 473 case 'j': /* jump to linenumber */ 474 if ( lutil_atoul( &jumpline, optarg ) ) { 475 usage( tool, progname ); 476 } 477 break; 478 479 case 'l': /* LDIF file */ 480 ldiffile = optarg; 481 break; 482 483 case 'M': 484 ber_str2bv( optarg, 0, 0, &mech ); 485 break; 486 487 case 'N': 488 if ( dn_mode && dn_mode != SLAP_TOOL_LDAPDN_NORMAL ) { 489 usage( tool, progname ); 490 } 491 dn_mode = SLAP_TOOL_LDAPDN_NORMAL; 492 break; 493 494 case 'n': /* which config file db to index */ 495 if ( lutil_atoi( &dbnum, optarg ) || dbnum < 0 ) { 496 usage( tool, progname ); 497 } 498 break; 499 500 case 'o': 501 if ( parse_slapopt( tool, &mode ) ) { 502 usage( tool, progname ); 503 } 504 break; 505 506 case 'P': 507 if ( dn_mode && dn_mode != SLAP_TOOL_LDAPDN_PRETTY ) { 508 usage( tool, progname ); 509 } 510 dn_mode = SLAP_TOOL_LDAPDN_PRETTY; 511 break; 512 513 case 'Q': 514 quiet++; 515 slap_debug = 0; 516 break; 517 518 case 'q': /* turn on quick */ 519 mode |= SLAP_TOOL_QUICK; 520 break; 521 522 case 'R': 523 realm = optarg; 524 break; 525 526 case 'S': 527 if ( lutil_atou( &csnsid, optarg ) 528 || csnsid > SLAP_SYNC_SID_MAX ) 529 { 530 usage( tool, progname ); 531 } 532 break; 533 534 case 's': 535 switch ( tool ) { 536 case SLAPADD: 537 case SLAPMODIFY: 538 /* no schema check */ 539 mode |= SLAP_TOOL_NO_SCHEMA_CHECK; 540 break; 541 542 case SLAPCAT: 543 case SLAPSCHEMA: 544 /* dump subtree */ 545 ch_free( subtree ); 546 subtree = optarg; 547 break; 548 } 549 break; 550 551 case 't': /* turn on truncate */ 552 truncatemode++; 553 mode |= SLAP_TRUNCATE_MODE; 554 break; 555 556 case 'U': 557 ber_str2bv( optarg, 0, 0, &authcID ); 558 break; 559 560 case 'u': /* dry run */ 561 dryrun++; 562 break; 563 564 case 'v': /* turn on verbose */ 565 verbose++; 566 break; 567 568 case 'w': /* write context csn at the end */ 569 update_ctxcsn++; 570 break; 571 572 case 'X': 573 ber_str2bv( optarg, 0, 0, &authzID ); 574 break; 575 576 default: 577 usage( tool, progname ); 578 break; 579 } 580 } 581 582#if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG) 583 if ( start_syslog ) { 584 char *logName; 585#ifdef HAVE_EBCDIC 586 logName = ch_strdup( progname ); 587 __atoe( logName ); 588#else 589 logName = (char *)progname; 590#endif 591 592#ifdef LOG_LOCAL4 593 openlog( logName, OPENLOG_OPTIONS, syslogUser ); 594#elif defined LOG_DEBUG 595 openlog( logName, OPENLOG_OPTIONS ); 596#endif 597#ifdef HAVE_EBCDIC 598 free( logName ); 599 logName = NULL; 600#endif 601 } 602#endif /* LDAP_DEBUG && LDAP_SYSLOG */ 603 604 switch ( tool ) { 605 case SLAPCAT: 606 case SLAPSCHEMA: 607 writer = 1; 608 break; 609 610 default: 611 writer = 0; 612 break; 613 } 614 615 switch ( tool ) { 616 case SLAPADD: 617 case SLAPCAT: 618 case SLAPMODIFY: 619 case SLAPSCHEMA: 620 if ( ( argc != optind ) || (dbnum >= 0 && base.bv_val != NULL ) ) { 621 usage( tool, progname ); 622 } 623 624 break; 625 626 case SLAPINDEX: 627 if ( dbnum >= 0 && base.bv_val != NULL ) { 628 usage( tool, progname ); 629 } 630 631 break; 632 633 case SLAPDN: 634 if ( argc == optind ) { 635 usage( tool, progname ); 636 } 637 break; 638 639 case SLAPAUTH: 640 if ( argc == optind && BER_BVISNULL( &authcID ) ) { 641 usage( tool, progname ); 642 } 643 break; 644 645 case SLAPTEST: 646 if ( argc != optind ) { 647 usage( tool, progname ); 648 } 649 break; 650 651 case SLAPACL: 652 if ( !BER_BVISNULL( &authcDN ) && !BER_BVISNULL( &authcID ) ) { 653 usage( tool, progname ); 654 } 655 if ( BER_BVISNULL( &base ) ) { 656 usage( tool, progname ); 657 } 658 ber_dupbv( &baseDN, &base ); 659 break; 660 661 default: 662 break; 663 } 664 665 if ( ldiffile == NULL ) { 666 dummy.fp = writer ? stdout : stdin; 667 ldiffp = &dummy; 668 669 } else if ((ldiffp = ldif_open( ldiffile, writer ? "w" : "r" )) 670 == NULL ) 671 { 672 perror( ldiffile ); 673 exit( EXIT_FAILURE ); 674 } 675 676 /* 677 * initialize stuff and figure out which backend we're dealing with 678 */ 679 680 slapTool = tool; 681 rc = slap_init( mode, progname ); 682 if ( rc != 0 ) { 683 fprintf( stderr, "%s: slap_init failed!\n", progname ); 684 exit( EXIT_FAILURE ); 685 } 686 687 rc = read_config( conffile, confdir ); 688 689 if ( rc != 0 ) { 690 fprintf( stderr, "%s: bad configuration %s!\n", 691 progname, confdir ? "directory" : "file" ); 692 exit( EXIT_FAILURE ); 693 } 694 695 if ( debug_unknowns ) { 696 rc = parse_debug_unknowns( debug_unknowns, &slap_debug ); 697 ldap_charray_free( debug_unknowns ); 698 debug_unknowns = NULL; 699 if ( rc ) 700 exit( EXIT_FAILURE ); 701 } 702 703#if defined(LDAP_SYSLOG) && defined(LDAP_DEBUG) 704 if ( syslog_unknowns ) { 705 rc = parse_debug_unknowns( syslog_unknowns, &ldap_syslog ); 706 ldap_charray_free( syslog_unknowns ); 707 syslog_unknowns = NULL; 708 if ( rc ) 709 exit( EXIT_FAILURE ); 710 } 711#endif 712 713 at_oc_cache = 1; 714 715 switch ( tool ) { 716 case SLAPADD: 717 case SLAPCAT: 718 case SLAPINDEX: 719 case SLAPMODIFY: 720 case SLAPSCHEMA: 721 if ( !nbackends ) { 722 fprintf( stderr, "No databases found " 723 "in config file\n" ); 724 exit( EXIT_FAILURE ); 725 } 726 break; 727 728 default: 729 break; 730 } 731 732 if ( use_glue ) { 733 rc = glue_sub_attach( 0 ); 734 735 if ( rc != 0 ) { 736 fprintf( stderr, 737 "%s: subordinate configuration error\n", progname ); 738 exit( EXIT_FAILURE ); 739 } 740 } 741 742 rc = slap_schema_check(); 743 744 if ( rc != 0 ) { 745 fprintf( stderr, "%s: slap_schema_prep failed!\n", progname ); 746 exit( EXIT_FAILURE ); 747 } 748 749 switch ( tool ) { 750 case SLAPTEST: 751 if ( dbnum >= 0 ) 752 goto get_db; 753 /* FALLTHRU */ 754 case SLAPDN: 755 case SLAPAUTH: 756 be = NULL; 757 goto startup; 758 759 default: 760 break; 761 } 762 763 if( filterstr ) { 764 filter = str2filter( filterstr ); 765 766 if( filter == NULL ) { 767 fprintf( stderr, "Invalid filter '%s'\n", filterstr ); 768 exit( EXIT_FAILURE ); 769 } 770 } 771 772 if( subtree ) { 773 struct berval val; 774 ber_str2bv( subtree, 0, 0, &val ); 775 rc = dnNormalize( 0, NULL, NULL, &val, &sub_ndn, NULL ); 776 if( rc != LDAP_SUCCESS ) { 777 fprintf( stderr, "Invalid subtree DN '%s'\n", subtree ); 778 exit( EXIT_FAILURE ); 779 } 780 781 if ( BER_BVISNULL( &base ) && dbnum == -1 ) { 782 base = val; 783 } else { 784 free( subtree ); 785 subtree = NULL; 786 } 787 } 788 789 if( base.bv_val != NULL ) { 790 struct berval nbase; 791 792 rc = dnNormalize( 0, NULL, NULL, &base, &nbase, NULL ); 793 if( rc != LDAP_SUCCESS ) { 794 fprintf( stderr, "%s: slap_init invalid suffix (\"%s\")\n", 795 progname, base.bv_val ); 796 exit( EXIT_FAILURE ); 797 } 798 799 be = select_backend( &nbase, 0 ); 800 ber_memfree( nbase.bv_val ); 801 BER_BVZERO( &nbase ); 802 803 if( be == NULL ) { 804 fprintf( stderr, "%s: slap_init no backend for \"%s\"\n", 805 progname, base.bv_val ); 806 exit( EXIT_FAILURE ); 807 } 808 switch ( tool ) { 809 case SLAPACL: 810 goto startup; 811 812 default: 813 break; 814 } 815 816 /* If the named base is a glue primary, operate on the 817 * entire context 818 */ 819 if ( SLAP_GLUE_INSTANCE( be ) ) { 820 nosubordinates = 1; 821 } 822 823 ch_free( base.bv_val ); 824 BER_BVZERO( &base ); 825 826 } else if ( dbnum == -1 ) { 827 /* no suffix and no dbnum specified, just default to 828 * the first available database 829 */ 830 if ( nbackends <= 0 ) { 831 fprintf( stderr, "No available databases\n" ); 832 exit( EXIT_FAILURE ); 833 } 834 LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { 835 dbnum++; 836 837 /* db #0 is cn=config, don't select it as a default */ 838 if ( dbnum < 1 ) continue; 839 840 if ( SLAP_MONITOR(be)) 841 continue; 842 843 /* If just doing the first by default and it is a 844 * glue subordinate, find the primary. 845 */ 846 if ( SLAP_GLUE_SUBORDINATE(be) ) { 847 nosubordinates = 1; 848 continue; 849 } 850 break; 851 } 852 853 if ( !be ) { 854 fprintf( stderr, "Available database(s) " 855 "do not allow %s\n", progname ); 856 exit( EXIT_FAILURE ); 857 } 858 859 if ( nosubordinates == 0 && dbnum > 1 ) { 860 Debug( LDAP_DEBUG_ANY, 861 "The first database does not allow %s;" 862 " using the first available one (%d)\n", 863 progname, dbnum ); 864 } 865 866 } else if ( dbnum >= nbackends ) { 867 fprintf( stderr, 868 "Database number selected via -n is out of range\n" 869 "Must be in the range 0 to %d" 870 " (the number of configured databases)\n", 871 nbackends - 1 ); 872 exit( EXIT_FAILURE ); 873 874 } else { 875get_db: 876 LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { 877 if ( dbnum == 0 ) break; 878 dbnum--; 879 } 880 } 881 882 if ( scope != LDAP_SCOPE_DEFAULT && BER_BVISNULL( &sub_ndn ) ) { 883 if ( be && be->be_nsuffix ) { 884 ber_dupbv( &sub_ndn, be->be_nsuffix ); 885 886 } else { 887 fprintf( stderr, 888 "<scope> needs a DN or a valid database\n" ); 889 exit( EXIT_FAILURE ); 890 } 891 } 892 893startup:; 894 if ( be ) { 895 BackendDB *bdtmp; 896 897 dbnum = 0; 898 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) { 899 if ( bdtmp == be ) break; 900 dbnum++; 901 } 902 } 903 904#ifdef CSRIMALLOC 905 mal_leaktrace(1); 906#endif 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 931int 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 970int 971slap_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 */ 1111unsigned long 1112slap_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 1157int 1158slap_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 1172int 1173slap_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