]> git.sur5r.net Git - openldap/blob - servers/slapd/main.c
minor cleanup
[openldap] / servers / slapd / main.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 #include "portable.h"
7
8 #include <stdio.h>
9
10 #include <ac/signal.h>
11 #include <ac/socket.h>
12 #include <ac/string.h>
13 #include <ac/time.h>
14 #include <ac/unistd.h>
15 #include <ac/wait.h>
16 #include <ac/errno.h>
17
18 #include "ldap_pvt.h"
19
20 #include "slap.h"
21 #include "lutil.h"
22 #include "ldif.h"
23
24 /* I guess this should be declared in ldap_pvt.h */
25 extern int ldap_pvt_tls_init_def_ctx( void );
26
27 #ifdef LDAP_SIGCHLD
28 static RETSIGTYPE wait4child( int sig );
29 #endif
30
31 #ifdef HAVE_NT_SERVICE_MANAGER
32 #define MAIN_RETURN(x) return
33 struct sockaddr_in      bind_addr;
34
35 /* in nt_main.c */
36 LDAP_LUTIL_V(SERVICE_STATUS)            SLAPDServiceStatus;
37 LDAP_LUTIL_V(SERVICE_STATUS_HANDLE)     hSLAPDServiceStatus;
38 extern ldap_pvt_thread_cond_t   started_event,          stopped_event;
39 extern int        is_NT_Service;
40
41 void CommenceStartupProcessing( LPCTSTR serverName,
42                                                            void(*stopper)(int));
43 void ReportSlapdShutdownComplete( void );
44 void *getRegParam( char *svc, char *value );
45
46 #define SERVICE_EXIT( e, n )    do { \
47         if ( is_NT_Service ) { \
48                 SLAPDServiceStatus.dwWin32ExitCode                              = (e); \
49                 SLAPDServiceStatus.dwServiceSpecificExitCode    = (n); \
50         } \
51 } while ( 0 )
52
53 #else
54 #define SERVICE_EXIT( e, n )
55 #define MAIN_RETURN(x) return(x)
56 #endif
57
58 #ifdef HAVE_NT_EVENT_LOG
59 void LogSlapdStartedEvent( char *svc, int slap_debug, char *configfile, char *urls );
60 void LogSlapdStoppedEvent( char *svc );
61 #endif
62
63 /*
64  * when more than one slapd is running on one machine, each one might have
65  * it's own LOCAL for syslogging and must have its own pid/args files
66  */
67
68 #ifndef HAVE_MKVERSION
69 const char Versionstr[] =
70         OPENLDAP_PACKAGE " " OPENLDAP_VERSION " Standalone LDAP Server (slapd)";
71 #endif
72
73 #ifdef LOG_LOCAL4
74
75 #define DEFAULT_SYSLOG_USER  LOG_LOCAL4
76
77 typedef struct _str2intDispatch {
78         char    *stringVal;
79         int      abbr;
80         int      intVal;
81 } STRDISP, *STRDISP_P;
82
83
84 /* table to compute syslog-options to integer */
85 static STRDISP  syslog_types[] = {
86         { "LOCAL0", sizeof("LOCAL0"), LOG_LOCAL0 },
87         { "LOCAL1", sizeof("LOCAL1"), LOG_LOCAL1 },
88         { "LOCAL2", sizeof("LOCAL2"), LOG_LOCAL2 },
89         { "LOCAL3", sizeof("LOCAL3"), LOG_LOCAL3 },
90         { "LOCAL4", sizeof("LOCAL4"), LOG_LOCAL4 },
91         { "LOCAL5", sizeof("LOCAL5"), LOG_LOCAL5 },
92         { "LOCAL6", sizeof("LOCAL6"), LOG_LOCAL6 },
93         { "LOCAL7", sizeof("LOCAL7"), LOG_LOCAL7 },
94         { NULL }
95 };
96
97 static int   cnvt_str2int( char *, STRDISP_P, int );
98
99 #endif  /* LOG_LOCAL4 */
100
101
102 static void
103 usage( char *name )
104 {
105         fprintf( stderr,
106                 "usage: %s options\n", name );
107         fprintf( stderr,
108                 "\t-d level\tDebug Level" "\n"
109                 "\t-f filename\tConfiguration File\n"
110 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
111                 "\t-g group\tGroup (id or name) to ran as\n"
112 #endif
113                 "\t-h URLs\tList of URLs to serve\n"
114 #ifdef LOG_LOCAL4
115                 "\t-l sysloguser\tSyslog User (default: LOCAL4)\n"
116 #endif
117                 "\t-n serverName\tservice name\n"
118 #ifdef HAVE_CHROOT
119                 "\t-r directory\n"
120 #endif
121                 "\t-s level\tSyslog Level\n"
122 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
123                 "\t-u user\tUser (id or name) to ran as\n"
124 #endif
125     );
126 }
127
128 #ifdef HAVE_NT_SERVICE_MANAGER
129 void WINAPI ServiceMain( DWORD argc, LPTSTR *argv )
130 #else
131 int main( int argc, char **argv )
132 #endif
133 {
134         int             i, no_detach = 0;
135         int             rc = 1;
136         char *urls = NULL;
137 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
138         char *username = NULL;
139         char *groupname = NULL;
140 #endif
141 #if defined(HAVE_CHROOT)
142         char *sandbox = NULL;
143 #endif
144 #ifdef LOG_LOCAL4
145     int     syslogUser = DEFAULT_SYSLOG_USER;
146 #endif
147
148 #ifdef HAVE_NT_SERVICE_MANAGER
149         char            *configfile = ".\\slapd.conf";
150 #else
151         char            *configfile = SLAPD_DEFAULT_CONFIGFILE;
152 #endif
153         char        *serverName = NULL;
154         int         serverMode = SLAP_SERVER_MODE;
155
156 #ifdef CSRIMALLOC
157         FILE *leakfile;
158         if( ( leakfile = fopen( "slapd.leak", "w" )) == NULL ) {
159                 leakfile = stderr;
160         }
161 #endif
162
163         g_argc = argc;
164         g_argv = argv;
165
166 #ifdef HAVE_NT_SERVICE_MANAGER
167         {
168                 int *i;
169                 char *newConfigFile;
170                 char *newUrls;
171                 char *regService = NULL;
172
173                 if ( is_NT_Service ) {
174                         serverName = argv[0];
175                         CommenceStartupProcessing( serverName, slap_sig_shutdown );
176                         if ( strcmp(serverName, SERVICE_NAME) )
177                             regService = serverName;
178                 }
179
180                 i = (int*)getRegParam( regService, "DebugLevel" );
181                 if ( i != NULL ) 
182                 {
183                         slap_debug = *i;
184 #ifdef NEW_LOGGING
185                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
186                                    "main: new debug level from registry is: %d\n", slap_debug ));
187 #else
188                         Debug( LDAP_DEBUG_ANY, "new debug level from registry is: %d\n", slap_debug, 0, 0 );
189 #endif
190                 }
191
192                 newUrls = (char *) getRegParam(regService, "Urls");
193                 if (newUrls)
194                 {
195                     if (urls)
196                         ch_free(urls);
197
198                     urls = ch_strdup(newUrls);
199 #ifdef NEW_LOGGING
200                     LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
201                                "main: new urls from registry: %s\n", urls ));
202 #else
203                     Debug(LDAP_DEBUG_ANY, "new urls from registry: %s\n",
204                           urls, 0, 0);
205 #endif
206
207                 }
208
209                 newConfigFile = (char*)getRegParam( regService, "ConfigFile" );
210                 if ( newConfigFile != NULL ) 
211                 {
212                         configfile = newConfigFile;
213 #ifdef NEW_LOGGING
214                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
215                                    "main: new config file from registry is: %s\n", configfile ));
216 #else
217                         Debug ( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", configfile, 0, 0 );
218 #endif
219
220                 }
221         }
222 #endif
223
224         while ( (i = getopt( argc, argv,
225                              "d:f:h:s:n:"
226 #ifdef HAVE_CHROOT
227                                 "r:"
228 #endif
229 #ifdef LOG_LOCAL4
230                              "l:"
231 #endif
232 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
233                              "u:g:"
234 #endif
235                              )) != EOF ) {
236                 switch ( i ) {
237                 case 'h':       /* listen URLs */
238                         if ( urls != NULL ) free( urls );
239                         urls = ch_strdup( optarg );
240             break;
241
242                 case 'd':       /* set debug level and 'do not detach' flag */
243                         no_detach = 1;
244 #ifdef LDAP_DEBUG
245                         slap_debug |= atoi( optarg );
246 #else
247                         if ( atoi( optarg ) != 0 )
248                                 fputs( "must compile with LDAP_DEBUG for debugging\n",
249                                        stderr );
250 #endif
251                         break;
252
253                 case 'f':       /* read config file */
254                         configfile = ch_strdup( optarg );
255                         break;
256
257                 case 's':       /* set syslog level */
258                         ldap_syslog = atoi( optarg );
259                         break;
260
261 #ifdef LOG_LOCAL4
262                 case 'l':       /* set syslog local user */
263                         syslogUser = cnvt_str2int( optarg,
264                                 syslog_types, DEFAULT_SYSLOG_USER );
265                         break;
266 #endif
267
268 #ifdef HAVE_CHROOT
269                 case 'r':
270                         if( sandbox ) free(sandbox);
271                         sandbox = ch_strdup( optarg );
272                         break;
273 #endif
274
275 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
276                 case 'u':       /* user name */
277                         if( username ) free(username);
278                         username = ch_strdup( optarg );
279                         break;
280
281                 case 'g':       /* group name */
282                         if( groupname ) free(groupname);
283                         groupname = ch_strdup( optarg );
284                         break;
285 #endif /* SETUID && GETUID */
286
287                 case 'n':  /* NT service name */
288                         if( serverName != NULL ) free( serverName );
289                         serverName = ch_strdup( optarg );
290                         break;
291
292                 default:
293                         usage( argv[0] );
294                         rc = 1;
295                         SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 );
296                         goto stop;
297                 }
298         }
299
300 #ifdef NEW_LOGGING
301         lutil_log_initialize( argc, argv );
302 #endif
303
304         lutil_set_debug_level( "slapd", slap_debug );
305         ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug);
306         ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug);
307         ldif_debug = slap_debug;
308
309 #ifdef NEW_LOGGING
310         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
311                    "%s", Versionstr ));
312 #else
313         Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 );
314 #endif
315
316
317         if( serverName == NULL ) {
318                 if ( (serverName = strrchr( argv[0], *LDAP_DIRSEP )) == NULL ) {
319                         serverName = ch_strdup( argv[0] );
320                 } else {
321                         serverName = ch_strdup( serverName + 1 );
322                 }
323         }
324
325 #ifdef LOG_LOCAL4
326         openlog( serverName, OPENLOG_OPTIONS, syslogUser );
327 #elif LOG_DEBUG
328         openlog( serverName, OPENLOG_OPTIONS );
329 #endif
330
331         if( slapd_daemon_init( urls ) != 0 ) {
332                 rc = 1;
333                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 );
334                 goto stop;
335         }
336
337 #if defined(HAVE_CHROOT)
338         if ( sandbox ) {
339                 if ( chdir( sandbox ) ) {
340                         perror("chdir");
341                         rc = 1;
342                         goto stop;
343                 }
344                 if ( chroot( sandbox ) ) {
345                         perror("chroot");
346                         rc = 1;
347                         goto stop;
348                 }
349         }
350 #endif
351
352 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
353         if ( username != NULL || groupname != NULL ) {
354                 slap_init_user( username, groupname );
355         }
356 #endif
357
358         extops_init();
359
360 #ifdef SLAPD_MODULES
361         if ( module_init() != 0 ) {
362                 rc = 1;
363                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 17 );
364                 goto destroy;
365         }
366 #endif
367
368         if ( slap_init( serverMode, serverName ) != 0 ) {
369                 rc = 1;
370                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 );
371                 goto destroy;
372         }
373
374         if ( schema_init( ) != 0 ) {
375 #ifdef NEW_LOGGING
376                 LDAP_LOG(( "operation", LDAP_LEVEL_CRIT,
377                            "main: schema initialization error\n" ));
378 #else
379                 Debug( LDAP_DEBUG_ANY,
380                     "schema initialization error\n",
381                     0, 0, 0 );
382 #endif
383
384                 goto destroy;
385         }
386
387         if ( read_config( configfile ) != 0 ) {
388                 rc = 1;
389                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 );
390                 goto destroy;
391         }
392
393         if ( schema_prep( ) != 0 ) {
394 #ifdef NEW_LOGGING
395                 LDAP_LOG(( "operation", LDAP_LEVEL_CRIT,
396                            "main: schema prep error\n"));
397 #else
398                 Debug( LDAP_DEBUG_ANY,
399                     "schema prep error\n",
400                     0, 0, 0 );
401 #endif
402
403                 goto destroy;
404         }
405
406 #ifdef HAVE_TLS
407         rc = ldap_pvt_tls_init();
408         if( rc != 0) {
409 #ifdef NEW_LOGGING
410                 LDAP_LOG(( "operation", LDAP_LEVEL_CRIT,
411                            "main: tls init failed: %d\n", rc ));
412 #else
413                 Debug( LDAP_DEBUG_ANY,
414                     "main: TLS init failed: %d\n",
415                     0, 0, 0 );
416 #endif
417                 rc = 1;
418                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
419                 goto destroy;
420         }
421
422         rc = ldap_pvt_tls_init_def_ctx();
423         if( rc != 0) {
424 #ifdef NEW_LOGGING
425                 LDAP_LOG(( "operation", LDAP_LEVEL_CRIT,
426                            "main: tls init def ctx failed: %d\n", rc ));
427 #else
428                 Debug( LDAP_DEBUG_ANY,
429                     "main: TLS init def ctx failed: %d\n",
430                     0, 0, 0 );
431 #endif
432                 rc = 1;
433                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
434                 goto destroy;
435         }
436 #endif
437
438         (void) SIGNAL( LDAP_SIGUSR1, slap_sig_wake );
439         (void) SIGNAL( LDAP_SIGUSR2, slap_sig_shutdown );
440
441 #ifdef SIGPIPE
442         (void) SIGNAL( SIGPIPE, SIG_IGN );
443 #endif
444 #ifdef SIGHUP
445         (void) SIGNAL( SIGHUP, slap_sig_shutdown );
446 #endif
447         (void) SIGNAL( SIGINT, slap_sig_shutdown );
448         (void) SIGNAL( SIGTERM, slap_sig_shutdown );
449 #ifdef LDAP_SIGCHLD
450         (void) SIGNAL( LDAP_SIGCHLD, wait4child );
451 #endif
452 #ifdef SIGBREAK
453         /* SIGBREAK is generated when Ctrl-Break is pressed. */
454         (void) SIGNAL( SIGBREAK, slap_sig_shutdown );
455 #endif
456
457 #ifndef HAVE_WINSOCK
458         lutil_detach( no_detach, 0 );
459 #endif /* HAVE_WINSOCK */
460
461 #ifdef CSRIMALLOC
462         mal_leaktrace(1);
463 #endif
464
465         if ( slap_startup( NULL )  != 0 ) {
466                 rc = 1;
467                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 );
468                 goto shutdown;
469         }
470
471         {
472                 FILE *fp;
473
474 #ifdef NEW_LOGGING
475                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
476                            "main: slapd starting.\n" ));
477 #else
478                 Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 );
479 #endif
480
481
482                 if (( slapd_pid_file != NULL ) &&
483                         (( fp = fopen( slapd_pid_file, "w" )) != NULL ))
484                 {
485                         fprintf( fp, "%d\n", (int) getpid() );
486                         fclose( fp );
487                 }
488
489                 if (( slapd_args_file != NULL ) &&
490                         (( fp = fopen( slapd_args_file, "w" )) != NULL ))
491                 {
492                         for ( i = 0; i < g_argc; i++ ) {
493                                 fprintf( fp, "%s ", g_argv[i] );
494                         }
495                         fprintf( fp, "\n" );
496                         fclose( fp );
497                 }
498         }
499
500 #ifdef HAVE_NT_EVENT_LOG
501         if (is_NT_Service)
502         LogSlapdStartedEvent( serverName, slap_debug, configfile, urls );
503 #endif
504
505         rc = slapd_daemon();
506
507 #ifdef HAVE_NT_SERVICE_MANAGER
508         /* Throw away the event that we used during the startup process. */
509         if ( is_NT_Service )
510                 ldap_pvt_thread_cond_destroy( &started_event );
511 #endif
512
513 shutdown:
514         /* remember an error during shutdown */
515         rc |= slap_shutdown( NULL );
516
517 destroy:
518         /* remember an error during destroy */
519         rc |= slap_destroy();
520
521 #ifdef SLAPD_MODULES
522         module_kill();
523 #endif
524
525         extops_kill();
526
527 stop:
528 #ifdef HAVE_NT_EVENT_LOG
529         if (is_NT_Service)
530         LogSlapdStoppedEvent( serverName );
531 #endif
532
533 #ifdef NEW_LOGGING
534         LDAP_LOG(( "operation", LDAP_LEVEL_CRIT,
535                    "main: slapd stopped.\n" ));
536 #else
537         Debug( LDAP_DEBUG_ANY, "slapd stopped.\n", 0, 0, 0 );
538 #endif
539
540
541 #ifdef HAVE_NT_SERVICE_MANAGER
542         ReportSlapdShutdownComplete();
543 #endif
544
545 #ifdef LOG_DEBUG
546     closelog();
547 #endif
548         slapd_daemon_destroy();
549
550         schema_destroy();
551
552 #ifdef HAVE_TLS
553         ldap_pvt_tls_destroy();
554 #endif
555
556 #ifdef CSRIMALLOC
557         mal_dumpleaktrace( leakfile );
558 #endif
559
560         MAIN_RETURN(rc);
561 }
562
563
564 #ifdef LDAP_SIGCHLD
565
566 /*
567  *  Catch and discard terminated child processes, to avoid zombies.
568  */
569
570 static RETSIGTYPE
571 wait4child( int sig )
572 {
573     int save_errno = errno;
574
575 #ifdef WNOHANG
576     errno = 0;
577 #ifdef HAVE_WAITPID
578     while ( waitpid( (pid_t)-1, NULL, WNOHANG ) > 0 || errno == EINTR )
579         ;       /* NULL */
580 #else
581     while ( wait3( NULL, WNOHANG, NULL ) > 0 || errno == EINTR )
582         ;       /* NULL */
583 #endif
584 #else
585     (void) wait( NULL );
586 #endif
587     (void) SIGNAL_REINSTALL( sig, wait4child );
588     errno = save_errno;
589 }
590
591 #endif /* SIGCHLD || SIGCLD */
592
593
594 #ifdef LOG_LOCAL4
595
596 /*
597  *  Convert a string to an integer by means of a dispatcher table
598  *  if the string is not in the table return the default
599  */
600
601 static int
602 cnvt_str2int( char *stringVal, STRDISP_P dispatcher, int defaultVal )
603 {
604     int        retVal = defaultVal;
605     STRDISP_P  disp;
606
607     for (disp = dispatcher; disp->stringVal; disp++) {
608
609         if (!strncasecmp (stringVal, disp->stringVal, disp->abbr)) {
610
611             retVal = disp->intVal;
612             break;
613
614         }
615     }
616
617     return (retVal);
618 }
619
620 #endif  /* LOG_LOCAL4 */