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