config.c 53.4 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-2009 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>
Howard Chu's avatar
Howard Chu committed
36
#include <ac/unistd.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
37

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

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

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

53
#define ARGS_STEP	512
Kurt Zeilenga's avatar
Kurt Zeilenga committed
54
55
56
57

/*
 * defaults for various global variables
 */
58
59
60
61
slap_mask_t		global_allows = 0;
slap_mask_t		global_disallows = 0;
int		global_gentlehup = 0;
int		global_idletimeout = 0;
62
int		global_writetimeout = 0;
63
char	*global_host = NULL;
64
struct berval global_host_bv = BER_BVNULL;
65
char	*global_realm = NULL;
66
char	*sasl_host = NULL;
67
68
69
70
71
72
73
74
75
76
77
78
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;
79

80
81
82
83
84
85
int use_reverse_lookup = 0;

#ifdef LDAP_SLAPI
int slapi_plugins_used = 0;
#endif

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

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

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

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

114
115
116
117
118
119
120
121
122
123
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
124
int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) {
125
	int rc, arg_user, arg_type, arg_syn, iarg;
126
	unsigned uiarg;
127
	long larg;
128
	unsigned long ularg;
129
	ber_len_t barg;
Howard Chu's avatar
Howard Chu committed
130
	
131
	if(Conf->arg_type == ARG_IGNORED) {
132
		Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
133
			c->log, Conf->name, 0);
134
		return(0);
135
	}
136
137
138
139
140
	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
141
142
143
		c->argc = 2;
		c->argv[1] = "";
	}
144
	if(Conf->min_args && (c->argc < Conf->min_args)) {
145
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> missing <%s> argument",
Howard Chu's avatar
Howard Chu committed
146
			c->argv[0], Conf->what ? Conf->what : "" );
147
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n", c->log, c->cr_msg, 0 );
148
		return(ARG_BAD_CONF);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
149
	}
150
	if(Conf->max_args && (c->argc > Conf->max_args)) {
151
152
		char	*ignored = " ignored";

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

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

int config_set_vals(ConfigTable *Conf, ConfigArgs *c) {
327
	int rc, arg_type;
Howard Chu's avatar
Howard Chu committed
328
	void *ptr = NULL;
Howard Chu's avatar
Howard Chu committed
329
330

	arg_type = Conf->arg_type;
331
332
	if(arg_type & ARG_MAGIC) {
		if(!c->be) c->be = frontendDB;
333
		c->cr_msg[0] = '\0';
334
		rc = (*((ConfigDriver*)Conf->arg_item))(c);
Howard Chu's avatar
Howard Chu committed
335
#if 0
336
		if(c->be == frontendDB) c->be = NULL;
Howard Chu's avatar
Howard Chu committed
337
#endif
338
		if(rc) {
339
340
			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
341
342
					c->argv[0], rc );
				Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n",
343
					c->log, c->cr_msg, 0 );
Howard Chu's avatar
Howard Chu committed
344
			}
345
			return(ARG_BAD_CONF);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
346
		}
347
348
		return(0);
	}
349
	if(arg_type & ARG_OFFSET) {
350
		if (c->be && c->table == Cft_Database)
351
352
353
354
			ptr = c->be->be_private;
		else if (c->bi)
			ptr = c->bi->bi_private;
		else {
355
			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> offset is missing base pointer",
Howard Chu's avatar
Howard Chu committed
356
357
				c->argv[0] );
			Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n",
358
				c->log, c->cr_msg, 0);
359
360
			return(ARG_BAD_CONF);
		}
361
		ptr = (void *)((char *)ptr + (long)Conf->arg_item);
362
	} else if (arg_type & ARGS_TYPES) {
363
		ptr = Conf->arg_item;
364
	}
