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