config.c 61 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/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 1998-2020 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 "ldif.h"
52
#include "config.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
53

Howard Chu's avatar
Howard Chu committed
54
55
56
57
58
59
60
61
#ifdef _WIN32
#define	LUTIL_ATOULX	lutil_atoullx
#define	Z	"I"
#else
#define	LUTIL_ATOULX	lutil_atoulx
#define	Z	"z"
#endif

62
#define ARGS_STEP	512
Kurt Zeilenga's avatar
Kurt Zeilenga committed
63
64
65
66

/*
 * defaults for various global variables
 */
67
68
69
70
slap_mask_t		global_allows = 0;
slap_mask_t		global_disallows = 0;
int		global_gentlehup = 0;
int		global_idletimeout = 0;
71
int		global_writetimeout = 0;
72
char	*global_host = NULL;
73
struct berval global_host_bv = BER_BVNULL;
74
char	*global_realm = NULL;
75
char	*sasl_host = NULL;
76
char	*sasl_cbinding = NULL;
77
78
79
80
81
82
83
84
85
86
87
88
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;
89

90
91
92
93
94
95
int use_reverse_lookup = 0;

#ifdef LDAP_SLAPI
int slapi_plugins_used = 0;
#endif

96
97
static int fp_getline(FILE *fp, ConfigArgs *c);
static void fp_getline_init(ConfigArgs *c);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
98

99
static char	*strtok_quote(char *line, char *sep, char **quote_ptr, int *inquote);
100
static char *strtok_quote_ldif(char **line);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
101

102
ConfigArgs *
103
104
new_config_args( BackendDB *be, const char *fname, int lineno, int argc, char **argv )
{
105
	ConfigArgs *c;
106
107
	c = ch_calloc( 1, sizeof( ConfigArgs ) );
	if ( c == NULL ) return(NULL);
108
109
110
111
112
	c->be     = be; 
	c->fname  = fname;
	c->argc   = argc;
	c->argv   = argv; 
	c->lineno = lineno;
113
	snprintf( c->log, sizeof( c->log ), "%s: line %d", fname, lineno );
114
115
	return(c);
}
116

Howard Chu's avatar
Howard Chu committed
117
118
119
120
121
122
123
void
init_config_argv( ConfigArgs *c )
{
	c->argv = ch_calloc( ARGS_STEP + 1, sizeof( *c->argv ) );
	c->argv_size = ARGS_STEP + 1;
}

124
125
126
127
128
129
130
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;
131
132
133
134
135
136
137
138
139
140
141
142
143
	if (( Conf[i].arg_type & ARGS_TYPES ) == ARG_BINARY ) {
		size_t decode_len = LUTIL_BASE64_DECODE_LEN(c->linelen);
		ch_free( c->tline );
		c->tline = ch_malloc( decode_len+1 );
		c->linelen = lutil_b64_pton( c->line, c->tline, decode_len );
		if ( c->linelen < 0 )
		{
			ch_free( c->tline );
			c->tline = NULL;
			return NULL;
		}
		c->line = c->tline;
	}
144
145
146
	return Conf+i;
}

Howard Chu's avatar
Howard Chu committed
147
int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) {
148
	int rc, arg_user, arg_type, arg_syn, iarg;
149
	unsigned uiarg;
150
	long larg;
Howard Chu's avatar
Howard Chu committed
151
	size_t ularg;
152
	ber_len_t barg;
Howard Chu's avatar
Howard Chu committed
153
	
154
	if(Conf->arg_type == ARG_IGNORED) {
155
		Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
156
			c->log, Conf->name );
157
		return(0);
158
	}
159
160
161
162
163
	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
164
165
166
		c->argc = 2;
		c->argv[1] = "";
	}
167
	if(Conf->min_args && (c->argc < Conf->min_args)) {
168
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> missing <%s> argument",
Howard Chu's avatar
Howard Chu committed
169
			c->argv[0], Conf->what ? Conf->what : "" );
170
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n", c->log, c->cr_msg );
171
		return(ARG_BAD_CONF);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172
	}
173
	if(Conf->max_args && (c->argc > Conf->max_args)) {
174
175
		char	*ignored = " ignored";

176
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> extra cruft after <%s>",
Howard Chu's avatar
Howard Chu committed
177
			c->argv[0], Conf->what );
