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