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