178
179

		ignored = "";
180
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s%s.\n",
181
				c->log, c->cr_msg, ignored );
182
		return(ARG_BAD_CONF);
183
	}
184
	if((arg_syn & ARG_DB) && !c->be) {
185
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> only allowed within database declaration",
Howard Chu's avatar
Howard Chu committed
186
			c->argv[0] );
187
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
188
			c->log, c->cr_msg );
189
190
		return(ARG_BAD_CONF);
	}
191
	if((arg_syn & ARG_PRE_BI) && c->bi) {
192
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must occur before any backend %sdeclaration",
193
			c->argv[0], (arg_syn & ARG_PRE_DB) ? "or database " : "" );
194
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
195
			c->log, c->cr_msg );
196
197
		return(ARG_BAD_CONF);
	}
198
	if((arg_syn & ARG_PRE_DB) && c->be && c->be != frontendDB) {
199
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must occur before any database declaration",
Howard Chu's avatar
Howard Chu committed
200
			c->argv[0] );
201
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
202
			c->log, c->cr_msg );
203
204
		return(ARG_BAD_CONF);
	}
205
	if((arg_syn & ARG_PAREN) && *c->argv[1] != '(' /*')'*/) {
206
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> old format not supported", c->argv[0] );
207
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
208
			c->log, c->cr_msg );
209
210
		return(ARG_BAD_CONF);
	}
211
	if(arg_type && !Conf->arg_item && !(arg_syn & ARG_OFFSET)) {
212
		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid config_table, arg_item is NULL",
Howard Chu's avatar
Howard Chu committed
213
			c->argv[0] );
214
		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
215
			c->log, c->cr_msg );
216
217
		return(ARG_BAD_CONF);
	}
218
	c->type = arg_user;
Howard Chu's avatar
Howard Chu committed
219
	memset(&c->values, 0, sizeof(c->values));
220
	if(arg_type == ARG_STRING) {
221
		assert( c->argc == 2 );
222
223
224
		if ( !check_only )
			c->value_string = ch_strdup(c->argv[1]);
	} else if(arg_type == ARG_BERVAL) {
225
		assert( c->argc == 2 );
226
227
		if ( !check_only )
			ber_str2bv( c->argv[1], 0, 1, &c->value_bv );
228
229
230
231
232
233
234
	} else if(arg_type == ARG_BINARY) {
		assert( c->argc == 2 );
		if ( !check_only ) {
			c->value_bv.bv_len = c->linelen;
			c->value_bv.bv_val = ch_malloc( c->linelen );
			AC_MEMCPY( c->value_bv.bv_val, c->line, c->linelen );
		}
235
236
	} else if(arg_type == ARG_DN) {
		struct berval bv;
237
		assert( c->argc == 2 );
238
239
240
		ber_str2bv( c->argv[1], 0, 0, &bv );
		rc = dnPrettyNormal( NULL, &bv, &c->value_dn, &c->value_ndn, NULL );
		if ( rc != LDAP_SUCCESS ) {
241
			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid DN %d (%s)",
242
				c->argv[0], rc, ldap_err2string( rc ));
243
			Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n" , c->log, c->cr_msg );
244
245
246
247
248
249
			return(ARG_BAD_CONF);
		}
		if ( check_only ) {
			ch_free( c->value_ndn.bv_val );
			ch_free( c->value_dn.bv_val );
		}
250
251
	} else if(arg_type == ARG_ATDESC) {
		const char *text = NULL;
252
		assert( c->argc == 2 );
253
254
255
256
257
		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 );
258
			Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n" , c->log, c->cr_msg );
259
260
			return(ARG_BAD_CONF);
		}
261
	} else {	/* all numeric */
Howard Chu's avatar
Howard Chu committed
262
		int j;
263
		iarg = 0; larg = 0; barg = 0;
264
		switch(arg_type) {
265
			case ARG_INT:
266
				assert( c->argc == 2 );
267
				if ( lutil_atoix( &iarg, c->argv[1], 0 ) != 0 ) {
268
					snprintf( c->cr_msg, sizeof( c->cr_msg ),
269
270
						"<%s> unable to parse \"%s\" as int",
						c->argv[0], c->argv[1] );
271
					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
272
						c->log, c->cr_msg );
273
274
275
					return(ARG_BAD_CONF);
				}
				break;
276
			case ARG_UINT:
277
				assert( c->argc == 2 );
278
279
280
281
282
				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",
283
						c->log, c->cr_msg );
