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