mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-21 03:10:25 +08:00
edc94862b7
Additional fix to 41352ea34d
The overlay must be deleted from the backend before the
callback can execute. In particular, it must be done before
the threadpool is unpaused.
1485 lines
33 KiB
C
1485 lines
33 KiB
C
/* backover.c - backend overlay routines */
|
|
/* $OpenLDAP$ */
|
|
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
|
*
|
|
* Copyright 2003-2020 The OpenLDAP Foundation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted only as authorized by the OpenLDAP
|
|
* Public License.
|
|
*
|
|
* A copy of this license is available in the file LICENSE in the
|
|
* top-level directory of the distribution or, alternatively, at
|
|
* <http://www.OpenLDAP.org/license.html>.
|
|
*/
|
|
|
|
/* Functions to overlay other modules over a backend. */
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ac/string.h>
|
|
#include <ac/socket.h>
|
|
|
|
#define SLAPD_TOOLS
|
|
#include "slap.h"
|
|
#include "config.h"
|
|
|
|
static slap_overinst *overlays;
|
|
|
|
static int
|
|
over_db_config(
|
|
BackendDB *be,
|
|
const char *fname,
|
|
int lineno,
|
|
int argc,
|
|
char **argv
|
|
)
|
|
{
|
|
slap_overinfo *oi = be->bd_info->bi_private;
|
|
slap_overinst *on = oi->oi_list;
|
|
BackendInfo *bi_orig = be->bd_info;
|
|
struct ConfigOCs *be_cf_ocs = be->be_cf_ocs;
|
|
ConfigArgs ca = {0};
|
|
int rc = 0;
|
|
|
|
if ( oi->oi_orig->bi_db_config ) {
|
|
be->bd_info = oi->oi_orig;
|
|
be->be_cf_ocs = oi->oi_orig->bi_cf_ocs;
|
|
rc = oi->oi_orig->bi_db_config( be, fname, lineno,
|
|
argc, argv );
|
|
|
|
if ( be->bd_info != oi->oi_orig ) {
|
|
slap_overinfo *oi2;
|
|
slap_overinst *on2, **onp;
|
|
BackendDB be2 = *be;
|
|
int i;
|
|
|
|
/* a database added an overlay;
|
|
* work it around... */
|
|
assert( overlay_is_over( be ) );
|
|
|
|
oi2 = ( slap_overinfo * )be->bd_info->bi_private;
|
|
on2 = oi2->oi_list;
|
|
|
|
/* need to put a uniqueness check here as well;
|
|
* note that in principle there could be more than
|
|
* one overlay as a result of multiple calls to
|
|
* overlay_config() */
|
|
be2.bd_info = (BackendInfo *)oi;
|
|
|
|
for ( i = 0, onp = &on2; *onp; i++, onp = &(*onp)->on_next ) {
|
|
if ( overlay_is_inst( &be2, (*onp)->on_bi.bi_type ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "over_db_config(): "
|
|
"warning, freshly added "
|
|
"overlay #%d \"%s\" is already in list\n",
|
|
i, (*onp)->on_bi.bi_type );
|
|
|
|
/* NOTE: if the overlay already exists,
|
|
* there is no way to merge the results
|
|
* of the configuration that may have
|
|
* occurred during bi_db_config(); we
|
|
* just issue a warning, and the
|
|
* administrator should deal with this */
|
|
}
|
|
}
|
|
*onp = oi->oi_list;
|
|
|
|
oi->oi_list = on2;
|
|
|
|
ch_free( be->bd_info );
|
|
}
|
|
|
|
be->bd_info = (BackendInfo *)oi;
|
|
if ( rc != SLAP_CONF_UNKNOWN ) return rc;
|
|
}
|
|
|
|
ca.argv = argv;
|
|
ca.argc = argc;
|
|
ca.fname = fname;
|
|
ca.lineno = lineno;
|
|
ca.be = be;
|
|
snprintf( ca.log, sizeof( ca.log ), "%s: line %d",
|
|
ca.fname, ca.lineno );
|
|
ca.op = SLAP_CONFIG_ADD;
|
|
ca.valx = -1;
|
|
|
|
for (; on; on=on->on_next) {
|
|
rc = SLAP_CONF_UNKNOWN;
|
|
if (on->on_bi.bi_cf_ocs) {
|
|
ConfigTable *ct;
|
|
ca.bi = &on->on_bi;
|
|
ct = config_find_keyword( on->on_bi.bi_cf_ocs->co_table, &ca );
|
|
if ( ct ) {
|
|
ca.table = on->on_bi.bi_cf_ocs->co_type;
|
|
rc = config_add_vals( ct, &ca );
|
|
if ( rc != SLAP_CONF_UNKNOWN )
|
|
break;
|
|
}
|
|
}
|
|
if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) {
|
|
be->bd_info = &on->on_bi;
|
|
rc = on->on_bi.bi_db_config( be, fname, lineno,
|
|
argc, argv );
|
|
if ( rc != SLAP_CONF_UNKNOWN ) break;
|
|
}
|
|
}
|
|
be->bd_info = bi_orig;
|
|
be->be_cf_ocs = be_cf_ocs;
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_db_open(
|
|
BackendDB *be,
|
|
ConfigReply *cr
|
|
)
|
|
{
|
|
slap_overinfo *oi = be->bd_info->bi_private;
|
|
slap_overinst *on = oi->oi_list;
|
|
BackendDB db = *be;
|
|
int rc = 0;
|
|
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
db.bd_info = oi->oi_orig;
|
|
if ( db.bd_info->bi_db_open ) {
|
|
rc = db.bd_info->bi_db_open( &db, cr );
|
|
}
|
|
|
|
for (; on && rc == 0; on=on->on_next) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
db.bd_info = &on->on_bi;
|
|
if ( db.bd_info->bi_db_open ) {
|
|
rc = db.bd_info->bi_db_open( &db, cr );
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_db_close(
|
|
BackendDB *be,
|
|
ConfigReply *cr
|
|
)
|
|
{
|
|
slap_overinfo *oi = be->bd_info->bi_private;
|
|
slap_overinst *on = oi->oi_list;
|
|
BackendInfo *bi_orig = be->bd_info;
|
|
int rc = 0;
|
|
|
|
for (; on && rc == 0; on=on->on_next) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
be->bd_info = &on->on_bi;
|
|
if ( be->bd_info->bi_db_close ) {
|
|
rc = be->bd_info->bi_db_close( be, cr );
|
|
}
|
|
}
|
|
|
|
if ( oi->oi_orig->bi_db_close ) {
|
|
be->bd_info = oi->oi_orig;
|
|
rc = be->bd_info->bi_db_close( be, cr );
|
|
}
|
|
|
|
be->bd_info = bi_orig;
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_db_destroy(
|
|
BackendDB *be,
|
|
ConfigReply *cr
|
|
)
|
|
{
|
|
slap_overinfo *oi = be->bd_info->bi_private;
|
|
slap_overinst *on = oi->oi_list, *next;
|
|
BackendInfo *bi_orig = be->bd_info;
|
|
int rc = 0;
|
|
|
|
be->bd_info = oi->oi_orig;
|
|
if ( be->bd_info->bi_db_destroy ) {
|
|
rc = be->bd_info->bi_db_destroy( be, cr );
|
|
}
|
|
|
|
for (; on && rc == 0; on=on->on_next) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
be->bd_info = &on->on_bi;
|
|
if ( be->bd_info->bi_db_destroy ) {
|
|
rc = be->bd_info->bi_db_destroy( be, cr );
|
|
}
|
|
}
|
|
|
|
on = oi->oi_list;
|
|
if ( on ) {
|
|
for (next = on->on_next; on; on=next) {
|
|
next = on->on_next;
|
|
free( on );
|
|
}
|
|
}
|
|
be->bd_info = bi_orig;
|
|
free( oi );
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_back_response ( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinfo *oi = op->o_callback->sc_private;
|
|
slap_overinst *on = oi->oi_list;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
BackendDB *be = op->o_bd, db = *op->o_bd;
|
|
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
op->o_bd = &db;
|
|
for (; on; on=on->on_next ) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
if ( on->on_response ) {
|
|
db.bd_info = (BackendInfo *)on;
|
|
rc = on->on_response( op, rs );
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
|
}
|
|
}
|
|
/* Bypass the remaining on_response layers, but allow
|
|
* normal execution to continue.
|
|
*/
|
|
if ( rc == SLAP_CB_BYPASS )
|
|
rc = SLAP_CB_CONTINUE;
|
|
op->o_bd = be;
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_access_allowed(
|
|
Operation *op,
|
|
Entry *e,
|
|
AttributeDescription *desc,
|
|
struct berval *val,
|
|
slap_access_t access,
|
|
AccessControlState *state,
|
|
slap_mask_t *maskp )
|
|
{
|
|
slap_overinfo *oi;
|
|
slap_overinst *on;
|
|
BackendInfo *bi;
|
|
BackendDB *be = op->o_bd, db;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
|
|
/* FIXME: used to happen for instance during abandon
|
|
* when global overlays are used... */
|
|
assert( op->o_bd != NULL );
|
|
|
|
bi = op->o_bd->bd_info;
|
|
/* Were we invoked on the frontend? */
|
|
if ( !bi->bi_access_allowed ) {
|
|
oi = frontendDB->bd_info->bi_private;
|
|
} else {
|
|
oi = op->o_bd->bd_info->bi_private;
|
|
}
|
|
on = oi->oi_list;
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
if ( on->on_bi.bi_access_allowed ) {
|
|
/* NOTE: do not copy the structure until required */
|
|
if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
db = *op->o_bd;
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
op->o_bd = &db;
|
|
}
|
|
|
|
op->o_bd->bd_info = (BackendInfo *)on;
|
|
rc = on->on_bi.bi_access_allowed( op, e,
|
|
desc, val, access, state, maskp );
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
|
}
|
|
}
|
|
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
BI_access_allowed *bi_access_allowed;
|
|
|
|
/* if the database structure was changed, o_bd points to a
|
|
* copy of the structure; put the original bd_info in place */
|
|
if ( SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
op->o_bd->bd_info = oi->oi_orig;
|
|
}
|
|
|
|
if ( oi->oi_orig->bi_access_allowed ) {
|
|
bi_access_allowed = oi->oi_orig->bi_access_allowed;
|
|
} else {
|
|
bi_access_allowed = slap_access_allowed;
|
|
}
|
|
|
|
rc = bi_access_allowed( op, e,
|
|
desc, val, access, state, maskp );
|
|
}
|
|
/* should not fall thru this far without anything happening... */
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
/* access not allowed */
|
|
rc = 0;
|
|
}
|
|
|
|
op->o_bd = be;
|
|
if ( SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
op->o_bd->bd_info = bi;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
overlay_entry_get_ov(
|
|
Operation *op,
|
|
struct berval *dn,
|
|
ObjectClass *oc,
|
|
AttributeDescription *ad,
|
|
int rw,
|
|
Entry **e,
|
|
slap_overinst *on )
|
|
{
|
|
slap_overinfo *oi = on->on_info;
|
|
BackendDB *be = op->o_bd, db;
|
|
BackendInfo *bi = op->o_bd->bd_info;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
if ( on->on_bi.bi_entry_get_rw ) {
|
|
/* NOTE: do not copy the structure until required */
|
|
if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
db = *op->o_bd;
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
op->o_bd = &db;
|
|
}
|
|
|
|
op->o_bd->bd_info = (BackendInfo *)on;
|
|
rc = on->on_bi.bi_entry_get_rw( op, dn,
|
|
oc, ad, rw, e );
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
|
}
|
|
}
|
|
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
/* if the database structure was changed, o_bd points to a
|
|
* copy of the structure; put the original bd_info in place */
|
|
if ( SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
op->o_bd->bd_info = oi->oi_orig;
|
|
}
|
|
|
|
if ( oi->oi_orig->bi_entry_get_rw ) {
|
|
rc = oi->oi_orig->bi_entry_get_rw( op, dn,
|
|
oc, ad, rw, e );
|
|
}
|
|
}
|
|
/* should not fall thru this far without anything happening... */
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
}
|
|
|
|
op->o_bd = be;
|
|
if ( SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
op->o_bd->bd_info = bi;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_entry_get_rw(
|
|
Operation *op,
|
|
struct berval *dn,
|
|
ObjectClass *oc,
|
|
AttributeDescription *ad,
|
|
int rw,
|
|
Entry **e )
|
|
{
|
|
slap_overinfo *oi;
|
|
slap_overinst *on;
|
|
|
|
assert( op->o_bd != NULL );
|
|
|
|
oi = op->o_bd->bd_info->bi_private;
|
|
on = oi->oi_list;
|
|
|
|
return overlay_entry_get_ov( op, dn, oc, ad, rw, e, on );
|
|
}
|
|
|
|
int
|
|
overlay_entry_release_ov(
|
|
Operation *op,
|
|
Entry *e,
|
|
int rw,
|
|
slap_overinst *on )
|
|
{
|
|
slap_overinfo *oi = on->on_info;
|
|
BackendDB *be = op->o_bd, db;
|
|
BackendInfo *bi = op->o_bd->bd_info;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
if ( on->on_bi.bi_entry_release_rw ) {
|
|
/* NOTE: do not copy the structure until required */
|
|
if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
db = *op->o_bd;
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
op->o_bd = &db;
|
|
}
|
|
|
|
op->o_bd->bd_info = (BackendInfo *)on;
|
|
rc = on->on_bi.bi_entry_release_rw( op, e, rw );
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
|
}
|
|
}
|
|
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
/* if the database structure was changed, o_bd points to a
|
|
* copy of the structure; put the original bd_info in place */
|
|
if ( SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
op->o_bd->bd_info = oi->oi_orig;
|
|
}
|
|
|
|
if ( oi->oi_orig->bi_entry_release_rw ) {
|
|
rc = oi->oi_orig->bi_entry_release_rw( op, e, rw );
|
|
}
|
|
}
|
|
/* should not fall thru this far without anything happening... */
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
entry_free( e );
|
|
rc = 0;
|
|
}
|
|
|
|
op->o_bd = be;
|
|
if ( SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
op->o_bd->bd_info = bi;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_entry_release_rw(
|
|
Operation *op,
|
|
Entry *e,
|
|
int rw )
|
|
{
|
|
slap_overinfo *oi;
|
|
slap_overinst *on;
|
|
|
|
assert( op->o_bd != NULL );
|
|
|
|
oi = op->o_bd->bd_info->bi_private;
|
|
on = oi->oi_list;
|
|
|
|
return overlay_entry_release_ov( op, e, rw, on );
|
|
}
|
|
|
|
static int
|
|
over_acl_group(
|
|
Operation *op,
|
|
Entry *e,
|
|
struct berval *gr_ndn,
|
|
struct berval *op_ndn,
|
|
ObjectClass *group_oc,
|
|
AttributeDescription *group_at )
|
|
{
|
|
slap_overinfo *oi;
|
|
slap_overinst *on;
|
|
BackendInfo *bi;
|
|
BackendDB *be = op->o_bd, db;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
|
|
/* FIXME: used to happen for instance during abandon
|
|
* when global overlays are used... */
|
|
assert( be != NULL );
|
|
|
|
bi = be->bd_info;
|
|
oi = bi->bi_private;
|
|
on = oi->oi_list;
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
if ( on->on_bi.bi_acl_group ) {
|
|
/* NOTE: do not copy the structure until required */
|
|
if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
db = *op->o_bd;
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
op->o_bd = &db;
|
|
}
|
|
|
|
op->o_bd->bd_info = (BackendInfo *)on;
|
|
rc = on->on_bi.bi_acl_group( op, e,
|
|
gr_ndn, op_ndn, group_oc, group_at );
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
|
}
|
|
}
|
|
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
BI_acl_group *bi_acl_group;
|
|
|
|
/* if the database structure was changed, o_bd points to a
|
|
* copy of the structure; put the original bd_info in place */
|
|
if ( SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
op->o_bd->bd_info = oi->oi_orig;
|
|
}
|
|
|
|
if ( oi->oi_orig->bi_acl_group ) {
|
|
bi_acl_group = oi->oi_orig->bi_acl_group;
|
|
} else {
|
|
bi_acl_group = backend_group;
|
|
}
|
|
|
|
rc = bi_acl_group( op, e,
|
|
gr_ndn, op_ndn, group_oc, group_at );
|
|
}
|
|
/* should not fall thru this far without anything happening... */
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
/* access not allowed */
|
|
rc = 0;
|
|
}
|
|
|
|
op->o_bd = be;
|
|
if ( SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
op->o_bd->bd_info = bi;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_acl_attribute(
|
|
Operation *op,
|
|
Entry *target,
|
|
struct berval *entry_ndn,
|
|
AttributeDescription *entry_at,
|
|
BerVarray *vals,
|
|
slap_access_t access )
|
|
{
|
|
slap_overinfo *oi;
|
|
slap_overinst *on;
|
|
BackendInfo *bi;
|
|
BackendDB *be = op->o_bd, db;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
|
|
/* FIXME: used to happen for instance during abandon
|
|
* when global overlays are used... */
|
|
assert( be != NULL );
|
|
|
|
bi = be->bd_info;
|
|
oi = bi->bi_private;
|
|
on = oi->oi_list;
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
if ( on->on_bi.bi_acl_attribute ) {
|
|
/* NOTE: do not copy the structure until required */
|
|
if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
db = *op->o_bd;
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
op->o_bd = &db;
|
|
}
|
|
|
|
op->o_bd->bd_info = (BackendInfo *)on;
|
|
rc = on->on_bi.bi_acl_attribute( op, target,
|
|
entry_ndn, entry_at, vals, access );
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
|
}
|
|
}
|
|
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
BI_acl_attribute *bi_acl_attribute;
|
|
|
|
/* if the database structure was changed, o_bd points to a
|
|
* copy of the structure; put the original bd_info in place */
|
|
if ( SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
op->o_bd->bd_info = oi->oi_orig;
|
|
}
|
|
|
|
if ( oi->oi_orig->bi_acl_attribute ) {
|
|
bi_acl_attribute = oi->oi_orig->bi_acl_attribute;
|
|
} else {
|
|
bi_acl_attribute = backend_attribute;
|
|
}
|
|
|
|
rc = bi_acl_attribute( op, target,
|
|
entry_ndn, entry_at, vals, access );
|
|
}
|
|
/* should not fall thru this far without anything happening... */
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
/* access not allowed */
|
|
rc = 0;
|
|
}
|
|
|
|
op->o_bd = be;
|
|
if ( SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
op->o_bd->bd_info = bi;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
overlay_callback_after_backover( Operation *op, slap_callback *sc, int append )
|
|
{
|
|
slap_callback **scp;
|
|
|
|
for ( scp = &op->o_callback; *scp != NULL; scp = &(*scp)->sc_next ) {
|
|
if ( (*scp)->sc_response == over_back_response ) {
|
|
sc->sc_next = (*scp)->sc_next;
|
|
(*scp)->sc_next = sc;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ( append ) {
|
|
*scp = sc;
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* default return code in case of missing backend function
|
|
* and overlay stack returning SLAP_CB_CONTINUE
|
|
*/
|
|
static int op_rc[ op_last ] = {
|
|
LDAP_UNWILLING_TO_PERFORM, /* bind */
|
|
LDAP_UNWILLING_TO_PERFORM, /* unbind */
|
|
LDAP_UNWILLING_TO_PERFORM, /* search */
|
|
SLAP_CB_CONTINUE, /* compare; pass to frontend */
|
|
LDAP_UNWILLING_TO_PERFORM, /* modify */
|
|
LDAP_UNWILLING_TO_PERFORM, /* modrdn */
|
|
LDAP_UNWILLING_TO_PERFORM, /* add */
|
|
LDAP_UNWILLING_TO_PERFORM, /* delete */
|
|
LDAP_UNWILLING_TO_PERFORM, /* abandon */
|
|
LDAP_UNWILLING_TO_PERFORM, /* cancel */
|
|
LDAP_UNWILLING_TO_PERFORM, /* extended */
|
|
LDAP_SUCCESS, /* aux_operational */
|
|
LDAP_SUCCESS, /* aux_chk_referrals */
|
|
SLAP_CB_CONTINUE /* aux_chk_controls; pass to frontend */
|
|
};
|
|
|
|
int overlay_op_walk(
|
|
Operation *op,
|
|
SlapReply *rs,
|
|
slap_operation_t which,
|
|
slap_overinfo *oi,
|
|
slap_overinst *on
|
|
)
|
|
{
|
|
BackendInfo *bi;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
|
|
for (; on; on=on->on_next ) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
bi = &on->on_bi;
|
|
if ( (&bi->bi_op_bind)[ which ] ) {
|
|
op->o_bd->bd_info = (BackendInfo *)on;
|
|
rc = (&bi->bi_op_bind)[ which ]( op, rs );
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
|
}
|
|
}
|
|
if ( rc == SLAP_CB_BYPASS )
|
|
rc = SLAP_CB_CONTINUE;
|
|
/* if an overlay halted processing, make sure
|
|
* any previously set cleanup handlers are run
|
|
*/
|
|
if ( rc != SLAP_CB_CONTINUE )
|
|
goto cleanup;
|
|
|
|
bi = oi->oi_orig;
|
|
if ( (&bi->bi_op_bind)[ which ] ) {
|
|
op->o_bd->bd_info = bi;
|
|
rc = (&bi->bi_op_bind)[ which ]( op, rs );
|
|
}
|
|
/* should not fall thru this far without anything happening... */
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
rc = op_rc[ which ];
|
|
}
|
|
|
|
/* The underlying backend didn't handle the request, make sure
|
|
* overlay cleanup is processed.
|
|
*/
|
|
if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
|
|
slap_callback *sc_next;
|
|
cleanup:
|
|
for ( ; op->o_callback && op->o_callback->sc_response !=
|
|
over_back_response; op->o_callback = sc_next ) {
|
|
sc_next = op->o_callback->sc_next;
|
|
if ( op->o_callback->sc_cleanup ) {
|
|
op->o_callback->sc_cleanup( op, rs );
|
|
}
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_op_func(
|
|
Operation *op,
|
|
SlapReply *rs,
|
|
slap_operation_t which
|
|
)
|
|
{
|
|
slap_overinfo *oi;
|
|
slap_overinst *on;
|
|
BackendDB *be = op->o_bd, db;
|
|
slap_callback **sc;
|
|
slap_callback *cb;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
|
|
/* FIXME: used to happen for instance during abandon
|
|
* when global overlays are used... */
|
|
assert( op->o_bd != NULL );
|
|
|
|
oi = op->o_bd->bd_info->bi_private;
|
|
on = oi->oi_list;
|
|
|
|
if ( !SLAP_ISOVERLAY( op->o_bd )) {
|
|
db = *op->o_bd;
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
op->o_bd = &db;
|
|
}
|
|
if ( op->o_tag != LDAP_REQ_ABANDON && op->o_tag != LDAP_REQ_UNBIND ) {
|
|
cb = (slap_callback *)op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
|
|
cb->sc_cleanup = NULL;
|
|
cb->sc_response = over_back_response;
|
|
cb->sc_writewait = NULL;
|
|
cb->sc_next = op->o_callback;
|
|
cb->sc_private = oi;
|
|
op->o_callback = cb;
|
|
}
|
|
|
|
rc = overlay_op_walk( op, rs, which, oi, on );
|
|
if ( rc != SLAPD_ASYNCOP && op->o_tag != LDAP_REQ_ABANDON && op->o_tag != LDAP_REQ_UNBIND ) {
|
|
for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) {
|
|
if ( *sc == cb ) {
|
|
*sc = cb->sc_next;
|
|
op->o_tmpfree( cb, op->o_tmpmemctx );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
op->o_bd = be;
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_op_bind( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_bind );
|
|
}
|
|
|
|
static int
|
|
over_op_unbind( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_unbind );
|
|
}
|
|
|
|
static int
|
|
over_op_search( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_search );
|
|
}
|
|
|
|
static int
|
|
over_op_compare( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_compare );
|
|
}
|
|
|
|
static int
|
|
over_op_modify( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_modify );
|
|
}
|
|
|
|
static int
|
|
over_op_modrdn( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_modrdn );
|
|
}
|
|
|
|
static int
|
|
over_op_add( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_add );
|
|
}
|
|
|
|
static int
|
|
over_op_delete( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_delete );
|
|
}
|
|
|
|
static int
|
|
over_op_abandon( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_abandon );
|
|
}
|
|
|
|
static int
|
|
over_op_cancel( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_cancel );
|
|
}
|
|
|
|
static int
|
|
over_op_extended( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_extended );
|
|
}
|
|
|
|
static int
|
|
over_aux_operational( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_aux_operational );
|
|
}
|
|
|
|
static int
|
|
over_aux_chk_referrals( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_aux_chk_referrals );
|
|
}
|
|
|
|
static int
|
|
over_aux_chk_controls( Operation *op, SlapReply *rs )
|
|
{
|
|
return over_op_func( op, rs, op_aux_chk_controls );
|
|
}
|
|
|
|
enum conn_which {
|
|
conn_init = 0,
|
|
conn_destroy,
|
|
conn_last
|
|
};
|
|
|
|
static int
|
|
over_connection_func(
|
|
BackendDB *bd,
|
|
Connection *conn,
|
|
enum conn_which which
|
|
)
|
|
{
|
|
slap_overinfo *oi;
|
|
slap_overinst *on;
|
|
BackendDB db;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
BI_connection_init **func;
|
|
|
|
/* FIXME: used to happen for instance during abandon
|
|
* when global overlays are used... */
|
|
assert( bd != NULL );
|
|
|
|
oi = bd->bd_info->bi_private;
|
|
on = oi->oi_list;
|
|
|
|
if ( !SLAP_ISOVERLAY( bd ) ) {
|
|
db = *bd;
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
bd = &db;
|
|
}
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DISABLED )
|
|
continue;
|
|
func = &on->on_bi.bi_connection_init;
|
|
if ( func[ which ] ) {
|
|
bd->bd_info = (BackendInfo *)on;
|
|
rc = func[ which ]( bd, conn );
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
|
}
|
|
}
|
|
|
|
func = &oi->oi_orig->bi_connection_init;
|
|
if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
|
|
bd->bd_info = oi->oi_orig;
|
|
rc = func[ which ]( bd, conn );
|
|
}
|
|
/* should not fall thru this far without anything happening... */
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
over_connection_init(
|
|
BackendDB *bd,
|
|
Connection *conn
|
|
)
|
|
{
|
|
return over_connection_func( bd, conn, conn_init );
|
|
}
|
|
|
|
static int
|
|
over_connection_destroy(
|
|
BackendDB *bd,
|
|
Connection *conn
|
|
)
|
|
{
|
|
return over_connection_func( bd, conn, conn_destroy );
|
|
}
|
|
|
|
int
|
|
overlay_register(
|
|
slap_overinst *on
|
|
)
|
|
{
|
|
slap_overinst *tmp;
|
|
|
|
/* FIXME: check for duplicates? */
|
|
for ( tmp = overlays; tmp != NULL; tmp = tmp->on_next ) {
|
|
if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_type ) == 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"overlay_register(\"%s\"): "
|
|
"name already in use.\n",
|
|
on->on_bi.bi_type );
|
|
return -1;
|
|
}
|
|
|
|
if ( on->on_bi.bi_obsolete_names != NULL ) {
|
|
int i;
|
|
|
|
for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
|
|
if ( strcmp( on->on_bi.bi_obsolete_names[ i ], tmp->on_bi.bi_type ) == 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"overlay_register(\"%s\"): "
|
|
"obsolete name \"%s\" already in use "
|
|
"by overlay \"%s\".\n",
|
|
on->on_bi.bi_type,
|
|
on->on_bi.bi_obsolete_names[ i ],
|
|
tmp->on_bi.bi_type );
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( tmp->on_bi.bi_obsolete_names != NULL ) {
|
|
int i;
|
|
|
|
for ( i = 0; tmp->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
|
|
int j;
|
|
|
|
if ( strcmp( on->on_bi.bi_type, tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"overlay_register(\"%s\"): "
|
|
"name already in use "
|
|
"as obsolete by overlay \"%s\".\n",
|
|
on->on_bi.bi_type,
|
|
tmp->on_bi.bi_obsolete_names[ i ] );
|
|
return -1;
|
|
}
|
|
|
|
if ( on->on_bi.bi_obsolete_names != NULL ) {
|
|
for ( j = 0; on->on_bi.bi_obsolete_names[ j ] != NULL; j++ ) {
|
|
if ( strcmp( on->on_bi.bi_obsolete_names[ j ], tmp->on_bi.bi_obsolete_names[ i ] ) == 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"overlay_register(\"%s\"): "
|
|
"obsolete name \"%s\" already in use "
|
|
"as obsolete by overlay \"%s\".\n",
|
|
on->on_bi.bi_type,
|
|
on->on_bi.bi_obsolete_names[ j ],
|
|
tmp->on_bi.bi_type );
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
on->on_next = overlays;
|
|
overlays = on;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* iterator on registered overlays; overlay_next( NULL ) returns the first
|
|
* overlay; subsequent calls with the previously returned value allow to
|
|
* iterate over the entire list; returns NULL when no more overlays are
|
|
* registered.
|
|
*/
|
|
|
|
slap_overinst *
|
|
overlay_next(
|
|
slap_overinst *on
|
|
)
|
|
{
|
|
if ( on == NULL ) {
|
|
return overlays;
|
|
}
|
|
|
|
return on->on_next;
|
|
}
|
|
|
|
/*
|
|
* returns a specific registered overlay based on the type; NULL if not
|
|
* registered.
|
|
*/
|
|
|
|
slap_overinst *
|
|
overlay_find( const char *over_type )
|
|
{
|
|
slap_overinst *on = overlays;
|
|
|
|
assert( over_type != NULL );
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
|
|
goto foundit;
|
|
}
|
|
|
|
if ( on->on_bi.bi_obsolete_names != NULL ) {
|
|
int i;
|
|
|
|
for ( i = 0; on->on_bi.bi_obsolete_names[ i ] != NULL; i++ ) {
|
|
if ( strcmp( on->on_bi.bi_obsolete_names[ i ], over_type ) == 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"overlay_find(\"%s\"): "
|
|
"obsolete name for \"%s\".\n",
|
|
on->on_bi.bi_obsolete_names[ i ],
|
|
on->on_bi.bi_type );
|
|
goto foundit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foundit:;
|
|
return on;
|
|
}
|
|
|
|
static const char overtype[] = "over";
|
|
|
|
/*
|
|
* returns TRUE (1) if the database is actually an overlay instance;
|
|
* FALSE (0) otherwise.
|
|
*/
|
|
|
|
int
|
|
overlay_is_over( BackendDB *be )
|
|
{
|
|
return be->bd_info->bi_type == overtype;
|
|
}
|
|
|
|
/*
|
|
* returns TRUE (1) if the given database is actually an overlay
|
|
* instance and, somewhere in the list, contains the requested overlay;
|
|
* FALSE (0) otherwise.
|
|
*/
|
|
|
|
int
|
|
overlay_is_inst( BackendDB *be, const char *over_type )
|
|
{
|
|
slap_overinst *on;
|
|
|
|
assert( be != NULL );
|
|
|
|
if ( !overlay_is_over( be ) ) {
|
|
return 0;
|
|
}
|
|
|
|
on = ((slap_overinfo *)be->bd_info->bi_private)->oi_list;
|
|
for ( ; on; on = on->on_next ) {
|
|
if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
overlay_register_control( BackendDB *be, const char *oid )
|
|
{
|
|
int gotit = 0;
|
|
int cid;
|
|
|
|
if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
|
|
return -1;
|
|
}
|
|
|
|
if ( SLAP_ISGLOBALOVERLAY( be ) ) {
|
|
BackendDB *bd;
|
|
|
|
/* add to all backends... */
|
|
LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
|
|
if ( bd == be->bd_self ) {
|
|
gotit = 1;
|
|
}
|
|
|
|
/* overlays can be instantiated multiple times, use
|
|
* be_ctrls[ cid ] as an instance counter, so that the
|
|
* overlay's controls are only really disabled after the
|
|
* last instance called overlay_register_control() */
|
|
bd->be_ctrls[ cid ]++;
|
|
bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
|
|
}
|
|
|
|
}
|
|
|
|
if ( !gotit ) {
|
|
/* overlays can be instantiated multiple times, use
|
|
* be_ctrls[ cid ] as an instance counter, so that the
|
|
* overlay's controls are only really unregistered after the
|
|
* last instance called overlay_register_control() */
|
|
be->bd_self->be_ctrls[ cid ]++;
|
|
be->bd_self->be_ctrls[ SLAP_MAX_CIDS ] = 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef SLAP_CONFIG_DELETE
|
|
void
|
|
overlay_unregister_control( BackendDB *be, const char *oid )
|
|
{
|
|
int gotit = 0;
|
|
int cid;
|
|
|
|
if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
|
|
return;
|
|
}
|
|
|
|
if ( SLAP_ISGLOBALOVERLAY( be ) ) {
|
|
BackendDB *bd;
|
|
|
|
/* remove from all backends... */
|
|
LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
|
|
if ( bd == be->bd_self ) {
|
|
gotit = 1;
|
|
}
|
|
|
|
bd->be_ctrls[ cid ]--;
|
|
}
|
|
}
|
|
|
|
if ( !gotit ) {
|
|
be->bd_self->be_ctrls[ cid ]--;
|
|
}
|
|
}
|
|
#endif /* SLAP_CONFIG_DELETE */
|
|
|
|
void
|
|
overlay_destroy_one( BackendDB *be, slap_overinst *on )
|
|
{
|
|
slap_overinfo *oi = on->on_info;
|
|
slap_overinst **oidx;
|
|
|
|
for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
|
|
if ( *oidx == on ) {
|
|
*oidx = on->on_next;
|
|
if ( on->on_bi.bi_db_destroy ) {
|
|
BackendInfo *bi_orig = be->bd_info;
|
|
be->bd_info = (BackendInfo *)on;
|
|
on->on_bi.bi_db_destroy( be, NULL );
|
|
be->bd_info = bi_orig;
|
|
}
|
|
free( on );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef SLAP_CONFIG_DELETE
|
|
typedef struct ov_remove_ctx {
|
|
BackendDB be;
|
|
slap_overinst *on;
|
|
} ov_remove_ctx;
|
|
|
|
int
|
|
overlay_remove_cb( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_callback *sc = op->o_callback;
|
|
ov_remove_ctx *rm_ctx = (ov_remove_ctx*) op->o_callback->sc_private;
|
|
|
|
op->o_callback = sc->sc_next;
|
|
rm_ctx->be.bd_info = (BackendInfo*) rm_ctx->on;
|
|
|
|
if ( rm_ctx->on->on_bi.bi_db_close ) {
|
|
rm_ctx->on->on_bi.bi_db_close( &rm_ctx->be, NULL );
|
|
}
|
|
if ( rm_ctx->on->on_bi.bi_db_destroy ) {
|
|
rm_ctx->on->on_bi.bi_db_destroy( &rm_ctx->be, NULL );
|
|
}
|
|
|
|
/* clean up after removing last overlay */
|
|
if ( ! rm_ctx->on->on_info->oi_list ) {
|
|
ch_free(rm_ctx->on->on_info);
|
|
}
|
|
ch_free( rm_ctx->on );
|
|
op->o_tmpfree( sc, op->o_tmpmemctx );
|
|
return SLAP_CB_CONTINUE;
|
|
}
|
|
|
|
void
|
|
overlay_remove( BackendDB *be, slap_overinst *on, Operation *op )
|
|
{
|
|
slap_overinfo *oi = on->on_info;
|
|
slap_overinst **oidx;
|
|
ov_remove_ctx *rm_ctx;
|
|
slap_callback *rm_cb, *cb;
|
|
|
|
/* remove overlay from oi_list */
|
|
for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
|
|
if ( *oidx == on ) {
|
|
*oidx = on->on_next;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* The db_close and db_destroy handlers to cleanup a release
|
|
* the overlay's resources are called from the cleanup callback
|
|
*/
|
|
|
|
rm_cb = op->o_tmpalloc( sizeof( slap_callback ) + sizeof( ov_remove_ctx ), op->o_tmpmemctx );
|
|
rm_cb->sc_next = NULL;
|
|
rm_cb->sc_cleanup = overlay_remove_cb;
|
|
rm_cb->sc_response = NULL;
|
|
rm_cb->sc_private = (void*) ( rm_cb + 1 );
|
|
rm_cb->sc_writewait = NULL;
|
|
|
|
rm_ctx = rm_cb->sc_private;
|
|
rm_ctx->be = *be;
|
|
rm_ctx->on = on;
|
|
|
|
/* Append callback to the end of the list */
|
|
if ( !op->o_callback ) {
|
|
op->o_callback = rm_cb;
|
|
} else {
|
|
for ( cb = op->o_callback; cb->sc_next; cb = cb->sc_next );
|
|
cb->sc_next = rm_cb;
|
|
}
|
|
|
|
/* if this is the last overlay */
|
|
if ( ! on->on_info->oi_list ) {
|
|
/* reset db flags and bd_info to orig */
|
|
SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_GLOBAL_OVERLAY;
|
|
be->bd_info = on->on_info->oi_orig;
|
|
}
|
|
}
|
|
#endif /* SLAP_CONFIG_DELETE */
|
|
|
|
void
|
|
overlay_insert( BackendDB *be, slap_overinst *on2, slap_overinst ***prev,
|
|
int idx )
|
|
{
|
|
slap_overinfo *oi = (slap_overinfo *)be->bd_info;
|
|
|
|
if ( idx == -1 ) {
|
|
on2->on_next = oi->oi_list;
|
|
oi->oi_list = on2;
|
|
} else {
|
|
int i, novs;
|
|
slap_overinst *on, **prev;
|
|
|
|
/* Since the list is in reverse order and is singly linked,
|
|
* we have to count the overlays and then insert backwards.
|
|
* Adding on overlay at a specific point should be a pretty
|
|
* infrequent occurrence.
|
|
*/
|
|
novs = 0;
|
|
for ( on = oi->oi_list; on; on=on->on_next )
|
|
novs++;
|
|
|
|
if (idx > novs)
|
|
idx = 0;
|
|
else
|
|
idx = novs - idx;
|
|
|
|
/* advance to insertion point */
|
|
prev = &oi->oi_list;
|
|
for ( i=0; i<idx; i++ ) {
|
|
on = *prev;
|
|
prev = &on->on_next;
|
|
}
|
|
/* insert */
|
|
on2->on_next = *prev;
|
|
*prev = on2;
|
|
}
|
|
}
|
|
|
|
void
|
|
overlay_move( BackendDB *be, slap_overinst *on, int idx )
|
|
{
|
|
slap_overinfo *oi = (slap_overinfo *)be->bd_info;
|
|
slap_overinst **onp;
|
|
|
|
for (onp = &oi->oi_list; *onp; onp= &(*onp)->on_next) {
|
|
if ( *onp == on ) {
|
|
*onp = on->on_next;
|
|
break;
|
|
}
|
|
}
|
|
overlay_insert( be, on, &onp, idx );
|
|
}
|
|
|
|
/* add an overlay to a particular backend. */
|
|
int
|
|
overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res, ConfigReply *cr )
|
|
{
|
|
slap_overinst *on = NULL, *on2 = NULL, **prev;
|
|
slap_overinfo *oi = NULL;
|
|
BackendInfo *bi = NULL;
|
|
|
|
if ( res )
|
|
*res = NULL;
|
|
|
|
on = overlay_find( ov );
|
|
if ( !on ) {
|
|
Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov );
|
|
return 1;
|
|
}
|
|
|
|
/* If this is the first overlay on this backend, set up the
|
|
* overlay info structure
|
|
*/
|
|
if ( !overlay_is_over( be ) ) {
|
|
int isglobal = 0;
|
|
|
|
/* NOTE: the first time a global overlay is configured,
|
|
* frontendDB gets this flag; it is used later by overlays
|
|
* to determine if they're stacked on top of the frontendDB */
|
|
if ( be->bd_info == frontendDB->bd_info || SLAP_ISGLOBALOVERLAY( be ) ) {
|
|
isglobal = 1;
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_DBONLY ) {
|
|
snprintf( cr->msg, sizeof( cr->msg ), "overlay_config(): "
|
|
"overlay \"%s\" cannot be global.", ov );
|
|
Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg );
|
|
return 1;
|
|
}
|
|
|
|
} else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) {
|
|
snprintf( cr->msg, sizeof( cr->msg ), "overlay_config(): "
|
|
"overlay \"%s\" can only be global.", ov );
|
|
Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg );
|
|
return 1;
|
|
}
|
|
|
|
oi = ch_malloc( sizeof( slap_overinfo ) );
|
|
oi->oi_orig = be->bd_info;
|
|
oi->oi_bi = *be->bd_info;
|
|
oi->oi_origdb = be;
|
|
|
|
if ( isglobal ) {
|
|
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
|
|
}
|
|
|
|
/* Save a pointer to ourself in bi_private.
|
|
*/
|
|
oi->oi_bi.bi_private = oi;
|
|
oi->oi_list = NULL;
|
|
bi = (BackendInfo *)oi;
|
|
|
|
bi->bi_type = (char *)overtype;
|
|
|
|
bi->bi_db_config = over_db_config;
|
|
bi->bi_db_open = over_db_open;
|
|
bi->bi_db_close = over_db_close;
|
|
bi->bi_db_destroy = over_db_destroy;
|
|
|
|
bi->bi_op_bind = over_op_bind;
|
|
bi->bi_op_unbind = over_op_unbind;
|
|
bi->bi_op_search = over_op_search;
|
|
bi->bi_op_compare = over_op_compare;
|
|
bi->bi_op_modify = over_op_modify;
|
|
bi->bi_op_modrdn = over_op_modrdn;
|
|
bi->bi_op_add = over_op_add;
|
|
bi->bi_op_delete = over_op_delete;
|
|
bi->bi_op_abandon = over_op_abandon;
|
|
bi->bi_op_cancel = over_op_cancel;
|
|
|
|
bi->bi_extended = over_op_extended;
|
|
|
|
/*
|
|
* this is fine because it has the same
|
|
* args of the operations; we need to rework
|
|
* all the hooks to share the same args
|
|
* of the operations...
|
|
*/
|
|
bi->bi_operational = over_aux_operational;
|
|
bi->bi_chk_referrals = over_aux_chk_referrals;
|
|
bi->bi_chk_controls = over_aux_chk_controls;
|
|
|
|
/* these have specific arglists */
|
|
bi->bi_entry_get_rw = over_entry_get_rw;
|
|
bi->bi_entry_release_rw = over_entry_release_rw;
|
|
bi->bi_access_allowed = over_access_allowed;
|
|
bi->bi_acl_group = over_acl_group;
|
|
bi->bi_acl_attribute = over_acl_attribute;
|
|
|
|
bi->bi_connection_init = over_connection_init;
|
|
bi->bi_connection_destroy = over_connection_destroy;
|
|
|
|
be->bd_info = bi;
|
|
|
|
} else {
|
|
if ( overlay_is_inst( be, ov ) ) {
|
|
if ( on->on_bi.bi_flags & SLAPO_BFLAG_SINGLE ) {
|
|
snprintf( cr->msg, sizeof( cr->msg ), "overlay_config(): "
|
|
"overlay \"%s\" already in list", ov );
|
|
Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg );
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
oi = be->bd_info->bi_private;
|
|
}
|
|
|
|
/* Insert new overlay into list. By default overlays are
|
|
* added to head of list and executed in LIFO order.
|
|
*/
|
|
on2 = ch_calloc( 1, sizeof(slap_overinst) );
|
|
*on2 = *on;
|
|
on2->on_info = oi;
|
|
|
|
prev = &oi->oi_list;
|
|
/* Do we need to find the insertion point? */
|
|
if ( idx >= 0 ) {
|
|
int i;
|
|
|
|
/* count current overlays */
|
|
for ( i=0, on=oi->oi_list; on; on=on->on_next, i++ );
|
|
|
|
/* are we just appending a new one? */
|
|
if ( idx >= i )
|
|
idx = -1;
|
|
}
|
|
overlay_insert( be, on2, &prev, idx );
|
|
|
|
/* Any initialization needed? */
|
|
if ( on2->on_bi.bi_db_init ) {
|
|
int rc;
|
|
be->bd_info = (BackendInfo *)on2;
|
|
rc = on2->on_bi.bi_db_init( be, cr);
|
|
be->bd_info = (BackendInfo *)oi;
|
|
if ( rc ) {
|
|
*prev = on2->on_next;
|
|
ch_free( on2 );
|
|
on2 = NULL;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
if ( res )
|
|
*res = &on2->on_bi;
|
|
|
|
return 0;
|
|
}
|