284
285
286
					return(ARG_BAD_CONF);
				}
				break;
287
			case ARG_LONG:
288
				assert( c->argc == 2 );
289
				if ( lutil_atolx( &larg, c->argv[1], 0 ) != 0 ) {
290
					snprintf( c->cr_msg, sizeof( c->cr_msg ),
291
292
						"<%s> unable to parse \"%s\" as long",
						c->argv[0], c->argv[1] );
293
					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
294
						c->log, c->cr_msg );
295
296
297
					return(ARG_BAD_CONF);
				}
				break;
298
			case ARG_ULONG:
299
				assert( c->argc == 2 );
Howard Chu's avatar
Howard Chu committed
300
				if ( LUTIL_ATOULX( &ularg, c->argv[1], 0 ) != 0 ) {
301
302
303
304
					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",
305
						c->log, c->cr_msg );
306
307
308
					return(ARG_BAD_CONF);
				}
				break;
309
310
			case ARG_BER_LEN_T: {
				unsigned long	l;
311
				assert( c->argc == 2 );
312
				if ( lutil_atoulx( &l, c->argv[1], 0 ) != 0 ) {
313
					snprintf( c->cr_msg, sizeof( c->cr_msg ),
314
315
						"<%s> unable to parse \"%s\" as ber_len_t",
						c->argv[0], c->argv[1] );
316
					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
317
						c->log, c->cr_msg );
318
319
320
321
					return(ARG_BAD_CONF);
				}
				barg = (ber_len_t)l;
				} break;
322
			case ARG_ON_OFF:
323
324
				/* note: this is an explicit exception
				 * to the "need exactly 2 args" rule */
325
				if (c->argc == 1) {
326
					iarg = 1;
327
				} else if ( !strcasecmp(c->argv[1], "on") ||
328
					!strcasecmp(c->argv[1], "true") ||
329
					!strcasecmp(c->argv[1], "yes") )
330
				{
331
					iarg = 1;
332
				} else if ( !strcasecmp(c->argv[1], "off") ||
333
					!strcasecmp(c->argv[1], "false") ||
334
					!strcasecmp(c->argv[1], "no") )
335
				{
336
337
					iarg = 0;
				} else {
338
					snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value",
Howard Chu's avatar
Howard Chu committed
339
						c->argv[0] );
340
					Debug(LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n",
341
						c->log, c->cr_msg );
342
					return(ARG_BAD_CONF);
343
344
				}
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
345
		}
Howard Chu's avatar
Howard Chu committed
346
		j = (arg_type & ARG_NONZERO) ? 1 : 0;
347
348
		if(iarg < j && larg < j && barg < (unsigned)j ) {
			larg = larg ? larg : (barg ? (long)barg : iarg);
349
			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value",
Howard Chu's avatar
Howard Chu committed
350
				c->argv[0] );
351
			Debug(LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n",
352
				c->log, c->cr_msg );
353
			return(ARG_BAD_CONF);
354
		}
355
		switch(arg_type) {
Howard Chu's avatar
Howard Chu committed
356
357
			case ARG_ON_OFF:
			case ARG_INT:		c->value_int = iarg;		break;
358
			case ARG_UINT:		c->value_uint = uiarg;		break;
Howard Chu's avatar
Howard Chu committed
359
			case ARG_LONG:		c->value_long = larg;		break;
360
			case ARG_ULONG:		c->value_ulong = ularg;		break;
Howard Chu's avatar
Howard Chu committed
361
362
			case ARG_BER_LEN_T:	c->value_ber_t = barg;		break;
		}
363
	}
Howard Chu's avatar
Howard Chu committed
364
365
366
367
	return 0;
}

