config.c 49.8 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* config.c - configuration file handling routines */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 1998-2008 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 * 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>.
 */
/* 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
25
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
26

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
29
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
30
31

#include <ac/string.h>
32
#include <ac/ctype.h>
33
#include <ac/signal.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
#include <ac/socket.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
35
#include <ac/errno.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
36

37
38
#include <sys/types.h>
#include <sys/stat.h>
Howard Chu's avatar
Howard Chu committed
39
40
41
42
43

#ifndef S_ISREG
#define	S_ISREG(m)	(((m) & _S_IFMT) == _S_IFREG)
#endif

44
#ifdef HAVE_UNISTD_H
45
#include <unistd.h>
Howard Chu's avatar
Howard Chu committed
46
#endif
47

48
#include "slap.h"
49
#ifdef LDAP_SLAPI
50
#include "slapi/slapi.h"
51
#endif
52
#include "lutil.h"
53
#include "lutil_ldap.h"
54
#include "config.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
55

56
#define ARGS_STEP	512
Kurt Zeilenga's avatar
Kurt Zeilenga committed
57
58
59
60

/*
 * defaults for various global variables
 */
61
62
63
64
65
66
slap_mask_t		global_allows = 0;
slap_mask_t		global_disallows = 0;
int		global_gentlehup = 0;
int		global_idletimeout = 0;
char	*global_host = NULL;
char	*global_realm = NULL;
67
char	*sasl_host = NULL;
68
69
70
71
72
73
74
75
76
77
78
79
char		**default_passwd_hash = NULL;
struct berval default_search_base = BER_BVNULL;
struct berval default_search_nbase = BER_BVNULL;

ber_len_t sockbuf_max_incoming = SLAP_SB_MAX_INCOMING_DEFAULT;
ber_len_t sockbuf_max_incoming_auth= SLAP_SB_MAX_INCOMING_AUTH;

int	slap_conn_max_pending = SLAP_CONN_MAX_PENDING_DEFAULT;
int	slap_conn_max_pending_auth = SLAP_CONN_MAX_PENDING_AUTH;

char   *slapd_pid_file  = NULL;
char   *slapd_args_file = NULL;
80

81
82
83
84
85
86
int use_reverse_lookup = 0;

#ifdef LDAP_SLAPI
int slapi_plugins_used = 0;
#endif

87
88
89
static int fp_getline(FILE *fp, ConfigArgs *c);
static void fp_getline_init(ConfigArgs *c);
static int fp_parse_line(ConfigArgs *c);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
90

91
static char	*strtok_quote(char *line, char *sep, char **quote_ptr);
92
static char *strtok_quote_ldif(char **line);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
93

94
ConfigArgs *
95
96
new_config_args( BackendDB *be, const char *fname, int lineno, int argc, char **argv )
{
97
	ConfigArgs *c;
98
99
	c = ch_calloc( 1, sizeof( ConfigArgs ) );
	if ( c == NULL ) return(NULL);
100
101
102
103
104
	c->be     = be; 
	c->fname  = fname;
	c->argc   = argc;
	c->argv   = argv; 
	c->lineno = lineno;
105
	snprintf( c->log, sizeof( c->log ), "%s: line %d", fname, lineno );
106
107
	return(c);
}
108

Howard Chu's avatar
Howard Chu committed
109
110
111
112
113
114
115
void
init_config_argv( ConfigArgs *c )
{
	c->argv = ch_calloc( ARGS_STEP + 1, sizeof( *c->argv ) );
	c->argv_size = ARGS_STEP + 1;
}

116
117
118
119
120
121
122
123
124
125
ConfigTable *config_find_keyword(ConfigTable *Conf, ConfigArgs *c) {
	int i;

	for(i = 0; Conf[i].name; i++)
		if( (Conf[i].length && (!strncasecmp(c->argv[0], Conf[i].name, Conf[i].length))) ||
			(!strcasecmp(c->argv[0], Conf[i].name)) ) break;
	if ( !Conf[i].name ) return NULL;
	return Conf+i;
}

