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