int config_set_vals(ConfigTable *Conf, ConfigArgs *c) {
368
	int rc, arg_type;
Howard Chu's avatar
Howard Chu committed
369
	void *ptr = NULL;
Howard Chu's avatar
Howard Chu committed
370
371

	arg_type = Conf->arg_type;
372
373
	if(arg_type & ARG_MAGIC) {
		if(!c->be) c->be = frontendDB;
374
		c->cr_msg[0] = '\0';
375
		rc = (*((ConfigDriver*)Conf->arg_item))(c);
Howard Chu's avatar
Howard Chu committed
376
#if 0
377
		if(c->be == frontendDB) c->be = NULL;
Howard Chu's avatar
Howard Chu committed
378
#endif
379
		if(rc) {
380
381
			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
382
383
					c->argv[0], rc );
				Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n",
384
					c->log, c->cr_msg );
Howard Chu's avatar
Howard Chu committed
385
			}
386
			return(ARG_BAD_CONF);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
387
		}
388
389
		return(0);
	}
390
	if(arg_type & ARG_OFFSET) {
391
		if (c->be && c->table == Cft_Database)
392
393
394
395
			ptr = c->be->be_private;
		else if (c->bi)
			ptr = c->bi->bi_private;
		else {
396
			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> offset is missing base pointer",
Howard Chu's avatar
Howard Chu committed
397
398
				c->argv[0] );
			Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n",
399
				c->log, c->cr_msg );
400
401
			return(ARG_BAD_CONF);
		}
402
		ptr = (void *)((char *)ptr + (long)Conf->arg_item);
403
	} else if (arg_type & ARGS_TYPES) {
404
		ptr = Conf->arg_item;
405
	}
406
407
	if(arg_type & ARGS_TYPES)
		switch(arg_type & ARGS_TYPES) {
408
			case ARG_ON_OFF:
Howard Chu's avatar
Howard Chu committed
409
			case ARG_INT: 		*(int*)ptr = c->value_int;			break;
410
			case ARG_UINT: 		*(unsigned*)ptr = c->value_uint;			break;
Howard Chu's avatar
Howard Chu committed
411
			case ARG_LONG:  	*(long*)ptr = c->value_long;			break;
Howard Chu's avatar
Howard Chu committed
412
			case ARG_ULONG:  	*(size_t*)ptr = c->value_ulong;			break;
Howard Chu's avatar
Howard Chu committed
413
			case ARG_BER_LEN_T: 	*(ber_len_t*)ptr = c->value_ber_t;			break;
414
			case ARG_STRING: {
415
				char *cc = *(char**)ptr;
416
				if(cc) {
Howard Chu's avatar
Howard Chu committed
417
					if ((arg_type & ARG_UNIQUE) && c->op == SLAP_CONFIG_ADD ) {
418
						Debug(LDAP_DEBUG_CONFIG, "%s: already set %s!\n",
419
							c->log, Conf->name );
420
421
						return(ARG_BAD_CONF);
					}
Howard Chu's avatar
Howard Chu committed
422
					ch_free(cc);
423
				}
424
				*(char **)ptr = c->value_string;
425
426
				break;
				}
427
			case ARG_BERVAL:
428
			case ARG_BINARY:
429
430
				*(struct berval *)ptr = c->value_bv;
				break;
431
432
433
			case ARG_ATDESC:
				*(AttributeDescription **)ptr = c->value_ad;
				break;
434
		}
Howard Chu's avatar
Howard Chu committed
435
436
437
438
	return(0);
}

int config_add_vals(ConfigTable *Conf, ConfigArgs *c) {
439
	int rc, arg_type;
Howard Chu's avatar
Howard Chu committed
440
441
442
443

	arg_type = Conf->arg_type;
	if(arg_type == ARG_IGNORED) {
		Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
444
			c->log, Conf->name );
Howard Chu's avatar
Howard Chu committed
445
446
447
448
449
		return(0);
	}
	rc = config_check_vals( Conf, c, 0 );
	if ( rc ) return rc;
	return config_set_vals( Conf, c );
450
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
451

452
453
454
455
int
config_del_vals(ConfigTable *cf, ConfigArgs *c)
{
	int rc = 0;
456

457
458
	/* If there is no handler, just ignore it */
	if ( cf->arg_type & ARG_MAGIC ) {
Howard Chu's avatar
Howard Chu committed
459
		c->argv[0] = cf->ad->ad_cname.bv_val;
460
461
462
463
		c->op = LDAP_MOD_DELETE;
		c->type = cf->arg_type & ARGS_USERLAND;
		rc = (*((ConfigDriver*)cf->arg_item))(c);
	}
464
	return rc;
465
466
}

