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