xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-ldap/config.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
1 /*	$NetBSD: config.c,v 1.2 2020/08/11 13:15:40 christos Exp $	*/
2 
3 /* config.c - ldap backend configuration file routine */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2003-2020 The OpenLDAP Foundation.
8  * Portions Copyright 1999-2003 Howard Chu.
9  * Portions Copyright 2000-2003 Pierangelo Masarati.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* ACKNOWLEDGEMENTS:
21  * This work was initially developed by the Howard Chu for inclusion
22  * in OpenLDAP Software and subsequently enhanced by Pierangelo
23  * Masarati.
24  */
25 
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: config.c,v 1.2 2020/08/11 13:15:40 christos Exp $");
28 
29 #include "portable.h"
30 
31 #include <stdio.h>
32 
33 #include <ac/string.h>
34 #include <ac/ctype.h>
35 #include <ac/socket.h>
36 
37 #include "slap.h"
38 #include "config.h"
39 #include "back-ldap.h"
40 #include "lutil.h"
41 #include "ldif.h"
42 
43 static SLAP_EXTOP_MAIN_FN ldap_back_exop_whoami;
44 
45 static ConfigDriver ldap_back_cf_gen;
46 static ConfigDriver ldap_pbind_cf_gen;
47 
48 enum {
49 	LDAP_BACK_CFG_URI = 1,
50 	LDAP_BACK_CFG_TLS,
51 	LDAP_BACK_CFG_ACL_AUTHCDN,
52 	LDAP_BACK_CFG_ACL_PASSWD,
53 	LDAP_BACK_CFG_ACL_METHOD,
54 	LDAP_BACK_CFG_ACL_BIND,
55 	LDAP_BACK_CFG_IDASSERT_MODE,
56 	LDAP_BACK_CFG_IDASSERT_AUTHCDN,
57 	LDAP_BACK_CFG_IDASSERT_PASSWD,
58 	LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
59 	LDAP_BACK_CFG_IDASSERT_PASSTHRU,
60 	LDAP_BACK_CFG_IDASSERT_METHOD,
61 	LDAP_BACK_CFG_IDASSERT_BIND,
62 	LDAP_BACK_CFG_REBIND,
63 	LDAP_BACK_CFG_CHASE,
64 	LDAP_BACK_CFG_T_F,
65 	LDAP_BACK_CFG_WHOAMI,
66 	LDAP_BACK_CFG_TIMEOUT,
67 	LDAP_BACK_CFG_IDLE_TIMEOUT,
68 	LDAP_BACK_CFG_CONN_TTL,
69 	LDAP_BACK_CFG_NETWORK_TIMEOUT,
70 	LDAP_BACK_CFG_VERSION,
71 	LDAP_BACK_CFG_SINGLECONN,
72 	LDAP_BACK_CFG_USETEMP,
73 	LDAP_BACK_CFG_CONNPOOLMAX,
74 	LDAP_BACK_CFG_CANCEL,
75 	LDAP_BACK_CFG_QUARANTINE,
76 	LDAP_BACK_CFG_ST_REQUEST,
77 	LDAP_BACK_CFG_NOREFS,
78 	LDAP_BACK_CFG_NOUNDEFFILTER,
79 	LDAP_BACK_CFG_ONERR,
80 
81 	LDAP_BACK_CFG_REWRITE,
82 	LDAP_BACK_CFG_KEEPALIVE,
83 
84 	LDAP_BACK_CFG_OMIT_UNKNOWN_SCHEMA,
85 
86 	LDAP_BACK_CFG_LAST
87 };
88 
89 static ConfigTable ldapcfg[] = {
90 	{ "uri", "uri", 2, 2, 0,
91 		ARG_MAGIC|LDAP_BACK_CFG_URI,
92 		ldap_back_cf_gen, "( OLcfgDbAt:0.14 "
93 			"NAME 'olcDbURI' "
94 			"DESC 'URI (list) for remote DSA' "
95 			"SYNTAX OMsDirectoryString "
96 			"SINGLE-VALUE )",
97 		NULL, NULL },
98 	{ "tls", "what", 2, 0, 0,
99 		ARG_MAGIC|LDAP_BACK_CFG_TLS,
100 		ldap_back_cf_gen, "( OLcfgDbAt:3.1 "
101 			"NAME 'olcDbStartTLS' "
102 			"DESC 'StartTLS' "
103 			"SYNTAX OMsDirectoryString "
104 			"SINGLE-VALUE )",
105 		NULL, NULL },
106 	{ "acl-authcDN", "DN", 2, 2, 0,
107 		ARG_DN|ARG_MAGIC|LDAP_BACK_CFG_ACL_AUTHCDN,
108 		ldap_back_cf_gen, "( OLcfgDbAt:3.2 "
109 			"NAME 'olcDbACLAuthcDn' "
110 			"DESC 'Remote ACL administrative identity' "
111 			"OBSOLETE "
112 			"SYNTAX OMsDN "
113 			"SINGLE-VALUE )",
114 		NULL, NULL },
115 	/* deprecated, will be removed; aliases "acl-authcDN" */
116 	{ "binddn", "DN", 2, 2, 0,
117 		ARG_DN|ARG_MAGIC|LDAP_BACK_CFG_ACL_AUTHCDN,
118 		ldap_back_cf_gen, NULL, NULL, NULL },
119 	{ "acl-passwd", "cred", 2, 2, 0,
120 		ARG_MAGIC|LDAP_BACK_CFG_ACL_PASSWD,
121 		ldap_back_cf_gen, "( OLcfgDbAt:3.3 "
122 			"NAME 'olcDbACLPasswd' "
123 			"DESC 'Remote ACL administrative identity credentials' "
124 			"OBSOLETE "
125 			"SYNTAX OMsDirectoryString "
126 			"SINGLE-VALUE )",
127 		NULL, NULL },
128 	/* deprecated, will be removed; aliases "acl-passwd" */
129 	{ "bindpw", "cred", 2, 2, 0,
130 		ARG_MAGIC|LDAP_BACK_CFG_ACL_PASSWD,
131 		ldap_back_cf_gen, NULL, NULL, NULL },
132 	/* deprecated, will be removed; aliases "acl-bind" */
133 	{ "acl-method", "args", 2, 0, 0,
134 		ARG_MAGIC|LDAP_BACK_CFG_ACL_METHOD,
135 		ldap_back_cf_gen, NULL, NULL, NULL },
136 	{ "acl-bind", "args", 2, 0, 0,
137 		ARG_MAGIC|LDAP_BACK_CFG_ACL_BIND,
138 		ldap_back_cf_gen, "( OLcfgDbAt:3.4 "
139 			"NAME 'olcDbACLBind' "
140 			"DESC 'Remote ACL administrative identity auth bind configuration' "
141 			"SYNTAX OMsDirectoryString "
142 			"SINGLE-VALUE )",
143 		NULL, NULL },
144 	{ "idassert-authcDN", "DN", 2, 2, 0,
145 		ARG_DN|ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_AUTHCDN,
146 		ldap_back_cf_gen, "( OLcfgDbAt:3.5 "
147 			"NAME 'olcDbIDAssertAuthcDn' "
148 			"DESC 'Remote Identity Assertion administrative identity' "
149 			"OBSOLETE "
150 			"SYNTAX OMsDN "
151 			"SINGLE-VALUE )",
152 		NULL, NULL },
153 	/* deprecated, will be removed; partially aliases "idassert-authcDN" */
154 	{ "proxyauthzdn", "DN", 2, 2, 0,
155 		ARG_DN|ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_AUTHCDN,
156 		ldap_back_cf_gen, NULL, NULL, NULL },
157 	{ "idassert-passwd", "cred", 2, 2, 0,
158 		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_PASSWD,
159 		ldap_back_cf_gen, "( OLcfgDbAt:3.6 "
160 			"NAME 'olcDbIDAssertPasswd' "
161 			"DESC 'Remote Identity Assertion administrative identity credentials' "
162 			"OBSOLETE "
163 			"SYNTAX OMsDirectoryString "
164 			"SINGLE-VALUE )",
165 		NULL, NULL },
166 	/* deprecated, will be removed; partially aliases "idassert-passwd" */
167 	{ "proxyauthzpw", "cred", 2, 2, 0,
168 		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_PASSWD,
169 		ldap_back_cf_gen, NULL, NULL, NULL },
170 	{ "idassert-bind", "args", 2, 0, 0,
171 		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_BIND,
172 		ldap_back_cf_gen, "( OLcfgDbAt:3.7 "
173 			"NAME 'olcDbIDAssertBind' "
174 			"DESC 'Remote Identity Assertion administrative identity auth bind configuration' "
175 			"SYNTAX OMsDirectoryString "
176 			"SINGLE-VALUE )",
177 		NULL, NULL },
178 	{ "idassert-method", "args", 2, 0, 0,
179 		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_METHOD,
180 		ldap_back_cf_gen, NULL, NULL, NULL },
181 	{ "idassert-mode", "mode>|u:<user>|[dn:]<DN", 2, 0, 0,
182 		ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_MODE,
183 		ldap_back_cf_gen, "( OLcfgDbAt:3.8 "
184 			"NAME 'olcDbIDAssertMode' "
185 			"DESC 'Remote Identity Assertion mode' "
186 			"OBSOLETE "
187 			"SYNTAX OMsDirectoryString "
188 			"SINGLE-VALUE)",
189 		NULL, NULL },
190 	{ "idassert-authzFrom", "authzRule", 2, 2, 0,
191 		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
192 		ldap_back_cf_gen, "( OLcfgDbAt:3.9 "
193 			"NAME 'olcDbIDAssertAuthzFrom' "
194 			"DESC 'Remote Identity Assertion authz rules' "
195 			"EQUALITY caseIgnoreMatch "
196 			"SYNTAX OMsDirectoryString "
197 			"X-ORDERED 'VALUES' )",
198 		NULL, NULL },
199 	{ "rebind-as-user", "true|FALSE", 1, 2, 0,
200 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_REBIND,
201 		ldap_back_cf_gen, "( OLcfgDbAt:3.10 "
202 			"NAME 'olcDbRebindAsUser' "
203 			"DESC 'Rebind as user' "
204 			"SYNTAX OMsBoolean "
205 			"SINGLE-VALUE )",
206 		NULL, NULL },
207 	{ "chase-referrals", "true|FALSE", 2, 2, 0,
208 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_CHASE,
209 		ldap_back_cf_gen, "( OLcfgDbAt:3.11 "
210 			"NAME 'olcDbChaseReferrals' "
211 			"DESC 'Chase referrals' "
212 			"SYNTAX OMsBoolean "
213 			"SINGLE-VALUE )",
214 		NULL, NULL },
215 	{ "t-f-support", "true|FALSE|discover", 2, 2, 0,
216 		ARG_MAGIC|LDAP_BACK_CFG_T_F,
217 		ldap_back_cf_gen, "( OLcfgDbAt:3.12 "
218 			"NAME 'olcDbTFSupport' "
219 			"DESC 'Absolute filters support' "
220 			"SYNTAX OMsDirectoryString "
221 			"SINGLE-VALUE )",
222 		NULL, NULL },
223 	{ "proxy-whoami", "true|FALSE", 1, 2, 0,
224 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_WHOAMI,
225 		ldap_back_cf_gen, "( OLcfgDbAt:3.13 "
226 			"NAME 'olcDbProxyWhoAmI' "
227 			"DESC 'Proxy whoAmI exop' "
228 			"SYNTAX OMsBoolean "
229 			"SINGLE-VALUE )",
230 		NULL, NULL },
231 	{ "timeout", "timeout(list)", 2, 0, 0,
232 		ARG_MAGIC|LDAP_BACK_CFG_TIMEOUT,
233 		ldap_back_cf_gen, "( OLcfgDbAt:3.14 "
234 			"NAME 'olcDbTimeout' "
235 			"DESC 'Per-operation timeouts' "
236 			"SYNTAX OMsDirectoryString "
237 			"SINGLE-VALUE )",
238 		NULL, NULL },
239 	{ "idle-timeout", "timeout", 2, 2, 0,
240 		ARG_MAGIC|LDAP_BACK_CFG_IDLE_TIMEOUT,
241 		ldap_back_cf_gen, "( OLcfgDbAt:3.15 "
242 			"NAME 'olcDbIdleTimeout' "
243 			"DESC 'connection idle timeout' "
244 			"SYNTAX OMsDirectoryString "
245 			"SINGLE-VALUE )",
246 		NULL, NULL },
247 	{ "conn-ttl", "ttl", 2, 2, 0,
248 		ARG_MAGIC|LDAP_BACK_CFG_CONN_TTL,
249 		ldap_back_cf_gen, "( OLcfgDbAt:3.16 "
250 			"NAME 'olcDbConnTtl' "
251 			"DESC 'connection ttl' "
252 			"SYNTAX OMsDirectoryString "
253 			"SINGLE-VALUE )",
254 		NULL, NULL },
255 	{ "network-timeout", "timeout", 2, 2, 0,
256 		ARG_MAGIC|LDAP_BACK_CFG_NETWORK_TIMEOUT,
257 		ldap_back_cf_gen, "( OLcfgDbAt:3.17 "
258 			"NAME 'olcDbNetworkTimeout' "
259 			"DESC 'connection network timeout' "
260 			"SYNTAX OMsDirectoryString "
261 			"SINGLE-VALUE )",
262 		NULL, NULL },
263 	{ "protocol-version", "version", 2, 2, 0,
264 		ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_VERSION,
265 		ldap_back_cf_gen, "( OLcfgDbAt:3.18 "
266 			"NAME 'olcDbProtocolVersion' "
267 			"DESC 'protocol version' "
268 			"SYNTAX OMsInteger "
269 			"SINGLE-VALUE )",
270 		NULL, NULL },
271 	{ "single-conn", "true|FALSE", 2, 2, 0,
272 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_SINGLECONN,
273 		ldap_back_cf_gen, "( OLcfgDbAt:3.19 "
274 			"NAME 'olcDbSingleConn' "
275 			"DESC 'cache a single connection per identity' "
276 			"SYNTAX OMsBoolean "
277 			"SINGLE-VALUE )",
278 		NULL, NULL },
279 	{ "cancel", "ABANDON|ignore|exop", 2, 2, 0,
280 		ARG_MAGIC|LDAP_BACK_CFG_CANCEL,
281 		ldap_back_cf_gen, "( OLcfgDbAt:3.20 "
282 			"NAME 'olcDbCancel' "
283 			"DESC 'abandon/ignore/exop operations when appropriate' "
284 			"SYNTAX OMsDirectoryString "
285 			"SINGLE-VALUE )",
286 		NULL, NULL },
287 	{ "quarantine", "retrylist", 2, 2, 0,
288 		ARG_MAGIC|LDAP_BACK_CFG_QUARANTINE,
289 		ldap_back_cf_gen, "( OLcfgDbAt:3.21 "
290 			"NAME 'olcDbQuarantine' "
291 			"DESC 'Quarantine database if connection fails and retry according to rule' "
292 			"SYNTAX OMsDirectoryString "
293 			"SINGLE-VALUE )",
294 		NULL, NULL },
295 	{ "use-temporary-conn", "true|FALSE", 2, 2, 0,
296 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_USETEMP,
297 		ldap_back_cf_gen, "( OLcfgDbAt:3.22 "
298 			"NAME 'olcDbUseTemporaryConn' "
299 			"DESC 'Use temporary connections if the cached one is busy' "
300 			"SYNTAX OMsBoolean "
301 			"SINGLE-VALUE )",
302 		NULL, NULL },
303 	{ "conn-pool-max", "<n>", 2, 2, 0,
304 		ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_CONNPOOLMAX,
305 		ldap_back_cf_gen, "( OLcfgDbAt:3.23 "
306 			"NAME 'olcDbConnectionPoolMax' "
307 			"DESC 'Max size of privileged connections pool' "
308 			"SYNTAX OMsInteger "
309 			"SINGLE-VALUE )",
310 		NULL, NULL },
311 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
312 	{ "session-tracking-request", "true|FALSE", 2, 2, 0,
313 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_ST_REQUEST,
314 		ldap_back_cf_gen, "( OLcfgDbAt:3.24 "
315 			"NAME 'olcDbSessionTrackingRequest' "
316 			"DESC 'Add session tracking control to proxied requests' "
317 			"SYNTAX OMsBoolean "
318 			"SINGLE-VALUE )",
319 		NULL, NULL },
320 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
321 	{ "norefs", "true|FALSE", 2, 2, 0,
322 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_NOREFS,
323 		ldap_back_cf_gen, "( OLcfgDbAt:3.25 "
324 			"NAME 'olcDbNoRefs' "
325 			"DESC 'Do not return search reference responses' "
326 			"SYNTAX OMsBoolean "
327 			"SINGLE-VALUE )",
328 		NULL, NULL },
329 	{ "noundeffilter", "true|FALSE", 2, 2, 0,
330 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_NOUNDEFFILTER,
331 		ldap_back_cf_gen, "( OLcfgDbAt:3.26 "
332 			"NAME 'olcDbNoUndefFilter' "
333 			"DESC 'Do not propagate undefined search filters' "
334 			"SYNTAX OMsBoolean "
335 			"SINGLE-VALUE )",
336 		NULL, NULL },
337 	{ "onerr", "CONTINUE|report|stop", 2, 2, 0,
338 		ARG_MAGIC|LDAP_BACK_CFG_ONERR,
339 		ldap_back_cf_gen, "( OLcfgDbAt:3.108 "
340 			"NAME 'olcDbOnErr' "
341 			"DESC 'error handling' "
342 			"SYNTAX OMsDirectoryString "
343 			"SINGLE-VALUE )",
344 		NULL, NULL },
345 	{ "idassert-passThru", "authzRule", 2, 2, 0,
346 		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_PASSTHRU,
347 		ldap_back_cf_gen, "( OLcfgDbAt:3.27 "
348 			"NAME 'olcDbIDAssertPassThru' "
349 			"DESC 'Remote Identity Assertion passthru rules' "
350 			"EQUALITY caseIgnoreMatch "
351 			"SYNTAX OMsDirectoryString "
352 			"X-ORDERED 'VALUES' )",
353 		NULL, NULL },
354 
355 	{ "suffixmassage", "[virtual]> <real", 2, 3, 0,
356 		ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
357 		ldap_back_cf_gen, NULL, NULL, NULL },
358 	{ "map", "attribute|objectClass> [*|<local>] *|<remote", 3, 4, 0,
359 		ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
360 		ldap_back_cf_gen, NULL, NULL, NULL },
361 	{ "rewrite", "<arglist>", 2, 4, STRLENOF( "rewrite" ),
362 		ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
363 		ldap_back_cf_gen, NULL, NULL, NULL },
364 	{ "omit-unknown-schema", "true|FALSE", 2, 2, 0,
365 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_OMIT_UNKNOWN_SCHEMA,
366 		ldap_back_cf_gen, "( OLcfgDbAt:3.28 "
367 			"NAME 'olcDbRemoveUnknownSchema' "
368 			"DESC 'Omit unknown schema when returning search results' "
369 			"SYNTAX OMsBoolean "
370 			"SINGLE-VALUE )",
371 		NULL, NULL },
372 	{ "keepalive", "keepalive", 2, 2, 0,
373 		ARG_MAGIC|LDAP_BACK_CFG_KEEPALIVE,
374 		ldap_back_cf_gen, "( OLcfgDbAt:3.29 "
375 			"NAME 'olcDbKeepalive' "
376 			"DESC 'TCP keepalive' "
377 			"SYNTAX OMsDirectoryString "
378 			"SINGLE-VALUE )",
379 		NULL, NULL },
380 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED,
381 		NULL, NULL, NULL, NULL }
382 };
383 
384 static ConfigOCs ldapocs[] = {
385 	{ "( OLcfgDbOc:3.1 "
386 		"NAME 'olcLDAPConfig' "
387 		"DESC 'LDAP backend configuration' "
388 		"SUP olcDatabaseConfig "
389 		"MAY ( olcDbURI "
390 			"$ olcDbStartTLS "
391 			"$ olcDbACLAuthcDn "
392 			"$ olcDbACLPasswd "
393 			"$ olcDbACLBind "
394 			"$ olcDbIDAssertAuthcDn "
395 			"$ olcDbIDAssertPasswd "
396 			"$ olcDbIDAssertBind "
397 			"$ olcDbIDAssertMode "
398 			"$ olcDbIDAssertAuthzFrom "
399 			"$ olcDbIDAssertPassThru "
400 			"$ olcDbRebindAsUser "
401 			"$ olcDbChaseReferrals "
402 			"$ olcDbTFSupport "
403 			"$ olcDbProxyWhoAmI "
404 			"$ olcDbTimeout "
405 			"$ olcDbIdleTimeout "
406 			"$ olcDbConnTtl "
407 			"$ olcDbNetworkTimeout "
408 			"$ olcDbProtocolVersion "
409 			"$ olcDbSingleConn "
410 			"$ olcDbCancel "
411 			"$ olcDbQuarantine "
412 			"$ olcDbUseTemporaryConn "
413 			"$ olcDbConnectionPoolMax "
414 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
415 			"$ olcDbSessionTrackingRequest "
416 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
417 			"$ olcDbNoRefs "
418 			"$ olcDbNoUndefFilter "
419 			"$ olcDbOnErr "
420 			"$ olcDbKeepalive "
421 		") )",
422 		 	Cft_Database, ldapcfg},
423 	{ NULL, 0, NULL }
424 };
425 
426 static ConfigTable pbindcfg[] = {
427 	{ "uri", "uri", 2, 2, 0,
428 		ARG_MAGIC|LDAP_BACK_CFG_URI,
429 		ldap_pbind_cf_gen, "( OLcfgDbAt:0.14 "
430 			"NAME 'olcDbURI' "
431 			"DESC 'URI (list) for remote DSA' "
432 			"SYNTAX OMsDirectoryString "
433 			"SINGLE-VALUE )",
434 		NULL, NULL },
435 	{ "tls", "what", 2, 0, 0,
436 		ARG_MAGIC|LDAP_BACK_CFG_TLS,
437 		ldap_pbind_cf_gen, "( OLcfgDbAt:3.1 "
438 			"NAME 'olcDbStartTLS' "
439 			"DESC 'StartTLS' "
440 			"SYNTAX OMsDirectoryString "
441 			"SINGLE-VALUE )",
442 		NULL, NULL },
443 	{ "network-timeout", "timeout", 2, 2, 0,
444 		ARG_MAGIC|LDAP_BACK_CFG_NETWORK_TIMEOUT,
445 		ldap_pbind_cf_gen, "( OLcfgDbAt:3.17 "
446 			"NAME 'olcDbNetworkTimeout' "
447 			"DESC 'connection network timeout' "
448 			"SYNTAX OMsDirectoryString "
449 			"SINGLE-VALUE )",
450 		NULL, NULL },
451 	{ "quarantine", "retrylist", 2, 2, 0,
452 		ARG_MAGIC|LDAP_BACK_CFG_QUARANTINE,
453 		ldap_pbind_cf_gen, "( OLcfgDbAt:3.21 "
454 			"NAME 'olcDbQuarantine' "
455 			"DESC 'Quarantine database if connection fails and retry according to rule' "
456 			"SYNTAX OMsDirectoryString "
457 			"SINGLE-VALUE )",
458 		NULL, NULL },
459 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED,
460 		NULL, NULL, NULL, NULL }
461 };
462 
463 static ConfigOCs pbindocs[] = {
464 	{ "( OLcfgOvOc:3.3 "
465 		"NAME 'olcPBindConfig' "
466 		"DESC 'Proxy Bind configuration' "
467 		"SUP olcOverlayConfig "
468 		"MUST olcDbURI "
469 		"MAY ( olcDbStartTLS "
470 			"$ olcDbNetworkTimeout "
471 			"$ olcDbQuarantine "
472 		") )",
473 		 	Cft_Overlay, pbindcfg},
474 	{ NULL, 0, NULL }
475 };
476 
477 static slap_verbmasks idassert_mode[] = {
478 	{ BER_BVC("self"),		LDAP_BACK_IDASSERT_SELF },
479 	{ BER_BVC("anonymous"),		LDAP_BACK_IDASSERT_ANONYMOUS },
480 	{ BER_BVC("none"),		LDAP_BACK_IDASSERT_NOASSERT },
481 	{ BER_BVC("legacy"),		LDAP_BACK_IDASSERT_LEGACY },
482 	{ BER_BVNULL,			0 }
483 };
484 
485 static slap_verbmasks tls_mode[] = {
486 	{ BER_BVC( "propagate" ),	LDAP_BACK_F_TLS_PROPAGATE_MASK },
487 	{ BER_BVC( "try-propagate" ),	LDAP_BACK_F_PROPAGATE_TLS },
488 	{ BER_BVC( "start" ),		LDAP_BACK_F_TLS_USE_MASK },
489 	{ BER_BVC( "try-start" ),	LDAP_BACK_F_USE_TLS },
490 	{ BER_BVC( "ldaps" ),		LDAP_BACK_F_TLS_LDAPS },
491 	{ BER_BVC( "none" ),		LDAP_BACK_F_NONE },
492 	{ BER_BVNULL,			0 }
493 };
494 
495 static slap_verbmasks t_f_mode[] = {
496 	{ BER_BVC( "yes" ),		LDAP_BACK_F_T_F },
497 	{ BER_BVC( "discover" ),	LDAP_BACK_F_T_F_DISCOVER },
498 	{ BER_BVC( "no" ),		LDAP_BACK_F_NONE },
499 	{ BER_BVNULL,			0 }
500 };
501 
502 static slap_verbmasks cancel_mode[] = {
503 	{ BER_BVC( "ignore" ),		LDAP_BACK_F_CANCEL_IGNORE },
504 	{ BER_BVC( "exop" ),		LDAP_BACK_F_CANCEL_EXOP },
505 	{ BER_BVC( "exop-discover" ),	LDAP_BACK_F_CANCEL_EXOP_DISCOVER },
506 	{ BER_BVC( "abandon" ),		LDAP_BACK_F_CANCEL_ABANDON },
507 	{ BER_BVNULL,			0 }
508 };
509 
510 static slap_verbmasks onerr_mode[] = {
511 	{ BER_BVC( "stop" ),		LDAP_BACK_F_ONERR_STOP },
512 	{ BER_BVC( "report" ),		LDAP_BACK_F_ONERR_STOP }, /* same behavior */
513 	{ BER_BVC( "continue" ),	LDAP_BACK_F_NONE },
514 	{ BER_BVNULL,			0 }
515 };
516 
517 /* see enum in slap.h */
518 static slap_cf_aux_table timeout_table[] = {
519 	{ BER_BVC("bind="),	SLAP_OP_BIND * sizeof( time_t ),	'u', 0, NULL },
520 	/* unbind makes no sense */
521 	{ BER_BVC("add="),	SLAP_OP_ADD * sizeof( time_t ),		'u', 0, NULL },
522 	{ BER_BVC("delete="),	SLAP_OP_DELETE * sizeof( time_t ),	'u', 0, NULL },
523 	{ BER_BVC("modrdn="),	SLAP_OP_MODRDN * sizeof( time_t ),	'u', 0, NULL },
524 	{ BER_BVC("modify="),	SLAP_OP_MODIFY * sizeof( time_t ),	'u', 0, NULL },
525 	{ BER_BVC("compare="),	SLAP_OP_COMPARE * sizeof( time_t ),	'u', 0, NULL },
526 	{ BER_BVC("search="),	SLAP_OP_SEARCH * sizeof( time_t ),	'u', 0, NULL },
527 	/* abandon makes little sense */
528 #if 0	/* not implemented yet */
529 	{ BER_BVC("extended="),	SLAP_OP_EXTENDED * sizeof( time_t ),	'u', 0, NULL },
530 #endif
531 	{ BER_BVNULL, 0, 0, 0, NULL }
532 };
533 
534 int
535 slap_retry_info_parse(
536 	char			*in,
537 	slap_retry_info_t 	*ri,
538 	char			*buf,
539 	ber_len_t		buflen )
540 {
541 	char			**retrylist = NULL;
542 	int			rc = 0;
543 	int			i;
544 
545 	slap_str2clist( &retrylist, in, " ;" );
546 	if ( retrylist == NULL ) {
547 		return 1;
548 	}
549 
550 	for ( i = 0; retrylist[ i ] != NULL; i++ )
551 		/* count */ ;
552 
553 	ri->ri_interval = ch_calloc( sizeof( time_t ), i + 1 );
554 	ri->ri_num = ch_calloc( sizeof( int ), i + 1 );
555 
556 	for ( i = 0; retrylist[ i ] != NULL; i++ ) {
557 		unsigned long	t;
558 		char		*sep = strchr( retrylist[ i ], ',' );
559 
560 		if ( sep == NULL ) {
561 			snprintf( buf, buflen,
562 				"missing comma in retry pattern #%d \"%s\"",
563 				i, retrylist[ i ] );
564 			rc = 1;
565 			goto done;
566 		}
567 
568 		*sep++ = '\0';
569 
570 		if ( lutil_parse_time( retrylist[ i ], &t ) ) {
571 			snprintf( buf, buflen,
572 				"unable to parse interval #%d \"%s\"",
573 				i, retrylist[ i ] );
574 			rc = 1;
575 			goto done;
576 		}
577 		ri->ri_interval[ i ] = (time_t)t;
578 
579 		if ( strcmp( sep, "+" ) == 0 ) {
580 			if ( retrylist[ i + 1 ] != NULL ) {
581 				snprintf( buf, buflen,
582 					"extra cruft after retry pattern "
583 					"#%d \"%s,+\" with \"forever\" mark",
584 					i, retrylist[ i ] );
585 				rc = 1;
586 				goto done;
587 			}
588 			ri->ri_num[ i ] = SLAP_RETRYNUM_FOREVER;
589 
590 		} else if ( lutil_atoi( &ri->ri_num[ i ], sep ) ) {
591 			snprintf( buf, buflen,
592 				"unable to parse retry num #%d \"%s\"",
593 				i, sep );
594 			rc = 1;
595 			goto done;
596 		}
597 	}
598 
599 	ri->ri_num[ i ] = SLAP_RETRYNUM_TAIL;
600 
601 	ri->ri_idx = 0;
602 	ri->ri_count = 0;
603 	ri->ri_last = (time_t)(-1);
604 
605 done:;
606 	ldap_charray_free( retrylist );
607 
608 	if ( rc ) {
609 		slap_retry_info_destroy( ri );
610 	}
611 
612 	return rc;
613 }
614 
615 int
616 slap_retry_info_unparse(
617 	slap_retry_info_t	*ri,
618 	struct berval		*bvout )
619 {
620 	char		buf[ BUFSIZ * 2 ],
621 			*ptr = buf;
622 	int		i, len, restlen = (int) sizeof( buf );
623 	struct berval	bv;
624 
625 	assert( ri != NULL );
626 	assert( bvout != NULL );
627 
628 	BER_BVZERO( bvout );
629 
630 	for ( i = 0; ri->ri_num[ i ] != SLAP_RETRYNUM_TAIL; i++ ) {
631 		if ( i > 0 ) {
632 			if ( --restlen <= 0 ) {
633 				return 1;
634 			}
635 			*ptr++ = ';';
636 		}
637 
638 		if ( lutil_unparse_time( ptr, restlen, ri->ri_interval[i] ) < 0 ) {
639 			return 1;
640 		}
641 		len = (int) strlen( ptr );
642 		if ( (restlen -= len + 1) <= 0 ) {
643 			return 1;
644 		}
645 		ptr += len;
646 		*ptr++ = ',';
647 
648 		if ( ri->ri_num[i] == SLAP_RETRYNUM_FOREVER ) {
649 			if ( --restlen <= 0 ) {
650 				return 1;
651 			}
652 			*ptr++ = '+';
653 
654 		} else {
655 			len = snprintf( ptr, restlen, "%d", ri->ri_num[i] );
656 			if ( (restlen -= len) <= 0 || len < 0 ) {
657 				return 1;
658 			}
659 			ptr += len;
660 		}
661 	}
662 
663 	bv.bv_val = buf;
664 	bv.bv_len = ptr - buf;
665 	ber_dupbv( bvout, &bv );
666 
667 	return 0;
668 }
669 
670 void
671 slap_retry_info_destroy(
672 	slap_retry_info_t	*ri )
673 {
674 	assert( ri != NULL );
675 
676 	assert( ri->ri_interval != NULL );
677 	ch_free( ri->ri_interval );
678 	ri->ri_interval = NULL;
679 
680 	assert( ri->ri_num != NULL );
681 	ch_free( ri->ri_num );
682 	ri->ri_num = NULL;
683 }
684 
685 int
686 slap_idassert_authzfrom_parse( ConfigArgs *c, slap_idassert_t *si )
687 {
688 	struct berval	bv;
689 	struct berval	in;
690 	int		rc;
691 
692  	if ( strcmp( c->argv[ 1 ], "*" ) == 0
693  		|| strcmp( c->argv[ 1 ], "dn:*" ) == 0
694  		|| strcasecmp( c->argv[ 1 ], "dn.regex:.*" ) == 0 )
695  	{
696  		if ( si->si_authz != NULL ) {
697  			snprintf( c->cr_msg, sizeof( c->cr_msg ),
698  				"\"idassert-authzFrom <authz>\": "
699  				"\"%s\" conflicts with existing authz rules",
700  				c->argv[ 1 ] );
701  			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
702  			return 1;
703  		}
704 
705  		si->si_flags |= LDAP_BACK_AUTH_AUTHZ_ALL;
706 
707  		return 0;
708 
709  	} else if ( ( si->si_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) {
710   		snprintf( c->cr_msg, sizeof( c->cr_msg ),
711   			"\"idassert-authzFrom <authz>\": "
712  			"\"<authz>\" conflicts with \"*\"" );
713   		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
714   		return 1;
715   	}
716 
717  	ber_str2bv( c->argv[ 1 ], 0, 0, &in );
718  	rc = authzNormalize( 0, NULL, NULL, &in, &bv, NULL );
719  	if ( rc != LDAP_SUCCESS ) {
720  		snprintf( c->cr_msg, sizeof( c->cr_msg ),
721  			"\"idassert-authzFrom <authz>\": "
722  			"invalid syntax" );
723  		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
724  		return 1;
725  	}
726 
727 	if ( c->valx == -1 ) {
728 		ber_bvarray_add( &si->si_authz, &bv );
729 
730 	} else {
731 		int i = 0;
732 		if ( si->si_authz != NULL ) {
733 			for ( ; !BER_BVISNULL( &si->si_authz[ i ] ); i++ )
734 				;
735 		}
736 
737 		if ( i <= c->valx ) {
738 			ber_bvarray_add( &si->si_authz, &bv );
739 
740 		} else {
741 			BerVarray tmp = ber_memrealloc( si->si_authz,
742 				sizeof( struct berval )*( i + 2 ) );
743 			if ( tmp == NULL ) {
744 				return -1;
745 			}
746 			si->si_authz = tmp;
747 			for ( ; i > c->valx; i-- ) {
748 				si->si_authz[ i ] = si->si_authz[ i - 1 ];
749 			}
750 			si->si_authz[ c->valx ] = bv;
751 		}
752 	}
753 
754 	return 0;
755 }
756 
757 static int
758 slap_idassert_passthru_parse( ConfigArgs *c, slap_idassert_t *si )
759 {
760 	struct berval	bv;
761 	struct berval	in;
762 	int		rc;
763 
764  	ber_str2bv( c->argv[ 1 ], 0, 0, &in );
765  	rc = authzNormalize( 0, NULL, NULL, &in, &bv, NULL );
766  	if ( rc != LDAP_SUCCESS ) {
767  		snprintf( c->cr_msg, sizeof( c->cr_msg ),
768  			"\"idassert-passThru <authz>\": "
769  			"invalid syntax" );
770  		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
771  		return 1;
772  	}
773 
774 	if ( c->valx == -1 ) {
775 		ber_bvarray_add( &si->si_passthru, &bv );
776 
777 	} else {
778 		int i = 0;
779 		if ( si->si_passthru != NULL ) {
780 			for ( ; !BER_BVISNULL( &si->si_passthru[ i ] ); i++ )
781 				;
782 		}
783 
784 		if ( i <= c->valx ) {
785 			ber_bvarray_add( &si->si_passthru, &bv );
786 
787 		} else {
788 			BerVarray tmp = ber_memrealloc( si->si_passthru,
789 				sizeof( struct berval )*( i + 2 ) );
790 			if ( tmp == NULL ) {
791 				return -1;
792 			}
793 			si->si_passthru = tmp;
794 			for ( ; i > c->valx; i-- ) {
795 				si->si_passthru[ i ] = si->si_passthru[ i - 1 ];
796 			}
797 			si->si_passthru[ c->valx ] = bv;
798 		}
799 	}
800 
801 	return 0;
802 }
803 
804 int
805 slap_idassert_parse( ConfigArgs *c, slap_idassert_t *si )
806 {
807 	int		i;
808 
809 	for ( i = 1; i < c->argc; i++ ) {
810 		if ( strncasecmp( c->argv[ i ], "mode=", STRLENOF( "mode=" ) ) == 0 ) {
811 			char	*argvi = c->argv[ i ] + STRLENOF( "mode=" );
812 			int	j;
813 
814 			j = verb_to_mask( argvi, idassert_mode );
815 			if ( BER_BVISNULL( &idassert_mode[ j ].word ) ) {
816 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
817 					"\"idassert-bind <args>\": "
818 					"unknown mode \"%s\"",
819 					argvi );
820 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
821 				return 1;
822 			}
823 
824 			si->si_mode = idassert_mode[ j ].mask;
825 
826 		} else if ( strncasecmp( c->argv[ i ], "authz=", STRLENOF( "authz=" ) ) == 0 ) {
827 			char	*argvi = c->argv[ i ] + STRLENOF( "authz=" );
828 
829 			if ( strcasecmp( argvi, "native" ) == 0 ) {
830 				if ( si->si_bc.sb_method != LDAP_AUTH_SASL ) {
831 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
832 						"\"idassert-bind <args>\": "
833 						"authz=\"native\" incompatible "
834 						"with auth method" );
835 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
836 					return 1;
837 				}
838 				si->si_flags |= LDAP_BACK_AUTH_NATIVE_AUTHZ;
839 
840 			} else if ( strcasecmp( argvi, "proxyAuthz" ) == 0 ) {
841 				si->si_flags &= ~LDAP_BACK_AUTH_NATIVE_AUTHZ;
842 
843 			} else {
844 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
845 					"\"idassert-bind <args>\": "
846 					"unknown authz \"%s\"",
847 					argvi );
848 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
849 				return 1;
850 			}
851 
852 		} else if ( strncasecmp( c->argv[ i ], "flags=", STRLENOF( "flags=" ) ) == 0 ) {
853 			char	*argvi = c->argv[ i ] + STRLENOF( "flags=" );
854 			char	**flags = ldap_str2charray( argvi, "," );
855 			int	j, err = 0;
856 
857 			if ( flags == NULL ) {
858 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
859 					"\"idassert-bind <args>\": "
860 					"unable to parse flags \"%s\"",
861 					argvi );
862 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
863 				return 1;
864 			}
865 
866 			for ( j = 0; flags[ j ] != NULL; j++ ) {
867 
868 				if ( strcasecmp( flags[ j ], "override" ) == 0 ) {
869 					si->si_flags |= LDAP_BACK_AUTH_OVERRIDE;
870 
871 				} else if ( strcasecmp( flags[ j ], "prescriptive" ) == 0 ) {
872 					si->si_flags |= LDAP_BACK_AUTH_PRESCRIPTIVE;
873 
874 				} else if ( strcasecmp( flags[ j ], "non-prescriptive" ) == 0 ) {
875 					si->si_flags &= ( ~LDAP_BACK_AUTH_PRESCRIPTIVE );
876 
877 				} else if ( strcasecmp( flags[ j ], "obsolete-proxy-authz" ) == 0 ) {
878 					if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
879 						Debug( LDAP_DEBUG_ANY,
880                                       		 		"%s: \"obsolete-proxy-authz\" flag "
881                                       		 		"in \"idassert-mode <args>\" "
882                                       		 		"incompatible with previously issued \"obsolete-encoding-workaround\" flag.\n",
883                                       	 			c->log, 0, 0 );
884 						err = 1;
885 						break;
886 
887 					} else {
888 						si->si_flags |= LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ;
889 					}
890 
891 				} else if ( strcasecmp( flags[ j ], "obsolete-encoding-workaround" ) == 0 ) {
892 					if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
893 						Debug( LDAP_DEBUG_ANY,
894                                       	 			"%s: \"obsolete-encoding-workaround\" flag "
895                                        			"in \"idassert-mode <args>\" "
896                                        			"incompatible with previously issued \"obsolete-proxy-authz\" flag.\n",
897                                        			c->log, 0, 0 );
898 						err = 1;
899 						break;
900 
901 					} else {
902 						si->si_flags |= LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND;
903 					}
904 
905 				} else if ( strcasecmp( flags[ j ], "proxy-authz-critical" ) == 0 ) {
906 					si->si_flags |= LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL;
907 
908 				} else if ( strcasecmp( flags[ j ], "proxy-authz-non-critical" ) == 0 ) {
909 					si->si_flags &= ~LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL;
910 
911 				} else {
912 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
913 						"\"idassert-bind <args>\": "
914 						"unknown flag \"%s\"",
915 						flags[ j ] );
916 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
917 					err = 1;
918 					break;
919 				}
920 			}
921 
922 			ldap_charray_free( flags );
923 			if ( err ) {
924 				return 1;
925 			}
926 
927 		} else if ( bindconf_parse( c->argv[ i ], &si->si_bc ) ) {
928 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
929 				"\"idassert-bind <args>\": "
930 				"unable to parse field \"%s\"",
931 				c->argv[ i ] );
932 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
933 			return 1;
934 		}
935 	}
936 
937 	if ( si->si_bc.sb_method == LDAP_AUTH_SIMPLE ) {
938 		if ( BER_BVISNULL( &si->si_bc.sb_binddn )
939 			|| BER_BVISNULL( &si->si_bc.sb_cred ) )
940 		{
941 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
942 				"\"idassert-bind <args>\": "
943 				"SIMPLE needs \"binddn\" and \"credentials\"" );
944 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
945 			return 1;
946 		}
947 	}
948 
949 	bindconf_tls_defaults( &si->si_bc );
950 
951 	return 0;
952 }
953 
954 /* NOTE: temporary, until back-meta is ported to back-config */
955 int
956 slap_idassert_passthru_parse_cf( const char *fname, int lineno, const char *arg, slap_idassert_t *si )
957 {
958 	ConfigArgs	c = { 0 };
959 	char		*argv[ 3 ];
960 
961 	snprintf( c.log, sizeof( c.log ), "%s: line %d", fname, lineno );
962 	c.argc = 2;
963 	c.argv = argv;
964 	argv[ 0 ] = "idassert-passThru";
965 	argv[ 1 ] = (char *)arg;
966 	argv[ 2 ] = NULL;
967 
968 	return slap_idassert_passthru_parse( &c, si );
969 }
970 
971 static int
972 ldap_back_cf_gen( ConfigArgs *c )
973 {
974 	ldapinfo_t	*li = ( ldapinfo_t * )c->be->be_private;
975 	int		rc = 0;
976 	int		i;
977 
978 	if ( c->op == SLAP_CONFIG_EMIT ) {
979 		struct berval	bv = BER_BVNULL;
980 
981 		if ( li == NULL ) {
982 			return 1;
983 		}
984 
985 		switch( c->type ) {
986 		case LDAP_BACK_CFG_URI:
987 			if ( li->li_uri != NULL ) {
988 				struct berval	bv, bv2;
989 
990 				ber_str2bv( li->li_uri, 0, 0, &bv );
991 				bv2.bv_len = bv.bv_len + STRLENOF( "\"\"" );
992 				bv2.bv_val = ch_malloc( bv2.bv_len + 1 );
993 				snprintf( bv2.bv_val, bv2.bv_len + 1,
994 					"\"%s\"", bv.bv_val );
995 				ber_bvarray_add( &c->rvalue_vals, &bv2 );
996 
997 			} else {
998 				rc = 1;
999 			}
1000 			break;
1001 
1002 		case LDAP_BACK_CFG_TLS: {
1003 			struct berval bc = BER_BVNULL, bv2;
1004 			enum_to_verb( tls_mode, ( li->li_flags & LDAP_BACK_F_TLS_MASK ), &bv );
1005 			assert( !BER_BVISNULL( &bv ) );
1006 			bindconf_tls_unparse( &li->li_tls, &bc );
1007 
1008 			if ( !BER_BVISEMPTY( &bc )) {
1009 				bv2.bv_len = bv.bv_len + bc.bv_len + 1;
1010 				bv2.bv_val = ch_malloc( bv2.bv_len + 1 );
1011 				strcpy( bv2.bv_val, bv.bv_val );
1012 				bv2.bv_val[bv.bv_len] = ' ';
1013 				strcpy( &bv2.bv_val[bv.bv_len + 1], bc.bv_val );
1014 				ber_bvarray_add( &c->rvalue_vals, &bv2 );
1015 
1016 			} else {
1017 				value_add_one( &c->rvalue_vals, &bv );
1018 			}
1019 			ber_memfree( bc.bv_val );
1020 			}
1021 			break;
1022 
1023 		case LDAP_BACK_CFG_ACL_AUTHCDN:
1024 		case LDAP_BACK_CFG_ACL_PASSWD:
1025 		case LDAP_BACK_CFG_ACL_METHOD:
1026 			/* handled by LDAP_BACK_CFG_ACL_BIND */
1027 			rc = 1;
1028 			break;
1029 
1030 		case LDAP_BACK_CFG_ACL_BIND: {
1031 			int	i;
1032 
1033 			if ( li->li_acl_authmethod == LDAP_AUTH_NONE ) {
1034 				return 1;
1035 			}
1036 
1037 			bindconf_unparse( &li->li_acl, &bv );
1038 
1039 			for ( i = 0; isspace( (unsigned char) bv.bv_val[ i ] ); i++ )
1040 				/* count spaces */ ;
1041 
1042 			if ( i ) {
1043 				bv.bv_len -= i;
1044 				AC_MEMCPY( bv.bv_val, &bv.bv_val[ i ],
1045 					bv.bv_len + 1 );
1046 			}
1047 
1048 			ber_bvarray_add( &c->rvalue_vals, &bv );
1049 			break;
1050 		}
1051 
1052 		case LDAP_BACK_CFG_IDASSERT_MODE:
1053 		case LDAP_BACK_CFG_IDASSERT_AUTHCDN:
1054 		case LDAP_BACK_CFG_IDASSERT_PASSWD:
1055 		case LDAP_BACK_CFG_IDASSERT_METHOD:
1056 			/* handled by LDAP_BACK_CFG_IDASSERT_BIND */
1057 			rc = 1;
1058 			break;
1059 
1060 		case LDAP_BACK_CFG_IDASSERT_AUTHZFROM:
1061 		case LDAP_BACK_CFG_IDASSERT_PASSTHRU: {
1062 			BerVarray	*bvp;
1063 			int		i;
1064 			struct berval	bv = BER_BVNULL;
1065 			char		buf[SLAP_TEXT_BUFLEN];
1066 
1067 			switch ( c->type ) {
1068 			case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: bvp = &li->li_idassert_authz; break;
1069 			case LDAP_BACK_CFG_IDASSERT_PASSTHRU: bvp = &li->li_idassert_passthru; break;
1070 			default: assert( 0 ); break;
1071 			}
1072 
1073 			if ( *bvp == NULL ) {
1074 				if ( bvp == &li->li_idassert_authz
1075 					&& ( li->li_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
1076 				{
1077 					BER_BVSTR( &bv, "*" );
1078 					value_add_one( &c->rvalue_vals, &bv );
1079 
1080 				} else {
1081 					rc = 1;
1082 				}
1083 				break;
1084 			}
1085 
1086 			for ( i = 0; !BER_BVISNULL( &((*bvp)[ i ]) ); i++ ) {
1087 				char *ptr;
1088 				int len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i );
1089 				bv.bv_len = ((*bvp)[ i ]).bv_len + len;
1090 				bv.bv_val = ber_memrealloc( bv.bv_val, bv.bv_len + 1 );
1091 				ptr = bv.bv_val;
1092 				ptr = lutil_strcopy( ptr, buf );
1093 				ptr = lutil_strncopy( ptr, ((*bvp)[ i ]).bv_val, ((*bvp)[ i ]).bv_len );
1094 				value_add_one( &c->rvalue_vals, &bv );
1095 			}
1096 			if ( bv.bv_val ) {
1097 				ber_memfree( bv.bv_val );
1098 			}
1099 			break;
1100 		}
1101 
1102 		case LDAP_BACK_CFG_IDASSERT_BIND: {
1103 			int		i;
1104 			struct berval	bc = BER_BVNULL;
1105 			char		*ptr;
1106 
1107 			if ( li->li_idassert_authmethod == LDAP_AUTH_NONE ) {
1108 				return 1;
1109 			}
1110 
1111 			if ( li->li_idassert_authmethod != LDAP_AUTH_NONE ) {
1112 				ber_len_t	len;
1113 
1114 				switch ( li->li_idassert_mode ) {
1115 				case LDAP_BACK_IDASSERT_OTHERID:
1116 				case LDAP_BACK_IDASSERT_OTHERDN:
1117 					break;
1118 
1119 				default: {
1120 					struct berval	mode = BER_BVNULL;
1121 
1122 					enum_to_verb( idassert_mode, li->li_idassert_mode, &mode );
1123 					if ( BER_BVISNULL( &mode ) ) {
1124 						/* there's something wrong... */
1125 						assert( 0 );
1126 						rc = 1;
1127 
1128 					} else {
1129 						bv.bv_len = STRLENOF( "mode=" ) + mode.bv_len;
1130 						bv.bv_val = ch_malloc( bv.bv_len + 1 );
1131 
1132 						ptr = lutil_strcopy( bv.bv_val, "mode=" );
1133 						ptr = lutil_strcopy( ptr, mode.bv_val );
1134 					}
1135 					break;
1136 				}
1137 				}
1138 
1139 				if ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) {
1140 					len = bv.bv_len + STRLENOF( "authz=native" );
1141 
1142 					if ( !BER_BVISEMPTY( &bv ) ) {
1143 						len += STRLENOF( " " );
1144 					}
1145 
1146 					bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
1147 
1148 					ptr = &bv.bv_val[ bv.bv_len ];
1149 
1150 					if ( !BER_BVISEMPTY( &bv ) ) {
1151 						ptr = lutil_strcopy( ptr, " " );
1152 					}
1153 
1154 					(void)lutil_strcopy( ptr, "authz=native" );
1155 				}
1156 
1157 				len = bv.bv_len + STRLENOF( "flags=non-prescriptive,override,obsolete-encoding-workaround,proxy-authz-non-critical" );
1158 				/* flags */
1159 				if ( !BER_BVISEMPTY( &bv ) ) {
1160 					len += STRLENOF( " " );
1161 				}
1162 
1163 				bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
1164 
1165 				ptr = &bv.bv_val[ bv.bv_len ];
1166 
1167 				if ( !BER_BVISEMPTY( &bv ) ) {
1168 					ptr = lutil_strcopy( ptr, " " );
1169 				}
1170 
1171 				ptr = lutil_strcopy( ptr, "flags=" );
1172 
1173 				if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1174 					ptr = lutil_strcopy( ptr, "prescriptive" );
1175 				} else {
1176 					ptr = lutil_strcopy( ptr, "non-prescriptive" );
1177 				}
1178 
1179 				if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
1180 					ptr = lutil_strcopy( ptr, ",override" );
1181 				}
1182 
1183 				if ( li->li_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
1184 					ptr = lutil_strcopy( ptr, ",obsolete-proxy-authz" );
1185 
1186 				} else if ( li->li_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
1187 					ptr = lutil_strcopy( ptr, ",obsolete-encoding-workaround" );
1188 				}
1189 
1190 				if ( li->li_idassert_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) {
1191 					ptr = lutil_strcopy( ptr, ",proxy-authz-critical" );
1192 
1193 				} else {
1194 					ptr = lutil_strcopy( ptr, ",proxy-authz-non-critical" );
1195 				}
1196 
1197 				bv.bv_len = ( ptr - bv.bv_val );
1198 				/* end-of-flags */
1199 			}
1200 
1201 			bindconf_unparse( &li->li_idassert.si_bc, &bc );
1202 
1203 			if ( !BER_BVISNULL( &bv ) ) {
1204 				ber_len_t	len = bv.bv_len + bc.bv_len;
1205 
1206 				bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
1207 
1208 				assert( bc.bv_val[ 0 ] == ' ' );
1209 
1210 				ptr = lutil_strcopy( &bv.bv_val[ bv.bv_len ], bc.bv_val );
1211 				free( bc.bv_val );
1212 				bv.bv_len = ptr - bv.bv_val;
1213 
1214 			} else {
1215 				for ( i = 0; isspace( (unsigned char) bc.bv_val[ i ] ); i++ )
1216 					/* count spaces */ ;
1217 
1218 				if ( i ) {
1219 					bc.bv_len -= i;
1220 					AC_MEMCPY( bc.bv_val, &bc.bv_val[ i ], bc.bv_len + 1 );
1221 				}
1222 
1223 				bv = bc;
1224 			}
1225 
1226 			ber_bvarray_add( &c->rvalue_vals, &bv );
1227 
1228 			break;
1229 		}
1230 
1231 		case LDAP_BACK_CFG_REBIND:
1232 			c->value_int = LDAP_BACK_SAVECRED( li );
1233 			break;
1234 
1235 		case LDAP_BACK_CFG_CHASE:
1236 			c->value_int = LDAP_BACK_CHASE_REFERRALS( li );
1237 			break;
1238 
1239 		case LDAP_BACK_CFG_T_F:
1240 			enum_to_verb( t_f_mode, (li->li_flags & LDAP_BACK_F_T_F_MASK2), &bv );
1241 			if ( BER_BVISNULL( &bv ) ) {
1242 				/* there's something wrong... */
1243 				assert( 0 );
1244 				rc = 1;
1245 
1246 			} else {
1247 				value_add_one( &c->rvalue_vals, &bv );
1248 			}
1249 			break;
1250 
1251 		case LDAP_BACK_CFG_WHOAMI:
1252 			c->value_int = LDAP_BACK_PROXY_WHOAMI( li );
1253 			break;
1254 
1255 		case LDAP_BACK_CFG_TIMEOUT:
1256 			BER_BVZERO( &bv );
1257 
1258 			for ( i = 0; i < SLAP_OP_LAST; i++ ) {
1259 				if ( li->li_timeout[ i ] != 0 ) {
1260 					break;
1261 				}
1262 			}
1263 
1264 			if ( i == SLAP_OP_LAST ) {
1265 				return 1;
1266 			}
1267 
1268 			slap_cf_aux_table_unparse( li->li_timeout, &bv, timeout_table );
1269 
1270 			if ( BER_BVISNULL( &bv ) ) {
1271 				return 1;
1272 			}
1273 
1274 			for ( i = 0; isspace( (unsigned char) bv.bv_val[ i ] ); i++ )
1275 				/* count spaces */ ;
1276 
1277 			if ( i ) {
1278 				bv.bv_len -= i;
1279 				AC_MEMCPY( bv.bv_val, &bv.bv_val[ i ],
1280 					bv.bv_len + 1 );
1281 			}
1282 
1283 			ber_bvarray_add( &c->rvalue_vals, &bv );
1284 			break;
1285 
1286 		case LDAP_BACK_CFG_IDLE_TIMEOUT: {
1287 			char	buf[ SLAP_TEXT_BUFLEN ];
1288 
1289 			if ( li->li_idle_timeout == 0 ) {
1290 				return 1;
1291 			}
1292 
1293 			lutil_unparse_time( buf, sizeof( buf ), li->li_idle_timeout );
1294 			ber_str2bv( buf, 0, 0, &bv );
1295 			value_add_one( &c->rvalue_vals, &bv );
1296 			} break;
1297 
1298 		case LDAP_BACK_CFG_CONN_TTL: {
1299 			char	buf[ SLAP_TEXT_BUFLEN ];
1300 
1301 			if ( li->li_conn_ttl == 0 ) {
1302 				return 1;
1303 			}
1304 
1305 			lutil_unparse_time( buf, sizeof( buf ), li->li_conn_ttl );
1306 			ber_str2bv( buf, 0, 0, &bv );
1307 			value_add_one( &c->rvalue_vals, &bv );
1308 			} break;
1309 
1310 		case LDAP_BACK_CFG_NETWORK_TIMEOUT: {
1311 			char	buf[ SLAP_TEXT_BUFLEN ];
1312 
1313 			if ( li->li_network_timeout == 0 ) {
1314 				return 1;
1315 			}
1316 
1317 			snprintf( buf, sizeof( buf ), "%ld",
1318 				(long)li->li_network_timeout );
1319 			ber_str2bv( buf, 0, 0, &bv );
1320 			value_add_one( &c->rvalue_vals, &bv );
1321 			} break;
1322 
1323 		case LDAP_BACK_CFG_VERSION:
1324 			if ( li->li_version == 0 ) {
1325 				return 1;
1326 			}
1327 
1328 			c->value_int = li->li_version;
1329 			break;
1330 
1331 		case LDAP_BACK_CFG_SINGLECONN:
1332 			c->value_int = LDAP_BACK_SINGLECONN( li );
1333 			break;
1334 
1335 		case LDAP_BACK_CFG_USETEMP:
1336 			c->value_int = LDAP_BACK_USE_TEMPORARIES( li );
1337 			break;
1338 
1339 		case LDAP_BACK_CFG_CONNPOOLMAX:
1340 			c->value_int = li->li_conn_priv_max;
1341 			break;
1342 
1343 		case LDAP_BACK_CFG_CANCEL: {
1344 			slap_mask_t	mask = LDAP_BACK_F_CANCEL_MASK2;
1345 
1346 			if ( LDAP_BACK_CANCEL_DISCOVER( li ) ) {
1347 				mask &= ~LDAP_BACK_F_CANCEL_EXOP;
1348 			}
1349 			enum_to_verb( cancel_mode, (li->li_flags & mask), &bv );
1350 			if ( BER_BVISNULL( &bv ) ) {
1351 				/* there's something wrong... */
1352 				assert( 0 );
1353 				rc = 1;
1354 
1355 			} else {
1356 				value_add_one( &c->rvalue_vals, &bv );
1357 			}
1358 			} break;
1359 
1360 		case LDAP_BACK_CFG_QUARANTINE:
1361 			if ( !LDAP_BACK_QUARANTINE( li ) ) {
1362 				rc = 1;
1363 				break;
1364 			}
1365 
1366 			rc = slap_retry_info_unparse( &li->li_quarantine, &bv );
1367 			if ( rc == 0 ) {
1368 				ber_bvarray_add( &c->rvalue_vals, &bv );
1369 			}
1370 			break;
1371 
1372 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1373 		case LDAP_BACK_CFG_ST_REQUEST:
1374 			c->value_int = LDAP_BACK_ST_REQUEST( li );
1375 			break;
1376 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1377 
1378 		case LDAP_BACK_CFG_NOREFS:
1379 			c->value_int = LDAP_BACK_NOREFS( li );
1380 			break;
1381 
1382 		case LDAP_BACK_CFG_NOUNDEFFILTER:
1383 			c->value_int = LDAP_BACK_NOUNDEFFILTER( li );
1384 			break;
1385 
1386 		case LDAP_BACK_CFG_OMIT_UNKNOWN_SCHEMA:
1387 			c->value_int = LDAP_BACK_OMIT_UNKNOWN_SCHEMA( li );
1388 			break;
1389 
1390 		case LDAP_BACK_CFG_ONERR:
1391 			enum_to_verb( onerr_mode, li->li_flags & LDAP_BACK_F_ONERR_STOP, &bv );
1392 			if ( BER_BVISNULL( &bv )) {
1393 				rc = 1;
1394 			} else {
1395 				value_add_one( &c->rvalue_vals, &bv );
1396 			}
1397 			break;
1398 
1399 		case LDAP_BACK_CFG_KEEPALIVE: {
1400 			struct berval bv;
1401 			char buf[AC_LINE_MAX];
1402 			bv.bv_len = AC_LINE_MAX;
1403 			bv.bv_val = &buf[0];
1404 			slap_keepalive_parse(&bv, &li->li_tls.sb_keepalive, 0, 0, 1);
1405 			value_add_one( &c->rvalue_vals, &bv );
1406 			break;
1407 			}
1408 
1409 		default:
1410 			/* FIXME: we need to handle all... */
1411 			assert( 0 );
1412 			break;
1413 		}
1414 		return rc;
1415 
1416 	} else if ( c->op == LDAP_MOD_DELETE ) {
1417 		switch( c->type ) {
1418 		case LDAP_BACK_CFG_URI:
1419 			if ( li->li_uri != NULL ) {
1420 				ch_free( li->li_uri );
1421 				li->li_uri = NULL;
1422 
1423 				assert( li->li_bvuri != NULL );
1424 				ber_bvarray_free( li->li_bvuri );
1425 				li->li_bvuri = NULL;
1426 			}
1427 
1428 			/* better cleanup the cached connections... */
1429 			/* NOTE: don't worry about locking: if we got here,
1430 			 * other threads are suspended. */
1431 			if ( li->li_conninfo.lai_tree != NULL ) {
1432 				avl_free( li->li_conninfo.lai_tree, ldap_back_conn_free );
1433 				li->li_conninfo.lai_tree = NULL;
1434 			}
1435 
1436 			break;
1437 
1438 		case LDAP_BACK_CFG_TLS:
1439 			rc = 1;
1440 			break;
1441 
1442 		case LDAP_BACK_CFG_ACL_AUTHCDN:
1443 		case LDAP_BACK_CFG_ACL_PASSWD:
1444 		case LDAP_BACK_CFG_ACL_METHOD:
1445 			/* handled by LDAP_BACK_CFG_ACL_BIND */
1446 			rc = 1;
1447 			break;
1448 
1449 		case LDAP_BACK_CFG_ACL_BIND:
1450 			bindconf_free( &li->li_acl );
1451 			break;
1452 
1453 		case LDAP_BACK_CFG_IDASSERT_MODE:
1454 		case LDAP_BACK_CFG_IDASSERT_AUTHCDN:
1455 		case LDAP_BACK_CFG_IDASSERT_PASSWD:
1456 		case LDAP_BACK_CFG_IDASSERT_METHOD:
1457 			/* handled by LDAP_BACK_CFG_IDASSERT_BIND */
1458 			rc = 1;
1459 			break;
1460 
1461 		case LDAP_BACK_CFG_IDASSERT_AUTHZFROM:
1462 		case LDAP_BACK_CFG_IDASSERT_PASSTHRU: {
1463 			BerVarray *bvp;
1464 
1465 			switch ( c->type ) {
1466 			case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: bvp = &li->li_idassert_authz; break;
1467 			case LDAP_BACK_CFG_IDASSERT_PASSTHRU: bvp = &li->li_idassert_passthru; break;
1468 			default: assert( 0 ); break;
1469 			}
1470 
1471 			if ( c->valx < 0 ) {
1472 				if ( *bvp != NULL ) {
1473 					ber_bvarray_free( *bvp );
1474 					*bvp = NULL;
1475 				}
1476 
1477 			} else {
1478 				int i;
1479 
1480 				if ( *bvp == NULL ) {
1481 					rc = 1;
1482 					break;
1483 				}
1484 
1485 				for ( i = 0; !BER_BVISNULL( &((*bvp)[ i ]) ); i++ )
1486 					;
1487 
1488 				if ( i >= c->valx ) {
1489 					rc = 1;
1490 					break;
1491 				}
1492 				ber_memfree( ((*bvp)[ c->valx ]).bv_val );
1493 				for ( i = c->valx; !BER_BVISNULL( &((*bvp)[ i + 1 ]) ); i++ ) {
1494 					(*bvp)[ i ] = (*bvp)[ i + 1 ];
1495 				}
1496 				BER_BVZERO( &((*bvp)[ i ]) );
1497 			}
1498 			} break;
1499 
1500 		case LDAP_BACK_CFG_IDASSERT_BIND:
1501 			bindconf_free( &li->li_idassert.si_bc );
1502 			memset( &li->li_idassert, 0, sizeof( slap_idassert_t ) );
1503 			break;
1504 
1505 		case LDAP_BACK_CFG_REBIND:
1506 		case LDAP_BACK_CFG_CHASE:
1507 		case LDAP_BACK_CFG_T_F:
1508 		case LDAP_BACK_CFG_WHOAMI:
1509 		case LDAP_BACK_CFG_CANCEL:
1510 			rc = 1;
1511 			break;
1512 
1513 		case LDAP_BACK_CFG_TIMEOUT:
1514 			for ( i = 0; i < SLAP_OP_LAST; i++ ) {
1515 				li->li_timeout[ i ] = 0;
1516 			}
1517 			break;
1518 
1519 		case LDAP_BACK_CFG_IDLE_TIMEOUT:
1520 			li->li_idle_timeout = 0;
1521 			break;
1522 
1523 		case LDAP_BACK_CFG_CONN_TTL:
1524 			li->li_conn_ttl = 0;
1525 			break;
1526 
1527 		case LDAP_BACK_CFG_NETWORK_TIMEOUT:
1528 			li->li_network_timeout = 0;
1529 			break;
1530 
1531 		case LDAP_BACK_CFG_VERSION:
1532 			li->li_version = 0;
1533 			break;
1534 
1535 		case LDAP_BACK_CFG_SINGLECONN:
1536 			li->li_flags &= ~LDAP_BACK_F_SINGLECONN;
1537 			break;
1538 
1539 		case LDAP_BACK_CFG_USETEMP:
1540 			li->li_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
1541 			break;
1542 
1543 		case LDAP_BACK_CFG_CONNPOOLMAX:
1544 			li->li_conn_priv_max = LDAP_BACK_CONN_PRIV_MIN;
1545 			break;
1546 
1547 		case LDAP_BACK_CFG_QUARANTINE:
1548 			if ( !LDAP_BACK_QUARANTINE( li ) ) {
1549 				break;
1550 			}
1551 
1552 			slap_retry_info_destroy( &li->li_quarantine );
1553 			ldap_pvt_thread_mutex_destroy( &li->li_quarantine_mutex );
1554 			li->li_isquarantined = 0;
1555 			li->li_flags &= ~LDAP_BACK_F_QUARANTINE;
1556 			break;
1557 
1558 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1559 		case LDAP_BACK_CFG_ST_REQUEST:
1560 			li->li_flags &= ~LDAP_BACK_F_ST_REQUEST;
1561 			break;
1562 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1563 
1564 		case LDAP_BACK_CFG_NOREFS:
1565 			li->li_flags &= ~LDAP_BACK_F_NOREFS;
1566 			break;
1567 
1568 		case LDAP_BACK_CFG_NOUNDEFFILTER:
1569 			li->li_flags &= ~LDAP_BACK_F_NOUNDEFFILTER;
1570 			break;
1571 
1572 		case LDAP_BACK_CFG_OMIT_UNKNOWN_SCHEMA:
1573 			li->li_flags &= ~LDAP_BACK_F_OMIT_UNKNOWN_SCHEMA;
1574 			break;
1575 
1576 		case LDAP_BACK_CFG_ONERR:
1577 			li->li_flags &= ~LDAP_BACK_F_ONERR_STOP;
1578 			break;
1579 
1580 		case LDAP_BACK_CFG_KEEPALIVE:
1581 			li->li_tls.sb_keepalive.sk_idle = 0;
1582 			li->li_tls.sb_keepalive.sk_probes = 0;
1583 			li->li_tls.sb_keepalive.sk_interval = 0;
1584 			break;
1585 
1586 		default:
1587 			/* FIXME: we need to handle all... */
1588 			assert( 0 );
1589 			break;
1590 		}
1591 		return rc;
1592 
1593 	}
1594 
1595 	switch( c->type ) {
1596 	case LDAP_BACK_CFG_URI: {
1597 		LDAPURLDesc	*tmpludp, *lud;
1598 		char		**urllist = NULL;
1599 		int		urlrc = LDAP_URL_SUCCESS, i;
1600 
1601 		if ( li->li_uri != NULL ) {
1602 			ch_free( li->li_uri );
1603 			li->li_uri = NULL;
1604 
1605 			assert( li->li_bvuri != NULL );
1606 			ber_bvarray_free( li->li_bvuri );
1607 			li->li_bvuri = NULL;
1608 		}
1609 
1610 		/* PARANOID: DN and more are not required nor allowed */
1611 		urlrc = ldap_url_parselist_ext( &lud, c->argv[ 1 ], ", \t", LDAP_PVT_URL_PARSE_NONE );
1612 		if ( urlrc != LDAP_URL_SUCCESS ) {
1613 			char	*why;
1614 
1615 			switch ( urlrc ) {
1616 			case LDAP_URL_ERR_MEM:
1617 				why = "no memory";
1618 				break;
1619 			case LDAP_URL_ERR_PARAM:
1620 		  		why = "parameter is bad";
1621 				break;
1622 			case LDAP_URL_ERR_BADSCHEME:
1623 				why = "URL doesn't begin with \"[c]ldap[si]://\"";
1624 				break;
1625 			case LDAP_URL_ERR_BADENCLOSURE:
1626 				why = "URL is missing trailing \">\"";
1627 				break;
1628 			case LDAP_URL_ERR_BADURL:
1629 				why = "URL is bad";
1630 				break;
1631 			case LDAP_URL_ERR_BADHOST:
1632 				why = "host/port is bad";
1633 				break;
1634 			case LDAP_URL_ERR_BADATTRS:
1635 				why = "bad (or missing) attributes";
1636 				break;
1637 			case LDAP_URL_ERR_BADSCOPE:
1638 				why = "scope string is invalid (or missing)";
1639 				break;
1640 			case LDAP_URL_ERR_BADFILTER:
1641 				why = "bad or missing filter";
1642 				break;
1643 			case LDAP_URL_ERR_BADEXTS:
1644 				why = "bad or missing extensions";
1645 				break;
1646 			default:
1647 				why = "unknown reason";
1648 				break;
1649 			}
1650 			snprintf( c->cr_msg, sizeof( c->cr_msg),
1651 					"unable to parse uri \"%s\" "
1652 					"in \"uri <uri>\" line: %s",
1653 					c->value_string, why );
1654 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1655 			urlrc = 1;
1656 			goto done_url;
1657 		}
1658 
1659 		for ( i = 0, tmpludp = lud;
1660 				tmpludp;
1661 				i++, tmpludp = tmpludp->lud_next )
1662 		{
1663 			if ( ( tmpludp->lud_dn != NULL
1664 						&& tmpludp->lud_dn[0] != '\0' )
1665 					|| tmpludp->lud_attrs != NULL
1666 					/* || tmpludp->lud_scope != LDAP_SCOPE_DEFAULT */
1667 					|| tmpludp->lud_filter != NULL
1668 					|| tmpludp->lud_exts != NULL )
1669 			{
1670 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
1671 						"warning, only protocol, "
1672 						"host and port allowed "
1673 						"in \"uri <uri>\" statement "
1674 						"for uri #%d of \"%s\"",
1675 						i, c->argv[ 1 ] );
1676 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1677 			}
1678 		}
1679 
1680 		for ( i = 0, tmpludp = lud;
1681 				tmpludp;
1682 				i++, tmpludp = tmpludp->lud_next )
1683 			/* just count */
1684 			;
1685 		urllist = ch_calloc( sizeof( char * ), i + 1 );
1686 
1687 		for ( i = 0, tmpludp = lud;
1688 				tmpludp;
1689 				i++, tmpludp = tmpludp->lud_next )
1690 		{
1691 			LDAPURLDesc	tmplud;
1692 
1693 			tmplud = *tmpludp;
1694 			tmplud.lud_dn = "";
1695 			tmplud.lud_attrs = NULL;
1696 			tmplud.lud_filter = NULL;
1697 			if ( !ldap_is_ldapi_url( tmplud.lud_scheme ) ) {
1698 				tmplud.lud_exts = NULL;
1699 				tmplud.lud_crit_exts = 0;
1700 			}
1701 
1702 			urllist[ i ]  = ldap_url_desc2str( &tmplud );
1703 
1704 			if ( urllist[ i ] == NULL ) {
1705 				snprintf( c->cr_msg, sizeof( c->cr_msg),
1706 					"unable to rebuild uri "
1707 					"in \"uri <uri>\" statement "
1708 					"for \"%s\"",
1709 					c->argv[ 1 ] );
1710 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1711 				urlrc = 1;
1712 				goto done_url;
1713 			}
1714 		}
1715 
1716 		li->li_uri = ldap_charray2str( urllist, " " );
1717 		for ( i = 0; urllist[ i ] != NULL; i++ ) {
1718 			struct berval	bv;
1719 
1720 			ber_str2bv( urllist[ i ], 0, 0, &bv );
1721 			ber_bvarray_add( &li->li_bvuri, &bv );
1722 			urllist[ i ] = NULL;
1723 		}
1724 		ldap_memfree( urllist );
1725 		urllist = NULL;
1726 
1727 done_url:;
1728 		if ( urllist ) {
1729 			ldap_charray_free( urllist );
1730 		}
1731 		if ( lud ) {
1732 			ldap_free_urllist( lud );
1733 		}
1734 		if ( urlrc != LDAP_URL_SUCCESS ) {
1735 			return 1;
1736 		}
1737 		break;
1738 	}
1739 
1740 	case LDAP_BACK_CFG_TLS:
1741 		i = verb_to_mask( c->argv[1], tls_mode );
1742 		if ( BER_BVISNULL( &tls_mode[i].word ) ) {
1743 			return 1;
1744 		}
1745 		li->li_flags &= ~LDAP_BACK_F_TLS_MASK;
1746 		li->li_flags |= tls_mode[i].mask;
1747 		if ( c->argc > 2 ) {
1748 			for ( i=2; i<c->argc; i++ ) {
1749 				if ( bindconf_tls_parse( c->argv[i], &li->li_tls ))
1750 					return 1;
1751 			}
1752 			bindconf_tls_defaults( &li->li_tls );
1753 		}
1754 		break;
1755 
1756 	case LDAP_BACK_CFG_ACL_AUTHCDN:
1757 		switch ( li->li_acl_authmethod ) {
1758 		case LDAP_AUTH_NONE:
1759 			li->li_acl_authmethod = LDAP_AUTH_SIMPLE;
1760 			break;
1761 
1762 		case LDAP_AUTH_SIMPLE:
1763 			break;
1764 
1765 		default:
1766 			snprintf( c->cr_msg, sizeof( c->cr_msg),
1767 				"\"acl-authcDN <DN>\" incompatible "
1768 				"with auth method %d",
1769 				li->li_acl_authmethod );
1770 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1771 			return 1;
1772 		}
1773 		if ( !BER_BVISNULL( &li->li_acl_authcDN ) ) {
1774 			free( li->li_acl_authcDN.bv_val );
1775 		}
1776 		ber_memfree_x( c->value_dn.bv_val, NULL );
1777 		li->li_acl_authcDN = c->value_ndn;
1778 		BER_BVZERO( &c->value_dn );
1779 		BER_BVZERO( &c->value_ndn );
1780 		break;
1781 
1782 	case LDAP_BACK_CFG_ACL_PASSWD:
1783 		switch ( li->li_acl_authmethod ) {
1784 		case LDAP_AUTH_NONE:
1785 			li->li_acl_authmethod = LDAP_AUTH_SIMPLE;
1786 			break;
1787 
1788 		case LDAP_AUTH_SIMPLE:
1789 			break;
1790 
1791 		default:
1792 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
1793 				"\"acl-passwd <cred>\" incompatible "
1794 				"with auth method %d",
1795 				li->li_acl_authmethod );
1796 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1797 			return 1;
1798 		}
1799 		if ( !BER_BVISNULL( &li->li_acl_passwd ) ) {
1800 			free( li->li_acl_passwd.bv_val );
1801 		}
1802 		ber_str2bv( c->argv[ 1 ], 0, 1, &li->li_acl_passwd );
1803 		break;
1804 
1805 	case LDAP_BACK_CFG_ACL_METHOD:
1806 	case LDAP_BACK_CFG_ACL_BIND:
1807 		for ( i = 1; i < c->argc; i++ ) {
1808 			if ( bindconf_parse( c->argv[ i ], &li->li_acl ) ) {
1809 				return 1;
1810 			}
1811 		}
1812 		bindconf_tls_defaults( &li->li_acl );
1813 		break;
1814 
1815 	case LDAP_BACK_CFG_IDASSERT_MODE:
1816 		i = verb_to_mask( c->argv[1], idassert_mode );
1817 		if ( BER_BVISNULL( &idassert_mode[i].word ) ) {
1818 			if ( strncasecmp( c->argv[1], "u:", STRLENOF( "u:" ) ) == 0 ) {
1819 				li->li_idassert_mode = LDAP_BACK_IDASSERT_OTHERID;
1820 				ber_str2bv( c->argv[1], 0, 1, &li->li_idassert_authzID );
1821 				li->li_idassert_authzID.bv_val[ 0 ] = 'u';
1822 
1823 			} else {
1824 				struct berval	id, ndn;
1825 
1826 				ber_str2bv( c->argv[1], 0, 0, &id );
1827 
1828 				if ( strncasecmp( c->argv[1], "dn:", STRLENOF( "dn:" ) ) == 0 ) {
1829 					id.bv_val += STRLENOF( "dn:" );
1830 					id.bv_len -= STRLENOF( "dn:" );
1831 				}
1832 
1833 				rc = dnNormalize( 0, NULL, NULL, &id, &ndn, NULL );
1834                                 if ( rc != LDAP_SUCCESS ) {
1835                                         Debug( LDAP_DEBUG_ANY,
1836                                                 "%s: line %d: idassert ID \"%s\" is not a valid DN\n",
1837                                                 c->fname, c->lineno, c->argv[1] );
1838                                         return 1;
1839                                 }
1840 
1841                                 li->li_idassert_authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
1842                                 li->li_idassert_authzID.bv_val = ch_malloc( li->li_idassert_authzID.bv_len + 1 );
1843                                 AC_MEMCPY( li->li_idassert_authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
1844                                 AC_MEMCPY( &li->li_idassert_authzID.bv_val[ STRLENOF( "dn:" ) ], ndn.bv_val, ndn.bv_len + 1 );
1845                                 ch_free( ndn.bv_val );
1846 
1847                                 li->li_idassert_mode = LDAP_BACK_IDASSERT_OTHERDN;
1848 			}
1849 
1850 		} else {
1851 			li->li_idassert_mode = idassert_mode[i].mask;
1852 		}
1853 
1854 		if ( c->argc > 2 ) {
1855 			int	i;
1856 
1857 			for ( i = 2; i < c->argc; i++ ) {
1858 				if ( strcasecmp( c->argv[ i ], "override" ) == 0 ) {
1859 					li->li_idassert_flags |= LDAP_BACK_AUTH_OVERRIDE;
1860 
1861 				} else if ( strcasecmp( c->argv[ i ], "prescriptive" ) == 0 ) {
1862 					li->li_idassert_flags |= LDAP_BACK_AUTH_PRESCRIPTIVE;
1863 
1864 				} else if ( strcasecmp( c->argv[ i ], "non-prescriptive" ) == 0 ) {
1865 					li->li_idassert_flags &= ( ~LDAP_BACK_AUTH_PRESCRIPTIVE );
1866 
1867 				} else if ( strcasecmp( c->argv[ i ], "obsolete-proxy-authz" ) == 0 ) {
1868 					if ( li->li_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
1869 						Debug( LDAP_DEBUG_ANY,
1870                                        	 		"%s: line %d: \"obsolete-proxy-authz\" flag "
1871                                         		"in \"idassert-mode <args>\" "
1872                                         		"incompatible with previously issued \"obsolete-encoding-workaround\" flag.\n",
1873                                         		c->fname, c->lineno, 0 );
1874                                 		return 1;
1875 					}
1876 					li->li_idassert_flags |= LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ;
1877 
1878 				} else if ( strcasecmp( c->argv[ i ], "obsolete-encoding-workaround" ) == 0 ) {
1879 					if ( li->li_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
1880 						Debug( LDAP_DEBUG_ANY,
1881                                        	 		"%s: line %d: \"obsolete-encoding-workaround\" flag "
1882                                         		"in \"idassert-mode <args>\" "
1883                                         		"incompatible with previously issued \"obsolete-proxy-authz\" flag.\n",
1884                                         		c->fname, c->lineno, 0 );
1885                                 		return 1;
1886 					}
1887 					li->li_idassert_flags |= LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND;
1888 
1889 				} else {
1890 					Debug( LDAP_DEBUG_ANY,
1891                                         	"%s: line %d: unknown flag #%d "
1892                                         	"in \"idassert-mode <args> "
1893                                         	"[<flags>]\" line.\n",
1894                                         	c->fname, c->lineno, i - 2 );
1895                                 	return 1;
1896 				}
1897                         }
1898                 }
1899 		break;
1900 
1901 	case LDAP_BACK_CFG_IDASSERT_AUTHCDN:
1902 		switch ( li->li_idassert_authmethod ) {
1903 		case LDAP_AUTH_NONE:
1904 			li->li_idassert_authmethod = LDAP_AUTH_SIMPLE;
1905 			break;
1906 
1907 		case LDAP_AUTH_SIMPLE:
1908 			break;
1909 
1910 		default:
1911 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
1912 				"\"idassert-authcDN <DN>\" incompatible "
1913 				"with auth method %d",
1914 				li->li_idassert_authmethod );
1915 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1916 			return 1;
1917 		}
1918 		if ( !BER_BVISNULL( &li->li_idassert_authcDN ) ) {
1919 			free( li->li_idassert_authcDN.bv_val );
1920 		}
1921 		ber_memfree_x( c->value_dn.bv_val, NULL );
1922 		li->li_idassert_authcDN = c->value_ndn;
1923 		BER_BVZERO( &c->value_dn );
1924 		BER_BVZERO( &c->value_ndn );
1925 		break;
1926 
1927 	case LDAP_BACK_CFG_IDASSERT_PASSWD:
1928 		switch ( li->li_idassert_authmethod ) {
1929 		case LDAP_AUTH_NONE:
1930 			li->li_idassert_authmethod = LDAP_AUTH_SIMPLE;
1931 			break;
1932 
1933 		case LDAP_AUTH_SIMPLE:
1934 			break;
1935 
1936 		default:
1937 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
1938 				"\"idassert-passwd <cred>\" incompatible "
1939 				"with auth method %d",
1940 				li->li_idassert_authmethod );
1941 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1942 			return 1;
1943 		}
1944 		if ( !BER_BVISNULL( &li->li_idassert_passwd ) ) {
1945 			free( li->li_idassert_passwd.bv_val );
1946 		}
1947 		ber_str2bv( c->argv[ 1 ], 0, 1, &li->li_idassert_passwd );
1948 		break;
1949 
1950 	case LDAP_BACK_CFG_IDASSERT_AUTHZFROM:
1951 		rc = slap_idassert_authzfrom_parse( c, &li->li_idassert );
1952 		break;
1953 
1954 	case LDAP_BACK_CFG_IDASSERT_PASSTHRU:
1955 		rc = slap_idassert_passthru_parse( c, &li->li_idassert );
1956 		break;
1957 
1958 	case LDAP_BACK_CFG_IDASSERT_METHOD:
1959 		/* no longer supported */
1960 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
1961 			"\"idassert-method <args>\": "
1962 			"no longer supported; use \"idassert-bind\"" );
1963 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1964 		return 1;
1965 
1966 	case LDAP_BACK_CFG_IDASSERT_BIND:
1967 		rc = slap_idassert_parse( c, &li->li_idassert );
1968 		break;
1969 
1970 	case LDAP_BACK_CFG_REBIND:
1971 		if ( c->argc == 1 || c->value_int ) {
1972 			li->li_flags |= LDAP_BACK_F_SAVECRED;
1973 
1974 		} else {
1975 			li->li_flags &= ~LDAP_BACK_F_SAVECRED;
1976 		}
1977 		break;
1978 
1979 	case LDAP_BACK_CFG_CHASE:
1980 		if ( c->argc == 1 || c->value_int ) {
1981 			li->li_flags |= LDAP_BACK_F_CHASE_REFERRALS;
1982 
1983 		} else {
1984 			li->li_flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
1985 		}
1986 		break;
1987 
1988 	case LDAP_BACK_CFG_T_F: {
1989 		slap_mask_t		mask;
1990 
1991 		i = verb_to_mask( c->argv[1], t_f_mode );
1992 		if ( BER_BVISNULL( &t_f_mode[i].word ) ) {
1993 			return 1;
1994 		}
1995 
1996 		mask = t_f_mode[i].mask;
1997 
1998 		if ( LDAP_BACK_ISOPEN( li )
1999 			&& mask == LDAP_BACK_F_T_F_DISCOVER
2000 			&& !LDAP_BACK_T_F( li ) )
2001 		{
2002 			slap_bindconf	sb = { BER_BVNULL };
2003 			int		rc;
2004 
2005 			if ( li->li_uri == NULL ) {
2006 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2007 					"need URI to discover absolute filters support "
2008 					"in \"t-f-support discover\"" );
2009 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2010 				return 1;
2011 			}
2012 
2013 			ber_str2bv( li->li_uri, 0, 0, &sb.sb_uri );
2014 			sb.sb_version = li->li_version;
2015 			sb.sb_method = LDAP_AUTH_SIMPLE;
2016 			BER_BVSTR( &sb.sb_binddn, "" );
2017 
2018 			rc = slap_discover_feature( &sb,
2019 					slap_schema.si_ad_supportedFeatures->ad_cname.bv_val,
2020 					LDAP_FEATURE_ABSOLUTE_FILTERS );
2021 			if ( rc == LDAP_COMPARE_TRUE ) {
2022 				mask |= LDAP_BACK_F_T_F;
2023 			}
2024 		}
2025 
2026 		li->li_flags &= ~LDAP_BACK_F_T_F_MASK2;
2027 		li->li_flags |= mask;
2028 		} break;
2029 
2030 	case LDAP_BACK_CFG_WHOAMI:
2031 		if ( c->argc == 1 || c->value_int ) {
2032 			li->li_flags |= LDAP_BACK_F_PROXY_WHOAMI;
2033 			load_extop( (struct berval *)&slap_EXOP_WHOAMI,
2034 					0, ldap_back_exop_whoami );
2035 
2036 		} else {
2037 			li->li_flags &= ~LDAP_BACK_F_PROXY_WHOAMI;
2038 		}
2039 		break;
2040 
2041 	case LDAP_BACK_CFG_TIMEOUT:
2042 		for ( i = 1; i < c->argc; i++ ) {
2043 			if ( isdigit( (unsigned char) c->argv[ i ][ 0 ] ) ) {
2044 				int		j;
2045 				unsigned	u;
2046 
2047 				if ( lutil_atoux( &u, c->argv[ i ], 0 ) != 0 ) {
2048 					snprintf( c->cr_msg, sizeof( c->cr_msg),
2049 						"unable to parse timeout \"%s\"",
2050 						c->argv[ i ] );
2051 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2052 					return 1;
2053 				}
2054 
2055 				for ( j = 0; j < SLAP_OP_LAST; j++ ) {
2056 					li->li_timeout[ j ] = u;
2057 				}
2058 
2059 				continue;
2060 			}
2061 
2062 			if ( slap_cf_aux_table_parse( c->argv[ i ], li->li_timeout, timeout_table, "slapd-ldap timeout" ) ) {
2063 				snprintf( c->cr_msg, sizeof( c->cr_msg),
2064 					"unable to parse timeout \"%s\"",
2065 					c->argv[ i ] );
2066 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2067 				return 1;
2068 			}
2069 		}
2070 		break;
2071 
2072 	case LDAP_BACK_CFG_IDLE_TIMEOUT: {
2073 		unsigned long	t;
2074 
2075 		if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
2076 			snprintf( c->cr_msg, sizeof( c->cr_msg),
2077 				"unable to parse idle timeout \"%s\"",
2078 				c->argv[ 1 ] );
2079 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2080 			return 1;
2081 		}
2082 		li->li_idle_timeout = (time_t)t;
2083 		} break;
2084 
2085 	case LDAP_BACK_CFG_CONN_TTL: {
2086 		unsigned long	t;
2087 
2088 		if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
2089 			snprintf( c->cr_msg, sizeof( c->cr_msg),
2090 				"unable to parse conn ttl\"%s\"",
2091 				c->argv[ 1 ] );
2092 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2093 			return 1;
2094 		}
2095 		li->li_conn_ttl = (time_t)t;
2096 		} break;
2097 
2098 	case LDAP_BACK_CFG_NETWORK_TIMEOUT: {
2099 		unsigned long	t;
2100 
2101 		if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
2102 			snprintf( c->cr_msg, sizeof( c->cr_msg),
2103 				"unable to parse network timeout \"%s\"",
2104 				c->argv[ 1 ] );
2105 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2106 			return 1;
2107 		}
2108 		li->li_network_timeout = (time_t)t;
2109 		} break;
2110 
2111 	case LDAP_BACK_CFG_VERSION:
2112 		if ( c->value_int != 0 && ( c->value_int < LDAP_VERSION_MIN || c->value_int > LDAP_VERSION_MAX ) ) {
2113 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2114 				"unsupported version \"%s\" "
2115 				"in \"protocol-version <version>\"",
2116 				c->argv[ 1 ] );
2117 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2118 			return 1;
2119 		}
2120 
2121 		li->li_version = c->value_int;
2122 		break;
2123 
2124 	case LDAP_BACK_CFG_SINGLECONN:
2125 		if ( c->value_int ) {
2126 			li->li_flags |= LDAP_BACK_F_SINGLECONN;
2127 
2128 		} else {
2129 			li->li_flags &= ~LDAP_BACK_F_SINGLECONN;
2130 		}
2131 		break;
2132 
2133 	case LDAP_BACK_CFG_USETEMP:
2134 		if ( c->value_int ) {
2135 			li->li_flags |= LDAP_BACK_F_USE_TEMPORARIES;
2136 
2137 		} else {
2138 			li->li_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
2139 		}
2140 		break;
2141 
2142 	case LDAP_BACK_CFG_CONNPOOLMAX:
2143 		if ( c->value_int < LDAP_BACK_CONN_PRIV_MIN
2144 			|| c->value_int > LDAP_BACK_CONN_PRIV_MAX )
2145 		{
2146 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2147 				"invalid max size " "of privileged "
2148 				"connections pool \"%s\" "
2149 				"in \"conn-pool-max <n> "
2150 				"(must be between %d and %d)\"",
2151 				c->argv[ 1 ],
2152 				LDAP_BACK_CONN_PRIV_MIN,
2153 				LDAP_BACK_CONN_PRIV_MAX );
2154 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2155 			return 1;
2156 		}
2157 		li->li_conn_priv_max = c->value_int;
2158 		break;
2159 
2160 	case LDAP_BACK_CFG_CANCEL: {
2161 		slap_mask_t		mask;
2162 
2163 		i = verb_to_mask( c->argv[1], cancel_mode );
2164 		if ( BER_BVISNULL( &cancel_mode[i].word ) ) {
2165 			return 1;
2166 		}
2167 
2168 		mask = cancel_mode[i].mask;
2169 
2170 		if ( LDAP_BACK_ISOPEN( li )
2171 			&& mask == LDAP_BACK_F_CANCEL_EXOP_DISCOVER
2172 			&& !LDAP_BACK_CANCEL( li ) )
2173 		{
2174 			slap_bindconf	sb = { BER_BVNULL };
2175 			int		rc;
2176 
2177 			if ( li->li_uri == NULL ) {
2178 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2179 					"need URI to discover \"cancel\" support "
2180 					"in \"cancel exop-discover\"" );
2181 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2182 				return 1;
2183 			}
2184 
2185 			ber_str2bv( li->li_uri, 0, 0, &sb.sb_uri );
2186 			sb.sb_version = li->li_version;
2187 			sb.sb_method = LDAP_AUTH_SIMPLE;
2188 			BER_BVSTR( &sb.sb_binddn, "" );
2189 
2190 			rc = slap_discover_feature( &sb,
2191 					slap_schema.si_ad_supportedExtension->ad_cname.bv_val,
2192 					LDAP_EXOP_CANCEL );
2193 			if ( rc == LDAP_COMPARE_TRUE ) {
2194 				mask |= LDAP_BACK_F_CANCEL_EXOP;
2195 			}
2196 		}
2197 
2198 		li->li_flags &= ~LDAP_BACK_F_CANCEL_MASK2;
2199 		li->li_flags |= mask;
2200 		} break;
2201 
2202 	case LDAP_BACK_CFG_QUARANTINE:
2203 		if ( LDAP_BACK_QUARANTINE( li ) ) {
2204 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2205 				"quarantine already defined" );
2206 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2207 			return 1;
2208 		}
2209 		rc = slap_retry_info_parse( c->argv[1], &li->li_quarantine,
2210 			c->cr_msg, sizeof( c->cr_msg ) );
2211 		if ( rc ) {
2212 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2213 
2214 		} else {
2215 			ldap_pvt_thread_mutex_init( &li->li_quarantine_mutex );
2216 			/* give it a chance to retry if the pattern gets reset
2217 			 * via back-config */
2218 			li->li_isquarantined = 0;
2219 			li->li_flags |= LDAP_BACK_F_QUARANTINE;
2220 		}
2221 		break;
2222 
2223 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
2224 	case LDAP_BACK_CFG_ST_REQUEST:
2225 		if ( c->value_int ) {
2226 			li->li_flags |= LDAP_BACK_F_ST_REQUEST;
2227 
2228 		} else {
2229 			li->li_flags &= ~LDAP_BACK_F_ST_REQUEST;
2230 		}
2231 		break;
2232 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
2233 
2234 	case LDAP_BACK_CFG_NOREFS:
2235 		if ( c->value_int ) {
2236 			li->li_flags |= LDAP_BACK_F_NOREFS;
2237 
2238 		} else {
2239 			li->li_flags &= ~LDAP_BACK_F_NOREFS;
2240 		}
2241 		break;
2242 
2243 	case LDAP_BACK_CFG_NOUNDEFFILTER:
2244 		if ( c->value_int ) {
2245 			li->li_flags |= LDAP_BACK_F_NOUNDEFFILTER;
2246 
2247 		} else {
2248 			li->li_flags &= ~LDAP_BACK_F_NOUNDEFFILTER;
2249 		}
2250 		break;
2251 
2252 	case LDAP_BACK_CFG_ONERR:
2253 	/* onerr? */
2254 		i = verb_to_mask( c->argv[1], onerr_mode );
2255 		if ( BER_BVISNULL( &onerr_mode[i].word ) ) {
2256 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2257 				"%s unknown argument \"%s\"",
2258 				c->argv[0], c->argv[1] );
2259 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2260 			return 1;
2261 		}
2262 		li->li_flags &= ~LDAP_BACK_F_ONERR_STOP;
2263 		li->li_flags |= onerr_mode[i].mask;
2264 		break;
2265 
2266 	case LDAP_BACK_CFG_REWRITE:
2267 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
2268 			"rewrite/remap capabilities have been moved "
2269 			"to the \"rwm\" overlay; see slapo-rwm(5) "
2270 			"for details (hint: add \"overlay rwm\" "
2271 			"and prefix all directives with \"rwm-\")" );
2272 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2273 		return 1;
2274 
2275 	case LDAP_BACK_CFG_OMIT_UNKNOWN_SCHEMA:
2276 		if ( c->value_int ) {
2277 			li->li_flags |= LDAP_BACK_F_OMIT_UNKNOWN_SCHEMA;
2278 
2279 		} else {
2280 			li->li_flags &= ~LDAP_BACK_F_OMIT_UNKNOWN_SCHEMA;
2281 		}
2282 		break;
2283 
2284 	case LDAP_BACK_CFG_KEEPALIVE:
2285 		slap_keepalive_parse( ber_bvstrdup(c->argv[1]),
2286 				 &li->li_tls.sb_keepalive, 0, 0, 0);
2287 		break;
2288 
2289 	default:
2290 		/* FIXME: try to catch inconsistencies */
2291 		assert( 0 );
2292 		break;
2293 	}
2294 
2295 	return rc;
2296 }
2297 
2298 int
2299 ldap_back_init_cf( BackendInfo *bi )
2300 {
2301 	int			rc;
2302 	AttributeDescription	*ad = NULL;
2303 	const char		*text;
2304 
2305 	/* Make sure we don't exceed the bits reserved for userland */
2306 	config_check_userland( LDAP_BACK_CFG_LAST );
2307 
2308 	bi->bi_cf_ocs = ldapocs;
2309 
2310 	rc = config_register_schema( ldapcfg, ldapocs );
2311 	if ( rc ) {
2312 		return rc;
2313 	}
2314 
2315 	/* setup olcDbAclPasswd and olcDbIDAssertPasswd
2316 	 * to be base64-encoded when written in LDIF form;
2317 	 * basically, we don't care if it fails */
2318 	rc = slap_str2ad( "olcDbACLPasswd", &ad, &text );
2319 	if ( rc ) {
2320 		Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
2321 			"warning, unable to get \"olcDbACLPasswd\" "
2322 			"attribute description: %d: %s\n",
2323 			rc, text, 0 );
2324 	} else {
2325 		(void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
2326 			ad->ad_type->sat_oid );
2327 	}
2328 
2329 	ad = NULL;
2330 	rc = slap_str2ad( "olcDbIDAssertPasswd", &ad, &text );
2331 	if ( rc ) {
2332 		Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
2333 			"warning, unable to get \"olcDbIDAssertPasswd\" "
2334 			"attribute description: %d: %s\n",
2335 			rc, text, 0 );
2336 	} else {
2337 		(void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
2338 			ad->ad_type->sat_oid );
2339 	}
2340 
2341 	return 0;
2342 }
2343 
2344 static int
2345 ldap_pbind_cf_gen( ConfigArgs *c )
2346 {
2347 	slap_overinst	*on = (slap_overinst *)c->bi;
2348 	void	*private = c->be->be_private;
2349 	int		rc;
2350 
2351 	c->be->be_private = on->on_bi.bi_private;
2352 	rc = ldap_back_cf_gen( c );
2353 	c->be->be_private = private;
2354 	return rc;
2355 }
2356 
2357 int
2358 ldap_pbind_init_cf( BackendInfo *bi )
2359 {
2360 	bi->bi_cf_ocs = pbindocs;
2361 
2362 	return config_register_schema( pbindcfg, pbindocs );
2363 }
2364 
2365 static int
2366 ldap_back_exop_whoami(
2367 		Operation	*op,
2368 		SlapReply	*rs )
2369 {
2370 	struct berval *bv = NULL;
2371 
2372 	if ( op->oq_extended.rs_reqdata != NULL ) {
2373 		/* no request data should be provided */
2374 		rs->sr_text = "no request data expected";
2375 		return rs->sr_err = LDAP_PROTOCOL_ERROR;
2376 	}
2377 
2378 	Statslog( LDAP_DEBUG_STATS, "%s WHOAMI\n",
2379 	    op->o_log_prefix, 0, 0, 0, 0 );
2380 
2381 	rs->sr_err = backend_check_restrictions( op, rs,
2382 			(struct berval *)&slap_EXOP_WHOAMI );
2383 	if( rs->sr_err != LDAP_SUCCESS ) return rs->sr_err;
2384 
2385 	/* if auth'd by back-ldap and request is proxied, forward it */
2386 	if ( op->o_conn->c_authz_backend
2387 		&& !strcmp( op->o_conn->c_authz_backend->be_type, "ldap" )
2388 		&& !dn_match( &op->o_ndn, &op->o_conn->c_ndn ) )
2389 	{
2390 		ldapconn_t	*lc = NULL;
2391 		LDAPControl c, *ctrls[2] = {NULL, NULL};
2392 		LDAPMessage *res;
2393 		Operation op2 = *op;
2394 		ber_int_t msgid;
2395 		int doretry = 1;
2396 		char *ptr;
2397 
2398 		ctrls[0] = &c;
2399 		op2.o_ndn = op->o_conn->c_ndn;
2400 		if ( !ldap_back_dobind( &lc, &op2, rs, LDAP_BACK_SENDERR ) ) {
2401 			return -1;
2402 		}
2403 		c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
2404 		c.ldctl_iscritical = 1;
2405 		c.ldctl_value.bv_val = op->o_tmpalloc(
2406 			op->o_ndn.bv_len + STRLENOF( "dn:" ) + 1,
2407 			op->o_tmpmemctx );
2408 		c.ldctl_value.bv_len = op->o_ndn.bv_len + 3;
2409 		ptr = c.ldctl_value.bv_val;
2410 		ptr = lutil_strcopy( ptr, "dn:" );
2411 		ptr = lutil_strncopy( ptr, op->o_ndn.bv_val, op->o_ndn.bv_len );
2412 		ptr[ 0 ] = '\0';
2413 
2414 retry:
2415 		rs->sr_err = ldap_whoami( lc->lc_ld, ctrls, NULL, &msgid );
2416 		if ( rs->sr_err == LDAP_SUCCESS ) {
2417 			/* by now, make sure no timeout is used (ITS#6282) */
2418 			struct timeval tv = { -1, 0 };
2419 			if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res ) == -1 ) {
2420 				ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER,
2421 					&rs->sr_err );
2422 				if ( rs->sr_err == LDAP_SERVER_DOWN && doretry ) {
2423 					doretry = 0;
2424 					if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
2425 						goto retry;
2426 					}
2427 				}
2428 
2429 			} else {
2430 				/* NOTE: are we sure "bv" will be malloc'ed
2431 				 * with the appropriate memory? */
2432 				rs->sr_err = ldap_parse_whoami( lc->lc_ld, res, &bv );
2433 				ldap_msgfree(res);
2434 			}
2435 		}
2436 		op->o_tmpfree( c.ldctl_value.bv_val, op->o_tmpmemctx );
2437 		if ( rs->sr_err != LDAP_SUCCESS ) {
2438 			rs->sr_err = slap_map_api2result( rs );
2439 		}
2440 
2441 		if ( lc != NULL ) {
2442 			ldap_back_release_conn( (ldapinfo_t *)op2.o_bd->be_private, lc );
2443 		}
2444 
2445 	} else {
2446 		/* else just do the same as before */
2447 		bv = (struct berval *) ch_malloc( sizeof( struct berval ) );
2448 		if ( !BER_BVISEMPTY( &op->o_dn ) ) {
2449 			bv->bv_len = op->o_dn.bv_len + STRLENOF( "dn:" );
2450 			bv->bv_val = ch_malloc( bv->bv_len + 1 );
2451 			AC_MEMCPY( bv->bv_val, "dn:", STRLENOF( "dn:" ) );
2452 			AC_MEMCPY( &bv->bv_val[ STRLENOF( "dn:" ) ], op->o_dn.bv_val,
2453 				op->o_dn.bv_len );
2454 			bv->bv_val[ bv->bv_len ] = '\0';
2455 
2456 		} else {
2457 			bv->bv_len = 0;
2458 			bv->bv_val = NULL;
2459 		}
2460 	}
2461 
2462 	rs->sr_rspdata = bv;
2463 	return rs->sr_err;
2464 }
2465 
2466 
2467