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