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