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