365
366
	if(arg_type & ARGS_TYPES)
		switch(arg_type & ARGS_TYPES) {
367
			case ARG_ON_OFF:
Howard Chu's avatar
Howard Chu committed
368
			case ARG_INT: 		*(int*)ptr = c->value_int;			break;
369
			case ARG_UINT: 		*(unsigned*)ptr = c->value_uint;			break;
Howard Chu's avatar
Howard Chu committed
370
			case ARG_LONG:  	*(long*)ptr = c->value_long;			break;
371
			case ARG_ULONG:  	*(unsigned long*)ptr = c->value_ulong;			break;
Howard Chu's avatar
Howard Chu committed
372
			case ARG_BER_LEN_T: 	*(ber_len_t*)ptr = c->value_ber_t;			break;
373
			case ARG_STRING: {
374
				char *cc = *(char**)ptr;
375
				if(cc) {
Howard Chu's avatar
Howard Chu committed
376
					if ((arg_type & ARG_UNIQUE) && c->op == SLAP_CONFIG_ADD ) {
377
						Debug(LDAP_DEBUG_CONFIG, "%s: already set %s!\n",
378
							c->log, Conf->name, 0 );
379
380
						return(ARG_BAD_CONF);
					}
Howard Chu's avatar
Howard Chu committed
381
					ch_free(cc);
382
				}
383
				*(char **)ptr = c->value_string;
384
385
				break;
				}
386
387
388
			case ARG_BERVAL:
				*(struct berval *)ptr = c->value_bv;
				break;
389
390
391
			case ARG_ATDESC:
				*(AttributeDescription **)ptr = c->value_ad;
				break;
392
		}
Howard Chu's avatar
Howard Chu committed
393
394
395
396
	return(0);
}

int config_add_vals(ConfigTable *Conf, ConfigArgs *c) {
397
	int rc, arg_type;
Howard Chu's avatar
Howard Chu committed
398
399
400
401
402
403
404
405
406
407

	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 );
408
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
409