Howard Chu's avatar
Howard Chu committed
126
int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) {
127
	int rc, arg_user, arg_type, arg_syn, iarg;
128
	unsigned uiarg;
129
130
	long larg;
	ber_len_t barg;
Howard Chu's avatar
Howard Chu committed
131
	
132
	if(Conf->arg_type == ARG_IGNORED) {
133
		Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
134
			c->log, Conf->name, 0);
135
		return(0);
136
	}
137
138
139
140
141
	arg_type = Conf->arg_type & ARGS_TYPES;
	arg_user = Conf->arg_type & ARGS_USERLAND;
	arg_syn = Conf->arg_type & ARGS_SYNTAX;

	if((arg_type == ARG_DN) && c->argc == 1) {
Howard Chu's avatar
Howard Chu committed
142
143
144
		c->argc = 2;
		c->argv[1] = "";
	}
145
	if(Conf->min_args && (c->argc < Conf->min_args)) {
146
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> missing <%s> argument",
Howard Chu's avatar
Howard Chu committed
147
			c->argv[0], Conf->what );
148
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n", c->log, c->cr_msg, 0 );
149
		return(ARG_BAD_CONF);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
150
	}
151
	if(Conf->max_args && (c->argc > Conf->max_args)) {
152
153
		char	*ignored = " ignored";

154
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> extra cruft after <%s>",
Howard Chu's avatar
Howard Chu committed
155
			c->argv[0], Conf->what );
156
157

		ignored = "";
158
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s%s.\n",
159
				c->log, c->cr_msg, ignored );
160
		return(ARG_BAD_CONF);
161
	}
162
	if((arg_syn & ARG_DB) && !c->be) {
163
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> only allowed within database declaration",
Howard Chu's avatar
Howard Chu committed
164
			c->argv[0] );
165
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
166
			c->log, c->cr_msg, 0);
167
168
		return(ARG_BAD_CONF);
	}
169
	if((arg_syn & ARG_PRE_BI) && c->bi) {
170
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must occur before any backend %sdeclaration",
171
			c->argv[0], (arg_syn & ARG_PRE_DB) ? "or database " : "" );
172
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
173
			c->log, c->cr_msg, 0 );
174
175
		return(ARG_BAD_CONF);
	}
176
	if((arg_syn & ARG_PRE_DB) && c->be && c->be != frontendDB) {
177
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must occur before any database declaration",
Howard Chu's avatar
Howard Chu committed
178
			c->argv[0] );
179
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
180
			c->log, c->cr_msg, 0);
181
182
		return(ARG_BAD_CONF);
	}
183
	if((arg_syn & ARG_PAREN) && *c->argv[1] != '(' /*')'*/) {
184
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> old format not supported", c->argv[0] );
185
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
186
			c->log, c->cr_msg, 0);
187
188
		return(ARG_BAD_CONF);
	}
189
	if(arg_type && !Conf->arg_item && !(arg_syn & ARG_OFFSET)) {
190
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid config_table, arg_item is NULL",
Howard Chu's avatar
Howard Chu committed
191
			c->argv[0] );
192
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
193
			c->log, c->cr_msg, 0);
194
195
		return(ARG_BAD_CONF);
	}
196
	c->type = arg_user;
Howard Chu's avatar
Howard Chu committed
197
	memset(&c->values, 0, sizeof(c->values));
198
199
200
201
202
203
204
205
206
207
208
	if(arg_type == ARG_STRING) {
		if ( !check_only )
			c->value_string = ch_strdup(c->argv[1]);
	} else if(arg_type == ARG_BERVAL) {
		if ( !check_only )
			ber_str2bv( c->argv[1], 0, 1, &c->value_bv );
	} else if(arg_type == ARG_DN) {
		struct berval bv;
		ber_str2bv( c->argv[1], 0, 0, &bv );
		rc = dnPrettyNormal( NULL, &bv, &c->value_dn, &c->value_ndn, NULL );
		if ( rc != LDAP_SUCCESS ) {
209
			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid DN %d (%s)",
210
				c->argv[0], rc, ldap_err2string( rc ));
211
			Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n" , c->log, c->cr_msg, 0);
212
213
214
215
216
217
218
			return(ARG_BAD_CONF);
		}
		if ( check_only ) {
			ch_free( c->value_ndn.bv_val );
			ch_free( c->value_dn.bv_val );
		}
	} else {	/* all numeric */
Howard Chu's avatar
Howard Chu committed
219
		int j;
220
		iarg = 0; larg = 0; barg = 0;
221
		switch(arg_type) {
222
			case ARG_INT:
223
				if ( lutil_atoix( &iarg, c->argv[1], 0 ) != 0 ) {
224
					snprintf( c->cr_msg, sizeof( c->cr_msg ),
225
226
						"<%s> unable to parse \"%s\" as int",
						c->argv[0], c->argv[1] );
227
					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
228
						c->log, c->cr_msg, 0);
229
230
231
					return(ARG_BAD_CONF);
				}
				break;
232
233
234
235
236
237
238
239
240
241
			case ARG_UINT:
				if ( lutil_atoux( &uiarg, c->argv[1], 0 ) != 0 ) {
					snprintf( c->cr_msg, sizeof( c->cr_msg ),
						"<%s> unable to parse \"%s\" as unsigned int",
						c->argv[0], c->argv[1] );
					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
						c->log, c->cr_msg, 0);
					return(ARG_BAD_CONF);
				}
				break;