Howard Chu's avatar
Howard Chu committed
467
468
469
470
471
int
config_get_vals(ConfigTable *cf, ConfigArgs *c)
{
	int rc = 0;
	struct berval bv;
472
	void *ptr;
Howard Chu's avatar
Howard Chu committed
473
474
475
476
477

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

Howard Chu's avatar
Howard Chu committed
478
	memset(&c->values, 0, sizeof(c->values));
479
	c->rvalue_vals = NULL;
Howard Chu's avatar
Howard Chu committed
480
	c->rvalue_nvals = NULL;
481
	c->op = SLAP_CONFIG_EMIT;
Howard Chu's avatar
Howard Chu committed
482
483
	c->type = cf->arg_type & ARGS_USERLAND;

Howard Chu's avatar
Howard Chu committed
484
485
486
487
	if ( cf->arg_type & ARG_MAGIC ) {
		rc = (*((ConfigDriver*)cf->arg_item))(c);
		if ( rc ) return rc;
	} else {
488
		if ( cf->arg_type & ARG_OFFSET ) {
489
			if (c->be && c->table == Cft_Database)
490
491
492
493
494
				ptr = c->be->be_private;
			else if ( c->bi )
				ptr = c->bi->bi_private;
			else
				return 1;
495
			ptr = (void *)((char *)ptr + (long)cf->arg_item);
496
497
498
499
		} else {
			ptr = cf->arg_item;
		}
		
500
		switch(cf->arg_type & ARGS_TYPES) {
Howard Chu's avatar
Howard Chu committed
501
		case ARG_ON_OFF:
502
		case ARG_INT:	c->value_int = *(int *)ptr; break;
503
		case ARG_UINT:	c->value_uint = *(unsigned *)ptr; break;
504
		case ARG_LONG:	c->value_long = *(long *)ptr; break;
Howard Chu's avatar
Howard Chu committed
505
		case ARG_ULONG:	c->value_ulong = *(size_t *)ptr; break;
506
		case ARG_BER_LEN_T:	c->value_ber_t = *(ber_len_t *)ptr; break;
Howard Chu's avatar
Howard Chu committed
507
		case ARG_STRING:
508
509
			if ( *(char **)ptr )
				c->value_string = ch_strdup(*(char **)ptr);
Howard Chu's avatar
Howard Chu committed
510
			break;
511
		case ARG_BERVAL:
512
			c->value_bv = *((struct berval *)ptr); break;
513
514
		case ARG_ATDESC:
			c->value_ad = *(AttributeDescription **)ptr; break;
Howard Chu's avatar
Howard Chu committed
515
516
		}
	}
517
	if ( cf->arg_type & ARGS_TYPES) {
Howard Chu's avatar
Howard Chu committed
518
		bv.bv_len = 0;
Howard Chu's avatar
Howard Chu committed
519
		bv.bv_val = c->log;
520
		switch(cf->arg_type & ARGS_TYPES) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
521
		case ARG_INT: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%d", c->value_int); break;
522
		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
523
		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
524
		case ARG_ULONG: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%" Z "u", c->value_ulong); break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
525
526
		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
527
			c->value_int ? "TRUE" : "FALSE"); break;
528
529
530
531
		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
532
				return 1;
533
534
			}
			break;
535
536
537
538
539
540
541
		case ARG_BERVAL:
			if ( !BER_BVISEMPTY( &c->value_bv )) {
				bv = c->value_bv;
			} else {
				return 1;
			}
			break;
542
543
544
545
546
547
548
		case ARG_ATDESC:
			if ( c->value_ad ) {
				bv = c->value_ad->ad_cname;
			} else {
				return 1;
			}
			break;
549
550
551
		default:
			bv.bv_val = NULL;
			break;
Howard Chu's avatar
Howard Chu committed
552
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
553
554
555
		if (bv.bv_val == c->log && bv.bv_len >= sizeof( c->log ) ) {
			return 1;
		}
