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