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