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