main.c 23.6 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1998-2008 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
7
8
9
10
11
12
13
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
14
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
15
16
17
18
19
20
21
22
23
24
25
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of Michigan at Ann Arbor. The name of the University
 * may not be used to endorse or promote products derived from this
 * software without specific prior written permission. This software
 * is provided ``as is'' without express or implied warranty.
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
26
#include "portable.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
27
28
29

#include <stdio.h>

30
#include <ac/ctype.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
31
32
33
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
34
#include <ac/unistd.h>
Hallvard Furuseth's avatar
Hallvard Furuseth committed
35
36
#include <ac/wait.h>
#include <ac/errno.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
37

38
#include "slap.h"
39
#include "lutil.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
40
#include "ldif.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
41

42
#ifdef LDAP_SLAPI
43
#include "slapi/slapi.h"
44
45
#endif

46
#ifdef LDAP_SIGCHLD
Hallvard Furuseth's avatar
Hallvard Furuseth committed
47
48
49
static RETSIGTYPE wait4child( int sig );
#endif

50
#ifdef HAVE_NT_SERVICE_MANAGER
51
#define MAIN_RETURN(x) return
Kurt Zeilenga's avatar
Kurt Zeilenga committed
52
static struct sockaddr_in	bind_addr;
53

54
55
#define SERVICE_EXIT( e, n )	do { \
	if ( is_NT_Service ) { \
56
57
		lutil_ServiceStatus.dwWin32ExitCode				= (e); \
		lutil_ServiceStatus.dwServiceSpecificExitCode	= (n); \
58
59
60
	} \
} while ( 0 )

61
62
#else
#define SERVICE_EXIT( e, n )
63
#define MAIN_RETURN(x) return(x)
64
65
#endif