410
411
412
413
int
config_del_vals(ConfigTable *cf, ConfigArgs *c)
{
	int rc = 0;
414

415
416
417
418
419
420
	/* 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);
	}
421
	return rc;
422
423
}

Howard Chu's avatar
Howard Chu committed
424
425
426
427
428
int
config_get_vals(ConfigTable *cf, ConfigArgs *c)
{
	int rc = 0;
	struct berval bv;
429
	void *ptr;
Howard Chu's avatar
Howard Chu committed
430
431
432
433
434

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

Howard Chu's avatar
Howard Chu committed
435
	memset(&c->values, 0, sizeof(c->values));
436
	c->rvalue_vals = NULL;
Howard Chu's avatar
Howard Chu committed
437
	c->rvalue_nvals = NULL;
438
	c->op = SLAP_CONFIG_EMIT;
Howard Chu's avatar
Howard Chu committed
439
440
	c->type = cf->arg_type & ARGS_USERLAND;

Howard Chu's avatar
Howard Chu committed
441
442
443
444
	if ( cf->arg_type & ARG_MAGIC ) {
		rc = (*((ConfigDriver*)cf->arg_item))(c);
		if ( rc ) return rc;
	} else {
445
		if ( cf->arg_type & ARG_OFFSET ) {
446
			if (c->be && c->table == Cft_Database)
447
448
449
450
451
				ptr = c->be->be_private;
			else if ( c->bi )
				ptr = c->bi->bi_private;
			else
				return 1;
452
			ptr = (void *)((char *)ptr + (long)cf->arg_item);
453
454
455
456
		} else {
			ptr = cf->arg_item;
		}
		
457
		switch(cf->arg_type & ARGS_TYPES) {
Howard Chu's avatar
Howard Chu committed
458
		case ARG_ON_OFF:
459
		case ARG_INT:	c->value_int = *(int *)ptr; break;
460
		case ARG_UINT:	c->value_uint = *(unsigned *)ptr; break;
461
		case ARG_LONG:	c->value_long = *(long *)ptr; break;
462
		case ARG_ULONG:	c->value_ulong = *(unsigned long *)ptr; break;
463
		case ARG_BER_LEN_T:	c->value_ber_t = *(ber_len_t *)ptr; break;
Howard Chu's avatar
Howard Chu committed
464
		case ARG_STRING:
465
466
			if ( *(char **)ptr )
				c->value_string = ch_strdup(*(char **)ptr);
Howard Chu's avatar
Howard Chu committed
467
			break;
468
469
		case ARG_BERVAL:
			ber_dupbv( &c->value_bv, (struct berval *)ptr ); break;
470
471
		case ARG_ATDESC:
			c->value_ad = *(AttributeDescription **)ptr; break;
Howard Chu's avatar
Howard Chu committed
472
473
		}
	}
474
	if ( cf->arg_type & ARGS_TYPES) {
Howard Chu's avatar
Howard Chu committed
475
		bv.bv_len = 0;
Howard Chu's avatar
Howard Chu committed
476
		bv.bv_val = c->log;
477
		switch(cf->arg_type & ARGS_TYPES) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
478
		case ARG_INT: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%d", c->value_int); break;
479
		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
480
		case ARG_LONG: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%ld", c->value_long); break;
Howard Chu's avatar
Howard Chu committed
481
		case ARG_ULONG: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%lu", c->value_ulong); break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
482
483
		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
484
			c->value_int ? "TRUE" : "FALSE"); break;
485
486
487
488
		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
489
				return 1;
490
491
			}
			break;
492
493
494
495
496
497
498
		case ARG_BERVAL:
			if ( !BER_BVISEMPTY( &c->value_bv )) {
				bv = c->value_bv;
			} else {
				return 1;
			}
			break;
499
500
501
502
503
504
505
		case ARG_ATDESC:
			if ( c->value_ad ) {
				bv = c->value_ad->ad_cname;
			} else {
				return 1;
			}
			break;
506
507
508
		default:
			bv.bv_val = NULL;
			break;
Howard Chu's avatar
Howard Chu committed
509
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
510
511
512
		if (bv.bv_val == c->log && bv.bv_len >= sizeof( c->log ) ) {
			return 1;
		}
513
		if (( cf->arg_type & ARGS_TYPES ) == ARG_STRING ) {
Howard Chu's avatar
Howard Chu committed
514
			ber_bvarray_add(&c->rvalue_vals, &bv);
515
		} else if ( !BER_BVISNULL( &bv ) ) {
Howard Chu's avatar
Howard Chu committed
516
			value_add_one(&c->rvalue_vals, &bv);
517
518
		}
		/* else: maybe c->rvalue_vals already set? */
Howard Chu's avatar
Howard Chu committed
519
520
521
522
	}
	return rc;
}

523
int
Howard Chu's avatar
Howard Chu committed
524
init_config_attrs(ConfigTable *ct) {
525
526
527
528
	int i, code;

	for (i=0; ct[i].name; i++ ) {
		if ( !ct[i].attribute ) continue;
529
		code = register_at( ct[i].attribute, &ct[i].ad, 1 );
530
		if ( code ) {
531
			fprintf( stderr, "init_config_attrs: register_at failed\n" );
532
			return code;
533
		}
534
	}
535
536

	return 0;
537
538
}

539
int
540
init_config_ocs( ConfigOCs *ocs ) {
541
	int i, code;
542

543
	for (i=0;ocs[i].co_def;i++) {
544
545
546
		code = register_oc( ocs[i].co_def, &ocs[i].co_oc, 1 );
		if ( code ) {
			fprintf( stderr, "init_config_ocs: register_oc failed\n" );
547
548
			return code;
		}
549
	}
550
551
552
	return 0;
}

