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