config.c 63.6 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-2021 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 "slap-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
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;

87
88
int	slap_max_filter_depth = SLAP_MAX_FILTER_DEPTH_DEFAULT;

89
90
char   *slapd_pid_file  = NULL;
char   *slapd_args_file = NULL;
91

92
93
94
95
96
97
int use_reverse_lookup = 0;

#ifdef LDAP_SLAPI
int slapi_plugins_used = 0;
#endif

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

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

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

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

126
127
128
129
130
131
132
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;
133
134
135
136
137
138
139
140
141
142
143
144
145
	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;
	}
146
147
148
	return Conf+i;
}

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

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

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

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

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

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

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

454
455
456
457
int
config_del_vals(ConfigTable *cf, ConfigArgs *c)
{
	int rc = 0;
458
	void *ptr;
459

460
	if ( cf->arg_type & ARG_MAGIC ) {
Howard Chu's avatar
Howard Chu committed
461
		c->argv[0] = cf->ad->ad_cname.bv_val;
462
463
464
		c->op = LDAP_MOD_DELETE;
		c->type = cf->arg_type & ARGS_USERLAND;
		rc = (*((ConfigDriver*)cf->arg_item))(c);
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
		return rc;
	}
	/* If there is no handler, just zero it */
	if ( cf->arg_type & ARG_OFFSET ) {
		if ( c->be && c->table == Cft_Database )
			ptr = c->be->be_private;
		else if ( c->bi )
			ptr = c->bi->bi_private;
		else {
			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> offset is missing base pointer",
				c->argv[0] );
			Debug( LDAP_DEBUG_CONFIG, "%s: %s!\n",
				c->log, c->cr_msg );
			return ARG_BAD_CONF;
		}
		ptr = (void *)((char *)ptr + (long)cf->arg_item);
	} else if ( cf->arg_type & ARGS_TYPES ) {
		ptr = cf->arg_item;
483
	}
484
485
486
	if ( cf->arg_type & ARGS_TYPES )
		switch ( cf->arg_type & ARGS_TYPES ) {
			case ARG_ON_OFF:
487
488
489
490
491
			case ARG_INT:		*(int *)ptr = cf->arg_default.v_int;		break;
			case ARG_UINT:		*(unsigned *)ptr = cf->arg_default.v_uint;	break;
			case ARG_LONG:		*(long *)ptr = cf->arg_default.v_long;		break;
			case ARG_ULONG:		*(size_t *)ptr = cf->arg_default.v_ulong;	break;
			case ARG_BER_LEN_T:	*(ber_len_t *)ptr = cf->arg_default.v_ber_t;	break;
492
493
			case ARG_STRING:
				ch_free( *(char**)ptr );
494
495
496
497
498
				if ( cf->arg_default.v_string ) {
					*(char **)ptr = ch_strdup( cf->arg_default.v_string );
				} else {
					*(char **)ptr = NULL;
				}
499
500
501
502
				break;
			case ARG_BERVAL:
			case ARG_BINARY:
				ch_free( ((struct berval *)ptr)->bv_val );
503
504
505
506
507
				if ( !BER_BVISNULL( &cf->arg_default.v_bv ) ) {
					ber_dupbv( (struct berval *)ptr, &cf->arg_default.v_bv );
				} else {
					BER_BVZERO( (struct berval *)ptr );
				}
508
509
				break;
			case ARG_ATDESC:
510
				*(AttributeDescription **)ptr = cf->arg_default.v_ad;
511
512
				break;
		}
513
	return rc;
514
515
}

