1/*	$NetBSD$	*/
2
3/* config.c - configuration file handling routines */
4/* OpenLDAP: pkg/ldap/servers/slapd/config.c,v 1.441.2.37 2010/04/19 15:32:26 quanah Exp */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 1998-2010 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18/* Portions Copyright (c) 1995 Regents of the University of Michigan.
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms are permitted
22 * provided that this notice is preserved and that due credit is given
23 * to the University of Michigan at Ann Arbor. The name of the University
24 * may not be used to endorse or promote products derived from this
25 * software without specific prior written permission. This software
26 * is provided ``as is'' without express or implied warranty.
27 */
28
29#include "portable.h"
30
31#include <stdio.h>
32
33#include <ac/string.h>
34#include <ac/ctype.h>
35#include <ac/signal.h>
36#include <ac/socket.h>
37#include <ac/errno.h>
38#include <ac/unistd.h>
39
40#include <sys/types.h>
41#include <sys/stat.h>
42
43#ifndef S_ISREG
44#define	S_ISREG(m)	(((m) & _S_IFMT) == _S_IFREG)
45#endif
46
47#include "slap.h"
48#ifdef LDAP_SLAPI
49#include "slapi/slapi.h"
50#endif
51#include "lutil.h"
52#include "lutil_ldap.h"
53#include "config.h"
54
55#define ARGS_STEP	512
56
57/*
58 * defaults for various global variables
59 */
60slap_mask_t		global_allows = 0;
61slap_mask_t		global_disallows = 0;
62int		global_gentlehup = 0;
63int		global_idletimeout = 0;
64int		global_writetimeout = 0;
65char	*global_host = NULL;
66struct berval global_host_bv = BER_BVNULL;
67char	*global_realm = NULL;
68char	*sasl_host = NULL;
69char		**default_passwd_hash = NULL;
70struct berval default_search_base = BER_BVNULL;
71struct berval default_search_nbase = BER_BVNULL;
72
73ber_len_t sockbuf_max_incoming = SLAP_SB_MAX_INCOMING_DEFAULT;
74ber_len_t sockbuf_max_incoming_auth= SLAP_SB_MAX_INCOMING_AUTH;
75
76int	slap_conn_max_pending = SLAP_CONN_MAX_PENDING_DEFAULT;
77int	slap_conn_max_pending_auth = SLAP_CONN_MAX_PENDING_AUTH;
78
79char   *slapd_pid_file  = NULL;
80char   *slapd_args_file = NULL;
81
82int use_reverse_lookup = 0;
83
84#ifdef LDAP_SLAPI
85int slapi_plugins_used = 0;
86#endif
87
88static int fp_getline(FILE *fp, ConfigArgs *c);
89static void fp_getline_init(ConfigArgs *c);
90
91static char	*strtok_quote(char *line, char *sep, char **quote_ptr);
92static char *strtok_quote_ldif(char **line);
93
94ConfigArgs *
95new_config_args( BackendDB *be, const char *fname, int lineno, int argc, char **argv )
96{
97	ConfigArgs *c;
98	c = ch_calloc( 1, sizeof( ConfigArgs ) );
99	if ( c == NULL ) return(NULL);
100	c->be     = be;
101	c->fname  = fname;
102	c->argc   = argc;
103	c->argv   = argv;
104	c->lineno = lineno;
105	snprintf( c->log, sizeof( c->log ), "%s: line %d", fname, lineno );
106	return(c);
107}
108
109void
110init_config_argv( ConfigArgs *c )
111{
112	c->argv = ch_calloc( ARGS_STEP + 1, sizeof( *c->argv ) );
113	c->argv_size = ARGS_STEP + 1;
114}
115
116ConfigTable *config_find_keyword(ConfigTable *Conf, ConfigArgs *c) {
117	int i;
118
119	for(i = 0; Conf[i].name; i++)
120		if( (Conf[i].length && (!strncasecmp(c->argv[0], Conf[i].name, Conf[i].length))) ||
121			(!strcasecmp(c->argv[0], Conf[i].name)) ) break;
122	if ( !Conf[i].name ) return NULL;
123	return Conf+i;
124}
125
126int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) {
127	int rc, arg_user, arg_type, arg_syn, iarg;
128	unsigned uiarg;
129	long larg;
130	unsigned long ularg;
131	ber_len_t barg;
132
133	if(Conf->arg_type == ARG_IGNORED) {
134		Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
135			c->log, Conf->name, 0);
136		return(0);
137	}
138	arg_type = Conf->arg_type & ARGS_TYPES;
139	arg_user = Conf->arg_type & ARGS_USERLAND;
140	arg_syn = Conf->arg_type & ARGS_SYNTAX;
141
142	if((arg_type == ARG_DN) && c->argc == 1) {
143		c->argc = 2;
144		c->argv[1] = "";
145	}
146	if(Conf->min_args && (c->argc < Conf->min_args)) {
147		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> missing <%s> argument",
148			c->argv[0], Conf->what ? Conf->what : "" );
149		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n", c->log, c->cr_msg, 0 );
150		return(ARG_BAD_CONF);
151	}
152	if(Conf->max_args && (c->argc > Conf->max_args)) {
153		char	*ignored = " ignored";
154
155		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> extra cruft after <%s>",
156			c->argv[0], Conf->what );
157
158		ignored = "";
159		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s%s.\n",
160				c->log, c->cr_msg, ignored );
161		return(ARG_BAD_CONF);
162	}
163	if((arg_syn & ARG_DB) && !c->be) {
164		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> only allowed within database declaration",
165			c->argv[0] );
166		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
167			c->log, c->cr_msg, 0);
168		return(ARG_BAD_CONF);
169	}
170	if((arg_syn & ARG_PRE_BI) && c->bi) {
171		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must occur before any backend %sdeclaration",
172			c->argv[0], (arg_syn & ARG_PRE_DB) ? "or database " : "" );
173		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
174			c->log, c->cr_msg, 0 );
175		return(ARG_BAD_CONF);
176	}
177	if((arg_syn & ARG_PRE_DB) && c->be && c->be != frontendDB) {
178		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must occur before any database declaration",
179			c->argv[0] );
180		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
181			c->log, c->cr_msg, 0);
182		return(ARG_BAD_CONF);
183	}
184	if((arg_syn & ARG_PAREN) && *c->argv[1] != '(' /*')'*/) {
185		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> old format not supported", c->argv[0] );
186		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
187			c->log, c->cr_msg, 0);
188		return(ARG_BAD_CONF);
189	}
190	if(arg_type && !Conf->arg_item && !(arg_syn & ARG_OFFSET)) {
191		snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid config_table, arg_item is NULL",
192			c->argv[0] );
193		Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
194			c->log, c->cr_msg, 0);
195		return(ARG_BAD_CONF);
196	}
197	c->type = arg_user;
198	memset(&c->values, 0, sizeof(c->values));
199	if(arg_type == ARG_STRING) {
200		if ( !check_only )
201			c->value_string = ch_strdup(c->argv[1]);
202	} else if(arg_type == ARG_BERVAL) {
203		if ( !check_only )
204			ber_str2bv( c->argv[1], 0, 1, &c->value_bv );
205	} else if(arg_type == ARG_DN) {
206		struct berval bv;
207		ber_str2bv( c->argv[1], 0, 0, &bv );
208		rc = dnPrettyNormal( NULL, &bv, &c->value_dn, &c->value_ndn, NULL );
209		if ( rc != LDAP_SUCCESS ) {
210			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid DN %d (%s)",
211				c->argv[0], rc, ldap_err2string( rc ));
212			Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n" , c->log, c->cr_msg, 0);
213			return(ARG_BAD_CONF);
214		}
215		if ( check_only ) {
216			ch_free( c->value_ndn.bv_val );
217			ch_free( c->value_dn.bv_val );
218		}
219	} else if(arg_type == ARG_ATDESC) {
220		const char *text = NULL;
221		c->value_ad = NULL;
222		rc = slap_str2ad( c->argv[1], &c->value_ad, &text );
223		if ( rc != LDAP_SUCCESS ) {
224			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid AttributeDescription %d (%s)",
225				c->argv[0], rc, text );
226			Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n" , c->log, c->cr_msg, 0);
227			return(ARG_BAD_CONF);
228		}
229	} else {	/* all numeric */
230		int j;
231		iarg = 0; larg = 0; barg = 0;
232		switch(arg_type) {
233			case ARG_INT:
234				if ( lutil_atoix( &iarg, c->argv[1], 0 ) != 0 ) {
235					snprintf( c->cr_msg, sizeof( c->cr_msg ),
236						"<%s> unable to parse \"%s\" as int",
237						c->argv[0], c->argv[1] );
238					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
239						c->log, c->cr_msg, 0);
240					return(ARG_BAD_CONF);
241				}
242				break;
243			case ARG_UINT:
244				if ( lutil_atoux( &uiarg, c->argv[1], 0 ) != 0 ) {
245					snprintf( c->cr_msg, sizeof( c->cr_msg ),
246						"<%s> unable to parse \"%s\" as unsigned int",
247						c->argv[0], c->argv[1] );
248					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
249						c->log, c->cr_msg, 0);
250					return(ARG_BAD_CONF);
251				}
252				break;
253			case ARG_LONG:
254				if ( lutil_atolx( &larg, c->argv[1], 0 ) != 0 ) {
255					snprintf( c->cr_msg, sizeof( c->cr_msg ),
256						"<%s> unable to parse \"%s\" as long",
257						c->argv[0], c->argv[1] );
258					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
259						c->log, c->cr_msg, 0);
260					return(ARG_BAD_CONF);
261				}
262				break;
263			case ARG_ULONG:
264				if ( lutil_atoulx( &ularg, c->argv[1], 0 ) != 0 ) {
265					snprintf( c->cr_msg, sizeof( c->cr_msg ),
266						"<%s> unable to parse \"%s\" as unsigned long",
267						c->argv[0], c->argv[1] );
268					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
269						c->log, c->cr_msg, 0);
270					return(ARG_BAD_CONF);
271				}
272				break;
273			case ARG_BER_LEN_T: {
274				unsigned long	l;
275				if ( lutil_atoulx( &l, c->argv[1], 0 ) != 0 ) {
276					snprintf( c->cr_msg, sizeof( c->cr_msg ),
277						"<%s> unable to parse \"%s\" as ber_len_t",
278						c->argv[0], c->argv[1] );
279					Debug(LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
280						c->log, c->cr_msg, 0);
281					return(ARG_BAD_CONF);
282				}
283				barg = (ber_len_t)l;
284				} break;
285			case ARG_ON_OFF:
286				if (c->argc == 1) {
287					iarg = 1;
288				} else if ( !strcasecmp(c->argv[1], "on") ||
289					!strcasecmp(c->argv[1], "true") ||
290					!strcasecmp(c->argv[1], "yes") )
291				{
292					iarg = 1;
293				} else if ( !strcasecmp(c->argv[1], "off") ||
294					!strcasecmp(c->argv[1], "false") ||
295					!strcasecmp(c->argv[1], "no") )
296				{
297					iarg = 0;
298				} else {
299					snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value",
300						c->argv[0] );
301					Debug(LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n",
302						c->log, c->cr_msg, 0 );
303					return(ARG_BAD_CONF);
304				}
305				break;
306		}
307		j = (arg_type & ARG_NONZERO) ? 1 : 0;
308		if(iarg < j && larg < j && barg < (unsigned)j ) {
309			larg = larg ? larg : (barg ? (long)barg : iarg);
310			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value",
311				c->argv[0] );
312			Debug(LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n",
313				c->log, c->cr_msg, 0 );
314			return(ARG_BAD_CONF);
315		}
316		switch(arg_type) {
317			case ARG_ON_OFF:
318			case ARG_INT:		c->value_int = iarg;		break;
319			case ARG_UINT:		c->value_uint = uiarg;		break;
320			case ARG_LONG:		c->value_long = larg;		break;
321			case ARG_ULONG:		c->value_ulong = ularg;		break;
322			case ARG_BER_LEN_T:	c->value_ber_t = barg;		break;
323		}
324	}
325	return 0;
326}
327
328int config_set_vals(ConfigTable *Conf, ConfigArgs *c) {
329	int rc, arg_type;
330	void *ptr = NULL;
331
332	arg_type = Conf->arg_type;
333	if(arg_type & ARG_MAGIC) {
334		if(!c->be) c->be = frontendDB;
335		c->cr_msg[0] = '\0';
336		rc = (*((ConfigDriver*)Conf->arg_item))(c);
337#if 0
338		if(c->be == frontendDB) c->be = NULL;
339#endif
340		if(rc) {
341			if ( !c->cr_msg[0] ) {
342				snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> handler exited with %d",
343					c->argv[0], rc );
344				Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n",
345					c->log, c->cr_msg, 0 );
346			}
347			return(ARG_BAD_CONF);
348		}
349		return(0);
350	}
351	if(arg_type & ARG_OFFSET) {
352		if (c->be && c->table == Cft_Database)
353			ptr = c->be->be_private;
354		else if (c->bi)
355			ptr = c->bi->bi_private;
356		else {
357			snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> offset is missing base pointer",
358				c->argv[0] );
359			Debug(LDAP_DEBUG_CONFIG, "%s: %s!\n",
360				c->log, c->cr_msg, 0);
361			return(ARG_BAD_CONF);
362		}
363		ptr = (void *)((char *)ptr + (long)Conf->arg_item);
364	} else if (arg_type & ARGS_TYPES) {
365		ptr = Conf->arg_item;
366	}
367	if(arg_type & ARGS_TYPES)
368		switch(arg_type & ARGS_TYPES) {
369			case ARG_ON_OFF:
370			case ARG_INT: 		*(int*)ptr = c->value_int;			break;
371			case ARG_UINT: 		*(unsigned*)ptr = c->value_uint;			break;
372			case ARG_LONG:  	*(long*)ptr = c->value_long;			break;
373			case ARG_ULONG:  	*(unsigned long*)ptr = c->value_ulong;			break;
374			case ARG_BER_LEN_T: 	*(ber_len_t*)ptr = c->value_ber_t;			break;
375			case ARG_STRING: {
376				char *cc = *(char**)ptr;
377				if(cc) {
378					if ((arg_type & ARG_UNIQUE) && c->op == SLAP_CONFIG_ADD ) {
379						Debug(LDAP_DEBUG_CONFIG, "%s: already set %s!\n",
380							c->log, Conf->name, 0 );
381						return(ARG_BAD_CONF);
382					}
383					ch_free(cc);
384				}
385				*(char **)ptr = c->value_string;
386				break;
387				}
388			case ARG_BERVAL:
389				*(struct berval *)ptr = c->value_bv;
390				break;
391			case ARG_ATDESC:
392				*(AttributeDescription **)ptr = c->value_ad;
393				break;
394		}
395	return(0);
396}
397
398int config_add_vals(ConfigTable *Conf, ConfigArgs *c) {
399	int rc, arg_type;
400
401	arg_type = Conf->arg_type;
402	if(arg_type == ARG_IGNORED) {
403		Debug(LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
404			c->log, Conf->name, 0);
405		return(0);
406	}
407	rc = config_check_vals( Conf, c, 0 );
408	if ( rc ) return rc;
409	return config_set_vals( Conf, c );
410}
411
412int
413config_del_vals(ConfigTable *cf, ConfigArgs *c)
414{
415	int rc = 0;
416
417	/* If there is no handler, just ignore it */
418	if ( cf->arg_type & ARG_MAGIC ) {
419		c->argv[0] = cf->ad->ad_cname.bv_val;
420		c->op = LDAP_MOD_DELETE;
421		c->type = cf->arg_type & ARGS_USERLAND;
422		rc = (*((ConfigDriver*)cf->arg_item))(c);
423	}
424	return rc;
425}
426
427int
428config_get_vals(ConfigTable *cf, ConfigArgs *c)
429{
430	int rc = 0;
431	struct berval bv;
432	void *ptr;
433
434	if ( cf->arg_type & ARG_IGNORED ) {
435		return 1;
436	}
437
438	memset(&c->values, 0, sizeof(c->values));
439	c->rvalue_vals = NULL;
440	c->rvalue_nvals = NULL;
441	c->op = SLAP_CONFIG_EMIT;
442	c->type = cf->arg_type & ARGS_USERLAND;
443
444	if ( cf->arg_type & ARG_MAGIC ) {
445		rc = (*((ConfigDriver*)cf->arg_item))(c);
446		if ( rc ) return rc;
447	} else {
448		if ( cf->arg_type & ARG_OFFSET ) {
449			if (c->be && c->table == Cft_Database)
450				ptr = c->be->be_private;
451			else if ( c->bi )
452				ptr = c->bi->bi_private;
453			else
454				return 1;
455			ptr = (void *)((char *)ptr + (long)cf->arg_item);
456		} else {
457			ptr = cf->arg_item;
458		}
459
460		switch(cf->arg_type & ARGS_TYPES) {
461		case ARG_ON_OFF:
462		case ARG_INT:	c->value_int = *(int *)ptr; break;
463		case ARG_UINT:	c->value_uint = *(unsigned *)ptr; break;
464		case ARG_LONG:	c->value_long = *(long *)ptr; break;
465		case ARG_ULONG:	c->value_ulong = *(unsigned long *)ptr; break;
466		case ARG_BER_LEN_T:	c->value_ber_t = *(ber_len_t *)ptr; break;
467		case ARG_STRING:
468			if ( *(char **)ptr )
469				c->value_string = ch_strdup(*(char **)ptr);
470			break;
471		case ARG_BERVAL:
472			ber_dupbv( &c->value_bv, (struct berval *)ptr ); break;
473		case ARG_ATDESC:
474			c->value_ad = *(AttributeDescription **)ptr; break;
475		}
476	}
477	if ( cf->arg_type & ARGS_TYPES) {
478		bv.bv_len = 0;
479		bv.bv_val = c->log;
480		switch(cf->arg_type & ARGS_TYPES) {
481		case ARG_INT: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%d", c->value_int); break;
482		case ARG_UINT: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%u", c->value_uint); break;
483		case ARG_LONG: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%ld", c->value_long); break;
484		case ARG_ULONG: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%lu", c->value_ulong); break;
485		case ARG_BER_LEN_T: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%ld", c->value_ber_t); break;
486		case ARG_ON_OFF: bv.bv_len = snprintf(bv.bv_val, sizeof( c->log ), "%s",
487			c->value_int ? "TRUE" : "FALSE"); break;
488		case ARG_STRING:
489			if ( c->value_string && c->value_string[0]) {
490				ber_str2bv( c->value_string, 0, 0, &bv);
491			} else {
492				return 1;
493			}
494			break;
495		case ARG_BERVAL:
496			if ( !BER_BVISEMPTY( &c->value_bv )) {
497				bv = c->value_bv;
498			} else {
499				return 1;
500			}
501			break;
502		case ARG_ATDESC:
503			if ( c->value_ad ) {
504				bv = c->value_ad->ad_cname;
505			} else {
506				return 1;
507			}
508			break;
509		default:
510			bv.bv_val = NULL;
511			break;
512		}
513		if (bv.bv_val == c->log && bv.bv_len >= sizeof( c->log ) ) {
514			return 1;
515		}
516		if (( cf->arg_type & ARGS_TYPES ) == ARG_STRING ) {
517			ber_bvarray_add(&c->rvalue_vals, &bv);
518		} else if ( !BER_BVISNULL( &bv ) ) {
519			value_add_one(&c->rvalue_vals, &bv);
520		}
521		/* else: maybe c->rvalue_vals already set? */
522	}
523	return rc;
524}
525
526int
527init_config_attrs(ConfigTable *ct) {
528	int i, code;
529
530	for (i=0; ct[i].name; i++ ) {
531		if ( !ct[i].attribute ) continue;
532		code = register_at( ct[i].attribute, &ct[i].ad, 1 );
533		if ( code ) {
534			fprintf( stderr, "init_config_attrs: register_at failed\n" );
535			return code;
536		}
537	}
538
539	return 0;
540}
541
542int
543init_config_ocs( ConfigOCs *ocs ) {
544	int i, code;
545
546	for (i=0;ocs[i].co_def;i++) {
547		code = register_oc( ocs[i].co_def, &ocs[i].co_oc, 1 );
548		if ( code ) {
549			fprintf( stderr, "init_config_ocs: register_oc failed\n" );
550			return code;
551		}
552	}
553	return 0;
554}
555
556/* Split an LDIF line into space-separated tokens. Words may be grouped
557 * by quotes. A quoted string may begin in the middle of a word, but must
558 * end at the end of the word (be followed by whitespace or EOS). Any other
559 * quotes are passed through unchanged. All other characters are passed
560 * through unchanged.
561 */
562static char *
563strtok_quote_ldif( char **line )
564{
565	char *beg, *ptr, *quote=NULL;
566	int inquote=0;
567
568	ptr = *line;
569
570	if ( !ptr || !*ptr )
571		return NULL;
572
573	while( isspace( (unsigned char) *ptr )) ptr++;
574
575	if ( *ptr == '"' ) {
576		inquote = 1;
577		ptr++;
578	}
579
580	beg = ptr;
581
582	for (;*ptr;ptr++) {
583		if ( *ptr == '"' ) {
584			if ( inquote && ( !ptr[1] || isspace((unsigned char) ptr[1]))) {
585				*ptr++ = '\0';
586				break;
587			}
588			inquote = 1;
589			quote = ptr;
590			continue;
591		}
592		if ( inquote )
593			continue;
594		if ( isspace( (unsigned char) *ptr )) {
595			*ptr++ = '\0';
596			break;
597		}
598	}
599	if ( quote ) {
600		while ( quote < ptr ) {
601			*quote = quote[1];
602			quote++;
603		}
604	}
605	if ( !*ptr ) {
606		*line = NULL;
607	} else {
608		while ( isspace( (unsigned char) *ptr )) ptr++;
609		*line = ptr;
610	}
611	return beg;
612}
613
614static void
615config_parse_ldif( ConfigArgs *c )
616{
617	char *next;
618	c->tline = ch_strdup(c->line);
619	next = c->tline;
620
621	while ((c->argv[c->argc] = strtok_quote_ldif( &next )) != NULL) {
622		c->argc++;
623		if ( c->argc >= c->argv_size ) {
624			char **tmp = ch_realloc( c->argv, (c->argv_size + ARGS_STEP) *
625				sizeof( *c->argv ));
626			c->argv = tmp;
627			c->argv_size += ARGS_STEP;
628		}
629	}
630	c->argv[c->argc] = NULL;
631}
632
633int
634config_parse_vals(ConfigTable *ct, ConfigArgs *c, int valx)
635{
636	int 	rc = 0;
637
638	snprintf( c->log, sizeof( c->log ), "%s: value #%d",
639		ct->ad->ad_cname.bv_val, valx );
640	c->argc = 1;
641	c->argv[0] = ct->ad->ad_cname.bv_val;
642
643	if ( ( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) {
644		c->argv[c->argc] = c->line;
645		c->argc++;
646		c->argv[c->argc] = NULL;
647		c->tline = NULL;
648	} else {
649		config_parse_ldif( c );
650	}
651	rc = config_check_vals( ct, c, 1 );
652	ch_free( c->tline );
653	c->tline = NULL;
654
655	if ( rc )
656		rc = LDAP_CONSTRAINT_VIOLATION;
657
658	return rc;
659}
660
661int
662config_parse_add(ConfigTable *ct, ConfigArgs *c, int valx)
663{
664	int	rc = 0;
665
666	snprintf( c->log, sizeof( c->log ), "%s: value #%d",
667		ct->ad->ad_cname.bv_val, valx );
668	c->argc = 1;
669	c->argv[0] = ct->ad->ad_cname.bv_val;
670
671	if ( ( ct->arg_type & ARG_QUOTE ) && c->line[ 0 ] != '"' ) {
672		c->argv[c->argc] = c->line;
673		c->argc++;
674		c->argv[c->argc] = NULL;
675		c->tline = NULL;
676	} else {
677		config_parse_ldif( c );
678	}
679	c->op = LDAP_MOD_ADD;
680	rc = config_add_vals( ct, c );
681	ch_free( c->tline );
682
683	return rc;
684}
685
686int
687read_config_file(const char *fname, int depth, ConfigArgs *cf, ConfigTable *cft)
688{
689	FILE *fp;
690	ConfigTable *ct;
691	ConfigArgs *c;
692	int rc;
693	struct stat s;
694
695	c = ch_calloc( 1, sizeof( ConfigArgs ) );
696	if ( c == NULL ) {
697		return 1;
698	}
699
700	if ( depth ) {
701		memcpy( c, cf, sizeof( ConfigArgs ) );
702	} else {
703		c->depth = depth; /* XXX */
704		c->bi = NULL;
705		c->be = NULL;
706	}
707
708	c->valx = -1;
709	c->fname = fname;
710	init_config_argv( c );
711
712	if ( stat( fname, &s ) != 0 ) {
713		ldap_syslog = 1;
714		Debug(LDAP_DEBUG_ANY,
715		    "could not stat config file \"%s\": %s (%d)\n",
716		    fname, strerror(errno), errno);
717		ch_free( c );
718		return(1);
719	}
720
721	if ( !S_ISREG( s.st_mode ) ) {
722		ldap_syslog = 1;
723		Debug(LDAP_DEBUG_ANY,
724		    "regular file expected, got \"%s\"\n",
725		    fname, 0, 0 );
726		ch_free( c );
727		return(1);
728	}
729
730	fp = fopen( fname, "r" );
731	if ( fp == NULL ) {
732		ldap_syslog = 1;
733		Debug(LDAP_DEBUG_ANY,
734		    "could not open config file \"%s\": %s (%d)\n",
735		    fname, strerror(errno), errno);
736		ch_free( c );
737		return(1);
738	}
739
740	Debug(LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0);
741
742	fp_getline_init(c);
743
744	c->tline = NULL;
745
746	while ( fp_getline( fp, c ) ) {
747		/* skip comments and blank lines */
748		if ( c->line[0] == '#' || c->line[0] == '\0' ) {
749			continue;
750		}
751
752		snprintf( c->log, sizeof( c->log ), "%s: line %d",
753				c->fname, c->lineno );
754
755		c->argc = 0;
756		ch_free( c->tline );
757		if ( config_fp_parse_line( c ) ) {
758			rc = 1;
759			goto done;
760		}
761
762		if ( c->argc < 1 ) {
763			Debug( LDAP_DEBUG_ANY, "%s: bad config line.\n",
764				c->log, 0, 0);
765			rc = 1;
766			goto done;
767		}
768
769		c->op = SLAP_CONFIG_ADD;
770
771		ct = config_find_keyword( cft, c );
772		if ( ct ) {
773			c->table = Cft_Global;
774			rc = config_add_vals( ct, c );
775			if ( !rc ) continue;
776
777			if ( rc & ARGS_USERLAND ) {
778				/* XXX a usertype would be opaque here */
779				Debug(LDAP_DEBUG_CONFIG, "%s: unknown user type <%s>\n",
780					c->log, c->argv[0], 0);
781				rc = 1;
782				goto done;
783
784			} else if ( rc == ARG_BAD_CONF ) {
785				rc = 1;
786				goto done;
787			}
788
789		} else if ( c->bi && !c->be ) {
790			rc = SLAP_CONF_UNKNOWN;
791			if ( c->bi->bi_cf_ocs ) {
792				ct = config_find_keyword( c->bi->bi_cf_ocs->co_table, c );
793				if ( ct ) {
794					c->table = c->bi->bi_cf_ocs->co_type;
795					rc = config_add_vals( ct, c );
796				}
797			}
798			if ( c->bi->bi_config && rc == SLAP_CONF_UNKNOWN ) {
799				rc = (*c->bi->bi_config)(c->bi, c->fname, c->lineno,
800					c->argc, c->argv);
801			}
802			if ( rc ) {
803				switch(rc) {
804				case SLAP_CONF_UNKNOWN:
805					Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
806						"<%s> inside backend info definition.\n",
807						c->log, *c->argv, 0);
808				default:
809					rc = 1;
810					goto done;
811				}
812			}
813
814		} else if ( c->be && c->be != frontendDB ) {
815			rc = SLAP_CONF_UNKNOWN;
816			if ( c->be->be_cf_ocs ) {
817				ct = config_find_keyword( c->be->be_cf_ocs->co_table, c );
818				if ( ct ) {
819					c->table = c->be->be_cf_ocs->co_type;
820					rc = config_add_vals( ct, c );
821				}
822			}
823			if ( c->be->be_config && rc == SLAP_CONF_UNKNOWN ) {
824				rc = (*c->be->be_config)(c->be, c->fname, c->lineno,
825					c->argc, c->argv);
826			}
827			if ( rc == SLAP_CONF_UNKNOWN && SLAP_ISGLOBALOVERLAY( frontendDB ) )
828			{
829				/* global overlays may need
830				 * definitions inside other databases...
831				 */
832				rc = (*frontendDB->be_config)( frontendDB,
833					c->fname, (int)c->lineno, c->argc, c->argv );
834			}
835
836			switch ( rc ) {
837			case 0:
838				break;
839
840			case SLAP_CONF_UNKNOWN:
841				Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
842					"<%s> inside backend database definition.\n",
843					c->log, *c->argv, 0);
844
845			default:
846				rc = 1;
847				goto done;
848			}
849
850		} else if ( frontendDB->be_config ) {
851			rc = (*frontendDB->be_config)( frontendDB,
852				c->fname, (int)c->lineno, c->argc, c->argv);
853			if ( rc ) {
854				switch(rc) {
855				case SLAP_CONF_UNKNOWN:
856					Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
857						"<%s> inside global database definition.\n",
858						c->log, *c->argv, 0);
859
860				default:
861					rc = 1;
862					goto done;
863				}
864			}
865
866		} else {
867			Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
868				"<%s> outside backend info and database definitions.\n",
869				c->log, *c->argv, 0);
870			rc = 1;
871			goto done;
872		}
873	}
874
875	rc = 0;
876
877done:
878	if ( cf ) {
879		cf->be = c->be;
880		cf->bi = c->bi;
881	}
882	ch_free(c->tline);
883	fclose(fp);
884	ch_free(c->argv);
885	ch_free(c);
886	return(rc);
887}
888
889/* restrictops, allows, disallows, requires, loglevel */
890
891int
892bverb_to_mask(struct berval *bword, slap_verbmasks *v) {
893	int i;
894	for(i = 0; !BER_BVISNULL(&v[i].word); i++) {
895		if(!ber_bvstrcasecmp(bword, &v[i].word)) break;
896	}
897	return(i);
898}
899
900int
901verb_to_mask(const char *word, slap_verbmasks *v) {
902	struct berval	bword;
903	ber_str2bv( word, 0, 0, &bword );
904	return bverb_to_mask( &bword, v );
905}
906
907int
908verbs_to_mask(int argc, char *argv[], slap_verbmasks *v, slap_mask_t *m) {
909	int i, j;
910	for(i = 1; i < argc; i++) {
911		j = verb_to_mask(argv[i], v);
912		if(BER_BVISNULL(&v[j].word)) return i;
913		while (!v[j].mask) j--;
914		*m |= v[j].mask;
915	}
916	return(0);
917}
918
919/* Mask keywords that represent multiple bits should occur before single
920 * bit keywords in the verbmasks array.
921 */
922int
923mask_to_verbs(slap_verbmasks *v, slap_mask_t m, BerVarray *bva) {
924	int i, rc = 1;
925
926	if (m) {
927		for (i=0; !BER_BVISNULL(&v[i].word); i++) {
928			if (!v[i].mask) continue;
929			if (( m & v[i].mask ) == v[i].mask ) {
930				value_add_one( bva, &v[i].word );
931				rc = 0;
932				m ^= v[i].mask;
933				if ( !m ) break;
934			}
935		}
936	}
937	return rc;
938}
939
940int
941slap_verbmasks_init( slap_verbmasks **vp, slap_verbmasks *v )
942{
943	int		i;
944
945	assert( *vp == NULL );
946
947	for ( i = 0; !BER_BVISNULL( &v[ i ].word ); i++ ) /* EMPTY */;
948
949	*vp = ch_calloc( i + 1, sizeof( slap_verbmasks ) );
950
951	for ( i = 0; !BER_BVISNULL( &v[ i ].word ); i++ ) {
952		ber_dupbv( &(*vp)[ i ].word, &v[ i ].word );
953		*((slap_mask_t *)&(*vp)[ i ].mask) = v[ i ].mask;
954	}
955
956	BER_BVZERO( &(*vp)[ i ].word );
957
958	return 0;
959}
960
961int
962slap_verbmasks_destroy( slap_verbmasks *v )
963{
964	int		i;
965
966	assert( v != NULL );
967
968	for ( i = 0; !BER_BVISNULL( &v[ i ].word ); i++ ) {
969		ch_free( v[ i ].word.bv_val );
970	}
971
972	ch_free( v );
973
974	return 0;
975}
976
977int
978slap_verbmasks_append(
979	slap_verbmasks	**vp,
980	slap_mask_t	m,
981	struct berval	*v,
982	slap_mask_t	*ignore )
983{
984	int	i;
985
986	if ( !m ) {
987		return LDAP_OPERATIONS_ERROR;
988	}
989
990	for ( i = 0; !BER_BVISNULL( &(*vp)[ i ].word ); i++ ) {
991		if ( !(*vp)[ i ].mask ) continue;
992
993		if ( ignore != NULL ) {
994			int	j;
995
996			for ( j = 0; ignore[ j ] != 0; j++ ) {
997				if ( (*vp)[ i ].mask == ignore[ j ] ) {
998					goto check_next;
999				}
1000			}
1001		}
1002
1003		if ( ( m & (*vp)[ i ].mask ) == (*vp)[ i ].mask ) {
1004			if ( ber_bvstrcasecmp( v, &(*vp)[ i ].word ) == 0 ) {
1005				/* already set; ignore */
1006				return LDAP_SUCCESS;
1007			}
1008			/* conflicts */
1009			return LDAP_TYPE_OR_VALUE_EXISTS;
1010		}
1011
1012		if ( m & (*vp)[ i ].mask ) {
1013			/* conflicts */
1014			return LDAP_CONSTRAINT_VIOLATION;
1015		}
1016check_next:;
1017	}
1018
1019	*vp = ch_realloc( *vp, sizeof( slap_verbmasks ) * ( i + 2 ) );
1020	ber_dupbv( &(*vp)[ i ].word, v );
1021	*((slap_mask_t *)&(*vp)[ i ].mask) = m;
1022	BER_BVZERO( &(*vp)[ i + 1 ].word );
1023
1024	return LDAP_SUCCESS;
1025}
1026
1027int
1028enum_to_verb(slap_verbmasks *v, slap_mask_t m, struct berval *bv) {
1029	int i;
1030
1031	for (i=0; !BER_BVISNULL(&v[i].word); i++) {
1032		if ( m == v[i].mask ) {
1033			if ( bv != NULL ) {
1034				*bv = v[i].word;
1035			}
1036			return i;
1037		}
1038	}
1039	return -1;
1040}
1041
1042/* register a new verbmask */
1043static int
1044slap_verbmask_register( slap_verbmasks *vm_, slap_verbmasks **vmp, struct berval *bv, int mask )
1045{
1046	slap_verbmasks	*vm = *vmp;
1047	int		i;
1048
1049	/* check for duplicate word */
1050	/* NOTE: we accept duplicate codes; the first occurrence will be used
1051	 * when mapping from mask to verb */
1052	i = verb_to_mask( bv->bv_val, vm );
1053	if ( !BER_BVISNULL( &vm[ i ].word ) ) {
1054		return -1;
1055	}
1056
1057	for ( i = 0; !BER_BVISNULL( &vm[ i ].word ); i++ )
1058		;
1059
1060	if ( vm == vm_ ) {
1061		/* first time: duplicate array */
1062		vm = ch_calloc( i + 2, sizeof( slap_verbmasks ) );
1063		for ( i = 0; !BER_BVISNULL( &vm_[ i ].word ); i++ )
1064		{
1065			ber_dupbv( &vm[ i ].word, &vm_[ i ].word );
1066			*((slap_mask_t*)&vm[ i ].mask) = vm_[ i ].mask;
1067		}
1068
1069	} else {
1070		vm = ch_realloc( vm, (i + 2) * sizeof( slap_verbmasks ) );
1071	}
1072
1073	ber_dupbv( &vm[ i ].word, bv );
1074	*((slap_mask_t*)&vm[ i ].mask) = mask;
1075
1076	BER_BVZERO( &vm[ i+1 ].word );
1077
1078	*vmp = vm;
1079
1080	return i;
1081}
1082
1083static slap_verbmasks slap_ldap_response_code_[] = {
1084	{ BER_BVC("success"),				LDAP_SUCCESS },
1085
1086	{ BER_BVC("operationsError"),			LDAP_OPERATIONS_ERROR },
1087	{ BER_BVC("protocolError"),			LDAP_PROTOCOL_ERROR },
1088	{ BER_BVC("timelimitExceeded"),			LDAP_TIMELIMIT_EXCEEDED },
1089	{ BER_BVC("sizelimitExceeded"),			LDAP_SIZELIMIT_EXCEEDED },
1090	{ BER_BVC("compareFalse"),			LDAP_COMPARE_FALSE },
1091	{ BER_BVC("compareTrue"),			LDAP_COMPARE_TRUE },
1092
1093	{ BER_BVC("authMethodNotSupported"),		LDAP_AUTH_METHOD_NOT_SUPPORTED },
1094	{ BER_BVC("strongAuthNotSupported"),		LDAP_STRONG_AUTH_NOT_SUPPORTED },
1095	{ BER_BVC("strongAuthRequired"),		LDAP_STRONG_AUTH_REQUIRED },
1096	{ BER_BVC("strongerAuthRequired"),		LDAP_STRONGER_AUTH_REQUIRED },
1097#if 0 /* not LDAPv3 */
1098	{ BER_BVC("partialResults"),			LDAP_PARTIAL_RESULTS },
1099#endif
1100
1101	{ BER_BVC("referral"),				LDAP_REFERRAL },
1102	{ BER_BVC("adminlimitExceeded"),		LDAP_ADMINLIMIT_EXCEEDED },
1103	{ BER_BVC("unavailableCriticalExtension"),	LDAP_UNAVAILABLE_CRITICAL_EXTENSION },
1104	{ BER_BVC("confidentialityRequired"),		LDAP_CONFIDENTIALITY_REQUIRED },
1105	{ BER_BVC("saslBindInProgress"),		LDAP_SASL_BIND_IN_PROGRESS },
1106
1107	{ BER_BVC("noSuchAttribute"),			LDAP_NO_SUCH_ATTRIBUTE },
1108	{ BER_BVC("undefinedType"),			LDAP_UNDEFINED_TYPE },
1109	{ BER_BVC("inappropriateMatching"),		LDAP_INAPPROPRIATE_MATCHING },
1110	{ BER_BVC("constraintViolation"),		LDAP_CONSTRAINT_VIOLATION },
1111	{ BER_BVC("typeOrValueExists"),			LDAP_TYPE_OR_VALUE_EXISTS },
1112	{ BER_BVC("invalidSyntax"),			LDAP_INVALID_SYNTAX },
1113
1114	{ BER_BVC("noSuchObject"),			LDAP_NO_SUCH_OBJECT },
1115	{ BER_BVC("aliasProblem"),			LDAP_ALIAS_PROBLEM },
1116	{ BER_BVC("invalidDnSyntax"),			LDAP_INVALID_DN_SYNTAX },
1117#if 0 /* not LDAPv3 */
1118	{ BER_BVC("isLeaf"),				LDAP_IS_LEAF },
1119#endif
1120	{ BER_BVC("aliasDerefProblem"),			LDAP_ALIAS_DEREF_PROBLEM },
1121
1122	{ BER_BVC("proxyAuthzFailure"),			LDAP_X_PROXY_AUTHZ_FAILURE },
1123	{ BER_BVC("inappropriateAuth"),			LDAP_INAPPROPRIATE_AUTH },
1124	{ BER_BVC("invalidCredentials"),		LDAP_INVALID_CREDENTIALS },
1125	{ BER_BVC("insufficientAccess"),		LDAP_INSUFFICIENT_ACCESS },
1126
1127	{ BER_BVC("busy"),				LDAP_BUSY },
1128	{ BER_BVC("unavailable"),			LDAP_UNAVAILABLE },
1129	{ BER_BVC("unwillingToPerform"),		LDAP_UNWILLING_TO_PERFORM },
1130	{ BER_BVC("loopDetect"),			LDAP_LOOP_DETECT },
1131
1132	{ BER_BVC("namingViolation"),			LDAP_NAMING_VIOLATION },
1133	{ BER_BVC("objectClassViolation"),		LDAP_OBJECT_CLASS_VIOLATION },
1134	{ BER_BVC("notAllowedOnNonleaf"),		LDAP_NOT_ALLOWED_ON_NONLEAF },
1135	{ BER_BVC("notAllowedOnRdn"),			LDAP_NOT_ALLOWED_ON_RDN },
1136	{ BER_BVC("alreadyExists"),			LDAP_ALREADY_EXISTS },
1137	{ BER_BVC("noObjectClassMods"),			LDAP_NO_OBJECT_CLASS_MODS },
1138	{ BER_BVC("resultsTooLarge"),			LDAP_RESULTS_TOO_LARGE },
1139	{ BER_BVC("affectsMultipleDsas"),		LDAP_AFFECTS_MULTIPLE_DSAS },
1140
1141	{ BER_BVC("other"),				LDAP_OTHER },
1142
1143	/* extension-specific */
1144
1145	{ BER_BVC("cupResourcesExhausted"),		LDAP_CUP_RESOURCES_EXHAUSTED },
1146	{ BER_BVC("cupSecurityViolation"),		LDAP_CUP_SECURITY_VIOLATION },
1147	{ BER_BVC("cupInvalidData"),			LDAP_CUP_INVALID_DATA },
1148	{ BER_BVC("cupUnsupportedScheme"),		LDAP_CUP_UNSUPPORTED_SCHEME },
1149	{ BER_BVC("cupReloadRequired"),			LDAP_CUP_RELOAD_REQUIRED },
1150
1151	{ BER_BVC("cancelled"),				LDAP_CANCELLED },
1152	{ BER_BVC("noSuchOperation"),			LDAP_NO_SUCH_OPERATION },
1153	{ BER_BVC("tooLate"),				LDAP_TOO_LATE },
1154	{ BER_BVC("cannotCancel"),			LDAP_CANNOT_CANCEL },
1155
1156	{ BER_BVC("assertionFailed"),			LDAP_ASSERTION_FAILED },
1157
1158	{ BER_BVC("proxiedAuthorizationDenied"),	LDAP_PROXIED_AUTHORIZATION_DENIED },
1159
1160	{ BER_BVC("syncRefreshRequired"),		LDAP_SYNC_REFRESH_REQUIRED },
1161
1162	{ BER_BVC("noOperation"),			LDAP_X_NO_OPERATION },
1163
1164	{ BER_BVNULL,				0 }
1165};
1166
1167slap_verbmasks *slap_ldap_response_code = slap_ldap_response_code_;
1168
1169int
1170slap_ldap_response_code_register( struct berval *bv, int err )
1171{
1172	return slap_verbmask_register( slap_ldap_response_code_,
1173		&slap_ldap_response_code, bv, err );
1174}
1175
1176#ifdef HAVE_TLS
1177static slap_verbmasks tlskey[] = {
1178	{ BER_BVC("no"),	SB_TLS_OFF },
1179	{ BER_BVC("yes"),	SB_TLS_ON },
1180	{ BER_BVC("critical"),	SB_TLS_CRITICAL },
1181	{ BER_BVNULL, 0 }
1182};
1183
1184static slap_verbmasks crlkeys[] = {
1185		{ BER_BVC("none"),	LDAP_OPT_X_TLS_CRL_NONE },
1186		{ BER_BVC("peer"),	LDAP_OPT_X_TLS_CRL_PEER },
1187		{ BER_BVC("all"),	LDAP_OPT_X_TLS_CRL_ALL },
1188		{ BER_BVNULL, 0 }
1189	};
1190
1191static slap_verbmasks vfykeys[] = {
1192		{ BER_BVC("never"),	LDAP_OPT_X_TLS_NEVER },
1193		{ BER_BVC("demand"),	LDAP_OPT_X_TLS_DEMAND },
1194		{ BER_BVC("try"),	LDAP_OPT_X_TLS_TRY },
1195		{ BER_BVC("hard"),	LDAP_OPT_X_TLS_HARD },
1196		{ BER_BVNULL, 0 }
1197	};
1198#endif
1199
1200static slap_verbmasks methkey[] = {
1201	{ BER_BVC("none"),	LDAP_AUTH_NONE },
1202	{ BER_BVC("simple"),	LDAP_AUTH_SIMPLE },
1203#ifdef HAVE_CYRUS_SASL
1204	{ BER_BVC("sasl"),	LDAP_AUTH_SASL },
1205#endif
1206	{ BER_BVNULL, 0 }
1207};
1208
1209static slap_verbmasks versionkey[] = {
1210	{ BER_BVC("2"),		LDAP_VERSION2 },
1211	{ BER_BVC("3"),		LDAP_VERSION3 },
1212	{ BER_BVNULL, 0 }
1213};
1214
1215static int
1216slap_keepalive_parse(
1217	struct berval *val,
1218	void *bc,
1219	slap_cf_aux_table *tab0,
1220	const char *tabmsg,
1221	int unparse )
1222{
1223	if ( unparse ) {
1224		slap_keepalive *sk = (slap_keepalive *)bc;
1225		int rc = snprintf( val->bv_val, val->bv_len, "%d:%d:%d",
1226			sk->sk_idle, sk->sk_probes, sk->sk_interval );
1227		if ( rc < 0 ) {
1228			return -1;
1229		}
1230
1231		if ( (unsigned)rc >= val->bv_len ) {
1232			return -1;
1233		}
1234
1235		val->bv_len = rc;
1236
1237	} else {
1238		char *s = val->bv_val;
1239		char *next;
1240		slap_keepalive *sk = (slap_keepalive *)bc;
1241		slap_keepalive sk2;
1242
1243		if ( s[0] == ':' ) {
1244			sk2.sk_idle = 0;
1245			s++;
1246
1247		} else {
1248			sk2.sk_idle = strtol( s, &next, 10 );
1249			if ( next == s || next[0] != ':' ) {
1250				return -1;
1251			}
1252
1253			if ( sk2.sk_idle < 0 ) {
1254				return -1;
1255			}
1256
1257			s = ++next;
1258		}
1259
1260		if ( s[0] == ':' ) {
1261			sk2.sk_probes = 0;
1262			s++;
1263
1264		} else {
1265			sk2.sk_probes = strtol( s, &next, 10 );
1266			if ( next == s || next[0] != ':' ) {
1267				return -1;
1268			}
1269
1270			if ( sk2.sk_probes < 0 ) {
1271				return -1;
1272			}
1273
1274			s = ++next;
1275		}
1276
1277		if ( s == '\0' ) {
1278			sk2.sk_interval = 0;
1279			s++;
1280
1281		} else {
1282			sk2.sk_interval = strtol( s, &next, 10 );
1283			if ( next == s || next[0] != '\0' ) {
1284				return -1;
1285			}
1286
1287			if ( sk2.sk_interval < 0 ) {
1288				return -1;
1289			}
1290		}
1291
1292		*sk = sk2;
1293
1294		ber_memfree( val->bv_val );
1295		BER_BVZERO( val );
1296	}
1297
1298	return 0;
1299}
1300
1301static int
1302slap_sb_uri(
1303	struct berval *val,
1304	void *bcp,
1305	slap_cf_aux_table *tab0,
1306	const char *tabmsg,
1307	int unparse )
1308{
1309	slap_bindconf *bc = bcp;
1310	if ( unparse ) {
1311		if ( bc->sb_uri.bv_len >= val->bv_len )
1312			return -1;
1313		val->bv_len = bc->sb_uri.bv_len;
1314		AC_MEMCPY( val->bv_val, bc->sb_uri.bv_val, val->bv_len );
1315	} else {
1316		bc->sb_uri = *val;
1317#ifdef HAVE_TLS
1318		if ( ldap_is_ldaps_url( val->bv_val ))
1319			bc->sb_tls_do_init = 1;
1320#endif
1321	}
1322	return 0;
1323}
1324
1325static slap_cf_aux_table bindkey[] = {
1326	{ BER_BVC("uri="), 0, 'x', 1, slap_sb_uri },
1327	{ BER_BVC("version="), offsetof(slap_bindconf, sb_version), 'i', 0, versionkey },
1328	{ BER_BVC("bindmethod="), offsetof(slap_bindconf, sb_method), 'i', 0, methkey },
1329	{ BER_BVC("timeout="), offsetof(slap_bindconf, sb_timeout_api), 'i', 0, NULL },
1330	{ BER_BVC("network-timeout="), offsetof(slap_bindconf, sb_timeout_net), 'i', 0, NULL },
1331	{ BER_BVC("binddn="), offsetof(slap_bindconf, sb_binddn), 'b', 1, (slap_verbmasks *)dnNormalize },
1332	{ BER_BVC("credentials="), offsetof(slap_bindconf, sb_cred), 'b', 1, NULL },
1333	{ BER_BVC("saslmech="), offsetof(slap_bindconf, sb_saslmech), 'b', 0, NULL },
1334	{ BER_BVC("secprops="), offsetof(slap_bindconf, sb_secprops), 's', 0, NULL },
1335	{ BER_BVC("realm="), offsetof(slap_bindconf, sb_realm), 'b', 0, NULL },
1336	{ BER_BVC("authcID="), offsetof(slap_bindconf, sb_authcId), 'b', 1, NULL },
1337	{ BER_BVC("authzID="), offsetof(slap_bindconf, sb_authzId), 'b', 1, (slap_verbmasks *)authzNormalize },
1338	{ BER_BVC("keepalive="), offsetof(slap_bindconf, sb_keepalive), 'x', 0, (slap_verbmasks *)slap_keepalive_parse },
1339#ifdef HAVE_TLS
1340	/* NOTE: replace "13" with the actual index
1341	 * of the first TLS-related line */
1342#define aux_TLS (bindkey+13)	/* beginning of TLS keywords */
1343
1344	{ BER_BVC("starttls="), offsetof(slap_bindconf, sb_tls), 'i', 0, tlskey },
1345	{ BER_BVC("tls_cert="), offsetof(slap_bindconf, sb_tls_cert), 's', 1, NULL },
1346	{ BER_BVC("tls_key="), offsetof(slap_bindconf, sb_tls_key), 's', 1, NULL },
1347	{ BER_BVC("tls_cacert="), offsetof(slap_bindconf, sb_tls_cacert), 's', 1, NULL },
1348	{ BER_BVC("tls_cacertdir="), offsetof(slap_bindconf, sb_tls_cacertdir), 's', 1, NULL },
1349	{ BER_BVC("tls_reqcert="), offsetof(slap_bindconf, sb_tls_reqcert), 's', 0, NULL },
1350	{ BER_BVC("tls_cipher_suite="), offsetof(slap_bindconf, sb_tls_cipher_suite), 's', 0, NULL },
1351	{ BER_BVC("tls_protocol_min="), offsetof(slap_bindconf, sb_tls_protocol_min), 's', 0, NULL },
1352#ifdef HAVE_OPENSSL_CRL
1353	{ BER_BVC("tls_crlcheck="), offsetof(slap_bindconf, sb_tls_crlcheck), 's', 0, NULL },
1354#endif
1355#endif
1356	{ BER_BVNULL, 0, 0, 0, NULL }
1357};
1358
1359/*
1360 * 's':	char *
1361 * 'b':	struct berval; if !NULL, normalize using ((slap_mr_normalize_func *)aux)
1362 * 'i':	int; if !NULL, compute using ((slap_verbmasks *)aux)
1363 * 'u':	unsigned
1364 * 'I':	long
1365 * 'U':	unsigned long
1366 */
1367
1368int
1369slap_cf_aux_table_parse( const char *word, void *dst, slap_cf_aux_table *tab0, LDAP_CONST char *tabmsg )
1370{
1371	int rc = SLAP_CONF_UNKNOWN;
1372	slap_cf_aux_table *tab;
1373
1374	for ( tab = tab0; !BER_BVISNULL( &tab->key ); tab++ ) {
1375		if ( !strncasecmp( word, tab->key.bv_val, tab->key.bv_len ) ) {
1376			char **cptr;
1377			int *iptr, j;
1378			unsigned *uptr;
1379			long *lptr;
1380			unsigned long *ulptr;
1381			struct berval *bptr;
1382			const char *val = word + tab->key.bv_len;
1383
1384			switch ( tab->type ) {
1385			case 's':
1386				cptr = (char **)((char *)dst + tab->off);
1387				*cptr = ch_strdup( val );
1388				rc = 0;
1389				break;
1390
1391			case 'b':
1392				bptr = (struct berval *)((char *)dst + tab->off);
1393				if ( tab->aux != NULL ) {
1394					struct berval	dn;
1395					slap_mr_normalize_func *normalize = (slap_mr_normalize_func *)tab->aux;
1396
1397					ber_str2bv( val, 0, 0, &dn );
1398					rc = normalize( 0, NULL, NULL, &dn, bptr, NULL );
1399
1400				} else {
1401					ber_str2bv( val, 0, 1, bptr );
1402					rc = 0;
1403				}
1404				break;
1405
1406			case 'i':
1407				iptr = (int *)((char *)dst + tab->off);
1408
1409				if ( tab->aux != NULL ) {
1410					slap_verbmasks *aux = (slap_verbmasks *)tab->aux;
1411
1412					assert( aux != NULL );
1413
1414					rc = 1;
1415					for ( j = 0; !BER_BVISNULL( &aux[j].word ); j++ ) {
1416						if ( !strcasecmp( val, aux[j].word.bv_val ) ) {
1417							*iptr = aux[j].mask;
1418							rc = 0;
1419							break;
1420						}
1421					}
1422
1423				} else {
1424					rc = lutil_atoix( iptr, val, 0 );
1425				}
1426				break;
1427
1428			case 'u':
1429				uptr = (unsigned *)((char *)dst + tab->off);
1430
1431				rc = lutil_atoux( uptr, val, 0 );
1432				break;
1433
1434			case 'I':
1435				lptr = (long *)((char *)dst + tab->off);
1436
1437				rc = lutil_atolx( lptr, val, 0 );
1438				break;
1439
1440			case 'U':
1441				ulptr = (unsigned long *)((char *)dst + tab->off);
1442
1443				rc = lutil_atoulx( ulptr, val, 0 );
1444				break;
1445
1446			case 'x':
1447				if ( tab->aux != NULL ) {
1448					struct berval value;
1449					slap_cf_aux_table_parse_x *func = (slap_cf_aux_table_parse_x *)tab->aux;
1450
1451					ber_str2bv( val, 0, 1, &value );
1452
1453					rc = func( &value, (void *)((char *)dst + tab->off), tab, tabmsg, 0 );
1454
1455				} else {
1456					rc = 1;
1457				}
1458				break;
1459			}
1460
1461			if ( rc ) {
1462				Debug( LDAP_DEBUG_ANY, "invalid %s value %s\n",
1463					tabmsg, word, 0 );
1464			}
1465
1466			return rc;
1467		}
1468	}
1469
1470	return rc;
1471}
1472
1473int
1474slap_cf_aux_table_unparse( void *src, struct berval *bv, slap_cf_aux_table *tab0 )
1475{
1476	char buf[AC_LINE_MAX], *ptr;
1477	slap_cf_aux_table *tab;
1478	struct berval tmp;
1479
1480	ptr = buf;
1481	for (tab = tab0; !BER_BVISNULL(&tab->key); tab++ ) {
1482		char **cptr;
1483		int *iptr, i;
1484		unsigned *uptr;
1485		long *lptr;
1486		unsigned long *ulptr;
1487		struct berval *bptr;
1488
1489		cptr = (char **)((char *)src + tab->off);
1490
1491		switch ( tab->type ) {
1492		case 'b':
1493			bptr = (struct berval *)((char *)src + tab->off);
1494			cptr = &bptr->bv_val;
1495
1496		case 's':
1497			if ( *cptr ) {
1498				*ptr++ = ' ';
1499				ptr = lutil_strcopy( ptr, tab->key.bv_val );
1500				if ( tab->quote ) *ptr++ = '"';
1501				ptr = lutil_strcopy( ptr, *cptr );
1502				if ( tab->quote ) *ptr++ = '"';
1503			}
1504			break;
1505
1506		case 'i':
1507			iptr = (int *)((char *)src + tab->off);
1508
1509			if ( tab->aux != NULL ) {
1510				slap_verbmasks *aux = (slap_verbmasks *)tab->aux;
1511
1512				for ( i = 0; !BER_BVISNULL( &aux[i].word ); i++ ) {
1513					if ( *iptr == aux[i].mask ) {
1514						*ptr++ = ' ';
1515						ptr = lutil_strcopy( ptr, tab->key.bv_val );
1516						ptr = lutil_strcopy( ptr, aux[i].word.bv_val );
1517						break;
1518					}
1519				}
1520
1521			} else {
1522				*ptr++ = ' ';
1523				ptr = lutil_strcopy( ptr, tab->key.bv_val );
1524				ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ), "%d", *iptr );
1525			}
1526			break;
1527
1528		case 'u':
1529			uptr = (unsigned *)((char *)src + tab->off);
1530			*ptr++ = ' ';
1531			ptr = lutil_strcopy( ptr, tab->key.bv_val );
1532			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ), "%u", *uptr );
1533			break;
1534
1535		case 'I':
1536			lptr = (long *)((char *)src + tab->off);
1537			*ptr++ = ' ';
1538			ptr = lutil_strcopy( ptr, tab->key.bv_val );
1539			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ), "%ld", *lptr );
1540			break;
1541
1542		case 'U':
1543			ulptr = (unsigned long *)((char *)src + tab->off);
1544			*ptr++ = ' ';
1545			ptr = lutil_strcopy( ptr, tab->key.bv_val );
1546			ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ), "%lu", *ulptr );
1547			break;
1548
1549		case 'x':
1550			{
1551				char *saveptr=ptr;
1552				*ptr++ = ' ';
1553				ptr = lutil_strcopy( ptr, tab->key.bv_val );
1554				if ( tab->quote ) *ptr++ = '"';
1555				if ( tab->aux != NULL ) {
1556					struct berval value;
1557					slap_cf_aux_table_parse_x *func = (slap_cf_aux_table_parse_x *)tab->aux;
1558					int rc;
1559
1560					value.bv_val = ptr;
1561					value.bv_len = buf + sizeof( buf ) - ptr;
1562
1563					rc = func( &value, (void *)((char *)src + tab->off), tab, "(unparse)", 1 );
1564					if ( rc == 0 ) {
1565						if (value.bv_len) {
1566							ptr += value.bv_len;
1567						} else {
1568							ptr = saveptr;
1569							break;
1570						}
1571					}
1572				}
1573				if ( tab->quote ) *ptr++ = '"';
1574			}
1575			break;
1576
1577		default:
1578			assert( 0 );
1579		}
1580	}
1581	tmp.bv_val = buf;
1582	tmp.bv_len = ptr - buf;
1583	ber_dupbv( bv, &tmp );
1584	return 0;
1585}
1586
1587int
1588slap_tls_get_config( LDAP *ld, int opt, char **val )
1589{
1590#ifdef HAVE_TLS
1591	slap_verbmasks *keys;
1592	int i, ival;
1593
1594	*val = NULL;
1595	switch( opt ) {
1596	case LDAP_OPT_X_TLS_CRLCHECK:
1597		keys = crlkeys;
1598		break;
1599	case LDAP_OPT_X_TLS_REQUIRE_CERT:
1600		keys = vfykeys;
1601		break;
1602	case LDAP_OPT_X_TLS_PROTOCOL_MIN: {
1603		char buf[8];
1604		ldap_pvt_tls_get_option( ld, opt, &ival );
1605		snprintf( buf, sizeof( buf ), "%d.%d",
1606			( ival >> 8 ) & 0xff, ival & 0xff );
1607		*val = ch_strdup( buf );
1608		return 0;
1609		}
1610	default:
1611		return -1;
1612	}
1613	ldap_pvt_tls_get_option( ld, opt, &ival );
1614	for (i=0; !BER_BVISNULL(&keys[i].word); i++) {
1615		if (keys[i].mask == ival) {
1616			*val = ch_strdup( keys[i].word.bv_val );
1617			return 0;
1618		}
1619	}
1620#endif
1621	return -1;
1622}
1623
1624int
1625bindconf_tls_parse( const char *word, slap_bindconf *bc )
1626{
1627#ifdef HAVE_TLS
1628	if ( slap_cf_aux_table_parse( word, bc, aux_TLS, "tls config" ) == 0 ) {
1629		bc->sb_tls_do_init = 1;
1630		return 0;
1631	}
1632#endif
1633	return -1;
1634}
1635
1636int
1637bindconf_tls_unparse( slap_bindconf *bc, struct berval *bv )
1638{
1639#ifdef HAVE_TLS
1640	return slap_cf_aux_table_unparse( bc, bv, aux_TLS );
1641#endif
1642	return -1;
1643}
1644
1645int
1646bindconf_parse( const char *word, slap_bindconf *bc )
1647{
1648#ifdef HAVE_TLS
1649	/* Detect TLS config changes explicitly */
1650	if ( bindconf_tls_parse( word, bc ) == 0 ) {
1651		return 0;
1652	}
1653#endif
1654	return slap_cf_aux_table_parse( word, bc, bindkey, "bind config" );
1655}
1656
1657int
1658bindconf_unparse( slap_bindconf *bc, struct berval *bv )
1659{
1660	return slap_cf_aux_table_unparse( bc, bv, bindkey );
1661}
1662
1663void bindconf_free( slap_bindconf *bc ) {
1664	if ( !BER_BVISNULL( &bc->sb_uri ) ) {
1665		ch_free( bc->sb_uri.bv_val );
1666		BER_BVZERO( &bc->sb_uri );
1667	}
1668	if ( !BER_BVISNULL( &bc->sb_binddn ) ) {
1669		ch_free( bc->sb_binddn.bv_val );
1670		BER_BVZERO( &bc->sb_binddn );
1671	}
1672	if ( !BER_BVISNULL( &bc->sb_cred ) ) {
1673		ch_free( bc->sb_cred.bv_val );
1674		BER_BVZERO( &bc->sb_cred );
1675	}
1676	if ( !BER_BVISNULL( &bc->sb_saslmech ) ) {
1677		ch_free( bc->sb_saslmech.bv_val );
1678		BER_BVZERO( &bc->sb_saslmech );
1679	}
1680	if ( bc->sb_secprops ) {
1681		ch_free( bc->sb_secprops );
1682		bc->sb_secprops = NULL;
1683	}
1684	if ( !BER_BVISNULL( &bc->sb_realm ) ) {
1685		ch_free( bc->sb_realm.bv_val );
1686		BER_BVZERO( &bc->sb_realm );
1687	}
1688	if ( !BER_BVISNULL( &bc->sb_authcId ) ) {
1689		ch_free( bc->sb_authcId.bv_val );
1690		BER_BVZERO( &bc->sb_authcId );
1691	}
1692	if ( !BER_BVISNULL( &bc->sb_authzId ) ) {
1693		ch_free( bc->sb_authzId.bv_val );
1694		BER_BVZERO( &bc->sb_authzId );
1695	}
1696#ifdef HAVE_TLS
1697	if ( bc->sb_tls_cert ) {
1698		ch_free( bc->sb_tls_cert );
1699		bc->sb_tls_cert = NULL;
1700	}
1701	if ( bc->sb_tls_key ) {
1702		ch_free( bc->sb_tls_key );
1703		bc->sb_tls_key = NULL;
1704	}
1705	if ( bc->sb_tls_cacert ) {
1706		ch_free( bc->sb_tls_cacert );
1707		bc->sb_tls_cacert = NULL;
1708	}
1709	if ( bc->sb_tls_cacertdir ) {
1710		ch_free( bc->sb_tls_cacertdir );
1711		bc->sb_tls_cacertdir = NULL;
1712	}
1713	if ( bc->sb_tls_reqcert ) {
1714		ch_free( bc->sb_tls_reqcert );
1715		bc->sb_tls_reqcert = NULL;
1716	}
1717	if ( bc->sb_tls_cipher_suite ) {
1718		ch_free( bc->sb_tls_cipher_suite );
1719		bc->sb_tls_cipher_suite = NULL;
1720	}
1721	if ( bc->sb_tls_protocol_min ) {
1722		ch_free( bc->sb_tls_protocol_min );
1723		bc->sb_tls_protocol_min = NULL;
1724	}
1725#ifdef HAVE_OPENSSL_CRL
1726	if ( bc->sb_tls_crlcheck ) {
1727		ch_free( bc->sb_tls_crlcheck );
1728		bc->sb_tls_crlcheck = NULL;
1729	}
1730#endif
1731#endif
1732}
1733
1734void
1735bindconf_tls_defaults( slap_bindconf *bc )
1736{
1737#ifdef HAVE_TLS
1738	if ( bc->sb_tls_do_init ) {
1739		if ( !bc->sb_tls_cacert )
1740			ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CACERTFILE,
1741				&bc->sb_tls_cacert );
1742		if ( !bc->sb_tls_cacertdir )
1743			ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CACERTDIR,
1744				&bc->sb_tls_cacertdir );
1745		if ( !bc->sb_tls_cert )
1746			ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CERTFILE,
1747				&bc->sb_tls_cert );
1748		if ( !bc->sb_tls_key )
1749			ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_KEYFILE,
1750				&bc->sb_tls_key );
1751		if ( !bc->sb_tls_cipher_suite )
1752			ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CIPHER_SUITE,
1753				&bc->sb_tls_cipher_suite );
1754		if ( !bc->sb_tls_reqcert )
1755			bc->sb_tls_reqcert = ch_strdup("demand");
1756#ifdef HAVE_OPENSSL_CRL
1757		if ( !bc->sb_tls_crlcheck )
1758			slap_tls_get_config( slap_tls_ld, LDAP_OPT_X_TLS_CRLCHECK,
1759				&bc->sb_tls_crlcheck );
1760#endif
1761	}
1762#endif
1763}
1764
1765#ifdef HAVE_TLS
1766static struct {
1767	const char *key;
1768	size_t offset;
1769	int opt;
1770} bindtlsopts[] = {
1771	{ "tls_cert", offsetof(slap_bindconf, sb_tls_cert), LDAP_OPT_X_TLS_CERTFILE },
1772	{ "tls_key", offsetof(slap_bindconf, sb_tls_key), LDAP_OPT_X_TLS_KEYFILE },
1773	{ "tls_cacert", offsetof(slap_bindconf, sb_tls_cacert), LDAP_OPT_X_TLS_CACERTFILE },
1774	{ "tls_cacertdir", offsetof(slap_bindconf, sb_tls_cacertdir), LDAP_OPT_X_TLS_CACERTDIR },
1775	{ "tls_cipher_suite", offsetof(slap_bindconf, sb_tls_cipher_suite), LDAP_OPT_X_TLS_CIPHER_SUITE },
1776	{ "tls_protocol_min", offsetof(slap_bindconf, sb_tls_protocol_min), LDAP_OPT_X_TLS_PROTOCOL_MIN },
1777	{0, 0}
1778};
1779
1780int bindconf_tls_set( slap_bindconf *bc, LDAP *ld )
1781{
1782	int i, rc, newctx = 0, res = 0;
1783	char *ptr = (char *)bc, **word;
1784
1785	bc->sb_tls_do_init = 0;
1786
1787	for (i=0; bindtlsopts[i].opt; i++) {
1788		word = (char **)(ptr + bindtlsopts[i].offset);
1789		if ( *word ) {
1790			rc = ldap_set_option( ld, bindtlsopts[i].opt, *word );
1791			if ( rc ) {
1792				Debug( LDAP_DEBUG_ANY,
1793					"bindconf_tls_set: failed to set %s to %s\n",
1794						bindtlsopts[i].key, *word, 0 );
1795				res = -1;
1796			} else
1797				newctx = 1;
1798		}
1799	}
1800	if ( bc->sb_tls_reqcert ) {
1801		rc = ldap_int_tls_config( ld, LDAP_OPT_X_TLS_REQUIRE_CERT,
1802			bc->sb_tls_reqcert );
1803		if ( rc ) {
1804			Debug( LDAP_DEBUG_ANY,
1805				"bindconf_tls_set: failed to set tls_reqcert to %s\n",
1806					bc->sb_tls_reqcert, 0, 0 );
1807			res = -1;
1808		} else
1809			newctx = 1;
1810	}
1811	if ( bc->sb_tls_protocol_min ) {
1812		rc = ldap_int_tls_config( ld, LDAP_OPT_X_TLS_PROTOCOL_MIN,
1813			bc->sb_tls_protocol_min );
1814		if ( rc ) {
1815			Debug( LDAP_DEBUG_ANY,
1816				"bindconf_tls_set: failed to set tls_protocol_min to %s\n",
1817					bc->sb_tls_protocol_min, 0, 0 );
1818			res = -1;
1819		} else
1820			newctx = 1;
1821	}
1822#ifdef HAVE_OPENSSL_CRL
1823	if ( bc->sb_tls_crlcheck ) {
1824		rc = ldap_int_tls_config( ld, LDAP_OPT_X_TLS_CRLCHECK,
1825			bc->sb_tls_crlcheck );
1826		if ( rc ) {
1827			Debug( LDAP_DEBUG_ANY,
1828				"bindconf_tls_set: failed to set tls_crlcheck to %s\n",
1829					bc->sb_tls_crlcheck, 0, 0 );
1830			res = -1;
1831		} else
1832			newctx = 1;
1833	}
1834#endif
1835	if ( newctx ) {
1836		int opt = 0;
1837
1838		if ( bc->sb_tls_ctx ) {
1839			ldap_pvt_tls_ctx_free( bc->sb_tls_ctx );
1840			bc->sb_tls_ctx = NULL;
1841		}
1842		rc = ldap_set_option( ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
1843		if ( rc )
1844			res = rc;
1845		else
1846			ldap_get_option( ld, LDAP_OPT_X_TLS_CTX, &bc->sb_tls_ctx );
1847	}
1848
1849	return res;
1850}
1851#endif
1852
1853/*
1854 * connect to a client using the bindconf data
1855 * note: should move "version" into bindconf...
1856 */
1857int
1858slap_client_connect( LDAP **ldp, slap_bindconf *sb )
1859{
1860	LDAP		*ld = NULL;
1861	int		rc;
1862	struct timeval tv;
1863
1864	/* Init connection to master */
1865	rc = ldap_initialize( &ld, sb->sb_uri.bv_val );
1866	if ( rc != LDAP_SUCCESS ) {
1867		Debug( LDAP_DEBUG_ANY,
1868			"slap_client_connect: "
1869			"ldap_initialize(%s) failed (%d)\n",
1870			sb->sb_uri.bv_val, rc, 0 );
1871		return rc;
1872	}
1873
1874	if ( sb->sb_version != 0 ) {
1875		ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
1876			(const void *)&sb->sb_version );
1877	}
1878
1879	if ( sb->sb_timeout_api ) {
1880		tv.tv_sec = sb->sb_timeout_api;
1881		tv.tv_usec = 0;
1882		ldap_set_option( ld, LDAP_OPT_TIMEOUT, &tv );
1883	}
1884
1885	if ( sb->sb_timeout_net ) {
1886		tv.tv_sec = sb->sb_timeout_net;
1887		tv.tv_usec = 0;
1888		ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, &tv );
1889	}
1890
1891	if ( sb->sb_keepalive.sk_idle ) {
1892		ldap_set_option( ld, LDAP_OPT_X_KEEPALIVE_IDLE, &sb->sb_keepalive.sk_idle );
1893	}
1894
1895	if ( sb->sb_keepalive.sk_probes ) {
1896		ldap_set_option( ld, LDAP_OPT_X_KEEPALIVE_PROBES, &sb->sb_keepalive.sk_probes );
1897	}
1898
1899	if ( sb->sb_keepalive.sk_interval ) {
1900		ldap_set_option( ld, LDAP_OPT_X_KEEPALIVE_INTERVAL, &sb->sb_keepalive.sk_interval );
1901	}
1902
1903#ifdef HAVE_TLS
1904	if ( sb->sb_tls_do_init ) {
1905		rc = bindconf_tls_set( sb, ld );
1906
1907	} else if ( sb->sb_tls_ctx ) {
1908		rc = ldap_set_option( ld, LDAP_OPT_X_TLS_CTX,
1909			sb->sb_tls_ctx );
1910	}
1911
1912	if ( rc ) {
1913		Debug( LDAP_DEBUG_ANY,
1914			"slap_client_connect: "
1915			"URI=%s TLS context initialization failed (%d)\n",
1916			sb->sb_uri.bv_val, rc, 0 );
1917		return rc;
1918	}
1919#endif
1920
1921	/* Bind */
1922	if ( sb->sb_tls ) {
1923		rc = ldap_start_tls_s( ld, NULL, NULL );
1924		if ( rc != LDAP_SUCCESS ) {
1925			Debug( LDAP_DEBUG_ANY,
1926				"slap_client_connect: URI=%s "
1927				"%s, ldap_start_tls failed (%d)\n",
1928				sb->sb_uri.bv_val,
1929				sb->sb_tls == SB_TLS_CRITICAL ?
1930					"Error" : "Warning",
1931				rc );
1932			if ( sb->sb_tls == SB_TLS_CRITICAL ) {
1933				goto done;
1934			}
1935		}
1936	}
1937
1938	if ( sb->sb_method == LDAP_AUTH_SASL ) {
1939#ifdef HAVE_CYRUS_SASL
1940		void *defaults;
1941
1942		if ( sb->sb_secprops != NULL ) {
1943			rc = ldap_set_option( ld,
1944				LDAP_OPT_X_SASL_SECPROPS, sb->sb_secprops);
1945
1946			if( rc != LDAP_OPT_SUCCESS ) {
1947				Debug( LDAP_DEBUG_ANY,
1948					"slap_client_connect: "
1949					"error, ldap_set_option "
1950					"(%s,SECPROPS,\"%s\") failed!\n",
1951					sb->sb_uri.bv_val, sb->sb_secprops, 0 );
1952				goto done;
1953			}
1954		}
1955
1956		defaults = lutil_sasl_defaults( ld,
1957			sb->sb_saslmech.bv_val,
1958			sb->sb_realm.bv_val,
1959			sb->sb_authcId.bv_val,
1960			sb->sb_cred.bv_val,
1961			sb->sb_authzId.bv_val );
1962		if ( defaults == NULL ) {
1963			rc = LDAP_OTHER;
1964			goto done;
1965		}
1966
1967		rc = ldap_sasl_interactive_bind_s( ld,
1968				sb->sb_binddn.bv_val,
1969				sb->sb_saslmech.bv_val,
1970				NULL, NULL,
1971				LDAP_SASL_QUIET,
1972				lutil_sasl_interact,
1973				defaults );
1974
1975		lutil_sasl_freedefs( defaults );
1976
1977		/* FIXME: different error behaviors according to
1978		 *	1) return code
1979		 *	2) on err policy : exit, retry, backoff ...
1980		 */
1981		if ( rc != LDAP_SUCCESS ) {
1982			static struct berval bv_GSSAPI = BER_BVC( "GSSAPI" );
1983
1984			Debug( LDAP_DEBUG_ANY, "slap_client_connect: URI=%s "
1985				"ldap_sasl_interactive_bind_s failed (%d)\n",
1986				sb->sb_uri.bv_val, rc, 0 );
1987
1988			/* FIXME (see above comment) */
1989			/* if Kerberos credentials cache is not active, retry */
1990			if ( ber_bvcmp( &sb->sb_saslmech, &bv_GSSAPI ) == 0 &&
1991				rc == LDAP_LOCAL_ERROR )
1992			{
1993				rc = LDAP_SERVER_DOWN;
1994			}
1995
1996			goto done;
1997		}
1998#else /* HAVE_CYRUS_SASL */
1999		/* Should never get here, we trapped this at config time */
2000		assert(0);
2001		Debug( LDAP_DEBUG_SYNC, "not compiled with SASL support\n", 0, 0, 0 );
2002		rc = LDAP_OTHER;
2003		goto done;
2004#endif
2005
2006	} else if ( sb->sb_method == LDAP_AUTH_SIMPLE ) {
2007		rc = ldap_sasl_bind_s( ld,
2008			sb->sb_binddn.bv_val, LDAP_SASL_SIMPLE,
2009			&sb->sb_cred, NULL, NULL, NULL );
2010		if ( rc != LDAP_SUCCESS ) {
2011			Debug( LDAP_DEBUG_ANY, "slap_client_connect: "
2012				"URI=%s DN=\"%s\" "
2013				"ldap_sasl_bind_s failed (%d)\n",
2014				sb->sb_uri.bv_val, sb->sb_binddn.bv_val, rc );
2015			goto done;
2016		}
2017	}
2018
2019done:;
2020	if ( rc ) {
2021		if ( ld ) {
2022			ldap_unbind_ext( ld, NULL, NULL );
2023			*ldp = NULL;
2024		}
2025
2026	} else {
2027		*ldp = ld;
2028	}
2029
2030	return rc;
2031}
2032
2033/* -------------------------------------- */
2034
2035
2036static char *
2037strtok_quote( char *line, char *sep, char **quote_ptr )
2038{
2039	int		inquote;
2040	char		*tmp;
2041	static char	*next;
2042
2043	*quote_ptr = NULL;
2044	if ( line != NULL ) {
2045		next = line;
2046	}
2047	while ( *next && strchr( sep, *next ) ) {
2048		next++;
2049	}
2050
2051	if ( *next == '\0' ) {
2052		next = NULL;
2053		return( NULL );
2054	}
2055	tmp = next;
2056
2057	for ( inquote = 0; *next; ) {
2058		switch ( *next ) {
2059		case '"':
2060			if ( inquote ) {
2061				inquote = 0;
2062			} else {
2063				inquote = 1;
2064			}
2065			AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
2066			break;
2067
2068		case '\\':
2069			if ( next[1] )
2070				AC_MEMCPY( next,
2071					    next + 1, strlen( next + 1 ) + 1 );
2072			next++;		/* dont parse the escaped character */
2073			break;
2074
2075		default:
2076			if ( ! inquote ) {
2077				if ( strchr( sep, *next ) != NULL ) {
2078					*quote_ptr = next;
2079					*next++ = '\0';
2080					return( tmp );
2081				}
2082			}
2083			next++;
2084			break;
2085		}
2086	}
2087
2088	return( tmp );
2089}
2090
2091static char	buf[AC_LINE_MAX];
2092static char	*line;
2093static size_t lmax, lcur;
2094
2095#define CATLINE( buf ) \
2096	do { \
2097		size_t len = strlen( buf ); \
2098		while ( lcur + len + 1 > lmax ) { \
2099			lmax += AC_LINE_MAX; \
2100			line = (char *) ch_realloc( line, lmax ); \
2101		} \
2102		strcpy( line + lcur, buf ); \
2103		lcur += len; \
2104	} while( 0 )
2105
2106static void
2107fp_getline_init(ConfigArgs *c) {
2108	c->lineno = -1;
2109	buf[0] = '\0';
2110}
2111
2112static int
2113fp_getline( FILE *fp, ConfigArgs *c )
2114{
2115	char	*p;
2116
2117	lcur = 0;
2118	CATLINE(buf);
2119	c->lineno++;
2120
2121	/* avoid stack of bufs */
2122	if ( strncasecmp( line, "include", STRLENOF( "include" ) ) == 0 ) {
2123		buf[0] = '\0';
2124		c->line = line;
2125		return(1);
2126	}
2127
2128	while ( fgets( buf, sizeof( buf ), fp ) ) {
2129		p = strchr( buf, '\n' );
2130		if ( p ) {
2131			if ( p > buf && p[-1] == '\r' ) {
2132				--p;
2133			}
2134			*p = '\0';
2135		}
2136		/* XXX ugly */
2137		c->line = line;
2138		if ( line[0]
2139				&& ( p = line + strlen( line ) - 1 )[0] == '\\'
2140				&& p[-1] != '\\' )
2141		{
2142			p[0] = '\0';
2143			lcur--;
2144
2145		} else {
2146			if ( !isspace( (unsigned char)buf[0] ) ) {
2147				return(1);
2148			}
2149			buf[0] = ' ';
2150		}
2151		CATLINE(buf);
2152		c->lineno++;
2153	}
2154
2155	buf[0] = '\0';
2156	c->line = line;
2157	return(line[0] ? 1 : 0);
2158}
2159
2160int
2161config_fp_parse_line(ConfigArgs *c)
2162{
2163	char *token;
2164	static char *const hide[] = {
2165		"rootpw", "replica", "syncrepl",  /* in slapd */
2166		"acl-bind", "acl-method", "idassert-bind",  /* in back-ldap */
2167		"acl-passwd", "bindpw",  /* in back-<ldap/meta> */
2168		"pseudorootpw",  /* in back-meta */
2169		"dbpasswd",  /* in back-sql */
2170		NULL
2171	};
2172	char *quote_ptr;
2173	int i = (int)(sizeof(hide)/sizeof(hide[0])) - 1;
2174
2175	c->tline = ch_strdup(c->line);
2176	token = strtok_quote(c->tline, " \t", &quote_ptr);
2177
2178	if(token) for(i = 0; hide[i]; i++) if(!strcasecmp(token, hide[i])) break;
2179	if(quote_ptr) *quote_ptr = ' ';
2180	Debug(LDAP_DEBUG_CONFIG, "line %d (%s%s)\n", c->lineno,
2181		hide[i] ? hide[i] : c->line, hide[i] ? " ***" : "");
2182	if(quote_ptr) *quote_ptr = '\0';
2183
2184	for(;; token = strtok_quote(NULL, " \t", &quote_ptr)) {
2185		if(c->argc >= c->argv_size) {
2186			char **tmp;
2187			tmp = ch_realloc(c->argv, (c->argv_size + ARGS_STEP) * sizeof(*c->argv));
2188			if(!tmp) {
2189				Debug(LDAP_DEBUG_ANY, "line %d: out of memory\n", c->lineno, 0, 0);
2190				return -1;
2191			}
2192			c->argv = tmp;
2193			c->argv_size += ARGS_STEP;
2194		}
2195		if(token == NULL)
2196			break;
2197		c->argv[c->argc++] = token;
2198	}
2199	c->argv[c->argc] = NULL;
2200	return(0);
2201}
2202
2203void
2204config_destroy( )
2205{
2206	ucdata_unload( UCDATA_ALL );
2207	if ( frontendDB ) {
2208		/* NOTE: in case of early exit, frontendDB can be NULL */
2209		if ( frontendDB->be_schemandn.bv_val )
2210			free( frontendDB->be_schemandn.bv_val );
2211		if ( frontendDB->be_schemadn.bv_val )
2212			free( frontendDB->be_schemadn.bv_val );
2213		if ( frontendDB->be_acl )
2214			acl_destroy( frontendDB->be_acl );
2215	}
2216	free( line );
2217	if ( slapd_args_file )
2218		free ( slapd_args_file );
2219	if ( slapd_pid_file )
2220		free ( slapd_pid_file );
2221	if ( default_passwd_hash )
2222		ldap_charray_free( default_passwd_hash );
2223}
2224
2225char **
2226slap_str2clist( char ***out, char *in, const char *brkstr )
2227{
2228	char	*str;
2229	char	*s;
2230	char	*lasts;
2231	int	i, j;
2232	char	**new;
2233
2234	/* find last element in list */
2235	for (i = 0; *out && (*out)[i]; i++);
2236
2237	/* protect the input string from strtok */
2238	str = ch_strdup( in );
2239
2240	if ( *str == '\0' ) {
2241		free( str );
2242		return( *out );
2243	}
2244
2245	/* Count words in string */
2246	j=1;
2247	for ( s = str; *s; s++ ) {
2248		if ( strchr( brkstr, *s ) != NULL ) {
2249			j++;
2250		}
2251	}
2252
2253	*out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) );
2254	new = *out + i;
2255	for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
2256		s != NULL;
2257		s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
2258	{
2259		*new = ch_strdup( s );
2260		new++;
2261	}
2262
2263	*new = NULL;
2264	free( str );
2265	return( *out );
2266}
2267
2268int config_generic_wrapper( Backend *be, const char *fname, int lineno,
2269	int argc, char **argv )
2270{
2271	ConfigArgs c = { 0 };
2272	ConfigTable *ct;
2273	int rc;
2274
2275	c.be = be;
2276	c.fname = fname;
2277	c.lineno = lineno;
2278	c.argc = argc;
2279	c.argv = argv;
2280	c.valx = -1;
2281	c.line = line;
2282	c.op = SLAP_CONFIG_ADD;
2283	snprintf( c.log, sizeof( c.log ), "%s: line %d", fname, lineno );
2284
2285	rc = SLAP_CONF_UNKNOWN;
2286	ct = config_find_keyword( be->be_cf_ocs->co_table, &c );
2287	if ( ct ) {
2288		c.table = be->be_cf_ocs->co_type;
2289		rc = config_add_vals( ct, &c );
2290	}
2291	return rc;
2292}
2293
2294/* See if the given URL (in plain and parsed form) matches
2295 * any of the server's listener addresses. Return matching
2296 * Listener or NULL for no match.
2297 */
2298Listener *config_check_my_url( const char *url, LDAPURLDesc *lud )
2299{
2300	Listener **l = slapd_get_listeners();
2301	int i, isMe;
2302
2303	/* Try a straight compare with Listener strings */
2304	for ( i=0; l && l[i]; i++ ) {
2305		if ( !strcasecmp( url, l[i]->sl_url.bv_val )) {
2306			return l[i];
2307		}
2308	}
2309
2310	isMe = 0;
2311	/* If hostname is empty, or is localhost, or matches
2312	 * our hostname, this url refers to this host.
2313	 * Compare it against listeners and ports.
2314	 */
2315	if ( !lud->lud_host || !lud->lud_host[0] ||
2316		!strncasecmp("localhost", lud->lud_host,
2317			STRLENOF("localhost")) ||
2318		!strcasecmp( global_host, lud->lud_host )) {
2319
2320		for ( i=0; l && l[i]; i++ ) {
2321			LDAPURLDesc *lu2;
2322			ldap_url_parse( l[i]->sl_url.bv_val, &lu2 );
2323			do {
2324				if ( strcasecmp( lud->lud_scheme,
2325					lu2->lud_scheme ))
2326					break;
2327				if ( lud->lud_port != lu2->lud_port )
2328					break;
2329				/* Listener on ANY address */
2330				if ( !lu2->lud_host || !lu2->lud_host[0] ) {
2331					isMe = 1;
2332					break;
2333				}
2334				/* URL on ANY address */
2335				if ( !lud->lud_host || !lud->lud_host[0] ) {
2336					isMe = 1;
2337					break;
2338				}
2339				/* Listener has specific host, must
2340				 * match it
2341				 */
2342				if ( !strcasecmp( lud->lud_host,
2343					lu2->lud_host )) {
2344					isMe = 1;
2345					break;
2346				}
2347			} while(0);
2348			ldap_free_urldesc( lu2 );
2349			if ( isMe ) {
2350				return l[i];
2351			}
2352		}
2353	}
2354	return NULL;
2355}
2356