Back to index

openldap  2.4.31
main.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
00016  * All rights reserved.
00017  *
00018  * Redistribution and use in source and binary forms are permitted
00019  * provided that this notice is preserved and that due credit is given
00020  * to the University of Michigan at Ann Arbor. The name of the University
00021  * may not be used to endorse or promote products derived from this
00022  * software without specific prior written permission. This software
00023  * is provided ``as is'' without express or implied warranty.
00024  */
00025 
00026 #include "portable.h"
00027 
00028 #include <stdio.h>
00029 
00030 #include <ac/ctype.h>
00031 #include <ac/socket.h>
00032 #include <ac/string.h>
00033 #include <ac/time.h>
00034 #include <ac/unistd.h>
00035 #include <ac/wait.h>
00036 #include <ac/errno.h>
00037 
00038 #include "slap.h"
00039 #include "lutil.h"
00040 #include "ldif.h"
00041 
00042 #ifdef LDAP_SLAPI
00043 #include "slapi/slapi.h"
00044 #endif
00045 
00046 #ifdef LDAP_SIGCHLD
00047 static RETSIGTYPE wait4child( int sig );
00048 #endif
00049 
00050 #ifdef HAVE_NT_SERVICE_MANAGER
00051 #define MAIN_RETURN(x) return
00052 static struct sockaddr_in   bind_addr;
00053 
00054 #define SERVICE_EXIT( e, n )       do { \
00055        if ( is_NT_Service ) { \
00056               lutil_ServiceStatus.dwWin32ExitCode                            = (e); \
00057               lutil_ServiceStatus.dwServiceSpecificExitCode    = (n); \
00058        } \
00059 } while ( 0 )
00060 
00061 #else
00062 #define SERVICE_EXIT( e, n )
00063 #define MAIN_RETURN(x) return(x)
00064 #endif
00065 
00066 typedef int (MainFunc) LDAP_P(( int argc, char *argv[] ));
00067 extern MainFunc slapadd, slapcat, slapdn, slapindex, slappasswd,
00068        slaptest, slapauth, slapacl, slapschema;
00069 
00070 static struct {
00071        char *name;
00072        MainFunc *func;
00073 } tools[] = {
00074        {"slapadd", slapadd},
00075        {"slapcat", slapcat},
00076        {"slapdn", slapdn},
00077        {"slapindex", slapindex},
00078        {"slappasswd", slappasswd},
00079        {"slapschema", slapschema},
00080        {"slaptest", slaptest},
00081        {"slapauth", slapauth},
00082        {"slapacl", slapacl},
00083        /* NOTE: new tools must be added in chronological order,
00084         * not in alphabetical order, because for backwards
00085         * compatibility name[4] is used to identify the
00086         * tools; so name[4]=='a' must refer to "slapadd" and
00087         * not to "slapauth".  Alphabetical order can be used
00088         * for tools whose name[4] is not used yet */
00089        {NULL, NULL}
00090 };
00091 
00092 /*
00093  * when more than one slapd is running on one machine, each one might have
00094  * it's own LOCAL for syslogging and must have its own pid/args files
00095  */
00096 
00097 #ifndef HAVE_MKVERSION
00098 const char Versionstr[] =
00099        OPENLDAP_PACKAGE " " OPENLDAP_VERSION " Standalone LDAP Server (slapd)";
00100 #endif
00101 
00102 extern OverlayInit slap_oinfo[];
00103 extern BackendInfo slap_binfo[];
00104 
00105 #define       CHECK_NONE    0x00
00106 #define       CHECK_CONFIG  0x01
00107 #define       CHECK_LOGLEVEL       0x02
00108 static int check = CHECK_NONE;
00109 static int version = 0;
00110 
00111 void *slap_tls_ctx;
00112 LDAP *slap_tls_ld;
00113 
00114 static int
00115 slapd_opt_slp( const char *val, void *arg )
00116 {
00117 #ifdef HAVE_SLP
00118        /* NULL is default */
00119        if ( val == NULL || *val == '(' || strcasecmp( val, "on" ) == 0 ) {
00120               slapd_register_slp = 1;
00121               slapd_slp_attrs = (val != NULL && *val == '(') ? val : NULL;
00122 
00123        } else if ( strcasecmp( val, "off" ) == 0 ) {
00124               slapd_register_slp = 0;
00125 
00126        /* NOTE: add support for URL specification? */
00127 
00128        } else {
00129               fprintf(stderr, "unrecognized value \"%s\" for SLP option\n", val );
00130               return -1;
00131        }
00132 
00133        return 0;
00134               
00135 #else
00136        fputs( "slapd: SLP support is not available\n", stderr );
00137        return 0;
00138 #endif
00139 }
00140 
00141 /*
00142  * Option helper structure:
00143  * 
00144  * oh_nam     is left-hand part of <option>[=<value>]
00145  * oh_fnc     is handler function
00146  * oh_arg     is an optional arg to oh_fnc
00147  * oh_usage   is the one-line usage string related to the option,
00148  *            which is assumed to start with <option>[=<value>]
00149  *
00150  * please leave valid options in the structure, and optionally #ifdef
00151  * their processing inside the helper, so that reasonable and helpful
00152  * error messages can be generated if a disabled option is requested.
00153  */
00154 struct option_helper {
00155        struct berval oh_name;
00156        int           (*oh_fnc)(const char *val, void *arg);
00157        void          *oh_arg;
00158        const char    *oh_usage;
00159 } option_helpers[] = {
00160        { BER_BVC("slp"),    slapd_opt_slp,       NULL, "slp[={on|off|(attrs)}] enable/disable SLP using (attrs)" },
00161        { BER_BVNULL, 0, NULL, NULL }
00162 };
00163 
00164 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
00165 #ifdef LOG_LOCAL4
00166 int
00167 parse_syslog_user( const char *arg, int *syslogUser )
00168 {
00169        static slap_verbmasks syslogUsers[] = {
00170               { BER_BVC( "LOCAL0" ), LOG_LOCAL0 },
00171               { BER_BVC( "LOCAL1" ), LOG_LOCAL1 },
00172               { BER_BVC( "LOCAL2" ), LOG_LOCAL2 },
00173               { BER_BVC( "LOCAL3" ), LOG_LOCAL3 },
00174               { BER_BVC( "LOCAL4" ), LOG_LOCAL4 },
00175               { BER_BVC( "LOCAL5" ), LOG_LOCAL5 },
00176               { BER_BVC( "LOCAL6" ), LOG_LOCAL6 },
00177               { BER_BVC( "LOCAL7" ), LOG_LOCAL7 },
00178 #ifdef LOG_USER
00179               { BER_BVC( "USER" ), LOG_USER },
00180 #endif /* LOG_USER */
00181 #ifdef LOG_DAEMON
00182               { BER_BVC( "DAEMON" ), LOG_DAEMON },
00183 #endif /* LOG_DAEMON */
00184               { BER_BVNULL, 0 }
00185        };
00186        int i = verb_to_mask( arg, syslogUsers );
00187 
00188        if ( BER_BVISNULL( &syslogUsers[ i ].word ) ) {
00189               Debug( LDAP_DEBUG_ANY,
00190                      "unrecognized syslog user \"%s\".\n",
00191                      arg, 0, 0 );
00192               return 1;
00193        }
00194 
00195        *syslogUser = syslogUsers[ i ].mask;
00196 
00197        return 0;
00198 }
00199 #endif /* LOG_LOCAL4 */
00200 
00201 int
00202 parse_syslog_level( const char *arg, int *levelp )
00203 {
00204        static slap_verbmasks       str2syslog_level[] = {
00205               { BER_BVC( "EMERG" ),       LOG_EMERG },
00206               { BER_BVC( "ALERT" ),       LOG_ALERT },
00207               { BER_BVC( "CRIT" ), LOG_CRIT },
00208               { BER_BVC( "ERR" ),  LOG_ERR },
00209               { BER_BVC( "WARNING" ),     LOG_WARNING },
00210               { BER_BVC( "NOTICE" ),      LOG_NOTICE },
00211               { BER_BVC( "INFO" ), LOG_INFO },
00212               { BER_BVC( "DEBUG" ),       LOG_DEBUG },
00213               { BER_BVNULL, 0 }
00214        };
00215        int i = verb_to_mask( arg, str2syslog_level );
00216        if ( BER_BVISNULL( &str2syslog_level[ i ].word ) ) {
00217               Debug( LDAP_DEBUG_ANY,
00218                      "unknown syslog level \"%s\".\n",
00219                      arg, 0, 0 );
00220               return 1;
00221        }
00222        
00223        *levelp = str2syslog_level[ i ].mask;
00224 
00225        return 0;
00226 }
00227 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
00228 
00229 int
00230 parse_debug_unknowns( char **unknowns, int *levelp )
00231 {
00232        int i, level, rc = 0;
00233 
00234        for ( i = 0; unknowns[ i ] != NULL; i++ ) {
00235               level = 0;
00236               if ( str2loglevel( unknowns[ i ], &level )) {
00237                      fprintf( stderr,
00238                             "unrecognized log level \"%s\"\n", unknowns[ i ] );
00239                      rc = 1;
00240               } else {
00241                      *levelp |= level;
00242               }
00243        }
00244        return rc;
00245 }
00246 
00247 int
00248 parse_debug_level( const char *arg, int *levelp, char ***unknowns )
00249 {
00250        int    level;
00251 
00252        if ( arg && arg[ 0 ] != '-' && !isdigit( (unsigned char) arg[ 0 ] ) )
00253        {
00254               int    i;
00255               char   **levels;
00256 
00257               levels = ldap_str2charray( arg, "," );
00258 
00259               for ( i = 0; levels[ i ] != NULL; i++ ) {
00260                      level = 0;
00261 
00262                      if ( str2loglevel( levels[ i ], &level ) ) {
00263                             /* remember this for later */
00264                             ldap_charray_add( unknowns, levels[ i ] );
00265                             fprintf( stderr,
00266                                    "unrecognized log level \"%s\" (deferred)\n",
00267                                    levels[ i ] );
00268                      } else {
00269                             *levelp |= level;
00270                      }
00271               }
00272 
00273               ldap_charray_free( levels );
00274 
00275        } else {
00276               int rc;
00277 
00278               if ( arg[0] == '-' ) {
00279                      rc = lutil_atoix( &level, arg, 0 );
00280               } else {
00281                      unsigned ulevel;
00282 
00283                      rc = lutil_atoux( &ulevel, arg, 0 );
00284                      level = (int)ulevel;
00285               }
00286 
00287               if ( rc ) {
00288                      fprintf( stderr,
00289                             "unrecognized log level "
00290                             "\"%s\"\n", arg );
00291                      return 1;
00292               }
00293 
00294               if ( level == 0 ) {
00295                      *levelp = 0;
00296 
00297               } else {
00298                      *levelp |= level;
00299               }
00300        }
00301 
00302        return 0;
00303 }
00304 
00305 static void
00306 usage( char *name )
00307 {
00308        fprintf( stderr,
00309               "usage: %s options\n", name );
00310        fprintf( stderr,
00311               "\t-4\t\tIPv4 only\n"
00312               "\t-6\t\tIPv6 only\n"
00313               "\t-T {acl|add|auth|cat|dn|index|passwd|test}\n"
00314               "\t\t\tRun in Tool mode\n"
00315               "\t-c cookie\tSync cookie of consumer\n"
00316               "\t-d level\tDebug level" "\n"
00317               "\t-f filename\tConfiguration file\n"
00318               "\t-F dir\tConfiguration directory\n"
00319 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
00320               "\t-g group\tGroup (id or name) to run as\n"
00321 #endif
00322               "\t-h URLs\t\tList of URLs to serve\n"
00323 #ifdef SLAP_DEFAULT_SYSLOG_USER
00324               "\t-l facility\tSyslog facility (default: LOCAL4)\n"
00325 #endif
00326               "\t-n serverName\tService name\n"
00327               "\t-o <opt>[=val] generic means to specify options" );
00328        if ( !BER_BVISNULL( &option_helpers[0].oh_name ) ) {
00329               int    i;
00330 
00331               fprintf( stderr, "; supported options:\n" );
00332               for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); i++) {
00333                      fprintf( stderr, "\t\t%s\n", option_helpers[i].oh_usage );
00334               }
00335        } else {
00336               fprintf( stderr, "\n" );
00337        }
00338        fprintf( stderr,     
00339 #ifdef HAVE_CHROOT
00340               "\t-r directory\tSandbox directory to chroot to\n"
00341 #endif
00342               "\t-s level\tSyslog level\n"
00343 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
00344               "\t-u user\t\tUser (id or name) to run as\n"
00345 #endif
00346               "\t-V\t\tprint version info (-VV exit afterwards, -VVV print\n"
00347               "\t\t\tinfo about static overlays and backends)\n"
00348     );
00349 }
00350 
00351 #ifdef HAVE_NT_SERVICE_MANAGER
00352 void WINAPI ServiceMain( DWORD argc, LPTSTR *argv )
00353 #else
00354 int main( int argc, char **argv )
00355 #endif
00356 {
00357        int           i, no_detach = 0;
00358        int           rc = 1;
00359        char *urls = NULL;
00360 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
00361        char *username = NULL;
00362        char *groupname = NULL;
00363 #endif
00364 #if defined(HAVE_CHROOT)
00365        char *sandbox = NULL;
00366 #endif
00367 #ifdef SLAP_DEFAULT_SYSLOG_USER
00368        int syslogUser = SLAP_DEFAULT_SYSLOG_USER;
00369 #endif
00370        
00371 #ifndef HAVE_WINSOCK
00372        int pid, waitfds[2];
00373 #endif
00374        int g_argc = argc;
00375        char **g_argv = argv;
00376 
00377        char *configfile = NULL;
00378        char *configdir = NULL;
00379        char *serverName;
00380        int serverMode = SLAP_SERVER_MODE;
00381 
00382        struct sync_cookie *scp = NULL;
00383        struct sync_cookie *scp_entry = NULL;
00384 
00385        char **debug_unknowns = NULL;
00386        char **syslog_unknowns = NULL;
00387 
00388        char *serverNamePrefix = "";
00389        size_t l;
00390 
00391        int slapd_pid_file_unlink = 0, slapd_args_file_unlink = 0;
00392        int firstopt = 1;
00393 
00394 #ifdef CSRIMALLOC
00395        FILE *leakfile;
00396        if( ( leakfile = fopen( "slapd.leak", "w" )) == NULL ) {
00397               leakfile = stderr;
00398        }
00399 #endif
00400 
00401        slap_sl_mem_init();
00402 
00403        (void) ldap_pvt_thread_initialize();
00404 
00405        serverName = lutil_progname( "slapd", argc, argv );
00406 
00407        if ( strcmp( serverName, "slapd" ) ) {
00408               for (i=0; tools[i].name; i++) {
00409                      if ( !strcmp( serverName, tools[i].name ) ) {
00410                             rc = tools[i].func(argc, argv);
00411                             MAIN_RETURN(rc);
00412                      }
00413               }
00414        }
00415 
00416 #ifdef HAVE_NT_SERVICE_MANAGER
00417        {
00418               int *ip;
00419               char *newConfigFile;
00420               char *newConfigDir;
00421               char *newUrls;
00422               char *regService = NULL;
00423 
00424               if ( is_NT_Service ) {
00425                      lutil_CommenceStartupProcessing( serverName, slap_sig_shutdown );
00426                      if ( strcmp(serverName, SERVICE_NAME) )
00427                          regService = serverName;
00428               }
00429 
00430               ip = (int*)lutil_getRegParam( regService, "DebugLevel" );
00431               if ( ip != NULL ) {
00432                      slap_debug = *ip;
00433                      Debug( LDAP_DEBUG_ANY,
00434                             "new debug level from registry is: %d\n", slap_debug, 0, 0 );
00435               }
00436 
00437               newUrls = (char *) lutil_getRegParam(regService, "Urls");
00438               if (newUrls) {
00439                   if (urls)
00440                      ch_free(urls);
00441 
00442                   urls = ch_strdup(newUrls);
00443                   Debug(LDAP_DEBUG_ANY, "new urls from registry: %s\n",
00444                             urls, 0, 0);
00445               }
00446 
00447               newConfigFile = (char*)lutil_getRegParam( regService, "ConfigFile" );
00448               if ( newConfigFile != NULL ) {
00449                      configfile = ch_strdup(newConfigFile);
00450                      Debug ( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", configfile, 0, 0 );
00451               }
00452 
00453               newConfigDir = (char*)lutil_getRegParam( regService, "ConfigDir" );
00454               if ( newConfigDir != NULL ) {
00455                      configdir = ch_strdup(newConfigDir);
00456                      Debug ( LDAP_DEBUG_ANY, "new config dir from registry is: %s\n", configdir, 0, 0 );
00457               }
00458        }
00459 #endif
00460 
00461        while ( (i = getopt( argc, argv,
00462                           "c:d:f:F:h:n:o:s:tT:V"
00463 #ifdef LDAP_PF_INET6
00464                             "46"
00465 #endif
00466 #ifdef HAVE_CHROOT
00467                             "r:"
00468 #endif
00469 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
00470                             "S:"
00471 #ifdef LOG_LOCAL4
00472                             "l:"
00473 #endif
00474 #endif
00475 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
00476                             "u:g:"
00477 #endif
00478                           )) != EOF ) {
00479               switch ( i ) {
00480 #ifdef LDAP_PF_INET6
00481               case '4':
00482                      slap_inet4or6 = AF_INET;
00483                      break;
00484               case '6':
00485                      slap_inet4or6 = AF_INET6;
00486                      break;
00487 #endif
00488 
00489               case 'h':     /* listen URLs */
00490                      if ( urls != NULL ) free( urls );
00491                      urls = ch_strdup( optarg );
00492                      break;
00493 
00494               case 'c':     /* provide sync cookie, override if exist in replica */
00495                      scp = (struct sync_cookie *) ch_calloc( 1,
00496                                                                       sizeof( struct sync_cookie ));
00497                      ber_str2bv( optarg, 0, 1, &scp->octet_str );
00498                      
00499                      /* This only parses out the rid at this point */
00500                      slap_parse_sync_cookie( scp, NULL );
00501 
00502                      if ( scp->rid == -1 ) {
00503                             Debug( LDAP_DEBUG_ANY,
00504                                           "main: invalid cookie \"%s\"\n",
00505                                           optarg, 0, 0 );
00506                             slap_sync_cookie_free( scp, 1 );
00507                             goto destroy;
00508                      }
00509 
00510                      LDAP_STAILQ_FOREACH( scp_entry, &slap_sync_cookie, sc_next ) {
00511                             if ( scp->rid == scp_entry->rid ) {
00512                                    Debug( LDAP_DEBUG_ANY,
00513                                               "main: duplicated replica id in cookies\n",
00514                                                  0, 0, 0 );
00515                                    slap_sync_cookie_free( scp, 1 );
00516                                    goto destroy;
00517                             }
00518                      }
00519                      LDAP_STAILQ_INSERT_TAIL( &slap_sync_cookie, scp, sc_next );
00520                      break;
00521 
00522               case 'd': {   /* set debug level and 'do not detach' flag */
00523                      int    level = 0;
00524 
00525                      if ( strcmp( optarg, "?" ) == 0 ) {
00526                             check |= CHECK_LOGLEVEL;
00527                             break;
00528                      }
00529 
00530                      no_detach = 1;
00531                      if ( parse_debug_level( optarg, &level, &debug_unknowns ) ) {
00532                             goto destroy;
00533                      }
00534 #ifdef LDAP_DEBUG
00535                      slap_debug |= level;
00536 #else
00537                      if ( level != 0 )
00538                             fputs( "must compile with LDAP_DEBUG for debugging\n",
00539                                    stderr );
00540 #endif
00541                      } break;
00542 
00543               case 'f':     /* read config file */
00544                      configfile = ch_strdup( optarg );
00545                      break;
00546 
00547               case 'F':     /* use config dir */
00548                      configdir = ch_strdup( optarg );
00549                      break;
00550 
00551               case 'o': {
00552                      char          *val = strchr( optarg, '=' );
00553                      struct berval opt;
00554 
00555                      opt.bv_val = optarg;
00556                      
00557                      if ( val ) {
00558                             opt.bv_len = ( val - optarg );
00559                             val++;
00560                      
00561                      } else {
00562                             opt.bv_len = strlen( optarg );
00563                      }
00564 
00565                      for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); i++ ) {
00566                             if ( ber_bvstrcasecmp( &option_helpers[i].oh_name, &opt ) == 0 ) {
00567                                    assert( option_helpers[i].oh_fnc != NULL );
00568                                    if ( (*option_helpers[i].oh_fnc)( val, option_helpers[i].oh_arg ) == -1 ) {
00569                                           /* we assume the option parsing helper
00570                                            * issues appropriate and self-explanatory
00571                                            * error messages... */
00572                                           goto stop;
00573                                    }
00574                                    break;
00575                             }
00576                      }
00577 
00578                      if ( BER_BVISNULL( &option_helpers[i].oh_name ) ) {
00579                             goto unhandled_option;
00580                      }
00581                      break;
00582               }
00583 
00584               case 's':     /* set syslog level */
00585                      if ( strcmp( optarg, "?" ) == 0 ) {
00586                             check |= CHECK_LOGLEVEL;
00587                             break;
00588                      }
00589 
00590                      if ( parse_debug_level( optarg, &ldap_syslog, &syslog_unknowns ) ) {
00591                             goto destroy;
00592                      }
00593                      break;
00594 
00595 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
00596               case 'S':
00597                      if ( parse_syslog_level( optarg, &ldap_syslog_level ) ) {
00598                             goto destroy;
00599                      }
00600                      break;
00601 
00602 #ifdef LOG_LOCAL4
00603               case 'l':     /* set syslog local user */
00604                      if ( parse_syslog_user( optarg, &syslogUser ) ) {
00605                             goto destroy;
00606                      }
00607                      break;
00608 #endif
00609 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
00610 
00611 #ifdef HAVE_CHROOT
00612               case 'r':
00613                      if( sandbox ) free(sandbox);
00614                      sandbox = ch_strdup( optarg );
00615                      break;
00616 #endif
00617 
00618 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
00619               case 'u':     /* user name */
00620                      if( username ) free(username);
00621                      username = ch_strdup( optarg );
00622                      break;
00623 
00624               case 'g':     /* group name */
00625                      if( groupname ) free(groupname);
00626                      groupname = ch_strdup( optarg );
00627                      break;
00628 #endif /* SETUID && GETUID */
00629 
00630               case 'n':  /* NT service name */
00631                      serverName = ch_strdup( optarg );
00632                      break;
00633 
00634               case 't':
00635                      /* deprecated; use slaptest instead */
00636                      fprintf( stderr, "option -t deprecated; "
00637                             "use slaptest command instead\n" );
00638                      check |= CHECK_CONFIG;
00639                      break;
00640 
00641               case 'V':
00642                      version++;
00643                      break;
00644 
00645               case 'T':
00646                      if ( firstopt == 0 ) {
00647                             fprintf( stderr, "warning: \"-T %s\" "
00648                                    "should be the first option.\n",
00649                                    optarg );
00650                      }
00651 
00652                      /* try full option string first */
00653                      for ( i = 0; tools[i].name; i++ ) {
00654                             if ( strcmp( optarg, &tools[i].name[4] ) == 0 ) {
00655                                    rc = tools[i].func( argc, argv );
00656                                    MAIN_RETURN( rc );
00657                             }
00658                      }
00659 
00660                      /* try bits of option string (backward compatibility for single char) */
00661                      l = strlen( optarg );
00662                      for ( i = 0; tools[i].name; i++ ) {
00663                             if ( strncmp( optarg, &tools[i].name[4], l ) == 0 ) {
00664                                    rc = tools[i].func( argc, argv );
00665                                    MAIN_RETURN( rc );
00666                             }
00667                      }
00668                      
00669                      /* issue error */
00670                      serverName = optarg;
00671                      serverNamePrefix = "slap";
00672                      fprintf( stderr, "program name \"%s%s\" unrecognized; "
00673                                    "aborting...\n", serverNamePrefix, serverName );
00674                      /* FALLTHRU */
00675               default:
00676 unhandled_option:;
00677                      usage( argv[0] );
00678                      rc = 1;
00679                      SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 );
00680                      goto stop;
00681               }
00682 
00683               if ( firstopt ) {
00684                      firstopt = 0;
00685               }
00686        }
00687 
00688        if ( optind != argc )
00689               goto unhandled_option;
00690 
00691        ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug);
00692        ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug);
00693        ldif_debug = slap_debug;
00694 
00695        if ( version ) {
00696               fprintf( stderr, "%s\n", Versionstr );
00697               if ( version > 2 ) {
00698                      if ( slap_oinfo[0].ov_type ) {
00699                             fprintf( stderr, "Included static overlays:\n");
00700                             for ( i= 0 ; slap_oinfo[i].ov_type; i++ ) {
00701                                    fprintf( stderr, "    %s\n", slap_oinfo[i].ov_type );
00702                             }
00703                      }
00704                      if ( slap_binfo[0].bi_type ) {
00705                             fprintf( stderr, "Included static backends:\n");
00706                             for ( i= 0 ; slap_binfo[i].bi_type; i++ ) {
00707                                    fprintf( stderr, "    %s\n", slap_binfo[i].bi_type );
00708                             }
00709                      }
00710               }
00711 
00712               if ( version > 1 ) goto stop;
00713        }
00714 
00715 #if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
00716        {
00717               char *logName;
00718 #ifdef HAVE_EBCDIC
00719               logName = ch_strdup( serverName );
00720               __atoe( logName );
00721 #else
00722               logName = serverName;
00723 #endif
00724 
00725 #ifdef LOG_LOCAL4
00726               openlog( logName, OPENLOG_OPTIONS, syslogUser );
00727 #elif defined LOG_DEBUG
00728               openlog( logName, OPENLOG_OPTIONS );
00729 #endif
00730 #ifdef HAVE_EBCDIC
00731               free( logName );
00732 #endif
00733        }
00734 #endif /* LDAP_DEBUG && LDAP_SYSLOG */
00735 
00736        Debug( LDAP_DEBUG_ANY, "%s", Versionstr, 0, 0 );
00737 
00738        global_host = ldap_pvt_get_fqdn( NULL );
00739        ber_str2bv( global_host, 0, 0, &global_host_bv );
00740 
00741        if( check == CHECK_NONE && slapd_daemon_init( urls ) != 0 ) {
00742               rc = 1;
00743               SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 );
00744               goto stop;
00745        }
00746 
00747 #if defined(HAVE_CHROOT)
00748        if ( sandbox ) {
00749               if ( chdir( sandbox ) ) {
00750                      perror("chdir");
00751                      rc = 1;
00752                      goto stop;
00753               }
00754               if ( chroot( sandbox ) ) {
00755                      perror("chroot");
00756                      rc = 1;
00757                      goto stop;
00758               }
00759        }
00760 #endif
00761 
00762 #if defined(HAVE_SETUID) && defined(HAVE_SETGID)
00763        if ( username != NULL || groupname != NULL ) {
00764               slap_init_user( username, groupname );
00765        }
00766 #endif
00767 
00768        extops_init();
00769        lutil_passwd_init();
00770 
00771 #ifdef HAVE_TLS
00772        rc = ldap_create( &slap_tls_ld );
00773        if ( rc ) {
00774               SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
00775               goto destroy;
00776        }
00777        /* Library defaults to full certificate checking. This is correct when
00778         * a client is verifying a server because all servers should have a
00779         * valid cert. But few clients have valid certs, so we want our default
00780         * to be no checking. The config file can override this as usual.
00781         */
00782        rc = LDAP_OPT_X_TLS_NEVER;
00783        (void) ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &rc );
00784 #endif
00785 
00786        rc = slap_init( serverMode, serverName );
00787        if ( rc ) {
00788               SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 );
00789               goto destroy;
00790        }
00791 
00792        if ( read_config( configfile, configdir ) != 0 ) {
00793               rc = 1;
00794               SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 );
00795 
00796               if ( check & CHECK_CONFIG ) {
00797                      fprintf( stderr, "config check failed\n" );
00798               }
00799 
00800               goto destroy;
00801        }
00802 
00803        if ( debug_unknowns ) {
00804               rc = parse_debug_unknowns( debug_unknowns, &slap_debug );
00805               ldap_charray_free( debug_unknowns );
00806               debug_unknowns = NULL;
00807               if ( rc )
00808                      goto destroy;
00809        }
00810        if ( syslog_unknowns ) {
00811               rc = parse_debug_unknowns( syslog_unknowns, &ldap_syslog );
00812               ldap_charray_free( syslog_unknowns );
00813               syslog_unknowns = NULL;
00814               if ( rc )
00815                      goto destroy;
00816        }      
00817 
00818        if ( check & CHECK_LOGLEVEL ) {
00819               rc = 0;
00820               goto destroy;
00821        }
00822 
00823        if ( check & CHECK_CONFIG ) {
00824               fprintf( stderr, "config check succeeded\n" );
00825 
00826               check &= ~CHECK_CONFIG;
00827               if ( check == CHECK_NONE ) {
00828                      rc = 0;
00829                      goto destroy;
00830               }
00831        }
00832 
00833        if ( glue_sub_attach( 0 ) != 0 ) {
00834               Debug( LDAP_DEBUG_ANY,
00835                   "subordinate config error\n",
00836                   0, 0, 0 );
00837 
00838               goto destroy;
00839        }
00840 
00841        if ( slap_schema_check( ) != 0 ) {
00842               Debug( LDAP_DEBUG_ANY,
00843                   "schema prep error\n",
00844                   0, 0, 0 );
00845 
00846               goto destroy;
00847        }
00848 
00849 #ifdef HAVE_TLS
00850        rc = ldap_pvt_tls_init();
00851        if( rc != 0) {
00852               Debug( LDAP_DEBUG_ANY,
00853                   "main: TLS init failed: %d\n",
00854                   rc, 0, 0 );
00855               rc = 1;
00856               SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
00857               goto destroy;
00858        }
00859 
00860        {
00861               int opt = 1;
00862 
00863               /* Force new ctx to be created */
00864               rc = ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
00865               if( rc == 0 ) {
00866                      /* The ctx's refcount is bumped up here */
00867                      ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CTX, &slap_tls_ctx );
00868                      load_extop( &slap_EXOP_START_TLS, 0, starttls_extop );
00869               } else if ( rc != LDAP_NOT_SUPPORTED ) {
00870                      Debug( LDAP_DEBUG_ANY,
00871                          "main: TLS init def ctx failed: %d\n",
00872                          rc, 0, 0 );
00873                      rc = 1;
00874                      SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
00875                      goto destroy;
00876               }
00877        }
00878 #endif
00879 
00880 #ifdef HAVE_CYRUS_SASL
00881        if( sasl_host == NULL ) {
00882               sasl_host = ch_strdup( global_host );
00883        }
00884 #endif
00885 
00886        (void) SIGNAL( LDAP_SIGUSR1, slap_sig_wake );
00887        (void) SIGNAL( LDAP_SIGUSR2, slap_sig_shutdown );
00888 
00889 #ifdef SIGPIPE
00890        (void) SIGNAL( SIGPIPE, SIG_IGN );
00891 #endif
00892 #ifdef SIGHUP
00893        (void) SIGNAL( SIGHUP, slap_sig_shutdown );
00894 #endif
00895        (void) SIGNAL( SIGINT, slap_sig_shutdown );
00896        (void) SIGNAL( SIGTERM, slap_sig_shutdown );
00897 #ifdef SIGTRAP
00898        (void) SIGNAL( SIGTRAP, slap_sig_shutdown );
00899 #endif
00900 #ifdef LDAP_SIGCHLD
00901        (void) SIGNAL( LDAP_SIGCHLD, wait4child );
00902 #endif
00903 #ifdef SIGBREAK
00904        /* SIGBREAK is generated when Ctrl-Break is pressed. */
00905        (void) SIGNAL( SIGBREAK, slap_sig_shutdown );
00906 #endif
00907 
00908 #ifndef HAVE_WINSOCK
00909        if ( !no_detach ) {
00910               if ( lutil_pair( waitfds ) < 0 ) {
00911                      Debug( LDAP_DEBUG_ANY,
00912                             "main: lutil_pair failed: %d\n",
00913                             0, 0, 0 );
00914                      rc = 1;
00915                      goto destroy;
00916               }
00917               pid = lutil_detach( no_detach, 0 );
00918               if ( pid ) {
00919                      char buf[4];
00920                      rc = EXIT_SUCCESS;
00921                      close( waitfds[1] );
00922                      if ( read( waitfds[0], buf, 1 ) != 1 )
00923                             rc = EXIT_FAILURE;
00924                      _exit( rc );
00925               } else {
00926                      close( waitfds[0] );
00927               }
00928        }
00929 #endif /* HAVE_WINSOCK */
00930 
00931 #ifdef CSRIMALLOC
00932        mal_leaktrace(1);
00933 #endif
00934 
00935        if ( slapd_pid_file != NULL ) {
00936               FILE *fp = fopen( slapd_pid_file, "w" );
00937 
00938               if ( fp == NULL ) {
00939                      int save_errno = errno;
00940 
00941                      Debug( LDAP_DEBUG_ANY, "unable to open pid file "
00942                             "\"%s\": %d (%s)\n",
00943                             slapd_pid_file,
00944                             save_errno, strerror( save_errno ) );
00945 
00946                      free( slapd_pid_file );
00947                      slapd_pid_file = NULL;
00948 
00949                      rc = 1;
00950                      goto destroy;
00951               }
00952               fprintf( fp, "%d\n", (int) getpid() );
00953               fclose( fp );
00954               slapd_pid_file_unlink = 1;
00955        }
00956 
00957        if ( slapd_args_file != NULL ) {
00958               FILE *fp = fopen( slapd_args_file, "w" );
00959 
00960               if ( fp == NULL ) {
00961                      int save_errno = errno;
00962 
00963                      Debug( LDAP_DEBUG_ANY, "unable to open args file "
00964                             "\"%s\": %d (%s)\n",
00965                             slapd_args_file,
00966                             save_errno, strerror( save_errno ) );
00967 
00968                      free( slapd_args_file );
00969                      slapd_args_file = NULL;
00970 
00971                      rc = 1;
00972                      goto destroy;
00973               }
00974 
00975               for ( i = 0; i < g_argc; i++ ) {
00976                      fprintf( fp, "%s ", g_argv[i] );
00977               }
00978               fprintf( fp, "\n" );
00979               fclose( fp );
00980               slapd_args_file_unlink = 1;
00981        }
00982 
00983        /*
00984         * FIXME: moved here from slapd_daemon_task()
00985         * because back-monitor db_open() needs it
00986         */
00987        time( &starttime );
00988 
00989        connections_init();
00990 
00991        if ( slap_startup( NULL ) != 0 ) {
00992               rc = 1;
00993               SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 );
00994               goto shutdown;
00995        }
00996 
00997        Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 );
00998 
00999 #ifndef HAVE_WINSOCK
01000        if ( !no_detach ) {
01001               write( waitfds[1], "1", 1 );
01002               close( waitfds[1] );
01003        }
01004 #endif
01005 
01006 #ifdef HAVE_NT_EVENT_LOG
01007        if (is_NT_Service)
01008        lutil_LogStartedEvent( serverName, slap_debug, configfile ?
01009               configfile : SLAPD_DEFAULT_CONFIGFILE , urls );
01010 #endif
01011 
01012        rc = slapd_daemon();
01013 
01014 #ifdef HAVE_NT_SERVICE_MANAGER
01015        /* Throw away the event that we used during the startup process. */
01016        if ( is_NT_Service )
01017               ldap_pvt_thread_cond_destroy( &started_event );
01018 #endif
01019 
01020 shutdown:
01021        /* remember an error during shutdown */
01022        rc |= slap_shutdown( NULL );
01023 
01024 destroy:
01025        if ( check & CHECK_LOGLEVEL ) {
01026               (void)loglevel_print( stdout );
01027        }
01028        /* remember an error during destroy */
01029        rc |= slap_destroy();
01030 
01031        while ( !LDAP_STAILQ_EMPTY( &slap_sync_cookie )) {
01032               scp = LDAP_STAILQ_FIRST( &slap_sync_cookie );
01033               LDAP_STAILQ_REMOVE_HEAD( &slap_sync_cookie, sc_next );
01034               ch_free( scp );
01035        }
01036 
01037 #ifdef SLAPD_MODULES
01038        module_kill();
01039 #endif
01040 
01041        extops_kill();
01042 
01043        supported_feature_destroy();
01044        entry_info_destroy();
01045 
01046 stop:
01047 #ifdef HAVE_NT_EVENT_LOG
01048        if (is_NT_Service)
01049        lutil_LogStoppedEvent( serverName );
01050 #endif
01051 
01052        Debug( LDAP_DEBUG_ANY, "slapd stopped.\n", 0, 0, 0 );
01053 
01054 
01055 #ifdef HAVE_NT_SERVICE_MANAGER
01056        lutil_ReportShutdownComplete();
01057 #endif
01058 
01059 #ifdef LOG_DEBUG
01060     closelog();
01061 #endif
01062        slapd_daemon_destroy();
01063 
01064        controls_destroy();
01065 
01066        filter_destroy();
01067 
01068        schema_destroy();
01069 
01070        lutil_passwd_destroy();
01071 
01072 #ifdef HAVE_TLS
01073        if ( slap_tls_ld ) {
01074               ldap_pvt_tls_ctx_free( slap_tls_ctx );
01075               ldap_unbind_ext( slap_tls_ld, NULL, NULL );
01076        }
01077        ldap_pvt_tls_destroy();
01078 #endif
01079 
01080        slap_sasl_regexp_destroy();
01081 
01082        if ( slapd_pid_file_unlink ) {
01083               unlink( slapd_pid_file );
01084        }
01085        if ( slapd_args_file_unlink ) {
01086               unlink( slapd_args_file );
01087        }
01088 
01089        config_destroy();
01090 
01091        if ( configfile )
01092               ch_free( configfile );
01093        if ( configdir )
01094               ch_free( configdir );
01095        if ( urls )
01096               ch_free( urls );
01097        if ( global_host )
01098               ch_free( global_host );
01099 
01100        /* kludge, get symbols referenced */
01101        tavl_free( NULL, NULL );
01102 
01103 #ifdef CSRIMALLOC
01104        mal_dumpleaktrace( leakfile );
01105 #endif
01106 
01107        MAIN_RETURN(rc);
01108 }
01109 
01110 
01111 #ifdef LDAP_SIGCHLD
01112 
01113 /*
01114  *  Catch and discard terminated child processes, to avoid zombies.
01115  */
01116 
01117 static RETSIGTYPE
01118 wait4child( int sig )
01119 {
01120     int save_errno = errno;
01121 
01122 #ifdef WNOHANG
01123     do
01124         errno = 0;
01125 #ifdef HAVE_WAITPID
01126     while ( waitpid( (pid_t)-1, NULL, WNOHANG ) > 0 || errno == EINTR );
01127 #else
01128     while ( wait3( NULL, WNOHANG, NULL ) > 0 || errno == EINTR );
01129 #endif
01130 #else
01131     (void) wait( NULL );
01132 #endif
01133     (void) SIGNAL_REINSTALL( sig, wait4child );
01134     errno = save_errno;
01135 }
01136 
01137 #endif /* LDAP_SIGCHLD */