66
typedef int (MainFunc) LDAP_P(( int argc, char *argv[] ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
67
extern MainFunc slapadd, slapcat, slapdn, slapindex, slappasswd,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
68
	slaptest, slapauth, slapacl;
69
70
71
72
73
74
75

static struct {
	char *name;
	MainFunc *func;
} tools[] = {
	{"slapadd", slapadd},
	{"slapcat", slapcat},
76
	{"slapdn", slapdn},
77
78
	{"slapindex", slapindex},
	{"slappasswd", slappasswd},
79
	{"slaptest", slaptest},
Kurt Zeilenga's avatar
Kurt Zeilenga committed
80
	{"slapauth", slapauth},
Pierangelo Masarati's avatar
Pierangelo Masarati committed
81
	{"slapacl", slapacl},
82
83
84
85
86
87
	/* NOTE: new tools must be added in chronological order,
	 * not in alphabetical order, because for backwards
	 * compatibility name[4] is used to identify the
	 * tools; so name[4]=='a' must refer to "slapadd" and
	 * not to "slapauth".  Alphabetical order can be used
	 * for tools whose name[4] is not used yet */
88
89
90
	{NULL, NULL}
};

91
92
93
94
95
/*
 * when more than one slapd is running on one machine, each one might have
 * it's own LOCAL for syslogging and must have its own pid/args files
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
96
#ifndef HAVE_MKVERSION
Kurt Zeilenga's avatar
Kurt Zeilenga committed
97
98
const char Versionstr[] =
	OPENLDAP_PACKAGE " " OPENLDAP_VERSION " Standalone LDAP Server (slapd)";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
99
100
#endif

101
102
103
#define	CHECK_NONE	0x00
#define	CHECK_CONFIG	0x01
#define	CHECK_LOGLEVEL	0x02
104
static int check = CHECK_NONE;
105
static int version = 0;
106

107
void *slap_tls_ctx;
Howard Chu's avatar
Howard Chu committed
108
LDAP *slap_tls_ld;
109

110
111
112
113
114
static int
slapd_opt_slp( const char *val, void *arg )
{
#ifdef HAVE_SLP
	/* NULL is default */
115
	if ( val == NULL || *val == '(' || strcasecmp( val, "on" ) == 0 ) {
116
		slapd_register_slp = 1;
117
		slapd_slp_attrs = (val != NULL && *val == '(') ? val : NULL;
118
119

	} else if ( strcasecmp( val, "off" ) == 0 ) {
120
		slapd_register_slp = 0;
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

	/* NOTE: add support for URL specification? */

	} else {
		fprintf(stderr, "unrecognized value \"%s\" for SLP option\n", val );
		return -1;
	}

	return 0;
		
#else
	fputs( "slapd: SLP support is not available\n", stderr );
	return 0;
#endif
}

137
138
139
140
141
142
143
144
145
146
147
148
149
/*
 * Option helper structure:
 * 
 * oh_nam	is left-hand part of <option>[=<value>]
 * oh_fnc	is handler function
 * oh_arg	is an optional arg to oh_fnc
 * oh_usage	is the one-line usage string related to the option,
 *		which is assumed to start with <option>[=<value>]
 *
 * please leave valid options in the structure, and optionally #ifdef
 * their processing inside the helper, so that reasonable and helpful
 * error messages can be generated if a disabled option is requested.
 */
150
151
152
153
struct option_helper {
	struct berval	oh_name;
	int		(*oh_fnc)(const char *val, void *arg);
	void		*oh_arg;
154
	const char	*oh_usage;
155
} option_helpers[] = {
156
	{ BER_BVC("slp"),	slapd_opt_slp,	NULL, "slp[={on|off|(attrs)}] enable/disable SLP using (attrs)" },
Hallvard Furuseth's avatar
Cleanup    
Hallvard Furuseth committed
157
	{ BER_BVNULL, 0, NULL, NULL }
158
159
};

Howard Chu's avatar
Howard Chu committed
160
#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
Pierangelo Masarati's avatar
Pierangelo Masarati committed
161
#ifdef LOG_LOCAL4
Pierangelo Masarati's avatar
Pierangelo Masarati committed
162
int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
163
parse_syslog_user( const char *arg, int *syslogUser )
164
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
	static slap_verbmasks syslogUsers[] = {
		{ BER_BVC( "LOCAL0" ), LOG_LOCAL0 },
		{ BER_BVC( "LOCAL1" ), LOG_LOCAL1 },
		{ BER_BVC( "LOCAL2" ), LOG_LOCAL2 },
		{ BER_BVC( "LOCAL3" ), LOG_LOCAL3 },
		{ BER_BVC( "LOCAL4" ), LOG_LOCAL4 },
		{ BER_BVC( "LOCAL5" ), LOG_LOCAL5 },
		{ BER_BVC( "LOCAL6" ), LOG_LOCAL6 },
		{ BER_BVC( "LOCAL7" ), LOG_LOCAL7 },
#ifdef LOG_USER
		{ BER_BVC( "USER" ), LOG_USER },
#endif /* LOG_USER */
#ifdef LOG_DAEMON
		{ BER_BVC( "DAEMON" ), LOG_DAEMON },
#endif /* LOG_DAEMON */
		{ BER_BVNULL, 0 }
	};
Pierangelo Masarati's avatar
Pierangelo Masarati committed
182
	int i = verb_to_mask( arg, syslogUsers );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
183
184

	if ( BER_BVISNULL( &syslogUsers[ i ].word ) ) {
185
186
		Debug( LDAP_DEBUG_ANY,
			"unrecognized syslog user \"%s\".\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
187
			arg, 0, 0 );
188
189
190
		return 1;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
191
192
	*syslogUser = syslogUsers[ i ].mask;

193
194
	return 0;
}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
195
#endif /* LOG_LOCAL4 */
196

Pierangelo Masarati's avatar
Pierangelo Masarati committed
197
int
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
parse_syslog_level( const char *arg, int *levelp )
{
	static slap_verbmasks	str2syslog_level[] = {
		{ BER_BVC( "EMERG" ),	LOG_EMERG },
		{ BER_BVC( "ALERT" ),	LOG_ALERT },
		{ BER_BVC( "CRIT" ),	LOG_CRIT },
		{ BER_BVC( "ERR" ),	LOG_ERR },
		{ BER_BVC( "WARNING" ),	LOG_WARNING },
		{ BER_BVC( "NOTICE" ),	LOG_NOTICE },
		{ BER_BVC( "INFO" ),	LOG_INFO },
		{ BER_BVC( "DEBUG" ),	LOG_DEBUG },
		{ BER_BVNULL, 0 }
	};
	int i = verb_to_mask( arg, str2syslog_level );
	if ( BER_BVISNULL( &str2syslog_level[ i ].word ) ) {
		Debug( LDAP_DEBUG_ANY,
			"unknown syslog level \"%s\".\n",
			arg, 0, 0 );
		return 1;
	}
	
	*levelp = str2syslog_level[ i ].mask;

	return 0;
}
Howard Chu's avatar
Howard Chu committed
223
#endif /* LDAP_DEBUG && LDAP_SYSLOG */
224

225
int
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
parse_debug_unknowns( char **unknowns, int *levelp )
{
	int i, level, rc = 0;

	for ( i = 0; unknowns[ i ] != NULL; i++ ) {
		level = 0;
		if ( str2loglevel( unknowns[ i ], &level )) {
			fprintf( stderr,
				"unrecognized log level \"%s\"\n", unknowns[ i ] );
			rc = 1;
		} else {
			*levelp |= level;
		}
	}
	return rc;
}

int
parse_debug_level( const char *arg, int *levelp, char ***unknowns )
245
246
247
{
	int	level;

248
	if ( arg && arg[ 0 ] != '-' && !isdigit( (unsigned char) arg[ 0 ] ) )
249
	{
250
		int	i;
251
252
253
254
255
256
257
258
		char	**levels;

		levels = ldap_str2charray( arg, "," );

		for ( i = 0; levels[ i ] != NULL; i++ ) {
			level = 0;

			if ( str2loglevel( levels[ i ], &level ) ) {
259
260
				/* remember this for later */
				ldap_charray_add( unknowns, levels[ i ] );
261
				fprintf( stderr,
262
263
					"unrecognized log level \"%s\" (deferred)\n",
					levels[ i ] );
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
			} else {
				*levelp |= level;
			}
		}

		ldap_charray_free( levels );

	} else {
		if ( lutil_atoix( &level, arg, 0 ) != 0 ) {
			fprintf( stderr,
				"unrecognized log level "
				"\"%s\"\n", arg );
			return 1;
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
279
280
281
282
283
284
		if ( level == 0 ) {
			*levelp = 0;

		} else {
			*levelp |= level;
		}
285
286
287
288
289
	}

	return 0;
}

Hallvard Furuseth's avatar
Hallvard Furuseth committed
290
static void
291
usage( char *name )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
292
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
293
294
295
	fprintf( stderr,
		"usage: %s options\n", name );
	fprintf( stderr,
296
297
		"\t-4\t\tIPv4 only\n"
		"\t-6\t\tIPv6 only\n"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
298
		"\t-T {acl|add|auth|cat|dn|index|passwd|test}\n"
299
		"\t\t\tRun in Tool mode\n"
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
300
		"\t-c cookie\tSync cookie of consumer\n"
301
302
		"\t-d level\tDebug level" "\n"
		"\t-f filename\tConfiguration file\n"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
303
		"\t-F dir\tConfiguration directory\n"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
304
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
305
		"\t-g group\tGroup (id or name) to run as\n"
306
#endif
307
		"\t-h URLs\t\tList of URLs to serve\n"
308
#ifdef SLAP_DEFAULT_SYSLOG_USER
309
		"\t-l facility\tSyslog facility (default: LOCAL4)\n"
310
#endif
311
		"\t-n serverName\tService name\n"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
312
		"\t-o <opt>[=val] generic means to specify options" );
313
314
315
316
317
318
319
320
321
322
323
	if ( !BER_BVISNULL( &option_helpers[0].oh_name ) ) {
		int	i;

		fprintf( stderr, "; supported options:\n" );
		for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); i++) {
			fprintf( stderr, "\t\t%s\n", option_helpers[i].oh_usage );
		}
	} else {
		fprintf( stderr, "\n" );
	}
	fprintf( stderr,	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
324
#ifdef HAVE_CHROOT
325
		"\t-r directory\tSandbox directory to chroot to\n"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
326
#endif
327
		"\t-s level\tSyslog level\n"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
328
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
329
		"\t-u user\t\tUser (id or name) to run as\n"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
330
#endif
331
		"\t-V\t\tprint version info (-VV only)\n"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
332
333
    );
}
334

