2003-06-11 10:27:51 +08:00
|
|
|
/* backover.c - backend overlay routines */
|
|
|
|
/* $OpenLDAP$ */
|
2003-11-27 09:17:14 +08:00
|
|
|
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
|
|
|
*
|
2008-01-08 08:19:56 +08:00
|
|
|
* Copyright 2003-2008 The OpenLDAP Foundation.
|
2003-11-27 09:17:14 +08:00
|
|
|
* All rights reserved.
|
2003-06-11 10:27:51 +08:00
|
|
|
*
|
2003-11-27 09:17:14 +08:00
|
|
|
* 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>.
|
2003-06-11 10:27:51 +08:00
|
|
|
*/
|
|
|
|
|
2003-11-27 09:17:14 +08:00
|
|
|
/* Functions to overlay other modules over a backend. */
|
|
|
|
|
2003-06-11 10:27:51 +08:00
|
|
|
#include "portable.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <ac/string.h>
|
|
|
|
#include <ac/socket.h>
|
|
|
|
|
|
|
|
#define SLAPD_TOOLS
|
|
|
|
#include "slap.h"
|
2005-05-09 13:02:23 +08:00
|
|
|
#include "config.h"
|
2003-06-11 10:27:51 +08:00
|
|
|
|
2004-04-06 21:30:52 +08:00
|
|
|
static slap_overinst *overlays;
|
2003-06-11 10:27:51 +08:00
|
|
|
|
|
|
|
static int
|
|
|
|
over_db_config(
|
|
|
|
BackendDB *be,
|
|
|
|
const char *fname,
|
|
|
|
int lineno,
|
|
|
|
int argc,
|
|
|
|
char **argv
|
|
|
|
)
|
|
|
|
{
|
2004-07-02 19:59:05 +08:00
|
|
|
slap_overinfo *oi = be->bd_info->bi_private;
|
2003-06-11 10:27:51 +08:00
|
|
|
slap_overinst *on = oi->oi_list;
|
2004-07-02 19:59:05 +08:00
|
|
|
BackendInfo *bi_orig = be->bd_info;
|
2005-05-23 15:20:49 +08:00
|
|
|
struct ConfigOCs *be_cf_ocs = be->be_cf_ocs;
|
2005-05-09 18:33:43 +08:00
|
|
|
ConfigArgs ca = {0};
|
2003-06-11 10:27:51 +08:00
|
|
|
int rc = 0;
|
|
|
|
|
2004-03-20 20:56:31 +08:00
|
|
|
if ( oi->oi_orig->bi_db_config ) {
|
|
|
|
be->bd_info = oi->oi_orig;
|
2005-05-23 15:20:49 +08:00
|
|
|
be->be_cf_ocs = oi->oi_orig->bi_cf_ocs;
|
2004-03-20 20:56:31 +08:00
|
|
|
rc = oi->oi_orig->bi_db_config( be, fname, lineno,
|
2003-06-11 10:27:51 +08:00
|
|
|
argc, argv );
|
2004-11-15 18:28:33 +08:00
|
|
|
|
|
|
|
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, 0 );
|
|
|
|
|
|
|
|
/* 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 );
|
|
|
|
}
|
|
|
|
|
2004-03-20 20:56:31 +08:00
|
|
|
be->bd_info = (BackendInfo *)oi;
|
2003-12-07 15:07:00 +08:00
|
|
|
if ( rc != SLAP_CONF_UNKNOWN ) return rc;
|
2003-06-11 10:27:51 +08:00
|
|
|
}
|
|
|
|
|
2005-05-09 13:02:23 +08:00
|
|
|
ca.argv = argv;
|
|
|
|
ca.argc = argc;
|
|
|
|
ca.fname = fname;
|
|
|
|
ca.lineno = lineno;
|
|
|
|
ca.be = be;
|
2005-11-23 09:13:39 +08:00
|
|
|
snprintf( ca.log, sizeof( ca.log ), "%s: line %d",
|
|
|
|
ca.fname, ca.lineno );
|
|
|
|
|
2003-06-11 10:27:51 +08:00
|
|
|
for (; on; on=on->on_next) {
|
2005-05-09 13:02:23 +08:00
|
|
|
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 ) {
|
2007-02-25 01:24:48 +08:00
|
|
|
ca.table = on->on_bi.bi_cf_ocs->co_type;
|
2005-05-09 13:02:23 +08:00
|
|
|
rc = config_add_vals( ct, &ca );
|
2005-09-28 16:30:14 +08:00
|
|
|
if ( rc != SLAP_CONF_UNKNOWN )
|
|
|
|
break;
|
2005-05-09 13:02:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (on->on_bi.bi_db_config && rc == SLAP_CONF_UNKNOWN) {
|
2004-03-20 20:56:31 +08:00
|
|
|
be->bd_info = &on->on_bi;
|
|
|
|
rc = on->on_bi.bi_db_config( be, fname, lineno,
|
2003-06-11 10:27:51 +08:00
|
|
|
argc, argv );
|
2003-12-07 15:07:00 +08:00
|
|
|
if ( rc != SLAP_CONF_UNKNOWN ) break;
|
2003-06-11 10:27:51 +08:00
|
|
|
}
|
|
|
|
}
|
2004-07-02 19:59:05 +08:00
|
|
|
be->bd_info = bi_orig;
|
2005-05-23 15:20:49 +08:00
|
|
|
be->be_cf_ocs = be_cf_ocs;
|
|
|
|
|
2003-06-11 10:27:51 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
over_db_open(
|
2007-07-26 01:21:05 +08:00
|
|
|
BackendDB *be,
|
2007-08-03 20:02:07 +08:00
|
|
|
ConfigReply *cr
|
2003-06-11 10:27:51 +08:00
|
|
|
)
|
|
|
|
{
|
2008-04-23 18:31:22 +08:00
|
|
|
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) {
|
|
|
|
db.bd_info = &on->on_bi;
|
|
|
|
if ( db.bd_info->bi_db_open ) {
|
|
|
|
rc = db.bd_info->bi_db_open( &db, cr );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
2003-06-11 10:27:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
over_db_close(
|
2007-07-26 01:21:05 +08:00
|
|
|
BackendDB *be,
|
2007-08-03 20:02:07 +08:00
|
|
|
ConfigReply *cr
|
2003-06-11 10:27:51 +08:00
|
|
|
)
|
|
|
|
{
|
2004-11-27 22:43:07 +08:00
|
|
|
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) {
|
|
|
|
be->bd_info = &on->on_bi;
|
|
|
|
if ( be->bd_info->bi_db_close ) {
|
2007-12-28 01:36:39 +08:00
|
|
|
rc = be->bd_info->bi_db_close( be, cr );
|
2004-11-27 22:43:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-11-29 22:17:16 +08:00
|
|
|
if ( oi->oi_orig->bi_db_close ) {
|
2004-11-27 22:43:07 +08:00
|
|
|
be->bd_info = oi->oi_orig;
|
2007-12-28 01:36:39 +08:00
|
|
|
rc = be->bd_info->bi_db_close( be, cr );
|
2004-11-27 22:43:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
be->bd_info = bi_orig;
|
|
|
|
return rc;
|
2003-06-11 10:27:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
over_db_destroy(
|
2007-07-26 01:21:05 +08:00
|
|
|
BackendDB *be,
|
2007-08-03 20:02:07 +08:00
|
|
|
ConfigReply *cr
|
2003-06-11 10:27:51 +08:00
|
|
|
)
|
|
|
|
{
|
2004-07-02 19:59:05 +08:00
|
|
|
slap_overinfo *oi = be->bd_info->bi_private;
|
2003-06-11 10:27:51 +08:00
|
|
|
slap_overinst *on = oi->oi_list, *next;
|
2008-04-23 18:31:22 +08:00
|
|
|
BackendInfo *bi_orig = be->bd_info;
|
2008-09-08 08:05:15 +08:00
|
|
|
int rc = 0;
|
2003-06-11 10:27:51 +08:00
|
|
|
|
2008-04-23 18:31:22 +08:00
|
|
|
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) {
|
|
|
|
be->bd_info = &on->on_bi;
|
|
|
|
if ( be->bd_info->bi_db_destroy ) {
|
|
|
|
rc = be->bd_info->bi_db_destroy( be, cr );
|
|
|
|
}
|
|
|
|
}
|
2003-06-11 10:27:51 +08:00
|
|
|
|
2008-04-23 18:31:22 +08:00
|
|
|
on = oi->oi_list;
|
2006-08-18 18:12:21 +08:00
|
|
|
if ( on ) {
|
|
|
|
for (next = on->on_next; on; on=next) {
|
|
|
|
next = on->on_next;
|
|
|
|
free( on );
|
|
|
|
}
|
2003-06-11 10:27:51 +08:00
|
|
|
}
|
2008-04-23 18:31:22 +08:00
|
|
|
be->bd_info = bi_orig;
|
2003-06-11 10:27:51 +08:00
|
|
|
free( oi );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
over_back_response ( Operation *op, SlapReply *rs )
|
|
|
|
{
|
2004-03-18 01:59:47 +08:00
|
|
|
slap_overinfo *oi = op->o_callback->sc_private;
|
2003-06-11 10:27:51 +08:00
|
|
|
slap_overinst *on = oi->oi_list;
|
2003-06-11 12:36:35 +08:00
|
|
|
int rc = SLAP_CB_CONTINUE;
|
2003-06-11 10:27:51 +08:00
|
|
|
BackendDB *be = op->o_bd, db = *op->o_bd;
|
|
|
|
|
2004-11-27 19:45:54 +08:00
|
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
2003-06-11 10:27:51 +08:00
|
|
|
op->o_bd = &db;
|
|
|
|
for (; on; on=on->on_next ) {
|
|
|
|
if ( on->on_response ) {
|
|
|
|
db.bd_info = (BackendInfo *)on;
|
|
|
|
rc = on->on_response( op, rs );
|
2003-08-19 11:22:07 +08:00
|
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
2003-06-11 10:27:51 +08:00
|
|
|
}
|
|
|
|
}
|
2006-12-13 11:03:47 +08:00
|
|
|
/* Bypass the remaining on_response layers, but allow
|
|
|
|
* normal execution to continue.
|
|
|
|
*/
|
|
|
|
if ( rc == SLAP_CB_BYPASS )
|
|
|
|
rc = SLAP_CB_CONTINUE;
|
2003-06-11 10:27:51 +08:00
|
|
|
op->o_bd = be;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-12 08:24:04 +08:00
|
|
|
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;
|
2005-11-26 15:53:07 +08:00
|
|
|
BackendInfo *bi;
|
2005-04-12 08:24:04 +08:00
|
|
|
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 );
|
|
|
|
|
2005-11-26 15:53:07 +08:00
|
|
|
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;
|
|
|
|
}
|
2005-04-12 08:24:04 +08:00
|
|
|
on = oi->oi_list;
|
|
|
|
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
|
|
if ( on->on_bi.bi_access_allowed ) {
|
2005-04-13 01:01:31 +08:00
|
|
|
/* NOTE: do not copy the structure until required */
|
2005-04-12 09:07:30 +08:00
|
|
|
if ( !SLAP_ISOVERLAY( op->o_bd ) ) {
|
|
|
|
db = *op->o_bd;
|
|
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
|
|
op->o_bd = &db;
|
|
|
|
}
|
|
|
|
|
2005-04-12 08:24:04 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-18 17:16:26 +08:00
|
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
|
|
BI_access_allowed *bi_access_allowed;
|
|
|
|
|
2005-04-13 06:38:54 +08:00
|
|
|
/* 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;
|
2005-04-12 09:07:30 +08:00
|
|
|
}
|
|
|
|
|
2005-04-18 17:16:26 +08:00
|
|
|
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,
|
2005-04-12 08:24:04 +08:00
|
|
|
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;
|
2005-04-18 17:16:26 +08:00
|
|
|
op->o_bd->bd_info = bi;
|
|
|
|
|
2005-04-12 08:24:04 +08:00
|
|
|
return rc;
|
|
|
|
}
|
2005-07-22 11:05:41 +08:00
|
|
|
|
2007-02-06 12:18:14 +08:00
|
|
|
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_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;
|
|
|
|
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_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;
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
2005-07-22 11:05:41 +08:00
|
|
|
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 = op->o_bd->bd_info;
|
|
|
|
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 );
|
|
|
|
|
|
|
|
oi = op->o_bd->bd_info->bi_private;
|
|
|
|
on = oi->oi_list;
|
|
|
|
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
|
|
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;
|
|
|
|
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 = op->o_bd->bd_info;
|
|
|
|
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 );
|
|
|
|
|
|
|
|
oi = op->o_bd->bd_info->bi_private;
|
|
|
|
on = oi->oi_list;
|
|
|
|
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
|
|
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;
|
|
|
|
op->o_bd->bd_info = bi;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2005-04-12 08:24:04 +08:00
|
|
|
|
2008-07-12 19:53:49 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-06-20 06:41:49 +08:00
|
|
|
/*
|
|
|
|
* default return code in case of missing backend function
|
|
|
|
* and overlay stack returning SLAP_CB_CONTINUE
|
|
|
|
*/
|
2005-07-21 22:13:57 +08:00
|
|
|
static int op_rc[ op_last ] = {
|
2005-06-20 06:41:49 +08:00
|
|
|
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 */
|
|
|
|
};
|
|
|
|
|
2005-07-21 21:35:32 +08:00
|
|
|
int overlay_op_walk(
|
2003-06-11 10:27:51 +08:00
|
|
|
Operation *op,
|
|
|
|
SlapReply *rs,
|
2005-07-21 21:35:32 +08:00
|
|
|
slap_operation_t which,
|
|
|
|
slap_overinfo *oi,
|
|
|
|
slap_overinst *on
|
2003-06-11 10:27:51 +08:00
|
|
|
)
|
|
|
|
{
|
|
|
|
BI_op_bind **func;
|
2003-09-29 13:04:43 +08:00
|
|
|
int rc = SLAP_CB_CONTINUE;
|
2003-06-11 10:27:51 +08:00
|
|
|
|
|
|
|
for (; on; on=on->on_next ) {
|
|
|
|
func = &on->on_bi.bi_op_bind;
|
|
|
|
if ( func[which] ) {
|
2005-01-17 02:23:13 +08:00
|
|
|
op->o_bd->bd_info = (BackendInfo *)on;
|
2003-06-11 10:27:51 +08:00
|
|
|
rc = func[which]( op, rs );
|
2003-09-29 13:04:43 +08:00
|
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
2003-06-11 10:27:51 +08:00
|
|
|
}
|
|
|
|
}
|
2006-12-13 11:03:47 +08:00
|
|
|
if ( rc == SLAP_CB_BYPASS )
|
|
|
|
rc = SLAP_CB_CONTINUE;
|
2003-06-11 10:45:50 +08:00
|
|
|
|
2004-03-20 20:56:31 +08:00
|
|
|
func = &oi->oi_orig->bi_op_bind;
|
2003-09-29 13:04:43 +08:00
|
|
|
if ( func[which] && rc == SLAP_CB_CONTINUE ) {
|
2005-01-17 02:23:13 +08:00
|
|
|
op->o_bd->bd_info = oi->oi_orig;
|
2003-06-11 10:27:51 +08:00
|
|
|
rc = func[which]( op, rs );
|
|
|
|
}
|
2003-09-29 13:04:43 +08:00
|
|
|
/* should not fall thru this far without anything happening... */
|
|
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
2004-04-06 17:33:14 +08:00
|
|
|
rc = op_rc[ which ];
|
2003-09-29 13:04:43 +08:00
|
|
|
}
|
2005-03-14 09:23:38 +08:00
|
|
|
|
|
|
|
/* The underlying backend didn't handle the request, make sure
|
|
|
|
* overlay cleanup is processed.
|
|
|
|
*/
|
|
|
|
if ( rc == LDAP_UNWILLING_TO_PERFORM ) {
|
|
|
|
slap_callback *sc_next;
|
2005-07-21 21:35:32 +08:00
|
|
|
for ( ; op->o_callback && op->o_callback->sc_response !=
|
|
|
|
over_back_response; op->o_callback = sc_next ) {
|
2005-03-14 09:23:38 +08:00
|
|
|
sc_next = op->o_callback->sc_next;
|
|
|
|
if ( op->o_callback->sc_cleanup ) {
|
|
|
|
op->o_callback->sc_cleanup( op, rs );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-07-21 21:35:32 +08:00
|
|
|
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 cb = {NULL, over_back_response, NULL, NULL};
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
cb.sc_next = op->o_callback;
|
|
|
|
cb.sc_private = oi;
|
|
|
|
op->o_callback = &cb;
|
|
|
|
|
|
|
|
rc = overlay_op_walk( op, rs, which, oi, on );
|
|
|
|
|
2004-07-02 19:59:05 +08:00
|
|
|
op->o_bd = be;
|
2003-12-07 16:51:23 +08:00
|
|
|
op->o_callback = cb.sc_next;
|
2003-06-11 10:27:51 +08:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
2004-04-06 01:28:13 +08:00
|
|
|
static int
|
2004-07-19 05:44:29 +08:00
|
|
|
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 )
|
2004-04-06 01:28:13 +08:00
|
|
|
{
|
|
|
|
return over_op_func( op, rs, op_aux_chk_referrals );
|
|
|
|
}
|
|
|
|
|
2005-01-30 06:04:34 +08:00
|
|
|
static int
|
|
|
|
over_aux_chk_controls( Operation *op, SlapReply *rs )
|
|
|
|
{
|
|
|
|
return over_op_func( op, rs, op_aux_chk_controls );
|
|
|
|
}
|
|
|
|
|
2005-06-20 06:41:49 +08:00
|
|
|
enum conn_which {
|
|
|
|
conn_init = 0,
|
2005-07-21 22:27:31 +08:00
|
|
|
conn_destroy,
|
|
|
|
conn_last
|
2005-06-20 06:41:49 +08:00
|
|
|
};
|
|
|
|
|
2005-01-31 06:02:37 +08:00
|
|
|
static int
|
2005-06-20 06:41:49 +08:00
|
|
|
over_connection_func(
|
2005-01-31 06:02:37 +08:00
|
|
|
BackendDB *bd,
|
2005-06-20 06:41:49 +08:00
|
|
|
Connection *conn,
|
|
|
|
enum conn_which which
|
2005-01-31 06:02:37 +08:00
|
|
|
)
|
|
|
|
{
|
2005-06-20 06:41:49 +08:00
|
|
|
slap_overinfo *oi;
|
|
|
|
slap_overinst *on;
|
|
|
|
BackendDB db;
|
|
|
|
int rc = SLAP_CB_CONTINUE;
|
|
|
|
BI_connection_init **func;
|
2005-01-31 06:02:37 +08:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2005-06-20 06:41:49 +08:00
|
|
|
if ( !SLAP_ISOVERLAY( bd ) ) {
|
2005-01-31 06:02:37 +08:00
|
|
|
db = *bd;
|
|
|
|
db.be_flags |= SLAP_DBFLAG_OVERLAY;
|
|
|
|
bd = &db;
|
|
|
|
}
|
|
|
|
|
2005-06-20 06:41:49 +08:00
|
|
|
for ( ; on; on = on->on_next ) {
|
|
|
|
func = &on->on_bi.bi_connection_init;
|
|
|
|
if ( func[ which ] ) {
|
2005-01-31 06:02:37 +08:00
|
|
|
bd->bd_info = (BackendInfo *)on;
|
2005-06-20 06:41:49 +08:00
|
|
|
rc = func[ which ]( bd, conn );
|
2005-01-31 06:02:37 +08:00
|
|
|
if ( rc != SLAP_CB_CONTINUE ) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-20 06:41:49 +08:00
|
|
|
func = &oi->oi_orig->bi_connection_init;
|
|
|
|
if ( func[ which ] && rc == SLAP_CB_CONTINUE ) {
|
2005-01-31 06:02:37 +08:00
|
|
|
bd->bd_info = oi->oi_orig;
|
2005-06-20 06:41:49 +08:00
|
|
|
rc = func[ which ]( bd, conn );
|
2005-01-31 06:02:37 +08:00
|
|
|
}
|
|
|
|
/* should not fall thru this far without anything happening... */
|
|
|
|
if ( rc == SLAP_CB_CONTINUE ) {
|
|
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-06-20 06:41:49 +08:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
2003-06-11 10:27:51 +08:00
|
|
|
int
|
|
|
|
overlay_register(
|
|
|
|
slap_overinst *on
|
|
|
|
)
|
|
|
|
{
|
2005-11-29 18:02:05 +08:00
|
|
|
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, 0, 0 );
|
|
|
|
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 ], 0 );
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-06-11 10:27:51 +08:00
|
|
|
on->on_next = overlays;
|
|
|
|
overlays = on;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-11-14 01:20:24 +08:00
|
|
|
/*
|
|
|
|
* iterator on registered overlays; overlay_next( NULL ) returns the first
|
2005-11-29 18:02:05 +08:00
|
|
|
* overlay; subsequent calls with the previously returned value allow to
|
|
|
|
* iterate over the entire list; returns NULL when no more overlays are
|
2004-11-14 01:20:24 +08:00
|
|
|
* registered.
|
|
|
|
*/
|
|
|
|
|
2004-03-17 05:55:45 +08:00
|
|
|
slap_overinst *
|
|
|
|
overlay_next(
|
|
|
|
slap_overinst *on
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if ( on == NULL ) {
|
|
|
|
return overlays;
|
|
|
|
}
|
|
|
|
|
|
|
|
return on->on_next;
|
|
|
|
}
|
|
|
|
|
2004-11-14 01:20:24 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2005-07-18 14:22:33 +08:00
|
|
|
assert( over_type != NULL );
|
2004-11-14 01:20:24 +08:00
|
|
|
|
|
|
|
for ( ; on; on = on->on_next ) {
|
|
|
|
if ( strcmp( on->on_bi.bi_type, over_type ) == 0 ) {
|
2005-11-28 22:13:54 +08:00
|
|
|
goto foundit;
|
2004-11-14 01:20:24 +08:00
|
|
|
}
|
2005-11-28 22:13:54 +08:00
|
|
|
|
|
|
|
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, 0 );
|
|
|
|
goto foundit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-11-14 01:20:24 +08:00
|
|
|
}
|
|
|
|
|
2005-11-28 22:13:54 +08:00
|
|
|
foundit:;
|
2004-11-14 01:20:24 +08:00
|
|
|
return on;
|
|
|
|
}
|
|
|
|
|
2003-06-11 10:27:51 +08:00
|
|
|
static const char overtype[] = "over";
|
|
|
|
|
2004-11-14 01:20:24 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2005-07-18 14:22:33 +08:00
|
|
|
assert( be != NULL );
|
2004-11-14 01:20:24 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-01-26 03:39:56 +08:00
|
|
|
int
|
|
|
|
overlay_register_control( BackendDB *be, const char *oid )
|
|
|
|
{
|
|
|
|
int gotit = 0;
|
2005-01-30 01:58:48 +08:00
|
|
|
int cid;
|
|
|
|
|
|
|
|
if ( slap_find_control_id( oid, &cid ) == LDAP_CONTROL_NOT_FOUND ) {
|
|
|
|
return -1;
|
|
|
|
}
|
2005-01-26 03:39:56 +08:00
|
|
|
|
2005-12-16 09:58:36 +08:00
|
|
|
if ( SLAP_ISGLOBALOVERLAY( be ) ) {
|
2005-03-24 13:13:31 +08:00
|
|
|
BackendDB *bd;
|
2005-01-26 03:39:56 +08:00
|
|
|
|
|
|
|
/* add to all backends... */
|
2005-03-24 13:13:31 +08:00
|
|
|
LDAP_STAILQ_FOREACH( bd, &backendDB, be_next ) {
|
2008-08-09 18:11:41 +08:00
|
|
|
if ( bd == be->bd_self ) {
|
2005-01-26 03:39:56 +08:00
|
|
|
gotit = 1;
|
|
|
|
}
|
|
|
|
|
2005-01-30 01:58:48 +08:00
|
|
|
bd->be_ctrls[ cid ] = 1;
|
2005-01-31 06:02:37 +08:00
|
|
|
bd->be_ctrls[ SLAP_MAX_CIDS ] = 1;
|
2005-01-26 03:39:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-11-20 17:23:43 +08:00
|
|
|
if ( !gotit ) {
|
2008-08-09 18:11:41 +08:00
|
|
|
be->bd_self->be_ctrls[ cid ] = 1;
|
|
|
|
be->bd_self->be_ctrls[ SLAP_MAX_CIDS ] = 1;
|
2005-01-26 03:39:56 +08:00
|
|
|
}
|
|
|
|
|
2005-11-20 17:23:43 +08:00
|
|
|
return 0;
|
2005-01-26 03:39:56 +08:00
|
|
|
}
|
|
|
|
|
2005-06-14 06:49:01 +08:00
|
|
|
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;
|
2007-07-26 01:21:05 +08:00
|
|
|
on->on_bi.bi_db_destroy( be, NULL );
|
2005-06-14 06:49:01 +08:00
|
|
|
be->bd_info = bi_orig;
|
|
|
|
}
|
|
|
|
free( on );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-12 19:46:57 +08:00
|
|
|
#ifdef SLAP_CONFIG_DELETE
|
|
|
|
void
|
|
|
|
overlay_remove( BackendDB *be, slap_overinst *on )
|
|
|
|
{
|
|
|
|
slap_overinfo *oi = on->on_info;
|
|
|
|
slap_overinst **oidx, *on2;
|
|
|
|
|
|
|
|
/* remove overlay from oi_list an call db_close and db_destroy
|
|
|
|
* handlers */
|
|
|
|
for ( oidx = &oi->oi_list; *oidx; oidx = &(*oidx)->on_next ) {
|
|
|
|
if ( *oidx == on ) {
|
|
|
|
*oidx = on->on_next;
|
|
|
|
BackendInfo *bi_orig = be->bd_info;
|
|
|
|
be->bd_info = (BackendInfo *)on;
|
|
|
|
if ( on->on_bi.bi_db_close ) {
|
|
|
|
on->on_bi.bi_db_close( be, NULL );
|
|
|
|
}
|
|
|
|
if ( on->on_bi.bi_db_destroy ) {
|
|
|
|
on->on_bi.bi_db_destroy( be, NULL );
|
|
|
|
}
|
|
|
|
be->bd_info = bi_orig;
|
|
|
|
free( on );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clean up after removing last overlay */
|
|
|
|
if ( ! oi->oi_list )
|
|
|
|
{
|
|
|
|
/* reset db flags and bd_info to orig */
|
|
|
|
SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_GLOBAL_OVERLAY;
|
|
|
|
be->bd_info = oi->oi_orig;
|
|
|
|
ch_free(oi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* SLAP_CONFIG_DELETE */
|
|
|
|
|
2006-12-24 08:56:37 +08:00
|
|
|
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;
|
|
|
|
slap_overinst *on, *otmp1 = NULL, *otmp2;
|
|
|
|
|
|
|
|
/* Since the list is in reverse order and is singly linked,
|
|
|
|
* we reverse it to find the idx insertion point. Adding
|
|
|
|
* on overlay at a specific point should be a pretty
|
|
|
|
* infrequent occurrence.
|
|
|
|
*/
|
|
|
|
for ( on = oi->oi_list; on; on=otmp2 ) {
|
|
|
|
otmp2 = on->on_next;
|
|
|
|
on->on_next = otmp1;
|
|
|
|
otmp1 = on;
|
|
|
|
}
|
|
|
|
oi->oi_list = NULL;
|
|
|
|
/* advance to insertion point */
|
|
|
|
for ( i=0, on = otmp1; i<idx; i++ ) {
|
|
|
|
otmp1 = on->on_next;
|
|
|
|
on->on_next = oi->oi_list;
|
|
|
|
oi->oi_list = on;
|
|
|
|
}
|
|
|
|
/* insert */
|
|
|
|
on2->on_next = oi->oi_list;
|
|
|
|
oi->oi_list = on2;
|
|
|
|
if ( otmp1 ) {
|
|
|
|
*prev = &otmp1->on_next;
|
|
|
|
/* replace remainder of list */
|
|
|
|
for ( on=otmp1; on; on=otmp1 ) {
|
|
|
|
otmp1 = on->on_next;
|
|
|
|
on->on_next = oi->oi_list;
|
|
|
|
oi->oi_list = on;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
2003-06-11 10:27:51 +08:00
|
|
|
/* add an overlay to a particular backend. */
|
|
|
|
int
|
2008-05-30 22:49:24 +08:00
|
|
|
overlay_config( BackendDB *be, const char *ov, int idx, BackendInfo **res, ConfigReply *cr )
|
2003-06-11 10:27:51 +08:00
|
|
|
{
|
2006-12-24 08:56:37 +08:00
|
|
|
slap_overinst *on = NULL, *on2 = NULL, **prev;
|
2004-03-17 05:55:45 +08:00
|
|
|
slap_overinfo *oi = NULL;
|
|
|
|
BackendInfo *bi = NULL;
|
2003-06-11 10:27:51 +08:00
|
|
|
|
2006-12-24 08:56:37 +08:00
|
|
|
if ( res )
|
|
|
|
*res = NULL;
|
|
|
|
|
2004-11-14 01:20:24 +08:00
|
|
|
on = overlay_find( ov );
|
2004-11-15 18:28:33 +08:00
|
|
|
if ( !on ) {
|
|
|
|
Debug( LDAP_DEBUG_ANY, "overlay \"%s\" not found\n", ov, 0, 0 );
|
2003-06-11 10:27:51 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2003-06-11 12:36:35 +08:00
|
|
|
/* If this is the first overlay on this backend, set up the
|
|
|
|
* overlay info structure
|
|
|
|
*/
|
2004-11-14 01:20:24 +08:00
|
|
|
if ( !overlay_is_over( be ) ) {
|
2006-01-15 02:02:35 +08:00
|
|
|
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 ) {
|
|
|
|
Debug( LDAP_DEBUG_ANY, "overlay_config(): "
|
|
|
|
"overlay \"%s\" cannot be global.\n",
|
|
|
|
ov, 0, 0 );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if ( on->on_bi.bi_flags & SLAPO_BFLAG_GLOBONLY ) {
|
|
|
|
Debug( LDAP_DEBUG_ANY, "overlay_config(): "
|
|
|
|
"overlay \"%s\" can only be global.\n",
|
|
|
|
ov, 0, 0 );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-11-15 18:28:33 +08:00
|
|
|
oi = ch_malloc( sizeof( slap_overinfo ) );
|
2004-03-20 20:56:31 +08:00
|
|
|
oi->oi_orig = be->bd_info;
|
2003-06-11 10:27:51 +08:00
|
|
|
oi->oi_bi = *be->bd_info;
|
2005-10-02 09:23:09 +08:00
|
|
|
oi->oi_origdb = be;
|
2004-07-02 19:59:05 +08:00
|
|
|
|
2006-01-15 02:02:35 +08:00
|
|
|
if ( isglobal ) {
|
2005-01-26 16:04:19 +08:00
|
|
|
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLOBAL_OVERLAY;
|
|
|
|
}
|
|
|
|
|
2004-07-02 19:59:05 +08:00
|
|
|
/* Save a pointer to ourself in bi_private.
|
|
|
|
*/
|
|
|
|
oi->oi_bi.bi_private = oi;
|
2003-06-11 10:27:51 +08:00
|
|
|
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;
|
2004-04-06 01:28:13 +08:00
|
|
|
|
2003-06-11 10:27:51 +08:00
|
|
|
bi->bi_extended = over_op_extended;
|
|
|
|
|
2004-04-06 01:28:13 +08:00
|
|
|
/*
|
|
|
|
* 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...
|
|
|
|
*/
|
2004-07-19 05:44:29 +08:00
|
|
|
bi->bi_operational = over_aux_operational;
|
|
|
|
bi->bi_chk_referrals = over_aux_chk_referrals;
|
2005-01-30 06:04:34 +08:00
|
|
|
bi->bi_chk_controls = over_aux_chk_controls;
|
2005-04-12 08:24:04 +08:00
|
|
|
|
2005-07-22 11:44:04 +08:00
|
|
|
/* these have specific arglists */
|
2007-02-06 12:18:14 +08:00
|
|
|
bi->bi_entry_get_rw = over_entry_get_rw;
|
|
|
|
bi->bi_entry_release_rw = over_entry_release_rw;
|
2005-04-12 08:24:04 +08:00
|
|
|
bi->bi_access_allowed = over_access_allowed;
|
2005-07-22 11:05:41 +08:00
|
|
|
bi->bi_acl_group = over_acl_group;
|
|
|
|
bi->bi_acl_attribute = over_acl_attribute;
|
2005-01-31 06:02:37 +08:00
|
|
|
|
2005-06-20 06:41:49 +08:00
|
|
|
bi->bi_connection_init = over_connection_init;
|
2005-01-31 06:02:37 +08:00
|
|
|
bi->bi_connection_destroy = over_connection_destroy;
|
2004-04-06 01:28:13 +08:00
|
|
|
|
2003-06-11 10:27:51 +08:00
|
|
|
be->bd_info = bi;
|
2004-03-17 05:55:45 +08:00
|
|
|
|
|
|
|
} else {
|
2004-11-15 18:28:33 +08:00
|
|
|
if ( overlay_is_inst( be, ov ) ) {
|
2006-01-15 02:02:35 +08:00
|
|
|
if ( SLAPO_SINGLE( be ) ) {
|
2007-12-28 01:36:39 +08:00
|
|
|
Debug( LDAP_DEBUG_ANY, "overlay_config(): "
|
|
|
|
"overlay \"%s\" already in list\n",
|
|
|
|
ov, 0, 0 );
|
2006-01-15 02:02:35 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2004-11-15 18:28:33 +08:00
|
|
|
}
|
|
|
|
|
2004-07-02 19:59:05 +08:00
|
|
|
oi = be->bd_info->bi_private;
|
2003-06-11 10:27:51 +08:00
|
|
|
}
|
|
|
|
|
2006-12-24 08:56:37 +08:00
|
|
|
/* Insert new overlay into list. By default overlays are
|
|
|
|
* added to head of list and executed in LIFO order.
|
2003-12-23 22:18:47 +08:00
|
|
|
*/
|
|
|
|
on2 = ch_calloc( 1, sizeof(slap_overinst) );
|
|
|
|
*on2 = *on;
|
|
|
|
on2->on_info = oi;
|
2006-12-24 08:56:37 +08:00
|
|
|
|
|
|
|
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 );
|
2003-06-11 10:27:51 +08:00
|
|
|
|
2003-06-11 12:36:35 +08:00
|
|
|
/* Any initialization needed? */
|
2006-12-24 08:56:37 +08:00
|
|
|
if ( on2->on_bi.bi_db_init ) {
|
2005-03-17 05:44:05 +08:00
|
|
|
int rc;
|
2003-06-11 12:36:35 +08:00
|
|
|
be->bd_info = (BackendInfo *)on2;
|
2008-05-30 22:49:24 +08:00
|
|
|
rc = on2->on_bi.bi_db_init( be, cr);
|
2003-06-11 12:36:35 +08:00
|
|
|
be->bd_info = (BackendInfo *)oi;
|
2006-07-15 08:18:44 +08:00
|
|
|
if ( rc ) {
|
2006-12-24 08:56:37 +08:00
|
|
|
*prev = on2->on_next;
|
2006-07-15 08:18:44 +08:00
|
|
|
ch_free( on2 );
|
2006-12-24 08:56:37 +08:00
|
|
|
on2 = NULL;
|
2006-07-15 08:18:44 +08:00
|
|
|
return rc;
|
|
|
|
}
|
2003-06-11 12:36:35 +08:00
|
|
|
}
|
|
|
|
|
2006-12-24 08:56:37 +08:00
|
|
|
if ( res )
|
|
|
|
*res = &on2->on_bi;
|
|
|
|
|
2003-06-11 10:27:51 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|