xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/main.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
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
49 static RETSIGTYPE wait4child( int sig );
50 #endif
51 
52 #ifdef HAVE_NT_SERVICE_MANAGER
53 #define MAIN_RETURN(x) return
54 static 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 
68 typedef int (MainFunc) LDAP_P(( int argc, char *argv[] ));
69 extern MainFunc slapadd, slapcat, slapdn, slapindex, slappasswd,
70 	slaptest, slapauth, slapacl, slapschema;
71 
72 static 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
100 const 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
107 static int check = CHECK_NONE;
108 static int version = 0;
109 
110 void *slap_tls_ctx;
111 LDAP *slap_tls_ld;
112 
113 static int
114 slapd_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  */
153 struct 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
165 int
166 parse_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 
200 int
201 parse_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 
228 int
229 parse_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 
246 int
247 parse_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 
304 static void
305 usage( 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
350 void WINAPI ServiceMain( DWORD argc, LPTSTR *argv )
351 #else
352 int 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:
671 unhandled_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 
971 shutdown:
972 	/* remember an error during shutdown */
973 	rc |= slap_shutdown( NULL );
974 
975 destroy:
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 
997 stop:
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 
1068 static RETSIGTYPE
1069 wait4child( 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