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