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