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