]> git.sur5r.net Git - openldap/blob - servers/slapd/main.c
2da444a9fc09ff18b0aa6a5112ea7405566c9a66
[openldap] / servers / slapd / main.c
1 #include "portable.h"
2
3 #include <stdio.h>
4
5 #include <ac/signal.h>
6 #include <ac/socket.h>
7 #include <ac/string.h>
8 #include <ac/time.h>
9 #include <ac/unistd.h>
10 #include <ac/wait.h>
11 #include <ac/signal.h>
12 #include <ac/errno.h>
13
14 #include "ldap_defaults.h"
15 #include "slap.h"
16 #include "lutil.h"
17
18 #ifdef LDAP_SIGCHLD
19 static RETSIGTYPE wait4child( int sig );
20 #endif
21
22 #ifdef HAVE_WINSOCK
23 #define MAIN_RETURN(x) return
24 struct sockaddr_in      bind_addr;
25
26 /* in nt_main.c */
27 extern SERVICE_STATUS                   SLAPDServiceStatus;
28 extern SERVICE_STATUS_HANDLE    hSLAPDServiceStatus;
29 extern ldap_pvt_thread_cond_t   started_event,          stopped_event;
30 extern int        is_NT_Service;
31
32 void LogSlapdStartedEvent( char *svc, int slap_debug, char *configfile, short port, int udp );
33 void LogSlapdStoppedEvent( char *svc );
34
35 void CommenceStartupProcessing( LPCTSTR serviceName,
36                                                            void(*stopper)(int));
37 void ReportSlapdShutdownComplete( void );
38 void *getRegParam( char *svc, char *value );
39
40 #define SERVICE_EXIT( e, n ) \
41                 if ( is_NT_Service ) \
42 { \
43                         SLAPDServiceStatus.dwWin32ExitCode                              = e; \
44                         SLAPDServiceStatus.dwServiceSpecificExitCode    = n; \
45
46 #else
47 #define SERVICE_EXIT( e, n )
48 #define MAIN_RETURN(x) return(x)
49 #endif
50
51 short port = LDAP_PORT;
52 #ifdef HAVE_TLS
53 short tls_port = LDAP_TLS_PORT;
54 #endif
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, "usage: %s [-d ?|debuglevel] [-f configfile] [-p portnumber] [-s sysloglevel]", name );
98     fprintf( stderr, "\n        [-a bind-address] [-i] [-u]" );
99 #ifdef HAVE_WINSOCK
100         fprintf( stderr, " [-n NTserviceName]" );
101 #endif
102 #if LDAP_CONNECTIONLESS
103         fprintf( stderr, " [-c]" );
104 #endif
105 #ifdef SLAPD_BDB2
106     fprintf( stderr, " [-t]" );
107 #endif
108 #ifdef LOG_LOCAL4
109     fprintf( stderr, " [-l sysloguser]" );
110 #endif
111 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
112     fprintf( stderr, " [-u user] [-g group]" );
113 #endif
114     fprintf( stderr, "\n" );
115 }
116
117 time_t starttime;
118 struct sockaddr_in      bind_addr;
119 ber_int_t tcps;
120 #ifdef HAVE_TLS
121 struct sockaddr_in      tls_bind_addr;
122 ber_int_t tls_tcps;
123 #endif
124
125 #ifdef HAVE_WINSOCK
126 void WINAPI ServiceMain( DWORD argc, LPTSTR *argv )
127 #else
128 int main( int argc, char **argv )
129 #endif
130 {
131         int             i;
132         int             inetd = 0;
133         int             rc;
134         struct slapd_args args;
135         int             udp;
136 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
137         char *username = NULL;
138         char *groupname = NULL;
139 #endif
140 #ifdef LOG_LOCAL4
141     int     syslogUser = DEFAULT_SYSLOG_USER;
142 #endif
143 #ifdef HAVE_WINSOCK
144         char        *NTservice  = SERVICE_NAME;
145         char            *configfile = ".\\slapd.conf";
146 #else
147         char            *configfile = SLAPD_DEFAULT_CONFIGFILE;
148 #endif
149         char        *serverName;
150         int         serverMode = SLAP_SERVER_MODE;
151         int             use_tls_port = 0;
152
153         (void) memset( (void*) &bind_addr, '\0', sizeof(bind_addr));
154         bind_addr.sin_family = AF_INET;
155         bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
156         bind_addr.sin_port = htons(port);
157 #ifdef HAVE_TLS
158         tls_bind_addr.sin_family = AF_INET;
159         tls_bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
160         tls_bind_addr.sin_port = htons(tls_port);
161 #endif
162
163         g_argc = argc;
164         g_argv = argv;
165
166 #ifdef HAVE_WINSOCK
167         {
168                 int *newPort;
169                 int *newDebugLevel;
170                 char *newConfigFile;
171                 ldap_debug = 0xffff;
172                 if ( is_NT_Service ) CommenceStartupProcessing( NTservice, slap_set_shutdown );
173                 newPort = (int*)getRegParam( NULL, "Port" );
174                 if ( newPort != NULL )
175                 {
176                         port = *newPort;
177                         bind_addr.sin_port = htons(port);
178                         Debug ( LDAP_DEBUG_ANY, "new port from registry is: %d\n", port, 0, 0 );
179                 }
180                 newDebugLevel = (int*)getRegParam( NULL, "DebugLevel" );
181                 if ( newDebugLevel != NULL ) 
182                 {
183                         slap_debug = *newDebugLevel;
184                         Debug( LDAP_DEBUG_ANY, "new debug level from registry is: %d\n", slap_debug, 0, 0 );
185                 }
186                 newConfigFile = (char*)getRegParam( NULL, "ConfigFile" );
187                 if ( newConfigFile != NULL ) 
188                 {
189                         configfile = newConfigFile;
190                         Debug ( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", configfile, 0, 0 );
191                 }
192         }
193 #endif
194
195         while ( (i = getopt( argc, argv,
196                              "d:f:ia:p:s:u"
197 #ifdef LOG_LOCAL4
198                              "l:"
199 #endif
200 #ifdef SLAPD_BDB2
201                              "t"
202 #endif
203 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
204                              "u:g:"
205 #endif
206 #ifdef LDAP_CONNECTIONLESS
207                                  "c"
208 #endif
209 #ifdef HAVE_WINSOCK
210                                  "n:"
211 #endif
212 #ifdef HAVE_TLS
213                              "P:T"
214 #endif
215                              )) != EOF ) {
216                 switch ( i ) {
217                 case 'a':       /* bind address */
218 #ifdef HAVE_WINSOCK
219                         if(!(bind_addr.sin_addr.S_un.S_addr = inet_addr(optarg)))
220 #else
221                         if(!inet_aton(optarg, &bind_addr.sin_addr))
222 #endif
223                         {
224                                 fprintf(stderr, "invalid address (%s) for -a option", optarg);
225                         }
226 #ifdef HAVE_TLS
227 #ifdef HAVE_WINSOCK
228                         tls_bind_addr.sin_addr.S_un.S_addr = inet_addr(optarg);
229 #else
230                         inet_aton(optarg, &tls_bind_addr.sin_addr);
231 #endif
232 #endif
233             break;
234
235 #ifdef LDAP_DEBUG
236                 case 'd':       /* turn on debugging */
237                         if ( optarg[0] == '?' ) {
238                                 printf( "Debug levels:\n" );
239                                 printf( "\tLDAP_DEBUG_TRACE\t%d\n",
240                                     LDAP_DEBUG_TRACE );
241                                 printf( "\tLDAP_DEBUG_PACKETS\t%d\n",
242                                     LDAP_DEBUG_PACKETS );
243                                 printf( "\tLDAP_DEBUG_ARGS\t\t%d\n",
244                                     LDAP_DEBUG_ARGS );
245                                 printf( "\tLDAP_DEBUG_CONNS\t%d\n",
246                                     LDAP_DEBUG_CONNS );
247                                 printf( "\tLDAP_DEBUG_BER\t\t%d\n",
248                                     LDAP_DEBUG_BER );
249                                 printf( "\tLDAP_DEBUG_FILTER\t%d\n",
250                                     LDAP_DEBUG_FILTER );
251                                 printf( "\tLDAP_DEBUG_CONFIG\t%d\n",
252                                     LDAP_DEBUG_CONFIG );
253                                 printf( "\tLDAP_DEBUG_ACL\t\t%d\n",
254                                     LDAP_DEBUG_ACL );
255                                 printf( "\tLDAP_DEBUG_STATS\t%d\n",
256                                     LDAP_DEBUG_STATS );
257                                 printf( "\tLDAP_DEBUG_STATS2\t%d\n",
258                                     LDAP_DEBUG_STATS2 );
259                                 printf( "\tLDAP_DEBUG_SHELL\t%d\n",
260                                     LDAP_DEBUG_SHELL );
261                                 printf( "\tLDAP_DEBUG_PARSE\t%d\n",
262                                     LDAP_DEBUG_PARSE );
263                                 printf( "\tLDAP_DEBUG_ANY\t\t%d\n",
264                                     LDAP_DEBUG_ANY );
265                                 exit( 0 );
266                         } else {
267                                 slap_debug |= atoi( optarg );
268                         }
269                         break;
270 #else
271                 case 'd':       /* turn on debugging */
272                         fprintf( stderr,
273                             "must compile with LDAP_DEBUG for debugging\n" );
274                         break;
275 #endif
276
277                 case 'f':       /* read config file */
278                         configfile = ch_strdup( optarg );
279                         break;
280
281                 case 'i':       /* run from inetd */
282                         inetd = 1;
283                         break;
284
285                 case 'p': {     /* port on which to listen */
286                                 port = (short)atoi( optarg );
287                                 if(! port ) {
288                                         fprintf(stderr, "-p %s must be numeric\n", optarg);
289                                 } else {
290                                         bind_addr.sin_port = htons(port);
291                                 }
292                         } break;
293
294 #ifdef HAVE_TLS
295                 case 'P': {     /* port on which to listen for TLS */
296                                 tls_port = (short)atoi( optarg );
297                                 if(! tls_port ) {
298                                         fprintf(stderr, "-P %s must be numeric\n", optarg);
299                                 } else {
300                                         tls_bind_addr.sin_port = htons(tls_port);
301                                 }
302                         } break;
303 #endif
304
305                 case 's':       /* set syslog level */
306                         ldap_syslog = atoi( optarg );
307                         break;
308
309 #ifdef LOG_LOCAL4
310                 case 'l':       /* set syslog local user */
311                         syslogUser = cnvt_str2int( optarg, syslog_types,
312                                            DEFAULT_SYSLOG_USER );
313                         break;
314 #endif
315
316 #ifdef LDAP_CONNECTIONLESS
317                 case 'c':       /* do connectionless (udp) */
318                         udp = 1;
319                         break;
320 #endif
321
322 #ifdef SLAPD_BDB2
323                 case 't':  /* timed server */
324                         serverMode = SLAP_TIMEDSERVER_MODE;
325                         break;
326 #endif
327
328 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
329                 case 'u':       /* user name */
330                         if( username ) free(username);
331                         username = ch_strdup( optarg );
332                         break;
333
334                 case 'g':       /* group name */
335                         if( groupname ) free(groupname);
336                         groupname = ch_strdup( optarg );
337                         break;
338 #endif /* SETUID && GETUID */
339 #ifdef HAVE_WINSOCK
340                 case 'n':  /* NT service name */
341                         NTservice = ch_strdup( optarg );
342                         break;
343 #endif
344 #ifdef HAVE_TLS
345                 case 'T':  /* Bind on TLS port */
346                         use_tls_port = 1;
347 #endif
348                 default:
349                         usage( argv[0] );
350                         rc = 1;
351                         SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 );
352                         goto stop;
353                 }
354         }
355
356         ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug);
357         ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug);
358         ldif_debug = slap_debug;
359
360         Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 );
361
362         if ( (serverName = strrchr( argv[0], *LDAP_DIRSEP )) == NULL ) {
363                 serverName = ch_strdup( argv[0] );
364         } else {
365                 serverName = ch_strdup( serverName + 1 );
366         }
367
368 #ifdef LOG_LOCAL4
369         openlog( serverName, OPENLOG_OPTIONS, syslogUser );
370 #else
371         openlog( serverName, OPENLOG_OPTIONS );
372 #endif
373
374 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
375         if ( username != NULL || groupname != NULL )
376                 slap_init_user( username, groupname );
377 #endif
378
379         if ( slap_init( serverMode, serverName ) != 0 ) {
380                 rc = 1;
381                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 );
382                 goto destroy;
383         }
384
385         if ( read_config( configfile ) != 0 ) {
386                 rc = 1;
387                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 );
388                 goto destroy;
389         }
390
391         tcps = set_socket( inetd ? NULL : &bind_addr );
392         if ( tcps == -1 )
393                 goto destroy;
394 #ifdef HAVE_TLS
395         if ( use_tls_port ) {
396                 tls_tcps = set_socket( inetd ? NULL : &tls_bind_addr );
397                 if ( tls_tcps == -1 )
398                         goto destroy;
399         } else {
400                 tls_tcps = -1;
401         }
402 #endif
403
404         (void) SIGNAL( LDAP_SIGUSR1, slap_do_nothing );
405         (void) SIGNAL( LDAP_SIGUSR2, slap_set_shutdown );
406 #ifdef SIGPIPE
407         (void) SIGNAL( SIGPIPE, SIG_IGN );
408 #endif
409 #ifdef SIGHUP
410         (void) SIGNAL( SIGHUP, slap_set_shutdown );
411 #endif
412         (void) SIGNAL( SIGINT, slap_set_shutdown );
413         (void) SIGNAL( SIGTERM, slap_set_shutdown );
414 #ifdef LDAP_SIGCHLD
415         (void) SIGNAL( LDAP_SIGCHLD, wait4child );
416 #endif
417 #ifdef SIGBREAK
418         /* SIGBREAK is generated when Ctrl-Break is pressed. */
419         (void) SIGNAL( SIGBREAK, slap_set_shutdown );
420 #endif
421
422 #ifndef HAVE_WINSOCK
423         if(!inetd) {
424 #ifdef LDAP_DEBUG
425                 lutil_detach( ldap_debug, 0 );
426 #else
427                 lutil_detach( 0, 0 );
428 #endif
429         }
430 #endif /* HAVE_WINSOC */
431
432         if ( slap_startup(-1)  != 0 ) {
433                 rc = 1;
434                 SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
435                 goto shutdown;
436         }
437
438         if(!inetd) {
439                 FILE *fp;
440
441                 args.addr = &bind_addr;
442 #ifdef HAVE_TLS
443                 args.tls_addr = &tls_bind_addr;
444 #endif
445
446                 Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 );
447
448                 if (( slapd_pid_file != NULL ) &&
449                         (( fp = fopen( slapd_pid_file, "w" )) != NULL ))
450                 {
451                         fprintf( fp, "%d\n", (int) getpid() );
452                         fclose( fp );
453                 }
454
455                 if (( slapd_args_file != NULL ) &&
456                         (( fp = fopen( slapd_args_file, "w" )) != NULL ))
457                 {
458                         for ( i = 0; i < g_argc; i++ ) {
459                                 fprintf( fp, "%s ", g_argv[i] );
460                         }
461                         fprintf( fp, "\n" );
462                         fclose( fp );
463                 }
464
465         } else {
466                 args.addr = NULL;
467 #ifdef HAVE_TLS
468                 args.tls_addr = NULL;
469 #endif
470         }
471         args.tcps = tcps;
472 #ifdef HAVE_TLS
473         args.tls_tcps = tls_tcps;
474 #endif
475
476         time( &starttime );
477 #ifdef HAVE_WINSOCK
478         LogSlapdStartedEvent( NTservice, slap_debug, configfile, port, udp );
479 #endif
480
481         rc = slapd_daemon( &args );
482
483 #ifdef HAVE_WINSOCK
484         /* Throw away the event that we used during the startup process. */
485         if ( is_NT_Service )
486                 ldap_pvt_thread_cond_destroy( &started_event );
487 #endif
488
489 shutdown:
490         /* remember an error during shutdown */
491         rc |= slap_shutdown(-1);
492 destroy:
493         /* remember an error during destroy */
494         rc |= slap_destroy();
495
496 stop:
497 #ifdef HAVE_WINSOCK
498         LogSlapdStoppedEvent( NTservice );
499 #endif
500         Debug( LDAP_DEBUG_ANY, "slapd stopped.\n", 0, 0, 0 );
501 #ifdef HAVE_WINSOCK
502         ReportSlapdShutdownComplete();
503 #endif
504
505     closelog();
506
507         MAIN_RETURN(rc);
508 }
509
510
511 #ifdef LDAP_SIGCHLD
512
513 /*
514  *  Catch and discard terminated child processes, to avoid zombies.
515  */
516
517 static RETSIGTYPE
518 wait4child( int sig )
519 {
520     int save_errno = errno;
521
522 #ifdef WNOHANG
523     errno = 0;
524 #ifdef HAVE_WAITPID
525     while ( waitpid( (pid_t)-1, NULL, WNOHANG ) >= 0 || errno == EINTR )
526         ;       /* NULL */
527 #else
528     while ( wait3( NULL, WNOHANG, NULL ) >= 0 || errno == EINTR )
529         ;       /* NULL */
530 #endif
531 #else
532     (void) wait( NULL );
533 #endif
534     (void) SIGNAL( sig, wait4child );
535     errno = save_errno;
536 }
537
538 #endif /* SIGCHLD || SIGCLD */
539
540
541 #ifdef LOG_LOCAL4
542
543 /*
544  *  Convert a string to an integer by means of a dispatcher table
545  *  if the string is not in the table return the default
546  */
547
548 static int
549 cnvt_str2int( char *stringVal, STRDISP_P dispatcher, int defaultVal )
550 {
551     int        retVal = defaultVal;
552     STRDISP_P  disp;
553
554     for (disp = dispatcher; disp->stringVal; disp++) {
555
556         if (!strncasecmp (stringVal, disp->stringVal, disp->abbr)) {
557
558             retVal = disp->intVal;
559             break;
560
561         }
562     }
563
564     return (retVal);
565
566 } /* cnvt_str2int */
567
568 #endif  /* LOG_LOCAL4 */