]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/config.c
Merge remote-tracking branch 'origin/mdb.master'
[openldap] / servers / slapd / back-meta / config.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2013 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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; break;
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                         if ( mt->mt_rwmap.rwm_bva_rewrite ) {
1831                                 ber_bvarray_free( mt->mt_rwmap.rwm_bva_rewrite );
1832                                 mt->mt_rwmap.rwm_bva_rewrite = NULL;
1833                         }
1834                         if ( mt->mt_rwmap.rwm_rw )
1835                                 rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
1836                         break;
1837
1838                 case LDAP_BACK_CFG_MAP:
1839                         if ( mt->mt_rwmap.rwm_bva_map ) {
1840                                 ber_bvarray_free( mt->mt_rwmap.rwm_bva_map );
1841                                 mt->mt_rwmap.rwm_bva_map = NULL;
1842                         }
1843                         meta_back_map_free( &mt->mt_rwmap.rwm_oc );
1844                         meta_back_map_free( &mt->mt_rwmap.rwm_at );
1845                         mt->mt_rwmap.rwm_oc.drop_missing = 0;
1846                         mt->mt_rwmap.rwm_at.drop_missing = 0;
1847                         break;
1848
1849                 case LDAP_BACK_CFG_SUBTREE_EX:
1850                 case LDAP_BACK_CFG_SUBTREE_IN:
1851                         /* can only be one of exclude or include */
1852                         if (( c->type == LDAP_BACK_CFG_SUBTREE_EX ) ^ mt->mt_subtree_exclude ) {
1853                                 rc = 1;
1854                                 break;
1855                         }
1856                         if ( c->valx < 0 ) {
1857                                 meta_subtree_destroy( mt->mt_subtree );
1858                                 mt->mt_subtree = NULL;
1859                         } else {
1860                                 metasubtree_t *ms, **mprev;
1861                                 for (i=0, mprev = &mt->mt_subtree, ms = *mprev; ms; ms = *mprev) {
1862                                         if ( i == c->valx ) {
1863                                                 *mprev = ms->ms_next;
1864                                                 meta_subtree_free( ms );
1865                                                 break;
1866                                         }
1867                                         i++;
1868                                         mprev = &ms->ms_next;
1869                                 }
1870                                 if ( i != c->valx )
1871                                         rc = 1;
1872                         }
1873                         break;
1874
1875                 case LDAP_BACK_CFG_FILTER:
1876                         if ( c->valx < 0 ) {
1877                                 meta_filter_destroy( mt->mt_filter );
1878                                 mt->mt_filter = NULL;
1879                         } else {
1880                                 metafilter_t *mf, **mprev;
1881                                 for (i=0, mprev = &mt->mt_filter, mf = *mprev; mf; mf = *mprev) {
1882                                         if ( i == c->valx ) {
1883                                                 *mprev = mf->mf_next;
1884                                                 meta_filter_free( mf );
1885                                                 break;
1886                                         }
1887                                         i++;
1888                                         mprev = &mf->mf_next;
1889                                 }
1890                                 if ( i != c->valx )
1891                                         rc = 1;
1892                         }
1893                         break;
1894
1895                 case LDAP_BACK_CFG_KEEPALIVE:
1896                         mt->mt_tls.sb_keepalive.sk_idle = 0;
1897                         mt->mt_tls.sb_keepalive.sk_probes = 0;
1898                         mt->mt_tls.sb_keepalive.sk_interval = 0;
1899                         break;
1900
1901                 default:
1902                         rc = 1;
1903                         break;
1904                 }
1905
1906                 return rc;
1907         }
1908
1909         if ( c->op == SLAP_CONFIG_ADD ) {
1910                 if ( c->type >= LDAP_BACK_CFG_LAST_BASE ) {
1911                         /* exclude CFG_URI from this check */
1912                         if ( c->type > LDAP_BACK_CFG_LAST_BOTH ) {
1913                                 if ( !mi->mi_ntargets ) {
1914                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1915                                                 "need \"uri\" directive first" );
1916                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1917                                         return 1;
1918                                 }
1919                         }
1920                         if ( mi->mi_ntargets ) {
1921                                 mt = mi->mi_targets[ mi->mi_ntargets-1 ];
1922                                 mc = &mt->mt_mc;
1923                         } else {
1924                                 mt = NULL;
1925                                 mc = &mi->mi_mc;
1926                         }
1927                 }
1928         } else {
1929                 if ( c->table == Cft_Database ) {
1930                         mt = NULL;
1931                         mc = &mi->mi_mc;
1932                 } else {
1933                         mt = c->ca_private;
1934                         if ( mt )
1935                                 mc = &mt->mt_mc;
1936                         else
1937                                 mc = NULL;
1938                 }
1939         }
1940
1941         switch( c->type ) {
1942         case LDAP_BACK_CFG_URI: {
1943                 LDAPURLDesc     *ludp;
1944                 struct berval   dn;
1945                 int             j;
1946
1947                 char            **uris = NULL;
1948
1949                 if ( c->be->be_nsuffix == NULL ) {
1950                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1951                                 "the suffix must be defined before any target" );
1952                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1953                         return 1;
1954                 }
1955
1956                 i = mi->mi_ntargets++;
1957
1958                 mi->mi_targets = ( metatarget_t ** )ch_realloc( mi->mi_targets,
1959                         sizeof( metatarget_t * ) * mi->mi_ntargets );
1960                 if ( mi->mi_targets == NULL ) {
1961                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1962                                 "out of memory while storing server name"
1963                                 " in \"%s <protocol>://<server>[:port]/<naming context>\"",
1964                                 c->argv[0] );
1965                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1966                         return 1;
1967                 }
1968
1969                 if ( meta_back_new_target( &mi->mi_targets[ i ] ) != 0 ) {
1970                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1971                                 "unable to init server"
1972                                 " in \"%s <protocol>://<server>[:port]/<naming context>\"",
1973                                 c->argv[0] );
1974                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1975                         return 1;
1976                 }
1977
1978                 mt = mi->mi_targets[ i ];
1979
1980                 mt->mt_rebind_f = mi->mi_rebind_f;
1981                 mt->mt_urllist_f = mi->mi_urllist_f;
1982                 mt->mt_urllist_p = mt;
1983
1984                 if ( META_BACK_QUARANTINE( mi ) ) {
1985                         ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
1986                 }
1987                 mt->mt_mc = mi->mi_mc;
1988
1989                 for ( j = 1; j < c->argc; j++ ) {
1990                         char    **tmpuris = ldap_str2charray( c->argv[ j ], "\t" );
1991
1992                         if ( tmpuris == NULL ) {
1993                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1994                                         "unable to parse URIs #%d"
1995                                         " in \"%s <protocol>://<server>[:port]/<naming context>\"",
1996                                         j-1, c->argv[0] );
1997                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1998                                 return 1;
1999                         }
2000
2001                         if ( j == 1 ) {
2002                                 uris = tmpuris;
2003
2004                         } else {
2005                                 ldap_charray_merge( &uris, tmpuris );
2006                                 ldap_charray_free( tmpuris );
2007                         }
2008                 }
2009
2010                 for ( j = 0; uris[ j ] != NULL; j++ ) {
2011                         char *tmpuri = NULL;
2012
2013                         /*
2014                          * uri MUST be legal!
2015                          */
2016                         if ( ldap_url_parselist_ext( &ludp, uris[ j ], "\t",
2017                                         LDAP_PVT_URL_PARSE_NONE ) != LDAP_SUCCESS
2018                                 || ludp->lud_next != NULL )
2019                         {
2020                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2021                                         "unable to parse URI #%d"
2022                                         " in \"%s <protocol>://<server>[:port]/<naming context>\"",
2023                                         j-1, c->argv[0] );
2024                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2025                                 ldap_charray_free( uris );
2026                                 return 1;
2027                         }
2028
2029                         if ( j == 0 ) {
2030
2031                                 /*
2032                                  * uri MUST have the <dn> part!
2033                                  */
2034                                 if ( ludp->lud_dn == NULL ) {
2035                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2036                                                 "missing <naming context> "
2037                                                 " in \"%s <protocol>://<server>[:port]/<naming context>\"",
2038                                                 c->argv[0] );
2039                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2040                                         ldap_free_urllist( ludp );
2041                                         ldap_charray_free( uris );
2042                                         return 1;
2043                                 }
2044
2045                                 /*
2046                                  * copies and stores uri and suffix
2047                                  */
2048                                 ber_str2bv( ludp->lud_dn, 0, 0, &dn );
2049                                 rc = dnPrettyNormal( NULL, &dn, &mt->mt_psuffix,
2050                                         &mt->mt_nsuffix, NULL );
2051                                 if ( rc != LDAP_SUCCESS ) {
2052                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2053                                                 "target DN is invalid \"%s\"",
2054                                                 c->argv[1] );
2055                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2056                                         ldap_free_urllist( ludp );
2057                                         ldap_charray_free( uris );
2058                                         return( 1 );
2059                                 }
2060
2061                                 ludp->lud_dn[ 0 ] = '\0';
2062
2063                                 switch ( ludp->lud_scope ) {
2064                                 case LDAP_SCOPE_DEFAULT:
2065                                         mt->mt_scope = LDAP_SCOPE_SUBTREE;
2066                                         break;
2067
2068                                 case LDAP_SCOPE_SUBTREE:
2069                                 case LDAP_SCOPE_SUBORDINATE:
2070                                         mt->mt_scope = ludp->lud_scope;
2071                                         break;
2072
2073                                 default:
2074                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2075                                                 "invalid scope for target \"%s\"",
2076                                                 c->argv[1] );
2077                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2078                                         ldap_free_urllist( ludp );
2079                                         ldap_charray_free( uris );
2080                                         return( 1 );
2081                                 }
2082
2083                         } else {
2084                                 /* check all, to apply the scope check on the first one */
2085                                 if ( ludp->lud_dn != NULL && ludp->lud_dn[ 0 ] != '\0' ) {
2086                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2087                                                 "multiple URIs must have no DN part" );
2088                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2089                                         ldap_free_urllist( ludp );
2090                                         ldap_charray_free( uris );
2091                                         return( 1 );
2092
2093                                 }
2094                         }
2095
2096                         tmpuri = ldap_url_list2urls( ludp );
2097                         ldap_free_urllist( ludp );
2098                         if ( tmpuri == NULL ) {
2099                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "no memory?" );
2100                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2101                                 ldap_charray_free( uris );
2102                                 return( 1 );
2103                         }
2104                         ldap_memfree( uris[ j ] );
2105                         uris[ j ] = tmpuri;
2106                 }
2107
2108                 mt->mt_uri = ldap_charray2str( uris, " " );
2109                 ldap_charray_free( uris );
2110                 if ( mt->mt_uri == NULL) {
2111                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "no memory?" );
2112                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2113                         return( 1 );
2114                 }
2115
2116                 /*
2117                  * uri MUST be a branch of suffix!
2118                  */
2119                 for ( j = 0; !BER_BVISNULL( &c->be->be_nsuffix[ j ] ); j++ ) {
2120                         if ( dnIsSuffix( &mt->mt_nsuffix, &c->be->be_nsuffix[ j ] ) ) {
2121                                 break;
2122                         }
2123                 }
2124
2125                 if ( BER_BVISNULL( &c->be->be_nsuffix[ j ] ) ) {
2126                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2127                                 "<naming context> of URI must be within the naming context of this database." );
2128                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2129                         return 1;
2130                 }
2131                 c->ca_private = mt;
2132                 c->cleanup = meta_cf_cleanup;
2133         } break;
2134         case LDAP_BACK_CFG_SUBTREE_EX:
2135         case LDAP_BACK_CFG_SUBTREE_IN:
2136         /* subtree-exclude */
2137                 if ( meta_subtree_config( mt, c )) {
2138                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2139                         return 1;
2140                 }
2141                 break;
2142
2143         case LDAP_BACK_CFG_FILTER: {
2144                 metafilter_t *mf, **m2;
2145                 mf = ch_malloc( sizeof( metafilter_t ));
2146                 rc = regcomp( &mf->mf_regex, c->argv[1], REG_EXTENDED );
2147                 if ( rc ) {
2148                         char regerr[ SLAP_TEXT_BUFLEN ];
2149                         regerror( rc, &mf->mf_regex, regerr, sizeof(regerr) );
2150                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2151                                 "regular expression \"%s\" bad because of %s",
2152                                 c->argv[1], regerr );
2153                         ch_free( mf );
2154                         return 1;
2155                 }
2156                 ber_str2bv( c->argv[1], 0, 1, &mf->mf_regex_pattern );
2157                 for ( m2 = &mt->mt_filter; *m2; m2 = &(*m2)->mf_next )
2158                         ;
2159                 *m2 = mf;
2160         } break;
2161
2162         case LDAP_BACK_CFG_DEFAULT_T:
2163         /* default target directive */
2164                 i = mi->mi_ntargets - 1;
2165
2166                 if ( c->argc == 1 ) {
2167                         if ( i < 0 ) {
2168                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2169                                         "\"%s\" alone must be inside a \"uri\" directive",
2170                                         c->argv[0] );
2171                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2172                                 return 1;
2173                         }
2174                         mi->mi_defaulttarget = i;
2175
2176                 } else {
2177                         if ( strcasecmp( c->argv[ 1 ], "none" ) == 0 ) {
2178                                 if ( i >= 0 ) {
2179                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2180                                                 "\"%s none\" should go before uri definitions",
2181                                                 c->argv[0] );
2182                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2183                                 }
2184                                 mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
2185
2186                         } else {
2187
2188                                 if ( lutil_atoi( &mi->mi_defaulttarget, c->argv[ 1 ] ) != 0
2189                                         || mi->mi_defaulttarget < 0
2190                                         || mi->mi_defaulttarget >= i - 1 )
2191                                 {
2192                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2193                                                 "illegal target number %d",
2194                                                 mi->mi_defaulttarget );
2195                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2196                                         return 1;
2197                                 }
2198                         }
2199                 }
2200                 break;
2201
2202         case LDAP_BACK_CFG_DNCACHE_TTL:
2203         /* ttl of dn cache */
2204                 if ( strcasecmp( c->argv[ 1 ], "forever" ) == 0 ) {
2205                         mi->mi_cache.ttl = META_DNCACHE_FOREVER;
2206
2207                 } else if ( strcasecmp( c->argv[ 1 ], "disabled" ) == 0 ) {
2208                         mi->mi_cache.ttl = META_DNCACHE_DISABLED;
2209
2210                 } else {
2211                         unsigned long   t;
2212
2213                         if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
2214                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2215                                         "unable to parse dncache ttl \"%s\"",
2216                                         c->argv[ 1 ] );
2217                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2218                                 return 1;
2219                         }
2220                         mi->mi_cache.ttl = (time_t)t;
2221                 }
2222                 break;
2223
2224         case LDAP_BACK_CFG_NETWORK_TIMEOUT: {
2225         /* network timeout when connecting to ldap servers */
2226                 unsigned long t;
2227
2228                 if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
2229                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2230                                 "unable to parse network timeout \"%s\"",
2231                                 c->argv[ 1 ] );
2232                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2233                         return 1;
2234                 }
2235                 mc->mc_network_timeout = (time_t)t;
2236                 } break;
2237
2238         case LDAP_BACK_CFG_IDLE_TIMEOUT: {
2239         /* idle timeout when connecting to ldap servers */
2240                 unsigned long   t;
2241
2242                 if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
2243                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2244                                 "unable to parse idle timeout \"%s\"",
2245                                 c->argv[ 1 ] );
2246                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2247                         return 1;
2248
2249                 }
2250                 mi->mi_idle_timeout = (time_t)t;
2251                 } break;
2252
2253         case LDAP_BACK_CFG_CONN_TTL: {
2254         /* conn ttl */
2255                 unsigned long   t;
2256
2257                 if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
2258                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2259                                 "unable to parse conn ttl \"%s\"",
2260                                 c->argv[ 1 ] );
2261                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2262                         return 1;
2263
2264                 }
2265                 mi->mi_conn_ttl = (time_t)t;
2266                 } break;
2267
2268         case LDAP_BACK_CFG_BIND_TIMEOUT:
2269         /* bind timeout when connecting to ldap servers */
2270                 mc->mc_bind_timeout.tv_sec = c->value_ulong/1000000;
2271                 mc->mc_bind_timeout.tv_usec = c->value_ulong%1000000;
2272                 break;
2273
2274         case LDAP_BACK_CFG_ACL_AUTHCDN:
2275         /* name to use for meta_back_group */
2276                 if ( strcasecmp( c->argv[ 0 ], "binddn" ) == 0 ) {
2277                         Debug( LDAP_DEBUG_ANY, "%s: "
2278                                 "\"binddn\" statement is deprecated; "
2279                                 "use \"acl-authcDN\" instead\n",
2280                                 c->log, 0, 0 );
2281                         /* FIXME: some day we'll need to throw an error */
2282                 }
2283
2284                 ber_memfree_x( c->value_dn.bv_val, NULL );
2285                 mt->mt_binddn = c->value_ndn;
2286                 BER_BVZERO( &c->value_dn );
2287                 BER_BVZERO( &c->value_ndn );
2288                 break;
2289
2290         case LDAP_BACK_CFG_ACL_PASSWD:
2291         /* password to use for meta_back_group */
2292                 if ( strcasecmp( c->argv[ 0 ], "bindpw" ) == 0 ) {
2293                         Debug( LDAP_DEBUG_ANY, "%s "
2294                                 "\"bindpw\" statement is deprecated; "
2295                                 "use \"acl-passwd\" instead\n",
2296                                 c->log, 0, 0 );
2297                         /* FIXME: some day we'll need to throw an error */
2298                 }
2299
2300                 ber_str2bv( c->argv[ 1 ], 0L, 1, &mt->mt_bindpw );
2301                 break;
2302
2303         case LDAP_BACK_CFG_REBIND:
2304         /* save bind creds for referral rebinds? */
2305                 if ( c->argc == 1 || c->value_int ) {
2306                         mc->mc_flags |= LDAP_BACK_F_SAVECRED;
2307                 } else {
2308                         mc->mc_flags &= ~LDAP_BACK_F_SAVECRED;
2309                 }
2310                 break;
2311
2312         case LDAP_BACK_CFG_CHASE:
2313                 if ( c->argc == 1 || c->value_int ) {
2314                         mc->mc_flags |= LDAP_BACK_F_CHASE_REFERRALS;
2315                 } else {
2316                         mc->mc_flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
2317                 }
2318                 break;
2319
2320         case LDAP_BACK_CFG_TLS:
2321                 i = verb_to_mask( c->argv[1], tls_mode );
2322                 if ( BER_BVISNULL( &tls_mode[i].word ) ) {
2323                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2324                                 "%s unknown argument \"%s\"",
2325                                 c->argv[0], c->argv[1] );
2326                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2327                         return 1;
2328                 }
2329                 mc->mc_flags &= ~LDAP_BACK_F_TLS_MASK;
2330                 mc->mc_flags |= tls_mode[i].mask;
2331
2332                 if ( c->argc > 2 ) {
2333                         if ( c->op == SLAP_CONFIG_ADD && mi->mi_ntargets == 0 ) {
2334                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2335                                         "need \"uri\" directive first" );
2336                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2337                                 return 1;
2338                         }
2339
2340                         for ( i = 2; i < c->argc; i++ ) {
2341                                 if ( bindconf_tls_parse( c->argv[i], &mt->mt_tls ))
2342                                         return 1;
2343                         }
2344                         bindconf_tls_defaults( &mt->mt_tls );
2345                 }
2346                 break;
2347
2348         case LDAP_BACK_CFG_T_F:
2349                 i = verb_to_mask( c->argv[1], t_f_mode );
2350                 if ( BER_BVISNULL( &t_f_mode[i].word ) ) {
2351                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2352                                 "%s unknown argument \"%s\"",
2353                                 c->argv[0], c->argv[1] );
2354                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2355                         return 1;
2356                 }
2357                 mc->mc_flags &= ~LDAP_BACK_F_T_F_MASK2;
2358                 mc->mc_flags |= t_f_mode[i].mask;
2359                 break;
2360
2361         case LDAP_BACK_CFG_ONERR:
2362         /* onerr? */
2363                 i = verb_to_mask( c->argv[1], onerr_mode );
2364                 if ( BER_BVISNULL( &onerr_mode[i].word ) ) {
2365                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2366                                 "%s unknown argument \"%s\"",
2367                                 c->argv[0], c->argv[1] );
2368                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2369                         return 1;
2370                 }
2371                 mi->mi_flags &= ~META_BACK_F_ONERR_MASK;
2372                 mi->mi_flags |= onerr_mode[i].mask;
2373                 break;
2374
2375         case LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER:
2376         /* bind-defer? */
2377                 if ( c->argc == 1 || c->value_int ) {
2378                         mi->mi_flags |= META_BACK_F_DEFER_ROOTDN_BIND;
2379                 } else {
2380                         mi->mi_flags &= ~META_BACK_F_DEFER_ROOTDN_BIND;
2381                 }
2382                 break;
2383
2384         case LDAP_BACK_CFG_SINGLECONN:
2385         /* single-conn? */
2386                 if ( mi->mi_ntargets > 0 ) {
2387                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2388                                 "\"%s\" must appear before target definitions",
2389                                 c->argv[0] );
2390                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2391                         return( 1 );
2392                 }
2393                 if ( c->value_int ) {
2394                         mi->mi_flags |= LDAP_BACK_F_SINGLECONN;
2395                 } else {
2396                         mi->mi_flags &= ~LDAP_BACK_F_SINGLECONN;
2397                 }
2398                 break;
2399
2400         case LDAP_BACK_CFG_USETEMP:
2401         /* use-temporaries? */
2402                 if ( mi->mi_ntargets > 0 ) {
2403                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2404                                 "\"%s\" must appear before target definitions",
2405                                 c->argv[0] );
2406                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2407                         return( 1 );
2408                 }
2409                 if ( c->value_int ) {
2410                         mi->mi_flags |= LDAP_BACK_F_USE_TEMPORARIES;
2411                 } else {
2412                         mi->mi_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
2413                 }
2414                 break;
2415
2416         case LDAP_BACK_CFG_CONNPOOLMAX:
2417         /* privileged connections pool max size ? */
2418                 if ( mi->mi_ntargets > 0 ) {
2419                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2420                                 "\"%s\" must appear before target definitions",
2421                                 c->argv[0] );
2422                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2423                         return( 1 );
2424                 }
2425
2426                 if ( c->value_int < LDAP_BACK_CONN_PRIV_MIN
2427                         || c->value_int > LDAP_BACK_CONN_PRIV_MAX )
2428                 {
2429                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2430                                 "invalid max size " "of privileged "
2431                                 "connections pool \"%s\" "
2432                                 "in \"conn-pool-max <n> "
2433                                 "(must be between %d and %d)\"",
2434                                 c->argv[ 1 ],
2435                                 LDAP_BACK_CONN_PRIV_MIN,
2436                                 LDAP_BACK_CONN_PRIV_MAX );
2437                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2438                         return 1;
2439                 }
2440                 mi->mi_conn_priv_max = c->value_int;
2441                 break;
2442
2443         case LDAP_BACK_CFG_CANCEL:
2444                 i = verb_to_mask( c->argv[1], cancel_mode );
2445                 if ( BER_BVISNULL( &cancel_mode[i].word ) ) {
2446                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2447                                 "%s unknown argument \"%s\"",
2448                                 c->argv[0], c->argv[1] );
2449                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2450                         return 1;
2451                 }
2452                 mc->mc_flags &= ~LDAP_BACK_F_CANCEL_MASK2;
2453                 mc->mc_flags |= t_f_mode[i].mask;
2454                 break;
2455
2456         case LDAP_BACK_CFG_TIMEOUT:
2457                 for ( i = 1; i < c->argc; i++ ) {
2458                         if ( isdigit( (unsigned char) c->argv[ i ][ 0 ] ) ) {
2459                                 int             j;
2460                                 unsigned        u;
2461
2462                                 if ( lutil_atoux( &u, c->argv[ i ], 0 ) != 0 ) {
2463                                         snprintf( c->cr_msg, sizeof( c->cr_msg),
2464                                                 "unable to parse timeout \"%s\"",
2465                                                 c->argv[ i ] );
2466                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2467                                         return 1;
2468                                 }
2469
2470                                 for ( j = 0; j < SLAP_OP_LAST; j++ ) {
2471                                         mc->mc_timeout[ j ] = u;
2472                                 }
2473
2474                                 continue;
2475                         }
2476
2477                         if ( slap_cf_aux_table_parse( c->argv[ i ], mc->mc_timeout, timeout_table, "slapd-meta timeout" ) ) {
2478                                 snprintf( c->cr_msg, sizeof( c->cr_msg),
2479                                         "unable to parse timeout \"%s\"",
2480                                         c->argv[ i ] );
2481                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2482                                 return 1;
2483                         }
2484                 }
2485                 break;
2486
2487         case LDAP_BACK_CFG_PSEUDOROOTDN:
2488         /* name to use as pseudo-root dn */
2489                 /*
2490                  * exact replacement:
2491                  *
2492
2493 idassert-bind   bindmethod=simple
2494                 binddn=<pseudorootdn>
2495                 credentials=<pseudorootpw>
2496                 mode=none
2497                 flags=non-prescriptive
2498 idassert-authzFrom      "dn:<rootdn>"
2499
2500                  * so that only when authc'd as <rootdn> the proxying occurs
2501                  * rebinding as the <pseudorootdn> without proxyAuthz.
2502                  */
2503
2504                 Debug( LDAP_DEBUG_ANY,
2505                         "%s: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
2506                         "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
2507                         c->log, 0, 0 );
2508
2509                 {
2510                         char    binddn[ SLAP_TEXT_BUFLEN ];
2511                         char    *cargv[] = {
2512                                 "idassert-bind",
2513                                 "bindmethod=simple",
2514                                 NULL,
2515                                 "mode=none",
2516                                 "flags=non-prescriptive",
2517                                 NULL
2518                         };
2519                         char **oargv;
2520                         int oargc;
2521                         int     cargc = 5;
2522                         int     rc;
2523
2524
2525                         if ( BER_BVISNULL( &c->be->be_rootndn ) ) {
2526                                 Debug( LDAP_DEBUG_ANY, "%s: \"pseudorootpw\": \"rootdn\" must be defined first.\n",
2527                                         c->log, 0, 0 );
2528                                 return 1;
2529                         }
2530
2531                         if ( sizeof( binddn ) <= (unsigned) snprintf( binddn,
2532                                         sizeof( binddn ), "binddn=%s", c->argv[ 1 ] ))
2533                         {
2534                                 Debug( LDAP_DEBUG_ANY, "%s: \"pseudorootdn\" too long.\n",
2535                                         c->log, 0, 0 );
2536                                 return 1;
2537                         }
2538                         cargv[ 2 ] = binddn;
2539
2540                         oargv = c->argv;
2541                         oargc = c->argc;
2542                         c->argv = cargv;
2543                         c->argc = cargc;
2544                         rc = mi->mi_ldap_extra->idassert_parse( c, &mt->mt_idassert );
2545                         c->argv = oargv;
2546                         c->argc = oargc;
2547                         if ( rc == 0 ) {
2548                                 struct berval   bv;
2549
2550                                 if ( mt->mt_idassert_authz != NULL ) {
2551                                         Debug( LDAP_DEBUG_ANY, "%s: \"idassert-authzFrom\" already defined (discarded).\n",
2552                                                 c->log, 0, 0 );
2553                                         ber_bvarray_free( mt->mt_idassert_authz );
2554                                         mt->mt_idassert_authz = NULL;
2555                                 }
2556
2557                                 assert( !BER_BVISNULL( &mt->mt_idassert_authcDN ) );
2558
2559                                 bv.bv_len = STRLENOF( "dn:" ) + c->be->be_rootndn.bv_len;
2560                                 bv.bv_val = ber_memalloc( bv.bv_len + 1 );
2561                                 AC_MEMCPY( bv.bv_val, "dn:", STRLENOF( "dn:" ) );
2562                                 AC_MEMCPY( &bv.bv_val[ STRLENOF( "dn:" ) ], c->be->be_rootndn.bv_val, c->be->be_rootndn.bv_len + 1 );
2563
2564                                 ber_bvarray_add( &mt->mt_idassert_authz, &bv );
2565                         }
2566
2567                         return rc;
2568                 }
2569                 break;
2570
2571         case LDAP_BACK_CFG_PSEUDOROOTPW:
2572         /* password to use as pseudo-root */
2573                 Debug( LDAP_DEBUG_ANY,
2574                         "%s: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
2575                         "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
2576                         c->log, 0, 0 );
2577
2578                 if ( BER_BVISNULL( &mt->mt_idassert_authcDN ) ) {
2579                         Debug( LDAP_DEBUG_ANY, "%s: \"pseudorootpw\": \"pseudorootdn\" must be defined first.\n",
2580                                 c->log, 0, 0 );
2581                         return 1;
2582                 }
2583
2584                 if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) {
2585                         memset( mt->mt_idassert_passwd.bv_val, 0,
2586                                 mt->mt_idassert_passwd.bv_len );
2587                         ber_memfree( mt->mt_idassert_passwd.bv_val );
2588                 }
2589                 ber_str2bv( c->argv[ 1 ], 0, 1, &mt->mt_idassert_passwd );
2590                 break;
2591
2592         case LDAP_BACK_CFG_IDASSERT_BIND:
2593         /* idassert-bind */
2594                 rc = mi->mi_ldap_extra->idassert_parse( c, &mt->mt_idassert );
2595                 break;
2596
2597         case LDAP_BACK_CFG_IDASSERT_AUTHZFROM:
2598         /* idassert-authzFrom */
2599                 rc = mi->mi_ldap_extra->idassert_authzfrom_parse( c, &mt->mt_idassert );
2600                 break;
2601
2602         case LDAP_BACK_CFG_QUARANTINE:
2603         /* quarantine */
2604                 if ( META_BACK_CMN_QUARANTINE( mc ) )
2605                 {
2606                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2607                                 "quarantine already defined" );
2608                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2609                         return 1;
2610                 }
2611
2612                 if ( mt ) {
2613                         mc->mc_quarantine.ri_interval = NULL;
2614                         mc->mc_quarantine.ri_num = NULL;
2615                         if ( !META_BACK_QUARANTINE( mi ) ) {
2616                                 ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
2617                         }
2618                 }
2619
2620                 if ( mi->mi_ldap_extra->retry_info_parse( c->argv[ 1 ], &mc->mc_quarantine, c->cr_msg, sizeof( c->cr_msg ) ) ) {
2621                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2622                         return 1;
2623                 }
2624
2625                 mc->mc_flags |= LDAP_BACK_F_QUARANTINE;
2626                 break;
2627
2628 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
2629         case LDAP_BACK_CFG_ST_REQUEST:
2630         /* session tracking request */
2631                 if ( c->value_int ) {
2632                         mc->mc_flags |= LDAP_BACK_F_ST_REQUEST;
2633                 } else {
2634                         mc->mc_flags &= ~LDAP_BACK_F_ST_REQUEST;
2635                 }
2636                 break;
2637 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
2638
2639         case LDAP_BACK_CFG_SUFFIXM:     /* FALLTHRU */
2640         case LDAP_BACK_CFG_REWRITE: {
2641         /* rewrite stuff ... */
2642                 ConfigArgs ca = { 0 };
2643                 char *line, **argv;
2644                 struct rewrite_info *rwi;
2645                 int cnt = 0, argc, ix = c->valx;
2646
2647                 if ( mt->mt_rwmap.rwm_bva_rewrite ) {
2648                         for ( ; !BER_BVISNULL( &mt->mt_rwmap.rwm_bva_rewrite[ cnt ] ); cnt++ )
2649                                 /* count */ ;
2650                 }
2651
2652                 if ( ix >= cnt || ix < 0 ) {
2653                         ix = cnt;
2654                 } else {
2655                         rwi = mt->mt_rwmap.rwm_rw;
2656
2657                         mt->mt_rwmap.rwm_rw = NULL;
2658                         rc = meta_rwi_init( &mt->mt_rwmap.rwm_rw );
2659
2660                         /* re-parse all rewrite rules, up to the one
2661                          * that needs to be added */
2662                         ca.fname = c->fname;
2663                         ca.lineno = c->lineno;
2664                         for ( i = 0; i < ix; i++ ) {
2665                                 ca.line = mt->mt_rwmap.rwm_bva_rewrite[ i ].bv_val;
2666                                 ca.argc = 0;
2667                                 config_fp_parse_line( &ca );
2668
2669                                 if ( !strcasecmp( ca.argv[0], "suffixmassage" )) {
2670                                         rc = meta_suffixm_config( &ca, ca.argc, ca.argv, mt );
2671                                 } else {
2672                                         rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
2673                                                 c->fname, c->lineno, ca.argc, ca.argv );
2674                                 }
2675                                 assert( rc == 0 );
2676                                 ch_free( ca.argv );
2677                                 ch_free( ca.tline );
2678                         }
2679                 }
2680                 argc = c->argc;
2681                 argv = c->argv;
2682                 if ( c->op != SLAP_CONFIG_ADD ) {
2683                         argc--;
2684                         argv++;
2685                 }
2686                 /* add the new rule */
2687                 if ( !strcasecmp( argv[0], "suffixmassage" )) {
2688                         rc = meta_suffixm_config( c, argc, argv, mt );
2689                 } else {
2690                         rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
2691                                                 c->fname, c->lineno, argc, argv );
2692                 }
2693                 if ( rc ) {
2694                         if ( ix < cnt ) {
2695                                 rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
2696                                 mt->mt_rwmap.rwm_rw = rwi;
2697                         }
2698                         return 1;
2699                 }
2700                 if ( ix < cnt ) {
2701                         for ( ; i < cnt; i++ ) {
2702                                 ca.line = mt->mt_rwmap.rwm_bva_rewrite[ i ].bv_val;
2703                                 ca.argc = 0;
2704                                 config_fp_parse_line( &ca );
2705
2706                                 if ( !strcasecmp( ca.argv[0], "suffixmassage" )) {
2707                                         rc = meta_suffixm_config( &ca, ca.argc, ca.argv, mt );
2708                                 } else {
2709                                         rc = rewrite_parse( mt->mt_rwmap.rwm_rw,
2710                                                 c->fname, c->lineno, ca.argc, argv );
2711                                 }
2712                                 assert( rc == 0 );
2713                                 ch_free( ca.argv );
2714                                 ch_free( ca.tline );
2715                         }
2716                 }
2717
2718                 /* save the rule info */
2719                 line = ldap_charray2str( argv, "\" \"" );
2720                 if ( line != NULL ) {
2721                         struct berval bv;
2722                         int len = strlen( argv[ 0 ] );
2723
2724                         ber_str2bv( line, 0, 0, &bv );
2725                         AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
2726                                 bv.bv_len - ( len + 1 ));
2727                         bv.bv_val[ bv.bv_len - 1] = '"';
2728                         ber_bvarray_add( &mt->mt_rwmap.rwm_bva_rewrite, &bv );
2729                         /* move it to the right slot */
2730                         if ( ix < cnt ) {
2731                                 for ( i=cnt; i>ix; i-- )
2732                                         mt->mt_rwmap.rwm_bva_rewrite[i+1] = mt->mt_rwmap.rwm_bva_rewrite[i];
2733                                 mt->mt_rwmap.rwm_bva_rewrite[i] = bv;
2734
2735                                 /* destroy old rules */
2736                                 rewrite_info_delete( &rwi );
2737                         }
2738                 }
2739                 } break;
2740
2741         case LDAP_BACK_CFG_MAP: {
2742         /* objectclass/attribute mapping */
2743                 ConfigArgs ca = { 0 };
2744                 char *argv[5];
2745                 struct ldapmap rwm_oc;
2746                 struct ldapmap rwm_at;
2747                 int cnt = 0, ix = c->valx;
2748
2749                 if ( mt->mt_rwmap.rwm_bva_map ) {
2750                         for ( ; !BER_BVISNULL( &mt->mt_rwmap.rwm_bva_map[ cnt ] ); cnt++ )
2751                                 /* count */ ;
2752                 }
2753
2754                 if ( ix >= cnt || ix < 0 ) {
2755                         ix = cnt;
2756                 } else {
2757                         rwm_oc = mt->mt_rwmap.rwm_oc;
2758                         rwm_at = mt->mt_rwmap.rwm_at;
2759
2760                         memset( &mt->mt_rwmap.rwm_oc, 0, sizeof( mt->mt_rwmap.rwm_oc ) );
2761                         memset( &mt->mt_rwmap.rwm_at, 0, sizeof( mt->mt_rwmap.rwm_at ) );
2762
2763                         /* re-parse all mappings, up to the one
2764                          * that needs to be added */
2765                         argv[0] = c->argv[0];
2766                         ca.fname = c->fname;
2767                         ca.lineno = c->lineno;
2768                         for ( i = 0; i < ix; i++ ) {
2769                                 ca.line = mt->mt_rwmap.rwm_bva_map[ i ].bv_val;
2770                                 ca.argc = 0;
2771                                 config_fp_parse_line( &ca );
2772
2773                                 argv[1] = ca.argv[0];
2774                                 argv[2] = ca.argv[1];
2775                                 argv[3] = ca.argv[2];
2776                                 argv[4] = ca.argv[3];
2777                                 ch_free( ca.argv );
2778                                 ca.argv = argv;
2779                                 ca.argc++;
2780                                 rc = ldap_back_map_config( &ca, &mt->mt_rwmap.rwm_oc,
2781                                         &mt->mt_rwmap.rwm_at );
2782
2783                                 ch_free( ca.tline );
2784                                 ca.tline = NULL;
2785                                 ca.argv = NULL;
2786
2787                                 /* in case of failure, restore
2788                                  * the existing mapping */
2789                                 if ( rc ) {
2790                                         goto map_fail;
2791                                 }
2792                         }
2793                 }
2794                 /* add the new mapping */
2795                 rc = ldap_back_map_config( c, &mt->mt_rwmap.rwm_oc,
2796                                         &mt->mt_rwmap.rwm_at );
2797                 if ( rc ) {
2798                         goto map_fail;
2799                 }
2800
2801                 if ( ix < cnt ) {
2802                         for ( ; i<cnt ; cnt++ ) {
2803                                 ca.line = mt->mt_rwmap.rwm_bva_map[ i ].bv_val;
2804                                 ca.argc = 0;
2805                                 config_fp_parse_line( &ca );
2806
2807                                 argv[1] = ca.argv[0];
2808                                 argv[2] = ca.argv[1];
2809                                 argv[3] = ca.argv[2];
2810                                 argv[4] = ca.argv[3];
2811
2812                                 ch_free( ca.argv );
2813                                 ca.argv = argv;
2814                                 ca.argc++;
2815                                 rc = ldap_back_map_config( &ca, &mt->mt_rwmap.rwm_oc,
2816                                         &mt->mt_rwmap.rwm_at );
2817
2818                                 ch_free( ca.tline );
2819                                 ca.tline = NULL;
2820                                 ca.argv = NULL;
2821
2822                                 /* in case of failure, restore
2823                                  * the existing mapping */
2824                                 if ( rc ) {
2825                                         goto map_fail;
2826                                 }
2827                         }
2828                 }
2829
2830                 /* save the map info */
2831                 argv[0] = ldap_charray2str( &c->argv[ 1 ], " " );
2832                 if ( argv[0] != NULL ) {
2833                         struct berval bv;
2834                         ber_str2bv( argv[0], 0, 0, &bv );
2835                         ber_bvarray_add( &mt->mt_rwmap.rwm_bva_map, &bv );
2836                         /* move it to the right slot */
2837                         if ( ix < cnt ) {
2838                                 for ( i=cnt; i>ix; i-- )
2839                                         mt->mt_rwmap.rwm_bva_map[i+1] = mt->mt_rwmap.rwm_bva_map[i];
2840                                 mt->mt_rwmap.rwm_bva_map[i] = bv;
2841
2842                                 /* destroy old mapping */
2843                                 meta_back_map_free( &rwm_oc );
2844                                 meta_back_map_free( &rwm_at );
2845                         }
2846                 }
2847                 break;
2848
2849 map_fail:;
2850                 if ( ix < cnt ) {
2851                         meta_back_map_free( &mt->mt_rwmap.rwm_oc );
2852                         meta_back_map_free( &mt->mt_rwmap.rwm_at );
2853                         mt->mt_rwmap.rwm_oc = rwm_oc;
2854                         mt->mt_rwmap.rwm_at = rwm_at;
2855                 }
2856                 } break;
2857
2858         case LDAP_BACK_CFG_NRETRIES: {
2859                 int             nretries = META_RETRY_UNDEFINED;
2860
2861                 if ( strcasecmp( c->argv[ 1 ], "forever" ) == 0 ) {
2862                         nretries = META_RETRY_FOREVER;
2863
2864                 } else if ( strcasecmp( c->argv[ 1 ], "never" ) == 0 ) {
2865                         nretries = META_RETRY_NEVER;
2866
2867                 } else {
2868                         if ( lutil_atoi( &nretries, c->argv[ 1 ] ) != 0 ) {
2869                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2870                                         "unable to parse nretries {never|forever|<retries>}: \"%s\"",
2871                                         c->argv[ 1 ] );
2872                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2873                                 return 1;
2874                         }
2875                 }
2876
2877                 mc->mc_nretries = nretries;
2878                 } break;
2879
2880         case LDAP_BACK_CFG_VERSION:
2881                 if ( c->value_int != 0 && ( c->value_int < LDAP_VERSION_MIN || c->value_int > LDAP_VERSION_MAX ) ) {
2882                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2883                                 "unsupported protocol version \"%s\"",
2884                                 c->argv[ 1 ] );
2885                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2886                         return 1;
2887                 }
2888                 mc->mc_version = c->value_int;
2889                 break;
2890
2891         case LDAP_BACK_CFG_NOREFS:
2892         /* do not return search references */
2893                 if ( c->value_int ) {
2894                         mc->mc_flags |= LDAP_BACK_F_NOREFS;
2895                 } else {
2896                         mc->mc_flags &= ~LDAP_BACK_F_NOREFS;
2897                 }
2898                 break;
2899
2900         case LDAP_BACK_CFG_NOUNDEFFILTER:
2901         /* do not propagate undefined search filters */
2902                 if ( c->value_int ) {
2903                         mc->mc_flags |= LDAP_BACK_F_NOUNDEFFILTER;
2904                 } else {
2905                         mc->mc_flags &= ~LDAP_BACK_F_NOUNDEFFILTER;
2906                 }
2907                 break;
2908
2909 #ifdef SLAPD_META_CLIENT_PR
2910         case LDAP_BACK_CFG_CLIENT_PR:
2911                 if ( strcasecmp( c->argv[ 1 ], "accept-unsolicited" ) == 0 ) {
2912                         mc->mc_ps = META_CLIENT_PR_ACCEPT_UNSOLICITED;
2913
2914                 } else if ( strcasecmp( c->argv[ 1 ], "disable" ) == 0 ) {
2915                         mc->mc_ps = META_CLIENT_PR_DISABLE;
2916
2917                 } else if ( lutil_atoi( &mc->mc_ps, c->argv[ 1 ] ) || mc->mc_ps < -1 ) {
2918                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
2919                                 "unable to parse client-pr {accept-unsolicited|disable|<size>}: \"%s\"",
2920                                 c->argv[ 1 ] );
2921                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
2922                         return( 1 );
2923                 }
2924                 break;
2925 #endif /* SLAPD_META_CLIENT_PR */
2926
2927         case LDAP_BACK_CFG_KEEPALIVE:
2928                 slap_keepalive_parse( ber_bvstrdup(c->argv[1]),
2929                                  &mt->mt_tls.sb_keepalive, 0, 0, 0);
2930                 break;
2931
2932         /* anything else */
2933         default:
2934                 return SLAP_CONF_UNKNOWN;
2935         }
2936
2937         return rc;
2938 }
2939
2940 int
2941 meta_back_init_cf( BackendInfo *bi )
2942 {
2943         int                     rc;
2944         AttributeDescription    *ad = NULL;
2945         const char              *text;
2946
2947         /* Make sure we don't exceed the bits reserved for userland */
2948         config_check_userland( LDAP_BACK_CFG_LAST );
2949
2950         bi->bi_cf_ocs = metaocs;
2951
2952         rc = config_register_schema( metacfg, metaocs );
2953         if ( rc ) {
2954                 return rc;
2955         }
2956
2957         /* setup olcDbAclPasswd and olcDbIDAssertPasswd
2958          * to be base64-encoded when written in LDIF form;
2959          * basically, we don't care if it fails */
2960         rc = slap_str2ad( "olcDbACLPasswd", &ad, &text );
2961         if ( rc ) {
2962                 Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
2963                         "warning, unable to get \"olcDbACLPasswd\" "
2964                         "attribute description: %d: %s\n",
2965                         rc, text, 0 );
2966         } else {
2967                 (void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
2968                         ad->ad_type->sat_oid );
2969         }
2970
2971         ad = NULL;
2972         rc = slap_str2ad( "olcDbIDAssertPasswd", &ad, &text );
2973         if ( rc ) {
2974                 Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
2975                         "warning, unable to get \"olcDbIDAssertPasswd\" "
2976                         "attribute description: %d: %s\n",
2977                         rc, text, 0 );
2978         } else {
2979                 (void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
2980                         ad->ad_type->sat_oid );
2981         }
2982
2983         return 0;
2984 }
2985
2986 static int
2987 ldap_back_map_config(
2988                 ConfigArgs *c,
2989                 struct ldapmap  *oc_map,
2990                 struct ldapmap  *at_map )
2991 {
2992         struct ldapmap          *map;
2993         struct ldapmapping      *mapping;
2994         char                    *src, *dst;
2995         int                     is_oc = 0;
2996
2997         if ( strcasecmp( c->argv[ 1 ], "objectclass" ) == 0 ) {
2998                 map = oc_map;
2999                 is_oc = 1;
3000
3001         } else if ( strcasecmp( c->argv[ 1 ], "attribute" ) == 0 ) {
3002                 map = at_map;
3003
3004         } else {
3005                 snprintf( c->cr_msg, sizeof(c->cr_msg),
3006                         "%s unknown argument \"%s\"",
3007                         c->argv[0], c->argv[1] );
3008                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3009                 return 1;
3010         }
3011
3012         if ( !is_oc && map->map == NULL ) {
3013                 /* only init if required */
3014                 ldap_back_map_init( map, &mapping );
3015         }
3016
3017         if ( strcmp( c->argv[ 2 ], "*" ) == 0 ) {
3018                 if ( c->argc < 4 || strcmp( c->argv[ 3 ], "*" ) == 0 ) {
3019                         map->drop_missing = ( c->argc < 4 );
3020                         goto success_return;
3021                 }
3022                 src = dst = c->argv[ 3 ];
3023
3024         } else if ( c->argc < 4 ) {
3025                 src = "";
3026                 dst = c->argv[ 2 ];
3027
3028         } else {
3029                 src = c->argv[ 2 ];
3030                 dst = ( strcmp( c->argv[ 3 ], "*" ) == 0 ? src : c->argv[ 3 ] );
3031         }
3032
3033         if ( ( map == at_map )
3034                 && ( strcasecmp( src, "objectclass" ) == 0
3035                         || strcasecmp( dst, "objectclass" ) == 0 ) )
3036         {
3037                 snprintf( c->cr_msg, sizeof(c->cr_msg),
3038                         "objectclass attribute cannot be mapped" );
3039                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3040                 return 1;
3041         }
3042
3043         mapping = (struct ldapmapping *)ch_calloc( 2,
3044                 sizeof(struct ldapmapping) );
3045         if ( mapping == NULL ) {
3046                 snprintf( c->cr_msg, sizeof(c->cr_msg),
3047                         "out of memory" );
3048                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3049                 return 1;
3050         }
3051         ber_str2bv( src, 0, 1, &mapping[ 0 ].src );
3052         ber_str2bv( dst, 0, 1, &mapping[ 0 ].dst );
3053         mapping[ 1 ].src = mapping[ 0 ].dst;
3054         mapping[ 1 ].dst = mapping[ 0 ].src;
3055
3056         /*
3057          * schema check
3058          */
3059         if ( is_oc ) {
3060                 if ( src[ 0 ] != '\0' ) {
3061                         if ( oc_bvfind( &mapping[ 0 ].src ) == NULL ) {
3062                                 Debug( LDAP_DEBUG_ANY,
3063         "warning, source objectClass '%s' should be defined in schema\n",
3064                                         c->log, src, 0 );
3065
3066                                 /*
3067                                  * FIXME: this should become an err
3068                                  */
3069                                 goto error_return;
3070                         }
3071                 }
3072
3073                 if ( oc_bvfind( &mapping[ 0 ].dst ) == NULL ) {
3074                         Debug( LDAP_DEBUG_ANY,
3075         "warning, destination objectClass '%s' is not defined in schema\n",
3076                                 c->log, dst, 0 );
3077                 }
3078         } else {
3079                 int                     rc;
3080                 const char              *text = NULL;
3081                 AttributeDescription    *ad = NULL;
3082
3083                 if ( src[ 0 ] != '\0' ) {
3084                         rc = slap_bv2ad( &mapping[ 0 ].src, &ad, &text );
3085                         if ( rc != LDAP_SUCCESS ) {
3086                                 Debug( LDAP_DEBUG_ANY,
3087         "warning, source attributeType '%s' should be defined in schema\n",
3088                                         c->log, src, 0 );
3089
3090                                 /*
3091                                  * FIXME: this should become an err
3092                                  */
3093                                 /*
3094                                  * we create a fake "proxied" ad
3095                                  * and add it here.
3096                                  */
3097
3098                                 rc = slap_bv2undef_ad( &mapping[ 0 ].src,
3099                                                 &ad, &text, SLAP_AD_PROXIED );
3100                                 if ( rc != LDAP_SUCCESS ) {
3101                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
3102                                                 "source attributeType \"%s\": %d (%s)",
3103                                                 src, rc, text ? text : "" );
3104                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3105                                         goto error_return;
3106                                 }
3107                         }
3108
3109                         ad = NULL;
3110                 }
3111
3112                 rc = slap_bv2ad( &mapping[ 0 ].dst, &ad, &text );
3113                 if ( rc != LDAP_SUCCESS ) {
3114                         Debug( LDAP_DEBUG_ANY,
3115         "warning, destination attributeType '%s' is not defined in schema\n",
3116                                 c->log, dst, 0 );
3117
3118                         /*
3119                          * we create a fake "proxied" ad
3120                          * and add it here.
3121                          */
3122
3123                         rc = slap_bv2undef_ad( &mapping[ 0 ].dst,
3124                                         &ad, &text, SLAP_AD_PROXIED );
3125                         if ( rc != LDAP_SUCCESS ) {
3126                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
3127                                         "destination attributeType \"%s\": %d (%s)\n",
3128                                         dst, rc, text ? text : "" );
3129                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3130                                 return 1;
3131                         }
3132                 }
3133         }
3134
3135         if ( (src[ 0 ] != '\0' && avl_find( map->map, (caddr_t)&mapping[ 0 ], mapping_cmp ) != NULL)
3136                         || avl_find( map->remap, (caddr_t)&mapping[ 1 ], mapping_cmp ) != NULL)
3137         {
3138                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
3139                         "duplicate mapping found." );
3140                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
3141                 goto error_return;
3142         }
3143
3144         if ( src[ 0 ] != '\0' ) {
3145                 avl_insert( &map->map, (caddr_t)&mapping[ 0 ],
3146                                         mapping_cmp, mapping_dup );
3147         }
3148         avl_insert( &map->remap, (caddr_t)&mapping[ 1 ],
3149                                 mapping_cmp, mapping_dup );
3150
3151 success_return:;
3152         return 0;
3153
3154 error_return:;
3155         if ( mapping ) {
3156                 ch_free( mapping[ 0 ].src.bv_val );
3157                 ch_free( mapping[ 0 ].dst.bv_val );
3158                 ch_free( mapping );
3159         }
3160
3161         return 1;
3162 }
3163
3164
3165 #ifdef ENABLE_REWRITE
3166 static char *
3167 suffix_massage_regexize( const char *s )
3168 {
3169         char *res, *ptr;
3170         const char *p, *r;
3171         int i;
3172
3173         if ( s[ 0 ] == '\0' ) {
3174                 return ch_strdup( "^(.+)$" );
3175         }
3176
3177         for ( i = 0, p = s;
3178                         ( r = strchr( p, ',' ) ) != NULL;
3179                         p = r + 1, i++ )
3180                 ;
3181
3182         res = ch_calloc( sizeof( char ),
3183                         strlen( s )
3184                         + STRLENOF( "((.+),)?" )
3185                         + STRLENOF( "[ ]?" ) * i
3186                         + STRLENOF( "$" ) + 1 );
3187
3188         ptr = lutil_strcopy( res, "((.+),)?" );
3189         for ( i = 0, p = s;
3190                         ( r = strchr( p, ',' ) ) != NULL;
3191                         p = r + 1 , i++ ) {
3192                 ptr = lutil_strncopy( ptr, p, r - p + 1 );
3193                 ptr = lutil_strcopy( ptr, "[ ]?" );
3194
3195                 if ( r[ 1 ] == ' ' ) {
3196                         r++;
3197                 }
3198         }
3199         ptr = lutil_strcopy( ptr, p );
3200         ptr[ 0 ] = '$';
3201         ptr++;
3202         ptr[ 0 ] = '\0';
3203
3204         return res;
3205 }
3206
3207 static char *
3208 suffix_massage_patternize( const char *s, const char *p )
3209 {
3210         ber_len_t       len;
3211         char            *res, *ptr;
3212
3213         len = strlen( p );
3214
3215         if ( s[ 0 ] == '\0' ) {
3216                 len++;
3217         }
3218
3219         res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
3220         if ( res == NULL ) {
3221                 return NULL;
3222         }
3223
3224         ptr = lutil_strcopy( res, ( p[ 0 ] == '\0' ? "%2" : "%1" ) );
3225         if ( s[ 0 ] == '\0' ) {
3226                 ptr[ 0 ] = ',';
3227                 ptr++;
3228         }
3229         lutil_strcopy( ptr, p );
3230
3231         return res;
3232 }
3233
3234 int
3235 suffix_massage_config(
3236                 struct rewrite_info *info,
3237                 struct berval *pvnc,
3238                 struct berval *nvnc,
3239                 struct berval *prnc,
3240                 struct berval *nrnc
3241 )
3242 {
3243         char *rargv[ 5 ];
3244         int line = 0;
3245
3246         rargv[ 0 ] = "rewriteEngine";
3247         rargv[ 1 ] = "on";
3248         rargv[ 2 ] = NULL;
3249         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
3250
3251         rargv[ 0 ] = "rewriteContext";
3252         rargv[ 1 ] = "default";
3253         rargv[ 2 ] = NULL;
3254         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
3255
3256         rargv[ 0 ] = "rewriteRule";
3257         rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val );
3258         rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
3259         rargv[ 3 ] = ":";
3260         rargv[ 4 ] = NULL;
3261         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3262         ch_free( rargv[ 1 ] );
3263         ch_free( rargv[ 2 ] );
3264
3265         if ( BER_BVISEMPTY( pvnc ) ) {
3266                 rargv[ 0 ] = "rewriteRule";
3267                 rargv[ 1 ] = "^$";
3268                 rargv[ 2 ] = prnc->bv_val;
3269                 rargv[ 3 ] = ":";
3270                 rargv[ 4 ] = NULL;
3271                 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3272         }
3273
3274         rargv[ 0 ] = "rewriteContext";
3275         rargv[ 1 ] = "searchEntryDN";
3276         rargv[ 2 ] = NULL;
3277         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
3278
3279         rargv[ 0 ] = "rewriteRule";
3280         rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val );
3281         rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
3282         rargv[ 3 ] = ":";
3283         rargv[ 4 ] = NULL;
3284         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3285         ch_free( rargv[ 1 ] );
3286         ch_free( rargv[ 2 ] );
3287
3288         if ( BER_BVISEMPTY( prnc ) ) {
3289                 rargv[ 0 ] = "rewriteRule";
3290                 rargv[ 1 ] = "^$";
3291                 rargv[ 2 ] = pvnc->bv_val;
3292                 rargv[ 3 ] = ":";
3293                 rargv[ 4 ] = NULL;
3294                 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3295         }
3296
3297         /* backward compatibility */
3298         rargv[ 0 ] = "rewriteContext";
3299         rargv[ 1 ] = "searchResult";
3300         rargv[ 2 ] = "alias";
3301         rargv[ 3 ] = "searchEntryDN";
3302         rargv[ 4 ] = NULL;
3303         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3304
3305         rargv[ 0 ] = "rewriteContext";
3306         rargv[ 1 ] = "matchedDN";
3307         rargv[ 2 ] = "alias";
3308         rargv[ 3 ] = "searchEntryDN";
3309         rargv[ 4 ] = NULL;
3310         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3311
3312         rargv[ 0 ] = "rewriteContext";
3313         rargv[ 1 ] = "searchAttrDN";
3314         rargv[ 2 ] = "alias";
3315         rargv[ 3 ] = "searchEntryDN";
3316         rargv[ 4 ] = NULL;
3317         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
3318
3319         /* NOTE: this corresponds to #undef'ining RWM_REFERRAL_REWRITE;
3320          * see servers/slapd/overlays/rwm.h for details */
3321         rargv[ 0 ] = "rewriteContext";
3322         rargv[ 1 ] = "referralAttrDN";
3323         rargv[ 2 ] = NULL;
3324         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
3325
3326         rargv[ 0 ] = "rewriteContext";
3327         rargv[ 1 ] = "referralDN";
3328         rargv[ 2 ] = NULL;
3329         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
3330
3331         return 0;
3332 }
3333 #endif /* ENABLE_REWRITE */
3334