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