242
			case ARG_LONG:
243
				if ( lutil_atolx( &larg, c->argv[1], 0 ) != 0 ) {
244
					snprintf( c->cr_msg, sizeof( c->cr_msg ),
245
246
						"<%s> unable to parse \"%s\" as long",
						c->argv[0], c->argv[1] );
247
					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
248
						c->log, c->cr_msg, 0);
249
250
251
252
253
					return(ARG_BAD_CONF);
				}
				break;
			case ARG_BER_LEN_T: {
				unsigned long	l;
254
				if ( lutil_atoulx( &l, c->argv[1], 0 ) != 0 ) {
255
					snprintf( c->cr_msg, sizeof( c->cr_msg ),
256
257
						"<%s> unable to parse \"%s\" as ber_len_t",
						c->argv[0], c->argv[1] );
258
					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
259
						c->log, c->cr_msg, 0);
260
261
262
263
					return(ARG_BAD_CONF);
				}
				barg = (ber_len_t)l;
				} break;
264
			case ARG_ON_OFF:
265
				if (c->argc == 1) {
266
					iarg = 1;
267
				} else if ( !strcasecmp(c->argv[1], "on") ||
268
					!strcasecmp(c->argv[1], "true") ||
269
					!strcasecmp(c->argv[1], "yes") )
270
				{
271
					iarg = 1;
272
				} else if ( !strcasecmp(c->argv[1], "off") ||
273
					!strcasecmp(c->argv[1], "false") ||
274
					!strcasecmp(c->argv[1], "no") )
275
				{
276
277
					iarg = 0;
				} else {
278
					snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value",
Howard Chu's avatar
Howard Chu committed
279
						c->argv[0] );
280
					Debug(LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n",
281
						c->log, c->cr_msg, 0 );
282
					return(ARG_BAD_CONF);
283
284
				}
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
285
		}
Howard Chu's avatar
Howard Chu committed
286
		j = (arg_type & ARG_NONZERO) ? 1 : 0;
Howard Chu's avatar
Howard Chu committed
287
		if(iarg < j && larg < j && barg < j ) {
288
			larg = larg ? larg : (barg ? barg : iarg);
289
			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value",
Howard Chu's avatar
Howard Chu committed
290
				c->argv[0] );
291
			Debug(LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n",
292
				c->log, c->cr_msg, 0 );
293
			return(ARG_BAD_CONF);
294
		}
295
		switch(arg_type) {
Howard Chu's avatar
Howard Chu committed
296
297
			case ARG_ON_OFF:
			case ARG_INT:		c->value_int = iarg;		break;
298
			case ARG_UINT:		c->value_uint = uiarg;		break;
Howard Chu's avatar
Howard Chu committed
299
300
301
			case ARG_LONG:		c->value_long = larg;		break;
			case ARG_BER_LEN_T:	c->value_ber_t = barg;		break;
		}
302
	}
Howard Chu's avatar
Howard Chu committed
303
304
305
306
	return 0;
}