Howard Chu's avatar
Howard Chu committed
516
517
518
519
520
int
config_get_vals(ConfigTable *cf, ConfigArgs *c)
{
	int rc = 0;
	struct berval bv;
521
	void *ptr;
Howard Chu's avatar
Howard Chu committed
522
523
524
525
526

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

Howard Chu's avatar
Howard Chu committed
527
	memset(&c->values, 0, sizeof(c->values));
528
	c->rvalue_vals = NULL;
Howard Chu's avatar
Howard Chu committed
529
	c->rvalue_nvals = NULL;
530
	c->op = SLAP_CONFIG_EMIT;
Howard Chu's avatar
Howard Chu committed
531
532
	c->type = cf->arg_type & ARGS_USERLAND;

Howard Chu's avatar
Howard Chu committed
533
534
535
536
	if ( cf->arg_type & ARG_MAGIC ) {
		rc = (*((ConfigDriver*)cf->arg_item))(c);
		if ( rc ) return rc;
	} else {
537
		if ( cf->arg_type & ARG_OFFSET ) {
538
			if (c->be && c->table == Cft_Database)
539
540
541
542
543
				ptr = c->be->be_private;
			else if ( c->bi )
				ptr = c->bi->bi_private;
			else
				return 1;
544
			ptr = (void *)((char *)ptr + (long)cf->arg_item);
545
546
547
548
		} else {
			ptr = cf->arg_item;
		}
		
549
		switch(cf->arg_type & ARGS_TYPES) {
Howard Chu's avatar
Howard Chu committed
550
		case ARG_ON_OFF:
551
		case ARG_INT:	c->value_int = *(int *)ptr; break;
552
		case ARG_UINT:	c->value_uint = *(unsigned *)ptr; break;
553
		case ARG_LONG:	c->value_long = *(long *)ptr; break;
Howard Chu's avatar
Howard Chu committed
554
		case ARG_ULONG:	c->value_ulong = *(size_t *)ptr; break;
555
		case ARG_BER_LEN_T:	c->value_ber_t = *(ber_len_t *)ptr; break;
Howard Chu's avatar
Howard Chu committed
556
		case ARG_STRING:
557
558
			if ( *(char **)ptr )
				c->value_string = ch_strdup(*(char **)ptr);
Howard Chu's avatar
Howard Chu committed
559
			break;
560
		case ARG_BERVAL:
561
			c->value_bv = *((struct berval *)ptr); break;
562
563
		case ARG_ATDESC:
			c->value_ad = *(AttributeDescription **)ptr; break;
Howard Chu's avatar
Howard Chu committed
564
565
		}
	}
566
	if ( cf->arg_type & ARGS_TYPES) {
Howard Chu's avatar
Howard Chu committed
567
		bv.bv_len = 0;
Howard Chu's avatar
Howard Chu committed
568
		bv.bv_val = c->log;
569
		switch(cf->arg_type & ARGS_TYPES) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
570
		case ARG_INT: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%d", c->value_int); break;
571
		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
572
		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
573
		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
574
575
		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
576
			c->value_int ? "TRUE" : "FALSE"); break;
577
578
579
580
		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
581
				return 1;
582
583
			}
			break;
584
585
586
587
588
589
590
		case ARG_BERVAL:
			if ( !BER_BVISEMPTY( &c->value_bv )) {
				bv = c->value_bv;
			} else {
				return 1;
			}
			break;
591
592
593
594
595
596
597
		case ARG_ATDESC:
			if ( c->value_ad ) {
				bv = c->value_ad->ad_cname;
			} else {
				return 1;
			}
			break;
598
599
600
		default:
			bv.bv_val = NULL;
			break;
Howard Chu's avatar
Howard Chu committed
601
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
602
603
604
		if (bv.bv_val == c->log && bv.bv_len >= sizeof( c->log ) ) {
			return 1;
		}
605
		if (( cf->arg_type & ARGS_TYPES ) == ARG_STRING ) {
Howard Chu's avatar
Howard Chu committed
606
			ber_bvarray_add(&c->rvalue_vals, &bv);
607
		} else if ( !BER_BVISNULL( &bv ) ) {
Howard Chu's avatar
Howard Chu committed
608
			value_add_one(&c->rvalue_vals, &bv);
609
610
		}
		/* else: maybe c->rvalue_vals already set? */
Howard Chu's avatar
Howard Chu committed
611
612
613
614
	}
	return rc;
}

615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
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;
}

644
int
Howard Chu's avatar
Howard Chu committed
645
init_config_attrs(ConfigTable *ct) {
646
647
648
649
	int i, code;

	for (i=0; ct[i].name; i++ ) {
		if ( !ct[i].attribute ) continue;
650
		code = register_at( ct[i].attribute, &ct[i].ad, 1 );
651
		if ( code ) {
652
			fprintf( stderr, "init_config_attrs: register_at failed\n" );
653
			return code;
654
		}
655
656
657
658
		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 );
		}
659
	}
660
661

	return 0;
662
663
}

664
int
665
init_config_ocs( ConfigOCs *ocs ) {
666
	int i, code;
667

668
	for (i=0;ocs[i].co_def;i++) {
669
670
671
		code = register_oc( ocs[i].co_def, &ocs[i].co_oc, 1 );
		if ( code ) {
			fprintf( stderr, "init_config_ocs: register_oc failed\n" );
672
673
			return code;
		}
674
	}
675
676
677
	return 0;
}