335
#ifdef HAVE_NT_SERVICE_MANAGER
336
337
338
339
void WINAPI ServiceMain( DWORD argc, LPTSTR *argv )
#else
int main( int argc, char **argv )
#endif
340
{
341
	int		i, no_detach = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
342
	int		rc = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
343
	char *urls = NULL;
344
345
346
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
	char *username = NULL;
	char *groupname = NULL;
347
#endif
348
349
350
#if defined(HAVE_CHROOT)
	char *sandbox = NULL;
#endif
351
#ifdef SLAP_DEFAULT_SYSLOG_USER
Pierangelo Masarati's avatar
Pierangelo Masarati committed
352
	int syslogUser = SLAP_DEFAULT_SYSLOG_USER;
353
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
354
355
356
	
	int g_argc = argc;
	char **g_argv = argv;
357

358
359
360
361
	char *configfile = NULL;
	char *configdir = NULL;
	char *serverName;
	int serverMode = SLAP_SERVER_MODE;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
362

363
364
	struct sync_cookie *scp = NULL;
	struct sync_cookie *scp_entry = NULL;
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
365

366
367
368
	char **debug_unknowns = NULL;
	char **syslog_unknowns = NULL;

369
	char *serverNamePrefix = "";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
370
371
	size_t	l;

372
	int slapd_pid_file_unlink = 0, slapd_args_file_unlink = 0;
373
	int firstopt = 1;
374

375
376
377
378
379
380
381
#ifdef CSRIMALLOC
	FILE *leakfile;
	if( ( leakfile = fopen( "slapd.leak", "w" )) == NULL ) {
		leakfile = stderr;
	}
#endif

382
	slap_sl_mem_init();
383

384
385
	(void) ldap_pvt_thread_initialize();

386
387
388
389
390
391
392
393
394
395
396
	serverName = lutil_progname( "slapd", argc, argv );

	if ( strcmp( serverName, "slapd" ) ) {
		for (i=0; tools[i].name; i++) {
			if ( !strcmp( serverName, tools[i].name ) ) {
				rc = tools[i].func(argc, argv);
				MAIN_RETURN(rc);
			}
		}
	}

397
#ifdef HAVE_NT_SERVICE_MANAGER
398
	{
399
		int *ip;
400
		char *newConfigFile;
401
		char *newConfigDir;
Howard Chu's avatar
Howard Chu committed
402
		char *newUrls;
403
		char *regService = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
404
405

		if ( is_NT_Service ) {
406
			lutil_CommenceStartupProcessing( serverName, slap_sig_shutdown );
407
408
			if ( strcmp(serverName, SERVICE_NAME) )
			    regService = serverName;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
409
410
		}

411
412
413
		ip = (int*)lutil_getRegParam( regService, "DebugLevel" );
		if ( ip != NULL ) {
			slap_debug = *ip;
414
415
			Debug( LDAP_DEBUG_ANY,
				"new debug level from registry is: %d\n", slap_debug, 0, 0 );
416
		}
Howard Chu's avatar
Howard Chu committed
417

418
		newUrls = (char *) lutil_getRegParam(regService, "Urls");
419
		if (newUrls) {
Howard Chu's avatar
Howard Chu committed
420
421
422
423
424
		    if (urls)
			ch_free(urls);

		    urls = ch_strdup(newUrls);
		    Debug(LDAP_DEBUG_ANY, "new urls from registry: %s\n",
425
				urls, 0, 0);
Howard Chu's avatar
Howard Chu committed
426
427
		}

428
		newConfigFile = (char*)lutil_getRegParam( regService, "ConfigFile" );
429
		if ( newConfigFile != NULL ) {
430
431
432
			configfile = newConfigFile;
			Debug ( LDAP_DEBUG_ANY, "new config file from registry is: %s\n", configfile, 0, 0 );
		}
433
434
435
436
437
438

		newConfigDir = (char*)lutil_getRegParam( regService, "ConfigDir" );
		if ( newConfigDir != NULL ) {
			configdir = newConfigDir;
			Debug ( LDAP_DEBUG_ANY, "new config dir from registry is: %s\n", configdir, 0, 0 );
		}
439
440
441
	}
#endif

442
	while ( (i = getopt( argc, argv,
443
			     "c:d:f:F:h:n:o:s:tT:V"
444
#ifdef LDAP_PF_INET6
445
446
				"46"
#endif
447
448
449
#ifdef HAVE_CHROOT
				"r:"
#endif
Howard Chu's avatar
Howard Chu committed
450
#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
451
				"S:"
452
#ifdef LOG_LOCAL4
453
				"l:"
454
#endif
Howard Chu's avatar
Howard Chu committed
455
#endif
456
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
457
				"u:g:"
458
#endif
459
			     )) != EOF ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
460
		switch ( i ) {
461
462
463
464
465
466
467
468
469
#ifdef LDAP_PF_INET6
		case '4':
			slap_inet4or6 = AF_INET;
			break;
		case '6':
			slap_inet4or6 = AF_INET6;
			break;
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
470
		case 'h':	/* listen URLs */
Hallvard Furuseth's avatar
Hallvard Furuseth committed
471
			if ( urls != NULL ) free( urls );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
472
			urls = ch_strdup( optarg );
473
			break;
474

Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
475
		case 'c':	/* provide sync cookie, override if exist in replica */
476
477
			scp = (struct sync_cookie *) ch_calloc( 1,
										sizeof( struct sync_cookie ));
Howard Chu's avatar
Howard Chu committed
478
			ber_str2bv( optarg, 0, 1, &scp->octet_str );
479
480
			
			/* This only parses out the rid at this point */
Howard Chu's avatar
Howard Chu committed
481
			slap_parse_sync_cookie( scp, NULL );
482

483
484
485
486
487
488
489
490
			if ( scp->rid == -1 ) {
				Debug( LDAP_DEBUG_ANY,
						"main: invalid cookie \"%s\"\n",
						optarg, 0, 0 );
				slap_sync_cookie_free( scp, 1 );
				goto destroy;
			}

491
			LDAP_STAILQ_FOREACH( scp_entry, &slap_sync_cookie, sc_next ) {
492
493
494
495
496
497
498
499
				if ( scp->rid == scp_entry->rid ) {
					Debug( LDAP_DEBUG_ANY,
						    "main: duplicated replica id in cookies\n",
							0, 0, 0 );
					slap_sync_cookie_free( scp, 1 );
					goto destroy;
				}
			}
500
			LDAP_STAILQ_INSERT_TAIL( &slap_sync_cookie, scp, sc_next );
Jong Hyuk Choi's avatar
Jong Hyuk Choi committed
501
502
			break;

503
504
505
		case 'd': {	/* set debug level and 'do not detach' flag */
			int	level = 0;

506
			if ( strcmp( optarg, "?" ) == 0 ) {
507
508
				check |= CHECK_LOGLEVEL;
				break;
509
510
			}

511
			no_detach = 1;
512
			if ( parse_debug_level( optarg, &level, &debug_unknowns ) ) {
513
				goto destroy;
514
			}
515
516
#ifdef LDAP_DEBUG
			slap_debug |= level;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
517
#else
518
			if ( level != 0 )
519
520
				fputs( "must compile with LDAP_DEBUG for debugging\n",
				       stderr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
521
#endif
522
			} break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
523
524

		case 'f':	/* read config file */
525
			configfile = ch_strdup( optarg );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
526
527
			break;

528
529
530
531
		case 'F':	/* use config dir */
			configdir = ch_strdup( optarg );
			break;

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
		case 'o': {
			char		*val = strchr( optarg, '=' );
			struct berval	opt;

			opt.bv_val = optarg;
			
			if ( val ) {
				opt.bv_len = ( val - optarg );
				val++;
			
			} else {
				opt.bv_len = strlen( optarg );
			}

			for ( i = 0; !BER_BVISNULL( &option_helpers[i].oh_name ); i++ ) {
				if ( ber_bvstrcasecmp( &option_helpers[i].oh_name, &opt ) == 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
548
549
550
551
552
553
					assert( option_helpers[i].oh_fnc != NULL );
					if ( (*option_helpers[i].oh_fnc)( val, option_helpers[i].oh_arg ) == -1 ) {
						/* we assume the option parsing helper
						 * issues appropriate and self-explanatory
						 * error messages... */
						goto stop;
554
					}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
555
					break;
556
557
558
559
560
561
562
563
564
				}
			}

			if ( BER_BVISNULL( &option_helpers[i].oh_name ) ) {
				goto unhandled_option;
			}
			break;
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
565
		case 's':	/* set syslog level */
566
			if ( strcmp( optarg, "?" ) == 0 ) {
567
568
				check |= CHECK_LOGLEVEL;
				break;
569
570
			}

571
			if ( parse_debug_level( optarg, &ldap_syslog, &syslog_unknowns ) ) {
572
573
				goto destroy;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
574
575
			break;

576
577
578
579
580
581
582
#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
		case 'S':
			if ( parse_syslog_level( optarg, &ldap_syslog_level ) ) {
				goto destroy;
			}
			break;

583
584
#ifdef LOG_LOCAL4
		case 'l':	/* set syslog local user */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
585
586
587
			if ( parse_syslog_user( optarg, &syslogUser ) ) {
				goto destroy;
			}
588
589
			break;
#endif
Howard Chu's avatar
Howard Chu committed
590
#endif /* LDAP_DEBUG && LDAP_SYSLOG */
591

592
593
594
595
596
597
598
#ifdef HAVE_CHROOT
		case 'r':
			if( sandbox ) free(sandbox);
			sandbox = ch_strdup( optarg );
			break;
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
599
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
600
601
		case 'u':	/* user name */
			if( username ) free(username);
602
603
604
			username = ch_strdup( optarg );
			break;

605
606
		case 'g':	/* group name */
			if( groupname ) free(groupname);
607
608
			groupname = ch_strdup( optarg );
			break;
609
#endif /* SETUID && GETUID */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
610

611
		case 'n':  /* NT service name */
612
			serverName = ch_strdup( optarg );
613
			break;
614

615
		case 't':
Pierangelo Masarati's avatar
Pierangelo Masarati committed
616
617
618
			/* deprecated; use slaptest instead */
			fprintf( stderr, "option -t deprecated; "
				"use slaptest command instead\n" );
619
			check |= CHECK_CONFIG;
620
			break;
621

622
623
624
		case 'V':
			version++;
			break;
625

626
		case 'T':
627
628
629
630
631
632
			if ( firstopt == 0 ) {
				fprintf( stderr, "warning: \"-T %s\" "
					"should be the first option.\n",
					optarg );
			}

633
634
			/* try full option string first */
			for ( i = 0; tools[i].name; i++ ) {
635
				if ( strcmp( optarg, &tools[i].name[4] ) == 0 ) {
636
637
					rc = tools[i].func( argc, argv );
					MAIN_RETURN( rc );
638
639
				}
			}
640
641
642
643
644
645
646
647
648
649
650

			/* try bits of option string (backward compatibility for single char) */
			l = strlen( optarg );
			for ( i = 0; tools[i].name; i++ ) {
				if ( strncmp( optarg, &tools[i].name[4], l ) == 0 ) {
					rc = tools[i].func( argc, argv );
					MAIN_RETURN( rc );
				}
			}
			
			/* issue error */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
651
652
653
654
			serverName = optarg;
			serverNamePrefix = "slap";
			fprintf( stderr, "program name \"%s%s\" unrecognized; "
					"aborting...\n", serverNamePrefix, serverName );
655
			/* FALLTHRU */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
656
		default:
657
unhandled_option:;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
658
			usage( argv[0] );
659
660
661
			rc = 1;
			SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 15 );
			goto stop;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
662
		}
663
664
665
666

		if ( firstopt ) {
			firstopt = 0;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
667
668
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
669
	ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug);
670
671
672
	ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug);
	ldif_debug = slap_debug;

673
674
675
676
	if ( version ) {
		fprintf( stderr, "%s\n", Versionstr );
		if ( version > 1 ) goto stop;
	}
677

678
#if defined(LDAP_DEBUG) && defined(LDAP_SYSLOG)
Howard Chu's avatar
Howard Chu committed
679
680
681
682
683
684
685
686
687
	{
		char *logName;
#ifdef HAVE_EBCDIC
		logName = ch_strdup( serverName );
		__atoe( logName );
#else
		logName = serverName;
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
688
#ifdef LOG_LOCAL4
Howard Chu's avatar
Howard Chu committed
689
		openlog( logName, OPENLOG_OPTIONS, syslogUser );
690
#elif defined LOG_DEBUG
Howard Chu's avatar
Howard Chu committed
691
692
693
694
		openlog( logName, OPENLOG_OPTIONS );
#endif
#ifdef HAVE_EBCDIC
		free( logName );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
695
#endif
Howard Chu's avatar
Howard Chu committed
696
	}
697
#endif /* LDAP_DEBUG && LDAP_SYSLOG */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
698

699
700
	Debug( LDAP_DEBUG_ANY, "%s", Versionstr, 0, 0 );

Howard Chu's avatar
Howard Chu committed
701
702
	global_host = ldap_pvt_get_fqdn( NULL );

703
	if( check == CHECK_NONE && slapd_daemon_init( urls ) != 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
704
705
706
707
		rc = 1;
		SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 16 );
		goto stop;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
708

709
#if defined(HAVE_CHROOT)
710
711
712
713
714
715
716
717
718
719
720
	if ( sandbox ) {
		if ( chdir( sandbox ) ) {
			perror("chdir");
			rc = 1;
			goto stop;
		}
		if ( chroot( sandbox ) ) {
			perror("chroot");
			rc = 1;
			goto stop;
		}
721
722
723
	}
#endif

724
#if defined(HAVE_SETUID) && defined(HAVE_SETGID)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
725
	if ( username != NULL || groupname != NULL ) {
726
		slap_init_user( username, groupname );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
727
	}
728
729
#endif

730
	extops_init();
731
	lutil_passwd_init();
732

Howard Chu's avatar
Howard Chu committed
733
734
735
736
737
738
#ifdef HAVE_TLS
	rc = ldap_create( &slap_tls_ld );
	if ( rc ) {
		SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
		goto destroy;
	}
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
739
740
741
742
743
744
745
	/* Library defaults to full certificate checking. This is correct when
	 * a client is verifying a server because all servers should have a
	 * valid cert. But few clients have valid certs, so we want our default
	 * to be no checking. The config file can override this as usual.
	 */
	rc = LDAP_OPT_X_TLS_NEVER;
	(void) ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &rc );
Howard Chu's avatar
Howard Chu committed
746
747
#endif

748
749
	rc = slap_init( serverMode, serverName );
	if ( rc ) {
750
751
752
753
		SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 18 );
		goto destroy;
	}

754
	if ( read_config( configfile, configdir ) != 0 ) {
755
		rc = 1;
756
		SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 19 );
757

758
		if ( check & CHECK_CONFIG ) {
759
760
761
762
763
764
			fprintf( stderr, "config check failed\n" );
		}

		goto destroy;
	}