int config_set_vals(ConfigTable *Conf, ConfigArgs *c) {
307
	int rc, arg_type;
Howard Chu's avatar
Howard Chu committed
308
	void *ptr = NULL;
Howard Chu's avatar
Howard Chu committed
309
310

	arg_type = Conf->arg_type;
311
312
	if(arg_type & ARG_MAGIC) {
		if(!c->be) c->be = frontendDB;
313
		c->cr_msg[0] = '\0';
314
		rc = (*((ConfigDriver*)Conf->arg_item))(c);
Howard Chu's avatar
Howard Chu committed
315
#if 0
316
		if(c->be == frontendDB) c->be = NULL;
Howard Chu's avatar
Howard Chu committed
317
#endif
318
		if(rc) {
319
320
			if ( !c->cr_msg[0] ) {
				snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> handler exited with %d",
Howard Chu's avatar
Howard Chu committed
321
322
					c->argv[0], rc );
				Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n",
323
					c->log, c->cr_msg, 0 );
Howard Chu's avatar
Howard Chu committed
324
			}
325
			return(ARG_BAD_CONF);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
326
		}
327
328
		return(0);
	}
329
	if(arg_type & ARG_OFFSET) {
330
		if (c->be && c->table == Cft_Database)
331
332
333
334
			ptr = c->be->be_private;
		else if (c->bi)
			ptr = c->bi->bi_private;
		else {
335
			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> offset is missing base pointer",
Howard Chu's avatar
Howard Chu committed
336
337
				c->argv[0] );
			Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n",
338
				c->log, c->cr_msg, 0);
339
340
			return(ARG_BAD_CONF);
		}
341
		ptr = (void *)((char *)ptr + (long)Conf->arg_item);
342
	} else if (arg_type & ARGS_TYPES) {
343
		ptr = Conf->arg_item;
344
	}
345
346
	if(arg_type & ARGS_TYPES)
		switch(arg_type & ARGS_TYPES) {
347
			case ARG_ON_OFF:
Howard Chu's avatar
Howard Chu committed
348
			case ARG_INT: 		*(int*)ptr = c->value_int;			break;
349
			case ARG_UINT: 		*(unsigned*)ptr = c->value_uint;			break;
Howard Chu's avatar
Howard Chu committed
350
351
			case ARG_LONG:  	*(long*)ptr = c->value_long;			break;
			case ARG_BER_LEN_T: 	*(ber_len_t*)ptr = c->value_ber_t;			break;
352
			case ARG_STRING: {
353
				char *cc = *(char**)ptr;
354
				if(cc) {
Howard Chu's avatar
Howard Chu committed
355
					if ((arg_type & ARG_UNIQUE) && c->op == SLAP_CONFIG_ADD ) {
356
						Debug(LDAP_DEBUG_CONFIG, "%s: already set %s!\n",
357
							c->log, Conf->name, 0 );
358
359
						return(ARG_BAD_CONF);
					}
Howard Chu's avatar
Howard Chu committed
360
					ch_free(cc);
361
				}
362
				*(char **)ptr = c->value_string;
363
364
				break;
				}
365
366
367
368
			case ARG_BERVAL:
				*(struct berval *)ptr = c->value_bv;
				break;
		}
Howard Chu's avatar
Howard Chu committed
369
370
371
372
	return(0);
}

int config_add_vals(ConfigTable *Conf, ConfigArgs *c) {
373
	int rc, arg_type;
Howard Chu's avatar
Howard Chu committed
374
375
376
377
378
379
380
381
382
383

	arg_type = Conf->arg_type;
	if(arg_type == ARG_IGNORED) {
		Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
			c->log, Conf->name, 0);
		return(0);
	}
	rc = config_check_vals( Conf, c, 0 );
	if ( rc ) return rc;
	return config_set_vals( Conf, c );
384
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
385

386
387
388
389
int
config_del_vals(ConfigTable *cf, ConfigArgs *c)
{
	int rc = 0;
390

391
392
393
394
395
396
	/* If there is no handler, just ignore it */
	if ( cf->arg_type & ARG_MAGIC ) {
		c->op = LDAP_MOD_DELETE;
		c->type = cf->arg_type & ARGS_USERLAND;
		rc = (*((ConfigDriver*)cf->arg_item))(c);
	}
397
	return rc;
398
399
}