556
		if (( cf->arg_type & ARGS_TYPES ) == ARG_STRING ) {
Howard Chu's avatar
Howard Chu committed
557
			ber_bvarray_add(&c->rvalue_vals, &bv);
558
		} else if ( !BER_BVISNULL( &bv ) ) {
Howard Chu's avatar
Howard Chu committed
559
			value_add_one(&c->rvalue_vals, &bv);
560
561
		}
		/* else: maybe c->rvalue_vals already set? */
Howard Chu's avatar
Howard Chu committed
562
563
564
565
	}
	return rc;
}

566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
int
config_push_cleanup(ConfigArgs *ca, ConfigDriver *cleanup)
{
	int i;
	/* silently ignore redundant push */
	for (i=0; i < ca->num_cleanups; i++) {
		if ( ca->cleanups[i] == cleanup )
			return 0;
	}

	if (ca->num_cleanups >= SLAP_CONFIG_CLEANUP_MAX)
		return -1;
	ca->cleanups[ca->num_cleanups++] = cleanup;
	return 0;
}

int
config_run_cleanup(ConfigArgs *ca)
{
	int i, rc = 0;

	for (i=0; i < ca->num_cleanups; i++) {
		rc = ca->cleanups[i](ca);
		if (rc)
			break;
	}
	return rc;
}

595
int
Howard Chu's avatar
Howard Chu committed
596
init_config_attrs(ConfigTable *ct) {
597
598
599
600
	int i, code;

	for (i=0; ct[i].name; i++ ) {
		if ( !ct[i].attribute ) continue;
601
		code = register_at( ct[i].attribute, &ct[i].ad, 1 );
602
		if ( code ) {
603
			fprintf( stderr, "init_config_attrs: register_at failed\n" );
604
			return code;
605
		}
606
607
608
609
		if (( ct[i].arg_type & ARGS_TYPES ) == ARG_BINARY ) {
			ldif_must_b64_encode_register( ct[i].ad->ad_cname.bv_val,
				ct[i].ad->ad_type->sat_oid );
		}
610
	}
611
612

	return 0;
613
614
}

615
int
616
init_config_ocs( ConfigOCs *ocs ) {
617
	int i, code;
618

619
	for (i=0;ocs[i].co_def;i++) {
620
621
622
		code = register_oc( ocs[i].co_def, &ocs[i].co_oc, 1 );
		if ( code ) {
			fprintf( stderr, "init_config_ocs: register_oc failed\n" );
623
624
			return code;
		}
625
	}
626
627
628
	return 0;
}

