From: Howard Chu Date: Thu, 1 Sep 2005 11:45:04 +0000 (+0000) Subject: Moving glue overlay back into slapd core, returning to 2.2 config syntax X-Git-Tag: OPENLDAP_REL_ENG_2_2_MP~515 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=4a1eabf257473d8eadf0c14d72d77a83e73ff09d;p=openldap Moving glue overlay back into slapd core, returning to 2.2 config syntax --- diff --git a/servers/slapd/Makefile.in b/servers/slapd/Makefile.in index f774b1322c..46ee8dac69 100644 --- a/servers/slapd/Makefile.in +++ b/servers/slapd/Makefile.in @@ -35,7 +35,7 @@ SRCS = main.c globals.c bconfig.c config.c daemon.c \ oidm.c starttls.c index.c sets.c referral.c root_dse.c \ sasl.c module.c mra.c mods.c sl_malloc.c zn_malloc.c limits.c \ operational.c matchedValues.c cancel.c syncrepl.c \ - backover.c ctxcsn.c ldapsync.c frontend.c \ + backglue.c backover.c ctxcsn.c ldapsync.c frontend.c \ slapadd.c slapcat.c slapcommon.c slapdn.c slapindex.c \ slappasswd.c slaptest.c slapauth.c slapacl.c component.c \ aci.c \ @@ -53,7 +53,7 @@ OBJS = main.o globals.o bconfig.o config.o daemon.o \ oidm.o starttls.o index.o sets.o referral.o root_dse.o \ sasl.o module.o mra.o mods.o sl_malloc.o zn_malloc.o limits.o \ operational.o matchedValues.o cancel.o syncrepl.o \ - backover.o ctxcsn.o ldapsync.o frontend.o \ + backglue.o backover.o ctxcsn.o ldapsync.o frontend.o \ slapadd.o slapcat.o slapcommon.o slapdn.o slapindex.o \ slappasswd.o slaptest.o slapauth.o slapacl.o component.o \ aci.o \ diff --git a/servers/slapd/backglue.c b/servers/slapd/backglue.c new file mode 100644 index 0000000000..936d617fde --- /dev/null +++ b/servers/slapd/backglue.c @@ -0,0 +1,942 @@ +/* backglue.c - backend glue */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 2001-2005 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 + * . + */ + +/* + * Functions to glue a bunch of other backends into a single tree. + * All of the glued backends must share a common suffix. E.g., you + * can glue o=foo and ou=bar,o=foo but you can't glue o=foo and o=bar. + * + * The purpose of these functions is to allow you to split a single database + * into pieces (for load balancing purposes, whatever) but still be able + * to treat it as a single database after it's been split. As such, each + * of the glued backends should have identical rootdn. + * -- Howard Chu + */ + +#include "portable.h" + +#include + +#include +#include + +#define SLAPD_TOOLS +#include "slap.h" + +typedef struct gluenode { + BackendDB *gn_be; + struct berval gn_pdn; +} gluenode; + +typedef struct glueinfo { + int gi_nodes; + struct berval gi_pdn; + gluenode gi_n[1]; +} glueinfo; + +static slap_overinst glue; + +static int glueMode; +static BackendDB *glueBack; + +static slap_response glue_op_response; + +/* Just like select_backend, but only for our backends */ +static BackendDB * +glue_back_select ( + BackendDB *be, + struct berval *dn +) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + glueinfo *gi = (glueinfo *)on->on_bi.bi_private; + int i; + + for (i = 0; igi_nodes; i++) { + assert( gi->gi_n[i].gn_be->be_nsuffix != NULL ); + + if (dnIsSuffix(dn, &gi->gi_n[i].gn_be->be_nsuffix[0])) { + return gi->gi_n[i].gn_be; + } + } + be->bd_info = on->on_info->oi_orig; + return be; +} + + +typedef struct glue_state { + int err; + int slimit; + int matchlen; + char *matched; + int nrefs; + BerVarray refs; +} glue_state; + +static int +glue_op_response ( Operation *op, SlapReply *rs ) +{ + glue_state *gs = op->o_callback->sc_private; + + switch(rs->sr_type) { + case REP_SEARCH: + if ( gs->slimit != SLAP_NO_LIMIT + && rs->sr_nentries >= gs->slimit ) + { + rs->sr_err = gs->err = LDAP_SIZELIMIT_EXCEEDED; + return -1; + } + /* fallthru */ + case REP_SEARCHREF: + return SLAP_CB_CONTINUE; + + default: + if (rs->sr_err == LDAP_SUCCESS || + rs->sr_err == LDAP_SIZELIMIT_EXCEEDED || + rs->sr_err == LDAP_TIMELIMIT_EXCEEDED || + rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED || + rs->sr_err == LDAP_NO_SUCH_OBJECT || + gs->err != LDAP_SUCCESS) + gs->err = rs->sr_err; + if (gs->err == LDAP_SUCCESS && gs->matched) { + ch_free (gs->matched); + gs->matched = NULL; + gs->matchlen = 0; + } + if (gs->err != LDAP_SUCCESS && rs->sr_matched) { + int len; + len = strlen (rs->sr_matched); + if (len > gs->matchlen) { + if (gs->matched) + ch_free (gs->matched); + gs->matched = ch_strdup (rs->sr_matched); + gs->matchlen = len; + } + } + if (rs->sr_ref) { + int i, j, k; + BerVarray new; + + for (i=0; rs->sr_ref[i].bv_val; i++); + + j = gs->nrefs; + if (!j) { + new = ch_malloc ((i+1)*sizeof(struct berval)); + } else { + new = ch_realloc(gs->refs, + (j+i+1)*sizeof(struct berval)); + } + for (k=0; ksr_ref[k] ); + } + new[j].bv_val = NULL; + gs->nrefs = j; + gs->refs = new; + } + } + return 0; +} + +static int +glue_op_func ( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + BackendDB *b0 = op->o_bd; + BackendInfo *bi0 = op->o_bd->bd_info; + BI_op_modify **func; + slap_operation_t which; + int rc; + + op->o_bd = glue_back_select (b0, &op->o_req_ndn); + b0->bd_info = on->on_info->oi_orig; + + switch(op->o_tag) { + case LDAP_REQ_ADD: which = op_add; break; + case LDAP_REQ_DELETE: which = op_delete; break; + case LDAP_REQ_MODIFY: which = op_modify; break; + case LDAP_REQ_MODRDN: which = op_modrdn; break; + } + + func = &op->o_bd->bd_info->bi_op_bind; + if ( func[which] ) + rc = func[which]( op, rs ); + else + rc = SLAP_CB_CONTINUE; + + op->o_bd = b0; + op->o_bd->bd_info = bi0; + return rc; +} + +static int +glue_chk_referrals ( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + BackendDB *b0 = op->o_bd; + BackendInfo *bi0 = op->o_bd->bd_info; + int rc; + + op->o_bd = glue_back_select (b0, &op->o_req_ndn); + b0->bd_info = on->on_info->oi_orig; + + if ( op->o_bd->bd_info->bi_chk_referrals ) + rc = ( *op->o_bd->bd_info->bi_chk_referrals )( op, rs ); + else + rc = SLAP_CB_CONTINUE; + + op->o_bd = b0; + op->o_bd->bd_info = bi0; + return rc; +} + +static int +glue_chk_controls ( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + BackendDB *b0 = op->o_bd; + BackendInfo *bi0 = op->o_bd->bd_info; + int rc = SLAP_CB_CONTINUE; + + op->o_bd = glue_back_select (b0, &op->o_req_ndn); + b0->bd_info = on->on_info->oi_orig; + + /* if the subordinate database has overlays, the bi_chk_controls() + * hook is actually over_aux_chk_controls(); in case it actually + * wraps a missing hok, we need to mimic the behavior + * of the frontend applied to that database */ + if ( op->o_bd->bd_info->bi_chk_controls ) { + rc = ( *op->o_bd->bd_info->bi_chk_controls )( op, rs ); + } + + + if ( rc == SLAP_CB_CONTINUE ) { + rc = backend_check_controls( op, rs ); + } + + op->o_bd = b0; + op->o_bd->bd_info = bi0; + return rc; +} + +static int +glue_op_search ( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + glueinfo *gi = (glueinfo *)on->on_bi.bi_private; + BackendDB *b0 = op->o_bd; + BackendDB *b1 = NULL, *btmp; + BackendInfo *bi0 = op->o_bd->bd_info; + int i; + long stoptime = 0; + glue_state gs = {0, 0, 0, NULL, 0, NULL}; + slap_callback cb = { NULL, glue_op_response, NULL, NULL }; + int scope0, slimit0, tlimit0; + struct berval dn, ndn, *pdn; + + cb.sc_private = &gs; + + cb.sc_next = op->o_callback; + + stoptime = slap_get_time () + op->ors_tlimit; + + op->o_bd = glue_back_select (b0, &op->o_req_ndn); + b0->bd_info = on->on_info->oi_orig; + + switch (op->ors_scope) { + case LDAP_SCOPE_BASE: + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + if (op->o_bd && op->o_bd->be_search) { + rs->sr_err = op->o_bd->be_search( op, rs ); + } + return rs->sr_err; + + case LDAP_SCOPE_ONELEVEL: + case LDAP_SCOPE_SUBTREE: +#ifdef LDAP_SCOPE_SUBORDINATE + case LDAP_SCOPE_SUBORDINATE: /* FIXME */ +#endif + +#if 0 + if ( op->o_sync ) { + if (op->o_bd && op->o_bd->be_search) { + rs->sr_err = op->o_bd->be_search( op, rs ); + } else { + send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM, + "No search target found"); + } + return rs->sr_err; + } +#endif + + op->o_callback = &cb; + rs->sr_err = gs.err = LDAP_UNWILLING_TO_PERFORM; + scope0 = op->ors_scope; + slimit0 = gs.slimit = op->ors_slimit; + tlimit0 = op->ors_tlimit; + dn = op->o_req_dn; + ndn = op->o_req_ndn; + b1 = op->o_bd; + + /* + * Execute in reverse order, most general first + */ + for (i = gi->gi_nodes; i >= 0; i--) { + if ( i == gi->gi_nodes ) { + btmp = b0; + pdn = &gi->gi_pdn; + } else { + btmp = gi->gi_n[i].gn_be; + pdn = &gi->gi_n[i].gn_pdn; + } + if (!btmp || !btmp->be_search) + continue; + if (!dnIsSuffix(&btmp->be_nsuffix[0], &b1->be_nsuffix[0])) + continue; + if (tlimit0 != SLAP_NO_LIMIT) { + op->ors_tlimit = stoptime - slap_get_time (); + if (op->ors_tlimit <= 0) { + rs->sr_err = gs.err = LDAP_TIMELIMIT_EXCEEDED; + break; + } + } + if (slimit0 != SLAP_NO_LIMIT) { + op->ors_slimit = slimit0 - rs->sr_nentries; + if (op->ors_slimit < 0) { + rs->sr_err = gs.err = LDAP_SIZELIMIT_EXCEEDED; + break; + } + } + rs->sr_err = 0; + /* + * check for abandon + */ + if (op->o_abandon) { + goto end_of_loop; + } + op->o_bd = btmp; + + assert( op->o_bd->be_suffix != NULL ); + assert( op->o_bd->be_nsuffix != NULL ); + + if (scope0 == LDAP_SCOPE_ONELEVEL && + dn_match(pdn, &ndn)) + { + op->ors_scope = LDAP_SCOPE_BASE; + op->o_req_dn = op->o_bd->be_suffix[0]; + op->o_req_ndn = op->o_bd->be_nsuffix[0]; + rs->sr_err = op->o_bd->be_search(op, rs); + + } else if (scope0 == LDAP_SCOPE_SUBTREE && + dn_match(&op->o_bd->be_nsuffix[0], &ndn)) + { + rs->sr_err = op->o_bd->be_search( op, rs ); + + } else if (scope0 == LDAP_SCOPE_SUBTREE && + dnIsSuffix(&op->o_bd->be_nsuffix[0], &ndn)) + { + op->o_req_dn = op->o_bd->be_suffix[0]; + op->o_req_ndn = op->o_bd->be_nsuffix[0]; + rs->sr_err = op->o_bd->be_search( op, rs ); + if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { + gs.err = LDAP_SUCCESS; + } + + } else if (dnIsSuffix(&ndn, &op->o_bd->be_nsuffix[0])) { + rs->sr_err = op->o_bd->be_search( op, rs ); + } + + switch ( gs.err ) { + + /* + * Add errors that should result in dropping + * the search + */ + case LDAP_SIZELIMIT_EXCEEDED: + case LDAP_TIMELIMIT_EXCEEDED: + case LDAP_ADMINLIMIT_EXCEEDED: + case LDAP_NO_SUCH_OBJECT: +#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR + case LDAP_CANNOT_CHAIN: +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + goto end_of_loop; + + default: + break; + } + } +end_of_loop:; + op->ors_scope = scope0; + op->ors_slimit = slimit0; + op->ors_tlimit = tlimit0; + op->o_req_dn = dn; + op->o_req_ndn = ndn; + + break; + } + if ( op->o_abandon ) { + rs->sr_err = SLAPD_ABANDON; + } else { + op->o_callback = cb.sc_next; + rs->sr_err = gs.err; + rs->sr_matched = gs.matched; + rs->sr_ref = gs.refs; + + send_ldap_result( op, rs ); + } + + op->o_bd = b0; + op->o_bd->bd_info = bi0; + if (gs.matched) + free (gs.matched); + if (gs.refs) + ber_bvarray_free(gs.refs); + return rs->sr_err; +} + +static BackendDB toolDB; + +static int +glue_tool_entry_open ( + BackendDB *b0, + int mode +) +{ + slap_overinfo *oi = (slap_overinfo *)b0->bd_info; + + /* We don't know which backend to talk to yet, so just + * remember the mode and move on... + */ + + glueMode = mode; + glueBack = NULL; + toolDB = *b0; + toolDB.bd_info = oi->oi_orig; + + return 0; +} + +static int +glue_tool_entry_close ( + BackendDB *b0 +) +{ + int rc = 0; + + if (glueBack) { + if (!glueBack->be_entry_close) + return 0; + rc = glueBack->be_entry_close (glueBack); + } + return rc; +} + +static slap_overinst * +glue_tool_inst( + BackendInfo *bi +) +{ + slap_overinfo *oi = (slap_overinfo *)bi; + slap_overinst *on; + + for ( on = oi->oi_list; on; on=on->on_next ) { + if ( !strcmp( on->on_bi.bi_type, glue.on_bi.bi_type )) + return on; + } + return NULL; +} + +/* This function will only be called in tool mode */ +static int +glue_open ( + BackendInfo *bi +) +{ + slap_overinst *on = glue_tool_inst( bi ); + glueinfo *gi = on->on_bi.bi_private; + static int glueOpened = 0; + int i, j, same, bsame = 0, rc = 0; + + if (glueOpened) return 0; + + glueOpened = 1; + + /* If we were invoked in tool mode, open all the underlying backends */ + if (slapMode & SLAP_TOOL_MODE) { + for (i = 0; igi_nodes; i++) { + same = 0; + /* Same type as our main backend? */ + if ( gi->gi_n[i].gn_be->bd_info == on->on_info->oi_orig ) + bsame = 1; + + /* Loop thru the bd_info's and make sure we only + * invoke their bi_open functions once each. + */ + for ( j = 0; jgi_n[i].gn_be->bd_info == + gi->gi_n[j].gn_be->bd_info ) { + same = 1; + break; + } + } + /* OK, it's unique and non-NULL, call it. */ + if ( !same && gi->gi_n[i].gn_be->bd_info->bi_open ) + rc = gi->gi_n[i].gn_be->bd_info->bi_open( + gi->gi_n[i].gn_be->bd_info ); + /* Let backend.c take care of the rest of startup */ + if ( !rc ) + rc = backend_startup_one( gi->gi_n[i].gn_be ); + if ( rc ) break; + } + if ( !rc && !bsame && on->on_info->oi_orig->bi_open ) + rc = on->on_info->oi_orig->bi_open( on->on_info->oi_orig ); + + } /* other case is impossible */ + return rc; +} + +/* This function will only be called in tool mode */ +static int +glue_close ( + BackendInfo *bi +) +{ + static int glueClosed = 0; + int rc = 0; + + if (glueClosed) return 0; + + glueClosed = 1; + + if (slapMode & SLAP_TOOL_MODE) { + rc = backend_shutdown( NULL ); + } + return rc; +} + +static int +glue_entry_release_rw ( + Operation *op, + Entry *e, + int rw +) +{ + BackendDB *b0, b2; + int rc = -1; + + b0 = op->o_bd; + b2 = *op->o_bd; + b2.bd_info = (BackendInfo *)glue_tool_inst( op->o_bd->bd_info ); + op->o_bd = glue_back_select (&b2, &e->e_nname); + + if ( op->o_bd->be_release ) { + rc = op->o_bd->be_release( op, e, rw ); + + } else { + /* FIXME: mimic be_entry_release_rw + * when no be_release() available */ + /* free entry */ + entry_free( e ); + rc = 0; + } + op->o_bd = b0; + return rc; +} + +static ID +glue_tool_entry_first ( + BackendDB *b0 +) +{ + slap_overinst *on = glue_tool_inst( b0->bd_info ); + glueinfo *gi = on->on_bi.bi_private; + int i; + + /* If we're starting from scratch, start at the most general */ + if (!glueBack) { + if ( toolDB.be_entry_open && toolDB.be_entry_first ) { + glueBack = &toolDB; + } else { + for (i = gi->gi_nodes-1; i >= 0; i--) { + if (gi->gi_n[i].gn_be->be_entry_open && + gi->gi_n[i].gn_be->be_entry_first) { + glueBack = gi->gi_n[i].gn_be; + break; + } + } + } + } + if (!glueBack || !glueBack->be_entry_open || !glueBack->be_entry_first || + glueBack->be_entry_open (glueBack, glueMode) != 0) + return NOID; + + return glueBack->be_entry_first (glueBack); +} + +static ID +glue_tool_entry_next ( + BackendDB *b0 +) +{ + slap_overinst *on = glue_tool_inst( b0->bd_info ); + glueinfo *gi = on->on_bi.bi_private; + int i; + ID rc; + + if (!glueBack || !glueBack->be_entry_next) + return NOID; + + rc = glueBack->be_entry_next (glueBack); + + /* If we ran out of entries in one database, move on to the next */ + while (rc == NOID) { + if ( glueBack && glueBack->be_entry_close ) + glueBack->be_entry_close (glueBack); + for (i=0; igi_nodes; i++) { + if (gi->gi_n[i].gn_be == glueBack) + break; + } + if (i == 0) { + glueBack = NULL; + break; + } else { + glueBack = gi->gi_n[i-1].gn_be; + rc = glue_tool_entry_first (b0); + } + } + return rc; +} + +static Entry * +glue_tool_entry_get ( + BackendDB *b0, + ID id +) +{ + if (!glueBack || !glueBack->be_entry_get) + return NULL; + + return glueBack->be_entry_get (glueBack, id); +} + +static ID +glue_tool_entry_put ( + BackendDB *b0, + Entry *e, + struct berval *text +) +{ + BackendDB *be, b2; + int rc = -1; + + b2 = *b0; + b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info ); + be = glue_back_select (&b2, &e->e_nname); + if ( be == &b2 ) be = &toolDB; + + if (!be->be_entry_put) + return NOID; + + if (!glueBack) { + if ( be->be_entry_open ) { + rc = be->be_entry_open (be, glueMode); + } + if (rc != 0) { + return NOID; + } + } else if (be != glueBack) { + /* If this entry belongs in a different branch than the + * previous one, close the current database and open the + * new one. + */ + if ( glueBack->be_entry_close ) { + glueBack->be_entry_close (glueBack); + } + if ( be->be_entry_open ) { + rc = be->be_entry_open (be, glueMode); + } + if (rc != 0) { + return NOID; + } + } + glueBack = be; + return be->be_entry_put (be, e, text); +} + +static int +glue_tool_entry_reindex ( + BackendDB *b0, + ID id +) +{ + if (!glueBack || !glueBack->be_entry_reindex) + return -1; + + return glueBack->be_entry_reindex (glueBack, id); +} + +static int +glue_tool_sync ( + BackendDB *b0 +) +{ + slap_overinst *on = glue_tool_inst( b0->bd_info ); + glueinfo *gi = on->on_bi.bi_private; + BackendInfo *bi = b0->bd_info; + int i; + + /* just sync everyone */ + for (i = 0; igi_nodes; i++) + if (gi->gi_n[i].gn_be->be_sync) + gi->gi_n[i].gn_be->be_sync (gi->gi_n[i].gn_be); + b0->bd_info = on->on_info->oi_orig; + if ( b0->be_sync ) + b0->be_sync( b0 ); + b0->bd_info = bi; + return 0; +} + +static int +glue_db_init( + BackendDB *be +) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + slap_overinfo *oi = on->on_info; + glueinfo *gi; + + gi = ch_calloc( 1, sizeof(glueinfo)); + on->on_bi.bi_private = gi; + dnParent( be->be_nsuffix, &gi->gi_pdn ); + + /* Currently the overlay framework doesn't handle these entry points + * but we need them.... + */ + oi->oi_bi.bi_open = glue_open; + oi->oi_bi.bi_close = glue_close; + + oi->oi_bi.bi_entry_release_rw = glue_entry_release_rw; + + oi->oi_bi.bi_tool_entry_open = glue_tool_entry_open; + oi->oi_bi.bi_tool_entry_close = glue_tool_entry_close; + oi->oi_bi.bi_tool_entry_first = glue_tool_entry_first; + oi->oi_bi.bi_tool_entry_next = glue_tool_entry_next; + oi->oi_bi.bi_tool_entry_get = glue_tool_entry_get; + oi->oi_bi.bi_tool_entry_put = glue_tool_entry_put; + oi->oi_bi.bi_tool_entry_reindex = glue_tool_entry_reindex; + oi->oi_bi.bi_tool_sync = glue_tool_sync; + + /*FIXME : need to add support */ + oi->oi_bi.bi_tool_dn2id_get = 0; + oi->oi_bi.bi_tool_id2entry_get = 0; + oi->oi_bi.bi_tool_entry_modify = 0; + + SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_INSTANCE; + + return 0; +} + +static int +glue_db_destroy ( + BackendDB *be +) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + glueinfo *gi = (glueinfo *)on->on_bi.bi_private; + + free (gi); + return SLAP_CB_CONTINUE; +} + +static int +glue_db_close( + BackendDB *be +) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + + on->on_info->oi_bi.bi_db_close = NULL; + return 0; +} + +int +glue_sub_del( BackendDB *b0 ) +{ + BackendDB *be; + int rc = 0; + + /* Find the top backend for this subordinate */ + be = b0; + while ( be=LDAP_STAILQ_NEXT( be, be_next )) { + slap_overinfo *oi; + slap_overinst *on; + glueinfo *gi; + int i; + + if ( SLAP_GLUE_SUBORDINATE( be )) + continue; + if ( !SLAP_GLUE_INSTANCE( be )) + continue; + if ( !dnIsSuffix( &b0->be_nsuffix[0], &be->be_nsuffix[0] )) + continue; + + /* OK, got the right backend, find the overlay */ + oi = (slap_overinfo *)be->bd_info; + for ( on=oi->oi_list; on; on=on->on_next ) { + if ( on->on_bi.bi_type == glue.on_bi.bi_type ) + break; + } + assert( on != NULL ); + gi = on->on_bi.bi_private; + for ( i=0; i < gi->gi_nodes; i++ ) { + if ( gi->gi_n[i].gn_be == b0 ) { + int j; + + for (j=i+1; j < gi->gi_nodes; j++) + gi->gi_n[j-1] = gi->gi_n[j]; + + gi->gi_nodes--; + } + } + } + if ( be == NULL ) + rc = LDAP_NO_SUCH_OBJECT; + + return rc; +} + +typedef struct glue_Addrec { + struct glue_Addrec *ga_next; + BackendDB *ga_be; +} glue_Addrec; + +/* List of added subordinates */ +static glue_Addrec *ga_list; + +/* Attach all the subordinate backends to their superior */ +static int +glue_sub_attach() +{ + glue_Addrec *ga, *gnext = NULL; + int rc = 0; + + /* For all the subordinate backends */ + for ( ga=ga_list; ga != NULL; ga = gnext ) { + BackendDB *be; + + gnext = ga->ga_next; + + /* Find the top backend for this subordinate */ + be = ga->ga_be; + while ( be=LDAP_STAILQ_NEXT( be, be_next )) { + slap_overinfo *oi; + slap_overinst *on; + glueinfo *gi; + + if ( SLAP_GLUE_SUBORDINATE( be )) + continue; + if ( !dnIsSuffix( &ga->ga_be->be_nsuffix[0], &be->be_nsuffix[0] )) + continue; + + /* If it's not already configured, set up the overlay */ + if ( !SLAP_GLUE_INSTANCE( be )) { + rc = overlay_config( be, glue.on_bi.bi_type ); + if ( rc ) + break; + } + /* Find the overlay instance */ + oi = (slap_overinfo *)be->bd_info; + for ( on=oi->oi_list; on; on=on->on_next ) { + if ( on->on_bi.bi_type == glue.on_bi.bi_type ) + break; + } + assert( on != NULL ); + gi = on->on_bi.bi_private; + gi = (glueinfo *)ch_realloc( gi, sizeof(glueinfo) + + gi->gi_nodes * sizeof(gluenode)); + gi->gi_n[gi->gi_nodes].gn_be = ga->ga_be; + dnParent( &ga->ga_be->be_nsuffix[0], + &gi->gi_n[gi->gi_nodes].gn_pdn ); + gi->gi_nodes++; + on->on_bi.bi_private = gi; + break; + } + if ( !be ) { + Debug( LDAP_DEBUG_ANY, "glue: no superior found for sub %s!\n", + ga->ga_be->be_suffix[0].bv_val, 0, 0 ); + rc = LDAP_NO_SUCH_OBJECT; + } + ch_free( ga ); + if ( rc ) break; + } + + ga_list = gnext; + + return rc; +} + +int +glue_sub_add( BackendDB *be, int advert, int online ) +{ + glue_Addrec *ga; + int rc = 0; + + SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_SUBORDINATE; + if ( advert ) + SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_ADVERTISE; + + ga = ch_malloc( sizeof( glue_Addrec )); + ga->ga_next = NULL; + ga->ga_be = be; + if ( ga_list ) { + glue_Addrec *g2 = ga_list; + + for ( ; g2 && g2->ga_next; g2=g2->ga_next ); + g2->ga_next = ga; + } else { + ga_list = ga; + } + + if ( online ) + rc = glue_sub_attach(); + + return rc; +} + +int +glue_sub_init() +{ + int rc; + + glue.on_bi.bi_type = "glue"; + + glue.on_bi.bi_db_init = glue_db_init; + glue.on_bi.bi_db_close = glue_db_close; + glue.on_bi.bi_db_destroy = glue_db_destroy; + + glue.on_bi.bi_op_search = glue_op_search; + glue.on_bi.bi_op_modify = glue_op_func; + glue.on_bi.bi_op_modrdn = glue_op_func; + glue.on_bi.bi_op_add = glue_op_func; + glue.on_bi.bi_op_delete = glue_op_func; + + glue.on_bi.bi_chk_referrals = glue_chk_referrals; + glue.on_bi.bi_chk_controls = glue_chk_controls; + + rc = overlay_register( &glue ); + if ( rc ) return rc; + + return glue_sub_attach(); +} diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 4b47318626..032cc1a0c4 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -105,6 +105,7 @@ static ConfigDriver config_schema_dn; static ConfigDriver config_sizelimit; static ConfigDriver config_timelimit; static ConfigDriver config_overlay; +static ConfigDriver config_subordinate; static ConfigDriver config_suffix; static ConfigDriver config_rootdn; static ConfigDriver config_rootpw; @@ -481,6 +482,9 @@ static ConfigTable config_back_cf_table[] = { #endif "( OLcfgGlAt:63 NAME 'olcSrvtab' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "subordinate", "[advertise]", 1, 2, 0, ARG_DB|ARG_MAGIC, + &config_subordinate, "( OLcfgDbAt:0.14 NAME 'olcSubordinate' " + "SYNTAX OMsDirectoryString )", NULL, NULL }, { "suffix", "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC, &config_suffix, "( OLcfgDbAt:0.10 NAME 'olcSuffix' " "SYNTAX OMsDN )", NULL, NULL }, @@ -634,7 +638,7 @@ static ConfigOCs cf_ocs[] = { "DESC 'OpenLDAP Database-specific options' " "SUP olcConfig STRUCTURAL " "MUST olcDatabase " - "MAY ( olcSuffix $ olcAccess $ olcLastMod $ olcLimits $ " + "MAY ( olcSuffix $ olcSubordinate $ olcAccess $ olcLastMod $ olcLimits $ " "olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ " "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ " "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncrepl $ " @@ -1560,6 +1564,42 @@ config_overlay(ConfigArgs *c) { return(0); } +static int +config_subordinate(ConfigArgs *c) +{ + int rc = 1; + int advertise; + + switch( c->op ) { + case SLAP_CONFIG_EMIT: + if ( SLAP_GLUE_SUBORDINATE( c->be )) { + struct berval bv; + + bv.bv_val = SLAP_GLUE_ADVERTISE( c->be ) ? "advertise" : "TRUE"; + bv.bv_len = SLAP_GLUE_ADVERTISE( c->be ) ? STRLENOF("advertise") : + STRLENOF("TRUE"); + + value_add_one( &c->rvalue_vals, &bv ); + rc = 0; + } + break; + case LDAP_MOD_DELETE: + if ( !c->line || strcasecmp( c->line, "advertise" )) { + glue_sub_del( c->be ); + } else { + SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_GLUE_ADVERTISE; + } + rc = 0; + break; + case LDAP_MOD_ADD: + case SLAP_CONFIG_ADD: + advertise = ( c->argc == 2 && !strcasecmp( c->argv[1], "advertise" )); + rc = glue_sub_add( c->be, advertise, CONFIG_ONLINE_ADD( c )); + break; + } + return rc; +} + static int config_suffix(ConfigArgs *c) { diff --git a/servers/slapd/main.c b/servers/slapd/main.c index 03b264513d..81fbed49f4 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -631,6 +631,14 @@ unhandled_option:; } } + if ( glue_sub_init( ) != 0 ) { + Debug( LDAP_DEBUG_ANY, + "subordinate config error\n", + 0, 0, 0 ); + + goto destroy; + } + if ( slap_schema_check( ) != 0 ) { Debug( LDAP_DEBUG_ANY, "schema prep error\n", diff --git a/servers/slapd/overlays/Makefile.in b/servers/slapd/overlays/Makefile.in index 59547e22fe..86c8f043ca 100644 --- a/servers/slapd/overlays/Makefile.in +++ b/servers/slapd/overlays/Makefile.in @@ -18,7 +18,6 @@ SRCS = overlays.c \ denyop.c \ dyngroup.c \ dynlist.c \ - glue.c \ lastmod.c \ pcache.c \ ppolicy.c \ @@ -68,9 +67,6 @@ dyngroup.la : dyngroup.lo dynlist.la : dynlist.lo $(LTLINK_MOD) -module -o $@ dynlist.lo version.lo $(LINK_LIBS) -glue.la : glue.lo - $(LTLINK_MOD) -module -o $@ glue.lo version.lo $(LINK_LIBS) - lastmod.la : lastmod.lo $(LTLINK_MOD) -module -o $@ lastmod.lo version.lo $(LINK_LIBS) diff --git a/servers/slapd/overlays/glue.c b/servers/slapd/overlays/glue.c deleted file mode 100644 index 52f3034ceb..0000000000 --- a/servers/slapd/overlays/glue.c +++ /dev/null @@ -1,876 +0,0 @@ -/* glue.c - backend glue overlay */ -/* $OpenLDAP$ */ -/* This work is part of OpenLDAP Software . - * - * Copyright 2001-2005 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 - * . - */ - -/* - * Functions to glue a bunch of other backends into a single tree. - * All of the glued backends must share a common suffix. E.g., you - * can glue o=foo and ou=bar,o=foo but you can't glue o=foo and o=bar. - * - * The purpose of these functions is to allow you to split a single database - * into pieces (for load balancing purposes, whatever) but still be able - * to treat it as a single database after it's been split. As such, each - * of the glued backends should have identical rootdn. - * -- Howard Chu - */ - -#include "portable.h" - -#ifdef SLAPD_OVER_GLUE - -#include - -#include -#include - -#define SLAPD_TOOLS -#include "slap.h" - -typedef struct gluenode { - BackendDB *gn_be; - struct berval gn_pdn; - int gn_async; -} gluenode; - -typedef struct glueinfo { - int gi_nodes; - struct berval gi_pdn; - gluenode gi_n[1]; -} glueinfo; - -static slap_overinst glue; - -static int glueMode; -static BackendDB *glueBack; - -static slap_response glue_op_response; - -/* Just like select_backend, but only for our backends */ -static BackendDB * -glue_back_select ( - BackendDB *be, - struct berval *dn -) -{ - slap_overinst *on = (slap_overinst *)be->bd_info; - glueinfo *gi = (glueinfo *)on->on_bi.bi_private; - int i; - - for (i = 0; igi_nodes; i++) { - assert( gi->gi_n[i].gn_be->be_nsuffix != NULL ); - - if (dnIsSuffix(dn, &gi->gi_n[i].gn_be->be_nsuffix[0])) { - return gi->gi_n[i].gn_be; - } - } - be->bd_info = on->on_info->oi_orig; - return be; -} - - -typedef struct glue_state { - int err; - int slimit; - int matchlen; - char *matched; - int nrefs; - BerVarray refs; -} glue_state; - -static int -glue_op_response ( Operation *op, SlapReply *rs ) -{ - glue_state *gs = op->o_callback->sc_private; - - switch(rs->sr_type) { - case REP_SEARCH: - if ( gs->slimit != SLAP_NO_LIMIT - && rs->sr_nentries >= gs->slimit ) - { - rs->sr_err = gs->err = LDAP_SIZELIMIT_EXCEEDED; - return -1; - } - /* fallthru */ - case REP_SEARCHREF: - return SLAP_CB_CONTINUE; - - default: - if (rs->sr_err == LDAP_SUCCESS || - rs->sr_err == LDAP_SIZELIMIT_EXCEEDED || - rs->sr_err == LDAP_TIMELIMIT_EXCEEDED || - rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED || - rs->sr_err == LDAP_NO_SUCH_OBJECT || - gs->err != LDAP_SUCCESS) - gs->err = rs->sr_err; - if (gs->err == LDAP_SUCCESS && gs->matched) { - ch_free (gs->matched); - gs->matched = NULL; - gs->matchlen = 0; - } - if (gs->err != LDAP_SUCCESS && rs->sr_matched) { - int len; - len = strlen (rs->sr_matched); - if (len > gs->matchlen) { - if (gs->matched) - ch_free (gs->matched); - gs->matched = ch_strdup (rs->sr_matched); - gs->matchlen = len; - } - } - if (rs->sr_ref) { - int i, j, k; - BerVarray new; - - for (i=0; rs->sr_ref[i].bv_val; i++); - - j = gs->nrefs; - if (!j) { - new = ch_malloc ((i+1)*sizeof(struct berval)); - } else { - new = ch_realloc(gs->refs, - (j+i+1)*sizeof(struct berval)); - } - for (k=0; ksr_ref[k] ); - } - new[j].bv_val = NULL; - gs->nrefs = j; - gs->refs = new; - } - } - return 0; -} - -static int -glue_op_func ( Operation *op, SlapReply *rs ) -{ - slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; - BackendDB *b0 = op->o_bd; - BackendInfo *bi0 = op->o_bd->bd_info; - BI_op_modify **func; - slap_operation_t which; - int rc; - - op->o_bd = glue_back_select (b0, &op->o_req_ndn); - b0->bd_info = on->on_info->oi_orig; - - switch(op->o_tag) { - case LDAP_REQ_ADD: which = op_add; break; - case LDAP_REQ_DELETE: which = op_delete; break; - case LDAP_REQ_MODIFY: which = op_modify; break; - case LDAP_REQ_MODRDN: which = op_modrdn; break; - } - - func = &op->o_bd->bd_info->bi_op_bind; - if ( func[which] ) - rc = func[which]( op, rs ); - else - rc = SLAP_CB_CONTINUE; - - op->o_bd = b0; - op->o_bd->bd_info = bi0; - return rc; -} - -static int -glue_chk_referrals ( Operation *op, SlapReply *rs ) -{ - slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; - BackendDB *b0 = op->o_bd; - BackendInfo *bi0 = op->o_bd->bd_info; - int rc; - - op->o_bd = glue_back_select (b0, &op->o_req_ndn); - b0->bd_info = on->on_info->oi_orig; - - if ( op->o_bd->bd_info->bi_chk_referrals ) - rc = ( *op->o_bd->bd_info->bi_chk_referrals )( op, rs ); - else - rc = SLAP_CB_CONTINUE; - - op->o_bd = b0; - op->o_bd->bd_info = bi0; - return rc; -} - -static int -glue_chk_controls ( Operation *op, SlapReply *rs ) -{ - slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; - BackendDB *b0 = op->o_bd; - BackendInfo *bi0 = op->o_bd->bd_info; - int rc = SLAP_CB_CONTINUE; - - op->o_bd = glue_back_select (b0, &op->o_req_ndn); - b0->bd_info = on->on_info->oi_orig; - - /* if the subordinate database has overlays, the bi_chk_controls() - * hook is actually over_aux_chk_controls(); in case it actually - * wraps a missing hok, we need to mimic the behavior - * of the frontend applied to that database */ - if ( op->o_bd->bd_info->bi_chk_controls ) { - rc = ( *op->o_bd->bd_info->bi_chk_controls )( op, rs ); - } - - - if ( rc == SLAP_CB_CONTINUE ) { - rc = backend_check_controls( op, rs ); - } - - op->o_bd = b0; - op->o_bd->bd_info = bi0; - return rc; -} - -static int -glue_op_search ( Operation *op, SlapReply *rs ) -{ - slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; - glueinfo *gi = (glueinfo *)on->on_bi.bi_private; - BackendDB *b0 = op->o_bd; - BackendDB *b1 = NULL, *btmp; - BackendInfo *bi0 = op->o_bd->bd_info; - int i; - long stoptime = 0; - glue_state gs = {0, 0, 0, NULL, 0, NULL}; - slap_callback cb = { NULL, glue_op_response, NULL, NULL }; - int scope0, slimit0, tlimit0; - struct berval dn, ndn, *pdn; - - cb.sc_private = &gs; - - cb.sc_next = op->o_callback; - - stoptime = slap_get_time () + op->ors_tlimit; - - op->o_bd = glue_back_select (b0, &op->o_req_ndn); - b0->bd_info = on->on_info->oi_orig; - - switch (op->ors_scope) { - case LDAP_SCOPE_BASE: - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - if (op->o_bd && op->o_bd->be_search) { - rs->sr_err = op->o_bd->be_search( op, rs ); - } - return rs->sr_err; - - case LDAP_SCOPE_ONELEVEL: - case LDAP_SCOPE_SUBTREE: -#ifdef LDAP_SCOPE_SUBORDINATE - case LDAP_SCOPE_SUBORDINATE: /* FIXME */ -#endif - -#if 0 - if ( op->o_sync ) { - if (op->o_bd && op->o_bd->be_search) { - rs->sr_err = op->o_bd->be_search( op, rs ); - } else { - send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM, - "No search target found"); - } - return rs->sr_err; - } -#endif - - op->o_callback = &cb; - rs->sr_err = gs.err = LDAP_UNWILLING_TO_PERFORM; - scope0 = op->ors_scope; - slimit0 = gs.slimit = op->ors_slimit; - tlimit0 = op->ors_tlimit; - dn = op->o_req_dn; - ndn = op->o_req_ndn; - b1 = op->o_bd; - - /* - * Execute in reverse order, most general first - */ - for (i = gi->gi_nodes; i >= 0; i--) { - if ( i == gi->gi_nodes ) { - btmp = b0; - pdn = &gi->gi_pdn; - } else { - btmp = gi->gi_n[i].gn_be; - pdn = &gi->gi_n[i].gn_pdn; - } - if (!btmp || !btmp->be_search) - continue; - if (!dnIsSuffix(&btmp->be_nsuffix[0], &b1->be_nsuffix[0])) - continue; - if (tlimit0 != SLAP_NO_LIMIT) { - op->ors_tlimit = stoptime - slap_get_time (); - if (op->ors_tlimit <= 0) { - rs->sr_err = gs.err = LDAP_TIMELIMIT_EXCEEDED; - break; - } - } - if (slimit0 != SLAP_NO_LIMIT) { - op->ors_slimit = slimit0 - rs->sr_nentries; - if (op->ors_slimit < 0) { - rs->sr_err = gs.err = LDAP_SIZELIMIT_EXCEEDED; - break; - } - } - rs->sr_err = 0; - /* - * check for abandon - */ - if (op->o_abandon) { - goto end_of_loop; - } - op->o_bd = btmp; - - assert( op->o_bd->be_suffix != NULL ); - assert( op->o_bd->be_nsuffix != NULL ); - - if (scope0 == LDAP_SCOPE_ONELEVEL && - dn_match(pdn, &ndn)) - { - op->ors_scope = LDAP_SCOPE_BASE; - op->o_req_dn = op->o_bd->be_suffix[0]; - op->o_req_ndn = op->o_bd->be_nsuffix[0]; - rs->sr_err = op->o_bd->be_search(op, rs); - - } else if (scope0 == LDAP_SCOPE_SUBTREE && - dn_match(&op->o_bd->be_nsuffix[0], &ndn)) - { - rs->sr_err = op->o_bd->be_search( op, rs ); - - } else if (scope0 == LDAP_SCOPE_SUBTREE && - dnIsSuffix(&op->o_bd->be_nsuffix[0], &ndn)) - { - op->o_req_dn = op->o_bd->be_suffix[0]; - op->o_req_ndn = op->o_bd->be_nsuffix[0]; - rs->sr_err = op->o_bd->be_search( op, rs ); - if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { - gs.err = LDAP_SUCCESS; - } - - } else if (dnIsSuffix(&ndn, &op->o_bd->be_nsuffix[0])) { - rs->sr_err = op->o_bd->be_search( op, rs ); - } - - switch ( gs.err ) { - - /* - * Add errors that should result in dropping - * the search - */ - case LDAP_SIZELIMIT_EXCEEDED: - case LDAP_TIMELIMIT_EXCEEDED: - case LDAP_ADMINLIMIT_EXCEEDED: - case LDAP_NO_SUCH_OBJECT: -#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR - case LDAP_CANNOT_CHAIN: -#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ - goto end_of_loop; - - default: - break; - } - } -end_of_loop:; - op->ors_scope = scope0; - op->ors_slimit = slimit0; - op->ors_tlimit = tlimit0; - op->o_req_dn = dn; - op->o_req_ndn = ndn; - - break; - } - if ( op->o_abandon ) { - rs->sr_err = SLAPD_ABANDON; - } else { - op->o_callback = cb.sc_next; - rs->sr_err = gs.err; - rs->sr_matched = gs.matched; - rs->sr_ref = gs.refs; - - send_ldap_result( op, rs ); - } - - op->o_bd = b0; - op->o_bd->bd_info = bi0; - if (gs.matched) - free (gs.matched); - if (gs.refs) - ber_bvarray_free(gs.refs); - return rs->sr_err; -} - -static BackendDB toolDB; - -static int -glue_tool_entry_open ( - BackendDB *b0, - int mode -) -{ - slap_overinfo *oi = (slap_overinfo *)b0->bd_info; - - /* We don't know which backend to talk to yet, so just - * remember the mode and move on... - */ - - glueMode = mode; - glueBack = NULL; - toolDB = *b0; - toolDB.bd_info = oi->oi_orig; - - return 0; -} - -static int -glue_tool_entry_close ( - BackendDB *b0 -) -{ - int rc = 0; - - if (glueBack) { - if (!glueBack->be_entry_close) - return 0; - rc = glueBack->be_entry_close (glueBack); - } - return rc; -} - -static slap_overinst * -glue_tool_inst( - BackendInfo *bi -) -{ - slap_overinfo *oi = (slap_overinfo *)bi; - slap_overinst *on; - - for ( on = oi->oi_list; on; on=on->on_next ) { - if ( !strcmp( on->on_bi.bi_type, glue.on_bi.bi_type )) - return on; - } - return NULL; -} - -/* This function will only be called in tool mode */ -static int -glue_open ( - BackendInfo *bi -) -{ - slap_overinst *on = glue_tool_inst( bi ); - glueinfo *gi = on->on_bi.bi_private; - static int glueOpened = 0; - int i, j, same, bsame = 0, rc = 0; - - if (glueOpened) return 0; - - glueOpened = 1; - - /* If we were invoked in tool mode, open all the underlying backends */ - if (slapMode & SLAP_TOOL_MODE) { - for (i = 0; igi_nodes; i++) { - same = 0; - /* Same type as our main backend? */ - if ( gi->gi_n[i].gn_be->bd_info == on->on_info->oi_orig ) - bsame = 1; - - /* Loop thru the bd_info's and make sure we only - * invoke their bi_open functions once each. - */ - for ( j = 0; jgi_n[i].gn_be->bd_info == - gi->gi_n[j].gn_be->bd_info ) { - same = 1; - break; - } - } - /* OK, it's unique and non-NULL, call it. */ - if ( !same && gi->gi_n[i].gn_be->bd_info->bi_open ) - rc = gi->gi_n[i].gn_be->bd_info->bi_open( - gi->gi_n[i].gn_be->bd_info ); - /* Let backend.c take care of the rest of startup */ - if ( !rc ) - rc = backend_startup_one( gi->gi_n[i].gn_be ); - if ( rc ) break; - } - if ( !rc && !bsame && on->on_info->oi_orig->bi_open ) - rc = on->on_info->oi_orig->bi_open( on->on_info->oi_orig ); - - } /* other case is impossible */ - return rc; -} - -/* This function will only be called in tool mode */ -static int -glue_close ( - BackendInfo *bi -) -{ - static int glueClosed = 0; - int rc = 0; - - if (glueClosed) return 0; - - glueClosed = 1; - - if (slapMode & SLAP_TOOL_MODE) { - rc = backend_shutdown( NULL ); - } - return rc; -} - -static int -glue_entry_release_rw ( - Operation *op, - Entry *e, - int rw -) -{ - BackendDB *b0, b2; - int rc = -1; - - b0 = op->o_bd; - b2 = *op->o_bd; - b2.bd_info = (BackendInfo *)glue_tool_inst( op->o_bd->bd_info ); - op->o_bd = glue_back_select (&b2, &e->e_nname); - - if ( op->o_bd->be_release ) { - rc = op->o_bd->be_release( op, e, rw ); - - } else { - /* FIXME: mimic be_entry_release_rw - * when no be_release() available */ - /* free entry */ - entry_free( e ); - rc = 0; - } - op->o_bd = b0; - return rc; -} - -static ID -glue_tool_entry_first ( - BackendDB *b0 -) -{ - slap_overinst *on = glue_tool_inst( b0->bd_info ); - glueinfo *gi = on->on_bi.bi_private; - int i; - - /* If we're starting from scratch, start at the most general */ - if (!glueBack) { - if ( toolDB.be_entry_open && toolDB.be_entry_first ) { - glueBack = &toolDB; - } else { - for (i = gi->gi_nodes-1; i >= 0; i--) { - if (gi->gi_n[i].gn_be->be_entry_open && - gi->gi_n[i].gn_be->be_entry_first) { - glueBack = gi->gi_n[i].gn_be; - break; - } - } - } - } - if (!glueBack || !glueBack->be_entry_open || !glueBack->be_entry_first || - glueBack->be_entry_open (glueBack, glueMode) != 0) - return NOID; - - return glueBack->be_entry_first (glueBack); -} - -static ID -glue_tool_entry_next ( - BackendDB *b0 -) -{ - slap_overinst *on = glue_tool_inst( b0->bd_info ); - glueinfo *gi = on->on_bi.bi_private; - int i; - ID rc; - - if (!glueBack || !glueBack->be_entry_next) - return NOID; - - rc = glueBack->be_entry_next (glueBack); - - /* If we ran out of entries in one database, move on to the next */ - while (rc == NOID) { - if ( glueBack && glueBack->be_entry_close ) - glueBack->be_entry_close (glueBack); - for (i=0; igi_nodes; i++) { - if (gi->gi_n[i].gn_be == glueBack) - break; - } - if (i == 0) { - glueBack = NULL; - break; - } else { - glueBack = gi->gi_n[i-1].gn_be; - rc = glue_tool_entry_first (b0); - } - } - return rc; -} - -static Entry * -glue_tool_entry_get ( - BackendDB *b0, - ID id -) -{ - if (!glueBack || !glueBack->be_entry_get) - return NULL; - - return glueBack->be_entry_get (glueBack, id); -} - -static ID -glue_tool_entry_put ( - BackendDB *b0, - Entry *e, - struct berval *text -) -{ - BackendDB *be, b2; - int rc = -1; - - b2 = *b0; - b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info ); - be = glue_back_select (&b2, &e->e_nname); - if ( be == &b2 ) be = &toolDB; - - if (!be->be_entry_put) - return NOID; - - if (!glueBack) { - if ( be->be_entry_open ) { - rc = be->be_entry_open (be, glueMode); - } - if (rc != 0) { - return NOID; - } - } else if (be != glueBack) { - /* If this entry belongs in a different branch than the - * previous one, close the current database and open the - * new one. - */ - if ( glueBack->be_entry_close ) { - glueBack->be_entry_close (glueBack); - } - if ( be->be_entry_open ) { - rc = be->be_entry_open (be, glueMode); - } - if (rc != 0) { - return NOID; - } - } - glueBack = be; - return be->be_entry_put (be, e, text); -} - -static int -glue_tool_entry_reindex ( - BackendDB *b0, - ID id -) -{ - if (!glueBack || !glueBack->be_entry_reindex) - return -1; - - return glueBack->be_entry_reindex (glueBack, id); -} - -static int -glue_tool_sync ( - BackendDB *b0 -) -{ - slap_overinst *on = glue_tool_inst( b0->bd_info ); - glueinfo *gi = on->on_bi.bi_private; - BackendInfo *bi = b0->bd_info; - int i; - - /* just sync everyone */ - for (i = 0; igi_nodes; i++) - if (gi->gi_n[i].gn_be->be_sync) - gi->gi_n[i].gn_be->be_sync (gi->gi_n[i].gn_be); - b0->bd_info = on->on_info->oi_orig; - if ( b0->be_sync ) - b0->be_sync( b0 ); - b0->bd_info = bi; - return 0; -} - -static int -glue_db_init( - BackendDB *be -) -{ - slap_overinst *on = (slap_overinst *)be->bd_info; - slap_overinfo *oi = on->on_info; - glueinfo *gi; - - gi = ch_calloc( 1, sizeof(glueinfo)); - on->on_bi.bi_private = gi; - dnParent( be->be_nsuffix, &gi->gi_pdn ); - - /* Currently the overlay framework doesn't handle these entry points - * but we need them.... - */ - oi->oi_bi.bi_open = glue_open; - oi->oi_bi.bi_close = glue_close; - - oi->oi_bi.bi_entry_release_rw = glue_entry_release_rw; - - oi->oi_bi.bi_tool_entry_open = glue_tool_entry_open; - oi->oi_bi.bi_tool_entry_close = glue_tool_entry_close; - oi->oi_bi.bi_tool_entry_first = glue_tool_entry_first; - oi->oi_bi.bi_tool_entry_next = glue_tool_entry_next; - oi->oi_bi.bi_tool_entry_get = glue_tool_entry_get; - oi->oi_bi.bi_tool_entry_put = glue_tool_entry_put; - oi->oi_bi.bi_tool_entry_reindex = glue_tool_entry_reindex; - oi->oi_bi.bi_tool_sync = glue_tool_sync; - - /*FIXME : need to add support */ - oi->oi_bi.bi_tool_dn2id_get = 0; - oi->oi_bi.bi_tool_id2entry_get = 0; - oi->oi_bi.bi_tool_entry_modify = 0; - - return 0; -} - -static int -glue_db_destroy ( - BackendDB *be -) -{ - slap_overinst *on = (slap_overinst *)be->bd_info; - glueinfo *gi = (glueinfo *)on->on_bi.bi_private; - - free (gi); - return SLAP_CB_CONTINUE; -} - -static int -glue_db_close( - BackendDB *be -) -{ - slap_overinst *on = (slap_overinst *)be->bd_info; - - on->on_info->oi_bi.bi_db_close = NULL; - return 0; -} - -static int -glue_db_config( - BackendDB *be, - const char *fname, - int lineno, - int argc, - char **argv -) -{ - slap_overinst *on = (slap_overinst *)be->bd_info; - glueinfo *gi = (glueinfo *)on->on_bi.bi_private; - - /* redundant; could be applied just once */ - SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_INSTANCE; - - if ( strcasecmp( argv[0], "glue-sub" ) == 0 ) { - int i, async = 0, advertise = 0; - BackendDB *b2; - struct berval bv, dn = BER_BVNULL; - - if ( argc < 2 ) { - fprintf( stderr, "%s: line %d: too few arguments in " - "\"glue-sub [async] [advertise]\"\n", fname, lineno ); - return -1; - } - for ( i = 2; i < argc; i++ ) { - if ( strcasecmp( argv[i], "async" ) == 0 ) { - async = 1; - - } else if ( strcasecmp( argv[i], "advertise" ) == 0 ) { - advertise = 1; - - } else { - fprintf( stderr, "%s: line %d: unrecognized option " - "\"%s\" ignored.\n", fname, lineno, argv[i] ); - } - } - ber_str2bv( argv[1], 0, 0, &bv ); - if ( dnNormalize( 0, NULL, NULL, &bv, &dn, NULL )) { - fprintf( stderr, "invalid suffixDN \"%s\"\n", argv[1] ); - return -1; - } - b2 = select_backend( &dn, 0, 1 ); - ber_memfree( dn.bv_val ); - if ( !b2 ) { - fprintf( stderr, "%s: line %d: unknown suffix \"%s\"\n", - fname, lineno, argv[1] ); - return -1; - } - if ( SLAP_GLUE_INSTANCE( b2 )) { - fprintf( stderr, "%s: line %d: backend for %s is already glued; " - "only one glue overlay is allowed per tree.\n", - fname, lineno, argv[1] ); - return -1; - } - SLAP_DBFLAGS(b2) |= SLAP_DBFLAG_GLUE_SUBORDINATE; - if ( advertise ) { - SLAP_DBFLAGS(b2) |= SLAP_DBFLAG_GLUE_ADVERTISE; - } - gi = (glueinfo *)ch_realloc( gi, sizeof(glueinfo) + - gi->gi_nodes * sizeof(gluenode)); - gi->gi_n[gi->gi_nodes].gn_be = b2; - dnParent( &b2->be_nsuffix[0], &gi->gi_n[gi->gi_nodes].gn_pdn ); - gi->gi_n[gi->gi_nodes].gn_async = async; - gi->gi_nodes++; - on->on_bi.bi_private = gi; - return 0; - } - return SLAP_CONF_UNKNOWN; -} - -int -glue_init() -{ - glue.on_bi.bi_type = "glue"; - - glue.on_bi.bi_db_init = glue_db_init; - glue.on_bi.bi_db_config = glue_db_config; - glue.on_bi.bi_db_close = glue_db_close; - glue.on_bi.bi_db_destroy = glue_db_destroy; - - glue.on_bi.bi_op_search = glue_op_search; - glue.on_bi.bi_op_modify = glue_op_func; - glue.on_bi.bi_op_modrdn = glue_op_func; - glue.on_bi.bi_op_add = glue_op_func; - glue.on_bi.bi_op_delete = glue_op_func; - - glue.on_bi.bi_chk_referrals = glue_chk_referrals; - glue.on_bi.bi_chk_controls = glue_chk_controls; - - return overlay_register( &glue ); -} - -#if SLAPD_OVER_GLUE == SLAPD_MOD_DYNAMIC -int -init_module( int argc, char *argv[] ) -{ - return glue_init(); -} -#endif /* SLAPD_OVER_GLUE == SLAPD_MOD_DYNAMIC */ - -#endif /* defined(SLAPD_OVER_GLUE */ diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 899d13dfcc..d79433ca20 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -389,6 +389,14 @@ LDAP_SLAPD_F (int) backend_operational LDAP_P(( LDAP_SLAPD_V(BackendInfo) slap_binfo[]; +/* + * backglue.c + */ + +LDAP_SLAPD_F (int) glue_sub_init( void ); +LDAP_SLAPD_F (int) glue_sub_add( BackendDB *be, int advert, int online ); +LDAP_SLAPD_F (int) glue_sub_del( BackendDB *be ); + /* * backover.c */ diff --git a/servers/slapd/slapcommon.c b/servers/slapd/slapcommon.c index a035874ee1..bbdb5bb3e3 100644 --- a/servers/slapd/slapcommon.c +++ b/servers/slapd/slapcommon.c @@ -424,6 +424,13 @@ slap_tool_init( break; } + rc = glue_sub_init(); + + if ( rc != 0 ) { + fprintf( stderr, "%s: subordinate configuration error\n", progname ); + exit( EXIT_FAILURE ); + } + rc = slap_schema_check(); if ( rc != 0 ) {