Howard Chu's avatar
Howard Chu committed
400
401
402
403
404
int
config_get_vals(ConfigTable *cf, ConfigArgs *c)
{
	int rc = 0;
	struct berval bv;
405
	void *ptr;
Howard Chu's avatar
Howard Chu committed
406
407
408
409
410

	if ( cf->arg_type & ARG_IGNORED ) {
		return 1;
	}

Howard Chu's avatar
Howard Chu committed
411
	memset(&c->values, 0, sizeof(c->values));
412
	c->rvalue_vals = NULL;
Howard Chu's avatar
Howard Chu committed
413
	c->rvalue_nvals = NULL;
414
	c->op = SLAP_CONFIG_EMIT;
Howard Chu's avatar
Howard Chu committed
415
416
	c->type = cf->arg_type & ARGS_USERLAND;

Howard Chu's avatar
Howard Chu committed
417
418
419
420
	if ( cf->arg_type & ARG_MAGIC ) {
		rc = (*((ConfigDriver*)cf->arg_item))(c);
		if ( rc ) return rc;
	} else {
421
		if ( cf->arg_type & ARG_OFFSET ) {
422
			if (c->be && c->table == Cft_Database)
423
424
425
426
427
				ptr = c->be->be_private;
			else if ( c->bi )
				ptr = c->bi->bi_private;
			else
				return 1;
428
			ptr = (void *)((char *)ptr + (long)cf->arg_item);
429
430
431
432
		} else {
			ptr = cf->arg_item;
		}
		
433
		switch(cf->arg_type & ARGS_TYPES) {
Howard Chu's avatar
Howard Chu committed
434
		case ARG_ON_OFF:
435
		case ARG_INT:	c->value_int = *(int *)ptr; break;
436
		case ARG_UINT:	c->value_uint = *(unsigned *)ptr; break;
437
438
		case ARG_LONG:	c->value_long = *(long *)ptr; break;
		case ARG_BER_LEN_T:	c->value_ber_t = *(ber_len_t *)ptr; break;
Howard Chu's avatar
Howard Chu committed
439
		case ARG_STRING:
440
441
			if ( *(char **)ptr )
				c->value_string = ch_strdup(*(char **)ptr);
Howard Chu's avatar
Howard Chu committed
442
			break;
443
444
		case ARG_BERVAL:
			ber_dupbv( &c->value_bv, (struct berval *)ptr ); break;
Howard Chu's avatar
Howard Chu committed
445
446
		}
	}
447
	if ( cf->arg_type & ARGS_TYPES) {
Howard Chu's avatar
Howard Chu committed
448
		bv.bv_len = 0;
Howard Chu's avatar
Howard Chu committed
449
		bv.bv_val = c->log;
450
		switch(cf->arg_type & ARGS_TYPES) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
451
		case ARG_INT: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%d", c->value_int); break;
452
		case ARG_UINT: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%u", c->value_uint); break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
453
454
455
		case ARG_LONG: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%ld", c->value_long); break;
		case ARG_BER_LEN_T: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%ld", c->value_ber_t); break;
		case ARG_ON_OFF: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%s",
Howard Chu's avatar
Howard Chu committed
456
			c->value_int ? "TRUE" : "FALSE"); break;
457
458
459
460
		case ARG_STRING:
			if ( c->value_string && c->value_string[0]) {
				ber_str2bv( c->value_string, 0, 0, &bv);
			} else {
Howard Chu's avatar
Howard Chu committed
461
				return 1;
462
463
			}
			break;
464
465
466
467
468
469
470
		case ARG_BERVAL:
			if ( !BER_BVISEMPTY( &c->value_bv )) {
				bv = c->value_bv;
			} else {
				return 1;
			}
			break;
471
472
473
		default:
			bv.bv_val = NULL;
			break;
Howard Chu's avatar
Howard Chu committed
474
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
475
476
477
		if (bv.bv_val == c->log && bv.bv_len >= sizeof( c->log ) ) {
			return 1;
		}
478
		if (( cf->arg_type & ARGS_TYPES ) == ARG_STRING ) {
Howard Chu's avatar
Howard Chu committed
479
			ber_bvarray_add(&c->rvalue_vals, &bv);
480
		} else if ( !BER_BVISNULL( &bv ) ) {
Howard Chu's avatar
Howard Chu committed
481
			value_add_one(&c->rvalue_vals, &bv);
482
483
		}
		/* else: maybe c->rvalue_vals already set? */
Howard Chu's avatar
Howard Chu committed
484
485
486
487
	}
	return rc;
}

