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