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 "slap.h"
39 #include "lutil.h"
40 #include "ldif.h"
41
42 #ifdef LDAP_SLAPI
43 #include "slapi/slapi.h"
44 #endif
45
46 #ifdef LDAP_SIGCHLD
47 static RETSIGTYPE wait4child( int sig );
48 #endif
49
50 #ifdef HAVE_NT_SERVICE_MANAGER
51 #define MAIN_RETURN(x) return
52 static struct sockaddr_in bind_addr;
53
54 #define SERVICE_EXIT( e, n ) do { \
55 if ( is_NT_Service ) { \
56 lutil_ServiceStatus.dwWin32ExitCode = (e); \
57 lutil_ServiceStatus.dwServiceSpecificExitCode = (n); \
58 } \
59 } while ( 0 )
60
61 #else
62 #define SERVICE_EXIT( e, n )
63 #define MAIN_RETURN(x) return(x)
64 #endif
65
66 typedef int (MainFunc) LDAP_P(( int argc, char *argv[] ));
67 extern MainFunc slapadd, slapcat, slapdn, slapindex, slappasswd,
68 slaptest, slapauth, slapacl, slapschema, slapmodify;
69
70 static struct {
71 char *name;
72 MainFunc *func;
73 } tools[] = {
74 {"slapadd", slapadd},
75 {"slapcat", slapcat},
76 {"slapdn", slapdn},
77 {"slapindex", slapindex},
78 {"slapmodify", slapmodify},
79 {"slappasswd", slappasswd},
80 {"slapschema", slapschema},
81 {"slaptest", slaptest},
82 {"slapauth", slapauth},
83 {"slapacl", slapacl},
84 /* NOTE: new tools must be added in chronological order,
85 * not in alphabetical order, because for backwards
86 * compatibility name[4] is used to identify the
87 * tools; so name[4]=='a' must refer to "slapadd" and
88 * not to "slapauth". Alphabetical order can be used
89 * for tools whose name[4] is not used yet */
90 {NULL, NULL}
91 };
92
93 /*
94 * when more than one slapd is running on one machine, each one might have
95 * it's own LOCAL for syslogging and must have its own pid/args files
96 */
97
98 #ifndef HAVE_MKVERSION
99 const char Versionstr[] =
100 OPENLDAP_PACKAGE " " OPENLDAP_VERSION " Standalone LDAP Server (slapd)";
101 #endif
102
103 extern OverlayInit slap_oinfo[];
104 extern BackendInfo slap_binfo[];
105
106 #define CHECK_NONE 0x00
107 #define CHECK_CONFIG 0x01
108 #define CHECK_LOGLEVEL 0x02
109 static int check = CHECK_NONE;
110 static int version = 0;
111
112 void *slap_tls_ctx;
113 LDAP *slap_tls_ld;
114
115 static int
slapd_opt_slp(const char * val,void * arg)116 slapd_opt_slp( const char *val, void *arg )
117 {
118 #ifdef HAVE_SLP
119 /* NULL is default */
120 if ( val == NULL || *val == '(' || strcasecmp( val, "on" ) == 0 ) {
121 slapd_register_slp = 1;
122 slapd_slp_attrs = (val != NULL && *val == '(') ? val : NULL;
123
124 } else if ( strcasecmp( val, "off" ) == 0 ) {
125 slapd_register_slp = 0;
126
127 /* NOTE: add support for URL specification? */
128
129 } else {
130 fprintf(stderr, "unrecognized value \"%s\" for SLP option\n", val );
131 return -1;
132 }
133
134 return 0;
135
136 #else
137 fputs( "slapd: SLP support is not available\n", stderr );
138 return 0;
139 #endif
140 }
141
142 /*
143 * Option helper structure:
144 *
145 * oh_nam is left-hand part of <option>[=<value>]
146 * oh_fnc is handler function
147 * oh_arg is an optional arg to oh_fnc
148 * oh_usage is the one-line usage string related to the option,
149 * which is assumed to start with <option>[=<value>]
150 *
151 * please leave valid options in the structure, and optionally #ifdef
152 * their processing inside the helper, so that reasonable and helpful
153 * error messages can be generated if a disabled option is requested.
154 */
155 struct option_helper {
156 struct berval oh_name;
157 int (*oh_fnc)(const char *val, void *arg);
158 void *oh_arg;
159 const char *oh_usage;
160 } option_helpers[] = {
161 { BER_BVC("slp"), slapd_opt_slp, NULL, "slp[={on|off|(attrs)}] enable/disable SLP using (attrs)" },
162 { BER_BVNULL, 0, NULL, NULL }
163 };
164
165 static void
usage(char * name)166 usage( char *name )
167 {
168 fprintf( stderr,
169 "usage: %s options\n", name );
170 fprintf( stderr,
171 "\t-4\t\tIPv4 only\n"
172 #ifdef LDAP_PF_INET6
173 "\t-6\t\tIPv6 only\n"
174 #endif
175 "\t-T {acl|add|auth|cat|dn|index|modify|passwd|test}\n"
176 "\t\t\tRun in Tool mode\n"
177 "\t-c cookie\tSync cookie of consumer\n"
178 "\t-d level\tDebug level" "\n"
179 "\t-f filename\tConfiguration file\n"
180 "\t-F dir\tConfiguration directory\n"
181 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
182 "\t-g group\tGroup (id or name) to run as\n"
183 #endif
184 "\t-h URLs\t\tList of URLs to serve\n"
185 #ifdef SLAP_DEFAULT_SYSLOG_USER
186 "\t-l facility\tSyslog facility (default: LOCAL4)\n"
187 #endif
188 "\t-n serverName\tService name\n"
189 "\t-o <opt>[=val] generic means to specify options" );
190 if ( !BER_BVISNULL( &option_helpers[0].oh_name ) ) {
191 int i;
192
193 fprintf( stderr, "; supported options:\n" );
194 for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); i++) {
195 fprintf( stderr, "\t\t%s\n", option_helpers[i].oh_usage );
196 }
197 } else {
198 fprintf( stderr, "\n" );
199 }
200 fprintf( stderr,
201 #ifdef HAVE_CHROOT
202 "\t-r directory\tSandbox directory to chroot to\n"
203 #endif
204 "\t-s level\tSyslog level\n"
205 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
206 "\t-u user\t\tUser (id or name) to run as\n"
207 #endif
208 "\t-V\t\tprint version info (-VV exit afterwards, -VVV print\n"
209 "\t\t\tinfo about static overlays and backends)\n"
210 );
211 }
212
213 #ifdef HAVE_NT_SERVICE_MANAGER
ServiceMain(DWORD argc,LPTSTR * argv)214 void WINAPI ServiceMain( DWORD argc, LPTSTR *argv )
215 #else
216 int main( int argc, char **argv )
217 #endif
218 {
219 int i, no_detach = 0;
220 int rc = 1;
221 char *urls = NULL;
222 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
223 char *username = NULL;
224 char *groupname = NULL;
225 #endif
226 #if defined(HAVE_CHROOT)
227 char *sandbox = NULL;
228 #endif
229 #ifdef SLAP_DEFAULT_SYSLOG_USER
230 int syslogUser = SLAP_DEFAULT_SYSLOG_USER;
231 #endif
232
233 #ifndef HAVE_WINSOCK
234 int pid, waitfds[2];
235 #endif
236 int g_argc = argc;
237 char **g_argv = argv;
238
239 char *configfile = NULL;
240 char *configdir = NULL;
241 char *serverName;
242 int serverMode = SLAP_SERVER_MODE;
243
244 struct sync_cookie *scp = NULL;
245 struct sync_cookie *scp_entry = NULL;
246
247 char *serverNamePrefix = "";
248 size_t l;
249
250 int slapd_pid_file_unlink = 0, slapd_args_file_unlink = 0;
251 int firstopt = 1;
252
253 #ifdef CSRIMALLOC
254 FILE *leakfile;
255 if( ( leakfile = fopen( "slapd.leak", "w" )) == NULL ) {
256 leakfile = stderr;
257 }
258 #endif
259
260 slap_sl_mem_init();
261
262 (void) ldap_pvt_thread_initialize();
263 ldap_pvt_thread_mutex_init( &logfile_mutex );
264
265 #ifdef HAVE_TLS
266 rc = ldap_create( &slap_tls_ld );
267 if ( rc ) {
268 MAIN_RETURN( rc );
269 }
270 /* Library defaults to full certificate checking. This is correct when
271 * a client is verifying a server because all servers should have a
272 * valid cert. But few clients have valid certs, so we want our default
273 * to be no checking. The config file can override this as usual.
274 */
275 rc = LDAP_OPT_X_TLS_NEVER;
276 (void) ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &rc );
277 #endif
278
279 serverName = lutil_progname( "slapd", argc, argv );
280
281 if ( strcmp( serverName, "slapd" ) ) {
282 #ifdef DEBUG_CLOSE
283 extern void slapd_debug_close();
284 slapd_debug_close();
285 #endif
286 for (i=0; tools[i].name; i++) {
287 if ( !strcmp( serverName, tools[i].name ) ) {
288 rc = tools[i].func(argc, argv);
289 MAIN_RETURN(rc);
290 }
291 }
292 }
293
294 #ifdef HAVE_NT_SERVICE_MANAGER
295 {
296 int *ip;
297 char *newConfigFile;
298 char *newConfigDir;
299 char *newUrls;
300 char *regService = NULL;
301
302 if ( is_NT_Service ) {
303 lutil_CommenceStartupProcessing( serverName, slap_sig_shutdown );
304 if ( strcmp(serverName, SERVICE_NAME) )
305 regService = serverName;
306 }
307
308 ip = (int*)lutil_getRegParam( regService, "DebugLevel" );
309 if ( ip != NULL ) {
310 slap_debug = *ip;
311 Debug( LDAP_DEBUG_ANY,
312 "new debug level from registry is: %d\n", slap_debug );
313 }
314
315 newUrls = (char *) lutil_getRegParam(regService, "Urls");
316 if (newUrls) {
317 if (urls)
318 ch_free(urls);
319
320 urls = ch_strdup(newUrls);
321 Debug(LDAP_DEBUG_ANY, "new urls from registry: %s\n",
322 urls );
323 }
324
325 newConfigFile = (char*)lutil_getRegParam( regService, "ConfigFile" );
326 if ( newConfigFile != NULL ) {
327 configfile = ch_strdup(newConfigFile);
328 Debug ( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", configfile );
329 }
330
331 newConfigDir = (char*)lutil_getRegParam( regService, "ConfigDir" );
332 if ( newConfigDir != NULL ) {
333 configdir = ch_strdup(newConfigDir);
334 Debug ( LDAP_DEBUG_ANY, "new config dir from registry is: %s\n", configdir );
335 }
336 }
337 #endif
338
339 while ( (i = getopt( argc, argv,
340 "c:d:f:F:h:n:o:s:tT:V"
341 #ifdef LDAP_PF_INET6
342 "46"
343 #endif
344 #ifdef HAVE_CHROOT
345 "r:"
346 #endif
347 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
348 "S:"
349 #ifdef LOG_LOCAL4
350 "l:"
351 #endif
352 #endif
353 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
354 "u:g:"
355 #endif
356 )) != EOF ) {
357 switch ( i ) {
358 case '4':
359 slap_inet4or6 = AF_INET;
360 break;
361 #ifdef LDAP_PF_INET6
362 case '6':
363 slap_inet4or6 = AF_INET6;
364 break;
365 #endif
366
367 case 'h': /* listen URLs */
368 if ( urls != NULL ) free( urls );
369 urls = optarg;
370 break;
371
372 case 'c': /* provide sync cookie, override if exist in consumer */
373 scp = (struct sync_cookie *) ch_calloc( 1,
374 sizeof( struct sync_cookie ));
375 ber_str2bv( optarg, 0, 1, &scp->octet_str );
376
377 /* This only parses out the rid at this point */
378 slap_parse_sync_cookie( scp, NULL );
379
380 if ( scp->rid == -1 ) {
381 Debug( LDAP_DEBUG_ANY,
382 "main: invalid cookie \"%s\"\n",
383 optarg );
384 slap_sync_cookie_free( scp, 1 );
385 goto destroy;
386 }
387
388 LDAP_STAILQ_FOREACH( scp_entry, &slap_sync_cookie, sc_next ) {
389 if ( scp->rid == scp_entry->rid ) {
390 Debug( LDAP_DEBUG_ANY,
391 "main: duplicated replica id in cookies\n" );
392 slap_sync_cookie_free( scp, 1 );
393 goto destroy;
394 }
395 }
396 LDAP_STAILQ_INSERT_TAIL( &slap_sync_cookie, scp, sc_next );
397 break;
398
399 case 'd': { /* set debug level and 'do not detach' flag */
400 int level = 0;
401
402 if ( strcmp( optarg, "?" ) == 0 ) {
403 check |= CHECK_LOGLEVEL;
404 break;
405 }
406
407 no_detach = 1;
408 if ( slap_parse_debug_level( optarg, &level, 0 ) ) {
409 goto destroy;
410 }
411 #ifdef LDAP_DEBUG
412 slap_debug |= level;
413 #else
414 if ( level != 0 )
415 fputs( "must compile with LDAP_DEBUG for debugging\n",
416 stderr );
417 #endif
418 } break;
419
420 case 'f': /* read config file */
421 configfile = optarg;
422 break;
423
424 case 'F': /* use config dir */
425 configdir = optarg;
426 break;
427
428 case 'o': {
429 char *val = strchr( optarg, '=' );
430 struct berval opt;
431
432 opt.bv_val = optarg;
433
434 if ( val ) {
435 opt.bv_len = ( val - optarg );
436 val++;
437
438 } else {
439 opt.bv_len = strlen( optarg );
440 }
441
442 for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); i++ ) {
443 if ( ber_bvstrcasecmp( &option_helpers[i].oh_name, &opt ) == 0 ) {
444 assert( option_helpers[i].oh_fnc != NULL );
445 if ( (*option_helpers[i].oh_fnc)( val, option_helpers[i].oh_arg ) == -1 ) {
446 /* we assume the option parsing helper
447 * issues appropriate and self-explanatory
448 * error messages... */
449 goto stop;
450 }
451 break;
452 }
453 }
454
455 if ( BER_BVISNULL( &option_helpers[i].oh_name ) ) {
456 goto unhandled_option;
457 }
458 break;
459 }
460
461 case 's': /* set syslog level */
462 if ( strcmp( optarg, "?" ) == 0 ) {
463 check |= CHECK_LOGLEVEL;
464 break;
465 }
466
467 if ( slap_parse_debug_level( optarg, &ldap_syslog, 1 ) ) {
468 goto destroy;
469 }
470 break;
471
472 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
473 case 'S':
474 if ( slap_parse_syslog_level( optarg, &ldap_syslog_level ) ) {
475 goto destroy;
476 }
477 break;
478
479 #ifdef LOG_LOCAL4
480 case 'l': /* set syslog local user */
481 if ( slap_parse_syslog_user( optarg, &syslogUser ) ) {
482 goto destroy;
483 }
484 break;
485 #endif
486 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
487
488 #ifdef HAVE_CHROOT
489 case 'r':
490 sandbox = optarg;
491 break;
492 #endif
493
494 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
495 case 'u': /* user name */
496 username = optarg;
497 break;
498
499 case 'g': /* group name */
500 groupname = optarg;
501 break;
502 #endif /* SETUID && GETUID */
503
504 case 'n': /* NT service name */
505 serverName = optarg;
506 break;
507
508 case 't':
509 /* deprecated; use slaptest instead */
510 fprintf( stderr, "option -t deprecated; "
511 "use slaptest command instead\n" );
512 check |= CHECK_CONFIG;
513 break;
514
515 case 'V':
516 version++;
517 break;
518
519 case 'T':
520 if ( firstopt == 0 ) {
521 fprintf( stderr, "warning: \"-T %s\" "
522 "should be the first option.\n",
523 optarg );
524 }
525
526 #ifdef DEBUG_CLOSE
527 extern void slapd_debug_close();
528 slapd_debug_close();
529 #endif
530 /* try full option string first */
531 for ( i = 0; tools[i].name; i++ ) {
532 if ( strcmp( optarg, &tools[i].name[4] ) == 0 ) {
533 rc = tools[i].func( argc, argv );
534 MAIN_RETURN( rc );
535 }
536 }
537
538 /* try bits of option string (backward compatibility for single char) */
539 l = strlen( optarg );
540 for ( i = 0; tools[i].name; i++ ) {
541 if ( strncmp( optarg, &tools[i].name[4], l ) == 0 ) {
542 rc = tools[i].func( argc, argv );
543 MAIN_RETURN( rc );
544 }
545 }
546
547 /* issue error */
548 serverName = optarg;
549 serverNamePrefix = "slap";
550 fprintf( stderr, "program name \"%s%s\" unrecognized; "
551 "aborting...\n", serverNamePrefix, serverName );
552 /* FALLTHRU */
553 default:
554 unhandled_option:;
555 usage( argv[0] );
556 rc = 1;
557 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 );
558 goto stop;
559 }
560
561 if ( firstopt ) {
562 firstopt = 0;
563 }
564 }
565
566 if ( optind != argc )
567 goto unhandled_option;
568
569 ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN, slap_debug_print);
570 ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug);
571 ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug);
572 ldif_debug = slap_debug;
573 slap_debug_orig = slap_debug;
574
575 if ( version ) {
576 fprintf( stderr, "%s\n", Versionstr );
577 if ( version > 2 ) {
578 if ( slap_oinfo[0].ov_type ) {
579 fprintf( stderr, "Included static overlays:\n");
580 for ( i= 0 ; slap_oinfo[i].ov_type; i++ ) {
581 fprintf( stderr, " %s\n", slap_oinfo[i].ov_type );
582 }
583 }
584 if ( slap_binfo[0].bi_type ) {
585 fprintf( stderr, "Included static backends:\n");
586 for ( i= 0 ; slap_binfo[i].bi_type; i++ ) {
587 fprintf( stderr, " %s\n", slap_binfo[i].bi_type );
588 }
589 }
590 }
591
592 if ( version > 1 ) goto stop;
593 }
594
595 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
596 {
597 char *logName;
598 #ifdef HAVE_EBCDIC
599 logName = ch_strdup( serverName );
600 __atoe( logName );
601 #else
602 logName = serverName;
603 #endif
604
605 #ifdef LOG_LOCAL4
606 openlog( logName, OPENLOG_OPTIONS, syslogUser );
607 #elif defined LOG_DEBUG
608 openlog( logName, OPENLOG_OPTIONS );
609 #endif
610 #ifdef HAVE_EBCDIC
611 free( logName );
612 #endif
613 }
614 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
615
616 Debug( LDAP_DEBUG_ANY, "%s", Versionstr );
617
618 global_host = ldap_pvt_get_fqdn( NULL );
619 ber_str2bv( global_host, 0, 0, &global_host_bv );
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
wait4child(int sig)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