488
int
Howard Chu's avatar
Howard Chu committed
489
init_config_attrs(ConfigTable *ct) {
490
491
492
493
	int i, code;

	for (i=0; ct[i].name; i++ ) {
		if ( !ct[i].attribute ) continue;
494
		code = register_at( ct[i].attribute, &ct[i].ad, 1 );
495
		if ( code ) {
496
			fprintf( stderr, "init_config_attrs: register_at failed\n" );
497
			return code;
498
		}
499
	}
500
501

	return 0;
502
503
}

504
int
505
init_config_ocs( ConfigOCs *ocs ) {
506
	int i, code;
507

508
	for (i=0;ocs[i].co_def;i++) {
509
510
511
		code = register_oc( ocs[i].co_def, &ocs[i].co_oc, 1 );
		if ( code ) {
			fprintf( stderr, "init_config_ocs: register_oc failed\n" );
512
513
			return code;
		}
514
	}
515
516
517
	return 0;
}

518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
/* Split an LDIF line into space-separated tokens. Words may be grouped
 * by quotes. A quoted string may begin in the middle of a word, but must
 * end at the end of the word (be followed by whitespace or EOS). Any other
 * quotes are passed through unchanged. All other characters are passed
 * through unchanged.
 */
static char *
strtok_quote_ldif( char **line )
{
	char *beg, *ptr, *quote=NULL;
	int inquote=0;

	ptr = *line;

	if ( !ptr || !*ptr )
		return NULL;

535
	while( isspace( (unsigned char) *ptr )) ptr++;
536
537
538
539
540
541
542
543
544
545

	if ( *ptr == '"' ) {
		inquote = 1;
		ptr++;
	}

	beg = ptr;

	for (;*ptr;ptr++) {
		if ( *ptr == '"' ) {
546
			if ( inquote && ( !ptr[1] || isspace((unsigned char) ptr[1]))) {
547
548
549
550
551
552
553
554
555
				*ptr++ = '\0';
				break;
			}
			inquote = 1;
			quote = ptr;
			continue;
		}
		if ( inquote )
			continue;
556
		if ( isspace( (unsigned char) *ptr )) {
557
558
559
560
561
562
563
564
565
566
567
568
569
			*ptr++ = '\0';
			break;
		}
	}
	if ( quote ) {
		while ( quote < ptr ) {
			*quote = quote[1];
			quote++;
		}
	}
	if ( !*ptr ) {
		*line = NULL;
	} else {
570
		while ( isspace( (unsigned char) *ptr )) ptr++;
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
		*line = ptr;
	}
	return beg;
}

static void
config_parse_ldif( ConfigArgs *c )
{
	char *next;
	c->tline = ch_strdup(c->line);
	next = c->tline;

	while ((c->argv[c->argc] = strtok_quote_ldif( &next )) != NULL) {
		c->argc++;
		if ( c->argc >= c->argv_size ) {
			char **tmp = ch_realloc( c->argv, (c->argv_size + ARGS_STEP) *
				sizeof( *c->argv ));
			c->argv = tmp;
			c->argv_size += ARGS_STEP;
		}
	}
	c->argv[c->argc] = NULL;
}

Howard Chu's avatar
Howard Chu committed
595
596
597
int
config_parse_vals(ConfigTable *ct, ConfigArgs *c, int valx)
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
598
	int 	rc = 0;
Howard Chu's avatar
Howard Chu committed
599
600
601
602
603

	snprintf( c->log, sizeof( c->log ), "%s: value #%d",
		ct->ad->ad_cname.bv_val, valx );
	c->argc = 1;
	c->argv[0] = ct->ad->ad_cname.bv_val;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
