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