1 /* bconfig.c - the config backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 * This work was originally developed by Howard Chu for inclusion
18 * in OpenLDAP Software.
24 #include <ac/string.h>
29 #define CONFIG_DN "cn=config"
31 typedef struct CfEntryInfo {
32 struct CfEntryInfo *ce_sibs;
33 struct CfEntryInfo *ce_kids;
40 ConfigFile *cb_config;
44 static AttributeDescription *cfAd_backend, *cfAd_database, *cfAd_overlay,
47 static ObjectClass *cfOc_global, *cfOc_backend, *cfOc_database,
48 *cfOc_include, *cfOc_overlay;
50 static struct oc_info {
56 "DESC 'OpenLDAP configuration object' "
58 "MAY ( cn $ olcConfigFile ) )", NULL },
61 "DESC 'OpenLDAP Global configuration options' "
62 "SUP olcConfig STRUCTURAL "
63 "MAY ( olcAccess $ olcAllows $ olcArgsFile $ olcAttributeOptions $ "
64 "olcAuthRewrite $ olcAuthzPolicy $ olcAuthzRegexp $ "
65 "olcConcurrency $ olcConnMaxPending $ olcConnMaxPendingAuth $ "
66 "olcDefaultSearchBase $ olcDisallows $ olcGentleHUP $ "
67 "olcIdleTimeout $ olcIndexSubstrIfMaxLen $ olcIndexSubstrIfMinLen $ "
68 "olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcLocalSSF $ "
69 "olcLogLevel $ olcModuleLoad $ olcModulePath $ olcObjectIdentifier $ "
70 "olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ "
71 "olcPlugin $ olcPluginLogFile $ olcReadOnly $ olcReferral $ "
72 "olcReplicaPidFile $ olcReplicaArgsFile $ olcReplicationInterval $ "
73 "olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
74 "olcRootDSE $ olcSaslHost $ olcSaslRealm $ olcSaslSecProps $ "
75 "olcSchemaCheck $ olcSchemaDN $ olcSecurity $ olcSizeLimit $ "
76 "olcSockbufMaxIncoming $ olcSockbufMaxIncomingAuth $ olcSrvtab $ "
77 "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ "
78 "olcTLSCACertificatePath $ olcTLSCertificateFile $ "
79 "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ "
80 "olcTLSRandFile $ olcTLSVerifyClient ) )", &cfOc_global },
82 "NAME 'olcBackendConfig' "
83 "DESC 'OpenLDAP Backend-specific options' "
84 "SUP olcConfig STRUCTURAL "
85 "MAY ( olcBackend ) )", &cfOc_backend },
87 "NAME 'olcDatabaseConfig' "
88 "DESC 'OpenLDAP Database-specific options' "
89 "SUP olcConfig STRUCTURAL "
90 "MAY ( olcAccess $ olcDatabase $ olcLastMod $ olcLimits $ "
91 "olcMaxDerefDepth $ olcReadOnly $ olcReplica $ olcReplogFile $ "
92 "olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ olcSchemaDN $ "
93 "olcSecurity $ olcSizeLimit $ olcSuffix $ olcSyncrepl $ "
94 "olcTimeLimit $ olcUpdateDN $ olcUpdateRef ) )", &cfOc_database },
96 "NAME 'olcIncludeFile' "
97 "DESC 'OpenLDAP configuration include file' "
98 "SUP olcConfig STRUCTURAL "
99 "MAY ( olcInclude $ olcModuleLoad $ olcModulePath $ olcRootDSE ) )",
102 "NAME 'olcOverlayConfig' "
103 "DESC 'OpenLDAP Overlay-specific options' "
104 "SUP olcConfig STRUCTURAL "
105 "MAY ( olcOverlay ) )", &cfOc_overlay },
110 config_back_bind( Operation *op, SlapReply *rs )
112 if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op )) {
113 ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ));
114 /* frontend sends result */
118 rs->sr_err = LDAP_INVALID_CREDENTIALS;
119 send_ldap_result( op, rs );
125 config_find_base( CfEntryInfo *root, struct berval *dn, CfEntryInfo **last )
130 if ( dn_match( &root->ce_entry->e_nname, dn ))
133 c = dn->bv_val+dn->bv_len;
134 for (;*c != ',';c--);
138 for (--c;c>dn->bv_val && *c != ',';c--);
142 cdn.bv_len = dn->bv_len - (c-dn->bv_val);
144 root = root->ce_kids;
146 for (;root;root=root->ce_sibs) {
147 if ( dn_match( &root->ce_entry->e_nname, &cdn )) {
148 if ( cdn.bv_val == dn->bv_val ) {
159 config_send( Operation *op, SlapReply *rs, CfEntryInfo *ce, int depth )
163 if ( test_filter( op, ce->ce_entry, op->ors_filter ) == LDAP_COMPARE_TRUE )
165 rs->sr_attrs = op->ors_attrs;
166 rs->sr_entry = ce->ce_entry;
167 rc = send_search_entry( op, rs );
169 if ( op->ors_scope == LDAP_SCOPE_SUBTREE ) {
171 rc = config_send( op, rs, ce->ce_kids, 1 );
175 for (ce=ce->ce_sibs; ce; ce=ce->ce_sibs) {
176 rc = config_send( op, rs, ce, 0 );
185 config_back_search( Operation *op, SlapReply *rs )
188 CfEntryInfo *ce, *last;
191 if ( !be_isroot( op ) ) {
192 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
193 send_ldap_result( op, rs );
196 cfb = (CfBackInfo *)op->o_bd->be_private;
198 ce = config_find_base( cfb->cb_root, &op->o_req_ndn, &last );
201 rs->sr_matched = last->ce_entry->e_name.bv_val;
202 rs->sr_err = LDAP_NO_SUCH_OBJECT;
205 switch ( op->ors_scope ) {
206 case LDAP_SCOPE_BASE:
207 case LDAP_SCOPE_SUBTREE:
208 config_send( op, rs, ce, 0 );
211 case LDAP_SCOPE_ONELEVEL:
212 for (ce = ce->ce_kids; ce; ce=ce->ce_sibs) {
213 config_send( op, rs, ce, 1 );
218 rs->sr_err = LDAP_SUCCESS;
220 send_ldap_result( op, rs );
225 config_alloc_entry( struct berval *pdn, struct berval *rdn )
227 Entry *e = ch_calloc( 1, sizeof(Entry) );
228 CfEntryInfo *ce = ch_calloc( 1, sizeof(CfEntryInfo) );
231 build_new_dn( &e->e_name, pdn, rdn, NULL );
232 ber_dupbv( &e->e_nname, &e->e_name );
241 config_build_entry( ConfigArgs *c, Entry *e, ObjectClass *oc,
242 struct berval *rdn, ConfigTable *ct, int table )
244 struct berval vals[2];
245 struct berval ad_name;
246 AttributeDescription *ad = NULL;
252 BER_BVZERO( &vals[1] );
254 vals[0] = oc->soc_cname;
255 attr_merge(e, slap_schema.si_ad_objectClass, vals, NULL );
256 ptr = strchr(rdn->bv_val, '=');
257 ad_name.bv_val = rdn->bv_val;
258 ad_name.bv_len = ptr - rdn->bv_val;
259 rc = slap_bv2ad( &ad_name, &ad, &text );
263 vals[0].bv_val = ptr+1;
264 vals[0].bv_len = rdn->bv_len - (vals[0].bv_val - rdn->bv_val);
265 attr_merge(e, ad, vals, NULL );
267 for (at=oc->soc_allowed;*at;at++) {
268 /* Skip the naming attr */
269 if ((*at)->sat_ad == ad || (*at)->sat_ad == slap_schema.si_ad_cn )
271 for (i=0;ct[i].name;i++) {
272 if (ct[i].ad == (*at)->sat_ad)
275 rc = config_get_vals(&ct[i], c);
276 if (rc == LDAP_SUCCESS) {
277 attr_merge(e, ct[i].ad, c->rvalue_vals, c->rvalue_nvals);
282 if ( table == BI_TABLE )
283 ct = c->bi->bi_cf_table;
285 ct = c->be->be_cf_table;
286 for (;ct && ct->name;ct++) {
287 if (!ct->ad) continue;
288 rc = config_get_vals(ct, c);
289 if (rc == LDAP_SUCCESS) {
290 attr_merge(e, ct->ad, c->rvalue_vals, c->rvalue_nvals);
299 config_build_includes( ConfigArgs *c, Entry *parent )
303 ConfigFile *cf = (ConfigFile *)c->line;
304 CfEntryInfo *ce, *ceparent, *ceprev;
306 ceparent = parent->e_private;
308 for (i=0; cf; cf=cf->c_sibs, i++) {
309 c->value_dn.bv_val = c->log;
310 c->value_dn.bv_len = sprintf(c->value_dn.bv_val, "cn=include{%d}", i);
311 e = config_alloc_entry( &parent->e_nname, &c->value_dn );
312 c->line = (char *)cf;
313 config_build_entry( c, e, cfOc_include, &c->value_dn,
314 c->bi->bi_cf_table, NO_TABLE );
316 if ( !ceparent->ce_kids ) {
317 ceparent->ce_kids = ce;
319 ceprev->ce_sibs = ce;
323 c->line = (char *)cf->c_kids;
324 config_build_includes( c, e );
331 config_back_db_open( BackendDB *be )
333 CfBackInfo *cfb = be->be_private;
336 CfEntryInfo *ce, *ceparent, *ceprev;
343 /* create root of tree */
344 ber_str2bv( CONFIG_DN, STRLENOF( CONFIG_DN ), 0, &rdn );
345 e = config_alloc_entry( NULL, &rdn );
350 c.line = (char *)cfb->cb_config;
351 ct = c.bi->bi_cf_table;
352 config_build_entry( &c, e, cfOc_global, &rdn, ct, NO_TABLE );
357 /* Create includeFile nodes... */
358 if ( cfb->cb_config->c_kids ) {
359 c.line = (char *)cfb->cb_config->c_kids;
360 ceprev = config_build_includes( &c, parent );
363 /* Create backend nodes. Skip if they don't provide a cf_table.
364 * There usually aren't any of these.
369 for (i=0; i<nBackendInfo; i++, bi++) {
370 if (!bi->bi_cf_table) continue;
371 if (!bi->bi_private) continue;
374 rdn.bv_len = sprintf(rdn.bv_val, "%s=%s", cfAd_backend->ad_cname.bv_val, bi->bi_type);
375 e = config_alloc_entry( &parent->e_nname, &rdn );
379 config_build_entry( &c, e, cfOc_backend, &rdn, ct, BI_TABLE );
380 if ( !ceparent->ce_kids ) {
381 ceparent->ce_kids = ce;
383 ceprev->ce_sibs = ce;
388 /* Create database nodes... */
389 for (i=0; i<nBackendDB; i++) {
390 slap_overinfo *oi = NULL;
394 bptr = &backendDB[i];
396 if ( overlay_is_over( bptr )) {
397 oi = bptr->bd_info->bi_private;
403 rdn.bv_len = sprintf(rdn.bv_val, "%s={%0x}%s", cfAd_database->ad_cname.bv_val,
405 e = config_alloc_entry( &parent->e_nname, &rdn );
411 config_build_entry( &c, e, cfOc_database, &rdn, ct, BE_TABLE );
412 if ( !ceparent->ce_kids ) {
413 ceparent->ce_kids = ce;
415 ceprev->ce_sibs = ce;
418 /* Iterate through overlays */
422 CfEntryInfo *opar = ce, *oprev = NULL;
425 for (j=0,on=oi->oi_list; on; j++,on=on->on_next) {
427 rdn.bv_len = sprintf(rdn.bv_val, "%s={%0x}%s",
428 cfAd_overlay->ad_cname.bv_val, j, on->on_bi.bi_type );
429 oe = config_alloc_entry( &e->e_nname, &rdn );
435 config_build_entry( &c, oe, cfOc_overlay, &rdn, ct, BI_TABLE );
436 if ( !opar->ce_kids ) {
450 config_back_db_destroy( Backend *be )
452 free( be->be_private );
457 config_back_initialize( BackendInfo *bi )
465 bi->bi_db_config = 0;
466 bi->bi_db_open = config_back_db_open;
468 bi->bi_db_destroy = config_back_db_destroy;
470 bi->bi_op_bind = config_back_bind;
471 bi->bi_op_unbind = 0;
472 bi->bi_op_search = config_back_search;
473 bi->bi_op_compare = 0;
474 bi->bi_op_modify = 0;
475 bi->bi_op_modrdn = 0;
477 bi->bi_op_delete = 0;
478 bi->bi_op_abandon = 0;
482 bi->bi_chk_referrals = 0;
484 bi->bi_connection_init = 0;
485 bi->bi_connection_destroy = 0;
492 AttributeDescription **desc;
493 AttributeDescription *sub;
495 { "attribute", NULL, NULL },
496 { "backend", &cfAd_backend, NULL },
497 { "database", &cfAd_database, NULL },
498 { "ditcontentrule", NULL, NULL },
499 { "include", &cfAd_include, NULL },
500 { "objectclass", NULL, NULL },
501 { "overlay", &cfAd_overlay, NULL },
505 int config_back_init( ConfigFile *cfp, ConfigTable *ct )
507 BackendInfo bi = {0};
513 bi.bi_type = "config";
514 bi.bi_init = config_back_initialize;
517 be = backend_db_init( bi.bi_type );
518 ber_str2bv( CONFIG_DN, 0, 1, &be->be_rootdn );
519 ber_dupbv( &be->be_rootndn, &be->be_rootdn );
520 ber_dupbv( &dn, &be->be_rootdn );
521 ber_bvarray_add( &be->be_suffix, &dn );
522 ber_dupbv( &dn, &be->be_rootdn );
523 ber_bvarray_add( &be->be_nsuffix, &dn );
524 cfb = ch_calloc( 1, sizeof(CfBackInfo));
525 cfb->cb_config = cfp;
526 be->be_private = cfb;
528 /* set up the notable AttributeDescriptions */
529 ads[0].sub = slap_schema.si_ad_attributeTypes;
530 ads[3].sub = slap_schema.si_ad_ditContentRules;
531 ads[5].sub = slap_schema.si_ad_objectClasses;
534 for (;ct->name;ct++) {
535 if (strcmp(ct->name, ads[i].name)) continue;
539 *ads[i].desc = ct->ad;
542 if (!ads[i].name) break;
545 /* set up the objectclasses */
546 for (i=0;cf_ocs[i].def;i++) {
551 oc = ldap_str2objectclass( cf_ocs[i].def, &code, &err,
552 LDAP_SCHEMA_ALLOW_ALL );
554 fprintf( stderr, "config_back_init: objectclass \"%s\": %s, %s\n",
555 cf_ocs[i].def, ldap_scherr2str(code), err );
558 code = oc_add(oc,0,&err);
560 fprintf( stderr, "config_back_init: objectclass \"%s\": %s, %s\n",
561 cf_ocs[i].def, scherr2str(code), err );
564 if ( cf_ocs[i].oc ) {
565 *cf_ocs[i].oc = oc_find(oc->oc_names[0]);