604
605

	if ( ( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) {
606
607
608
609
		c->argv[c->argc] = c->line;
		c->argc++;
		c->argv[c->argc] = NULL;
		c->tline = NULL;
Howard Chu's avatar
Howard Chu committed
610
	} else {
611
		config_parse_ldif( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
612
	}
613
614
	rc = config_check_vals( ct, c, 1 );
	ch_free( c->tline );
615
	c->tline = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
616

Howard Chu's avatar
Howard Chu committed
617
618
	if ( rc )
		rc = LDAP_CONSTRAINT_VIOLATION;
Howard Chu's avatar
Howard Chu committed
619
620
621
622
623

	return rc;
}

int
624
config_parse_add(ConfigTable *ct, ConfigArgs *c, int valx)
Howard Chu's avatar
Howard Chu committed
625
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
626
	int	rc = 0;
Howard Chu's avatar
Howard Chu committed
627
628

	snprintf( c->log, sizeof( c->log ), "%s: value #%d",
629
		ct->ad->ad_cname.bv_val, valx );
Howard Chu's avatar
Howard Chu committed
630
631
	c->argc = 1;
	c->argv[0] = ct->ad->ad_cname.bv_val;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
632
633

	if ( ( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) {
634
635
636
637
		c->argv[c->argc] = c->line;
		c->argc++;
		c->argv[c->argc] = NULL;
		c->tline = NULL;
Howard Chu's avatar
Howard Chu committed
638
	} else {
639
		config_parse_ldif( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
640
	}
641
642
	c->op = LDAP_MOD_ADD;
	rc = config_add_vals( ct, c );
Howard Chu's avatar
Howard Chu committed
643
	ch_free( c->tline );
644

Howard Chu's avatar
Howard Chu committed
645
646
647
	return rc;
}

648
int
649
read_config_file(const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft)
650
651
{
	FILE *fp;
652
	ConfigTable *ct;
653
	ConfigArgs *c;
654
	int rc;
655
	struct stat s;
656

657
658
659
660
	c = ch_calloc( 1, sizeof( ConfigArgs ) );
	if ( c == NULL ) {
		return 1;
	}
661

662
663
	if ( depth ) {
		memcpy( c, cf, sizeof( ConfigArgs ) );
664
665
666
667
668
	} else {
		c->depth = depth; /* XXX */
		c->bi = NULL;
		c->be = NULL;
	}
669

670
	c->valx = -1;
671
	c->fname = fname;
Howard Chu's avatar
Howard Chu committed
672
	init_config_argv( c );
Gary Williams's avatar
Gary Williams committed
673

674
675
676
677
678
	if ( stat( fname, &s ) != 0 ) {
		ldap_syslog = 1;
		Debug(LDAP_DEBUG_ANY,
		    "could not stat config file \"%s\": %s (%d)\n",
		    fname, strerror(errno), errno);
Howard Chu's avatar
Howard Chu committed
679
		ch_free( c );
680
681
682
683
684
685
686
687
		return(1);
	}

	if ( !S_ISREG( s.st_mode ) ) {
		ldap_syslog = 1;
		Debug(LDAP_DEBUG_ANY,
		    "regular file expected, got \"%s\"\n",
		    fname, 0, 0 );
Howard Chu's avatar
Howard Chu committed
688
		ch_free( c );
689
690
691
		return(1);
	}

692
693
	fp = fopen( fname, "r" );
	if ( fp == NULL ) {
694
695
696
697
		ldap_syslog = 1;
		Debug(LDAP_DEBUG_ANY,
		    "could not open config file \"%s\": %s (%d)\n",
		    fname, strerror(errno), errno);
Howard Chu's avatar
Howard Chu committed
698
		ch_free( c );
699
700
		return(1);
	}
701

702
	Debug(LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0);
703

704
	fp_getline_init(c);
Gary Williams's avatar
Gary Williams committed
705

Howard Chu's avatar
Howard Chu committed
706
707
	c->tline = NULL;

708
	while ( fp_getline( fp, c ) ) {
709
		/* skip comments and blank lines */
710
711
712
		if ( c->line[0] == '#' || c->line[0] == '\0' ) {
			continue;
		}
713

714
		snprintf( c->log, sizeof( c->log ), "%s: line %d",
715
716
				c->fname, c->lineno );

717
		c->argc = 0;
Howard Chu's avatar
Howard Chu committed
718
		ch_free( c->tline );
719
		if ( fp_parse_line( c ) ) {
Howard Chu's avatar
Howard Chu committed
720
			rc = 1;
721
			goto done;
722
		}
723

724
		if ( c->argc < 1 ) {
725
			Debug( LDAP_DEBUG_ANY, "%s: bad config line.\n",
726
727
				c->log, 0, 0);
			rc = 1;
728
			goto done;
729
		}
Gary Williams's avatar
Gary Williams committed
730

Howard Chu's avatar
Howard Chu committed
731
		c->op = SLAP_CONFIG_ADD;
732

733
		ct = config_find_keyword( cft, c );
734
		if ( ct ) {
735
			c->table = Cft_Global;
736
737
738
739
740
741
742
			rc = config_add_vals( ct, c );
			if ( !rc ) continue;

			if ( rc & ARGS_USERLAND ) {
				/* XXX a usertype would be opaque here */
				Debug(LDAP_DEBUG_CONFIG, "%s: unknown user type <%s>\n",
					c->log, c->argv[0], 0);
Howard Chu's avatar
Howard Chu committed
743
				rc = 1;
744
				goto done;
745

746
			} else if ( rc == ARG_BAD_CONF ) {
Howard Chu's avatar
Howard Chu committed
747
				rc = 1;
748
				goto done;
749
			}
750
			
751
		} else if ( c->bi && !c->be ) {
752
			rc = SLAP_CONF_UNKNOWN;
753
			if ( c->bi->bi_cf_ocs ) {
754
				ct = config_find_keyword( c->bi->bi_cf_ocs->co_table, c );
755
				if ( ct ) {
756
					c->table = c->bi->bi_cf_ocs->co_type;
757
758
					rc = config_add_vals( ct, c );
				}
759
760
			}
			if ( c->bi->bi_config && rc == SLAP_CONF_UNKNOWN ) {
761
762
763
				rc = (*c->bi->bi_config)(c->bi, c->fname, c->lineno,
					c->argc, c->argv);
			}
764
765
			if ( rc ) {
				switch(rc) {
766
				case SLAP_CONF_UNKNOWN:
767
768
					Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
						"<%s> inside backend info definition.\n",
769
						c->log, *c->argv, 0);
770
				default:
Howard Chu's avatar
Howard Chu committed
771
					rc = 1;
772
					goto done;
773
				}
774
			}
775

776
		} else if ( c->be && c->be != frontendDB ) {
777
			rc = SLAP_CONF_UNKNOWN;
778
779
			if ( c->be->be_cf_ocs ) {
				ct = config_find_keyword( c->be->be_cf_ocs->co_table, c );
780
				if ( ct ) {
781
					c->table = c->be->be_cf_ocs->co_type;
782
783
					rc = config_add_vals( ct, c );
				}
784
785
			}
			if ( c->be->be_config && rc == SLAP_CONF_UNKNOWN ) {
Howard Chu's avatar
Howard Chu committed
786
787
				rc = (*c->be->be_config)(c->be, c->fname, c->lineno,
					c->argc, c->argv);
788
			}
789
790
			if ( rc == SLAP_CONF_UNKNOWN && SLAP_ISGLOBALOVERLAY( frontendDB ) )
			{
791
792
793
				/* global overlays may need 
				 * definitions inside other databases...
				 */
794
795
				rc = (*frontendDB->be_config)( frontendDB,
					c->fname, (int)c->lineno, c->argc, c->argv );
796
797
798
799
800
801
802
			}

			switch ( rc ) {
			case 0:
				break;

			case SLAP_CONF_UNKNOWN:
803
804
				Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
					"<%s> inside backend database definition.\n",
805
806
807
808
809
					c->log, *c->argv, 0);
				
			default:
				rc = 1;
				goto done;
810
			}
811
812

		} else if ( frontendDB->be_config ) {
813
814
			rc = (*frontendDB->be_config)( frontendDB,
				c->fname, (int)c->lineno, c->argc, c->argv);
815
816
			if ( rc ) {
				switch(rc) {
817
				case SLAP_CONF_UNKNOWN:
818
819
					Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
						"<%s> inside global database definition.\n",
820
						c->log, *c->argv, 0);
821

822
				default:
Howard Chu's avatar
Howard Chu committed
823
					rc = 1;
824
					goto done;
825
				}
826
			}
827
			
828
		} else {
829
830
			Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
				"<%s> outside backend info and database definitions.\n",
831
832
				c->log, *c->argv, 0);
			rc = 1;
833
			goto done;
834
835
		}
	}