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