765
766
767
768
769
770
771
772
773
774
775
776
777
	if ( debug_unknowns ) {
		rc = parse_debug_unknowns( debug_unknowns, &slap_debug );
		ldap_charray_free( debug_unknowns );
		debug_unknowns = NULL;
		if ( rc )
			goto destroy;
	}
	if ( syslog_unknowns ) {
		rc = parse_debug_unknowns( syslog_unknowns, &ldap_syslog );
		ldap_charray_free( syslog_unknowns );
		syslog_unknowns = NULL;
		if ( rc )
			goto destroy;
778
779
780
781
782
	}	

	if ( check & CHECK_LOGLEVEL ) {
		rc = 0;
		goto destroy;
783
784
	}

785
	if ( check & CHECK_CONFIG ) {
786
		fprintf( stderr, "config check succeeded\n" );
787
788
789
790
791
792

		check &= ~CHECK_CONFIG;
		if ( check == CHECK_NONE ) {
			rc = 0;
			goto destroy;
		}
793
794
	}

795
	if ( glue_sub_attach( ) != 0 ) {
796
797
798
799
800
801
802
		Debug( LDAP_DEBUG_ANY,
		    "subordinate config error\n",
		    0, 0, 0 );

		goto destroy;
	}

803
	if ( slap_schema_check( ) != 0 ) {
804
805
806
		Debug( LDAP_DEBUG_ANY,
		    "schema prep error\n",
		    0, 0, 0 );
807

808
809
810
		goto destroy;
	}

