]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/config.c
e81ada38ba0ab47a691db007d9803b5f2ad72a07
[openldap] / servers / slapd / back-meta / config.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2012 The OpenLDAP Foundation.
5  * Portions Copyright 2001-2003 Pierangelo Masarati.
6  * Portions Copyright 1999-2003 Howard Chu.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by the Howard Chu for inclusion
19  * in OpenLDAP Software and subsequently enhanced by Pierangelo
20  * Masarati.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/string.h>
28 #include <ac/socket.h>
29
30 #include "slap.h"
31 #include "config.h"
32 #include "lutil.h"
33 #include "../back-ldap/back-ldap.h"
34 #include "back-meta.h"
35
36 static ConfigDriver meta_back_cf_gen;
37 static ConfigLDAPadd meta_ldadd;
38 static ConfigCfAdd meta_cfadd;
39
40 static int ldap_back_map_config(
41         ConfigArgs *c,
42         struct ldapmap  *oc_map,
43         struct ldapmap  *at_map );
44
45 /* Three sets of enums:
46  *      1) attrs that are only valid in the base config
47  *      2) attrs that are valid in base or target
48  *      3) attrs that are only valid in a target
49  */
50
51 /* Base attrs */
52 enum {
53         LDAP_BACK_CFG_CONN_TTL = 1,
54         LDAP_BACK_CFG_DNCACHE_TTL,
55         LDAP_BACK_CFG_IDLE_TIMEOUT,
56         LDAP_BACK_CFG_ONERR,
57         LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER,
58         LDAP_BACK_CFG_SINGLECONN,
59         LDAP_BACK_CFG_USETEMP,
60         LDAP_BACK_CFG_CONNPOOLMAX,
61         LDAP_BACK_CFG_LAST_BASE
62 };
63
64 /* Base or target */
65 enum {
66         LDAP_BACK_CFG_BIND_TIMEOUT = LDAP_BACK_CFG_LAST_BASE,
67         LDAP_BACK_CFG_CANCEL,
68         LDAP_BACK_CFG_CHASE,
69         LDAP_BACK_CFG_CLIENT_PR,
70         LDAP_BACK_CFG_DEFAULT_T,
71         LDAP_BACK_CFG_NETWORK_TIMEOUT,
72         LDAP_BACK_CFG_NOREFS,
73         LDAP_BACK_CFG_NOUNDEFFILTER,
74         LDAP_BACK_CFG_NRETRIES,
75         LDAP_BACK_CFG_QUARANTINE,
76         LDAP_BACK_CFG_REBIND,
77         LDAP_BACK_CFG_TIMEOUT,
78         LDAP_BACK_CFG_VERSION,
79         LDAP_BACK_CFG_ST_REQUEST,
80         LDAP_BACK_CFG_T_F,
81         LDAP_BACK_CFG_TLS,
82         LDAP_BACK_CFG_LAST_BOTH
83 };
84
85 /* Target attrs */
86 enum {
87         LDAP_BACK_CFG_URI = LDAP_BACK_CFG_LAST_BOTH,
88         LDAP_BACK_CFG_ACL_AUTHCDN,
89         LDAP_BACK_CFG_ACL_PASSWD,
90         LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
91         LDAP_BACK_CFG_IDASSERT_BIND,
92         LDAP_BACK_CFG_REWRITE,
93         LDAP_BACK_CFG_SUFFIXM,
94         LDAP_BACK_CFG_MAP,
95         LDAP_BACK_CFG_SUBTREE_EX,
96         LDAP_BACK_CFG_SUBTREE_IN,
97         LDAP_BACK_CFG_PSEUDOROOTDN,
98         LDAP_BACK_CFG_PSEUDOROOTPW,
99
100         LDAP_BACK_CFG_LAST
101 };
102
103 static ConfigTable metacfg[] = {
104         { "uri", "uri", 2, 2, 0,
105                 ARG_MAGIC|LDAP_BACK_CFG_URI,
106                 meta_back_cf_gen, "( OLcfgDbAt:0.14 "
107                         "NAME 'olcDbURI' "
108                         "DESC 'URI (list) for remote DSA' "
109                         "SYNTAX OMsDirectoryString "
110                         "SINGLE-VALUE )",
111                 NULL, NULL },
112         { "tls", "what", 2, 0, 0,
113                 ARG_MAGIC|LDAP_BACK_CFG_TLS,
114                 meta_back_cf_gen, "( OLcfgDbAt:3.1 "
115                         "NAME 'olcDbStartTLS' "
116                         "DESC 'StartTLS' "
117                         "SYNTAX OMsDirectoryString "
118                         "SINGLE-VALUE )",
119                 NULL, NULL },
120         { "acl-authcDN", "DN", 2, 2, 0,
121                 ARG_DN|ARG_MAGIC|LDAP_BACK_CFG_ACL_AUTHCDN,
122                 meta_back_cf_gen, "( OLcfgDbAt:3.2 "
123                         "NAME 'olcDbACLAuthcDn' "
124                         "DESC 'Remote ACL administrative identity' "
125                         "OBSOLETE "
126                         "SYNTAX OMsDN "
127                         "SINGLE-VALUE )",
128                 NULL, NULL },
129         /* deprecated, will be removed; aliases "acl-authcDN" */
130         { "binddn", "DN", 2, 2, 0,
131                 ARG_DN|ARG_MAGIC|LDAP_BACK_CFG_ACL_AUTHCDN,
132                 meta_back_cf_gen, NULL, NULL, NULL },
133         { "acl-passwd", "cred", 2, 2, 0,
134                 ARG_MAGIC|LDAP_BACK_CFG_ACL_PASSWD,
135                 meta_back_cf_gen, "( OLcfgDbAt:3.3 "
136                         "NAME 'olcDbACLPasswd' "
137                         "DESC 'Remote ACL administrative identity credentials' "
138                         "OBSOLETE "
139                         "SYNTAX OMsDirectoryString "
140                         "SINGLE-VALUE )",
141                 NULL, NULL },
142         /* deprecated, will be removed; aliases "acl-passwd" */
143         { "bindpw", "cred", 2, 2, 0,
144                 ARG_MAGIC|LDAP_BACK_CFG_ACL_PASSWD,
145                 meta_back_cf_gen, NULL, NULL, NULL },
146         { "idassert-bind", "args", 2, 0, 0,
147                 ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_BIND,
148                 meta_back_cf_gen, "( OLcfgDbAt:3.7 "
149                         "NAME 'olcDbIDAssertBind' "
150                         "DESC 'Remote Identity Assertion administrative identity auth bind configuration' "
151                         "SYNTAX OMsDirectoryString "
152                         "SINGLE-VALUE )",
153                 NULL, NULL },
154         { "idassert-authzFrom", "authzRule", 2, 2, 0,
155                 ARG_MAGIC|LDAP_BACK_CFG_IDASSERT_AUTHZFROM,
156                 meta_back_cf_gen, "( OLcfgDbAt:3.9 "
157                         "NAME 'olcDbIDAssertAuthzFrom' "
158                         "DESC 'Remote Identity Assertion authz rules' "
159                         "EQUALITY caseIgnoreMatch "
160                         "SYNTAX OMsDirectoryString "
161                         "X-ORDERED 'VALUES' )",
162                 NULL, NULL },
163         { "rebind-as-user", "true|FALSE", 1, 2, 0,
164                 ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_REBIND,
165                 meta_back_cf_gen, "( OLcfgDbAt:3.10 "
166                         "NAME 'olcDbRebindAsUser' "
167                         "DESC 'Rebind as user' "
168                         "SYNTAX OMsBoolean "
169                         "SINGLE-VALUE )",
170                 NULL, NULL },
171         { "chase-referrals", "true|FALSE", 2, 2, 0,
172                 ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_CHASE,
173                 meta_back_cf_gen, "( OLcfgDbAt:3.11 "
174                         "NAME 'olcDbChaseReferrals' "
175                         "DESC 'Chase referrals' "
176                         "SYNTAX OMsBoolean "
177                         "SINGLE-VALUE )",
178                 NULL, NULL },
179         { "t-f-support", "true|FALSE|discover", 2, 2, 0,
180                 ARG_MAGIC|LDAP_BACK_CFG_T_F,
181                 meta_back_cf_gen, "( OLcfgDbAt:3.12 "
182                         "NAME 'olcDbTFSupport' "
183                         "DESC 'Absolute filters support' "
184                         "SYNTAX OMsDirectoryString "
185                         "SINGLE-VALUE )",
186                 NULL, NULL },
187         { "timeout", "timeout(list)", 2, 0, 0,
188                 ARG_MAGIC|LDAP_BACK_CFG_TIMEOUT,
189                 meta_back_cf_gen, "( OLcfgDbAt:3.14 "
190                         "NAME 'olcDbTimeout' "
191                         "DESC 'Per-operation timeouts' "
192                         "SYNTAX OMsDirectoryString "
193                         "SINGLE-VALUE )",
194                 NULL, NULL },
195         { "idle-timeout", "timeout", 2, 2, 0,
196                 ARG_MAGIC|LDAP_BACK_CFG_IDLE_TIMEOUT,
197                 meta_back_cf_gen, "( OLcfgDbAt:3.15 "
198                         "NAME 'olcDbIdleTimeout' "
199                         "DESC 'connection idle timeout' "
200                         "SYNTAX OMsDirectoryString "
201                         "SINGLE-VALUE )",
202                 NULL, NULL },
203         { "conn-ttl", "ttl", 2, 2, 0,
204                 ARG_MAGIC|LDAP_BACK_CFG_CONN_TTL,
205                 meta_back_cf_gen, "( OLcfgDbAt:3.16 "
206                         "NAME 'olcDbConnTtl' "
207                         "DESC 'connection ttl' "
208                         "SYNTAX OMsDirectoryString "
209                         "SINGLE-VALUE )",
210                 NULL, NULL },
211         { "network-timeout", "timeout", 2, 2, 0,
212                 ARG_MAGIC|LDAP_BACK_CFG_NETWORK_TIMEOUT,
213                 meta_back_cf_gen, "( OLcfgDbAt:3.17 "
214                         "NAME 'olcDbNetworkTimeout' "
215                         "DESC 'connection network timeout' "
216                         "SYNTAX OMsDirectoryString "
217                         "SINGLE-VALUE )",
218                 NULL, NULL },
219         { "protocol-version", "version", 2, 2, 0,
220                 ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_VERSION,
221                 meta_back_cf_gen, "( OLcfgDbAt:3.18 "
222                         "NAME 'olcDbProtocolVersion' "
223                         "DESC 'protocol version' "
224                         "SYNTAX OMsInteger "
225                         "SINGLE-VALUE )",
226                 NULL, NULL },
227         { "single-conn", "true|FALSE", 2, 2, 0,
228                 ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_SINGLECONN,
229                 meta_back_cf_gen, "( OLcfgDbAt:3.19 "
230                         "NAME 'olcDbSingleConn' "
231                         "DESC 'cache a single connection per identity' "
232                         "SYNTAX OMsBoolean "
233                         "SINGLE-VALUE )",
234                 NULL, NULL },
235         { "cancel", "ABANDON|ignore|exop", 2, 2, 0,
236                 ARG_MAGIC|LDAP_BACK_CFG_CANCEL,
237                 meta_back_cf_gen, "( OLcfgDbAt:3.20 "
238                         "NAME 'olcDbCancel' "
239                         "DESC 'abandon/ignore/exop operations when appropriate' "
240                         "SYNTAX OMsDirectoryString "
241                         "SINGLE-VALUE )",
242                 NULL, NULL },
243         { "quarantine", "retrylist", 2, 2, 0,
244                 ARG_MAGIC|LDAP_BACK_CFG_QUARANTINE,
245                 meta_back_cf_gen, "( OLcfgDbAt:3.21 "
246                         "NAME 'olcDbQuarantine' "
247                         "DESC 'Quarantine database if connection fails and retry according to rule' "
248                         "SYNTAX OMsDirectoryString "
249                         "SINGLE-VALUE )",
250                 NULL, NULL },
251         { "use-temporary-conn", "true|FALSE", 2, 2, 0,
252                 ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_USETEMP,
253                 meta_back_cf_gen, "( OLcfgDbAt:3.22 "
254                         "NAME 'olcDbUseTemporaryConn' "
255                         "DESC 'Use temporary connections if the cached one is busy' "
256                         "SYNTAX OMsBoolean "
257                         "SINGLE-VALUE )",
258                 NULL, NULL },
259         { "conn-pool-max", "<n>", 2, 2, 0,
260                 ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_CONNPOOLMAX,
261                 meta_back_cf_gen, "( OLcfgDbAt:3.23 "
262                         "NAME 'olcDbConnectionPoolMax' "
263                         "DESC 'Max size of privileged connections pool' "
264                         "SYNTAX OMsInteger "
265                         "SINGLE-VALUE )",
266                 NULL, NULL },
267 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
268         { "session-tracking-request", "true|FALSE", 2, 2, 0,
269                 ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_ST_REQUEST,
270                 meta_back_cf_gen, "( OLcfgDbAt:3.24 "
271                         "NAME 'olcDbSessionTrackingRequest' "
272                         "DESC 'Add session tracking control to proxied requests' "
273                         "SYNTAX OMsBoolean "
274                         "SINGLE-VALUE )",
275                 NULL, NULL },
276 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
277         { "norefs", "true|FALSE", 2, 2, 0,
278                 ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_NOREFS,
279                 meta_back_cf_gen, "( OLcfgDbAt:3.25 "
280                         "NAME 'olcDbNoRefs' "
281                         "DESC 'Do not return search reference responses' "
282                         "SYNTAX OMsBoolean "
283                         "SINGLE-VALUE )",
284                 NULL, NULL },
285         { "noundeffilter", "true|FALSE", 2, 2, 0,
286                 ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_NOUNDEFFILTER,
287                 meta_back_cf_gen, "( OLcfgDbAt:3.26 "
288                         "NAME 'olcDbNoUndefFilter' "
289                         "DESC 'Do not propagate undefined search filters' "
290                         "SYNTAX OMsBoolean "
291                         "SINGLE-VALUE )",
292                 NULL, NULL },
293
294         { "rewrite", "arglist", 2, 4, STRLENOF( "rewrite" ),
295                 ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
296                 meta_back_cf_gen, "( OLcfgDbAt:3.101 "
297                         "NAME 'olcDbRewrite' "
298                         "DESC 'DN rewriting rules' "
299                         "SYNTAX OMsDirectoryString )",
300                 NULL, NULL },
301         { "suffixmassage", "virtual> <real", 3, 3, 0,
302                 ARG_MAGIC|LDAP_BACK_CFG_SUFFIXM,
303                 meta_back_cf_gen, NULL, NULL, NULL },
304
305         { "map", "attribute|objectClass> [*|<local>] *|<remote", 3, 4, 0,
306                 ARG_MAGIC|LDAP_BACK_CFG_MAP,
307                 meta_back_cf_gen, "( OLcfgDbAt:3.102 "
308                         "NAME 'olcDbMap' "
309                         "DESC 'Map attribute and objectclass names' "
310                         "SYNTAX OMsDirectoryString )",
311                 NULL, NULL },
312
313         { "subtree-exclude", "pattern", 2, 2, 0,
314                 ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_SUBTREE_EX,
315                 meta_back_cf_gen, "( OLcfgDbAt:3.103 "
316                         "NAME 'olcDbSubtreeExclude' "
317                         "DESC 'DN of subtree to exclude from target' "
318                         "SYNTAX OMsDirectoryString )",
319                 NULL, NULL },
320         { "subtree-include", "pattern", 2, 2, 0,
321                 ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_SUBTREE_IN,
322                 meta_back_cf_gen, "( OLcfgDbAt:3.104 "
323                         "NAME 'olcDbSubtreeInclude' "
324                         "DESC 'DN of subtree to include in target' "
325                         "SYNTAX OMsDirectoryString )",
326                 NULL, NULL },
327         { "default-target", "[none|<target ID>]", 1, 2, 0,
328                 ARG_MAGIC|LDAP_BACK_CFG_DEFAULT_T,
329                 meta_back_cf_gen, "( OLcfgDbAt:3.105 "
330                         "NAME 'olcDbDefaultTarget' "
331                         "DESC 'Specify the default target' "
332                         "SYNTAX OMsDirectoryString "
333                         "SINGLE-VALUE )",
334                 NULL, NULL },
335         { "dncache-ttl", "ttl", 2, 2, 0,
336                 ARG_MAGIC|LDAP_BACK_CFG_DNCACHE_TTL,
337                 meta_back_cf_gen, "( OLcfgDbAt:3.106 "
338                         "NAME 'olcDbDnCacheTtl' "
339                         "DESC 'dncache ttl' "
340                         "SYNTAX OMsDirectoryString "
341                         "SINGLE-VALUE )",
342                 NULL, NULL },
343         { "bind-timeout", "microseconds", 2, 2, 0,
344                 ARG_MAGIC|LDAP_BACK_CFG_BIND_TIMEOUT,
345                 meta_back_cf_gen, "( OLcfgDbAt:3.107 "
346                         "NAME 'olcDbBindTimeout' "
347                         "DESC 'bind timeout' "
348                         "SYNTAX OMsDirectoryString "
349                         "SINGLE-VALUE )",
350                 NULL, NULL },
351         { "onerr", "CONTINUE|report|stop", 2, 2, 0,
352                 ARG_MAGIC|LDAP_BACK_CFG_ONERR,
353                 meta_back_cf_gen, "( OLcfgDbAt:3.108 "
354                         "NAME 'olcDbOnErr' "
355                         "DESC 'error handling' "
356                         "SYNTAX OMsDirectoryString "
357                         "SINGLE-VALUE )",
358                 NULL, NULL },
359         { "pseudoroot-bind-defer", "TRUE|false", 2, 2, 0,
360                 ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER,
361                 meta_back_cf_gen, "( OLcfgDbAt:3.109 "
362                         "NAME 'olcDbPseudoRootBindDefer' "
363                         "DESC 'error handling' "
364                         "SYNTAX OMsBoolean "
365                         "SINGLE-VALUE )",
366                 NULL, NULL },
367         { "root-bind-defer", "TRUE|false", 2, 2, 0,
368                 ARG_MAGIC|ARG_ON_OFF|LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER,
369                 meta_back_cf_gen, NULL, NULL, NULL },
370         { "pseudorootdn", "dn", 2, 2, 0,
371                 ARG_MAGIC|ARG_DN|LDAP_BACK_CFG_PSEUDOROOTDN,
372                 meta_back_cf_gen, NULL, NULL, NULL },
373         { "pseudorootpw", "password", 2, 2, 0,
374                 ARG_MAGIC|ARG_STRING|LDAP_BACK_CFG_PSEUDOROOTDN,
375                 meta_back_cf_gen, NULL, NULL, NULL },
376         { "nretries", "NEVER|forever|<number>", 2, 2, 0,
377                 ARG_MAGIC|ARG_STRING|LDAP_BACK_CFG_NRETRIES,
378                 meta_back_cf_gen, "( OLcfgDbAt:3.110 "
379                         "NAME 'olcDbNretries' "
380                         "DESC 'retry handling' "
381                         "SYNTAX OMsDirectoryString "
382                         "SINGLE-VALUE )",
383                 NULL, NULL },
384         { "client-pr", "accept-unsolicited|disable|<size>", 2, 2, 0,
385                 ARG_MAGIC|ARG_STRING|LDAP_BACK_CFG_CLIENT_PR,
386                 meta_back_cf_gen, "( OLcfgDbAt:3.111 "
387                         "NAME 'olcDbClientPr' "
388                         "DESC 'PagedResults handling' "
389                         "SYNTAX OMsDirectoryString "
390                         "SINGLE-VALUE )",
391                 NULL, NULL },
392
393         { "", "", 0, 0, 0, ARG_IGNORED,
394                 NULL, "( OLcfgDbAt:3.100 NAME 'olcMetaSub' "
395                         "DESC 'Placeholder to name a Target entry' "
396                         "SYNTAX OMsDirectoryString "
397                         "SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
398
399         { NULL, NULL, 0, 0, 0, ARG_IGNORED,
400                 NULL, NULL, NULL, NULL }
401 };
402
403 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
404 #define ST_ATTR "$ olcDbSessionTrackingRequest "
405 #else
406 #define ST_ATTR ""
407 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
408
409 #define COMMON_ATTRS    \
410                         "$ olcDbBindTimeout " \
411                         "$ olcDbCancel " \
412                         "$ olcDbChaseReferrals " \
413                         "$ olcDbClientPr " \
414                         "$ olcDbDefaultTarget " \
415                         "$ olcDbNetworkTimeout " \
416                         "$ olcDbNoRefs " \
417                         "$ olcDbNoUndefFilter " \
418                         "$ olcDbNretries " \
419                         "$ olcDbProtocolVersion " \
420                         "$ olcDbQuarantine " \
421                         "$ olcDbRebindAsUser " \
422                         ST_ATTR \
423                         "$ olcDbStartTLS " \
424                         "$ olcDbTFSupport "
425
426 static ConfigOCs metaocs[] = {
427         { "( OLcfgDbOc:3.2 "
428                 "NAME 'olcMetaConfig' "
429                 "DESC 'Meta backend configuration' "
430                 "SUP olcDatabaseConfig "
431                 "MAY ( olcDbConnTtl "
432                         "$ olcDbDnCacheTtl "
433                         "$ olcDbIdleTimeout "
434                         "$ olcDbOnErr "
435                         "$ olcDbPseudoRootBindDefer "
436                         "$ olcDbSingleConn "
437                         "$ olcDbUseTemporaryConn "
438                         "$ olcDbConnectionPoolMax "
439
440                         /* defaults, may be overridden per-target */
441                         COMMON_ATTRS
442                 ") )",
443                         Cft_Database, metacfg, NULL, meta_cfadd },
444         { "( OLcfgDbOc:3.3 "
445                 "NAME 'olcMetaTargetConfig' "
446                 "DESC 'Meta target configuration' "
447                 "SUP olcConfig STRUCTURAL "
448                 "MUST ( olcMetaSub $ olcDbURI ) "
449                 "MAY ( olcDbACLAuthcDn "
450                         "$ olcDbACLPasswd "
451                         "$ olcDbIDAssertAuthzFrom "
452                         "$ olcDbIDAssertBind "
453                         "$ olcDbMap "
454                         "$ olcDbRewrite "
455                         "$ olcDbSubtreeExclude "
456                         "$ olcDbSubtreeInclude "
457                         "$ olcDbTimeout "
458
459                         /* defaults may be inherited */
460                         COMMON_ATTRS
461                 ") )",
462                         Cft_Misc, metacfg, meta_ldadd },
463         { NULL, 0, NULL }
464 };
465
466 static int
467 meta_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *c )
468 {
469         if ( p->ce_type != Cft_Database || !p->ce_bi ||
470                 p->ce_bi->bi_cf_ocs != metaocs )
471                 return LDAP_CONSTRAINT_VIOLATION;
472
473         return LDAP_SUCCESS;
474 }
475
476 static int
477 meta_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *c )
478 {
479         metainfo_t      *mi = ( metainfo_t * )c->be->be_private;
480         struct berval bv;
481         int i;
482
483         for ( i=0; i<mi->mi_ntargets; i++ ) {
484         }
485
486         return LDAP_SUCCESS;
487 }
488
489 static int
490 meta_back_new_target(
491         metatarget_t    **mtp )
492 {
493         char                    *rargv[ 3 ];
494         metatarget_t            *mt;
495
496         *mtp = NULL;
497
498         mt = ch_calloc( sizeof( metatarget_t ), 1 );
499
500         mt->mt_rwmap.rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
501         if ( mt->mt_rwmap.rwm_rw == NULL ) {
502                 ch_free( mt );
503                 return -1;
504         }
505
506         /*
507          * the filter rewrite as a string must be disabled
508          * by default; it can be re-enabled by adding rules;
509          * this creates an empty rewriteContext
510          */
511         rargv[ 0 ] = "rewriteContext";
512         rargv[ 1 ] = "searchFilter";
513         rargv[ 2 ] = NULL;
514         rewrite_parse( mt->mt_rwmap.rwm_rw, "<suffix massage>", 1, 2, rargv );
515
516         rargv[ 0 ] = "rewriteContext";
517         rargv[ 1 ] = "default";
518         rargv[ 2 ] = NULL;
519         rewrite_parse( mt->mt_rwmap.rwm_rw, "<suffix massage>", 1, 2, rargv );
520
521         ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex );
522
523         mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY;
524         mt->mt_idassert_authmethod = LDAP_AUTH_NONE;
525         mt->mt_idassert_tls = SB_TLS_DEFAULT;
526
527         /* by default, use proxyAuthz control on each operation */
528         mt->mt_idassert_flags = LDAP_BACK_AUTH_PRESCRIPTIVE;
529
530         *mtp = mt;
531
532         return 0;
533 }
534
535 int
536 meta_subtree_destroy( metasubtree_t *ms )
537 {
538         if ( ms->ms_next ) {
539                 meta_subtree_destroy( ms->ms_next );
540         }
541
542         switch ( ms->ms_type ) {
543         case META_ST_SUBTREE:
544         case META_ST_SUBORDINATE:
545                 ber_memfree( ms->ms_dn.bv_val );
546                 break;
547
548         case META_ST_REGEX:
549                 regfree( &ms->ms_regex );
550                 ch_free( ms->ms_regex_pattern );
551                 break;
552
553         default:
554                 return -1;
555         }
556
557         ch_free( ms );
558
559         return 0;
560 }
561
562 static int
563 meta_subtree_config(
564         metatarget_t *mt,
565         ConfigArgs *c )
566 {
567         meta_st_t       type = META_ST_SUBTREE;
568         char            *pattern;
569         struct berval   ndn = BER_BVNULL;
570         metasubtree_t   *ms = NULL;
571
572         if ( c->type == LDAP_BACK_CFG_SUBTREE_EX ) {
573                 if ( mt->mt_subtree && !mt->mt_subtree_exclude ) {
574                         snprintf( c->cr_msg, sizeof(c->cr_msg),
575                                 "\"subtree-exclude\" incompatible with previous \"subtree-include\" directives" );
576                         return 1;
577                 }
578
579                 mt->mt_subtree_exclude = 1;
580
581         } else {
582                 if ( mt->mt_subtree && mt->mt_subtree_exclude ) {
583                         snprintf( c->cr_msg, sizeof(c->cr_msg),
584                                 "\"subtree-include\" incompatible with previous \"subtree-exclude\" directives" );
585                         return 1;
586                 }
587         }
588
589         pattern = c->argv[1];
590         if ( strncasecmp( pattern, "dn", STRLENOF( "dn" ) ) == 0 ) {
591                 char *style;
592
593                 pattern = &pattern[STRLENOF( "dn")];
594
595                 if ( pattern[0] == '.' ) {
596                         style = &pattern[1];
597
598                         if ( strncasecmp( style, "subtree", STRLENOF( "subtree" ) ) == 0 ) {
599                                 type = META_ST_SUBTREE;
600                                 pattern = &style[STRLENOF( "subtree" )];
601
602                         } else if ( strncasecmp( style, "children", STRLENOF( "children" ) ) == 0 ) {
603                                 type = META_ST_SUBORDINATE;
604                                 pattern = &style[STRLENOF( "children" )];
605
606                         } else if ( strncasecmp( style, "sub", STRLENOF( "sub" ) ) == 0 ) {
607                                 type = META_ST_SUBTREE;
608                                 pattern = &style[STRLENOF( "sub" )];
609
610                         } else if ( strncasecmp( style, "regex", STRLENOF( "regex" ) ) == 0 ) {
611                                 type = META_ST_REGEX;
612                                 pattern = &style[STRLENOF( "regex" )];
613
614                         } else {
615                                 snprintf( c->cr_msg, sizeof(c->cr_msg), "unknown style in \"dn.<style>\"" );
616                                 return 1;
617                         }
618                 }
619
620                 if ( pattern[0] != ':' ) {
621                         snprintf( c->cr_msg, sizeof(c->cr_msg), "missing colon after \"dn.<style>\"" );
622                         return 1;
623                 }
624                 pattern++;
625         }
626
627         switch ( type ) {
628         case META_ST_SUBTREE:
629         case META_ST_SUBORDINATE: {
630                 struct berval dn;
631
632                 ber_str2bv( pattern, 0, 0, &dn );
633                 if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL )
634                         != LDAP_SUCCESS )
635                 {
636                         snprintf( c->cr_msg, sizeof(c->cr_msg), "DN=\"%s\" is invalid", pattern );
637                         return 1;
638                 }
639
640                 if ( !dnIsSuffix( &ndn, &mt->mt_nsuffix ) ) {
641                         snprintf( c->cr_msg, sizeof(c->cr_msg),
642                                 "DN=\"%s\" is not a subtree of target \"%s\"",
643                                 pattern, mt->mt_nsuffix.bv_val );
644                         ber_memfree( ndn.bv_val );
645                         return( 1 );
646                 }
647                 } break;
648
649         default:
650                 /* silence warnings */
651                 break;
652         }
653
654         ms = ch_calloc( sizeof( metasubtree_t ), 1 );
655         ms->ms_type = type;
656
657         switch ( ms->ms_type ) {
658         case META_ST_SUBTREE:
659         case META_ST_SUBORDINATE:
660                 ms->ms_dn = ndn;
661                 break;
662
663         case META_ST_REGEX: {
664                 int rc;
665
666                 rc = regcomp( &ms->ms_regex, pattern, REG_EXTENDED|REG_ICASE );
667                 if ( rc != 0 ) {
668                         char regerr[ SLAP_TEXT_BUFLEN ];
669
670                         regerror( rc, &ms->ms_regex, regerr, sizeof(regerr) );
671
672                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
673                                 "regular expression \"%s\" bad because of %s",
674                                 pattern, regerr );
675                         ch_free( ms );
676                         return 1;
677                 }
678                 ms->ms_regex_pattern = ch_strdup( pattern );
679                 } break;
680         }
681
682         if ( mt->mt_subtree == NULL ) {
683                  mt->mt_subtree = ms;
684
685         } else {
686                 metasubtree_t **msp;
687
688                 for ( msp = &mt->mt_subtree; *msp; ) {
689                         switch ( ms->ms_type ) {
690                         case META_ST_SUBTREE:
691                                 switch ( (*msp)->ms_type ) {
692                                 case META_ST_SUBTREE:
693                                         if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
694                                                 metasubtree_t *tmp = *msp;
695                                                 Debug( LDAP_DEBUG_CONFIG,
696                                                         "%s: previous rule \"dn.subtree:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
697                                                         c->log, pattern, (*msp)->ms_dn.bv_val );
698                                                 *msp = (*msp)->ms_next;
699                                                 tmp->ms_next = NULL;
700                                                 meta_subtree_destroy( tmp );
701                                                 continue;
702
703                                         } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) ) {
704                                                 Debug( LDAP_DEBUG_CONFIG,
705                                                         "%s: previous rule \"dn.subtree:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
706                                                         c->log, (*msp)->ms_dn.bv_val, pattern );
707                                                 meta_subtree_destroy( ms );
708                                                 ms = NULL;
709                                                 return( 0 );
710                                         }
711                                         break;
712
713                                 case META_ST_SUBORDINATE:
714                                         if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
715                                                 metasubtree_t *tmp = *msp;
716                                                 Debug( LDAP_DEBUG_CONFIG,
717                                                         "%s: previous rule \"dn.children:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
718                                                         c->log, pattern, (*msp)->ms_dn.bv_val );
719                                                 *msp = (*msp)->ms_next;
720                                                 tmp->ms_next = NULL;
721                                                 meta_subtree_destroy( tmp );
722                                                 continue;
723
724                                         } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) && ms->ms_dn.bv_len > (*msp)->ms_dn.bv_len ) {
725                                                 Debug( LDAP_DEBUG_CONFIG,
726                                                         "%s: previous rule \"dn.children:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
727                                                         c->log, (*msp)->ms_dn.bv_val, pattern );
728                                                 meta_subtree_destroy( ms );
729                                                 ms = NULL;
730                                                 return( 0 );
731                                         }
732                                         break;
733
734                                 case META_ST_REGEX:
735                                         if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
736                                                 Debug( LDAP_DEBUG_CONFIG,
737                                                         "%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n",
738                                                         c->log, (*msp)->ms_regex_pattern, ms->ms_dn.bv_val );
739                                         }
740                                         break;
741                                 }
742                                 break;
743
744                         case META_ST_SUBORDINATE:
745                                 switch ( (*msp)->ms_type ) {
746                                 case META_ST_SUBTREE:
747                                         if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
748                                                 metasubtree_t *tmp = *msp;
749                                                 Debug( LDAP_DEBUG_CONFIG,
750                                                         "%s: previous rule \"dn.children:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
751                                                         c->log, pattern, (*msp)->ms_dn.bv_val );
752                                                 *msp = (*msp)->ms_next;
753                                                 tmp->ms_next = NULL;
754                                                 meta_subtree_destroy( tmp );
755                                                 continue;
756
757                                         } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) && ms->ms_dn.bv_len > (*msp)->ms_dn.bv_len ) {
758                                                 Debug( LDAP_DEBUG_CONFIG,
759                                                         "%s: previous rule \"dn.children:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
760                                                         c->log, (*msp)->ms_dn.bv_val, pattern );
761                                                 meta_subtree_destroy( ms );
762                                                 ms = NULL;
763                                                 return( 0 );
764                                         }
765                                         break;
766
767                                 case META_ST_SUBORDINATE:
768                                         if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
769                                                 metasubtree_t *tmp = *msp;
770                                                 Debug( LDAP_DEBUG_CONFIG,
771                                                         "%s: previous rule \"dn.children:%s\" is contained in rule \"dn.children:%s\" (replaced)\n",
772                                                         c->log, pattern, (*msp)->ms_dn.bv_val );
773                                                 *msp = (*msp)->ms_next;
774                                                 tmp->ms_next = NULL;
775                                                 meta_subtree_destroy( tmp );
776                                                 continue;
777
778                                         } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) ) {
779                                                 Debug( LDAP_DEBUG_CONFIG,
780                                                         "%s: previous rule \"dn.children:%s\" contains rule \"dn.children:%s\" (ignored)\n",
781                                                         c->log, (*msp)->ms_dn.bv_val, pattern );
782                                                 meta_subtree_destroy( ms );
783                                                 ms = NULL;
784                                                 return( 0 );
785                                         }
786                                         break;
787
788                                 case META_ST_REGEX:
789                                         if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
790                                                 Debug( LDAP_DEBUG_CONFIG,
791                                                         "%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n",
792                                                         c->log, (*msp)->ms_regex_pattern, ms->ms_dn.bv_val );
793                                         }
794                                         break;
795                                 }
796                                 break;
797
798                         case META_ST_REGEX:
799                                 switch ( (*msp)->ms_type ) {
800                                 case META_ST_SUBTREE:
801                                 case META_ST_SUBORDINATE:
802                                         if ( regexec( &ms->ms_regex, (*msp)->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
803                                                 Debug( LDAP_DEBUG_CONFIG,
804                                                         "%s: previous rule \"dn.subtree:%s\" may be contained in rule \"dn.regex:%s\"\n",
805                                                         c->log, (*msp)->ms_dn.bv_val, ms->ms_regex_pattern );
806                                         }
807                                         break;
808
809                                 case META_ST_REGEX:
810                                         /* no check possible */
811                                         break;
812                                 }
813                                 break;
814                         }
815
816                         msp = &(*msp)->ms_next;
817                 }
818
819                 *msp = ms;
820         }
821
822         return 0;
823 }
824
825 static slap_verbmasks idassert_mode[] = {
826         { BER_BVC("self"),              LDAP_BACK_IDASSERT_SELF },
827         { BER_BVC("anonymous"),         LDAP_BACK_IDASSERT_ANONYMOUS },
828         { BER_BVC("none"),              LDAP_BACK_IDASSERT_NOASSERT },
829         { BER_BVC("legacy"),            LDAP_BACK_IDASSERT_LEGACY },
830         { BER_BVNULL,                   0 }
831 };
832
833 static slap_verbmasks tls_mode[] = {
834         { BER_BVC( "propagate" ),       LDAP_BACK_F_TLS_PROPAGATE_MASK },
835         { BER_BVC( "try-propagate" ),   LDAP_BACK_F_PROPAGATE_TLS },
836         { BER_BVC( "start" ),           LDAP_BACK_F_TLS_USE_MASK },
837         { BER_BVC( "try-start" ),       LDAP_BACK_F_USE_TLS },
838         { BER_BVC( "ldaps" ),           LDAP_BACK_F_TLS_LDAPS },
839         { BER_BVC( "none" ),            LDAP_BACK_F_NONE },
840         { BER_BVNULL,                   0 }
841 };
842
843 static slap_verbmasks t_f_mode[] = {
844         { BER_BVC( "yes" ),             LDAP_BACK_F_T_F },
845         { BER_BVC( "discover" ),        LDAP_BACK_F_T_F_DISCOVER },
846         { BER_BVC( "no" ),              LDAP_BACK_F_NONE },
847         { BER_BVNULL,                   0 }
848 };
849
850 static slap_verbmasks cancel_mode[] = {
851         { BER_BVC( "ignore" ),          LDAP_BACK_F_CANCEL_IGNORE },
852         { BER_BVC( "exop" ),            LDAP_BACK_F_CANCEL_EXOP },
853         { BER_BVC( "exop-discover" ),   LDAP_BACK_F_CANCEL_EXOP_DISCOVER },
854         { BER_BVC( "abandon" ),         LDAP_BACK_F_CANCEL_ABANDON },
855         { BER_BVNULL,                   0 }
856 };
857
858 static slap_verbmasks onerr_mode[] = {
859         { BER_BVC( "stop" ),            META_BACK_F_ONERR_STOP },
860         { BER_BVC( "report" ),  META_BACK_F_ONERR_REPORT },
861         { BER_BVC( "continue" ),                LDAP_BACK_F_NONE },
862         { BER_BVNULL,                   0 }
863 };
864
865 /* see enum in slap.h */
866 static slap_cf_aux_table timeout_table[] = {
867         { BER_BVC("bind="),     SLAP_OP_BIND * sizeof( time_t ),        'u', 0, NULL },
868         /* unbind makes no sense */
869         { BER_BVC("add="),      SLAP_OP_ADD * sizeof( time_t ),         'u', 0, NULL },
870         { BER_BVC("delete="),   SLAP_OP_DELETE * sizeof( time_t ),      'u', 0, NULL },
871         { BER_BVC("modrdn="),   SLAP_OP_MODRDN * sizeof( time_t ),      'u', 0, NULL },
872         { BER_BVC("modify="),   SLAP_OP_MODIFY * sizeof( time_t ),      'u', 0, NULL },
873         { BER_BVC("compare="),  SLAP_OP_COMPARE * sizeof( time_t ),     'u', 0, NULL },
874         { BER_BVC("search="),   SLAP_OP_SEARCH * sizeof( time_t ),      'u', 0, NULL },
875         /* abandon makes little sense */
876 #if 0   /* not implemented yet */
877         { BER_BVC("extended="), SLAP_OP_EXTENDED * sizeof( time_t ),    'u', 0, NULL },
878 #endif
879         { BER_BVNULL, 0, 0, 0, NULL }
880 };
881
882 static int
883 meta_back_cf_gen( ConfigArgs *c )
884 {
885         metainfo_t      *mi = ( metainfo_t * )c->be->be_private;
886         metatarget_t    *mt;
887         metacommon_t    *mc;
888
889         int i, rc = 0;
890
891         assert( mi != NULL );
892
893         if ( c->op == SLAP_CONFIG_EMIT ) {
894                 return 1;
895         } else if ( c->op == LDAP_MOD_DELETE ) {
896                 return 1;
897         }
898
899         if ( c->type >= LDAP_BACK_CFG_LAST_BASE ) {
900                 /* exclude CFG_URI from this check */
901                 if ( c->type > LDAP_BACK_CFG_LAST_BOTH ) {
902                         if ( !mi->mi_ntargets ) {
903                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
904                                         "need \"uri\" directive first" );
905                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
906                                 return 1;
907                         }
908                 }
909                 if ( mi->mi_ntargets ) {
910                         mt = mi->mi_targets[ mi->mi_ntargets-1 ];
911                         mc = &mt->mt_mc;
912                 } else {
913                         mt = NULL;
914                         mc = &mi->mi_mc;
915                 }
916         }
917
918         switch( c->type ) {
919         case LDAP_BACK_CFG_URI: {
920                 LDAPURLDesc     *ludp;
921                 struct berval   dn;
922                 int             j;
923
924                 char            **uris = NULL;
925
926                 if ( c->be->be_nsuffix == NULL ) {
927                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
928                                 "the suffix must be defined before any target" );
929                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
930                         return 1;
931                 }
932
933                 i = mi->mi_ntargets++;
934
935                 mi->mi_targets = ( metatarget_t ** )ch_realloc( mi->mi_targets,
936                         sizeof( metatarget_t * ) * mi->mi_ntargets );
937                 if ( mi->mi_targets == NULL ) {
938                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
939                                 "out of memory while storing server name"
940                                 " in \"%s <protocol>://<server>[:port]/<naming context>\"",
941                                 c->argv[0] );
942                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
943                         return 1;
944                 }
945
946                 if ( meta_back_new_target( &mi->mi_targets[ i ] ) != 0 ) {
947                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
948                                 "unable to init server"
949                                 " in \"%s <protocol>://<server>[:port]/<naming context>\"",
950                                 c->argv[0] );
951                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
952                         return 1;
953                 }
954
955                 mt = mi->mi_targets[ i ];
956
957                 mt->mt_rebind_f = mi->mi_rebind_f;
958                 mt->mt_urllist_f = mi->mi_urllist_f;
959                 mt->mt_urllist_p = mt;
960
961                 mt->mt_nretries = mi->mi_nretries;
962                 mt->mt_quarantine = mi->mi_quarantine;
963                 if ( META_BACK_QUARANTINE( mi ) ) {
964                         ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
965                 }
966                 mt->mt_mc = mi->mi_mc;
967
968                 for ( j = 1; j < c->argc; j++ ) {
969                         char    **tmpuris = ldap_str2charray( c->argv[ j ], "\t" );
970
971                         if ( tmpuris == NULL ) {
972                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
973                                         "unable to parse URIs #%d"
974                                         " in \"%s <protocol>://<server>[:port]/<naming context>\"",
975                                         j-1, c->argv[0] );
976                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
977                                 return 1;
978                         }
979
980                         if ( j == 0 ) {
981                                 uris = tmpuris;
982
983                         } else {
984                                 ldap_charray_merge( &uris, tmpuris );
985                                 ldap_charray_free( tmpuris );
986                         }
987                 }
988
989                 for ( j = 0; uris[ j ] != NULL; j++ ) {
990                         char *tmpuri = NULL;
991
992                         /*
993                          * uri MUST be legal!
994                          */
995                         if ( ldap_url_parselist_ext( &ludp, uris[ j ], "\t",
996                                         LDAP_PVT_URL_PARSE_NONE ) != LDAP_SUCCESS
997                                 || ludp->lud_next != NULL )
998                         {
999                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1000                                         "unable to parse URI #%d"
1001                                         " in \"%s <protocol>://<server>[:port]/<naming context>\"",
1002                                         j-1, c->argv[0] );
1003                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1004                                 ldap_charray_free( uris );
1005                                 return 1;
1006                         }
1007
1008                         if ( j == 0 ) {
1009
1010                                 /*
1011                                  * uri MUST have the <dn> part!
1012                                  */
1013                                 if ( ludp->lud_dn == NULL ) {
1014                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1015                                                 "missing <naming context> "
1016                                                 " in \"%s <protocol>://<server>[:port]/<naming context>\"",
1017                                                 c->argv[0] );
1018                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1019                                         ldap_free_urllist( ludp );
1020                                         ldap_charray_free( uris );
1021                                         return 1;
1022                                 }
1023
1024                                 /*
1025                                  * copies and stores uri and suffix
1026                                  */
1027                                 ber_str2bv( ludp->lud_dn, 0, 0, &dn );
1028                                 rc = dnPrettyNormal( NULL, &dn, &mt->mt_psuffix,
1029                                         &mt->mt_nsuffix, NULL );
1030                                 if ( rc != LDAP_SUCCESS ) {
1031                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1032                                                 "target DN is invalid \"%s\"",
1033                                                 c->argv[1] );
1034                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1035                                         ldap_free_urllist( ludp );
1036                                         ldap_charray_free( uris );
1037                                         return( 1 );
1038                                 }
1039
1040                                 ludp->lud_dn[ 0 ] = '\0';
1041
1042                                 switch ( ludp->lud_scope ) {
1043                                 case LDAP_SCOPE_DEFAULT:
1044                                         mt->mt_scope = LDAP_SCOPE_SUBTREE;
1045                                         break;
1046
1047                                 case LDAP_SCOPE_SUBTREE:
1048                                 case LDAP_SCOPE_SUBORDINATE:
1049                                         mt->mt_scope = ludp->lud_scope;
1050                                         break;
1051
1052                                 default:
1053                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1054                                                 "invalid scope for target \"%s\"",
1055                                                 c->argv[1] );
1056                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1057                                         ldap_free_urllist( ludp );
1058                                         ldap_charray_free( uris );
1059                                         return( 1 );
1060                                 }
1061
1062                         } else {
1063                                 /* check all, to apply the scope check on the first one */
1064                                 if ( ludp->lud_dn != NULL && ludp->lud_dn[ 0 ] != '\0' ) {
1065                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1066                                                 "multiple URIs must have no DN part" );
1067                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1068                                         ldap_free_urllist( ludp );
1069                                         ldap_charray_free( uris );
1070                                         return( 1 );
1071
1072                                 }
1073                         }
1074
1075                         tmpuri = ldap_url_list2urls( ludp );
1076                         ldap_free_urllist( ludp );
1077                         if ( tmpuri == NULL ) {
1078                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "no memory?" );
1079                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1080                                 ldap_charray_free( uris );
1081                                 return( 1 );
1082                         }
1083                         ldap_memfree( uris[ j ] );
1084                         uris[ j ] = tmpuri;
1085                 }
1086
1087                 mt->mt_uri = ldap_charray2str( uris, " " );
1088                 ldap_charray_free( uris );
1089                 if ( mt->mt_uri == NULL) {
1090                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "no memory?" );
1091                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1092                         return( 1 );
1093                 }
1094
1095                 /*
1096                  * uri MUST be a branch of suffix!
1097                  */
1098                 for ( j = 0; !BER_BVISNULL( &c->be->be_nsuffix[ j ] ); j++ ) {
1099                         if ( dnIsSuffix( &mt->mt_nsuffix, &c->be->be_nsuffix[ j ] ) ) {
1100                                 break;
1101                         }
1102                 }
1103
1104                 if ( BER_BVISNULL( &c->be->be_nsuffix[ j ] ) ) {
1105                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1106                                 "<naming context> of URI must be within the naming context of this database." );
1107                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1108                         return 1;
1109                 }
1110         } break;
1111         case LDAP_BACK_CFG_SUBTREE_EX:
1112         case LDAP_BACK_CFG_SUBTREE_IN:
1113         /* subtree-exclude */
1114                 if ( meta_subtree_config( mt, c )) {
1115                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1116                         return 1;
1117                 }
1118                 break;
1119
1120         case LDAP_BACK_CFG_DEFAULT_T:
1121         /* default target directive */
1122                 i = mi->mi_ntargets - 1;
1123
1124                 if ( c->argc == 1 ) {
1125                         if ( i < 0 ) {
1126                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1127                                         "\"%s\" alone must be inside a \"uri\" directive",
1128                                         c->argv[0] );
1129                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1130                                 return 1;
1131                         }
1132                         mi->mi_defaulttarget = i;
1133
1134                 } else {
1135                         if ( strcasecmp( c->argv[ 1 ], "none" ) == 0 ) {
1136                                 if ( i >= 0 ) {
1137                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1138                                                 "\"%s none\" should go before uri definitions",
1139                                                 c->argv[0] );
1140                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1141                                 }
1142                                 mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
1143
1144                         } else {
1145
1146                                 if ( lutil_atoi( &mi->mi_defaulttarget, c->argv[ 1 ] ) != 0
1147                                         || mi->mi_defaulttarget < 0
1148                                         || mi->mi_defaulttarget >= i - 1 )
1149                                 {
1150                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1151                                                 "illegal target number %d",
1152                                                 mi->mi_defaulttarget );
1153                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1154                                         return 1;
1155                                 }
1156                         }
1157                 }
1158                 break;
1159
1160         case LDAP_BACK_CFG_DNCACHE_TTL:
1161         /* ttl of dn cache */
1162                 if ( strcasecmp( c->argv[ 1 ], "forever" ) == 0 ) {
1163                         mi->mi_cache.ttl = META_DNCACHE_FOREVER;
1164
1165                 } else if ( strcasecmp( c->argv[ 1 ], "disabled" ) == 0 ) {
1166                         mi->mi_cache.ttl = META_DNCACHE_DISABLED;
1167
1168                 } else {
1169                         unsigned long   t;
1170
1171                         if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
1172                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1173                                         "unable to parse dncache ttl \"%s\"",
1174                                         c->argv[ 1 ] );
1175                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1176                                 return 1;
1177                         }
1178                         mi->mi_cache.ttl = (time_t)t;
1179                 }
1180                 break;
1181
1182         case LDAP_BACK_CFG_NETWORK_TIMEOUT: {
1183         /* network timeout when connecting to ldap servers */
1184                 unsigned long t;
1185
1186                 if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
1187                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1188                                 "unable to parse network timeout \"%s\"",
1189                                 c->argv[ 1 ] );
1190                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1191                         return 1;
1192                 }
1193                 mc->mc_network_timeout = (time_t)t;
1194                 } break;
1195
1196         case LDAP_BACK_CFG_IDLE_TIMEOUT: {
1197         /* idle timeout when connecting to ldap servers */
1198                 unsigned long   t;
1199
1200                 if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
1201                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1202                                 "unable to parse idle timeout \"%s\"",
1203                                 c->argv[ 1 ] );
1204                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1205                         return 1;
1206
1207                 }
1208                 mi->mi_idle_timeout = (time_t)t;
1209                 } break;
1210
1211         case LDAP_BACK_CFG_CONN_TTL: {
1212         /* conn ttl */
1213                 unsigned long   t;
1214
1215                 if ( lutil_parse_time( c->argv[ 1 ], &t ) ) {
1216                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1217                                 "unable to parse conn ttl \"%s\"",
1218                                 c->argv[ 1 ] );
1219                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1220                         return 1;
1221
1222                 }
1223                 mi->mi_conn_ttl = (time_t)t;
1224                 } break;
1225
1226         case LDAP_BACK_CFG_BIND_TIMEOUT: {
1227         /* bind timeout when connecting to ldap servers */
1228                 unsigned long   t;
1229
1230                 if ( lutil_atoul( &t, c->argv[ 1 ] ) != 0 ) {
1231                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1232                                 "unable to parse bind timeout \"%s\"",
1233                                 c->argv[ 1 ] );
1234                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1235                         return 1;
1236
1237                 }
1238                 mc->mc_bind_timeout.tv_sec = t/1000000;
1239                 mc->mc_bind_timeout.tv_usec = t%1000000;
1240                 } break;
1241
1242         case LDAP_BACK_CFG_ACL_AUTHCDN:
1243         /* name to use for meta_back_group */
1244                 if ( strcasecmp( c->argv[ 0 ], "binddn" ) == 0 ) {
1245                         Debug( LDAP_DEBUG_ANY, "%s: "
1246                                 "\"binddn\" statement is deprecated; "
1247                                 "use \"acl-authcDN\" instead\n",
1248                                 c->log, 0, 0 );
1249                         /* FIXME: some day we'll need to throw an error */
1250                 }
1251
1252                 ber_memfree_x( c->value_dn.bv_val, NULL );
1253                 mt->mt_binddn = c->value_ndn;
1254                 BER_BVZERO( &c->value_dn );
1255                 BER_BVZERO( &c->value_ndn );
1256                 break;
1257
1258         case LDAP_BACK_CFG_ACL_PASSWD:
1259         /* password to use for meta_back_group */
1260                 if ( strcasecmp( c->argv[ 0 ], "bindpw" ) == 0 ) {
1261                         Debug( LDAP_DEBUG_ANY, "%s "
1262                                 "\"bindpw\" statement is deprecated; "
1263                                 "use \"acl-passwd\" instead\n",
1264                                 c->log, 0, 0 );
1265                         /* FIXME: some day we'll need to throw an error */
1266                 }
1267
1268                 ber_str2bv( c->argv[ 1 ], 0L, 1, &mt->mt_bindpw );
1269                 break;
1270
1271         case LDAP_BACK_CFG_REBIND:
1272         /* save bind creds for referral rebinds? */
1273                 if ( c->argc == 1 || c->value_int ) {
1274                         mc->mc_flags |= LDAP_BACK_F_SAVECRED;
1275                 } else {
1276                         mc->mc_flags &= ~LDAP_BACK_F_SAVECRED;
1277                 }
1278                 break;
1279
1280         case LDAP_BACK_CFG_CHASE:
1281                 if ( c->argc == 1 || c->value_int ) {
1282                         mc->mc_flags |= LDAP_BACK_F_CHASE_REFERRALS;
1283                 } else {
1284                         mc->mc_flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
1285                 }
1286                 break;
1287
1288         case LDAP_BACK_CFG_TLS:
1289                 i = verb_to_mask( c->argv[1], tls_mode );
1290                 if ( BER_BVISNULL( &tls_mode[i].word ) ) {
1291                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1292                                 "%s unknown argument \"%s\"",
1293                                 c->argv[0], c->argv[1] );
1294                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1295                         return 1;
1296                 }
1297                 mc->mc_flags &= ~LDAP_BACK_F_TLS_MASK;
1298                 mc->mc_flags |= tls_mode[i].mask;
1299
1300                 if ( c->argc > 2 ) {
1301                         metatarget_t    *mt = NULL;
1302
1303                         if ( mi->mi_ntargets - 1 < 0 ) {
1304                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1305                                         "need \"uri\" directive first" );
1306                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1307                                 return 1;
1308                         }
1309
1310                         mt = mi->mi_targets[ mi->mi_ntargets - 1 ];
1311
1312                         for ( i = 2; i < c->argc; i++ ) {
1313                                 if ( bindconf_tls_parse( c->argv[i], &mt->mt_tls ))
1314                                         return 1;
1315                         }
1316                         bindconf_tls_defaults( &mt->mt_tls );
1317                 }
1318                 break;
1319
1320         case LDAP_BACK_CFG_T_F:
1321                 i = verb_to_mask( c->argv[1], t_f_mode );
1322                 if ( BER_BVISNULL( &t_f_mode[i].word ) ) {
1323                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1324                                 "%s unknown argument \"%s\"",
1325                                 c->argv[0], c->argv[1] );
1326                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1327                         return 1;
1328                 }
1329                 mc->mc_flags &= ~LDAP_BACK_F_T_F_MASK2;
1330                 mc->mc_flags |= t_f_mode[i].mask;
1331                 break;
1332
1333         case LDAP_BACK_CFG_ONERR:
1334         /* onerr? */
1335                 i = verb_to_mask( c->argv[1], onerr_mode );
1336                 if ( BER_BVISNULL( &onerr_mode[i].word ) ) {
1337                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1338                                 "%s unknown argument \"%s\"",
1339                                 c->argv[0], c->argv[1] );
1340                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1341                         return 1;
1342                 }
1343                 mi->mi_flags &= ~META_BACK_F_ONERR_MASK;
1344                 mi->mi_flags |= onerr_mode[i].mask;
1345                 break;
1346
1347         case LDAP_BACK_CFG_PSEUDOROOT_BIND_DEFER:
1348         /* bind-defer? */
1349                 if ( c->argc == 1 || c->value_int ) {
1350                         mi->mi_flags |= META_BACK_F_DEFER_ROOTDN_BIND;
1351                 } else {
1352                         mi->mi_flags &= ~META_BACK_F_DEFER_ROOTDN_BIND;
1353                 }
1354                 break;
1355
1356         case LDAP_BACK_CFG_SINGLECONN:
1357         /* single-conn? */
1358                 if ( mi->mi_ntargets > 0 ) {
1359                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1360                                 "\"%s\" must appear before target definitions",
1361                                 c->argv[0] );
1362                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1363                         return( 1 );
1364                 }
1365                 if ( c->value_int ) {
1366                         mi->mi_flags |= LDAP_BACK_F_SINGLECONN;
1367                 } else {
1368                         mi->mi_flags &= ~LDAP_BACK_F_SINGLECONN;
1369                 }
1370                 break;
1371
1372         case LDAP_BACK_CFG_USETEMP:
1373         /* use-temporaries? */
1374                 if ( mi->mi_ntargets > 0 ) {
1375                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1376                                 "\"%s\" must appear before target definitions",
1377                                 c->argv[0] );
1378                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1379                         return( 1 );
1380                 }
1381                 if ( c->value_int ) {
1382                         mi->mi_flags |= LDAP_BACK_F_USE_TEMPORARIES;
1383                 } else {
1384                         mi->mi_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
1385                 }
1386                 break;
1387
1388         case LDAP_BACK_CFG_CONNPOOLMAX:
1389         /* privileged connections pool max size ? */
1390                 if ( mi->mi_ntargets > 0 ) {
1391                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1392                                 "\"%s\" must appear before target definitions",
1393                                 c->argv[0] );
1394                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1395                         return( 1 );
1396                 }
1397
1398                 if ( c->value_int < LDAP_BACK_CONN_PRIV_MIN
1399                         || c->value_int > LDAP_BACK_CONN_PRIV_MAX )
1400                 {
1401                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1402                                 "invalid max size " "of privileged "
1403                                 "connections pool \"%s\" "
1404                                 "in \"conn-pool-max <n> "
1405                                 "(must be between %d and %d)\"",
1406                                 c->argv[ 1 ],
1407                                 LDAP_BACK_CONN_PRIV_MIN,
1408                                 LDAP_BACK_CONN_PRIV_MAX );
1409                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1410                         return 1;
1411                 }
1412                 mi->mi_conn_priv_max = c->value_int;
1413                 break;
1414
1415         case LDAP_BACK_CFG_CANCEL:
1416                 i = verb_to_mask( c->argv[1], cancel_mode );
1417                 if ( BER_BVISNULL( &cancel_mode[i].word ) ) {
1418                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1419                                 "%s unknown argument \"%s\"",
1420                                 c->argv[0], c->argv[1] );
1421                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1422                         return 1;
1423                 }
1424                 mc->mc_flags &= ~LDAP_BACK_F_CANCEL_MASK2;
1425                 mc->mc_flags |= t_f_mode[i].mask;
1426                 break;
1427
1428         case LDAP_BACK_CFG_TIMEOUT:
1429                 for ( i = 1; i < c->argc; i++ ) {
1430                         if ( isdigit( (unsigned char) c->argv[ i ][ 0 ] ) ) {
1431                                 int             j;
1432                                 unsigned        u;
1433
1434                                 if ( lutil_atoux( &u, c->argv[ i ], 0 ) != 0 ) {
1435                                         snprintf( c->cr_msg, sizeof( c->cr_msg),
1436                                                 "unable to parse timeout \"%s\"",
1437                                                 c->argv[ i ] );
1438                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1439                                         return 1;
1440                                 }
1441
1442                                 for ( j = 0; j < SLAP_OP_LAST; j++ ) {
1443                                         mc->mc_timeout[ j ] = u;
1444                                 }
1445
1446                                 continue;
1447                         }
1448
1449                         if ( slap_cf_aux_table_parse( c->argv[ i ], mc->mc_timeout, timeout_table, "slapd-meta timeout" ) ) {
1450                                 snprintf( c->cr_msg, sizeof( c->cr_msg),
1451                                         "unable to parse timeout \"%s\"",
1452                                         c->argv[ i ] );
1453                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1454                                 return 1;
1455                         }
1456                 }
1457                 break;
1458
1459         case LDAP_BACK_CFG_PSEUDOROOTDN:
1460         /* name to use as pseudo-root dn */
1461                 /*
1462                  * exact replacement:
1463                  *
1464
1465 idassert-bind   bindmethod=simple
1466                 binddn=<pseudorootdn>
1467                 credentials=<pseudorootpw>
1468                 mode=none
1469                 flags=non-prescriptive
1470 idassert-authzFrom      "dn:<rootdn>"
1471
1472                  * so that only when authc'd as <rootdn> the proxying occurs
1473                  * rebinding as the <pseudorootdn> without proxyAuthz.
1474                  */
1475
1476                 Debug( LDAP_DEBUG_ANY,
1477                         "%s: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
1478                         "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
1479                         c->log, 0, 0 );
1480
1481                 {
1482                         char    binddn[ SLAP_TEXT_BUFLEN ];
1483                         char    *cargv[] = {
1484                                 "idassert-bind",
1485                                 "bindmethod=simple",
1486                                 NULL,
1487                                 "mode=none",
1488                                 "flags=non-prescriptive",
1489                                 NULL
1490                         };
1491                         char **oargv;
1492                         int oargc;
1493                         int     cargc = 5;
1494                         int     rc;
1495
1496
1497                         if ( BER_BVISNULL( &c->be->be_rootndn ) ) {
1498                                 Debug( LDAP_DEBUG_ANY, "%s: \"pseudorootpw\": \"rootdn\" must be defined first.\n",
1499                                         c->log, 0, 0 );
1500                                 return 1;
1501                         }
1502
1503                         if ( sizeof( binddn ) <= (unsigned) snprintf( binddn,
1504                                         sizeof( binddn ), "binddn=%s", c->argv[ 1 ] ))
1505                         {
1506                                 Debug( LDAP_DEBUG_ANY, "%s: \"pseudorootdn\" too long.\n",
1507                                         c->log, 0, 0 );
1508                                 return 1;
1509                         }
1510                         cargv[ 2 ] = binddn;
1511
1512                         oargv = c->argv;
1513                         oargc = c->argc;
1514                         c->argv = cargv;
1515                         c->argc = cargc;
1516                         rc = mi->mi_ldap_extra->idassert_parse( c, &mt->mt_idassert );
1517                         c->argv = oargv;
1518                         c->argc = oargc;
1519                         if ( rc == 0 ) {
1520                                 struct berval   bv;
1521
1522                                 if ( mt->mt_idassert_authz != NULL ) {
1523                                         Debug( LDAP_DEBUG_ANY, "%s: \"idassert-authzFrom\" already defined (discarded).\n",
1524                                                 c->log, 0, 0 );
1525                                         ber_bvarray_free( mt->mt_idassert_authz );
1526                                         mt->mt_idassert_authz = NULL;
1527                                 }
1528
1529                                 assert( !BER_BVISNULL( &mt->mt_idassert_authcDN ) );
1530
1531                                 bv.bv_len = STRLENOF( "dn:" ) + c->be->be_rootndn.bv_len;
1532                                 bv.bv_val = ber_memalloc( bv.bv_len + 1 );
1533                                 AC_MEMCPY( bv.bv_val, "dn:", STRLENOF( "dn:" ) );
1534                                 AC_MEMCPY( &bv.bv_val[ STRLENOF( "dn:" ) ], c->be->be_rootndn.bv_val, c->be->be_rootndn.bv_len + 1 );
1535
1536                                 ber_bvarray_add( &mt->mt_idassert_authz, &bv );
1537                         }
1538
1539                         return rc;
1540                 }
1541                 break;
1542
1543         case LDAP_BACK_CFG_PSEUDOROOTPW:
1544         /* password to use as pseudo-root */
1545                 Debug( LDAP_DEBUG_ANY,
1546                         "%s: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
1547                         "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
1548                         c->log, 0, 0 );
1549
1550                 if ( BER_BVISNULL( &mt->mt_idassert_authcDN ) ) {
1551                         Debug( LDAP_DEBUG_ANY, "%s: \"pseudorootpw\": \"pseudorootdn\" must be defined first.\n",
1552                                 c->log, 0, 0 );
1553                         return 1;
1554                 }
1555
1556                 if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) {
1557                         memset( mt->mt_idassert_passwd.bv_val, 0,
1558                                 mt->mt_idassert_passwd.bv_len );
1559                         ber_memfree( mt->mt_idassert_passwd.bv_val );
1560                 }
1561                 ber_str2bv( c->argv[ 1 ], 0, 1, &mt->mt_idassert_passwd );
1562                 break;
1563
1564         case LDAP_BACK_CFG_IDASSERT_BIND:
1565         /* idassert-bind */
1566                 rc = mi->mi_ldap_extra->idassert_parse( c, &mt->mt_idassert );
1567                 break;
1568
1569         case LDAP_BACK_CFG_IDASSERT_AUTHZFROM:
1570         /* idassert-authzFrom */
1571                 rc = mi->mi_ldap_extra->idassert_authzfrom_parse( c, &mt->mt_idassert );
1572                 break;
1573
1574         case LDAP_BACK_CFG_QUARANTINE:
1575         /* quarantine */
1576                 if ( META_BACK_CMN_QUARANTINE( mc ) )
1577                 {
1578                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1579                                 "quarantine already defined" );
1580                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1581                         return 1;
1582                 }
1583
1584                 if ( mt ) {
1585                         mc->mc_quarantine.ri_interval = NULL;
1586                         mc->mc_quarantine.ri_num = NULL;
1587                         if ( !META_BACK_QUARANTINE( mi ) ) {
1588                                 ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
1589                         }
1590                 }
1591
1592                 if ( mi->mi_ldap_extra->retry_info_parse( c->argv[ 1 ], &mc->mc_quarantine, c->cr_msg, sizeof( c->cr_msg ) ) ) {
1593                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1594                         return 1;
1595                 }
1596
1597                 mc->mc_flags |= LDAP_BACK_F_QUARANTINE;
1598                 break;
1599
1600 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1601         case LDAP_BACK_CFG_ST_REQUEST:
1602         /* session tracking request */
1603                 if ( c->value_int ) {
1604                         mc->mc_flags |= LDAP_BACK_F_ST_REQUEST;
1605                 } else {
1606                         mc->mc_flags &= ~LDAP_BACK_F_ST_REQUEST;
1607                 }
1608                 break;
1609 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1610
1611         case LDAP_BACK_CFG_SUFFIXM: {
1612         /* dn massaging */
1613                 BackendDB       *tmp_bd;
1614                 struct berval   dn, nvnc, pvnc, nrnc, prnc;
1615                 int j;
1616
1617                 /*
1618                  * syntax:
1619                  *
1620                  *      suffixmassage <suffix> <massaged suffix>
1621                  *
1622                  * the <suffix> field must be defined as a valid suffix
1623                  * (or suffixAlias?) for the current database;
1624                  * the <massaged suffix> shouldn't have already been
1625                  * defined as a valid suffix or suffixAlias for the
1626                  * current server
1627                  */
1628
1629                 ber_str2bv( c->argv[ 1 ], 0, 0, &dn );
1630                 if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1631                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1632                                 "suffix \"%s\" is invalid",
1633                                 c->argv[1] );
1634                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1635                         return 1;
1636                 }
1637
1638                 for ( j = 0; !BER_BVISNULL( &c->be->be_nsuffix[ j ] ); j++ ) {
1639                         if ( dnIsSuffix( &nvnc, &c->be->be_nsuffix[ 0 ] ) ) {
1640                                 break;
1641                         }
1642                 }
1643
1644                 if ( BER_BVISNULL( &c->be->be_nsuffix[ j ] ) ) {
1645                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1646                                 "suffix \"%s\" must be within the database naming context",
1647                                 c->argv[1] );
1648                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1649                         free( pvnc.bv_val );
1650                         free( nvnc.bv_val );
1651                         return 1;
1652                 }
1653
1654                 ber_str2bv( c->argv[ 2 ], 0, 0, &dn );
1655                 if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1656                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1657                                 "massaged suffix \"%s\" is invalid",
1658                                 c->argv[2] );
1659                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1660                         free( pvnc.bv_val );
1661                         free( nvnc.bv_val );
1662                         return 1;
1663                 }
1664
1665                 tmp_bd = select_backend( &nrnc, 0 );
1666                 if ( tmp_bd != NULL && tmp_bd->be_private == c->be->be_private ) {
1667                         Debug( LDAP_DEBUG_ANY,
1668         "%s: warning: <massaged suffix> \"%s\" resolves to this database, in "
1669         "\"suffixMassage <suffix> <massaged suffix>\"\n",
1670                                 c->log, prnc.bv_val, 0 );
1671                 }
1672
1673                 /*
1674                  * The suffix massaging is emulated by means of the
1675                  * rewrite capabilities
1676                  */
1677                 rc = suffix_massage_config( mt->mt_rwmap.rwm_rw,
1678                                 &pvnc, &nvnc, &prnc, &nrnc );
1679
1680                 free( pvnc.bv_val );
1681                 free( nvnc.bv_val );
1682                 free( prnc.bv_val );
1683                 free( nrnc.bv_val );
1684
1685                 return rc;
1686                 }
1687
1688         case LDAP_BACK_CFG_REWRITE:
1689         /* rewrite stuff ... */
1690                 return rewrite_parse( mt->mt_rwmap.rwm_rw,
1691                                 c->fname, c->lineno, c->argc, c->argv );
1692
1693         case LDAP_BACK_CFG_MAP:
1694         /* objectclass/attribute mapping */
1695                 return ldap_back_map_config( c, &mt->mt_rwmap.rwm_oc,
1696                                 &mt->mt_rwmap.rwm_at );
1697
1698         case LDAP_BACK_CFG_NRETRIES: {
1699                 int             nretries = META_RETRY_UNDEFINED;
1700
1701                 if ( strcasecmp( c->argv[ 1 ], "forever" ) == 0 ) {
1702                         nretries = META_RETRY_FOREVER;
1703
1704                 } else if ( strcasecmp( c->argv[ 1 ], "never" ) == 0 ) {
1705                         nretries = META_RETRY_NEVER;
1706
1707                 } else {
1708                         if ( lutil_atoi( &nretries, c->argv[ 1 ] ) != 0 ) {
1709                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1710                                         "unable to parse nretries {never|forever|<retries>}: \"%s\"",
1711                                         c->argv[ 1 ] );
1712                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1713                                 return 1;
1714                         }
1715                 }
1716
1717                 mc->mc_nretries = nretries;
1718                 } break;
1719
1720         case LDAP_BACK_CFG_VERSION:
1721                 if ( c->value_int != 0 && ( c->value_int < LDAP_VERSION_MIN || c->value_int > LDAP_VERSION_MAX ) ) {
1722                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1723                                 "unsupported protocol version \"%s\"",
1724                                 c->argv[ 1 ] );
1725                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1726                         return 1;
1727                 }
1728                 mc->mc_version = c->value_int;
1729                 break;
1730
1731         case LDAP_BACK_CFG_NOREFS:
1732         /* do not return search references */
1733                 if ( c->value_int ) {
1734                         mc->mc_flags |= LDAP_BACK_F_NOREFS;
1735                 } else {
1736                         mc->mc_flags &= ~LDAP_BACK_F_NOREFS;
1737                 }
1738                 break;
1739
1740         case LDAP_BACK_CFG_NOUNDEFFILTER:
1741         /* do not propagate undefined search filters */
1742                 if ( c->value_int ) {
1743                         mc->mc_flags |= LDAP_BACK_F_NOUNDEFFILTER;
1744                 } else {
1745                         mc->mc_flags &= ~LDAP_BACK_F_NOUNDEFFILTER;
1746                 }
1747                 break;
1748
1749 #ifdef SLAPD_META_CLIENT_PR
1750         case LDAP_BACK_CFG_CLIENT_PR:
1751                 if ( strcasecmp( c->argv[ 1 ], "accept-unsolicited" ) == 0 ) {
1752                         mc->mc_ps = META_CLIENT_PR_ACCEPT_UNSOLICITED;
1753
1754                 } else if ( strcasecmp( c->argv[ 1 ], "disable" ) == 0 ) {
1755                         mc->mc_ps = META_CLIENT_PR_DISABLE;
1756
1757                 } else if ( lutil_atoi( &mc->mc_ps, c->argv[ 1 ] ) || mc->mc_ps < -1 ) {
1758                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1759                                 "unable to parse client-pr {accept-unsolicited|disable|<size>}: \"%s\"",
1760                                 c->argv[ 1 ] );
1761                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1762                         return( 1 );
1763                 }
1764                 break;
1765 #endif /* SLAPD_META_CLIENT_PR */
1766
1767         /* anything else */
1768         default:
1769                 return SLAP_CONF_UNKNOWN;
1770         }
1771
1772         return rc;
1773 }
1774
1775 int
1776 meta_back_init_cf( BackendInfo *bi )
1777 {
1778         int                     rc;
1779         AttributeDescription    *ad = NULL;
1780         const char              *text;
1781
1782         /* Make sure we don't exceed the bits reserved for userland */
1783         config_check_userland( LDAP_BACK_CFG_LAST );
1784
1785         bi->bi_cf_ocs = metaocs;
1786
1787         rc = config_register_schema( metacfg, metaocs );
1788         if ( rc ) {
1789                 return rc;
1790         }
1791
1792         /* setup olcDbAclPasswd and olcDbIDAssertPasswd
1793          * to be base64-encoded when written in LDIF form;
1794          * basically, we don't care if it fails */
1795         rc = slap_str2ad( "olcDbACLPasswd", &ad, &text );
1796         if ( rc ) {
1797                 Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
1798                         "warning, unable to get \"olcDbACLPasswd\" "
1799                         "attribute description: %d: %s\n",
1800                         rc, text, 0 );
1801         } else {
1802                 (void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
1803                         ad->ad_type->sat_oid );
1804         }
1805
1806         ad = NULL;
1807         rc = slap_str2ad( "olcDbIDAssertPasswd", &ad, &text );
1808         if ( rc ) {
1809                 Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
1810                         "warning, unable to get \"olcDbIDAssertPasswd\" "
1811                         "attribute description: %d: %s\n",
1812                         rc, text, 0 );
1813         } else {
1814                 (void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
1815                         ad->ad_type->sat_oid );
1816         }
1817
1818         return 0;
1819 }
1820
1821 static int
1822 ldap_back_map_config(
1823                 ConfigArgs *c,
1824                 struct ldapmap  *oc_map,
1825                 struct ldapmap  *at_map )
1826 {
1827         struct ldapmap          *map;
1828         struct ldapmapping      *mapping;
1829         char                    *src, *dst;
1830         int                     is_oc = 0;
1831
1832         if ( strcasecmp( c->argv[ 1 ], "objectclass" ) == 0 ) {
1833                 map = oc_map;
1834                 is_oc = 1;
1835
1836         } else if ( strcasecmp( c->argv[ 1 ], "attribute" ) == 0 ) {
1837                 map = at_map;
1838
1839         } else {
1840                 snprintf( c->cr_msg, sizeof(c->cr_msg),
1841                         "%s unknown argument \"%s\"",
1842                         c->argv[0], c->argv[1] );
1843                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1844                 return 1;
1845         }
1846
1847         if ( !is_oc && map->map == NULL ) {
1848                 /* only init if required */
1849                 ldap_back_map_init( map, &mapping );
1850         }
1851
1852         if ( strcmp( c->argv[ 2 ], "*" ) == 0 ) {
1853                 if ( c->argc < 4 || strcmp( c->argv[ 3 ], "*" ) == 0 ) {
1854                         map->drop_missing = ( c->argc < 4 );
1855                         goto success_return;
1856                 }
1857                 src = dst = c->argv[ 3 ];
1858
1859         } else if ( c->argc < 4 ) {
1860                 src = "";
1861                 dst = c->argv[ 2 ];
1862
1863         } else {
1864                 src = c->argv[ 2 ];
1865                 dst = ( strcmp( c->argv[ 3 ], "*" ) == 0 ? src : c->argv[ 3 ] );
1866         }
1867
1868         if ( ( map == at_map )
1869                 && ( strcasecmp( src, "objectclass" ) == 0
1870                         || strcasecmp( dst, "objectclass" ) == 0 ) )
1871         {
1872                 snprintf( c->cr_msg, sizeof(c->cr_msg),
1873                         "objectclass attribute cannot be mapped" );
1874                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1875                 return 1;
1876         }
1877
1878         mapping = (struct ldapmapping *)ch_calloc( 2,
1879                 sizeof(struct ldapmapping) );
1880         if ( mapping == NULL ) {
1881                 snprintf( c->cr_msg, sizeof(c->cr_msg),
1882                         "out of memory" );
1883                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1884                 return 1;
1885         }
1886         ber_str2bv( src, 0, 1, &mapping[ 0 ].src );
1887         ber_str2bv( dst, 0, 1, &mapping[ 0 ].dst );
1888         mapping[ 1 ].src = mapping[ 0 ].dst;
1889         mapping[ 1 ].dst = mapping[ 0 ].src;
1890
1891         /*
1892          * schema check
1893          */
1894         if ( is_oc ) {
1895                 if ( src[ 0 ] != '\0' ) {
1896                         if ( oc_bvfind( &mapping[ 0 ].src ) == NULL ) {
1897                                 Debug( LDAP_DEBUG_ANY,
1898         "warning, source objectClass '%s' should be defined in schema\n",
1899                                         c->log, src, 0 );
1900
1901                                 /*
1902                                  * FIXME: this should become an err
1903                                  */
1904                                 goto error_return;
1905                         }
1906                 }
1907
1908                 if ( oc_bvfind( &mapping[ 0 ].dst ) == NULL ) {
1909                         Debug( LDAP_DEBUG_ANY,
1910         "warning, destination objectClass '%s' is not defined in schema\n",
1911                                 c->log, dst, 0 );
1912                 }
1913         } else {
1914                 int                     rc;
1915                 const char              *text = NULL;
1916                 AttributeDescription    *ad = NULL;
1917
1918                 if ( src[ 0 ] != '\0' ) {
1919                         rc = slap_bv2ad( &mapping[ 0 ].src, &ad, &text );
1920                         if ( rc != LDAP_SUCCESS ) {
1921                                 Debug( LDAP_DEBUG_ANY,
1922         "warning, source attributeType '%s' should be defined in schema\n",
1923                                         c->log, src, 0 );
1924
1925                                 /*
1926                                  * FIXME: this should become an err
1927                                  */
1928                                 /*
1929                                  * we create a fake "proxied" ad
1930                                  * and add it here.
1931                                  */
1932
1933                                 rc = slap_bv2undef_ad( &mapping[ 0 ].src,
1934                                                 &ad, &text, SLAP_AD_PROXIED );
1935                                 if ( rc != LDAP_SUCCESS ) {
1936                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1937                                                 "source attributeType \"%s\": %d (%s)",
1938                                                 src, rc, text ? text : "" );
1939                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1940                                         goto error_return;
1941                                 }
1942                         }
1943
1944                         ad = NULL;
1945                 }
1946
1947                 rc = slap_bv2ad( &mapping[ 0 ].dst, &ad, &text );
1948                 if ( rc != LDAP_SUCCESS ) {
1949                         Debug( LDAP_DEBUG_ANY,
1950         "warning, destination attributeType '%s' is not defined in schema\n",
1951                                 c->log, dst, 0 );
1952
1953                         /*
1954                          * we create a fake "proxied" ad
1955                          * and add it here.
1956                          */
1957
1958                         rc = slap_bv2undef_ad( &mapping[ 0 ].dst,
1959                                         &ad, &text, SLAP_AD_PROXIED );
1960                         if ( rc != LDAP_SUCCESS ) {
1961                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1962                                         "destination attributeType \"%s\": %d (%s)\n",
1963                                         dst, rc, text ? text : "" );
1964                                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1965                                 return 1;
1966                         }
1967                 }
1968         }
1969
1970         if ( (src[ 0 ] != '\0' && avl_find( map->map, (caddr_t)&mapping[ 0 ], mapping_cmp ) != NULL)
1971                         || avl_find( map->remap, (caddr_t)&mapping[ 1 ], mapping_cmp ) != NULL)
1972         {
1973                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1974                         "duplicate mapping found." );
1975                 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
1976                 goto error_return;
1977         }
1978
1979         if ( src[ 0 ] != '\0' ) {
1980                 avl_insert( &map->map, (caddr_t)&mapping[ 0 ],
1981                                         mapping_cmp, mapping_dup );
1982         }
1983         avl_insert( &map->remap, (caddr_t)&mapping[ 1 ],
1984                                 mapping_cmp, mapping_dup );
1985
1986 success_return:;
1987         return 0;
1988
1989 error_return:;
1990         if ( mapping ) {
1991                 ch_free( mapping[ 0 ].src.bv_val );
1992                 ch_free( mapping[ 0 ].dst.bv_val );
1993                 ch_free( mapping );
1994         }
1995
1996         return 1;
1997 }
1998
1999
2000 #ifdef ENABLE_REWRITE
2001 static char *
2002 suffix_massage_regexize( const char *s )
2003 {
2004         char *res, *ptr;
2005         const char *p, *r;
2006         int i;
2007
2008         if ( s[ 0 ] == '\0' ) {
2009                 return ch_strdup( "^(.+)$" );
2010         }
2011
2012         for ( i = 0, p = s;
2013                         ( r = strchr( p, ',' ) ) != NULL;
2014                         p = r + 1, i++ )
2015                 ;
2016
2017         res = ch_calloc( sizeof( char ),
2018                         strlen( s )
2019                         + STRLENOF( "((.+),)?" )
2020                         + STRLENOF( "[ ]?" ) * i
2021                         + STRLENOF( "$" ) + 1 );
2022
2023         ptr = lutil_strcopy( res, "((.+),)?" );
2024         for ( i = 0, p = s;
2025                         ( r = strchr( p, ',' ) ) != NULL;
2026                         p = r + 1 , i++ ) {
2027                 ptr = lutil_strncopy( ptr, p, r - p + 1 );
2028                 ptr = lutil_strcopy( ptr, "[ ]?" );
2029
2030                 if ( r[ 1 ] == ' ' ) {
2031                         r++;
2032                 }
2033         }
2034         ptr = lutil_strcopy( ptr, p );
2035         ptr[ 0 ] = '$';
2036         ptr++;
2037         ptr[ 0 ] = '\0';
2038
2039         return res;
2040 }
2041
2042 static char *
2043 suffix_massage_patternize( const char *s, const char *p )
2044 {
2045         ber_len_t       len;
2046         char            *res, *ptr;
2047
2048         len = strlen( p );
2049
2050         if ( s[ 0 ] == '\0' ) {
2051                 len++;
2052         }
2053
2054         res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
2055         if ( res == NULL ) {
2056                 return NULL;
2057         }
2058
2059         ptr = lutil_strcopy( res, ( p[ 0 ] == '\0' ? "%2" : "%1" ) );
2060         if ( s[ 0 ] == '\0' ) {
2061                 ptr[ 0 ] = ',';
2062                 ptr++;
2063         }
2064         lutil_strcopy( ptr, p );
2065
2066         return res;
2067 }
2068
2069 int
2070 suffix_massage_config(
2071                 struct rewrite_info *info,
2072                 struct berval *pvnc,
2073                 struct berval *nvnc,
2074                 struct berval *prnc,
2075                 struct berval *nrnc
2076 )
2077 {
2078         char *rargv[ 5 ];
2079         int line = 0;
2080
2081         rargv[ 0 ] = "rewriteEngine";
2082         rargv[ 1 ] = "on";
2083         rargv[ 2 ] = NULL;
2084         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
2085
2086         rargv[ 0 ] = "rewriteContext";
2087         rargv[ 1 ] = "default";
2088         rargv[ 2 ] = NULL;
2089         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
2090
2091         rargv[ 0 ] = "rewriteRule";
2092         rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val );
2093         rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
2094         rargv[ 3 ] = ":";
2095         rargv[ 4 ] = NULL;
2096         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2097         ch_free( rargv[ 1 ] );
2098         ch_free( rargv[ 2 ] );
2099
2100         if ( BER_BVISEMPTY( pvnc ) ) {
2101                 rargv[ 0 ] = "rewriteRule";
2102                 rargv[ 1 ] = "^$";
2103                 rargv[ 2 ] = prnc->bv_val;
2104                 rargv[ 3 ] = ":";
2105                 rargv[ 4 ] = NULL;
2106                 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2107         }
2108
2109         rargv[ 0 ] = "rewriteContext";
2110         rargv[ 1 ] = "searchEntryDN";
2111         rargv[ 2 ] = NULL;
2112         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
2113
2114         rargv[ 0 ] = "rewriteRule";
2115         rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val );
2116         rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
2117         rargv[ 3 ] = ":";
2118         rargv[ 4 ] = NULL;
2119         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2120         ch_free( rargv[ 1 ] );
2121         ch_free( rargv[ 2 ] );
2122
2123         if ( BER_BVISEMPTY( prnc ) ) {
2124                 rargv[ 0 ] = "rewriteRule";
2125                 rargv[ 1 ] = "^$";
2126                 rargv[ 2 ] = pvnc->bv_val;
2127                 rargv[ 3 ] = ":";
2128                 rargv[ 4 ] = NULL;
2129                 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2130         }
2131
2132         /* backward compatibility */
2133         rargv[ 0 ] = "rewriteContext";
2134         rargv[ 1 ] = "searchResult";
2135         rargv[ 2 ] = "alias";
2136         rargv[ 3 ] = "searchEntryDN";
2137         rargv[ 4 ] = NULL;
2138         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2139
2140         rargv[ 0 ] = "rewriteContext";
2141         rargv[ 1 ] = "matchedDN";
2142         rargv[ 2 ] = "alias";
2143         rargv[ 3 ] = "searchEntryDN";
2144         rargv[ 4 ] = NULL;
2145         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2146
2147         rargv[ 0 ] = "rewriteContext";
2148         rargv[ 1 ] = "searchAttrDN";
2149         rargv[ 2 ] = "alias";
2150         rargv[ 3 ] = "searchEntryDN";
2151         rargv[ 4 ] = NULL;
2152         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2153
2154         /* NOTE: this corresponds to #undef'ining RWM_REFERRAL_REWRITE;
2155          * see servers/slapd/overlays/rwm.h for details */
2156         rargv[ 0 ] = "rewriteContext";
2157         rargv[ 1 ] = "referralAttrDN";
2158         rargv[ 2 ] = NULL;
2159         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
2160
2161         rargv[ 0 ] = "rewriteContext";
2162         rargv[ 1 ] = "referralDN";
2163         rargv[ 2 ] = NULL;
2164         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
2165
2166         return 0;
2167 }
2168 #endif /* ENABLE_REWRITE */
2169