1/* $NetBSD: main.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */ 2 3/* $OpenLDAP$ */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2021 The OpenLDAP Foundation. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17/* Portions Copyright (c) 1995 Regents of the University of Michigan. 18 * All rights reserved. 19 * 20 * Redistribution and use in source and binary forms are permitted 21 * provided that this notice is preserved and that due credit is given 22 * to the University of Michigan at Ann Arbor. The name of the University 23 * may not be used to endorse or promote products derived from this 24 * software without specific prior written permission. This software 25 * is provided ``as is'' without express or implied warranty. 26 */ 27 28#include <sys/cdefs.h> 29__RCSID("$NetBSD: main.c,v 1.3 2021/08/14 16:14:58 christos Exp $"); 30 31#include "portable.h" 32 33#include <stdio.h> 34 35#include <ac/ctype.h> 36#include <ac/socket.h> 37#include <ac/string.h> 38#include <ac/time.h> 39#include <ac/unistd.h> 40#include <ac/wait.h> 41#include <ac/errno.h> 42 43#include "slap.h" 44#include "lutil.h" 45#include "ldif.h" 46 47#ifdef LDAP_SLAPI 48#include "slapi/slapi.h" 49#endif 50 51#ifdef LDAP_SIGCHLD 52static RETSIGTYPE wait4child( int sig ); 53#endif 54 55#ifdef HAVE_NT_SERVICE_MANAGER 56#define MAIN_RETURN(x) return 57static struct sockaddr_in bind_addr; 58 59#define SERVICE_EXIT( e, n ) do { \ 60 if ( is_NT_Service ) { \ 61 lutil_ServiceStatus.dwWin32ExitCode = (e); \ 62 lutil_ServiceStatus.dwServiceSpecificExitCode = (n); \ 63 } \ 64} while ( 0 ) 65 66#else 67#define SERVICE_EXIT( e, n ) 68#define MAIN_RETURN(x) return(x) 69#endif 70 71typedef int (MainFunc) LDAP_P(( int argc, char *argv[] )); 72extern MainFunc slapadd, slapcat, slapdn, slapindex, slappasswd, 73 slaptest, slapauth, slapacl, slapschema, slapmodify; 74 75static struct { 76 char *name; 77 MainFunc *func; 78} tools[] = { 79 {"slapadd", slapadd}, 80 {"slapcat", slapcat}, 81 {"slapdn", slapdn}, 82 {"slapindex", slapindex}, 83 {"slapmodify", slapmodify}, 84 {"slappasswd", slappasswd}, 85 {"slapschema", slapschema}, 86 {"slaptest", slaptest}, 87 {"slapauth", slapauth}, 88 {"slapacl", slapacl}, 89 /* NOTE: new tools must be added in chronological order, 90 * not in alphabetical order, because for backwards 91 * compatibility name[4] is used to identify the 92 * tools; so name[4]=='a' must refer to "slapadd" and 93 * not to "slapauth". Alphabetical order can be used 94 * for tools whose name[4] is not used yet */ 95 {NULL, NULL} 96}; 97 98/* 99 * when more than one slapd is running on one machine, each one might have 100 * it's own LOCAL for syslogging and must have its own pid/args files 101 */ 102 103#ifndef HAVE_MKVERSION 104const char Versionstr[] = 105 OPENLDAP_PACKAGE " " OPENLDAP_VERSION " Standalone LDAP Server (slapd)"; 106#endif 107 108extern OverlayInit slap_oinfo[]; 109extern BackendInfo slap_binfo[]; 110 111#define CHECK_NONE 0x00 112#define CHECK_CONFIG 0x01 113#define CHECK_LOGLEVEL 0x02 114static int check = CHECK_NONE; 115static int version = 0; 116 117void *slap_tls_ctx; 118LDAP *slap_tls_ld; 119 120static int 121slapd_opt_slp( const char *val, void *arg ) 122{ 123#ifdef HAVE_SLP 124 /* NULL is default */ 125 if ( val == NULL || *val == '(' || strcasecmp( val, "on" ) == 0 ) { 126 slapd_register_slp = 1; 127 slapd_slp_attrs = (val != NULL && *val == '(') ? val : NULL; 128 129 } else if ( strcasecmp( val, "off" ) == 0 ) { 130 slapd_register_slp = 0; 131 132 /* NOTE: add support for URL specification? */ 133 134 } else { 135 fprintf(stderr, "unrecognized value \"%s\" for SLP option\n", val ); 136 return -1; 137 } 138 139 return 0; 140 141#else 142 fputs( "slapd: SLP support is not available\n", stderr ); 143 return 0; 144#endif 145} 146 147/* 148 * Option helper structure: 149 * 150 * oh_nam is left-hand part of <option>[=<value>] 151 * oh_fnc is handler function 152 * oh_arg is an optional arg to oh_fnc 153 * oh_usage is the one-line usage string related to the option, 154 * which is assumed to start with <option>[=<value>] 155 * 156 * please leave valid options in the structure, and optionally #ifdef 157 * their processing inside the helper, so that reasonable and helpful 158 * error messages can be generated if a disabled option is requested. 159 */ 160struct option_helper { 161 struct berval oh_name; 162 int (*oh_fnc)(const char *val, void *arg); 163 void *oh_arg; 164 const char *oh_usage; 165} option_helpers[] = { 166 { BER_BVC("slp"), slapd_opt_slp, NULL, "slp[={on|off|(attrs)}] enable/disable SLP using (attrs)" }, 167 { BER_BVNULL, 0, NULL, NULL } 168}; 169 170#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG) 171#ifdef LOG_LOCAL4 172int 173parse_syslog_user( const char *arg, int *syslogUser ) 174{ 175 static slap_verbmasks syslogUsers[] = { 176 { BER_BVC( "LOCAL0" ), LOG_LOCAL0 }, 177 { BER_BVC( "LOCAL1" ), LOG_LOCAL1 }, 178 { BER_BVC( "LOCAL2" ), LOG_LOCAL2 }, 179 { BER_BVC( "LOCAL3" ), LOG_LOCAL3 }, 180 { BER_BVC( "LOCAL4" ), LOG_LOCAL4 }, 181 { BER_BVC( "LOCAL5" ), LOG_LOCAL5 }, 182 { BER_BVC( "LOCAL6" ), LOG_LOCAL6 }, 183 { BER_BVC( "LOCAL7" ), LOG_LOCAL7 }, 184#ifdef LOG_USER 185 { BER_BVC( "USER" ), LOG_USER }, 186#endif /* LOG_USER */ 187#ifdef LOG_DAEMON 188 { BER_BVC( "DAEMON" ), LOG_DAEMON }, 189#endif /* LOG_DAEMON */ 190 { BER_BVNULL, 0 } 191 }; 192 int i = verb_to_mask( arg, syslogUsers ); 193 194 if ( BER_BVISNULL( &syslogUsers[ i ].word ) ) { 195 Debug( LDAP_DEBUG_ANY, 196 "unrecognized syslog user \"%s\".\n", 197 arg ); 198 return 1; 199 } 200 201 *syslogUser = syslogUsers[ i ].mask; 202 203 return 0; 204} 205#endif /* LOG_LOCAL4 */ 206 207int 208parse_syslog_level( const char *arg, int *levelp ) 209{ 210 static slap_verbmasks str2syslog_level[] = { 211 { BER_BVC( "EMERG" ), LOG_EMERG }, 212 { BER_BVC( "ALERT" ), LOG_ALERT }, 213 { BER_BVC( "CRIT" ), LOG_CRIT }, 214 { BER_BVC( "ERR" ), LOG_ERR }, 215 { BER_BVC( "WARNING" ), LOG_WARNING }, 216 { BER_BVC( "NOTICE" ), LOG_NOTICE }, 217 { BER_BVC( "INFO" ), LOG_INFO }, 218 { BER_BVC( "DEBUG" ), LOG_DEBUG }, 219 { BER_BVNULL, 0 } 220 }; 221 int i = verb_to_mask( arg, str2syslog_level ); 222 if ( BER_BVISNULL( &str2syslog_level[ i ].word ) ) { 223 Debug( LDAP_DEBUG_ANY, 224 "unknown syslog level \"%s\".\n", 225 arg ); 226 return 1; 227 } 228 229 *levelp = str2syslog_level[ i ].mask; 230 231 return 0; 232} 233#endif /* LDAP_DEBUG && LDAP_SYSLOG */ 234 235static char **debug_unknowns; 236static char **syslog_unknowns; 237 238int 239parse_debug_unknowns( char **unknowns, int *levelp ) 240{ 241 int i, level, rc = 0; 242 243 for ( i = 0; unknowns[ i ] != NULL; i++ ) { 244 level = 0; 245 if ( str2loglevel( unknowns[ i ], &level )) { 246 fprintf( stderr, 247 "unrecognized log level \"%s\"\n", unknowns[ i ] ); 248 rc = 1; 249 } else { 250 *levelp |= level; 251 } 252 } 253 return rc; 254} 255 256int 257parse_debug_level( const char *arg, int *levelp, char ***unknowns ) 258{ 259 int level; 260 261 if ( arg && arg[ 0 ] != '-' && !isdigit( (unsigned char) arg[ 0 ] ) ) 262 { 263 int i; 264 char **levels; 265 266 levels = ldap_str2charray( arg, "," ); 267 268 for ( i = 0; levels[ i ] != NULL; i++ ) { 269 level = 0; 270 271 if ( str2loglevel( levels[ i ], &level ) ) { 272 /* remember this for later */ 273 ldap_charray_add( unknowns, levels[ i ] ); 274 fprintf( stderr, 275 "unrecognized log level \"%s\" (deferred)\n", 276 levels[ i ] ); 277 } else { 278 *levelp |= level; 279 } 280 } 281 282 ldap_charray_free( levels ); 283 284 } else { 285 int rc; 286 287 if ( arg[0] == '-' ) { 288 rc = lutil_atoix( &level, arg, 0 ); 289 } else { 290 unsigned ulevel; 291 292 rc = lutil_atoux( &ulevel, arg, 0 ); 293 level = (int)ulevel; 294 } 295 296 if ( rc ) { 297 fprintf( stderr, 298 "unrecognized log level " 299 "\"%s\"\n", arg ); 300 return 1; 301 } 302 303 if ( level == 0 ) { 304 *levelp = 0; 305 306 } else { 307 *levelp |= level; 308 } 309 } 310 311 return 0; 312} 313 314void slap_check_unknown_level( char *levelstr, int level ) 315{ 316 int i; 317 318 if ( debug_unknowns ) { 319 for ( i = 0; debug_unknowns[ i ]; i++ ) { 320 if ( !strcasecmp( debug_unknowns[ i ], levelstr )) { 321 slap_debug |= level; 322 break; 323 } 324 } 325 } 326 327 if ( syslog_unknowns ) { 328 for ( i = 0; syslog_unknowns[ i ]; i++ ) { 329 if ( !strcasecmp( syslog_unknowns[ i ], levelstr )) { 330 ldap_syslog |= level; 331 break; 332 } 333 } 334 } 335} 336 337static void 338usage( char *name ) 339{ 340 fprintf( stderr, 341 "usage: %s options\n", name ); 342 fprintf( stderr, 343 "\t-4\t\tIPv4 only\n" 344#ifdef LDAP_PF_INET6 345 "\t-6\t\tIPv6 only\n" 346#endif 347 "\t-T {acl|add|auth|cat|dn|index|modify|passwd|test}\n" 348 "\t\t\tRun in Tool mode\n" 349 "\t-c cookie\tSync cookie of consumer\n" 350 "\t-d level\tDebug level" "\n" 351 "\t-f filename\tConfiguration file\n" 352 "\t-F dir\tConfiguration directory\n" 353#if defined(HAVE_SETUID) && defined(HAVE_SETGID) 354 "\t-g group\tGroup (id or name) to run as\n" 355#endif 356 "\t-h URLs\t\tList of URLs to serve\n" 357#ifdef SLAP_DEFAULT_SYSLOG_USER 358 "\t-l facility\tSyslog facility (default: LOCAL4)\n" 359#endif 360 "\t-n serverName\tService name\n" 361 "\t-o <opt>[=val] generic means to specify options" ); 362 if ( !BER_BVISNULL( &option_helpers[0].oh_name ) ) { 363 int i; 364 365 fprintf( stderr, "; supported options:\n" ); 366 for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); i++) { 367 fprintf( stderr, "\t\t%s\n", option_helpers[i].oh_usage ); 368 } 369 } else { 370 fprintf( stderr, "\n" ); 371 } 372 fprintf( stderr, 373#ifdef HAVE_CHROOT 374 "\t-r directory\tSandbox directory to chroot to\n" 375#endif 376 "\t-s level\tSyslog level\n" 377#if defined(HAVE_SETUID) && defined(HAVE_SETGID) 378 "\t-u user\t\tUser (id or name) to run as\n" 379#endif 380 "\t-V\t\tprint version info (-VV exit afterwards, -VVV print\n" 381 "\t\t\tinfo about static overlays and backends)\n" 382 ); 383} 384 385typedef void (BER_logger)(const char *buf); 386static BER_logger *ber_logger; 387static void debug_print( const char *data ) 388{ 389 char buf[4136]; /* 4096 + 40 */ 390#ifdef HAVE_CLOCK_GETTIME 391 struct timespec tv; 392#define TS "%08x" 393#define Tfrac tv.tv_nsec 394 clock_gettime( CLOCK_REALTIME, &tv ); 395#else 396 struct timeval tv; 397#define TS "%05x" 398#define Tfrac tv.tv_usec 399 gettimeofday( &tv, NULL ); 400#endif 401 402 buf[sizeof(buf)-1] = '\0'; 403 snprintf( buf, sizeof(buf)-1, "%lx." TS " %p %s", 404 (long)tv.tv_sec, Tfrac, (void *)ldap_pvt_thread_self(), data ); 405 ber_logger( buf ); 406} 407 408#ifdef HAVE_NT_SERVICE_MANAGER 409void WINAPI ServiceMain( DWORD argc, LPTSTR *argv ) 410#else 411int main( int argc, char **argv ) 412#endif 413{ 414 int i, no_detach = 0; 415 int rc = 1; 416 char *urls = NULL; 417#if defined(HAVE_SETUID) && defined(HAVE_SETGID) 418 char *username = NULL; 419 char *groupname = NULL; 420#endif 421#if defined(HAVE_CHROOT) 422 char *sandbox = NULL; 423#endif 424#ifdef SLAP_DEFAULT_SYSLOG_USER 425 int syslogUser = SLAP_DEFAULT_SYSLOG_USER; 426#endif 427 428#ifndef HAVE_WINSOCK 429 int pid, waitfds[2]; 430#endif 431 int g_argc = argc; 432 char **g_argv = argv; 433 434 char *configfile = NULL; 435 char *configdir = NULL; 436 char *serverName; 437 int serverMode = SLAP_SERVER_MODE; 438 439 struct sync_cookie *scp = NULL; 440 struct sync_cookie *scp_entry = NULL; 441 442 char *serverNamePrefix = ""; 443 size_t l; 444 445 int slapd_pid_file_unlink = 0, slapd_args_file_unlink = 0; 446 int firstopt = 1; 447 448#ifdef CSRIMALLOC 449 FILE *leakfile; 450 if( ( leakfile = fopen( "slapd.leak", "w" )) == NULL ) { 451 leakfile = stderr; 452 } 453#endif 454 455 slap_sl_mem_init(); 456 457 458 (void) ldap_pvt_thread_initialize(); 459 460 serverName = lutil_progname( "slapd", argc, argv ); 461 462 if ( strcmp( serverName, "slapd" ) ) { 463#ifdef DEBUG_CLOSE 464 extern void slapd_debug_close(); 465 slapd_debug_close(); 466#endif 467 for (i=0; tools[i].name; i++) { 468 if ( !strcmp( serverName, tools[i].name ) ) { 469 rc = tools[i].func(argc, argv); 470 MAIN_RETURN(rc); 471 } 472 } 473 } 474 475#ifdef HAVE_NT_SERVICE_MANAGER 476 { 477 int *ip; 478 char *newConfigFile; 479 char *newConfigDir; 480 char *newUrls; 481 char *regService = NULL; 482 483 if ( is_NT_Service ) { 484 lutil_CommenceStartupProcessing( serverName, slap_sig_shutdown ); 485 if ( strcmp(serverName, SERVICE_NAME) ) 486 regService = serverName; 487 } 488 489 ip = (int*)lutil_getRegParam( regService, "DebugLevel" ); 490 if ( ip != NULL ) { 491 slap_debug = *ip; 492 Debug( LDAP_DEBUG_ANY, 493 "new debug level from registry is: %d\n", slap_debug ); 494 } 495 496 newUrls = (char *) lutil_getRegParam(regService, "Urls"); 497 if (newUrls) { 498 if (urls) 499 ch_free(urls); 500 501 urls = ch_strdup(newUrls); 502 Debug(LDAP_DEBUG_ANY, "new urls from registry: %s\n", 503 urls ); 504 } 505 506 newConfigFile = (char*)lutil_getRegParam( regService, "ConfigFile" ); 507 if ( newConfigFile != NULL ) { 508 configfile = ch_strdup(newConfigFile); 509 Debug ( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", configfile ); 510 } 511 512 newConfigDir = (char*)lutil_getRegParam( regService, "ConfigDir" ); 513 if ( newConfigDir != NULL ) { 514 configdir = ch_strdup(newConfigDir); 515 Debug ( LDAP_DEBUG_ANY, "new config dir from registry is: %s\n", configdir ); 516 } 517 } 518#endif 519 520 while ( (i = getopt( argc, argv, 521 "c:d:f:F:h:n:o:s:tT:V" 522#ifdef LDAP_PF_INET6 523 "46" 524#endif 525#ifdef HAVE_CHROOT 526 "r:" 527#endif 528#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG) 529 "S:" 530#ifdef LOG_LOCAL4 531 "l:" 532#endif 533#endif 534#if defined(HAVE_SETUID) && defined(HAVE_SETGID) 535 "u:g:" 536#endif 537 )) != EOF ) { 538 switch ( i ) { 539 case '4': 540 slap_inet4or6 = AF_INET; 541 break; 542#ifdef LDAP_PF_INET6 543 case '6': 544 slap_inet4or6 = AF_INET6; 545 break; 546#endif 547 548 case 'h': /* listen URLs */ 549 if ( urls != NULL ) free( urls ); 550 urls = optarg; 551 break; 552 553 case 'c': /* provide sync cookie, override if exist in consumer */ 554 scp = (struct sync_cookie *) ch_calloc( 1, 555 sizeof( struct sync_cookie )); 556 ber_str2bv( optarg, 0, 1, &scp->octet_str ); 557 558 /* This only parses out the rid at this point */ 559 slap_parse_sync_cookie( scp, NULL ); 560 561 if ( scp->rid == -1 ) { 562 Debug( LDAP_DEBUG_ANY, 563 "main: invalid cookie \"%s\"\n", 564 optarg ); 565 slap_sync_cookie_free( scp, 1 ); 566 goto destroy; 567 } 568 569 LDAP_STAILQ_FOREACH( scp_entry, &slap_sync_cookie, sc_next ) { 570 if ( scp->rid == scp_entry->rid ) { 571 Debug( LDAP_DEBUG_ANY, 572 "main: duplicated replica id in cookies\n" ); 573 slap_sync_cookie_free( scp, 1 ); 574 goto destroy; 575 } 576 } 577 LDAP_STAILQ_INSERT_TAIL( &slap_sync_cookie, scp, sc_next ); 578 break; 579 580 case 'd': { /* set debug level and 'do not detach' flag */ 581 int level = 0; 582 583 if ( strcmp( optarg, "?" ) == 0 ) { 584 check |= CHECK_LOGLEVEL; 585 break; 586 } 587 588 no_detach = 1; 589 if ( parse_debug_level( optarg, &level, &debug_unknowns ) ) { 590 goto destroy; 591 } 592#ifdef LDAP_DEBUG 593 slap_debug |= level; 594#else 595 if ( level != 0 ) 596 fputs( "must compile with LDAP_DEBUG for debugging\n", 597 stderr ); 598#endif 599 } break; 600 601 case 'f': /* read config file */ 602 configfile = optarg; 603 break; 604 605 case 'F': /* use config dir */ 606 configdir = optarg; 607 break; 608 609 case 'o': { 610 char *val = strchr( optarg, '=' ); 611 struct berval opt; 612 613 opt.bv_val = optarg; 614 615 if ( val ) { 616 opt.bv_len = ( val - optarg ); 617 val++; 618 619 } else { 620 opt.bv_len = strlen( optarg ); 621 } 622 623 for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); i++ ) { 624 if ( ber_bvstrcasecmp( &option_helpers[i].oh_name, &opt ) == 0 ) { 625 assert( option_helpers[i].oh_fnc != NULL ); 626 if ( (*option_helpers[i].oh_fnc)( val, option_helpers[i].oh_arg ) == -1 ) { 627 /* we assume the option parsing helper 628 * issues appropriate and self-explanatory 629 * error messages... */ 630 goto stop; 631 } 632 break; 633 } 634 } 635 636 if ( BER_BVISNULL( &option_helpers[i].oh_name ) ) { 637 goto unhandled_option; 638 } 639 break; 640 } 641 642 case 's': /* set syslog level */ 643 if ( strcmp( optarg, "?" ) == 0 ) { 644 check |= CHECK_LOGLEVEL; 645 break; 646 } 647 648 if ( parse_debug_level( optarg, &ldap_syslog, &syslog_unknowns ) ) { 649 goto destroy; 650 } 651 break; 652 653#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG) 654 case 'S': 655 if ( parse_syslog_level( optarg, &ldap_syslog_level ) ) { 656 goto destroy; 657 } 658 break; 659 660#ifdef LOG_LOCAL4 661 case 'l': /* set syslog local user */ 662 if ( parse_syslog_user( optarg, &syslogUser ) ) { 663 goto destroy; 664 } 665 break; 666#endif 667#endif /* LDAP_DEBUG && LDAP_SYSLOG */ 668 669#ifdef HAVE_CHROOT 670 case 'r': 671 sandbox = optarg; 672 break; 673#endif 674 675#if defined(HAVE_SETUID) && defined(HAVE_SETGID) 676 case 'u': /* user name */ 677 username = optarg; 678 break; 679 680 case 'g': /* group name */ 681 groupname = optarg; 682 break; 683#endif /* SETUID && GETUID */ 684 685 case 'n': /* NT service name */ 686 serverName = optarg; 687 break; 688 689 case 't': 690 /* deprecated; use slaptest instead */ 691 fprintf( stderr, "option -t deprecated; " 692 "use slaptest command instead\n" ); 693 check |= CHECK_CONFIG; 694 break; 695 696 case 'V': 697 version++; 698 break; 699 700 case 'T': 701 if ( firstopt == 0 ) { 702 fprintf( stderr, "warning: \"-T %s\" " 703 "should be the first option.\n", 704 optarg ); 705 } 706 707#ifdef DEBUG_CLOSE 708 extern void slapd_debug_close(); 709 slapd_debug_close(); 710#endif 711 /* try full option string first */ 712 for ( i = 0; tools[i].name; i++ ) { 713 if ( strcmp( optarg, &tools[i].name[4] ) == 0 ) { 714 rc = tools[i].func( argc, argv ); 715 MAIN_RETURN( rc ); 716 } 717 } 718 719 /* try bits of option string (backward compatibility for single char) */ 720 l = strlen( optarg ); 721 for ( i = 0; tools[i].name; i++ ) { 722 if ( strncmp( optarg, &tools[i].name[4], l ) == 0 ) { 723 rc = tools[i].func( argc, argv ); 724 MAIN_RETURN( rc ); 725 } 726 } 727 728 /* issue error */ 729 serverName = optarg; 730 serverNamePrefix = "slap"; 731 fprintf( stderr, "program name \"%s%s\" unrecognized; " 732 "aborting...\n", serverNamePrefix, serverName ); 733 /* FALLTHRU */ 734 default: 735unhandled_option:; 736 usage( argv[0] ); 737 rc = 1; 738 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 ); 739 goto stop; 740 } 741 742 if ( firstopt ) { 743 firstopt = 0; 744 } 745 } 746 747 if ( optind != argc ) 748 goto unhandled_option; 749 750 ber_get_option(NULL, LBER_OPT_LOG_PRINT_FN, &ber_logger); 751 ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN, debug_print); 752 ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug); 753 ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug); 754 ldif_debug = slap_debug; 755 756 if ( version ) { 757 fprintf( stderr, "%s\n", Versionstr ); 758 if ( version > 2 ) { 759 if ( slap_oinfo[0].ov_type ) { 760 fprintf( stderr, "Included static overlays:\n"); 761 for ( i= 0 ; slap_oinfo[i].ov_type; i++ ) { 762 fprintf( stderr, " %s\n", slap_oinfo[i].ov_type ); 763 } 764 } 765 if ( slap_binfo[0].bi_type ) { 766 fprintf( stderr, "Included static backends:\n"); 767 for ( i= 0 ; slap_binfo[i].bi_type; i++ ) { 768 fprintf( stderr, " %s\n", slap_binfo[i].bi_type ); 769 } 770 } 771 } 772 773 if ( version > 1 ) goto stop; 774 } 775 776#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG) 777 { 778 char *logName; 779#ifdef HAVE_EBCDIC 780 logName = ch_strdup( serverName ); 781 __atoe( logName ); 782#else 783 logName = serverName; 784#endif 785 786#ifdef LOG_LOCAL4 787 openlog( logName, OPENLOG_OPTIONS, syslogUser ); 788#elif defined LOG_DEBUG 789 openlog( logName, OPENLOG_OPTIONS ); 790#endif 791#ifdef HAVE_EBCDIC 792 free( logName ); 793#endif 794 } 795#endif /* LDAP_DEBUG && LDAP_SYSLOG */ 796 797 Debug( LDAP_DEBUG_ANY, "%s", Versionstr ); 798 799 global_host = ldap_pvt_get_fqdn( NULL ); 800 ber_str2bv( global_host, 0, 0, &global_host_bv ); 801 802 if( check == CHECK_NONE && slapd_daemon_init( urls ) != 0 ) { 803 rc = 1; 804 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 ); 805 goto stop; 806 } 807 808#if defined(HAVE_CHROOT) 809 if ( sandbox ) { 810 if ( chdir( sandbox ) ) { 811 perror("chdir"); 812 rc = 1; 813 goto stop; 814 } 815 if ( chroot( sandbox ) ) { 816 perror("chroot"); 817 rc = 1; 818 goto stop; 819 } 820 if ( chdir( "/" ) ) { 821 perror("chdir"); 822 rc = 1; 823 goto stop; 824 } 825 } 826#endif 827 828#if defined(HAVE_SETUID) && defined(HAVE_SETGID) 829 if ( username != NULL || groupname != NULL ) { 830 slap_init_user( username, groupname ); 831 } 832#endif 833 834 extops_init(); 835 lutil_passwd_init(); 836 837#ifdef HAVE_TLS 838 rc = ldap_create( &slap_tls_ld ); 839 if ( rc ) { 840 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 ); 841 goto destroy; 842 } 843 /* Library defaults to full certificate checking. This is correct when 844 * a client is verifying a server because all servers should have a 845 * valid cert. But few clients have valid certs, so we want our default 846 * to be no checking. The config file can override this as usual. 847 */ 848 rc = LDAP_OPT_X_TLS_NEVER; 849 (void) ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &rc ); 850#endif 851 852 rc = slap_init( serverMode, serverName ); 853 if ( rc ) { 854 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 ); 855 goto destroy; 856 } 857 858 if ( read_config( configfile, configdir ) != 0 ) { 859 rc = 1; 860 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 ); 861 862 if ( check & CHECK_CONFIG ) { 863 fprintf( stderr, "config check failed\n" ); 864 } 865 866 goto destroy; 867 } 868 869 if ( debug_unknowns ) { 870 rc = parse_debug_unknowns( debug_unknowns, &slap_debug ); 871 ldap_charray_free( debug_unknowns ); 872 debug_unknowns = NULL; 873 if ( rc ) 874 goto destroy; 875 ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug ); 876 ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug ); 877 } 878 if ( syslog_unknowns ) { 879 rc = parse_debug_unknowns( syslog_unknowns, &ldap_syslog ); 880 ldap_charray_free( syslog_unknowns ); 881 syslog_unknowns = NULL; 882 if ( rc ) 883 goto destroy; 884 } 885 886 if ( check & CHECK_LOGLEVEL ) { 887 rc = 0; 888 goto destroy; 889 } 890 891 if ( check & CHECK_CONFIG ) { 892 fprintf( stderr, "config check succeeded\n" ); 893 894 check &= ~CHECK_CONFIG; 895 if ( check == CHECK_NONE ) { 896 rc = 0; 897 goto destroy; 898 } 899 } 900 901 if ( glue_sub_attach( 0 ) != 0 ) { 902 Debug( LDAP_DEBUG_ANY, 903 "subordinate config error\n" ); 904 905 goto destroy; 906 } 907 908 if ( slap_schema_check( ) != 0 ) { 909 Debug( LDAP_DEBUG_ANY, 910 "schema prep error\n" ); 911 912 goto destroy; 913 } 914 915#ifdef HAVE_TLS 916 rc = ldap_pvt_tls_init( 1 ); 917 if( rc != 0) { 918 Debug( LDAP_DEBUG_ANY, 919 "main: TLS init failed: %d\n", 920 rc ); 921 rc = 1; 922 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 ); 923 goto destroy; 924 } 925 926 { 927 int opt = 1; 928 929 /* Force new ctx to be created */ 930 rc = ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt ); 931 if( rc == 0 ) { 932 /* The ctx's refcount is bumped up here */ 933 ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CTX, &slap_tls_ctx ); 934 load_extop( &slap_EXOP_START_TLS, 0, starttls_extop ); 935 } else if ( rc != LDAP_NOT_SUPPORTED ) { 936 Debug( LDAP_DEBUG_ANY, 937 "main: TLS init def ctx failed: %d\n", 938 rc ); 939 rc = 1; 940 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 ); 941 goto destroy; 942 } 943 } 944#endif 945 946#ifdef HAVE_CYRUS_SASL 947 if( sasl_host == NULL ) { 948 sasl_host = ch_strdup( global_host ); 949 } 950#endif 951 952 (void) SIGNAL( LDAP_SIGUSR1, slap_sig_wake ); 953 (void) SIGNAL( LDAP_SIGUSR2, slap_sig_shutdown ); 954 955#ifdef SIGPIPE 956 (void) SIGNAL( SIGPIPE, SIG_IGN ); 957#endif 958#ifdef SIGHUP 959 (void) SIGNAL( SIGHUP, slap_sig_shutdown ); 960#endif 961 (void) SIGNAL( SIGINT, slap_sig_shutdown ); 962 (void) SIGNAL( SIGTERM, slap_sig_shutdown ); 963#ifdef SIGTRAP 964 (void) SIGNAL( SIGTRAP, slap_sig_shutdown ); 965#endif 966#ifdef LDAP_SIGCHLD 967 (void) SIGNAL( LDAP_SIGCHLD, wait4child ); 968#endif 969#ifdef SIGBREAK 970 /* SIGBREAK is generated when Ctrl-Break is pressed. */ 971 (void) SIGNAL( SIGBREAK, slap_sig_shutdown ); 972#endif 973 974#ifndef HAVE_WINSOCK 975 if ( !no_detach ) { 976 if ( lutil_pair( waitfds ) < 0 ) { 977 Debug( LDAP_DEBUG_ANY, 978 "main: lutil_pair failed: %d\n", 979 0 ); 980 rc = 1; 981 goto destroy; 982 } 983 pid = lutil_detach( no_detach, 0 ); 984 if ( pid ) { 985 char buf[4]; 986 rc = EXIT_SUCCESS; 987 close( waitfds[1] ); 988 if ( read( waitfds[0], buf, 1 ) != 1 ) 989 rc = EXIT_FAILURE; 990 _exit( rc ); 991 } else { 992 close( waitfds[0] ); 993 } 994 } 995#endif /* HAVE_WINSOCK */ 996 997#ifdef CSRIMALLOC 998 mal_leaktrace(1); 999#endif 1000 1001 if ( slapd_pid_file != NULL ) { 1002 FILE *fp = fopen( slapd_pid_file, "w" ); 1003 1004 if ( fp == NULL ) { 1005 char ebuf[128]; 1006 int save_errno = errno; 1007 1008 Debug( LDAP_DEBUG_ANY, "unable to open pid file " 1009 "\"%s\": %d (%s)\n", 1010 slapd_pid_file, 1011 save_errno, AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) ); 1012 1013 free( slapd_pid_file ); 1014 slapd_pid_file = NULL; 1015 1016 rc = 1; 1017 goto destroy; 1018 } 1019 fprintf( fp, "%d\n", (int) getpid() ); 1020 fclose( fp ); 1021 slapd_pid_file_unlink = 1; 1022 } 1023 1024 if ( slapd_args_file != NULL ) { 1025 FILE *fp = fopen( slapd_args_file, "w" ); 1026 1027 if ( fp == NULL ) { 1028 char ebuf[128]; 1029 int save_errno = errno; 1030 1031 Debug( LDAP_DEBUG_ANY, "unable to open args file " 1032 "\"%s\": %d (%s)\n", 1033 slapd_args_file, 1034 save_errno, AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) ); 1035 1036 free( slapd_args_file ); 1037 slapd_args_file = NULL; 1038 1039 rc = 1; 1040 goto destroy; 1041 } 1042 1043 for ( i = 0; i < g_argc; i++ ) { 1044 fprintf( fp, "%s ", g_argv[i] ); 1045 } 1046 fprintf( fp, "\n" ); 1047 fclose( fp ); 1048 slapd_args_file_unlink = 1; 1049 } 1050 1051 /* 1052 * FIXME: moved here from slapd_daemon_task() 1053 * because back-monitor db_open() needs it 1054 */ 1055 time( &starttime ); 1056 1057 connections_init(); 1058 1059 if ( slap_startup( NULL ) != 0 ) { 1060 rc = 1; 1061 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 ); 1062 goto shutdown; 1063 } 1064 1065 Debug( LDAP_DEBUG_ANY, "slapd starting\n" ); 1066 1067#ifndef HAVE_WINSOCK 1068 if ( !no_detach ) { 1069 write( waitfds[1], "1", 1 ); 1070 close( waitfds[1] ); 1071 } 1072#endif 1073 1074#ifdef HAVE_NT_EVENT_LOG 1075 if (is_NT_Service) 1076 lutil_LogStartedEvent( serverName, slap_debug, configfile ? 1077 configfile : SLAPD_DEFAULT_CONFIGFILE , urls ); 1078#endif 1079 1080 rc = slapd_daemon(); 1081 1082#ifdef HAVE_NT_SERVICE_MANAGER 1083 /* Throw away the event that we used during the startup process. */ 1084 if ( is_NT_Service ) 1085 ldap_pvt_thread_cond_destroy( &started_event ); 1086#endif 1087 1088shutdown: 1089 /* remember an error during shutdown */ 1090 rc |= slap_shutdown( NULL ); 1091 1092destroy: 1093 if ( check & CHECK_LOGLEVEL ) { 1094 (void)loglevel_print( stdout ); 1095 } 1096 /* remember an error during destroy */ 1097 rc |= slap_destroy(); 1098 1099 while ( !LDAP_STAILQ_EMPTY( &slap_sync_cookie )) { 1100 scp = LDAP_STAILQ_FIRST( &slap_sync_cookie ); 1101 LDAP_STAILQ_REMOVE_HEAD( &slap_sync_cookie, sc_next ); 1102 ch_free( scp ); 1103 } 1104 1105#ifdef SLAPD_MODULES 1106 module_kill(); 1107#endif 1108 1109 extops_kill(); 1110 1111 supported_feature_destroy(); 1112 entry_info_destroy(); 1113 1114stop: 1115#ifdef HAVE_NT_EVENT_LOG 1116 if (is_NT_Service) 1117 lutil_LogStoppedEvent( serverName ); 1118#endif 1119 1120 Debug( LDAP_DEBUG_ANY, "slapd stopped.\n" ); 1121 1122 1123#ifdef HAVE_NT_SERVICE_MANAGER 1124 lutil_ReportShutdownComplete(); 1125#endif 1126 1127#ifdef LOG_DEBUG 1128 closelog(); 1129#endif 1130 slapd_daemon_destroy(); 1131 1132 controls_destroy(); 1133 1134 filter_destroy(); 1135 1136 schema_destroy(); 1137 1138 lutil_passwd_destroy(); 1139 1140#ifdef HAVE_TLS 1141 if ( slap_tls_ld ) { 1142 ldap_pvt_tls_ctx_free( slap_tls_ctx ); 1143 ldap_unbind_ext( slap_tls_ld, NULL, NULL ); 1144 } 1145 ldap_pvt_tls_destroy(); 1146#endif 1147 1148 slap_sasl_regexp_destroy(); 1149 1150 if ( slapd_pid_file_unlink ) { 1151 unlink( slapd_pid_file ); 1152 } 1153 if ( slapd_args_file_unlink ) { 1154 unlink( slapd_args_file ); 1155 } 1156 1157 config_destroy(); 1158 1159 if ( global_host ) 1160 ch_free( global_host ); 1161 1162 /* kludge, get symbols referenced */ 1163 ldap_tavl_free( NULL, NULL ); 1164 1165#ifdef CSRIMALLOC 1166 mal_dumpleaktrace( leakfile ); 1167#endif 1168 1169 MAIN_RETURN(rc); 1170} 1171 1172 1173#ifdef LDAP_SIGCHLD 1174 1175/* 1176 * Catch and discard terminated child processes, to avoid zombies. 1177 */ 1178 1179static RETSIGTYPE 1180wait4child( int sig ) 1181{ 1182 int save_errno = errno; 1183 1184#ifdef WNOHANG 1185 do 1186 errno = 0; 1187#ifdef HAVE_WAITPID 1188 while ( waitpid( (pid_t)-1, NULL, WNOHANG ) > 0 || errno == EINTR ); 1189#else 1190 while ( wait3( NULL, WNOHANG, NULL ) > 0 || errno == EINTR ); 1191#endif 1192#else 1193 (void) wait( NULL ); 1194#endif 1195 (void) SIGNAL_REINSTALL( sig, wait4child ); 1196 errno = save_errno; 1197} 1198 1199#endif /* LDAP_SIGCHLD */ 1200