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