]> git.sur5r.net Git - openldap/blob - servers/slapd/bconfig.c
ITS#4556,ITS#5723
[openldap] / servers / slapd / bconfig.c
1 /* bconfig.c - the config backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2005-2008 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was originally developed by Howard Chu for inclusion
18  * in OpenLDAP Software.
19  */
20
21 #include "portable.h"
22
23 #include <stdio.h>
24 #include <ac/string.h>
25 #include <ac/ctype.h>
26 #include <ac/errno.h>
27 #include <sys/stat.h>
28
29 #include "slap.h"
30
31 #ifdef LDAP_SLAPI
32 #include "slapi/slapi.h"
33 #endif
34
35 #include <ldif.h>
36 #include <lutil.h>
37
38 #include "config.h"
39
40 #define CONFIG_RDN      "cn=config"
41 #define SCHEMA_RDN      "cn=schema"
42
43 static struct berval config_rdn = BER_BVC(CONFIG_RDN);
44 static struct berval schema_rdn = BER_BVC(SCHEMA_RDN);
45
46 extern int slap_DN_strict;      /* dn.c */
47
48 #ifdef SLAPD_MODULES
49 typedef struct modpath_s {
50         struct modpath_s *mp_next;
51         struct berval mp_path;
52         BerVarray mp_loads;
53 } ModPaths;
54
55 static ModPaths modpaths, *modlast = &modpaths, *modcur = &modpaths;
56 #endif
57
58 typedef struct ConfigFile {
59         struct ConfigFile *c_sibs;
60         struct ConfigFile *c_kids;
61         struct berval c_file;
62         AttributeType *c_at_head, *c_at_tail;
63         ContentRule *c_cr_head, *c_cr_tail;
64         ObjectClass *c_oc_head, *c_oc_tail;
65         OidMacro *c_om_head, *c_om_tail;
66         Syntax *c_syn_head, *c_syn_tail;
67         BerVarray c_dseFiles;
68 } ConfigFile;
69
70 typedef struct {
71         ConfigFile *cb_config;
72         CfEntryInfo *cb_root;
73         BackendDB       cb_db;  /* underlying database */
74         int             cb_got_ldif;
75         int             cb_use_ldif;
76 } CfBackInfo;
77
78 static CfBackInfo cfBackInfo;
79
80 static char     *passwd_salt;
81 static FILE *logfile;
82 static char     *logfileName;
83 #ifdef SLAP_AUTH_REWRITE
84 static BerVarray authz_rewrites;
85 #endif
86
87 static struct berval cfdir;
88
89 /* Private state */
90 static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay,
91         *cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om, *cfAd_syntax;
92
93 static ConfigFile *cfn;
94
95 static Avlnode *CfOcTree;
96
97 /* System schema state */
98 extern AttributeType *at_sys_tail;      /* at.c */
99 extern ObjectClass *oc_sys_tail;        /* oc.c */
100 extern OidMacro *om_sys_tail;   /* oidm.c */
101 extern Syntax *syn_sys_tail;    /* syntax.c */
102 static AttributeType *cf_at_tail;
103 static ObjectClass *cf_oc_tail;
104 static OidMacro *cf_om_tail;
105 static Syntax *cf_syn_tail;
106
107 static int config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca,
108         SlapReply *rs, int *renumber, Operation *op );
109
110 static int config_check_schema( Operation *op, CfBackInfo *cfb );
111
112 static ConfigDriver config_fname;
113 static ConfigDriver config_cfdir;
114 static ConfigDriver config_generic;
115 static ConfigDriver config_search_base;
116 static ConfigDriver config_passwd_hash;
117 static ConfigDriver config_schema_dn;
118 static ConfigDriver config_sizelimit;
119 static ConfigDriver config_timelimit;
120 static ConfigDriver config_overlay;
121 static ConfigDriver config_subordinate; 
122 static ConfigDriver config_suffix; 
123 static ConfigDriver config_rootdn;
124 static ConfigDriver config_rootpw;
125 static ConfigDriver config_restrict;
126 static ConfigDriver config_allows;
127 static ConfigDriver config_disallows;
128 static ConfigDriver config_requires;
129 static ConfigDriver config_security;
130 static ConfigDriver config_referral;
131 static ConfigDriver config_loglevel;
132 static ConfigDriver config_updatedn;
133 static ConfigDriver config_updateref;
134 static ConfigDriver config_include;
135 static ConfigDriver config_obsolete;
136 #ifdef HAVE_TLS
137 static ConfigDriver config_tls_option;
138 static ConfigDriver config_tls_config;
139 #endif
140 extern ConfigDriver syncrepl_config;
141
142 enum {
143         CFG_ACL = 1,
144         CFG_BACKEND,
145         CFG_DATABASE,
146         CFG_TLS_RAND,
147         CFG_TLS_CIPHER,
148         CFG_TLS_CERT_FILE,
149         CFG_TLS_CERT_KEY,
150         CFG_TLS_CA_PATH,
151         CFG_TLS_CA_FILE,
152         CFG_TLS_DH_FILE,
153         CFG_TLS_VERIFY,
154         CFG_TLS_CRLCHECK,
155         CFG_TLS_CRL_FILE,
156         CFG_CONCUR,
157         CFG_THREADS,
158         CFG_SALT,
159         CFG_LIMITS,
160         CFG_RO,
161         CFG_REWRITE,
162         CFG_DEPTH,
163         CFG_OID,
164         CFG_OC,
165         CFG_DIT,
166         CFG_ATTR,
167         CFG_ATOPT,
168         CFG_ROOTDSE,
169         CFG_LOGFILE,
170         CFG_PLUGIN,
171         CFG_MODLOAD,
172         CFG_MODPATH,
173         CFG_LASTMOD,
174         CFG_AZPOLICY,
175         CFG_AZREGEXP,
176         CFG_SASLSECP,
177         CFG_SSTR_IF_MAX,
178         CFG_SSTR_IF_MIN,
179         CFG_TTHREADS,
180         CFG_MIRRORMODE,
181         CFG_HIDDEN,
182         CFG_MONITORING,
183         CFG_SERVERID,
184         CFG_SORTVALS,
185         CFG_IX_INTLEN,
186         CFG_SYNTAX,
187
188         CFG_LAST
189 };
190
191 typedef struct {
192         char *name, *oid;
193 } OidRec;
194
195 static OidRec OidMacros[] = {
196         /* OpenLDAProot:1.12.2 */
197         { "OLcfg", "1.3.6.1.4.1.4203.1.12.2" },
198         { "OLcfgAt", "OLcfg:3" },
199         { "OLcfgGlAt", "OLcfgAt:0" },
200         { "OLcfgBkAt", "OLcfgAt:1" },
201         { "OLcfgDbAt", "OLcfgAt:2" },
202         { "OLcfgOvAt", "OLcfgAt:3" },
203         { "OLcfgCtAt", "OLcfgAt:4" },   /* contrib modules */
204         { "OLcfgOc", "OLcfg:4" },
205         { "OLcfgGlOc", "OLcfgOc:0" },
206         { "OLcfgBkOc", "OLcfgOc:1" },
207         { "OLcfgDbOc", "OLcfgOc:2" },
208         { "OLcfgOvOc", "OLcfgOc:3" },
209         { "OLcfgCtOc", "OLcfgOc:4" },   /* contrib modules */
210
211         /* Syntaxes. We should just start using the standard names and
212          * document that they are predefined and available for users
213          * to reference in their own schema. Defining schema without
214          * OID macros is for masochists...
215          */
216         { "OMsyn", "1.3.6.1.4.1.1466.115.121.1" },
217         { "OMsBoolean", "OMsyn:7" },
218         { "OMsDN", "OMsyn:12" },
219         { "OMsDirectoryString", "OMsyn:15" },
220         { "OMsIA5String", "OMsyn:26" },
221         { "OMsInteger", "OMsyn:27" },
222         { "OMsOID", "OMsyn:38" },
223         { "OMsOctetString", "OMsyn:40" },
224         { NULL, NULL }
225 };
226
227 /*
228  * Backend/Database registry
229  *
230  * OLcfg{Bk|Db}{Oc|At}:0                -> common
231  * OLcfg{Bk|Db}{Oc|At}:1                -> back-bdb(/back-hdb)
232  * OLcfg{Bk|Db}{Oc|At}:2                -> back-ldif
233  * OLcfg{Bk|Db}{Oc|At}:3                -> back-ldap
234  * OLcfg{Bk|Db}{Oc|At}:4                -> back-monitor
235  * OLcfg{Bk|Db}{Oc|At}:5                -> back-relay
236  * OLcfg{Bk|Db}{Oc|At}:6                -> back-sql
237  * OLcfg{Bk|Db}{Oc|At}:7                -> back-sock
238  */
239
240 /*
241  * Overlay registry
242  *
243  * OLcfgOv{Oc|At}:1                     -> syncprov
244  * OLcfgOv{Oc|At}:2                     -> pcache
245  * OLcfgOv{Oc|At}:3                     -> chain
246  * OLcfgOv{Oc|At}:4                     -> accesslog
247  * OLcfgOv{Oc|At}:5                     -> valsort
248  * OLcfgOv{Oc|At}:7                     -> distproc
249  * OLcfgOv{Oc|At}:8                     -> dynlist
250  * OLcfgOv{Oc|At}:9                     -> dds
251  * OLcfgOv{Oc|At}:10                    -> unique
252  * OLcfgOv{Oc|At}:11                    -> refint
253  * OLcfgOv{Oc|At}:12                    -> ppolicy
254  * OLcfgOv{Oc|At}:13                    -> constraint
255  * OLcfgOv{Oc|At}:14                    -> translucent
256  * OLcfgOv{Oc|At}:15                    -> auditlog
257  * OLcfgOv{Oc|At}:16                    -> rwm
258  * OLcfgOv{Oc|At}:17                    -> dyngroup
259  * OLcfgOv{Oc|At}:18                    -> memberof
260  * OLcfgOv{Oc|At}:19                    -> collect
261  * OLcfgOv{Oc|At}:20                    -> retcode
262  */
263
264 /* alphabetical ordering */
265
266 static ConfigTable config_back_cf_table[] = {
267         /* This attr is read-only */
268         { "", "", 0, 0, 0, ARG_MAGIC,
269                 &config_fname, "( OLcfgGlAt:78 NAME 'olcConfigFile' "
270                         "DESC 'File for slapd configuration directives' "
271                         "EQUALITY caseIgnoreMatch "
272                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
273         { "", "", 0, 0, 0, ARG_MAGIC,
274                 &config_cfdir, "( OLcfgGlAt:79 NAME 'olcConfigDir' "
275                         "DESC 'Directory for slapd configuration backend' "
276                         "EQUALITY caseIgnoreMatch "
277                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
278         { "access",     NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC|CFG_ACL,
279                 &config_generic, "( OLcfgGlAt:1 NAME 'olcAccess' "
280                         "DESC 'Access Control List' "
281                         "EQUALITY caseIgnoreMatch "
282                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
283         { "allows",     "features", 2, 0, 5, ARG_PRE_DB|ARG_MAGIC,
284                 &config_allows, "( OLcfgGlAt:2 NAME 'olcAllows' "
285                         "DESC 'Allowed set of deprecated features' "
286                         "EQUALITY caseIgnoreMatch "
287                         "SYNTAX OMsDirectoryString )", NULL, NULL },
288         { "argsfile", "file", 2, 2, 0, ARG_STRING,
289                 &slapd_args_file, "( OLcfgGlAt:3 NAME 'olcArgsFile' "
290                         "DESC 'File for slapd command line options' "
291                         "EQUALITY caseIgnoreMatch "
292                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
293         { "attributeoptions", NULL, 0, 0, 0, ARG_MAGIC|CFG_ATOPT,
294                 &config_generic, "( OLcfgGlAt:5 NAME 'olcAttributeOptions' "
295                         "EQUALITY caseIgnoreMatch "
296                         "SYNTAX OMsDirectoryString )", NULL, NULL },
297         { "attribute",  "attribute", 2, 0, STRLENOF( "attribute" ),
298                 ARG_PAREN|ARG_MAGIC|CFG_ATTR,
299                 &config_generic, "( OLcfgGlAt:4 NAME 'olcAttributeTypes' "
300                         "DESC 'OpenLDAP attributeTypes' "
301                         "EQUALITY caseIgnoreMatch "
302                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
303                                 NULL, NULL },
304         { "authid-rewrite", NULL, 2, 0, STRLENOF( "authid-rewrite" ),
305 #ifdef SLAP_AUTH_REWRITE
306                 ARG_MAGIC|CFG_REWRITE|ARG_NO_INSERT, &config_generic,
307 #else
308                 ARG_IGNORED, NULL,
309 #endif
310                  "( OLcfgGlAt:6 NAME 'olcAuthIDRewrite' "
311                         "EQUALITY caseIgnoreMatch "
312                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
313         { "authz-policy", "policy", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_AZPOLICY,
314                 &config_generic, "( OLcfgGlAt:7 NAME 'olcAuthzPolicy' "
315                         "EQUALITY caseIgnoreMatch "
316                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
317         { "authz-regexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP|ARG_NO_INSERT,
318                 &config_generic, "( OLcfgGlAt:8 NAME 'olcAuthzRegexp' "
319                         "EQUALITY caseIgnoreMatch "
320                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
321         { "backend", "type", 2, 2, 0, ARG_PRE_DB|ARG_MAGIC|CFG_BACKEND,
322                 &config_generic, "( OLcfgGlAt:9 NAME 'olcBackend' "
323                         "DESC 'A type of backend' "
324                         "EQUALITY caseIgnoreMatch "
325                         "SYNTAX OMsDirectoryString SINGLE-VALUE X-ORDERED 'SIBLINGS' )",
326                                 NULL, NULL },
327         { "concurrency", "level", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_CONCUR,
328                 &config_generic, "( OLcfgGlAt:10 NAME 'olcConcurrency' "
329                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
330         { "conn_max_pending", "max", 2, 2, 0, ARG_INT,
331                 &slap_conn_max_pending, "( OLcfgGlAt:11 NAME 'olcConnMaxPending' "
332                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
333         { "conn_max_pending_auth", "max", 2, 2, 0, ARG_INT,
334                 &slap_conn_max_pending_auth, "( OLcfgGlAt:12 NAME 'olcConnMaxPendingAuth' "
335                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
336         { "database", "type", 2, 2, 0, ARG_MAGIC|CFG_DATABASE,
337                 &config_generic, "( OLcfgGlAt:13 NAME 'olcDatabase' "
338                         "DESC 'The backend type for a database instance' "
339                         "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
340         { "defaultSearchBase", "dn", 2, 2, 0, ARG_PRE_BI|ARG_PRE_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
341                 &config_search_base, "( OLcfgGlAt:14 NAME 'olcDefaultSearchBase' "
342                         "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
343         { "disallows", "features", 2, 0, 8, ARG_PRE_DB|ARG_MAGIC,
344                 &config_disallows, "( OLcfgGlAt:15 NAME 'olcDisallows' "
345                         "EQUALITY caseIgnoreMatch "
346                         "SYNTAX OMsDirectoryString )", NULL, NULL },
347         { "ditcontentrule",     NULL, 0, 0, 0, ARG_MAGIC|CFG_DIT|ARG_NO_DELETE|ARG_NO_INSERT,
348                 &config_generic, "( OLcfgGlAt:16 NAME 'olcDitContentRules' "
349                         "DESC 'OpenLDAP DIT content rules' "
350                         "EQUALITY caseIgnoreMatch "
351                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
352                         NULL, NULL },
353         { "gentlehup", "on|off", 2, 2, 0,
354 #ifdef SIGHUP
355                 ARG_ON_OFF, &global_gentlehup,
356 #else
357                 ARG_IGNORED, NULL,
358 #endif
359                 "( OLcfgGlAt:17 NAME 'olcGentleHUP' "
360                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
361         { "hidden", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_HIDDEN,
362                 &config_generic, "( OLcfgDbAt:0.17 NAME 'olcHidden' "
363                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
364         { "idletimeout", "timeout", 2, 2, 0, ARG_INT,
365                 &global_idletimeout, "( OLcfgGlAt:18 NAME 'olcIdleTimeout' "
366                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
367         { "include", "file", 2, 2, 0, ARG_MAGIC,
368                 &config_include, "( OLcfgGlAt:19 NAME 'olcInclude' "
369                         "SUP labeledURI )", NULL, NULL },
370         { "index_substr_if_minlen", "min", 2, 2, 0, ARG_INT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MIN,
371                 &config_generic, "( OLcfgGlAt:20 NAME 'olcIndexSubstrIfMinLen' "
372                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
373         { "index_substr_if_maxlen", "max", 2, 2, 0, ARG_INT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MAX,
374                 &config_generic, "( OLcfgGlAt:21 NAME 'olcIndexSubstrIfMaxLen' "
375                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
376         { "index_substr_any_len", "len", 2, 2, 0, ARG_INT|ARG_NONZERO,
377                 &index_substr_any_len, "( OLcfgGlAt:22 NAME 'olcIndexSubstrAnyLen' "
378                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
379         { "index_substr_any_step", "step", 2, 2, 0, ARG_INT|ARG_NONZERO,
380                 &index_substr_any_step, "( OLcfgGlAt:23 NAME 'olcIndexSubstrAnyStep' "
381                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
382         { "index_intlen", "len", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_IX_INTLEN,
383                 &config_generic, "( OLcfgGlAt:84 NAME 'olcIndexIntLen' "
384                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
385         { "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD,
386                 &config_generic, "( OLcfgDbAt:0.4 NAME 'olcLastMod' "
387                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
388         { "ldapsyntax", "syntax", 2, 0, 0,
389                 ARG_PAREN|ARG_MAGIC|CFG_SYNTAX,
390                 &config_generic, "( OLcfgGlAt:85 NAME 'olcLdapSyntaxes' "
391                         "DESC 'OpenLDAP ldapSyntax' "
392                         "EQUALITY caseIgnoreMatch "
393                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
394                                 NULL, NULL },
395         { "limits", "limits", 2, 0, 0, ARG_DB|ARG_MAGIC|CFG_LIMITS,
396                 &config_generic, "( OLcfgDbAt:0.5 NAME 'olcLimits' "
397                         "EQUALITY caseIgnoreMatch "
398                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
399         { "localSSF", "ssf", 2, 2, 0, ARG_INT,
400                 &local_ssf, "( OLcfgGlAt:26 NAME 'olcLocalSSF' "
401                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
402         { "logfile", "file", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_LOGFILE,
403                 &config_generic, "( OLcfgGlAt:27 NAME 'olcLogFile' "
404                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
405         { "loglevel", "level", 2, 0, 0, ARG_MAGIC,
406                 &config_loglevel, "( OLcfgGlAt:28 NAME 'olcLogLevel' "
407                         "EQUALITY caseIgnoreMatch "
408                         "SYNTAX OMsDirectoryString )", NULL, NULL },
409         { "maxDerefDepth", "depth", 2, 2, 0, ARG_DB|ARG_INT|ARG_MAGIC|CFG_DEPTH,
410                 &config_generic, "( OLcfgDbAt:0.6 NAME 'olcMaxDerefDepth' "
411                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
412         { "mirrormode", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_MIRRORMODE,
413                 &config_generic, "( OLcfgDbAt:0.16 NAME 'olcMirrorMode' "
414                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
415         { "moduleload", "file", 2, 0, 0,
416 #ifdef SLAPD_MODULES
417                 ARG_MAGIC|CFG_MODLOAD|ARG_NO_DELETE, &config_generic,
418 #else
419                 ARG_IGNORED, NULL,
420 #endif
421                 "( OLcfgGlAt:30 NAME 'olcModuleLoad' "
422                         "EQUALITY caseIgnoreMatch "
423                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
424         { "modulepath", "path", 2, 2, 0,
425 #ifdef SLAPD_MODULES
426                 ARG_MAGIC|CFG_MODPATH|ARG_NO_DELETE|ARG_NO_INSERT, &config_generic,
427 #else
428                 ARG_IGNORED, NULL,
429 #endif
430                 "( OLcfgGlAt:31 NAME 'olcModulePath' "
431                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
432         { "monitoring", "TRUE|FALSE", 2, 2, 0,
433                 ARG_MAGIC|CFG_MONITORING|ARG_DB|ARG_ON_OFF, &config_generic,
434                 "( OLcfgDbAt:0.18 NAME 'olcMonitoring' "
435                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
436         { "objectclass", "objectclass", 2, 0, 0, ARG_PAREN|ARG_MAGIC|CFG_OC,
437                 &config_generic, "( OLcfgGlAt:32 NAME 'olcObjectClasses' "
438                 "DESC 'OpenLDAP object classes' "
439                 "EQUALITY caseIgnoreMatch "
440                 "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
441                         NULL, NULL },
442         { "objectidentifier", "name> <oid",     3, 3, 0, ARG_MAGIC|CFG_OID,
443                 &config_generic, "( OLcfgGlAt:33 NAME 'olcObjectIdentifier' "
444                         "EQUALITY caseIgnoreMatch "
445                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
446         { "overlay", "overlay", 2, 2, 0, ARG_MAGIC,
447                 &config_overlay, "( OLcfgGlAt:34 NAME 'olcOverlay' "
448                         "SUP olcDatabase SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
449         { "password-crypt-salt-format", "salt", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_SALT,
450                 &config_generic, "( OLcfgGlAt:35 NAME 'olcPasswordCryptSaltFormat' "
451                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
452         { "password-hash", "hash", 2, 2, 0, ARG_MAGIC,
453                 &config_passwd_hash, "( OLcfgGlAt:36 NAME 'olcPasswordHash' "
454                         "EQUALITY caseIgnoreMatch "
455                         "SYNTAX OMsDirectoryString )", NULL, NULL },
456         { "pidfile", "file", 2, 2, 0, ARG_STRING,
457                 &slapd_pid_file, "( OLcfgGlAt:37 NAME 'olcPidFile' "
458                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
459         { "plugin", NULL, 0, 0, 0,
460 #ifdef LDAP_SLAPI
461                 ARG_MAGIC|CFG_PLUGIN, &config_generic,
462 #else
463                 ARG_IGNORED, NULL,
464 #endif
465                 "( OLcfgGlAt:38 NAME 'olcPlugin' "
466                         "EQUALITY caseIgnoreMatch "
467                         "SYNTAX OMsDirectoryString )", NULL, NULL },
468         { "pluginlog", "filename", 2, 2, 0,
469 #ifdef LDAP_SLAPI
470                 ARG_STRING, &slapi_log_file,
471 #else
472                 ARG_IGNORED, NULL,
473 #endif
474                 "( OLcfgGlAt:39 NAME 'olcPluginLogFile' "
475                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
476         { "readonly", "on|off", 2, 2, 0, ARG_MAY_DB|ARG_ON_OFF|ARG_MAGIC|CFG_RO,
477                 &config_generic, "( OLcfgGlAt:40 NAME 'olcReadOnly' "
478                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
479         { "referral", "url", 2, 2, 0, ARG_MAGIC,
480                 &config_referral, "( OLcfgGlAt:41 NAME 'olcReferral' "
481                         "SUP labeledURI SINGLE-VALUE )", NULL, NULL },
482         { "replica", "host or uri", 2, 0, 0, ARG_DB|ARG_MAGIC,
483                 &config_obsolete, "( OLcfgDbAt:0.7 NAME 'olcReplica' "
484                         "EQUALITY caseIgnoreMatch "
485                         "SUP labeledURI X-ORDERED 'VALUES' )", NULL, NULL },
486         { "replica-argsfile", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC,
487                 &config_obsolete, "( OLcfgGlAt:43 NAME 'olcReplicaArgsFile' "
488                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
489         { "replica-pidfile", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC,
490                 &config_obsolete, "( OLcfgGlAt:44 NAME 'olcReplicaPidFile' "
491                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
492         { "replicationInterval", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC,
493                 &config_obsolete, "( OLcfgGlAt:45 NAME 'olcReplicationInterval' "
494                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
495         { "replogfile", "filename", 2, 2, 0, ARG_MAY_DB|ARG_MAGIC,
496                 &config_obsolete, "( OLcfgGlAt:46 NAME 'olcReplogFile' "
497                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
498         { "require", "features", 2, 0, 7, ARG_MAY_DB|ARG_MAGIC,
499                 &config_requires, "( OLcfgGlAt:47 NAME 'olcRequires' "
500                         "EQUALITY caseIgnoreMatch "
501                         "SYNTAX OMsDirectoryString )", NULL, NULL },
502         { "restrict", "op_list", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
503                 &config_restrict, "( OLcfgGlAt:48 NAME 'olcRestrict' "
504                         "EQUALITY caseIgnoreMatch "
505                         "SYNTAX OMsDirectoryString )", NULL, NULL },
506         { "reverse-lookup", "on|off", 2, 2, 0,
507 #ifdef SLAPD_RLOOKUPS
508                 ARG_ON_OFF, &use_reverse_lookup,
509 #else
510                 ARG_IGNORED, NULL,
511 #endif
512                 "( OLcfgGlAt:49 NAME 'olcReverseLookup' "
513                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
514         { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
515                 &config_rootdn, "( OLcfgDbAt:0.8 NAME 'olcRootDN' "
516                         "EQUALITY distinguishedNameMatch "
517                         "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
518         { "rootDSE", "file", 2, 2, 0, ARG_MAGIC|CFG_ROOTDSE,
519                 &config_generic, "( OLcfgGlAt:51 NAME 'olcRootDSE' "
520                         "EQUALITY caseIgnoreMatch "
521                         "SYNTAX OMsDirectoryString )", NULL, NULL },
522         { "rootpw", "password", 2, 2, 0, ARG_BERVAL|ARG_DB|ARG_MAGIC,
523                 &config_rootpw, "( OLcfgDbAt:0.9 NAME 'olcRootPW' "
524                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
525         { "sasl-authz-policy", NULL, 2, 2, 0, ARG_MAGIC|CFG_AZPOLICY,
526                 &config_generic, NULL, NULL, NULL },
527         { "sasl-host", "host", 2, 2, 0,
528 #ifdef HAVE_CYRUS_SASL
529                 ARG_STRING|ARG_UNIQUE, &sasl_host,
530 #else
531                 ARG_IGNORED, NULL,
532 #endif
533                 "( OLcfgGlAt:53 NAME 'olcSaslHost' "
534                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
535         { "sasl-realm", "realm", 2, 2, 0,
536 #ifdef HAVE_CYRUS_SASL
537                 ARG_STRING|ARG_UNIQUE, &global_realm,
538 #else
539                 ARG_IGNORED, NULL,
540 #endif
541                 "( OLcfgGlAt:54 NAME 'olcSaslRealm' "
542                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
543         { "sasl-regexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
544                 &config_generic, NULL, NULL, NULL },
545         { "sasl-secprops", "properties", 2, 2, 0,
546 #ifdef HAVE_CYRUS_SASL
547                 ARG_MAGIC|CFG_SASLSECP, &config_generic,
548 #else
549                 ARG_IGNORED, NULL,
550 #endif
551                 "( OLcfgGlAt:56 NAME 'olcSaslSecProps' "
552                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
553         { "saslRegexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
554                 &config_generic, NULL, NULL, NULL },
555         { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
556                 &config_schema_dn, "( OLcfgGlAt:58 NAME 'olcSchemaDN' "
557                         "EQUALITY distinguishedNameMatch "
558                         "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
559         { "security", "factors", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
560                 &config_security, "( OLcfgGlAt:59 NAME 'olcSecurity' "
561                         "EQUALITY caseIgnoreMatch "
562                         "SYNTAX OMsDirectoryString )", NULL, NULL },
563         { "serverID", "number> <[URI]", 2, 3, 0, ARG_MAGIC|CFG_SERVERID,
564                 &config_generic, "( OLcfgGlAt:81 NAME 'olcServerID' "
565                         "EQUALITY caseIgnoreMatch "
566                         "SYNTAX OMsDirectoryString )", NULL, NULL },
567         { "sizelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
568                 &config_sizelimit, "( OLcfgGlAt:60 NAME 'olcSizeLimit' "
569                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
570         { "sockbuf_max_incoming", "max", 2, 2, 0, ARG_BER_LEN_T,
571                 &sockbuf_max_incoming, "( OLcfgGlAt:61 NAME 'olcSockbufMaxIncoming' "
572                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
573         { "sockbuf_max_incoming_auth", "max", 2, 2, 0, ARG_BER_LEN_T,
574                 &sockbuf_max_incoming_auth, "( OLcfgGlAt:62 NAME 'olcSockbufMaxIncomingAuth' "
575                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
576         { "sortvals", "attr", 2, 0, 0, ARG_MAGIC|CFG_SORTVALS,
577                 &config_generic, "( OLcfgGlAt:83 NAME 'olcSortVals' "
578                         "DESC 'Attributes whose values will always be sorted' "
579                         "EQUALITY caseIgnoreMatch "
580                         "SYNTAX OMsDirectoryString )", NULL, NULL },
581         { "subordinate", "[advertise]", 1, 2, 0, ARG_DB|ARG_MAGIC,
582                 &config_subordinate, "( OLcfgDbAt:0.15 NAME 'olcSubordinate' "
583                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
584         { "suffix",     "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
585                 &config_suffix, "( OLcfgDbAt:0.10 NAME 'olcSuffix' "
586                         "EQUALITY distinguishedNameMatch "
587                         "SYNTAX OMsDN )", NULL, NULL },
588         { "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC,
589                 &syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' "
590                         "EQUALITY caseIgnoreMatch "
591                         "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
592         { "threads", "count", 2, 2, 0,
593 #ifdef NO_THREADS
594                 ARG_IGNORED, NULL,
595 #else
596                 ARG_INT|ARG_MAGIC|CFG_THREADS, &config_generic,
597 #endif
598                 "( OLcfgGlAt:66 NAME 'olcThreads' "
599                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
600         { "timelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
601                 &config_timelimit, "( OLcfgGlAt:67 NAME 'olcTimeLimit' "
602                         "SYNTAX OMsDirectoryString )", NULL, NULL },
603         { "TLSCACertificateFile", NULL, 0, 0, 0,
604 #ifdef HAVE_TLS
605                 CFG_TLS_CA_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
606 #else
607                 ARG_IGNORED, NULL,
608 #endif
609                 "( OLcfgGlAt:68 NAME 'olcTLSCACertificateFile' "
610                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
611         { "TLSCACertificatePath", NULL, 0, 0, 0,
612 #ifdef HAVE_TLS
613                 CFG_TLS_CA_PATH|ARG_STRING|ARG_MAGIC, &config_tls_option,
614 #else
615                 ARG_IGNORED, NULL,
616 #endif
617                 "( OLcfgGlAt:69 NAME 'olcTLSCACertificatePath' "
618                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
619         { "TLSCertificateFile", NULL, 0, 0, 0,
620 #ifdef HAVE_TLS
621                 CFG_TLS_CERT_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
622 #else
623                 ARG_IGNORED, NULL,
624 #endif
625                 "( OLcfgGlAt:70 NAME 'olcTLSCertificateFile' "
626                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
627         { "TLSCertificateKeyFile", NULL, 0, 0, 0,
628 #ifdef HAVE_TLS
629                 CFG_TLS_CERT_KEY|ARG_STRING|ARG_MAGIC, &config_tls_option,
630 #else
631                 ARG_IGNORED, NULL,
632 #endif
633                 "( OLcfgGlAt:71 NAME 'olcTLSCertificateKeyFile' "
634                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
635         { "TLSCipherSuite",     NULL, 0, 0, 0,
636 #ifdef HAVE_TLS
637                 CFG_TLS_CIPHER|ARG_STRING|ARG_MAGIC, &config_tls_option,
638 #else
639                 ARG_IGNORED, NULL,
640 #endif
641                 "( OLcfgGlAt:72 NAME 'olcTLSCipherSuite' "
642                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
643         { "TLSCRLCheck", NULL, 0, 0, 0,
644 #if defined(HAVE_TLS) && defined(HAVE_OPENSSL_CRL)
645                 CFG_TLS_CRLCHECK|ARG_STRING|ARG_MAGIC, &config_tls_config,
646 #else
647                 ARG_IGNORED, NULL,
648 #endif
649                 "( OLcfgGlAt:73 NAME 'olcTLSCRLCheck' "
650                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
651         { "TLSCRLFile", NULL, 0, 0, 0,
652 #if defined(HAVE_GNUTLS)
653                 CFG_TLS_CRL_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
654 #else
655                 ARG_IGNORED, NULL,
656 #endif
657                 "( OLcfgGlAt:82 NAME 'olcTLSCRLFile' "
658                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
659         { "TLSRandFile", NULL, 0, 0, 0,
660 #ifdef HAVE_TLS
661                 CFG_TLS_RAND|ARG_STRING|ARG_MAGIC, &config_tls_option,
662 #else
663                 ARG_IGNORED, NULL,
664 #endif
665                 "( OLcfgGlAt:74 NAME 'olcTLSRandFile' "
666                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
667         { "TLSVerifyClient", NULL, 0, 0, 0,
668 #ifdef HAVE_TLS
669                 CFG_TLS_VERIFY|ARG_STRING|ARG_MAGIC, &config_tls_config,
670 #else
671                 ARG_IGNORED, NULL,
672 #endif
673                 "( OLcfgGlAt:75 NAME 'olcTLSVerifyClient' "
674                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
675         { "TLSDHParamFile", NULL, 0, 0, 0,
676 #ifdef HAVE_TLS
677                 CFG_TLS_DH_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
678 #else
679                 ARG_IGNORED, NULL,
680 #endif
681                 "( OLcfgGlAt:77 NAME 'olcTLSDHParamFile' "
682                         "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
683         { "tool-threads", "count", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_TTHREADS,
684                 &config_generic, "( OLcfgGlAt:80 NAME 'olcToolThreads' "
685                         "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
686         { "ucdata-path", "path", 2, 2, 0, ARG_IGNORED,
687                 NULL, NULL, NULL, NULL },
688         { "updatedn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
689                 &config_updatedn, "( OLcfgDbAt:0.12 NAME 'olcUpdateDN' "
690                         "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
691         { "updateref", "url", 2, 2, 0, ARG_DB|ARG_MAGIC,
692                 &config_updateref, "( OLcfgDbAt:0.13 NAME 'olcUpdateRef' "
693                         "EQUALITY caseIgnoreMatch "
694                         "SUP labeledURI )", NULL, NULL },
695         { NULL, NULL, 0, 0, 0, ARG_IGNORED,
696                 NULL, NULL, NULL, NULL }
697 };
698
699 /* Need to no-op this keyword for dynamic config */
700 ConfigTable olcDatabaseDummy[] = {
701         { "", "", 0, 0, 0, ARG_IGNORED,
702                 NULL, "( OLcfgGlAt:13 NAME 'olcDatabase' "
703                         "DESC 'The backend type for a database instance' "
704                         "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
705         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
706 };
707
708 /* Routines to check if a child can be added to this type */
709 static ConfigLDAPadd cfAddSchema, cfAddInclude, cfAddDatabase,
710         cfAddBackend, cfAddModule, cfAddOverlay;
711
712 /* NOTE: be careful when defining array members
713  * that can be conditionally compiled */
714 #define CFOC_GLOBAL     cf_ocs[1]
715 #define CFOC_SCHEMA     cf_ocs[2]
716 #define CFOC_BACKEND    cf_ocs[3]
717 #define CFOC_DATABASE   cf_ocs[4]
718 #define CFOC_OVERLAY    cf_ocs[5]
719 #define CFOC_INCLUDE    cf_ocs[6]
720 #define CFOC_FRONTEND   cf_ocs[7]
721 #ifdef SLAPD_MODULES
722 #define CFOC_MODULE     cf_ocs[8]
723 #endif /* SLAPD_MODULES */
724
725 static ConfigOCs cf_ocs[] = {
726         { "( OLcfgGlOc:0 "
727                 "NAME 'olcConfig' "
728                 "DESC 'OpenLDAP configuration object' "
729                 "ABSTRACT SUP top )", Cft_Abstract, NULL },
730         { "( OLcfgGlOc:1 "
731                 "NAME 'olcGlobal' "
732                 "DESC 'OpenLDAP Global configuration options' "
733                 "SUP olcConfig STRUCTURAL "
734                 "MAY ( cn $ olcConfigFile $ olcConfigDir $ olcAllows $ olcArgsFile $ "
735                  "olcAttributeOptions $ olcAuthIDRewrite $ "
736                  "olcAuthzPolicy $ olcAuthzRegexp $ olcConcurrency $ "
737                  "olcConnMaxPending $ olcConnMaxPendingAuth $ "
738                  "olcDisallows $ olcGentleHUP $ olcIdleTimeout $ "
739                  "olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ "
740                  "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcIndexIntLen $ "
741                  "olcLocalSSF $ olcLogFile $ olcLogLevel $ "
742                  "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ "
743                  "olcPluginLogFile $ olcReadOnly $ olcReferral $ "
744                  "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
745                  "olcRootDSE $ "
746                  "olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
747                  "olcSecurity $ olcServerID $ olcSizeLimit $ "
748                  "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ "
749                  "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ "
750                  "olcTLSCACertificatePath $ olcTLSCertificateFile $ "
751                  "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ "
752                  "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ "
753                  "olcTLSCRLFile $ olcToolThreads $ "
754                  "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ "
755                  "olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Global },
756         { "( OLcfgGlOc:2 "
757                 "NAME 'olcSchemaConfig' "
758                 "DESC 'OpenLDAP schema object' "
759                 "SUP olcConfig STRUCTURAL "
760                 "MAY ( cn $ olcObjectIdentifier $ olcAttributeTypes $ "
761                  "olcObjectClasses $ olcDitContentRules $ olcLdapSyntaxes ) )",
762                         Cft_Schema, NULL, cfAddSchema },
763         { "( OLcfgGlOc:3 "
764                 "NAME 'olcBackendConfig' "
765                 "DESC 'OpenLDAP Backend-specific options' "
766                 "SUP olcConfig STRUCTURAL "
767                 "MUST olcBackend )", Cft_Backend, NULL, cfAddBackend },
768         { "( OLcfgGlOc:4 "
769                 "NAME 'olcDatabaseConfig' "
770                 "DESC 'OpenLDAP Database-specific options' "
771                 "SUP olcConfig STRUCTURAL "
772                 "MUST olcDatabase "
773                 "MAY ( olcHidden $ olcSuffix $ olcSubordinate $ olcAccess $ "
774                  "olcLastMod $ olcLimits $ "
775                  "olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ "
776                  "olcReplicaArgsFile $ olcReplicaPidFile $ olcReplicationInterval $ "
777                  "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ "
778                  "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncrepl $ "
779                  "olcTimeLimit $ olcUpdateDN $ olcUpdateRef $ olcMirrorMode $ "
780                  "olcMonitoring ) )",
781                         Cft_Database, NULL, cfAddDatabase },
782         { "( OLcfgGlOc:5 "
783                 "NAME 'olcOverlayConfig' "
784                 "DESC 'OpenLDAP Overlay-specific options' "
785                 "SUP olcConfig STRUCTURAL "
786                 "MUST olcOverlay )", Cft_Overlay, NULL, cfAddOverlay },
787         { "( OLcfgGlOc:6 "
788                 "NAME 'olcIncludeFile' "
789                 "DESC 'OpenLDAP configuration include file' "
790                 "SUP olcConfig STRUCTURAL "
791                 "MUST olcInclude "
792                 "MAY ( cn $ olcRootDSE ) )",
793                 /* Used to be Cft_Include, that def has been removed */
794                 Cft_Abstract, NULL, cfAddInclude },
795         /* This should be STRUCTURAL like all the other database classes, but
796          * that would mean inheriting all of the olcDatabaseConfig attributes,
797          * which causes them to be merged twice in config_build_entry.
798          */
799         { "( OLcfgGlOc:7 "
800                 "NAME 'olcFrontendConfig' "
801                 "DESC 'OpenLDAP frontend configuration' "
802                 "AUXILIARY "
803                 "MAY ( olcDefaultSearchBase $ olcPasswordHash $ olcSortVals ) )",
804                 Cft_Database, NULL, NULL },
805 #ifdef SLAPD_MODULES
806         { "( OLcfgGlOc:8 "
807                 "NAME 'olcModuleList' "
808                 "DESC 'OpenLDAP dynamic module info' "
809                 "SUP olcConfig STRUCTURAL "
810                 "MAY ( cn $ olcModulePath $ olcModuleLoad ) )",
811                 Cft_Module, NULL, cfAddModule },
812 #endif
813         { NULL, 0, NULL }
814 };
815
816 typedef struct ServerID {
817         struct ServerID *si_next;
818         struct berval si_url;
819         int si_num;
820 } ServerID;
821
822 static ServerID *sid_list;
823
824 typedef struct voidList {
825         struct voidList *vl_next;
826         void *vl_ptr;
827 } voidList;
828
829 typedef struct ADlist {
830         struct ADlist *al_next;
831         AttributeDescription *al_desc;
832 } ADlist;
833
834 static ADlist *sortVals;
835
836 static int
837 config_generic(ConfigArgs *c) {
838         int i;
839
840         if ( c->op == SLAP_CONFIG_EMIT ) {
841                 int rc = 0;
842                 switch(c->type) {
843                 case CFG_CONCUR:
844                         c->value_int = ldap_pvt_thread_get_concurrency();
845                         break;
846                 case CFG_THREADS:
847                         c->value_int = connection_pool_max;
848                         break;
849                 case CFG_TTHREADS:
850                         c->value_int = slap_tool_thread_max;
851                         break;
852                 case CFG_SALT:
853                         if ( passwd_salt )
854                                 c->value_string = ch_strdup( passwd_salt );
855                         else
856                                 rc = 1;
857                         break;
858                 case CFG_LIMITS:
859                         if ( c->be->be_limits ) {
860                                 char buf[4096*3];
861                                 struct berval bv;
862
863                                 for ( i=0; c->be->be_limits[i]; i++ ) {
864                                         bv.bv_len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i );
865                                         if ( bv.bv_len >= sizeof( buf ) ) {
866                                                 ber_bvarray_free_x( c->rvalue_vals, NULL );
867                                                 c->rvalue_vals = NULL;
868                                                 rc = 1;
869                                                 break;
870                                         }
871                                         bv.bv_val = buf + bv.bv_len;
872                                         limits_unparse( c->be->be_limits[i], &bv,
873                                                         sizeof( buf ) - ( bv.bv_val - buf ) );
874                                         bv.bv_len += bv.bv_val - buf;
875                                         bv.bv_val = buf;
876                                         value_add_one( &c->rvalue_vals, &bv );
877                                 }
878                         }
879                         if ( !c->rvalue_vals ) rc = 1;
880                         break;
881                 case CFG_RO:
882                         c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_OP_WRITES) ==
883                                 SLAP_RESTRICT_OP_WRITES;
884                         break;
885                 case CFG_AZPOLICY:
886                         c->value_string = ch_strdup( slap_sasl_getpolicy());
887                         break;
888                 case CFG_AZREGEXP:
889                         slap_sasl_regexp_unparse( &c->rvalue_vals );
890                         if ( !c->rvalue_vals ) rc = 1;
891                         break;
892 #ifdef HAVE_CYRUS_SASL
893                 case CFG_SASLSECP: {
894                         struct berval bv = BER_BVNULL;
895                         slap_sasl_secprops_unparse( &bv );
896                         if ( !BER_BVISNULL( &bv )) {
897                                 ber_bvarray_add( &c->rvalue_vals, &bv );
898                         } else {
899                                 rc = 1;
900                         }
901                         }
902                         break;
903 #endif
904                 case CFG_DEPTH:
905                         c->value_int = c->be->be_max_deref_depth;
906                         break;
907                 case CFG_HIDDEN:
908                         if ( SLAP_DBHIDDEN( c->be )) {
909                                 c->value_int = 1;
910                         } else {
911                                 rc = 1;
912                         }
913                         break;
914                 case CFG_OID: {
915                         ConfigFile *cf = c->ca_private;
916                         if ( !cf )
917                                 oidm_unparse( &c->rvalue_vals, NULL, NULL, 1 );
918                         else if ( cf->c_om_head )
919                                 oidm_unparse( &c->rvalue_vals, cf->c_om_head,
920                                         cf->c_om_tail, 0 );
921                         if ( !c->rvalue_vals )
922                                 rc = 1;
923                         }
924                         break;
925                 case CFG_ATOPT:
926                         ad_unparse_options( &c->rvalue_vals );
927                         break;
928                 case CFG_OC: {
929                         ConfigFile *cf = c->ca_private;
930                         if ( !cf )
931                                 oc_unparse( &c->rvalue_vals, NULL, NULL, 1 );
932                         else if ( cf->c_oc_head )
933                                 oc_unparse( &c->rvalue_vals, cf->c_oc_head,
934                                         cf->c_oc_tail, 0 );
935                         if ( !c->rvalue_vals )
936                                 rc = 1;
937                         }
938                         break;
939                 case CFG_ATTR: {
940                         ConfigFile *cf = c->ca_private;
941                         if ( !cf )
942                                 at_unparse( &c->rvalue_vals, NULL, NULL, 1 );
943                         else if ( cf->c_at_head )
944                                 at_unparse( &c->rvalue_vals, cf->c_at_head,
945                                         cf->c_at_tail, 0 );
946                         if ( !c->rvalue_vals )
947                                 rc = 1;
948                         }
949                         break;
950                 case CFG_SYNTAX: {
951                         ConfigFile *cf = c->ca_private;
952                         if ( !cf )
953                                 syn_unparse( &c->rvalue_vals, NULL, NULL, 1 );
954                         else if ( cf->c_syn_head )
955                                 syn_unparse( &c->rvalue_vals, cf->c_syn_head,
956                                         cf->c_syn_tail, 0 );
957                         if ( !c->rvalue_vals )
958                                 rc = 1;
959                         }
960                         break;
961                 case CFG_DIT: {
962                         ConfigFile *cf = c->ca_private;
963                         if ( !cf )
964                                 cr_unparse( &c->rvalue_vals, NULL, NULL, 1 );
965                         else if ( cf->c_cr_head )
966                                 cr_unparse( &c->rvalue_vals, cf->c_cr_head,
967                                         cf->c_cr_tail, 0 );
968                         if ( !c->rvalue_vals )
969                                 rc = 1;
970                         }
971                         break;
972                         
973                 case CFG_ACL: {
974                         AccessControl *a;
975                         char *src, *dst, ibuf[11];
976                         struct berval bv, abv;
977                         AccessControl *end;
978                         if ( c->be == frontendDB )
979                                 end = NULL;
980                         else
981                                 end = frontendDB->be_acl;
982                         for (i=0, a=c->be->be_acl; a && a != end; i++,a=a->acl_next) {
983                                 abv.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
984                                 if ( abv.bv_len >= sizeof( ibuf ) ) {
985                                         ber_bvarray_free_x( c->rvalue_vals, NULL );
986                                         c->rvalue_vals = NULL;
987                                         i = 0;
988                                         break;
989                                 }
990                                 acl_unparse( a, &bv );
991                                 abv.bv_val = ch_malloc( abv.bv_len + bv.bv_len + 1 );
992                                 AC_MEMCPY( abv.bv_val, ibuf, abv.bv_len );
993                                 /* Turn TAB / EOL into plain space */
994                                 for (src=bv.bv_val,dst=abv.bv_val+abv.bv_len; *src; src++) {
995                                         if (isspace((unsigned char)*src)) *dst++ = ' ';
996                                         else *dst++ = *src;
997                                 }
998                                 *dst = '\0';
999                                 if (dst[-1] == ' ') {
1000                                         dst--;
1001                                         *dst = '\0';
1002                                 }
1003                                 abv.bv_len = dst - abv.bv_val;
1004                                 ber_bvarray_add( &c->rvalue_vals, &abv );
1005                         }
1006                         rc = (!i);
1007                         break;
1008                 }
1009                 case CFG_ROOTDSE: {
1010                         ConfigFile *cf = c->ca_private;
1011                         if ( cf->c_dseFiles ) {
1012                                 value_add( &c->rvalue_vals, cf->c_dseFiles );
1013                         } else {
1014                                 rc = 1;
1015                         }
1016                         }
1017                         break;
1018                 case CFG_SERVERID:
1019                         if ( sid_list ) {
1020                                 ServerID *si;
1021                                 struct berval bv;
1022
1023                                 for ( si = sid_list; si; si=si->si_next ) {
1024                                         assert( si->si_num >= 0 && si->si_num <= SLAP_SYNC_SID_MAX );
1025                                         if ( !BER_BVISEMPTY( &si->si_url )) {
1026                                                 bv.bv_len = si->si_url.bv_len + 6;
1027                                                 bv.bv_val = ch_malloc( bv.bv_len );
1028                                                 sprintf( bv.bv_val, "%d %s", si->si_num,
1029                                                         si->si_url.bv_val );
1030                                                 ber_bvarray_add( &c->rvalue_vals, &bv );
1031                                         } else {
1032                                                 char buf[5];
1033                                                 bv.bv_val = buf;
1034                                                 bv.bv_len = sprintf( buf, "%d", si->si_num );
1035                                                 value_add_one( &c->rvalue_vals, &bv );
1036                                         }
1037                                 }
1038                         } else {
1039                                 rc = 1;
1040                         }
1041                         break;
1042                 case CFG_LOGFILE:
1043                         if ( logfileName )
1044                                 c->value_string = ch_strdup( logfileName );
1045                         else
1046                                 rc = 1;
1047                         break;
1048                 case CFG_LASTMOD:
1049                         c->value_int = (SLAP_NOLASTMOD(c->be) == 0);
1050                         break;
1051                 case CFG_MIRRORMODE:
1052                         if ( SLAP_SHADOW(c->be))
1053                                 c->value_int = (SLAP_SINGLE_SHADOW(c->be) == 0);
1054                         else
1055                                 rc = 1;
1056                         break;
1057                 case CFG_MONITORING:
1058                         c->value_int = (SLAP_DBMONITORING(c->be) != 0);
1059                         break;
1060                 case CFG_SSTR_IF_MAX:
1061                         c->value_int = index_substr_if_maxlen;
1062                         break;
1063                 case CFG_SSTR_IF_MIN:
1064                         c->value_int = index_substr_if_minlen;
1065                         break;
1066                 case CFG_IX_INTLEN:
1067                         c->value_int = index_intlen;
1068                         break;
1069                 case CFG_SORTVALS: {
1070                         ADlist *sv;
1071                         rc = 1;
1072                         for ( sv = sortVals; sv; sv = sv->al_next ) {
1073                                 value_add_one( &c->rvalue_vals, &sv->al_desc->ad_cname );
1074                                 rc = 0;
1075                         }
1076                         } break;
1077 #ifdef SLAPD_MODULES
1078                 case CFG_MODLOAD: {
1079                         ModPaths *mp = c->ca_private;
1080                         if (mp->mp_loads) {
1081                                 int i;
1082                                 for (i=0; !BER_BVISNULL(&mp->mp_loads[i]); i++) {
1083                                         struct berval bv;
1084                                         bv.bv_val = c->log;
1085                                         bv.bv_len = snprintf( bv.bv_val, sizeof( c->log ),
1086                                                 SLAP_X_ORDERED_FMT "%s", i,
1087                                                 mp->mp_loads[i].bv_val );
1088                                         if ( bv.bv_len >= sizeof( c->log ) ) {
1089                                                 ber_bvarray_free_x( c->rvalue_vals, NULL );
1090                                                 c->rvalue_vals = NULL;
1091                                                 break;
1092                                         }
1093                                         value_add_one( &c->rvalue_vals, &bv );
1094                                 }
1095                         }
1096
1097                         rc = c->rvalue_vals ? 0 : 1;
1098                         }
1099                         break;
1100                 case CFG_MODPATH: {
1101                         ModPaths *mp = c->ca_private;
1102                         if ( !BER_BVISNULL( &mp->mp_path ))
1103                                 value_add_one( &c->rvalue_vals, &mp->mp_path );
1104
1105                         rc = c->rvalue_vals ? 0 : 1;
1106                         }
1107                         break;
1108 #endif
1109 #ifdef LDAP_SLAPI
1110                 case CFG_PLUGIN:
1111                         slapi_int_plugin_unparse( c->be, &c->rvalue_vals );
1112                         if ( !c->rvalue_vals ) rc = 1;
1113                         break;
1114 #endif
1115 #ifdef SLAP_AUTH_REWRITE
1116                 case CFG_REWRITE:
1117                         if ( authz_rewrites ) {
1118                                 struct berval bv, idx;
1119                                 char ibuf[32];
1120                                 int i;
1121
1122                                 idx.bv_val = ibuf;
1123                                 for ( i=0; !BER_BVISNULL( &authz_rewrites[i] ); i++ ) {
1124                                         idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
1125                                         if ( idx.bv_len >= sizeof( ibuf ) ) {
1126                                                 ber_bvarray_free_x( c->rvalue_vals, NULL );
1127                                                 c->rvalue_vals = NULL;
1128                                                 break;
1129                                         }
1130                                         bv.bv_len = idx.bv_len + authz_rewrites[i].bv_len;
1131                                         bv.bv_val = ch_malloc( bv.bv_len + 1 );
1132                                         AC_MEMCPY( bv.bv_val, idx.bv_val, idx.bv_len );
1133                                         AC_MEMCPY( &bv.bv_val[ idx.bv_len ],
1134                                                 authz_rewrites[i].bv_val,
1135                                                 authz_rewrites[i].bv_len + 1 );
1136                                         ber_bvarray_add( &c->rvalue_vals, &bv );
1137                                 }
1138                         }
1139                         if ( !c->rvalue_vals ) rc = 1;
1140                         break;
1141 #endif
1142                 default:
1143                         rc = 1;
1144                 }
1145                 return rc;
1146         } else if ( c->op == LDAP_MOD_DELETE ) {
1147                 int rc = 0;
1148                 switch(c->type) {
1149                 /* single-valued attrs, no-ops */
1150                 case CFG_CONCUR:
1151                 case CFG_THREADS:
1152                 case CFG_TTHREADS:
1153                 case CFG_RO:
1154                 case CFG_AZPOLICY:
1155                 case CFG_DEPTH:
1156                 case CFG_LASTMOD:
1157                 case CFG_MIRRORMODE:
1158                 case CFG_MONITORING:
1159                 case CFG_SASLSECP:
1160                 case CFG_SSTR_IF_MAX:
1161                 case CFG_SSTR_IF_MIN:
1162                         break;
1163
1164                 /* no-ops, requires slapd restart */
1165                 case CFG_PLUGIN:
1166                 case CFG_MODLOAD:
1167                 case CFG_AZREGEXP:
1168                 case CFG_REWRITE:
1169                         snprintf(c->log, sizeof( c->log ), "change requires slapd restart");
1170                         break;
1171
1172                 case CFG_SALT:
1173                         ch_free( passwd_salt );
1174                         passwd_salt = NULL;
1175                         break;
1176
1177                 case CFG_LOGFILE:
1178                         ch_free( logfileName );
1179                         logfileName = NULL;
1180                         if ( logfile ) {
1181                                 fclose( logfile );
1182                                 logfile = NULL;
1183                         }
1184                         break;
1185
1186                 case CFG_SERVERID: {
1187                         ServerID *si, **sip;
1188
1189                         for ( i=0, si = sid_list, sip = &sid_list;
1190                                 si; si = *sip, i++ ) {
1191                                 if ( c->valx == -1 || i == c->valx ) {
1192                                         *sip = si->si_next;
1193                                         ch_free( si );
1194                                         if ( c->valx >= 0 )
1195                                                 break;
1196                                 } else {
1197                                         sip = &si->si_next;
1198                                 }
1199                         }
1200                         }
1201                         break;
1202                 case CFG_HIDDEN:
1203                         c->be->be_flags &= ~SLAP_DBFLAG_HIDDEN;
1204                         break;
1205
1206                 case CFG_IX_INTLEN:
1207                         index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
1208                         index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
1209                                 SLAP_INDEX_INTLEN_DEFAULT );
1210                         break;
1211
1212                 case CFG_ACL:
1213                         if ( c->valx < 0 ) {
1214                                 AccessControl *end;
1215                                 if ( c->be == frontendDB )
1216                                         end = NULL;
1217                                 else
1218                                         end = frontendDB->be_acl;
1219                                 acl_destroy( c->be->be_acl, end );
1220                                 c->be->be_acl = end;
1221
1222                         } else {
1223                                 AccessControl **prev, *a;
1224                                 int i;
1225                                 for (i=0, prev = &c->be->be_acl; i < c->valx;
1226                                         i++ ) {
1227                                         a = *prev;
1228                                         prev = &a->acl_next;
1229                                 }
1230                                 a = *prev;
1231                                 *prev = a->acl_next;
1232                                 acl_free( a );
1233                         }
1234                         break;
1235
1236                 case CFG_OC: {
1237                         CfEntryInfo *ce;
1238                         /* Can be NULL when undoing a failed add */
1239                         if ( c->ca_entry ) {
1240                                 ce = c->ca_entry->e_private;
1241                                 /* can't modify the hardcoded schema */
1242                                 if ( ce->ce_parent->ce_type == Cft_Global )
1243                                         return 1;
1244                                 }
1245                         }
1246                         cfn = c->ca_private;
1247                         if ( c->valx < 0 ) {
1248                                 ObjectClass *oc;
1249
1250                                 for( oc = cfn->c_oc_head; oc; oc_next( &oc )) {
1251                                         oc_delete( oc );
1252                                         if ( oc  == cfn->c_oc_tail )
1253                                                 break;
1254                                 }
1255                                 cfn->c_oc_head = cfn->c_oc_tail = NULL;
1256                         } else {
1257                                 ObjectClass *oc, *prev = NULL;
1258
1259                                 for ( i=0, oc=cfn->c_oc_head; i<c->valx; i++) {
1260                                         prev = oc;
1261                                         oc_next( &oc );
1262                                 }
1263                                 oc_delete( oc );
1264                                 if ( cfn->c_oc_tail == oc ) {
1265                                         cfn->c_oc_tail = prev;
1266                                 }
1267                                 if ( cfn->c_oc_head == oc ) {
1268                                         oc_next( &oc );
1269                                         cfn->c_oc_head = oc;
1270                                 }
1271                         }
1272                         break;
1273
1274                 case CFG_ATTR: {
1275                         CfEntryInfo *ce;
1276                         /* Can be NULL when undoing a failed add */
1277                         if ( c->ca_entry ) {
1278                                 ce = c->ca_entry->e_private;
1279                                 /* can't modify the hardcoded schema */
1280                                 if ( ce->ce_parent->ce_type == Cft_Global )
1281                                         return 1;
1282                                 }
1283                         }
1284                         cfn = c->ca_private;
1285                         if ( c->valx < 0 ) {
1286                                 AttributeType *at;
1287
1288                                 for( at = cfn->c_at_head; at; at_next( &at )) {
1289                                         at_delete( at );
1290                                         if ( at  == cfn->c_at_tail )
1291                                                 break;
1292                                 }
1293                                 cfn->c_at_head = cfn->c_at_tail = NULL;
1294                         } else {
1295                                 AttributeType *at, *prev = NULL;
1296
1297                                 for ( i=0, at=cfn->c_at_head; i<c->valx; i++) {
1298                                         prev = at;
1299                                         at_next( &at );
1300                                 }
1301                                 at_delete( at );
1302                                 if ( cfn->c_at_tail == at ) {
1303                                         cfn->c_at_tail = prev;
1304                                 }
1305                                 if ( cfn->c_at_head == at ) {
1306                                         at_next( &at );
1307                                         cfn->c_at_head = at;
1308                                 }
1309                         }
1310                         break;
1311
1312                 case CFG_SYNTAX: {
1313                         CfEntryInfo *ce;
1314                         /* Can be NULL when undoing a failed add */
1315                         if ( c->ca_entry ) {
1316                                 ce = c->ca_entry->e_private;
1317                                 /* can't modify the hardcoded schema */
1318                                 if ( ce->ce_parent->ce_type == Cft_Global )
1319                                         return 1;
1320                                 }
1321                         }
1322                         cfn = c->ca_private;
1323                         if ( c->valx < 0 ) {
1324                                 Syntax *syn;
1325
1326                                 for( syn = cfn->c_syn_head; syn; syn_next( &syn )) {
1327                                         syn_delete( syn );
1328                                         if ( syn == cfn->c_syn_tail )
1329                                                 break;
1330                                 }
1331                                 cfn->c_syn_head = cfn->c_syn_tail = NULL;
1332                         } else {
1333                                 Syntax *syn, *prev = NULL;
1334
1335                                 for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++) {
1336                                         prev = syn;
1337                                         syn_next( &syn );
1338                                 }
1339                                 syn_delete( syn );
1340                                 if ( cfn->c_syn_tail == syn ) {
1341                                         cfn->c_syn_tail = prev;
1342                                 }
1343                                 if ( cfn->c_syn_head == syn ) {
1344                                         syn_next( &syn );
1345                                         cfn->c_syn_head = syn;
1346                                 }
1347                         }
1348                         break;
1349                 case CFG_SORTVALS:
1350                         if ( c->valx < 0 ) {
1351                                 ADlist *sv;
1352                                 for ( sv = sortVals; sv; sv = sortVals ) {
1353                                         sortVals = sv->al_next;
1354                                         sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL;
1355                                         ch_free( sv );
1356                                 }
1357                         } else {
1358                                 ADlist *sv, **prev;
1359                                 int i = 0;
1360
1361                                 for ( prev = &sortVals, sv = sortVals; i < c->valx; i++ ) {
1362                                         prev = &sv->al_next;
1363                                         sv = sv->al_next;
1364                                 }
1365                                 sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL;
1366                                 *prev = sv->al_next;
1367                                 ch_free( sv );
1368                         }
1369                         break;
1370
1371                 case CFG_LIMITS:
1372                         /* FIXME: there is no limits_free function */
1373                 case CFG_ATOPT:
1374                         /* FIXME: there is no ad_option_free function */
1375                 case CFG_ROOTDSE:
1376                         /* FIXME: there is no way to remove attributes added by
1377                                 a DSE file */
1378                 case CFG_OID:
1379                 case CFG_DIT:
1380                 case CFG_MODPATH:
1381                 default:
1382                         rc = 1;
1383                         break;
1384                 }
1385                 return rc;
1386         }
1387
1388         switch(c->type) {
1389                 case CFG_BACKEND:
1390                         if(!(c->bi = backend_info(c->argv[1]))) {
1391                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> failed init", c->argv[0] );
1392                                 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
1393                                         c->log, c->cr_msg, c->argv[1] );
1394                                 return(1);
1395                         }
1396                         break;
1397
1398                 case CFG_DATABASE:
1399                         c->bi = NULL;
1400                         /* NOTE: config is always the first backend!
1401                          */
1402                         if ( !strcasecmp( c->argv[1], "config" )) {
1403                                 c->be = LDAP_STAILQ_FIRST(&backendDB);
1404                         } else if ( !strcasecmp( c->argv[1], "frontend" )) {
1405                                 c->be = frontendDB;
1406                         } else {
1407                                 c->be = backend_db_init(c->argv[1], NULL, c->valx, &c->reply);
1408                                 if ( !c->be ) {
1409                                         if ( c->cr_msg[0] == 0 )
1410                                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> failed init", c->argv[0] );
1411                                         Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", c->log, c->cr_msg, c->argv[1] );
1412                                         return(1);
1413                                 }
1414                         }
1415                         break;
1416
1417                 case CFG_CONCUR:
1418                         ldap_pvt_thread_set_concurrency(c->value_int);
1419                         break;
1420
1421                 case CFG_THREADS:
1422                         if ( c->value_int < 2 ) {
1423                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1424                                         "threads=%d smaller than minimum value 2",
1425                                         c->value_int );
1426                                 Debug(LDAP_DEBUG_ANY, "%s: %s.\n",
1427                                         c->log, c->cr_msg, 0 );
1428                                 return 1;
1429
1430                         } else if ( c->value_int > 2 * SLAP_MAX_WORKER_THREADS ) {
1431                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1432                                         "warning, threads=%d larger than twice the default (2*%d=%d); YMMV",
1433                                         c->value_int, SLAP_MAX_WORKER_THREADS, 2 * SLAP_MAX_WORKER_THREADS );
1434                                 Debug(LDAP_DEBUG_ANY, "%s: %s.\n",
1435                                         c->log, c->cr_msg, 0 );
1436                         }
1437                         if ( slapMode & SLAP_SERVER_MODE )
1438                                 ldap_pvt_thread_pool_maxthreads(&connection_pool, c->value_int);
1439                         connection_pool_max = c->value_int;     /* save for reference */
1440                         break;
1441
1442                 case CFG_TTHREADS:
1443                         if ( slapMode & SLAP_TOOL_MODE )
1444                                 ldap_pvt_thread_pool_maxthreads(&connection_pool, c->value_int);
1445                         slap_tool_thread_max = c->value_int;    /* save for reference */
1446                         break;
1447
1448                 case CFG_SALT:
1449                         if ( passwd_salt ) ch_free( passwd_salt );
1450                         passwd_salt = c->value_string;
1451                         lutil_salt_format(passwd_salt);
1452                         break;
1453
1454                 case CFG_LIMITS:
1455                         if(limits_parse(c->be, c->fname, c->lineno, c->argc, c->argv))
1456                                 return(1);
1457                         break;
1458
1459                 case CFG_RO:
1460                         if(c->value_int)
1461                                 c->be->be_restrictops |= SLAP_RESTRICT_OP_WRITES;
1462                         else
1463                                 c->be->be_restrictops &= ~SLAP_RESTRICT_OP_WRITES;
1464                         break;
1465
1466                 case CFG_AZPOLICY:
1467                         ch_free(c->value_string);
1468                         if (slap_sasl_setpolicy( c->argv[1] )) {
1469                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] );
1470                                 Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
1471                                         c->log, c->cr_msg, c->argv[1] );
1472                                 return(1);
1473                         }
1474                         break;
1475                 
1476                 case CFG_AZREGEXP:
1477                         if (slap_sasl_regexp_config( c->argv[1], c->argv[2] ))
1478                                 return(1);
1479                         break;
1480                                 
1481 #ifdef HAVE_CYRUS_SASL
1482                 case CFG_SASLSECP:
1483                         {
1484                         char *txt = slap_sasl_secprops( c->argv[1] );
1485                         if ( txt ) {
1486                                 snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> %s",
1487                                         c->argv[0], txt );
1488                                 Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0 );
1489                                 return(1);
1490                         }
1491                         break;
1492                         }
1493 #endif
1494
1495                 case CFG_DEPTH:
1496                         c->be->be_max_deref_depth = c->value_int;
1497                         break;
1498
1499                 case CFG_OID: {
1500                         OidMacro *om;
1501
1502                         if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
1503                                 cfn = c->ca_private;
1504                         if(parse_oidm(c, 1, &om))
1505                                 return(1);
1506                         if (!cfn->c_om_head) cfn->c_om_head = om;
1507                         cfn->c_om_tail = om;
1508                         }
1509                         break;
1510
1511                 case CFG_OC: {
1512                         ObjectClass *oc, *prev;
1513
1514                         if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
1515                                 cfn = c->ca_private;
1516                         if ( c->valx < 0 ) {
1517                                 prev = cfn->c_oc_tail;
1518                         } else {
1519                                 prev = NULL;
1520                                 /* If adding anything after the first, prev is easy */
1521                                 if ( c->valx ) {
1522                                         int i;
1523                                         for (i=0, oc = cfn->c_oc_head; i<c->valx; i++) {
1524                                                 prev = oc;
1525                                                 oc_next( &oc );
1526                                         }
1527                                 } else
1528                                 /* If adding the first, and head exists, find its prev */
1529                                         if (cfn->c_oc_head) {
1530                                         for ( oc_start( &oc ); oc != cfn->c_oc_head; ) {
1531                                                 prev = oc;
1532                                                 oc_next( &oc );
1533                                         }
1534                                 }
1535                                 /* else prev is NULL, append to end of global list */
1536                         }
1537                         if(parse_oc(c, &oc, prev)) return(1);
1538                         if (!cfn->c_oc_head) cfn->c_oc_head = oc;
1539                         if (cfn->c_oc_tail == prev) cfn->c_oc_tail = oc;
1540                         }
1541                         break;
1542
1543                 case CFG_ATTR: {
1544                         AttributeType *at, *prev;
1545
1546                         if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
1547                                 cfn = c->ca_private;
1548                         if ( c->valx < 0 ) {
1549                                 prev = cfn->c_at_tail;
1550                         } else {
1551                                 prev = NULL;
1552                                 /* If adding anything after the first, prev is easy */
1553                                 if ( c->valx ) {
1554                                         int i;
1555                                         for (i=0, at = cfn->c_at_head; i<c->valx; i++) {
1556                                                 prev = at;
1557                                                 at_next( &at );
1558                                         }
1559                                 } else
1560                                 /* If adding the first, and head exists, find its prev */
1561                                         if (cfn->c_at_head) {
1562                                         for ( at_start( &at ); at != cfn->c_at_head; ) {
1563                                                 prev = at;
1564                                                 at_next( &at );
1565                                         }
1566                                 }
1567                                 /* else prev is NULL, append to end of global list */
1568                         }
1569                         if(parse_at(c, &at, prev)) return(1);
1570                         if (!cfn->c_at_head) cfn->c_at_head = at;
1571                         if (cfn->c_at_tail == prev) cfn->c_at_tail = at;
1572                         }
1573                         break;
1574
1575                 case CFG_SYNTAX: {
1576                         Syntax *syn, *prev;
1577
1578                         if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
1579                                 cfn = c->ca_private;
1580                         if ( c->valx < 0 ) {
1581                                 prev = cfn->c_syn_tail;
1582                         } else {
1583                                 prev = NULL;
1584                                 /* If adding anything after the first, prev is easy */
1585                                 if ( c->valx ) {
1586                                         int i;
1587                                         for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++ ) {
1588                                                 prev = syn;
1589                                                 syn_next( &syn );
1590                                         }
1591                                 } else
1592                                 /* If adding the first, and head exists, find its prev */
1593                                         if (cfn->c_syn_head) {
1594                                         for ( syn_start( &syn ); syn != cfn->c_syn_head; ) {
1595                                                 prev = syn;
1596                                                 syn_next( &syn );
1597                                         }
1598                                 }
1599                                 /* else prev is NULL, append to end of global list */
1600                         }
1601                         if ( parse_syn( c, &syn, prev ) ) return(1);
1602                         if ( !cfn->c_syn_head ) cfn->c_syn_head = syn;
1603                         if ( cfn->c_syn_tail == prev ) cfn->c_syn_tail = syn;
1604                         }
1605                         break;
1606
1607                 case CFG_DIT: {
1608                         ContentRule *cr;
1609
1610                         if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
1611                                 cfn = c->ca_private;
1612                         if(parse_cr(c, &cr)) return(1);
1613                         if (!cfn->c_cr_head) cfn->c_cr_head = cr;
1614                         cfn->c_cr_tail = cr;
1615                         }
1616                         break;
1617
1618                 case CFG_ATOPT:
1619                         ad_define_option(NULL, NULL, 0);
1620                         for(i = 1; i < c->argc; i++)
1621                                 if(ad_define_option(c->argv[i], c->fname, c->lineno))
1622                                         return(1);
1623                         break;
1624
1625                 case CFG_IX_INTLEN:
1626                         if ( c->value_int < SLAP_INDEX_INTLEN_DEFAULT )
1627                                 c->value_int = SLAP_INDEX_INTLEN_DEFAULT;
1628                         else if ( c->value_int > 255 )
1629                                 c->value_int = 255;
1630                         index_intlen = c->value_int;
1631                         index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
1632                                 index_intlen );
1633                         break;
1634                         
1635                 case CFG_SORTVALS: {
1636                         ADlist *svnew = NULL, *svtail, *sv;
1637
1638                         for ( i = 1; i < c->argc; i++ ) {
1639                                 AttributeDescription *ad = NULL;
1640                                 const char *text;
1641                                 int rc;
1642
1643                                 rc = slap_str2ad( c->argv[i], &ad, &text );
1644                                 if ( rc ) {
1645                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown attribute type #%d",
1646                                                 c->argv[0], i );
1647 sortval_reject:
1648                                         Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
1649                                                 c->log, c->cr_msg, c->argv[i] );
1650                                         for ( sv = svnew; sv; sv = svnew ) {
1651                                                 svnew = sv->al_next;
1652                                                 ch_free( sv );
1653                                         }
1654                                         return 1;
1655                                 }
1656                                 if (( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) ||
1657                                         ad->ad_type->sat_single_value ) {
1658                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> inappropriate attribute type #%d",
1659                                                 c->argv[0], i );
1660                                         goto sortval_reject;
1661                                 }
1662                                 sv = ch_malloc( sizeof( ADlist ));
1663                                 sv->al_desc = ad;
1664                                 if ( !svnew ) {
1665                                         svnew = sv;
1666                                 } else {
1667                                         svtail->al_next = sv;
1668                                 }
1669                                 svtail = sv;
1670                         }
1671                         sv->al_next = NULL;
1672                         for ( sv = svnew; sv; sv = sv->al_next )
1673                                 sv->al_desc->ad_type->sat_flags |= SLAP_AT_SORTED_VAL;
1674                         for ( sv = sortVals; sv && sv->al_next; sv = sv->al_next );
1675                         if ( sv )
1676                                 sv->al_next = svnew;
1677                         else
1678                                 sortVals = svnew;
1679                         }
1680                         break;
1681
1682                 case CFG_ACL:
1683                         /* Don't append to the global ACL if we're on a specific DB */
1684                         i = c->valx;
1685                         if ( c->be != frontendDB && frontendDB->be_acl && c->valx == -1 ) {
1686                                 AccessControl *a;
1687                                 i = 0;
1688                                 for ( a=c->be->be_acl; a && a != frontendDB->be_acl;
1689                                         a = a->acl_next )
1690                                         i++;
1691                         }
1692                         if ( parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, i ) ) {
1693                                 return 1;
1694                         }
1695                         break;
1696
1697                 case CFG_ROOTDSE:
1698                         if(root_dse_read_file(c->argv[1])) {
1699                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> could not read file", c->argv[0] );
1700                                 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
1701                                         c->log, c->cr_msg, c->argv[1] );
1702                                 return(1);
1703                         }
1704                         {
1705                                 struct berval bv;
1706                                 ber_str2bv( c->argv[1], 0, 1, &bv );
1707                                 if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
1708                                         cfn = c->ca_private;
1709                                 ber_bvarray_add( &cfn->c_dseFiles, &bv );
1710                         }
1711                         break;
1712
1713                 case CFG_SERVERID:
1714                         {
1715                                 ServerID *si, **sip;
1716                                 LDAPURLDesc *lud;
1717                                 int num;
1718                                 if ( lutil_atoi( &num, c->argv[1] ) ||
1719                                         num < 0 || num > SLAP_SYNC_SID_MAX )
1720                                 {
1721                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1722                                                 "<%s> illegal server ID", c->argv[0] );
1723                                         Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
1724                                                 c->log, c->cr_msg, c->argv[1] );
1725                                         return 1;
1726                                 }
1727                                 /* only one value allowed if no URL is given */
1728                                 if ( c->argc > 2 ) {
1729                                         int len;
1730
1731                                         if ( sid_list && BER_BVISEMPTY( &sid_list->si_url )) {
1732                                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1733                                                         "<%s> only one server ID allowed now", c->argv[0] );
1734                                                 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
1735                                                         c->log, c->cr_msg, c->argv[1] );
1736                                                 return 1;
1737                                         }
1738
1739                                         if ( ldap_url_parse( c->argv[2], &lud )) {
1740                                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1741                                                         "<%s> invalid URL", c->argv[0] );
1742                                                 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
1743                                                         c->log, c->cr_msg, c->argv[2] );
1744                                                 return 1;
1745                                         }
1746                                         len = strlen( c->argv[2] );
1747                                         si = ch_malloc( sizeof(ServerID) + len + 1 );
1748                                         si->si_url.bv_val = (char *)(si+1);
1749                                         si->si_url.bv_len = len;
1750                                         strcpy( si->si_url.bv_val, c->argv[2] );
1751                                 } else {
1752                                         if ( sid_list ) {
1753                                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1754                                                         "<%s> unqualified server ID not allowed now", c->argv[0] );
1755                                                 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
1756                                                         c->log, c->cr_msg, c->argv[1] );
1757                                                 return 1;
1758                                         }
1759                                         si = ch_malloc( sizeof(ServerID) );
1760                                         BER_BVZERO( &si->si_url );
1761                                         slap_serverID = num;
1762                                         Debug( LDAP_DEBUG_CONFIG,
1763                                                 "%s: SID=%d\n",
1764                                                 c->log, slap_serverID, 0 );
1765                                 }
1766                                 si->si_next = NULL;
1767                                 si->si_num = num;
1768                                 for ( sip = &sid_list; *sip; sip = &(*sip)->si_next );
1769                                 *sip = si;
1770
1771                                 if (( slapMode & SLAP_SERVER_MODE ) && c->argc > 2 ) {
1772                                         /* If hostname is empty, or is localhost, or matches
1773                                          * our hostname, this serverID refers to this host.
1774                                          * Compare it against listeners and ports.
1775                                          */
1776                                         if ( !lud->lud_host || !lud->lud_host[0] ||
1777                                                 !strncasecmp("localhost", lud->lud_host,
1778                                                         STRLENOF("localhost")) ||
1779                                                 !strcasecmp( global_host, lud->lud_host )) {
1780                                                 Listener **l = slapd_get_listeners();
1781                                                 int i;
1782
1783                                                 for ( i=0; l && l[i]; i++ ) {
1784                                                         LDAPURLDesc *lu2;
1785                                                         int isMe = 0;
1786                                                         ldap_url_parse( l[i]->sl_url.bv_val, &lu2 );
1787                                                         do {
1788                                                                 if ( strcasecmp( lud->lud_scheme,
1789                                                                         lu2->lud_scheme ))
1790                                                                         break;
1791                                                                 if ( lud->lud_port != lu2->lud_port )
1792                                                                         break;
1793                                                                 /* Listener on ANY address */
1794                                                                 if ( !lu2->lud_host || !lu2->lud_host[0] ) {
1795                                                                         isMe = 1;
1796                                                                         break;
1797                                                                 }
1798                                                                 /* URL on ANY address */
1799                                                                 if ( !lud->lud_host || !lud->lud_host[0] ) {
1800                                                                         isMe = 1;
1801                                                                         break;
1802                                                                 }
1803                                                                 /* Listener has specific host, must
1804                                                                  * match it
1805                                                                  */
1806                                                                 if ( !strcasecmp( lud->lud_host,
1807                                                                         lu2->lud_host )) {
1808                                                                         isMe = 1;
1809                                                                         break;
1810                                                                 }
1811                                                         } while(0);
1812                                                         ldap_free_urldesc( lu2 );
1813                                                         if ( isMe ) {
1814                                                                 slap_serverID = si->si_num;
1815                                                                 Debug( LDAP_DEBUG_CONFIG,
1816                                                                         "%s: SID=%d (listener=%s)\n",
1817                                                                         c->log, slap_serverID,
1818                                                                         l[i]->sl_url.bv_val );
1819                                                                 break;
1820                                                         }
1821                                                 }
1822                                         }
1823                                 }
1824                                 if ( c->argc > 2 )
1825                                         ldap_free_urldesc( lud );
1826                         }
1827                         break;
1828                 case CFG_LOGFILE: {
1829                                 if ( logfileName ) ch_free( logfileName );
1830                                 logfileName = c->value_string;
1831                                 logfile = fopen(logfileName, "w");
1832                                 if(logfile) lutil_debug_file(logfile);
1833                         } break;
1834
1835                 case CFG_LASTMOD:
1836                         if(SLAP_NOLASTMODCMD(c->be)) {
1837                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> not available for %s database",
1838                                         c->argv[0], c->be->bd_info->bi_type );
1839                                 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
1840                                         c->log, c->cr_msg, 0 );
1841                                 return(1);
1842                         }
1843                         if(c->value_int)
1844                                 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_NOLASTMOD;
1845                         else
1846                                 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_NOLASTMOD;
1847                         break;
1848
1849                 case CFG_MIRRORMODE:
1850                         if(!SLAP_SHADOW(c->be)) {
1851                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database is not a shadow",
1852                                         c->argv[0] );
1853                                 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
1854                                         c->log, c->cr_msg, 0 );
1855                                 return(1);
1856                         }
1857                         if(c->value_int)
1858                                 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_SINGLE_SHADOW;
1859                         else
1860                                 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SINGLE_SHADOW;
1861                         break;
1862
1863                 case CFG_MONITORING:
1864                         if(c->value_int)
1865                                 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_MONITORING;
1866                         else
1867                                 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_MONITORING;
1868                         break;
1869
1870                 case CFG_HIDDEN:
1871                         if (c->value_int)
1872                                 SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_HIDDEN;
1873                         else
1874                                 SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_HIDDEN;
1875                         break;
1876
1877                 case CFG_SSTR_IF_MAX:
1878                         if (c->value_int < index_substr_if_minlen) {
1879                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] );
1880                                 Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n",
1881                                         c->log, c->cr_msg, c->value_int );
1882                                 return(1);
1883                         }
1884                         index_substr_if_maxlen = c->value_int;
1885                         break;
1886
1887                 case CFG_SSTR_IF_MIN:
1888                         if (c->value_int > index_substr_if_maxlen) {
1889                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] );
1890                                 Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n",
1891                                         c->log, c->cr_msg, c->value_int );
1892                                 return(1);
1893                         }
1894                         index_substr_if_minlen = c->value_int;
1895                         break;
1896
1897 #ifdef SLAPD_MODULES
1898                 case CFG_MODLOAD:
1899                         /* If we're just adding a module on an existing modpath,
1900                          * make sure we've selected the current path.
1901                          */
1902                         if ( c->op == LDAP_MOD_ADD && c->ca_private && modcur != c->ca_private ) {
1903                                 modcur = c->ca_private;
1904                                 /* This should never fail */
1905                                 if ( module_path( modcur->mp_path.bv_val )) {
1906                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> module path no longer valid",
1907                                                 c->argv[0] );
1908                                         Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
1909                                                 c->log, c->cr_msg, modcur->mp_path.bv_val );
1910                                         return(1);
1911                                 }
1912                         }
1913                         if(module_load(c->argv[1], c->argc - 2, (c->argc > 2) ? c->argv + 2 : NULL))
1914                                 return(1);
1915                         /* Record this load on the current path */
1916                         {
1917                                 struct berval bv;
1918                                 char *ptr;
1919                                 if ( c->op == SLAP_CONFIG_ADD ) {
1920                                         ptr = c->line + STRLENOF("moduleload");
1921                                         while (!isspace((unsigned char) *ptr)) ptr++;
1922                                         while (isspace((unsigned char) *ptr)) ptr++;
1923                                 } else {
1924                                         ptr = c->line;
1925                                 }
1926                                 ber_str2bv(ptr, 0, 1, &bv);
1927                                 ber_bvarray_add( &modcur->mp_loads, &bv );
1928                         }
1929                         /* Check for any new hardcoded schema */
1930                         if ( c->op == LDAP_MOD_ADD && CONFIG_ONLINE_ADD( c )) {
1931                                 config_check_schema( NULL, &cfBackInfo );
1932                         }
1933                         break;
1934
1935                 case CFG_MODPATH:
1936                         if(module_path(c->argv[1])) return(1);
1937                         /* Record which path was used with each module */
1938                         {
1939                                 ModPaths *mp;
1940
1941                                 if (!modpaths.mp_loads) {
1942                                         mp = &modpaths;
1943                                 } else {
1944                                         mp = ch_malloc( sizeof( ModPaths ));
1945                                         modlast->mp_next = mp;
1946                                 }
1947                                 ber_str2bv(c->argv[1], 0, 1, &mp->mp_path);
1948                                 mp->mp_next = NULL;
1949                                 mp->mp_loads = NULL;
1950                                 modlast = mp;
1951                                 c->ca_private = mp;
1952                                 modcur = mp;
1953                         }
1954                         
1955                         break;
1956 #endif
1957
1958 #ifdef LDAP_SLAPI
1959                 case CFG_PLUGIN:
1960                         if(slapi_int_read_config(c->be, c->fname, c->lineno, c->argc, c->argv) != LDAP_SUCCESS)
1961                                 return(1);
1962                         slapi_plugins_used++;
1963                         break;
1964 #endif
1965
1966 #ifdef SLAP_AUTH_REWRITE
1967                 case CFG_REWRITE: {
1968                         struct berval bv;
1969                         char *line;
1970                         
1971                         if(slap_sasl_rewrite_config(c->fname, c->lineno, c->argc, c->argv))
1972                                 return(1);
1973
1974                         if ( c->argc > 1 ) {
1975                                 char    *s;
1976
1977                                 /* quote all args but the first */
1978                                 line = ldap_charray2str( c->argv, "\" \"" );
1979                                 ber_str2bv( line, 0, 0, &bv );
1980                                 s = ber_bvchr( &bv, '"' );
1981                                 assert( s != NULL );
1982                                 /* move the trailing quote of argv[0] to the end */
1983                                 AC_MEMCPY( s, s + 1, bv.bv_len - ( s - bv.bv_val ) );
1984                                 bv.bv_val[ bv.bv_len - 1 ] = '"';
1985
1986                         } else {
1987                                 ber_str2bv( c->argv[ 0 ], 0, 1, &bv );
1988                         }
1989                         
1990                         ber_bvarray_add( &authz_rewrites, &bv );
1991                         }
1992                         break;
1993 #endif
1994
1995
1996                 default:
1997                         Debug( LDAP_DEBUG_ANY,
1998                                 "%s: unknown CFG_TYPE %d.\n",
1999                                 c->log, c->type, 0 );
2000                         return 1;
2001
2002         }
2003         return(0);
2004 }
2005
2006
2007 static int
2008 config_fname(ConfigArgs *c) {
2009         if(c->op == SLAP_CONFIG_EMIT) {
2010                 if (c->ca_private) {
2011                         ConfigFile *cf = c->ca_private;
2012                         value_add_one( &c->rvalue_vals, &cf->c_file );
2013                         return 0;
2014                 }
2015                 return 1;
2016         }
2017         return(0);
2018 }
2019
2020 static int
2021 config_cfdir(ConfigArgs *c) {
2022         if(c->op == SLAP_CONFIG_EMIT) {
2023                 if ( !BER_BVISEMPTY( &cfdir )) {
2024                         value_add_one( &c->rvalue_vals, &cfdir );
2025                         return 0;
2026                 }
2027                 return 1;
2028         }
2029         return(0);
2030 }
2031
2032 static int
2033 config_search_base(ConfigArgs *c) {
2034         if(c->op == SLAP_CONFIG_EMIT) {
2035                 int rc = 1;
2036                 if (!BER_BVISEMPTY(&default_search_base)) {
2037                         value_add_one(&c->rvalue_vals, &default_search_base);
2038                         value_add_one(&c->rvalue_nvals, &default_search_nbase);
2039                         rc = 0;
2040                 }
2041                 return rc;
2042         } else if( c->op == LDAP_MOD_DELETE ) {
2043                 ch_free( default_search_base.bv_val );
2044                 ch_free( default_search_nbase.bv_val );
2045                 BER_BVZERO( &default_search_base );
2046                 BER_BVZERO( &default_search_nbase );
2047                 return 0;
2048         }
2049
2050         if(c->bi || c->be != frontendDB) {
2051                 Debug(LDAP_DEBUG_ANY, "%s: defaultSearchBase line must appear "
2052                         "prior to any backend or database definition\n",
2053                         c->log, 0, 0);
2054                 return(1);
2055         }
2056
2057         if(default_search_nbase.bv_len) {
2058                 free(default_search_base.bv_val);
2059                 free(default_search_nbase.bv_val);
2060         }
2061
2062         default_search_base = c->value_dn;
2063         default_search_nbase = c->value_ndn;
2064         return(0);
2065 }
2066
2067 /* For RE23 compatibility we allow this in the global entry
2068  * but we now defer it to the frontend entry to allow modules
2069  * to load new hash types.
2070  */
2071 static int
2072 config_passwd_hash(ConfigArgs *c) {
2073         int i;
2074         if (c->op == SLAP_CONFIG_EMIT) {
2075                 struct berval bv;
2076                 /* Don't generate it in the global entry */
2077                 if ( c->table == Cft_Global )
2078                         return 1;
2079                 for (i=0; default_passwd_hash && default_passwd_hash[i]; i++) {
2080                         ber_str2bv(default_passwd_hash[i], 0, 0, &bv);
2081                         value_add_one(&c->rvalue_vals, &bv);
2082                 }
2083                 return i ? 0 : 1;
2084         } else if ( c->op == LDAP_MOD_DELETE ) {
2085                 /* Deleting from global is a no-op, only the frontendDB entry matters */
2086                 if ( c->table == Cft_Global )
2087                         return 0;
2088                 if ( c->valx < 0 ) {
2089                         ldap_charray_free( default_passwd_hash );
2090                         default_passwd_hash = NULL;
2091                 } else {
2092                         i = c->valx;
2093                         ch_free( default_passwd_hash[i] );
2094                         for (; default_passwd_hash[i]; i++ )
2095                                 default_passwd_hash[i] = default_passwd_hash[i+1];
2096                 }
2097                 return 0;
2098         }
2099         for(i = 1; i < c->argc; i++) {
2100                 if(!lutil_passwd_scheme(c->argv[i])) {
2101                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> scheme not available", c->argv[0] );
2102                         Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
2103                                 c->log, c->cr_msg, c->argv[i]);
2104                 } else {
2105                         ldap_charray_add(&default_passwd_hash, c->argv[i]);
2106                 }
2107         }
2108         if(!default_passwd_hash) {
2109                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> no valid hashes found", c->argv[0] );
2110                 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
2111                         c->log, c->cr_msg, 0 );
2112                 return(1);
2113         }
2114         return(0);
2115 }
2116
2117 static int
2118 config_schema_dn(ConfigArgs *c) {
2119         if ( c->op == SLAP_CONFIG_EMIT ) {
2120                 int rc = 1;
2121                 if ( !BER_BVISEMPTY( &c->be->be_schemadn )) {
2122                         value_add_one(&c->rvalue_vals, &c->be->be_schemadn);
2123                         value_add_one(&c->rvalue_nvals, &c->be->be_schemandn);
2124                         rc = 0;
2125                 }
2126                 return rc;
2127         } else if ( c->op == LDAP_MOD_DELETE ) {
2128                 ch_free( c->be->be_schemadn.bv_val );
2129                 ch_free( c->be->be_schemandn.bv_val );
2130                 BER_BVZERO( &c->be->be_schemadn );
2131                 BER_BVZERO( &c->be->be_schemandn );
2132                 return 0;
2133         }
2134         ch_free( c->be->be_schemadn.bv_val );
2135         ch_free( c->be->be_schemandn.bv_val );
2136         c->be->be_schemadn = c->value_dn;
2137         c->be->be_schemandn = c->value_ndn;
2138         return(0);
2139 }
2140
2141 static int
2142 config_sizelimit(ConfigArgs *c) {
2143         int i, rc = 0;
2144         struct slap_limits_set *lim = &c->be->be_def_limit;
2145         if (c->op == SLAP_CONFIG_EMIT) {
2146                 char buf[8192];
2147                 struct berval bv;
2148                 bv.bv_val = buf;
2149                 bv.bv_len = 0;
2150                 limits_unparse_one( lim, SLAP_LIMIT_SIZE, &bv, sizeof( buf ) );
2151                 if ( !BER_BVISEMPTY( &bv ))
2152                         value_add_one( &c->rvalue_vals, &bv );
2153                 else
2154                         rc = 1;
2155                 return rc;
2156         } else if ( c->op == LDAP_MOD_DELETE ) {
2157                 /* Reset to defaults */
2158                 lim->lms_s_soft = SLAPD_DEFAULT_SIZELIMIT;
2159                 lim->lms_s_hard = 0;
2160                 lim->lms_s_unchecked = -1;
2161                 lim->lms_s_pr = 0;
2162                 lim->lms_s_pr_hide = 0;
2163                 lim->lms_s_pr_total = 0;
2164                 return 0;
2165         }
2166         for(i = 1; i < c->argc; i++) {
2167                 if(!strncasecmp(c->argv[i], "size", 4)) {
2168                         rc = limits_parse_one(c->argv[i], lim);
2169                         if ( rc ) {
2170                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] );
2171                                 Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2172                                         c->log, c->cr_msg, c->argv[i]);
2173                                 return(1);
2174                         }
2175                 } else {
2176                         if(!strcasecmp(c->argv[i], "unlimited")) {
2177                                 lim->lms_s_soft = -1;
2178                         } else {
2179                                 if ( lutil_atoix( &lim->lms_s_soft, c->argv[i], 0 ) != 0 ) {
2180                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse limit", c->argv[0]);
2181                                         Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2182                                                 c->log, c->cr_msg, c->argv[i]);
2183                                         return(1);
2184                                 }
2185                         }
2186                         lim->lms_s_hard = 0;
2187                 }
2188         }
2189         return(0);
2190 }
2191
2192 static int
2193 config_timelimit(ConfigArgs *c) {
2194         int i, rc = 0;
2195         struct slap_limits_set *lim = &c->be->be_def_limit;
2196         if (c->op == SLAP_CONFIG_EMIT) {
2197                 char buf[8192];
2198                 struct berval bv;
2199                 bv.bv_val = buf;
2200                 bv.bv_len = 0;
2201                 limits_unparse_one( lim, SLAP_LIMIT_TIME, &bv, sizeof( buf ) );
2202                 if ( !BER_BVISEMPTY( &bv ))
2203                         value_add_one( &c->rvalue_vals, &bv );
2204                 else
2205                         rc = 1;
2206                 return rc;
2207         } else if ( c->op == LDAP_MOD_DELETE ) {
2208                 /* Reset to defaults */
2209                 lim->lms_t_soft = SLAPD_DEFAULT_TIMELIMIT;
2210                 lim->lms_t_hard = 0;
2211                 return 0;
2212         }
2213         for(i = 1; i < c->argc; i++) {
2214                 if(!strncasecmp(c->argv[i], "time", 4)) {
2215                         rc = limits_parse_one(c->argv[i], lim);
2216                         if ( rc ) {
2217                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] );
2218                                 Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2219                                         c->log, c->cr_msg, c->argv[i]);
2220                                 return(1);
2221                         }
2222                 } else {
2223                         if(!strcasecmp(c->argv[i], "unlimited")) {
2224                                 lim->lms_t_soft = -1;
2225                         } else {
2226                                 if ( lutil_atoix( &lim->lms_t_soft, c->argv[i], 0 ) != 0 ) {
2227                                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse limit", c->argv[0]);
2228                                         Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2229                                                 c->log, c->cr_msg, c->argv[i]);
2230                                         return(1);
2231                                 }
2232                         }
2233                         lim->lms_t_hard = 0;
2234                 }
2235         }
2236         return(0);
2237 }
2238
2239 static int
2240 config_overlay(ConfigArgs *c) {
2241         if (c->op == SLAP_CONFIG_EMIT) {
2242                 return 1;
2243         } else if ( c->op == LDAP_MOD_DELETE ) {
2244                 assert(0);
2245         }
2246         if(c->argv[1][0] == '-' && overlay_config(c->be, &c->argv[1][1],
2247                 c->valx, &c->bi, &c->reply)) {
2248                 /* log error */
2249                 Debug( LDAP_DEBUG_ANY,
2250                         "%s: (optional) %s overlay \"%s\" configuration failed.\n",
2251                         c->log, c->be == frontendDB ? "global " : "", &c->argv[1][1]);
2252                 return 1;
2253         } else if(overlay_config(c->be, c->argv[1], c->valx, &c->bi, &c->reply)) {
2254                 return(1);
2255         }
2256         return(0);
2257 }
2258
2259 static int
2260 config_subordinate(ConfigArgs *c)
2261 {
2262         int rc = 1;
2263         int advertise;
2264
2265         switch( c->op ) {
2266         case SLAP_CONFIG_EMIT:
2267                 if ( SLAP_GLUE_SUBORDINATE( c->be )) {
2268                         struct berval bv;
2269
2270                         bv.bv_val = SLAP_GLUE_ADVERTISE( c->be ) ? "advertise" : "TRUE";
2271                         bv.bv_len = SLAP_GLUE_ADVERTISE( c->be ) ? STRLENOF("advertise") :
2272                                 STRLENOF("TRUE");
2273
2274                         value_add_one( &c->rvalue_vals, &bv );
2275                         rc = 0;
2276                 }
2277                 break;
2278         case LDAP_MOD_DELETE:
2279                 if ( !c->line  || strcasecmp( c->line, "advertise" )) {
2280                         glue_sub_del( c->be );
2281                 } else {
2282                         SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_GLUE_ADVERTISE;
2283                 }
2284                 rc = 0;
2285                 break;
2286         case LDAP_MOD_ADD:
2287         case SLAP_CONFIG_ADD:
2288                 advertise = ( c->argc == 2 && !strcasecmp( c->argv[1], "advertise" ));
2289                 rc = glue_sub_add( c->be, advertise, CONFIG_ONLINE_ADD( c ));
2290                 break;
2291         }
2292         return rc;
2293 }
2294
2295 static int
2296 config_suffix(ConfigArgs *c)
2297 {
2298         Backend *tbe;
2299         struct berval pdn, ndn;
2300         char    *notallowed = NULL;
2301
2302         if ( c->be == frontendDB ) {
2303                 notallowed = "frontend";
2304
2305         } else if ( SLAP_MONITOR(c->be) ) {
2306                 notallowed = "monitor";
2307
2308         } else if ( SLAP_CONFIG(c->be) ) {
2309                 notallowed = "config";
2310         }
2311
2312         if ( notallowed != NULL ) {
2313                 char    buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
2314
2315                 switch ( c->op ) {
2316                 case LDAP_MOD_ADD:
2317                 case LDAP_MOD_DELETE:
2318                 case LDAP_MOD_REPLACE:
2319                 case LDAP_MOD_INCREMENT:
2320                 case SLAP_CONFIG_ADD:
2321                         if ( !BER_BVISNULL( &c->value_dn ) ) {
2322                                 snprintf( buf, sizeof( buf ), "<%s> ",
2323                                                 c->value_dn.bv_val );
2324                         }
2325
2326                         Debug(LDAP_DEBUG_ANY,
2327                                 "%s: suffix %snot allowed in %s database.\n",
2328                                 c->log, buf, notallowed );
2329                         break;
2330
2331                 case SLAP_CONFIG_EMIT:
2332                         /* don't complain when emitting... */
2333                         break;
2334
2335                 default:
2336                         /* FIXME: don't know what values may be valid;
2337                          * please remove assertion, or add legal values
2338                          * to either block */
2339                         assert( 0 );
2340                         break;
2341                 }
2342
2343                 return 1;
2344         }
2345
2346         if (c->op == SLAP_CONFIG_EMIT) {
2347                 if ( c->be->be_suffix == NULL
2348                                 || BER_BVISNULL( &c->be->be_suffix[0] ) )
2349                 {
2350                         return 1;
2351                 } else {
2352                         value_add( &c->rvalue_vals, c->be->be_suffix );
2353                         value_add( &c->rvalue_nvals, c->be->be_nsuffix );
2354                         return 0;
2355                 }
2356         } else if ( c->op == LDAP_MOD_DELETE ) {
2357                 if ( c->valx < 0 ) {
2358                         ber_bvarray_free( c->be->be_suffix );
2359                         ber_bvarray_free( c->be->be_nsuffix );
2360                         c->be->be_suffix = NULL;
2361                         c->be->be_nsuffix = NULL;
2362                 } else {
2363                         int i = c->valx;
2364                         ch_free( c->be->be_suffix[i].bv_val );
2365                         ch_free( c->be->be_nsuffix[i].bv_val );
2366                         do {
2367                                 c->be->be_suffix[i] = c->be->be_suffix[i+1];
2368                                 c->be->be_nsuffix[i] = c->be->be_nsuffix[i+1];
2369                                 i++;
2370                         } while ( !BER_BVISNULL( &c->be->be_suffix[i] ) );
2371                 }
2372                 return 0;
2373         }
2374
2375 #ifdef SLAPD_MONITOR_DN
2376         if(!strcasecmp(c->argv[1], SLAPD_MONITOR_DN)) {
2377                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> DN is reserved for monitoring slapd",
2378                         c->argv[0] );
2379                 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
2380                         c->log, c->cr_msg, SLAPD_MONITOR_DN);
2381                 return(1);
2382         }
2383 #endif
2384
2385         if (SLAP_DB_ONE_SUFFIX( c->be ) && c->be->be_suffix ) {
2386                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> Only one suffix is allowed on this %s backend",
2387                         c->argv[0], c->be->bd_info->bi_type );
2388                 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
2389                         c->log, c->cr_msg, 0);
2390                 return(1);
2391         }
2392
2393         pdn = c->value_dn;
2394         ndn = c->value_ndn;
2395
2396         if (SLAP_DBHIDDEN( c->be ))
2397                 tbe = NULL;
2398         else
2399                 tbe = select_backend(&ndn, 0);
2400         if(tbe == c->be) {
2401                 Debug( LDAP_DEBUG_ANY, "%s: suffix already served by this backend!.\n",
2402                         c->log, 0, 0);
2403                 return 1;
2404                 free(pdn.bv_val);
2405                 free(ndn.bv_val);
2406         } else if(tbe) {
2407                 BackendDB *b2 = tbe;
2408
2409                 /* Does tbe precede be? */
2410                 while (( b2 = LDAP_STAILQ_NEXT(b2, be_next )) && b2 && b2 != c->be );
2411
2412                 if ( b2 ) {
2413                         char    *type = tbe->bd_info->bi_type;
2414
2415                         if ( overlay_is_over( tbe ) ) {
2416                                 slap_overinfo   *oi = (slap_overinfo *)tbe->bd_info->bi_private;
2417                                 type = oi->oi_orig->bi_type;
2418                         }
2419
2420                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> namingContext \"%s\" "
2421                                 "already served by a preceding %s database",
2422                                 c->argv[0], pdn.bv_val, type );
2423                         Debug(LDAP_DEBUG_ANY, "%s: %s serving namingContext \"%s\"\n",
2424                                 c->log, c->cr_msg, tbe->be_suffix[0].bv_val);
2425                         free(pdn.bv_val);
2426                         free(ndn.bv_val);
2427                         return(1);
2428                 }
2429         }
2430         if(pdn.bv_len == 0 && default_search_nbase.bv_len) {
2431                 Debug(LDAP_DEBUG_ANY, "%s: suffix DN empty and default search "
2432                         "base provided \"%s\" (assuming okay)\n",
2433                         c->log, default_search_base.bv_val, 0);
2434         }
2435         ber_bvarray_add(&c->be->be_suffix, &pdn);
2436         ber_bvarray_add(&c->be->be_nsuffix, &ndn);
2437         return(0);
2438 }
2439
2440 static int
2441 config_rootdn(ConfigArgs *c) {
2442         if (c->op == SLAP_CONFIG_EMIT) {
2443                 if ( !BER_BVISNULL( &c->be->be_rootdn )) {
2444                         value_add_one(&c->rvalue_vals, &c->be->be_rootdn);
2445                         value_add_one(&c->rvalue_nvals, &c->be->be_rootndn);
2446                         return 0;
2447                 } else {
2448                         return 1;
2449                 }
2450         } else if ( c->op == LDAP_MOD_DELETE ) {
2451                 ch_free( c->be->be_rootdn.bv_val );
2452                 ch_free( c->be->be_rootndn.bv_val );
2453                 BER_BVZERO( &c->be->be_rootdn );
2454                 BER_BVZERO( &c->be->be_rootndn );
2455                 return 0;
2456         }
2457         if ( !BER_BVISNULL( &c->be->be_rootdn )) {
2458                 ch_free( c->be->be_rootdn.bv_val );
2459                 ch_free( c->be->be_rootndn.bv_val );
2460         }
2461         c->be->be_rootdn = c->value_dn;
2462         c->be->be_rootndn = c->value_ndn;
2463         return(0);
2464 }
2465
2466 static int
2467 config_rootpw(ConfigArgs *c) {
2468         Backend *tbe;
2469
2470         if (c->op == SLAP_CONFIG_EMIT) {
2471                 if (!BER_BVISEMPTY(&c->be->be_rootpw)) {
2472                         /* don't copy, because "rootpw" is marked
2473                          * as CFG_BERVAL */
2474                         c->value_bv = c->be->be_rootpw;
2475                         return 0;
2476                 }
2477                 return 1;
2478         } else if ( c->op == LDAP_MOD_DELETE ) {
2479                 ch_free( c->be->be_rootpw.bv_val );
2480                 BER_BVZERO( &c->be->be_rootpw );
2481                 return 0;
2482         }
2483
2484         tbe = select_backend(&c->be->be_rootndn, 0);
2485         if(tbe != c->be) {
2486                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> can only be set when rootdn is under suffix",
2487                         c->argv[0] );
2488                 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
2489                         c->log, c->cr_msg, 0);
2490                 return(1);
2491         }
2492         if ( !BER_BVISNULL( &c->be->be_rootpw ))
2493                 ch_free( c->be->be_rootpw.bv_val );
2494         c->be->be_rootpw = c->value_bv;
2495         return(0);
2496 }
2497
2498 static int
2499 config_restrict(ConfigArgs *c) {
2500         slap_mask_t restrictops = 0;
2501         int i;
2502         slap_verbmasks restrictable_ops[] = {
2503                 { BER_BVC("bind"),              SLAP_RESTRICT_OP_BIND },
2504                 { BER_BVC("add"),               SLAP_RESTRICT_OP_ADD },
2505                 { BER_BVC("modify"),            SLAP_RESTRICT_OP_MODIFY },
2506                 { BER_BVC("rename"),            SLAP_RESTRICT_OP_RENAME },
2507                 { BER_BVC("modrdn"),            0 },
2508                 { BER_BVC("delete"),            SLAP_RESTRICT_OP_DELETE },
2509                 { BER_BVC("search"),            SLAP_RESTRICT_OP_SEARCH },
2510                 { BER_BVC("compare"),           SLAP_RESTRICT_OP_COMPARE },
2511                 { BER_BVC("read"),              SLAP_RESTRICT_OP_READS },
2512                 { BER_BVC("write"),             SLAP_RESTRICT_OP_WRITES },
2513                 { BER_BVC("extended"),          SLAP_RESTRICT_OP_EXTENDED },
2514                 { BER_BVC("extended=" LDAP_EXOP_START_TLS ),            SLAP_RESTRICT_EXOP_START_TLS },
2515                 { BER_BVC("extended=" LDAP_EXOP_MODIFY_PASSWD ),        SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
2516                 { BER_BVC("extended=" LDAP_EXOP_X_WHO_AM_I ),           SLAP_RESTRICT_EXOP_WHOAMI },
2517                 { BER_BVC("extended=" LDAP_EXOP_X_CANCEL ),             SLAP_RESTRICT_EXOP_CANCEL },
2518                 { BER_BVC("all"),               SLAP_RESTRICT_OP_ALL },
2519                 { BER_BVNULL,   0 }
2520         };
2521
2522         if (c->op == SLAP_CONFIG_EMIT) {
2523                 return mask_to_verbs( restrictable_ops, c->be->be_restrictops,
2524                         &c->rvalue_vals );
2525         } else if ( c->op == LDAP_MOD_DELETE ) {
2526                 if ( !c->line ) {
2527                         c->be->be_restrictops = 0;
2528                 } else {
2529                         restrictops = verb_to_mask( c->line, restrictable_ops );
2530                         c->be->be_restrictops ^= restrictops;
2531                 }
2532                 return 0;
2533         }
2534         i = verbs_to_mask( c->argc, c->argv, restrictable_ops, &restrictops );
2535         if ( i ) {
2536                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown operation", c->argv[0] );
2537                 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2538                         c->log, c->cr_msg, c->argv[i]);
2539                 return(1);
2540         }
2541         if ( restrictops & SLAP_RESTRICT_OP_EXTENDED )
2542                 restrictops &= ~SLAP_RESTRICT_EXOP_MASK;
2543         c->be->be_restrictops |= restrictops;
2544         return(0);
2545 }
2546
2547 static int
2548 config_allows(ConfigArgs *c) {
2549         slap_mask_t allows = 0;
2550         int i;
2551         slap_verbmasks allowable_ops[] = {
2552                 { BER_BVC("bind_v2"),           SLAP_ALLOW_BIND_V2 },
2553                 { BER_BVC("bind_anon_cred"),    SLAP_ALLOW_BIND_ANON_CRED },
2554                 { BER_BVC("bind_anon_dn"),      SLAP_ALLOW_BIND_ANON_DN },
2555                 { BER_BVC("update_anon"),       SLAP_ALLOW_UPDATE_ANON },
2556                 { BER_BVC("proxy_authz_anon"),  SLAP_ALLOW_PROXY_AUTHZ_ANON },
2557                 { BER_BVNULL,   0 }
2558         };
2559         if (c->op == SLAP_CONFIG_EMIT) {
2560                 return mask_to_verbs( allowable_ops, global_allows, &c->rvalue_vals );
2561         } else if ( c->op == LDAP_MOD_DELETE ) {
2562                 if ( !c->line ) {
2563                         global_allows = 0;
2564                 } else {
2565                         allows = verb_to_mask( c->line, allowable_ops );
2566                         global_allows ^= allows;
2567                 }
2568                 return 0;
2569         }
2570         i = verbs_to_mask(c->argc, c->argv, allowable_ops, &allows);
2571         if ( i ) {
2572                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature", c->argv[0] );
2573                 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2574                         c->log, c->cr_msg, c->argv[i]);
2575                 return(1);
2576         }
2577         global_allows |= allows;
2578         return(0);
2579 }
2580
2581 static int
2582 config_disallows(ConfigArgs *c) {
2583         slap_mask_t disallows = 0;
2584         int i;
2585         slap_verbmasks disallowable_ops[] = {
2586                 { BER_BVC("bind_anon"),         SLAP_DISALLOW_BIND_ANON },
2587                 { BER_BVC("bind_simple"),       SLAP_DISALLOW_BIND_SIMPLE },
2588                 { BER_BVC("tls_2_anon"),                SLAP_DISALLOW_TLS_2_ANON },
2589                 { BER_BVC("tls_authc"),         SLAP_DISALLOW_TLS_AUTHC },
2590                 { BER_BVNULL, 0 }
2591         };
2592         if (c->op == SLAP_CONFIG_EMIT) {
2593                 return mask_to_verbs( disallowable_ops, global_disallows, &c->rvalue_vals );
2594         } else if ( c->op == LDAP_MOD_DELETE ) {
2595                 if ( !c->line ) {
2596                         global_disallows = 0;
2597                 } else {
2598                         disallows = verb_to_mask( c->line, disallowable_ops );
2599                         global_disallows ^= disallows;
2600                 }
2601                 return 0;
2602         }
2603         i = verbs_to_mask(c->argc, c->argv, disallowable_ops, &disallows);
2604         if ( i ) {
2605                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature", c->argv[0] );
2606                 Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2607                         c->log, c->cr_msg, c->argv[i]);
2608                 return(1);
2609         }
2610         global_disallows |= disallows;
2611         return(0);
2612 }
2613
2614 static int
2615 config_requires(ConfigArgs *c) {
2616         slap_mask_t requires = frontendDB->be_requires;
2617         int i, argc = c->argc;
2618         char **argv = c->argv;
2619
2620         slap_verbmasks requires_ops[] = {
2621                 { BER_BVC("bind"),              SLAP_REQUIRE_BIND },
2622                 { BER_BVC("LDAPv3"),            SLAP_REQUIRE_LDAP_V3 },
2623                 { BER_BVC("authc"),             SLAP_REQUIRE_AUTHC },
2624                 { BER_BVC("sasl"),              SLAP_REQUIRE_SASL },
2625                 { BER_BVC("strong"),            SLAP_REQUIRE_STRONG },
2626                 { BER_BVNULL, 0 }
2627         };
2628         if (c->op == SLAP_CONFIG_EMIT) {
2629                 return mask_to_verbs( requires_ops, c->be->be_requires, &c->rvalue_vals );
2630         } else if ( c->op == LDAP_MOD_DELETE ) {
2631                 if ( !c->line ) {
2632                         c->be->be_requires = 0;
2633                 } else {
2634                         requires = verb_to_mask( c->line, requires_ops );
2635                         c->be->be_requires ^= requires;
2636                 }
2637                 return 0;
2638         }
2639         /* "none" can only be first, to wipe out default/global values */
2640         if ( strcasecmp( c->argv[ 1 ], "none" ) == 0 ) {
2641                 argv++;
2642                 argc--;
2643                 requires = 0;
2644         }
2645         i = verbs_to_mask(argc, argv, requires_ops, &requires);
2646         if ( i ) {
2647                 if (strcasecmp( c->argv[ i ], "none" ) == 0 ) {
2648                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> \"none\" (#%d) must be listed first", c->argv[0], i - 1 );
2649                         Debug(LDAP_DEBUG_ANY, "%s: %s\n",
2650                                 c->log, c->cr_msg, 0);
2651                 } else {
2652                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature #%d", c->argv[0], i - 1 );
2653                         Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2654                                 c->log, c->cr_msg, c->argv[i]);
2655                 }
2656                 return(1);
2657         }
2658         c->be->be_requires = requires;
2659         return(0);
2660 }
2661
2662 static slap_verbmasks   *loglevel_ops;
2663
2664 static int
2665 loglevel_init( void )
2666 {
2667         slap_verbmasks  lo[] = {
2668                 { BER_BVC("Any"),       -1 },
2669                 { BER_BVC("Trace"),     LDAP_DEBUG_TRACE },
2670                 { BER_BVC("Packets"),   LDAP_DEBUG_PACKETS },
2671                 { BER_BVC("Args"),      LDAP_DEBUG_ARGS },
2672                 { BER_BVC("Conns"),     LDAP_DEBUG_CONNS },
2673                 { BER_BVC("BER"),       LDAP_DEBUG_BER },
2674                 { BER_BVC("Filter"),    LDAP_DEBUG_FILTER },
2675                 { BER_BVC("Config"),    LDAP_DEBUG_CONFIG },
2676                 { BER_BVC("ACL"),       LDAP_DEBUG_ACL },
2677                 { BER_BVC("Stats"),     LDAP_DEBUG_STATS },
2678                 { BER_BVC("Stats2"),    LDAP_DEBUG_STATS2 },
2679                 { BER_BVC("Shell"),     LDAP_DEBUG_SHELL },
2680                 { BER_BVC("Parse"),     LDAP_DEBUG_PARSE },
2681 #if 0   /* no longer used (nor supported) */
2682                 { BER_BVC("Cache"),     LDAP_DEBUG_CACHE },
2683                 { BER_BVC("Index"),     LDAP_DEBUG_INDEX },
2684 #endif
2685                 { BER_BVC("Sync"),      LDAP_DEBUG_SYNC },
2686                 { BER_BVC("None"),      LDAP_DEBUG_NONE },
2687                 { BER_BVNULL,           0 }
2688         };
2689
2690         return slap_verbmasks_init( &loglevel_ops, lo );
2691 }
2692
2693 static void
2694 loglevel_destroy( void )
2695 {
2696         if ( loglevel_ops ) {
2697                 (void)slap_verbmasks_destroy( loglevel_ops );
2698         }
2699         loglevel_ops = NULL;
2700 }
2701
2702 static slap_mask_t      loglevel_ignore[] = { -1, 0 };
2703
2704 int
2705 slap_loglevel_register( slap_mask_t m, struct berval *s )
2706 {
2707         int     rc;
2708
2709         if ( loglevel_ops == NULL ) {
2710                 loglevel_init();
2711         }
2712
2713         rc = slap_verbmasks_append( &loglevel_ops, m, s, loglevel_ignore );
2714
2715         if ( rc != 0 ) {
2716                 Debug( LDAP_DEBUG_ANY, "slap_loglevel_register(%lu, \"%s\") failed\n",
2717                         m, s->bv_val, 0 );
2718         }
2719
2720         return rc;
2721 }
2722
2723 int
2724 slap_loglevel_get( struct berval *s, int *l )
2725 {
2726         int             rc;
2727         slap_mask_t     m, i;
2728
2729         if ( loglevel_ops == NULL ) {
2730                 loglevel_init();
2731         }
2732
2733         for ( m = 0, i = 1; !BER_BVISNULL( &loglevel_ops[ i ].word ); i++ ) {
2734                 m |= loglevel_ops[ i ].mask;
2735         }
2736
2737         for ( i = 1; m & i; i <<= 1 )
2738                 ;
2739
2740         if ( i == 0 ) {
2741                 return -1;
2742         }
2743
2744         rc = slap_verbmasks_append( &loglevel_ops, i, s, loglevel_ignore );
2745
2746         if ( rc != 0 ) {
2747                 Debug( LDAP_DEBUG_ANY, "slap_loglevel_get(%lu, \"%s\") failed\n",
2748                         i, s->bv_val, 0 );
2749
2750         } else {
2751                 *l = i;
2752         }
2753
2754         return rc;
2755 }
2756
2757 int
2758 str2loglevel( const char *s, int *l )
2759 {
2760         int     i;
2761
2762         if ( loglevel_ops == NULL ) {
2763                 loglevel_init();
2764         }
2765
2766         i = verb_to_mask( s, loglevel_ops );
2767
2768         if ( BER_BVISNULL( &loglevel_ops[ i ].word ) ) {
2769                 return -1;
2770         }
2771
2772         *l = loglevel_ops[ i ].mask;
2773
2774         return 0;
2775 }
2776
2777 const char *
2778 loglevel2str( int l )
2779 {
2780         struct berval   bv = BER_BVNULL;
2781
2782         loglevel2bv( l, &bv );
2783
2784         return bv.bv_val;
2785 }
2786
2787 int
2788 loglevel2bv( int l, struct berval *bv )
2789 {
2790         if ( loglevel_ops == NULL ) {
2791                 loglevel_init();
2792         }
2793
2794         BER_BVZERO( bv );
2795
2796         return enum_to_verb( loglevel_ops, l, bv ) == -1;
2797 }
2798
2799 int
2800 loglevel2bvarray( int l, BerVarray *bva )
2801 {
2802         if ( loglevel_ops == NULL ) {
2803                 loglevel_init();
2804         }
2805
2806         return mask_to_verbs( loglevel_ops, l, bva );
2807 }
2808
2809 int
2810 loglevel_print( FILE *out )
2811 {
2812         int     i;
2813
2814         if ( loglevel_ops == NULL ) {
2815                 loglevel_init();
2816         }
2817
2818         fprintf( out, "Installed log subsystems:\n\n" );
2819         for ( i = 0; !BER_BVISNULL( &loglevel_ops[ i ].word ); i++ ) {
2820                 fprintf( out, "\t%-30s (%lu)\n",
2821                         loglevel_ops[ i ].word.bv_val,
2822                         loglevel_ops[ i ].mask );
2823         }
2824
2825         fprintf( out, "\nNOTE: custom log subsystems may be later installed "
2826                 "by specific code\n\n" );
2827
2828         return 0;
2829 }
2830
2831 static int config_syslog;
2832
2833 static int
2834 config_loglevel(ConfigArgs *c) {
2835         int i;
2836
2837         if ( loglevel_ops == NULL ) {
2838                 loglevel_init();
2839         }
2840
2841         if (c->op == SLAP_CONFIG_EMIT) {
2842                 /* Get default or commandline slapd setting */
2843                 if ( ldap_syslog && !config_syslog )
2844                         config_syslog = ldap_syslog;
2845                 return loglevel2bvarray( config_syslog, &c->rvalue_vals );
2846
2847         } else if ( c->op == LDAP_MOD_DELETE ) {
2848                 if ( !c->line ) {
2849                         config_syslog = 0;
2850                 } else {
2851                         int level = verb_to_mask( c->line, loglevel_ops );
2852                         config_syslog ^= level;
2853                 }
2854                 if ( slapMode & SLAP_SERVER_MODE ) {
2855                         ldap_syslog = config_syslog;
2856                 }
2857                 return 0;
2858         }
2859
2860         for( i=1; i < c->argc; i++ ) {
2861                 int     level;
2862
2863                 if ( isdigit((unsigned char)c->argv[i][0]) || c->argv[i][0] == '-' ) {
2864                         if( lutil_atoi( &level, c->argv[i] ) != 0 ) {
2865                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse level", c->argv[0] );
2866                                 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2867                                         c->log, c->cr_msg, c->argv[i]);
2868                                 return( 1 );
2869                         }
2870                 } else {
2871                         if ( str2loglevel( c->argv[i], &level ) ) {
2872                                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown level", c->argv[0] );
2873                                 Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2874                                         c->log, c->cr_msg, c->argv[i]);
2875                                 return( 1 );
2876                         }
2877                 }
2878                 /* Explicitly setting a zero clears all the levels */
2879                 if ( level )
2880                         config_syslog |= level;
2881                 else
2882                         config_syslog = 0;
2883         }
2884         if ( slapMode & SLAP_SERVER_MODE ) {
2885                 ldap_syslog = config_syslog;
2886         }
2887         return(0);
2888 }
2889
2890 static int
2891 config_referral(ConfigArgs *c) {
2892         struct berval val;
2893         if (c->op == SLAP_CONFIG_EMIT) {
2894                 if ( default_referral ) {
2895                         value_add( &c->rvalue_vals, default_referral );
2896                         return 0;
2897                 } else {
2898                         return 1;
2899                 }
2900         } else if ( c->op == LDAP_MOD_DELETE ) {
2901                 if ( c->valx < 0 ) {
2902                         ber_bvarray_free( default_referral );
2903                         default_referral = NULL;
2904                 } else {
2905                         int i = c->valx;
2906                         ch_free( default_referral[i].bv_val );
2907                         for (; default_referral[i].bv_val; i++ )
2908                                 default_referral[i] = default_referral[i+1];
2909                 }
2910                 return 0;
2911         }
2912         if(validate_global_referral(c->argv[1])) {
2913                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid URL", c->argv[0] );
2914                 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
2915                         c->log, c->cr_msg, c->argv[1]);
2916                 return(1);
2917         }
2918
2919         ber_str2bv(c->argv[1], 0, 0, &val);
2920         if(value_add_one(&default_referral, &val)) return(LDAP_OTHER);
2921         return(0);
2922 }
2923
2924 static struct {
2925         struct berval key;
2926         int off;
2927 } sec_keys[] = {
2928         { BER_BVC("ssf="), offsetof(slap_ssf_set_t, sss_ssf) },
2929         { BER_BVC("transport="), offsetof(slap_ssf_set_t, sss_transport) },
2930         { BER_BVC("tls="), offsetof(slap_ssf_set_t, sss_tls) },
2931         { BER_BVC("sasl="), offsetof(slap_ssf_set_t, sss_sasl) },
2932         { BER_BVC("update_ssf="), offsetof(slap_ssf_set_t, sss_update_ssf) },
2933         { BER_BVC("update_transport="), offsetof(slap_ssf_set_t, sss_update_transport) },
2934         { BER_BVC("update_tls="), offsetof(slap_ssf_set_t, sss_update_tls) },
2935         { BER_BVC("update_sasl="), offsetof(slap_ssf_set_t, sss_update_sasl) },
2936         { BER_BVC("simple_bind="), offsetof(slap_ssf_set_t, sss_simple_bind) },
2937         { BER_BVNULL, 0 }
2938 };
2939
2940 static int
2941 config_security(ConfigArgs *c) {
2942         slap_ssf_set_t *set = &c->be->be_ssf_set;
2943         char *next;
2944         int i, j;
2945         if (c->op == SLAP_CONFIG_EMIT) {
2946                 char numbuf[32];
2947                 struct berval bv;
2948                 slap_ssf_t *tgt;
2949                 int rc = 1;
2950
2951                 for (i=0; !BER_BVISNULL( &sec_keys[i].key ); i++) {
2952                         tgt = (slap_ssf_t *)((char *)set + sec_keys[i].off);
2953                         if ( *tgt ) {
2954                                 rc = 0;
2955                                 bv.bv_len = snprintf( numbuf, sizeof( numbuf ), "%u", *tgt );
2956                                 if ( bv.bv_len >= sizeof( numbuf ) ) {
2957                                         ber_bvarray_free_x( c->rvalue_vals, NULL );
2958                                         c->rvalue_vals = NULL;
2959                                         rc = 1;
2960                                         break;
2961                                 }
2962                                 bv.bv_len += sec_keys[i].key.bv_len;
2963                                 bv.bv_val = ch_malloc( bv.bv_len + 1);
2964                                 next = lutil_strcopy( bv.bv_val, sec_keys[i].key.bv_val );
2965                                 strcpy( next, numbuf );
2966                                 ber_bvarray_add( &c->rvalue_vals, &bv );
2967                         }
2968                 }
2969                 return rc;
2970         }
2971         for(i = 1; i < c->argc; i++) {
2972                 slap_ssf_t *tgt = NULL;
2973                 char *src = NULL;
2974                 for ( j=0; !BER_BVISNULL( &sec_keys[j].key ); j++ ) {
2975                         if(!strncasecmp(c->argv[i], sec_keys[j].key.bv_val,
2976                                 sec_keys[j].key.bv_len)) {
2977                                 src = c->argv[i] + sec_keys[j].key.bv_len;
2978                                 tgt = (slap_ssf_t *)((char *)set + sec_keys[j].off);
2979                                 break;
2980                         }
2981                 }
2982                 if ( !tgt ) {
2983                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown factor", c->argv[0] );
2984                         Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
2985                                 c->log, c->cr_msg, c->argv[i]);
2986                         return(1);
2987                 }
2988
2989                 if ( lutil_atou( tgt, src ) != 0 ) {
2990                         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse factor", c->argv[0] );
2991                         Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
2992                                 c->log, c->cr_msg, c->argv[i]);
2993                         return(1);
2994                 }
2995         }
2996         return(0);
2997 }
2998
2999 char *
3000 anlist_unparse( AttributeName *an, char *ptr, ber_len_t buflen ) {
3001         int comma = 0;
3002         char *start = ptr;
3003
3004         for (; !BER_BVISNULL( &an->an_name ); an++) {
3005                 /* if buflen == 0, assume the buffer size has been 
3006                  * already checked otherwise */
3007                 if ( buflen > 0 && buflen - ( ptr - start ) < comma + an->an_name.bv_len ) return NULL;
3008                 if ( comma ) *ptr++ = ',';
3009                 ptr = lutil_strcopy( ptr, an->an_name.bv_val );
3010                 comma = 1;
3011         }
3012         return ptr;
3013 }
3014
3015 static int
3016 config_updatedn(ConfigArgs *c) {
3017         if (c->op == SLAP_CONFIG_EMIT) {
3018                 if (!BER_BVISEMPTY(&c->be->be_update_ndn)) {
3019                         value_add_one(&c->rvalue_vals, &c->be->be_update_ndn);
3020                         value_add_one(&c->rvalue_nvals, &c->be->be_update_ndn);
3021                         return 0;
3022                 }
3023                 return 1;
3024         } else if ( c->op == LDAP_MOD_DELETE ) {
3025                 ch_free( c->be->be_update_ndn.bv_val );
3026                 BER_BVZERO( &c->be->be_update_ndn );
3027                 SLAP_DBFLAGS(c->be) ^= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW);
3028                 return 0;
3029         }
3030         if(SLAP_SHADOW(c->be)) {
3031                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database already shadowed", c->argv[0] );
3032                 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
3033                         c->log, c->cr_msg, 0);
3034                 return(1);
3035         }
3036
3037         ber_memfree_x( c->value_dn.bv_val, NULL );
3038         if ( !BER_BVISNULL( &c->be->be_update_ndn ) ) {
3039                 ber_memfree_x( c->be->be_update_ndn.bv_val, NULL );
3040         }
3041         c->be->be_update_ndn = c->value_ndn;
3042         BER_BVZERO( &c->value_dn );
3043         BER_BVZERO( &c->value_ndn );
3044
3045         return config_slurp_shadow( c );
3046 }
3047
3048 int
3049 config_shadow( ConfigArgs *c, int flag )
3050 {
3051         char    *notallowed = NULL;
3052
3053         if ( c->be == frontendDB ) {
3054                 notallowed = "frontend";
3055
3056         } else if ( SLAP_MONITOR(c->be) ) {
3057                 notallowed = "monitor";
3058         }
3059
3060         if ( notallowed != NULL ) {
3061                 Debug( LDAP_DEBUG_ANY, "%s: %s database cannot be shadow.\n", c->log, notallowed, 0 );
3062                 return 1;
3063         }
3064
3065         SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SINGLE_SHADOW | flag);
3066
3067         return 0;
3068 }
3069
3070 static int
3071 config_updateref(ConfigArgs *c) {
3072         struct berval val;
3073         if (c->op == SLAP_CONFIG_EMIT) {
3074                 if ( c->be->be_update_refs ) {
3075                         value_add( &c->rvalue_vals, c->be->be_update_refs );
3076                         return 0;
3077                 } else {
3078                         return 1;
3079                 }
3080         } else if ( c->op == LDAP_MOD_DELETE ) {
3081                 if ( c->valx < 0 ) {
3082                         ber_bvarray_free( c->be->be_update_refs );
3083                         c->be->be_update_refs = NULL;
3084                 } else {
3085                         int i = c->valx;
3086                         ch_free( c->be->be_update_refs[i].bv_val );
3087                         for (; c->be->be_update_refs[i].bv_val; i++)
3088                                 c->be->be_update_refs[i] = c->be->be_update_refs[i+1];
3089                 }
3090                 return 0;
3091         }
3092         if(!SLAP_SHADOW(c->be) && !c->be->be_syncinfo) {
3093                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must appear after syncrepl or updatedn",
3094                         c->argv[0] );
3095                 Debug(LDAP_DEBUG_ANY, "%s: %s\n",
3096                         c->log, c->cr_msg, 0);
3097                 return(1);
3098         }
3099
3100         if(validate_global_referral(c->argv[1])) {
3101                 snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid URL", c->argv[0] );
3102                 Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
3103                         c->log, c->cr_msg, c->argv[1]);
3104                 return(1);
3105         }
3106         ber_str2bv(c->argv[1], 0, 0, &val);
3107         if(value_add_one(&c->be->be_update_refs, &val)) return(LDAP_OTHER);
3108         return(0);
3109 }
3110
3111 static int
3112 config_obsolete(ConfigArgs *c) {
3113         if (c->op == SLAP_CONFIG_EMIT)
3114                 return 1;
3115
3116         snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> keyword is obsolete (ignored)",
3117                 c->argv[0] );
3118         Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0);
3119         return(0);
3120 }
3121
3122 static int
3123 config_include(ConfigArgs *c) {
3124         int savelineno = c->lineno;
3125         int rc;
3126         ConfigFile *cf;
3127         ConfigFile *cfsave = cfn;
3128         ConfigFile *cf2 = NULL;
3129
3130         /* Leftover from RE23. No dynamic config for include files */
3131         if ( c->op == SLAP_CONFIG_EMIT || c->op == LDAP_MOD_DELETE )
3132                 return 1;
3133
3134         cf = ch_calloc( 1, sizeof(ConfigFile));
3135         if ( cfn->c_kids ) {
3136                 for (cf2=cfn->c_kids; cf2 && cf2->c_sibs; cf2=cf2->c_sibs) ;
3137                 cf2->c_sibs = cf;
3138         } else {
3139                 cfn->c_kids = cf;
3140         }
3141         cfn = cf;
3142         ber_str2bv( c->argv[1], 0, 1, &cf->c_file );
3143         rc = read_config_file(c->argv[1], c->depth + 1, c, config_back_cf_table);
3144         c->lineno = savelineno - 1;
3145         cfn = cfsave;
3146         if ( rc ) {
3147                 if ( cf2 ) cf2->c_sibs = NULL;
3148                 else cfn->c_kids = NULL;
3149                 ch_free( cf->c_file.bv_val );
3150                 ch_free( cf );
3151         } else {
3152                 c->ca_private = cf;
3153         }
3154         return(rc);
3155 }
3156
3157 #ifdef HAVE_TLS
3158 static int
3159 config_tls_option(ConfigArgs *c) {
3160         int flag;
3161         LDAP *ld = slap_tls_ld;
3162         switch(c->type) {
3163         case CFG_TLS_RAND:      flag = LDAP_OPT_X_TLS_RANDOM_FILE;      ld = NULL; break;
3164         case CFG_TLS_CIPHER:    flag = LDAP_OPT_X_TLS_CIPHER_SUITE;     break;
3165         case CFG_TLS_CERT_FILE: flag = LDAP_OPT_X_TLS_CERTFILE;         break;  
3166         case CFG_TLS_CERT_KEY:  flag = LDAP_OPT_X_TLS_KEYFILE;          break;
3167         case CFG_TLS_CA_PATH:   flag = LDAP_OPT_X_TLS_CACERTDIR;        break;
3168         case CFG_TLS_CA_FILE:   flag = LDAP_OPT_X_TLS_CACERTFILE;       break;
3169         case CFG_TLS_DH_FILE:   flag = LDAP_OPT_X_TLS_DHFILE;   break;
3170 #ifdef HAVE_GNUTLS
3171         case CFG_TLS_CRL_FILE:  flag = LDAP_OPT_X_TLS_CRLFILE;  break;
3172 #endif
3173         default:                Debug(LDAP_DEBUG_ANY, "%s: "
3174                                         "unknown tls_option <0x%x>\n",
3175                                         c->log, c->type, 0);
3176                 return 1;
3177         }
3178         if (c->op == SLAP_CONFIG_EMIT) {
3179                 return ldap_pvt_tls_get_option( ld, flag, &c->value_string );
3180         } else if ( c->op == LDAP_MOD_DELETE ) {
3181                 return ldap_pvt_tls_set_option( ld, flag, NULL );
3182         }
3183         ch_free(c->value_string);
3184         return(ldap_pvt_tls_set_option(ld, flag, c->argv[1]));
3185 }
3186
3187 /* FIXME: this ought to be provided by libldap */
3188 static int
3189 config_tls_config(ConfigArgs *c) {
3190         int i, flag;
3191         switch(c->type) {
3192         case CFG_TLS_CRLCHECK:  flag = LDAP_OPT_X_TLS_CRLCHECK; break;
3193         case CFG_TLS_VERIFY:    flag = LDAP_OPT_X_TLS_REQUIRE_CERT; break;
3194         default:
3195                 Debug(LDAP_DEBUG_ANY, "%s: "
3196                                 "unknown tls_option <0x%x>\n",
3197                                 c->log, c->type, 0);
3198                 return 1;
3199         }
3200         if (c->op == SLAP_CONFIG_EMIT) {
3201                 return slap_tls_get_config( slap_tls_ld, flag, &c->value_string );
3202         } else if ( c->op == LDAP_MOD_DELETE ) {
3203                 int i = 0;
3204                 return ldap_pvt_tls_set_option( slap_tls_ld, flag, &i );
3205         }
3206         ch_free( c->value_string );
3207         if ( isdigit( (unsigned char)c->argv[1][0] ) ) {
3208                 if ( lutil_atoi( &i, c->argv[1] ) != 0 ) {
3209                         Debug(LDAP_DEBUG_ANY, "%s: "
3210                                 "unable to parse %s \"%s\"\n",
3211                                 c->log, c->argv[0], c->argv[1] );
3212                         return 1;
3213                 }
3214                 return(ldap_pvt_tls_set_option(slap_tls_ld, flag, &i));
3215         } else {
3216                 return(ldap_int_tls_config(slap_tls_ld, flag, c->argv[1]));
3217         }
3218 }
3219 #endif
3220
3221 static CfEntryInfo *
3222 config_find_base( CfEntryInfo *root, struct berval *dn, CfEntryInfo **last )
3223 {
3224         struct berval cdn;
3225         char *c;
3226
3227         if ( !root ) {
3228                 *last = NULL;
3229                 return NULL;
3230         }
3231
3232         if ( dn_match( &root->ce_entry->e_nname, dn ))
3233                 return root;
3234
3235         c = dn->bv_val+dn->bv_len;
3236         for (;*c != ',';c--);
3237
3238         while(root) {
3239                 *last = root;
3240                 for (--c;c>dn->bv_val && *c != ',';c--);
3241                 cdn.bv_val = c;
3242                 if ( *c == ',' )
3243                         cdn.bv_val++;
3244                 cdn.bv_len = dn->bv_len - (cdn.bv_val - dn->bv_val);
3245
3246                 root = root->ce_kids;
3247
3248                 for (;root;root=root->ce_sibs) {
3249                         if ( dn_match( &root->ce_entry->e_nname, &cdn )) {
3250                                 if ( cdn.bv_val == dn->bv_val ) {
3251                                         return root;
3252                                 }
3253                                 break;
3254                         }
3255                 }
3256         }
3257         return root;
3258 }
3259
3260 typedef struct setup_cookie {
3261         CfBackInfo *cfb;
3262         ConfigArgs *ca;
3263         Entry *frontend;
3264         Entry *config;
3265         int got_frontend;
3266         int got_config;
3267 } setup_cookie;
3268
3269 static int
3270 config_ldif_resp( Operation *op, SlapReply *rs )
3271 {
3272         if ( rs->sr_type == REP_SEARCH ) {
3273                 setup_cookie *sc = op->o_callback->sc_private;
3274                 struct berval pdn;
3275
3276                 sc->cfb->cb_got_ldif = 1;
3277                 /* Does the frontend exist? */
3278                 if ( !sc->got_frontend ) {
3279                         if ( !strncmp( rs->sr_entry->e_nname.bv_val,
3280                                 "olcDatabase", STRLENOF( "olcDatabase" )))
3281                         {
3282                                 if ( strncmp( rs->sr_entry->e_nname.bv_val +
3283                                         STRLENOF( "olcDatabase" ), "={-1}frontend",
3284                                         STRLENOF( "={-1}frontend" )))
3285                                 {
3286                                         struct berval rdn;
3287                                         int i = op->o_noop;
3288                                         sc->ca->be = frontendDB;
3289                                         sc->ca->bi = frontendDB->bd_info;
3290                                         frontendDB->be_cf_ocs = &CFOC_FRONTEND;
3291                                         rdn.bv_val = sc->ca->log;
3292                                         rdn.bv_len = snprintf(rdn.bv_val, sizeof( sc->ca->log ),
3293                                                 "%s=" SLAP_X_ORDERED_FMT "%s",
3294                                                 cfAd_database->ad_cname.bv_val, -1,
3295                                                 sc->ca->bi->bi_type);
3296                                         op->o_noop = 1;
3297                                         sc->frontend = config_build_entry( op, rs,
3298                                                 sc->cfb->cb_root, sc->ca, &rdn, &CFOC_DATABASE,
3299                                                 sc->ca->be->be_cf_ocs );
3300                                         op->o_noop = i;
3301                                         sc->got_frontend++;
3302                                 } else {
3303                                         sc->got_frontend++;
3304                                         goto ok;
3305                                 }
3306                         }
3307                 }
3308
3309                 dnParent( &rs->sr_entry->e_nname, &pdn );
3310
3311                 /* Does the configDB exist? */
3312                 if ( sc->got_frontend && !sc->got_config &&
3313                         !strncmp( rs->sr_entry->e_nname.bv_val,
3314                         "olcDatabase", STRLENOF( "olcDatabase" )) &&
3315                         dn_match( &config_rdn, &pdn ) )
3316                 {
3317                         if ( strncmp( rs->sr_entry->e_nname.bv_val +
3318                                 STRLENOF( "olcDatabase" ), "={0}config",
3319                                 STRLENOF( "={0}config" )))
3320                         {
3321                                 struct berval rdn;
3322                                 int i = op->o_noop;
3323                                 sc->ca->be = LDAP_STAILQ_FIRST( &backendDB );
3324                                 sc->ca->bi = sc->ca->be->bd_info;
3325                                 rdn.bv_val = sc->ca->log;
3326                                 rdn.bv_len = snprintf(rdn.bv_val, sizeof( sc->ca->log ),
3327                                         "%s=" SLAP_X_ORDERED_FMT "%s",
3328                                         cfAd_database->ad_cname.bv_val, 0,
3329                                         sc->ca->bi->bi_type);
3330                                 op->o_noop = 1;
3331                                 sc->config = config_build_entry( op, rs, sc->cfb->cb_root,
3332                                         sc->ca, &rdn, &CFOC_DATABASE, sc->ca->be->be_cf_ocs );
3333                                 op->o_noop = i;
3334                         }
3335                         sc->got_config++;
3336                 }
3337
3338 ok:
3339                 rs->sr_err = config_add_internal( sc->cfb, rs->sr_entry, sc->ca, NULL, NULL, NULL );
3340                 if ( rs->sr_err != LDAP_SUCCESS ) {
3341                         Debug( LDAP_DEBUG_ANY, "config error processing %s: %s\n",
3342                                 rs->sr_entry->e_name.bv_val, sc->ca->cr_msg, 0 );
3343                 }
3344         }
3345         return rs->sr_err;
3346 }
3347
3348 /* Configure and read the underlying back-ldif store */
3349 static int
3350 config_setup_ldif( BackendDB *be, const char *dir, int readit ) {
3351         CfBackInfo *cfb = be->be_private;
3352         ConfigArgs c = {0};
3353         ConfigTable *ct;
3354         char *argv[3];
3355         int rc = 0;
3356         setup_cookie sc;
3357         slap_callback cb = { NULL, config_ldif_resp, NULL, NULL };
3358         Connection conn = {0};
3359         OperationBuffer opbuf;
3360         Operation *op;
3361         SlapReply rs = {REP_RESULT};
3362         Filter filter = { LDAP_FILTER_PRESENT };
3363         struct berval filterstr = BER_BVC("(objectclass=*)");
3364         struct stat st;
3365
3366         /* Is the config directory available? */
3367         if ( stat( dir, &st ) < 0 ) {
3368                 /* No, so don't bother using the backing store.
3369                  * All changes will be in-memory only.
3370                  */
3371                 return 0;
3372         }
3373                 
3374         cfb->cb_db.bd_info = backend_info( "ldif" );
3375         if ( !cfb->cb_db.bd_info )
3376                 return 0;       /* FIXME: eventually this will be a fatal error */
3377
3378         if ( backend_db_init( "ldif", &cfb->cb_db, -1, NULL ) == NULL )
3379                 return 1;
3380
3381         cfb->cb_db.be_suffix = be->be_suffix;
3382         cfb->cb_db.be_nsuffix = be->be_nsuffix;
3383
3384         /* The suffix is always "cn=config". The underlying DB's rootdn
3385          * is always the same as the suffix.
3386          */
3387         cfb->cb_db.be_rootdn = be->be_suffix[0];
3388         cfb->cb_db.be_rootndn = be->be_nsuffix[0];
3389
3390         ber_str2bv( dir, 0, 1, &cfdir );
3391
3392         c.be = &cfb->cb_db;
3393         c.fname = "slapd";
3394         c.argc = 2;
3395         argv[0] = "directory";
3396         argv[1] = (char *)dir;
3397         argv[2] = NULL;
3398         c.argv = argv;
3399         c.reply.err = 0;
3400         c.reply.msg[0] = 0;
3401         c.table = Cft_Database;
3402
3403         ct = config_find_keyword( c.be->be_cf_ocs->co_table, &c );
3404         if ( !ct )
3405                 return 1;
3406
3407         if ( config_add_vals( ct, &c ))
3408                 return 1;
3409
3410         if ( backend_startup_one( &cfb->cb_db, &c.reply ))
3411                 return 1;
3412
3413         if ( readit ) {
3414                 void *thrctx = ldap_pvt_thread_pool_context();
3415                 int prev_DN_strict;
3416
3417                 connection_fake_init( &conn, &opbuf, thrctx );
3418                 op = &opbuf.ob_op;
3419
3420                 filter.f_desc = slap_schema.si_ad_objectClass;
3421
3422                 op->o_tag = LDAP_REQ_SEARCH;
3423
3424                 op->ors_filter = &filter;
3425                 op->ors_filterstr = filterstr;
3426                 op->ors_scope = LDAP_SCOPE_SUBTREE;
3427
3428                 op->o_dn = c.be->be_rootdn;
3429                 op->o_ndn = c.be->be_rootndn;
3430
3431                 op->o_req_dn = be->be_suffix[0];
3432                 op->o_req_ndn = be->be_nsuffix[0];
3433
3434                 op->ors_tlimit = SLAP_NO_LIMIT;
3435                 op->ors_slimit = SLAP_NO_LIMIT;
3436
3437                 op->ors_attrs = slap_anlist_all_attributes;
3438                 op->ors_attrsonly = 0;
3439
3440                 op->o_callback = &cb;
3441                 sc.cfb = cfb;
3442                 sc.ca = &c;
3443                 cb.sc_private = &sc;
3444                 sc.got_frontend = 0;
3445                 sc.got_config = 0;
3446                 sc.frontend = NULL;
3447                 sc.config = NULL;
3448
3449                 op->o_bd = &cfb->cb_db;
3450                 
3451                 /* Allow unknown attrs in DNs */
3452                 prev_DN_strict = slap_DN_strict;
3453                 slap_DN_strict = 0;
3454
3455                 rc = op->o_bd->be_search( op, &rs );
3456
3457                 /* Restore normal DN validation */
3458                 slap_DN_strict = prev_DN_strict;
3459
3460                 op->o_tag = LDAP_REQ_ADD;
3461                 if ( rc == LDAP_SUCCESS && sc.frontend ) {
3462                         op->ora_e = sc.frontend;
3463                         rc = op->o_bd->be_add( op, &rs );
3464                 }
3465                 if ( rc == LDAP_SUCCESS && sc.config ) {
3466                         op->ora_e = sc.config;
3467                         rc = op->o_bd->be_add( op, &rs );
3468                 }
3469                 ldap_pvt_thread_pool_context_reset( thrctx );
3470         }
3471
3472         /* ITS#4194 - only use if it's present, or we're converting. */
3473         if ( !readit || rc == LDAP_SUCCESS )
3474                 cfb->cb_use_ldif = 1;
3475
3476         return rc;
3477 }
3478
3479 static int
3480 CfOc_cmp( const void *c1, const void *c2 ) {
3481         const ConfigOCs *co1 = c1;
3482         const ConfigOCs *co2 = c2;
3483
3484         return ber_bvcmp( co1->co_name, co2->co_name );
3485 }
3486
3487 int
3488 config_register_schema(ConfigTable *ct, ConfigOCs *ocs) {
3489         int i;
3490
3491         i = init_config_attrs( ct );
3492         if ( i ) return i;
3493
3494         /* set up the objectclasses */
3495         i = init_config_ocs( ocs );
3496         if ( i ) return i;
3497
3498         for (i=0; ocs[i].co_def; i++) {
3499                 if ( ocs[i].co_oc ) {
3500                         ocs[i].co_name = &ocs[i].co_oc->soc_cname;
3501                         if ( !ocs[i].co_table )
3502                                 ocs[i].co_table = ct;
3503                         avl_insert( &CfOcTree, &ocs[i], CfOc_cmp, avl_dup_error );
3504                 }
3505         }
3506         return 0;
3507 }
3508
3509 int
3510 read_config(const char *fname, const char *dir) {
3511         BackendDB *be;
3512         CfBackInfo *cfb;
3513         const char *cfdir, *cfname;
3514         int rc;
3515
3516         /* Setup the config backend */
3517         be = backend_db_init( "config", NULL, 0, NULL );
3518         if ( !be )
3519                 return 1;
3520
3521         cfb = be->be_private;
3522         be->be_dfltaccess = ACL_NONE;
3523
3524         /* If no .conf, or a dir was specified, setup the dir */
3525         if ( !fname || dir ) {
3526                 if ( dir ) {
3527                         /* If explicitly given, check for existence */
3528                         struct stat st;
3529
3530                         if ( stat( dir, &st ) < 0 ) {
3531                                 Debug( LDAP_DEBUG_ANY,
3532                                         "invalid config directory %s, error %d\n",
3533                                                 dir, errno, 0 );
3534                                 return 1;
3535                         }
3536                         cfdir = dir;
3537                 } else {
3538                         cfdir = SLAPD_DEFAULT_CONFIGDIR;
3539                 }
3540                 /* if fname is defaulted, try reading .d */
3541                 rc = config_setup_ldif( be, cfdir, !fname );
3542
3543                 if ( rc ) {
3544                         /* It may be OK if the base object doesn't exist yet. */
3545                         if ( rc != LDAP_NO_SUCH_OBJECT )
3546                                 return 1;
3547                         /* ITS#4194: But if dir was specified and no fname,
3548                          * then we were supposed to read the dir. Unless we're
3549                          * trying to slapadd the dir...
3550                          */
3551                         if ( dir && !fname ) {
3552                                 if ( slapMode & (SLAP_SERVER_MODE|SLAP_TOOL_READMAIN|SLAP_TOOL_READONLY))
3553                                         return 1;
3554                                 /* Assume it's slapadd with a config dir, let it continue */
3555                                 rc = 0;
3556                                 cfb->cb_got_ldif = 1;
3557                                 cfb->cb_use_ldif = 1;
3558                                 goto done;
3559                         }
3560                 }
3561
3562                 /* If we read the config from back-ldif, nothing to do here */
3563                 if ( cfb->cb_got_ldif ) {
3564                         rc = 0;
3565                         goto done;
3566                 }
3567         }
3568
3569         if ( fname )
3570                 cfname = fname;
3571         else
3572                 cfname = SLAPD_DEFAULT_CONFIGFILE;
3573
3574         rc = read_config_file(cfname, 0, NULL, config_back_cf_table);
3575
3576         if ( rc == 0 )
3577                 ber_str2bv( cfname, 0, 1, &cfb->cb_config->c_file );
3578
3579 done:
3580         if ( rc == 0 && BER_BVISNULL( &frontendDB->be_schemadn ) ) {
3581                 ber_str2bv( SLAPD_SCHEMA_DN, STRLENOF( SLAPD_SCHEMA_DN ), 1,
3582                         &frontendDB->be_schemadn );
3583                 rc = dnNormalize( 0, NULL, NULL, &frontendDB->be_schemadn, &frontendDB->be_schemandn, NULL );
3584                 if ( rc != LDAP_SUCCESS ) {
3585                         Debug(LDAP_DEBUG_ANY, "read_config: "
3586                                 "unable to normalize default schema DN \"%s\"\n",
3587                                 frontendDB->be_schemadn.bv_val, 0, 0 );
3588                         /* must not happen */
3589                         assert( 0 );
3590                 }
3591         }
3592         return rc;
3593 }
3594
3595 static int
3596 config_back_bind( Operation *op, SlapReply *rs )
3597 {
3598         if ( be_isroot_pw( op ) ) {
3599                 ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ));
3600                 /* frontend sends result */
3601                 return LDAP_SUCCESS;
3602         }
3603
3604         rs->sr_err = LDAP_INVALID_CREDENTIALS;
3605         send_ldap_result( op, rs );
3606
3607         return rs->sr_err;
3608 }
3609
3610 static int
3611 config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth )
3612 {
3613         int rc = 0;
3614
3615         if ( test_filter( op, ce->ce_entry, op->ors_filter ) == LDAP_COMPARE_TRUE )
3616         {
3617                 rs->sr_attrs = op->ors_attrs;
3618                 rs->sr_entry = ce->ce_entry;
3619                 rs->sr_flags = 0;
3620                 rc = send_search_entry( op, rs );
3621         }
3622         if ( op->ors_scope == LDAP_SCOPE_SUBTREE ) {
3623                 if ( ce->ce_kids ) {
3624                         rc = config_send( op, rs, ce->ce_kids, 1 );
3625                         if ( rc ) return rc;
3626                 }
3627                 if ( depth ) {
3628                         for (ce=ce->ce_sibs; ce; ce=ce->ce_sibs) {
3629                                 rc = config_send( op, rs, ce, 0 );
3630                                 if ( rc ) break;
3631                         }
3632                 }
3633         }
3634         return rc;
3635 }
3636
3637 static ConfigTable *
3638 config_find_table( ConfigOCs **colst, int nocs, AttributeDescription *ad,
3639         ConfigArgs *ca )
3640 {
3641         int i, j;
3642
3643         for (j=0; j<nocs; j++) {
3644                 for (i=0; colst[j]->co_table[i].name; i++)
3645                         if ( colst[j]->co_table[i].ad == ad ) {
3646                                 ca->table = colst[j]->co_type;
3647                                 return &colst[j]->co_table[i];
3648                         }
3649         }
3650         return NULL;
3651 }
3652
3653 /* Sort the attributes of the entry according to the order defined
3654  * in the objectclass, with required attributes occurring before
3655  * allowed attributes. For any attributes with sequencing dependencies
3656  * (e.g., rootDN must be defined after suffix) the objectclass must
3657  * list the attributes in the desired sequence.
3658  */
3659 static void
3660 sort_attrs( Entry *e, ConfigOCs **colst, int nocs )
3661 {
3662         Attribute *a, *head = NULL, *tail = NULL, **prev;
3663         int i, j;
3664
3665         for (i=0; i<nocs; i++) {
3666                 if ( colst[i]->co_oc->soc_required ) {
3667                         AttributeType **at = colst[i]->co_oc->soc_required;
3668                         for (j=0; at[j]; j++) {
3669                                 for (a=e->e_attrs, prev=&e->e_attrs; a;
3670                                         prev = &(*prev)->a_next, a=a->a_next) {
3671                                         if ( a->a_desc == at[j]->sat_ad ) {
3672                                                 *prev = a->a_next;
3673                                                 if (!head) {
3674                                                         head = a;
3675                                                         tail = a;
3676                                                 } else {
3677                                                         tail->a_next = a;
3678                                                         tail = a;
3679                                                 }
3680                                                 break;
3681                                         }
3682                                 }
3683                         }
3684                 }
3685                 if ( colst[i]->co_oc->soc_allowed ) {
3686                         AttributeType **at = colst[i]->co_oc->soc_allowed;
3687                         for (j=0; at[j]; j++) {
3688                                 for (a=e->e_attrs, prev=&e->e_attrs; a;
3689                                         prev = &(*prev)->a_next, a=a->a_next) {
3690                                         if ( a->a_desc == at[j]->sat_ad ) {
3691                                                 *prev = a->a_next;
3692                                                 if (!head) {
3693                                                         head = a;
3694                                                         tail = a;
3695                                                 } else {
3696                                                         tail->a_next = a;
3697                                                         tail = a;
3698                                                 }
3699                                                 break;
3700                                         }
3701                                 }
3702                         }
3703                 }
3704         }
3705         if ( tail ) {
3706                 tail->a_next = e->e_attrs;
3707                 e->e_attrs = head;
3708         }
3709 }
3710
3711 static int
3712 check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr )
3713 {
3714         Attribute *a = NULL;
3715         AttributeDescription *ad;
3716         BerVarray vals;
3717
3718         int i, rc = 0;
3719
3720         if ( isAttr ) {
3721                 a = ptr;
3722                 ad = a->a_desc;
3723                 vals = a->a_vals;
3724         } else {
3725                 Modifications *ml = ptr;
3726                 ad = ml->sml_desc;
3727                 vals = ml->sml_values;
3728         }
3729
3730         if ( a && ( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL )) {
3731                 rc = ordered_value_sort( a, 1 );
3732                 if ( rc ) {
3733                         snprintf(ca->cr_msg, sizeof( ca->cr_msg ), "ordered_value_sort failed on attr %s\n",
3734                                 ad->ad_cname.bv_val );
3735                         return rc;
3736                 }
3737         }
3738         for ( i=0; vals[i].bv_val; i++ ) {
3739                 ca->line = vals[i].bv_val;
3740                 if (( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) &&
3741                         ca->line[0] == '{' ) {
3742                         char *idx = strchr( ca->line, '}' );
3743                         if ( idx ) ca->line = idx+1;
3744                 }
3745                 rc = config_parse_vals( ct, ca, i );
3746                 if ( rc ) {
3747                         break;
3748                 }
3749         }
3750         return rc;
3751 }
3752
3753 static int
3754 config_rename_attr( SlapReply *rs, Entry *e, struct berval *rdn,
3755         Attribute **at )
3756 {
3757         struct berval rtype, rval;
3758         Attribute *a;
3759         AttributeDescription *ad = NULL;
3760
3761         dnRdn( &e->e_name, rdn );
3762         rval.bv_val = strchr(rdn->bv_val, '=' ) + 1;
3763         rval.bv_len = rdn->bv_len - (rval.bv_val - rdn->bv_val);
3764         rtype.bv_val = rdn->bv_val;
3765         rtype.bv_len = rval.bv_val - rtype.bv_val - 1;
3766
3767         /* Find attr */
3768         slap_bv2ad( &rtype, &ad, &rs->sr_text );
3769         a = attr_find( e->e_attrs, ad );
3770         if (!a ) return LDAP_NAMING_VIOLATION;
3771         *at = a;
3772
3773         return 0;
3774 }
3775
3776 static void
3777 config_rename_kids( CfEntryInfo *ce )
3778 {
3779         CfEntryInfo *ce2;
3780         struct berval rdn, nrdn;
3781
3782         for (ce2 = ce->ce_kids; ce2; ce2 = ce2->ce_sibs) {
3783                 dnRdn ( &ce2->ce_entry->e_name, &rdn );
3784                 dnRdn ( &ce2->ce_entry->e_nname, &nrdn );
3785                 free( ce2->ce_entry->e_name.bv_val );
3786                 free( ce2->ce_entry->e_nname.bv_val );
3787                 build_new_dn( &ce2->ce_entry->e_name, &ce->ce_entry->e_name,
3788                         &rdn, NULL );
3789                 build_new_dn( &ce2->ce_entry->e_nname, &ce->ce_entry->e_nname,
3790                         &nrdn, NULL );
3791                 config_rename_kids( ce2 );
3792         }
3793 }
3794
3795 static int
3796 config_rename_one( Operation *op, SlapReply *rs, Entry *e,
3797         CfEntryInfo *parent, Attribute *a, struct berval *newrdn,
3798         struct berval *nnewrdn, int use_ldif )
3799 {
3800         char *ptr1;
3801         int rc = 0;
3802         struct berval odn, ondn;
3803
3804         odn = e->e_name;
3805         ondn = e->e_nname;
3806         build_new_dn( &e->e_name, &parent->ce_entry->e_name, newrdn, NULL );
3807         build_new_dn( &e->e_nname, &parent->ce_entry->e_nname, nnewrdn, NULL );
3808
3809         /* Replace attr */
3810         free( a->a_vals[0].bv_val );
3811         ptr1 = strchr( newrdn->bv_val, '=' ) + 1;
3812         a->a_vals[0].bv_len = newrdn->bv_len - (ptr1 - newrdn->bv_val);
3813         a->a_vals[0].bv_val = ch_malloc( a->a_vals[0].bv_len + 1 );
3814         strcpy( a->a_vals[0].bv_val, ptr1 );
3815
3816         if ( a->a_nvals != a->a_vals ) {
3817                 free( a->a_nvals[0].bv_val );
3818                 ptr1 = strchr( nnewrdn->bv_val, '=' ) + 1;
3819                 a->a_nvals[0].bv_len = nnewrdn->bv_len - (ptr1 - nnewrdn->bv_val);
3820                 a->a_nvals[0].bv_val = ch_malloc( a->a_nvals[0].bv_len + 1 );
3821                 strcpy( a->a_nvals[0].bv_val, ptr1 );
3822         }
3823         if ( use_ldif ) {
3824                 CfBackInfo *cfb = (CfBackInfo *)op->o_bd->be_private;
3825                 BackendDB *be = op->o_bd;
3826                 slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
3827                 struct berval dn, ndn, xdn, xndn;
3828
3829                 op->o_bd = &cfb->cb_db;
3830
3831                 /* Save current rootdn; use the underlying DB's rootdn */
3832                 dn = op->o_dn;
3833                 ndn = op->o_ndn;
3834                 xdn = op->o_req_dn;
3835                 xndn = op->o_req_ndn;
3836                 op->o_dn = op->o_bd->be_rootdn;
3837                 op->o_ndn = op->o_bd->be_rootndn;
3838                 op->o_req_dn = odn;
3839                 op->o_req_ndn = ondn;
3840
3841                 scp = op->o_callback;
3842                 op->o_callback = &sc;
3843                 op->orr_newrdn = *newrdn;
3844                 op->orr_nnewrdn = *nnewrdn;
3845                 op->orr_newSup = NULL;
3846                 op->orr_nnewSup = NULL;
3847                 op->orr_deleteoldrdn = 1;
3848                 op->orr_modlist = NULL;
3849                 slap_modrdn2mods( op, rs );
3850                 slap_mods_opattrs( op, &op->orr_modlist, 1 );
3851                 rc = op->o_bd->be_modrdn( op, rs );
3852                 slap_mods_free( op->orr_modlist, 1 );
3853
3854                 op->o_bd = be;
3855                 op->o_callback = scp;
3856                 op->o_dn = dn;
3857                 op->o_ndn = ndn;
3858                 op->o_req_dn = xdn;
3859                 op->o_req_ndn = xndn;
3860         }
3861         free( odn.bv_val );
3862         free( ondn.bv_val );
3863         if ( e->e_private )
3864                 config_rename_kids( e->e_private );
3865         return rc;
3866 }
3867
3868 static int
3869 config_renumber_one( Operation *op, SlapReply *rs, CfEntryInfo *parent, 
3870         Entry *e, int idx, int tailindex, int use_ldif )
3871 {
3872         struct berval ival, newrdn, nnewrdn;
3873         struct berval rdn;
3874         Attribute *a;
3875         char ibuf[32], *ptr1, *ptr2 = NULL;
3876         int rc = 0;
3877
3878         rc = config_rename_attr( rs, e, &rdn, &a );
3879         if ( rc ) return rc;
3880
3881         ival.bv_val = ibuf;
3882         ival.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, idx );
3883         if ( ival.bv_len >= sizeof( ibuf ) ) {
3884                 return LDAP_NAMING_VIOLATION;
3885         }
3886         
3887         newrdn.bv_len = rdn.bv_len + ival.bv_len;
3888         newrdn.bv_val = ch_malloc( newrdn.bv_len+1 );
3889
3890         if ( tailindex ) {
3891                 ptr1 = lutil_strncopy( newrdn.bv_val, rdn.bv_val, rdn.bv_len );
3892                 ptr1 = lutil_strcopy( ptr1, ival.bv_val );
3893         } else {
3894                 int xlen;
3895                 ptr2 = ber_bvchr( &rdn, '}' );
3896                 if ( ptr2 ) {
3897                         ptr2++;
3898                 } else {
3899                         ptr2 = rdn.bv_val + a->a_desc->ad_cname.bv_len + 1;
3900                 }
3901                 xlen = rdn.bv_len - (ptr2 - rdn.bv_val);
3902                 ptr1 = lutil_strncopy( newrdn.bv_val, a->a_desc->ad_cname.bv_val,
3903                         a->a_desc->ad_cname.bv_len );
3904                 *ptr1++ = '=';
3905                 ptr1 = lutil_strcopy( ptr1, ival.bv_val );
3906                 ptr1 = lutil_strncopy( ptr1, ptr2, xlen );
3907                 *ptr1 = '\0';
3908         }
3909
3910         /* Do the equivalent of ModRDN */
3911         /* Replace DN / NDN */
3912         newrdn.bv_len = ptr1 - newrdn.bv_val;
3913         rdnNormalize( 0, NULL, NULL, &newrdn, &nnewrdn, NULL );
3914         rc = config_rename_one( op, rs, e, parent, a, &newrdn, &nnewrdn, use_ldif );
3915
3916         free( nnewrdn.bv_val );
3917         free( newrdn.bv_val );
3918         return rc;
3919 }
3920
3921 static int
3922 check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e,
3923         SlapReply *rs, int *renum, int *ibase )
3924 {
3925         CfEntryInfo *ce;
3926         int index = -1, gotindex = 0, nsibs, rc = 0;
3927         int renumber = 0, tailindex = 0, isfrontend = 0, isconfig = 0;
3928         char *ptr1, *ptr2 = NULL;
3929         struct berval rdn;
3930
3931         if ( renum ) *renum = 0;
3932
3933         /* These entries don't get indexed/renumbered */
3934         if ( ce_type == Cft_Global ) return 0;
3935         if ( ce_type == Cft_Schema && parent->ce_type == Cft_Global ) return 0;
3936
3937         if ( ce_type == Cft_Module )
3938                 tailindex = 1;
3939
3940         /* See if the rdn has an index already */
3941         dnRdn( &e->e_name, &rdn );
3942         if ( ce_type == Cft_Database ) {
3943                 if ( !strncmp( rdn.bv_val + rdn.bv_len - STRLENOF("frontend"),
3944                                 "frontend", STRLENOF("frontend") )) 
3945                         isfrontend = 1;
3946                 else if ( !strncmp( rdn.bv_val + rdn.bv_len - STRLENOF("config"),
3947                                 "config", STRLENOF("config") )) 
3948                         isconfig = 1;
3949         }
3950         ptr1 = ber_bvchr( &e->e_name, '{' );
3951         if ( ptr1 && ptr1 < &e->e_name.bv_val[ rdn.bv_len ] ) {
3952                 char    *next;
3953                 ptr2 = strchr( ptr1, '}' );
3954                 if ( !ptr2 || ptr2 > &e->e_name.bv_val[ rdn.bv_len ] )
3955                         return LDAP_NAMING_VIOLATION;
3956                 if ( ptr2-ptr1 == 1)
3957                         return LDAP_NAMING_VIOLATION;
3958                 gotindex = 1;
3959                 index = strtol( ptr1 + 1, &next, 10 );
3960                 if ( next == ptr1 + 1 || next[ 0 ] != '}' ) {
3961                         return LDAP_NAMING_VIOLATION;
3962                 }
3963                 if ( index < 0 ) {
3964                         /* Special case, we allow -1 for the frontendDB */
3965                         if ( index != -1 || !isfrontend )
3966                                 return LDAP_NAMING_VIOLATION;
3967                 }
3968                 if ( isconfig && index != 0 ){
3969                         return LDAP_NAMING_VIOLATION;
3970                 }
3971         }
3972
3973         /* count related kids */
3974         for (nsibs=0, ce=parent->ce_kids; ce; ce=ce->ce_sibs) {
3975                 if ( ce->ce_type == ce_type ) nsibs++;
3976         }
3977
3978         /* account for -1 frontend */
3979         if ( ce_type == Cft_Database )
3980                 nsibs--;
3981
3982         if ( index != nsibs ) {
3983                 if ( gotindex ) {
3984                         if ( index < nsibs ) {
3985                                 if ( tailindex ) return LDAP_NAMING_VIOLATION;
3986                                 /* Siblings need to be renumbered */
3987                                 if ( index != -1 || !isfrontend )
3988                                         renumber = 1;
3989                         }
3990                 }
3991                 /* config DB is always "0" */
3992                 if ( isconfig && index == -1 ) {
3993                         index = 0;
3994                 }
3995                 if (( !isfrontend && index == -1 ) || ( index > nsibs ) ){
3996                         index = nsibs;
3997                 }
3998
3999                 /* just make index = nsibs */
4000                 if ( !renumber ) {
4001                         rc = config_renumber_one( NULL, rs, parent, e, index, tailindex, 0 );
4002                 }
4003         }
4004         if ( ibase ) *ibase = index;
4005         if ( renum ) *renum = renumber;
4006         return rc;
4007 }
4008
4009 static int
4010 count_oc( ObjectClass *oc, ConfigOCs ***copp, int *nocs )
4011 {
4012         ConfigOCs       co, *cop;
4013         ObjectClass     **sups;
4014
4015         co.co_name = &oc->soc_cname;
4016         cop = avl_find( CfOcTree, &co, CfOc_cmp );
4017         if ( cop ) {
4018                 int     i;
4019
4020                 /* check for duplicates */
4021                 for ( i = 0; i < *nocs; i++ ) {
4022                         if ( *copp && (*copp)[i] == cop ) {
4023                                 break;
4024                         }
4025                 }
4026
4027                 if ( i == *nocs ) {
4028                         ConfigOCs **tmp = ch_realloc( *copp, (*nocs + 1)*sizeof( ConfigOCs * ) );
4029                         if ( tmp == NULL ) {
4030                                 return -1;
4031                         }
4032                         *copp = tmp;
4033                         (*copp)[*nocs] = cop;
4034                         (*nocs)++;
4035                 }
4036         }
4037
4038         for ( sups = oc->soc_sups; sups && *sups; sups++ ) {
4039                 if ( count_oc( *sups, copp, nocs ) ) {
4040                         return -1;
4041                 }
4042         }
4043
4044         return 0;
4045 }
4046
4047 static ConfigOCs **
4048 count_ocs( Attribute *oc_at, int *nocs )
4049 {
4050         int             i;
4051         ConfigOCs       **colst = NULL;
4052
4053         *nocs = 0;
4054
4055         for ( i = 0; !BER_BVISNULL( &oc_at->a_nvals[i] ); i++ )
4056                 /* count attrs */ ;
4057
4058         for ( ; i--; ) {
4059                 ObjectClass     *oc = oc_bvfind( &oc_at->a_nvals[i] );
4060
4061                 assert( oc != NULL );
4062                 if ( count_oc( oc, &colst, nocs ) ) {
4063                         ch_free( colst );
4064                         return NULL;
4065                 }
4066         }
4067
4068         return colst;
4069 }
4070
4071 static int
4072 cfAddInclude( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
4073 {
4074         /* Leftover from RE23. Never parse this entry */
4075         return LDAP_COMPARE_TRUE;
4076 }
4077
4078 static int
4079 cfAddSchema( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
4080 {
4081         ConfigFile *cfo;
4082
4083         /* This entry is hardcoded, don't re-parse it */
4084         if ( p->ce_type == Cft_Global ) {
4085                 cfn = p->ce_private;
4086                 ca->ca_private = cfn;
4087                 return LDAP_COMPARE_TRUE;
4088         }
4089         if ( p->ce_type != Cft_Schema )
4090                 return LDAP_CONSTRAINT_VIOLATION;
4091
4092         cfn = ch_calloc( 1, sizeof(ConfigFile) );
4093         ca->ca_private = cfn;
4094         cfo = p->ce_private;
4095         cfn->c_sibs = cfo->c_kids;
4096         cfo->c_kids = cfn;
4097         return LDAP_SUCCESS;
4098 }
4099
4100 static int
4101 cfAddDatabase( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
4102 {
4103         if ( p->ce_type != Cft_Global ) {
4104                 return LDAP_CONSTRAINT_VIOLATION;
4105         }
4106         /* config must be {0}, nothing else allowed */
4107         if ( !strncmp( e->e_nname.bv_val, "olcDatabase={0}", STRLENOF("olcDatabase={0}")) &&
4108                 strncmp( e->e_nname.bv_val + STRLENOF("olcDatabase={0}"), "config,", STRLENOF("config,") )) {
4109                 return LDAP_CONSTRAINT_VIOLATION;
4110         }
4111         ca->be = frontendDB;    /* just to get past check_vals */
4112         return LDAP_SUCCESS;
4113 }
4114
4115 static int
4116 cfAddBackend( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
4117 {
4118         if ( p->ce_type != Cft_Global ) {
4119                 return LDAP_CONSTRAINT_VIOLATION;
4120         }
4121         return LDAP_SUCCESS;
4122 }
4123
4124 static int
4125 cfAddModule( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
4126 {
4127         if ( p->ce_type != Cft_Global ) {
4128                 return LDAP_CONSTRAINT_VIOLATION;
4129         }
4130         return LDAP_SUCCESS;
4131 }
4132
4133 static int
4134 cfAddOverlay( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
4135 {
4136         if ( p->ce_type != Cft_Database ) {
4137                 return LDAP_CONSTRAINT_VIOLATION;
4138         }
4139         ca->be = p->ce_be;
4140         return LDAP_SUCCESS;
4141 }
4142
4143 static void
4144 schema_destroy_one( ConfigArgs *ca, ConfigOCs **colst, int nocs,
4145         CfEntryInfo *p )
4146 {
4147         ConfigTable *ct;
4148         ConfigFile *cfo;
4149         AttributeDescription *ad;
4150         const char *text;
4151
4152         ca->valx = -1;
4153         ca->line = NULL;
4154         if ( cfn->c_cr_head ) {
4155                 struct berval bv = BER_BVC("olcDitContentRules");
4156                 ad = NULL;
4157                 slap_bv2ad( &bv, &ad, &text );
4158                 ct = config_find_table( colst, nocs, ad, ca );
4159                 config_del_vals( ct, ca );
4160         }
4161         if ( cfn->c_oc_head ) {
4162                 struct berval bv = BER_BVC("olcObjectClasses");
4163                 ad = NULL;
4164                 slap_bv2ad( &bv, &ad, &text );
4165                 ct = config_find_table( colst, nocs, ad, ca );
4166                 config_del_vals( ct, ca );
4167         }
4168         if ( cfn->c_at_head ) {
4169                 struct berval bv = BER_BVC("olcAttributeTypes");
4170                 ad = NULL;
4171                 slap_bv2ad( &bv, &ad, &text );
4172                 ct = config_find_table( colst, nocs, ad, ca );
4173                 config_del_vals( ct, ca );
4174         }
4175         if ( cfn->c_syn_head ) {
4176                 struct berval bv = BER_BVC("olcLdapSyntaxes");
4177                 ad = NULL;
4178                 slap_bv2ad( &bv, &ad, &text );
4179                 ct = config_find_table( colst, nocs, ad, ca );
4180                 config_del_vals( ct, ca );
4181         }
4182         if ( cfn->c_om_head ) {
4183                 struct berval bv = BER_BVC("olcObjectIdentifier");
4184                 ad = NULL;
4185                 slap_bv2ad( &bv, &ad, &text );
4186                 ct = config_find_table( colst, nocs, ad, ca );
4187                 config_del_vals( ct, ca );
4188         }
4189         cfo = p->ce_private;
4190         cfo->c_kids = cfn->c_sibs;
4191         ch_free( cfn );
4192 }
4193
4194 static int
4195 config_add_oc( ConfigOCs **cop, CfEntryInfo *last, Entry *e, ConfigArgs *ca )
4196 {
4197         int             rc = LDAP_CONSTRAINT_VIOLATION;
4198         ObjectClass     **ocp;
4199
4200         if ( (*cop)->co_ldadd ) {
4201                 rc = (*cop)->co_ldadd( last, e, ca );
4202                 if ( rc != LDAP_CONSTRAINT_VIOLATION ) {
4203                         return rc;
4204                 }
4205         }
4206
4207         for ( ocp = (*cop)->co_oc->soc_sups; ocp && *ocp; ocp++ ) {
4208                 ConfigOCs       co = { 0 };
4209
4210                 co.co_name = &(*ocp)->soc_cname;
4211                 *cop = avl_find( CfOcTree, &co, CfOc_cmp );
4212                 if ( *cop == NULL ) {
4213                         return rc;
4214                 }
4215
4216                 rc = config_add_oc( cop, last, e, ca );
4217                 if ( rc != LDAP_CONSTRAINT_VIOLATION ) {
4218                         return rc;
4219                 }
4220         }
4221
4222         return rc;
4223 }
4224
4225 /* Parse an LDAP entry into config directives */
4226 static int
4227 config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs,
4228         int *renum, Operation *op )
4229 {
4230         CfEntryInfo     *ce, *last = NULL;
4231         ConfigOCs       co, *coptr, **colst;
4232         Attribute       *a, *oc_at, *soc_at;
4233         int             i, ibase = -1, nocs, rc = 0;
4234         struct berval   pdn;
4235         ConfigTable     *ct;
4236         char            *ptr, *log_prefix = op ? op->o_log_prefix : "";
4237
4238         memset( ca, 0, sizeof(ConfigArgs));
4239
4240         /* Make sure parent exists and entry does not. But allow
4241          * Databases and Overlays to be inserted. Don't do any
4242          * auto-renumbering if manageDSAit control is present.
4243          */
4244         ce = config_find_base( cfb->cb_root, &e->e_nname, &last );
4245         if ( ce ) {
4246                 if ( ( op && op->o_managedsait ) ||
4247                         ( ce->ce_type != Cft_Database && ce->ce_type != Cft_Overlay &&
4248                           ce->ce_type != Cft_Module ) )
4249                 {
4250                         Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
4251                                 "DN=\"%s\" already exists\n",
4252                                 log_prefix, e->e_name.bv_val, 0 );
4253                         return LDAP_ALREADY_EXISTS;
4254                 }
4255         }
4256
4257         dnParent( &e->e_nname, &pdn );
4258
4259         /* If last is NULL, the new entry is the root/suffix entry, 
4260          * otherwise last should be the parent.
4261          */
4262         if ( last && !dn_match( &last->ce_entry->e_nname, &pdn ) ) {
4263                 if ( rs ) {
4264                         rs->sr_matched = last->ce_entry->e_name.bv_val;
4265                 }
4266                 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
4267                         "DN=\"%s\" not child of DN=\"%s\"\n",
4268                         log_prefix, e->e_name.bv_val,
4269                         last->ce_entry->e_name.bv_val );
4270                 return LDAP_NO_SUCH_OBJECT;
4271         }
4272
4273         if ( op ) {
4274                 /* No parent, must be root. This will never happen... */
4275                 if ( !last && !be_isroot( op ) && !be_shadow_update( op ) ) {
4276                         return LDAP_NO_SUCH_OBJECT;
4277                 }
4278
4279                 if ( last && !access_allowed( op, last->ce_entry,
4280                         slap_schema.si_ad_children, NULL, ACL_WADD, NULL ) )
4281                 {
4282                         Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
4283                                 "DN=\"%s\" no write access to \"children\" of parent\n",
4284                                 log_prefix, e->e_name.bv_val, 0 );
4285                         return LDAP_INSUFFICIENT_ACCESS;
4286                 }
4287         }
4288
4289         oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
4290         if ( !oc_at ) {
4291                 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
4292                         "DN=\"%s\" no objectClass\n",
4293                         log_prefix, e->e_name.bv_val, 0 );
4294                 return LDAP_OBJECT_CLASS_VIOLATION;
4295         }
4296
4297         soc_at = attr_find( e->e_attrs, slap_schema.si_ad_structuralObjectClass );
4298         if ( !soc_at ) {
4299                 ObjectClass     *soc = NULL;
4300                 char            textbuf[ SLAP_TEXT_BUFLEN ];
4301                 const char      *text = textbuf;
4302
4303                 /* FIXME: check result */
4304                 rc = structural_class( oc_at->a_nvals, &soc, NULL,
4305                         &text, textbuf, sizeof(textbuf), NULL );
4306                 if ( rc != LDAP_SUCCESS ) {
4307                         Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
4308                                 "DN=\"%s\" no structural objectClass (%s)\n",
4309                                 log_prefix, e->e_name.bv_val, text );
4310                         return rc;
4311                 }
4312                 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, &soc->soc_cname, NULL );
4313                 soc_at = attr_find( e->e_attrs, slap_schema.si_ad_structuralObjectClass );
4314                 if ( soc_at == NULL ) {
4315                         Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
4316                                 "DN=\"%s\" no structural objectClass; "
4317                                 "unable to merge computed class %s\n",
4318                                 log_prefix, e->e_name.bv_val,
4319                                 soc->soc_cname.bv_val );
4320                         return LDAP_OBJECT_CLASS_VIOLATION;
4321                 }
4322
4323                 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
4324                         "DN=\"%s\" no structural objectClass; "
4325                         "computed objectClass %s merged\n",
4326                         log_prefix, e->e_name.bv_val,
4327                         soc->soc_cname.bv_val );
4328         }
4329
4330         /* Fake the coordinates based on whether we're part of an
4331          * LDAP Add or if reading the config dir
4332          */
4333         if ( rs ) {
4334                 ca->fname = "slapd";
4335                 ca->lineno = 0;
4336         } else {
4337                 ca->fname = cfdir.bv_val;
4338                 ca->lineno = 1;
4339         }
4340         ca->ca_op = op;
4341
4342         co.co_name = &soc_at->a_nvals[0];
4343         coptr = avl_find( CfOcTree, &co, CfOc_cmp );
4344         if ( coptr == NULL ) {
4345                 Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
4346                         "DN=\"%s\" no structural objectClass in configuration table\n",
4347                         log_prefix, e->e_name.bv_val, 0 );
4348                 return LDAP_OBJECT_CLASS_VIOLATION;
4349         }
4350
4351         /* Only the root can be Cft_Global, everything else must
4352          * have a parent. Only limited nesting arrangements are allowed.
4353          */
4354         rc = LDAP_CONSTRAINT_VIOLATION;
4355         if ( coptr->co_type == Cft_Global && !last ) {
4356                 cfn = cfb->cb_config;
4357                 ca->ca_private = cfn;
4358                 ca->be = frontendDB;    /* just to get past check_vals */
4359                 rc = LDAP_SUCCESS;
4360         }
4361
4362         colst = count_ocs( oc_at, &nocs );
4363
4364         /* Check whether the Add is allowed by its parent, and do
4365          * any necessary arg setup
4366          */
4367         if ( last ) {
4368                 rc = config_add_oc( &coptr, last, e, ca );
4369                 if ( rc == LDAP_CONSTRAINT_VIOLATION ) {
4370                         for ( i = 0; i<nocs; i++ ) {
4371                                 /* Already checked these */
4372                                 if ( colst[i]->co_oc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
4373                                         continue;
4374                                 if ( colst[i]->co_ldadd &&
4375                                         ( rc = colst[i]->co_ldadd( last, e, ca ))
4376                                                 != LDAP_CONSTRAINT_VIOLATION ) {
4377                                         coptr = colst[i];
4378                                         break;
4379                                 }
4380                         }
4381                 }
4382                 if ( rc == LDAP_CONSTRAINT_VIOLATION ) {
4383                         Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
4384                                 "DN=\"%s\" no structural objectClass add function\n",
4385                                 log_prefix, e->e_name.bv_val, 0 );
4386                         return LDAP_OBJECT_CLASS_VIOLATION;
4387                 }
4388         }
4389
4390         /* Add the entry but don't parse it, we already have its contents */
4391         if ( rc == LDAP_COMPARE_TRUE ) {
4392                 rc = LDAP_SUCCESS;
4393                 goto ok;
4394         }
4395
4396         if ( rc != LDAP_SUCCESS )
4397                 goto done_noop;
4398
4399         /* Parse all the values and check for simple syntax errors before
4400          * performing any set actions.
4401          *
4402          * If doing an LDAPadd, check for indexed names and any necessary
4403          * renaming/renumbering. Entries that don't need indexed names are
4404          * ignored. Entries that need an indexed name and arrive without one
4405          * are assigned to the end. Entries that arrive with an index may
4406          * cause the following entries to be renumbered/bumped down.
4407          *
4408          * Note that "pseudo-indexed" entries (cn=Include{xx}, cn=Module{xx})
4409          * don't allow Adding an entry with an index that's already in use.
4410          * This is flagged as an error (LDAP_ALREADY_EXISTS) up above.
4411          *
4412          * These entries can have auto-assigned indexes (appended to the end)
4413          * but only the other types support auto-renumbering of siblings.
4414          */
4415         {
4416                 rc = check_name_index( last, coptr->co_type, e, rs, renum,
4417                         &ibase );
4418                 if ( rc ) {
4419                         goto done_noop;
4420                 }
4421                 if ( renum && *renum && coptr->co_type != Cft_Database &&
4422                         coptr->co_type != Cft_Overlay )
4423                 {
4424                         snprintf( ca->cr_msg, sizeof( ca->cr_msg ),
4425                                 "operation requires sibling renumbering" );
4426                         rc = LDAP_UNWILLING_TO_PERFORM;
4427                         goto done_noop;
4428                 }
4429         }
4430
4431         init_config_argv( ca );
4432
4433         /* Make sure we process attrs in the required order */
4434         sort_attrs( e, colst, nocs );
4435
4436         for ( a = e->e_attrs; a; a = a->a_next ) {
4437                 if ( a == oc_at ) continue;
4438                 ct = config_find_table( colst, nocs, a->a_desc, ca );
4439                 if ( !ct ) continue;    /* user data? */
4440                 rc = check_vals( ct, ca, a, 1 );
4441                 if ( rc ) goto done_noop;
4442         }
4443
4444         /* Basic syntax checks are OK. Do the actual settings. */
4445         for ( a=e->e_attrs; a; a=a->a_next ) {
4446                 if ( a == oc_at ) continue;
4447                 ct = config_find_table( colst, nocs, a->a_desc, ca );
4448                 if ( !ct ) continue;    /* user data? */
4449                 for (i=0; a->a_vals[i].bv_val; i++) {
4450                         char *iptr = NULL;
4451                         ca->line = a->a_vals[i].bv_val;
4452                         if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) {
4453                                 ptr = strchr( ca->line, '}' );
4454                                 if ( ptr ) {
4455                                         iptr = strchr( ca->line, '{' );
4456                                         ca->line = ptr+1;
4457                                 }
4458                         }
4459                         if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED_SIB ) {
4460                                 if ( iptr ) {
4461                                         ca->valx = strtol( iptr+1, NULL, 0 );
4462                                 } else {
4463                                         ca->valx = -1;
4464                                 }
4465                         } else {
4466                                 ca->valx = i;
4467                         }
4468                         rc = config_parse_add( ct, ca, i );
4469                         if ( rc ) {
4470                                 rc = LDAP_OTHER;
4471                                 goto done;
4472                         }
4473                 }
4474         }
4475 ok:
4476         /* Newly added databases and overlays need to be started up */
4477         if ( CONFIG_ONLINE_ADD( ca )) {
4478                 if ( colst[0]->co_type == Cft_Database ) {
4479                         rc = backend_startup_one( ca->be, &ca->reply );
4480
4481                 } else if ( colst[0]->co_type == Cft_Overlay ) {
4482                         if ( ca->bi->bi_db_open ) {
4483                                 BackendInfo *bi_orig = ca->be->bd_info;
4484                                 ca->be->bd_info = ca->bi;
4485                                 rc = ca->bi->bi_db_open( ca->be, &ca->reply );
4486                                 ca->be->bd_info = bi_orig;
4487                         }
4488                 } else if ( ca->cleanup ) {
4489                         rc = ca->cleanup( ca );
4490                 }
4491                 if ( rc ) {
4492                         if (ca->cr_msg[0] == '\0')
4493                                 snprintf( ca->cr_msg, sizeof( ca->cr_msg ), "<%s> failed startup", ca->argv[0] );
4494
4495                         Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
4496                                 ca->log, ca->cr_msg, ca->argv[1] );
4497                         rc = LDAP_OTHER;
4498                         goto done;
4499                 }
4500         }
4501
4502         ca->valx = ibase;
4503         ce = ch_calloc( 1, sizeof(CfEntryInfo) );
4504         ce->ce_parent = last;
4505         ce->ce_entry = entry_dup( e );
4506         ce->ce_entry->e_private = ce;
4507         ce->ce_type = colst[0]->co_type;
4508         ce->ce_be = ca->be;
4509         ce->ce_bi = ca->bi;
4510         ce->ce_private = ca->ca_private;
4511         ca->ca_entry = ce->ce_entry;
4512         if ( !last ) {
4513                 cfb->cb_root = ce;
4514         } else if ( last->ce_kids ) {
4515                 CfEntryInfo *c2, **cprev;
4516
4517                 /* Advance to first of this type */
4518                 cprev = &last->ce_kids;
4519                 for ( c2 = *cprev; c2 && c2->ce_type < ce->ce_type; ) {
4520                         cprev = &c2->ce_sibs;
4521                         c2 = c2->ce_sibs;
4522                 }
4523                 /* Account for the (-1) frontendDB entry */
4524                 if ( ce->ce_type == Cft_Database ) {
4525                         if ( ca->be == frontendDB )
4526                                 ibase = 0;
4527                         else if ( ibase != -1 )
4528                                 ibase++;
4529                 }
4530                 /* Append */
4531                 if ( ibase < 0 ) {
4532                         for (c2 = *cprev; c2 && c2->ce_type == ce->ce_type;) {
4533                                 cprev = &c2->ce_sibs;
4534                                 c2 = c2->ce_sibs;
4535                         }
4536                 } else {
4537                 /* Insert */
4538                         int i;
4539                         for ( i=0; i<ibase; i++ ) {
4540                                 c2 = *cprev;
4541                                 cprev = &c2->ce_sibs;
4542                         }
4543                 }
4544                 ce->ce_sibs = *cprev;
4545                 *cprev = ce;
4546         } else {
4547                 last->ce_kids = ce;
4548         }
4549
4550 done:
4551         if ( rc ) {
4552                 if ( (colst[0]->co_type == Cft_Database) && ca->be ) {
4553                         if ( ca->be != frontendDB )
4554                                 backend_destroy_one( ca->be, 1 );
4555                 } else if ( (colst[0]->co_type == Cft_Overlay) && ca->bi ) {
4556                         overlay_destroy_one( ca->be, (slap_overinst *)ca->bi );
4557                 } else if ( colst[0]->co_type == Cft_Schema ) {
4558                         schema_destroy_one( ca, colst, nocs, last );
4559                 }
4560         }
4561 done_noop:
4562
4563         ch_free( ca->argv );
4564         if ( colst ) ch_free( colst );
4565         return rc;
4566 }
4567
4568 #define BIGTMP  10000
4569 static int
4570 config_rename_add( Operation *op, SlapReply *rs, CfEntryInfo *ce,
4571         int base, int rebase, int max, int use_ldif )
4572 {
4573         CfEntryInfo *ce2, *ce3, *cetmp = NULL, *cerem = NULL;
4574         ConfigType etype = ce->ce_type;
4575         int count = 0, rc = 0;
4576
4577         /* Reverse ce list */
4578         for (ce2 = ce->ce_sibs;ce2;ce2 = ce3) {
4579                 if (ce2->ce_type != etype) {
4580                         cerem = ce2;
4581                         break;
4582                 }
4583                 ce3 = ce2->ce_sibs;
4584                 ce2->ce_sibs = cetmp;
4585                 cetmp = ce2;
4586                 count++;
4587                 if ( max && count >= max ) {
4588                         cerem = ce3;
4589                         break;
4590                 }
4591         }
4592
4593         /* Move original to a temp name until increments are done */
4594         if ( rebase ) {
4595                 ce->ce_entry->e_private = NULL;
4596                 rc = config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
4597                         base+BIGTMP, 0, use_ldif );
4598                 ce->ce_entry->e_private = ce;
4599         }
4600         /* start incrementing */
4601         for (ce2=cetmp; ce2; ce2=ce3) {
4602                 ce3 = ce2->ce_sibs;
4603                 ce2->ce_sibs = cerem;
4604                 cerem = ce2;
4605                 if ( rc == 0 ) 
4606                         rc = config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
4607                                 count+base, 0, use_ldif );
4608                 count--;
4609         }
4610         if ( rebase )
4611                 rc = config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
4612                         base, 0, use_ldif );
4613         return rc;
4614 }
4615
4616 static int
4617 config_rename_del( Operation *op, SlapReply *rs, CfEntryInfo *ce,
4618         CfEntryInfo *ce2, int old, int use_ldif )
4619 {
4620         int count = 0;
4621
4622         /* Renumber original to a temp value */
4623         ce->ce_entry->e_private = NULL;
4624         config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
4625                 old+BIGTMP, 0, use_ldif );
4626         ce->ce_entry->e_private = ce;
4627
4628         /* start decrementing */
4629         for (; ce2 != ce; ce2=ce2->ce_sibs) {
4630                 config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
4631                         count+old, 0, use_ldif );
4632                 count++;
4633         }
4634         return config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
4635                 count+old, 0, use_ldif );
4636 }
4637
4638 /* Parse an LDAP entry into config directives, then store in underlying
4639  * database.
4640  */
4641 static int
4642 config_back_add( Operation *op, SlapReply *rs )
4643 {
4644         CfBackInfo *cfb;
4645         int renumber;
4646         ConfigArgs ca;
4647
4648         if ( !access_allowed( op, op->ora_e, slap_schema.si_ad_entry,
4649                 NULL, ACL_WADD, NULL )) {
4650                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
4651                 goto out;
4652         }
4653
4654         /*
4655          * Check for attribute ACL
4656          */
4657         if ( !acl_check_modlist( op, op->ora_e, op->orm_modlist )) {
4658                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
4659                 rs->sr_text = "no write access to attribute";
4660                 goto out;
4661         }
4662
4663         cfb = (CfBackInfo *)op->o_bd->be_private;
4664
4665         /* add opattrs for syncprov */
4666         {
4667                 char textbuf[SLAP_TEXT_BUFLEN];
4668                 size_t textlen = sizeof textbuf;
4669                 rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1,
4670                         &rs->sr_text, textbuf, sizeof( textbuf ) );
4671                 if ( rs->sr_err != LDAP_SUCCESS )
4672                         goto out;
4673                 rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
4674                 if ( rs->sr_err != LDAP_SUCCESS ) {
4675                         Debug( LDAP_DEBUG_TRACE,
4676                                 LDAP_XSTRING(config_back_add) ": entry failed op attrs add: "
4677                                 "%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
4678                         goto out;
4679                 }
4680         }
4681
4682         ldap_pvt_thread_pool_pause( &connection_pool );
4683
4684         /* Strategy:
4685          * 1) check for existence of entry
4686          * 2) check for sibling renumbering
4687          * 3) perform internal add
4688          * 4) perform any necessary renumbering
4689          * 5) store entry in underlying database
4690          */
4691         rs->sr_err = config_add_internal( cfb, op->ora_e, &ca, rs, &renumber, op );
4692         if ( rs->sr_err != LDAP_SUCCESS ) {
4693                 rs->sr_text = ca.cr_msg;
4694                 goto out2;
4695         }
4696
4697         if ( renumber ) {
4698                 CfEntryInfo *ce = ca.ca_entry->e_private;
4699                 req_add_s addr = op->oq_add;
4700                 op->o_tag = LDAP_REQ_MODRDN;
4701                 rs->sr_err = config_rename_add( op, rs, ce, ca.valx, 0, 0, cfb->cb_use_ldif );
4702                 op->o_tag = LDAP_REQ_ADD;
4703                 op->oq_add = addr;
4704                 if ( rs->sr_err != LDAP_SUCCESS ) {
4705                         goto out2;
4706                 }
4707         }
4708
4709         if ( cfb->cb_use_ldif ) {
4710                 BackendDB *be = op->o_bd;
4711                 slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
4712                 struct berval dn, ndn;
4713
4714                 op->o_bd = &cfb->cb_db;
4715
4716                 /* Save current rootdn; use the underlying DB's rootdn */
4717                 dn = op->o_dn;
4718                 ndn = op->o_ndn;
4719                 op->o_dn = op->o_bd->be_rootdn;
4720                 op->o_ndn = op->o_bd->be_rootndn;
4721
4722                 scp = op->o_callback;
4723                 op->o_callback = &sc;
4724                 op->o_bd->be_add( op, rs );
4725                 op->o_bd = be;
4726                 op->o_callback = scp;
4727                 op->o_dn = dn;
4728                 op->o_ndn = ndn;
4729         }
4730
4731 out2:;
4732         ldap_pvt_thread_pool_resume( &connection_pool );
4733
4734 out:;
4735         send_ldap_result( op, rs );
4736         slap_graduate_commit_csn( op );
4737         return rs->sr_err;
4738 }
4739
4740 typedef struct delrec {
4741         struct delrec *next;
4742         int nidx;
4743         int idx[1];
4744 } delrec;
4745
4746 static int
4747 config_modify_add( ConfigTable *ct, ConfigArgs *ca, AttributeDescription *ad,
4748         int i )
4749 {
4750         int rc;
4751
4752         if (ad->ad_type->sat_flags & SLAP_AT_ORDERED &&
4753                 ca->line[0] == '{' )
4754         {
4755                 char *ptr = strchr( ca->line + 1, '}' );
4756                 if ( ptr ) {
4757                         char    *next;
4758
4759                         ca->valx = strtol( ca->line + 1, &next, 0 );
4760                         if ( next == ca->line + 1 || next[ 0 ] != '}' ) {
4761                                 return LDAP_OTHER;
4762                         }
4763                         ca->line = ptr+1;
4764                 }
4765         }
4766         rc = config_parse_add( ct, ca, i );
4767         if ( rc ) {
4768                 rc = LDAP_OTHER;
4769         }
4770         return rc;
4771 }
4772
4773 static int
4774 config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
4775         ConfigArgs *ca )
4776 {
4777         int rc = LDAP_UNWILLING_TO_PERFORM;
4778         Modifications *ml;
4779         Entry *e = ce->ce_entry;
4780         Attribute *save_attrs = e->e_attrs, *oc_at, *s, *a;
4781         ConfigTable *ct;
4782         ConfigOCs **colst;
4783         int i, nocs;
4784         char *ptr;
4785         delrec *dels = NULL, *deltail = NULL;
4786
4787         oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
4788         if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION;
4789
4790         colst = count_ocs( oc_at, &nocs );
4791
4792         /* make sure add/del flags are clear; should always be true */
4793         for ( s = save_attrs; s; s = s->a_next ) {
4794                 s->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL);
4795         }
4796
4797         e->e_attrs = attrs_dup( e->e_attrs );
4798
4799         init_config_argv( ca );
4800         ca->be = ce->ce_be;
4801         ca->bi = ce->ce_bi;
4802         ca->ca_private = ce->ce_private;
4803         ca->ca_entry = e;
4804         ca->fname = "slapd";
4805         ca->ca_op = op;
4806         strcpy( ca->log, "back-config" );
4807
4808         for (ml = op->orm_modlist; ml; ml=ml->sml_next) {
4809                 ct = config_find_table( colst, nocs, ml->sml_desc, ca );
4810                 switch (ml->sml_op) {
4811                 case LDAP_MOD_DELETE:
4812                 case LDAP_MOD_REPLACE: {
4813                         BerVarray vals = NULL, nvals = NULL;
4814                         int *idx = NULL;
4815                         if ( ct && ( ct->arg_type & ARG_NO_DELETE )) {
4816                                 rc = LDAP_OTHER;
4817                                 snprintf(ca->cr_msg, sizeof(ca->cr_msg), "cannot delete %s",
4818                                         ml->sml_desc->ad_cname.bv_val );
4819                                 goto out_noop;
4820                         }
4821                         if ( ml->sml_op == LDAP_MOD_REPLACE ) {
4822                                 vals = ml->sml_values;
4823                                 nvals = ml->sml_nvalues;
4824                                 ml->sml_values = NULL;
4825                                 ml->sml_nvalues = NULL;
4826                         }
4827                         /* If we're deleting by values, remember the indexes of the
4828                          * values we deleted.
4829                          */
4830                         if ( ct && ml->sml_values ) {
4831                                 delrec *d;
4832                                 i = ml->sml_numvals;
4833                                 d = ch_malloc( sizeof(delrec) + (i - 1)* sizeof(int));
4834                                 d->nidx = i;
4835                                 d->next = NULL;
4836                                 if ( dels ) {
4837                                         deltail->next = d;
4838                                 } else {
4839                                         dels = d;
4840                                 }
4841                                 deltail = d;
4842                                 idx = d->idx;
4843                         }
4844                         rc = modify_delete_vindex(e, &ml->sml_mod,
4845                                 get_permissiveModify(op),
4846                                 &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg), idx );
4847                         if ( ml->sml_op == LDAP_MOD_REPLACE ) {
4848                                 ml->sml_values = vals;
4849                                 ml->sml_nvalues = nvals;
4850                         }
4851                         if ( !vals )
4852                                 break;
4853                         }
4854                         /* FALLTHRU: LDAP_MOD_REPLACE && vals */
4855
4856                 case LDAP_MOD_ADD:
4857                 case SLAP_MOD_SOFTADD: {
4858                         int mop = ml->sml_op;
4859                         int navals = -1;
4860                         ml->sml_op = LDAP_MOD_ADD;
4861                         if ( ct ) {
4862                                 if ( ct->arg_type & ARG_NO_INSERT ) {
4863                                         Attribute *a = attr_find( e->e_attrs, ml->sml_desc );
4864                                         if ( a ) {
4865                                                 navals = a->a_numvals;
4866                                         }
4867                                 }
4868                                 for ( i=0; !BER_BVISNULL( &ml->sml_values[i] ); i++ ) {
4869                                         if ( ml->sml_values[i].bv_val[0] == '{' &&
4870                                                 navals >= 0 )
4871                                         {
4872                                                 char    *next, *val = ml->sml_values[i].bv_val + 1;
4873                                                 int     j;
4874
4875                                                 j = strtol( val, &next, 0 );
4876                                                 if ( next == val || next[ 0 ] != '}' || j < navals ) {
4877                                                         rc = LDAP_OTHER;
4878                                                         snprintf(ca->cr_msg, sizeof(ca->cr_msg), "cannot insert %s",
4879                                                                 ml->sml_desc->ad_cname.bv_val );
4880                                                         goto out_noop;
4881                                                 }
4882                                         }
4883                                         rc = check_vals( ct, ca, ml, 0 );
4884                                         if ( rc ) goto out_noop;
4885                                 }
4886                         }
4887                         rc = modify_add_values(e, &ml->sml_mod,
4888                                    get_permissiveModify(op),
4889                                    &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) );
4890
4891                         /* If value already exists, show success here
4892                          * and ignore this operation down below.
4893                          */
4894                         if ( mop == SLAP_MOD_SOFTADD ) {
4895                                 if ( rc == LDAP_TYPE_OR_VALUE_EXISTS )
4896                                         rc = LDAP_SUCCESS;
4897                                 else
4898                                         mop = LDAP_MOD_ADD;
4899                         }
4900                         ml->sml_op = mop;
4901                         break;
4902                         }
4903
4904                         break;
4905                 case LDAP_MOD_INCREMENT:        /* FIXME */
4906                         break;
4907                 default:
4908                         break;
4909                 }
4910                 if(rc != LDAP_SUCCESS) break;
4911         }
4912         
4913         if ( rc == LDAP_SUCCESS) {
4914                 /* check that the entry still obeys the schema */
4915                 rc = entry_schema_check(op, e, NULL, 0, 0,
4916                         &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) );
4917         }
4918         if ( rc ) goto out_noop;
4919
4920         /* Basic syntax checks are OK. Do the actual settings. */
4921         for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
4922                 ct = config_find_table( colst, nocs, ml->sml_desc, ca );
4923                 if ( !ct ) continue;
4924
4925                 s = attr_find( save_attrs, ml->sml_desc );
4926                 a = attr_find( e->e_attrs, ml->sml_desc );
4927
4928                 switch (ml->sml_op) {
4929                 case LDAP_MOD_DELETE:
4930                 case LDAP_MOD_REPLACE: {
4931                         BerVarray vals = NULL, nvals = NULL;
4932                         delrec *d = NULL;
4933
4934                         if ( ml->sml_op == LDAP_MOD_REPLACE ) {
4935                                 vals = ml->sml_values;
4936                                 nvals = ml->sml_nvalues;
4937                                 ml->sml_values = NULL;
4938                                 ml->sml_nvalues = NULL;
4939                         }
4940
4941                         if ( ml->sml_values )
4942                                 d = dels;
4943
4944                         /* If we didn't delete the whole attribute */
4945                         if ( ml->sml_values && a ) {
4946                                 struct berval *mvals;
4947                                 int j;
4948
4949                                 if ( ml->sml_nvalues )
4950                                         mvals = ml->sml_nvalues;
4951                                 else
4952                                         mvals = ml->sml_values;
4953
4954                                 /* use the indexes we saved up above */
4955                                 for (i=0; i < d->nidx; i++) {
4956                                         struct berval bv = *mvals++;
4957                                         if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED &&
4958                                                 bv.bv_val[0] == '{' ) {
4959                                                 ptr = strchr( bv.bv_val, '}' ) + 1;
4960                                                 bv.bv_len -= ptr - bv.bv_val;
4961                                                 bv.bv_val = ptr;
4962                                         }
4963                                         ca->line = bv.bv_val;
4964                                         ca->valx = d->idx[i];
4965                                         rc = config_del_vals( ct, ca );
4966                                         if ( rc != LDAP_SUCCESS ) break;
4967                                         if ( s )
4968                                                 s->a_flags |= SLAP_ATTR_IXDEL;
4969                                         for (j=i+1; j < d->nidx; j++)
4970                                                 if ( d->idx[j] >d->idx[i] )
4971                                                         d->idx[j]--;
4972                                 }
4973                         } else {
4974                                 ca->valx = -1;
4975                                 ca->line = NULL;
4976                                 rc = config_del_vals( ct, ca );
4977                                 if ( rc ) rc = LDAP_OTHER;
4978                                 if ( s )
4979                                         s->a_flags |= SLAP_ATTR_IXDEL;
4980                         }
4981                         if ( ml->sml_values ) {
4982                                 d = d->next;
4983                                 ch_free( dels );
4984                                 dels = d;
4985                         }
4986                         if ( ml->sml_op == LDAP_MOD_REPLACE ) {
4987                                 ml->sml_values = vals;
4988                                 ml->sml_nvalues = nvals;
4989                         }
4990                         if ( !vals || rc != LDAP_SUCCESS )
4991                                 break;
4992                         }
4993                         /* FALLTHRU: LDAP_MOD_REPLACE && vals */
4994
4995                 case LDAP_MOD_ADD:
4996                         for (i=0; ml->sml_values[i].bv_val; i++) {
4997                                 ca->line = ml->sml_values[i].bv_val;
4998                                 ca->valx = -1;
4999                                 rc = config_modify_add( ct, ca, ml->sml_desc, i );
5000                                 if ( rc )
5001                                         goto out;
5002                                 a->a_flags |= SLAP_ATTR_IXADD;
5003                         }
5004                         break;
5005                 }
5006         }
5007
5008 out:
5009         /* Undo for a failed operation */
5010         if ( rc != LDAP_SUCCESS ) {
5011                 ConfigReply msg = ca->reply;
5012                 for ( s = save_attrs; s; s = s->a_next ) {
5013                         if ( s->a_flags & SLAP_ATTR_IXDEL ) {
5014                                 s->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
5015                                 ct = config_find_table( colst, nocs, s->a_desc, ca );
5016                                 a = attr_find( e->e_attrs, s->a_desc );
5017                                 if ( a ) {
5018                                         /* clear the flag so the add check below will skip it */
5019                                         a->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
5020                                         ca->valx = -1;
5021                                         ca->line = NULL;
5022                                         config_del_vals( ct, ca );
5023                                 }
5024                                 for ( i=0; !BER_BVISNULL( &s->a_vals[i] ); i++ ) {
5025                                         ca->line = s->a_vals[i].bv_val;
5026                                         ca->valx = -1;
5027                                         config_modify_add( ct, ca, s->a_desc, i );
5028                                 }
5029                         }
5030                 }
5031                 for ( a = e->e_attrs; a; a = a->a_next ) {
5032                         if ( a->a_flags & SLAP_ATTR_IXADD ) {
5033                                 ct = config_find_table( colst, nocs, a->a_desc, ca );
5034                                 ca->valx = -1;
5035                                 ca->line = NULL;
5036                                 config_del_vals( ct, ca );
5037                                 s = attr_find( save_attrs, a->a_desc );
5038                                 if ( s ) {
5039                                         s->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
5040                                         for ( i=0; !BER_BVISNULL( &s->a_vals[i] ); i++ ) {
5041                                                 ca->line = s->a_vals[i].bv_val;
5042                                                 ca->valx = -1;
5043                                                 config_modify_add( ct, ca, s->a_desc, i );
5044                                         }
5045                                 }
5046                         }
5047                 }
5048                 ca->reply = msg;
5049         }
5050
5051         if ( ca->cleanup )
5052                 ca->cleanup( ca );
5053 out_noop:
5054         if ( rc == LDAP_SUCCESS ) {
5055                 attrs_free( save_attrs );
5056         } else {
5057                 attrs_free( e->e_attrs );
5058                 e->e_attrs = save_attrs;
5059         }
5060         ch_free( ca->argv );
5061         if ( colst ) ch_free( colst );
5062         while( dels ) {
5063                 deltail = dels->next;
5064                 ch_free( dels );
5065                 dels = deltail;
5066         }
5067
5068         return rc;
5069 }
5070
5071 static int
5072 config_back_modify( Operation *op, SlapReply *rs )
5073 {
5074         CfBackInfo *cfb;
5075         CfEntryInfo *ce, *last;
5076         Modifications *ml;
5077         ConfigArgs ca = {0};
5078         struct berval rdn;
5079         char *ptr;
5080         AttributeDescription *rad = NULL;
5081         int do_pause = 1;
5082
5083         cfb = (CfBackInfo *)op->o_bd->be_private;
5084
5085         ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
5086         if ( !ce ) {
5087                 if ( last )
5088                         rs->sr_matched = last->ce_entry->e_name.bv_val;
5089                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
5090                 goto out;
5091         }
5092
5093         if ( !acl_check_modlist( op, ce->ce_entry, op->orm_modlist )) {
5094                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
5095                 goto out;
5096         }
5097
5098         /* Get type of RDN */
5099         rdn = ce->ce_entry->e_nname;
5100         ptr = strchr( rdn.bv_val, '=' );
5101         rdn.bv_len = ptr - rdn.bv_val;
5102         slap_bv2ad( &rdn, &rad, &rs->sr_text );
5103
5104         /* Some basic validation... */
5105         for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
5106                 /* Don't allow Modify of RDN; must use ModRdn for that. */
5107                 if ( ml->sml_desc == rad ) {
5108                         rs->sr_err = LDAP_NOT_ALLOWED_ON_RDN;
5109                         rs->sr_text = "Use modrdn to change the entry name";
5110                         goto out;
5111                 }
5112                 /* Internal update of contextCSN? */
5113                 if ( ml->sml_desc == slap_schema.si_ad_contextCSN && op->o_conn->c_conn_idx == -1 ) {
5114                         do_pause = 0;
5115                         break;
5116                 }
5117         }
5118
5119         slap_mods_opattrs( op, &op->orm_modlist, 1 );
5120
5121         if ( do_pause )
5122                 ldap_pvt_thread_pool_pause( &connection_pool );
5123
5124         /* Strategy:
5125          * 1) perform the Modify on the cached Entry.
5126          * 2) verify that the Entry still satisfies the schema.
5127          * 3) perform the individual config operations.
5128          * 4) store Modified entry in underlying LDIF backend.
5129          */
5130         rs->sr_err = config_modify_internal( ce, op, rs, &ca );
5131         if ( rs->sr_err ) {
5132                 rs->sr_text = ca.cr_msg;
5133         } else if ( cfb->cb_use_ldif ) {
5134                 BackendDB *be = op->o_bd;
5135                 slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
5136                 struct berval dn, ndn;
5137
5138                 op->o_bd = &cfb->cb_db;
5139
5140                 dn = op->o_dn;
5141                 ndn = op->o_ndn;
5142                 op->o_dn = op->o_bd->be_rootdn;
5143                 op->o_ndn = op->o_bd->be_rootndn;
5144
5145                 scp = op->o_callback;
5146                 op->o_callback = &sc;
5147                 op->o_bd->be_modify( op, rs );
5148                 op->o_bd = be;
5149                 op->o_callback = scp;
5150                 op->o_dn = dn;
5151                 op->o_ndn = ndn;
5152         }
5153
5154         if ( do_pause )
5155                 ldap_pvt_thread_pool_resume( &connection_pool );
5156 out:
5157         send_ldap_result( op, rs );
5158         slap_graduate_commit_csn( op );
5159         return rs->sr_err;
5160 }
5161
5162 static int
5163 config_back_modrdn( Operation *op, SlapReply *rs )
5164 {
5165         CfBackInfo *cfb;
5166         CfEntryInfo *ce, *last;
5167         struct berval rdn;
5168         int ixold, ixnew;
5169
5170         cfb = (CfBackInfo *)op->o_bd->be_private;
5171
5172         ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
5173         if ( !ce ) {
5174                 if ( last )
5175                         rs->sr_matched = last->ce_entry->e_name.bv_val;
5176                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
5177                 goto out;
5178         }
5179         if ( !access_allowed( op, ce->ce_entry, slap_schema.si_ad_entry,
5180                 NULL, ACL_WRITE, NULL )) {
5181                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
5182                 goto out;
5183         }
5184         { Entry *parent;
5185                 if ( ce->ce_parent )
5186                         parent = ce->ce_parent->ce_entry;
5187                 else
5188                         parent = (Entry *)&slap_entry_root;
5189                 if ( !access_allowed( op, parent, slap_schema.si_ad_children,
5190                         NULL, ACL_WRITE, NULL )) {
5191                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
5192                         goto out;
5193                 }
5194         }
5195
5196         /* We don't allow moving objects to new parents.
5197          * Generally we only allow reordering a set of ordered entries.
5198          */
5199         if ( op->orr_newSup ) {
5200                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
5201                 goto out;
5202         }
5203
5204         /* If newRDN == oldRDN, quietly succeed */
5205         dnRdn( &op->o_req_ndn, &rdn );
5206         if ( dn_match( &rdn, &op->orr_nnewrdn )) {
5207                 rs->sr_err = LDAP_SUCCESS;
5208                 goto out;
5209         }
5210
5211         /* Current behavior, subject to change as needed:
5212          *
5213          * For backends and overlays, we only allow renumbering.
5214          * For schema, we allow renaming with the same number.
5215          * Otherwise, the op is not allowed.
5216          */
5217
5218         if ( ce->ce_type == Cft_Schema ) {
5219                 char *ptr1, *ptr2;
5220                 int len;
5221
5222                 /* Can't alter the main cn=schema entry */
5223                 if ( ce->ce_parent->ce_type == Cft_Global ) {
5224                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
5225                         rs->sr_text = "renaming not allowed for this entry";
5226                         goto out;
5227                 }
5228
5229                 /* We could support this later if desired */
5230                 ptr1 = ber_bvchr( &rdn, '}' );
5231                 ptr2 = ber_bvchr( &op->orr_newrdn, '}' );
5232                 len = ptr1 - rdn.bv_val;
5233                 if ( len != ptr2 - op->orr_newrdn.bv_val ||
5234                         strncmp( rdn.bv_val, op->orr_newrdn.bv_val, len )) {
5235                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
5236                         rs->sr_text = "schema reordering not supported";
5237                         goto out;
5238                 }
5239         } else if ( ce->ce_type == Cft_Database ||
5240                 ce->ce_type == Cft_Overlay ) {
5241                 char *ptr1, *ptr2, *iptr1, *iptr2;
5242                 int len1, len2;
5243
5244                 iptr2 = ber_bvchr( &op->orr_newrdn, '=' ) + 1;
5245                 if ( *iptr2 != '{' ) {
5246                         rs->sr_err = LDAP_NAMING_VIOLATION;
5247                         rs->sr_text = "new ordering index is required";
5248                         goto out;
5249                 }
5250                 iptr2++;
5251                 iptr1 = ber_bvchr( &rdn, '{' ) + 1;
5252                 ptr1 = ber_bvchr( &rdn, '}' );
5253                 ptr2 = ber_bvchr( &op->orr_newrdn, '}' );
5254                 if ( !ptr2 ) {
5255                         rs->sr_err = LDAP_NAMING_VIOLATION;
5256                         rs->sr_text = "new ordering index is required";
5257                         goto out;
5258                 }
5259
5260                 len1 = ptr1 - rdn.bv_val;
5261                 len2 = ptr2 - op->orr_newrdn.bv_val;
5262
5263                 if ( rdn.bv_len - len1 != op->orr_newrdn.bv_len - len2 ||
5264                         strncmp( ptr1, ptr2, rdn.bv_len - len1 )) {
5265                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
5266                         rs->sr_text = "changing database/overlay type not allowed";
5267                         goto out;
5268                 }
5269                 ixold = strtol( iptr1, NULL, 0 );
5270                 ixnew = strtol( iptr2, &ptr1, 0 );
5271                 if ( ptr1 != ptr2 || ixold < 0 || ixnew < 0 ) {
5272                         rs->sr_err = LDAP_NAMING_VIOLATION;
5273                         goto out;
5274                 }
5275                 /* config DB is always 0, cannot be changed */
5276                 if ( ce->ce_type == Cft_Database && ( ixold == 0 || ixnew == 0 )) {
5277                         rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
5278                         goto out;
5279                 }
5280         } else {
5281                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
5282                 rs->sr_text = "renaming not supported for this entry";
5283                 goto out;
5284         }
5285
5286         ldap_pvt_thread_pool_pause( &connection_pool );
5287
5288         if ( ce->ce_type == Cft_Schema ) {
5289                 req_modrdn_s modr = op->oq_modrdn;
5290                 struct berval rdn;
5291                 Attribute *a;
5292                 rs->sr_err = config_rename_attr( rs, ce->ce_entry, &rdn, &a );
5293                 if ( rs->sr_err == LDAP_SUCCESS ) {
5294                         rs->sr_err = config_rename_one( op, rs, ce->ce_entry,
5295                                 ce->ce_parent, a, &op->orr_newrdn, &op->orr_nnewrdn,
5296                                 cfb->cb_use_ldif );
5297                 }
5298                 op->oq_modrdn = modr;
5299         } else {
5300                 CfEntryInfo *ce2, *cebase, **cprev, **cbprev, *ceold;
5301                 req_modrdn_s modr = op->oq_modrdn;
5302                 int i;
5303
5304                 /* Advance to first of this type */
5305                 cprev = &ce->ce_parent->ce_kids;
5306                 for ( ce2 = *cprev; ce2 && ce2->ce_type != ce->ce_type; ) {
5307                         cprev = &ce2->ce_sibs;
5308                         ce2 = ce2->ce_sibs;
5309                 }
5310                 /* Skip the -1 entry */
5311                 if ( ce->ce_type == Cft_Database ) {
5312                         cprev = &ce2->ce_sibs;
5313                         ce2 = ce2->ce_sibs;
5314                 }
5315                 cebase = ce2;
5316                 cbprev = cprev;
5317
5318                 /* Remove from old slot */
5319                 for ( ce2 = *cprev; ce2 && ce2 != ce; ce2 = ce2->ce_sibs )
5320                         cprev = &ce2->ce_sibs;
5321                 *cprev = ce->ce_sibs;
5322                 ceold = ce->ce_sibs;
5323
5324                 /* Insert into new slot */
5325                 cprev = cbprev;
5326                 for ( i=0; i<ixnew; i++ ) {
5327                         ce2 = *cprev;
5328                         if ( !ce2 )
5329                                 break;
5330                         cprev = &ce2->ce_sibs;
5331                 }
5332                 ce->ce_sibs = *cprev;
5333                 *cprev = ce;
5334
5335                 ixnew = i;
5336
5337                 /* NOTE: These should be encoded in the OC tables, not inline here */
5338                 if ( ce->ce_type == Cft_Database )
5339                         backend_db_move( ce->ce_be, ixnew );
5340                 else if ( ce->ce_type == Cft_Overlay )
5341                         overlay_move( ce->ce_be, (slap_overinst *)ce->ce_bi, ixnew );
5342                         
5343                 if ( ixold < ixnew ) {
5344                         rs->sr_err = config_rename_del( op, rs, ce, ceold, ixold,
5345                                 cfb->cb_use_ldif );
5346                 } else {
5347                         rs->sr_err = config_rename_add( op, rs, ce, ixnew, 1,
5348                                 ixold - ixnew, cfb->cb_use_ldif );
5349                 }
5350                 op->oq_modrdn = modr;
5351         }
5352
5353         ldap_pvt_thread_pool_resume( &connection_pool );
5354 out:
5355         send_ldap_result( op, rs );
5356         return rs->sr_err;
5357 }
5358
5359 static int
5360 config_back_delete( Operation *op, SlapReply *rs )
5361 {
5362 #ifdef SLAP_CONFIG_DELETE
5363         CfBackInfo *cfb;
5364         CfEntryInfo *ce, *last, *ce2;
5365
5366         cfb = (CfBackInfo *)op->o_bd->be_private;
5367
5368         ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
5369         if ( !ce ) {
5370                 if ( last )
5371                         rs->sr_matched = last->ce_entry->e_name.bv_val;
5372                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
5373         } else if ( ce->ce_kids ) {
5374                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
5375         } else if ( ce->ce_type == Cft_Overlay ){
5376                 char *iptr;
5377                 int count, ixold;
5378
5379                 ldap_pvt_thread_pool_pause( &connection_pool );
5380                 
5381                 overlay_remove( ce->ce_be, (slap_overinst *)ce->ce_bi );
5382
5383                 /* remove CfEntryInfo from the siblings list */
5384                 if ( ce->ce_parent->ce_kids == ce ) {
5385                         ce->ce_parent->ce_kids = ce->ce_sibs;
5386                 } else {
5387                         for ( ce2 = ce->ce_parent->ce_kids ; ce2; ce2 = ce2->ce_sibs ) {
5388                                 if ( ce2->ce_sibs == ce ) {
5389                                         ce2->ce_sibs = ce->ce_sibs;
5390                                         break;
5391                                 }
5392                         }
5393                 }
5394
5395                 /* remove from underlying database */
5396                 if ( cfb->cb_use_ldif ) {
5397                         BackendDB *be = op->o_bd;
5398                         slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
5399                         struct berval dn, ndn, req_dn, req_ndn;
5400
5401                         op->o_bd = &cfb->cb_db;
5402
5403                         dn = op->o_dn;
5404                         ndn = op->o_ndn;
5405                         req_dn = op->o_req_dn;
5406                         req_ndn = op->o_req_ndn;
5407
5408                         op->o_dn = op->o_bd->be_rootdn;
5409                         op->o_ndn = op->o_bd->be_rootndn;
5410                         op->o_req_dn = ce->ce_entry->e_name;
5411                         op->o_req_ndn = ce->ce_entry->e_nname;
5412
5413                         scp = op->o_callback;
5414                         op->o_callback = &sc;
5415                         op->o_bd->be_delete( op, rs );
5416                         op->o_bd = be;
5417                         op->o_callback = scp;
5418                         op->o_dn = dn;
5419                         op->o_ndn = ndn;
5420                         op->o_req_dn = req_dn;
5421                         op->o_req_ndn = req_ndn;
5422                 }
5423
5424                 /* renumber siblings */
5425                 iptr = ber_bvchr( &op->o_req_ndn, '{' ) + 1;
5426                 ixold = strtol( iptr, NULL, 0 );
5427                 for (ce2 = ce->ce_sibs, count=0; ce2; ce2=ce2->ce_sibs) {
5428                         config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
5429                                 count+ixold, 0, cfb->cb_use_ldif );
5430                         count++;
5431                 }
5432
5433                 ce->ce_entry->e_private=NULL;
5434                 entry_free(ce->ce_entry);
5435                 ch_free(ce);
5436                 ldap_pvt_thread_pool_resume( &connection_pool );
5437         } else {
5438                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
5439         }
5440 #else
5441         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
5442 #endif /* SLAP_CONFIG_DELETE */
5443         send_ldap_result( op, rs );
5444         return rs->sr_err;
5445 }
5446
5447 static int
5448 config_back_search( Operation *op, SlapReply *rs )
5449 {
5450         CfBackInfo *cfb;
5451         CfEntryInfo *ce, *last;
5452         slap_mask_t mask;
5453
5454         cfb = (CfBackInfo *)op->o_bd->be_private;
5455
5456         ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
5457         if ( !ce ) {
5458                 if ( last )
5459                         rs->sr_matched = last->ce_entry->e_name.bv_val;
5460                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
5461                 goto out;
5462         }
5463         if ( !access_allowed_mask( op, ce->ce_entry, slap_schema.si_ad_entry, NULL,
5464                 ACL_SEARCH, NULL, &mask ))
5465         {
5466                 if ( !ACL_GRANT( mask, ACL_DISCLOSE )) {
5467                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
5468                 } else {
5469                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
5470                 }
5471                 goto out;
5472         }
5473         switch ( op->ors_scope ) {
5474         case LDAP_SCOPE_BASE:
5475         case LDAP_SCOPE_SUBTREE:
5476                 config_send( op, rs, ce, 0 );
5477                 break;
5478                 
5479         case LDAP_SCOPE_ONELEVEL:
5480                 for (ce = ce->ce_kids; ce; ce=ce->ce_sibs) {
5481                         config_send( op, rs, ce, 1 );
5482                 }
5483                 break;
5484         }
5485                 
5486         rs->sr_err = LDAP_SUCCESS;
5487 out:
5488         send_ldap_result( op, rs );
5489         return 0;
5490 }
5491
5492 /* no-op, we never free entries */
5493 int config_entry_release(
5494         Operation *op,
5495         Entry *e,
5496         int rw )
5497 {
5498         if ( !e->e_private ) {
5499                 entry_free( e );
5500         }
5501         return LDAP_SUCCESS;
5502 }
5503
5504 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
5505  */
5506 int config_back_entry_get(
5507         Operation *op,
5508         struct berval *ndn,
5509         ObjectClass *oc,
5510         AttributeDescription *at,
5511         int rw,
5512         Entry **ent )
5513 {
5514         CfBackInfo *cfb;
5515         CfEntryInfo *ce, *last;
5516         int rc = LDAP_NO_SUCH_OBJECT;
5517
5518         cfb = (CfBackInfo *)op->o_bd->be_private;
5519
5520         ce = config_find_base( cfb->cb_root, ndn, &last );
5521         if ( ce ) {
5522                 *ent = ce->ce_entry;
5523                 if ( *ent ) {
5524                         rc = LDAP_SUCCESS;
5525                         if ( oc && !is_entry_objectclass_or_sub( *ent, oc ) ) {
5526                                 rc = LDAP_NO_SUCH_ATTRIBUTE;
5527                                 *ent = NULL;
5528                         }
5529                 }
5530         }
5531
5532         return rc;
5533 }
5534
5535 static int
5536 config_build_attrs( Entry *e, AttributeType **at, AttributeDescription *ad,
5537         ConfigTable *ct, ConfigArgs *c )
5538 {
5539         int i, rc;
5540
5541         for (; at && *at; at++) {
5542                 /* Skip the naming attr */
5543                 if ((*at)->sat_ad == ad || (*at)->sat_ad == slap_schema.si_ad_cn )
5544                         continue;
5545                 for (i=0;ct[i].name;i++) {
5546                         if (ct[i].ad == (*at)->sat_ad) {
5547                                 rc = config_get_vals(&ct[i], c);
5548                                 /* NOTE: tolerate that config_get_vals()
5549                                  * returns success with no values */
5550                                 if (rc == LDAP_SUCCESS && c->rvalue_vals != NULL ) {
5551                                         if ( c->rvalue_nvals )
5552                                                 rc = attr_merge(e, ct[i].ad, c->rvalue_vals,
5553                                                         c->rvalue_nvals);
5554                                         else {
5555                                                 slap_syntax_validate_func *validate =
5556                                                         ct[i].ad->ad_type->sat_syntax->ssyn_validate;
5557                                                 if ( validate ) {
5558                                                         int j;
5559                                                         for ( j=0; c->rvalue_vals[j].bv_val; j++ ) {
5560                                                                 rc = ordered_value_validate( ct[i].ad,
5561                                                                         &c->rvalue_vals[j], LDAP_MOD_ADD );
5562                                                                 if ( rc ) {
5563                                                                         Debug( LDAP_DEBUG_ANY,
5564                                                                                 "config_build_attrs: error %d on %s value #%d\n",
5565                                                                                 rc, ct[i].ad->ad_cname.bv_val, j );
5566                                                                         return rc;
5567                                                                 }
5568                                                         }
5569                                                 }
5570                                                         
5571                                                 rc = attr_merge_normalize(e, ct[i].ad,
5572                                                         c->rvalue_vals, NULL);
5573                                         }
5574                                         ber_bvarray_free( c->rvalue_nvals );
5575                                         ber_bvarray_free( c->rvalue_vals );
5576                                         if ( rc ) {
5577                                                 Debug( LDAP_DEBUG_ANY,
5578                                                         "config_build_attrs: error %d on %s\n",
5579                                                         rc, ct[i].ad->ad_cname.bv_val, 0 );
5580                                                 return rc;
5581                                         }
5582                                 }
5583                                 break;
5584                         }
5585                 }
5586         }
5587         return 0;
5588 }
5589
5590 Entry *
5591 config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent,
5592         ConfigArgs *c, struct berval *rdn, ConfigOCs *main, ConfigOCs *extra )
5593 {
5594         Entry *e = entry_alloc();
5595         CfEntryInfo *ce = ch_calloc( 1, sizeof(CfEntryInfo) );
5596         struct berval val;
5597         struct berval ad_name;
5598         AttributeDescription *ad = NULL;
5599         int rc;
5600         char *ptr;
5601         const char *text = "";
5602         Attribute *oc_at;
5603         struct berval pdn;
5604         ObjectClass *oc;
5605         CfEntryInfo *ceprev = NULL;
5606
5607         Debug( LDAP_DEBUG_TRACE, "config_build_entry: \"%s\"\n", rdn->bv_val, 0, 0);
5608         e->e_private = ce;
5609         ce->ce_entry = e;
5610         ce->ce_type = main->co_type;
5611         ce->ce_parent = parent;
5612         if ( parent ) {
5613                 pdn = parent->ce_entry->e_nname;
5614                 if ( parent->ce_kids && parent->ce_kids->ce_type <= ce->ce_type )
5615                         for ( ceprev = parent->ce_kids; ceprev->ce_sibs &&
5616                                 ceprev->ce_type <= ce->ce_type;
5617                                 ceprev = ceprev->ce_sibs );
5618         } else {
5619                 BER_BVZERO( &pdn );
5620         }
5621
5622         ce->ce_private = c->ca_private;
5623         ce->ce_be = c->be;
5624         ce->ce_bi = c->bi;
5625
5626         build_new_dn( &e->e_name, &pdn, rdn, NULL );
5627         ber_dupbv( &e->e_nname, &e->e_name );
5628
5629         attr_merge_normalize_one(e, slap_schema.si_ad_objectClass,
5630                 main->co_name, NULL );
5631         if ( extra )
5632                 attr_merge_normalize_one(e, slap_schema.si_ad_objectClass,
5633                         extra->co_name, NULL );
5634         ptr = strchr(rdn->bv_val, '=');
5635         ad_name.bv_val = rdn->bv_val;
5636         ad_name.bv_len = ptr - rdn->bv_val;
5637         rc = slap_bv2ad( &ad_name, &ad, &text );
5638         if ( rc ) {
5639                 goto fail;
5640         }
5641         val.bv_val = ptr+1;
5642         val.bv_len = rdn->bv_len - (val.bv_val - rdn->bv_val);
5643         attr_merge_normalize_one(e, ad, &val, NULL );
5644
5645         oc = main->co_oc;
5646         c->table = main->co_type;
5647         if ( oc->soc_required ) {
5648                 rc = config_build_attrs( e, oc->soc_required, ad, main->co_table, c );
5649                 if ( rc ) goto fail;
5650         }
5651
5652         if ( oc->soc_allowed ) {
5653                 rc = config_build_attrs( e, oc->soc_allowed, ad, main->co_table, c );
5654                 if ( rc ) goto fail;
5655         }
5656
5657         if ( extra ) {
5658                 oc = extra->co_oc;
5659                 c->table = extra->co_type;
5660                 if ( oc->soc_required ) {
5661                         rc = config_build_attrs( e, oc->soc_required, ad, extra->co_table, c );
5662                         if ( rc ) goto fail;
5663                 }
5664
5665                 if ( oc->soc_allowed ) {
5666                         rc = config_build_attrs( e, oc->soc_allowed, ad, extra->co_table, c );
5667                         if ( rc ) goto fail;
5668                 }
5669         }
5670
5671         oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
5672         rc = structural_class(oc_at->a_vals, &oc, NULL, &text, c->cr_msg,
5673                 sizeof(c->cr_msg), op ? op->o_tmpmemctx : NULL );
5674         if ( rc != LDAP_SUCCESS ) {
5675 fail:
5676                 Debug( LDAP_DEBUG_ANY,
5677                         "config_build_entry: build \"%s\" failed: \"%s\"\n",
5678                         rdn->bv_val, text, 0);
5679                 return NULL;
5680         }
5681         attr_merge_normalize_one(e, slap_schema.si_ad_structuralObjectClass, &oc->soc_cname, NULL );
5682         if ( op ) {
5683                 op->ora_e = e;
5684                 op->ora_modlist = NULL;
5685                 slap_add_opattrs( op, NULL, NULL, 0, 0 );
5686                 if ( !op->o_noop ) {
5687                         op->o_bd->be_add( op, rs );
5688                         if ( ( rs->sr_err != LDAP_SUCCESS ) 
5689                                         && (rs->sr_err != LDAP_ALREADY_EXISTS) ) {
5690                                 goto fail;
5691                         }
5692                 }
5693         }
5694         if ( ceprev ) {
5695                 ce->ce_sibs = ceprev->ce_sibs;
5696                 ceprev->ce_sibs = ce;
5697         } else if ( parent ) {
5698                 ce->ce_sibs = parent->ce_kids;
5699                 parent->ce_kids = ce;
5700         }
5701
5702         return e;
5703 }
5704
5705 static int
5706 config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent,
5707         Operation *op, SlapReply *rs )
5708 {
5709         Entry *e;
5710         ConfigFile *cf = c->ca_private;
5711         char *ptr;
5712         struct berval bv, rdn;
5713
5714         for (; cf; cf=cf->c_sibs, c->depth++) {
5715                 if ( !cf->c_at_head && !cf->c_cr_head && !cf->c_oc_head &&
5716                         !cf->c_om_head && !cf->c_syn_head ) continue;
5717                 c->value_dn.bv_val = c->log;
5718                 LUTIL_SLASHPATH( cf->c_file.bv_val );
5719                 bv.bv_val = strrchr(cf->c_file.bv_val, LDAP_DIRSEP[0]);
5720                 if ( !bv.bv_val ) {
5721                         bv = cf->c_file;
5722                 } else {
5723                         bv.bv_val++;
5724                         bv.bv_len = cf->c_file.bv_len - (bv.bv_val - cf->c_file.bv_val);
5725                 }
5726                 ptr = strchr( bv.bv_val, '.' );
5727                 if ( ptr )
5728                         bv.bv_len = ptr - bv.bv_val;
5729                 c->value_dn.bv_len = snprintf(c->value_dn.bv_val, sizeof( c->log ), "cn=" SLAP_X_ORDERED_FMT, c->depth);
5730                 if ( c->value_dn.bv_len >= sizeof( c->log ) ) {
5731                         /* FIXME: how can indicate error? */
5732                         return -1;
5733                 }
5734                 strncpy( c->value_dn.bv_val + c->value_dn.bv_len, bv.bv_val,
5735                         bv.bv_len );
5736                 c->value_dn.bv_len += bv.bv_len;
5737                 c->value_dn.bv_val[c->value_dn.bv_len] ='\0';
5738                 rdn = c->value_dn;
5739
5740                 c->ca_private = cf;
5741                 e = config_build_entry( op, rs, ceparent, c, &rdn,
5742                         &CFOC_SCHEMA, NULL );
5743                 if ( !e ) {
5744                         return -1;
5745                 } else if ( e && cf->c_kids ) {
5746                         c->ca_private = cf->c_kids;
5747                         config_build_schema_inc( c, e->e_private, op, rs );
5748                 }
5749         }
5750         return 0;
5751 }
5752
5753 #ifdef SLAPD_MODULES
5754
5755 static int
5756 config_build_modules( ConfigArgs *c, CfEntryInfo *ceparent,
5757         Operation *op, SlapReply *rs )
5758 {
5759         int i;
5760         ModPaths *mp;
5761
5762         for (i=0, mp=&modpaths; mp; mp=mp->mp_next, i++) {
5763                 if ( BER_BVISNULL( &mp->mp_path ) && !mp->mp_loads )
5764                         continue;
5765                 c->value_dn.bv_val = c->log;
5766                 c->value_dn.bv_len = snprintf(c->value_dn.bv_val, sizeof( c->log ), "cn=module" SLAP_X_ORDERED_FMT, i);
5767                 if ( c->value_dn.bv_len >= sizeof( c->log ) ) {
5768                         /* FIXME: how can indicate error? */
5769                         return -1;
5770                 }
5771                 c->ca_private = mp;
5772                 if ( ! config_build_entry( op, rs, ceparent, c, &c->value_dn, &CFOC_MODULE, NULL )) {
5773                         return -1;
5774                 }
5775         }
5776         return 0;
5777 }
5778 #endif
5779
5780 static int
5781 config_check_schema(Operation *op, CfBackInfo *cfb)
5782 {
5783         struct berval schema_dn = BER_BVC(SCHEMA_RDN "," CONFIG_RDN);
5784         ConfigArgs c = {0};
5785         CfEntryInfo *ce, *last;
5786         Entry *e;
5787
5788         /* If there's no root entry, we must be in the midst of converting */
5789         if ( !cfb->cb_root )
5790                 return 0;
5791
5792         /* Make sure the main schema entry exists */
5793         ce = config_find_base( cfb->cb_root, &schema_dn, &last );
5794         if ( ce ) {
5795                 Attribute *a;
5796                 struct berval *bv;
5797
5798                 e = ce->ce_entry;
5799
5800                 /* Make sure it's up to date */
5801                 if ( cf_om_tail != om_sys_tail ) {
5802                         a = attr_find( e->e_attrs, cfAd_om );
5803                         if ( a ) {
5804                                 if ( a->a_nvals != a->a_vals )
5805                                         ber_bvarray_free( a->a_nvals );
5806                                 ber_bvarray_free( a->a_vals );
5807                                 a->a_vals = NULL;
5808                                 a->a_nvals = NULL;
5809                                 a->a_numvals = 0;
5810                         }
5811                         oidm_unparse( &bv, NULL, NULL, 1 );
5812                         attr_merge_normalize( e, cfAd_om, bv, NULL );
5813                         ber_bvarray_free( bv );
5814                         cf_om_tail = om_sys_tail;
5815                 }
5816                 if ( cf_at_tail != at_sys_tail ) {
5817                         a = attr_find( e->e_attrs, cfAd_attr );
5818                         if ( a ) {
5819                                 if ( a->a_nvals != a->a_vals )
5820                                         ber_bvarray_free( a->a_nvals );
5821                                 ber_bvarray_free( a->a_vals );
5822                                 a->a_vals = NULL;
5823                                 a->a_nvals = NULL;
5824                                 a->a_numvals = 0;
5825                         }
5826                         at_unparse( &bv, NULL, NULL, 1 );
5827                         attr_merge_normalize( e, cfAd_attr, bv, NULL );
5828                         ber_bvarray_free( bv );
5829                         cf_at_tail = at_sys_tail;
5830                 }
5831                 if ( cf_oc_tail != oc_sys_tail ) {
5832                         a = attr_find( e->e_attrs, cfAd_oc );
5833                         if ( a ) {
5834                                 if ( a->a_nvals != a->a_vals )
5835                                         ber_bvarray_free( a->a_nvals );
5836                                 ber_bvarray_free( a->a_vals );
5837                                 a->a_vals = NULL;
5838                                 a->a_nvals = NULL;
5839                                 a->a_numvals = 0;
5840                         }
5841                         oc_unparse( &bv, NULL, NULL, 1 );
5842                         attr_merge_normalize( e, cfAd_oc, bv, NULL );
5843                         ber_bvarray_free( bv );
5844                         cf_oc_tail = oc_sys_tail;
5845                 }
5846                 if ( cf_syn_tail != syn_sys_tail ) {
5847                         a = attr_find( e->e_attrs, cfAd_syntax );
5848                         if ( a ) {
5849                                 if ( a->a_nvals != a->a_vals )
5850                                         ber_bvarray_free( a->a_nvals );
5851                                 ber_bvarray_free( a->a_vals );
5852                                 a->a_vals = NULL;
5853                                 a->a_nvals = NULL;
5854                                 a->a_numvals = 0;
5855                         }
5856                         syn_unparse( &bv, NULL, NULL, 1 );
5857                         attr_merge_normalize( e, cfAd_syntax, bv, NULL );
5858                         ber_bvarray_free( bv );
5859                         cf_syn_tail = syn_sys_tail;
5860                 }
5861         } else {
5862                 SlapReply rs = {REP_RESULT};
5863                 c.ca_private = NULL;
5864                 e = config_build_entry( op, &rs, cfb->cb_root, &c, &schema_rdn,
5865                         &CFOC_SCHEMA, NULL );
5866                 if ( !e ) {
5867                         return -1;
5868                 }
5869                 ce = e->e_private;
5870                 ce->ce_private = cfb->cb_config;
5871                 cf_at_tail = at_sys_tail;
5872                 cf_oc_tail = oc_sys_tail;
5873                 cf_om_tail = om_sys_tail;
5874                 cf_syn_tail = syn_sys_tail;
5875         }
5876         return 0;
5877 }
5878
5879 static const char *defacl[] = {
5880         NULL, "to", "*", "by", "*", "none", NULL
5881 };
5882
5883 static int
5884 config_back_db_open( BackendDB *be, ConfigReply *cr )
5885 {
5886         CfBackInfo *cfb = be->be_private;
5887         struct berval rdn;
5888         Entry *e, *parent;
5889         CfEntryInfo *ce, *ceparent;
5890         int i, unsupp = 0;
5891         BackendInfo *bi;
5892         ConfigArgs c;
5893         Connection conn = {0};
5894         OperationBuffer opbuf;
5895         Operation *op;
5896         slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
5897         SlapReply rs = {REP_RESULT};
5898         void *thrctx = NULL;
5899
5900         Debug( LDAP_DEBUG_TRACE, "config_back_db_open\n", 0, 0, 0);
5901
5902         /* If we have no explicitly configured ACLs, don't just use
5903          * the global ACLs. Explicitly deny access to everything.
5904          */
5905         if ( frontendDB->be_acl && be->be_acl == frontendDB->be_acl ) {
5906                 parse_acl(be, "config_back_db_open", 0, 6, (char **)defacl, 0 );
5907         }
5908
5909         thrctx = ldap_pvt_thread_pool_context();
5910         connection_fake_init( &conn, &opbuf, thrctx );
5911         op = &opbuf.ob_op;
5912
5913         op->o_tag = LDAP_REQ_ADD;
5914         op->o_callback = &cb;
5915         op->o_bd = &cfb->cb_db;
5916         op->o_dn = op->o_bd->be_rootdn;
5917         op->o_ndn = op->o_bd->be_rootndn;
5918
5919         if ( !cfb->cb_use_ldif ) {
5920                 op->o_noop = 1;
5921         }
5922
5923         /* If we read the config from back-ldif, do some quick sanity checks */
5924         if ( cfb->cb_got_ldif ) {
5925                 return config_check_schema( op, cfb );
5926         }
5927
5928         /* create root of tree */
5929         rdn = config_rdn;
5930         c.ca_private = cfb->cb_config;
5931         c.be = frontendDB;
5932         e = config_build_entry( op, &rs, NULL, &c, &rdn, &CFOC_GLOBAL, NULL );
5933         if ( !e ) {
5934                 return -1;
5935         }
5936         ce = e->e_private;
5937         cfb->cb_root = ce;
5938
5939         parent = e;
5940         ceparent = ce;
5941
5942 #ifdef SLAPD_MODULES
5943         /* Create Module nodes... */
5944         if ( modpaths.mp_loads ) {
5945                 if ( config_build_modules( &c, ceparent, op, &rs ) ){
5946                         return -1;
5947                 }
5948         }
5949 #endif
5950
5951         /* Create schema nodes... cn=schema will contain the hardcoded core
5952          * schema, read-only. Child objects will contain runtime loaded schema
5953          * files.
5954          */
5955         rdn = schema_rdn;
5956         c.ca_private = NULL;
5957         e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_SCHEMA, NULL );
5958         if ( !e ) {
5959                 return -1;
5960         }
5961         ce = e->e_private;
5962         ce->ce_private = cfb->cb_config;
5963         cf_at_tail = at_sys_tail;
5964         cf_oc_tail = oc_sys_tail;
5965         cf_om_tail = om_sys_tail;
5966         cf_syn_tail = syn_sys_tail;
5967
5968         /* Create schema nodes for included schema... */
5969         if ( cfb->cb_config->c_kids ) {
5970                 c.depth = 0;
5971                 c.ca_private = cfb->cb_config->c_kids;
5972                 if (config_build_schema_inc( &c, ce, op, &rs )) {
5973                         return -1;
5974                 }
5975         }
5976
5977         /* Create backend nodes. Skip if they don't provide a cf_table.
5978          * There usually aren't any of these.
5979          */
5980         
5981         c.line = 0;
5982         LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next) {
5983                 if (!bi->bi_cf_ocs) {
5984                         /* If it only supports the old config mech, complain. */
5985                         if ( bi->bi_config ) {
5986                                 Debug( LDAP_DEBUG_ANY,
5987                                         "WARNING: No dynamic config support for backend %s.\n",
5988                                         bi->bi_type, 0, 0 );
5989                                 unsupp++;
5990                         }
5991                         continue;
5992                 }
5993                 if (!bi->bi_private) continue;
5994
5995                 rdn.bv_val = c.log;
5996                 rdn.bv_len = snprintf(rdn.bv_val, sizeof( c.log ),
5997                         "%s=%s", cfAd_backend->ad_cname.bv_val, bi->bi_type);
5998                 if ( rdn.bv_len >= sizeof( c.log ) ) {
5999                         /* FIXME: holler ... */ ;
6000                 }
6001                 c.bi = bi;
6002                 e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_BACKEND,
6003                         bi->bi_cf_ocs );
6004                 if ( !e ) {
6005                         return -1;
6006                 }
6007         }
6008
6009         /* Create database nodes... */
6010         frontendDB->be_cf_ocs = &CFOC_FRONTEND;
6011         LDAP_STAILQ_NEXT(frontendDB, be_next) = LDAP_STAILQ_FIRST(&backendDB);
6012         for ( i = -1, be = frontendDB ; be;
6013                 i++, be = LDAP_STAILQ_NEXT( be, be_next )) {
6014                 slap_overinfo *oi = NULL;
6015
6016                 if ( overlay_is_over( be )) {
6017                         oi = be->bd_info->bi_private;
6018                         bi = oi->oi_orig;
6019                 } else {
6020                         bi = be->bd_info;
6021                 }
6022
6023                 /* If this backend supports the old config mechanism, but not
6024                  * the new mech, complain.
6025                  */
6026                 if ( !be->be_cf_ocs && bi->bi_db_config ) {
6027                         Debug( LDAP_DEBUG_ANY,
6028                                 "WARNING: No dynamic config support for database %s.\n",
6029                                 bi->bi_type, 0, 0 );
6030                         unsupp++;
6031                 }
6032                 rdn.bv_val = c.log;
6033                 rdn.bv_len = snprintf(rdn.bv_val, sizeof( c.log ),
6034                         "%s=" SLAP_X_ORDERED_FMT "%s", cfAd_database->ad_cname.bv_val,
6035                         i, bi->bi_type);
6036                 if ( rdn.bv_len >= sizeof( c.log ) ) {
6037                         /* FIXME: holler ... */ ;
6038                 }
6039                 c.be = be;
6040                 c.bi = bi;
6041                 e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_DATABASE,
6042                         be->be_cf_ocs );
6043                 if ( !e ) {
6044                         return -1;
6045                 }
6046                 ce = e->e_private;
6047                 if ( be->be_cf_ocs && be->be_cf_ocs->co_cfadd )
6048                         be->be_cf_ocs->co_cfadd( op, &rs, e, &c );
6049                 /* Iterate through overlays */
6050                 if ( oi ) {
6051                         slap_overinst *on;
6052                         Entry *oe;
6053                         int j;
6054                         voidList *vl, *v0 = NULL;
6055
6056                         /* overlays are in LIFO order, must reverse stack */
6057                         for (on=oi->oi_list; on; on=on->on_next) {
6058                                 vl = ch_malloc( sizeof( voidList ));
6059                                 vl->vl_next = v0;
6060                                 v0 = vl;
6061                                 vl->vl_ptr = on;
6062                         }
6063                         for (j=0; vl; j++,vl=v0) {
6064                                 on = vl->vl_ptr;
6065                                 v0 = vl->vl_next;
6066                                 ch_free( vl );
6067                                 if ( on->on_bi.bi_db_config && !on->on_bi.bi_cf_ocs ) {
6068                                         Debug( LDAP_DEBUG_ANY,
6069                                                 "WARNING: No dynamic config support for overlay %s.\n",
6070                                                 on->on_bi.bi_type, 0, 0 );
6071                                         unsupp++;
6072                                 }
6073                                 rdn.bv_val = c.log;
6074                                 rdn.bv_len = snprintf(rdn.bv_val, sizeof( c.log ),
6075                                         "%s=" SLAP_X_ORDERED_FMT "%s",
6076                                         cfAd_overlay->ad_cname.bv_val, j, on->on_bi.bi_type );
6077                                 if ( rdn.bv_len >= sizeof( c.log ) ) {
6078                                         /* FIXME: holler ... */ ;
6079                                 }
6080                                 c.be = be;
6081                                 c.bi = &on->on_bi;
6082                                 oe = config_build_entry( op, &rs, ce, &c, &rdn,
6083                                         &CFOC_OVERLAY, c.bi->bi_cf_ocs );
6084                                 if ( !oe ) {
6085                                         return -1;
6086                                 }
6087                                 if ( c.bi->bi_cf_ocs && c.bi->bi_cf_ocs->co_cfadd )
6088                                         c.bi->bi_cf_ocs->co_cfadd( op, &rs, oe, &c );
6089                         }
6090                 }
6091         }
6092         if ( thrctx )
6093                 ldap_pvt_thread_pool_context_reset( thrctx );
6094
6095         if ( unsupp  && cfb->cb_use_ldif ) {
6096                 Debug( LDAP_DEBUG_ANY, "\nWARNING: The converted cn=config "
6097                         "directory is incomplete and may not work.\n\n", 0, 0, 0 );
6098         }
6099
6100         return 0;
6101 }
6102
6103 static void
6104 cfb_free_cffile( ConfigFile *cf )
6105 {
6106         ConfigFile *next;
6107
6108         for (; cf; cf=next) {
6109                 next = cf->c_sibs;
6110                 if ( cf->c_kids )
6111                         cfb_free_cffile( cf->c_kids );
6112                 ch_free( cf->c_file.bv_val );
6113                 ber_bvarray_free( cf->c_dseFiles );
6114                 ch_free( cf );
6115         }
6116 }
6117
6118 static void
6119 cfb_free_entries( CfEntryInfo *ce )
6120 {
6121         CfEntryInfo *next;
6122
6123         for (; ce; ce=next) {
6124                 next = ce->ce_sibs;
6125                 if ( ce->ce_kids )
6126                         cfb_free_entries( ce->ce_kids );
6127                 ce->ce_entry->e_private = NULL;
6128                 entry_free( ce->ce_entry );
6129                 ch_free( ce );
6130         }
6131 }
6132
6133 static int
6134 config_back_db_close( BackendDB *be, ConfigReply *cr )
6135 {
6136         CfBackInfo *cfb = be->be_private;
6137
6138         cfb_free_entries( cfb->cb_root );
6139         cfb->cb_root = NULL;
6140
6141         if ( cfb->cb_db.bd_info ) {
6142                 backend_shutdown( &cfb->cb_db );
6143         }
6144
6145         return 0;
6146 }
6147
6148 static int
6149 config_back_db_destroy( BackendDB *be, ConfigReply *cr )
6150 {
6151         CfBackInfo *cfb = be->be_private;
6152
6153         cfb_free_cffile( cfb->cb_config );
6154
6155         ch_free( cfdir.bv_val );
6156
6157         avl_free( CfOcTree, NULL );
6158
6159         if ( cfb->cb_db.bd_info ) {
6160                 cfb->cb_db.be_suffix = NULL;
6161                 cfb->cb_db.be_nsuffix = NULL;
6162                 BER_BVZERO( &cfb->cb_db.be_rootdn );
6163                 BER_BVZERO( &cfb->cb_db.be_rootndn );
6164
6165                 backend_destroy_one( &cfb->cb_db, 0 );
6166         }
6167
6168         loglevel_destroy();
6169
6170         return 0;
6171 }
6172
6173 static int
6174 config_back_db_init( BackendDB *be, ConfigReply* cr )
6175 {
6176         struct berval dn;
6177         CfBackInfo *cfb;
6178
6179         cfb = &cfBackInfo;
6180         cfb->cb_config = ch_calloc( 1, sizeof(ConfigFile));
6181         cfn = cfb->cb_config;
6182         be->be_private = cfb;
6183
6184         ber_dupbv( &be->be_rootdn, &config_rdn );
6185         ber_dupbv( &be->be_rootndn, &be->be_rootdn );
6186         ber_dupbv( &dn, &be->be_rootdn );
6187         ber_bvarray_add( &be->be_suffix, &dn );
6188         ber_dupbv( &dn, &be->be_rootdn );
6189         ber_bvarray_add( &be->be_nsuffix, &dn );
6190
6191         /* Hide from namingContexts */
6192         SLAP_BFLAGS(be) |= SLAP_BFLAG_CONFIG;
6193
6194         return 0;
6195 }
6196
6197 static int
6198 config_back_destroy( BackendInfo *bi )
6199 {
6200         ldif_must_b64_encode_release();
6201         return 0;
6202 }
6203
6204 static int
6205 config_tool_entry_open( BackendDB *be, int mode )
6206 {
6207         CfBackInfo *cfb = be->be_private;
6208         BackendInfo *bi = cfb->cb_db.bd_info;
6209
6210         if ( bi && bi->bi_tool_entry_open )
6211                 return bi->bi_tool_entry_open( &cfb->cb_db, mode );
6212         else
6213                 return -1;
6214         
6215 }
6216
6217 static int
6218 config_tool_entry_close( BackendDB *be )
6219 {
6220         CfBackInfo *cfb = be->be_private;
6221         BackendInfo *bi = cfb->cb_db.bd_info;
6222
6223         if ( bi && bi->bi_tool_entry_close )
6224                 return bi->bi_tool_entry_close( &cfb->cb_db );
6225         else
6226                 return -1;
6227 }
6228
6229 static ID
6230 config_tool_entry_first( BackendDB *be )
6231 {
6232         CfBackInfo *cfb = be->be_private;
6233         BackendInfo *bi = cfb->cb_db.bd_info;
6234
6235         if ( bi && bi->bi_tool_entry_first )
6236                 return bi->bi_tool_entry_first( &cfb->cb_db );
6237         else
6238                 return NOID;
6239 }
6240
6241 static ID
6242 config_tool_entry_next( BackendDB *be )
6243 {
6244         CfBackInfo *cfb = be->be_private;
6245         BackendInfo *bi = cfb->cb_db.bd_info;
6246
6247         if ( bi && bi->bi_tool_entry_next )
6248                 return bi->bi_tool_entry_next( &cfb->cb_db );
6249         else
6250                 return NOID;
6251 }
6252
6253 static Entry *
6254 config_tool_entry_get( BackendDB *be, ID id )
6255 {
6256         CfBackInfo *cfb = be->be_private;
6257         BackendInfo *bi = cfb->cb_db.bd_info;
6258
6259         if ( bi && bi->bi_tool_entry_get )
6260                 return bi->bi_tool_entry_get( &cfb->cb_db, id );
6261         else
6262                 return NULL;
6263 }
6264
6265 static int entry_put_got_frontend=0;
6266 static int entry_put_got_config=0;
6267 static ID
6268 config_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
6269 {
6270         CfBackInfo *cfb = be->be_private;
6271         BackendInfo *bi = cfb->cb_db.bd_info;
6272         int rc;
6273         struct berval rdn, vals[ 2 ];
6274         ConfigArgs ca;
6275         OperationBuffer opbuf;
6276         Entry *ce;
6277         Connection conn = {0};
6278         Operation *op = NULL;
6279         void *thrctx;
6280         int isFrontend = 0;
6281
6282         /* Create entry for frontend database if it does not exist already */
6283         if ( !entry_put_got_frontend ) {
6284                 if ( !strncmp( e->e_nname.bv_val, "olcDatabase", 
6285                                 STRLENOF( "olcDatabase" ))) {
6286                         if ( strncmp( e->e_nname.bv_val + 
6287                                         STRLENOF( "olcDatabase" ), "={-1}frontend",
6288                                         STRLENOF( "={-1}frontend" )) && 
6289                                         strncmp( e->e_nname.bv_val + 
6290                                         STRLENOF( "olcDatabase" ), "=frontend",
6291                                         STRLENOF( "=frontend" ))) {
6292                                 vals[1].bv_len = 0;
6293                                 vals[1].bv_val = NULL;
6294                                 memset( &ca, 0, sizeof(ConfigArgs));
6295                                 ca.be = frontendDB;
6296                                 ca.bi = frontendDB->bd_info;
6297                                 ca.be->be_cf_ocs = &CFOC_FRONTEND;
6298                                 rdn.bv_val = ca.log;
6299                                 rdn.bv_len = snprintf(rdn.bv_val, sizeof( ca.log ),
6300                                         "%s=" SLAP_X_ORDERED_FMT "%s",
6301                                         cfAd_database->ad_cname.bv_val, -1,
6302                                         ca.bi->bi_type);
6303                                 ce = config_build_entry( NULL, NULL, cfb->cb_root, &ca, &rdn,
6304                                                 &CFOC_DATABASE, ca.be->be_cf_ocs );
6305                                 thrctx = ldap_pvt_thread_pool_context();
6306                                 connection_fake_init2( &conn, &opbuf, thrctx,0 );
6307                                 op = &opbuf.ob_op;
6308                                 op->o_bd = &cfb->cb_db;
6309                                 op->o_tag = LDAP_REQ_ADD;
6310                                 op->ora_e = ce;
6311                                 op->o_dn = be->be_rootdn;
6312                                 op->o_ndn = be->be_rootndn;
6313                                 rc = slap_add_opattrs(op, NULL, NULL, 0, 0);
6314                                 if ( rc != LDAP_SUCCESS ) {
6315                                         text->bv_val = "autocreation of \"olcDatabase={-1}frontend\" failed";
6316                                         text->bv_len = STRLENOF("autocreation of \"olcDatabase={-1}frontend\" failed");
6317                                         return NOID;
6318                                 }
6319
6320                                 if ( ce && bi && bi->bi_tool_entry_put && 
6321                                                 bi->bi_tool_entry_put( &cfb->cb_db, ce, text ) != NOID ) {
6322                                         entry_put_got_frontend++;
6323                                 } else {
6324                                         text->bv_val = "autocreation of \"olcDatabase={-1}frontend\" failed";
6325                                         text->bv_len = STRLENOF("autocreation of \"olcDatabase={-1}frontend\" failed");
6326                                         return NOID;
6327                                 }
6328                         } else {
6329                                 entry_put_got_frontend++;
6330                                 isFrontend = 1;
6331                         }
6332                 }
6333         }
6334         /* Create entry for config database if it does not exist already */
6335         if ( !entry_put_got_config && !isFrontend ) {
6336                 if ( !strncmp( e->e_nname.bv_val, "olcDatabase",
6337                                 STRLENOF( "olcDatabase" ))) {
6338                         if ( strncmp( e->e_nname.bv_val +
6339                                         STRLENOF( "olcDatabase" ), "={0}config",
6340                                         STRLENOF( "={0}config" )) &&
6341                                         strncmp( e->e_nname.bv_val +
6342                                         STRLENOF( "olcDatabase" ), "=config",
6343                                         STRLENOF( "=config" )) ) {
6344                                 vals[1].bv_len = 0;
6345                                 vals[1].bv_val = NULL;
6346                                 memset( &ca, 0, sizeof(ConfigArgs));
6347                                 ca.be = LDAP_STAILQ_FIRST( &backendDB );
6348                                 ca.bi = ca.be->bd_info;
6349                                 rdn.bv_val = ca.log;
6350                                 rdn.bv_len = snprintf(rdn.bv_val, sizeof( ca.log ),
6351                                         "%s=" SLAP_X_ORDERED_FMT "%s",
6352                                         cfAd_database->ad_cname.bv_val, 0,
6353                                         ca.bi->bi_type);
6354                                 ce = config_build_entry( NULL, NULL, cfb->cb_root, &ca, &rdn, &CFOC_DATABASE,
6355                                                 ca.be->be_cf_ocs );
6356                                 if ( ! op ) {
6357                                         thrctx = ldap_pvt_thread_pool_context();
6358                                         connection_fake_init2( &conn, &opbuf, thrctx,0 );
6359                                         op = &opbuf.ob_op;
6360                                         op->o_bd = &cfb->cb_db;
6361                                         op->o_tag = LDAP_REQ_ADD;
6362                                         op->o_dn = be->be_rootdn;
6363                                         op->o_ndn = be->be_rootndn;
6364                                 }
6365                                 op->ora_e = ce;
6366                                 rc = slap_add_opattrs(op, NULL, NULL, 0, 0);
6367                                 if ( rc != LDAP_SUCCESS ) {
6368                                         text->bv_val = "autocreation of \"olcDatabase={0}config\" failed";
6369                                         text->bv_len = STRLENOF("autocreation of \"olcDatabase={0}config\" failed");
6370                                         return NOID;
6371                                 }
6372                                 if (ce && bi && bi->bi_tool_entry_put &&
6373                                                 bi->bi_tool_entry_put( &cfb->cb_db, ce, text ) != NOID ) {
6374                                         entry_put_got_config++;
6375                                 } else {
6376                                         text->bv_val = "autocreation of \"olcDatabase={0}config\" failed";
6377                                         text->bv_len = STRLENOF("autocreation of \"olcDatabase={0}config\" failed");
6378                                         return NOID;
6379                                 }
6380                         } else {
6381                                 entry_put_got_config++;
6382                         }
6383                 }
6384         }
6385         if ( bi && bi->bi_tool_entry_put &&
6386                 config_add_internal( cfb, e, &ca, NULL, NULL, NULL ) == 0 )
6387                 return bi->bi_tool_entry_put( &cfb->cb_db, e, text );
6388         else
6389                 return NOID;
6390 }
6391
6392 static struct {
6393         char *name;
6394         AttributeDescription **desc;
6395 } ads[] = {
6396         { "attribute", &cfAd_attr },
6397         { "backend", &cfAd_backend },
6398         { "database", &cfAd_database },
6399         { "include", &cfAd_include },
6400         { "ldapsyntax", &cfAd_syntax },
6401         { "objectclass", &cfAd_oc },
6402         { "objectidentifier", &cfAd_om },
6403         { "overlay", &cfAd_overlay },
6404         { NULL, NULL }
6405 };
6406
6407 /* Notes:
6408  *   add / delete: all types that may be added or deleted must use an
6409  * X-ORDERED attributeType for their RDN. Adding and deleting entries
6410  * should automatically renumber the index of any siblings as needed,
6411  * so that no gaps in the numbering sequence exist after the add/delete
6412  * is completed.
6413  *   What can be added:
6414  *     schema objects
6415  *     backend objects for backend-specific config directives
6416  *     database objects
6417  *     overlay objects
6418  *
6419  *   delete: probably no support this time around.
6420  *
6421  *   modrdn: generally not done. Will be invoked automatically by add/
6422  * delete to update numbering sequence. Perform as an explicit operation
6423  * so that the renumbering effect may be replicated. Subtree rename must
6424  * be supported, since renumbering a database will affect all its child
6425  * overlays.
6426  *
6427  *  modify: must be fully supported. 
6428  */
6429
6430 int
6431 config_back_initialize( BackendInfo *bi )
6432 {
6433         ConfigTable             *ct = config_back_cf_table;
6434         ConfigArgs ca;
6435         char                    *argv[4];
6436         int                     i;
6437         AttributeDescription    *ad = NULL;
6438         const char              *text;
6439         static char             *controls[] = {
6440                 LDAP_CONTROL_MANAGEDSAIT,
6441                 NULL
6442         };
6443
6444         /* Make sure we don't exceed the bits reserved for userland */
6445         config_check_userland( CFG_LAST );
6446
6447         bi->bi_controls = controls;
6448
6449         bi->bi_open = 0;
6450         bi->bi_close = 0;
6451         bi->bi_config = 0;
6452         bi->bi_destroy = config_back_destroy;
6453
6454         bi->bi_db_init = config_back_db_init;
6455         bi->bi_db_config = 0;
6456         bi->bi_db_open = config_back_db_open;
6457         bi->bi_db_close = config_back_db_close;
6458         bi->bi_db_destroy = config_back_db_destroy;
6459
6460         bi->bi_op_bind = config_back_bind;
6461         bi->bi_op_unbind = 0;
6462         bi->bi_op_search = config_back_search;
6463         bi->bi_op_compare = 0;
6464         bi->bi_op_modify = config_back_modify;
6465         bi->bi_op_modrdn = config_back_modrdn;
6466         bi->bi_op_add = config_back_add;
6467         bi->bi_op_delete = config_back_delete;
6468         bi->bi_op_abandon = 0;
6469
6470         bi->bi_extended = 0;
6471
6472         bi->bi_chk_referrals = 0;
6473
6474         bi->bi_access_allowed = slap_access_allowed;
6475
6476         bi->bi_connection_init = 0;
6477         bi->bi_connection_destroy = 0;
6478
6479         bi->bi_entry_release_rw = config_entry_release;
6480         bi->bi_entry_get_rw = config_back_entry_get;
6481
6482         bi->bi_tool_entry_open = config_tool_entry_open;
6483         bi->bi_tool_entry_close = config_tool_entry_close;
6484         bi->bi_tool_entry_first = config_tool_entry_first;
6485         bi->bi_tool_entry_next = config_tool_entry_next;
6486         bi->bi_tool_entry_get = config_tool_entry_get;
6487         bi->bi_tool_entry_put = config_tool_entry_put;
6488
6489         ca.argv = argv;
6490         argv[ 0 ] = "slapd";
6491         ca.argv = argv;
6492         ca.argc = 3;
6493         ca.fname = argv[0];
6494
6495         argv[3] = NULL;
6496         for (i=0; OidMacros[i].name; i++ ) {
6497                 argv[1] = OidMacros[i].name;
6498                 argv[2] = OidMacros[i].oid;
6499                 parse_oidm( &ca, 0, NULL );
6500         }
6501
6502         bi->bi_cf_ocs = cf_ocs;
6503
6504         i = config_register_schema( ct, cf_ocs );
6505         if ( i ) return i;
6506
6507         i = slap_str2ad( "olcDatabase", &olcDatabaseDummy[0].ad, &text );
6508         if ( i ) return i;
6509
6510         /* setup olcRootPW to be base64-encoded when written in LDIF form;
6511          * basically, we don't care if it fails */
6512         i = slap_str2ad( "olcRootPW", &ad, &text );
6513         if ( i ) {
6514                 Debug( LDAP_DEBUG_ANY, "config_back_initialize: "
6515                         "warning, unable to get \"olcRootPW\" "
6516                         "attribute description: %d: %s\n",
6517                         i, text, 0 );
6518         } else {
6519                 (void)ldif_must_b64_encode_register( ad->ad_cname.bv_val,
6520                         ad->ad_type->sat_oid );
6521         }
6522
6523         /* set up the notable AttributeDescriptions */
6524         i = 0;
6525         for (;ct->name;ct++) {
6526                 if (strcmp(ct->name, ads[i].name)) continue;
6527                 *ads[i].desc = ct->ad;
6528                 i++;
6529                 if (!ads[i].name) break;
6530         }
6531
6532         return 0;
6533 }
6534