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