553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
/* 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;

570
	while( isspace( (unsigned char) *ptr )) ptr++;
571
572
573
574
575
576
577
578
579
580

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

	beg = ptr;

	for (;*ptr;ptr++) {
		if ( *ptr == '"' ) {
581
			if ( inquote && ( !ptr[1] || isspace((unsigned char) ptr[1]))) {
582
583
584
585
586
587
588
589
590
				*ptr++ = '\0';
				break;
			}
			inquote = 1;
			quote = ptr;
			continue;
		}
		if ( inquote )
			continue;
591
		if ( isspace( (unsigned char) *ptr )) {
592
593
594
595
596
597
598
599
600
601
602
603
604
			*ptr++ = '\0';
			break;
		}
	}
	if ( quote ) {
		while ( quote < ptr ) {
			*quote = quote[1];
			quote++;
		}
	}
	if ( !*ptr ) {
		*line = NULL;
	} else {
605
		while ( isspace( (unsigned char) *ptr )) ptr++;
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
		*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
630
631
632
int
config_parse_vals(ConfigTable *ct, ConfigArgs *c, int valx)
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
633
	int 	rc = 0;
Howard Chu's avatar
Howard Chu committed
634
635
636
637
638

	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
639
640

	if ( ( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) {
641
642
643
644
		c->argv[c->argc] = c->line;
		c->argc++;
		c->argv[c->argc] = NULL;
		c->tline = NULL;
Howard Chu's avatar
Howard Chu committed
645
	} else {
646
		config_parse_ldif( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
647
	}
648
649
	rc = config_check_vals( ct, c, 1 );
	ch_free( c->tline );
650
	c->tline = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
651

Howard Chu's avatar
Howard Chu committed
652
653
	if ( rc )
		rc = LDAP_CONSTRAINT_VIOLATION;
Howard Chu's avatar
Howard Chu committed
654
655
656
657
658

	return rc;
}

int
659
config_parse_add(ConfigTable *ct, ConfigArgs *c, int valx)
Howard Chu's avatar
Howard Chu committed
660
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
661
	int	rc = 0;
Howard Chu's avatar
Howard Chu committed
662
663

	snprintf( c->log, sizeof( c->log ), "%s: value #%d",
664
		ct->ad->ad_cname.bv_val, valx );
Howard Chu's avatar
Howard Chu committed
665
666
	c->argc = 1;
	c->argv[0] = ct->ad->ad_cname.bv_val;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
667
668

	if ( ( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) {
669
670
671
672
		c->argv[c->argc] = c->line;
		c->argc++;
		c->argv[c->argc] = NULL;
		c->tline = NULL;
Howard Chu's avatar
Howard Chu committed
673
	} else {
674
		config_parse_ldif( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
675
	}
676
677
	c->op = LDAP_MOD_ADD;
	rc = config_add_vals( ct, c );
Howard Chu's avatar
Howard Chu committed
678
	ch_free( c->tline );
679

Howard Chu's avatar
Howard Chu committed
680
681
682
	return rc;
}

683
int
684
read_config_file(const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft)
685
686
{
	FILE *fp;
687
	ConfigTable *ct;
688
	ConfigArgs *c;
689
	int rc;
690
	struct stat s;
691

Howard Chu's avatar
Howard Chu committed
692
693
694
695
	c = ch_calloc( 1, sizeof( ConfigArgs ) );
	if ( c == NULL ) {
		return 1;
	}
696

Howard Chu's avatar
Howard Chu committed
697
698
699
700
701
702
	if ( depth ) {
		memcpy( c, cf, sizeof( ConfigArgs ) );
	} else {
		c->depth = depth; /* XXX */
		c->bi = NULL;
		c->be = NULL;
703
	}
Gary Williams's avatar
Gary Williams committed
704

Howard Chu's avatar
Howard Chu committed
705
706
707
708
	c->valx = -1;
	c->fname = fname;
	init_config_argv( c );

709
710
711
712
713
	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
714
		ch_free( c );
715
716
717
718
719
720
721
722
		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
723
		ch_free( c );
724
725
726
		return(1);
	}

727
728
	fp = fopen( fname, "r" );
	if ( fp == NULL ) {
729
730
731
732
		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
733
		ch_free( c );
734
735
		return(1);
	}
736

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

739
	fp_getline_init(c);
Gary Williams's avatar
Gary Williams committed
740

