xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-asyncmeta/config.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: config.c,v 1.2 2021/08/14 16:14:59 christos Exp $	*/
2 
3 /* config.c - configuration parsing for back-asyncmeta */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2016-2021 The OpenLDAP Foundation.
8  * Portions Copyright 2016 Symas Corporation.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 
20 /* ACKNOWLEDGEMENTS:
21  * This work was developed by Symas Corporation
22  * based on back-meta module for inclusion in OpenLDAP Software.
23  * This work was sponsored by Ericsson. */
24 
25 #include <sys/cdefs.h>
26 __RCSID("$NetBSD: config.c,v 1.2 2021/08/14 16:14:59 christos Exp $");
27 
28 #include "portable.h"
29 
30 #include <stdio.h>
31 #include <ctype.h>
32 
33 #include <ac/string.h>
34 #include <ac/socket.h>
35 
36 #include "slap.h"
37 #include "slap-config.h"
38 #include "lutil.h"
39 #include "ldif.h"
40 #include "../back-ldap/back-ldap.h"
41 #include "back-asyncmeta.h"
42 
43 #ifdef LDAP_DEVEL
44 #define SLAP_AUTH_DN	1
45 #endif
46 
47 static ConfigDriver asyncmeta_back_cf_gen;
48 static ConfigLDAPadd asyncmeta_ldadd;
49 static ConfigCfAdd asyncmeta_cfadd;
50 
51 /* Three sets of enums:
52  *	1) attrs that are only valid in the base config
53  *	2) attrs that are valid in base or target
54  *	3) attrs that are only valid in a target
55  */
56 
57 /* Base attrs */
58 enum {
59 	LDAP_BACK_CFG_DNCACHE_TTL = 1,
60 	LDAP_BACK_CFG_IDLE_TIMEOUT,
61 	LDAP_BACK_CFG_ONERR,
62 	LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER,
63 	LDAP_BACK_CFG_CONNPOOLMAX,
64 	LDAP_BACK_CFG_MAX_TIMEOUT_OPS,
65 	LDAP_BACK_CFG_MAX_PENDING_OPS,
66 	LDAP_BACK_CFG_MAX_TARGET_CONNS,
67 	LDAP_BACK_CFG_LAST_BASE,
68 };
69 
70 /* Base or target */
71 enum {
72 	LDAP_BACK_CFG_BIND_TIMEOUT = LDAP_BACK_CFG_LAST_BASE,
73 	LDAP_BACK_CFG_CANCEL,
74 	LDAP_BACK_CFG_CHASE,
75 	LDAP_BACK_CFG_CLIENT_PR,
76 	LDAP_BACK_CFG_DEFAULT_T,
77 	LDAP_BACK_CFG_NETWORK_TIMEOUT,
78 	LDAP_BACK_CFG_NOREFS,
79 	LDAP_BACK_CFG_NOUNDEFFILTER,
80 	LDAP_BACK_CFG_NRETRIES,
81 	LDAP_BACK_CFG_QUARANTINE,
82 	LDAP_BACK_CFG_REBIND,
83 	LDAP_BACK_CFG_TIMEOUT,
84 	LDAP_BACK_CFG_VERSION,
85 	LDAP_BACK_CFG_ST_REQUEST,
86 	LDAP_BACK_CFG_T_F,
87 	LDAP_BACK_CFG_TLS,
88 	LDAP_BACK_CFG_LAST_BOTH
89 };
90 
91 /* Target attrs */
92 enum {
93 	LDAP_BACK_CFG_URI = LDAP_BACK_CFG_LAST_BOTH,
94 	LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
95 	LDAP_BACK_CFG_IDASSERT_BIND,
96 	LDAP_BACK_CFG_SUFFIXM,
97 	LDAP_BACK_CFG_SUBTREE_EX,
98 	LDAP_BACK_CFG_SUBTREE_IN,
99 	LDAP_BACK_CFG_KEEPALIVE,
100 	LDAP_BACK_CFG_FILTER,
101 	LDAP_BACK_CFG_TCP_USER_TIMEOUT,
102 	LDAP_BACK_CFG_LAST
103 };
104 
105 static ConfigTable a_metacfg[] = {
106 	{ "uri", "uri", 2, 0, 0,
107 		ARG_MAGIC|LDAP_BACK_CFG_URI,
108 		asyncmeta_back_cf_gen, "( OLcfgDbAt:0.14 "
109 			"NAME 'olcDbURI' "
110 			"DESC 'URI (list) for remote DSA' "
111 			"SYNTAX OMsDirectoryString "
112 			"SINGLE-VALUE )",
113 		NULL, NULL },
114 	{ "tls", "what", 2, 0, 0,
115 		ARG_MAGIC|LDAP_BACK_CFG_TLS,
116 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.1 "
117 			"NAME 'olcDbStartTLS' "
118 			"DESC 'StartTLS' "
119 			"SYNTAX OMsDirectoryString "
120 			"SINGLE-VALUE )",
121 		NULL, NULL },
122 	{ "idassert-bind", "args", 2, 0, 0,
123 		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_BIND,
124 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.7 "
125 			"NAME 'olcDbIDAssertBind' "
126 			"DESC 'Remote Identity Assertion administrative identity auth bind configuration' "
127 			"SYNTAX OMsDirectoryString "
128 			"SINGLE-VALUE )",
129 		NULL, NULL },
130 	{ "idassert-authzFrom", "authzRule", 2, 2, 0,
131 		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
132 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.9 "
133 			"NAME 'olcDbIDAssertAuthzFrom' "
134 			"DESC 'Remote Identity Assertion authz rules' "
135 			"EQUALITY caseIgnoreMatch "
136 			"SYNTAX OMsDirectoryString "
137 			"X-ORDERED 'VALUES' )",
138 		NULL, NULL },
139 	{ "rebind-as-user", "true|FALSE", 1, 2, 0,
140 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_REBIND,
141 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.10 "
142 			"NAME 'olcDbRebindAsUser' "
143 			"DESC 'Rebind as user' "
144 			"SYNTAX OMsBoolean "
145 			"SINGLE-VALUE )",
146 		NULL, NULL },
147 	{ "chase-referrals", "true|FALSE", 2, 2, 0,
148 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_CHASE,
149 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.11 "
150 			"NAME 'olcDbChaseReferrals' "
151 			"DESC 'Chase referrals' "
152 			"SYNTAX OMsBoolean "
153 			"SINGLE-VALUE )",
154 		NULL, NULL },
155 	{ "t-f-support", "true|FALSE|discover", 2, 2, 0,
156 		ARG_MAGIC|LDAP_BACK_CFG_T_F,
157 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.12 "
158 			"NAME 'olcDbTFSupport' "
159 			"DESC 'Absolute filters support' "
160 			"SYNTAX OMsDirectoryString "
161 			"SINGLE-VALUE )",
162 		NULL, NULL },
163 	{ "timeout", "timeout(list)", 2, 0, 0,
164 		ARG_MAGIC|LDAP_BACK_CFG_TIMEOUT,
165 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.14 "
166 			"NAME 'olcDbTimeout' "
167 			"DESC 'Per-operation timeouts' "
168 			"SYNTAX OMsDirectoryString "
169 			"SINGLE-VALUE )",
170 		NULL, NULL },
171 	{ "idle-timeout", "timeout", 2, 2, 0,
172 		ARG_MAGIC|LDAP_BACK_CFG_IDLE_TIMEOUT,
173 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.15 "
174 			"NAME 'olcDbIdleTimeout' "
175 			"DESC 'connection idle timeout' "
176 			"SYNTAX OMsDirectoryString "
177 			"SINGLE-VALUE )",
178 		NULL, NULL },
179 	{ "network-timeout", "timeout", 2, 2, 0,
180 		ARG_MAGIC|LDAP_BACK_CFG_NETWORK_TIMEOUT,
181 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.17 "
182 			"NAME 'olcDbNetworkTimeout' "
183 			"DESC 'connection network timeout' "
184 			"SYNTAX OMsDirectoryString "
185 			"SINGLE-VALUE )",
186 		NULL, NULL },
187 	{ "protocol-version", "version", 2, 2, 0,
188 		ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_VERSION,
189 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.18 "
190 			"NAME 'olcDbProtocolVersion' "
191 			"DESC 'protocol version' "
192 			"SYNTAX OMsInteger "
193 			"SINGLE-VALUE )",
194 		NULL, NULL },
195 
196 	{ "cancel", "ABANDON|ignore|exop", 2, 2, 0,
197 		ARG_MAGIC|LDAP_BACK_CFG_CANCEL,
198 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.20 "
199 			"NAME 'olcDbCancel' "
200 			"DESC 'abandon/ignore/exop operations when appropriate' "
201 			"SYNTAX OMsDirectoryString "
202 			"SINGLE-VALUE )",
203 		NULL, NULL },
204 	{ "quarantine", "retrylist", 2, 2, 0,
205 		ARG_MAGIC|LDAP_BACK_CFG_QUARANTINE,
206 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.21 "
207 			"NAME 'olcDbQuarantine' "
208 			"DESC 'Quarantine database if connection fails and retry according to rule' "
209 			"SYNTAX OMsDirectoryString "
210 			"SINGLE-VALUE )",
211 		NULL, NULL },
212 
213 	{ "conn-pool-max", "<n>", 2, 2, 0,
214 		ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_CONNPOOLMAX,
215 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.23 "
216 			"NAME 'olcDbConnectionPoolMax' "
217 			"DESC 'Max size of privileged connections pool' "
218 			"SYNTAX OMsInteger "
219 			"SINGLE-VALUE )",
220 		NULL, NULL },
221 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
222 	{ "session-tracking-request", "true|FALSE", 2, 2, 0,
223 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_ST_REQUEST,
224 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.24 "
225 			"NAME 'olcDbSessionTrackingRequest' "
226 			"DESC 'Add session tracking control to proxied requests' "
227 			"SYNTAX OMsBoolean "
228 			"SINGLE-VALUE )",
229 		NULL, NULL },
230 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
231 	{ "norefs", "true|FALSE", 2, 2, 0,
232 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_NOREFS,
233 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.25 "
234 			"NAME 'olcDbNoRefs' "
235 			"DESC 'Do not return search reference responses' "
236 			"SYNTAX OMsBoolean "
237 			"SINGLE-VALUE )",
238 		NULL, NULL },
239 	{ "noundeffilter", "true|FALSE", 2, 2, 0,
240 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_NOUNDEFFILTER,
241 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.26 "
242 			"NAME 'olcDbNoUndefFilter' "
243 			"DESC 'Do not propagate undefined search filters' "
244 			"SYNTAX OMsBoolean "
245 			"SINGLE-VALUE )",
246 		NULL, NULL },
247 
248 	{ "suffixmassage", "local> <remote", 2, 3, 0,
249 		ARG_MAGIC|LDAP_BACK_CFG_SUFFIXM,
250 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.117 "
251 			"NAME 'olcDbSuffixMassage' "
252 			"DESC 'DN suffix massage' "
253 			"EQUALITY caseIgnoreMatch "
254 			"SYNTAX OMsDirectoryString "
255 			"SINGLE-VALUE )",
256 		NULL, NULL },
257 
258 	{ "subtree-exclude", "pattern", 2, 2, 0,
259 		ARG_MAGIC|LDAP_BACK_CFG_SUBTREE_EX,
260 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.103 "
261 			"NAME 'olcDbSubtreeExclude' "
262 			"DESC 'DN of subtree to exclude from target' "
263 			"EQUALITY caseIgnoreMatch "
264 			"SYNTAX OMsDirectoryString )",
265 		NULL, NULL },
266 	{ "subtree-include", "pattern", 2, 2, 0,
267 		ARG_MAGIC|LDAP_BACK_CFG_SUBTREE_IN,
268 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.104 "
269 			"NAME 'olcDbSubtreeInclude' "
270 			"DESC 'DN of subtree to include in target' "
271 			"EQUALITY caseIgnoreMatch "
272 			"SYNTAX OMsDirectoryString )",
273 		NULL, NULL },
274 	{ "default-target", "[none|<target ID>]", 1, 2, 0,
275 		ARG_MAGIC|LDAP_BACK_CFG_DEFAULT_T,
276 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.105 "
277 			"NAME 'olcDbDefaultTarget' "
278 			"DESC 'Specify the default target' "
279 			"SYNTAX OMsDirectoryString "
280 			"SINGLE-VALUE )",
281 		NULL, NULL },
282 	{ "dncache-ttl", "ttl", 2, 2, 0,
283 		ARG_MAGIC|LDAP_BACK_CFG_DNCACHE_TTL,
284 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.106 "
285 			"NAME 'olcDbDnCacheTtl' "
286 			"DESC 'dncache ttl' "
287 			"SYNTAX OMsDirectoryString "
288 			"SINGLE-VALUE )",
289 		NULL, NULL },
290 	{ "bind-timeout", "microseconds", 2, 2, 0,
291 		ARG_MAGIC|ARG_ULONG|LDAP_BACK_CFG_BIND_TIMEOUT,
292 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.107 "
293 			"NAME 'olcDbBindTimeout' "
294 			"DESC 'bind timeout' "
295 			"SYNTAX OMsDirectoryString "
296 			"SINGLE-VALUE )",
297 		NULL, NULL },
298 	{ "onerr", "CONTINUE|report|stop", 2, 2, 0,
299 		ARG_MAGIC|LDAP_BACK_CFG_ONERR,
300 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.108 "
301 			"NAME 'olcDbOnErr' "
302 			"DESC 'error handling' "
303 			"SYNTAX OMsDirectoryString "
304 			"SINGLE-VALUE )",
305 		NULL, NULL },
306 	{ "pseudoroot-bind-defer", "TRUE|false", 2, 2, 0,
307 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER,
308 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.109 "
309 			"NAME 'olcDbPseudoRootBindDefer' "
310 			"DESC 'error handling' "
311 			"SYNTAX OMsBoolean "
312 			"SINGLE-VALUE )",
313 		NULL, NULL },
314 	{ "root-bind-defer", "TRUE|false", 2, 2, 0,
315 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER,
316 		asyncmeta_back_cf_gen, NULL, NULL, NULL },
317 	{ "nretries", "NEVER|forever|<number>", 2, 2, 0,
318 		ARG_MAGIC|LDAP_BACK_CFG_NRETRIES,
319 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.110 "
320 			"NAME 'olcDbNretries' "
321 			"DESC 'retry handling' "
322 			"SYNTAX OMsDirectoryString "
323 			"SINGLE-VALUE )",
324 		NULL, NULL },
325 	{ "client-pr", "accept-unsolicited|disable|<size>", 2, 2, 0,
326 		ARG_MAGIC|LDAP_BACK_CFG_CLIENT_PR,
327 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.111 "
328 			"NAME 'olcDbClientPr' "
329 			"DESC 'PagedResults handling' "
330 			"SYNTAX OMsDirectoryString "
331 			"SINGLE-VALUE )",
332 		NULL, NULL },
333 
334 	{ "", "", 0, 0, 0, ARG_IGNORED,
335 		NULL, "( OLcfgDbAt:3.116 NAME 'olcAsyncMetaSub' "
336 			"DESC 'Placeholder to name a Target entry' "
337 			"EQUALITY caseIgnoreMatch "
338 			"SYNTAX OMsDirectoryString "
339 			"SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
340 
341 	{ "keepalive", "keepalive", 2, 2, 0,
342 		ARG_MAGIC|LDAP_BACK_CFG_KEEPALIVE,
343 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.29 "
344 			"NAME 'olcDbKeepalive' "
345 			"DESC 'TCP keepalive' "
346 			"SYNTAX OMsDirectoryString "
347 			"SINGLE-VALUE )",
348 		NULL, NULL },
349 
350 	{ "tcp-user-timeout", "milliseconds", 2, 2, 0,
351 		ARG_MAGIC|ARG_UINT|LDAP_BACK_CFG_TCP_USER_TIMEOUT,
352 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.30 "
353 			"NAME 'olcDbTcpUserTimeout' "
354 			"DESC 'TCP User Timeout' "
355 			"SYNTAX OMsInteger "
356 			"SINGLE-VALUE )",
357 		NULL, NULL },
358 
359 	{ "filter", "pattern", 2, 2, 0,
360 		ARG_MAGIC|LDAP_BACK_CFG_FILTER,
361 		asyncmeta_back_cf_gen, "( OLcfgDbAt:3.112 "
362 			"NAME 'olcDbFilter' "
363 			"DESC 'Filter regex pattern to include in target' "
364 			"EQUALITY caseExactMatch "
365 			"SYNTAX OMsDirectoryString )",
366 		NULL, NULL },
367 
368 	{ "max-pending-ops", "<n>", 2, 2, 0,
369 	  ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_MAX_PENDING_OPS,
370 	  asyncmeta_back_cf_gen, "( OLcfgDbAt:3.113 "
371 	  "NAME 'olcDbMaxPendingOps' "
372 	  "DESC 'Maximum number of pending operations' "
373 	  "SYNTAX OMsInteger "
374 	  "SINGLE-VALUE )",
375 	  NULL, NULL },
376 
377 	{ "max-target-conns", "<n>", 2, 2, 0,
378 	  ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_MAX_TARGET_CONNS,
379 	  asyncmeta_back_cf_gen, "( OLcfgDbAt:3.114 "
380 	  "NAME 'olcDbMaxTargetConns' "
381 	  "DESC 'Maximum number of open connections per target' "
382 	  "SYNTAX OMsInteger "
383 	  "SINGLE-VALUE )",
384 	  NULL, NULL },
385 
386 	{ "max-timeout-ops", "<n>", 2, 2, 0,
387 	  ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_MAX_TIMEOUT_OPS,
388 	  asyncmeta_back_cf_gen, "( OLcfgDbAt:3.115 "
389 	  "NAME 'olcDbMaxTimeoutOps' "
390 	  "DESC 'Maximum number of consecutive timeout operations after which the connection is reset' "
391 	  "SYNTAX OMsInteger "
392 	  "SINGLE-VALUE )",
393 	  NULL, NULL },
394 
395 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED,
396 		NULL, NULL, NULL, NULL }
397 };
398 
399 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
400 #define	ST_ATTR "$ olcDbSessionTrackingRequest "
401 #else
402 #define	ST_ATTR ""
403 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
404 
405 #define COMMON_ATTRS	\
406 			"$ olcDbBindTimeout " \
407 			"$ olcDbCancel " \
408 			"$ olcDbChaseReferrals " \
409 			"$ olcDbClientPr " \
410 			"$ olcDbDefaultTarget " \
411 			"$ olcDbNetworkTimeout " \
412 			"$ olcDbNoRefs " \
413 			"$ olcDbNoUndefFilter " \
414 			"$ olcDbNretries " \
415 			"$ olcDbProtocolVersion " \
416 			"$ olcDbQuarantine " \
417 			"$ olcDbRebindAsUser " \
418 			ST_ATTR \
419 			"$ olcDbStartTLS " \
420 			"$ olcDbTFSupport "
421 
422 static ConfigOCs a_metaocs[] = {
423 	{ "( OLcfgDbOc:3.4 "
424 		"NAME 'olcAsyncMetaConfig' "
425 		"DESC 'Asyncmeta backend configuration' "
426 		"SUP olcDatabaseConfig "
427 		"MAY ( olcDbDnCacheTtl "
428 			"$ olcDbIdleTimeout "
429 			"$ olcDbOnErr "
430 			"$ olcDbPseudoRootBindDefer "
431 			"$ olcDbConnectionPoolMax "
432 	                "$ olcDbMaxTimeoutOps"
433 	                "$ olcDbMaxPendingOps "
434 	                "$ olcDbMaxTargetConns"
435 			/* defaults, may be overridden per-target */
436 			COMMON_ATTRS
437 		") )",
438 			Cft_Database, a_metacfg, NULL, asyncmeta_cfadd },
439 	{ "( OLcfgDbOc:3.5 "
440 		"NAME 'olcAsyncMetaTargetConfig' "
441 		"DESC 'Asyncmeta target configuration' "
442 		"SUP olcConfig STRUCTURAL "
443 		"MUST ( olcAsyncMetaSub $ olcDbURI ) "
444 		"MAY ( olcDbIDAssertAuthzFrom "
445 			"$ olcDbIDAssertBind "
446 			"$ olcDbSuffixMassage "
447 			"$ olcDbSubtreeExclude "
448 			"$ olcDbSubtreeInclude "
449 			"$ olcDbTimeout "
450 			"$ olcDbKeepalive "
451 			"$ olcDbFilter "
452 			"$ olcDbTcpUserTimeout "
453 
454 			/* defaults may be inherited */
455 			COMMON_ATTRS
456 		") )",
457 			Cft_Misc, a_metacfg, asyncmeta_ldadd },
458 	{ NULL, 0, NULL }
459 };
460 
461 static int
asyncmeta_ldadd(CfEntryInfo * p,Entry * e,ConfigArgs * c)462 asyncmeta_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *c )
463 {
464 	if ( p->ce_type != Cft_Database || !p->ce_be ||
465 		p->ce_be->be_cf_ocs != a_metaocs )
466 		return LDAP_CONSTRAINT_VIOLATION;
467 
468 	c->be = p->ce_be;
469 	return LDAP_SUCCESS;
470 }
471 
472 static int
asyncmeta_cfadd(Operation * op,SlapReply * rs,Entry * p,ConfigArgs * c)473 asyncmeta_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *c )
474 {
475 	a_metainfo_t	*mi = ( a_metainfo_t * )c->be->be_private;
476 	struct berval bv;
477 	int i;
478 
479 	bv.bv_val = c->cr_msg;
480 	for ( i=0; i<mi->mi_ntargets; i++ ) {
481 		bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg),
482 			"olcAsyncMetaSub=" SLAP_X_ORDERED_FMT "uri", i );
483 		c->ca_private = mi->mi_targets[i];
484 		c->valx = i;
485 		config_build_entry( op, rs, p->e_private, c,
486 			&bv, &a_metaocs[1], NULL );
487 	}
488 
489 	return LDAP_SUCCESS;
490 }
491 
492 static int
asyncmeta_back_new_target(a_metatarget_t ** mtp)493 asyncmeta_back_new_target(
494 	a_metatarget_t	**mtp )
495 {
496 	a_metatarget_t		*mt;
497 
498 	*mtp = NULL;
499 
500 	mt = ch_calloc( sizeof( a_metatarget_t ), 1 );
501 
502 	ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex );
503 
504 	mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY;
505 	mt->mt_idassert_authmethod = LDAP_AUTH_NONE;
506 	mt->mt_idassert_tls = SB_TLS_DEFAULT;
507 	/* by default, use proxyAuthz control on each operation */
508 	mt->mt_idassert_flags = LDAP_BACK_AUTH_PRESCRIPTIVE;
509 
510 	*mtp = mt;
511 
512 	return 0;
513 }
514 
515 /* suffixmassage config */
516 static int
asyncmeta_suffixm_config(ConfigArgs * c,int argc,char ** argv,a_metatarget_t * mt)517 asyncmeta_suffixm_config(
518 	ConfigArgs *c,
519 	int argc,
520 	char **argv,
521 	a_metatarget_t *mt
522 )
523 {
524 	BackendDB 	*tmp_bd;
525 	struct berval	dn, nvnc, pvnc, nrnc, prnc;
526 	int j;
527 
528 	/*
529 	 * syntax:
530 	 *
531 	 * 	suffixmassage <local suffix> <remote suffix>
532 	 *
533 	 * the <local suffix> field must be defined as a valid suffix
534 	 * (or suffixAlias?) for the current database;
535 	 * the <remote suffix> shouldn't have already been
536 	 * defined as a valid suffix or suffixAlias for the
537 	 * current server
538 	 */
539 
540 	ber_str2bv( argv[ 1 ], 0, 0, &dn );
541 	if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
542 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
543 			"suffix \"%s\" is invalid",
544 			argv[1] );
545 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
546 		return 1;
547 	}
548 
549 	for ( j = 0; !BER_BVISNULL( &c->be->be_nsuffix[ j ] ); j++ ) {
550 		if ( dnIsSuffix( &nvnc, &c->be->be_nsuffix[ 0 ] ) ) {
551 			break;
552 		}
553 	}
554 
555 	if ( BER_BVISNULL( &c->be->be_nsuffix[ j ] ) ) {
556 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
557 			"suffix \"%s\" must be within the database naming context",
558 			argv[1] );
559 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
560 		free( pvnc.bv_val );
561 		free( nvnc.bv_val );
562 		return 1;
563 	}
564 
565 	ber_str2bv( argv[ 2 ], 0, 0, &dn );
566 	if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
567 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
568 			"massaged suffix \"%s\" is invalid",
569 			argv[2] );
570 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
571 		free( pvnc.bv_val );
572 		free( nvnc.bv_val );
573 		return 1;
574 	}
575 
576 	tmp_bd = select_backend( &nrnc, 0 );
577 	if ( tmp_bd != NULL && tmp_bd->be_private == c->be->be_private ) {
578 		Debug( LDAP_DEBUG_ANY,
579 	"%s: warning: <massaged suffix> \"%s\" resolves to this database, in "
580 	"\"suffixMassage <suffix> <massaged suffix>\"\n",
581 			c->log, prnc.bv_val );
582 	}
583 
584 	mt->mt_lsuffixm = pvnc;
585 	mt->mt_rsuffixm = prnc;
586 
587 	free( nvnc.bv_val );
588 	free( nrnc.bv_val );
589 
590 	return 0;
591 }
592 
593 int
asyncmeta_subtree_free(a_metasubtree_t * ms)594 asyncmeta_subtree_free( a_metasubtree_t *ms )
595 {
596 	switch ( ms->ms_type ) {
597 	case META_ST_SUBTREE:
598 	case META_ST_SUBORDINATE:
599 		ber_memfree( ms->ms_dn.bv_val );
600 		break;
601 
602 	case META_ST_REGEX:
603 		regfree( &ms->ms_regex );
604 		ber_memfree( ms->ms_regex_pattern.bv_val );
605 		break;
606 
607 	default:
608 		return -1;
609 	}
610 
611 	ch_free( ms );
612 	return 0;
613 }
614 
615 int
asyncmeta_subtree_destroy(a_metasubtree_t * ms)616 asyncmeta_subtree_destroy( a_metasubtree_t *ms )
617 {
618 	if ( ms->ms_next ) {
619 		asyncmeta_subtree_destroy( ms->ms_next );
620 	}
621 
622 	return asyncmeta_subtree_free( ms );
623 }
624 
625 static void
asyncmeta_filter_free(metafilter_t * mf)626 asyncmeta_filter_free( metafilter_t *mf )
627 {
628 	regfree( &mf->mf_regex );
629 	ber_memfree( mf->mf_regex_pattern.bv_val );
630 	ch_free( mf );
631 }
632 
633 void
asyncmeta_filter_destroy(metafilter_t * mf)634 asyncmeta_filter_destroy( metafilter_t *mf )
635 {
636 	if ( mf->mf_next )
637 		asyncmeta_filter_destroy( mf->mf_next );
638 	asyncmeta_filter_free( mf );
639 }
640 
641 static struct berval st_styles[] = {
642 	BER_BVC("subtree"),
643 	BER_BVC("children"),
644 	BER_BVC("regex")
645 };
646 
647 static int
asyncmeta_subtree_unparse(ConfigArgs * c,a_metatarget_t * mt)648 asyncmeta_subtree_unparse(
649 	ConfigArgs *c,
650 	a_metatarget_t *mt )
651 {
652 	a_metasubtree_t	*ms;
653 	struct berval bv, *style;
654 
655 	if ( !mt->mt_subtree )
656 		return 1;
657 
658 	/* can only be one of exclude or include */
659 	if (( c->type == LDAP_BACK_CFG_SUBTREE_EX ) ^ mt->mt_subtree_exclude )
660 		return 1;
661 
662 	bv.bv_val = c->cr_msg;
663 	for ( ms=mt->mt_subtree; ms; ms=ms->ms_next ) {
664 		if (ms->ms_type == META_ST_SUBTREE)
665 			style = &st_styles[0];
666 		else if ( ms->ms_type == META_ST_SUBORDINATE )
667 			style = &st_styles[1];
668 		else if ( ms->ms_type == META_ST_REGEX )
669 			style = &st_styles[2];
670 		else {
671 			assert(0);
672 			continue;
673 		}
674 		bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg),
675 			"dn.%s:%s", style->bv_val, ms->ms_dn.bv_val );
676 		value_add_one( &c->rvalue_vals, &bv );
677 	}
678 	return 0;
679 }
680 
681 static int
asyncmeta_subtree_config(a_metatarget_t * mt,ConfigArgs * c)682 asyncmeta_subtree_config(
683 	a_metatarget_t *mt,
684 	ConfigArgs *c )
685 {
686 	meta_st_t	type = META_ST_SUBTREE;
687 	char		*pattern;
688 	struct berval	ndn = BER_BVNULL;
689 	a_metasubtree_t	*ms = NULL;
690 
691 	if ( c->type == LDAP_BACK_CFG_SUBTREE_EX ) {
692 		if ( mt->mt_subtree && !mt->mt_subtree_exclude ) {
693 			snprintf( c->cr_msg, sizeof(c->cr_msg),
694 				"\"subtree-exclude\" incompatible with previous \"subtree-include\" directives" );
695 			return 1;
696 		}
697 
698 		mt->mt_subtree_exclude = 1;
699 
700 	} else {
701 		if ( mt->mt_subtree && mt->mt_subtree_exclude ) {
702 			snprintf( c->cr_msg, sizeof(c->cr_msg),
703 				"\"subtree-include\" incompatible with previous \"subtree-exclude\" directives" );
704 			return 1;
705 		}
706 	}
707 
708 	pattern = c->argv[1];
709 	if ( strncasecmp( pattern, "dn", STRLENOF( "dn" ) ) == 0 ) {
710 		char *style;
711 
712 		pattern = &pattern[STRLENOF( "dn")];
713 
714 		if ( pattern[0] == '.' ) {
715 			style = &pattern[1];
716 
717 			if ( strncasecmp( style, "subtree", STRLENOF( "subtree" ) ) == 0 ) {
718 				type = META_ST_SUBTREE;
719 				pattern = &style[STRLENOF( "subtree" )];
720 
721 			} else if ( strncasecmp( style, "children", STRLENOF( "children" ) ) == 0 ) {
722 				type = META_ST_SUBORDINATE;
723 				pattern = &style[STRLENOF( "children" )];
724 
725 			} else if ( strncasecmp( style, "sub", STRLENOF( "sub" ) ) == 0 ) {
726 				type = META_ST_SUBTREE;
727 				pattern = &style[STRLENOF( "sub" )];
728 
729 			} else if ( strncasecmp( style, "regex", STRLENOF( "regex" ) ) == 0 ) {
730 				type = META_ST_REGEX;
731 				pattern = &style[STRLENOF( "regex" )];
732 
733 			} else {
734 				snprintf( c->cr_msg, sizeof(c->cr_msg), "unknown style in \"dn.<style>\"" );
735 				return 1;
736 			}
737 		}
738 
739 		if ( pattern[0] != ':' ) {
740 			snprintf( c->cr_msg, sizeof(c->cr_msg), "missing colon after \"dn.<style>\"" );
741 			return 1;
742 		}
743 		pattern++;
744 	}
745 
746 	switch ( type ) {
747 	case META_ST_SUBTREE:
748 	case META_ST_SUBORDINATE: {
749 		struct berval dn;
750 
751 		ber_str2bv( pattern, 0, 0, &dn );
752 		if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL )
753 			!= LDAP_SUCCESS )
754 		{
755 			snprintf( c->cr_msg, sizeof(c->cr_msg), "DN=\"%s\" is invalid", pattern );
756 			return 1;
757 		}
758 
759 		if ( !dnIsSuffix( &ndn, &mt->mt_nsuffix ) ) {
760 			snprintf( c->cr_msg, sizeof(c->cr_msg),
761 				"DN=\"%s\" is not a subtree of target \"%s\"",
762 				pattern, mt->mt_nsuffix.bv_val );
763 			ber_memfree( ndn.bv_val );
764 			return( 1 );
765 		}
766 		} break;
767 
768 	default:
769 		/* silence warnings */
770 		break;
771 	}
772 
773 	ms = ch_calloc( sizeof( a_metasubtree_t ), 1 );
774 	ms->ms_type = type;
775 
776 	switch ( ms->ms_type ) {
777 	case META_ST_SUBTREE:
778 	case META_ST_SUBORDINATE:
779 		ms->ms_dn = ndn;
780 		break;
781 
782 	case META_ST_REGEX: {
783 		int rc;
784 
785 		rc = regcomp( &ms->ms_regex, pattern, REG_EXTENDED|REG_ICASE );
786 		if ( rc != 0 ) {
787 			char regerr[ SLAP_TEXT_BUFLEN ];
788 
789 			regerror( rc, &ms->ms_regex, regerr, sizeof(regerr) );
790 
791 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
792 				"regular expression \"%s\" bad because of %s",
793 				pattern, regerr );
794 			ch_free( ms );
795 			return 1;
796 		}
797 		ber_str2bv( pattern, 0, 1, &ms->ms_regex_pattern );
798 		} break;
799 	}
800 
801 	if ( mt->mt_subtree == NULL ) {
802 		 mt->mt_subtree = ms;
803 
804 	} else {
805 		a_metasubtree_t **msp;
806 
807 		for ( msp = &mt->mt_subtree; *msp; ) {
808 			switch ( ms->ms_type ) {
809 			case META_ST_SUBTREE:
810 				switch ( (*msp)->ms_type ) {
811 				case META_ST_SUBTREE:
812 					if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
813 						a_metasubtree_t *tmp = *msp;
814 						Debug( LDAP_DEBUG_CONFIG,
815 							"%s: previous rule \"dn.subtree:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
816 							c->log, pattern, (*msp)->ms_dn.bv_val );
817 						*msp = (*msp)->ms_next;
818 						tmp->ms_next = NULL;
819 						asyncmeta_subtree_destroy( tmp );
820 						continue;
821 
822 					} else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) ) {
823 						Debug( LDAP_DEBUG_CONFIG,
824 							"%s: previous rule \"dn.subtree:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
825 							c->log, (*msp)->ms_dn.bv_val, pattern );
826 						asyncmeta_subtree_destroy( ms );
827 						ms = NULL;
828 						return( 0 );
829 					}
830 					break;
831 
832 				case META_ST_SUBORDINATE:
833 					if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
834 						a_metasubtree_t *tmp = *msp;
835 						Debug( LDAP_DEBUG_CONFIG,
836 							"%s: previous rule \"dn.children:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
837 							c->log, pattern, (*msp)->ms_dn.bv_val );
838 						*msp = (*msp)->ms_next;
839 						tmp->ms_next = NULL;
840 						asyncmeta_subtree_destroy( tmp );
841 						continue;
842 
843 					} else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) && ms->ms_dn.bv_len > (*msp)->ms_dn.bv_len ) {
844 						Debug( LDAP_DEBUG_CONFIG,
845 							"%s: previous rule \"dn.children:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
846 							c->log, (*msp)->ms_dn.bv_val, pattern );
847 						asyncmeta_subtree_destroy( ms );
848 						ms = NULL;
849 						return( 0 );
850 					}
851 					break;
852 
853 				case META_ST_REGEX:
854 					if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
855 						Debug( LDAP_DEBUG_CONFIG,
856 							"%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n",
857 							c->log, (*msp)->ms_regex_pattern.bv_val, ms->ms_dn.bv_val );
858 					}
859 					break;
860 				}
861 				break;
862 
863 			case META_ST_SUBORDINATE:
864 				switch ( (*msp)->ms_type ) {
865 				case META_ST_SUBTREE:
866 					if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
867 						a_metasubtree_t *tmp = *msp;
868 						Debug( LDAP_DEBUG_CONFIG,
869 							"%s: previous rule \"dn.children:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
870 							c->log, pattern, (*msp)->ms_dn.bv_val );
871 						*msp = (*msp)->ms_next;
872 						tmp->ms_next = NULL;
873 						asyncmeta_subtree_destroy( tmp );
874 						continue;
875 
876 					} else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) && ms->ms_dn.bv_len > (*msp)->ms_dn.bv_len ) {
877 						Debug( LDAP_DEBUG_CONFIG,
878 							"%s: previous rule \"dn.children:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
879 							c->log, (*msp)->ms_dn.bv_val, pattern );
880 						asyncmeta_subtree_destroy( ms );
881 						ms = NULL;
882 						return( 0 );
883 					}
884 					break;
885 
886 				case META_ST_SUBORDINATE:
887 					if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
888 						a_metasubtree_t *tmp = *msp;
889 						Debug( LDAP_DEBUG_CONFIG,
890 							"%s: previous rule \"dn.children:%s\" is contained in rule \"dn.children:%s\" (replaced)\n",
891 							c->log, pattern, (*msp)->ms_dn.bv_val );
892 						*msp = (*msp)->ms_next;
893 						tmp->ms_next = NULL;
894 						asyncmeta_subtree_destroy( tmp );
895 						continue;
896 
897 					} else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) ) {
898 						Debug( LDAP_DEBUG_CONFIG,
899 							"%s: previous rule \"dn.children:%s\" contains rule \"dn.children:%s\" (ignored)\n",
900 							c->log, (*msp)->ms_dn.bv_val, pattern );
901 						asyncmeta_subtree_destroy( ms );
902 						ms = NULL;
903 						return( 0 );
904 					}
905 					break;
906 
907 				case META_ST_REGEX:
908 					if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
909 						Debug( LDAP_DEBUG_CONFIG,
910 							"%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n",
911 							c->log, (*msp)->ms_regex_pattern.bv_val, ms->ms_dn.bv_val );
912 					}
913 					break;
914 				}
915 				break;
916 
917 			case META_ST_REGEX:
918 				switch ( (*msp)->ms_type ) {
919 				case META_ST_SUBTREE:
920 				case META_ST_SUBORDINATE:
921 					if ( regexec( &ms->ms_regex, (*msp)->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
922 						Debug( LDAP_DEBUG_CONFIG,
923 							"%s: previous rule \"dn.subtree:%s\" may be contained in rule \"dn.regex:%s\"\n",
924 							c->log, (*msp)->ms_dn.bv_val, ms->ms_regex_pattern.bv_val );
925 					}
926 					break;
927 
928 				case META_ST_REGEX:
929 					/* no check possible */
930 					break;
931 				}
932 				break;
933 			}
934 
935 			msp = &(*msp)->ms_next;
936 		}
937 
938 		*msp = ms;
939 	}
940 
941 	return 0;
942 }
943 
944 static slap_verbmasks idassert_mode[] = {
945 	{ BER_BVC("self"),		LDAP_BACK_IDASSERT_SELF },
946 	{ BER_BVC("anonymous"),		LDAP_BACK_IDASSERT_ANONYMOUS },
947 	{ BER_BVC("none"),		LDAP_BACK_IDASSERT_NOASSERT },
948 	{ BER_BVC("legacy"),		LDAP_BACK_IDASSERT_LEGACY },
949 	{ BER_BVNULL,			0 }
950 };
951 
952 static slap_verbmasks tls_mode[] = {
953 	{ BER_BVC( "propagate" ),	LDAP_BACK_F_TLS_PROPAGATE_MASK },
954 	{ BER_BVC( "try-propagate" ),	LDAP_BACK_F_PROPAGATE_TLS },
955 	{ BER_BVC( "start" ),		LDAP_BACK_F_TLS_USE_MASK },
956 	{ BER_BVC( "try-start" ),	LDAP_BACK_F_USE_TLS },
957 	{ BER_BVC( "ldaps" ),		LDAP_BACK_F_TLS_LDAPS },
958 	{ BER_BVC( "none" ),		LDAP_BACK_F_NONE },
959 	{ BER_BVNULL,			0 }
960 };
961 
962 static slap_verbmasks t_f_mode[] = {
963 	{ BER_BVC( "yes" ),		LDAP_BACK_F_T_F },
964 	{ BER_BVC( "discover" ),	LDAP_BACK_F_T_F_DISCOVER },
965 	{ BER_BVC( "no" ),		LDAP_BACK_F_NONE },
966 	{ BER_BVNULL,			0 }
967 };
968 
969 static slap_verbmasks cancel_mode[] = {
970 	{ BER_BVC( "ignore" ),		LDAP_BACK_F_CANCEL_IGNORE },
971 	{ BER_BVC( "exop" ),		LDAP_BACK_F_CANCEL_EXOP },
972 	{ BER_BVC( "exop-discover" ),	LDAP_BACK_F_CANCEL_EXOP_DISCOVER },
973 	{ BER_BVC( "abandon" ),		LDAP_BACK_F_CANCEL_ABANDON },
974 	{ BER_BVNULL,			0 }
975 };
976 
977 static slap_verbmasks onerr_mode[] = {
978 	{ BER_BVC( "stop" ),		META_BACK_F_ONERR_STOP },
979 	{ BER_BVC( "report" ),	META_BACK_F_ONERR_REPORT },
980 	{ BER_BVC( "continue" ),		LDAP_BACK_F_NONE },
981 	{ BER_BVNULL,			0 }
982 };
983 
984 /* see enum in slap.h */
985 static slap_cf_aux_table timeout_table[] = {
986 	{ BER_BVC("bind="),	SLAP_OP_BIND * sizeof( time_t ),	'u', 0, NULL },
987 	/* unbind makes no sense */
988 	{ BER_BVC("add="),	SLAP_OP_ADD * sizeof( time_t ),		'u', 0, NULL },
989 	{ BER_BVC("delete="),	SLAP_OP_DELETE * sizeof( time_t ),	'u', 0, NULL },
990 	{ BER_BVC("modrdn="),	SLAP_OP_MODRDN * sizeof( time_t ),	'u', 0, NULL },
991 	{ BER_BVC("modify="),	SLAP_OP_MODIFY * sizeof( time_t ),	'u', 0, NULL },
992 	{ BER_BVC("compare="),	SLAP_OP_COMPARE * sizeof( time_t ),	'u', 0, NULL },
993 	{ BER_BVC("search="),	SLAP_OP_SEARCH * sizeof( time_t ),	'u', 0, NULL },
994 	/* abandon makes little sense */
995 #if 0	/* not implemented yet */
996 	{ BER_BVC("extended="),	SLAP_OP_EXTENDED * sizeof( time_t ),	'u', 0, NULL },
997 #endif
998 	{ BER_BVNULL, 0, 0, 0, NULL }
999 };
1000 
1001 static int
asyncmeta_cf_cleanup(ConfigArgs * c)1002 asyncmeta_cf_cleanup( ConfigArgs *c )
1003 {
1004 	a_metainfo_t	*mi = ( a_metainfo_t * )c->be->be_private;
1005 	a_metatarget_t	*mt = c->ca_private;
1006 
1007 	return asyncmeta_target_finish( mi, mt, c->log, c->cr_msg, sizeof( c->cr_msg ));
1008 }
1009 
1010 static int
asyncmeta_back_cf_gen(ConfigArgs * c)1011 asyncmeta_back_cf_gen( ConfigArgs *c )
1012 {
1013 	a_metainfo_t	*mi = ( a_metainfo_t * )c->be->be_private;
1014 	a_metatarget_t	*mt = NULL;
1015 	a_metacommon_t	*mc = NULL;
1016 
1017 	int i, rc = 0;
1018 
1019 	assert( mi != NULL );
1020 
1021 	if ( c->op == SLAP_CONFIG_EMIT || c->op == LDAP_MOD_DELETE ) {
1022 		if ( !mi )
1023 			return 1;
1024 
1025 		if ( c->table == Cft_Database ) {
1026 			mt = NULL;
1027 			mc = &mi->mi_mc;
1028 		} else {
1029 			mt = c->ca_private;
1030 			mc = &mt->mt_mc;
1031 		}
1032 	}
1033 
1034 	if ( c->op == SLAP_CONFIG_EMIT ) {
1035 		struct berval bv = BER_BVNULL;
1036 
1037 		switch( c->type ) {
1038 		/* Base attrs */
1039 
1040 		case LDAP_BACK_CFG_DNCACHE_TTL:
1041 			if ( mi->mi_cache.ttl == META_DNCACHE_DISABLED ) {
1042 				return 1;
1043 			} else if ( mi->mi_cache.ttl == META_DNCACHE_FOREVER ) {
1044 				BER_BVSTR( &bv, "forever" );
1045 			} else {
1046 				char	buf[ SLAP_TEXT_BUFLEN ];
1047 
1048 				lutil_unparse_time( buf, sizeof( buf ), mi->mi_cache.ttl );
1049 				ber_str2bv( buf, 0, 0, &bv );
1050 			}
1051 			value_add_one( &c->rvalue_vals, &bv );
1052 			break;
1053 
1054 		case LDAP_BACK_CFG_IDLE_TIMEOUT:
1055 			if ( mi->mi_idle_timeout == 0 ) {
1056 				return 1;
1057 			} else {
1058 				char	buf[ SLAP_TEXT_BUFLEN ];
1059 
1060 				lutil_unparse_time( buf, sizeof( buf ), mi->mi_idle_timeout );
1061 				ber_str2bv( buf, 0, 0, &bv );
1062 				value_add_one( &c->rvalue_vals, &bv );
1063 			}
1064 			break;
1065 
1066 		case LDAP_BACK_CFG_ONERR:
1067 			enum_to_verb( onerr_mode, mi->mi_flags & META_BACK_F_ONERR_MASK, &bv );
1068 			if ( BER_BVISNULL( &bv )) {
1069 				rc = 1;
1070 			} else {
1071 				value_add_one( &c->rvalue_vals, &bv );
1072 			}
1073 			break;
1074 
1075 		case LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER:
1076 			c->value_int = META_BACK_DEFER_ROOTDN_BIND( mi );
1077 			break;
1078 
1079 		case LDAP_BACK_CFG_CONNPOOLMAX:
1080 			c->value_int = mi->mi_conn_priv_max;
1081 			break;
1082 
1083 		/* common attrs */
1084 		case LDAP_BACK_CFG_BIND_TIMEOUT:
1085 			if ( mc->mc_bind_timeout.tv_sec == 0 &&
1086 				mc->mc_bind_timeout.tv_usec == 0 ) {
1087 				return 1;
1088 			} else {
1089 				c->value_ulong = mc->mc_bind_timeout.tv_sec * 1000000UL +
1090 					mc->mc_bind_timeout.tv_usec;
1091 			}
1092 			break;
1093 
1094 		case LDAP_BACK_CFG_CANCEL: {
1095 			slap_mask_t	mask = LDAP_BACK_F_CANCEL_MASK2;
1096 
1097 			if ( mt && META_BACK_TGT_CANCEL_DISCOVER( mt ) ) {
1098 				mask &= ~LDAP_BACK_F_CANCEL_EXOP;
1099 			}
1100 			enum_to_verb( cancel_mode, (mc->mc_flags & mask), &bv );
1101 			if ( BER_BVISNULL( &bv ) ) {
1102 				/* there's something wrong... */
1103 				assert( 0 );
1104 				rc = 1;
1105 
1106 			} else {
1107 				value_add_one( &c->rvalue_vals, &bv );
1108 			}
1109 			} break;
1110 
1111 		case LDAP_BACK_CFG_CHASE:
1112 			c->value_int = META_BACK_CMN_CHASE_REFERRALS(mc);
1113 			break;
1114 
1115 #ifdef SLAPD_META_CLIENT_PR
1116 		case LDAP_BACK_CFG_CLIENT_PR:
1117 			if ( mc->mc_ps == META_CLIENT_PR_DISABLE ) {
1118 				return 1;
1119 			} else if ( mc->mc_ps == META_CLIENT_PR_ACCEPT_UNSOLICITED ) {
1120 				BER_BVSTR( &bv, "accept-unsolicited" );
1121 			} else {
1122 				bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%d", mc->mc_ps );
1123 				bv.bv_val = c->cr_msg;
1124 			}
1125 			value_add_one( &c->rvalue_vals, &bv );
1126 			break;
1127 #endif /* SLAPD_META_CLIENT_PR */
1128 
1129 		case LDAP_BACK_CFG_DEFAULT_T:
1130 			if ( mt || mi->mi_defaulttarget == META_DEFAULT_TARGET_NONE )
1131 				return 1;
1132 			bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%d", mi->mi_defaulttarget );
1133 			bv.bv_val = c->cr_msg;
1134 			value_add_one( &c->rvalue_vals, &bv );
1135 			break;
1136 
1137 		case LDAP_BACK_CFG_NETWORK_TIMEOUT:
1138 			if ( mc->mc_network_timeout == 0 ) {
1139 				return 1;
1140 			}
1141 			bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%ld",
1142 				mc->mc_network_timeout );
1143 			bv.bv_val = c->cr_msg;
1144 			value_add_one( &c->rvalue_vals, &bv );
1145 			break;
1146 
1147 		case LDAP_BACK_CFG_NOREFS:
1148 			c->value_int = META_BACK_CMN_NOREFS(mc);
1149 			break;
1150 
1151 		case LDAP_BACK_CFG_NOUNDEFFILTER:
1152 			c->value_int = META_BACK_CMN_NOUNDEFFILTER(mc);
1153 			break;
1154 
1155 		case LDAP_BACK_CFG_NRETRIES:
1156 			if ( mc->mc_nretries == META_RETRY_FOREVER ) {
1157 				BER_BVSTR( &bv, "forever" );
1158 			} else if ( mc->mc_nretries == META_RETRY_NEVER ) {
1159 				BER_BVSTR( &bv, "never" );
1160 			} else {
1161 				bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%d",
1162 					mc->mc_nretries );
1163 				bv.bv_val = c->cr_msg;
1164 			}
1165 			value_add_one( &c->rvalue_vals, &bv );
1166 			break;
1167 
1168 		case LDAP_BACK_CFG_QUARANTINE:
1169 			if ( !META_BACK_CMN_QUARANTINE( mc )) {
1170 				rc = 1;
1171 				break;
1172 			}
1173 			rc = mi->mi_ldap_extra->retry_info_unparse( &mc->mc_quarantine, &bv );
1174 			if ( rc == 0 ) {
1175 				ber_bvarray_add( &c->rvalue_vals, &bv );
1176 			}
1177 			break;
1178 
1179 		case LDAP_BACK_CFG_REBIND:
1180 			c->value_int = META_BACK_CMN_SAVECRED(mc);
1181 			break;
1182 
1183 		case LDAP_BACK_CFG_TIMEOUT:
1184 			for ( i = 0; i < SLAP_OP_LAST; i++ ) {
1185 				if ( mc->mc_timeout[ i ] != META_BACK_CFG_DEFAULT_OPS_TIMEOUT ) {
1186 					break;
1187 				}
1188 			}
1189 
1190 			if ( i == SLAP_OP_LAST ) {
1191 				return 1;
1192 			}
1193 
1194 			BER_BVZERO( &bv );
1195 			slap_cf_aux_table_unparse( mc->mc_timeout, &bv, timeout_table );
1196 
1197 			if ( BER_BVISNULL( &bv ) ) {
1198 				return 1;
1199 			}
1200 
1201 			for ( i = 0; isspace( (unsigned char) bv.bv_val[ i ] ); i++ )
1202 				/* count spaces */ ;
1203 
1204 			if ( i ) {
1205 				bv.bv_len -= i;
1206 				AC_MEMCPY( bv.bv_val, &bv.bv_val[ i ],
1207 					bv.bv_len + 1 );
1208 			}
1209 
1210 			ber_bvarray_add( &c->rvalue_vals, &bv );
1211 			break;
1212 
1213 		case LDAP_BACK_CFG_VERSION:
1214 			if ( mc->mc_version == 0 )
1215 				return 1;
1216 			c->value_int = mc->mc_version;
1217 			break;
1218 
1219 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1220 		case LDAP_BACK_CFG_ST_REQUEST:
1221 			c->value_int = META_BACK_CMN_ST_REQUEST( mc );
1222 			break;
1223 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1224 
1225 		case LDAP_BACK_CFG_T_F:
1226 			enum_to_verb( t_f_mode, (mc->mc_flags & LDAP_BACK_F_T_F_MASK2), &bv );
1227 			if ( BER_BVISNULL( &bv ) ) {
1228 				/* there's something wrong... */
1229 				assert( 0 );
1230 				rc = 1;
1231 
1232 			} else {
1233 				value_add_one( &c->rvalue_vals, &bv );
1234 			}
1235 			break;
1236 
1237 		case LDAP_BACK_CFG_TLS: {
1238 			struct berval bc = BER_BVNULL, bv2;
1239 
1240 			if (( mc->mc_flags & LDAP_BACK_F_TLS_MASK ) == LDAP_BACK_F_NONE ) {
1241 				rc = 1;
1242 				break;
1243 			}
1244 			enum_to_verb( tls_mode, ( mc->mc_flags & LDAP_BACK_F_TLS_MASK ), &bv );
1245 			assert( !BER_BVISNULL( &bv ) );
1246 
1247 			if ( mt ) {
1248 				bindconf_tls_unparse( &mt->mt_tls, &bc );
1249 			}
1250 
1251 			if ( !BER_BVISEMPTY( &bc )) {
1252 				bv2.bv_len = bv.bv_len + bc.bv_len + 1;
1253 				bv2.bv_val = ch_malloc( bv2.bv_len + 1 );
1254 				strcpy( bv2.bv_val, bv.bv_val );
1255 				bv2.bv_val[bv.bv_len] = ' ';
1256 				strcpy( &bv2.bv_val[bv.bv_len + 1], bc.bv_val );
1257 				ber_memfree( bc.bv_val );
1258 				ber_bvarray_add( &c->rvalue_vals, &bv2 );
1259 			} else {
1260 				value_add_one( &c->rvalue_vals, &bv );
1261 			}
1262 			} break;
1263 
1264 		/* target attrs */
1265 		case LDAP_BACK_CFG_URI: {
1266 			char *p2, *p1 = strchr( mt->mt_uri, ' ' );
1267 			bv.bv_len = strlen( mt->mt_uri ) + 3 + mt->mt_psuffix.bv_len;
1268 			bv.bv_val = ch_malloc( bv.bv_len + 1 );
1269 			p2 = bv.bv_val;
1270 			*p2++ = '"';
1271 			if ( p1 ) {
1272 				p2 = lutil_strncopy( p2, mt->mt_uri, p1 - mt->mt_uri );
1273 			} else {
1274 				p2 = lutil_strcopy( p2, mt->mt_uri );
1275 			}
1276 			*p2++ = '/';
1277 			p2 = lutil_strcopy( p2, mt->mt_psuffix.bv_val );
1278 			*p2++ = '"';
1279 			if ( p1 ) {
1280 				strcpy( p2, p1 );
1281 			}
1282 			ber_bvarray_add( &c->rvalue_vals, &bv );
1283 			} break;
1284 
1285 		case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: {
1286 			BerVarray	*bvp;
1287 			int		i;
1288 			struct berval	bv = BER_BVNULL;
1289 			char		buf[SLAP_TEXT_BUFLEN];
1290 
1291 			bvp = &mt->mt_idassert_authz;
1292 			if ( *bvp == NULL ) {
1293 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL )
1294 				{
1295 					BER_BVSTR( &bv, "*" );
1296 					value_add_one( &c->rvalue_vals, &bv );
1297 
1298 				} else {
1299 					rc = 1;
1300 				}
1301 				break;
1302 			}
1303 
1304 			for ( i = 0; !BER_BVISNULL( &((*bvp)[ i ]) ); i++ ) {
1305 				char *ptr;
1306 				int len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i );
1307 				bv.bv_len = ((*bvp)[ i ]).bv_len + len;
1308 				bv.bv_val = ber_memrealloc( bv.bv_val, bv.bv_len + 1 );
1309 				ptr = bv.bv_val;
1310 				ptr = lutil_strcopy( ptr, buf );
1311 				ptr = lutil_strncopy( ptr, ((*bvp)[ i ]).bv_val, ((*bvp)[ i ]).bv_len );
1312 				value_add_one( &c->rvalue_vals, &bv );
1313 			}
1314 			if ( bv.bv_val ) {
1315 				ber_memfree( bv.bv_val );
1316 			}
1317 			break;
1318 		}
1319 
1320 		case LDAP_BACK_CFG_IDASSERT_BIND: {
1321 			int		i;
1322 			struct berval	bc = BER_BVNULL;
1323 			char		*ptr;
1324 
1325 			if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE ) {
1326 				return 1;
1327 			} else {
1328 				ber_len_t	len;
1329 
1330 				switch ( mt->mt_idassert_mode ) {
1331 				case LDAP_BACK_IDASSERT_OTHERID:
1332 				case LDAP_BACK_IDASSERT_OTHERDN:
1333 					break;
1334 
1335 				default: {
1336 					struct berval	mode = BER_BVNULL;
1337 
1338 					enum_to_verb( idassert_mode, mt->mt_idassert_mode, &mode );
1339 					if ( BER_BVISNULL( &mode ) ) {
1340 						/* there's something wrong... */
1341 						assert( 0 );
1342 						rc = 1;
1343 
1344 					} else {
1345 						bv.bv_len = STRLENOF( "mode=" ) + mode.bv_len;
1346 						bv.bv_val = ch_malloc( bv.bv_len + 1 );
1347 
1348 						ptr = lutil_strcopy( bv.bv_val, "mode=" );
1349 						ptr = lutil_strcopy( ptr, mode.bv_val );
1350 					}
1351 					break;
1352 				}
1353 				}
1354 
1355 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) {
1356 					len = bv.bv_len + STRLENOF( "authz=native" );
1357 
1358 					if ( !BER_BVISEMPTY( &bv ) ) {
1359 						len += STRLENOF( " " );
1360 					}
1361 
1362 					bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
1363 
1364 					ptr = &bv.bv_val[ bv.bv_len ];
1365 
1366 					if ( !BER_BVISEMPTY( &bv ) ) {
1367 						ptr = lutil_strcopy( ptr, " " );
1368 					}
1369 
1370 					(void)lutil_strcopy( ptr, "authz=native" );
1371 				}
1372 
1373 				len = bv.bv_len + STRLENOF( "flags=non-prescriptive,override,obsolete-encoding-workaround,proxy-authz-non-critical,dn-authzid" );
1374 				/* flags */
1375 				if ( !BER_BVISEMPTY( &bv ) ) {
1376 					len += STRLENOF( " " );
1377 				}
1378 
1379 				bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
1380 
1381 				ptr = &bv.bv_val[ bv.bv_len ];
1382 
1383 				if ( !BER_BVISEMPTY( &bv ) ) {
1384 					ptr = lutil_strcopy( ptr, " " );
1385 				}
1386 
1387 				ptr = lutil_strcopy( ptr, "flags=" );
1388 
1389 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1390 					ptr = lutil_strcopy( ptr, "prescriptive" );
1391 				} else {
1392 					ptr = lutil_strcopy( ptr, "non-prescriptive" );
1393 				}
1394 
1395 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
1396 					ptr = lutil_strcopy( ptr, ",override" );
1397 				}
1398 
1399 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
1400 					ptr = lutil_strcopy( ptr, ",obsolete-proxy-authz" );
1401 
1402 				} else if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
1403 					ptr = lutil_strcopy( ptr, ",obsolete-encoding-workaround" );
1404 				}
1405 
1406 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) {
1407 					ptr = lutil_strcopy( ptr, ",proxy-authz-critical" );
1408 
1409 				} else {
1410 					ptr = lutil_strcopy( ptr, ",proxy-authz-non-critical" );
1411 				}
1412 
1413 #ifdef SLAP_AUTH_DN
1414 				switch ( mt->mt_idassert_flags & LDAP_BACK_AUTH_DN_MASK ) {
1415 				case LDAP_BACK_AUTH_DN_AUTHZID:
1416 					ptr = lutil_strcopy( ptr, ",dn-authzid" );
1417 					break;
1418 
1419 				case LDAP_BACK_AUTH_DN_WHOAMI:
1420 					ptr = lutil_strcopy( ptr, ",dn-whoami" );
1421 					break;
1422 
1423 				default:
1424 #if 0 /* implicit */
1425 					ptr = lutil_strcopy( ptr, ",dn-none" );
1426 #endif
1427 					break;
1428 				}
1429 #endif
1430 
1431 				bv.bv_len = ( ptr - bv.bv_val );
1432 				/* end-of-flags */
1433 			}
1434 
1435 			bindconf_unparse( &mt->mt_idassert.si_bc, &bc );
1436 
1437 			if ( !BER_BVISNULL( &bv ) ) {
1438 				ber_len_t	len = bv.bv_len + bc.bv_len;
1439 
1440 				bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
1441 
1442 				assert( bc.bv_val[ 0 ] == ' ' );
1443 
1444 				ptr = lutil_strcopy( &bv.bv_val[ bv.bv_len ], bc.bv_val );
1445 				free( bc.bv_val );
1446 				bv.bv_len = ptr - bv.bv_val;
1447 
1448 			} else {
1449 				for ( i = 0; isspace( (unsigned char) bc.bv_val[ i ] ); i++ )
1450 					/* count spaces */ ;
1451 
1452 				if ( i ) {
1453 					bc.bv_len -= i;
1454 					AC_MEMCPY( bc.bv_val, &bc.bv_val[ i ], bc.bv_len + 1 );
1455 				}
1456 
1457 				bv = bc;
1458 			}
1459 
1460 			ber_bvarray_add( &c->rvalue_vals, &bv );
1461 
1462 			break;
1463 		}
1464 
1465 		case LDAP_BACK_CFG_SUFFIXM:
1466 			if ( mt->mt_lsuffixm.bv_val ) {
1467 				struct berval bv;
1468 				char *ptr;
1469 				bv.bv_len = mt->mt_lsuffixm.bv_len + 2 + 1 + mt->mt_rsuffixm.bv_len + 2;
1470 				bv.bv_val = ch_malloc( bv.bv_len + 1 );
1471 				ptr = bv.bv_val;
1472 				*ptr++ = '"';
1473 				ptr = lutil_strcopy(ptr, mt->mt_lsuffixm.bv_val);
1474 				ptr = lutil_strcopy(ptr, "\" \"");
1475 				ptr = lutil_strcopy(ptr, mt->mt_rsuffixm.bv_val);
1476 				*ptr++ = '"';
1477 				*ptr = '\0';
1478 				ber_bvarray_add( &c->rvalue_vals, &bv );
1479 				rc = 0;
1480 			} else
1481 				rc = 1;
1482 			break;
1483 
1484 		case LDAP_BACK_CFG_SUBTREE_EX:
1485 		case LDAP_BACK_CFG_SUBTREE_IN:
1486 			rc = asyncmeta_subtree_unparse( c, mt );
1487 			break;
1488 
1489 		case LDAP_BACK_CFG_FILTER:
1490 			if ( mt->mt_filter == NULL ) {
1491 				rc = 1;
1492 			} else {
1493 				metafilter_t *mf;
1494 				for ( mf = mt->mt_filter; mf; mf = mf->mf_next )
1495 					value_add_one( &c->rvalue_vals, &mf->mf_regex_pattern );
1496 			}
1497 			break;
1498 		case LDAP_BACK_CFG_MAX_PENDING_OPS:
1499 			c->value_int = mi->mi_max_pending_ops;
1500 			break;
1501 
1502 		case LDAP_BACK_CFG_MAX_TARGET_CONNS:
1503 			c->value_int = mi->mi_max_target_conns;
1504 			break;
1505 		case LDAP_BACK_CFG_MAX_TIMEOUT_OPS:
1506 			c->value_int = mi->mi_max_timeout_ops;
1507 			break;
1508 
1509 		case LDAP_BACK_CFG_KEEPALIVE: {
1510 				struct berval bv;
1511 				char buf[AC_LINE_MAX];
1512 				bv.bv_len = AC_LINE_MAX;
1513 				bv.bv_val = &buf[0];
1514 				slap_keepalive_parse(&bv, &mt->mt_tls.sb_keepalive, 0, 0, 1);
1515 				value_add_one( &c->rvalue_vals, &bv );
1516 				break;
1517 			}
1518 
1519 		case LDAP_BACK_CFG_TCP_USER_TIMEOUT:
1520 			c->value_uint = mt->mt_tls.sb_tcp_user_timeout;
1521 			break;
1522 
1523 		default:
1524 			rc = 1;
1525 		}
1526 		return rc;
1527 	} else if ( c->op == LDAP_MOD_DELETE ) {
1528 		switch( c->type ) {
1529 		/* Base attrs */
1530 		case LDAP_BACK_CFG_DNCACHE_TTL:
1531 			mi->mi_cache.ttl = META_DNCACHE_DISABLED;
1532 			break;
1533 
1534 		case LDAP_BACK_CFG_IDLE_TIMEOUT:
1535 			mi->mi_idle_timeout = 0;
1536 			break;
1537 
1538 		case LDAP_BACK_CFG_ONERR:
1539 			mi->mi_flags &= ~META_BACK_F_ONERR_MASK;
1540 			break;
1541 
1542 		case LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER:
1543 			mi->mi_flags &= ~META_BACK_F_DEFER_ROOTDN_BIND;
1544 			break;
1545 
1546 		case LDAP_BACK_CFG_CONNPOOLMAX:
1547 			mi->mi_conn_priv_max = LDAP_BACK_CONN_PRIV_MIN;
1548 			break;
1549 
1550 		/* common attrs */
1551 		case LDAP_BACK_CFG_BIND_TIMEOUT:
1552 			mc->mc_bind_timeout.tv_sec = 0;
1553 			mc->mc_bind_timeout.tv_usec = 0;
1554 			break;
1555 
1556 		case LDAP_BACK_CFG_CANCEL:
1557 			mc->mc_flags &= ~LDAP_BACK_F_CANCEL_MASK2;
1558 			break;
1559 
1560 		case LDAP_BACK_CFG_CHASE:
1561 			mc->mc_flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
1562 			break;
1563 
1564 #ifdef SLAPD_META_CLIENT_PR
1565 		case LDAP_BACK_CFG_CLIENT_PR:
1566 			mc->mc_ps = META_CLIENT_PR_DISABLE;
1567 			break;
1568 #endif /* SLAPD_META_CLIENT_PR */
1569 
1570 		case LDAP_BACK_CFG_DEFAULT_T:
1571 			mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
1572 			break;
1573 
1574 		case LDAP_BACK_CFG_NETWORK_TIMEOUT:
1575 			mc->mc_network_timeout = 0;
1576 			break;
1577 
1578 		case LDAP_BACK_CFG_NOREFS:
1579 			mc->mc_flags &= ~LDAP_BACK_F_NOREFS;
1580 			break;
1581 
1582 		case LDAP_BACK_CFG_NOUNDEFFILTER:
1583 			mc->mc_flags &= ~LDAP_BACK_F_NOUNDEFFILTER;
1584 			break;
1585 
1586 		case LDAP_BACK_CFG_NRETRIES:
1587 			mc->mc_nretries = META_RETRY_DEFAULT;
1588 			break;
1589 
1590 		case LDAP_BACK_CFG_QUARANTINE:
1591 			if ( META_BACK_CMN_QUARANTINE( mc )) {
1592 				mi->mi_ldap_extra->retry_info_destroy( &mc->mc_quarantine );
1593 				mc->mc_flags &= ~LDAP_BACK_F_QUARANTINE;
1594 				if ( mc == &mt->mt_mc ) {
1595 					ldap_pvt_thread_mutex_destroy( &mt->mt_quarantine_mutex );
1596 					mt->mt_isquarantined = 0;
1597 				}
1598 			}
1599 			break;
1600 
1601 		case LDAP_BACK_CFG_REBIND:
1602 			mc->mc_flags &= ~LDAP_BACK_F_SAVECRED;
1603 			break;
1604 
1605 		case LDAP_BACK_CFG_TIMEOUT:
1606 			for ( i = 0; i < SLAP_OP_LAST; i++ ) {
1607 				mc->mc_timeout[ i ] = 0;
1608 			}
1609 			break;
1610 
1611 		case LDAP_BACK_CFG_VERSION:
1612 			mc->mc_version = 0;
1613 			break;
1614 
1615 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1616 		case LDAP_BACK_CFG_ST_REQUEST:
1617 			mc->mc_flags &= ~LDAP_BACK_F_ST_REQUEST;
1618 			break;
1619 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1620 
1621 		case LDAP_BACK_CFG_T_F:
1622 			mc->mc_flags &= ~LDAP_BACK_F_T_F_MASK2;
1623 			break;
1624 
1625 		case LDAP_BACK_CFG_TLS:
1626 			mc->mc_flags &= ~LDAP_BACK_F_TLS_MASK;
1627 			if ( mt )
1628 				bindconf_free( &mt->mt_tls );
1629 			break;
1630 
1631 		/* target attrs */
1632 		case LDAP_BACK_CFG_URI:
1633 			if ( mt->mt_uri ) {
1634 				ch_free( mt->mt_uri );
1635 				mt->mt_uri = NULL;
1636 			}
1637 			/* FIXME: should have a way to close all cached
1638 			 * connections associated with this target.
1639 			 */
1640 			break;
1641 
1642 		case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: {
1643 			BerVarray *bvp;
1644 
1645 			bvp = &mt->mt_idassert_authz;
1646 			if ( c->valx < 0 ) {
1647 				if ( *bvp != NULL ) {
1648 					ber_bvarray_free( *bvp );
1649 					*bvp = NULL;
1650 				}
1651 
1652 			} else {
1653 				if ( *bvp == NULL ) {
1654 					rc = 1;
1655 					break;
1656 				}
1657 
1658 				for ( i = 0; !BER_BVISNULL( &((*bvp)[ i ]) ); i++ )
1659 					;
1660 
1661 				if ( i >= c->valx ) {
1662 					rc = 1;
1663 					break;
1664 				}
1665 				ber_memfree( ((*bvp)[ c->valx ]).bv_val );
1666 				for ( i = c->valx; !BER_BVISNULL( &((*bvp)[ i + 1 ]) ); i++ ) {
1667 					(*bvp)[ i ] = (*bvp)[ i + 1 ];
1668 				}
1669 				BER_BVZERO( &((*bvp)[ i ]) );
1670 			}
1671 			} break;
1672 
1673 		case LDAP_BACK_CFG_IDASSERT_BIND:
1674 			bindconf_free( &mt->mt_idassert.si_bc );
1675 			memset( &mt->mt_idassert, 0, sizeof( slap_idassert_t ) );
1676 			break;
1677 
1678 		case LDAP_BACK_CFG_SUFFIXM:
1679 			if ( mt->mt_lsuffixm.bv_val ) {
1680 				ch_free( mt->mt_lsuffixm.bv_val );
1681 				ch_free( mt->mt_rsuffixm.bv_val );
1682 				BER_BVZERO( &mt->mt_lsuffixm );
1683 				BER_BVZERO( &mt->mt_rsuffixm );
1684 			}
1685 			break;
1686 
1687 		case LDAP_BACK_CFG_SUBTREE_EX:
1688 		case LDAP_BACK_CFG_SUBTREE_IN:
1689 			/* can only be one of exclude or include */
1690 			if (( c->type == LDAP_BACK_CFG_SUBTREE_EX ) ^ mt->mt_subtree_exclude ) {
1691 				rc = 1;
1692 				break;
1693 			}
1694 			if ( c->valx < 0 ) {
1695 				asyncmeta_subtree_destroy( mt->mt_subtree );
1696 				mt->mt_subtree = NULL;
1697 			} else {
1698 				a_metasubtree_t *ms, **mprev;
1699 				for (i=0, mprev = &mt->mt_subtree, ms = *mprev; ms; ms = *mprev) {
1700 					if ( i == c->valx ) {
1701 						*mprev = ms->ms_next;
1702 						asyncmeta_subtree_free( ms );
1703 						break;
1704 					}
1705 					i++;
1706 					mprev = &ms->ms_next;
1707 				}
1708 				if ( i != c->valx )
1709 					rc = 1;
1710 			}
1711 			break;
1712 
1713 		case LDAP_BACK_CFG_FILTER:
1714 			if ( c->valx < 0 ) {
1715 				asyncmeta_filter_destroy( mt->mt_filter );
1716 				mt->mt_filter = NULL;
1717 			} else {
1718 				metafilter_t *mf, **mprev;
1719 				for (i=0, mprev = &mt->mt_filter, mf = *mprev; mf; mf = *mprev) {
1720 					if ( i == c->valx ) {
1721 						*mprev = mf->mf_next;
1722 						asyncmeta_filter_free( mf );
1723 						break;
1724 					}
1725 					i++;
1726 					mprev = &mf->mf_next;
1727 				}
1728 				if ( i != c->valx )
1729 					rc = 1;
1730 			}
1731 			break;
1732 		case LDAP_BACK_CFG_MAX_PENDING_OPS:
1733 			mi->mi_max_pending_ops = 0;
1734 			break;
1735 
1736 		case LDAP_BACK_CFG_MAX_TARGET_CONNS:
1737 			mi->mi_max_target_conns = 0;
1738 			break;
1739 
1740 		case LDAP_BACK_CFG_MAX_TIMEOUT_OPS:
1741 			mi->mi_max_timeout_ops = 0;
1742 			break;
1743 
1744 		case LDAP_BACK_CFG_KEEPALIVE:
1745 			mt->mt_tls.sb_keepalive.sk_idle = 0;
1746 			mt->mt_tls.sb_keepalive.sk_probes = 0;
1747 			mt->mt_tls.sb_keepalive.sk_interval = 0;
1748 			break;
1749 
1750 		case LDAP_BACK_CFG_TCP_USER_TIMEOUT:
1751 			mt->mt_tls.sb_tcp_user_timeout = 0;
1752 			break;
1753 
1754 		default:
1755 			rc = 1;
1756 			break;
1757 		}
1758 
1759 		return rc;
1760 	}
1761 
1762 	if ( c->op == SLAP_CONFIG_ADD ) {
1763 		if ( c->type >= LDAP_BACK_CFG_LAST_BASE ) {
1764 			/* exclude CFG_URI from this check */
1765 			if ( c->type > LDAP_BACK_CFG_LAST_BOTH ) {
1766 				if ( !mi->mi_ntargets ) {
1767 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
1768 						"need \"uri\" directive first" );
1769 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1770 					return 1;
1771 				}
1772 			}
1773 			if ( mi->mi_ntargets ) {
1774 				mt = mi->mi_targets[ mi->mi_ntargets-1 ];
1775 				mc = &mt->mt_mc;
1776 			} else {
1777 				mt = NULL;
1778 				mc = &mi->mi_mc;
1779 			}
1780 		}
1781 	} else {
1782 		if ( c->table == Cft_Database ) {
1783 			mt = NULL;
1784 			mc = &mi->mi_mc;
1785 		} else {
1786 			mt = c->ca_private;
1787 			if ( mt )
1788 				mc = &mt->mt_mc;
1789 			else
1790 				mc = NULL;
1791 		}
1792 	}
1793 
1794 	switch( c->type ) {
1795 	case LDAP_BACK_CFG_URI: {
1796 		LDAPURLDesc 	*ludp;
1797 		struct berval	dn;
1798 		int		j;
1799 
1800 		char		**uris = NULL;
1801 
1802 		if ( c->be->be_nsuffix == NULL ) {
1803 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
1804 				"the suffix must be defined before any target" );
1805 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1806 			return 1;
1807 		}
1808 
1809 		i = mi->mi_ntargets++;
1810 
1811 		mi->mi_targets = ( a_metatarget_t ** )ch_realloc( mi->mi_targets,
1812 			sizeof( a_metatarget_t * ) * mi->mi_ntargets );
1813 		if ( mi->mi_targets == NULL ) {
1814 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
1815 				"out of memory while storing server name"
1816 				" in \"%s <protocol>://<server>[:port]/<naming context>\"",
1817 				c->argv[0] );
1818 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1819 			return 1;
1820 		}
1821 
1822 		if ( asyncmeta_back_new_target( &mi->mi_targets[ i ] ) != 0 ) {
1823 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
1824 				"unable to init server"
1825 				" in \"%s <protocol>://<server>[:port]/<naming context>\"",
1826 				c->argv[0] );
1827 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1828 			return 1;
1829 		}
1830 
1831 		mt = mi->mi_targets[ i ];
1832 
1833 		mt->mt_rebind_f = mi->mi_rebind_f;
1834 		mt->mt_urllist_f = mi->mi_urllist_f;
1835 		mt->mt_urllist_p = mt;
1836 
1837 		if ( META_BACK_QUARANTINE( mi ) ) {
1838 			ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
1839 		}
1840 		mt->mt_mc = mi->mi_mc;
1841 
1842 		for ( j = 1; j < c->argc; j++ ) {
1843 			char	**tmpuris = ldap_str2charray( c->argv[ j ], "\t" );
1844 
1845 			if ( tmpuris == NULL ) {
1846 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
1847 					"unable to parse URIs #%d"
1848 					" in \"%s <protocol>://<server>[:port]/<naming context>\"",
1849 					j-1, c->argv[0] );
1850 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1851 				return 1;
1852 			}
1853 
1854 			if ( j == 1 ) {
1855 				uris = tmpuris;
1856 
1857 			} else {
1858 				ldap_charray_merge( &uris, tmpuris );
1859 				ldap_charray_free( tmpuris );
1860 			}
1861 		}
1862 
1863 		for ( j = 0; uris[ j ] != NULL; j++ ) {
1864 			char *tmpuri = NULL;
1865 
1866 			/*
1867 			 * uri MUST be legal!
1868 			 */
1869 			if ( ldap_url_parselist_ext( &ludp, uris[ j ], "\t",
1870 					LDAP_PVT_URL_PARSE_NONE ) != LDAP_SUCCESS
1871 				|| ludp->lud_next != NULL )
1872 			{
1873 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
1874 					"unable to parse URI #%d"
1875 					" in \"%s <protocol>://<server>[:port]/<naming context>\"",
1876 					j-1, c->argv[0] );
1877 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1878 				ldap_charray_free( uris );
1879 				return 1;
1880 			}
1881 
1882 			if ( j == 0 ) {
1883 
1884 				/*
1885 				 * uri MUST have the <dn> part!
1886 				 */
1887 				if ( ludp->lud_dn == NULL ) {
1888 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
1889 						"missing <naming context> "
1890 						" in \"%s <protocol>://<server>[:port]/<naming context>\"",
1891 						c->argv[0] );
1892 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1893 					ldap_free_urllist( ludp );
1894 					ldap_charray_free( uris );
1895 					return 1;
1896 				}
1897 
1898 				/*
1899 				 * copies and stores uri and suffix
1900 				 */
1901 				ber_str2bv( ludp->lud_dn, 0, 0, &dn );
1902 				rc = dnPrettyNormal( NULL, &dn, &mt->mt_psuffix,
1903 					&mt->mt_nsuffix, NULL );
1904 				if ( rc != LDAP_SUCCESS ) {
1905 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
1906 						"target DN is invalid \"%s\"",
1907 						c->argv[1] );
1908 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1909 					ldap_free_urllist( ludp );
1910 					ldap_charray_free( uris );
1911 					return( 1 );
1912 				}
1913 
1914 				ludp->lud_dn[ 0 ] = '\0';
1915 
1916 				switch ( ludp->lud_scope ) {
1917 				case LDAP_SCOPE_DEFAULT:
1918 					mt->mt_scope = LDAP_SCOPE_SUBTREE;
1919 					break;
1920 
1921 				case LDAP_SCOPE_SUBTREE:
1922 				case LDAP_SCOPE_SUBORDINATE:
1923 					mt->mt_scope = ludp->lud_scope;
1924 					break;
1925 
1926 				default:
1927 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
1928 						"invalid scope for target \"%s\"",
1929 						c->argv[1] );
1930 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1931 					ldap_free_urllist( ludp );
1932 					ldap_charray_free( uris );
1933 					return( 1 );
1934 				}
1935 
1936 			} else {
1937 				/* check all, to apply the scope check on the first one */
1938 				if ( ludp->lud_dn != NULL && ludp->lud_dn[ 0 ] != '\0' ) {
1939 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
1940 						"multiple URIs must have no DN part" );
1941 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1942 					ldap_free_urllist( ludp );
1943 					ldap_charray_free( uris );
1944 					return( 1 );
1945 
1946 				}
1947 			}
1948 
1949 			tmpuri = ldap_url_list2urls( ludp );
1950 			ldap_free_urllist( ludp );
1951 			if ( tmpuri == NULL ) {
1952 				snprintf( c->cr_msg, sizeof( c->cr_msg ), "no memory?" );
1953 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1954 				ldap_charray_free( uris );
1955 				return( 1 );
1956 			}
1957 			ldap_memfree( uris[ j ] );
1958 			uris[ j ] = tmpuri;
1959 		}
1960 
1961 		mt->mt_uri = ldap_charray2str( uris, " " );
1962 		ldap_charray_free( uris );
1963 		if ( mt->mt_uri == NULL) {
1964 			snprintf( c->cr_msg, sizeof( c->cr_msg ), "no memory?" );
1965 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1966 			return( 1 );
1967 		}
1968 
1969 		/*
1970 		 * uri MUST be a branch of suffix!
1971 		 */
1972 		for ( j = 0; !BER_BVISNULL( &c->be->be_nsuffix[ j ] ); j++ ) {
1973 			if ( dnIsSuffix( &mt->mt_nsuffix, &c->be->be_nsuffix[ j ] ) ) {
1974 				break;
1975 			}
1976 		}
1977 
1978 		if ( BER_BVISNULL( &c->be->be_nsuffix[ j ] ) ) {
1979 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
1980 				"<naming context> of URI must be within the naming context of this database." );
1981 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1982 			return 1;
1983 		}
1984 		c->ca_private = mt;
1985 		config_push_cleanup( c, asyncmeta_cf_cleanup );
1986 	} break;
1987 	case LDAP_BACK_CFG_SUBTREE_EX:
1988 	case LDAP_BACK_CFG_SUBTREE_IN:
1989 	/* subtree-exclude */
1990 		if ( asyncmeta_subtree_config( mt, c )) {
1991 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
1992 			return 1;
1993 		}
1994 		break;
1995 
1996 	case LDAP_BACK_CFG_FILTER: {
1997 		metafilter_t *mf, **m2;
1998 		mf = ch_malloc( sizeof( metafilter_t ));
1999 		rc = regcomp( &mf->mf_regex, c->argv[1], REG_EXTENDED );
2000 		if ( rc ) {
2001 			char regerr[ SLAP_TEXT_BUFLEN ];
2002 			regerror( rc, &mf->mf_regex, regerr, sizeof(regerr) );
2003 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2004 				"regular expression \"%s\" bad because of %s",
2005 				c->argv[1], regerr );
2006 			ch_free( mf );
2007 			return 1;
2008 		}
2009 		ber_str2bv( c->argv[1], 0, 1, &mf->mf_regex_pattern );
2010 		for ( m2 = &mt->mt_filter; *m2; m2 = &(*m2)->mf_next )
2011 			;
2012 		*m2 = mf;
2013 	} break;
2014 	case LDAP_BACK_CFG_MAX_PENDING_OPS:
2015 		if (c->value_int < 0) {
2016 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2017 				  "max-pending-ops invalid value %d",
2018 				  c->value_int);
2019 			return 1;
2020 		}
2021 		mi->mi_max_pending_ops = c->value_int;
2022 		break;
2023 	case LDAP_BACK_CFG_MAX_TARGET_CONNS:
2024 	{
2025 		if (c->value_int < 0) {
2026 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2027 				  "max-target-conns invalid value %d",
2028 				  c->value_int);
2029 			return 1;
2030 		}
2031 		mi->mi_max_target_conns = c->value_int;
2032 	}
2033 		break;
2034 	case LDAP_BACK_CFG_MAX_TIMEOUT_OPS:
2035 		if (c->value_int < 0) {
2036 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2037 				  "max-timeout-ops invalid value %d",
2038 				  c->value_int);
2039 			return 1;
2040 		}
2041 		mi->mi_max_timeout_ops = c->value_int;
2042 		break;
2043 
2044 	case LDAP_BACK_CFG_DEFAULT_T:
2045 	/* default target directive */
2046 		i = mi->mi_ntargets - 1;
2047 
2048 		if ( c->argc == 1 ) {
2049 			if ( i < 0 ) {
2050 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2051 					"\"%s\" alone must be inside a \"uri\" directive",
2052 					c->argv[0] );
2053 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2054 				return 1;
2055 			}
2056 			mi->mi_defaulttarget = i;
2057 
2058 		} else {
2059 			if ( strcasecmp( c->argv[ 1 ], "none" ) == 0 ) {
2060 				if ( i >= 0 ) {
2061 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
2062 						"\"%s none\" should go before uri definitions",
2063 						c->argv[0] );
2064 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2065 				}
2066 				mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
2067 
2068 			} else {
2069 
2070 				if ( lutil_atoi( &mi->mi_defaulttarget, c->argv[ 1 ] ) != 0
2071 					|| mi->mi_defaulttarget < 0
2072 					|| mi->mi_defaulttarget >= i - 1 )
2073 				{
2074 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
2075 						"illegal target number %d",
2076 						mi->mi_defaulttarget );
2077 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2078 					return 1;
2079 				}
2080 			}
2081 		}
2082 		break;
2083 
2084 	case LDAP_BACK_CFG_DNCACHE_TTL:
2085 	/* ttl of dn cache */
2086 		if ( strcasecmp( c->argv[ 1 ], "forever" ) == 0 ) {
2087 			mi->mi_cache.ttl = META_DNCACHE_FOREVER;
2088 
2089 		} else if ( strcasecmp( c->argv[ 1 ], "disabled" ) == 0 ) {
2090 			mi->mi_cache.ttl = META_DNCACHE_DISABLED;
2091 
2092 		} else {
2093 			unsigned long	t;
2094 
2095 			if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
2096 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2097 					"unable to parse dncache ttl \"%s\"",
2098 					c->argv[ 1 ] );
2099 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2100 				return 1;
2101 			}
2102 			mi->mi_cache.ttl = (time_t)t;
2103 		}
2104 		break;
2105 
2106 	case LDAP_BACK_CFG_NETWORK_TIMEOUT: {
2107 	/* network timeout when connecting to ldap servers */
2108 		unsigned long t;
2109 
2110 		if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
2111 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2112 				"unable to parse network timeout \"%s\"",
2113 				c->argv[ 1 ] );
2114 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2115 			return 1;
2116 		}
2117 		mc->mc_network_timeout = (time_t)t;
2118 		} break;
2119 
2120 	case LDAP_BACK_CFG_IDLE_TIMEOUT: {
2121 	/* idle timeout when connecting to ldap servers */
2122 		unsigned long	t;
2123 
2124 		if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
2125 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2126 				"unable to parse idle timeout \"%s\"",
2127 				c->argv[ 1 ] );
2128 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2129 			return 1;
2130 
2131 		}
2132 		mi->mi_idle_timeout = (time_t)t;
2133 		} break;
2134 
2135 	case LDAP_BACK_CFG_BIND_TIMEOUT:
2136 	/* bind timeout when connecting to ldap servers */
2137 		mc->mc_bind_timeout.tv_sec = c->value_ulong/1000000;
2138 		mc->mc_bind_timeout.tv_usec = c->value_ulong%1000000;
2139 		break;
2140 
2141 	case LDAP_BACK_CFG_REBIND:
2142 	/* save bind creds for referral rebinds? */
2143 		if ( c->argc == 1 || c->value_int ) {
2144 			mc->mc_flags |= LDAP_BACK_F_SAVECRED;
2145 		} else {
2146 			mc->mc_flags &= ~LDAP_BACK_F_SAVECRED;
2147 		}
2148 		break;
2149 
2150 	case LDAP_BACK_CFG_CHASE:
2151 		if ( c->argc == 1 || c->value_int ) {
2152 			mc->mc_flags |= LDAP_BACK_F_CHASE_REFERRALS;
2153 		} else {
2154 			mc->mc_flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
2155 		}
2156 		break;
2157 
2158 	case LDAP_BACK_CFG_TLS:
2159 		i = verb_to_mask( c->argv[1], tls_mode );
2160 		if ( BER_BVISNULL( &tls_mode[i].word ) ) {
2161 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2162 				"%s unknown argument \"%s\"",
2163 				c->argv[0], c->argv[1] );
2164 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2165 			return 1;
2166 		}
2167 		mc->mc_flags &= ~LDAP_BACK_F_TLS_MASK;
2168 		mc->mc_flags |= tls_mode[i].mask;
2169 
2170 		if ( c->argc > 2 ) {
2171 			if ( c->op == SLAP_CONFIG_ADD && mi->mi_ntargets == 0 ) {
2172 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2173 					"need \"uri\" directive first" );
2174 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2175 				return 1;
2176 			}
2177 
2178 			for ( i = 2; i < c->argc; i++ ) {
2179 				if ( bindconf_tls_parse( c->argv[i], &mt->mt_tls ))
2180 					return 1;
2181 			}
2182 			bindconf_tls_defaults( &mt->mt_tls );
2183 		}
2184 		break;
2185 
2186 	case LDAP_BACK_CFG_T_F:
2187 		i = verb_to_mask( c->argv[1], t_f_mode );
2188 		if ( BER_BVISNULL( &t_f_mode[i].word ) ) {
2189 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2190 				"%s unknown argument \"%s\"",
2191 				c->argv[0], c->argv[1] );
2192 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2193 			return 1;
2194 		}
2195 		mc->mc_flags &= ~LDAP_BACK_F_T_F_MASK2;
2196 		mc->mc_flags |= t_f_mode[i].mask;
2197 		break;
2198 
2199 	case LDAP_BACK_CFG_ONERR:
2200 	/* onerr? */
2201 		i = verb_to_mask( c->argv[1], onerr_mode );
2202 		if ( BER_BVISNULL( &onerr_mode[i].word ) ) {
2203 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2204 				"%s unknown argument \"%s\"",
2205 				c->argv[0], c->argv[1] );
2206 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2207 			return 1;
2208 		}
2209 		mi->mi_flags &= ~META_BACK_F_ONERR_MASK;
2210 		mi->mi_flags |= onerr_mode[i].mask;
2211 		break;
2212 
2213 	case LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER:
2214 	/* bind-defer? */
2215 		if ( c->argc == 1 || c->value_int ) {
2216 			mi->mi_flags |= META_BACK_F_DEFER_ROOTDN_BIND;
2217 		} else {
2218 			mi->mi_flags &= ~META_BACK_F_DEFER_ROOTDN_BIND;
2219 		}
2220 		break;
2221 
2222 	case LDAP_BACK_CFG_CONNPOOLMAX:
2223 	/* privileged connections pool max size ? */
2224 		if ( mi->mi_ntargets > 0 ) {
2225 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2226 				"\"%s\" must appear before target definitions",
2227 				c->argv[0] );
2228 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2229 			return( 1 );
2230 		}
2231 
2232 		if ( c->value_int < LDAP_BACK_CONN_PRIV_MIN
2233 			|| c->value_int > LDAP_BACK_CONN_PRIV_MAX )
2234 		{
2235 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2236 				"invalid max size " "of privileged "
2237 				"connections pool \"%s\" "
2238 				"in \"conn-pool-max <n> "
2239 				"(must be between %d and %d)\"",
2240 				c->argv[ 1 ],
2241 				LDAP_BACK_CONN_PRIV_MIN,
2242 				LDAP_BACK_CONN_PRIV_MAX );
2243 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2244 			return 1;
2245 		}
2246 		mi->mi_conn_priv_max = c->value_int;
2247 		break;
2248 
2249 	case LDAP_BACK_CFG_CANCEL:
2250 		i = verb_to_mask( c->argv[1], cancel_mode );
2251 		if ( BER_BVISNULL( &cancel_mode[i].word ) ) {
2252 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2253 				"%s unknown argument \"%s\"",
2254 				c->argv[0], c->argv[1] );
2255 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2256 			return 1;
2257 		}
2258 		mc->mc_flags &= ~LDAP_BACK_F_CANCEL_MASK2;
2259 		mc->mc_flags |= cancel_mode[i].mask;
2260 		break;
2261 
2262 	case LDAP_BACK_CFG_TIMEOUT:
2263 		for ( i = 1; i < c->argc; i++ ) {
2264 			if ( isdigit( (unsigned char) c->argv[ i ][ 0 ] ) ) {
2265 				int		j;
2266 				unsigned	u;
2267 
2268 				if ( lutil_atoux( &u, c->argv[ i ], 0 ) != 0 ) {
2269 					snprintf( c->cr_msg, sizeof( c->cr_msg),
2270 						"unable to parse timeout \"%s\"",
2271 						c->argv[ i ] );
2272 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2273 					return 1;
2274 				}
2275 
2276 				for ( j = 0; j < SLAP_OP_LAST; j++ ) {
2277 					mc->mc_timeout[ j ] = u;
2278 				}
2279 
2280 				continue;
2281 			}
2282 
2283 			if ( slap_cf_aux_table_parse( c->argv[ i ], mc->mc_timeout, timeout_table, "slapd-meta timeout" ) ) {
2284 				snprintf( c->cr_msg, sizeof( c->cr_msg),
2285 					"unable to parse timeout \"%s\"",
2286 					c->argv[ i ] );
2287 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2288 				return 1;
2289 			}
2290 		}
2291 		break;
2292 
2293 	case LDAP_BACK_CFG_IDASSERT_BIND:
2294 	/* idassert-bind */
2295 		rc = mi->mi_ldap_extra->idassert_parse( c, &mt->mt_idassert );
2296 		break;
2297 
2298 	case LDAP_BACK_CFG_IDASSERT_AUTHZFROM:
2299 	/* idassert-authzFrom */
2300 		rc = mi->mi_ldap_extra->idassert_authzfrom_parse( c, &mt->mt_idassert );
2301 		break;
2302 
2303 	case LDAP_BACK_CFG_QUARANTINE:
2304 	/* quarantine */
2305 		if ( META_BACK_CMN_QUARANTINE( mc ) )
2306 		{
2307 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2308 				"quarantine already defined" );
2309 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2310 			return 1;
2311 		}
2312 
2313 		if ( mt ) {
2314 			mc->mc_quarantine.ri_interval = NULL;
2315 			mc->mc_quarantine.ri_num = NULL;
2316 			if ( !META_BACK_QUARANTINE( mi ) ) {
2317 				ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
2318 			}
2319 		}
2320 
2321 		if ( mi->mi_ldap_extra->retry_info_parse( c->argv[ 1 ], &mc->mc_quarantine, c->cr_msg, sizeof( c->cr_msg ) ) ) {
2322 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2323 			return 1;
2324 		}
2325 
2326 		mc->mc_flags |= LDAP_BACK_F_QUARANTINE;
2327 		break;
2328 
2329 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
2330 	case LDAP_BACK_CFG_ST_REQUEST:
2331 	/* session tracking request */
2332 		if ( c->value_int ) {
2333 			mc->mc_flags |= LDAP_BACK_F_ST_REQUEST;
2334 		} else {
2335 			mc->mc_flags &= ~LDAP_BACK_F_ST_REQUEST;
2336 		}
2337 		break;
2338 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
2339 
2340 	case LDAP_BACK_CFG_SUFFIXM:
2341 		rc = asyncmeta_suffixm_config( c, c->argc, c->argv, mt );
2342 		break;
2343 
2344 	case LDAP_BACK_CFG_NRETRIES: {
2345 		int		nretries = META_RETRY_UNDEFINED;
2346 
2347 		if ( strcasecmp( c->argv[ 1 ], "forever" ) == 0 ) {
2348 			nretries = META_RETRY_FOREVER;
2349 
2350 		} else if ( strcasecmp( c->argv[ 1 ], "never" ) == 0 ) {
2351 			nretries = META_RETRY_NEVER;
2352 
2353 		} else {
2354 			if ( lutil_atoi( &nretries, c->argv[ 1 ] ) != 0 ) {
2355 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2356 					"unable to parse nretries {never|forever|<retries>}: \"%s\"",
2357 					c->argv[ 1 ] );
2358 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2359 				return 1;
2360 			}
2361 		}
2362 
2363 		mc->mc_nretries = nretries;
2364 		} break;
2365 
2366 	case LDAP_BACK_CFG_VERSION:
2367 		if ( c->value_int != 0 && ( c->value_int < LDAP_VERSION_MIN || c->value_int > LDAP_VERSION_MAX ) ) {
2368 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2369 				"unsupported protocol version \"%s\"",
2370 				c->argv[ 1 ] );
2371 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2372 			return 1;
2373 		}
2374 		mc->mc_version = c->value_int;
2375 		break;
2376 
2377 	case LDAP_BACK_CFG_NOREFS:
2378 	/* do not return search references */
2379 		if ( c->value_int ) {
2380 			mc->mc_flags |= LDAP_BACK_F_NOREFS;
2381 		} else {
2382 			mc->mc_flags &= ~LDAP_BACK_F_NOREFS;
2383 		}
2384 		break;
2385 
2386 	case LDAP_BACK_CFG_NOUNDEFFILTER:
2387 	/* do not propagate undefined search filters */
2388 		if ( c->value_int ) {
2389 			mc->mc_flags |= LDAP_BACK_F_NOUNDEFFILTER;
2390 		} else {
2391 			mc->mc_flags &= ~LDAP_BACK_F_NOUNDEFFILTER;
2392 		}
2393 		break;
2394 
2395 #ifdef SLAPD_META_CLIENT_PR
2396 	case LDAP_BACK_CFG_CLIENT_PR:
2397 		if ( strcasecmp( c->argv[ 1 ], "accept-unsolicited" ) == 0 ) {
2398 			mc->mc_ps = META_CLIENT_PR_ACCEPT_UNSOLICITED;
2399 
2400 		} else if ( strcasecmp( c->argv[ 1 ], "disable" ) == 0 ) {
2401 			mc->mc_ps = META_CLIENT_PR_DISABLE;
2402 
2403 		} else if ( lutil_atoi( &mc->mc_ps, c->argv[ 1 ] ) || mc->mc_ps < -1 ) {
2404 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2405 				"unable to parse client-pr {accept-unsolicited|disable|<size>}: \"%s\"",
2406 				c->argv[ 1 ] );
2407 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
2408 			return( 1 );
2409 		}
2410 		break;
2411 #endif /* SLAPD_META_CLIENT_PR */
2412 
2413 	case LDAP_BACK_CFG_KEEPALIVE:
2414 		slap_keepalive_parse( ber_bvstrdup(c->argv[1]),
2415 				 &mt->mt_tls.sb_keepalive, 0, 0, 0);
2416 		break;
2417 
2418 	case LDAP_BACK_CFG_TCP_USER_TIMEOUT:
2419 		mt->mt_tls.sb_tcp_user_timeout = c->value_uint;
2420 		break;
2421 
2422 	/* anything else */
2423 	default:
2424 		return SLAP_CONF_UNKNOWN;
2425 	}
2426 
2427 	return rc;
2428 }
2429 
2430 int
asyncmeta_back_init_cf(BackendInfo * bi)2431 asyncmeta_back_init_cf( BackendInfo *bi )
2432 {
2433 	int			rc;
2434 
2435 	/* Make sure we don't exceed the bits reserved for userland */
2436 	config_check_userland( LDAP_BACK_CFG_LAST );
2437 
2438 	bi->bi_cf_ocs = a_metaocs;
2439 
2440 	rc = config_register_schema( a_metacfg, a_metaocs );
2441 	if ( rc ) {
2442 		return rc;
2443 	}
2444 
2445 	return 0;
2446 }
2447