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