811
#ifdef HAVE_TLS
812
	rc = ldap_pvt_tls_init();
Kurt Zeilenga's avatar
Kurt Zeilenga committed
813
814
815
816
817
818
819
820
	if( rc != 0) {
		Debug( LDAP_DEBUG_ANY,
		    "main: TLS init failed: %d\n",
		    0, 0, 0 );
		rc = 1;
		SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
		goto destroy;
	}
Howard Chu's avatar
Howard Chu committed
821

Howard Chu's avatar
Howard Chu committed
822
	{
Howard Chu's avatar
Howard Chu committed
823
		int opt = 1;
Howard Chu's avatar
Howard Chu committed
824
825

		/* Force new ctx to be created */
Howard Chu's avatar
Howard Chu committed
826
		rc = ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
827
		if( rc == 0 ) {
Howard Chu's avatar
Howard Chu committed
828
829
			/* The ctx's refcount is bumped up here */
			ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CTX, &slap_tls_ctx );
830
831
			load_extop( &slap_EXOP_START_TLS, 0, starttls_extop );
		} else if ( rc != LDAP_NOT_SUPPORTED ) {
Howard Chu's avatar
Howard Chu committed
832
833
834
835
836
837
838
			Debug( LDAP_DEBUG_ANY,
			    "main: TLS init def ctx failed: %d\n",
			    rc, 0, 0 );
			rc = 1;
			SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 20 );
			goto destroy;
		}
