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