629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
/* 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;

646
	while( isspace( (unsigned char) *ptr )) ptr++;
647
648
649
650
651
652
653
654
655
656

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

	beg = ptr;

	for (;*ptr;ptr++) {
		if ( *ptr == '"' ) {
657
			if ( inquote && ( !ptr[1] || isspace((unsigned char) ptr[1]))) {
658
659
660
661
662
663
664
665
666
				*ptr++ = '\0';
				break;
			}
			inquote = 1;
			quote = ptr;
			continue;
		}
		if ( inquote )
			continue;
667
		if ( isspace( (unsigned char) *ptr )) {
668
669
670
671
672
673
674
675
676
677
678
679
680
			*ptr++ = '\0';
			break;
		}
	}
	if ( quote ) {
		while ( quote < ptr ) {
			*quote = quote[1];
			quote++;
		}
	}
	if ( !*ptr ) {
		*line = NULL;
	} else {
681
		while ( isspace( (unsigned char) *ptr )) ptr++;
682
683
684
685
686
		*line = ptr;
	}
	return beg;
}

687
void
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
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
706
707
708
int
config_parse_vals(ConfigTable *ct, ConfigArgs *c, int valx)
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
709
	int 	rc = 0;
710
	int arg_type = ct->arg_type & ARGS_TYPES;
Howard Chu's avatar
Howard Chu committed
711
712
713
714
715

	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
716

717
718
	if ( (( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) ||
		(arg_type == ARG_BERVAL || arg_type == ARG_BINARY)) {
719
720
721
722
		c->argv[c->argc] = c->line;
		c->argc++;
		c->argv[c->argc] = NULL;
		c->tline = NULL;
Howard Chu's avatar
Howard Chu committed
723
	} else {
724
		config_parse_ldif( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
725
	}
726
727
	rc = config_check_vals( ct, c, 1 );
	ch_free( c->tline );
728
	c->tline = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
729

Howard Chu's avatar
Howard Chu committed
730
731
	if ( rc )
		rc = LDAP_CONSTRAINT_VIOLATION;
Howard Chu's avatar
Howard Chu committed
732
733
734
735
736

	return rc;
}

int
737
config_parse_add(ConfigTable *ct, ConfigArgs *c, int valx)
Howard Chu's avatar
Howard Chu committed
738
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
739
	int	rc = 0;
740
	int arg_type = ct->arg_type & ARGS_TYPES;
Howard Chu's avatar
Howard Chu committed
741
742

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

747
748
	if ( (( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) ||
		(arg_type == ARG_BERVAL || arg_type == ARG_BINARY)) {
749
750
751
752
		c->argv[c->argc] = c->line;
		c->argc++;
		c->argv[c->argc] = NULL;
		c->tline = NULL;
Howard Chu's avatar
Howard Chu committed
753
	} else {
754
		config_parse_ldif( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
755
	}
756
757
	c->op = LDAP_MOD_ADD;
	rc = config_add_vals( ct, c );
Howard Chu's avatar
Howard Chu committed
758
	ch_free( c->tline );
759

Howard Chu's avatar
Howard Chu committed
760
761
762
	return rc;
}

763
int
764
read_config_file(const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft)
765
766
{
	FILE *fp;
767
	ConfigTable *ct;
768
	ConfigArgs *c;
769
	int rc;
770
	struct stat s;
771

Howard Chu's avatar
Howard Chu committed
772
773
774
775
	c = ch_calloc( 1, sizeof( ConfigArgs ) );
	if ( c == NULL ) {
		return 1;
	}
776

Howard Chu's avatar
Howard Chu committed
777
778
779
780
781
782
	if ( depth ) {
		memcpy( c, cf, sizeof( ConfigArgs ) );
	} else {
		c->depth = depth; /* XXX */
		c->bi = NULL;
		c->be = NULL;
783
	}
Gary Williams's avatar
Gary Williams committed
784

Howard Chu's avatar
Howard Chu committed
785
786
787
788
	c->valx = -1;
	c->fname = fname;
	init_config_argv( c );

789
790
791
792
793
	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
794
		ch_free( c->argv );
Howard Chu's avatar
Howard Chu committed
795
		ch_free( c );
796
797
798
799
800
801
802
		return(1);
	}

	if ( !S_ISREG( s.st_mode ) ) {
		ldap_syslog = 1;
		Debug(LDAP_DEBUG_ANY,
		    "regular file expected, got \"%s\"\n",
803
		    fname );
Howard Chu's avatar
Howard Chu committed
804
		ch_free( c->argv );
Howard Chu's avatar
Howard Chu committed
805
		ch_free( c );
806
807
808
		return(1);
	}

809
810
	fp = fopen( fname, "r" );
	if ( fp == NULL ) {
811
812
813
814
		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
815
		ch_free( c->argv );
Howard Chu's avatar
Howard Chu committed
816
		ch_free( c );
817
818
		return(1);
	}
819

820
	Debug(LDAP_DEBUG_CONFIG, "reading config file %s\n", fname );
821

822
	fp_getline_init(c);
Gary Williams's avatar
Gary Williams committed
823

Howard Chu's avatar
Howard Chu committed
824
825
	c->tline = NULL;

826
	while ( fp_getline( fp, c ) ) {
827
		/* skip comments and blank lines */
828
829
830
		if ( c->line[0] == '#' || c->line[0] == '\0' ) {
			continue;
		}
831

832
		snprintf( c->log, sizeof( c->log ), "%s: line %d",
833
834
				c->fname, c->lineno );

835
		c->argc = 0;
Howard Chu's avatar
Howard Chu committed
836
		ch_free( c->tline );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
837
		if ( config_fp_parse_line( c ) ) {
Howard Chu's avatar
Howard Chu committed
838
			rc = 1;
839
			goto done;
840
		}
841

842
		if ( c->argc < 1 ) {
843
			Debug( LDAP_DEBUG_ANY, "%s: bad config line.\n",
844
				c->log );
845
			rc = 1;
846
			goto done;
847
		}
Gary Williams's avatar
Gary Williams committed
848

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