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