xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/config.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: config.c,v 1.1.1.3 2010/12/12 15:22:26 adam Exp $	*/
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  */
60 slap_mask_t		global_allows = 0;
61 slap_mask_t		global_disallows = 0;
62 int		global_gentlehup = 0;
63 int		global_idletimeout = 0;
64 int		global_writetimeout = 0;
65 char	*global_host = NULL;
66 struct berval global_host_bv = BER_BVNULL;
67 char	*global_realm = NULL;
68 char	*sasl_host = NULL;
69 char		**default_passwd_hash = NULL;
70 struct berval default_search_base = BER_BVNULL;
71 struct berval default_search_nbase = BER_BVNULL;
72 
73 ber_len_t sockbuf_max_incoming = SLAP_SB_MAX_INCOMING_DEFAULT;
74 ber_len_t sockbuf_max_incoming_auth= SLAP_SB_MAX_INCOMING_AUTH;
75 
76 int	slap_conn_max_pending = SLAP_CONN_MAX_PENDING_DEFAULT;
77 int	slap_conn_max_pending_auth = SLAP_CONN_MAX_PENDING_AUTH;
78 
79 char   *slapd_pid_file  = NULL;
80 char   *slapd_args_file = NULL;
81 
82 int use_reverse_lookup = 0;
83 
84 #ifdef LDAP_SLAPI
85 int slapi_plugins_used = 0;
86 #endif
87 
88 static int fp_getline(FILE *fp, ConfigArgs *c);
89 static void fp_getline_init(ConfigArgs *c);
90 
91 static char	*strtok_quote(char *line, char *sep, char **quote_ptr);
92 static char *strtok_quote_ldif(char **line);
93 
94 ConfigArgs *
95 new_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 
109 void
110 init_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 
116 ConfigTable *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 
126 int config_check_vals(ConfigTable *Conf, ConfigArgs *c, int check_only ) {
127 	int rc, arg_user, arg_type, arg_syn, iarg;
128 	unsigned uiarg;
129 	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 
328 int 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 
398 int 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 
412 int
413 config_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 
427 int
428 config_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 
526 int
527 init_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 
542 int
543 init_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  */
562 static char *
563 strtok_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 
614 static void
615 config_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 
633 int
634 config_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 
661 int
662 config_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 
686 int
687 read_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 
877 done:
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 
891 int
892 bverb_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 
900 int
901 verb_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 
907 int
908 verbs_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  */
922 int
923 mask_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 
940 int
941 slap_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 
961 int
962 slap_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 
977 int
978 slap_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 		}
1016 check_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 
1027 int
1028 enum_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 */
1043 static int
1044 slap_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 
1083 static 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 
1167 slap_verbmasks *slap_ldap_response_code = slap_ldap_response_code_;
1168 
1169 int
1170 slap_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
1177 static 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 
1184 static 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 
1191 static 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 
1200 static 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 
1209 static slap_verbmasks versionkey[] = {
1210 	{ BER_BVC("2"),		LDAP_VERSION2 },
1211 	{ BER_BVC("3"),		LDAP_VERSION3 },
1212 	{ BER_BVNULL, 0 }
1213 };
1214 
1215 static int
1216 slap_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 
1301 static int
1302 slap_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 
1325 static 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 
1368 int
1369 slap_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 
1473 int
1474 slap_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 
1587 int
1588 slap_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 
1624 int
1625 bindconf_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 
1636 int
1637 bindconf_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 
1645 int
1646 bindconf_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 
1657 int
1658 bindconf_unparse( slap_bindconf *bc, struct berval *bv )
1659 {
1660 	return slap_cf_aux_table_unparse( bc, bv, bindkey );
1661 }
1662 
1663 void 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 
1734 void
1735 bindconf_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
1766 static 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 
1780 int 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  */
1857 int
1858 slap_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 
2019 done:;
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 
2036 static char *
2037 strtok_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 
2091 static char	buf[AC_LINE_MAX];
2092 static char	*line;
2093 static 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 
2106 static void
2107 fp_getline_init(ConfigArgs *c) {
2108 	c->lineno = -1;
2109 	buf[0] = '\0';
2110 }
2111 
2112 static int
2113 fp_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 
2160 int
2161 config_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 
2203 void
2204 config_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 
2225 char **
2226 slap_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 
2268 int 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  */
2298 Listener *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