Howard Chu's avatar
Howard Chu committed
839
	}
840
841
#endif

842
843
844
845
846
847
#ifdef HAVE_CYRUS_SASL
	if( sasl_host == NULL ) {
		sasl_host = ch_strdup( global_host );
	}
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
848
849
850
	(void) SIGNAL( LDAP_SIGUSR1, slap_sig_wake );
	(void) SIGNAL( LDAP_SIGUSR2, slap_sig_shutdown );

851
#ifdef SIGPIPE
852
	(void) SIGNAL( SIGPIPE, SIG_IGN );
853
854
#endif
#ifdef SIGHUP
Kurt Zeilenga's avatar
Kurt Zeilenga committed
855
	(void) SIGNAL( SIGHUP, slap_sig_shutdown );
856
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
857
858
	(void) SIGNAL( SIGINT, slap_sig_shutdown );
	(void) SIGNAL( SIGTERM, slap_sig_shutdown );
859
#ifdef SIGTRAP
860
	(void) SIGNAL( SIGTRAP, slap_sig_shutdown );
861
#endif
862
863
#ifdef LDAP_SIGCHLD
	(void) SIGNAL( LDAP_SIGCHLD, wait4child );
Hallvard Furuseth's avatar
Hallvard Furuseth committed
864
#endif
865
#ifdef SIGBREAK
866
	/* SIGBREAK is generated when Ctrl-Break is pressed. */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
