xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-meta/config.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: config.c,v 1.1.1.5 2014/05/28 09:58:50 tron Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2014 The OpenLDAP Foundation.
7  * Portions Copyright 2001-2003 Pierangelo Masarati.
8  * Portions Copyright 1999-2003 Howard Chu.
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 /* ACKNOWLEDGEMENTS:
20  * This work was initially developed by the Howard Chu for inclusion
21  * in OpenLDAP Software and subsequently enhanced by Pierangelo
22  * Masarati.
23  */
24 
25 #include "portable.h"
26 
27 #include <stdio.h>
28 #include <ctype.h>
29 
30 #include <ac/string.h>
31 #include <ac/socket.h>
32 
33 #include "slap.h"
34 #include "config.h"
35 #include "lutil.h"
36 #include "ldif.h"
37 #include "../back-ldap/back-ldap.h"
38 #include "back-meta.h"
39 
40 #ifdef LDAP_DEVEL
41 #define SLAP_AUTH_DN	1
42 #endif
43 
44 static ConfigDriver meta_back_cf_gen;
45 static ConfigLDAPadd meta_ldadd;
46 static ConfigCfAdd meta_cfadd;
47 
48 static int ldap_back_map_config(
49 	ConfigArgs *c,
50 	struct ldapmap	*oc_map,
51 	struct ldapmap	*at_map );
52 
53 /* Three sets of enums:
54  *	1) attrs that are only valid in the base config
55  *	2) attrs that are valid in base or target
56  *	3) attrs that are only valid in a target
57  */
58 
59 /* Base attrs */
60 enum {
61 	LDAP_BACK_CFG_CONN_TTL = 1,
62 	LDAP_BACK_CFG_DNCACHE_TTL,
63 	LDAP_BACK_CFG_IDLE_TIMEOUT,
64 	LDAP_BACK_CFG_ONERR,
65 	LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER,
66 	LDAP_BACK_CFG_SINGLECONN,
67 	LDAP_BACK_CFG_USETEMP,
68 	LDAP_BACK_CFG_CONNPOOLMAX,
69 	LDAP_BACK_CFG_LAST_BASE
70 };
71 
72 /* Base or target */
73 enum {
74 	LDAP_BACK_CFG_BIND_TIMEOUT = LDAP_BACK_CFG_LAST_BASE,
75 	LDAP_BACK_CFG_CANCEL,
76 	LDAP_BACK_CFG_CHASE,
77 	LDAP_BACK_CFG_CLIENT_PR,
78 	LDAP_BACK_CFG_DEFAULT_T,
79 	LDAP_BACK_CFG_NETWORK_TIMEOUT,
80 	LDAP_BACK_CFG_NOREFS,
81 	LDAP_BACK_CFG_NOUNDEFFILTER,
82 	LDAP_BACK_CFG_NRETRIES,
83 	LDAP_BACK_CFG_QUARANTINE,
84 	LDAP_BACK_CFG_REBIND,
85 	LDAP_BACK_CFG_TIMEOUT,
86 	LDAP_BACK_CFG_VERSION,
87 	LDAP_BACK_CFG_ST_REQUEST,
88 	LDAP_BACK_CFG_T_F,
89 	LDAP_BACK_CFG_TLS,
90 	LDAP_BACK_CFG_LAST_BOTH
91 };
92 
93 /* Target attrs */
94 enum {
95 	LDAP_BACK_CFG_URI = LDAP_BACK_CFG_LAST_BOTH,
96 	LDAP_BACK_CFG_ACL_AUTHCDN,
97 	LDAP_BACK_CFG_ACL_PASSWD,
98 	LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
99 	LDAP_BACK_CFG_IDASSERT_BIND,
100 	LDAP_BACK_CFG_REWRITE,
101 	LDAP_BACK_CFG_SUFFIXM,
102 	LDAP_BACK_CFG_MAP,
103 	LDAP_BACK_CFG_SUBTREE_EX,
104 	LDAP_BACK_CFG_SUBTREE_IN,
105 	LDAP_BACK_CFG_PSEUDOROOTDN,
106 	LDAP_BACK_CFG_PSEUDOROOTPW,
107 	LDAP_BACK_CFG_KEEPALIVE,
108 	LDAP_BACK_CFG_FILTER,
109 
110 	LDAP_BACK_CFG_LAST
111 };
112 
113 static ConfigTable metacfg[] = {
114 	{ "uri", "uri", 2, 0, 0,
115 		ARG_MAGIC|LDAP_BACK_CFG_URI,
116 		meta_back_cf_gen, "( OLcfgDbAt:0.14 "
117 			"NAME 'olcDbURI' "
118 			"DESC 'URI (list) for remote DSA' "
119 			"SYNTAX OMsDirectoryString "
120 			"SINGLE-VALUE )",
121 		NULL, NULL },
122 	{ "tls", "what", 2, 0, 0,
123 		ARG_MAGIC|LDAP_BACK_CFG_TLS,
124 		meta_back_cf_gen, "( OLcfgDbAt:3.1 "
125 			"NAME 'olcDbStartTLS' "
126 			"DESC 'StartTLS' "
127 			"SYNTAX OMsDirectoryString "
128 			"SINGLE-VALUE )",
129 		NULL, NULL },
130 	{ "acl-authcDN", "DN", 2, 2, 0,
131 		ARG_DN|ARG_MAGIC|LDAP_BACK_CFG_ACL_AUTHCDN,
132 		meta_back_cf_gen, "( OLcfgDbAt:3.2 "
133 			"NAME 'olcDbACLAuthcDn' "
134 			"DESC 'Remote ACL administrative identity' "
135 			"OBSOLETE "
136 			"SYNTAX OMsDN "
137 			"SINGLE-VALUE )",
138 		NULL, NULL },
139 	/* deprecated, will be removed; aliases "acl-authcDN" */
140 	{ "binddn", "DN", 2, 2, 0,
141 		ARG_DN|ARG_MAGIC|LDAP_BACK_CFG_ACL_AUTHCDN,
142 		meta_back_cf_gen, NULL, NULL, NULL },
143 	{ "acl-passwd", "cred", 2, 2, 0,
144 		ARG_MAGIC|LDAP_BACK_CFG_ACL_PASSWD,
145 		meta_back_cf_gen, "( OLcfgDbAt:3.3 "
146 			"NAME 'olcDbACLPasswd' "
147 			"DESC 'Remote ACL administrative identity credentials' "
148 			"OBSOLETE "
149 			"SYNTAX OMsDirectoryString "
150 			"SINGLE-VALUE )",
151 		NULL, NULL },
152 	/* deprecated, will be removed; aliases "acl-passwd" */
153 	{ "bindpw", "cred", 2, 2, 0,
154 		ARG_MAGIC|LDAP_BACK_CFG_ACL_PASSWD,
155 		meta_back_cf_gen, NULL, NULL, NULL },
156 	{ "idassert-bind", "args", 2, 0, 0,
157 		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_BIND,
158 		meta_back_cf_gen, "( OLcfgDbAt:3.7 "
159 			"NAME 'olcDbIDAssertBind' "
160 			"DESC 'Remote Identity Assertion administrative identity auth bind configuration' "
161 			"SYNTAX OMsDirectoryString "
162 			"SINGLE-VALUE )",
163 		NULL, NULL },
164 	{ "idassert-authzFrom", "authzRule", 2, 2, 0,
165 		ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
166 		meta_back_cf_gen, "( OLcfgDbAt:3.9 "
167 			"NAME 'olcDbIDAssertAuthzFrom' "
168 			"DESC 'Remote Identity Assertion authz rules' "
169 			"EQUALITY caseIgnoreMatch "
170 			"SYNTAX OMsDirectoryString "
171 			"X-ORDERED 'VALUES' )",
172 		NULL, NULL },
173 	{ "rebind-as-user", "true|FALSE", 1, 2, 0,
174 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_REBIND,
175 		meta_back_cf_gen, "( OLcfgDbAt:3.10 "
176 			"NAME 'olcDbRebindAsUser' "
177 			"DESC 'Rebind as user' "
178 			"SYNTAX OMsBoolean "
179 			"SINGLE-VALUE )",
180 		NULL, NULL },
181 	{ "chase-referrals", "true|FALSE", 2, 2, 0,
182 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_CHASE,
183 		meta_back_cf_gen, "( OLcfgDbAt:3.11 "
184 			"NAME 'olcDbChaseReferrals' "
185 			"DESC 'Chase referrals' "
186 			"SYNTAX OMsBoolean "
187 			"SINGLE-VALUE )",
188 		NULL, NULL },
189 	{ "t-f-support", "true|FALSE|discover", 2, 2, 0,
190 		ARG_MAGIC|LDAP_BACK_CFG_T_F,
191 		meta_back_cf_gen, "( OLcfgDbAt:3.12 "
192 			"NAME 'olcDbTFSupport' "
193 			"DESC 'Absolute filters support' "
194 			"SYNTAX OMsDirectoryString "
195 			"SINGLE-VALUE )",
196 		NULL, NULL },
197 	{ "timeout", "timeout(list)", 2, 0, 0,
198 		ARG_MAGIC|LDAP_BACK_CFG_TIMEOUT,
199 		meta_back_cf_gen, "( OLcfgDbAt:3.14 "
200 			"NAME 'olcDbTimeout' "
201 			"DESC 'Per-operation timeouts' "
202 			"SYNTAX OMsDirectoryString "
203 			"SINGLE-VALUE )",
204 		NULL, NULL },
205 	{ "idle-timeout", "timeout", 2, 2, 0,
206 		ARG_MAGIC|LDAP_BACK_CFG_IDLE_TIMEOUT,
207 		meta_back_cf_gen, "( OLcfgDbAt:3.15 "
208 			"NAME 'olcDbIdleTimeout' "
209 			"DESC 'connection idle timeout' "
210 			"SYNTAX OMsDirectoryString "
211 			"SINGLE-VALUE )",
212 		NULL, NULL },
213 	{ "conn-ttl", "ttl", 2, 2, 0,
214 		ARG_MAGIC|LDAP_BACK_CFG_CONN_TTL,
215 		meta_back_cf_gen, "( OLcfgDbAt:3.16 "
216 			"NAME 'olcDbConnTtl' "
217 			"DESC 'connection ttl' "
218 			"SYNTAX OMsDirectoryString "
219 			"SINGLE-VALUE )",
220 		NULL, NULL },
221 	{ "network-timeout", "timeout", 2, 2, 0,
222 		ARG_MAGIC|LDAP_BACK_CFG_NETWORK_TIMEOUT,
223 		meta_back_cf_gen, "( OLcfgDbAt:3.17 "
224 			"NAME 'olcDbNetworkTimeout' "
225 			"DESC 'connection network timeout' "
226 			"SYNTAX OMsDirectoryString "
227 			"SINGLE-VALUE )",
228 		NULL, NULL },
229 	{ "protocol-version", "version", 2, 2, 0,
230 		ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_VERSION,
231 		meta_back_cf_gen, "( OLcfgDbAt:3.18 "
232 			"NAME 'olcDbProtocolVersion' "
233 			"DESC 'protocol version' "
234 			"SYNTAX OMsInteger "
235 			"SINGLE-VALUE )",
236 		NULL, NULL },
237 	{ "single-conn", "true|FALSE", 2, 2, 0,
238 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_SINGLECONN,
239 		meta_back_cf_gen, "( OLcfgDbAt:3.19 "
240 			"NAME 'olcDbSingleConn' "
241 			"DESC 'cache a single connection per identity' "
242 			"SYNTAX OMsBoolean "
243 			"SINGLE-VALUE )",
244 		NULL, NULL },
245 	{ "cancel", "ABANDON|ignore|exop", 2, 2, 0,
246 		ARG_MAGIC|LDAP_BACK_CFG_CANCEL,
247 		meta_back_cf_gen, "( OLcfgDbAt:3.20 "
248 			"NAME 'olcDbCancel' "
249 			"DESC 'abandon/ignore/exop operations when appropriate' "
250 			"SYNTAX OMsDirectoryString "
251 			"SINGLE-VALUE )",
252 		NULL, NULL },
253 	{ "quarantine", "retrylist", 2, 2, 0,
254 		ARG_MAGIC|LDAP_BACK_CFG_QUARANTINE,
255 		meta_back_cf_gen, "( OLcfgDbAt:3.21 "
256 			"NAME 'olcDbQuarantine' "
257 			"DESC 'Quarantine database if connection fails and retry according to rule' "
258 			"SYNTAX OMsDirectoryString "
259 			"SINGLE-VALUE )",
260 		NULL, NULL },
261 	{ "use-temporary-conn", "true|FALSE", 2, 2, 0,
262 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_USETEMP,
263 		meta_back_cf_gen, "( OLcfgDbAt:3.22 "
264 			"NAME 'olcDbUseTemporaryConn' "
265 			"DESC 'Use temporary connections if the cached one is busy' "
266 			"SYNTAX OMsBoolean "
267 			"SINGLE-VALUE )",
268 		NULL, NULL },
269 	{ "conn-pool-max", "<n>", 2, 2, 0,
270 		ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_CONNPOOLMAX,
271 		meta_back_cf_gen, "( OLcfgDbAt:3.23 "
272 			"NAME 'olcDbConnectionPoolMax' "
273 			"DESC 'Max size of privileged connections pool' "
274 			"SYNTAX OMsInteger "
275 			"SINGLE-VALUE )",
276 		NULL, NULL },
277 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
278 	{ "session-tracking-request", "true|FALSE", 2, 2, 0,
279 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_ST_REQUEST,
280 		meta_back_cf_gen, "( OLcfgDbAt:3.24 "
281 			"NAME 'olcDbSessionTrackingRequest' "
282 			"DESC 'Add session tracking control to proxied requests' "
283 			"SYNTAX OMsBoolean "
284 			"SINGLE-VALUE )",
285 		NULL, NULL },
286 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
287 	{ "norefs", "true|FALSE", 2, 2, 0,
288 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_NOREFS,
289 		meta_back_cf_gen, "( OLcfgDbAt:3.25 "
290 			"NAME 'olcDbNoRefs' "
291 			"DESC 'Do not return search reference responses' "
292 			"SYNTAX OMsBoolean "
293 			"SINGLE-VALUE )",
294 		NULL, NULL },
295 	{ "noundeffilter", "true|FALSE", 2, 2, 0,
296 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_NOUNDEFFILTER,
297 		meta_back_cf_gen, "( OLcfgDbAt:3.26 "
298 			"NAME 'olcDbNoUndefFilter' "
299 			"DESC 'Do not propagate undefined search filters' "
300 			"SYNTAX OMsBoolean "
301 			"SINGLE-VALUE )",
302 		NULL, NULL },
303 
304 	{ "rewrite", "arglist", 2, 0, STRLENOF( "rewrite" ),
305 		ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
306 		meta_back_cf_gen, "( OLcfgDbAt:3.101 "
307 			"NAME 'olcDbRewrite' "
308 			"DESC 'DN rewriting rules' "
309 			"EQUALITY caseIgnoreMatch "
310 			"SYNTAX OMsDirectoryString "
311 			"X-ORDERED 'VALUES' )",
312 		NULL, NULL },
313 	{ "suffixmassage", "virtual> <real", 2, 3, 0,
314 		ARG_MAGIC|LDAP_BACK_CFG_SUFFIXM,
315 		meta_back_cf_gen, NULL, NULL, NULL },
316 
317 	{ "map", "attribute|objectClass> [*|<local>] *|<remote", 3, 4, 0,
318 		ARG_MAGIC|LDAP_BACK_CFG_MAP,
319 		meta_back_cf_gen, "( OLcfgDbAt:3.102 "
320 			"NAME 'olcDbMap' "
321 			"DESC 'Map attribute and objectclass names' "
322 			"EQUALITY caseIgnoreMatch "
323 			"SYNTAX OMsDirectoryString "
324 			"X-ORDERED 'VALUES' )",
325 		NULL, NULL },
326 
327 	{ "subtree-exclude", "pattern", 2, 2, 0,
328 		ARG_MAGIC|LDAP_BACK_CFG_SUBTREE_EX,
329 		meta_back_cf_gen, "( OLcfgDbAt:3.103 "
330 			"NAME 'olcDbSubtreeExclude' "
331 			"DESC 'DN of subtree to exclude from target' "
332 			"EQUALITY caseIgnoreMatch "
333 			"SYNTAX OMsDirectoryString )",
334 		NULL, NULL },
335 	{ "subtree-include", "pattern", 2, 2, 0,
336 		ARG_MAGIC|LDAP_BACK_CFG_SUBTREE_IN,
337 		meta_back_cf_gen, "( OLcfgDbAt:3.104 "
338 			"NAME 'olcDbSubtreeInclude' "
339 			"DESC 'DN of subtree to include in target' "
340 			"EQUALITY caseIgnoreMatch "
341 			"SYNTAX OMsDirectoryString )",
342 		NULL, NULL },
343 	{ "default-target", "[none|<target ID>]", 1, 2, 0,
344 		ARG_MAGIC|LDAP_BACK_CFG_DEFAULT_T,
345 		meta_back_cf_gen, "( OLcfgDbAt:3.105 "
346 			"NAME 'olcDbDefaultTarget' "
347 			"DESC 'Specify the default target' "
348 			"SYNTAX OMsDirectoryString "
349 			"SINGLE-VALUE )",
350 		NULL, NULL },
351 	{ "dncache-ttl", "ttl", 2, 2, 0,
352 		ARG_MAGIC|LDAP_BACK_CFG_DNCACHE_TTL,
353 		meta_back_cf_gen, "( OLcfgDbAt:3.106 "
354 			"NAME 'olcDbDnCacheTtl' "
355 			"DESC 'dncache ttl' "
356 			"SYNTAX OMsDirectoryString "
357 			"SINGLE-VALUE )",
358 		NULL, NULL },
359 	{ "bind-timeout", "microseconds", 2, 2, 0,
360 		ARG_MAGIC|ARG_ULONG|LDAP_BACK_CFG_BIND_TIMEOUT,
361 		meta_back_cf_gen, "( OLcfgDbAt:3.107 "
362 			"NAME 'olcDbBindTimeout' "
363 			"DESC 'bind timeout' "
364 			"SYNTAX OMsDirectoryString "
365 			"SINGLE-VALUE )",
366 		NULL, NULL },
367 	{ "onerr", "CONTINUE|report|stop", 2, 2, 0,
368 		ARG_MAGIC|LDAP_BACK_CFG_ONERR,
369 		meta_back_cf_gen, "( OLcfgDbAt:3.108 "
370 			"NAME 'olcDbOnErr' "
371 			"DESC 'error handling' "
372 			"SYNTAX OMsDirectoryString "
373 			"SINGLE-VALUE )",
374 		NULL, NULL },
375 	{ "pseudoroot-bind-defer", "TRUE|false", 2, 2, 0,
376 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER,
377 		meta_back_cf_gen, "( OLcfgDbAt:3.109 "
378 			"NAME 'olcDbPseudoRootBindDefer' "
379 			"DESC 'error handling' "
380 			"SYNTAX OMsBoolean "
381 			"SINGLE-VALUE )",
382 		NULL, NULL },
383 	{ "root-bind-defer", "TRUE|false", 2, 2, 0,
384 		ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER,
385 		meta_back_cf_gen, NULL, NULL, NULL },
386 	{ "pseudorootdn", "dn", 2, 2, 0,
387 		ARG_MAGIC|ARG_DN|LDAP_BACK_CFG_PSEUDOROOTDN,
388 		meta_back_cf_gen, NULL, NULL, NULL },
389 	{ "pseudorootpw", "password", 2, 2, 0,
390 		ARG_MAGIC|ARG_STRING|LDAP_BACK_CFG_PSEUDOROOTDN,
391 		meta_back_cf_gen, NULL, NULL, NULL },
392 	{ "nretries", "NEVER|forever|<number>", 2, 2, 0,
393 		ARG_MAGIC|LDAP_BACK_CFG_NRETRIES,
394 		meta_back_cf_gen, "( OLcfgDbAt:3.110 "
395 			"NAME 'olcDbNretries' "
396 			"DESC 'retry handling' "
397 			"SYNTAX OMsDirectoryString "
398 			"SINGLE-VALUE )",
399 		NULL, NULL },
400 	{ "client-pr", "accept-unsolicited|disable|<size>", 2, 2, 0,
401 		ARG_MAGIC|LDAP_BACK_CFG_CLIENT_PR,
402 		meta_back_cf_gen, "( OLcfgDbAt:3.111 "
403 			"NAME 'olcDbClientPr' "
404 			"DESC 'PagedResults handling' "
405 			"SYNTAX OMsDirectoryString "
406 			"SINGLE-VALUE )",
407 		NULL, NULL },
408 
409 	{ "", "", 0, 0, 0, ARG_IGNORED,
410 		NULL, "( OLcfgDbAt:3.100 NAME 'olcMetaSub' "
411 			"DESC 'Placeholder to name a Target entry' "
412 			"EQUALITY caseIgnoreMatch "
413 			"SYNTAX OMsDirectoryString "
414 			"SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
415 
416 	{ "keepalive", "keepalive", 2, 2, 0,
417 		ARG_MAGIC|LDAP_BACK_CFG_KEEPALIVE,
418 		meta_back_cf_gen, "( OLcfgDbAt:3.29 "
419 			"NAME 'olcDbKeepalive' "
420 			"DESC 'TCP keepalive' "
421 			"SYNTAX OMsDirectoryString "
422 			"SINGLE-VALUE )",
423 		NULL, NULL },
424 
425 	{ "filter", "pattern", 2, 2, 0,
426 		ARG_MAGIC|LDAP_BACK_CFG_FILTER,
427 		meta_back_cf_gen, "( OLcfgDbAt:3.112 "
428 			"NAME 'olcDbFilter' "
429 			"DESC 'Filter regex pattern to include in target' "
430 			"EQUALITY caseExactMatch "
431 			"SYNTAX OMsDirectoryString )",
432 		NULL, NULL },
433 
434 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED,
435 		NULL, NULL, NULL, NULL }
436 };
437 
438 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
439 #define	ST_ATTR "$ olcDbSessionTrackingRequest "
440 #else
441 #define	ST_ATTR ""
442 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
443 
444 #define COMMON_ATTRS	\
445 			"$ olcDbBindTimeout " \
446 			"$ olcDbCancel " \
447 			"$ olcDbChaseReferrals " \
448 			"$ olcDbClientPr " \
449 			"$ olcDbDefaultTarget " \
450 			"$ olcDbNetworkTimeout " \
451 			"$ olcDbNoRefs " \
452 			"$ olcDbNoUndefFilter " \
453 			"$ olcDbNretries " \
454 			"$ olcDbProtocolVersion " \
455 			"$ olcDbQuarantine " \
456 			"$ olcDbRebindAsUser " \
457 			ST_ATTR \
458 			"$ olcDbStartTLS " \
459 			"$ olcDbTFSupport "
460 
461 static ConfigOCs metaocs[] = {
462 	{ "( OLcfgDbOc:3.2 "
463 		"NAME 'olcMetaConfig' "
464 		"DESC 'Meta backend configuration' "
465 		"SUP olcDatabaseConfig "
466 		"MAY ( olcDbConnTtl "
467 			"$ olcDbDnCacheTtl "
468 			"$ olcDbIdleTimeout "
469 			"$ olcDbOnErr "
470 			"$ olcDbPseudoRootBindDefer "
471 			"$ olcDbSingleConn "
472 			"$ olcDbUseTemporaryConn "
473 			"$ olcDbConnectionPoolMax "
474 
475 			/* defaults, may be overridden per-target */
476 			COMMON_ATTRS
477 		") )",
478 			Cft_Database, metacfg, NULL, meta_cfadd },
479 	{ "( OLcfgDbOc:3.3 "
480 		"NAME 'olcMetaTargetConfig' "
481 		"DESC 'Meta target configuration' "
482 		"SUP olcConfig STRUCTURAL "
483 		"MUST ( olcMetaSub $ olcDbURI ) "
484 		"MAY ( olcDbACLAuthcDn "
485 			"$ olcDbACLPasswd "
486 			"$ olcDbIDAssertAuthzFrom "
487 			"$ olcDbIDAssertBind "
488 			"$ olcDbMap "
489 			"$ olcDbRewrite "
490 			"$ olcDbSubtreeExclude "
491 			"$ olcDbSubtreeInclude "
492 			"$ olcDbTimeout "
493 			"$ olcDbKeepalive "
494 			"$ olcDbFilter "
495 
496 			/* defaults may be inherited */
497 			COMMON_ATTRS
498 		") )",
499 			Cft_Misc, metacfg, meta_ldadd },
500 	{ NULL, 0, NULL }
501 };
502 
503 static int
504 meta_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *c )
505 {
506 	if ( p->ce_type != Cft_Database || !p->ce_be ||
507 		p->ce_be->be_cf_ocs != metaocs )
508 		return LDAP_CONSTRAINT_VIOLATION;
509 
510 	c->be = p->ce_be;
511 	return LDAP_SUCCESS;
512 }
513 
514 static int
515 meta_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *c )
516 {
517 	metainfo_t	*mi = ( metainfo_t * )c->be->be_private;
518 	struct berval bv;
519 	int i;
520 
521 	bv.bv_val = c->cr_msg;
522 	for ( i=0; i<mi->mi_ntargets; i++ ) {
523 		bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg),
524 			"olcMetaSub=" SLAP_X_ORDERED_FMT "uri", i );
525 		c->ca_private = mi->mi_targets[i];
526 		c->valx = i;
527 		config_build_entry( op, rs, p->e_private, c,
528 			&bv, &metaocs[1], NULL );
529 	}
530 
531 	return LDAP_SUCCESS;
532 }
533 
534 static int
535 meta_rwi_init( struct rewrite_info **rwm_rw )
536 {
537 	char			*rargv[ 3 ];
538 
539 	*rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
540 	if ( *rwm_rw == NULL ) {
541 		return -1;
542 	}
543 	/*
544 	 * the filter rewrite as a string must be disabled
545 	 * by default; it can be re-enabled by adding rules;
546 	 * this creates an empty rewriteContext
547 	 */
548 	rargv[ 0 ] = "rewriteContext";
549 	rargv[ 1 ] = "searchFilter";
550 	rargv[ 2 ] = NULL;
551 	rewrite_parse( *rwm_rw, "<suffix massage>", 1, 2, rargv );
552 
553 	rargv[ 0 ] = "rewriteContext";
554 	rargv[ 1 ] = "default";
555 	rargv[ 2 ] = NULL;
556 	rewrite_parse( *rwm_rw, "<suffix massage>", 1, 2, rargv );
557 
558 	return 0;
559 }
560 
561 static int
562 meta_back_new_target(
563 	metatarget_t	**mtp )
564 {
565 	metatarget_t		*mt;
566 
567 	*mtp = NULL;
568 
569 	mt = ch_calloc( sizeof( metatarget_t ), 1 );
570 
571 	if ( meta_rwi_init( &mt->mt_rwmap.rwm_rw )) {
572 		ch_free( mt );
573 		return -1;
574 	}
575 
576 	ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex );
577 
578 	mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY;
579 	mt->mt_idassert_authmethod = LDAP_AUTH_NONE;
580 	mt->mt_idassert_tls = SB_TLS_DEFAULT;
581 
582 	/* by default, use proxyAuthz control on each operation */
583 	mt->mt_idassert_flags = LDAP_BACK_AUTH_PRESCRIPTIVE;
584 
585 	*mtp = mt;
586 
587 	return 0;
588 }
589 
590 /* Validation for suffixmassage_config */
591 static int
592 meta_suffixm_config(
593 	ConfigArgs *c,
594 	int argc,
595 	char **argv,
596 	metatarget_t *mt
597 )
598 {
599 	BackendDB 	*tmp_bd;
600 	struct berval	dn, nvnc, pvnc, nrnc, prnc;
601 	int j, rc;
602 
603 	/*
604 	 * syntax:
605 	 *
606 	 * 	suffixmassage <suffix> <massaged suffix>
607 	 *
608 	 * the <suffix> field must be defined as a valid suffix
609 	 * (or suffixAlias?) for the current database;
610 	 * the <massaged suffix> shouldn't have already been
611 	 * defined as a valid suffix or suffixAlias for the
612 	 * current server
613 	 */
614 
615 	ber_str2bv( argv[ 1 ], 0, 0, &dn );
616 	if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
617 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
618 			"suffix \"%s\" is invalid",
619 			argv[1] );
620 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
621 		return 1;
622 	}
623 
624 	for ( j = 0; !BER_BVISNULL( &c->be->be_nsuffix[ j ] ); j++ ) {
625 		if ( dnIsSuffix( &nvnc, &c->be->be_nsuffix[ 0 ] ) ) {
626 			break;
627 		}
628 	}
629 
630 	if ( BER_BVISNULL( &c->be->be_nsuffix[ j ] ) ) {
631 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
632 			"suffix \"%s\" must be within the database naming context",
633 			argv[1] );
634 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
635 		free( pvnc.bv_val );
636 		free( nvnc.bv_val );
637 		return 1;
638 	}
639 
640 	ber_str2bv( argv[ 2 ], 0, 0, &dn );
641 	if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
642 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
643 			"massaged suffix \"%s\" is invalid",
644 			argv[2] );
645 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
646 		free( pvnc.bv_val );
647 		free( nvnc.bv_val );
648 		return 1;
649 	}
650 
651 	tmp_bd = select_backend( &nrnc, 0 );
652 	if ( tmp_bd != NULL && tmp_bd->be_private == c->be->be_private ) {
653 		Debug( LDAP_DEBUG_ANY,
654 	"%s: warning: <massaged suffix> \"%s\" resolves to this database, in "
655 	"\"suffixMassage <suffix> <massaged suffix>\"\n",
656 			c->log, prnc.bv_val, 0 );
657 	}
658 
659 	/*
660 	 * The suffix massaging is emulated by means of the
661 	 * rewrite capabilities
662 	 */
663 	rc = suffix_massage_config( mt->mt_rwmap.rwm_rw,
664 			&pvnc, &nvnc, &prnc, &nrnc );
665 
666 	free( pvnc.bv_val );
667 	free( nvnc.bv_val );
668 	free( prnc.bv_val );
669 	free( nrnc.bv_val );
670 
671 	return rc;
672 }
673 
674 static int
675 slap_bv_x_ordered_unparse( BerVarray in, BerVarray *out )
676 {
677 	int		i;
678 	BerVarray	bva = NULL;
679 	char		ibuf[32], *ptr;
680 	struct berval	idx;
681 
682 	assert( in != NULL );
683 
684 	for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
685 		/* count'em */ ;
686 
687 	if ( i == 0 ) {
688 		return 1;
689 	}
690 
691 	idx.bv_val = ibuf;
692 
693 	bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
694 	BER_BVZERO( &bva[ 0 ] );
695 
696 	for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
697 		idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
698 		if ( idx.bv_len >= sizeof( ibuf ) ) {
699 			ber_bvarray_free( bva );
700 			return 1;
701 		}
702 
703 		bva[i].bv_len = idx.bv_len + in[i].bv_len;
704 		bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
705 		ptr = lutil_strcopy( bva[i].bv_val, ibuf );
706 		ptr = lutil_strcopy( ptr, in[i].bv_val );
707 		*ptr = '\0';
708 		BER_BVZERO( &bva[ i + 1 ] );
709 	}
710 
711 	*out = bva;
712 	return 0;
713 }
714 
715 int
716 meta_subtree_free( metasubtree_t *ms )
717 {
718 	switch ( ms->ms_type ) {
719 	case META_ST_SUBTREE:
720 	case META_ST_SUBORDINATE:
721 		ber_memfree( ms->ms_dn.bv_val );
722 		break;
723 
724 	case META_ST_REGEX:
725 		regfree( &ms->ms_regex );
726 		ber_memfree( ms->ms_regex_pattern.bv_val );
727 		break;
728 
729 	default:
730 		return -1;
731 	}
732 
733 	ch_free( ms );
734 	return 0;
735 }
736 
737 int
738 meta_subtree_destroy( metasubtree_t *ms )
739 {
740 	if ( ms->ms_next ) {
741 		meta_subtree_destroy( ms->ms_next );
742 	}
743 
744 	return meta_subtree_free( ms );
745 }
746 
747 static void
748 meta_filter_free( metafilter_t *mf )
749 {
750 	regfree( &mf->mf_regex );
751 	ber_memfree( mf->mf_regex_pattern.bv_val );
752 	ch_free( mf );
753 }
754 
755 void
756 meta_filter_destroy( metafilter_t *mf )
757 {
758 	if ( mf->mf_next )
759 		meta_filter_destroy( mf->mf_next );
760 	meta_filter_free( mf );
761 }
762 
763 static struct berval st_styles[] = {
764 	BER_BVC("subtree"),
765 	BER_BVC("children"),
766 	BER_BVC("regex")
767 };
768 
769 static int
770 meta_subtree_unparse(
771 	ConfigArgs *c,
772 	metatarget_t *mt )
773 {
774 	metasubtree_t	*ms;
775 	struct berval bv, *style;
776 
777 	if ( !mt->mt_subtree )
778 		return 1;
779 
780 	/* can only be one of exclude or include */
781 	if (( c->type == LDAP_BACK_CFG_SUBTREE_EX ) ^ mt->mt_subtree_exclude )
782 		return 1;
783 
784 	bv.bv_val = c->cr_msg;
785 	for ( ms=mt->mt_subtree; ms; ms=ms->ms_next ) {
786 		if (ms->ms_type == META_ST_SUBTREE)
787 			style = &st_styles[0];
788 		else if ( ms->ms_type == META_ST_SUBORDINATE )
789 			style = &st_styles[1];
790 		else if ( ms->ms_type == META_ST_REGEX )
791 			style = &st_styles[2];
792 		else {
793 			assert(0);
794 			continue;
795 		}
796 		bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg),
797 			"dn.%s:%s", style->bv_val, ms->ms_dn.bv_val );
798 		value_add_one( &c->rvalue_vals, &bv );
799 	}
800 	return 0;
801 }
802 
803 static int
804 meta_subtree_config(
805 	metatarget_t *mt,
806 	ConfigArgs *c )
807 {
808 	meta_st_t	type = META_ST_SUBTREE;
809 	char		*pattern;
810 	struct berval	ndn = BER_BVNULL;
811 	metasubtree_t	*ms = NULL;
812 
813 	if ( c->type == LDAP_BACK_CFG_SUBTREE_EX ) {
814 		if ( mt->mt_subtree && !mt->mt_subtree_exclude ) {
815 			snprintf( c->cr_msg, sizeof(c->cr_msg),
816 				"\"subtree-exclude\" incompatible with previous \"subtree-include\" directives" );
817 			return 1;
818 		}
819 
820 		mt->mt_subtree_exclude = 1;
821 
822 	} else {
823 		if ( mt->mt_subtree && mt->mt_subtree_exclude ) {
824 			snprintf( c->cr_msg, sizeof(c->cr_msg),
825 				"\"subtree-include\" incompatible with previous \"subtree-exclude\" directives" );
826 			return 1;
827 		}
828 	}
829 
830 	pattern = c->argv[1];
831 	if ( strncasecmp( pattern, "dn", STRLENOF( "dn" ) ) == 0 ) {
832 		char *style;
833 
834 		pattern = &pattern[STRLENOF( "dn")];
835 
836 		if ( pattern[0] == '.' ) {
837 			style = &pattern[1];
838 
839 			if ( strncasecmp( style, "subtree", STRLENOF( "subtree" ) ) == 0 ) {
840 				type = META_ST_SUBTREE;
841 				pattern = &style[STRLENOF( "subtree" )];
842 
843 			} else if ( strncasecmp( style, "children", STRLENOF( "children" ) ) == 0 ) {
844 				type = META_ST_SUBORDINATE;
845 				pattern = &style[STRLENOF( "children" )];
846 
847 			} else if ( strncasecmp( style, "sub", STRLENOF( "sub" ) ) == 0 ) {
848 				type = META_ST_SUBTREE;
849 				pattern = &style[STRLENOF( "sub" )];
850 
851 			} else if ( strncasecmp( style, "regex", STRLENOF( "regex" ) ) == 0 ) {
852 				type = META_ST_REGEX;
853 				pattern = &style[STRLENOF( "regex" )];
854 
855 			} else {
856 				snprintf( c->cr_msg, sizeof(c->cr_msg), "unknown style in \"dn.<style>\"" );
857 				return 1;
858 			}
859 		}
860 
861 		if ( pattern[0] != ':' ) {
862 			snprintf( c->cr_msg, sizeof(c->cr_msg), "missing colon after \"dn.<style>\"" );
863 			return 1;
864 		}
865 		pattern++;
866 	}
867 
868 	switch ( type ) {
869 	case META_ST_SUBTREE:
870 	case META_ST_SUBORDINATE: {
871 		struct berval dn;
872 
873 		ber_str2bv( pattern, 0, 0, &dn );
874 		if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL )
875 			!= LDAP_SUCCESS )
876 		{
877 			snprintf( c->cr_msg, sizeof(c->cr_msg), "DN=\"%s\" is invalid", pattern );
878 			return 1;
879 		}
880 
881 		if ( !dnIsSuffix( &ndn, &mt->mt_nsuffix ) ) {
882 			snprintf( c->cr_msg, sizeof(c->cr_msg),
883 				"DN=\"%s\" is not a subtree of target \"%s\"",
884 				pattern, mt->mt_nsuffix.bv_val );
885 			ber_memfree( ndn.bv_val );
886 			return( 1 );
887 		}
888 		} break;
889 
890 	default:
891 		/* silence warnings */
892 		break;
893 	}
894 
895 	ms = ch_calloc( sizeof( metasubtree_t ), 1 );
896 	ms->ms_type = type;
897 
898 	switch ( ms->ms_type ) {
899 	case META_ST_SUBTREE:
900 	case META_ST_SUBORDINATE:
901 		ms->ms_dn = ndn;
902 		break;
903 
904 	case META_ST_REGEX: {
905 		int rc;
906 
907 		rc = regcomp( &ms->ms_regex, pattern, REG_EXTENDED|REG_ICASE );
908 		if ( rc != 0 ) {
909 			char regerr[ SLAP_TEXT_BUFLEN ];
910 
911 			regerror( rc, &ms->ms_regex, regerr, sizeof(regerr) );
912 
913 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
914 				"regular expression \"%s\" bad because of %s",
915 				pattern, regerr );
916 			ch_free( ms );
917 			return 1;
918 		}
919 		ber_str2bv( pattern, 0, 1, &ms->ms_regex_pattern );
920 		} break;
921 	}
922 
923 	if ( mt->mt_subtree == NULL ) {
924 		 mt->mt_subtree = ms;
925 
926 	} else {
927 		metasubtree_t **msp;
928 
929 		for ( msp = &mt->mt_subtree; *msp; ) {
930 			switch ( ms->ms_type ) {
931 			case META_ST_SUBTREE:
932 				switch ( (*msp)->ms_type ) {
933 				case META_ST_SUBTREE:
934 					if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
935 						metasubtree_t *tmp = *msp;
936 						Debug( LDAP_DEBUG_CONFIG,
937 							"%s: previous rule \"dn.subtree:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
938 							c->log, pattern, (*msp)->ms_dn.bv_val );
939 						*msp = (*msp)->ms_next;
940 						tmp->ms_next = NULL;
941 						meta_subtree_destroy( tmp );
942 						continue;
943 
944 					} else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) ) {
945 						Debug( LDAP_DEBUG_CONFIG,
946 							"%s: previous rule \"dn.subtree:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
947 							c->log, (*msp)->ms_dn.bv_val, pattern );
948 						meta_subtree_destroy( ms );
949 						ms = NULL;
950 						return( 0 );
951 					}
952 					break;
953 
954 				case META_ST_SUBORDINATE:
955 					if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
956 						metasubtree_t *tmp = *msp;
957 						Debug( LDAP_DEBUG_CONFIG,
958 							"%s: previous rule \"dn.children:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
959 							c->log, pattern, (*msp)->ms_dn.bv_val );
960 						*msp = (*msp)->ms_next;
961 						tmp->ms_next = NULL;
962 						meta_subtree_destroy( tmp );
963 						continue;
964 
965 					} else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) && ms->ms_dn.bv_len > (*msp)->ms_dn.bv_len ) {
966 						Debug( LDAP_DEBUG_CONFIG,
967 							"%s: previous rule \"dn.children:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
968 							c->log, (*msp)->ms_dn.bv_val, pattern );
969 						meta_subtree_destroy( ms );
970 						ms = NULL;
971 						return( 0 );
972 					}
973 					break;
974 
975 				case META_ST_REGEX:
976 					if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
977 						Debug( LDAP_DEBUG_CONFIG,
978 							"%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n",
979 							c->log, (*msp)->ms_regex_pattern.bv_val, ms->ms_dn.bv_val );
980 					}
981 					break;
982 				}
983 				break;
984 
985 			case META_ST_SUBORDINATE:
986 				switch ( (*msp)->ms_type ) {
987 				case META_ST_SUBTREE:
988 					if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
989 						metasubtree_t *tmp = *msp;
990 						Debug( LDAP_DEBUG_CONFIG,
991 							"%s: previous rule \"dn.children:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
992 							c->log, pattern, (*msp)->ms_dn.bv_val );
993 						*msp = (*msp)->ms_next;
994 						tmp->ms_next = NULL;
995 						meta_subtree_destroy( tmp );
996 						continue;
997 
998 					} else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) && ms->ms_dn.bv_len > (*msp)->ms_dn.bv_len ) {
999 						Debug( LDAP_DEBUG_CONFIG,
1000 							"%s: previous rule \"dn.children:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
1001 							c->log, (*msp)->ms_dn.bv_val, pattern );
1002 						meta_subtree_destroy( ms );
1003 						ms = NULL;
1004 						return( 0 );
1005 					}
1006 					break;
1007 
1008 				case META_ST_SUBORDINATE:
1009 					if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
1010 						metasubtree_t *tmp = *msp;
1011 						Debug( LDAP_DEBUG_CONFIG,
1012 							"%s: previous rule \"dn.children:%s\" is contained in rule \"dn.children:%s\" (replaced)\n",
1013 							c->log, pattern, (*msp)->ms_dn.bv_val );
1014 						*msp = (*msp)->ms_next;
1015 						tmp->ms_next = NULL;
1016 						meta_subtree_destroy( tmp );
1017 						continue;
1018 
1019 					} else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) ) {
1020 						Debug( LDAP_DEBUG_CONFIG,
1021 							"%s: previous rule \"dn.children:%s\" contains rule \"dn.children:%s\" (ignored)\n",
1022 							c->log, (*msp)->ms_dn.bv_val, pattern );
1023 						meta_subtree_destroy( ms );
1024 						ms = NULL;
1025 						return( 0 );
1026 					}
1027 					break;
1028 
1029 				case META_ST_REGEX:
1030 					if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
1031 						Debug( LDAP_DEBUG_CONFIG,
1032 							"%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n",
1033 							c->log, (*msp)->ms_regex_pattern.bv_val, ms->ms_dn.bv_val );
1034 					}
1035 					break;
1036 				}
1037 				break;
1038 
1039 			case META_ST_REGEX:
1040 				switch ( (*msp)->ms_type ) {
1041 				case META_ST_SUBTREE:
1042 				case META_ST_SUBORDINATE:
1043 					if ( regexec( &ms->ms_regex, (*msp)->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
1044 						Debug( LDAP_DEBUG_CONFIG,
1045 							"%s: previous rule \"dn.subtree:%s\" may be contained in rule \"dn.regex:%s\"\n",
1046 							c->log, (*msp)->ms_dn.bv_val, ms->ms_regex_pattern.bv_val );
1047 					}
1048 					break;
1049 
1050 				case META_ST_REGEX:
1051 					/* no check possible */
1052 					break;
1053 				}
1054 				break;
1055 			}
1056 
1057 			msp = &(*msp)->ms_next;
1058 		}
1059 
1060 		*msp = ms;
1061 	}
1062 
1063 	return 0;
1064 }
1065 
1066 static slap_verbmasks idassert_mode[] = {
1067 	{ BER_BVC("self"),		LDAP_BACK_IDASSERT_SELF },
1068 	{ BER_BVC("anonymous"),		LDAP_BACK_IDASSERT_ANONYMOUS },
1069 	{ BER_BVC("none"),		LDAP_BACK_IDASSERT_NOASSERT },
1070 	{ BER_BVC("legacy"),		LDAP_BACK_IDASSERT_LEGACY },
1071 	{ BER_BVNULL,			0 }
1072 };
1073 
1074 static slap_verbmasks tls_mode[] = {
1075 	{ BER_BVC( "propagate" ),	LDAP_BACK_F_TLS_PROPAGATE_MASK },
1076 	{ BER_BVC( "try-propagate" ),	LDAP_BACK_F_PROPAGATE_TLS },
1077 	{ BER_BVC( "start" ),		LDAP_BACK_F_TLS_USE_MASK },
1078 	{ BER_BVC( "try-start" ),	LDAP_BACK_F_USE_TLS },
1079 	{ BER_BVC( "ldaps" ),		LDAP_BACK_F_TLS_LDAPS },
1080 	{ BER_BVC( "none" ),		LDAP_BACK_F_NONE },
1081 	{ BER_BVNULL,			0 }
1082 };
1083 
1084 static slap_verbmasks t_f_mode[] = {
1085 	{ BER_BVC( "yes" ),		LDAP_BACK_F_T_F },
1086 	{ BER_BVC( "discover" ),	LDAP_BACK_F_T_F_DISCOVER },
1087 	{ BER_BVC( "no" ),		LDAP_BACK_F_NONE },
1088 	{ BER_BVNULL,			0 }
1089 };
1090 
1091 static slap_verbmasks cancel_mode[] = {
1092 	{ BER_BVC( "ignore" ),		LDAP_BACK_F_CANCEL_IGNORE },
1093 	{ BER_BVC( "exop" ),		LDAP_BACK_F_CANCEL_EXOP },
1094 	{ BER_BVC( "exop-discover" ),	LDAP_BACK_F_CANCEL_EXOP_DISCOVER },
1095 	{ BER_BVC( "abandon" ),		LDAP_BACK_F_CANCEL_ABANDON },
1096 	{ BER_BVNULL,			0 }
1097 };
1098 
1099 static slap_verbmasks onerr_mode[] = {
1100 	{ BER_BVC( "stop" ),		META_BACK_F_ONERR_STOP },
1101 	{ BER_BVC( "report" ),	META_BACK_F_ONERR_REPORT },
1102 	{ BER_BVC( "continue" ),		LDAP_BACK_F_NONE },
1103 	{ BER_BVNULL,			0 }
1104 };
1105 
1106 /* see enum in slap.h */
1107 static slap_cf_aux_table timeout_table[] = {
1108 	{ BER_BVC("bind="),	SLAP_OP_BIND * sizeof( time_t ),	'u', 0, NULL },
1109 	/* unbind makes no sense */
1110 	{ BER_BVC("add="),	SLAP_OP_ADD * sizeof( time_t ),		'u', 0, NULL },
1111 	{ BER_BVC("delete="),	SLAP_OP_DELETE * sizeof( time_t ),	'u', 0, NULL },
1112 	{ BER_BVC("modrdn="),	SLAP_OP_MODRDN * sizeof( time_t ),	'u', 0, NULL },
1113 	{ BER_BVC("modify="),	SLAP_OP_MODIFY * sizeof( time_t ),	'u', 0, NULL },
1114 	{ BER_BVC("compare="),	SLAP_OP_COMPARE * sizeof( time_t ),	'u', 0, NULL },
1115 	{ BER_BVC("search="),	SLAP_OP_SEARCH * sizeof( time_t ),	'u', 0, NULL },
1116 	/* abandon makes little sense */
1117 #if 0	/* not implemented yet */
1118 	{ BER_BVC("extended="),	SLAP_OP_EXTENDED * sizeof( time_t ),	'u', 0, NULL },
1119 #endif
1120 	{ BER_BVNULL, 0, 0, 0, NULL }
1121 };
1122 
1123 static int
1124 meta_cf_cleanup( ConfigArgs *c )
1125 {
1126 	metainfo_t	*mi = ( metainfo_t * )c->be->be_private;
1127 	metatarget_t	*mt = c->ca_private;
1128 
1129 	return meta_target_finish( mi, mt, c->log, c->cr_msg, sizeof( c->cr_msg ));
1130 }
1131 
1132 static int
1133 meta_back_cf_gen( ConfigArgs *c )
1134 {
1135 	metainfo_t	*mi = ( metainfo_t * )c->be->be_private;
1136 	metatarget_t	*mt;
1137 	metacommon_t	*mc;
1138 
1139 	int i, rc = 0;
1140 
1141 	assert( mi != NULL );
1142 
1143 	if ( c->op == SLAP_CONFIG_EMIT || c->op == LDAP_MOD_DELETE ) {
1144 		if ( !mi )
1145 			return 1;
1146 
1147 		if ( c->table == Cft_Database ) {
1148 			mt = NULL;
1149 			mc = &mi->mi_mc;
1150 		} else {
1151 			mt = c->ca_private;
1152 			mc = &mt->mt_mc;
1153 		}
1154 	}
1155 
1156 	if ( c->op == SLAP_CONFIG_EMIT ) {
1157 		struct berval bv = BER_BVNULL;
1158 
1159 		switch( c->type ) {
1160 		/* Base attrs */
1161 		case LDAP_BACK_CFG_CONN_TTL:
1162 			if ( mi->mi_conn_ttl == 0 ) {
1163 				return 1;
1164 			} else {
1165 				char	buf[ SLAP_TEXT_BUFLEN ];
1166 
1167 				lutil_unparse_time( buf, sizeof( buf ), mi->mi_conn_ttl );
1168 				ber_str2bv( buf, 0, 0, &bv );
1169 				value_add_one( &c->rvalue_vals, &bv );
1170 			}
1171 			break;
1172 
1173 		case LDAP_BACK_CFG_DNCACHE_TTL:
1174 			if ( mi->mi_cache.ttl == META_DNCACHE_DISABLED ) {
1175 				return 1;
1176 			} else if ( mi->mi_cache.ttl == META_DNCACHE_FOREVER ) {
1177 				BER_BVSTR( &bv, "forever" );
1178 			} else {
1179 				char	buf[ SLAP_TEXT_BUFLEN ];
1180 
1181 				lutil_unparse_time( buf, sizeof( buf ), mi->mi_cache.ttl );
1182 				ber_str2bv( buf, 0, 0, &bv );
1183 			}
1184 			value_add_one( &c->rvalue_vals, &bv );
1185 			break;
1186 
1187 		case LDAP_BACK_CFG_IDLE_TIMEOUT:
1188 			if ( mi->mi_idle_timeout == 0 ) {
1189 				return 1;
1190 			} else {
1191 				char	buf[ SLAP_TEXT_BUFLEN ];
1192 
1193 				lutil_unparse_time( buf, sizeof( buf ), mi->mi_idle_timeout );
1194 				ber_str2bv( buf, 0, 0, &bv );
1195 				value_add_one( &c->rvalue_vals, &bv );
1196 			}
1197 			break;
1198 
1199 		case LDAP_BACK_CFG_ONERR:
1200 			enum_to_verb( onerr_mode, mi->mi_flags & META_BACK_F_ONERR_MASK, &bv );
1201 			if ( BER_BVISNULL( &bv )) {
1202 				rc = 1;
1203 			} else {
1204 				value_add_one( &c->rvalue_vals, &bv );
1205 			}
1206 			break;
1207 
1208 		case LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER:
1209 			c->value_int = META_BACK_DEFER_ROOTDN_BIND( mi );
1210 			break;
1211 
1212 		case LDAP_BACK_CFG_SINGLECONN:
1213 			c->value_int = LDAP_BACK_SINGLECONN( mi );
1214 			break;
1215 
1216 		case LDAP_BACK_CFG_USETEMP:
1217 			c->value_int = LDAP_BACK_USE_TEMPORARIES( mi );
1218 			break;
1219 
1220 		case LDAP_BACK_CFG_CONNPOOLMAX:
1221 			c->value_int = mi->mi_conn_priv_max;
1222 			break;
1223 
1224 		/* common attrs */
1225 		case LDAP_BACK_CFG_BIND_TIMEOUT:
1226 			if ( mc->mc_bind_timeout.tv_sec == 0 &&
1227 				mc->mc_bind_timeout.tv_usec == 0 ) {
1228 				return 1;
1229 			} else {
1230 				c->value_ulong = mc->mc_bind_timeout.tv_sec * 1000000UL +
1231 					mc->mc_bind_timeout.tv_usec;
1232 			}
1233 			break;
1234 
1235 		case LDAP_BACK_CFG_CANCEL: {
1236 			slap_mask_t	mask = LDAP_BACK_F_CANCEL_MASK2;
1237 
1238 			if ( mt && META_BACK_TGT_CANCEL_DISCOVER( mt ) ) {
1239 				mask &= ~LDAP_BACK_F_CANCEL_EXOP;
1240 			}
1241 			enum_to_verb( cancel_mode, (mc->mc_flags & mask), &bv );
1242 			if ( BER_BVISNULL( &bv ) ) {
1243 				/* there's something wrong... */
1244 				assert( 0 );
1245 				rc = 1;
1246 
1247 			} else {
1248 				value_add_one( &c->rvalue_vals, &bv );
1249 			}
1250 			} break;
1251 
1252 		case LDAP_BACK_CFG_CHASE:
1253 			c->value_int = META_BACK_CMN_CHASE_REFERRALS(mc);
1254 			break;
1255 
1256 #ifdef SLAPD_META_CLIENT_PR
1257 		case LDAP_BACK_CFG_CLIENT_PR:
1258 			if ( mc->mc_ps == META_CLIENT_PR_DISABLE ) {
1259 				return 1;
1260 			} else if ( mc->mc_ps == META_CLIENT_PR_ACCEPT_UNSOLICITED ) {
1261 				BER_BVSTR( &bv, "accept-unsolicited" );
1262 			} else {
1263 				bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%d", mc->mc_ps );
1264 				bv.bv_val = c->cr_msg;
1265 			}
1266 			value_add_one( &c->rvalue_vals, &bv );
1267 			break;
1268 #endif /* SLAPD_META_CLIENT_PR */
1269 
1270 		case LDAP_BACK_CFG_DEFAULT_T:
1271 			if ( mt || mi->mi_defaulttarget == META_DEFAULT_TARGET_NONE )
1272 				return 1;
1273 			bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%d", mi->mi_defaulttarget );
1274 			bv.bv_val = c->cr_msg;
1275 			value_add_one( &c->rvalue_vals, &bv );
1276 			break;
1277 
1278 		case LDAP_BACK_CFG_NETWORK_TIMEOUT:
1279 			if ( mc->mc_network_timeout == 0 ) {
1280 				return 1;
1281 			}
1282 			bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%ld",
1283 				mc->mc_network_timeout );
1284 			bv.bv_val = c->cr_msg;
1285 			value_add_one( &c->rvalue_vals, &bv );
1286 			break;
1287 
1288 		case LDAP_BACK_CFG_NOREFS:
1289 			c->value_int = META_BACK_CMN_NOREFS(mc);
1290 			break;
1291 
1292 		case LDAP_BACK_CFG_NOUNDEFFILTER:
1293 			c->value_int = META_BACK_CMN_NOUNDEFFILTER(mc);
1294 			break;
1295 
1296 		case LDAP_BACK_CFG_NRETRIES:
1297 			if ( mc->mc_nretries == META_RETRY_FOREVER ) {
1298 				BER_BVSTR( &bv, "forever" );
1299 			} else if ( mc->mc_nretries == META_RETRY_NEVER ) {
1300 				BER_BVSTR( &bv, "never" );
1301 			} else {
1302 				bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "%d",
1303 					mc->mc_nretries );
1304 				bv.bv_val = c->cr_msg;
1305 			}
1306 			value_add_one( &c->rvalue_vals, &bv );
1307 			break;
1308 
1309 		case LDAP_BACK_CFG_QUARANTINE:
1310 			if ( !META_BACK_CMN_QUARANTINE( mc )) {
1311 				rc = 1;
1312 				break;
1313 			}
1314 			rc = mi->mi_ldap_extra->retry_info_unparse( &mc->mc_quarantine, &bv );
1315 			if ( rc == 0 ) {
1316 				ber_bvarray_add( &c->rvalue_vals, &bv );
1317 			}
1318 			break;
1319 
1320 		case LDAP_BACK_CFG_REBIND:
1321 			c->value_int = META_BACK_CMN_SAVECRED(mc);
1322 			break;
1323 
1324 		case LDAP_BACK_CFG_TIMEOUT:
1325 			for ( i = 0; i < SLAP_OP_LAST; i++ ) {
1326 				if ( mc->mc_timeout[ i ] != 0 ) {
1327 					break;
1328 				}
1329 			}
1330 
1331 			if ( i == SLAP_OP_LAST ) {
1332 				return 1;
1333 			}
1334 
1335 			BER_BVZERO( &bv );
1336 			slap_cf_aux_table_unparse( mc->mc_timeout, &bv, timeout_table );
1337 
1338 			if ( BER_BVISNULL( &bv ) ) {
1339 				return 1;
1340 			}
1341 
1342 			for ( i = 0; isspace( (unsigned char) bv.bv_val[ i ] ); i++ )
1343 				/* count spaces */ ;
1344 
1345 			if ( i ) {
1346 				bv.bv_len -= i;
1347 				AC_MEMCPY( bv.bv_val, &bv.bv_val[ i ],
1348 					bv.bv_len + 1 );
1349 			}
1350 
1351 			ber_bvarray_add( &c->rvalue_vals, &bv );
1352 			break;
1353 
1354 		case LDAP_BACK_CFG_VERSION:
1355 			if ( mc->mc_version == 0 )
1356 				return 1;
1357 			c->value_int = mc->mc_version;
1358 			break;
1359 
1360 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1361 		case LDAP_BACK_CFG_ST_REQUEST:
1362 			c->value_int = META_BACK_CMN_ST_REQUEST( mc );
1363 			break;
1364 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1365 
1366 		case LDAP_BACK_CFG_T_F:
1367 			enum_to_verb( t_f_mode, (mc->mc_flags & LDAP_BACK_F_T_F_MASK2), &bv );
1368 			if ( BER_BVISNULL( &bv ) ) {
1369 				/* there's something wrong... */
1370 				assert( 0 );
1371 				rc = 1;
1372 
1373 			} else {
1374 				value_add_one( &c->rvalue_vals, &bv );
1375 			}
1376 			break;
1377 
1378 		case LDAP_BACK_CFG_TLS: {
1379 			struct berval bc = BER_BVNULL, bv2;
1380 
1381 			if (( mc->mc_flags & LDAP_BACK_F_TLS_MASK ) == LDAP_BACK_F_NONE ) {
1382 				rc = 1;
1383 				break;
1384 			}
1385 			enum_to_verb( tls_mode, ( mc->mc_flags & LDAP_BACK_F_TLS_MASK ), &bv );
1386 			assert( !BER_BVISNULL( &bv ) );
1387 
1388 			if ( mt ) {
1389 				bindconf_tls_unparse( &mt->mt_tls, &bc );
1390 			}
1391 
1392 			if ( !BER_BVISEMPTY( &bc )) {
1393 				bv2.bv_len = bv.bv_len + bc.bv_len + 1;
1394 				bv2.bv_val = ch_malloc( bv2.bv_len + 1 );
1395 				strcpy( bv2.bv_val, bv.bv_val );
1396 				bv2.bv_val[bv.bv_len] = ' ';
1397 				strcpy( &bv2.bv_val[bv.bv_len + 1], bc.bv_val );
1398 				ber_memfree( bc.bv_val );
1399 				ber_bvarray_add( &c->rvalue_vals, &bv2 );
1400 			} else {
1401 				value_add_one( &c->rvalue_vals, &bv );
1402 			}
1403 			} break;
1404 
1405 		/* target attrs */
1406 		case LDAP_BACK_CFG_URI: {
1407 			char *p2, *p1 = strchr( mt->mt_uri, ' ' );
1408 			bv.bv_len = strlen( mt->mt_uri ) + 3 + mt->mt_psuffix.bv_len;
1409 			bv.bv_val = ch_malloc( bv.bv_len + 1 );
1410 			p2 = bv.bv_val;
1411 			*p2++ = '"';
1412 			if ( p1 ) {
1413 				p2 = lutil_strncopy( p2, mt->mt_uri, p1 - mt->mt_uri );
1414 			} else {
1415 				p2 = lutil_strcopy( p2, mt->mt_uri );
1416 			}
1417 			*p2++ = '/';
1418 			p2 = lutil_strcopy( p2, mt->mt_psuffix.bv_val );
1419 			*p2++ = '"';
1420 			if ( p1 ) {
1421 				strcpy( p2, p1 );
1422 			}
1423 			ber_bvarray_add( &c->rvalue_vals, &bv );
1424 			} break;
1425 
1426 		case LDAP_BACK_CFG_ACL_AUTHCDN:
1427 		case LDAP_BACK_CFG_ACL_PASSWD:
1428 			/* FIXME no point here, there is no code implementing
1429 			 * their features. Was this supposed to implement
1430 			 * acl-bind like back-ldap?
1431 			 */
1432 			rc = 1;
1433 			break;
1434 
1435 		case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: {
1436 			BerVarray	*bvp;
1437 			int		i;
1438 			struct berval	bv = BER_BVNULL;
1439 			char		buf[SLAP_TEXT_BUFLEN];
1440 
1441 			bvp = &mt->mt_idassert_authz;
1442 			if ( *bvp == NULL ) {
1443 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL )
1444 				{
1445 					BER_BVSTR( &bv, "*" );
1446 					value_add_one( &c->rvalue_vals, &bv );
1447 
1448 				} else {
1449 					rc = 1;
1450 				}
1451 				break;
1452 			}
1453 
1454 			for ( i = 0; !BER_BVISNULL( &((*bvp)[ i ]) ); i++ ) {
1455 				char *ptr;
1456 				int len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i );
1457 				bv.bv_len = ((*bvp)[ i ]).bv_len + len;
1458 				bv.bv_val = ber_memrealloc( bv.bv_val, bv.bv_len + 1 );
1459 				ptr = bv.bv_val;
1460 				ptr = lutil_strcopy( ptr, buf );
1461 				ptr = lutil_strncopy( ptr, ((*bvp)[ i ]).bv_val, ((*bvp)[ i ]).bv_len );
1462 				value_add_one( &c->rvalue_vals, &bv );
1463 			}
1464 			if ( bv.bv_val ) {
1465 				ber_memfree( bv.bv_val );
1466 			}
1467 			break;
1468 		}
1469 
1470 		case LDAP_BACK_CFG_IDASSERT_BIND: {
1471 			int		i;
1472 			struct berval	bc = BER_BVNULL;
1473 			char		*ptr;
1474 
1475 			if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE ) {
1476 				return 1;
1477 			} else {
1478 				ber_len_t	len;
1479 
1480 				switch ( mt->mt_idassert_mode ) {
1481 				case LDAP_BACK_IDASSERT_OTHERID:
1482 				case LDAP_BACK_IDASSERT_OTHERDN:
1483 					break;
1484 
1485 				default: {
1486 					struct berval	mode = BER_BVNULL;
1487 
1488 					enum_to_verb( idassert_mode, mt->mt_idassert_mode, &mode );
1489 					if ( BER_BVISNULL( &mode ) ) {
1490 						/* there's something wrong... */
1491 						assert( 0 );
1492 						rc = 1;
1493 
1494 					} else {
1495 						bv.bv_len = STRLENOF( "mode=" ) + mode.bv_len;
1496 						bv.bv_val = ch_malloc( bv.bv_len + 1 );
1497 
1498 						ptr = lutil_strcopy( bv.bv_val, "mode=" );
1499 						ptr = lutil_strcopy( ptr, mode.bv_val );
1500 					}
1501 					break;
1502 				}
1503 				}
1504 
1505 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) {
1506 					len = bv.bv_len + STRLENOF( "authz=native" );
1507 
1508 					if ( !BER_BVISEMPTY( &bv ) ) {
1509 						len += STRLENOF( " " );
1510 					}
1511 
1512 					bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
1513 
1514 					ptr = &bv.bv_val[ bv.bv_len ];
1515 
1516 					if ( !BER_BVISEMPTY( &bv ) ) {
1517 						ptr = lutil_strcopy( ptr, " " );
1518 					}
1519 
1520 					(void)lutil_strcopy( ptr, "authz=native" );
1521 				}
1522 
1523 				len = bv.bv_len + STRLENOF( "flags=non-prescriptive,override,obsolete-encoding-workaround,proxy-authz-non-critical,dn-authzid" );
1524 				/* flags */
1525 				if ( !BER_BVISEMPTY( &bv ) ) {
1526 					len += STRLENOF( " " );
1527 				}
1528 
1529 				bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
1530 
1531 				ptr = &bv.bv_val[ bv.bv_len ];
1532 
1533 				if ( !BER_BVISEMPTY( &bv ) ) {
1534 					ptr = lutil_strcopy( ptr, " " );
1535 				}
1536 
1537 				ptr = lutil_strcopy( ptr, "flags=" );
1538 
1539 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1540 					ptr = lutil_strcopy( ptr, "prescriptive" );
1541 				} else {
1542 					ptr = lutil_strcopy( ptr, "non-prescriptive" );
1543 				}
1544 
1545 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
1546 					ptr = lutil_strcopy( ptr, ",override" );
1547 				}
1548 
1549 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
1550 					ptr = lutil_strcopy( ptr, ",obsolete-proxy-authz" );
1551 
1552 				} else if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
1553 					ptr = lutil_strcopy( ptr, ",obsolete-encoding-workaround" );
1554 				}
1555 
1556 				if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) {
1557 					ptr = lutil_strcopy( ptr, ",proxy-authz-critical" );
1558 
1559 				} else {
1560 					ptr = lutil_strcopy( ptr, ",proxy-authz-non-critical" );
1561 				}
1562 
1563 #ifdef SLAP_AUTH_DN
1564 				switch ( mt->mt_idassert_flags & LDAP_BACK_AUTH_DN_MASK ) {
1565 				case LDAP_BACK_AUTH_DN_AUTHZID:
1566 					ptr = lutil_strcopy( ptr, ",dn-authzid" );
1567 					break;
1568 
1569 				case LDAP_BACK_AUTH_DN_WHOAMI:
1570 					ptr = lutil_strcopy( ptr, ",dn-whoami" );
1571 					break;
1572 
1573 				default:
1574 #if 0 /* implicit */
1575 					ptr = lutil_strcopy( ptr, ",dn-none" );
1576 #endif
1577 					break;
1578 				}
1579 #endif
1580 
1581 				bv.bv_len = ( ptr - bv.bv_val );
1582 				/* end-of-flags */
1583 			}
1584 
1585 			bindconf_unparse( &mt->mt_idassert.si_bc, &bc );
1586 
1587 			if ( !BER_BVISNULL( &bv ) ) {
1588 				ber_len_t	len = bv.bv_len + bc.bv_len;
1589 
1590 				bv.bv_val = ch_realloc( bv.bv_val, len + 1 );
1591 
1592 				assert( bc.bv_val[ 0 ] == ' ' );
1593 
1594 				ptr = lutil_strcopy( &bv.bv_val[ bv.bv_len ], bc.bv_val );
1595 				free( bc.bv_val );
1596 				bv.bv_len = ptr - bv.bv_val;
1597 
1598 			} else {
1599 				for ( i = 0; isspace( (unsigned char) bc.bv_val[ i ] ); i++ )
1600 					/* count spaces */ ;
1601 
1602 				if ( i ) {
1603 					bc.bv_len -= i;
1604 					AC_MEMCPY( bc.bv_val, &bc.bv_val[ i ], bc.bv_len + 1 );
1605 				}
1606 
1607 				bv = bc;
1608 			}
1609 
1610 			ber_bvarray_add( &c->rvalue_vals, &bv );
1611 
1612 			break;
1613 		}
1614 
1615 		case LDAP_BACK_CFG_SUFFIXM:	/* unused */
1616 		case LDAP_BACK_CFG_REWRITE:
1617 			if ( mt->mt_rwmap.rwm_bva_rewrite == NULL ) {
1618 				rc = 1;
1619 			} else {
1620 				rc = slap_bv_x_ordered_unparse( mt->mt_rwmap.rwm_bva_rewrite, &c->rvalue_vals );
1621 			}
1622 			break;
1623 
1624 		case LDAP_BACK_CFG_MAP:
1625 			if ( mt->mt_rwmap.rwm_bva_map == NULL ) {
1626 				rc = 1;
1627 			} else {
1628 				rc = slap_bv_x_ordered_unparse( mt->mt_rwmap.rwm_bva_map, &c->rvalue_vals );
1629 			}
1630 			break;
1631 
1632 		case LDAP_BACK_CFG_SUBTREE_EX:
1633 		case LDAP_BACK_CFG_SUBTREE_IN:
1634 			rc = meta_subtree_unparse( c, mt );
1635 			break;
1636 
1637 		case LDAP_BACK_CFG_FILTER:
1638 			if ( mt->mt_filter == NULL ) {
1639 				rc = 1;
1640 			} else {
1641 				metafilter_t *mf;
1642 				for ( mf = mt->mt_filter; mf; mf = mf->mf_next )
1643 					value_add_one( &c->rvalue_vals, &mf->mf_regex_pattern );
1644 			}
1645 			break;
1646 
1647 		/* replaced by idassert */
1648 		case LDAP_BACK_CFG_PSEUDOROOTDN:
1649 		case LDAP_BACK_CFG_PSEUDOROOTPW:
1650 			rc = 1;
1651 			break;
1652 
1653 		case LDAP_BACK_CFG_KEEPALIVE: {
1654 				struct berval bv;
1655 				char buf[AC_LINE_MAX];
1656 				bv.bv_len = AC_LINE_MAX;
1657 				bv.bv_val = &buf[0];
1658 				slap_keepalive_parse(&bv, &mt->mt_tls.sb_keepalive, 0, 0, 1);
1659 				value_add_one( &c->rvalue_vals, &bv );
1660 				break;
1661 			}
1662 
1663 		default:
1664 			rc = 1;
1665 		}
1666 		return rc;
1667 	} else if ( c->op == LDAP_MOD_DELETE ) {
1668 		switch( c->type ) {
1669 		/* Base attrs */
1670 		case LDAP_BACK_CFG_CONN_TTL:
1671 			mi->mi_conn_ttl = 0;
1672 			break;
1673 
1674 		case LDAP_BACK_CFG_DNCACHE_TTL:
1675 			mi->mi_cache.ttl = META_DNCACHE_DISABLED;
1676 			break;
1677 
1678 		case LDAP_BACK_CFG_IDLE_TIMEOUT:
1679 			mi->mi_idle_timeout = 0;
1680 			break;
1681 
1682 		case LDAP_BACK_CFG_ONERR:
1683 			mi->mi_flags &= ~META_BACK_F_ONERR_MASK;
1684 			break;
1685 
1686 		case LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER:
1687 			mi->mi_flags &= ~META_BACK_F_DEFER_ROOTDN_BIND;
1688 			break;
1689 
1690 		case LDAP_BACK_CFG_SINGLECONN:
1691 			mi->mi_flags &= ~LDAP_BACK_F_SINGLECONN;
1692 			break;
1693 
1694 		case LDAP_BACK_CFG_USETEMP:
1695 			mi->mi_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
1696 			break;
1697 
1698 		case LDAP_BACK_CFG_CONNPOOLMAX:
1699 			mi->mi_conn_priv_max = LDAP_BACK_CONN_PRIV_MIN;
1700 			break;
1701 
1702 		/* common attrs */
1703 		case LDAP_BACK_CFG_BIND_TIMEOUT:
1704 			mc->mc_bind_timeout.tv_sec = 0;
1705 			mc->mc_bind_timeout.tv_usec = 0;
1706 			break;
1707 
1708 		case LDAP_BACK_CFG_CANCEL:
1709 			mc->mc_flags &= ~LDAP_BACK_F_CANCEL_MASK2;
1710 			break;
1711 
1712 		case LDAP_BACK_CFG_CHASE:
1713 			mc->mc_flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
1714 			break;
1715 
1716 #ifdef SLAPD_META_CLIENT_PR
1717 		case LDAP_BACK_CFG_CLIENT_PR:
1718 			mc->mc_ps = META_CLIENT_PR_DISABLE;
1719 			break;
1720 #endif /* SLAPD_META_CLIENT_PR */
1721 
1722 		case LDAP_BACK_CFG_DEFAULT_T:
1723 			mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
1724 			break;
1725 
1726 		case LDAP_BACK_CFG_NETWORK_TIMEOUT:
1727 			mc->mc_network_timeout = 0;
1728 			break;
1729 
1730 		case LDAP_BACK_CFG_NOREFS:
1731 			mc->mc_flags &= ~LDAP_BACK_F_NOREFS;
1732 			break;
1733 
1734 		case LDAP_BACK_CFG_NOUNDEFFILTER:
1735 			mc->mc_flags &= ~LDAP_BACK_F_NOUNDEFFILTER;
1736 			break;
1737 
1738 		case LDAP_BACK_CFG_NRETRIES:
1739 			mc->mc_nretries = META_RETRY_DEFAULT;
1740 			break;
1741 
1742 		case LDAP_BACK_CFG_QUARANTINE:
1743 			if ( META_BACK_CMN_QUARANTINE( mc )) {
1744 				mi->mi_ldap_extra->retry_info_destroy( &mc->mc_quarantine );
1745 				mc->mc_flags &= ~LDAP_BACK_F_QUARANTINE;
1746 				if ( mc == &mt->mt_mc ) {
1747 					ldap_pvt_thread_mutex_destroy( &mt->mt_quarantine_mutex );
1748 					mt->mt_isquarantined = 0;
1749 				}
1750 			}
1751 			break;
1752 
1753 		case LDAP_BACK_CFG_REBIND:
1754 			mc->mc_flags &= ~LDAP_BACK_F_SAVECRED;
1755 			break;
1756 
1757 		case LDAP_BACK_CFG_TIMEOUT:
1758 			for ( i = 0; i < SLAP_OP_LAST; i++ ) {
1759 				mc->mc_timeout[ i ] = 0;
1760 			}
1761 			break;
1762 
1763 		case LDAP_BACK_CFG_VERSION:
1764 			mc->mc_version = 0;
1765 			break;
1766 
1767 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1768 		case LDAP_BACK_CFG_ST_REQUEST:
1769 			mc->mc_flags &= ~LDAP_BACK_F_ST_REQUEST;
1770 			break;
1771 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1772 
1773 		case LDAP_BACK_CFG_T_F:
1774 			mc->mc_flags &= ~LDAP_BACK_F_T_F_MASK2;
1775 			break;
1776 
1777 		case LDAP_BACK_CFG_TLS:
1778 			mc->mc_flags &= ~LDAP_BACK_F_TLS_MASK;
1779 			if ( mt )
1780 				bindconf_free( &mt->mt_tls );
1781 			break;
1782 
1783 		/* target attrs */
1784 		case LDAP_BACK_CFG_URI:
1785 			if ( mt->mt_uri ) {
1786 				ch_free( mt->mt_uri );
1787 				mt->mt_uri = NULL;
1788 			}
1789 			/* FIXME: should have a way to close all cached
1790 			 * connections associated with this target.
1791 			 */
1792 			break;
1793 
1794 		case LDAP_BACK_CFG_IDASSERT_AUTHZFROM: {
1795 			BerVarray *bvp;
1796 
1797 			bvp = &mt->mt_idassert_authz; break;
1798 			if ( c->valx < 0 ) {
1799 				if ( *bvp != NULL ) {
1800 					ber_bvarray_free( *bvp );
1801 					*bvp = NULL;
1802 				}
1803 
1804 			} else {
1805 				if ( *bvp == NULL ) {
1806 					rc = 1;
1807 					break;
1808 				}
1809 
1810 				for ( i = 0; !BER_BVISNULL( &((*bvp)[ i ]) ); i++ )
1811 					;
1812 
1813 				if ( i >= c->valx ) {
1814 					rc = 1;
1815 					break;
1816 				}
1817 				ber_memfree( ((*bvp)[ c->valx ]).bv_val );
1818 				for ( i = c->valx; !BER_BVISNULL( &((*bvp)[ i + 1 ]) ); i++ ) {
1819 					(*bvp)[ i ] = (*bvp)[ i + 1 ];
1820 				}
1821 				BER_BVZERO( &((*bvp)[ i ]) );
1822 			}
1823 			} break;
1824 
1825 		case LDAP_BACK_CFG_IDASSERT_BIND:
1826 			bindconf_free( &mt->mt_idassert.si_bc );
1827 			memset( &mt->mt_idassert, 0, sizeof( slap_idassert_t ) );
1828 			break;
1829 
1830 		case LDAP_BACK_CFG_SUFFIXM:	/* unused */
1831 		case LDAP_BACK_CFG_REWRITE:
1832 			if ( mt->mt_rwmap.rwm_bva_rewrite ) {
1833 				ber_bvarray_free( mt->mt_rwmap.rwm_bva_rewrite );
1834 				mt->mt_rwmap.rwm_bva_rewrite = NULL;
1835 			}
1836 			if ( mt->mt_rwmap.rwm_rw )
1837 				rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
1838 			break;
1839 
1840 		case LDAP_BACK_CFG_MAP:
1841 			if ( mt->mt_rwmap.rwm_bva_map ) {
1842 				ber_bvarray_free( mt->mt_rwmap.rwm_bva_map );
1843 				mt->mt_rwmap.rwm_bva_map = NULL;
1844 			}
1845 			meta_back_map_free( &mt->mt_rwmap.rwm_oc );
1846 			meta_back_map_free( &mt->mt_rwmap.rwm_at );
1847 			mt->mt_rwmap.rwm_oc.drop_missing = 0;
1848 			mt->mt_rwmap.rwm_at.drop_missing = 0;
1849 			break;
1850 
1851 		case LDAP_BACK_CFG_SUBTREE_EX:
1852 		case LDAP_BACK_CFG_SUBTREE_IN:
1853 			/* can only be one of exclude or include */
1854 			if (( c->type == LDAP_BACK_CFG_SUBTREE_EX ) ^ mt->mt_subtree_exclude ) {
1855 				rc = 1;
1856 				break;
1857 			}
1858 			if ( c->valx < 0 ) {
1859 				meta_subtree_destroy( mt->mt_subtree );
1860 				mt->mt_subtree = NULL;
1861 			} else {
1862 				metasubtree_t *ms, **mprev;
1863 				for (i=0, mprev = &mt->mt_subtree, ms = *mprev; ms; ms = *mprev) {
1864 					if ( i == c->valx ) {
1865 						*mprev = ms->ms_next;
1866 						meta_subtree_free( ms );
1867 						break;
1868 					}
1869 					i++;
1870 					mprev = &ms->ms_next;
1871 				}
1872 				if ( i != c->valx )
1873 					rc = 1;
1874 			}
1875 			break;
1876 
1877 		case LDAP_BACK_CFG_FILTER:
1878 			if ( c->valx < 0 ) {
1879 				meta_filter_destroy( mt->mt_filter );
1880 				mt->mt_filter = NULL;
1881 			} else {
1882 				metafilter_t *mf, **mprev;
1883 				for (i=0, mprev = &mt->mt_filter, mf = *mprev; mf; mf = *mprev) {
1884 					if ( i == c->valx ) {
1885 						*mprev = mf->mf_next;
1886 						meta_filter_free( mf );
1887 						break;
1888 					}
1889 					i++;
1890 					mprev = &mf->mf_next;
1891 				}
1892 				if ( i != c->valx )
1893 					rc = 1;
1894 			}
1895 			break;
1896 
1897 		case LDAP_BACK_CFG_KEEPALIVE:
1898 			mt->mt_tls.sb_keepalive.sk_idle = 0;
1899 			mt->mt_tls.sb_keepalive.sk_probes = 0;
1900 			mt->mt_tls.sb_keepalive.sk_interval = 0;
1901 			break;
1902 
1903 		default:
1904 			rc = 1;
1905 			break;
1906 		}
1907 
1908 		return rc;
1909 	}
1910 
1911 	if ( c->op == SLAP_CONFIG_ADD ) {
1912 		if ( c->type >= LDAP_BACK_CFG_LAST_BASE ) {
1913 			/* exclude CFG_URI from this check */
1914 			if ( c->type > LDAP_BACK_CFG_LAST_BOTH ) {
1915 				if ( !mi->mi_ntargets ) {
1916 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
1917 						"need \"uri\" directive first" );
1918 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1919 					return 1;
1920 				}
1921 			}
1922 			if ( mi->mi_ntargets ) {
1923 				mt = mi->mi_targets[ mi->mi_ntargets-1 ];
1924 				mc = &mt->mt_mc;
1925 			} else {
1926 				mt = NULL;
1927 				mc = &mi->mi_mc;
1928 			}
1929 		}
1930 	} else {
1931 		if ( c->table == Cft_Database ) {
1932 			mt = NULL;
1933 			mc = &mi->mi_mc;
1934 		} else {
1935 			mt = c->ca_private;
1936 			if ( mt )
1937 				mc = &mt->mt_mc;
1938 			else
1939 				mc = NULL;
1940 		}
1941 	}
1942 
1943 	switch( c->type ) {
1944 	case LDAP_BACK_CFG_URI: {
1945 		LDAPURLDesc 	*ludp;
1946 		struct berval	dn;
1947 		int		j;
1948 
1949 		char		**uris = NULL;
1950 
1951 		if ( c->be->be_nsuffix == NULL ) {
1952 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
1953 				"the suffix must be defined before any target" );
1954 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1955 			return 1;
1956 		}
1957 
1958 		i = mi->mi_ntargets++;
1959 
1960 		mi->mi_targets = ( metatarget_t ** )ch_realloc( mi->mi_targets,
1961 			sizeof( metatarget_t * ) * mi->mi_ntargets );
1962 		if ( mi->mi_targets == NULL ) {
1963 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
1964 				"out of memory while storing server name"
1965 				" in \"%s <protocol>://<server>[:port]/<naming context>\"",
1966 				c->argv[0] );
1967 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1968 			return 1;
1969 		}
1970 
1971 		if ( meta_back_new_target( &mi->mi_targets[ i ] ) != 0 ) {
1972 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
1973 				"unable to init server"
1974 				" in \"%s <protocol>://<server>[:port]/<naming context>\"",
1975 				c->argv[0] );
1976 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1977 			return 1;
1978 		}
1979 
1980 		mt = mi->mi_targets[ i ];
1981 
1982 		mt->mt_rebind_f = mi->mi_rebind_f;
1983 		mt->mt_urllist_f = mi->mi_urllist_f;
1984 		mt->mt_urllist_p = mt;
1985 
1986 		if ( META_BACK_QUARANTINE( mi ) ) {
1987 			ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
1988 		}
1989 		mt->mt_mc = mi->mi_mc;
1990 
1991 		for ( j = 1; j < c->argc; j++ ) {
1992 			char	**tmpuris = ldap_str2charray( c->argv[ j ], "\t" );
1993 
1994 			if ( tmpuris == NULL ) {
1995 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
1996 					"unable to parse URIs #%d"
1997 					" in \"%s <protocol>://<server>[:port]/<naming context>\"",
1998 					j-1, c->argv[0] );
1999 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2000 				return 1;
2001 			}
2002 
2003 			if ( j == 1 ) {
2004 				uris = tmpuris;
2005 
2006 			} else {
2007 				ldap_charray_merge( &uris, tmpuris );
2008 				ldap_charray_free( tmpuris );
2009 			}
2010 		}
2011 
2012 		for ( j = 0; uris[ j ] != NULL; j++ ) {
2013 			char *tmpuri = NULL;
2014 
2015 			/*
2016 			 * uri MUST be legal!
2017 			 */
2018 			if ( ldap_url_parselist_ext( &ludp, uris[ j ], "\t",
2019 					LDAP_PVT_URL_PARSE_NONE ) != LDAP_SUCCESS
2020 				|| ludp->lud_next != NULL )
2021 			{
2022 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2023 					"unable to parse URI #%d"
2024 					" in \"%s <protocol>://<server>[:port]/<naming context>\"",
2025 					j-1, c->argv[0] );
2026 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2027 				ldap_charray_free( uris );
2028 				return 1;
2029 			}
2030 
2031 			if ( j == 0 ) {
2032 
2033 				/*
2034 				 * uri MUST have the <dn> part!
2035 				 */
2036 				if ( ludp->lud_dn == NULL ) {
2037 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
2038 						"missing <naming context> "
2039 						" in \"%s <protocol>://<server>[:port]/<naming context>\"",
2040 						c->argv[0] );
2041 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2042 					ldap_free_urllist( ludp );
2043 					ldap_charray_free( uris );
2044 					return 1;
2045 				}
2046 
2047 				/*
2048 				 * copies and stores uri and suffix
2049 				 */
2050 				ber_str2bv( ludp->lud_dn, 0, 0, &dn );
2051 				rc = dnPrettyNormal( NULL, &dn, &mt->mt_psuffix,
2052 					&mt->mt_nsuffix, NULL );
2053 				if ( rc != LDAP_SUCCESS ) {
2054 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
2055 						"target DN is invalid \"%s\"",
2056 						c->argv[1] );
2057 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2058 					ldap_free_urllist( ludp );
2059 					ldap_charray_free( uris );
2060 					return( 1 );
2061 				}
2062 
2063 				ludp->lud_dn[ 0 ] = '\0';
2064 
2065 				switch ( ludp->lud_scope ) {
2066 				case LDAP_SCOPE_DEFAULT:
2067 					mt->mt_scope = LDAP_SCOPE_SUBTREE;
2068 					break;
2069 
2070 				case LDAP_SCOPE_SUBTREE:
2071 				case LDAP_SCOPE_SUBORDINATE:
2072 					mt->mt_scope = ludp->lud_scope;
2073 					break;
2074 
2075 				default:
2076 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
2077 						"invalid scope for target \"%s\"",
2078 						c->argv[1] );
2079 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2080 					ldap_free_urllist( ludp );
2081 					ldap_charray_free( uris );
2082 					return( 1 );
2083 				}
2084 
2085 			} else {
2086 				/* check all, to apply the scope check on the first one */
2087 				if ( ludp->lud_dn != NULL && ludp->lud_dn[ 0 ] != '\0' ) {
2088 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
2089 						"multiple URIs must have no DN part" );
2090 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2091 					ldap_free_urllist( ludp );
2092 					ldap_charray_free( uris );
2093 					return( 1 );
2094 
2095 				}
2096 			}
2097 
2098 			tmpuri = ldap_url_list2urls( ludp );
2099 			ldap_free_urllist( ludp );
2100 			if ( tmpuri == NULL ) {
2101 				snprintf( c->cr_msg, sizeof( c->cr_msg ), "no memory?" );
2102 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2103 				ldap_charray_free( uris );
2104 				return( 1 );
2105 			}
2106 			ldap_memfree( uris[ j ] );
2107 			uris[ j ] = tmpuri;
2108 		}
2109 
2110 		mt->mt_uri = ldap_charray2str( uris, " " );
2111 		ldap_charray_free( uris );
2112 		if ( mt->mt_uri == NULL) {
2113 			snprintf( c->cr_msg, sizeof( c->cr_msg ), "no memory?" );
2114 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2115 			return( 1 );
2116 		}
2117 
2118 		/*
2119 		 * uri MUST be a branch of suffix!
2120 		 */
2121 		for ( j = 0; !BER_BVISNULL( &c->be->be_nsuffix[ j ] ); j++ ) {
2122 			if ( dnIsSuffix( &mt->mt_nsuffix, &c->be->be_nsuffix[ j ] ) ) {
2123 				break;
2124 			}
2125 		}
2126 
2127 		if ( BER_BVISNULL( &c->be->be_nsuffix[ j ] ) ) {
2128 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2129 				"<naming context> of URI must be within the naming context of this database." );
2130 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2131 			return 1;
2132 		}
2133 		c->ca_private = mt;
2134 		c->cleanup = meta_cf_cleanup;
2135 	} break;
2136 	case LDAP_BACK_CFG_SUBTREE_EX:
2137 	case LDAP_BACK_CFG_SUBTREE_IN:
2138 	/* subtree-exclude */
2139 		if ( meta_subtree_config( mt, c )) {
2140 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2141 			return 1;
2142 		}
2143 		break;
2144 
2145 	case LDAP_BACK_CFG_FILTER: {
2146 		metafilter_t *mf, **m2;
2147 		mf = ch_malloc( sizeof( metafilter_t ));
2148 		rc = regcomp( &mf->mf_regex, c->argv[1], REG_EXTENDED );
2149 		if ( rc ) {
2150 			char regerr[ SLAP_TEXT_BUFLEN ];
2151 			regerror( rc, &mf->mf_regex, regerr, sizeof(regerr) );
2152 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2153 				"regular expression \"%s\" bad because of %s",
2154 				c->argv[1], regerr );
2155 			ch_free( mf );
2156 			return 1;
2157 		}
2158 		ber_str2bv( c->argv[1], 0, 1, &mf->mf_regex_pattern );
2159 		for ( m2 = &mt->mt_filter; *m2; m2 = &(*m2)->mf_next )
2160 			;
2161 		*m2 = mf;
2162 	} break;
2163 
2164 	case LDAP_BACK_CFG_DEFAULT_T:
2165 	/* default target directive */
2166 		i = mi->mi_ntargets - 1;
2167 
2168 		if ( c->argc == 1 ) {
2169  			if ( i < 0 ) {
2170 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2171 					"\"%s\" alone must be inside a \"uri\" directive",
2172 					c->argv[0] );
2173 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2174 				return 1;
2175 			}
2176 			mi->mi_defaulttarget = i;
2177 
2178 		} else {
2179 			if ( strcasecmp( c->argv[ 1 ], "none" ) == 0 ) {
2180 				if ( i >= 0 ) {
2181 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
2182 						"\"%s none\" should go before uri definitions",
2183 						c->argv[0] );
2184 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2185 				}
2186 				mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
2187 
2188 			} else {
2189 
2190 				if ( lutil_atoi( &mi->mi_defaulttarget, c->argv[ 1 ] ) != 0
2191 					|| mi->mi_defaulttarget < 0
2192 					|| mi->mi_defaulttarget >= i - 1 )
2193 				{
2194 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
2195 						"illegal target number %d",
2196 						mi->mi_defaulttarget );
2197 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2198 					return 1;
2199 				}
2200 			}
2201 		}
2202 		break;
2203 
2204 	case LDAP_BACK_CFG_DNCACHE_TTL:
2205 	/* ttl of dn cache */
2206 		if ( strcasecmp( c->argv[ 1 ], "forever" ) == 0 ) {
2207 			mi->mi_cache.ttl = META_DNCACHE_FOREVER;
2208 
2209 		} else if ( strcasecmp( c->argv[ 1 ], "disabled" ) == 0 ) {
2210 			mi->mi_cache.ttl = META_DNCACHE_DISABLED;
2211 
2212 		} else {
2213 			unsigned long	t;
2214 
2215 			if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
2216 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2217 					"unable to parse dncache ttl \"%s\"",
2218 					c->argv[ 1 ] );
2219 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2220 				return 1;
2221 			}
2222 			mi->mi_cache.ttl = (time_t)t;
2223 		}
2224 		break;
2225 
2226 	case LDAP_BACK_CFG_NETWORK_TIMEOUT: {
2227 	/* network timeout when connecting to ldap servers */
2228 		unsigned long t;
2229 
2230 		if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
2231 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2232 				"unable to parse network timeout \"%s\"",
2233 				c->argv[ 1 ] );
2234 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2235 			return 1;
2236 		}
2237 		mc->mc_network_timeout = (time_t)t;
2238 		} break;
2239 
2240 	case LDAP_BACK_CFG_IDLE_TIMEOUT: {
2241 	/* idle timeout when connecting to ldap servers */
2242 		unsigned long	t;
2243 
2244 		if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
2245 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2246 				"unable to parse idle timeout \"%s\"",
2247 				c->argv[ 1 ] );
2248 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2249 			return 1;
2250 
2251 		}
2252 		mi->mi_idle_timeout = (time_t)t;
2253 		} break;
2254 
2255 	case LDAP_BACK_CFG_CONN_TTL: {
2256 	/* conn ttl */
2257 		unsigned long	t;
2258 
2259 		if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
2260 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2261 				"unable to parse conn ttl \"%s\"",
2262 				c->argv[ 1 ] );
2263 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2264 			return 1;
2265 
2266 		}
2267 		mi->mi_conn_ttl = (time_t)t;
2268 		} break;
2269 
2270 	case LDAP_BACK_CFG_BIND_TIMEOUT:
2271 	/* bind timeout when connecting to ldap servers */
2272 		mc->mc_bind_timeout.tv_sec = c->value_ulong/1000000;
2273 		mc->mc_bind_timeout.tv_usec = c->value_ulong%1000000;
2274 		break;
2275 
2276 	case LDAP_BACK_CFG_ACL_AUTHCDN:
2277 	/* name to use for meta_back_group */
2278 		if ( strcasecmp( c->argv[ 0 ], "binddn" ) == 0 ) {
2279 			Debug( LDAP_DEBUG_ANY, "%s: "
2280 				"\"binddn\" statement is deprecated; "
2281 				"use \"acl-authcDN\" instead\n",
2282 				c->log, 0, 0 );
2283 			/* FIXME: some day we'll need to throw an error */
2284 		}
2285 
2286 		ber_memfree_x( c->value_dn.bv_val, NULL );
2287 		mt->mt_binddn = c->value_ndn;
2288 		BER_BVZERO( &c->value_dn );
2289 		BER_BVZERO( &c->value_ndn );
2290 		break;
2291 
2292 	case LDAP_BACK_CFG_ACL_PASSWD:
2293 	/* password to use for meta_back_group */
2294 		if ( strcasecmp( c->argv[ 0 ], "bindpw" ) == 0 ) {
2295 			Debug( LDAP_DEBUG_ANY, "%s "
2296 				"\"bindpw\" statement is deprecated; "
2297 				"use \"acl-passwd\" instead\n",
2298 				c->log, 0, 0 );
2299 			/* FIXME: some day we'll need to throw an error */
2300 		}
2301 
2302 		ber_str2bv( c->argv[ 1 ], 0L, 1, &mt->mt_bindpw );
2303 		break;
2304 
2305 	case LDAP_BACK_CFG_REBIND:
2306 	/* save bind creds for referral rebinds? */
2307 		if ( c->argc == 1 || c->value_int ) {
2308 			mc->mc_flags |= LDAP_BACK_F_SAVECRED;
2309 		} else {
2310 			mc->mc_flags &= ~LDAP_BACK_F_SAVECRED;
2311 		}
2312 		break;
2313 
2314 	case LDAP_BACK_CFG_CHASE:
2315 		if ( c->argc == 1 || c->value_int ) {
2316 			mc->mc_flags |= LDAP_BACK_F_CHASE_REFERRALS;
2317 		} else {
2318 			mc->mc_flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
2319 		}
2320 		break;
2321 
2322 	case LDAP_BACK_CFG_TLS:
2323 		i = verb_to_mask( c->argv[1], tls_mode );
2324 		if ( BER_BVISNULL( &tls_mode[i].word ) ) {
2325 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2326 				"%s unknown argument \"%s\"",
2327 				c->argv[0], c->argv[1] );
2328 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2329 			return 1;
2330 		}
2331 		mc->mc_flags &= ~LDAP_BACK_F_TLS_MASK;
2332 		mc->mc_flags |= tls_mode[i].mask;
2333 
2334 		if ( c->argc > 2 ) {
2335 			if ( c->op == SLAP_CONFIG_ADD && mi->mi_ntargets == 0 ) {
2336 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2337 					"need \"uri\" directive first" );
2338 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2339 				return 1;
2340 			}
2341 
2342 			for ( i = 2; i < c->argc; i++ ) {
2343 				if ( bindconf_tls_parse( c->argv[i], &mt->mt_tls ))
2344 					return 1;
2345 			}
2346 			bindconf_tls_defaults( &mt->mt_tls );
2347 		}
2348 		break;
2349 
2350 	case LDAP_BACK_CFG_T_F:
2351 		i = verb_to_mask( c->argv[1], t_f_mode );
2352 		if ( BER_BVISNULL( &t_f_mode[i].word ) ) {
2353 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2354 				"%s unknown argument \"%s\"",
2355 				c->argv[0], c->argv[1] );
2356 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2357 			return 1;
2358 		}
2359 		mc->mc_flags &= ~LDAP_BACK_F_T_F_MASK2;
2360 		mc->mc_flags |= t_f_mode[i].mask;
2361 		break;
2362 
2363 	case LDAP_BACK_CFG_ONERR:
2364 	/* onerr? */
2365 		i = verb_to_mask( c->argv[1], onerr_mode );
2366 		if ( BER_BVISNULL( &onerr_mode[i].word ) ) {
2367 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2368 				"%s unknown argument \"%s\"",
2369 				c->argv[0], c->argv[1] );
2370 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2371 			return 1;
2372 		}
2373 		mi->mi_flags &= ~META_BACK_F_ONERR_MASK;
2374 		mi->mi_flags |= onerr_mode[i].mask;
2375 		break;
2376 
2377 	case LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER:
2378 	/* bind-defer? */
2379 		if ( c->argc == 1 || c->value_int ) {
2380 			mi->mi_flags |= META_BACK_F_DEFER_ROOTDN_BIND;
2381 		} else {
2382 			mi->mi_flags &= ~META_BACK_F_DEFER_ROOTDN_BIND;
2383 		}
2384 		break;
2385 
2386 	case LDAP_BACK_CFG_SINGLECONN:
2387 	/* single-conn? */
2388 		if ( mi->mi_ntargets > 0 ) {
2389 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2390 				"\"%s\" must appear before target definitions",
2391 				c->argv[0] );
2392 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2393 			return( 1 );
2394 		}
2395 		if ( c->value_int ) {
2396 			mi->mi_flags |= LDAP_BACK_F_SINGLECONN;
2397 		} else {
2398 			mi->mi_flags &= ~LDAP_BACK_F_SINGLECONN;
2399 		}
2400 		break;
2401 
2402 	case LDAP_BACK_CFG_USETEMP:
2403 	/* use-temporaries? */
2404 		if ( mi->mi_ntargets > 0 ) {
2405 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2406 				"\"%s\" must appear before target definitions",
2407 				c->argv[0] );
2408 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2409 			return( 1 );
2410 		}
2411 		if ( c->value_int ) {
2412 			mi->mi_flags |= LDAP_BACK_F_USE_TEMPORARIES;
2413 		} else {
2414 			mi->mi_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
2415 		}
2416 		break;
2417 
2418 	case LDAP_BACK_CFG_CONNPOOLMAX:
2419 	/* privileged connections pool max size ? */
2420 		if ( mi->mi_ntargets > 0 ) {
2421 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2422 				"\"%s\" must appear before target definitions",
2423 				c->argv[0] );
2424 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2425 			return( 1 );
2426 		}
2427 
2428 		if ( c->value_int < LDAP_BACK_CONN_PRIV_MIN
2429 			|| c->value_int > LDAP_BACK_CONN_PRIV_MAX )
2430 		{
2431 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2432 				"invalid max size " "of privileged "
2433 				"connections pool \"%s\" "
2434 				"in \"conn-pool-max <n> "
2435 				"(must be between %d and %d)\"",
2436 				c->argv[ 1 ],
2437 				LDAP_BACK_CONN_PRIV_MIN,
2438 				LDAP_BACK_CONN_PRIV_MAX );
2439 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2440 			return 1;
2441 		}
2442 		mi->mi_conn_priv_max = c->value_int;
2443 		break;
2444 
2445 	case LDAP_BACK_CFG_CANCEL:
2446 		i = verb_to_mask( c->argv[1], cancel_mode );
2447 		if ( BER_BVISNULL( &cancel_mode[i].word ) ) {
2448 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2449 				"%s unknown argument \"%s\"",
2450 				c->argv[0], c->argv[1] );
2451 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2452 			return 1;
2453 		}
2454 		mc->mc_flags &= ~LDAP_BACK_F_CANCEL_MASK2;
2455 		mc->mc_flags |= t_f_mode[i].mask;
2456 		break;
2457 
2458 	case LDAP_BACK_CFG_TIMEOUT:
2459 		for ( i = 1; i < c->argc; i++ ) {
2460 			if ( isdigit( (unsigned char) c->argv[ i ][ 0 ] ) ) {
2461 				int		j;
2462 				unsigned	u;
2463 
2464 				if ( lutil_atoux( &u, c->argv[ i ], 0 ) != 0 ) {
2465 					snprintf( c->cr_msg, sizeof( c->cr_msg),
2466 						"unable to parse timeout \"%s\"",
2467 						c->argv[ i ] );
2468 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2469 					return 1;
2470 				}
2471 
2472 				for ( j = 0; j < SLAP_OP_LAST; j++ ) {
2473 					mc->mc_timeout[ j ] = u;
2474 				}
2475 
2476 				continue;
2477 			}
2478 
2479 			if ( slap_cf_aux_table_parse( c->argv[ i ], mc->mc_timeout, timeout_table, "slapd-meta timeout" ) ) {
2480 				snprintf( c->cr_msg, sizeof( c->cr_msg),
2481 					"unable to parse timeout \"%s\"",
2482 					c->argv[ i ] );
2483 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2484 				return 1;
2485 			}
2486 		}
2487 		break;
2488 
2489 	case LDAP_BACK_CFG_PSEUDOROOTDN:
2490 	/* name to use as pseudo-root dn */
2491 		/*
2492 		 * exact replacement:
2493 		 *
2494 
2495 idassert-bind	bindmethod=simple
2496 		binddn=<pseudorootdn>
2497 		credentials=<pseudorootpw>
2498 		mode=none
2499 		flags=non-prescriptive
2500 idassert-authzFrom	"dn:<rootdn>"
2501 
2502 		 * so that only when authc'd as <rootdn> the proxying occurs
2503 		 * rebinding as the <pseudorootdn> without proxyAuthz.
2504 		 */
2505 
2506 		Debug( LDAP_DEBUG_ANY,
2507 			"%s: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
2508 			"use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
2509 			c->log, 0, 0 );
2510 
2511 		{
2512 			char	binddn[ SLAP_TEXT_BUFLEN ];
2513 			char	*cargv[] = {
2514 				"idassert-bind",
2515 				"bindmethod=simple",
2516 				NULL,
2517 				"mode=none",
2518 				"flags=non-prescriptive",
2519 				NULL
2520 			};
2521 			char **oargv;
2522 			int oargc;
2523 			int	cargc = 5;
2524 			int	rc;
2525 
2526 
2527 			if ( BER_BVISNULL( &c->be->be_rootndn ) ) {
2528 				Debug( LDAP_DEBUG_ANY, "%s: \"pseudorootpw\": \"rootdn\" must be defined first.\n",
2529 					c->log, 0, 0 );
2530 				return 1;
2531 			}
2532 
2533 			if ( sizeof( binddn ) <= (unsigned) snprintf( binddn,
2534 					sizeof( binddn ), "binddn=%s", c->argv[ 1 ] ))
2535 			{
2536 				Debug( LDAP_DEBUG_ANY, "%s: \"pseudorootdn\" too long.\n",
2537 					c->log, 0, 0 );
2538 				return 1;
2539 			}
2540 			cargv[ 2 ] = binddn;
2541 
2542 			oargv = c->argv;
2543 			oargc = c->argc;
2544 			c->argv = cargv;
2545 			c->argc = cargc;
2546 			rc = mi->mi_ldap_extra->idassert_parse( c, &mt->mt_idassert );
2547 			c->argv = oargv;
2548 			c->argc = oargc;
2549 			if ( rc == 0 ) {
2550 				struct berval	bv;
2551 
2552 				if ( mt->mt_idassert_authz != NULL ) {
2553 					Debug( LDAP_DEBUG_ANY, "%s: \"idassert-authzFrom\" already defined (discarded).\n",
2554 						c->log, 0, 0 );
2555 					ber_bvarray_free( mt->mt_idassert_authz );
2556 					mt->mt_idassert_authz = NULL;
2557 				}
2558 
2559 				assert( !BER_BVISNULL( &mt->mt_idassert_authcDN ) );
2560 
2561 				bv.bv_len = STRLENOF( "dn:" ) + c->be->be_rootndn.bv_len;
2562 				bv.bv_val = ber_memalloc( bv.bv_len + 1 );
2563 				AC_MEMCPY( bv.bv_val, "dn:", STRLENOF( "dn:" ) );
2564 				AC_MEMCPY( &bv.bv_val[ STRLENOF( "dn:" ) ], c->be->be_rootndn.bv_val, c->be->be_rootndn.bv_len + 1 );
2565 
2566 				ber_bvarray_add( &mt->mt_idassert_authz, &bv );
2567 			}
2568 
2569 			return rc;
2570 		}
2571 		break;
2572 
2573 	case LDAP_BACK_CFG_PSEUDOROOTPW:
2574 	/* password to use as pseudo-root */
2575 		Debug( LDAP_DEBUG_ANY,
2576 			"%s: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
2577 			"use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
2578 			c->log, 0, 0 );
2579 
2580 		if ( BER_BVISNULL( &mt->mt_idassert_authcDN ) ) {
2581 			Debug( LDAP_DEBUG_ANY, "%s: \"pseudorootpw\": \"pseudorootdn\" must be defined first.\n",
2582 				c->log, 0, 0 );
2583 			return 1;
2584 		}
2585 
2586 		if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) {
2587 			memset( mt->mt_idassert_passwd.bv_val, 0,
2588 				mt->mt_idassert_passwd.bv_len );
2589 			ber_memfree( mt->mt_idassert_passwd.bv_val );
2590 		}
2591 		ber_str2bv( c->argv[ 1 ], 0, 1, &mt->mt_idassert_passwd );
2592 		break;
2593 
2594 	case LDAP_BACK_CFG_IDASSERT_BIND:
2595 	/* idassert-bind */
2596 		rc = mi->mi_ldap_extra->idassert_parse( c, &mt->mt_idassert );
2597 		break;
2598 
2599 	case LDAP_BACK_CFG_IDASSERT_AUTHZFROM:
2600 	/* idassert-authzFrom */
2601 		rc = mi->mi_ldap_extra->idassert_authzfrom_parse( c, &mt->mt_idassert );
2602 		break;
2603 
2604 	case LDAP_BACK_CFG_QUARANTINE:
2605 	/* quarantine */
2606 		if ( META_BACK_CMN_QUARANTINE( mc ) )
2607 		{
2608 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2609 				"quarantine already defined" );
2610 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2611 			return 1;
2612 		}
2613 
2614 		if ( mt ) {
2615 			mc->mc_quarantine.ri_interval = NULL;
2616 			mc->mc_quarantine.ri_num = NULL;
2617 			if ( !META_BACK_QUARANTINE( mi ) ) {
2618 				ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
2619 			}
2620 		}
2621 
2622 		if ( mi->mi_ldap_extra->retry_info_parse( c->argv[ 1 ], &mc->mc_quarantine, c->cr_msg, sizeof( c->cr_msg ) ) ) {
2623 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2624 			return 1;
2625 		}
2626 
2627 		mc->mc_flags |= LDAP_BACK_F_QUARANTINE;
2628 		break;
2629 
2630 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
2631 	case LDAP_BACK_CFG_ST_REQUEST:
2632 	/* session tracking request */
2633 		if ( c->value_int ) {
2634 			mc->mc_flags |= LDAP_BACK_F_ST_REQUEST;
2635 		} else {
2636 			mc->mc_flags &= ~LDAP_BACK_F_ST_REQUEST;
2637 		}
2638 		break;
2639 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
2640 
2641 	case LDAP_BACK_CFG_SUFFIXM:	/* FALLTHRU */
2642 	case LDAP_BACK_CFG_REWRITE: {
2643 	/* rewrite stuff ... */
2644 		ConfigArgs ca = { 0 };
2645 		char *line, **argv;
2646 		struct rewrite_info *rwi;
2647 		int cnt = 0, argc, ix = c->valx;
2648 
2649 		if ( mt->mt_rwmap.rwm_bva_rewrite ) {
2650 			for ( ; !BER_BVISNULL( &mt->mt_rwmap.rwm_bva_rewrite[ cnt ] ); cnt++ )
2651 				/* count */ ;
2652 		}
2653 
2654 		if ( ix >= cnt || ix < 0 ) {
2655 			ix = cnt;
2656 		} else {
2657 			rwi = mt->mt_rwmap.rwm_rw;
2658 
2659 			mt->mt_rwmap.rwm_rw = NULL;
2660 			rc = meta_rwi_init( &mt->mt_rwmap.rwm_rw );
2661 
2662 			/* re-parse all rewrite rules, up to the one
2663 			 * that needs to be added */
2664 			ca.fname = c->fname;
2665 			ca.lineno = c->lineno;
2666 			for ( i = 0; i < ix; i++ ) {
2667 				ca.line = mt->mt_rwmap.rwm_bva_rewrite[ i ].bv_val;
2668 				ca.argc = 0;
2669 				config_fp_parse_line( &ca );
2670 
2671 				if ( !strcasecmp( ca.argv[0], "suffixmassage" )) {
2672 					rc = meta_suffixm_config( &ca, ca.argc, ca.argv, mt );
2673 				} else {
2674 					rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
2675 						c->fname, c->lineno, ca.argc, ca.argv );
2676 				}
2677 				assert( rc == 0 );
2678 				ch_free( ca.argv );
2679 				ch_free( ca.tline );
2680 			}
2681 		}
2682 		argc = c->argc;
2683 		argv = c->argv;
2684 		if ( c->op != SLAP_CONFIG_ADD ) {
2685 			argc--;
2686 			argv++;
2687 		}
2688 		/* add the new rule */
2689 		if ( !strcasecmp( argv[0], "suffixmassage" )) {
2690 			rc = meta_suffixm_config( c, argc, argv, mt );
2691 		} else {
2692 			rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
2693 						c->fname, c->lineno, argc, argv );
2694 		}
2695 		if ( rc ) {
2696 			if ( ix < cnt ) {
2697 				rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
2698 				mt->mt_rwmap.rwm_rw = rwi;
2699 			}
2700 			return 1;
2701 		}
2702 		if ( ix < cnt ) {
2703 			for ( ; i < cnt; i++ ) {
2704 				ca.line = mt->mt_rwmap.rwm_bva_rewrite[ i ].bv_val;
2705 				ca.argc = 0;
2706 				config_fp_parse_line( &ca );
2707 
2708 				if ( !strcasecmp( ca.argv[0], "suffixmassage" )) {
2709 					rc = meta_suffixm_config( &ca, ca.argc, ca.argv, mt );
2710 				} else {
2711 					rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
2712 						c->fname, c->lineno, ca.argc, argv );
2713 				}
2714 				assert( rc == 0 );
2715 				ch_free( ca.argv );
2716 				ch_free( ca.tline );
2717 			}
2718 		}
2719 
2720 		/* save the rule info */
2721 		line = ldap_charray2str( argv, "\" \"" );
2722 		if ( line != NULL ) {
2723 			struct berval bv;
2724 			int len = strlen( argv[ 0 ] );
2725 
2726 			ber_str2bv( line, 0, 0, &bv );
2727 			AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
2728 				bv.bv_len - ( len + 1 ));
2729 			bv.bv_val[ bv.bv_len - 1] = '"';
2730 			ber_bvarray_add( &mt->mt_rwmap.rwm_bva_rewrite, &bv );
2731 			/* move it to the right slot */
2732 			if ( ix < cnt ) {
2733 				for ( i=cnt; i>ix; i-- )
2734 					mt->mt_rwmap.rwm_bva_rewrite[i+1] = mt->mt_rwmap.rwm_bva_rewrite[i];
2735 				mt->mt_rwmap.rwm_bva_rewrite[i] = bv;
2736 
2737 				/* destroy old rules */
2738 				rewrite_info_delete( &rwi );
2739 			}
2740 		}
2741 		} break;
2742 
2743 	case LDAP_BACK_CFG_MAP: {
2744 	/* objectclass/attribute mapping */
2745 		ConfigArgs ca = { 0 };
2746 		char *argv[5];
2747 		struct ldapmap rwm_oc;
2748 		struct ldapmap rwm_at;
2749 		int cnt = 0, ix = c->valx;
2750 
2751 		if ( mt->mt_rwmap.rwm_bva_map ) {
2752 			for ( ; !BER_BVISNULL( &mt->mt_rwmap.rwm_bva_map[ cnt ] ); cnt++ )
2753 				/* count */ ;
2754 		}
2755 
2756 		if ( ix >= cnt || ix < 0 ) {
2757 			ix = cnt;
2758 		} else {
2759 			rwm_oc = mt->mt_rwmap.rwm_oc;
2760 			rwm_at = mt->mt_rwmap.rwm_at;
2761 
2762 			memset( &mt->mt_rwmap.rwm_oc, 0, sizeof( mt->mt_rwmap.rwm_oc ) );
2763 			memset( &mt->mt_rwmap.rwm_at, 0, sizeof( mt->mt_rwmap.rwm_at ) );
2764 
2765 			/* re-parse all mappings, up to the one
2766 			 * that needs to be added */
2767 			argv[0] = c->argv[0];
2768 			ca.fname = c->fname;
2769 			ca.lineno = c->lineno;
2770 			for ( i = 0; i < ix; i++ ) {
2771 				ca.line = mt->mt_rwmap.rwm_bva_map[ i ].bv_val;
2772 				ca.argc = 0;
2773 				config_fp_parse_line( &ca );
2774 
2775 				argv[1] = ca.argv[0];
2776 				argv[2] = ca.argv[1];
2777 				argv[3] = ca.argv[2];
2778 				argv[4] = ca.argv[3];
2779 				ch_free( ca.argv );
2780 				ca.argv = argv;
2781 				ca.argc++;
2782 				rc = ldap_back_map_config( &ca, &mt->mt_rwmap.rwm_oc,
2783 					&mt->mt_rwmap.rwm_at );
2784 
2785 				ch_free( ca.tline );
2786 				ca.tline = NULL;
2787 				ca.argv = NULL;
2788 
2789 				/* in case of failure, restore
2790 				 * the existing mapping */
2791 				if ( rc ) {
2792 					goto map_fail;
2793 				}
2794 			}
2795 		}
2796 		/* add the new mapping */
2797 		rc = ldap_back_map_config( c, &mt->mt_rwmap.rwm_oc,
2798 					&mt->mt_rwmap.rwm_at );
2799 		if ( rc ) {
2800 			goto map_fail;
2801 		}
2802 
2803 		if ( ix < cnt ) {
2804 			for ( ; i<cnt ; cnt++ ) {
2805 				ca.line = mt->mt_rwmap.rwm_bva_map[ i ].bv_val;
2806 				ca.argc = 0;
2807 				config_fp_parse_line( &ca );
2808 
2809 				argv[1] = ca.argv[0];
2810 				argv[2] = ca.argv[1];
2811 				argv[3] = ca.argv[2];
2812 				argv[4] = ca.argv[3];
2813 
2814 				ch_free( ca.argv );
2815 				ca.argv = argv;
2816 				ca.argc++;
2817 				rc = ldap_back_map_config( &ca, &mt->mt_rwmap.rwm_oc,
2818 					&mt->mt_rwmap.rwm_at );
2819 
2820 				ch_free( ca.tline );
2821 				ca.tline = NULL;
2822 				ca.argv = NULL;
2823 
2824 				/* in case of failure, restore
2825 				 * the existing mapping */
2826 				if ( rc ) {
2827 					goto map_fail;
2828 				}
2829 			}
2830 		}
2831 
2832 		/* save the map info */
2833 		argv[0] = ldap_charray2str( &c->argv[ 1 ], " " );
2834 		if ( argv[0] != NULL ) {
2835 			struct berval bv;
2836 			ber_str2bv( argv[0], 0, 0, &bv );
2837 			ber_bvarray_add( &mt->mt_rwmap.rwm_bva_map, &bv );
2838 			/* move it to the right slot */
2839 			if ( ix < cnt ) {
2840 				for ( i=cnt; i>ix; i-- )
2841 					mt->mt_rwmap.rwm_bva_map[i+1] = mt->mt_rwmap.rwm_bva_map[i];
2842 				mt->mt_rwmap.rwm_bva_map[i] = bv;
2843 
2844 				/* destroy old mapping */
2845 				meta_back_map_free( &rwm_oc );
2846 				meta_back_map_free( &rwm_at );
2847 			}
2848 		}
2849 		break;
2850 
2851 map_fail:;
2852 		if ( ix < cnt ) {
2853 			meta_back_map_free( &mt->mt_rwmap.rwm_oc );
2854 			meta_back_map_free( &mt->mt_rwmap.rwm_at );
2855 			mt->mt_rwmap.rwm_oc = rwm_oc;
2856 			mt->mt_rwmap.rwm_at = rwm_at;
2857 		}
2858 		} break;
2859 
2860 	case LDAP_BACK_CFG_NRETRIES: {
2861 		int		nretries = META_RETRY_UNDEFINED;
2862 
2863 		if ( strcasecmp( c->argv[ 1 ], "forever" ) == 0 ) {
2864 			nretries = META_RETRY_FOREVER;
2865 
2866 		} else if ( strcasecmp( c->argv[ 1 ], "never" ) == 0 ) {
2867 			nretries = META_RETRY_NEVER;
2868 
2869 		} else {
2870 			if ( lutil_atoi( &nretries, c->argv[ 1 ] ) != 0 ) {
2871 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
2872 					"unable to parse nretries {never|forever|<retries>}: \"%s\"",
2873 					c->argv[ 1 ] );
2874 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2875 				return 1;
2876 			}
2877 		}
2878 
2879 		mc->mc_nretries = nretries;
2880 		} break;
2881 
2882 	case LDAP_BACK_CFG_VERSION:
2883 		if ( c->value_int != 0 && ( c->value_int < LDAP_VERSION_MIN || c->value_int > LDAP_VERSION_MAX ) ) {
2884 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2885 				"unsupported protocol version \"%s\"",
2886 				c->argv[ 1 ] );
2887 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2888 			return 1;
2889 		}
2890 		mc->mc_version = c->value_int;
2891 		break;
2892 
2893 	case LDAP_BACK_CFG_NOREFS:
2894 	/* do not return search references */
2895 		if ( c->value_int ) {
2896 			mc->mc_flags |= LDAP_BACK_F_NOREFS;
2897 		} else {
2898 			mc->mc_flags &= ~LDAP_BACK_F_NOREFS;
2899 		}
2900 		break;
2901 
2902 	case LDAP_BACK_CFG_NOUNDEFFILTER:
2903 	/* do not propagate undefined search filters */
2904 		if ( c->value_int ) {
2905 			mc->mc_flags |= LDAP_BACK_F_NOUNDEFFILTER;
2906 		} else {
2907 			mc->mc_flags &= ~LDAP_BACK_F_NOUNDEFFILTER;
2908 		}
2909 		break;
2910 
2911 #ifdef SLAPD_META_CLIENT_PR
2912 	case LDAP_BACK_CFG_CLIENT_PR:
2913 		if ( strcasecmp( c->argv[ 1 ], "accept-unsolicited" ) == 0 ) {
2914 			mc->mc_ps = META_CLIENT_PR_ACCEPT_UNSOLICITED;
2915 
2916 		} else if ( strcasecmp( c->argv[ 1 ], "disable" ) == 0 ) {
2917 			mc->mc_ps = META_CLIENT_PR_DISABLE;
2918 
2919 		} else if ( lutil_atoi( &mc->mc_ps, c->argv[ 1 ] ) || mc->mc_ps < -1 ) {
2920 			snprintf( c->cr_msg, sizeof( c->cr_msg ),
2921 				"unable to parse client-pr {accept-unsolicited|disable|<size>}: \"%s\"",
2922 				c->argv[ 1 ] );
2923 			Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2924 			return( 1 );
2925 		}
2926 		break;
2927 #endif /* SLAPD_META_CLIENT_PR */
2928 
2929 	case LDAP_BACK_CFG_KEEPALIVE:
2930 		slap_keepalive_parse( ber_bvstrdup(c->argv[1]),
2931 				 &mt->mt_tls.sb_keepalive, 0, 0, 0);
2932 		break;
2933 
2934 	/* anything else */
2935 	default:
2936 		return SLAP_CONF_UNKNOWN;
2937 	}
2938 
2939 	return rc;
2940 }
2941 
2942 int
2943 meta_back_init_cf( BackendInfo *bi )
2944 {
2945 	int			rc;
2946 	AttributeDescription	*ad = NULL;
2947 	const char		*text;
2948 
2949 	/* Make sure we don't exceed the bits reserved for userland */
2950 	config_check_userland( LDAP_BACK_CFG_LAST );
2951 
2952 	bi->bi_cf_ocs = metaocs;
2953 
2954 	rc = config_register_schema( metacfg, metaocs );
2955 	if ( rc ) {
2956 		return rc;
2957 	}
2958 
2959 	/* setup olcDbAclPasswd and olcDbIDAssertPasswd
2960 	 * to be base64-encoded when written in LDIF form;
2961 	 * basically, we don't care if it fails */
2962 	rc = slap_str2ad( "olcDbACLPasswd", &ad, &text );
2963 	if ( rc ) {
2964 		Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
2965 			"warning, unable to get \"olcDbACLPasswd\" "
2966 			"attribute description: %d: %s\n",
2967 			rc, text, 0 );
2968 	} else {
2969 		(void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
2970 			ad->ad_type->sat_oid );
2971 	}
2972 
2973 	ad = NULL;
2974 	rc = slap_str2ad( "olcDbIDAssertPasswd", &ad, &text );
2975 	if ( rc ) {
2976 		Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
2977 			"warning, unable to get \"olcDbIDAssertPasswd\" "
2978 			"attribute description: %d: %s\n",
2979 			rc, text, 0 );
2980 	} else {
2981 		(void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
2982 			ad->ad_type->sat_oid );
2983 	}
2984 
2985 	return 0;
2986 }
2987 
2988 static int
2989 ldap_back_map_config(
2990 		ConfigArgs *c,
2991 		struct ldapmap	*oc_map,
2992 		struct ldapmap	*at_map )
2993 {
2994 	struct ldapmap		*map;
2995 	struct ldapmapping	*mapping;
2996 	char			*src, *dst;
2997 	int			is_oc = 0;
2998 
2999 	if ( strcasecmp( c->argv[ 1 ], "objectclass" ) == 0 ) {
3000 		map = oc_map;
3001 		is_oc = 1;
3002 
3003 	} else if ( strcasecmp( c->argv[ 1 ], "attribute" ) == 0 ) {
3004 		map = at_map;
3005 
3006 	} else {
3007 		snprintf( c->cr_msg, sizeof(c->cr_msg),
3008 			"%s unknown argument \"%s\"",
3009 			c->argv[0], c->argv[1] );
3010 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3011 		return 1;
3012 	}
3013 
3014 	if ( !is_oc && map->map == NULL ) {
3015 		/* only init if required */
3016 		ldap_back_map_init( map, &mapping );
3017 	}
3018 
3019 	if ( strcmp( c->argv[ 2 ], "*" ) == 0 ) {
3020 		if ( c->argc < 4 || strcmp( c->argv[ 3 ], "*" ) == 0 ) {
3021 			map->drop_missing = ( c->argc < 4 );
3022 			goto success_return;
3023 		}
3024 		src = dst = c->argv[ 3 ];
3025 
3026 	} else if ( c->argc < 4 ) {
3027 		src = "";
3028 		dst = c->argv[ 2 ];
3029 
3030 	} else {
3031 		src = c->argv[ 2 ];
3032 		dst = ( strcmp( c->argv[ 3 ], "*" ) == 0 ? src : c->argv[ 3 ] );
3033 	}
3034 
3035 	if ( ( map == at_map )
3036 		&& ( strcasecmp( src, "objectclass" ) == 0
3037 			|| strcasecmp( dst, "objectclass" ) == 0 ) )
3038 	{
3039 		snprintf( c->cr_msg, sizeof(c->cr_msg),
3040 			"objectclass attribute cannot be mapped" );
3041 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3042 		return 1;
3043 	}
3044 
3045 	mapping = (struct ldapmapping *)ch_calloc( 2,
3046 		sizeof(struct ldapmapping) );
3047 	if ( mapping == NULL ) {
3048 		snprintf( c->cr_msg, sizeof(c->cr_msg),
3049 			"out of memory" );
3050 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3051 		return 1;
3052 	}
3053 	ber_str2bv( src, 0, 1, &mapping[ 0 ].src );
3054 	ber_str2bv( dst, 0, 1, &mapping[ 0 ].dst );
3055 	mapping[ 1 ].src = mapping[ 0 ].dst;
3056 	mapping[ 1 ].dst = mapping[ 0 ].src;
3057 
3058 	/*
3059 	 * schema check
3060 	 */
3061 	if ( is_oc ) {
3062 		if ( src[ 0 ] != '\0' ) {
3063 			if ( oc_bvfind( &mapping[ 0 ].src ) == NULL ) {
3064 				Debug( LDAP_DEBUG_ANY,
3065 	"warning, source objectClass '%s' should be defined in schema\n",
3066 					c->log, src, 0 );
3067 
3068 				/*
3069 				 * FIXME: this should become an err
3070 				 */
3071 				goto error_return;
3072 			}
3073 		}
3074 
3075 		if ( oc_bvfind( &mapping[ 0 ].dst ) == NULL ) {
3076 			Debug( LDAP_DEBUG_ANY,
3077 	"warning, destination objectClass '%s' is not defined in schema\n",
3078 				c->log, dst, 0 );
3079 		}
3080 	} else {
3081 		int			rc;
3082 		const char		*text = NULL;
3083 		AttributeDescription	*ad = NULL;
3084 
3085 		if ( src[ 0 ] != '\0' ) {
3086 			rc = slap_bv2ad( &mapping[ 0 ].src, &ad, &text );
3087 			if ( rc != LDAP_SUCCESS ) {
3088 				Debug( LDAP_DEBUG_ANY,
3089 	"warning, source attributeType '%s' should be defined in schema\n",
3090 					c->log, src, 0 );
3091 
3092 				/*
3093 				 * FIXME: this should become an err
3094 				 */
3095 				/*
3096 				 * we create a fake "proxied" ad
3097 				 * and add it here.
3098 				 */
3099 
3100 				rc = slap_bv2undef_ad( &mapping[ 0 ].src,
3101 						&ad, &text, SLAP_AD_PROXIED );
3102 				if ( rc != LDAP_SUCCESS ) {
3103 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
3104 						"source attributeType \"%s\": %d (%s)",
3105 						src, rc, text ? text : "" );
3106 					Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3107 					goto error_return;
3108 				}
3109 			}
3110 
3111 			ad = NULL;
3112 		}
3113 
3114 		rc = slap_bv2ad( &mapping[ 0 ].dst, &ad, &text );
3115 		if ( rc != LDAP_SUCCESS ) {
3116 			Debug( LDAP_DEBUG_ANY,
3117 	"warning, destination attributeType '%s' is not defined in schema\n",
3118 				c->log, dst, 0 );
3119 
3120 			/*
3121 			 * we create a fake "proxied" ad
3122 			 * and add it here.
3123 			 */
3124 
3125 			rc = slap_bv2undef_ad( &mapping[ 0 ].dst,
3126 					&ad, &text, SLAP_AD_PROXIED );
3127 			if ( rc != LDAP_SUCCESS ) {
3128 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
3129 					"destination attributeType \"%s\": %d (%s)\n",
3130 					dst, rc, text ? text : "" );
3131 				Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3132 				return 1;
3133 			}
3134 		}
3135 	}
3136 
3137 	if ( (src[ 0 ] != '\0' && avl_find( map->map, (caddr_t)&mapping[ 0 ], mapping_cmp ) != NULL)
3138 			|| avl_find( map->remap, (caddr_t)&mapping[ 1 ], mapping_cmp ) != NULL)
3139 	{
3140 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
3141 			"duplicate mapping found." );
3142 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3143 		goto error_return;
3144 	}
3145 
3146 	if ( src[ 0 ] != '\0' ) {
3147 		avl_insert( &map->map, (caddr_t)&mapping[ 0 ],
3148 					mapping_cmp, mapping_dup );
3149 	}
3150 	avl_insert( &map->remap, (caddr_t)&mapping[ 1 ],
3151 				mapping_cmp, mapping_dup );
3152 
3153 success_return:;
3154 	return 0;
3155 
3156 error_return:;
3157 	if ( mapping ) {
3158 		ch_free( mapping[ 0 ].src.bv_val );
3159 		ch_free( mapping[ 0 ].dst.bv_val );
3160 		ch_free( mapping );
3161 	}
3162 
3163 	return 1;
3164 }
3165 
3166 
3167 #ifdef ENABLE_REWRITE
3168 static char *
3169 suffix_massage_regexize( const char *s )
3170 {
3171 	char *res, *ptr;
3172 	const char *p, *r;
3173 	int i;
3174 
3175 	if ( s[ 0 ] == '\0' ) {
3176 		return ch_strdup( "^(.+)$" );
3177 	}
3178 
3179 	for ( i = 0, p = s;
3180 			( r = strchr( p, ',' ) ) != NULL;
3181 			p = r + 1, i++ )
3182 		;
3183 
3184 	res = ch_calloc( sizeof( char ),
3185 			strlen( s )
3186 			+ STRLENOF( "((.+),)?" )
3187 			+ STRLENOF( "[ ]?" ) * i
3188 			+ STRLENOF( "$" ) + 1 );
3189 
3190 	ptr = lutil_strcopy( res, "((.+),)?" );
3191 	for ( i = 0, p = s;
3192 			( r = strchr( p, ',' ) ) != NULL;
3193 			p = r + 1 , i++ ) {
3194 		ptr = lutil_strncopy( ptr, p, r - p + 1 );
3195 		ptr = lutil_strcopy( ptr, "[ ]?" );
3196 
3197 		if ( r[ 1 ] == ' ' ) {
3198 			r++;
3199 		}
3200 	}
3201 	ptr = lutil_strcopy( ptr, p );
3202 	ptr[ 0 ] = '$';
3203 	ptr++;
3204 	ptr[ 0 ] = '\0';
3205 
3206 	return res;
3207 }
3208 
3209 static char *
3210 suffix_massage_patternize( const char *s, const char *p )
3211 {
3212 	ber_len_t	len;
3213 	char		*res, *ptr;
3214 
3215 	len = strlen( p );
3216 
3217 	if ( s[ 0 ] == '\0' ) {
3218 		len++;
3219 	}
3220 
3221 	res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
3222 	if ( res == NULL ) {
3223 		return NULL;
3224 	}
3225 
3226 	ptr = lutil_strcopy( res, ( p[ 0 ] == '\0' ? "%2" : "%1" ) );
3227 	if ( s[ 0 ] == '\0' ) {
3228 		ptr[ 0 ] = ',';
3229 		ptr++;
3230 	}
3231 	lutil_strcopy( ptr, p );
3232 
3233 	return res;
3234 }
3235 
3236 int
3237 suffix_massage_config(
3238 		struct rewrite_info *info,
3239 		struct berval *pvnc,
3240 		struct berval *nvnc,
3241 		struct berval *prnc,
3242 		struct berval *nrnc
3243 )
3244 {
3245 	char *rargv[ 5 ];
3246 	int line = 0;
3247 
3248 	rargv[ 0 ] = "rewriteEngine";
3249 	rargv[ 1 ] = "on";
3250 	rargv[ 2 ] = NULL;
3251 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
3252 
3253 	rargv[ 0 ] = "rewriteContext";
3254 	rargv[ 1 ] = "default";
3255 	rargv[ 2 ] = NULL;
3256 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
3257 
3258 	rargv[ 0 ] = "rewriteRule";
3259 	rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val );
3260 	rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
3261 	rargv[ 3 ] = ":";
3262 	rargv[ 4 ] = NULL;
3263 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3264 	ch_free( rargv[ 1 ] );
3265 	ch_free( rargv[ 2 ] );
3266 
3267 	if ( BER_BVISEMPTY( pvnc ) ) {
3268 		rargv[ 0 ] = "rewriteRule";
3269 		rargv[ 1 ] = "^$";
3270 		rargv[ 2 ] = prnc->bv_val;
3271 		rargv[ 3 ] = ":";
3272 		rargv[ 4 ] = NULL;
3273 		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3274 	}
3275 
3276 	rargv[ 0 ] = "rewriteContext";
3277 	rargv[ 1 ] = "searchEntryDN";
3278 	rargv[ 2 ] = NULL;
3279 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
3280 
3281 	rargv[ 0 ] = "rewriteRule";
3282 	rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val );
3283 	rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
3284 	rargv[ 3 ] = ":";
3285 	rargv[ 4 ] = NULL;
3286 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3287 	ch_free( rargv[ 1 ] );
3288 	ch_free( rargv[ 2 ] );
3289 
3290 	if ( BER_BVISEMPTY( prnc ) ) {
3291 		rargv[ 0 ] = "rewriteRule";
3292 		rargv[ 1 ] = "^$";
3293 		rargv[ 2 ] = pvnc->bv_val;
3294 		rargv[ 3 ] = ":";
3295 		rargv[ 4 ] = NULL;
3296 		rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3297 	}
3298 
3299 	/* backward compatibility */
3300 	rargv[ 0 ] = "rewriteContext";
3301 	rargv[ 1 ] = "searchResult";
3302 	rargv[ 2 ] = "alias";
3303 	rargv[ 3 ] = "searchEntryDN";
3304 	rargv[ 4 ] = NULL;
3305 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3306 
3307 	rargv[ 0 ] = "rewriteContext";
3308 	rargv[ 1 ] = "matchedDN";
3309 	rargv[ 2 ] = "alias";
3310 	rargv[ 3 ] = "searchEntryDN";
3311 	rargv[ 4 ] = NULL;
3312 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3313 
3314 	rargv[ 0 ] = "rewriteContext";
3315 	rargv[ 1 ] = "searchAttrDN";
3316 	rargv[ 2 ] = "alias";
3317 	rargv[ 3 ] = "searchEntryDN";
3318 	rargv[ 4 ] = NULL;
3319 	rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3320 
3321 	/* NOTE: this corresponds to #undef'ining RWM_REFERRAL_REWRITE;
3322 	 * see servers/slapd/overlays/rwm.h for details */
3323         rargv[ 0 ] = "rewriteContext";
3324 	rargv[ 1 ] = "referralAttrDN";
3325 	rargv[ 2 ] = NULL;
3326 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
3327 
3328 	rargv[ 0 ] = "rewriteContext";
3329 	rargv[ 1 ] = "referralDN";
3330 	rargv[ 2 ] = NULL;
3331 	rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
3332 
3333 	return 0;
3334 }
3335 #endif /* ENABLE_REWRITE */
3336 
3337