Howard Chu's avatar
Howard Chu committed
741
742
	c->tline = NULL;

743
	while ( fp_getline( fp, c ) ) {
744
		/* skip comments and blank lines */
745
746
747
		if ( c->line[0] == '#' || c->line[0] == '\0' ) {
			continue;
		}
748

749
		snprintf( c->log, sizeof( c->log ), "%s: line %d",
750
751
				c->fname, c->lineno );

752
		c->argc = 0;
Howard Chu's avatar
Howard Chu committed
753
		ch_free( c->tline );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
754
		if ( config_fp_parse_line( c ) ) {
Howard Chu's avatar
Howard Chu committed
755
			rc = 1;
756
			goto done;
757
		}
758

759
		if ( c->argc < 1 ) {
760
			Debug( LDAP_DEBUG_ANY, "%s: bad config line.\n",
761
762
				c->log, 0, 0);
			rc = 1;
763
			goto done;
764
		}
Gary Williams's avatar
Gary Williams committed
765

Howard Chu's avatar
Howard Chu committed
766
		c->op = SLAP_CONFIG_ADD;
767

768
		ct = config_find_keyword( cft, c );
769
		if ( ct ) {
770
			c->table = Cft_Global;
771
772
773
774
775
776
777
			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
778
				rc = 1;
779
				goto done;
780

781
			} else if ( rc == ARG_BAD_CONF ) {
Howard Chu's avatar
Howard Chu committed
782
				rc = 1;
783
				goto done;
784
			}
785
			
786
		} else if ( c->bi && !c->be ) {
787
			rc = SLAP_CONF_UNKNOWN;
788
			if ( c->bi->bi_cf_ocs ) {
789
				ct = config_find_keyword( c->bi->bi_cf_ocs->co_table, c );
790
				if ( ct ) {
791
					c->table = c->bi->bi_cf_ocs->co_type;
792
793
					rc = config_add_vals( ct, c );
				}
794
795
			}
			if ( c->bi->bi_config && rc == SLAP_CONF_UNKNOWN ) {
796
797
798
				rc = (*c->bi->bi_config)(c->bi, c->fname, c->lineno,
					c->argc, c->argv);
			}
799
800
			if ( rc ) {
				switch(rc) {
801
				case SLAP_CONF_UNKNOWN:
802
803
					Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
						"<%s> inside backend info definition.\n",
804
						c->log, *c->argv, 0);
805
				default:
Howard Chu's avatar
Howard Chu committed
806
					rc = 1;
807
					goto done;
808
				}
809
			}
810

811
		} else if ( c->be && c->be != frontendDB ) {
812
			rc = SLAP_CONF_UNKNOWN;
813
814
			if ( c->be->be_cf_ocs ) {
				ct = config_find_keyword( c->be->be_cf_ocs->co_table, c );
815
				if ( ct ) {
816
					c->table = c->be->be_cf_ocs->co_type;
817
818
					rc = config_add_vals( ct, c );
				}
819
820
			}
			if ( c->be->be_config && rc == SLAP_CONF_UNKNOWN ) {
Howard Chu's avatar
Howard Chu committed
821
822
				rc = (*c->be->be_config)(c->be, c->fname, c->lineno,
					c->argc, c->argv);
823
			}
824
825
			if ( rc == SLAP_CONF_UNKNOWN && SLAP_ISGLOBALOVERLAY( frontendDB ) )
			{
826
827
828
				/* global overlays may need 
				 * definitions inside other databases...
				 */
829
830
				rc = (*frontendDB->be_config)( frontendDB,
					c->fname, (int)c->lineno, c->argc, c->argv );
831
832
833
834
835
836
837
			}

			switch ( rc ) {
			case 0:
				break;

			case SLAP_CONF_UNKNOWN:
838
839
				Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
					"<%s> inside backend database definition.\n",
840
841
842
843
844
					c->log, *c->argv, 0);
				
			default:
				rc = 1;
				goto done;
Howard Chu's avatar
<