867
	(void) SIGNAL( SIGBREAK, slap_sig_shutdown );
868
#endif
869

870
#ifndef HAVE_WINSOCK
871
	lutil_detach( no_detach, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
872
#endif /* HAVE_WINSOCK */
873

874
875
876
877
#ifdef CSRIMALLOC
	mal_leaktrace(1);
#endif

878
879
	if ( slapd_pid_file != NULL ) {
		FILE *fp = fopen( slapd_pid_file, "w" );
880

881
882
883
884
885
886
887
		if ( fp == NULL ) {
			int save_errno = errno;

			Debug( LDAP_DEBUG_ANY, "unable to open pid file "
				"\"%s\": %d (%s)\n",
				slapd_pid_file,
				save_errno, strerror( save_errno ) );
888

889
			free( slapd_pid_file );
890
			slapd_pid_file = NULL;
891
892

			rc = 1;
893
			goto destroy;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
894
		}
895
896
		fprintf( fp, "%d\n", (int) getpid() );
		fclose( fp );
897
		slapd_pid_file_unlink = 1;
898
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
899

900
901
	if ( slapd_args_file != NULL ) {
		FILE *fp = fopen( slapd_args_file, "w" );
902

903
904
905
906
907
908
909
910
911
		if ( fp == NULL ) {
			int save_errno = errno;

			Debug( LDAP_DEBUG_ANY, "unable to open args file "
				"\"%s\": %d (%s)\n",
				slapd_args_file,
				save_errno, strerror( save_errno ) );

			free( slapd_args_file );
912
			slapd_args_file = NULL;
913
914

			rc = 1;
915
			goto destroy;
916
917
918
919
		}

		for ( i = 0; i < g_argc; i++ ) {
			fprintf( fp, "%s ", g_argv[i] );
920
		}
921
922
		fprintf( fp, "\n" );
		fclose( fp );
923
		slapd_args_file_unlink = 1;
924
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
925

926
927
928
929
930
931
932
933
934
935
936
937
938
939
	/*
	 * FIXME: moved here from slapd_daemon_task()
	 * because back-monitor db_open() needs it
	 */
	time( &starttime );

	if ( slap_startup( NULL ) != 0 ) {
		rc = 1;
		SERVICE_EXIT( ERROR_SERVICE_SPECIFIC_ERROR, 21 );
		goto shutdown;
	}

	Debug( LDAP_DEBUG_ANY, "slapd starting\n", 0, 0, 0 );

940
#ifdef HAVE_NT_EVENT_LOG
Howard Chu's avatar
Howard Chu committed
941
	if (is_NT_Service)
Howard Chu's avatar
Howard Chu committed
942
943
	lutil_LogStartedEvent( serverName, slap_debug, configfile ?
		configfile : SLAPD_DEFAULT_CONFIGFILE , urls );
944
945
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
946
	rc = slapd_daemon();
947

948
#ifdef HAVE_NT_SERVICE_MANAGER
949
	/* Throw away the event that we used during the startup process. */
950
951
952
	if ( is_NT_Service )
		ldap_pvt_thread_cond_destroy( &started_event );
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
953

954
shutdown:
955
	/* remember an error during shutdown */
956
	rc |= slap_shutdown( NULL );
957

958
destroy:
959
960
961
	if ( check & CHECK_LOGLEVEL ) {
		(void)loglevel_print( stdout );
	}
962
963
964
	/* remember an error during destroy */
	rc |= slap_destroy();

965
966
967
	while ( !LDAP_STAILQ_EMPTY( &slap_sync_cookie )) {
		scp = LDAP_STAILQ_FIRST( &slap_sync_cookie );
		LDAP_STAILQ_REMOVE_HEAD( &slap_sync_cookie, sc_next );
968
969
970
		ch_free( scp );
	}

971
972
973
974
#ifdef SLAPD_MODULES
	module_kill();
#endif

975
976
	extops_kill();

977
	supported_feature_destroy();
978
	entry_info_destroy();
979

980
stop:
981
#ifdef HAVE_NT_EVENT_LOG
Howard Chu's avatar
Howard Chu committed
982
	if (is_NT_Service)
983
	lutil_LogStoppedEvent( serverName );
984
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
985

986
	Debug( LDAP_DEBUG_ANY, "slapd stopped.\n", 0, 0, 0 );
987

Kurt Zeilenga's avatar
Kurt Zeilenga committed
988

989
#ifdef HAVE_NT_SERVICE_MANAGER
990
	lutil_ReportShutdownComplete();
991
#endif
992

993
#ifdef LOG_DEBUG
994
    closelog();
995
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
996