678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
/* 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;

695
	while( isspace( (unsigned char) *ptr )) ptr++;
696
697
698
699
700
701
702
703
704
705

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

	beg = ptr;

	for (;*ptr;ptr++) {
		if ( *ptr == '"' ) {
706
			if ( inquote && ( !ptr[1] || isspace((unsigned char) ptr[1]))) {
707
708
709
710
711
712
713
714
715
				*ptr++ = '\0';
				break;
			}
			inquote = 1;
			quote = ptr;
			continue;
		}
		if ( inquote )
			continue;
716
		if ( isspace( (unsigned char) *ptr )) {
717
718
719
720
721
722
723
724
725
726
727
728
729
			*ptr++ = '\0';
			break;
		}
	}
	if ( quote ) {
		while ( quote < ptr ) {
			*quote = quote[1];
			quote++;
		}
	}
	if ( !*ptr ) {
		*line = NULL;
	} else {
730
		while ( isspace( (unsigned char) *ptr )) ptr++;
731
732
733
734
735
		*line = ptr;
	}
	return beg;
}

736
void
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
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
755
756
757
int
config_parse_vals(ConfigTable *ct, ConfigArgs *c, int valx)
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
758
	int 	rc = 0;
759
	int arg_type = ct->arg_type & ARGS_TYPES;
Howard Chu's avatar
Howard Chu committed
760
761
762
763
764

	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
765

766
767
	if ( (( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) ||
		(arg_type == ARG_BERVAL || arg_type == ARG_BINARY)) {
768
769
770
771
		c->argv[c->argc] = c->line;
		c->argc++;
		c->argv[c->argc] = NULL;
		c->tline = NULL;
Howard Chu's avatar
Howard Chu committed
772
	} else {
773
		config_parse_ldif( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
774
	}
775
776
	rc = config_check_vals( ct, c, 1 );
	ch_free( c->tline );
777
	c->tline = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
778

Howard Chu's avatar
Howard Chu committed
779
780
	if ( rc )
		rc = LDAP_CONSTRAINT_VIOLATION;
Howard Chu's avatar
Howard Chu committed
781
782
783
784
785

	return rc;
}

int
786
config_parse_add(ConfigTable *ct, ConfigArgs *c, int valx)
Howard Chu's avatar
Howard Chu committed
787
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
788
	int	rc = 0;
789
	int arg_type = ct->arg_type & ARGS_TYPES;
Howard Chu's avatar
Howard Chu committed
790
791

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

796
797
	if ( (( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) ||
		(arg_type == ARG_BERVAL || arg_type == ARG_BINARY)) {
798
799
800
801
		c->argv[c->argc] = c->line;
		c->argc++;
		c->argv[c->argc] = NULL;
		c->tline = NULL;
Howard Chu's avatar
Howard Chu committed
802
	} else {
803
		config_parse_ldif( c );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
804
	}
805
806
	c->op = LDAP_MOD_ADD;
	rc = config_add_vals( ct, c );
Howard Chu's avatar
Howard Chu committed
807
	ch_free( c->tline );
808

Howard Chu's avatar
Howard Chu committed
809
810
811
	return rc;
}

812
int
813
read_config_file(const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft)
814
815
{
	FILE *fp;
816
	ConfigTable *ct;
817
	ConfigArgs *c;
818
	int rc;
819
	struct stat s;
820

Howard Chu's avatar
Howard Chu committed
821
822
823
824
	c = ch_calloc( 1, sizeof( ConfigArgs ) );
	if ( c == NULL ) {
		return 1;
	}
825

Howard Chu's avatar
Howard Chu committed
826
827
828
829
830
831
	if ( depth ) {
		memcpy( c, cf, sizeof( ConfigArgs ) );
	} else {
		c->depth = depth; /* XXX */
		c->bi = NULL;
		c->be = NULL;
832
	}
Gary Williams's avatar
Gary Williams committed
833

Howard Chu's avatar
Howard Chu committed
834
835
836
837
	c->valx = -1;
	c->fname = fname;
	init_config_argv( c );

838
	if ( stat( fname, &s ) != 0 ) {
839
		char ebuf[128];
840
		int saved_errno = errno;
841
842
843
		ldap_syslog = 1;
		Debug(LDAP_DEBUG_ANY,
		    "could not stat config file \"%s\": %s (%d)\n",
844
		    fname, AC_STRERROR_R( saved_errno, ebuf, sizeof(ebuf) ), saved_errno);
Howard Chu's avatar
Howard Chu committed
845
		ch_free( c->argv );
Howard Chu's avatar
Howard Chu committed
846
		ch_free( c );
847
848
849
850
851
852
853
		return(1);
	}

	if ( !S_ISREG( s.st_mode ) ) {
		ldap_syslog = 1;
		Debug(LDAP_DEBUG_ANY,
		    "regular file expected, got \"%s\"\n",
854
		    fname );
Howard Chu's avatar
Howard Chu committed
855
		ch_free( c->argv );
Howard Chu's avatar
Howard Chu committed
856
		ch_free( c );
857
858
859
		return(1);
	}

860
861
	fp = fopen( fname, "r" );
	if ( fp == NULL ) {
862
		char ebuf[128];
863
		int saved_errno = errno;
864
865
866
		ldap_syslog = 1;
		Debug(LDAP_DEBUG_ANY,
		    "could not open config file \"%s\": %s (%d)\n",
867
		    fname, AC_STRERROR_R( saved_errno, ebuf, sizeof(ebuf) ), saved_errno);
Howard Chu's avatar
Howard Chu committed
868
		ch_free( c->argv );