Back to index

openldap  2.4.31
bconfig.c
Go to the documentation of this file.
00001 /* bconfig.c - the config backend */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2005-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS:
00017  * This work was originally developed by Howard Chu for inclusion
00018  * in OpenLDAP Software.
00019  */
00020 
00021 #include "portable.h"
00022 
00023 #include <stdio.h>
00024 #include <ac/string.h>
00025 #include <ac/ctype.h>
00026 #include <ac/errno.h>
00027 #include <sys/stat.h>
00028 #include <ac/unistd.h>
00029 
00030 #include "slap.h"
00031 
00032 #ifdef LDAP_SLAPI
00033 #include "slapi/slapi.h"
00034 #endif
00035 
00036 #include <ldif.h>
00037 #include <lutil.h>
00038 
00039 #include "config.h"
00040 
00041 #define       CONFIG_RDN    "cn=config"
00042 #define       SCHEMA_RDN    "cn=schema"
00043 
00044 static struct berval config_rdn = BER_BVC(CONFIG_RDN);
00045 static struct berval schema_rdn = BER_BVC(SCHEMA_RDN);
00046 
00047 extern int slap_DN_strict;  /* dn.c */
00048 
00049 #ifdef SLAPD_MODULES
00050 typedef struct modpath_s {
00051        struct modpath_s *mp_next;
00052        struct berval mp_path;
00053        BerVarray mp_loads;
00054 } ModPaths;
00055 
00056 static ModPaths modpaths, *modlast = &modpaths, *modcur = &modpaths;
00057 #endif
00058 
00059 typedef struct ConfigFile {
00060        struct ConfigFile *c_sibs;
00061        struct ConfigFile *c_kids;
00062        struct berval c_file;
00063        AttributeType *c_at_head, *c_at_tail;
00064        ContentRule *c_cr_head, *c_cr_tail;
00065        ObjectClass *c_oc_head, *c_oc_tail;
00066        OidMacro *c_om_head, *c_om_tail;
00067        Syntax *c_syn_head, *c_syn_tail;
00068        BerVarray c_dseFiles;
00069 } ConfigFile;
00070 
00071 typedef struct {
00072        ConfigFile *cb_config;
00073        CfEntryInfo *cb_root;
00074        BackendDB     cb_db; /* underlying database */
00075        int           cb_got_ldif;
00076        int           cb_use_ldif;
00077 } CfBackInfo;
00078 
00079 static CfBackInfo cfBackInfo;
00080 
00081 static char   *passwd_salt;
00082 static FILE *logfile;
00083 static char   *logfileName;
00084 #ifdef SLAP_AUTH_REWRITE
00085 static BerVarray authz_rewrites;
00086 #endif
00087 static AccessControl *defacl_parsed = NULL;
00088 
00089 static struct berval cfdir;
00090 
00091 /* Private state */
00092 static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay,
00093        *cfAd_include, *cfAd_attr, *cfAd_oc, *cfAd_om, *cfAd_syntax;
00094 
00095 static ConfigFile *cfn;
00096 
00097 static Avlnode *CfOcTree;
00098 
00099 /* System schema state */
00100 extern AttributeType *at_sys_tail; /* at.c */
00101 extern ObjectClass *oc_sys_tail;   /* oc.c */
00102 extern OidMacro *om_sys_tail;      /* oidm.c */
00103 extern Syntax *syn_sys_tail;       /* syntax.c */
00104 static AttributeType *cf_at_tail;
00105 static ObjectClass *cf_oc_tail;
00106 static OidMacro *cf_om_tail;
00107 static Syntax *cf_syn_tail;
00108 
00109 static int config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca,
00110        SlapReply *rs, int *renumber, Operation *op );
00111 
00112 static int config_check_schema( Operation *op, CfBackInfo *cfb );
00113 
00114 static ConfigDriver config_fname;
00115 static ConfigDriver config_cfdir;
00116 static ConfigDriver config_generic;
00117 static ConfigDriver config_search_base;
00118 static ConfigDriver config_passwd_hash;
00119 static ConfigDriver config_schema_dn;
00120 static ConfigDriver config_sizelimit;
00121 static ConfigDriver config_timelimit;
00122 static ConfigDriver config_overlay;
00123 static ConfigDriver config_subordinate; 
00124 static ConfigDriver config_suffix; 
00125 #ifdef LDAP_TCP_BUFFER
00126 static ConfigDriver config_tcp_buffer; 
00127 #endif /* LDAP_TCP_BUFFER */
00128 static ConfigDriver config_rootdn;
00129 static ConfigDriver config_rootpw;
00130 static ConfigDriver config_restrict;
00131 static ConfigDriver config_allows;
00132 static ConfigDriver config_disallows;
00133 static ConfigDriver config_requires;
00134 static ConfigDriver config_security;
00135 static ConfigDriver config_referral;
00136 static ConfigDriver config_loglevel;
00137 static ConfigDriver config_updatedn;
00138 static ConfigDriver config_updateref;
00139 static ConfigDriver config_extra_attrs;
00140 static ConfigDriver config_include;
00141 static ConfigDriver config_obsolete;
00142 #ifdef HAVE_TLS
00143 static ConfigDriver config_tls_option;
00144 static ConfigDriver config_tls_config;
00145 #endif
00146 extern ConfigDriver syncrepl_config;
00147 
00148 enum {
00149        CFG_ACL = 1,
00150        CFG_BACKEND,
00151        CFG_DATABASE,
00152        CFG_TLS_RAND,
00153        CFG_TLS_CIPHER,
00154        CFG_TLS_PROTOCOL_MIN,
00155        CFG_TLS_CERT_FILE,
00156        CFG_TLS_CERT_KEY,
00157        CFG_TLS_CA_PATH,
00158        CFG_TLS_CA_FILE,
00159        CFG_TLS_DH_FILE,
00160        CFG_TLS_VERIFY,
00161        CFG_TLS_CRLCHECK,
00162        CFG_TLS_CRL_FILE,
00163        CFG_CONCUR,
00164        CFG_THREADS,
00165        CFG_SALT,
00166        CFG_LIMITS,
00167        CFG_RO,
00168        CFG_REWRITE,
00169        CFG_DEPTH,
00170        CFG_OID,
00171        CFG_OC,
00172        CFG_DIT,
00173        CFG_ATTR,
00174        CFG_ATOPT,
00175        CFG_ROOTDSE,
00176        CFG_LOGFILE,
00177        CFG_PLUGIN,
00178        CFG_MODLOAD,
00179        CFG_MODPATH,
00180        CFG_LASTMOD,
00181        CFG_AZPOLICY,
00182        CFG_AZREGEXP,
00183        CFG_SASLSECP,
00184        CFG_SSTR_IF_MAX,
00185        CFG_SSTR_IF_MIN,
00186        CFG_TTHREADS,
00187        CFG_MIRRORMODE,
00188        CFG_HIDDEN,
00189        CFG_MONITORING,
00190        CFG_SERVERID,
00191        CFG_SORTVALS,
00192        CFG_IX_INTLEN,
00193        CFG_SYNTAX,
00194        CFG_ACL_ADD,
00195        CFG_SYNC_SUBENTRY,
00196        CFG_LTHREADS,
00197 
00198        CFG_LAST
00199 };
00200 
00201 typedef struct {
00202        char *name, *oid;
00203 } OidRec;
00204 
00205 static OidRec OidMacros[] = {
00206        /* OpenLDAProot:1.12.2 */
00207        { "OLcfg", "1.3.6.1.4.1.4203.1.12.2" },
00208        { "OLcfgAt", "OLcfg:3" },
00209        { "OLcfgGlAt", "OLcfgAt:0" },
00210        { "OLcfgBkAt", "OLcfgAt:1" },
00211        { "OLcfgDbAt", "OLcfgAt:2" },
00212        { "OLcfgOvAt", "OLcfgAt:3" },
00213        { "OLcfgCtAt", "OLcfgAt:4" },      /* contrib modules */
00214        { "OLcfgOc", "OLcfg:4" },
00215        { "OLcfgGlOc", "OLcfgOc:0" },
00216        { "OLcfgBkOc", "OLcfgOc:1" },
00217        { "OLcfgDbOc", "OLcfgOc:2" },
00218        { "OLcfgOvOc", "OLcfgOc:3" },
00219        { "OLcfgCtOc", "OLcfgOc:4" },      /* contrib modules */
00220 
00221        /* Syntaxes. We should just start using the standard names and
00222         * document that they are predefined and available for users
00223         * to reference in their own schema. Defining schema without
00224         * OID macros is for masochists...
00225         */
00226        { "OMsyn", "1.3.6.1.4.1.1466.115.121.1" },
00227        { "OMsBoolean", "OMsyn:7" },
00228        { "OMsDN", "OMsyn:12" },
00229        { "OMsDirectoryString", "OMsyn:15" },
00230        { "OMsIA5String", "OMsyn:26" },
00231        { "OMsInteger", "OMsyn:27" },
00232        { "OMsOID", "OMsyn:38" },
00233        { "OMsOctetString", "OMsyn:40" },
00234        { NULL, NULL }
00235 };
00236 
00237 /*
00238  * Backend/Database registry
00239  *
00240  * OLcfg{Bk|Db}{Oc|At}:0           -> common
00241  * OLcfg{Bk|Db}{Oc|At}:1           -> back-bdb(/back-hdb)
00242  * OLcfg{Bk|Db}{Oc|At}:2           -> back-ldif
00243  * OLcfg{Bk|Db}{Oc|At}:3           -> back-ldap
00244  * OLcfg{Bk|Db}{Oc|At}:4           -> back-monitor
00245  * OLcfg{Bk|Db}{Oc|At}:5           -> back-relay
00246  * OLcfg{Bk|Db}{Oc|At}:6           -> back-sql(/back-ndb)
00247  * OLcfg{Bk|Db}{Oc|At}:7           -> back-sock
00248  * OLcfg{Bk|Db}{Oc|At}:8           -> back-null
00249  * OLcfg{Bk|Db}{Oc|At}:9           -> back-passwd
00250  * OLcfg{Bk|Db}{Oc|At}:10          -> back-shell
00251  * OLcfg{Bk|Db}{Oc|At}:11          -> back-perl
00252  * OLcfg{Bk|Db}{Oc|At}:12          -> back-mdb
00253  */
00254 
00255 /*
00256  * Overlay registry
00257  *
00258  * OLcfgOv{Oc|At}:1                -> syncprov
00259  * OLcfgOv{Oc|At}:2                -> pcache
00260  * OLcfgOv{Oc|At}:3                -> chain
00261  * OLcfgOv{Oc|At}:4                -> accesslog
00262  * OLcfgOv{Oc|At}:5                -> valsort
00263  * OLcfgOv{Oc|At}:7                -> distproc
00264  * OLcfgOv{Oc|At}:8                -> dynlist
00265  * OLcfgOv{Oc|At}:9                -> dds
00266  * OLcfgOv{Oc|At}:10               -> unique
00267  * OLcfgOv{Oc|At}:11               -> refint
00268  * OLcfgOv{Oc|At}:12                      -> ppolicy
00269  * OLcfgOv{Oc|At}:13               -> constraint
00270  * OLcfgOv{Oc|At}:14               -> translucent
00271  * OLcfgOv{Oc|At}:15               -> auditlog
00272  * OLcfgOv{Oc|At}:16               -> rwm
00273  * OLcfgOv{Oc|At}:17               -> dyngroup
00274  * OLcfgOv{Oc|At}:18               -> memberof
00275  * OLcfgOv{Oc|At}:19               -> collect
00276  * OLcfgOv{Oc|At}:20               -> retcode
00277  * OLcfgOv{Oc|At}:21               -> sssvlv
00278  */
00279 
00280 /* alphabetical ordering */
00281 
00282 static ConfigTable config_back_cf_table[] = {
00283        /* This attr is read-only */
00284        { "", "", 0, 0, 0, ARG_MAGIC,
00285               &config_fname, "( OLcfgGlAt:78 NAME 'olcConfigFile' "
00286                      "DESC 'File for slapd configuration directives' "
00287                      "EQUALITY caseIgnoreMatch "
00288                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00289        { "", "", 0, 0, 0, ARG_MAGIC,
00290               &config_cfdir, "( OLcfgGlAt:79 NAME 'olcConfigDir' "
00291                      "DESC 'Directory for slapd configuration backend' "
00292                      "EQUALITY caseIgnoreMatch "
00293                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00294        { "access",   NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC|CFG_ACL,
00295               &config_generic, "( OLcfgGlAt:1 NAME 'olcAccess' "
00296                      "DESC 'Access Control List' "
00297                      "EQUALITY caseIgnoreMatch "
00298                      "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
00299        { "add_content_acl", NULL, 0, 0, 0, ARG_MAY_DB|ARG_ON_OFF|ARG_MAGIC|CFG_ACL_ADD,
00300               &config_generic, "( OLcfgGlAt:86 NAME 'olcAddContentAcl' "
00301                      "DESC 'Check ACLs against content of Add ops' "
00302                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00303        { "allows",   "features", 2, 0, 5, ARG_PRE_DB|ARG_MAGIC,
00304               &config_allows, "( OLcfgGlAt:2 NAME 'olcAllows' "
00305                      "DESC 'Allowed set of deprecated features' "
00306                      "EQUALITY caseIgnoreMatch "
00307                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00308        { "argsfile", "file", 2, 2, 0, ARG_STRING,
00309               &slapd_args_file, "( OLcfgGlAt:3 NAME 'olcArgsFile' "
00310                      "DESC 'File for slapd command line options' "
00311                      "EQUALITY caseIgnoreMatch "
00312                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00313        { "attributeoptions", NULL, 0, 0, 0, ARG_MAGIC|CFG_ATOPT,
00314               &config_generic, "( OLcfgGlAt:5 NAME 'olcAttributeOptions' "
00315                      "EQUALITY caseIgnoreMatch "
00316                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00317        { "attribute",       "attribute", 2, 0, STRLENOF( "attribute" ),
00318               ARG_PAREN|ARG_MAGIC|CFG_ATTR,
00319               &config_generic, "( OLcfgGlAt:4 NAME 'olcAttributeTypes' "
00320                      "DESC 'OpenLDAP attributeTypes' "
00321                      "EQUALITY caseIgnoreMatch "
00322                      "SUBSTR caseIgnoreSubstringsMatch "
00323                      "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
00324                             NULL, NULL },
00325        { "authid-rewrite", NULL, 2, 0, STRLENOF( "authid-rewrite" ),
00326 #ifdef SLAP_AUTH_REWRITE
00327               ARG_MAGIC|CFG_REWRITE|ARG_NO_INSERT, &config_generic,
00328 #else
00329               ARG_IGNORED, NULL,
00330 #endif
00331                "( OLcfgGlAt:6 NAME 'olcAuthIDRewrite' "
00332                      "EQUALITY caseIgnoreMatch "
00333                      "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
00334        { "authz-policy", "policy", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_AZPOLICY,
00335               &config_generic, "( OLcfgGlAt:7 NAME 'olcAuthzPolicy' "
00336                      "EQUALITY caseIgnoreMatch "
00337                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00338        { "authz-regexp", "regexp> <DN", 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP|ARG_NO_INSERT,
00339               &config_generic, "( OLcfgGlAt:8 NAME 'olcAuthzRegexp' "
00340                      "EQUALITY caseIgnoreMatch "
00341                      "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
00342        { "backend", "type", 2, 2, 0, ARG_PRE_DB|ARG_MAGIC|CFG_BACKEND,
00343               &config_generic, "( OLcfgGlAt:9 NAME 'olcBackend' "
00344                      "DESC 'A type of backend' "
00345                      "EQUALITY caseIgnoreMatch "
00346                      "SYNTAX OMsDirectoryString SINGLE-VALUE X-ORDERED 'SIBLINGS' )",
00347                             NULL, NULL },
00348        { "concurrency", "level", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_CONCUR,
00349               &config_generic, "( OLcfgGlAt:10 NAME 'olcConcurrency' "
00350                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00351        { "conn_max_pending", "max", 2, 2, 0, ARG_INT,
00352               &slap_conn_max_pending, "( OLcfgGlAt:11 NAME 'olcConnMaxPending' "
00353                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00354        { "conn_max_pending_auth", "max", 2, 2, 0, ARG_INT,
00355               &slap_conn_max_pending_auth, "( OLcfgGlAt:12 NAME 'olcConnMaxPendingAuth' "
00356                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00357        { "database", "type", 2, 2, 0, ARG_MAGIC|CFG_DATABASE,
00358               &config_generic, "( OLcfgGlAt:13 NAME 'olcDatabase' "
00359                      "DESC 'The backend type for a database instance' "
00360                      "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
00361        { "defaultSearchBase", "dn", 2, 2, 0, ARG_PRE_BI|ARG_PRE_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
00362               &config_search_base, "( OLcfgGlAt:14 NAME 'olcDefaultSearchBase' "
00363                      "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
00364        { "disallows", "features", 2, 0, 8, ARG_PRE_DB|ARG_MAGIC,
00365               &config_disallows, "( OLcfgGlAt:15 NAME 'olcDisallows' "
00366                      "EQUALITY caseIgnoreMatch "
00367                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00368        { "ditcontentrule",  NULL, 0, 0, 0, ARG_MAGIC|CFG_DIT|ARG_NO_DELETE|ARG_NO_INSERT,
00369               &config_generic, "( OLcfgGlAt:16 NAME 'olcDitContentRules' "
00370                      "DESC 'OpenLDAP DIT content rules' "
00371                      "EQUALITY caseIgnoreMatch "
00372                      "SUBSTR caseIgnoreSubstringsMatch "
00373                      "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
00374                      NULL, NULL },
00375        { "extra_attrs", "attrlist", 2, 2, 0, ARG_DB|ARG_MAGIC,
00376               &config_extra_attrs, "( OLcfgDbAt:0.20 NAME 'olcExtraAttrs' "
00377                      "EQUALITY caseIgnoreMatch "
00378                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00379        { "gentlehup", "on|off", 2, 2, 0,
00380 #ifdef SIGHUP
00381               ARG_ON_OFF, &global_gentlehup,
00382 #else
00383               ARG_IGNORED, NULL,
00384 #endif
00385               "( OLcfgGlAt:17 NAME 'olcGentleHUP' "
00386                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00387        { "hidden", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_HIDDEN,
00388               &config_generic, "( OLcfgDbAt:0.17 NAME 'olcHidden' "
00389                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00390        { "idletimeout", "timeout", 2, 2, 0, ARG_INT,
00391               &global_idletimeout, "( OLcfgGlAt:18 NAME 'olcIdleTimeout' "
00392                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00393        { "include", "file", 2, 2, 0, ARG_MAGIC,
00394               &config_include, "( OLcfgGlAt:19 NAME 'olcInclude' "
00395                      "SUP labeledURI )", NULL, NULL },
00396        { "index_substr_if_minlen", "min", 2, 2, 0, ARG_UINT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MIN,
00397               &config_generic, "( OLcfgGlAt:20 NAME 'olcIndexSubstrIfMinLen' "
00398                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00399        { "index_substr_if_maxlen", "max", 2, 2, 0, ARG_UINT|ARG_NONZERO|ARG_MAGIC|CFG_SSTR_IF_MAX,
00400               &config_generic, "( OLcfgGlAt:21 NAME 'olcIndexSubstrIfMaxLen' "
00401                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00402        { "index_substr_any_len", "len", 2, 2, 0, ARG_INT|ARG_NONZERO,
00403               &index_substr_any_len, "( OLcfgGlAt:22 NAME 'olcIndexSubstrAnyLen' "
00404                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00405        { "index_substr_any_step", "step", 2, 2, 0, ARG_INT|ARG_NONZERO,
00406               &index_substr_any_step, "( OLcfgGlAt:23 NAME 'olcIndexSubstrAnyStep' "
00407                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00408        { "index_intlen", "len", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_IX_INTLEN,
00409               &config_generic, "( OLcfgGlAt:84 NAME 'olcIndexIntLen' "
00410                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00411        { "lastmod", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_LASTMOD,
00412               &config_generic, "( OLcfgDbAt:0.4 NAME 'olcLastMod' "
00413                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00414        { "ldapsyntax",      "syntax", 2, 0, 0,
00415               ARG_PAREN|ARG_MAGIC|CFG_SYNTAX,
00416               &config_generic, "( OLcfgGlAt:85 NAME 'olcLdapSyntaxes' "
00417                      "DESC 'OpenLDAP ldapSyntax' "
00418                      "EQUALITY caseIgnoreMatch "
00419                      "SUBSTR caseIgnoreSubstringsMatch "
00420                      "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
00421                             NULL, NULL },
00422        { "limits", "limits", 2, 0, 0, ARG_DB|ARG_MAGIC|CFG_LIMITS,
00423               &config_generic, "( OLcfgDbAt:0.5 NAME 'olcLimits' "
00424                      "EQUALITY caseIgnoreMatch "
00425                      "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
00426        { "listener-threads", "count", 2, 0, 0,
00427 #ifdef NO_THREADS
00428               ARG_IGNORED, NULL,
00429 #else
00430               ARG_UINT|ARG_MAGIC|CFG_LTHREADS, &config_generic,
00431 #endif
00432               "( OLcfgGlAt:93 NAME 'olcListenerThreads' "
00433                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00434        { "localSSF", "ssf", 2, 2, 0, ARG_INT,
00435               &local_ssf, "( OLcfgGlAt:26 NAME 'olcLocalSSF' "
00436                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00437        { "logfile", "file", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_LOGFILE,
00438               &config_generic, "( OLcfgGlAt:27 NAME 'olcLogFile' "
00439                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00440        { "loglevel", "level", 2, 0, 0, ARG_MAGIC,
00441               &config_loglevel, "( OLcfgGlAt:28 NAME 'olcLogLevel' "
00442                      "EQUALITY caseIgnoreMatch "
00443                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00444        { "maxDerefDepth", "depth", 2, 2, 0, ARG_DB|ARG_INT|ARG_MAGIC|CFG_DEPTH,
00445               &config_generic, "( OLcfgDbAt:0.6 NAME 'olcMaxDerefDepth' "
00446                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00447        { "mirrormode", "on|off", 2, 2, 0, ARG_DB|ARG_ON_OFF|ARG_MAGIC|CFG_MIRRORMODE,
00448               &config_generic, "( OLcfgDbAt:0.16 NAME 'olcMirrorMode' "
00449                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00450        { "moduleload",      "file", 2, 0, 0,
00451 #ifdef SLAPD_MODULES
00452               ARG_MAGIC|CFG_MODLOAD|ARG_NO_DELETE, &config_generic,
00453 #else
00454               ARG_IGNORED, NULL,
00455 #endif
00456               "( OLcfgGlAt:30 NAME 'olcModuleLoad' "
00457                      "EQUALITY caseIgnoreMatch "
00458                      "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
00459        { "modulepath", "path", 2, 2, 0,
00460 #ifdef SLAPD_MODULES
00461               ARG_MAGIC|CFG_MODPATH|ARG_NO_DELETE|ARG_NO_INSERT, &config_generic,
00462 #else
00463               ARG_IGNORED, NULL,
00464 #endif
00465               "( OLcfgGlAt:31 NAME 'olcModulePath' "
00466                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00467        { "monitoring", "TRUE|FALSE", 2, 2, 0,
00468               ARG_MAGIC|CFG_MONITORING|ARG_DB|ARG_ON_OFF, &config_generic,
00469               "( OLcfgDbAt:0.18 NAME 'olcMonitoring' "
00470                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00471        { "objectclass", "objectclass", 2, 0, 0, ARG_PAREN|ARG_MAGIC|CFG_OC,
00472               &config_generic, "( OLcfgGlAt:32 NAME 'olcObjectClasses' "
00473               "DESC 'OpenLDAP object classes' "
00474               "EQUALITY caseIgnoreMatch "
00475               "SUBSTR caseIgnoreSubstringsMatch "
00476               "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )",
00477                      NULL, NULL },
00478        { "objectidentifier", "name> <oid",       3, 3, 0, ARG_MAGIC|CFG_OID,
00479               &config_generic, "( OLcfgGlAt:33 NAME 'olcObjectIdentifier' "
00480                      "EQUALITY caseIgnoreMatch "
00481                      "SUBSTR caseIgnoreSubstringsMatch "
00482                      "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
00483        { "overlay", "overlay", 2, 2, 0, ARG_MAGIC,
00484               &config_overlay, "( OLcfgGlAt:34 NAME 'olcOverlay' "
00485                      "SUP olcDatabase SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
00486        { "password-crypt-salt-format", "salt", 2, 2, 0, ARG_STRING|ARG_MAGIC|CFG_SALT,
00487               &config_generic, "( OLcfgGlAt:35 NAME 'olcPasswordCryptSaltFormat' "
00488                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00489        { "password-hash", "hash", 2, 0, 0, ARG_MAGIC,
00490               &config_passwd_hash, "( OLcfgGlAt:36 NAME 'olcPasswordHash' "
00491                      "EQUALITY caseIgnoreMatch "
00492                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00493        { "pidfile", "file", 2, 2, 0, ARG_STRING,
00494               &slapd_pid_file, "( OLcfgGlAt:37 NAME 'olcPidFile' "
00495                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00496        { "plugin", NULL, 0, 0, 0,
00497 #ifdef LDAP_SLAPI
00498               ARG_MAGIC|CFG_PLUGIN, &config_generic,
00499 #else
00500               ARG_IGNORED, NULL,
00501 #endif
00502               "( OLcfgGlAt:38 NAME 'olcPlugin' "
00503                      "EQUALITY caseIgnoreMatch "
00504                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00505        { "pluginlog", "filename", 2, 2, 0,
00506 #ifdef LDAP_SLAPI
00507               ARG_STRING, &slapi_log_file,
00508 #else
00509               ARG_IGNORED, NULL,
00510 #endif
00511               "( OLcfgGlAt:39 NAME 'olcPluginLogFile' "
00512                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00513        { "readonly", "on|off", 2, 2, 0, ARG_MAY_DB|ARG_ON_OFF|ARG_MAGIC|CFG_RO,
00514               &config_generic, "( OLcfgGlAt:40 NAME 'olcReadOnly' "
00515                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00516        { "referral", "url", 2, 2, 0, ARG_MAGIC,
00517               &config_referral, "( OLcfgGlAt:41 NAME 'olcReferral' "
00518                      "SUP labeledURI SINGLE-VALUE )", NULL, NULL },
00519        { "replica", "host or uri", 2, 0, 0, ARG_DB|ARG_MAGIC,
00520               &config_obsolete, "( OLcfgDbAt:0.7 NAME 'olcReplica' "
00521                      "EQUALITY caseIgnoreMatch "
00522                      "SUP labeledURI X-ORDERED 'VALUES' )", NULL, NULL },
00523        { "replica-argsfile", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC,
00524               &config_obsolete, "( OLcfgGlAt:43 NAME 'olcReplicaArgsFile' "
00525                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00526        { "replica-pidfile", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC,
00527               &config_obsolete, "( OLcfgGlAt:44 NAME 'olcReplicaPidFile' "
00528                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00529        { "replicationInterval", NULL, 0, 0, 0, ARG_MAY_DB|ARG_MAGIC,
00530               &config_obsolete, "( OLcfgGlAt:45 NAME 'olcReplicationInterval' "
00531                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00532        { "replogfile", "filename", 2, 2, 0, ARG_MAY_DB|ARG_MAGIC,
00533               &config_obsolete, "( OLcfgGlAt:46 NAME 'olcReplogFile' "
00534                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00535        { "require", "features", 2, 0, 7, ARG_MAY_DB|ARG_MAGIC,
00536               &config_requires, "( OLcfgGlAt:47 NAME 'olcRequires' "
00537                      "EQUALITY caseIgnoreMatch "
00538                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00539        { "restrict", "op_list", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
00540               &config_restrict, "( OLcfgGlAt:48 NAME 'olcRestrict' "
00541                      "EQUALITY caseIgnoreMatch "
00542                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00543        { "reverse-lookup", "on|off", 2, 2, 0,
00544 #ifdef SLAPD_RLOOKUPS
00545               ARG_ON_OFF, &use_reverse_lookup,
00546 #else
00547               ARG_IGNORED, NULL,
00548 #endif
00549               "( OLcfgGlAt:49 NAME 'olcReverseLookup' "
00550                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00551        { "rootdn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
00552               &config_rootdn, "( OLcfgDbAt:0.8 NAME 'olcRootDN' "
00553                      "EQUALITY distinguishedNameMatch "
00554                      "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
00555        { "rootDSE", "file", 2, 2, 0, ARG_MAGIC|CFG_ROOTDSE,
00556               &config_generic, "( OLcfgGlAt:51 NAME 'olcRootDSE' "
00557                      "EQUALITY caseIgnoreMatch "
00558                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00559        { "rootpw", "password", 2, 2, 0, ARG_BERVAL|ARG_DB|ARG_MAGIC,
00560               &config_rootpw, "( OLcfgDbAt:0.9 NAME 'olcRootPW' "
00561                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00562        { "sasl-authz-policy", NULL, 2, 2, 0, ARG_MAGIC|CFG_AZPOLICY,
00563               &config_generic, NULL, NULL, NULL },
00564        { "sasl-auxprops", NULL, 2, 0, 0,
00565 #ifdef HAVE_CYRUS_SASL
00566               ARG_STRING|ARG_UNIQUE, &slap_sasl_auxprops,
00567 #else
00568               ARG_IGNORED, NULL,
00569 #endif
00570               "( OLcfgGlAt:89 NAME 'olcSaslAuxprops' "
00571                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00572        { "sasl-host", "host", 2, 2, 0,
00573 #ifdef HAVE_CYRUS_SASL
00574               ARG_STRING|ARG_UNIQUE, &sasl_host,
00575 #else
00576               ARG_IGNORED, NULL,
00577 #endif
00578               "( OLcfgGlAt:53 NAME 'olcSaslHost' "
00579                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00580        { "sasl-realm", "realm", 2, 2, 0,
00581 #ifdef HAVE_CYRUS_SASL
00582               ARG_STRING|ARG_UNIQUE, &global_realm,
00583 #else
00584               ARG_IGNORED, NULL,
00585 #endif
00586               "( OLcfgGlAt:54 NAME 'olcSaslRealm' "
00587                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00588        { "sasl-regexp", NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
00589               &config_generic, NULL, NULL, NULL },
00590        { "sasl-secprops", "properties", 2, 2, 0,
00591 #ifdef HAVE_CYRUS_SASL
00592               ARG_MAGIC|CFG_SASLSECP, &config_generic,
00593 #else
00594               ARG_IGNORED, NULL,
00595 #endif
00596               "( OLcfgGlAt:56 NAME 'olcSaslSecProps' "
00597                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00598        { "saslRegexp",      NULL, 3, 3, 0, ARG_MAGIC|CFG_AZREGEXP,
00599               &config_generic, NULL, NULL, NULL },
00600        { "schemadn", "dn", 2, 2, 0, ARG_MAY_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
00601               &config_schema_dn, "( OLcfgGlAt:58 NAME 'olcSchemaDN' "
00602                      "EQUALITY distinguishedNameMatch "
00603                      "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
00604        { "security", "factors", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
00605               &config_security, "( OLcfgGlAt:59 NAME 'olcSecurity' "
00606                      "EQUALITY caseIgnoreMatch "
00607                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00608        { "serverID", "number> <[URI]", 2, 3, 0, ARG_MAGIC|CFG_SERVERID,
00609               &config_generic, "( OLcfgGlAt:81 NAME 'olcServerID' "
00610                      "EQUALITY caseIgnoreMatch "
00611                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00612        { "sizelimit", "limit",     2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
00613               &config_sizelimit, "( OLcfgGlAt:60 NAME 'olcSizeLimit' "
00614                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00615        { "sockbuf_max_incoming", "max", 2, 2, 0, ARG_BER_LEN_T,
00616               &sockbuf_max_incoming, "( OLcfgGlAt:61 NAME 'olcSockbufMaxIncoming' "
00617                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00618        { "sockbuf_max_incoming_auth", "max", 2, 2, 0, ARG_BER_LEN_T,
00619               &sockbuf_max_incoming_auth, "( OLcfgGlAt:62 NAME 'olcSockbufMaxIncomingAuth' "
00620                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00621        { "sortvals", "attr", 2, 0, 0, ARG_MAGIC|CFG_SORTVALS,
00622               &config_generic, "( OLcfgGlAt:83 NAME 'olcSortVals' "
00623                      "DESC 'Attributes whose values will always be sorted' "
00624                      "EQUALITY caseIgnoreMatch "
00625                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00626        { "subordinate", "[advertise]", 1, 2, 0, ARG_DB|ARG_MAGIC,
00627               &config_subordinate, "( OLcfgDbAt:0.15 NAME 'olcSubordinate' "
00628                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00629        { "suffix",   "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
00630               &config_suffix, "( OLcfgDbAt:0.10 NAME 'olcSuffix' "
00631                      "EQUALITY distinguishedNameMatch "
00632                      "SYNTAX OMsDN )", NULL, NULL },
00633        { "sync_use_subentry", NULL, 0, 0, 0, ARG_ON_OFF|ARG_DB|ARG_MAGIC|CFG_SYNC_SUBENTRY,
00634               &config_generic, "( OLcfgDbAt:0.19 NAME 'olcSyncUseSubentry' "
00635                      "DESC 'Store sync context in a subentry' "
00636                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00637        { "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC,
00638               &syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' "
00639                      "EQUALITY caseIgnoreMatch "
00640                      "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
00641        { "tcp-buffer", "[listener=<listener>] [{read|write}=]size", 0, 0, 0,
00642 #ifndef LDAP_TCP_BUFFER
00643               ARG_IGNORED, NULL,
00644 #else /* LDAP_TCP_BUFFER */
00645               ARG_MAGIC, &config_tcp_buffer,
00646 #endif /* LDAP_TCP_BUFFER */
00647                      "( OLcfgGlAt:90 NAME 'olcTCPBuffer' "
00648                      "DESC 'Custom TCP buffer size' "
00649                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00650        { "threads", "count", 2, 2, 0,
00651 #ifdef NO_THREADS
00652               ARG_IGNORED, NULL,
00653 #else
00654               ARG_INT|ARG_MAGIC|CFG_THREADS, &config_generic,
00655 #endif
00656               "( OLcfgGlAt:66 NAME 'olcThreads' "
00657                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00658        { "timelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
00659               &config_timelimit, "( OLcfgGlAt:67 NAME 'olcTimeLimit' "
00660                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00661        { "TLSCACertificateFile", NULL, 2, 2, 0,
00662 #ifdef HAVE_TLS
00663               CFG_TLS_CA_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
00664 #else
00665               ARG_IGNORED, NULL,
00666 #endif
00667               "( OLcfgGlAt:68 NAME 'olcTLSCACertificateFile' "
00668                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00669        { "TLSCACertificatePath", NULL,    2, 2, 0,
00670 #ifdef HAVE_TLS
00671               CFG_TLS_CA_PATH|ARG_STRING|ARG_MAGIC, &config_tls_option,
00672 #else
00673               ARG_IGNORED, NULL,
00674 #endif
00675               "( OLcfgGlAt:69 NAME 'olcTLSCACertificatePath' "
00676                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00677        { "TLSCertificateFile", NULL, 2, 2, 0,
00678 #ifdef HAVE_TLS
00679               CFG_TLS_CERT_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
00680 #else
00681               ARG_IGNORED, NULL,
00682 #endif
00683               "( OLcfgGlAt:70 NAME 'olcTLSCertificateFile' "
00684                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00685        { "TLSCertificateKeyFile", NULL, 2, 2, 0,
00686 #ifdef HAVE_TLS
00687               CFG_TLS_CERT_KEY|ARG_STRING|ARG_MAGIC, &config_tls_option,
00688 #else
00689               ARG_IGNORED, NULL,
00690 #endif
00691               "( OLcfgGlAt:71 NAME 'olcTLSCertificateKeyFile' "
00692                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00693        { "TLSCipherSuite",  NULL, 2, 2, 0,
00694 #ifdef HAVE_TLS
00695               CFG_TLS_CIPHER|ARG_STRING|ARG_MAGIC, &config_tls_option,
00696 #else
00697               ARG_IGNORED, NULL,
00698 #endif
00699               "( OLcfgGlAt:72 NAME 'olcTLSCipherSuite' "
00700                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00701        { "TLSCRLCheck", NULL, 2, 2, 0,
00702 #if defined(HAVE_TLS) && defined(HAVE_OPENSSL_CRL)
00703               CFG_TLS_CRLCHECK|ARG_STRING|ARG_MAGIC, &config_tls_config,
00704 #else
00705               ARG_IGNORED, NULL,
00706 #endif
00707               "( OLcfgGlAt:73 NAME 'olcTLSCRLCheck' "
00708                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00709        { "TLSCRLFile", NULL, 2, 2, 0,
00710 #if defined(HAVE_GNUTLS)
00711               CFG_TLS_CRL_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
00712 #else
00713               ARG_IGNORED, NULL,
00714 #endif
00715               "( OLcfgGlAt:82 NAME 'olcTLSCRLFile' "
00716                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00717        { "TLSRandFile", NULL, 2, 2, 0,
00718 #ifdef HAVE_TLS
00719               CFG_TLS_RAND|ARG_STRING|ARG_MAGIC, &config_tls_option,
00720 #else
00721               ARG_IGNORED, NULL,
00722 #endif
00723               "( OLcfgGlAt:74 NAME 'olcTLSRandFile' "
00724                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00725        { "TLSVerifyClient", NULL, 2, 2, 0,
00726 #ifdef HAVE_TLS
00727               CFG_TLS_VERIFY|ARG_STRING|ARG_MAGIC, &config_tls_config,
00728 #else
00729               ARG_IGNORED, NULL,
00730 #endif
00731               "( OLcfgGlAt:75 NAME 'olcTLSVerifyClient' "
00732                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00733        { "TLSDHParamFile", NULL, 2, 2, 0,
00734 #ifdef HAVE_TLS
00735               CFG_TLS_DH_FILE|ARG_STRING|ARG_MAGIC, &config_tls_option,
00736 #else
00737               ARG_IGNORED, NULL,
00738 #endif
00739               "( OLcfgGlAt:77 NAME 'olcTLSDHParamFile' "
00740                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00741        { "TLSProtocolMin",  NULL, 2, 2, 0,
00742 #ifdef HAVE_TLS
00743               CFG_TLS_PROTOCOL_MIN|ARG_STRING|ARG_MAGIC, &config_tls_config,
00744 #else
00745               ARG_IGNORED, NULL,
00746 #endif
00747               "( OLcfgGlAt:87 NAME 'olcTLSProtocolMin' "
00748                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00749        { "tool-threads", "count", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_TTHREADS,
00750               &config_generic, "( OLcfgGlAt:80 NAME 'olcToolThreads' "
00751                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00752        { "ucdata-path", "path", 2, 2, 0, ARG_IGNORED,
00753               NULL, NULL, NULL, NULL },
00754        { "updatedn", "dn", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
00755               &config_updatedn, "( OLcfgDbAt:0.12 NAME 'olcUpdateDN' "
00756                      "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
00757        { "updateref", "url", 2, 2, 0, ARG_DB|ARG_MAGIC,
00758               &config_updateref, "( OLcfgDbAt:0.13 NAME 'olcUpdateRef' "
00759                      "EQUALITY caseIgnoreMatch "
00760                      "SUP labeledURI )", NULL, NULL },
00761        { "writetimeout", "timeout", 2, 2, 0, ARG_INT,
00762               &global_writetimeout, "( OLcfgGlAt:88 NAME 'olcWriteTimeout' "
00763                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00764        { NULL,       NULL, 0, 0, 0, ARG_IGNORED,
00765               NULL, NULL, NULL, NULL }
00766 };
00767 
00768 /* Need to no-op this keyword for dynamic config */
00769 ConfigTable olcDatabaseDummy[] = {
00770        { "", "", 0, 0, 0, ARG_IGNORED,
00771               NULL, "( OLcfgGlAt:13 NAME 'olcDatabase' "
00772                      "DESC 'The backend type for a database instance' "
00773                      "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
00774        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
00775 };
00776 
00777 /* Routines to check if a child can be added to this type */
00778 static ConfigLDAPadd cfAddSchema, cfAddInclude, cfAddDatabase,
00779        cfAddBackend, cfAddModule, cfAddOverlay;
00780 
00781 /* NOTE: be careful when defining array members
00782  * that can be conditionally compiled */
00783 #define CFOC_GLOBAL  cf_ocs[1]
00784 #define CFOC_SCHEMA  cf_ocs[2]
00785 #define CFOC_BACKEND cf_ocs[3]
00786 #define CFOC_DATABASE       cf_ocs[4]
00787 #define CFOC_OVERLAY cf_ocs[5]
00788 #define CFOC_INCLUDE cf_ocs[6]
00789 #define CFOC_FRONTEND       cf_ocs[7]
00790 #ifdef SLAPD_MODULES
00791 #define CFOC_MODULE  cf_ocs[8]
00792 #endif /* SLAPD_MODULES */
00793 
00794 static ConfigOCs cf_ocs[] = {
00795        { "( OLcfgGlOc:0 "
00796               "NAME 'olcConfig' "
00797               "DESC 'OpenLDAP configuration object' "
00798               "ABSTRACT SUP top )", Cft_Abstract, NULL },
00799        { "( OLcfgGlOc:1 "
00800               "NAME 'olcGlobal' "
00801               "DESC 'OpenLDAP Global configuration options' "
00802               "SUP olcConfig STRUCTURAL "
00803               "MAY ( cn $ olcConfigFile $ olcConfigDir $ olcAllows $ olcArgsFile $ "
00804                "olcAttributeOptions $ olcAuthIDRewrite $ "
00805                "olcAuthzPolicy $ olcAuthzRegexp $ olcConcurrency $ "
00806                "olcConnMaxPending $ olcConnMaxPendingAuth $ "
00807                "olcDisallows $ olcGentleHUP $ olcIdleTimeout $ "
00808                "olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ "
00809                "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcIndexIntLen $ "
00810                "olcLocalSSF $ olcLogFile $ olcLogLevel $ "
00811                "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ "
00812                "olcPluginLogFile $ olcReadOnly $ olcReferral $ "
00813                "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
00814                "olcRootDSE $ "
00815                "olcSaslAuxprops $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
00816                "olcSecurity $ olcServerID $ olcSizeLimit $ "
00817                "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ "
00818                "olcTCPBuffer $ "
00819                "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ "
00820                "olcTLSCACertificatePath $ olcTLSCertificateFile $ "
00821                "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ "
00822                "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ "
00823                "olcTLSCRLFile $ olcToolThreads $ olcWriteTimeout $ "
00824                "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ "
00825                "olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Global },
00826        { "( OLcfgGlOc:2 "
00827               "NAME 'olcSchemaConfig' "
00828               "DESC 'OpenLDAP schema object' "
00829               "SUP olcConfig STRUCTURAL "
00830               "MAY ( cn $ olcObjectIdentifier $ olcLdapSyntaxes $ "
00831                "olcAttributeTypes $ olcObjectClasses $ olcDitContentRules ) )",
00832                      Cft_Schema, NULL, cfAddSchema },
00833        { "( OLcfgGlOc:3 "
00834               "NAME 'olcBackendConfig' "
00835               "DESC 'OpenLDAP Backend-specific options' "
00836               "SUP olcConfig STRUCTURAL "
00837               "MUST olcBackend )", Cft_Backend, NULL, cfAddBackend },
00838        { "( OLcfgGlOc:4 "
00839               "NAME 'olcDatabaseConfig' "
00840               "DESC 'OpenLDAP Database-specific options' "
00841               "SUP olcConfig STRUCTURAL "
00842               "MUST olcDatabase "
00843               "MAY ( olcHidden $ olcSuffix $ olcSubordinate $ olcAccess $ "
00844                "olcAddContentAcl $ olcLastMod $ olcLimits $ "
00845                "olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ "
00846                "olcReplicaArgsFile $ olcReplicaPidFile $ olcReplicationInterval $ "
00847                "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ "
00848                "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncUseSubentry $ olcSyncrepl $ "
00849                "olcTimeLimit $ olcUpdateDN $ olcUpdateRef $ olcMirrorMode $ "
00850                "olcMonitoring $ olcExtraAttrs ) )",
00851                      Cft_Database, NULL, cfAddDatabase },
00852        { "( OLcfgGlOc:5 "
00853               "NAME 'olcOverlayConfig' "
00854               "DESC 'OpenLDAP Overlay-specific options' "
00855               "SUP olcConfig STRUCTURAL "
00856               "MUST olcOverlay )", Cft_Overlay, NULL, cfAddOverlay },
00857        { "( OLcfgGlOc:6 "
00858               "NAME 'olcIncludeFile' "
00859               "DESC 'OpenLDAP configuration include file' "
00860               "SUP olcConfig STRUCTURAL "
00861               "MUST olcInclude "
00862               "MAY ( cn $ olcRootDSE ) )",
00863               /* Used to be Cft_Include, that def has been removed */
00864               Cft_Abstract, NULL, cfAddInclude },
00865        /* This should be STRUCTURAL like all the other database classes, but
00866         * that would mean inheriting all of the olcDatabaseConfig attributes,
00867         * which causes them to be merged twice in config_build_entry.
00868         */
00869        { "( OLcfgGlOc:7 "
00870               "NAME 'olcFrontendConfig' "
00871               "DESC 'OpenLDAP frontend configuration' "
00872               "AUXILIARY "
00873               "MAY ( olcDefaultSearchBase $ olcPasswordHash $ olcSortVals ) )",
00874               Cft_Database, NULL, NULL },
00875 #ifdef SLAPD_MODULES
00876        { "( OLcfgGlOc:8 "
00877               "NAME 'olcModuleList' "
00878               "DESC 'OpenLDAP dynamic module info' "
00879               "SUP olcConfig STRUCTURAL "
00880               "MAY ( cn $ olcModulePath $ olcModuleLoad ) )",
00881               Cft_Module, NULL, cfAddModule },
00882 #endif
00883        { NULL, 0, NULL }
00884 };
00885 
00886 typedef struct ServerID {
00887        struct ServerID *si_next;
00888        struct berval si_url;
00889        int si_num;
00890 } ServerID;
00891 
00892 static ServerID *sid_list;
00893 static ServerID *sid_set;
00894 
00895 typedef struct voidList {
00896        struct voidList *vl_next;
00897        void *vl_ptr;
00898 } voidList;
00899 
00900 typedef struct ADlist {
00901        struct ADlist *al_next;
00902        AttributeDescription *al_desc;
00903 } ADlist;
00904 
00905 static ADlist *sortVals;
00906 
00907 static int
00908 config_generic(ConfigArgs *c) {
00909        int i;
00910 
00911        if ( c->op == SLAP_CONFIG_EMIT ) {
00912               int rc = 0;
00913               switch(c->type) {
00914               case CFG_CONCUR:
00915                      c->value_int = ldap_pvt_thread_get_concurrency();
00916                      break;
00917               case CFG_THREADS:
00918                      c->value_int = connection_pool_max;
00919                      break;
00920               case CFG_TTHREADS:
00921                      c->value_int = slap_tool_thread_max;
00922                      break;
00923               case CFG_LTHREADS:
00924                      c->value_uint = slapd_daemon_threads;
00925                      break;
00926               case CFG_SALT:
00927                      if ( passwd_salt )
00928                             c->value_string = ch_strdup( passwd_salt );
00929                      else
00930                             rc = 1;
00931                      break;
00932               case CFG_LIMITS:
00933                      if ( c->be->be_limits ) {
00934                             char buf[4096*3];
00935                             struct berval bv;
00936 
00937                             for ( i=0; c->be->be_limits[i]; i++ ) {
00938                                    bv.bv_len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i );
00939                                    if ( bv.bv_len >= sizeof( buf ) ) {
00940                                           ber_bvarray_free_x( c->rvalue_vals, NULL );
00941                                           c->rvalue_vals = NULL;
00942                                           rc = 1;
00943                                           break;
00944                                    }
00945                                    bv.bv_val = buf + bv.bv_len;
00946                                    limits_unparse( c->be->be_limits[i], &bv,
00947                                                  sizeof( buf ) - ( bv.bv_val - buf ) );
00948                                    bv.bv_len += bv.bv_val - buf;
00949                                    bv.bv_val = buf;
00950                                    value_add_one( &c->rvalue_vals, &bv );
00951                             }
00952                      }
00953                      if ( !c->rvalue_vals ) rc = 1;
00954                      break;
00955               case CFG_RO:
00956                      c->value_int = (c->be->be_restrictops & SLAP_RESTRICT_READONLY);
00957                      break;
00958               case CFG_AZPOLICY:
00959                      c->value_string = ch_strdup( slap_sasl_getpolicy());
00960                      break;
00961               case CFG_AZREGEXP:
00962                      slap_sasl_regexp_unparse( &c->rvalue_vals );
00963                      if ( !c->rvalue_vals ) rc = 1;
00964                      break;
00965 #ifdef HAVE_CYRUS_SASL
00966               case CFG_SASLSECP: {
00967                      struct berval bv = BER_BVNULL;
00968                      slap_sasl_secprops_unparse( &bv );
00969                      if ( !BER_BVISNULL( &bv )) {
00970                             ber_bvarray_add( &c->rvalue_vals, &bv );
00971                      } else {
00972                             rc = 1;
00973                      }
00974                      }
00975                      break;
00976 #endif
00977               case CFG_DEPTH:
00978                      c->value_int = c->be->be_max_deref_depth;
00979                      break;
00980               case CFG_HIDDEN:
00981                      if ( SLAP_DBHIDDEN( c->be )) {
00982                             c->value_int = 1;
00983                      } else {
00984                             rc = 1;
00985                      }
00986                      break;
00987               case CFG_OID: {
00988                      ConfigFile *cf = c->ca_private;
00989                      if ( !cf )
00990                             oidm_unparse( &c->rvalue_vals, NULL, NULL, 1 );
00991                      else if ( cf->c_om_head )
00992                             oidm_unparse( &c->rvalue_vals, cf->c_om_head,
00993                                    cf->c_om_tail, 0 );
00994                      if ( !c->rvalue_vals )
00995                             rc = 1;
00996                      }
00997                      break;
00998               case CFG_ATOPT:
00999                      ad_unparse_options( &c->rvalue_vals );
01000                      break;
01001               case CFG_OC: {
01002                      ConfigFile *cf = c->ca_private;
01003                      if ( !cf )
01004                             oc_unparse( &c->rvalue_vals, NULL, NULL, 1 );
01005                      else if ( cf->c_oc_head )
01006                             oc_unparse( &c->rvalue_vals, cf->c_oc_head,
01007                                    cf->c_oc_tail, 0 );
01008                      if ( !c->rvalue_vals )
01009                             rc = 1;
01010                      }
01011                      break;
01012               case CFG_ATTR: {
01013                      ConfigFile *cf = c->ca_private;
01014                      if ( !cf )
01015                             at_unparse( &c->rvalue_vals, NULL, NULL, 1 );
01016                      else if ( cf->c_at_head )
01017                             at_unparse( &c->rvalue_vals, cf->c_at_head,
01018                                    cf->c_at_tail, 0 );
01019                      if ( !c->rvalue_vals )
01020                             rc = 1;
01021                      }
01022                      break;
01023               case CFG_SYNTAX: {
01024                      ConfigFile *cf = c->ca_private;
01025                      if ( !cf )
01026                             syn_unparse( &c->rvalue_vals, NULL, NULL, 1 );
01027                      else if ( cf->c_syn_head )
01028                             syn_unparse( &c->rvalue_vals, cf->c_syn_head,
01029                                    cf->c_syn_tail, 0 );
01030                      if ( !c->rvalue_vals )
01031                             rc = 1;
01032                      }
01033                      break;
01034               case CFG_DIT: {
01035                      ConfigFile *cf = c->ca_private;
01036                      if ( !cf )
01037                             cr_unparse( &c->rvalue_vals, NULL, NULL, 1 );
01038                      else if ( cf->c_cr_head )
01039                             cr_unparse( &c->rvalue_vals, cf->c_cr_head,
01040                                    cf->c_cr_tail, 0 );
01041                      if ( !c->rvalue_vals )
01042                             rc = 1;
01043                      }
01044                      break;
01045                      
01046               case CFG_ACL: {
01047                      AccessControl *a;
01048                      char *src, *dst, ibuf[11];
01049                      struct berval bv, abv;
01050                      for (i=0, a=c->be->be_acl; a; i++,a=a->acl_next) {
01051                             abv.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
01052                             if ( abv.bv_len >= sizeof( ibuf ) ) {
01053                                    ber_bvarray_free_x( c->rvalue_vals, NULL );
01054                                    c->rvalue_vals = NULL;
01055                                    i = 0;
01056                                    break;
01057                             }
01058                             acl_unparse( a, &bv );
01059                             abv.bv_val = ch_malloc( abv.bv_len + bv.bv_len + 1 );
01060                             AC_MEMCPY( abv.bv_val, ibuf, abv.bv_len );
01061                             /* Turn TAB / EOL into plain space */
01062                             for (src=bv.bv_val,dst=abv.bv_val+abv.bv_len; *src; src++) {
01063                                    if (isspace((unsigned char)*src)) *dst++ = ' ';
01064                                    else *dst++ = *src;
01065                             }
01066                             *dst = '\0';
01067                             if (dst[-1] == ' ') {
01068                                    dst--;
01069                                    *dst = '\0';
01070                             }
01071                             abv.bv_len = dst - abv.bv_val;
01072                             ber_bvarray_add( &c->rvalue_vals, &abv );
01073                      }
01074                      rc = (!i);
01075                      break;
01076               }
01077               case CFG_ACL_ADD:
01078                      c->value_int = (SLAP_DBACL_ADD(c->be) != 0);
01079                      break;
01080               case CFG_ROOTDSE: {
01081                      ConfigFile *cf = c->ca_private;
01082                      if ( cf->c_dseFiles ) {
01083                             value_add( &c->rvalue_vals, cf->c_dseFiles );
01084                      } else {
01085                             rc = 1;
01086                      }
01087                      }
01088                      break;
01089               case CFG_SERVERID:
01090                      if ( sid_list ) {
01091                             ServerID *si;
01092                             struct berval bv;
01093 
01094                             for ( si = sid_list; si; si=si->si_next ) {
01095                                    assert( si->si_num >= 0 && si->si_num <= SLAP_SYNC_SID_MAX );
01096                                    if ( !BER_BVISEMPTY( &si->si_url )) {
01097                                           bv.bv_len = si->si_url.bv_len + 6;
01098                                           bv.bv_val = ch_malloc( bv.bv_len );
01099                                           bv.bv_len = sprintf( bv.bv_val, "%d %s", si->si_num,
01100                                                  si->si_url.bv_val );
01101                                           ber_bvarray_add( &c->rvalue_vals, &bv );
01102                                    } else {
01103                                           char buf[5];
01104                                           bv.bv_val = buf;
01105                                           bv.bv_len = sprintf( buf, "%d", si->si_num );
01106                                           value_add_one( &c->rvalue_vals, &bv );
01107                                    }
01108                             }
01109                      } else {
01110                             rc = 1;
01111                      }
01112                      break;
01113               case CFG_LOGFILE:
01114                      if ( logfileName )
01115                             c->value_string = ch_strdup( logfileName );
01116                      else
01117                             rc = 1;
01118                      break;
01119               case CFG_LASTMOD:
01120                      c->value_int = (SLAP_NOLASTMOD(c->be) == 0);
01121                      break;
01122               case CFG_SYNC_SUBENTRY:
01123                      c->value_int = (SLAP_SYNC_SUBENTRY(c->be) != 0);
01124                      break;
01125               case CFG_MIRRORMODE:
01126                      if ( SLAP_SHADOW(c->be))
01127                             c->value_int = (SLAP_MULTIMASTER(c->be) != 0);
01128                      else
01129                             rc = 1;
01130                      break;
01131               case CFG_MONITORING:
01132                      c->value_int = (SLAP_DBMONITORING(c->be) != 0);
01133                      break;
01134               case CFG_SSTR_IF_MAX:
01135                      c->value_uint = index_substr_if_maxlen;
01136                      break;
01137               case CFG_SSTR_IF_MIN:
01138                      c->value_uint = index_substr_if_minlen;
01139                      break;
01140               case CFG_IX_INTLEN:
01141                      c->value_int = index_intlen;
01142                      break;
01143               case CFG_SORTVALS: {
01144                      ADlist *sv;
01145                      rc = 1;
01146                      for ( sv = sortVals; sv; sv = sv->al_next ) {
01147                             value_add_one( &c->rvalue_vals, &sv->al_desc->ad_cname );
01148                             rc = 0;
01149                      }
01150                      } break;
01151 #ifdef SLAPD_MODULES
01152               case CFG_MODLOAD: {
01153                      ModPaths *mp = c->ca_private;
01154                      if (mp->mp_loads) {
01155                             int i;
01156                             for (i=0; !BER_BVISNULL(&mp->mp_loads[i]); i++) {
01157                                    struct berval bv;
01158                                    bv.bv_val = c->log;
01159                                    bv.bv_len = snprintf( bv.bv_val, sizeof( c->log ),
01160                                           SLAP_X_ORDERED_FMT "%s", i,
01161                                           mp->mp_loads[i].bv_val );
01162                                    if ( bv.bv_len >= sizeof( c->log ) ) {
01163                                           ber_bvarray_free_x( c->rvalue_vals, NULL );
01164                                           c->rvalue_vals = NULL;
01165                                           break;
01166                                    }
01167                                    value_add_one( &c->rvalue_vals, &bv );
01168                             }
01169                      }
01170 
01171                      rc = c->rvalue_vals ? 0 : 1;
01172                      }
01173                      break;
01174               case CFG_MODPATH: {
01175                      ModPaths *mp = c->ca_private;
01176                      if ( !BER_BVISNULL( &mp->mp_path ))
01177                             value_add_one( &c->rvalue_vals, &mp->mp_path );
01178 
01179                      rc = c->rvalue_vals ? 0 : 1;
01180                      }
01181                      break;
01182 #endif
01183 #ifdef LDAP_SLAPI
01184               case CFG_PLUGIN:
01185                      slapi_int_plugin_unparse( c->be, &c->rvalue_vals );
01186                      if ( !c->rvalue_vals ) rc = 1;
01187                      break;
01188 #endif
01189 #ifdef SLAP_AUTH_REWRITE
01190               case CFG_REWRITE:
01191                      if ( authz_rewrites ) {
01192                             struct berval bv, idx;
01193                             char ibuf[32];
01194                             int i;
01195 
01196                             idx.bv_val = ibuf;
01197                             for ( i=0; !BER_BVISNULL( &authz_rewrites[i] ); i++ ) {
01198                                    idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
01199                                    if ( idx.bv_len >= sizeof( ibuf ) ) {
01200                                           ber_bvarray_free_x( c->rvalue_vals, NULL );
01201                                           c->rvalue_vals = NULL;
01202                                           break;
01203                                    }
01204                                    bv.bv_len = idx.bv_len + authz_rewrites[i].bv_len;
01205                                    bv.bv_val = ch_malloc( bv.bv_len + 1 );
01206                                    AC_MEMCPY( bv.bv_val, idx.bv_val, idx.bv_len );
01207                                    AC_MEMCPY( &bv.bv_val[ idx.bv_len ],
01208                                           authz_rewrites[i].bv_val,
01209                                           authz_rewrites[i].bv_len + 1 );
01210                                    ber_bvarray_add( &c->rvalue_vals, &bv );
01211                             }
01212                      }
01213                      if ( !c->rvalue_vals ) rc = 1;
01214                      break;
01215 #endif
01216               default:
01217                      rc = 1;
01218               }
01219               return rc;
01220        } else if ( c->op == LDAP_MOD_DELETE ) {
01221               int rc = 0;
01222               switch(c->type) {
01223               /* single-valued attrs, no-ops */
01224               case CFG_CONCUR:
01225               case CFG_THREADS:
01226               case CFG_TTHREADS:
01227               case CFG_LTHREADS:
01228               case CFG_RO:
01229               case CFG_AZPOLICY:
01230               case CFG_DEPTH:
01231               case CFG_LASTMOD:
01232               case CFG_MONITORING:
01233               case CFG_SASLSECP:
01234               case CFG_SSTR_IF_MAX:
01235               case CFG_SSTR_IF_MIN:
01236               case CFG_ACL_ADD:
01237               case CFG_SYNC_SUBENTRY:
01238                      break;
01239 
01240               /* no-ops, requires slapd restart */
01241               case CFG_PLUGIN:
01242               case CFG_MODLOAD:
01243               case CFG_AZREGEXP:
01244               case CFG_REWRITE:
01245                      snprintf(c->log, sizeof( c->log ), "change requires slapd restart");
01246                      break;
01247 
01248               case CFG_MIRRORMODE:
01249                      SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_MULTI_SHADOW;
01250                      if(SLAP_SHADOW(c->be))
01251                             SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SINGLE_SHADOW;
01252                      break;
01253 
01254               case CFG_SALT:
01255                      ch_free( passwd_salt );
01256                      passwd_salt = NULL;
01257                      break;
01258 
01259               case CFG_LOGFILE:
01260                      ch_free( logfileName );
01261                      logfileName = NULL;
01262                      if ( logfile ) {
01263                             fclose( logfile );
01264                             logfile = NULL;
01265                      }
01266                      break;
01267 
01268               case CFG_SERVERID: {
01269                      ServerID *si, **sip;
01270 
01271                      for ( i=0, si = sid_list, sip = &sid_list;
01272                             si; si = *sip, i++ ) {
01273                             if ( c->valx == -1 || i == c->valx ) {
01274                                    *sip = si->si_next;
01275                                    if ( sid_set == si )
01276                                           sid_set = NULL;
01277                                    ch_free( si );
01278                                    if ( c->valx >= 0 )
01279                                           break;
01280                             } else {
01281                                    sip = &si->si_next;
01282                             }
01283                      }
01284                      }
01285                      break;
01286               case CFG_HIDDEN:
01287                      c->be->be_flags &= ~SLAP_DBFLAG_HIDDEN;
01288                      break;
01289 
01290               case CFG_IX_INTLEN:
01291                      index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
01292                      index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
01293                             SLAP_INDEX_INTLEN_DEFAULT );
01294                      break;
01295 
01296               case CFG_ACL:
01297                      if ( c->valx < 0 ) {
01298                             acl_destroy( c->be->be_acl );
01299                             c->be->be_acl = NULL;
01300 
01301                      } else {
01302                             AccessControl **prev, *a;
01303                             int i;
01304                             for (i=0, prev = &c->be->be_acl; i < c->valx;
01305                                    i++ ) {
01306                                    a = *prev;
01307                                    prev = &a->acl_next;
01308                             }
01309                             a = *prev;
01310                             *prev = a->acl_next;
01311                             acl_free( a );
01312                      }
01313                      if ( SLAP_CONFIG( c->be ) && !c->be->be_acl ) {
01314                             Debug( LDAP_DEBUG_CONFIG, "config_generic (CFG_ACL): "
01315                                           "Last explicit ACL for back-config removed. "
01316                                           "Using hardcoded default\n", 0, 0, 0 );
01317                             c->be->be_acl = defacl_parsed;
01318                      }
01319                      break;
01320 
01321               case CFG_OC: {
01322                      CfEntryInfo *ce;
01323                      /* Can be NULL when undoing a failed add */
01324                      if ( c->ca_entry ) {
01325                             ce = c->ca_entry->e_private;
01326                             /* can't modify the hardcoded schema */
01327                             if ( ce->ce_parent->ce_type == Cft_Global )
01328                                    return 1;
01329                             }
01330                      }
01331                      cfn = c->ca_private;
01332                      if ( c->valx < 0 ) {
01333                             ObjectClass *oc;
01334 
01335                             for( oc = cfn->c_oc_head; oc; oc_next( &oc )) {
01336                                    oc_delete( oc );
01337                                    if ( oc  == cfn->c_oc_tail )
01338                                           break;
01339                             }
01340                             cfn->c_oc_head = cfn->c_oc_tail = NULL;
01341                      } else {
01342                             ObjectClass *oc, *prev = NULL;
01343 
01344                             for ( i=0, oc=cfn->c_oc_head; i<c->valx; i++) {
01345                                    prev = oc;
01346                                    oc_next( &oc );
01347                             }
01348                             oc_delete( oc );
01349                             if ( cfn->c_oc_tail == oc ) {
01350                                    cfn->c_oc_tail = prev;
01351                             }
01352                             if ( cfn->c_oc_head == oc ) {
01353                                    oc_next( &oc );
01354                                    cfn->c_oc_head = oc;
01355                             }
01356                      }
01357                      break;
01358 
01359               case CFG_ATTR: {
01360                      CfEntryInfo *ce;
01361                      /* Can be NULL when undoing a failed add */
01362                      if ( c->ca_entry ) {
01363                             ce = c->ca_entry->e_private;
01364                             /* can't modify the hardcoded schema */
01365                             if ( ce->ce_parent->ce_type == Cft_Global )
01366                                    return 1;
01367                             }
01368                      }
01369                      cfn = c->ca_private;
01370                      if ( c->valx < 0 ) {
01371                             AttributeType *at;
01372 
01373                             for( at = cfn->c_at_head; at; at_next( &at )) {
01374                                    at_delete( at );
01375                                    if ( at  == cfn->c_at_tail )
01376                                           break;
01377                             }
01378                             cfn->c_at_head = cfn->c_at_tail = NULL;
01379                      } else {
01380                             AttributeType *at, *prev = NULL;
01381 
01382                             for ( i=0, at=cfn->c_at_head; i<c->valx; i++) {
01383                                    prev = at;
01384                                    at_next( &at );
01385                             }
01386                             at_delete( at );
01387                             if ( cfn->c_at_tail == at ) {
01388                                    cfn->c_at_tail = prev;
01389                             }
01390                             if ( cfn->c_at_head == at ) {
01391                                    at_next( &at );
01392                                    cfn->c_at_head = at;
01393                             }
01394                      }
01395                      break;
01396 
01397               case CFG_SYNTAX: {
01398                      CfEntryInfo *ce;
01399                      /* Can be NULL when undoing a failed add */
01400                      if ( c->ca_entry ) {
01401                             ce = c->ca_entry->e_private;
01402                             /* can't modify the hardcoded schema */
01403                             if ( ce->ce_parent->ce_type == Cft_Global )
01404                                    return 1;
01405                             }
01406                      }
01407                      cfn = c->ca_private;
01408                      if ( c->valx < 0 ) {
01409                             Syntax *syn;
01410 
01411                             for( syn = cfn->c_syn_head; syn; syn_next( &syn )) {
01412                                    syn_delete( syn );
01413                                    if ( syn == cfn->c_syn_tail )
01414                                           break;
01415                             }
01416                             cfn->c_syn_head = cfn->c_syn_tail = NULL;
01417                      } else {
01418                             Syntax *syn, *prev = NULL;
01419 
01420                             for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++) {
01421                                    prev = syn;
01422                                    syn_next( &syn );
01423                             }
01424                             syn_delete( syn );
01425                             if ( cfn->c_syn_tail == syn ) {
01426                                    cfn->c_syn_tail = prev;
01427                             }
01428                             if ( cfn->c_syn_head == syn ) {
01429                                    syn_next( &syn );
01430                                    cfn->c_syn_head = syn;
01431                             }
01432                      }
01433                      break;
01434               case CFG_SORTVALS:
01435                      if ( c->valx < 0 ) {
01436                             ADlist *sv;
01437                             for ( sv = sortVals; sv; sv = sortVals ) {
01438                                    sortVals = sv->al_next;
01439                                    sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL;
01440                                    ch_free( sv );
01441                             }
01442                      } else {
01443                             ADlist *sv, **prev;
01444                             int i = 0;
01445 
01446                             for ( prev = &sortVals, sv = sortVals; i < c->valx; i++ ) {
01447                                    prev = &sv->al_next;
01448                                    sv = sv->al_next;
01449                             }
01450                             sv->al_desc->ad_type->sat_flags &= ~SLAP_AT_SORTED_VAL;
01451                             *prev = sv->al_next;
01452                             ch_free( sv );
01453                      }
01454                      break;
01455 
01456               case CFG_LIMITS:
01457                      /* FIXME: there is no limits_free function */
01458                      if ( c->valx < 0 ) {
01459                             limits_destroy( c->be->be_limits );
01460                             c->be->be_limits = NULL;
01461 
01462                      } else {
01463                             int cnt, num = -1;
01464 
01465                             if ( c->be->be_limits ) {
01466                                    for ( num = 0; c->be->be_limits[ num ]; num++ )
01467                                           /* just count */ ;
01468                             }
01469 
01470                             if ( c->valx >= num ) {
01471                                    return 1;
01472                             }
01473 
01474                             if ( num == 1 ) {
01475                                    limits_destroy( c->be->be_limits );
01476                                    c->be->be_limits = NULL;
01477 
01478                             } else {
01479                                    limits_free_one( c->be->be_limits[ c->valx ] );
01480 
01481                                    for ( cnt = c->valx; cnt < num; cnt++ ) {
01482                                           c->be->be_limits[ cnt ] = c->be->be_limits[ cnt + 1 ];
01483                                    }
01484                             }
01485                      }
01486                      break;
01487 
01488               case CFG_ATOPT:
01489                      /* FIXME: there is no ad_option_free function */
01490               case CFG_ROOTDSE:
01491                      /* FIXME: there is no way to remove attributes added by
01492                             a DSE file */
01493               case CFG_OID:
01494               case CFG_DIT:
01495               case CFG_MODPATH:
01496               default:
01497                      rc = 1;
01498                      break;
01499               }
01500               return rc;
01501        }
01502 
01503        switch(c->type) {
01504               case CFG_BACKEND:
01505                      if(!(c->bi = backend_info(c->argv[1]))) {
01506                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> failed init", c->argv[0] );
01507                             Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
01508                                    c->log, c->cr_msg, c->argv[1] );
01509                             return(1);
01510                      }
01511                      break;
01512 
01513               case CFG_DATABASE:
01514                      c->bi = NULL;
01515                      /* NOTE: config is always the first backend!
01516                       */
01517                      if ( !strcasecmp( c->argv[1], "config" )) {
01518                             c->be = LDAP_STAILQ_FIRST(&backendDB);
01519                      } else if ( !strcasecmp( c->argv[1], "frontend" )) {
01520                             c->be = frontendDB;
01521                      } else {
01522                             c->be = backend_db_init(c->argv[1], NULL, c->valx, &c->reply);
01523                             if ( !c->be ) {
01524                                    if ( c->cr_msg[0] == 0 )
01525                                           snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> failed init", c->argv[0] );
01526                                    Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n", c->log, c->cr_msg, c->argv[1] );
01527                                    return(1);
01528                             }
01529                      }
01530                      break;
01531 
01532               case CFG_CONCUR:
01533                      ldap_pvt_thread_set_concurrency(c->value_int);
01534                      break;
01535 
01536               case CFG_THREADS:
01537                      if ( c->value_int < 2 ) {
01538                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
01539                                    "threads=%d smaller than minimum value 2",
01540                                    c->value_int );
01541                             Debug(LDAP_DEBUG_ANY, "%s: %s.\n",
01542                                    c->log, c->cr_msg, 0 );
01543                             return 1;
01544 
01545                      } else if ( c->value_int > 2 * SLAP_MAX_WORKER_THREADS ) {
01546                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
01547                                    "warning, threads=%d larger than twice the default (2*%d=%d); YMMV",
01548                                    c->value_int, SLAP_MAX_WORKER_THREADS, 2 * SLAP_MAX_WORKER_THREADS );
01549                             Debug(LDAP_DEBUG_ANY, "%s: %s.\n",
01550                                    c->log, c->cr_msg, 0 );
01551                      }
01552                      if ( slapMode & SLAP_SERVER_MODE )
01553                             ldap_pvt_thread_pool_maxthreads(&connection_pool, c->value_int);
01554                      connection_pool_max = c->value_int;       /* save for reference */
01555                      break;
01556 
01557               case CFG_TTHREADS:
01558                      if ( slapMode & SLAP_TOOL_MODE )
01559                             ldap_pvt_thread_pool_maxthreads(&connection_pool, c->value_int);
01560                      slap_tool_thread_max = c->value_int;      /* save for reference */
01561                      break;
01562 
01563               case CFG_LTHREADS:
01564                      { int mask = 0;
01565                      /* use a power of two */
01566                      while (c->value_uint > 1) {
01567                             c->value_uint >>= 1;
01568                             mask <<= 1;
01569                             mask |= 1;
01570                      }
01571                      slapd_daemon_mask = mask;
01572                      slapd_daemon_threads = mask+1;
01573                      }
01574                      break;
01575 
01576               case CFG_SALT:
01577                      if ( passwd_salt ) ch_free( passwd_salt );
01578                      passwd_salt = c->value_string;
01579                      lutil_salt_format(passwd_salt);
01580                      break;
01581 
01582               case CFG_LIMITS:
01583                      if(limits_parse(c->be, c->fname, c->lineno, c->argc, c->argv))
01584                             return(1);
01585                      break;
01586 
01587               case CFG_RO:
01588                      if(c->value_int)
01589                             c->be->be_restrictops |= SLAP_RESTRICT_READONLY;
01590                      else
01591                             c->be->be_restrictops &= ~SLAP_RESTRICT_READONLY;
01592                      break;
01593 
01594               case CFG_AZPOLICY:
01595                      ch_free(c->value_string);
01596                      if (slap_sasl_setpolicy( c->argv[1] )) {
01597                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] );
01598                             Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
01599                                    c->log, c->cr_msg, c->argv[1] );
01600                             return(1);
01601                      }
01602                      break;
01603               
01604               case CFG_AZREGEXP:
01605                      if (slap_sasl_regexp_config( c->argv[1], c->argv[2] ))
01606                             return(1);
01607                      break;
01608                             
01609 #ifdef HAVE_CYRUS_SASL
01610               case CFG_SASLSECP:
01611                      {
01612                      char *txt = slap_sasl_secprops( c->argv[1] );
01613                      if ( txt ) {
01614                             snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> %s",
01615                                    c->argv[0], txt );
01616                             Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0 );
01617                             return(1);
01618                      }
01619                      break;
01620                      }
01621 #endif
01622 
01623               case CFG_DEPTH:
01624                      c->be->be_max_deref_depth = c->value_int;
01625                      break;
01626 
01627               case CFG_OID: {
01628                      OidMacro *om;
01629 
01630                      if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
01631                             cfn = c->ca_private;
01632                      if(parse_oidm(c, 1, &om))
01633                             return(1);
01634                      if (!cfn->c_om_head) cfn->c_om_head = om;
01635                      cfn->c_om_tail = om;
01636                      }
01637                      break;
01638 
01639               case CFG_OC: {
01640                      ObjectClass *oc, *prev;
01641 
01642                      if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
01643                             cfn = c->ca_private;
01644                      if ( c->valx < 0 ) {
01645                             prev = cfn->c_oc_tail;
01646                      } else {
01647                             prev = NULL;
01648                             /* If adding anything after the first, prev is easy */
01649                             if ( c->valx ) {
01650                                    int i;
01651                                    for (i=0, oc = cfn->c_oc_head; i<c->valx; i++) {
01652                                           prev = oc;
01653                                           if ( !oc_next( &oc ))
01654                                                  break;
01655                                    }
01656                             } else
01657                             /* If adding the first, and head exists, find its prev */
01658                                    if (cfn->c_oc_head) {
01659                                    for ( oc_start( &oc ); oc != cfn->c_oc_head; ) {
01660                                           prev = oc;
01661                                           oc_next( &oc );
01662                                    }
01663                             }
01664                             /* else prev is NULL, append to end of global list */
01665                      }
01666                      if(parse_oc(c, &oc, prev)) return(1);
01667                      if (!cfn->c_oc_head || !c->valx) cfn->c_oc_head = oc;
01668                      if (cfn->c_oc_tail == prev) cfn->c_oc_tail = oc;
01669                      }
01670                      break;
01671 
01672               case CFG_ATTR: {
01673                      AttributeType *at, *prev;
01674 
01675                      if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
01676                             cfn = c->ca_private;
01677                      if ( c->valx < 0 ) {
01678                             prev = cfn->c_at_tail;
01679                      } else {
01680                             prev = NULL;
01681                             /* If adding anything after the first, prev is easy */
01682                             if ( c->valx ) {
01683                                    int i;
01684                                    for (i=0, at = cfn->c_at_head; i<c->valx; i++) {
01685                                           prev = at;
01686                                           if ( !at_next( &at ))
01687                                                  break;
01688                                    }
01689                             } else
01690                             /* If adding the first, and head exists, find its prev */
01691                                    if (cfn->c_at_head) {
01692                                    for ( at_start( &at ); at != cfn->c_at_head; ) {
01693                                           prev = at;
01694                                           at_next( &at );
01695                                    }
01696                             }
01697                             /* else prev is NULL, append to end of global list */
01698                      }
01699                      if(parse_at(c, &at, prev)) return(1);
01700                      if (!cfn->c_at_head || !c->valx) cfn->c_at_head = at;
01701                      if (cfn->c_at_tail == prev) cfn->c_at_tail = at;
01702                      }
01703                      break;
01704 
01705               case CFG_SYNTAX: {
01706                      Syntax *syn, *prev;
01707 
01708                      if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
01709                             cfn = c->ca_private;
01710                      if ( c->valx < 0 ) {
01711                             prev = cfn->c_syn_tail;
01712                      } else {
01713                             prev = NULL;
01714                             /* If adding anything after the first, prev is easy */
01715                             if ( c->valx ) {
01716                                    int i;
01717                                    for ( i = 0, syn = cfn->c_syn_head; i < c->valx; i++ ) {
01718                                           prev = syn;
01719                                           if ( !syn_next( &syn ))
01720                                                  break;
01721                                    }
01722                             } else
01723                             /* If adding the first, and head exists, find its prev */
01724                                    if (cfn->c_syn_head) {
01725                                    for ( syn_start( &syn ); syn != cfn->c_syn_head; ) {
01726                                           prev = syn;
01727                                           syn_next( &syn );
01728                                    }
01729                             }
01730                             /* else prev is NULL, append to end of global list */
01731                      }
01732                      if ( parse_syn( c, &syn, prev ) ) return(1);
01733                      if ( !cfn->c_syn_head || !c->valx ) cfn->c_syn_head = syn;
01734                      if ( cfn->c_syn_tail == prev ) cfn->c_syn_tail = syn;
01735                      }
01736                      break;
01737 
01738               case CFG_DIT: {
01739                      ContentRule *cr;
01740 
01741                      if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
01742                             cfn = c->ca_private;
01743                      if(parse_cr(c, &cr)) return(1);
01744                      if (!cfn->c_cr_head) cfn->c_cr_head = cr;
01745                      cfn->c_cr_tail = cr;
01746                      }
01747                      break;
01748 
01749               case CFG_ATOPT:
01750                      ad_define_option(NULL, NULL, 0);
01751                      for(i = 1; i < c->argc; i++)
01752                             if(ad_define_option(c->argv[i], c->fname, c->lineno))
01753                                    return(1);
01754                      break;
01755 
01756               case CFG_IX_INTLEN:
01757                      if ( c->value_int < SLAP_INDEX_INTLEN_DEFAULT )
01758                             c->value_int = SLAP_INDEX_INTLEN_DEFAULT;
01759                      else if ( c->value_int > 255 )
01760                             c->value_int = 255;
01761                      index_intlen = c->value_int;
01762                      index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
01763                             index_intlen );
01764                      break;
01765                      
01766               case CFG_SORTVALS: {
01767                      ADlist *svnew = NULL, *svtail, *sv;
01768 
01769                      for ( i = 1; i < c->argc; i++ ) {
01770                             AttributeDescription *ad = NULL;
01771                             const char *text;
01772                             int rc;
01773 
01774                             rc = slap_str2ad( c->argv[i], &ad, &text );
01775                             if ( rc ) {
01776                                    snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown attribute type #%d",
01777                                           c->argv[0], i );
01778 sortval_reject:
01779                                    Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
01780                                           c->log, c->cr_msg, c->argv[i] );
01781                                    for ( sv = svnew; sv; sv = svnew ) {
01782                                           svnew = sv->al_next;
01783                                           ch_free( sv );
01784                                    }
01785                                    return 1;
01786                             }
01787                             if (( ad->ad_type->sat_flags & SLAP_AT_ORDERED ) ||
01788                                    ad->ad_type->sat_single_value ) {
01789                                    snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> inappropriate attribute type #%d",
01790                                           c->argv[0], i );
01791                                    goto sortval_reject;
01792                             }
01793                             sv = ch_malloc( sizeof( ADlist ));
01794                             sv->al_desc = ad;
01795                             if ( !svnew ) {
01796                                    svnew = sv;
01797                             } else {
01798                                    svtail->al_next = sv;
01799                             }
01800                             svtail = sv;
01801                      }
01802                      sv->al_next = NULL;
01803                      for ( sv = svnew; sv; sv = sv->al_next )
01804                             sv->al_desc->ad_type->sat_flags |= SLAP_AT_SORTED_VAL;
01805                      for ( sv = sortVals; sv && sv->al_next; sv = sv->al_next );
01806                      if ( sv )
01807                             sv->al_next = svnew;
01808                      else
01809                             sortVals = svnew;
01810                      }
01811                      break;
01812 
01813               case CFG_ACL:
01814                      if ( SLAP_CONFIG( c->be ) && c->be->be_acl == defacl_parsed) {
01815                             c->be->be_acl = NULL;
01816                      }
01817                      /* Don't append to the global ACL if we're on a specific DB */
01818                      i = c->valx;
01819                      if ( c->valx == -1 ) {
01820                             AccessControl *a;
01821                             i = 0;
01822                             for ( a=c->be->be_acl; a; a = a->acl_next )
01823                                    i++;
01824                      }
01825                      if ( parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, i ) ) {
01826                             if ( SLAP_CONFIG( c->be ) && !c->be->be_acl) {
01827                                    c->be->be_acl = defacl_parsed;
01828                             }
01829                             return 1;
01830                      }
01831                      break;
01832 
01833               case CFG_ACL_ADD:
01834                      if(c->value_int)
01835                             SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_ACL_ADD;
01836                      else
01837                             SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_ACL_ADD;
01838                      break;
01839 
01840               case CFG_ROOTDSE:
01841                      if(root_dse_read_file(c->argv[1])) {
01842                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> could not read file", c->argv[0] );
01843                             Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
01844                                    c->log, c->cr_msg, c->argv[1] );
01845                             return(1);
01846                      }
01847                      {
01848                             struct berval bv;
01849                             ber_str2bv( c->argv[1], 0, 1, &bv );
01850                             if ( c->op == LDAP_MOD_ADD && c->ca_private && cfn != c->ca_private )
01851                                    cfn = c->ca_private;
01852                             ber_bvarray_add( &cfn->c_dseFiles, &bv );
01853                      }
01854                      break;
01855 
01856               case CFG_SERVERID:
01857                      {
01858                             ServerID *si, **sip;
01859                             LDAPURLDesc *lud;
01860                             int num;
01861                             if (( lutil_atoi( &num, c->argv[1] ) &&   
01862                                    lutil_atoix( &num, c->argv[1], 16 )) ||
01863                                    num < 0 || num > SLAP_SYNC_SID_MAX )
01864                             {
01865                                    snprintf( c->cr_msg, sizeof( c->cr_msg ),
01866                                           "<%s> illegal server ID", c->argv[0] );
01867                                    Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
01868                                           c->log, c->cr_msg, c->argv[1] );
01869                                    return 1;
01870                             }
01871                             /* only one value allowed if no URL is given */
01872                             if ( c->argc > 2 ) {
01873                                    int len;
01874 
01875                                    if ( sid_list && BER_BVISEMPTY( &sid_list->si_url )) {
01876                                           snprintf( c->cr_msg, sizeof( c->cr_msg ),
01877                                                  "<%s> only one server ID allowed now", c->argv[0] );
01878                                           Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
01879                                                  c->log, c->cr_msg, c->argv[1] );
01880                                           return 1;
01881                                    }
01882 
01883                                    if ( ldap_url_parse( c->argv[2], &lud )) {
01884                                           snprintf( c->cr_msg, sizeof( c->cr_msg ),
01885                                                  "<%s> invalid URL", c->argv[0] );
01886                                           Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
01887                                                  c->log, c->cr_msg, c->argv[2] );
01888                                           return 1;
01889                                    }
01890                                    len = strlen( c->argv[2] );
01891                                    si = ch_malloc( sizeof(ServerID) + len + 1 );
01892                                    si->si_url.bv_val = (char *)(si+1);
01893                                    si->si_url.bv_len = len;
01894                                    strcpy( si->si_url.bv_val, c->argv[2] );
01895                             } else {
01896                                    if ( sid_list ) {
01897                                           snprintf( c->cr_msg, sizeof( c->cr_msg ),
01898                                                  "<%s> unqualified server ID not allowed now", c->argv[0] );
01899                                           Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
01900                                                  c->log, c->cr_msg, c->argv[1] );
01901                                           return 1;
01902                                    }
01903                                    si = ch_malloc( sizeof(ServerID) );
01904                                    BER_BVZERO( &si->si_url );
01905                                    slap_serverID = num;
01906                                    Debug( LDAP_DEBUG_CONFIG,
01907                                           "%s: SID=0x%03x\n",
01908                                           c->log, slap_serverID, 0 );
01909                                    sid_set = si;
01910                             }
01911                             si->si_next = NULL;
01912                             si->si_num = num;
01913                             for ( sip = &sid_list; *sip; sip = &(*sip)->si_next );
01914                             *sip = si;
01915 
01916                             if (( slapMode & SLAP_SERVER_MODE ) && c->argc > 2 ) {
01917                                    Listener *l = config_check_my_url( c->argv[2], lud );
01918                                    if ( l ) {
01919                                           if ( sid_set ) {
01920                                                  ldap_free_urldesc( lud );
01921                                                  snprintf( c->cr_msg, sizeof( c->cr_msg ),
01922                                                         "<%s> multiple server ID URLs matched, only one is allowed", c->argv[0] );
01923                                                  Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
01924                                                         c->log, c->cr_msg, c->argv[1] );
01925                                                  return 1;
01926                                           }
01927                                           slap_serverID = si->si_num;
01928                                           Debug( LDAP_DEBUG_CONFIG,
01929                                                  "%s: SID=0x%03x (listener=%s)\n",
01930                                                  c->log, slap_serverID,
01931                                                  l->sl_url.bv_val );
01932                                           sid_set = si;
01933                                    }
01934                             }
01935                             if ( c->argc > 2 )
01936                                    ldap_free_urldesc( lud );
01937                      }
01938                      break;
01939               case CFG_LOGFILE: {
01940                             if ( logfileName ) ch_free( logfileName );
01941                             logfileName = c->value_string;
01942                             logfile = fopen(logfileName, "w");
01943                             if(logfile) lutil_debug_file(logfile);
01944                      } break;
01945 
01946               case CFG_LASTMOD:
01947                      if(SLAP_NOLASTMODCMD(c->be)) {
01948                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> not available for %s database",
01949                                    c->argv[0], c->be->bd_info->bi_type );
01950                             Debug(LDAP_DEBUG_ANY, "%s: %s\n",
01951                                    c->log, c->cr_msg, 0 );
01952                             return(1);
01953                      }
01954                      if(c->value_int)
01955                             SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_NOLASTMOD;
01956                      else
01957                             SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_NOLASTMOD;
01958                      break;
01959 
01960               case CFG_MIRRORMODE:
01961                      if(c->value_int && !SLAP_SHADOW(c->be)) {
01962                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database is not a shadow",
01963                                    c->argv[0] );
01964                             Debug(LDAP_DEBUG_ANY, "%s: %s\n",
01965                                    c->log, c->cr_msg, 0 );
01966                             return(1);
01967                      }
01968                      if(c->value_int) {
01969                             SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_SINGLE_SHADOW;
01970                             SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_MULTI_SHADOW;
01971                      } else {
01972                             SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SINGLE_SHADOW;
01973                             SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_MULTI_SHADOW;
01974                      }
01975                      break;
01976 
01977               case CFG_MONITORING:
01978                      if(c->value_int)
01979                             SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_MONITORING;
01980                      else
01981                             SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_MONITORING;
01982                      break;
01983 
01984               case CFG_HIDDEN:
01985                      if (c->value_int)
01986                             SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_HIDDEN;
01987                      else
01988                             SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_HIDDEN;
01989                      break;
01990 
01991               case CFG_SYNC_SUBENTRY:
01992                      if (c->value_int)
01993                             SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SYNC_SUBENTRY;
01994                      else
01995                             SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_SYNC_SUBENTRY;
01996                      break;
01997 
01998               case CFG_SSTR_IF_MAX:
01999                      if (c->value_uint < index_substr_if_minlen) {
02000                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] );
02001                             Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n",
02002                                    c->log, c->cr_msg, c->value_int );
02003                             return(1);
02004                      }
02005                      index_substr_if_maxlen = c->value_uint;
02006                      break;
02007 
02008               case CFG_SSTR_IF_MIN:
02009                      if (c->value_uint > index_substr_if_maxlen) {
02010                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] );
02011                             Debug(LDAP_DEBUG_ANY, "%s: %s (%d)\n",
02012                                    c->log, c->cr_msg, c->value_int );
02013                             return(1);
02014                      }
02015                      index_substr_if_minlen = c->value_uint;
02016                      break;
02017 
02018 #ifdef SLAPD_MODULES
02019               case CFG_MODLOAD:
02020                      /* If we're just adding a module on an existing modpath,
02021                       * make sure we've selected the current path.
02022                       */
02023                      if ( c->op == LDAP_MOD_ADD && c->ca_private && modcur != c->ca_private ) {
02024                             modcur = c->ca_private;
02025                             /* This should never fail */
02026                             if ( module_path( modcur->mp_path.bv_val )) {
02027                                    snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> module path no longer valid",
02028                                           c->argv[0] );
02029                                    Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
02030                                           c->log, c->cr_msg, modcur->mp_path.bv_val );
02031                                    return(1);
02032                             }
02033                      }
02034                      if(module_load(c->argv[1], c->argc - 2, (c->argc > 2) ? c->argv + 2 : NULL))
02035                             return(1);
02036                      /* Record this load on the current path */
02037                      {
02038                             struct berval bv;
02039                             char *ptr;
02040                             if ( c->op == SLAP_CONFIG_ADD ) {
02041                                    ptr = c->line + STRLENOF("moduleload");
02042                                    while (!isspace((unsigned char) *ptr)) ptr++;
02043                                    while (isspace((unsigned char) *ptr)) ptr++;
02044                             } else {
02045                                    ptr = c->line;
02046                             }
02047                             ber_str2bv(ptr, 0, 1, &bv);
02048                             ber_bvarray_add( &modcur->mp_loads, &bv );
02049                      }
02050                      /* Check for any new hardcoded schema */
02051                      if ( c->op == LDAP_MOD_ADD && CONFIG_ONLINE_ADD( c )) {
02052                             config_check_schema( NULL, &cfBackInfo );
02053                      }
02054                      break;
02055 
02056               case CFG_MODPATH:
02057                      if(module_path(c->argv[1])) return(1);
02058                      /* Record which path was used with each module */
02059                      {
02060                             ModPaths *mp;
02061 
02062                             if (!modpaths.mp_loads) {
02063                                    mp = &modpaths;
02064                             } else {
02065                                    mp = ch_malloc( sizeof( ModPaths ));
02066                                    modlast->mp_next = mp;
02067                             }
02068                             ber_str2bv(c->argv[1], 0, 1, &mp->mp_path);
02069                             mp->mp_next = NULL;
02070                             mp->mp_loads = NULL;
02071                             modlast = mp;
02072                             c->ca_private = mp;
02073                             modcur = mp;
02074                      }
02075                      
02076                      break;
02077 #endif
02078 
02079 #ifdef LDAP_SLAPI
02080               case CFG_PLUGIN:
02081                      if(slapi_int_read_config(c->be, c->fname, c->lineno, c->argc, c->argv) != LDAP_SUCCESS)
02082                             return(1);
02083                      slapi_plugins_used++;
02084                      break;
02085 #endif
02086 
02087 #ifdef SLAP_AUTH_REWRITE
02088               case CFG_REWRITE: {
02089                      struct berval bv;
02090                      char *line;
02091                      int rc = 0;
02092 
02093                      if ( c->op == LDAP_MOD_ADD ) {
02094                             c->argv++;
02095                             c->argc--;
02096                      }
02097                      if(slap_sasl_rewrite_config(c->fname, c->lineno, c->argc, c->argv))
02098                             rc = 1;
02099                      if ( rc == 0 ) {
02100 
02101                             if ( c->argc > 1 ) {
02102                                    char   *s;
02103 
02104                                    /* quote all args but the first */
02105                                    line = ldap_charray2str( c->argv, "\" \"" );
02106                                    ber_str2bv( line, 0, 0, &bv );
02107                                    s = ber_bvchr( &bv, '"' );
02108                                    assert( s != NULL );
02109                                    /* move the trailing quote of argv[0] to the end */
02110                                    AC_MEMCPY( s, s + 1, bv.bv_len - ( s - bv.bv_val ) );
02111                                    bv.bv_val[ bv.bv_len - 1 ] = '"';
02112 
02113                             } else {
02114                                    ber_str2bv( c->argv[ 0 ], 0, 1, &bv );
02115                             }
02116 
02117                             ber_bvarray_add( &authz_rewrites, &bv );
02118                      }
02119                      if ( c->op == LDAP_MOD_ADD ) {
02120                             c->argv--;
02121                             c->argc++;
02122                      }
02123                      return rc;
02124                      }
02125 #endif
02126 
02127 
02128               default:
02129                      Debug( LDAP_DEBUG_ANY,
02130                             "%s: unknown CFG_TYPE %d.\n",
02131                             c->log, c->type, 0 );
02132                      return 1;
02133 
02134        }
02135        return(0);
02136 }
02137 
02138 
02139 static int
02140 config_fname(ConfigArgs *c) {
02141        if(c->op == SLAP_CONFIG_EMIT) {
02142               if (c->ca_private) {
02143                      ConfigFile *cf = c->ca_private;
02144                      value_add_one( &c->rvalue_vals, &cf->c_file );
02145                      return 0;
02146               }
02147               return 1;
02148        }
02149        return(0);
02150 }
02151 
02152 static int
02153 config_cfdir(ConfigArgs *c) {
02154        if(c->op == SLAP_CONFIG_EMIT) {
02155               if ( !BER_BVISEMPTY( &cfdir )) {
02156                      value_add_one( &c->rvalue_vals, &cfdir );
02157                      return 0;
02158               }
02159               return 1;
02160        }
02161        return(0);
02162 }
02163 
02164 static int
02165 config_search_base(ConfigArgs *c) {
02166        if(c->op == SLAP_CONFIG_EMIT) {
02167               int rc = 1;
02168               if (!BER_BVISEMPTY(&default_search_base)) {
02169                      value_add_one(&c->rvalue_vals, &default_search_base);
02170                      value_add_one(&c->rvalue_nvals, &default_search_nbase);
02171                      rc = 0;
02172               }
02173               return rc;
02174        } else if( c->op == LDAP_MOD_DELETE ) {
02175               ch_free( default_search_base.bv_val );
02176               ch_free( default_search_nbase.bv_val );
02177               BER_BVZERO( &default_search_base );
02178               BER_BVZERO( &default_search_nbase );
02179               return 0;
02180        }
02181 
02182        if(c->bi || c->be != frontendDB) {
02183               Debug(LDAP_DEBUG_ANY, "%s: defaultSearchBase line must appear "
02184                      "prior to any backend or database definition\n",
02185                      c->log, 0, 0);
02186               return(1);
02187        }
02188 
02189        if(default_search_nbase.bv_len) {
02190               free(default_search_base.bv_val);
02191               free(default_search_nbase.bv_val);
02192        }
02193 
02194        default_search_base = c->value_dn;
02195        default_search_nbase = c->value_ndn;
02196        return(0);
02197 }
02198 
02199 /* For RE23 compatibility we allow this in the global entry
02200  * but we now defer it to the frontend entry to allow modules
02201  * to load new hash types.
02202  */
02203 static int
02204 config_passwd_hash(ConfigArgs *c) {
02205        int i;
02206        if (c->op == SLAP_CONFIG_EMIT) {
02207               struct berval bv;
02208               /* Don't generate it in the global entry */
02209               if ( c->table == Cft_Global )
02210                      return 1;
02211               for (i=0; default_passwd_hash && default_passwd_hash[i]; i++) {
02212                      ber_str2bv(default_passwd_hash[i], 0, 0, &bv);
02213                      value_add_one(&c->rvalue_vals, &bv);
02214               }
02215               return i ? 0 : 1;
02216        } else if ( c->op == LDAP_MOD_DELETE ) {
02217               /* Deleting from global is a no-op, only the frontendDB entry matters */
02218               if ( c->table == Cft_Global )
02219                      return 0;
02220               if ( c->valx < 0 ) {
02221                      ldap_charray_free( default_passwd_hash );
02222                      default_passwd_hash = NULL;
02223               } else {
02224                      i = c->valx;
02225                      ch_free( default_passwd_hash[i] );
02226                      for (; default_passwd_hash[i]; i++ )
02227                             default_passwd_hash[i] = default_passwd_hash[i+1];
02228               }
02229               return 0;
02230        }
02231        for(i = 1; i < c->argc; i++) {
02232               if(!lutil_passwd_scheme(c->argv[i])) {
02233                      snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> scheme not available", c->argv[0] );
02234                      Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
02235                             c->log, c->cr_msg, c->argv[i]);
02236               } else {
02237                      ldap_charray_add(&default_passwd_hash, c->argv[i]);
02238               }
02239        }
02240        if(!default_passwd_hash) {
02241               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> no valid hashes found", c->argv[0] );
02242               Debug(LDAP_DEBUG_ANY, "%s: %s\n",
02243                      c->log, c->cr_msg, 0 );
02244               return(1);
02245        }
02246        return(0);
02247 }
02248 
02249 static int
02250 config_schema_dn(ConfigArgs *c) {
02251        if ( c->op == SLAP_CONFIG_EMIT ) {
02252               int rc = 1;
02253               if ( !BER_BVISEMPTY( &c->be->be_schemadn )) {
02254                      value_add_one(&c->rvalue_vals, &c->be->be_schemadn);
02255                      value_add_one(&c->rvalue_nvals, &c->be->be_schemandn);
02256                      rc = 0;
02257               }
02258               return rc;
02259        } else if ( c->op == LDAP_MOD_DELETE ) {
02260               ch_free( c->be->be_schemadn.bv_val );
02261               ch_free( c->be->be_schemandn.bv_val );
02262               BER_BVZERO( &c->be->be_schemadn );
02263               BER_BVZERO( &c->be->be_schemandn );
02264               return 0;
02265        }
02266        ch_free( c->be->be_schemadn.bv_val );
02267        ch_free( c->be->be_schemandn.bv_val );
02268        c->be->be_schemadn = c->value_dn;
02269        c->be->be_schemandn = c->value_ndn;
02270        return(0);
02271 }
02272 
02273 static int
02274 config_sizelimit(ConfigArgs *c) {
02275        int i, rc = 0;
02276        struct slap_limits_set *lim = &c->be->be_def_limit;
02277        if (c->op == SLAP_CONFIG_EMIT) {
02278               char buf[8192];
02279               struct berval bv;
02280               bv.bv_val = buf;
02281               bv.bv_len = 0;
02282               limits_unparse_one( lim, SLAP_LIMIT_SIZE, &bv, sizeof( buf ) );
02283               if ( !BER_BVISEMPTY( &bv ))
02284                      value_add_one( &c->rvalue_vals, &bv );
02285               else
02286                      rc = 1;
02287               return rc;
02288        } else if ( c->op == LDAP_MOD_DELETE ) {
02289               /* Reset to defaults or values from frontend */
02290               if ( c->be == frontendDB ) {
02291                      lim->lms_s_soft = SLAPD_DEFAULT_SIZELIMIT;
02292                      lim->lms_s_hard = 0;
02293                      lim->lms_s_unchecked = -1;
02294                      lim->lms_s_pr = 0;
02295                      lim->lms_s_pr_hide = 0;
02296                      lim->lms_s_pr_total = 0;
02297               } else {
02298                      lim->lms_s_soft = frontendDB->be_def_limit.lms_s_soft;
02299                      lim->lms_s_hard = frontendDB->be_def_limit.lms_s_hard;
02300                      lim->lms_s_unchecked = frontendDB->be_def_limit.lms_s_unchecked;
02301                      lim->lms_s_pr = frontendDB->be_def_limit.lms_s_pr;
02302                      lim->lms_s_pr_hide = frontendDB->be_def_limit.lms_s_pr_hide;
02303                      lim->lms_s_pr_total = frontendDB->be_def_limit.lms_s_pr_total;
02304               }
02305               goto ok;
02306        }
02307        for(i = 1; i < c->argc; i++) {
02308               if(!strncasecmp(c->argv[i], "size", 4)) {
02309                      rc = limits_parse_one(c->argv[i], lim);
02310                      if ( rc ) {
02311                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] );
02312                             Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
02313                                    c->log, c->cr_msg, c->argv[i]);
02314                             return(1);
02315                      }
02316               } else {
02317                      if(!strcasecmp(c->argv[i], "unlimited")) {
02318                             lim->lms_s_soft = -1;
02319                      } else {
02320                             if ( lutil_atoix( &lim->lms_s_soft, c->argv[i], 0 ) != 0 ) {
02321                                    snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse limit", c->argv[0]);
02322                                    Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
02323                                           c->log, c->cr_msg, c->argv[i]);
02324                                    return(1);
02325                             }
02326                      }
02327                      lim->lms_s_hard = 0;
02328               }
02329        }
02330 
02331 ok:
02332        if ( ( c->be == frontendDB ) && ( c->ca_entry ) ) {
02333               /* This is a modification to the global limits apply it to
02334                * the other databases as needed */
02335               AttributeDescription *ad=NULL;
02336               const char *text = NULL;
02337               CfEntryInfo *ce = c->ca_entry->e_private;
02338 
02339               slap_str2ad(c->argv[0], &ad, &text);
02340               /* if we got here... */
02341               assert( ad != NULL );
02342 
02343               if ( ce->ce_type == Cft_Global ){
02344                      ce = ce->ce_kids;
02345               }
02346               for (; ce; ce=ce->ce_sibs) {
02347                      Entry *dbe = ce->ce_entry;
02348                      if ( (ce->ce_type == Cft_Database) && (ce->ce_be != frontendDB)
02349                                    && (!attr_find(dbe->e_attrs, ad)) ) {
02350                             ce->ce_be->be_def_limit.lms_s_soft = lim->lms_s_soft;
02351                             ce->ce_be->be_def_limit.lms_s_hard = lim->lms_s_hard;
02352                             ce->ce_be->be_def_limit.lms_s_unchecked =lim->lms_s_unchecked;
02353                             ce->ce_be->be_def_limit.lms_s_pr =lim->lms_s_pr;
02354                             ce->ce_be->be_def_limit.lms_s_pr_hide =lim->lms_s_pr_hide;
02355                             ce->ce_be->be_def_limit.lms_s_pr_total =lim->lms_s_pr_total;
02356                      }
02357               }
02358        }
02359        return(0);
02360 }
02361 
02362 static int
02363 config_timelimit(ConfigArgs *c) {
02364        int i, rc = 0;
02365        struct slap_limits_set *lim = &c->be->be_def_limit;
02366        if (c->op == SLAP_CONFIG_EMIT) {
02367               char buf[8192];
02368               struct berval bv;
02369               bv.bv_val = buf;
02370               bv.bv_len = 0;
02371               limits_unparse_one( lim, SLAP_LIMIT_TIME, &bv, sizeof( buf ) );
02372               if ( !BER_BVISEMPTY( &bv ))
02373                      value_add_one( &c->rvalue_vals, &bv );
02374               else
02375                      rc = 1;
02376               return rc;
02377        } else if ( c->op == LDAP_MOD_DELETE ) {
02378               /* Reset to defaults or values from frontend */
02379               if ( c->be == frontendDB ) {
02380                      lim->lms_t_soft = SLAPD_DEFAULT_TIMELIMIT;
02381                      lim->lms_t_hard = 0;
02382               } else {
02383                      lim->lms_t_soft = frontendDB->be_def_limit.lms_t_soft;
02384                      lim->lms_t_hard = frontendDB->be_def_limit.lms_t_hard;
02385               }
02386               goto ok;
02387        }
02388        for(i = 1; i < c->argc; i++) {
02389               if(!strncasecmp(c->argv[i], "time", 4)) {
02390                      rc = limits_parse_one(c->argv[i], lim);
02391                      if ( rc ) {
02392                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse value", c->argv[0] );
02393                             Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
02394                                    c->log, c->cr_msg, c->argv[i]);
02395                             return(1);
02396                      }
02397               } else {
02398                      if(!strcasecmp(c->argv[i], "unlimited")) {
02399                             lim->lms_t_soft = -1;
02400                      } else {
02401                             if ( lutil_atoix( &lim->lms_t_soft, c->argv[i], 0 ) != 0 ) {
02402                                    snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse limit", c->argv[0]);
02403                                    Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
02404                                           c->log, c->cr_msg, c->argv[i]);
02405                                    return(1);
02406                             }
02407                      }
02408                      lim->lms_t_hard = 0;
02409               }
02410        }
02411 
02412 ok:
02413        if ( ( c->be == frontendDB ) && ( c->ca_entry ) ) {
02414               /* This is a modification to the global limits apply it to
02415                * the other databases as needed */
02416               AttributeDescription *ad=NULL;
02417               const char *text = NULL;
02418               CfEntryInfo *ce = c->ca_entry->e_private;
02419 
02420               slap_str2ad(c->argv[0], &ad, &text);
02421               /* if we got here... */
02422               assert( ad != NULL );
02423 
02424               if ( ce->ce_type == Cft_Global ){
02425                      ce = ce->ce_kids;
02426               }
02427               for (; ce; ce=ce->ce_sibs) {
02428                      Entry *dbe = ce->ce_entry;
02429                      if ( (ce->ce_type == Cft_Database) && (ce->ce_be != frontendDB)
02430                                    && (!attr_find(dbe->e_attrs, ad)) ) {
02431                             ce->ce_be->be_def_limit.lms_t_soft = lim->lms_t_soft;
02432                             ce->ce_be->be_def_limit.lms_t_hard = lim->lms_t_hard;
02433                      }
02434               }
02435        }
02436        return(0);
02437 }
02438 
02439 static int
02440 config_overlay(ConfigArgs *c) {
02441        if (c->op == SLAP_CONFIG_EMIT) {
02442               return 1;
02443        } else if ( c->op == LDAP_MOD_DELETE ) {
02444               assert(0);
02445        }
02446        if(c->argv[1][0] == '-' && overlay_config(c->be, &c->argv[1][1],
02447               c->valx, &c->bi, &c->reply)) {
02448               /* log error */
02449               Debug( LDAP_DEBUG_ANY,
02450                      "%s: (optional) %s overlay \"%s\" configuration failed.\n",
02451                      c->log, c->be == frontendDB ? "global " : "", &c->argv[1][1]);
02452               return 1;
02453        } else if(overlay_config(c->be, c->argv[1], c->valx, &c->bi, &c->reply)) {
02454               return(1);
02455        }
02456        return(0);
02457 }
02458 
02459 static int
02460 config_subordinate(ConfigArgs *c)
02461 {
02462        int rc = 1;
02463        int advertise = 0;
02464 
02465        switch( c->op ) {
02466        case SLAP_CONFIG_EMIT:
02467               if ( SLAP_GLUE_SUBORDINATE( c->be )) {
02468                      struct berval bv;
02469 
02470                      bv.bv_val = SLAP_GLUE_ADVERTISE( c->be ) ? "advertise" : "TRUE";
02471                      bv.bv_len = SLAP_GLUE_ADVERTISE( c->be ) ? STRLENOF("advertise") :
02472                             STRLENOF("TRUE");
02473 
02474                      value_add_one( &c->rvalue_vals, &bv );
02475                      rc = 0;
02476               }
02477               break;
02478        case LDAP_MOD_DELETE:
02479               if ( !c->line  || strcasecmp( c->line, "advertise" )) {
02480                      glue_sub_del( c->be );
02481               } else {
02482                      SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_GLUE_ADVERTISE;
02483               }
02484               rc = 0;
02485               break;
02486        case LDAP_MOD_ADD:
02487        case SLAP_CONFIG_ADD:
02488               if ( c->be->be_nsuffix == NULL ) {
02489                      /* log error */
02490                      snprintf( c->cr_msg, sizeof( c->cr_msg),
02491                             "subordinate configuration needs a suffix" );
02492                      Debug( LDAP_DEBUG_ANY,
02493                             "%s: %s.\n",
02494                             c->log, c->cr_msg, 0 );
02495                      rc = 1;
02496                      break;
02497               }
02498 
02499               if ( c->argc == 2 ) {
02500                      if ( strcasecmp( c->argv[1], "advertise" ) == 0 ) {
02501                             advertise = 1;
02502 
02503                      } else if ( strcasecmp( c->argv[1], "TRUE" ) != 0 ) {
02504                             /* log error */
02505                             snprintf( c->cr_msg, sizeof( c->cr_msg),
02506                                    "subordinate must be \"TRUE\" or \"advertise\"" );
02507                             Debug( LDAP_DEBUG_ANY,
02508                                    "%s: suffix \"%s\": %s.\n",
02509                                    c->log, c->be->be_suffix[0].bv_val, c->cr_msg );
02510                             rc = 1;
02511                             break;
02512                      }
02513               }
02514 
02515               rc = glue_sub_add( c->be, advertise, CONFIG_ONLINE_ADD( c ));
02516               break;
02517        }
02518 
02519        return rc;
02520 }
02521 
02522 /*
02523  * [listener=<listener>] [{read|write}=]<size>
02524  */
02525 
02526 #ifdef LDAP_TCP_BUFFER
02527 static BerVarray tcp_buffer;
02528 int tcp_buffer_num;
02529 
02530 #define SLAP_TCP_RMEM (0x1U)
02531 #define SLAP_TCP_WMEM (0x2U)
02532 
02533 static int
02534 tcp_buffer_parse( struct berval *val, int argc, char **argv,
02535               int *size, int *rw, Listener **l )
02536 {
02537        int i, rc = LDAP_SUCCESS;
02538        LDAPURLDesc *lud = NULL;
02539        char *ptr;
02540 
02541        if ( val != NULL && argv == NULL ) {
02542               char *s = val->bv_val;
02543 
02544               argv = ldap_str2charray( s, " \t" );
02545               if ( argv == NULL ) {
02546                      return LDAP_OTHER;
02547               }
02548        }
02549 
02550        i = 0;
02551        if ( strncasecmp( argv[ i ], "listener=", STRLENOF( "listener=" ) )
02552               == 0 )
02553        {
02554               char *url = argv[ i ] + STRLENOF( "listener=" );
02555               
02556               if ( ldap_url_parse( url, &lud ) ) {
02557                      rc = LDAP_INVALID_SYNTAX;
02558                      goto done;
02559               }
02560 
02561               *l = config_check_my_url( url, lud );
02562               if ( *l == NULL ) {
02563                      rc = LDAP_NO_SUCH_ATTRIBUTE;
02564                      goto done;
02565               }
02566 
02567               i++;
02568        }
02569 
02570        ptr = argv[ i ];
02571        if ( strncasecmp( ptr, "read=", STRLENOF( "read=" ) ) == 0 ) {
02572               *rw |= SLAP_TCP_RMEM;
02573               ptr += STRLENOF( "read=" );
02574 
02575        } else if ( strncasecmp( ptr, "write=", STRLENOF( "write=" ) ) == 0 ) {
02576               *rw |= SLAP_TCP_WMEM;
02577               ptr += STRLENOF( "write=" );
02578 
02579        } else {
02580               *rw |= ( SLAP_TCP_RMEM | SLAP_TCP_WMEM );
02581        }
02582 
02583        /* accept any base */
02584        if ( lutil_atoix( size, ptr, 0 ) ) {
02585               rc = LDAP_INVALID_SYNTAX;
02586               goto done;
02587        }
02588 
02589 done:;
02590        if ( val != NULL && argv != NULL ) {
02591               ldap_charray_free( argv );
02592        }
02593 
02594        if ( lud != NULL ) {
02595               ldap_free_urldesc( lud );
02596        }
02597 
02598        return rc;
02599 }
02600 
02601 static int
02602 tcp_buffer_delete_one( struct berval *val )
02603 {
02604        int rc = 0;
02605        int size = -1, rw = 0;
02606        Listener *l = NULL;
02607 
02608        rc = tcp_buffer_parse( val, 0, NULL, &size, &rw, &l );
02609        if ( rc != 0 ) {
02610               return rc;
02611        }
02612 
02613        if ( l != NULL ) {
02614               int i;
02615               Listener **ll = slapd_get_listeners();
02616 
02617               for ( i = 0; ll[ i ] != NULL; i++ ) {
02618                      if ( ll[ i ] == l ) break;
02619               }
02620 
02621               if ( ll[ i ] == NULL ) {
02622                      return LDAP_NO_SUCH_ATTRIBUTE;
02623               }
02624 
02625               if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = -1;
02626               if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = -1;
02627 
02628               for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) {
02629                      if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = -1;
02630                      if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = -1;
02631               }
02632 
02633        } else {
02634               /* NOTE: this affects listeners without a specific setting,
02635                * does not reset all listeners.  If a listener without
02636                * specific settings was assigned a buffer because of
02637                * a global setting, it will not be reset.  In any case,
02638                * buffer changes will only take place at restart. */
02639               if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = -1;
02640               if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = -1;
02641        }
02642 
02643        return rc;
02644 }
02645 
02646 static int
02647 tcp_buffer_delete( BerVarray vals )
02648 {
02649        int i;
02650 
02651        for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
02652               tcp_buffer_delete_one( &vals[ i ] );
02653        }
02654 
02655        return 0;
02656 }
02657 
02658 static int
02659 tcp_buffer_unparse( int size, int rw, Listener *l, struct berval *val )
02660 {
02661        char buf[sizeof("2147483648")], *ptr;
02662 
02663        /* unparse for later use */
02664        val->bv_len = snprintf( buf, sizeof( buf ), "%d", size );
02665        if ( l != NULL ) {
02666               val->bv_len += STRLENOF( "listener=" " " ) + l->sl_url.bv_len;
02667        }
02668 
02669        if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
02670               if ( rw & SLAP_TCP_RMEM ) {
02671                      val->bv_len += STRLENOF( "read=" );
02672               } else if ( rw & SLAP_TCP_WMEM ) {
02673                      val->bv_len += STRLENOF( "write=" );
02674               }
02675        }
02676 
02677        val->bv_val = SLAP_MALLOC( val->bv_len + 1 );
02678 
02679        ptr = val->bv_val;
02680 
02681        if ( l != NULL ) {
02682               ptr = lutil_strcopy( ptr, "listener=" );
02683               ptr = lutil_strncopy( ptr, l->sl_url.bv_val, l->sl_url.bv_len );
02684               *ptr++ = ' ';
02685        }
02686 
02687        if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
02688               if ( rw & SLAP_TCP_RMEM ) {
02689                      ptr = lutil_strcopy( ptr, "read=" );
02690               } else if ( rw & SLAP_TCP_WMEM ) {
02691                      ptr = lutil_strcopy( ptr, "write=" );
02692               }
02693        }
02694 
02695        ptr = lutil_strcopy( ptr, buf );
02696        *ptr = '\0';
02697 
02698        assert( val->bv_val + val->bv_len == ptr );
02699 
02700        return LDAP_SUCCESS;
02701 }
02702 
02703 static int
02704 tcp_buffer_add_one( int argc, char **argv )
02705 {
02706        int rc = 0;
02707        int size = -1, rw = 0;
02708        Listener *l = NULL;
02709 
02710        struct berval val;
02711 
02712        /* parse */
02713        rc = tcp_buffer_parse( NULL, argc, argv, &size, &rw, &l );
02714        if ( rc != 0 ) {
02715               return rc;
02716        }
02717 
02718        /* unparse for later use */
02719        rc = tcp_buffer_unparse( size, rw, l, &val );
02720        if ( rc != LDAP_SUCCESS ) {
02721               return rc;
02722        }
02723 
02724        /* use parsed values */
02725        if ( l != NULL ) {
02726               int i;
02727               Listener **ll = slapd_get_listeners();
02728 
02729               for ( i = 0; ll[ i ] != NULL; i++ ) {
02730                      if ( ll[ i ] == l ) break;
02731               }
02732 
02733               if ( ll[ i ] == NULL ) {
02734                      return LDAP_NO_SUCH_ATTRIBUTE;
02735               }
02736 
02737               /* buffer only applies to TCP listeners;
02738                * we do not do any check here, and delegate them
02739                * to setsockopt(2) */
02740               if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = size;
02741               if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = size;
02742 
02743               for ( i++ ; ll[ i ] != NULL && bvmatch( &l->sl_url, &ll[ i ]->sl_url ); i++ ) {
02744                      if ( rw & SLAP_TCP_RMEM ) ll[ i ]->sl_tcp_rmem = size;
02745                      if ( rw & SLAP_TCP_WMEM ) ll[ i ]->sl_tcp_wmem = size;
02746               }
02747 
02748        } else {
02749               /* NOTE: this affects listeners without a specific setting,
02750                * does not set all listeners */
02751               if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = size;
02752               if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = size;
02753        }
02754 
02755        tcp_buffer = SLAP_REALLOC( tcp_buffer, sizeof( struct berval ) * ( tcp_buffer_num + 2 ) );
02756        /* append */
02757        tcp_buffer[ tcp_buffer_num ] = val;
02758 
02759        tcp_buffer_num++;
02760        BER_BVZERO( &tcp_buffer[ tcp_buffer_num ] );
02761 
02762        return rc;
02763 }
02764 
02765 static int
02766 config_tcp_buffer( ConfigArgs *c )
02767 {
02768        if ( c->op == SLAP_CONFIG_EMIT ) {
02769               if ( tcp_buffer == NULL || BER_BVISNULL( &tcp_buffer[ 0 ] ) ) {
02770                      return 1;
02771               }
02772               value_add( &c->rvalue_vals, tcp_buffer );
02773               value_add( &c->rvalue_nvals, tcp_buffer );
02774               
02775        } else if ( c->op == LDAP_MOD_DELETE ) {
02776               if ( !c->line  ) {
02777                      tcp_buffer_delete( tcp_buffer );
02778                      ber_bvarray_free( tcp_buffer );
02779                      tcp_buffer = NULL;
02780                      tcp_buffer_num = 0;
02781 
02782               } else {
02783                      int rc = 0;
02784                      int size = -1, rw = 0;
02785                      Listener *l = NULL;
02786 
02787                      struct berval val = BER_BVNULL;
02788 
02789                      int i;
02790 
02791                      if ( tcp_buffer_num == 0 ) {
02792                             return 1;
02793                      }
02794 
02795                      /* parse */
02796                      rc = tcp_buffer_parse( NULL, c->argc - 1, &c->argv[ 1 ], &size, &rw, &l );
02797                      if ( rc != 0 ) {
02798                             return 1;
02799                      }
02800 
02801                      /* unparse for later use */
02802                      rc = tcp_buffer_unparse( size, rw, l, &val );
02803                      if ( rc != LDAP_SUCCESS ) {
02804                             return 1;
02805                      }
02806 
02807                      for ( i = 0; !BER_BVISNULL( &tcp_buffer[ i ] ); i++ ) {
02808                             if ( bvmatch( &tcp_buffer[ i ], &val ) ) {
02809                                    break;
02810                             }
02811                      }
02812 
02813                      if ( BER_BVISNULL( &tcp_buffer[ i ] ) ) {
02814                             /* not found */
02815                             rc = 1;
02816                             goto done;
02817                      }
02818 
02819                      tcp_buffer_delete_one( &tcp_buffer[ i ] );
02820                      ber_memfree( tcp_buffer[ i ].bv_val );
02821                      for ( ; i < tcp_buffer_num; i++ ) {
02822                             tcp_buffer[ i ] = tcp_buffer[ i + 1 ];
02823                      }
02824                      tcp_buffer_num--;
02825 
02826 done:;
02827                      if ( !BER_BVISNULL( &val ) ) {
02828                             SLAP_FREE( val.bv_val );
02829                      }
02830        
02831               }
02832 
02833        } else {
02834               int rc;
02835 
02836               rc = tcp_buffer_add_one( c->argc - 1, &c->argv[ 1 ] );
02837               if ( rc ) {
02838                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
02839                             "<%s> unable to add value #%d",
02840                             c->argv[0], tcp_buffer_num );
02841                      Debug( LDAP_DEBUG_ANY, "%s: %s\n",
02842                             c->log, c->cr_msg, 0 );
02843                      return 1;
02844               }
02845        }
02846 
02847        return 0;
02848 }
02849 #endif /* LDAP_TCP_BUFFER */
02850 
02851 static int
02852 config_suffix(ConfigArgs *c)
02853 {
02854        Backend *tbe;
02855        struct berval pdn, ndn;
02856        char   *notallowed = NULL;
02857 
02858        if ( c->be == frontendDB ) {
02859               notallowed = "frontend";
02860 
02861        } else if ( SLAP_MONITOR(c->be) ) {
02862               notallowed = "monitor";
02863 
02864        } else if ( SLAP_CONFIG(c->be) ) {
02865               notallowed = "config";
02866        }
02867 
02868        if ( notallowed != NULL ) {
02869               char   buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
02870 
02871               switch ( c->op ) {
02872               case LDAP_MOD_ADD:
02873               case LDAP_MOD_DELETE:
02874               case LDAP_MOD_REPLACE:
02875               case LDAP_MOD_INCREMENT:
02876               case SLAP_CONFIG_ADD:
02877                      if ( !BER_BVISNULL( &c->value_dn ) ) {
02878                             snprintf( buf, sizeof( buf ), "<%s> ",
02879                                           c->value_dn.bv_val );
02880                      }
02881 
02882                      Debug(LDAP_DEBUG_ANY,
02883                             "%s: suffix %snot allowed in %s database.\n",
02884                             c->log, buf, notallowed );
02885                      break;
02886 
02887               case SLAP_CONFIG_EMIT:
02888                      /* don't complain when emitting... */
02889                      break;
02890 
02891               default:
02892                      /* FIXME: don't know what values may be valid;
02893                       * please remove assertion, or add legal values
02894                       * to either block */
02895                      assert( 0 );
02896                      break;
02897               }
02898 
02899               return 1;
02900        }
02901 
02902        if (c->op == SLAP_CONFIG_EMIT) {
02903               if ( c->be->be_suffix == NULL
02904                             || BER_BVISNULL( &c->be->be_suffix[0] ) )
02905               {
02906                      return 1;
02907               } else {
02908                      value_add( &c->rvalue_vals, c->be->be_suffix );
02909                      value_add( &c->rvalue_nvals, c->be->be_nsuffix );
02910                      return 0;
02911               }
02912        } else if ( c->op == LDAP_MOD_DELETE ) {
02913               if ( c->valx < 0 ) {
02914                      ber_bvarray_free( c->be->be_suffix );
02915                      ber_bvarray_free( c->be->be_nsuffix );
02916                      c->be->be_suffix = NULL;
02917                      c->be->be_nsuffix = NULL;
02918               } else {
02919                      int i = c->valx;
02920                      ch_free( c->be->be_suffix[i].bv_val );
02921                      ch_free( c->be->be_nsuffix[i].bv_val );
02922                      do {
02923                             c->be->be_suffix[i] = c->be->be_suffix[i+1];
02924                             c->be->be_nsuffix[i] = c->be->be_nsuffix[i+1];
02925                             i++;
02926                      } while ( !BER_BVISNULL( &c->be->be_suffix[i] ) );
02927               }
02928               return 0;
02929        }
02930 
02931 #ifdef SLAPD_MONITOR_DN
02932        if(!strcasecmp(c->argv[1], SLAPD_MONITOR_DN)) {
02933               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> DN is reserved for monitoring slapd",
02934                      c->argv[0] );
02935               Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
02936                      c->log, c->cr_msg, SLAPD_MONITOR_DN);
02937               return(1);
02938        }
02939 #endif
02940 
02941        if (SLAP_DB_ONE_SUFFIX( c->be ) && c->be->be_suffix &&
02942               !BER_BVISNULL( &c->be->be_suffix[0] )) {
02943               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> Only one suffix is allowed on this %s backend",
02944                      c->argv[0], c->be->bd_info->bi_type );
02945               Debug(LDAP_DEBUG_ANY, "%s: %s\n",
02946                      c->log, c->cr_msg, 0);
02947               return(1);
02948        }
02949 
02950        pdn = c->value_dn;
02951        ndn = c->value_ndn;
02952 
02953        if (SLAP_DBHIDDEN( c->be ))
02954               tbe = NULL;
02955        else
02956               tbe = select_backend(&ndn, 0);
02957        if(tbe == c->be) {
02958               Debug( LDAP_DEBUG_ANY, "%s: suffix already served by this backend!.\n",
02959                      c->log, 0, 0);
02960               return 1;
02961               free(pdn.bv_val);
02962               free(ndn.bv_val);
02963        } else if(tbe) {
02964               BackendDB *b2 = tbe;
02965 
02966               /* Does tbe precede be? */
02967               while (( b2 = LDAP_STAILQ_NEXT(b2, be_next )) && b2 && b2 != c->be );
02968 
02969               if ( b2 ) {
02970                      char   *type = tbe->bd_info->bi_type;
02971 
02972                      if ( overlay_is_over( tbe ) ) {
02973                             slap_overinfo *oi = (slap_overinfo *)tbe->bd_info->bi_private;
02974                             type = oi->oi_orig->bi_type;
02975                      }
02976 
02977                      snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> namingContext \"%s\" "
02978                             "already served by a preceding %s database",
02979                             c->argv[0], pdn.bv_val, type );
02980                      Debug(LDAP_DEBUG_ANY, "%s: %s serving namingContext \"%s\"\n",
02981                             c->log, c->cr_msg, tbe->be_suffix[0].bv_val);
02982                      free(pdn.bv_val);
02983                      free(ndn.bv_val);
02984                      return(1);
02985               }
02986        }
02987        if(pdn.bv_len == 0 && default_search_nbase.bv_len) {
02988               Debug(LDAP_DEBUG_ANY, "%s: suffix DN empty and default search "
02989                      "base provided \"%s\" (assuming okay)\n",
02990                      c->log, default_search_base.bv_val, 0);
02991        }
02992        ber_bvarray_add(&c->be->be_suffix, &pdn);
02993        ber_bvarray_add(&c->be->be_nsuffix, &ndn);
02994        return(0);
02995 }
02996 
02997 static int
02998 config_rootdn(ConfigArgs *c) {
02999        if (c->op == SLAP_CONFIG_EMIT) {
03000               if ( !BER_BVISNULL( &c->be->be_rootdn )) {
03001                      value_add_one(&c->rvalue_vals, &c->be->be_rootdn);
03002                      value_add_one(&c->rvalue_nvals, &c->be->be_rootndn);
03003                      return 0;
03004               } else {
03005                      return 1;
03006               }
03007        } else if ( c->op == LDAP_MOD_DELETE ) {
03008               ch_free( c->be->be_rootdn.bv_val );
03009               ch_free( c->be->be_rootndn.bv_val );
03010               BER_BVZERO( &c->be->be_rootdn );
03011               BER_BVZERO( &c->be->be_rootndn );
03012               return 0;
03013        }
03014        if ( !BER_BVISNULL( &c->be->be_rootdn )) {
03015               ch_free( c->be->be_rootdn.bv_val );
03016               ch_free( c->be->be_rootndn.bv_val );
03017        }
03018        c->be->be_rootdn = c->value_dn;
03019        c->be->be_rootndn = c->value_ndn;
03020        return(0);
03021 }
03022 
03023 static int
03024 config_rootpw(ConfigArgs *c) {
03025        Backend *tbe;
03026 
03027        if (c->op == SLAP_CONFIG_EMIT) {
03028               if (!BER_BVISEMPTY(&c->be->be_rootpw)) {
03029                      /* don't copy, because "rootpw" is marked
03030                       * as CFG_BERVAL */
03031                      c->value_bv = c->be->be_rootpw;
03032                      return 0;
03033               }
03034               return 1;
03035        } else if ( c->op == LDAP_MOD_DELETE ) {
03036               ch_free( c->be->be_rootpw.bv_val );
03037               BER_BVZERO( &c->be->be_rootpw );
03038               return 0;
03039        }
03040 
03041        tbe = select_backend(&c->be->be_rootndn, 0);
03042        if(tbe != c->be) {
03043               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> can only be set when rootdn is under suffix",
03044                      c->argv[0] );
03045               Debug(LDAP_DEBUG_ANY, "%s: %s\n",
03046                      c->log, c->cr_msg, 0);
03047               return(1);
03048        }
03049        if ( !BER_BVISNULL( &c->be->be_rootpw ))
03050               ch_free( c->be->be_rootpw.bv_val );
03051        c->be->be_rootpw = c->value_bv;
03052        return(0);
03053 }
03054 
03055 static int
03056 config_restrict(ConfigArgs *c) {
03057        slap_mask_t restrictops = 0;
03058        int i;
03059        slap_verbmasks restrictable_ops[] = {
03060               { BER_BVC("bind"),          SLAP_RESTRICT_OP_BIND },
03061               { BER_BVC("add"),           SLAP_RESTRICT_OP_ADD },
03062               { BER_BVC("modify"),        SLAP_RESTRICT_OP_MODIFY },
03063               { BER_BVC("rename"),        SLAP_RESTRICT_OP_RENAME },
03064               { BER_BVC("modrdn"),        0 },
03065               { BER_BVC("delete"),        SLAP_RESTRICT_OP_DELETE },
03066               { BER_BVC("search"),        SLAP_RESTRICT_OP_SEARCH },
03067               { BER_BVC("compare"),              SLAP_RESTRICT_OP_COMPARE },
03068               { BER_BVC("read"),          SLAP_RESTRICT_OP_READS },
03069               { BER_BVC("write"),         SLAP_RESTRICT_OP_WRITES },
03070               { BER_BVC("extended"),             SLAP_RESTRICT_OP_EXTENDED },
03071               { BER_BVC("extended=" LDAP_EXOP_START_TLS ),            SLAP_RESTRICT_EXOP_START_TLS },
03072               { BER_BVC("extended=" LDAP_EXOP_MODIFY_PASSWD ), SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
03073               { BER_BVC("extended=" LDAP_EXOP_X_WHO_AM_I ),           SLAP_RESTRICT_EXOP_WHOAMI },
03074               { BER_BVC("extended=" LDAP_EXOP_X_CANCEL ),             SLAP_RESTRICT_EXOP_CANCEL },
03075               { BER_BVC("all"),           SLAP_RESTRICT_OP_ALL },
03076               { BER_BVNULL, 0 }
03077        };
03078 
03079        if (c->op == SLAP_CONFIG_EMIT) {
03080               return mask_to_verbs( restrictable_ops, c->be->be_restrictops,
03081                      &c->rvalue_vals );
03082        } else if ( c->op == LDAP_MOD_DELETE ) {
03083               if ( !c->line ) {
03084                      c->be->be_restrictops = 0;
03085               } else {
03086                      i = verb_to_mask( c->line, restrictable_ops );
03087                      c->be->be_restrictops &= ~restrictable_ops[i].mask;
03088               }
03089               return 0;
03090        }
03091        i = verbs_to_mask( c->argc, c->argv, restrictable_ops, &restrictops );
03092        if ( i ) {
03093               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown operation", c->argv[0] );
03094               Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
03095                      c->log, c->cr_msg, c->argv[i]);
03096               return(1);
03097        }
03098        if ( restrictops & SLAP_RESTRICT_OP_EXTENDED )
03099               restrictops &= ~SLAP_RESTRICT_EXOP_MASK;
03100        c->be->be_restrictops |= restrictops;
03101        return(0);
03102 }
03103 
03104 static int
03105 config_allows(ConfigArgs *c) {
03106        slap_mask_t allows = 0;
03107        int i;
03108        slap_verbmasks allowable_ops[] = {
03109               { BER_BVC("bind_v2"),              SLAP_ALLOW_BIND_V2 },
03110               { BER_BVC("bind_anon_cred"),       SLAP_ALLOW_BIND_ANON_CRED },
03111               { BER_BVC("bind_anon_dn"),  SLAP_ALLOW_BIND_ANON_DN },
03112               { BER_BVC("update_anon"),   SLAP_ALLOW_UPDATE_ANON },
03113               { BER_BVC("proxy_authz_anon"),     SLAP_ALLOW_PROXY_AUTHZ_ANON },
03114               { BER_BVNULL, 0 }
03115        };
03116        if (c->op == SLAP_CONFIG_EMIT) {
03117               return mask_to_verbs( allowable_ops, global_allows, &c->rvalue_vals );
03118        } else if ( c->op == LDAP_MOD_DELETE ) {
03119               if ( !c->line ) {
03120                      global_allows = 0;
03121               } else {
03122                      i = verb_to_mask( c->line, allowable_ops );
03123                      global_allows &= ~allowable_ops[i].mask;
03124               }
03125               return 0;
03126        }
03127        i = verbs_to_mask(c->argc, c->argv, allowable_ops, &allows);
03128        if ( i ) {
03129               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature", c->argv[0] );
03130               Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
03131                      c->log, c->cr_msg, c->argv[i]);
03132               return(1);
03133        }
03134        global_allows |= allows;
03135        return(0);
03136 }
03137 
03138 static int
03139 config_disallows(ConfigArgs *c) {
03140        slap_mask_t disallows = 0;
03141        int i;
03142        slap_verbmasks disallowable_ops[] = {
03143               { BER_BVC("bind_anon"),            SLAP_DISALLOW_BIND_ANON },
03144               { BER_BVC("bind_simple"),   SLAP_DISALLOW_BIND_SIMPLE },
03145               { BER_BVC("tls_2_anon"),           SLAP_DISALLOW_TLS_2_ANON },
03146               { BER_BVC("tls_authc"),            SLAP_DISALLOW_TLS_AUTHC },
03147               { BER_BVC("proxy_authz_non_critical"),    SLAP_DISALLOW_PROXY_AUTHZ_N_CRIT },
03148               { BER_BVC("dontusecopy_non_critical"),    SLAP_DISALLOW_DONTUSECOPY_N_CRIT },
03149               { BER_BVNULL, 0 }
03150        };
03151        if (c->op == SLAP_CONFIG_EMIT) {
03152               return mask_to_verbs( disallowable_ops, global_disallows, &c->rvalue_vals );
03153        } else if ( c->op == LDAP_MOD_DELETE ) {
03154               if ( !c->line ) {
03155                      global_disallows = 0;
03156               } else {
03157                      i = verb_to_mask( c->line, disallowable_ops );
03158                      global_disallows &= ~disallowable_ops[i].mask;
03159               }
03160               return 0;
03161        }
03162        i = verbs_to_mask(c->argc, c->argv, disallowable_ops, &disallows);
03163        if ( i ) {
03164               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature", c->argv[0] );
03165               Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
03166                      c->log, c->cr_msg, c->argv[i]);
03167               return(1);
03168        }
03169        global_disallows |= disallows;
03170        return(0);
03171 }
03172 
03173 static int
03174 config_requires(ConfigArgs *c) {
03175        slap_mask_t requires = frontendDB->be_requires;
03176        int i, argc = c->argc;
03177        char **argv = c->argv;
03178 
03179        slap_verbmasks requires_ops[] = {
03180               { BER_BVC("bind"),          SLAP_REQUIRE_BIND },
03181               { BER_BVC("LDAPv3"),        SLAP_REQUIRE_LDAP_V3 },
03182               { BER_BVC("authc"),         SLAP_REQUIRE_AUTHC },
03183               { BER_BVC("sasl"),          SLAP_REQUIRE_SASL },
03184               { BER_BVC("strong"),        SLAP_REQUIRE_STRONG },
03185               { BER_BVNULL, 0 }
03186        };
03187        if (c->op == SLAP_CONFIG_EMIT) {
03188               return mask_to_verbs( requires_ops, c->be->be_requires, &c->rvalue_vals );
03189        } else if ( c->op == LDAP_MOD_DELETE ) {
03190               if ( !c->line ) {
03191                      c->be->be_requires = 0;
03192               } else {
03193                      i = verb_to_mask( c->line, requires_ops );
03194                      c->be->be_requires &= ~requires_ops[i].mask;
03195               }
03196               return 0;
03197        }
03198        /* "none" can only be first, to wipe out default/global values */
03199        if ( strcasecmp( c->argv[ 1 ], "none" ) == 0 ) {
03200               argv++;
03201               argc--;
03202               requires = 0;
03203        }
03204        i = verbs_to_mask(argc, argv, requires_ops, &requires);
03205        if ( i ) {
03206               if (strcasecmp( c->argv[ i ], "none" ) == 0 ) {
03207                      snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> \"none\" (#%d) must be listed first", c->argv[0], i - 1 );
03208                      Debug(LDAP_DEBUG_ANY, "%s: %s\n",
03209                             c->log, c->cr_msg, 0);
03210               } else {
03211                      snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown feature #%d", c->argv[0], i - 1 );
03212                      Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
03213                             c->log, c->cr_msg, c->argv[i]);
03214               }
03215               return(1);
03216        }
03217        c->be->be_requires = requires;
03218        return(0);
03219 }
03220 
03221 static int
03222 config_extra_attrs(ConfigArgs *c)
03223 {
03224        assert( c->be != NULL );
03225 
03226        if ( c->op == SLAP_CONFIG_EMIT ) {
03227               int i;
03228 
03229               if ( c->be->be_extra_anlist == NULL ) {
03230                      return 1;
03231               }
03232 
03233               for ( i = 0; !BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ); i++ ) {
03234                      value_add_one( &c->rvalue_vals, &c->be->be_extra_anlist[i].an_name );
03235               }
03236 
03237        } else if ( c->op == LDAP_MOD_DELETE ) {
03238               if ( c->be->be_extra_anlist == NULL ) {
03239                      return 1;
03240               }
03241 
03242               if ( c->valx < 0 ) {
03243                      anlist_free( c->be->be_extra_anlist, 1, NULL );
03244                      c->be->be_extra_anlist = NULL;
03245 
03246               } else {
03247                      int i;
03248 
03249                      for ( i = 0; i < c->valx && !BER_BVISNULL( &c->be->be_extra_anlist[i + 1].an_name ); i++ )
03250                             ;
03251 
03252                      if ( BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ) ) {
03253                             return 1;
03254                      }
03255 
03256                      ch_free( c->be->be_extra_anlist[i].an_name.bv_val );
03257 
03258                      for ( ; !BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ); i++ ) {
03259                             c->be->be_extra_anlist[i] = c->be->be_extra_anlist[i + 1];
03260                      }
03261               }
03262 
03263        } else {
03264               c->be->be_extra_anlist = str2anlist( c->be->be_extra_anlist, c->argv[1], " ,\t" );
03265               if ( c->be->be_extra_anlist == NULL ) {
03266                      return 1;
03267               }
03268        }
03269 
03270        return 0;
03271 }
03272 
03273 static slap_verbmasks       *loglevel_ops;
03274 
03275 static int
03276 loglevel_init( void )
03277 {
03278        slap_verbmasks       lo[] = {
03279               { BER_BVC("Any"),    (slap_mask_t) LDAP_DEBUG_ANY },
03280               { BER_BVC("Trace"),  LDAP_DEBUG_TRACE },
03281               { BER_BVC("Packets"),       LDAP_DEBUG_PACKETS },
03282               { BER_BVC("Args"),   LDAP_DEBUG_ARGS },
03283               { BER_BVC("Conns"),  LDAP_DEBUG_CONNS },
03284               { BER_BVC("BER"),    LDAP_DEBUG_BER },
03285               { BER_BVC("Filter"), LDAP_DEBUG_FILTER },
03286               { BER_BVC("Config"), LDAP_DEBUG_CONFIG },
03287               { BER_BVC("ACL"),    LDAP_DEBUG_ACL },
03288               { BER_BVC("Stats"),  LDAP_DEBUG_STATS },
03289               { BER_BVC("Stats2"), LDAP_DEBUG_STATS2 },
03290               { BER_BVC("Shell"),  LDAP_DEBUG_SHELL },
03291               { BER_BVC("Parse"),  LDAP_DEBUG_PARSE },
03292 #if 0  /* no longer used (nor supported) */
03293               { BER_BVC("Cache"),  LDAP_DEBUG_CACHE },
03294               { BER_BVC("Index"),  LDAP_DEBUG_INDEX },
03295 #endif
03296               { BER_BVC("Sync"),   LDAP_DEBUG_SYNC },
03297               { BER_BVC("None"),   LDAP_DEBUG_NONE },
03298               { BER_BVNULL,        0 }
03299        };
03300 
03301        return slap_verbmasks_init( &loglevel_ops, lo );
03302 }
03303 
03304 static void
03305 loglevel_destroy( void )
03306 {
03307        if ( loglevel_ops ) {
03308               (void)slap_verbmasks_destroy( loglevel_ops );
03309        }
03310        loglevel_ops = NULL;
03311 }
03312 
03313 static slap_mask_t   loglevel_ignore[] = { -1, 0 };
03314 
03315 int
03316 slap_loglevel_register( slap_mask_t m, struct berval *s )
03317 {
03318        int    rc;
03319 
03320        if ( loglevel_ops == NULL ) {
03321               loglevel_init();
03322        }
03323 
03324        rc = slap_verbmasks_append( &loglevel_ops, m, s, loglevel_ignore );
03325 
03326        if ( rc != 0 ) {
03327               Debug( LDAP_DEBUG_ANY, "slap_loglevel_register(%lu, \"%s\") failed\n",
03328                      m, s->bv_val, 0 );
03329        }
03330 
03331        return rc;
03332 }
03333 
03334 int
03335 slap_loglevel_get( struct berval *s, int *l )
03336 {
03337        int           rc;
03338        slap_mask_t   m, i;
03339 
03340        if ( loglevel_ops == NULL ) {
03341               loglevel_init();
03342        }
03343 
03344        for ( m = 0, i = 1; !BER_BVISNULL( &loglevel_ops[ i ].word ); i++ ) {
03345               m |= loglevel_ops[ i ].mask;
03346        }
03347 
03348        for ( i = 1; m & i; i <<= 1 )
03349               ;
03350 
03351        if ( i == 0 ) {
03352               return -1;
03353        }
03354 
03355        rc = slap_verbmasks_append( &loglevel_ops, i, s, loglevel_ignore );
03356 
03357        if ( rc != 0 ) {
03358               Debug( LDAP_DEBUG_ANY, "slap_loglevel_get(%lu, \"%s\") failed\n",
03359                      i, s->bv_val, 0 );
03360 
03361        } else {
03362               *l = i;
03363        }
03364 
03365        return rc;
03366 }
03367 
03368 int
03369 str2loglevel( const char *s, int *l )
03370 {
03371        int    i;
03372 
03373        if ( loglevel_ops == NULL ) {
03374               loglevel_init();
03375        }
03376 
03377        i = verb_to_mask( s, loglevel_ops );
03378 
03379        if ( BER_BVISNULL( &loglevel_ops[ i ].word ) ) {
03380               return -1;
03381        }
03382 
03383        *l = loglevel_ops[ i ].mask;
03384 
03385        return 0;
03386 }
03387 
03388 const char *
03389 loglevel2str( int l )
03390 {
03391        struct berval bv = BER_BVNULL;
03392 
03393        loglevel2bv( l, &bv );
03394 
03395        return bv.bv_val;
03396 }
03397 
03398 int
03399 loglevel2bv( int l, struct berval *bv )
03400 {
03401        if ( loglevel_ops == NULL ) {
03402               loglevel_init();
03403        }
03404 
03405        BER_BVZERO( bv );
03406 
03407        return enum_to_verb( loglevel_ops, l, bv ) == -1;
03408 }
03409 
03410 int
03411 loglevel2bvarray( int l, BerVarray *bva )
03412 {
03413        if ( loglevel_ops == NULL ) {
03414               loglevel_init();
03415        }
03416 
03417        return mask_to_verbs( loglevel_ops, l, bva );
03418 }
03419 
03420 int
03421 loglevel_print( FILE *out )
03422 {
03423        int    i;
03424 
03425        if ( loglevel_ops == NULL ) {
03426               loglevel_init();
03427        }
03428 
03429        fprintf( out, "Installed log subsystems:\n\n" );
03430        for ( i = 0; !BER_BVISNULL( &loglevel_ops[ i ].word ); i++ ) {
03431               unsigned mask = loglevel_ops[ i ].mask & 0xffffffffUL;
03432               fprintf( out,
03433                      (mask == ((slap_mask_t) -1 & 0xffffffffUL)
03434                       ? "\t%-30s (-1, 0xffffffff)\n" : "\t%-30s (%u, 0x%x)\n"),
03435                      loglevel_ops[ i ].word.bv_val, mask, mask );
03436        }
03437 
03438        fprintf( out, "\nNOTE: custom log subsystems may be later installed "
03439               "by specific code\n\n" );
03440 
03441        return 0;
03442 }
03443 
03444 static int config_syslog;
03445 
03446 static int
03447 config_loglevel(ConfigArgs *c) {
03448        int i;
03449 
03450        if ( loglevel_ops == NULL ) {
03451               loglevel_init();
03452        }
03453 
03454        if (c->op == SLAP_CONFIG_EMIT) {
03455               /* Get default or commandline slapd setting */
03456               if ( ldap_syslog && !config_syslog )
03457                      config_syslog = ldap_syslog;
03458               return loglevel2bvarray( config_syslog, &c->rvalue_vals );
03459 
03460        } else if ( c->op == LDAP_MOD_DELETE ) {
03461               if ( !c->line ) {
03462                      config_syslog = 0;
03463               } else {
03464                      i = verb_to_mask( c->line, loglevel_ops );
03465                      config_syslog &= ~loglevel_ops[i].mask;
03466               }
03467               if ( slapMode & SLAP_SERVER_MODE ) {
03468                      ldap_syslog = config_syslog;
03469               }
03470               return 0;
03471        }
03472 
03473        for( i=1; i < c->argc; i++ ) {
03474               int    level;
03475 
03476               if ( isdigit((unsigned char)c->argv[i][0]) || c->argv[i][0] == '-' ) {
03477                      if( lutil_atoix( &level, c->argv[i], 0 ) != 0 ) {
03478                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse level", c->argv[0] );
03479                             Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
03480                                    c->log, c->cr_msg, c->argv[i]);
03481                             return( 1 );
03482                      }
03483               } else {
03484                      if ( str2loglevel( c->argv[i], &level ) ) {
03485                             snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown level", c->argv[0] );
03486                             Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
03487                                    c->log, c->cr_msg, c->argv[i]);
03488                             return( 1 );
03489                      }
03490               }
03491               /* Explicitly setting a zero clears all the levels */
03492               if ( level )
03493                      config_syslog |= level;
03494               else
03495                      config_syslog = 0;
03496        }
03497        if ( slapMode & SLAP_SERVER_MODE ) {
03498               ldap_syslog = config_syslog;
03499        }
03500        return(0);
03501 }
03502 
03503 static int
03504 config_referral(ConfigArgs *c) {
03505        struct berval val;
03506        if (c->op == SLAP_CONFIG_EMIT) {
03507               if ( default_referral ) {
03508                      value_add( &c->rvalue_vals, default_referral );
03509                      return 0;
03510               } else {
03511                      return 1;
03512               }
03513        } else if ( c->op == LDAP_MOD_DELETE ) {
03514               if ( c->valx < 0 ) {
03515                      ber_bvarray_free( default_referral );
03516                      default_referral = NULL;
03517               } else {
03518                      int i = c->valx;
03519                      ch_free( default_referral[i].bv_val );
03520                      for (; default_referral[i].bv_val; i++ )
03521                             default_referral[i] = default_referral[i+1];
03522               }
03523               return 0;
03524        }
03525        if(validate_global_referral(c->argv[1])) {
03526               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid URL", c->argv[0] );
03527               Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
03528                      c->log, c->cr_msg, c->argv[1]);
03529               return(1);
03530        }
03531 
03532        ber_str2bv(c->argv[1], 0, 0, &val);
03533        if(value_add_one(&default_referral, &val)) return(LDAP_OTHER);
03534        return(0);
03535 }
03536 
03537 static struct {
03538        struct berval key;
03539        int off;
03540 } sec_keys[] = {
03541        { BER_BVC("ssf="), offsetof(slap_ssf_set_t, sss_ssf) },
03542        { BER_BVC("transport="), offsetof(slap_ssf_set_t, sss_transport) },
03543        { BER_BVC("tls="), offsetof(slap_ssf_set_t, sss_tls) },
03544        { BER_BVC("sasl="), offsetof(slap_ssf_set_t, sss_sasl) },
03545        { BER_BVC("update_ssf="), offsetof(slap_ssf_set_t, sss_update_ssf) },
03546        { BER_BVC("update_transport="), offsetof(slap_ssf_set_t, sss_update_transport) },
03547        { BER_BVC("update_tls="), offsetof(slap_ssf_set_t, sss_update_tls) },
03548        { BER_BVC("update_sasl="), offsetof(slap_ssf_set_t, sss_update_sasl) },
03549        { BER_BVC("simple_bind="), offsetof(slap_ssf_set_t, sss_simple_bind) },
03550        { BER_BVNULL, 0 }
03551 };
03552 
03553 static int
03554 config_security(ConfigArgs *c) {
03555        slap_ssf_set_t *set = &c->be->be_ssf_set;
03556        char *next;
03557        int i, j;
03558        if (c->op == SLAP_CONFIG_EMIT) {
03559               char numbuf[32];
03560               struct berval bv;
03561               slap_ssf_t *tgt;
03562               int rc = 1;
03563 
03564               for (i=0; !BER_BVISNULL( &sec_keys[i].key ); i++) {
03565                      tgt = (slap_ssf_t *)((char *)set + sec_keys[i].off);
03566                      if ( *tgt ) {
03567                             rc = 0;
03568                             bv.bv_len = snprintf( numbuf, sizeof( numbuf ), "%u", *tgt );
03569                             if ( bv.bv_len >= sizeof( numbuf ) ) {
03570                                    ber_bvarray_free_x( c->rvalue_vals, NULL );
03571                                    c->rvalue_vals = NULL;
03572                                    rc = 1;
03573                                    break;
03574                             }
03575                             bv.bv_len += sec_keys[i].key.bv_len;
03576                             bv.bv_val = ch_malloc( bv.bv_len + 1);
03577                             next = lutil_strcopy( bv.bv_val, sec_keys[i].key.bv_val );
03578                             strcpy( next, numbuf );
03579                             ber_bvarray_add( &c->rvalue_vals, &bv );
03580                      }
03581               }
03582               return rc;
03583        }
03584        for(i = 1; i < c->argc; i++) {
03585               slap_ssf_t *tgt = NULL;
03586               char *src = NULL;
03587               for ( j=0; !BER_BVISNULL( &sec_keys[j].key ); j++ ) {
03588                      if(!strncasecmp(c->argv[i], sec_keys[j].key.bv_val,
03589                             sec_keys[j].key.bv_len)) {
03590                             src = c->argv[i] + sec_keys[j].key.bv_len;
03591                             tgt = (slap_ssf_t *)((char *)set + sec_keys[j].off);
03592                             break;
03593                      }
03594               }
03595               if ( !tgt ) {
03596                      snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown factor", c->argv[0] );
03597                      Debug(LDAP_DEBUG_ANY, "%s: %s %s\n",
03598                             c->log, c->cr_msg, c->argv[i]);
03599                      return(1);
03600               }
03601 
03602               if ( lutil_atou( tgt, src ) != 0 ) {
03603                      snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unable to parse factor", c->argv[0] );
03604                      Debug(LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
03605                             c->log, c->cr_msg, c->argv[i]);
03606                      return(1);
03607               }
03608        }
03609        return(0);
03610 }
03611 
03612 char *
03613 anlist_unparse( AttributeName *an, char *ptr, ber_len_t buflen ) {
03614        int comma = 0;
03615        char *start = ptr;
03616 
03617        for (; !BER_BVISNULL( &an->an_name ); an++) {
03618               /* if buflen == 0, assume the buffer size has been 
03619                * already checked otherwise */
03620               if ( buflen > 0 && buflen - ( ptr - start ) < comma + an->an_name.bv_len ) return NULL;
03621               if ( comma ) *ptr++ = ',';
03622               ptr = lutil_strcopy( ptr, an->an_name.bv_val );
03623               comma = 1;
03624        }
03625        return ptr;
03626 }
03627 
03628 static int
03629 config_updatedn(ConfigArgs *c) {
03630        if (c->op == SLAP_CONFIG_EMIT) {
03631               if (!BER_BVISEMPTY(&c->be->be_update_ndn)) {
03632                      value_add_one(&c->rvalue_vals, &c->be->be_update_ndn);
03633                      value_add_one(&c->rvalue_nvals, &c->be->be_update_ndn);
03634                      return 0;
03635               }
03636               return 1;
03637        } else if ( c->op == LDAP_MOD_DELETE ) {
03638               ch_free( c->be->be_update_ndn.bv_val );
03639               BER_BVZERO( &c->be->be_update_ndn );
03640               SLAP_DBFLAGS(c->be) ^= (SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SLURP_SHADOW);
03641               return 0;
03642        }
03643        if(SLAP_SHADOW(c->be)) {
03644               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> database already shadowed", c->argv[0] );
03645               Debug(LDAP_DEBUG_ANY, "%s: %s\n",
03646                      c->log, c->cr_msg, 0);
03647               return(1);
03648        }
03649 
03650        ber_memfree_x( c->value_dn.bv_val, NULL );
03651        if ( !BER_BVISNULL( &c->be->be_update_ndn ) ) {
03652               ber_memfree_x( c->be->be_update_ndn.bv_val, NULL );
03653        }
03654        c->be->be_update_ndn = c->value_ndn;
03655        BER_BVZERO( &c->value_dn );
03656        BER_BVZERO( &c->value_ndn );
03657 
03658        return config_slurp_shadow( c );
03659 }
03660 
03661 int
03662 config_shadow( ConfigArgs *c, slap_mask_t flag )
03663 {
03664        char   *notallowed = NULL;
03665 
03666        if ( c->be == frontendDB ) {
03667               notallowed = "frontend";
03668 
03669        } else if ( SLAP_MONITOR(c->be) ) {
03670               notallowed = "monitor";
03671        }
03672 
03673        if ( notallowed != NULL ) {
03674               Debug( LDAP_DEBUG_ANY, "%s: %s database cannot be shadow.\n", c->log, notallowed, 0 );
03675               return 1;
03676        }
03677 
03678        if ( SLAP_SHADOW(c->be) ) {
03679               /* if already shadow, only check consistency */
03680               if ( ( SLAP_DBFLAGS(c->be) & flag ) != flag ) {
03681                      Debug( LDAP_DEBUG_ANY, "%s: inconsistent shadow flag 0x%lx.\n",
03682                             c->log, flag, 0 );
03683                      return 1;
03684               }
03685 
03686        } else {
03687               SLAP_DBFLAGS(c->be) |= (SLAP_DBFLAG_SHADOW | flag);
03688               if ( !SLAP_MULTIMASTER( c->be ))
03689                      SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SINGLE_SHADOW;
03690        }
03691 
03692        return 0;
03693 }
03694 
03695 static int
03696 config_updateref(ConfigArgs *c) {
03697        struct berval val;
03698        if (c->op == SLAP_CONFIG_EMIT) {
03699               if ( c->be->be_update_refs ) {
03700                      value_add( &c->rvalue_vals, c->be->be_update_refs );
03701                      return 0;
03702               } else {
03703                      return 1;
03704               }
03705        } else if ( c->op == LDAP_MOD_DELETE ) {
03706               if ( c->valx < 0 ) {
03707                      ber_bvarray_free( c->be->be_update_refs );
03708                      c->be->be_update_refs = NULL;
03709               } else {
03710                      int i = c->valx;
03711                      ch_free( c->be->be_update_refs[i].bv_val );
03712                      for (; c->be->be_update_refs[i].bv_val; i++)
03713                             c->be->be_update_refs[i] = c->be->be_update_refs[i+1];
03714               }
03715               return 0;
03716        }
03717        if(!SLAP_SHADOW(c->be) && !c->be->be_syncinfo) {
03718               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> must appear after syncrepl or updatedn",
03719                      c->argv[0] );
03720               Debug(LDAP_DEBUG_ANY, "%s: %s\n",
03721                      c->log, c->cr_msg, 0);
03722               return(1);
03723        }
03724 
03725        if(validate_global_referral(c->argv[1])) {
03726               snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid URL", c->argv[0] );
03727               Debug(LDAP_DEBUG_ANY, "%s: %s (%s)\n",
03728                      c->log, c->cr_msg, c->argv[1]);
03729               return(1);
03730        }
03731        ber_str2bv(c->argv[1], 0, 0, &val);
03732        if(value_add_one(&c->be->be_update_refs, &val)) return(LDAP_OTHER);
03733        return(0);
03734 }
03735 
03736 static int
03737 config_obsolete(ConfigArgs *c) {
03738        if (c->op == SLAP_CONFIG_EMIT)
03739               return 1;
03740 
03741        snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> keyword is obsolete (ignored)",
03742               c->argv[0] );
03743        Debug(LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg, 0);
03744        return(0);
03745 }
03746 
03747 static int
03748 config_include(ConfigArgs *c) {
03749        int savelineno = c->lineno;
03750        int rc;
03751        ConfigFile *cf;
03752        ConfigFile *cfsave = cfn;
03753        ConfigFile *cf2 = NULL;
03754 
03755        /* Leftover from RE23. No dynamic config for include files */
03756        if ( c->op == SLAP_CONFIG_EMIT || c->op == LDAP_MOD_DELETE )
03757               return 1;
03758 
03759        cf = ch_calloc( 1, sizeof(ConfigFile));
03760        if ( cfn->c_kids ) {
03761               for (cf2=cfn->c_kids; cf2 && cf2->c_sibs; cf2=cf2->c_sibs) ;
03762               cf2->c_sibs = cf;
03763        } else {
03764               cfn->c_kids = cf;
03765        }
03766        cfn = cf;
03767        ber_str2bv( c->argv[1], 0, 1, &cf->c_file );
03768        rc = read_config_file(c->argv[1], c->depth + 1, c, config_back_cf_table);
03769        c->lineno = savelineno - 1;
03770        cfn = cfsave;
03771        if ( rc ) {
03772               if ( cf2 ) cf2->c_sibs = NULL;
03773               else cfn->c_kids = NULL;
03774               ch_free( cf->c_file.bv_val );
03775               ch_free( cf );
03776        } else {
03777               c->ca_private = cf;
03778        }
03779        return(rc);
03780 }
03781 
03782 #ifdef HAVE_TLS
03783 static int
03784 config_tls_cleanup(ConfigArgs *c) {
03785        int rc = 0;
03786 
03787        if ( slap_tls_ld ) {
03788               int opt = 1;
03789 
03790               ldap_pvt_tls_ctx_free( slap_tls_ctx );
03791 
03792               /* Force new ctx to be created */
03793               rc = ldap_pvt_tls_set_option( slap_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
03794               if( rc == 0 ) {
03795                      /* The ctx's refcount is bumped up here */
03796                      ldap_pvt_tls_get_option( slap_tls_ld, LDAP_OPT_X_TLS_CTX, &slap_tls_ctx );
03797                      /* This is a no-op if it's already loaded */
03798                      load_extop( &slap_EXOP_START_TLS, 0, starttls_extop );
03799               }
03800        }
03801        return rc;
03802 }
03803 
03804 static int
03805 config_tls_option(ConfigArgs *c) {
03806        int flag;
03807        LDAP *ld = slap_tls_ld;
03808        switch(c->type) {
03809        case CFG_TLS_RAND:   flag = LDAP_OPT_X_TLS_RANDOM_FILE; ld = NULL; break;
03810        case CFG_TLS_CIPHER: flag = LDAP_OPT_X_TLS_CIPHER_SUITE;       break;
03811        case CFG_TLS_CERT_FILE:     flag = LDAP_OPT_X_TLS_CERTFILE;           break; 
03812        case CFG_TLS_CERT_KEY:      flag = LDAP_OPT_X_TLS_KEYFILE;            break;
03813        case CFG_TLS_CA_PATH:       flag = LDAP_OPT_X_TLS_CACERTDIR;   break;
03814        case CFG_TLS_CA_FILE:       flag = LDAP_OPT_X_TLS_CACERTFILE;  break;
03815        case CFG_TLS_DH_FILE:       flag = LDAP_OPT_X_TLS_DHFILE;      break;
03816 #ifdef HAVE_GNUTLS
03817        case CFG_TLS_CRL_FILE:      flag = LDAP_OPT_X_TLS_CRLFILE;     break;
03818 #endif
03819        default:             Debug(LDAP_DEBUG_ANY, "%s: "
03820                                    "unknown tls_option <0x%x>\n",
03821                                    c->log, c->type, 0);
03822               return 1;
03823        }
03824        if (c->op == SLAP_CONFIG_EMIT) {
03825               return ldap_pvt_tls_get_option( ld, flag, &c->value_string );
03826        } else if ( c->op == LDAP_MOD_DELETE ) {
03827               c->cleanup = config_tls_cleanup;
03828               return ldap_pvt_tls_set_option( ld, flag, NULL );
03829        }
03830        ch_free(c->value_string);
03831        c->cleanup = config_tls_cleanup;
03832        return(ldap_pvt_tls_set_option(ld, flag, c->argv[1]));
03833 }
03834 
03835 /* FIXME: this ought to be provided by libldap */
03836 static int
03837 config_tls_config(ConfigArgs *c) {
03838        int i, flag;
03839        switch(c->type) {
03840        case CFG_TLS_CRLCHECK:      flag = LDAP_OPT_X_TLS_CRLCHECK; break;
03841        case CFG_TLS_VERIFY: flag = LDAP_OPT_X_TLS_REQUIRE_CERT; break;
03842        case CFG_TLS_PROTOCOL_MIN: flag = LDAP_OPT_X_TLS_PROTOCOL_MIN; break;
03843        default:
03844               Debug(LDAP_DEBUG_ANY, "%s: "
03845                             "unknown tls_option <0x%x>\n",
03846                             c->log, c->type, 0);
03847               return 1;
03848        }
03849        if (c->op == SLAP_CONFIG_EMIT) {
03850               return slap_tls_get_config( slap_tls_ld, flag, &c->value_string );
03851        } else if ( c->op == LDAP_MOD_DELETE ) {
03852               int i = 0;
03853               c->cleanup = config_tls_cleanup;
03854               return ldap_pvt_tls_set_option( slap_tls_ld, flag, &i );
03855        }
03856        ch_free( c->value_string );
03857        c->cleanup = config_tls_cleanup;
03858        if ( isdigit( (unsigned char)c->argv[1][0] ) ) {
03859               if ( lutil_atoi( &i, c->argv[1] ) != 0 ) {
03860                      Debug(LDAP_DEBUG_ANY, "%s: "
03861                             "unable to parse %s \"%s\"\n",
03862                             c->log, c->argv[0], c->argv[1] );
03863                      return 1;
03864               }
03865               return(ldap_pvt_tls_set_option(slap_tls_ld, flag, &i));
03866        } else {
03867               return(ldap_int_tls_config(slap_tls_ld, flag, c->argv[1]));
03868        }
03869 }
03870 #endif
03871 
03872 static CfEntryInfo *
03873 config_find_base( CfEntryInfo *root, struct berval *dn, CfEntryInfo **last )
03874 {
03875        struct berval cdn;
03876        char *c;
03877 
03878        if ( !root ) {
03879               *last = NULL;
03880               return NULL;
03881        }
03882 
03883        if ( dn_match( &root->ce_entry->e_nname, dn ))
03884               return root;
03885 
03886        c = dn->bv_val+dn->bv_len;
03887        for (;*c != ',';c--);
03888 
03889        while(root) {
03890               *last = root;
03891               for (--c;c>dn->bv_val && *c != ',';c--);
03892               cdn.bv_val = c;
03893               if ( *c == ',' )
03894                      cdn.bv_val++;
03895               cdn.bv_len = dn->bv_len - (cdn.bv_val - dn->bv_val);
03896 
03897               root = root->ce_kids;
03898 
03899               for (;root;root=root->ce_sibs) {
03900                      if ( dn_match( &root->ce_entry->e_nname, &cdn )) {
03901                             if ( cdn.bv_val == dn->bv_val ) {
03902                                    return root;
03903                             }
03904                             break;
03905                      }
03906               }
03907        }
03908        return root;
03909 }
03910 
03911 typedef struct setup_cookie {
03912        CfBackInfo *cfb;
03913        ConfigArgs *ca;
03914        Entry *frontend;
03915        Entry *config;
03916        int got_frontend;
03917        int got_config;
03918 } setup_cookie;
03919 
03920 static int
03921 config_ldif_resp( Operation *op, SlapReply *rs )
03922 {
03923        if ( rs->sr_type == REP_SEARCH ) {
03924               setup_cookie *sc = op->o_callback->sc_private;
03925               struct berval pdn;
03926 
03927               sc->cfb->cb_got_ldif = 1;
03928               /* Does the frontend exist? */
03929               if ( !sc->got_frontend ) {
03930                      if ( !strncmp( rs->sr_entry->e_nname.bv_val,
03931                             "olcDatabase", STRLENOF( "olcDatabase" )))
03932                      {
03933                             if ( strncmp( rs->sr_entry->e_nname.bv_val +
03934                                    STRLENOF( "olcDatabase" ), "={-1}frontend",
03935                                    STRLENOF( "={-1}frontend" )))
03936                             {
03937                                    struct berval rdn;
03938                                    int i = op->o_noop;
03939                                    sc->ca->be = frontendDB;
03940                                    sc->ca->bi = frontendDB->bd_info;
03941                                    frontendDB->be_cf_ocs = &CFOC_FRONTEND;
03942                                    rdn.bv_val = sc->ca->log;
03943                                    rdn.bv_len = snprintf(rdn.bv_val, sizeof( sc->ca->log ),
03944                                           "%s=" SLAP_X_ORDERED_FMT "%s",
03945                                           cfAd_database->ad_cname.bv_val, -1,
03946                                           sc->ca->bi->bi_type);
03947                                    op->o_noop = 1;
03948                                    sc->frontend = config_build_entry( op, rs,
03949                                           sc->cfb->cb_root, sc->ca, &rdn, &CFOC_DATABASE,
03950                                           sc->ca->be->be_cf_ocs );
03951                                    op->o_noop = i;
03952                                    sc->got_frontend++;
03953                             } else {
03954                                    sc->got_frontend++;
03955                                    goto ok;
03956                             }
03957                      }
03958               }
03959 
03960               dnParent( &rs->sr_entry->e_nname, &pdn );
03961 
03962               /* Does the configDB exist? */
03963               if ( sc->got_frontend && !sc->got_config &&
03964                      !strncmp( rs->sr_entry->e_nname.bv_val,
03965                      "olcDatabase", STRLENOF( "olcDatabase" )) &&
03966                      dn_match( &config_rdn, &pdn ) )
03967               {
03968                      if ( strncmp( rs->sr_entry->e_nname.bv_val +
03969                             STRLENOF( "olcDatabase" ), "={0}config",
03970                             STRLENOF( "={0}config" )))
03971                      {
03972                             struct berval rdn;
03973                             int i = op->o_noop;
03974                             sc->ca->be = LDAP_STAILQ_FIRST( &backendDB );
03975                             sc->ca->bi = sc->ca->be->bd_info;
03976                             rdn.bv_val = sc->ca->log;
03977                             rdn.bv_len = snprintf(rdn.bv_val, sizeof( sc->ca->log ),
03978                                    "%s=" SLAP_X_ORDERED_FMT "%s",
03979                                    cfAd_database->ad_cname.bv_val, 0,
03980                                    sc->ca->bi->bi_type);
03981                             op->o_noop = 1;
03982                             sc->config = config_build_entry( op, rs, sc->cfb->cb_root,
03983                                    sc->ca, &rdn, &CFOC_DATABASE, sc->ca->be->be_cf_ocs );
03984                             op->o_noop = i;
03985                      }
03986                      sc->got_config++;
03987               }
03988 
03989 ok:
03990               rs->sr_err = config_add_internal( sc->cfb, rs->sr_entry, sc->ca, NULL, NULL, NULL );
03991               if ( rs->sr_err != LDAP_SUCCESS ) {
03992                      Debug( LDAP_DEBUG_ANY, "config error processing %s: %s\n",
03993                             rs->sr_entry->e_name.bv_val, sc->ca->cr_msg, 0 );
03994               }
03995        }
03996        return rs->sr_err;
03997 }
03998 
03999 /* Configure and read the underlying back-ldif store */
04000 static int
04001 config_setup_ldif( BackendDB *be, const char *dir, int readit ) {
04002        CfBackInfo *cfb = be->be_private;
04003        ConfigArgs c = {0};
04004        ConfigTable *ct;
04005        char *argv[3];
04006        int rc = 0;
04007        setup_cookie sc;
04008        slap_callback cb = { NULL, config_ldif_resp, NULL, NULL };
04009        Connection conn = {0};
04010        OperationBuffer opbuf;
04011        Operation *op;
04012        SlapReply rs = {REP_RESULT};
04013        Filter filter = { LDAP_FILTER_PRESENT };
04014        struct berval filterstr = BER_BVC("(objectclass=*)");
04015        struct stat st;
04016 
04017        /* Is the config directory available? */
04018        if ( stat( dir, &st ) < 0 ) {
04019               /* No, so don't bother using the backing store.
04020                * All changes will be in-memory only.
04021                */
04022               return 0;
04023        }
04024               
04025        cfb->cb_db.bd_info = backend_info( "ldif" );
04026        if ( !cfb->cb_db.bd_info )
04027               return 0;     /* FIXME: eventually this will be a fatal error */
04028 
04029        if ( backend_db_init( "ldif", &cfb->cb_db, -1, NULL ) == NULL )
04030               return 1;
04031 
04032        cfb->cb_db.be_suffix = be->be_suffix;
04033        cfb->cb_db.be_nsuffix = be->be_nsuffix;
04034 
04035        /* The suffix is always "cn=config". The underlying DB's rootdn
04036         * is always the same as the suffix.
04037         */
04038        cfb->cb_db.be_rootdn = be->be_suffix[0];
04039        cfb->cb_db.be_rootndn = be->be_nsuffix[0];
04040 
04041        ber_str2bv( dir, 0, 1, &cfdir );
04042 
04043        c.be = &cfb->cb_db;
04044        c.fname = "slapd";
04045        c.argc = 2;
04046        argv[0] = "directory";
04047        argv[1] = (char *)dir;
04048        argv[2] = NULL;
04049        c.argv = argv;
04050        c.reply.err = 0;
04051        c.reply.msg[0] = 0;
04052        c.table = Cft_Database;
04053 
04054        ct = config_find_keyword( c.be->be_cf_ocs->co_table, &c );
04055        if ( !ct )
04056               return 1;
04057 
04058        if ( config_add_vals( ct, &c ))
04059               return 1;
04060 
04061        if ( backend_startup_one( &cfb->cb_db, &c.reply ))
04062               return 1;
04063 
04064        if ( readit ) {
04065               void *thrctx = ldap_pvt_thread_pool_context();
04066               int prev_DN_strict;
04067 
04068               connection_fake_init( &conn, &opbuf, thrctx );
04069               op = &opbuf.ob_op;
04070 
04071               filter.f_desc = slap_schema.si_ad_objectClass;
04072 
04073               op->o_tag = LDAP_REQ_SEARCH;
04074 
04075               op->ors_filter = &filter;
04076               op->ors_filterstr = filterstr;
04077               op->ors_scope = LDAP_SCOPE_SUBTREE;
04078 
04079               op->o_dn = c.be->be_rootdn;
04080               op->o_ndn = c.be->be_rootndn;
04081 
04082               op->o_req_dn = be->be_suffix[0];
04083               op->o_req_ndn = be->be_nsuffix[0];
04084 
04085               op->ors_tlimit = SLAP_NO_LIMIT;
04086               op->ors_slimit = SLAP_NO_LIMIT;
04087 
04088               op->ors_attrs = slap_anlist_all_attributes;
04089               op->ors_attrsonly = 0;
04090 
04091               op->o_callback = &cb;
04092               sc.cfb = cfb;
04093               sc.ca = &c;
04094               cb.sc_private = &sc;
04095               sc.got_frontend = 0;
04096               sc.got_config = 0;
04097               sc.frontend = NULL;
04098               sc.config = NULL;
04099 
04100               op->o_bd = &cfb->cb_db;
04101               
04102               /* Allow unknown attrs in DNs */
04103               prev_DN_strict = slap_DN_strict;
04104               slap_DN_strict = 0;
04105 
04106               rc = op->o_bd->be_search( op, &rs );
04107 
04108               /* Restore normal DN validation */
04109               slap_DN_strict = prev_DN_strict;
04110 
04111               op->o_tag = LDAP_REQ_ADD;
04112               if ( rc == LDAP_SUCCESS && sc.frontend ) {
04113                      rs_reinit( &rs, REP_RESULT );
04114                      op->ora_e = sc.frontend;
04115                      rc = op->o_bd->be_add( op, &rs );
04116               }
04117               if ( rc == LDAP_SUCCESS && sc.config ) {
04118                      rs_reinit( &rs, REP_RESULT );
04119                      op->ora_e = sc.config;
04120                      rc = op->o_bd->be_add( op, &rs );
04121               }
04122               ldap_pvt_thread_pool_context_reset( thrctx );
04123        }
04124 
04125        /* ITS#4194 - only use if it's present, or we're converting. */
04126        if ( !readit || rc == LDAP_SUCCESS )
04127               cfb->cb_use_ldif = 1;
04128 
04129        return rc;
04130 }
04131 
04132 static int
04133 CfOc_cmp( const void *c1, const void *c2 ) {
04134        const ConfigOCs *co1 = c1;
04135        const ConfigOCs *co2 = c2;
04136 
04137        return ber_bvcmp( co1->co_name, co2->co_name );
04138 }
04139 
04140 int
04141 config_register_schema(ConfigTable *ct, ConfigOCs *ocs) {
04142        int i;
04143 
04144        i = init_config_attrs( ct );
04145        if ( i ) return i;
04146 
04147        /* set up the objectclasses */
04148        i = init_config_ocs( ocs );
04149        if ( i ) return i;
04150 
04151        for (i=0; ocs[i].co_def; i++) {
04152               if ( ocs[i].co_oc ) {
04153                      ocs[i].co_name = &ocs[i].co_oc->soc_cname;
04154                      if ( !ocs[i].co_table )
04155                             ocs[i].co_table = ct;
04156                      avl_insert( &CfOcTree, &ocs[i], CfOc_cmp, avl_dup_error );
04157               }
04158        }
04159        return 0;
04160 }
04161 
04162 int
04163 read_config(const char *fname, const char *dir) {
04164        BackendDB *be;
04165        CfBackInfo *cfb;
04166        const char *cfdir, *cfname;
04167        int rc;
04168 
04169        /* Setup the config backend */
04170        be = backend_db_init( "config", NULL, 0, NULL );
04171        if ( !be )
04172               return 1;
04173 
04174        cfb = be->be_private;
04175        be->be_dfltaccess = ACL_NONE;
04176 
04177        /* If no .conf, or a dir was specified, setup the dir */
04178        if ( !fname || dir ) {
04179               if ( dir ) {
04180                      /* If explicitly given, check for existence */
04181                      struct stat st;
04182 
04183                      if ( stat( dir, &st ) < 0 ) {
04184                             Debug( LDAP_DEBUG_ANY,
04185                                    "invalid config directory %s, error %d\n",
04186                                           dir, errno, 0 );
04187                             return 1;
04188                      }
04189                      cfdir = dir;
04190               } else {
04191                      cfdir = SLAPD_DEFAULT_CONFIGDIR;
04192               }
04193               /* if fname is defaulted, try reading .d */
04194               rc = config_setup_ldif( be, cfdir, !fname );
04195 
04196               if ( rc ) {
04197                      /* It may be OK if the base object doesn't exist yet. */
04198                      if ( rc != LDAP_NO_SUCH_OBJECT )
04199                             return 1;
04200                      /* ITS#4194: But if dir was specified and no fname,
04201                       * then we were supposed to read the dir. Unless we're
04202                       * trying to slapadd the dir...
04203                       */
04204                      if ( dir && !fname ) {
04205                             if ( slapMode & (SLAP_SERVER_MODE|SLAP_TOOL_READMAIN|SLAP_TOOL_READONLY))
04206                                    return 1;
04207                             /* Assume it's slapadd with a config dir, let it continue */
04208                             rc = 0;
04209                             cfb->cb_got_ldif = 1;
04210                             cfb->cb_use_ldif = 1;
04211                             goto done;
04212                      }
04213               }
04214 
04215               /* If we read the config from back-ldif, nothing to do here */
04216               if ( cfb->cb_got_ldif ) {
04217                      rc = 0;
04218                      goto done;
04219               }
04220        }
04221 
04222        if ( fname )
04223               cfname = fname;
04224        else
04225               cfname = SLAPD_DEFAULT_CONFIGFILE;
04226 
04227        rc = read_config_file(cfname, 0, NULL, config_back_cf_table);
04228 
04229        if ( rc == 0 )
04230               ber_str2bv( cfname, 0, 1, &cfb->cb_config->c_file );
04231 
04232 done:
04233        if ( rc == 0 && BER_BVISNULL( &frontendDB->be_schemadn ) ) {
04234               ber_str2bv( SLAPD_SCHEMA_DN, STRLENOF( SLAPD_SCHEMA_DN ), 1,
04235                      &frontendDB->be_schemadn );
04236               rc = dnNormalize( 0, NULL, NULL, &frontendDB->be_schemadn, &frontendDB->be_schemandn, NULL );
04237               if ( rc != LDAP_SUCCESS ) {
04238                      Debug(LDAP_DEBUG_ANY, "read_config: "
04239                             "unable to normalize default schema DN \"%s\"\n",
04240                             frontendDB->be_schemadn.bv_val, 0, 0 );
04241                      /* must not happen */
04242                      assert( 0 );
04243               }
04244        }
04245        if ( rc == 0 && ( slapMode & SLAP_SERVER_MODE ) && sid_list ) {
04246               if ( !BER_BVISEMPTY( &sid_list->si_url ) && !sid_set ) {
04247                      Debug(LDAP_DEBUG_ANY, "read_config: no serverID / URL match found. "
04248                             "Check slapd -h arguments.\n", 0,0,0 );
04249                      rc = LDAP_OTHER;
04250               }
04251        }
04252        return rc;
04253 }
04254 
04255 static int
04256 config_back_bind( Operation *op, SlapReply *rs )
04257 {
04258        if ( be_isroot_pw( op ) ) {
04259               ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ));
04260               /* frontend sends result */
04261               return LDAP_SUCCESS;
04262        }
04263 
04264        rs->sr_err = LDAP_INVALID_CREDENTIALS;
04265        send_ldap_result( op, rs );
04266 
04267        return rs->sr_err;
04268 }
04269 
04270 static int
04271 config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth )
04272 {
04273        int rc = 0;
04274 
04275        if ( test_filter( op, ce->ce_entry, op->ors_filter ) == LDAP_COMPARE_TRUE )
04276        {
04277               rs->sr_attrs = op->ors_attrs;
04278               rs->sr_entry = ce->ce_entry;
04279               rs->sr_flags = 0;
04280               rc = send_search_entry( op, rs );
04281               if ( rc != LDAP_SUCCESS ) {
04282                      return rc;
04283               }
04284        }
04285        if ( op->ors_scope == LDAP_SCOPE_SUBTREE ) {
04286               if ( ce->ce_kids ) {
04287                      rc = config_send( op, rs, ce->ce_kids, 1 );
04288                      if ( rc ) return rc;
04289               }
04290               if ( depth ) {
04291                      for (ce=ce->ce_sibs; ce; ce=ce->ce_sibs) {
04292                             rc = config_send( op, rs, ce, 0 );
04293                             if ( rc ) break;
04294                      }
04295               }
04296        }
04297        return rc;
04298 }
04299 
04300 static ConfigTable *
04301 config_find_table( ConfigOCs **colst, int nocs, AttributeDescription *ad,
04302        ConfigArgs *ca )
04303 {
04304        int i, j;
04305 
04306        for (j=0; j<nocs; j++) {
04307               for (i=0; colst[j]->co_table[i].name; i++)
04308                      if ( colst[j]->co_table[i].ad == ad ) {
04309                             ca->table = colst[j]->co_type;
04310                             return &colst[j]->co_table[i];
04311                      }
04312        }
04313        return NULL;
04314 }
04315 
04316 /* Sort the attributes of the entry according to the order defined
04317  * in the objectclass, with required attributes occurring before
04318  * allowed attributes. For any attributes with sequencing dependencies
04319  * (e.g., rootDN must be defined after suffix) the objectclass must
04320  * list the attributes in the desired sequence.
04321  */
04322 static void
04323 sort_attrs( Entry *e, ConfigOCs **colst, int nocs )
04324 {
04325        Attribute *a, *head = NULL, *tail = NULL, **prev;
04326        int i, j;
04327 
04328        for (i=0; i<nocs; i++) {
04329               if ( colst[i]->co_oc->soc_required ) {
04330                      AttributeType **at = colst[i]->co_oc->soc_required;
04331                      for (j=0; at[j]; j++) {
04332                             for (a=e->e_attrs, prev=&e->e_attrs; a;
04333                                    prev = &(*prev)->a_next, a=a->a_next) {
04334                                    if ( a->a_desc == at[j]->sat_ad ) {
04335                                           *prev = a->a_next;
04336                                           if (!head) {
04337                                                  head = a;
04338                                                  tail = a;
04339                                           } else {
04340                                                  tail->a_next = a;
04341                                                  tail = a;
04342                                           }
04343                                           break;
04344                                    }
04345                             }
04346                      }
04347               }
04348               if ( colst[i]->co_oc->soc_allowed ) {
04349                      AttributeType **at = colst[i]->co_oc->soc_allowed;
04350                      for (j=0; at[j]; j++) {
04351                             for (a=e->e_attrs, prev=&e->e_attrs; a;
04352                                    prev = &(*prev)->a_next, a=a->a_next) {
04353                                    if ( a->a_desc == at[j]->sat_ad ) {
04354                                           *prev = a->a_next;
04355                                           if (!head) {
04356                                                  head = a;
04357                                                  tail = a;
04358                                           } else {
04359                                                  tail->a_next = a;
04360                                                  tail = a;
04361                                           }
04362                                           break;
04363                                    }
04364                             }
04365                      }
04366               }
04367        }
04368        if ( tail ) {
04369               tail->a_next = e->e_attrs;
04370               e->e_attrs = head;
04371        }
04372 }
04373 
04374 static int
04375 check_vals( ConfigTable *ct, ConfigArgs *ca, void *ptr, int isAttr )
04376 {
04377        Attribute *a = NULL;
04378        AttributeDescription *ad;
04379        BerVarray vals;
04380 
04381        int i, rc = 0;
04382 
04383        if ( isAttr ) {
04384               a = ptr;
04385               ad = a->a_desc;
04386               vals = a->a_vals;
04387        } else {
04388               Modifications *ml = ptr;
04389               ad = ml->sml_desc;
04390               vals = ml->sml_values;
04391        }
04392 
04393        if ( a && ( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL )) {
04394               rc = ordered_value_sort( a, 1 );
04395               if ( rc ) {
04396                      snprintf(ca->cr_msg, sizeof( ca->cr_msg ), "ordered_value_sort failed on attr %s\n",
04397                             ad->ad_cname.bv_val );
04398                      return rc;
04399               }
04400        }
04401        for ( i=0; vals[i].bv_val; i++ ) {
04402               ca->line = vals[i].bv_val;
04403               if (( ad->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) &&
04404                      ca->line[0] == '{' ) {
04405                      char *idx = strchr( ca->line, '}' );
04406                      if ( idx ) ca->line = idx+1;
04407               }
04408               rc = config_parse_vals( ct, ca, i );
04409               if ( rc ) {
04410                      break;
04411               }
04412        }
04413        return rc;
04414 }
04415 
04416 static int
04417 config_rename_attr( SlapReply *rs, Entry *e, struct berval *rdn,
04418        Attribute **at )
04419 {
04420        struct berval rtype, rval;
04421        Attribute *a;
04422        AttributeDescription *ad = NULL;
04423 
04424        dnRdn( &e->e_name, rdn );
04425        rval.bv_val = strchr(rdn->bv_val, '=' ) + 1;
04426        rval.bv_len = rdn->bv_len - (rval.bv_val - rdn->bv_val);
04427        rtype.bv_val = rdn->bv_val;
04428        rtype.bv_len = rval.bv_val - rtype.bv_val - 1;
04429 
04430        /* Find attr */
04431        slap_bv2ad( &rtype, &ad, &rs->sr_text );
04432        a = attr_find( e->e_attrs, ad );
04433        if (!a ) return LDAP_NAMING_VIOLATION;
04434        *at = a;
04435 
04436        return 0;
04437 }
04438 
04439 static void
04440 config_rename_kids( CfEntryInfo *ce )
04441 {
04442        CfEntryInfo *ce2;
04443        struct berval rdn, nrdn;
04444 
04445        for (ce2 = ce->ce_kids; ce2; ce2 = ce2->ce_sibs) {
04446               struct berval newdn, newndn;
04447               dnRdn ( &ce2->ce_entry->e_name, &rdn );
04448               dnRdn ( &ce2->ce_entry->e_nname, &nrdn );
04449               build_new_dn( &newdn, &ce->ce_entry->e_name, &rdn, NULL );
04450               build_new_dn( &newndn, &ce->ce_entry->e_nname, &nrdn, NULL );
04451               free( ce2->ce_entry->e_name.bv_val );
04452               free( ce2->ce_entry->e_nname.bv_val );
04453               ce2->ce_entry->e_name = newdn;
04454               ce2->ce_entry->e_nname = newndn;
04455               config_rename_kids( ce2 );
04456        }
04457 }
04458 
04459 static int
04460 config_rename_one( Operation *op, SlapReply *rs, Entry *e,
04461        CfEntryInfo *parent, Attribute *a, struct berval *newrdn,
04462        struct berval *nnewrdn, int use_ldif )
04463 {
04464        char *ptr1;
04465        int rc = 0;
04466        struct berval odn, ondn;
04467 
04468        odn = e->e_name;
04469        ondn = e->e_nname;
04470        build_new_dn( &e->e_name, &parent->ce_entry->e_name, newrdn, NULL );
04471        build_new_dn( &e->e_nname, &parent->ce_entry->e_nname, nnewrdn, NULL );
04472 
04473        /* Replace attr */
04474        free( a->a_vals[0].bv_val );
04475        ptr1 = strchr( newrdn->bv_val, '=' ) + 1;
04476        a->a_vals[0].bv_len = newrdn->bv_len - (ptr1 - newrdn->bv_val);
04477        a->a_vals[0].bv_val = ch_malloc( a->a_vals[0].bv_len + 1 );
04478        strcpy( a->a_vals[0].bv_val, ptr1 );
04479 
04480        if ( a->a_nvals != a->a_vals ) {
04481               free( a->a_nvals[0].bv_val );
04482               ptr1 = strchr( nnewrdn->bv_val, '=' ) + 1;
04483               a->a_nvals[0].bv_len = nnewrdn->bv_len - (ptr1 - nnewrdn->bv_val);
04484               a->a_nvals[0].bv_val = ch_malloc( a->a_nvals[0].bv_len + 1 );
04485               strcpy( a->a_nvals[0].bv_val, ptr1 );
04486        }
04487        if ( use_ldif ) {
04488               CfBackInfo *cfb = (CfBackInfo *)op->o_bd->be_private;
04489               BackendDB *be = op->o_bd;
04490               slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
04491               struct berval dn, ndn, xdn, xndn;
04492 
04493               op->o_bd = &cfb->cb_db;
04494 
04495               /* Save current rootdn; use the underlying DB's rootdn */
04496               dn = op->o_dn;
04497               ndn = op->o_ndn;
04498               xdn = op->o_req_dn;
04499               xndn = op->o_req_ndn;
04500               op->o_dn = op->o_bd->be_rootdn;
04501               op->o_ndn = op->o_bd->be_rootndn;
04502               op->o_req_dn = odn;
04503               op->o_req_ndn = ondn;
04504 
04505               scp = op->o_callback;
04506               op->o_callback = &sc;
04507               op->orr_newrdn = *newrdn;
04508               op->orr_nnewrdn = *nnewrdn;
04509               op->orr_newSup = NULL;
04510               op->orr_nnewSup = NULL;
04511               op->orr_deleteoldrdn = 1;
04512               op->orr_modlist = NULL;
04513               slap_modrdn2mods( op, rs );
04514               slap_mods_opattrs( op, &op->orr_modlist, 1 );
04515               rc = op->o_bd->be_modrdn( op, rs );
04516               slap_mods_free( op->orr_modlist, 1 );
04517 
04518               op->o_bd = be;
04519               op->o_callback = scp;
04520               op->o_dn = dn;
04521               op->o_ndn = ndn;
04522               op->o_req_dn = xdn;
04523               op->o_req_ndn = xndn;
04524        }
04525        free( odn.bv_val );
04526        free( ondn.bv_val );
04527        if ( e->e_private )
04528               config_rename_kids( e->e_private );
04529        return rc;
04530 }
04531 
04532 static int
04533 config_renumber_one( Operation *op, SlapReply *rs, CfEntryInfo *parent, 
04534        Entry *e, int idx, int tailindex, int use_ldif )
04535 {
04536        struct berval ival, newrdn, nnewrdn;
04537        struct berval rdn;
04538        Attribute *a;
04539        char ibuf[32], *ptr1, *ptr2 = NULL;
04540        int rc = 0;
04541 
04542        rc = config_rename_attr( rs, e, &rdn, &a );
04543        if ( rc ) return rc;
04544 
04545        ival.bv_val = ibuf;
04546        ival.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, idx );
04547        if ( ival.bv_len >= sizeof( ibuf ) ) {
04548               return LDAP_NAMING_VIOLATION;
04549        }
04550        
04551        newrdn.bv_len = rdn.bv_len + ival.bv_len;
04552        newrdn.bv_val = ch_malloc( newrdn.bv_len+1 );
04553 
04554        if ( tailindex ) {
04555               ptr1 = lutil_strncopy( newrdn.bv_val, rdn.bv_val, rdn.bv_len );
04556               ptr1 = lutil_strcopy( ptr1, ival.bv_val );
04557        } else {
04558               int xlen;
04559               ptr2 = ber_bvchr( &rdn, '}' );
04560               if ( ptr2 ) {
04561                      ptr2++;
04562               } else {
04563                      ptr2 = rdn.bv_val + a->a_desc->ad_cname.bv_len + 1;
04564               }
04565               xlen = rdn.bv_len - (ptr2 - rdn.bv_val);
04566               ptr1 = lutil_strncopy( newrdn.bv_val, a->a_desc->ad_cname.bv_val,
04567                      a->a_desc->ad_cname.bv_len );
04568               *ptr1++ = '=';
04569               ptr1 = lutil_strcopy( ptr1, ival.bv_val );
04570               ptr1 = lutil_strncopy( ptr1, ptr2, xlen );
04571               *ptr1 = '\0';
04572        }
04573 
04574        /* Do the equivalent of ModRDN */
04575        /* Replace DN / NDN */
04576        newrdn.bv_len = ptr1 - newrdn.bv_val;
04577        rdnNormalize( 0, NULL, NULL, &newrdn, &nnewrdn, NULL );
04578        rc = config_rename_one( op, rs, e, parent, a, &newrdn, &nnewrdn, use_ldif );
04579 
04580        free( nnewrdn.bv_val );
04581        free( newrdn.bv_val );
04582        return rc;
04583 }
04584 
04585 static int
04586 check_name_index( CfEntryInfo *parent, ConfigType ce_type, Entry *e,
04587        SlapReply *rs, int *renum, int *ibase )
04588 {
04589        CfEntryInfo *ce;
04590        int index = -1, gotindex = 0, nsibs, rc = 0;
04591        int renumber = 0, tailindex = 0, isfrontend = 0, isconfig = 0;
04592        char *ptr1, *ptr2 = NULL;
04593        struct berval rdn;
04594 
04595        if ( renum ) *renum = 0;
04596 
04597        /* These entries don't get indexed/renumbered */
04598        if ( ce_type == Cft_Global ) return 0;
04599        if ( ce_type == Cft_Schema && parent->ce_type == Cft_Global ) return 0;
04600 
04601        if ( ce_type == Cft_Module )
04602               tailindex = 1;
04603 
04604        /* See if the rdn has an index already */
04605        dnRdn( &e->e_name, &rdn );
04606        if ( ce_type == Cft_Database ) {
04607               if ( !strncmp( rdn.bv_val + rdn.bv_len - STRLENOF("frontend"),
04608                             "frontend", STRLENOF("frontend") )) 
04609                      isfrontend = 1;
04610               else if ( !strncmp( rdn.bv_val + rdn.bv_len - STRLENOF("config"),
04611                             "config", STRLENOF("config") )) 
04612                      isconfig = 1;
04613        }
04614        ptr1 = ber_bvchr( &e->e_name, '{' );
04615        if ( ptr1 && ptr1 < &e->e_name.bv_val[ rdn.bv_len ] ) {
04616               char   *next;
04617               ptr2 = strchr( ptr1, '}' );
04618               if ( !ptr2 || ptr2 > &e->e_name.bv_val[ rdn.bv_len ] )
04619                      return LDAP_NAMING_VIOLATION;
04620               if ( ptr2-ptr1 == 1)
04621                      return LDAP_NAMING_VIOLATION;
04622               gotindex = 1;
04623               index = strtol( ptr1 + 1, &next, 10 );
04624               if ( next == ptr1 + 1 || next[ 0 ] != '}' ) {
04625                      return LDAP_NAMING_VIOLATION;
04626               }
04627               if ( index < 0 ) {
04628                      /* Special case, we allow -1 for the frontendDB */
04629                      if ( index != -1 || !isfrontend )
04630                             return LDAP_NAMING_VIOLATION;
04631               }
04632               if ( isconfig && index != 0 ){
04633                      return LDAP_NAMING_VIOLATION;
04634               }
04635        }
04636 
04637        /* count related kids */
04638        for (nsibs=0, ce=parent->ce_kids; ce; ce=ce->ce_sibs) {
04639               if ( ce->ce_type == ce_type ) nsibs++;
04640        }
04641 
04642        /* account for -1 frontend */
04643        if ( ce_type == Cft_Database )
04644               nsibs--;
04645 
04646        if ( index != nsibs ) {
04647               if ( gotindex ) {
04648                      if ( index < nsibs ) {
04649                             if ( tailindex ) return LDAP_NAMING_VIOLATION;
04650                             /* Siblings need to be renumbered */
04651                             if ( index != -1 || !isfrontend )
04652                                    renumber = 1;
04653                      }
04654               }
04655               /* config DB is always "0" */
04656               if ( isconfig && index == -1 ) {
04657                      index = 0;
04658               }
04659               if (( !isfrontend && index == -1 ) || ( index > nsibs ) ){
04660                      index = nsibs;
04661               }
04662 
04663               /* just make index = nsibs */
04664               if ( !renumber ) {
04665                      rc = config_renumber_one( NULL, rs, parent, e, index, tailindex, 0 );
04666               }
04667        }
04668        if ( ibase ) *ibase = index;
04669        if ( renum ) *renum = renumber;
04670        return rc;
04671 }
04672 
04673 /* Insert all superior classes of the given class */
04674 static int
04675 count_oc( ObjectClass *oc, ConfigOCs ***copp, int *nocs )
04676 {
04677        ConfigOCs     co, *cop;
04678        ObjectClass   **sups;
04679 
04680        for ( sups = oc->soc_sups; sups && *sups; sups++ ) {
04681               if ( count_oc( *sups, copp, nocs ) ) {
04682                      return -1;
04683               }
04684        }
04685 
04686        co.co_name = &oc->soc_cname;
04687        cop = avl_find( CfOcTree, &co, CfOc_cmp );
04688        if ( cop ) {
04689               int    i;
04690 
04691               /* check for duplicates */
04692               for ( i = 0; i < *nocs; i++ ) {
04693                      if ( *copp && (*copp)[i] == cop ) {
04694                             break;
04695                      }
04696               }
04697 
04698               if ( i == *nocs ) {
04699                      ConfigOCs **tmp = ch_realloc( *copp, (*nocs + 1)*sizeof( ConfigOCs * ) );
04700                      if ( tmp == NULL ) {
04701                             return -1;
04702                      }
04703                      *copp = tmp;
04704                      (*copp)[*nocs] = cop;
04705                      (*nocs)++;
04706               }
04707        }
04708 
04709        return 0;
04710 }
04711 
04712 /* Find all superior classes of the given objectclasses,
04713  * return list in order of most-subordinate first.
04714  *
04715  * Special / auxiliary / Cft_Misc classes always take precedence.
04716  */
04717 static ConfigOCs **
04718 count_ocs( Attribute *oc_at, int *nocs )
04719 {
04720        int           i, j, misc = -1;
04721        ConfigOCs     **colst = NULL;
04722 
04723        *nocs = 0;
04724 
04725        for ( i = oc_at->a_numvals; i--; ) {
04726               ObjectClass   *oc = oc_bvfind( &oc_at->a_nvals[i] );
04727 
04728               assert( oc != NULL );
04729               if ( count_oc( oc, &colst, nocs ) ) {
04730                      ch_free( colst );
04731                      return NULL;
04732               }
04733        }
04734 
04735        /* invert order */
04736        i = 0;
04737        j = *nocs - 1;
04738        while ( i < j ) {
04739               ConfigOCs *tmp = colst[i];
04740               colst[i] = colst[j];
04741               colst[j] = tmp;
04742               if (tmp->co_type == Cft_Misc)
04743                      misc = j;
04744               i++; j--;
04745        }
04746        /* Move misc class to front of list */
04747        if (misc > 0) {
04748               ConfigOCs *tmp = colst[misc];
04749               for (i=misc; i>0; i--)
04750                      colst[i] = colst[i-1];
04751               colst[0] = tmp;
04752        }
04753 
04754        return colst;
04755 }
04756 
04757 static int
04758 cfAddInclude( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
04759 {
04760        /* Leftover from RE23. Never parse this entry */
04761        return LDAP_COMPARE_TRUE;
04762 }
04763 
04764 static int
04765 cfAddSchema( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
04766 {
04767        ConfigFile *cfo;
04768 
04769        /* This entry is hardcoded, don't re-parse it */
04770        if ( p->ce_type == Cft_Global ) {
04771               cfn = p->ce_private;
04772               ca->ca_private = cfn;
04773               return LDAP_COMPARE_TRUE;
04774        }
04775        if ( p->ce_type != Cft_Schema )
04776               return LDAP_CONSTRAINT_VIOLATION;
04777 
04778        cfn = ch_calloc( 1, sizeof(ConfigFile) );
04779        ca->ca_private = cfn;
04780        cfo = p->ce_private;
04781        cfn->c_sibs = cfo->c_kids;
04782        cfo->c_kids = cfn;
04783        return LDAP_SUCCESS;
04784 }
04785 
04786 static int
04787 cfAddDatabase( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
04788 {
04789        if ( p->ce_type != Cft_Global ) {
04790               return LDAP_CONSTRAINT_VIOLATION;
04791        }
04792        /* config must be {0}, nothing else allowed */
04793        if ( !strncmp( e->e_nname.bv_val, "olcDatabase={0}", STRLENOF("olcDatabase={0}")) &&
04794               strncmp( e->e_nname.bv_val + STRLENOF("olcDatabase={0}"), "config,", STRLENOF("config,") )) {
04795               return LDAP_CONSTRAINT_VIOLATION;
04796        }
04797        ca->be = frontendDB; /* just to get past check_vals */
04798        return LDAP_SUCCESS;
04799 }
04800 
04801 static int
04802 cfAddBackend( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
04803 {
04804        if ( p->ce_type != Cft_Global ) {
04805               return LDAP_CONSTRAINT_VIOLATION;
04806        }
04807        return LDAP_SUCCESS;
04808 }
04809 
04810 static int
04811 cfAddModule( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
04812 {
04813        if ( p->ce_type != Cft_Global ) {
04814               return LDAP_CONSTRAINT_VIOLATION;
04815        }
04816        return LDAP_SUCCESS;
04817 }
04818 
04819 static int
04820 cfAddOverlay( CfEntryInfo *p, Entry *e, struct config_args_s *ca )
04821 {
04822        if ( p->ce_type != Cft_Database ) {
04823               return LDAP_CONSTRAINT_VIOLATION;
04824        }
04825        ca->be = p->ce_be;
04826        return LDAP_SUCCESS;
04827 }
04828 
04829 static void
04830 schema_destroy_one( ConfigArgs *ca, ConfigOCs **colst, int nocs,
04831        CfEntryInfo *p )
04832 {
04833        ConfigTable *ct;
04834        ConfigFile *cfo;
04835        AttributeDescription *ad;
04836        const char *text;
04837 
04838        ca->valx = -1;
04839        ca->line = NULL;
04840        ca->argc = 1;
04841        if ( cfn->c_cr_head ) {
04842               struct berval bv = BER_BVC("olcDitContentRules");
04843               ad = NULL;
04844               slap_bv2ad( &bv, &ad, &text );
04845               ct = config_find_table( colst, nocs, ad, ca );
04846               config_del_vals( ct, ca );
04847        }
04848        if ( cfn->c_oc_head ) {
04849               struct berval bv = BER_BVC("olcObjectClasses");
04850               ad = NULL;
04851               slap_bv2ad( &bv, &ad, &text );
04852               ct = config_find_table( colst, nocs, ad, ca );
04853               config_del_vals( ct, ca );
04854        }
04855        if ( cfn->c_at_head ) {
04856               struct berval bv = BER_BVC("olcAttributeTypes");
04857               ad = NULL;
04858               slap_bv2ad( &bv, &ad, &text );
04859               ct = config_find_table( colst, nocs, ad, ca );
04860               config_del_vals( ct, ca );
04861        }
04862        if ( cfn->c_syn_head ) {
04863               struct berval bv = BER_BVC("olcLdapSyntaxes");
04864               ad = NULL;
04865               slap_bv2ad( &bv, &ad, &text );
04866               ct = config_find_table( colst, nocs, ad, ca );
04867               config_del_vals( ct, ca );
04868        }
04869        if ( cfn->c_om_head ) {
04870               struct berval bv = BER_BVC("olcObjectIdentifier");
04871               ad = NULL;
04872               slap_bv2ad( &bv, &ad, &text );
04873               ct = config_find_table( colst, nocs, ad, ca );
04874               config_del_vals( ct, ca );
04875        }
04876        cfo = p->ce_private;
04877        cfo->c_kids = cfn->c_sibs;
04878        ch_free( cfn );
04879 }
04880 
04881 static int
04882 config_add_oc( ConfigOCs **cop, CfEntryInfo *last, Entry *e, ConfigArgs *ca )
04883 {
04884        int           rc = LDAP_CONSTRAINT_VIOLATION;
04885        ObjectClass   **ocp;
04886 
04887        if ( (*cop)->co_ldadd ) {
04888               rc = (*cop)->co_ldadd( last, e, ca );
04889               if ( rc != LDAP_CONSTRAINT_VIOLATION ) {
04890                      return rc;
04891               }
04892        }
04893 
04894        for ( ocp = (*cop)->co_oc->soc_sups; ocp && *ocp; ocp++ ) {
04895               ConfigOCs     co = { 0 };
04896 
04897               co.co_name = &(*ocp)->soc_cname;
04898               *cop = avl_find( CfOcTree, &co, CfOc_cmp );
04899               if ( *cop == NULL ) {
04900                      return rc;
04901               }
04902 
04903               rc = config_add_oc( cop, last, e, ca );
04904               if ( rc != LDAP_CONSTRAINT_VIOLATION ) {
04905                      return rc;
04906               }
04907        }
04908 
04909        return rc;
04910 }
04911 
04912 /* Parse an LDAP entry into config directives */
04913 static int
04914 config_add_internal( CfBackInfo *cfb, Entry *e, ConfigArgs *ca, SlapReply *rs,
04915        int *renum, Operation *op )
04916 {
04917        CfEntryInfo   *ce, *last = NULL;
04918        ConfigOCs     co, *coptr, **colst;
04919        Attribute     *a, *oc_at, *soc_at;
04920        int           i, ibase = -1, nocs, rc = 0;
04921        struct berval pdn;
04922        ConfigTable   *ct;
04923        char          *ptr, *log_prefix = op ? op->o_log_prefix : "";
04924 
04925        memset( ca, 0, sizeof(ConfigArgs));
04926 
04927        /* Make sure parent exists and entry does not. But allow
04928         * Databases and Overlays to be inserted. Don't do any
04929         * auto-renumbering if manageDSAit control is present.
04930         */
04931        ce = config_find_base( cfb->cb_root, &e->e_nname, &last );
04932        if ( ce ) {
04933               if ( ( op && op->o_managedsait ) ||
04934                      ( ce->ce_type != Cft_Database && ce->ce_type != Cft_Overlay &&
04935                        ce->ce_type != Cft_Module ) )
04936               {
04937                      Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
04938                             "DN=\"%s\" already exists\n",
04939                             log_prefix, e->e_name.bv_val, 0 );
04940                      /* global schema ignores all writes */
04941                      if ( ce->ce_type == Cft_Schema && ce->ce_parent->ce_type == Cft_Global )
04942                             return LDAP_COMPARE_TRUE;
04943                      return LDAP_ALREADY_EXISTS;
04944               }
04945        }
04946 
04947        dnParent( &e->e_nname, &pdn );
04948 
04949        /* If last is NULL, the new entry is the root/suffix entry, 
04950         * otherwise last should be the parent.
04951         */
04952        if ( last && !dn_match( &last->ce_entry->e_nname, &pdn ) ) {
04953               if ( rs ) {
04954                      rs->sr_matched = last->ce_entry->e_name.bv_val;
04955               }
04956               Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
04957                      "DN=\"%s\" not child of DN=\"%s\"\n",
04958                      log_prefix, e->e_name.bv_val,
04959                      last->ce_entry->e_name.bv_val );
04960               return LDAP_NO_SUCH_OBJECT;
04961        }
04962 
04963        if ( op ) {
04964               /* No parent, must be root. This will never happen... */
04965               if ( !last && !be_isroot( op ) && !be_shadow_update( op ) ) {
04966                      return LDAP_NO_SUCH_OBJECT;
04967               }
04968 
04969               if ( last && !access_allowed( op, last->ce_entry,
04970                      slap_schema.si_ad_children, NULL, ACL_WADD, NULL ) )
04971               {
04972                      Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
04973                             "DN=\"%s\" no write access to \"children\" of parent\n",
04974                             log_prefix, e->e_name.bv_val, 0 );
04975                      return LDAP_INSUFFICIENT_ACCESS;
04976               }
04977        }
04978 
04979        oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
04980        if ( !oc_at ) {
04981               Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
04982                      "DN=\"%s\" no objectClass\n",
04983                      log_prefix, e->e_name.bv_val, 0 );
04984               return LDAP_OBJECT_CLASS_VIOLATION;
04985        }
04986 
04987        soc_at = attr_find( e->e_attrs, slap_schema.si_ad_structuralObjectClass );
04988        if ( !soc_at ) {
04989               ObjectClass   *soc = NULL;
04990               char          textbuf[ SLAP_TEXT_BUFLEN ];
04991               const char    *text = textbuf;
04992 
04993               /* FIXME: check result */
04994               rc = structural_class( oc_at->a_nvals, &soc, NULL,
04995                      &text, textbuf, sizeof(textbuf), NULL );
04996               if ( rc != LDAP_SUCCESS ) {
04997                      Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
04998                             "DN=\"%s\" no structural objectClass (%s)\n",
04999                             log_prefix, e->e_name.bv_val, text );
05000                      return rc;
05001               }
05002               attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, &soc->soc_cname, NULL );
05003               soc_at = attr_find( e->e_attrs, slap_schema.si_ad_structuralObjectClass );
05004               if ( soc_at == NULL ) {
05005                      Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
05006                             "DN=\"%s\" no structural objectClass; "
05007                             "unable to merge computed class %s\n",
05008                             log_prefix, e->e_name.bv_val,
05009                             soc->soc_cname.bv_val );
05010                      return LDAP_OBJECT_CLASS_VIOLATION;
05011               }
05012 
05013               Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
05014                      "DN=\"%s\" no structural objectClass; "
05015                      "computed objectClass %s merged\n",
05016                      log_prefix, e->e_name.bv_val,
05017                      soc->soc_cname.bv_val );
05018        }
05019 
05020        /* Fake the coordinates based on whether we're part of an
05021         * LDAP Add or if reading the config dir
05022         */
05023        if ( rs ) {
05024               ca->fname = "slapd";
05025               ca->lineno = 0;
05026        } else {
05027               ca->fname = cfdir.bv_val;
05028               ca->lineno = 1;
05029        }
05030        ca->ca_op = op;
05031 
05032        co.co_name = &soc_at->a_nvals[0];
05033        coptr = avl_find( CfOcTree, &co, CfOc_cmp );
05034        if ( coptr == NULL ) {
05035               Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
05036                      "DN=\"%s\" no structural objectClass in configuration table\n",
05037                      log_prefix, e->e_name.bv_val, 0 );
05038               return LDAP_OBJECT_CLASS_VIOLATION;
05039        }
05040 
05041        /* Only the root can be Cft_Global, everything else must
05042         * have a parent. Only limited nesting arrangements are allowed.
05043         */
05044        rc = LDAP_CONSTRAINT_VIOLATION;
05045        if ( coptr->co_type == Cft_Global && !last ) {
05046               cfn = cfb->cb_config;
05047               ca->ca_private = cfn;
05048               ca->be = frontendDB; /* just to get past check_vals */
05049               rc = LDAP_SUCCESS;
05050        }
05051 
05052        colst = count_ocs( oc_at, &nocs );
05053 
05054        /* Check whether the Add is allowed by its parent, and do
05055         * any necessary arg setup
05056         */
05057        if ( last ) {
05058               rc = config_add_oc( &coptr, last, e, ca );
05059               if ( rc == LDAP_CONSTRAINT_VIOLATION ) {
05060                      for ( i = 0; i<nocs; i++ ) {
05061                             /* Already checked these */
05062                             if ( colst[i]->co_oc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
05063                                    continue;
05064                             if ( colst[i]->co_ldadd &&
05065                                    ( rc = colst[i]->co_ldadd( last, e, ca ))
05066                                           != LDAP_CONSTRAINT_VIOLATION ) {
05067                                    coptr = colst[i];
05068                                    break;
05069                             }
05070                      }
05071               }
05072               if ( rc == LDAP_CONSTRAINT_VIOLATION ) {
05073                      Debug( LDAP_DEBUG_TRACE, "%s: config_add_internal: "
05074                             "DN=\"%s\" no structural objectClass add function\n",
05075                             log_prefix, e->e_name.bv_val, 0 );
05076                      return LDAP_OBJECT_CLASS_VIOLATION;
05077               }
05078        }
05079 
05080        /* Add the entry but don't parse it, we already have its contents */
05081        if ( rc == LDAP_COMPARE_TRUE ) {
05082               rc = LDAP_SUCCESS;
05083               goto ok;
05084        }
05085 
05086        if ( rc != LDAP_SUCCESS )
05087               goto done_noop;
05088 
05089        /* Parse all the values and check for simple syntax errors before
05090         * performing any set actions.
05091         *
05092         * If doing an LDAPadd, check for indexed names and any necessary
05093         * renaming/renumbering. Entries that don't need indexed names are
05094         * ignored. Entries that need an indexed name and arrive without one
05095         * are assigned to the end. Entries that arrive with an index may
05096         * cause the following entries to be renumbered/bumped down.
05097         *
05098         * Note that "pseudo-indexed" entries (cn=Include{xx}, cn=Module{xx})
05099         * don't allow Adding an entry with an index that's already in use.
05100         * This is flagged as an error (LDAP_ALREADY_EXISTS) up above.
05101         *
05102         * These entries can have auto-assigned indexes (appended to the end)
05103         * but only the other types support auto-renumbering of siblings.
05104         */
05105        {
05106               rc = check_name_index( last, coptr->co_type, e, rs, renum,
05107                      &ibase );
05108               if ( rc ) {
05109                      goto done_noop;
05110               }
05111               if ( renum && *renum && coptr->co_type != Cft_Database &&
05112                      coptr->co_type != Cft_Overlay )
05113               {
05114                      snprintf( ca->cr_msg, sizeof( ca->cr_msg ),
05115                             "operation requires sibling renumbering" );
05116                      rc = LDAP_UNWILLING_TO_PERFORM;
05117                      goto done_noop;
05118               }
05119        }
05120 
05121        init_config_argv( ca );
05122 
05123        /* Make sure we process attrs in the required order */
05124        sort_attrs( e, colst, nocs );
05125 
05126        for ( a = e->e_attrs; a; a = a->a_next ) {
05127               if ( a == oc_at ) continue;
05128               ct = config_find_table( colst, nocs, a->a_desc, ca );
05129               if ( !ct ) continue; /* user data? */
05130               rc = check_vals( ct, ca, a, 1 );
05131               if ( rc ) goto done_noop;
05132        }
05133 
05134        /* Basic syntax checks are OK. Do the actual settings. */
05135        for ( a=e->e_attrs; a; a=a->a_next ) {
05136               if ( a == oc_at ) continue;
05137               ct = config_find_table( colst, nocs, a->a_desc, ca );
05138               if ( !ct ) continue; /* user data? */
05139               for (i=0; a->a_vals[i].bv_val; i++) {
05140                      char *iptr = NULL;
05141                      ca->valx = -1;
05142                      ca->line = a->a_vals[i].bv_val;
05143                      if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED ) {
05144                             ptr = strchr( ca->line, '}' );
05145                             if ( ptr ) {
05146                                    iptr = strchr( ca->line, '{' );
05147                                    ca->line = ptr+1;
05148                             }
05149                      }
05150                      if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED_SIB ) {
05151                             if ( iptr ) {
05152                                    ca->valx = strtol( iptr+1, NULL, 0 );
05153                             }
05154                      } else {
05155                             ca->valx = i;
05156                      }
05157                      rc = config_parse_add( ct, ca, i );
05158                      if ( rc ) {
05159                             rc = LDAP_OTHER;
05160                             goto done;
05161                      }
05162               }
05163        }
05164 ok:
05165        /* Newly added databases and overlays need to be started up */
05166        if ( CONFIG_ONLINE_ADD( ca )) {
05167               if ( coptr->co_type == Cft_Database ) {
05168                      rc = backend_startup_one( ca->be, &ca->reply );
05169 
05170               } else if ( coptr->co_type == Cft_Overlay ) {
05171                      if ( ca->bi->bi_db_open ) {
05172                             BackendInfo *bi_orig = ca->be->bd_info;
05173                             ca->be->bd_info = ca->bi;
05174                             rc = ca->bi->bi_db_open( ca->be, &ca->reply );
05175                             ca->be->bd_info = bi_orig;
05176                      }
05177               } else if ( ca->cleanup ) {
05178                      rc = ca->cleanup( ca );
05179               }
05180               if ( rc ) {
05181                      if (ca->cr_msg[0] == '\0')
05182                             snprintf( ca->cr_msg, sizeof( ca->cr_msg ), "<%s> failed startup", ca->argv[0] );
05183 
05184                      Debug(LDAP_DEBUG_ANY, "%s: %s (%s)!\n",
05185                             ca->log, ca->cr_msg, ca->argv[1] );
05186                      rc = LDAP_OTHER;
05187                      goto done;
05188               }
05189        }
05190 
05191        ca->valx = ibase;
05192        ce = ch_calloc( 1, sizeof(CfEntryInfo) );
05193        ce->ce_parent = last;
05194        ce->ce_entry = entry_dup( e );
05195        ce->ce_entry->e_private = ce;
05196        ce->ce_type = coptr->co_type;
05197        ce->ce_be = ca->be;
05198        ce->ce_bi = ca->bi;
05199        ce->ce_private = ca->ca_private;
05200        ca->ca_entry = ce->ce_entry;
05201        if ( !last ) {
05202               cfb->cb_root = ce;
05203        } else if ( last->ce_kids ) {
05204               CfEntryInfo *c2, **cprev;
05205 
05206               /* Advance to first of this type */
05207               cprev = &last->ce_kids;
05208               for ( c2 = *cprev; c2 && c2->ce_type < ce->ce_type; ) {
05209                      cprev = &c2->ce_sibs;
05210                      c2 = c2->ce_sibs;
05211               }
05212               /* Account for the (-1) frontendDB entry */
05213               if ( ce->ce_type == Cft_Database ) {
05214                      if ( ca->be == frontendDB )
05215                             ibase = 0;
05216                      else if ( ibase != -1 )
05217                             ibase++;
05218               }
05219               /* Append */
05220               if ( ibase < 0 ) {
05221                      for (c2 = *cprev; c2 && c2->ce_type == ce->ce_type;) {
05222                             cprev = &c2->ce_sibs;
05223                             c2 = c2->ce_sibs;
05224                      }
05225               } else {
05226               /* Insert */
05227                      int i;
05228                      for ( i=0; i<ibase; i++ ) {
05229                             c2 = *cprev;
05230                             cprev = &c2->ce_sibs;
05231                      }
05232               }
05233               ce->ce_sibs = *cprev;
05234               *cprev = ce;
05235        } else {
05236               last->ce_kids = ce;
05237        }
05238 
05239 done:
05240        if ( rc ) {
05241               if ( (coptr->co_type == Cft_Database) && ca->be ) {
05242                      if ( ca->be != frontendDB )
05243                             backend_destroy_one( ca->be, 1 );
05244               } else if ( (coptr->co_type == Cft_Overlay) && ca->bi ) {
05245                      overlay_destroy_one( ca->be, (slap_overinst *)ca->bi );
05246               } else if ( coptr->co_type == Cft_Schema ) {
05247                      schema_destroy_one( ca, colst, nocs, last );
05248               }
05249        }
05250 done_noop:
05251 
05252        ch_free( ca->argv );
05253        if ( colst ) ch_free( colst );
05254        return rc;
05255 }
05256 
05257 #define       BIGTMP 10000
05258 static int
05259 config_rename_add( Operation *op, SlapReply *rs, CfEntryInfo *ce,
05260        int base, int rebase, int max, int use_ldif )
05261 {
05262        CfEntryInfo *ce2, *ce3, *cetmp = NULL, *cerem = NULL;
05263        ConfigType etype = ce->ce_type;
05264        int count = 0, rc = 0;
05265 
05266        /* Reverse ce list */
05267        for (ce2 = ce->ce_sibs;ce2;ce2 = ce3) {
05268               if (ce2->ce_type != etype) {
05269                      cerem = ce2;
05270                      break;
05271               }
05272               ce3 = ce2->ce_sibs;
05273               ce2->ce_sibs = cetmp;
05274               cetmp = ce2;
05275               count++;
05276               if ( max && count >= max ) {
05277                      cerem = ce3;
05278                      break;
05279               }
05280        }
05281 
05282        /* Move original to a temp name until increments are done */
05283        if ( rebase ) {
05284               ce->ce_entry->e_private = NULL;
05285               rc = config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
05286                      base+BIGTMP, 0, use_ldif );
05287               ce->ce_entry->e_private = ce;
05288        }
05289        /* start incrementing */
05290        for (ce2=cetmp; ce2; ce2=ce3) {
05291               ce3 = ce2->ce_sibs;
05292               ce2->ce_sibs = cerem;
05293               cerem = ce2;
05294               if ( rc == 0 ) 
05295                      rc = config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
05296                             count+base, 0, use_ldif );
05297               count--;
05298        }
05299        if ( rebase )
05300               rc = config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
05301                      base, 0, use_ldif );
05302        return rc;
05303 }
05304 
05305 static int
05306 config_rename_del( Operation *op, SlapReply *rs, CfEntryInfo *ce,
05307        CfEntryInfo *ce2, int old, int use_ldif )
05308 {
05309        int count = 0;
05310 
05311        /* Renumber original to a temp value */
05312        ce->ce_entry->e_private = NULL;
05313        config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
05314               old+BIGTMP, 0, use_ldif );
05315        ce->ce_entry->e_private = ce;
05316 
05317        /* start decrementing */
05318        for (; ce2 != ce; ce2=ce2->ce_sibs) {
05319               config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
05320                      count+old, 0, use_ldif );
05321               count++;
05322        }
05323        return config_renumber_one( op, rs, ce->ce_parent, ce->ce_entry,
05324               count+old, 0, use_ldif );
05325 }
05326 
05327 /* Parse an LDAP entry into config directives, then store in underlying
05328  * database.
05329  */
05330 static int
05331 config_back_add( Operation *op, SlapReply *rs )
05332 {
05333        CfBackInfo *cfb;
05334        int renumber;
05335        ConfigArgs ca;
05336 
05337        if ( !access_allowed( op, op->ora_e, slap_schema.si_ad_entry,
05338               NULL, ACL_WADD, NULL )) {
05339               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
05340               goto out;
05341        }
05342 
05343        /*
05344         * Check for attribute ACL
05345         */
05346        if ( !acl_check_modlist( op, op->ora_e, op->orm_modlist )) {
05347               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
05348               rs->sr_text = "no write access to attribute";
05349               goto out;
05350        }
05351 
05352        cfb = (CfBackInfo *)op->o_bd->be_private;
05353 
05354        /* add opattrs for syncprov */
05355        {
05356               char textbuf[SLAP_TEXT_BUFLEN];
05357               size_t textlen = sizeof textbuf;
05358               rs->sr_err = entry_schema_check(op, op->ora_e, NULL, 0, 1, NULL,
05359                      &rs->sr_text, textbuf, sizeof( textbuf ) );
05360               if ( rs->sr_err != LDAP_SUCCESS )
05361                      goto out;
05362               rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
05363               if ( rs->sr_err != LDAP_SUCCESS ) {
05364                      Debug( LDAP_DEBUG_TRACE,
05365                             LDAP_XSTRING(config_back_add) ": entry failed op attrs add: "
05366                             "%s (%d)\n", rs->sr_text, rs->sr_err, 0 );
05367                      goto out;
05368               }
05369        }
05370 
05371        if ( op->o_abandon ) {
05372               rs->sr_err = SLAPD_ABANDON;
05373               goto out;
05374        }
05375        ldap_pvt_thread_pool_pause( &connection_pool );
05376 
05377        /* Strategy:
05378         * 1) check for existence of entry
05379         * 2) check for sibling renumbering
05380         * 3) perform internal add
05381         * 4) perform any necessary renumbering
05382         * 5) store entry in underlying database
05383         */
05384        rs->sr_err = config_add_internal( cfb, op->ora_e, &ca, rs, &renumber, op );
05385        if ( rs->sr_err != LDAP_SUCCESS ) {
05386               rs->sr_text = ca.cr_msg;
05387               goto out2;
05388        }
05389 
05390        if ( renumber ) {
05391               CfEntryInfo *ce = ca.ca_entry->e_private;
05392               req_add_s addr = op->oq_add;
05393               op->o_tag = LDAP_REQ_MODRDN;
05394               rs->sr_err = config_rename_add( op, rs, ce, ca.valx, 0, 0, cfb->cb_use_ldif );
05395               op->o_tag = LDAP_REQ_ADD;
05396               op->oq_add = addr;
05397               if ( rs->sr_err != LDAP_SUCCESS ) {
05398                      goto out2;
05399               }
05400        }
05401 
05402        if ( cfb->cb_use_ldif ) {
05403               BackendDB *be = op->o_bd;
05404               slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
05405               struct berval dn, ndn;
05406 
05407               op->o_bd = &cfb->cb_db;
05408 
05409               /* Save current rootdn; use the underlying DB's rootdn */
05410               dn = op->o_dn;
05411               ndn = op->o_ndn;
05412               op->o_dn = op->o_bd->be_rootdn;
05413               op->o_ndn = op->o_bd->be_rootndn;
05414 
05415               scp = op->o_callback;
05416               op->o_callback = &sc;
05417               op->o_bd->be_add( op, rs );
05418               op->o_bd = be;
05419               op->o_callback = scp;
05420               op->o_dn = dn;
05421               op->o_ndn = ndn;
05422        }
05423 
05424 out2:;
05425        ldap_pvt_thread_pool_resume( &connection_pool );
05426 
05427 out:;
05428        {      int repl = op->o_dont_replicate;
05429               if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
05430                      rs->sr_text = NULL; /* Set after config_add_internal */
05431                      rs->sr_err = LDAP_SUCCESS;
05432                      op->o_dont_replicate = 1;
05433               }
05434               send_ldap_result( op, rs );
05435               op->o_dont_replicate = repl;
05436        }
05437        slap_graduate_commit_csn( op );
05438        return rs->sr_err;
05439 }
05440 
05441 typedef struct delrec {
05442        struct delrec *next;
05443        int nidx;
05444        int idx[1];
05445 } delrec;
05446 
05447 static int
05448 config_modify_add( ConfigTable *ct, ConfigArgs *ca, AttributeDescription *ad,
05449        int i )
05450 {
05451        int rc;
05452 
05453        ca->valx = -1;
05454        if (ad->ad_type->sat_flags & SLAP_AT_ORDERED &&
05455               ca->line[0] == '{' )
05456        {
05457               char *ptr = strchr( ca->line + 1, '}' );
05458               if ( ptr ) {
05459                      char   *next;
05460 
05461                      ca->valx = strtol( ca->line + 1, &next, 0 );
05462                      if ( next == ca->line + 1 || next[ 0 ] != '}' ) {
05463                             return LDAP_OTHER;
05464                      }
05465                      ca->line = ptr+1;
05466               }
05467        }
05468        rc = config_parse_add( ct, ca, i );
05469        if ( rc ) {
05470               rc = LDAP_OTHER;
05471        }
05472        return rc;
05473 }
05474 
05475 static int
05476 config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs,
05477        ConfigArgs *ca )
05478 {
05479        int rc = LDAP_UNWILLING_TO_PERFORM;
05480        Modifications *ml;
05481        Entry *e = ce->ce_entry;
05482        Attribute *save_attrs = e->e_attrs, *oc_at, *s, *a;
05483        ConfigTable *ct;
05484        ConfigOCs **colst;
05485        int i, nocs;
05486        char *ptr;
05487        delrec *dels = NULL, *deltail = NULL;
05488 
05489        oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
05490        if ( !oc_at ) return LDAP_OBJECT_CLASS_VIOLATION;
05491 
05492        for (ml = op->orm_modlist; ml; ml=ml->sml_next) {
05493               if (ml->sml_desc == slap_schema.si_ad_objectClass)
05494                      return rc;
05495        }
05496 
05497        colst = count_ocs( oc_at, &nocs );
05498 
05499        /* make sure add/del flags are clear; should always be true */
05500        for ( s = save_attrs; s; s = s->a_next ) {
05501               s->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL);
05502        }
05503 
05504        e->e_attrs = attrs_dup( e->e_attrs );
05505 
05506        init_config_argv( ca );
05507        ca->be = ce->ce_be;
05508        ca->bi = ce->ce_bi;
05509        ca->ca_private = ce->ce_private;
05510        ca->ca_entry = e;
05511        ca->fname = "slapd";
05512        ca->ca_op = op;
05513        strcpy( ca->log, "back-config" );
05514 
05515        for (ml = op->orm_modlist; ml; ml=ml->sml_next) {
05516               ct = config_find_table( colst, nocs, ml->sml_desc, ca );
05517               switch (ml->sml_op) {
05518               case LDAP_MOD_DELETE:
05519               case LDAP_MOD_REPLACE:
05520               case SLAP_MOD_SOFTDEL:
05521               {
05522                      BerVarray vals = NULL, nvals = NULL;
05523                      int *idx = NULL;
05524                      if ( ct && ( ct->arg_type & ARG_NO_DELETE )) {
05525                             rc = LDAP_OTHER;
05526                             snprintf(ca->cr_msg, sizeof(ca->cr_msg), "cannot delete %s",
05527                                    ml->sml_desc->ad_cname.bv_val );
05528                             goto out_noop;
05529                      }
05530                      if ( ml->sml_op == LDAP_MOD_REPLACE ) {
05531                             vals = ml->sml_values;
05532                             nvals = ml->sml_nvalues;
05533                             ml->sml_values = NULL;
05534                             ml->sml_nvalues = NULL;
05535                      }
05536                      /* If we're deleting by values, remember the indexes of the
05537                       * values we deleted.
05538                       */
05539                      if ( ct && ml->sml_values ) {
05540                             delrec *d;
05541                             i = ml->sml_numvals;
05542                             d = ch_malloc( sizeof(delrec) + (i - 1)* sizeof(int));
05543                             d->nidx = i;
05544                             d->next = NULL;
05545                             if ( dels ) {
05546                                    deltail->next = d;
05547                             } else {
05548                                    dels = d;
05549                             }
05550                             deltail = d;
05551                             idx = d->idx;
05552                      }
05553                      rc = modify_delete_vindex(e, &ml->sml_mod,
05554                             get_permissiveModify(op),
05555                             &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg), idx );
05556                      if ( ml->sml_op == LDAP_MOD_REPLACE ) {
05557                             ml->sml_values = vals;
05558                             ml->sml_nvalues = nvals;
05559                      }
05560                      if ( rc == LDAP_NO_SUCH_ATTRIBUTE && ml->sml_op == SLAP_MOD_SOFTDEL )
05561                      {
05562                             rc = LDAP_SUCCESS;
05563                      }
05564                      /* FIXME: check rc before fallthru? */
05565                      if ( !vals )
05566                             break;
05567               }
05568                      /* FALLTHRU: LDAP_MOD_REPLACE && vals */
05569 
05570               case SLAP_MOD_ADD_IF_NOT_PRESENT:
05571                      if ( ml->sml_op == SLAP_MOD_ADD_IF_NOT_PRESENT
05572                             && attr_find( e->e_attrs, ml->sml_desc ) )
05573                      {
05574                             rc = LDAP_SUCCESS;
05575                             break;
05576                      }
05577 
05578               case LDAP_MOD_ADD:
05579               case SLAP_MOD_SOFTADD: {
05580                      int mop = ml->sml_op;
05581                      int navals = -1;
05582                      ml->sml_op = LDAP_MOD_ADD;
05583                      if ( ct ) {
05584                             if ( ct->arg_type & ARG_NO_INSERT ) {
05585                                    Attribute *a = attr_find( e->e_attrs, ml->sml_desc );
05586                                    if ( a ) {
05587                                           navals = a->a_numvals;
05588                                    }
05589                             }
05590                             for ( i=0; !BER_BVISNULL( &ml->sml_values[i] ); i++ ) {
05591                                    if ( ml->sml_values[i].bv_val[0] == '{' &&
05592                                           navals >= 0 )
05593                                    {
05594                                           char   *next, *val = ml->sml_values[i].bv_val + 1;
05595                                           int    j;
05596 
05597                                           j = strtol( val, &next, 0 );
05598                                           if ( next == val || next[ 0 ] != '}' || j < navals ) {
05599                                                  rc = LDAP_OTHER;
05600                                                  snprintf(ca->cr_msg, sizeof(ca->cr_msg), "cannot insert %s",
05601                                                         ml->sml_desc->ad_cname.bv_val );
05602                                                  goto out_noop;
05603                                           }
05604                                    }
05605                                    rc = check_vals( ct, ca, ml, 0 );
05606                                    if ( rc ) goto out_noop;
05607                             }
05608                      }
05609                      rc = modify_add_values(e, &ml->sml_mod,
05610                                get_permissiveModify(op),
05611                                &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) );
05612 
05613                      /* If value already exists, show success here
05614                       * and ignore this operation down below.
05615                       */
05616                      if ( mop == SLAP_MOD_SOFTADD ) {
05617                             if ( rc == LDAP_TYPE_OR_VALUE_EXISTS )
05618                                    rc = LDAP_SUCCESS;
05619                             else
05620                                    mop = LDAP_MOD_ADD;
05621                      }
05622                      ml->sml_op = mop;
05623                      break;
05624                      }
05625 
05626                      break;
05627               case LDAP_MOD_INCREMENT:    /* FIXME */
05628                      break;
05629               default:
05630                      break;
05631               }
05632               if(rc != LDAP_SUCCESS) break;
05633        }
05634        
05635        if ( rc == LDAP_SUCCESS) {
05636               /* check that the entry still obeys the schema */
05637               rc = entry_schema_check(op, e, NULL, 0, 0, NULL,
05638                      &rs->sr_text, ca->cr_msg, sizeof(ca->cr_msg) );
05639        }
05640        if ( rc ) goto out_noop;
05641 
05642        /* Basic syntax checks are OK. Do the actual settings. */
05643        for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
05644               ct = config_find_table( colst, nocs, ml->sml_desc, ca );
05645               if ( !ct ) continue;
05646 
05647               s = attr_find( save_attrs, ml->sml_desc );
05648               a = attr_find( e->e_attrs, ml->sml_desc );
05649 
05650               switch (ml->sml_op) {
05651               case LDAP_MOD_DELETE:
05652               case LDAP_MOD_REPLACE: {
05653                      BerVarray vals = NULL, nvals = NULL;
05654                      delrec *d = NULL;
05655 
05656                      if ( ml->sml_op == LDAP_MOD_REPLACE ) {
05657                             vals = ml->sml_values;
05658                             nvals = ml->sml_nvalues;
05659                             ml->sml_values = NULL;
05660                             ml->sml_nvalues = NULL;
05661                      }
05662 
05663                      if ( ml->sml_values )
05664                             d = dels;
05665 
05666                      /* If we didn't delete the whole attribute */
05667                      if ( ml->sml_values && a ) {
05668                             struct berval *mvals;
05669                             int j;
05670 
05671                             if ( ml->sml_nvalues )
05672                                    mvals = ml->sml_nvalues;
05673                             else
05674                                    mvals = ml->sml_values;
05675 
05676                             /* use the indexes we saved up above */
05677                             for (i=0; i < d->nidx; i++) {
05678                                    struct berval bv = *mvals++;
05679                                    if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED &&
05680                                           bv.bv_val[0] == '{' ) {
05681                                           ptr = strchr( bv.bv_val, '}' ) + 1;
05682                                           bv.bv_len -= ptr - bv.bv_val;
05683                                           bv.bv_val = ptr;
05684                                    }
05685                                    ca->line = bv.bv_val;
05686                                    ca->valx = d->idx[i];
05687                                    config_parse_vals(ct, ca, d->idx[i] );
05688                                    rc = config_del_vals( ct, ca );
05689                                    if ( rc != LDAP_SUCCESS ) break;
05690                                    if ( s )
05691                                           s->a_flags |= SLAP_ATTR_IXDEL;
05692                                    for (j=i+1; j < d->nidx; j++)
05693                                           if ( d->idx[j] >d->idx[i] )
05694                                                  d->idx[j]--;
05695                             }
05696                      } else {
05697                             ca->valx = -1;
05698                             ca->line = NULL;
05699                             ca->argc = 1;
05700                             rc = config_del_vals( ct, ca );
05701                             if ( rc ) rc = LDAP_OTHER;
05702                             if ( s )
05703                                    s->a_flags |= SLAP_ATTR_IXDEL;
05704                      }
05705                      if ( ml->sml_values ) {
05706                             d = d->next;
05707                             ch_free( dels );
05708                             dels = d;
05709                      }
05710                      if ( ml->sml_op == LDAP_MOD_REPLACE ) {
05711                             ml->sml_values = vals;
05712                             ml->sml_nvalues = nvals;
05713                      }
05714                      if ( !vals || rc != LDAP_SUCCESS )
05715                             break;
05716                      }
05717                      /* FALLTHRU: LDAP_MOD_REPLACE && vals */
05718 
05719               case LDAP_MOD_ADD:
05720                      if ( !a )
05721                             break;
05722                      for (i=0; ml->sml_values[i].bv_val; i++) {
05723                             ca->line = ml->sml_values[i].bv_val;
05724                             ca->valx = -1;
05725                             rc = config_modify_add( ct, ca, ml->sml_desc, i );
05726                             if ( rc )
05727                                    goto out;
05728                             a->a_flags |= SLAP_ATTR_IXADD;
05729                      }
05730                      break;
05731               }
05732        }
05733 
05734 out:
05735        /* Undo for a failed operation */
05736        if ( rc != LDAP_SUCCESS ) {
05737               ConfigReply msg = ca->reply;
05738               for ( s = save_attrs; s; s = s->a_next ) {
05739                      if ( s->a_flags & SLAP_ATTR_IXDEL ) {
05740                             s->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
05741                             ct = config_find_table( colst, nocs, s->a_desc, ca );
05742                             a = attr_find( e->e_attrs, s->a_desc );
05743                             if ( a ) {
05744                                    /* clear the flag so the add check below will skip it */
05745                                    a->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
05746                                    ca->valx = -1;
05747                                    ca->line = NULL;
05748                                    ca->argc = 1;
05749                                    config_del_vals( ct, ca );
05750                             }
05751                             for ( i=0; !BER_BVISNULL( &s->a_vals[i] ); i++ ) {
05752                                    ca->line = s->a_vals[i].bv_val;
05753                                    ca->valx = -1;
05754                                    config_modify_add( ct, ca, s->a_desc, i );
05755                             }
05756                      }
05757               }
05758               for ( a = e->e_attrs; a; a = a->a_next ) {
05759                      if ( a->a_flags & SLAP_ATTR_IXADD ) {
05760                             ct = config_find_table( colst, nocs, a->a_desc, ca );
05761                             ca->valx = -1;
05762                             ca->line = NULL;
05763                             ca->argc = 1;
05764                             config_del_vals( ct, ca );
05765                             s = attr_find( save_attrs, a->a_desc );
05766                             if ( s ) {
05767                                    s->a_flags &= ~(SLAP_ATTR_IXDEL|SLAP_ATTR_IXADD);
05768                                    for ( i=0; !BER_BVISNULL( &s->a_vals[i] ); i++ ) {
05769                                           ca->line = s->a_vals[i].bv_val;
05770                                           ca->valx = -1;
05771                                           config_modify_add( ct, ca, s->a_desc, i );
05772                                    }
05773                             }
05774                      }
05775               }
05776               ca->reply = msg;
05777        }
05778 
05779        if ( ca->cleanup )
05780               ca->cleanup( ca );
05781 out_noop:
05782        if ( rc == LDAP_SUCCESS ) {
05783               attrs_free( save_attrs );
05784               rs->sr_text = NULL;
05785        } else {
05786               attrs_free( e->e_attrs );
05787               e->e_attrs = save_attrs;
05788        }
05789        ch_free( ca->argv );
05790        if ( colst ) ch_free( colst );
05791        while( dels ) {
05792               deltail = dels->next;
05793               ch_free( dels );
05794               dels = deltail;
05795        }
05796 
05797        return rc;
05798 }
05799 
05800 static int
05801 config_back_modify( Operation *op, SlapReply *rs )
05802 {
05803        CfBackInfo *cfb;
05804        CfEntryInfo *ce, *last;
05805        Modifications *ml;
05806        ConfigArgs ca = {0};
05807        struct berval rdn;
05808        char *ptr;
05809        AttributeDescription *rad = NULL;
05810        int do_pause = 1;
05811 
05812        cfb = (CfBackInfo *)op->o_bd->be_private;
05813 
05814        ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
05815        if ( !ce ) {
05816               if ( last )
05817                      rs->sr_matched = last->ce_entry->e_name.bv_val;
05818               rs->sr_err = LDAP_NO_SUCH_OBJECT;
05819               goto out;
05820        }
05821 
05822        if ( !acl_check_modlist( op, ce->ce_entry, op->orm_modlist )) {
05823               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
05824               goto out;
05825        }
05826 
05827        /* Get type of RDN */
05828        rdn = ce->ce_entry->e_nname;
05829        ptr = strchr( rdn.bv_val, '=' );
05830        rdn.bv_len = ptr - rdn.bv_val;
05831        rs->sr_err = slap_bv2ad( &rdn, &rad, &rs->sr_text );
05832        if ( rs->sr_err != LDAP_SUCCESS ) {
05833               goto out;
05834        }
05835 
05836        /* Some basic validation... */
05837        for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
05838               /* Don't allow Modify of RDN; must use ModRdn for that. */
05839               if ( ml->sml_desc == rad ) {
05840                      rs->sr_err = LDAP_NOT_ALLOWED_ON_RDN;
05841                      rs->sr_text = "Use modrdn to change the entry name";
05842                      goto out;
05843               }
05844               /* Internal update of contextCSN? */
05845               if ( ml->sml_desc == slap_schema.si_ad_contextCSN && op->o_conn->c_conn_idx == -1 ) {
05846                      do_pause = 0;
05847                      break;
05848               }
05849        }
05850 
05851        slap_mods_opattrs( op, &op->orm_modlist, 1 );
05852 
05853        if ( do_pause ) {
05854               if ( op->o_abandon ) {
05855                      rs->sr_err = SLAPD_ABANDON;
05856                      goto out;
05857               }
05858               ldap_pvt_thread_pool_pause( &connection_pool );
05859        }
05860 
05861        /* Strategy:
05862         * 1) perform the Modify on the cached Entry.
05863         * 2) verify that the Entry still satisfies the schema.
05864         * 3) perform the individual config operations.
05865         * 4) store Modified entry in underlying LDIF backend.
05866         */
05867        rs->sr_err = config_modify_internal( ce, op, rs, &ca );
05868        if ( rs->sr_err ) {
05869               rs->sr_text = ca.cr_msg;
05870        } else if ( cfb->cb_use_ldif ) {
05871               BackendDB *be = op->o_bd;
05872               slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
05873               struct berval dn, ndn;
05874 
05875               op->o_bd = &cfb->cb_db;
05876 
05877               dn = op->o_dn;
05878               ndn = op->o_ndn;
05879               op->o_dn = op->o_bd->be_rootdn;
05880               op->o_ndn = op->o_bd->be_rootndn;
05881 
05882               scp = op->o_callback;
05883               op->o_callback = &sc;
05884               op->o_bd->be_modify( op, rs );
05885               op->o_bd = be;
05886               op->o_callback = scp;
05887               op->o_dn = dn;
05888               op->o_ndn = ndn;
05889        }
05890 
05891        if ( do_pause )
05892               ldap_pvt_thread_pool_resume( &connection_pool );
05893 out:
05894        send_ldap_result( op, rs );
05895        slap_graduate_commit_csn( op );
05896        return rs->sr_err;
05897 }
05898 
05899 static int
05900 config_back_modrdn( Operation *op, SlapReply *rs )
05901 {
05902        CfBackInfo *cfb;
05903        CfEntryInfo *ce, *last;
05904        struct berval rdn;
05905        int ixold, ixnew;
05906 
05907        cfb = (CfBackInfo *)op->o_bd->be_private;
05908 
05909        ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
05910        if ( !ce ) {
05911               if ( last )
05912                      rs->sr_matched = last->ce_entry->e_name.bv_val;
05913               rs->sr_err = LDAP_NO_SUCH_OBJECT;
05914               goto out;
05915        }
05916        if ( !access_allowed( op, ce->ce_entry, slap_schema.si_ad_entry,
05917               NULL, ACL_WRITE, NULL )) {
05918               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
05919               goto out;
05920        }
05921        { Entry *parent;
05922               if ( ce->ce_parent )
05923                      parent = ce->ce_parent->ce_entry;
05924               else
05925                      parent = (Entry *)&slap_entry_root;
05926               if ( !access_allowed( op, parent, slap_schema.si_ad_children,
05927                      NULL, ACL_WRITE, NULL )) {
05928                      rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
05929                      goto out;
05930               }
05931        }
05932 
05933        /* We don't allow moving objects to new parents.
05934         * Generally we only allow reordering a set of ordered entries.
05935         */
05936        if ( op->orr_newSup ) {
05937               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
05938               goto out;
05939        }
05940 
05941        /* If newRDN == oldRDN, quietly succeed */
05942        dnRdn( &op->o_req_ndn, &rdn );
05943        if ( dn_match( &rdn, &op->orr_nnewrdn )) {
05944               rs->sr_err = LDAP_SUCCESS;
05945               goto out;
05946        }
05947 
05948        /* Current behavior, subject to change as needed:
05949         *
05950         * For backends and overlays, we only allow renumbering.
05951         * For schema, we allow renaming with the same number.
05952         * Otherwise, the op is not allowed.
05953         */
05954 
05955        if ( ce->ce_type == Cft_Schema ) {
05956               char *ptr1, *ptr2;
05957               int len;
05958 
05959               /* Can't alter the main cn=schema entry */
05960               if ( ce->ce_parent->ce_type == Cft_Global ) {
05961                      rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
05962                      rs->sr_text = "renaming not allowed for this entry";
05963                      goto out;
05964               }
05965 
05966               /* We could support this later if desired */
05967               ptr1 = ber_bvchr( &rdn, '}' );
05968               ptr2 = ber_bvchr( &op->orr_newrdn, '}' );
05969               len = ptr1 - rdn.bv_val;
05970               if ( len != ptr2 - op->orr_newrdn.bv_val ||
05971                      strncmp( rdn.bv_val, op->orr_newrdn.bv_val, len )) {
05972                      rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
05973                      rs->sr_text = "schema reordering not supported";
05974                      goto out;
05975               }
05976        } else if ( ce->ce_type == Cft_Database ||
05977               ce->ce_type == Cft_Overlay ) {
05978               char *ptr1, *ptr2, *iptr1, *iptr2;
05979               int len1, len2;
05980 
05981               iptr2 = ber_bvchr( &op->orr_newrdn, '=' ) + 1;
05982               if ( *iptr2 != '{' ) {
05983                      rs->sr_err = LDAP_NAMING_VIOLATION;
05984                      rs->sr_text = "new ordering index is required";
05985                      goto out;
05986               }
05987               iptr2++;
05988               iptr1 = ber_bvchr( &rdn, '{' ) + 1;
05989               ptr1 = ber_bvchr( &rdn, '}' );
05990               ptr2 = ber_bvchr( &op->orr_newrdn, '}' );
05991               if ( !ptr2 ) {
05992                      rs->sr_err = LDAP_NAMING_VIOLATION;
05993                      rs->sr_text = "new ordering index is required";
05994                      goto out;
05995               }
05996 
05997               len1 = ptr1 - rdn.bv_val;
05998               len2 = ptr2 - op->orr_newrdn.bv_val;
05999 
06000               if ( rdn.bv_len - len1 != op->orr_newrdn.bv_len - len2 ||
06001                      strncmp( ptr1, ptr2, rdn.bv_len - len1 )) {
06002                      rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
06003                      rs->sr_text = "changing database/overlay type not allowed";
06004                      goto out;
06005               }
06006               ixold = strtol( iptr1, NULL, 0 );
06007               ixnew = strtol( iptr2, &ptr1, 0 );
06008               if ( ptr1 != ptr2 || ixold < 0 || ixnew < 0 ) {
06009                      rs->sr_err = LDAP_NAMING_VIOLATION;
06010                      goto out;
06011               }
06012               /* config DB is always 0, cannot be changed */
06013               if ( ce->ce_type == Cft_Database && ( ixold == 0 || ixnew == 0 )) {
06014                      rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
06015                      goto out;
06016               }
06017        } else {
06018               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
06019               rs->sr_text = "renaming not supported for this entry";
06020               goto out;
06021        }
06022 
06023        if ( op->o_abandon ) {
06024               rs->sr_err = SLAPD_ABANDON;
06025               goto out;
06026        }
06027        ldap_pvt_thread_pool_pause( &connection_pool );
06028 
06029        if ( ce->ce_type == Cft_Schema ) {
06030               req_modrdn_s modr = op->oq_modrdn;
06031               struct berval rdn;
06032               Attribute *a;
06033               rs->sr_err = config_rename_attr( rs, ce->ce_entry, &rdn, &a );
06034               if ( rs->sr_err == LDAP_SUCCESS ) {
06035                      rs->sr_err = config_rename_one( op, rs, ce->ce_entry,
06036                             ce->ce_parent, a, &op->orr_newrdn, &op->orr_nnewrdn,
06037                             cfb->cb_use_ldif );
06038               }
06039               op->oq_modrdn = modr;
06040        } else {
06041               CfEntryInfo *ce2, *cebase, **cprev, **cbprev, *ceold;
06042               req_modrdn_s modr = op->oq_modrdn;
06043               int i;
06044 
06045               /* Advance to first of this type */
06046               cprev = &ce->ce_parent->ce_kids;
06047               for ( ce2 = *cprev; ce2 && ce2->ce_type != ce->ce_type; ) {
06048                      cprev = &ce2->ce_sibs;
06049                      ce2 = ce2->ce_sibs;
06050               }
06051               /* Skip the -1 entry */
06052               if ( ce->ce_type == Cft_Database ) {
06053                      cprev = &ce2->ce_sibs;
06054                      ce2 = ce2->ce_sibs;
06055               }
06056               cebase = ce2;
06057               cbprev = cprev;
06058 
06059               /* Remove from old slot */
06060               for ( ce2 = *cprev; ce2 && ce2 != ce; ce2 = ce2->ce_sibs )
06061                      cprev = &ce2->ce_sibs;
06062               *cprev = ce->ce_sibs;
06063               ceold = ce->ce_sibs;
06064 
06065               /* Insert into new slot */
06066               cprev = cbprev;
06067               for ( i=0; i<ixnew; i++ ) {
06068                      ce2 = *cprev;
06069                      if ( !ce2 )
06070                             break;
06071                      cprev = &ce2->ce_sibs;
06072               }
06073               ce->ce_sibs = *cprev;
06074               *cprev = ce;
06075 
06076               ixnew = i;
06077 
06078               /* NOTE: These should be encoded in the OC tables, not inline here */
06079               if ( ce->ce_type == Cft_Database )
06080                      backend_db_move( ce->ce_be, ixnew );
06081               else if ( ce->ce_type == Cft_Overlay )
06082                      overlay_move( ce->ce_be, (slap_overinst *)ce->ce_bi, ixnew );
06083                      
06084               if ( ixold < ixnew ) {
06085                      rs->sr_err = config_rename_del( op, rs, ce, ceold, ixold,
06086                             cfb->cb_use_ldif );
06087               } else {
06088                      rs->sr_err = config_rename_add( op, rs, ce, ixnew, 1,
06089                             ixold - ixnew, cfb->cb_use_ldif );
06090               }
06091               op->oq_modrdn = modr;
06092        }
06093 
06094        ldap_pvt_thread_pool_resume( &connection_pool );
06095 out:
06096        send_ldap_result( op, rs );
06097        return rs->sr_err;
06098 }
06099 
06100 static int
06101 config_back_delete( Operation *op, SlapReply *rs )
06102 {
06103 #ifdef SLAP_CONFIG_DELETE
06104        CfBackInfo *cfb;
06105        CfEntryInfo *ce, *last, *ce2;
06106 
06107        cfb = (CfBackInfo *)op->o_bd->be_private;
06108 
06109        ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
06110        if ( !ce ) {
06111               if ( last )
06112                      rs->sr_matched = last->ce_entry->e_name.bv_val;
06113               rs->sr_err = LDAP_NO_SUCH_OBJECT;
06114        } else if ( ce->ce_kids ) {
06115               rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
06116        } else if ( op->o_abandon ) {
06117               rs->sr_err = SLAPD_ABANDON;
06118        } else if ( ce->ce_type == Cft_Overlay ||
06119                      ce->ce_type == Cft_Database ||
06120                      ce->ce_type == Cft_Misc ){
06121               char *iptr;
06122               int count, ixold;
06123 
06124               ldap_pvt_thread_pool_pause( &connection_pool );
06125 
06126               if ( ce->ce_type == Cft_Overlay ){
06127                      overlay_remove( ce->ce_be, (slap_overinst *)ce->ce_bi, op );
06128               } else if ( ce->ce_type == Cft_Misc ) {
06129                      /*
06130                       * only Cft_Misc objects that have a co_lddel handler set in
06131                       * the ConfigOCs struct can be deleted. This code also
06132                       * assumes that the entry can be only have one objectclass
06133                       * with co_type == Cft_Misc
06134                       */
06135                      ConfigOCs co, *coptr;
06136                      Attribute *oc_at;
06137                      int i;
06138 
06139                      oc_at = attr_find( ce->ce_entry->e_attrs,
06140                                    slap_schema.si_ad_objectClass );
06141                      if ( !oc_at ) {
06142                             rs->sr_err = LDAP_OTHER;
06143                             rs->sr_text = "objectclass not found";
06144                             ldap_pvt_thread_pool_resume( &connection_pool );
06145                             goto out;
06146                      }
06147                      for ( i=0; !BER_BVISNULL(&oc_at->a_nvals[i]); i++ ) {
06148                             co.co_name = &oc_at->a_nvals[i];
06149                             coptr = avl_find( CfOcTree, &co, CfOc_cmp );
06150                             if ( coptr == NULL || coptr->co_type != Cft_Misc ) {
06151                                    continue;
06152                             }
06153                             if ( ! coptr->co_lddel || coptr->co_lddel( ce, op ) ){
06154                                    rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
06155                                    if ( ! coptr->co_lddel ) {
06156                                           rs->sr_text = "No delete handler found";
06157                                    } else {
06158                                           rs->sr_err = LDAP_OTHER;
06159                                           /* FIXME: We should return a helpful error message
06160                                            * here */
06161                                    }
06162                                    ldap_pvt_thread_pool_resume( &connection_pool );
06163                                    goto out;
06164                             }
06165                             break;
06166                      }
06167               } else if (ce->ce_type == Cft_Database ) {
06168                      if ( ce->ce_be == frontendDB || ce->ce_be == op->o_bd ){
06169                             rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
06170                             rs->sr_text = "Cannot delete config or frontend database";
06171                             ldap_pvt_thread_pool_resume( &connection_pool );
06172                             goto out;
06173                      }
06174                      if ( ce->ce_be->bd_info->bi_db_close ) {
06175                             ce->ce_be->bd_info->bi_db_close( ce->ce_be, NULL );
06176                      }
06177                      backend_destroy_one( ce->ce_be, 1);
06178               }
06179 
06180               /* remove CfEntryInfo from the siblings list */
06181               if ( ce->ce_parent->ce_kids == ce ) {
06182                      ce->ce_parent->ce_kids = ce->ce_sibs;
06183               } else {
06184                      for ( ce2 = ce->ce_parent->ce_kids ; ce2; ce2 = ce2->ce_sibs ) {
06185                             if ( ce2->ce_sibs == ce ) {
06186                                    ce2->ce_sibs = ce->ce_sibs;
06187                                    break;
06188                             }
06189                      }
06190               }
06191 
06192               /* remove from underlying database */
06193               if ( cfb->cb_use_ldif ) {
06194                      BackendDB *be = op->o_bd;
06195                      slap_callback sc = { NULL, slap_null_cb, NULL, NULL }, *scp;
06196                      struct berval dn, ndn, req_dn, req_ndn;
06197 
06198                      op->o_bd = &cfb->cb_db;
06199 
06200                      dn = op->o_dn;
06201                      ndn = op->o_ndn;
06202                      req_dn = op->o_req_dn;
06203                      req_ndn = op->o_req_ndn;
06204 
06205                      op->o_dn = op->o_bd->be_rootdn;
06206                      op->o_ndn = op->o_bd->be_rootndn;
06207                      op->o_req_dn = ce->ce_entry->e_name;
06208                      op->o_req_ndn = ce->ce_entry->e_nname;
06209 
06210                      scp = op->o_callback;
06211                      op->o_callback = &sc;
06212                      op->o_bd->be_delete( op, rs );
06213                      op->o_bd = be;
06214                      op->o_callback = scp;
06215                      op->o_dn = dn;
06216                      op->o_ndn = ndn;
06217                      op->o_req_dn = req_dn;
06218                      op->o_req_ndn = req_ndn;
06219               }
06220 
06221               /* renumber siblings */
06222               iptr = ber_bvchr( &op->o_req_ndn, '{' ) + 1;
06223               ixold = strtol( iptr, NULL, 0 );
06224               for (ce2 = ce->ce_sibs, count=0; ce2; ce2=ce2->ce_sibs) {
06225                      config_renumber_one( op, rs, ce2->ce_parent, ce2->ce_entry,
06226                             count+ixold, 0, cfb->cb_use_ldif );
06227                      count++;
06228               }
06229 
06230               ce->ce_entry->e_private=NULL;
06231               entry_free(ce->ce_entry);
06232               ch_free(ce);
06233               ldap_pvt_thread_pool_resume( &connection_pool );
06234        } else {
06235               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
06236        }
06237 out:
06238 #else
06239        rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
06240 #endif /* SLAP_CONFIG_DELETE */
06241        send_ldap_result( op, rs );
06242        return rs->sr_err;
06243 }
06244 
06245 static int
06246 config_back_search( Operation *op, SlapReply *rs )
06247 {
06248        CfBackInfo *cfb;
06249        CfEntryInfo *ce, *last;
06250        slap_mask_t mask;
06251 
06252        cfb = (CfBackInfo *)op->o_bd->be_private;
06253 
06254        ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
06255        if ( !ce ) {
06256               if ( last )
06257                      rs->sr_matched = last->ce_entry->e_name.bv_val;
06258               rs->sr_err = LDAP_NO_SUCH_OBJECT;
06259               goto out;
06260        }
06261        if ( !access_allowed_mask( op, ce->ce_entry, slap_schema.si_ad_entry, NULL,
06262               ACL_SEARCH, NULL, &mask ))
06263        {
06264               if ( !ACL_GRANT( mask, ACL_DISCLOSE )) {
06265                      rs->sr_err = LDAP_NO_SUCH_OBJECT;
06266               } else {
06267                      rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
06268               }
06269               goto out;
06270        }
06271        switch ( op->ors_scope ) {
06272        case LDAP_SCOPE_BASE:
06273        case LDAP_SCOPE_SUBTREE:
06274               rs->sr_err = config_send( op, rs, ce, 0 );
06275               break;
06276               
06277        case LDAP_SCOPE_ONELEVEL:
06278               for (ce = ce->ce_kids; ce; ce=ce->ce_sibs) {
06279                      rs->sr_err = config_send( op, rs, ce, 1 );
06280                      if ( rs->sr_err ) {
06281                             break;
06282                      }
06283               }
06284               break;
06285        }
06286 
06287 out:
06288        send_ldap_result( op, rs );
06289        return rs->sr_err;
06290 }
06291 
06292 /* no-op, we never free entries */
06293 int config_entry_release(
06294        Operation *op,
06295        Entry *e,
06296        int rw )
06297 {
06298        if ( !e->e_private ) {
06299               entry_free( e );
06300        }
06301        return LDAP_SUCCESS;
06302 }
06303 
06304 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
06305  */
06306 int config_back_entry_get(
06307        Operation *op,
06308        struct berval *ndn,
06309        ObjectClass *oc,
06310        AttributeDescription *at,
06311        int rw,
06312        Entry **ent )
06313 {
06314        CfBackInfo *cfb;
06315        CfEntryInfo *ce, *last;
06316        int rc = LDAP_NO_SUCH_OBJECT;
06317 
06318        cfb = (CfBackInfo *)op->o_bd->be_private;
06319 
06320        ce = config_find_base( cfb->cb_root, ndn, &last );
06321        if ( ce ) {
06322               *ent = ce->ce_entry;
06323               if ( *ent ) {
06324                      rc = LDAP_SUCCESS;
06325                      if ( oc && !is_entry_objectclass_or_sub( *ent, oc ) ) {
06326                             rc = LDAP_NO_SUCH_ATTRIBUTE;
06327                             *ent = NULL;
06328                      }
06329               }
06330        }
06331 
06332        return rc;
06333 }
06334 
06335 static int
06336 config_build_attrs( Entry *e, AttributeType **at, AttributeDescription *ad,
06337        ConfigTable *ct, ConfigArgs *c )
06338 {
06339        int i, rc;
06340 
06341        for (; at && *at; at++) {
06342               /* Skip the naming attr */
06343               if ((*at)->sat_ad == ad || (*at)->sat_ad == slap_schema.si_ad_cn )
06344                      continue;
06345               for (i=0;ct[i].name;i++) {
06346                      if (ct[i].ad == (*at)->sat_ad) {
06347                             rc = config_get_vals(&ct[i], c);
06348                             /* NOTE: tolerate that config_get_vals()
06349                              * returns success with no values */
06350                             if (rc == LDAP_SUCCESS && c->rvalue_vals != NULL ) {
06351                                    if ( c->rvalue_nvals )
06352                                           rc = attr_merge(e, ct[i].ad, c->rvalue_vals,
06353                                                  c->rvalue_nvals);
06354                                    else {
06355                                           slap_syntax_validate_func *validate =
06356                                                  ct[i].ad->ad_type->sat_syntax->ssyn_validate;
06357                                           if ( validate ) {
06358                                                  int j;
06359                                                  for ( j=0; c->rvalue_vals[j].bv_val; j++ ) {
06360                                                         rc = ordered_value_validate( ct[i].ad,
06361                                                                &c->rvalue_vals[j], LDAP_MOD_ADD );
06362                                                         if ( rc ) {
06363                                                                Debug( LDAP_DEBUG_ANY,
06364                                                                       "config_build_attrs: error %d on %s value #%d\n",
06365                                                                       rc, ct[i].ad->ad_cname.bv_val, j );
06366                                                                return rc;
06367                                                         }
06368                                                  }
06369                                           }
06370                                                  
06371                                           rc = attr_merge_normalize(e, ct[i].ad,
06372                                                  c->rvalue_vals, NULL);
06373                                    }
06374                                    ber_bvarray_free( c->rvalue_nvals );
06375                                    ber_bvarray_free( c->rvalue_vals );
06376                                    if ( rc ) {
06377                                           Debug( LDAP_DEBUG_ANY,
06378                                                  "config_build_attrs: error %d on %s\n",
06379                                                  rc, ct[i].ad->ad_cname.bv_val, 0 );
06380                                           return rc;
06381                                    }
06382                             }
06383                             break;
06384                      }
06385               }
06386        }
06387        return 0;
06388 }
06389 
06390 /* currently (2010) does not access rs except possibly writing rs->sr_err */
06391 
06392 Entry *
06393 config_build_entry( Operation *op, SlapReply *rs, CfEntryInfo *parent,
06394        ConfigArgs *c, struct berval *rdn, ConfigOCs *main, ConfigOCs *extra )
06395 {
06396        Entry *e = entry_alloc();
06397        CfEntryInfo *ce = ch_calloc( 1, sizeof(CfEntryInfo) );
06398        struct berval val;
06399        struct berval ad_name;
06400        AttributeDescription *ad = NULL;
06401        int rc;
06402        char *ptr;
06403        const char *text = "";
06404        Attribute *oc_at;
06405        struct berval pdn;
06406        ObjectClass *oc;
06407        CfEntryInfo *ceprev = NULL;
06408 
06409        Debug( LDAP_DEBUG_TRACE, "config_build_entry: \"%s\"\n", rdn->bv_val, 0, 0);
06410        e->e_private = ce;
06411        ce->ce_entry = e;
06412        ce->ce_type = main->co_type;
06413        ce->ce_parent = parent;
06414        if ( parent ) {
06415               pdn = parent->ce_entry->e_nname;
06416               if ( parent->ce_kids && parent->ce_kids->ce_type <= ce->ce_type )
06417                      for ( ceprev = parent->ce_kids; ceprev->ce_sibs &&
06418                             ceprev->ce_type <= ce->ce_type;
06419                             ceprev = ceprev->ce_sibs );
06420        } else {
06421               BER_BVZERO( &pdn );
06422        }
06423 
06424        ce->ce_private = c->ca_private;
06425        ce->ce_be = c->be;
06426        ce->ce_bi = c->bi;
06427 
06428        build_new_dn( &e->e_name, &pdn, rdn, NULL );
06429        ber_dupbv( &e->e_nname, &e->e_name );
06430 
06431        attr_merge_normalize_one(e, slap_schema.si_ad_objectClass,
06432               main->co_name, NULL );
06433        if ( extra )
06434               attr_merge_normalize_one(e, slap_schema.si_ad_objectClass,
06435                      extra->co_name, NULL );
06436        ptr = strchr(rdn->bv_val, '=');
06437        ad_name.bv_val = rdn->bv_val;
06438        ad_name.bv_len = ptr - rdn->bv_val;
06439        rc = slap_bv2ad( &ad_name, &ad, &text );
06440        if ( rc ) {
06441               goto fail;
06442        }
06443        val.bv_val = ptr+1;
06444        val.bv_len = rdn->bv_len - (val.bv_val - rdn->bv_val);
06445        attr_merge_normalize_one(e, ad, &val, NULL );
06446 
06447        oc = main->co_oc;
06448        c->table = main->co_type;
06449        if ( oc->soc_required ) {
06450               rc = config_build_attrs( e, oc->soc_required, ad, main->co_table, c );
06451               if ( rc ) goto fail;
06452        }
06453 
06454        if ( oc->soc_allowed ) {
06455               rc = config_build_attrs( e, oc->soc_allowed, ad, main->co_table, c );
06456               if ( rc ) goto fail;
06457        }
06458 
06459        if ( extra ) {
06460               oc = extra->co_oc;
06461               c->table = extra->co_type;
06462               if ( oc->soc_required ) {
06463                      rc = config_build_attrs( e, oc->soc_required, ad, extra->co_table, c );
06464                      if ( rc ) goto fail;
06465               }
06466 
06467               if ( oc->soc_allowed ) {
06468                      rc = config_build_attrs( e, oc->soc_allowed, ad, extra->co_table, c );
06469                      if ( rc ) goto fail;
06470               }
06471        }
06472 
06473        oc_at = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
06474        rc = structural_class(oc_at->a_vals, &oc, NULL, &text, c->cr_msg,
06475               sizeof(c->cr_msg), op ? op->o_tmpmemctx : NULL );
06476        if ( rc != LDAP_SUCCESS ) {
06477 fail:
06478               Debug( LDAP_DEBUG_ANY,
06479                      "config_build_entry: build \"%s\" failed: \"%s\"\n",
06480                      rdn->bv_val, text, 0);
06481               return NULL;
06482        }
06483        attr_merge_normalize_one(e, slap_schema.si_ad_structuralObjectClass, &oc->soc_cname, NULL );
06484        if ( op ) {
06485               op->ora_e = e;
06486               op->ora_modlist = NULL;
06487               slap_add_opattrs( op, NULL, NULL, 0, 0 );
06488               if ( !op->o_noop ) {
06489                      SlapReply rs2 = {REP_RESULT};
06490                      op->o_bd->be_add( op, &rs2 );
06491                      rs->sr_err = rs2.sr_err;
06492                      rs_assert_done( &rs2 );
06493                      if ( ( rs2.sr_err != LDAP_SUCCESS ) 
06494                                    && (rs2.sr_err != LDAP_ALREADY_EXISTS) ) {
06495                             goto fail;
06496                      }
06497               }
06498        }
06499        if ( ceprev ) {
06500               ce->ce_sibs = ceprev->ce_sibs;
06501               ceprev->ce_sibs = ce;
06502        } else if ( parent ) {
06503               ce->ce_sibs = parent->ce_kids;
06504               parent->ce_kids = ce;
06505        }
06506 
06507        return e;
06508 }
06509 
06510 static int
06511 config_build_schema_inc( ConfigArgs *c, CfEntryInfo *ceparent,
06512        Operation *op, SlapReply *rs )
06513 {
06514        Entry *e;
06515        ConfigFile *cf = c->ca_private;
06516        char *ptr;
06517        struct berval bv, rdn;
06518 
06519        for (; cf; cf=cf->c_sibs, c->depth++) {
06520               if ( !cf->c_at_head && !cf->c_cr_head && !cf->c_oc_head &&
06521                      !cf->c_om_head && !cf->c_syn_head ) continue;
06522               c->value_dn.bv_val = c->log;
06523               LUTIL_SLASHPATH( cf->c_file.bv_val );
06524               bv.bv_val = strrchr(cf->c_file.bv_val, LDAP_DIRSEP[0]);
06525               if ( !bv.bv_val ) {
06526                      bv = cf->c_file;
06527               } else {
06528                      bv.bv_val++;
06529                      bv.bv_len = cf->c_file.bv_len - (bv.bv_val - cf->c_file.bv_val);
06530               }
06531               ptr = strchr( bv.bv_val, '.' );
06532               if ( ptr )
06533                      bv.bv_len = ptr - bv.bv_val;
06534               c->value_dn.bv_len = snprintf(c->value_dn.bv_val, sizeof( c->log ), "cn=" SLAP_X_ORDERED_FMT, c->depth);
06535               if ( c->value_dn.bv_len >= sizeof( c->log ) ) {
06536                      /* FIXME: how can indicate error? */
06537                      return -1;
06538               }
06539               strncpy( c->value_dn.bv_val + c->value_dn.bv_len, bv.bv_val,
06540                      bv.bv_len );
06541               c->value_dn.bv_len += bv.bv_len;
06542               c->value_dn.bv_val[c->value_dn.bv_len] ='\0';
06543               rdnNormalize( 0, NULL, NULL, &c->value_dn, &rdn, NULL );
06544 
06545               c->ca_private = cf;
06546               e = config_build_entry( op, rs, ceparent, c, &rdn,
06547                      &CFOC_SCHEMA, NULL );
06548               ch_free( rdn.bv_val );
06549               if ( !e ) {
06550                      return -1;
06551               } else if ( e && cf->c_kids ) {
06552                      c->ca_private = cf->c_kids;
06553                      config_build_schema_inc( c, e->e_private, op, rs );
06554               }
06555        }
06556        return 0;
06557 }
06558 
06559 #ifdef SLAPD_MODULES
06560 
06561 static int
06562 config_build_modules( ConfigArgs *c, CfEntryInfo *ceparent,
06563        Operation *op, SlapReply *rs )
06564 {
06565        int i;
06566        ModPaths *mp;
06567 
06568        for (i=0, mp=&modpaths; mp; mp=mp->mp_next, i++) {
06569               if ( BER_BVISNULL( &mp->mp_path ) && !mp->mp_loads )
06570                      continue;
06571               c->value_dn.bv_val = c->log;
06572               c->value_dn.bv_len = snprintf(c->value_dn.bv_val, sizeof( c->log ), "cn=module" SLAP_X_ORDERED_FMT, i);
06573               if ( c->value_dn.bv_len >= sizeof( c->log ) ) {
06574                      /* FIXME: how can indicate error? */
06575                      return -1;
06576               }
06577               c->ca_private = mp;
06578               if ( ! config_build_entry( op, rs, ceparent, c, &c->value_dn, &CFOC_MODULE, NULL )) {
06579                      return -1;
06580               }
06581        }
06582         return 0;
06583 }
06584 #endif
06585 
06586 static int
06587 config_check_schema(Operation *op, CfBackInfo *cfb)
06588 {
06589        struct berval schema_dn = BER_BVC(SCHEMA_RDN "," CONFIG_RDN);
06590        ConfigArgs c = {0};
06591        CfEntryInfo *ce, *last;
06592        Entry *e;
06593 
06594        /* If there's no root entry, we must be in the midst of converting */
06595        if ( !cfb->cb_root )
06596               return 0;
06597 
06598        /* Make sure the main schema entry exists */
06599        ce = config_find_base( cfb->cb_root, &schema_dn, &last );
06600        if ( ce ) {
06601               Attribute *a;
06602               struct berval *bv;
06603 
06604               e = ce->ce_entry;
06605 
06606               /* Make sure it's up to date */
06607               if ( cf_om_tail != om_sys_tail ) {
06608                      a = attr_find( e->e_attrs, cfAd_om );
06609                      if ( a ) {
06610                             if ( a->a_nvals != a->a_vals )
06611                                    ber_bvarray_free( a->a_nvals );
06612                             ber_bvarray_free( a->a_vals );
06613                             a->a_vals = NULL;
06614                             a->a_nvals = NULL;
06615                             a->a_numvals = 0;
06616                      }
06617                      oidm_unparse( &bv, NULL, NULL, 1 );
06618                      attr_merge_normalize( e, cfAd_om, bv, NULL );
06619                      ber_bvarray_free( bv );
06620                      cf_om_tail = om_sys_tail;
06621               }
06622               if ( cf_at_tail != at_sys_tail ) {
06623                      a = attr_find( e->e_attrs, cfAd_attr );
06624                      if ( a ) {
06625                             if ( a->a_nvals != a->a_vals )
06626                                    ber_bvarray_free( a->a_nvals );
06627                             ber_bvarray_free( a->a_vals );
06628                             a->a_vals = NULL;
06629                             a->a_nvals = NULL;
06630                             a->a_numvals = 0;
06631                      }
06632                      at_unparse( &bv, NULL, NULL, 1 );
06633                      attr_merge_normalize( e, cfAd_attr, bv, NULL );
06634                      ber_bvarray_free( bv );
06635                      cf_at_tail = at_sys_tail;
06636               }
06637               if ( cf_oc_tail != oc_sys_tail ) {
06638                      a = attr_find( e->e_attrs, cfAd_oc );
06639                      if ( a ) {
06640                             if ( a->a_nvals != a->a_vals )
06641                                    ber_bvarray_free( a->a_nvals );
06642                             ber_bvarray_free( a->a_vals );
06643                             a->a_vals = NULL;
06644                             a->a_nvals = NULL;
06645                             a->a_numvals = 0;
06646                      }
06647                      oc_unparse( &bv, NULL, NULL, 1 );
06648                      attr_merge_normalize( e, cfAd_oc, bv, NULL );
06649                      ber_bvarray_free( bv );
06650                      cf_oc_tail = oc_sys_tail;
06651               }
06652               if ( cf_syn_tail != syn_sys_tail ) {
06653                      a = attr_find( e->e_attrs, cfAd_syntax );
06654                      if ( a ) {
06655                             if ( a->a_nvals != a->a_vals )
06656                                    ber_bvarray_free( a->a_nvals );
06657                             ber_bvarray_free( a->a_vals );
06658                             a->a_vals = NULL;
06659                             a->a_nvals = NULL;
06660                             a->a_numvals = 0;
06661                      }
06662                      syn_unparse( &bv, NULL, NULL, 1 );
06663                      attr_merge_normalize( e, cfAd_syntax, bv, NULL );
06664                      ber_bvarray_free( bv );
06665                      cf_syn_tail = syn_sys_tail;
06666               }
06667        } else {
06668               SlapReply rs = {REP_RESULT};
06669               c.ca_private = NULL;
06670               e = config_build_entry( op, &rs, cfb->cb_root, &c, &schema_rdn,
06671                      &CFOC_SCHEMA, NULL );
06672               if ( !e ) {
06673                      return -1;
06674               }
06675               ce = e->e_private;
06676               ce->ce_private = cfb->cb_config;
06677               cf_at_tail = at_sys_tail;
06678               cf_oc_tail = oc_sys_tail;
06679               cf_om_tail = om_sys_tail;
06680               cf_syn_tail = syn_sys_tail;
06681        }
06682        return 0;
06683 }
06684 
06685 static const char *defacl[] = {
06686        NULL, "to", "*", "by", "*", "none", NULL
06687 };
06688 
06689 static int
06690 config_back_db_open( BackendDB *be, ConfigReply *cr )
06691 {
06692        CfBackInfo *cfb = be->be_private;
06693        struct berval rdn;
06694        Entry *e, *parent;
06695        CfEntryInfo *ce, *ceparent;
06696        int i, unsupp = 0;
06697        BackendInfo *bi;
06698        ConfigArgs c;
06699        Connection conn = {0};
06700        OperationBuffer opbuf;
06701        Operation *op;
06702        slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
06703        SlapReply rs = {REP_RESULT};
06704        void *thrctx = NULL;
06705        AccessControl *save_access;
06706 
06707        Debug( LDAP_DEBUG_TRACE, "config_back_db_open\n", 0, 0, 0);
06708 
06709        /* If we have no explicitly configured ACLs, don't just use
06710         * the global ACLs. Explicitly deny access to everything.
06711         */
06712        save_access = be->bd_self->be_acl;
06713        be->bd_self->be_acl = NULL;
06714        parse_acl(be->bd_self, "config_back_db_open", 0, 6, (char **)defacl, 0 );
06715        defacl_parsed = be->bd_self->be_acl;
06716        if ( save_access ) {
06717               be->bd_self->be_acl = save_access;
06718        } else {
06719               Debug( LDAP_DEBUG_CONFIG, "config_back_db_open: "
06720                             "No explicit ACL for back-config configured. "
06721                             "Using hardcoded default\n", 0, 0, 0 );
06722        }
06723 
06724        thrctx = ldap_pvt_thread_pool_context();
06725        connection_fake_init( &conn, &opbuf, thrctx );
06726        op = &opbuf.ob_op;
06727 
06728        op->o_tag = LDAP_REQ_ADD;
06729        op->o_callback = &cb;
06730        op->o_bd = &cfb->cb_db;
06731        op->o_dn = op->o_bd->be_rootdn;
06732        op->o_ndn = op->o_bd->be_rootndn;
06733 
06734        if ( !cfb->cb_use_ldif ) {
06735               op->o_noop = 1;
06736        }
06737 
06738        /* If we read the config from back-ldif, do some quick sanity checks */
06739        if ( cfb->cb_got_ldif ) {
06740               return config_check_schema( op, cfb );
06741        }
06742 
06743        /* create root of tree */
06744        rdn = config_rdn;
06745        c.ca_private = cfb->cb_config;
06746        c.be = frontendDB;
06747        e = config_build_entry( op, &rs, NULL, &c, &rdn, &CFOC_GLOBAL, NULL );
06748        if ( !e ) {
06749               return -1;
06750        }
06751        ce = e->e_private;
06752        cfb->cb_root = ce;
06753 
06754        parent = e;
06755        ceparent = ce;
06756 
06757 #ifdef SLAPD_MODULES
06758        /* Create Module nodes... */
06759        if ( modpaths.mp_loads ) {
06760               if ( config_build_modules( &c, ceparent, op, &rs ) ){
06761                      return -1;
06762               }
06763        }
06764 #endif
06765 
06766        /* Create schema nodes... cn=schema will contain the hardcoded core
06767         * schema, read-only. Child objects will contain runtime loaded schema
06768         * files.
06769         */
06770        rdn = schema_rdn;
06771        c.ca_private = NULL;
06772        e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_SCHEMA, NULL );
06773        if ( !e ) {
06774               return -1;
06775        }
06776        ce = e->e_private;
06777        ce->ce_private = cfb->cb_config;
06778        cf_at_tail = at_sys_tail;
06779        cf_oc_tail = oc_sys_tail;
06780        cf_om_tail = om_sys_tail;
06781        cf_syn_tail = syn_sys_tail;
06782 
06783        /* Create schema nodes for included schema... */
06784        if ( cfb->cb_config->c_kids ) {
06785               int rc;
06786               c.depth = 0;
06787               c.ca_private = cfb->cb_config->c_kids;
06788               rc = config_build_schema_inc( &c, ce, op, &rs );
06789               if ( rc ) {
06790                      return -1;
06791               }
06792        }
06793 
06794        /* Create backend nodes. Skip if they don't provide a cf_table.
06795         * There usually aren't any of these.
06796         */
06797        
06798        c.line = 0;
06799        LDAP_STAILQ_FOREACH( bi, &backendInfo, bi_next) {
06800               if (!bi->bi_cf_ocs) {
06801                      /* If it only supports the old config mech, complain. */
06802                      if ( bi->bi_config ) {
06803                             Debug( LDAP_DEBUG_ANY,
06804                                    "WARNING: No dynamic config support for backend %s.\n",
06805                                    bi->bi_type, 0, 0 );
06806                             unsupp++;
06807                      }
06808                      continue;
06809               }
06810               if (!bi->bi_private) continue;
06811 
06812               rdn.bv_val = c.log;
06813               rdn.bv_len = snprintf(rdn.bv_val, sizeof( c.log ),
06814                      "%s=%s", cfAd_backend->ad_cname.bv_val, bi->bi_type);
06815               if ( rdn.bv_len >= sizeof( c.log ) ) {
06816                      /* FIXME: holler ... */ ;
06817               }
06818               c.bi = bi;
06819               e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_BACKEND,
06820                      bi->bi_cf_ocs );
06821               if ( !e ) {
06822                      return -1;
06823               }
06824        }
06825 
06826        /* Create database nodes... */
06827        frontendDB->be_cf_ocs = &CFOC_FRONTEND;
06828        LDAP_STAILQ_NEXT(frontendDB, be_next) = LDAP_STAILQ_FIRST(&backendDB);
06829        for ( i = -1, be = frontendDB ; be;
06830               i++, be = LDAP_STAILQ_NEXT( be, be_next )) {
06831               slap_overinfo *oi = NULL;
06832 
06833               if ( overlay_is_over( be )) {
06834                      oi = be->bd_info->bi_private;
06835                      bi = oi->oi_orig;
06836               } else {
06837                      bi = be->bd_info;
06838               }
06839 
06840               /* If this backend supports the old config mechanism, but not
06841                * the new mech, complain.
06842                */
06843               if ( !be->be_cf_ocs && bi->bi_db_config ) {
06844                      Debug( LDAP_DEBUG_ANY,
06845                             "WARNING: No dynamic config support for database %s.\n",
06846                             bi->bi_type, 0, 0 );
06847                      unsupp++;
06848               }
06849               rdn.bv_val = c.log;
06850               rdn.bv_len = snprintf(rdn.bv_val, sizeof( c.log ),
06851                      "%s=" SLAP_X_ORDERED_FMT "%s", cfAd_database->ad_cname.bv_val,
06852                      i, bi->bi_type);
06853               if ( rdn.bv_len >= sizeof( c.log ) ) {
06854                      /* FIXME: holler ... */ ;
06855               }
06856               c.be = be;
06857               c.bi = bi;
06858               e = config_build_entry( op, &rs, ceparent, &c, &rdn, &CFOC_DATABASE,
06859                      be->be_cf_ocs );
06860               if ( !e ) {
06861                      return -1;
06862               }
06863               ce = e->e_private;
06864               if ( be->be_cf_ocs && be->be_cf_ocs->co_cfadd ) {
06865                      rs_reinit( &rs, REP_RESULT );
06866