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