X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=servers%2Fslapd%2Fbackglue.c;h=f0ab5ca02dadc5bbd6231aee7ada458dc32fa8d7;hb=843e327a39e1ba023001fbbbe89733a431956549;hp=79f20b8f27ad67abdad5b15e51f0e241d9a6b0cb;hpb=f8fb4aca7668c722f41941be719203aa8c298e12;p=openldap diff --git a/servers/slapd/backglue.c b/servers/slapd/backglue.c index 79f20b8f27..f0ab5ca02d 100644 --- a/servers/slapd/backglue.c +++ b/servers/slapd/backglue.c @@ -1,8 +1,17 @@ -/* backglue.c - backend glue routines */ +/* backglue.c - backend glue */ /* $OpenLDAP$ */ -/* - * Copyright 2001-2002 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file +/* This work is part of OpenLDAP Software . + * + * Copyright 2001-2007 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 + * . */ /* @@ -10,18 +19,10 @@ * 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. * - * This uses the backend structures and routines extensively, but is - * not an actual backend of its own. To use it you must add a "subordinate" - * keyword to the configuration of other backends. Subordinates will - * automatically be connected to their parent backend. - * * 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 and rootpw. - * - * If you need more elaborate configuration, you probably should be using - * back-meta instead. + * of the glued backends should have identical rootdn. * -- Howard Chu */ @@ -29,619 +30,612 @@ #include +#include #include #define SLAPD_TOOLS #include "slap.h" typedef struct gluenode { - BackendDB *be; - char *pdn; + BackendDB *gn_be; + struct berval gn_pdn; } gluenode; typedef struct glueinfo { - BackendDB *be; - int nodes; - gluenode n[1]; + 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, - const char *dn + struct berval *dn ) { - glueinfo *gi = (glueinfo *) be->be_private; - struct berval bv; + slap_overinst *on = (slap_overinst *)be->bd_info; + glueinfo *gi = (glueinfo *)on->on_bi.bi_private; int i; - bv.bv_len = strlen(dn); - bv.bv_val = (char *) dn; + for (i = gi->gi_nodes-1; i >= 0; i--) { + assert( gi->gi_n[i].gn_be->be_nsuffix != NULL ); - for (i = 0; inodes; i++) { - if (dnIsSuffix(&bv, gi->n[i].be->be_nsuffix[0])) { - return gi->n[i].be; + if (dnIsSuffix(dn, &gi->gi_n[i].gn_be->be_nsuffix[0])) { + return gi->gi_n[i].gn_be; } } - return NULL; + be->bd_info = on->on_info->oi_orig; + return be; } -/* This function will only be called in tool mode */ -static int -glue_back_open ( - BackendInfo *bi -) -{ - int rc = 0; - static int glueOpened = 0; - - if (glueOpened) return 0; - glueOpened = 1; +typedef struct glue_state { + char *matched; + BerVarray refs; + LDAPControl **ctrls; + int err; + int matchlen; + int nrefs; + int nctrls; +} glue_state; - /* If we were invoked in tool mode, open all the underlying backends */ - if (slapMode & SLAP_TOOL_MODE) { - rc = backend_startup (NULL); - } /* other case is impossible */ - return rc; +static int +glue_op_cleanup( Operation *op, SlapReply *rs ) +{ + /* This is not a final result */ + if (rs->sr_type == REP_RESULT ) + rs->sr_type = REP_GLUE_RESULT; + return SLAP_CB_CONTINUE; } -/* This function will only be called in tool mode */ static int -glue_back_close ( - BackendInfo *bi -) +glue_op_response ( Operation *op, SlapReply *rs ) { - static int glueClosed = 0; - int rc; + glue_state *gs = op->o_callback->sc_private; + + switch(rs->sr_type) { + case REP_SEARCH: + case REP_SEARCHREF: + case REP_INTERMEDIATE: + 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; - if (glueClosed) return 0; + for (i=0; rs->sr_ref[i].bv_val; i++); - glueClosed = 1; + 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; + } + if (rs->sr_ctrls) { + int i, j, k; + LDAPControl **newctrls; - if (slapMode & SLAP_TOOL_MODE) { - rc = backend_shutdown (NULL); + for (i=0; rs->sr_ctrls[i]; i++); + + j = gs->nctrls; + if (!j) { + newctrls = ch_malloc((i+1)*sizeof(LDAPControl *)); + } else { + newctrls = ch_realloc(gs->ctrls, + (j+i+1)*sizeof(LDAPControl *)); + } + for (k=0; ksr_ctrls[k]; + if ( !BER_BVISNULL( &rs->sr_ctrls[k]->ldctl_value )) + ber_dupbv( &newctrls[j]->ldctl_value, + &rs->sr_ctrls[k]->ldctl_value ); + } + newctrls[j] = NULL; + gs->nctrls = j; + gs->ctrls = newctrls; + } } - return rc; + return 0; } static int -glue_back_db_open ( - BackendDB *be -) +glue_op_func ( Operation *op, SlapReply *rs ) { - glueinfo *gi = (glueinfo *)be->be_private; - static int glueOpened = 0; - int rc = 0; + 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 = op_bind; + int rc; - if (glueOpened) return 0; + op->o_bd = glue_back_select (b0, &op->o_req_ndn); - glueOpened = 1; + /* If we're on the master backend, let overlay framework handle it */ + if ( op->o_bd == b0 ) + return SLAP_CB_CONTINUE; + + b0->bd_info = on->on_info->oi_orig; - gi->be->be_acl = be->be_acl; + 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; + case LDAP_REQ_EXTENDED: which = op_extended; break; + default: assert( 0 ); break; + } - if (gi->be->bd_info->bi_db_open) - rc = gi->be->bd_info->bi_db_open(gi->be); + func = &op->o_bd->bd_info->bi_op_bind; + if ( func[which] ) + rc = func[which]( op, rs ); + else + rc = SLAP_CB_BYPASS; + op->o_bd = b0; + op->o_bd->bd_info = bi0; return rc; } static int -glue_back_db_close ( - BackendDB *be -) +glue_response ( Operation *op, SlapReply *rs ) { - glueinfo *gi = (glueinfo *)be->be_private; - static int glueClosed = 0; + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + BackendDB *be = op->o_bd; + be = glue_back_select (op->o_bd, &op->o_req_ndn); - if (glueClosed) return 0; - - glueClosed = 1; - - /* Close the master */ - if (gi->be->bd_info->bi_db_close) - gi->be->bd_info->bi_db_close( gi->be ); - - return 0; + /* If we're on the master backend, let overlay framework handle it. + * Otherwise, bail out. + */ + return ( op->o_bd == be ) ? SLAP_CB_CONTINUE : SLAP_CB_BYPASS; } static int -glue_back_db_destroy ( - BackendDB *be -) +glue_chk_referrals ( Operation *op, SlapReply *rs ) { - glueinfo *gi = (glueinfo *)be->be_private; + slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; + BackendDB *b0 = op->o_bd; + BackendInfo *bi0 = op->o_bd->bd_info; + int rc; - if (gi->be->bd_info->bi_db_destroy) - gi->be->bd_info->bi_db_destroy( gi->be ); - free (gi->be); - free (gi); - return 0; -} + op->o_bd = glue_back_select (b0, &op->o_req_ndn); + if ( op->o_bd == b0 ) + return SLAP_CB_CONTINUE; -typedef struct glue_state { - int err; - int nentries; - int matchlen; - char *matched; - int nrefs; - BVarray refs; -} glue_state; + b0->bd_info = on->on_info->oi_orig; -static void -glue_back_response ( - Connection *conn, - Operation *op, - ber_tag_t tag, - ber_int_t msgid, - ber_int_t err, - const char *matched, - const char *text, - BVarray ref, - const char *resoid, - struct berval *resdata, - struct berval *sasldata, - LDAPControl **ctrls -) -{ - glue_state *gs = op->o_glue; + 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; +} - if (err == LDAP_SUCCESS || gs->err != LDAP_SUCCESS) - gs->err = err; - if (gs->err == LDAP_SUCCESS && gs->matched) { - free (gs->matched); - gs->matchlen = 0; +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); + if ( op->o_bd == b0 ) + return SLAP_CB_CONTINUE; + + 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 (gs->err != LDAP_SUCCESS && matched) { - int len; - len = strlen (matched); - if (len > gs->matchlen) { - if (gs->matched) - free (gs->matched); - gs->matched = ch_strdup (matched); - gs->matchlen = len; - } + + + if ( rc == SLAP_CB_CONTINUE ) { + rc = backend_check_controls( op, rs ); } - if (ref) { - int i, j, k; - BVarray new; - for (i=0; ref[i].bv_val; i++); + op->o_bd = b0; + op->o_bd->bd_info = bi0; + return rc; +} - 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; ko_bd == b0 && on->on_next ) { + BackendInfo *bi = op->o_bd->bd_info; + int rc = SLAP_CB_CONTINUE; + for ( on=on->on_next; on; on=on->on_next ) { + op->o_bd->bd_info = (BackendInfo *)on; + if ( on->on_bi.bi_op_search ) { + rc = on->on_bi.bi_op_search( op, rs ); + if ( rc != SLAP_CB_CONTINUE ) + break; + } } - new[j].bv_val = NULL; - gs->nrefs = j; - gs->refs = new; + op->o_bd->bd_info = bi; + if ( rc != SLAP_CB_CONTINUE ) + return rc; } + return op->o_bd->be_search( op, rs ); } -static void -glue_back_sresult ( - Connection *c, - Operation *op, - ber_int_t err, - const char *matched, - const char *text, - BVarray refs, - LDAPControl **ctrls, - int nentries -) +static int +glue_op_search ( Operation *op, SlapReply *rs ) { - glue_state *gs = op->o_glue; + 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, starttime; + glue_state gs = {NULL, NULL, NULL, 0, 0, 0, 0}; + slap_callback cb = { NULL, glue_op_response, glue_op_cleanup, NULL }; + int scope0, tlimit0; + struct berval dn, ndn, *pdn; - gs->nentries += nentries; - glue_back_response (c, op, 0, 0, err, matched, text, refs, - NULL, NULL, NULL, ctrls); -} + cb.sc_private = &gs; -static int -glue_back_search ( - BackendDB *b0, - Connection *conn, - Operation *op, - struct berval *dn, - struct berval *ndn, - int scope, - int deref, - int slimit, - int tlimit, - Filter *filter, - struct berval *filterstr, - AttributeName *attrs, - int attrsonly -) -{ - glueinfo *gi = (glueinfo *)b0->be_private; - BackendDB *be; - int i, rc, t2limit = 0, s2limit = 0; - long stoptime = 0; - glue_state gs = {0}; - struct berval bv; + cb.sc_next = op->o_callback; + starttime = op->o_time; + stoptime = slap_get_time () + op->ors_tlimit; - if (tlimit) { - stoptime = slap_get_time () + tlimit; - } + op->o_bd = glue_back_select (b0, &op->o_req_ndn); + b0->bd_info = on->on_info->oi_orig; - switch (scope) { + switch (op->ors_scope) { case LDAP_SCOPE_BASE: - be = glue_back_select (b0, ndn->bv_val); + if ( op->o_bd == b0 ) + return SLAP_CB_CONTINUE; - if (be && be->be_search) { - rc = be->be_search (be, conn, op, dn, ndn, scope, - deref, slimit, tlimit, filter, filterstr, - attrs, attrsonly); - } else { - rc = LDAP_UNWILLING_TO_PERFORM; - send_ldap_result (conn, op, rc, NULL, - "No search target found", NULL, NULL); + 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 rc; + return rs->sr_err; case LDAP_SCOPE_ONELEVEL: case LDAP_SCOPE_SUBTREE: - op->o_glue = &gs; - op->o_sresult = glue_back_sresult; - op->o_response = glue_back_response; + case LDAP_SCOPE_SUBORDINATE: /* FIXME */ + op->o_callback = &cb; + rs->sr_err = gs.err = LDAP_UNWILLING_TO_PERFORM; + scope0 = op->ors_scope; + 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 + * Execute in reverse order, most specific first */ - for (i = gi->nodes-1; i >= 0; i--) { - if (!gi->n[i].be || !gi->n[i].be->be_search) - continue; - if (tlimit) { - t2limit = stoptime - slap_get_time (); - if (t2limit <= 0) - break; + 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 (slimit) { - s2limit = slimit - gs.nentries; - if (s2limit <= 0) + if (!btmp || !btmp->be_search) + continue; + if (!dnIsSuffix(&btmp->be_nsuffix[0], &b1->be_nsuffix[0])) + continue; + if (tlimit0 != SLAP_NO_LIMIT) { + op->o_time = slap_get_time(); + op->ors_tlimit = stoptime - op->o_time; + if (op->ors_tlimit <= 0) { + rs->sr_err = gs.err = LDAP_TIMELIMIT_EXCEEDED; break; + } } + rs->sr_err = 0; /* * check for abandon */ - ldap_pvt_thread_mutex_lock (&op->o_abandonmutex); - rc = op->o_abandon; - ldap_pvt_thread_mutex_unlock (&op->o_abandonmutex); - if (rc) { - rc = 0; - goto done; + 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); + if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { + gs.err = LDAP_SUCCESS; + } + op->ors_scope = LDAP_SCOPE_ONELEVEL; + op->o_req_dn = dn; + op->o_req_ndn = ndn; + + } else if (scope0 == LDAP_SCOPE_SUBTREE && + dn_match(&op->o_bd->be_nsuffix[0], &ndn)) + { + rs->sr_err = glue_sub_search( op, rs, b0, on ); + + } 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 = glue_sub_search( op, rs, b0, on ); + if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { + gs.err = LDAP_SUCCESS; + } + op->o_req_dn = dn; + op->o_req_ndn = ndn; + + } else if (dnIsSuffix(&ndn, &op->o_bd->be_nsuffix[0])) { + rs->sr_err = glue_sub_search( op, rs, b0, on ); } - be = gi->n[i].be; - if (scope == LDAP_SCOPE_ONELEVEL && - !strcmp (gi->n[i].pdn, ndn->bv_val)) { - rc = be->be_search (be, conn, op, - be->be_suffix[0], be->be_nsuffix[0], - LDAP_SCOPE_BASE, deref, - s2limit, t2limit, filter, filterstr, - attrs, attrsonly); - - } else if (scope == LDAP_SCOPE_SUBTREE && - dnIsSuffix(be->be_nsuffix[0], ndn)) { - rc = be->be_search (be, conn, op, - be->be_suffix[0], be->be_nsuffix[0], - scope, deref, - s2limit, t2limit, filter, filterstr, - attrs, attrsonly); - - } else if (dnIsSuffix(&bv, be->be_nsuffix[0])) { - rc = be->be_search (be, conn, op, dn, ndn, - scope, deref, - s2limit, t2limit, filter, filterstr, - attrs, attrsonly); + + 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_X_CANNOT_CHAIN: +#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ + goto end_of_loop; + + default: + break; } } +end_of_loop:; + op->ors_scope = scope0; + op->ors_tlimit = tlimit0; + op->o_time = starttime; + op->o_req_dn = dn; + op->o_req_ndn = ndn; + break; } - op->o_sresult = NULL; - op->o_response = NULL; - op->o_glue = NULL; + 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; + rs->sr_ctrls = gs.ctrls; - send_search_result (conn, op, gs.err, gs.matched, NULL, - gs.refs, NULL, gs.nentries); + send_ldap_result( op, rs ); + } -done: + op->o_bd = b0; + op->o_bd->bd_info = bi0; if (gs.matched) free (gs.matched); if (gs.refs) - bvarray_free(gs.refs); - return rc; -} - -static int -glue_back_bind ( - BackendDB *b0, - Connection *conn, - Operation *op, - struct berval *dn, - struct berval *ndn, - int method, - struct berval *cred, - struct berval *edn -) -{ - BackendDB *be; - int rc; - - be = glue_back_select (b0, ndn->bv_val); - - if (be && be->be_bind) { - conn->c_authz_backend = be; - rc = be->be_bind (be, conn, op, dn, ndn, method, cred, edn); - } else { - rc = LDAP_UNWILLING_TO_PERFORM; - send_ldap_result (conn, op, rc, NULL, "No bind target found", - NULL, NULL); + ber_bvarray_free(gs.refs); + if (gs.ctrls) { + for (i = gs.nctrls; --i >= 0; ) { + if (!BER_BVISNULL( &gs.ctrls[i]->ldctl_value )) + free(gs.ctrls[i]->ldctl_value.bv_val); + free(gs.ctrls[i]); + } + free(gs.ctrls); } - return rc; + return rs->sr_err; } -static int -glue_back_compare ( - BackendDB *b0, - Connection *conn, - Operation *op, - struct berval *dn, - struct berval *ndn, - AttributeAssertion *ava -) -{ - BackendDB *be; - int rc; - - be = glue_back_select (b0, ndn->bv_val); - - if (be && be->be_compare) { - rc = be->be_compare (be, conn, op, dn, ndn, ava); - } else { - rc = LDAP_UNWILLING_TO_PERFORM; - send_ldap_result (conn, op, rc, NULL, "No compare target found", - NULL, NULL); - } - return rc; -} +static BackendDB toolDB; static int -glue_back_modify ( +glue_tool_entry_open ( BackendDB *b0, - Connection *conn, - Operation *op, - struct berval *dn, - struct berval *ndn, - Modifications *mod + int mode ) { - BackendDB *be; - int rc; - - be = glue_back_select (b0, ndn->bv_val); - - if (be && be->be_modify) { - rc = be->be_modify (be, conn, op, dn, ndn, mod); - } else { - rc = LDAP_UNWILLING_TO_PERFORM; - send_ldap_result (conn, op, rc, NULL, - "No modify target found", NULL, NULL); - } - return rc; -} + slap_overinfo *oi = (slap_overinfo *)b0->bd_info; -static int -glue_back_modrdn ( - BackendDB *b0, - Connection *conn, - Operation *op, - struct berval *dn, - struct berval *ndn, - struct berval *newrdn, - struct berval *nnewrdn, - int del, - struct berval *newsup, - struct berval *nnewsup -) -{ - BackendDB *be; - int rc; + /* We don't know which backend to talk to yet, so just + * remember the mode and move on... + */ - be = glue_back_select (b0, ndn->bv_val); + glueMode = mode; + glueBack = NULL; + toolDB = *b0; + toolDB.bd_info = oi->oi_orig; - if (be && be->be_modrdn) { - rc = be->be_modrdn (be, conn, op, dn, ndn, - newrdn, nnewrdn, del, newsup, nnewsup ); - } else { - rc = LDAP_UNWILLING_TO_PERFORM; - send_ldap_result (conn, op, rc, NULL, - "No modrdn target found", NULL, NULL); - } - return rc; + return 0; } static int -glue_back_add ( - BackendDB *b0, - Connection *conn, - Operation *op, - Entry *e +glue_tool_entry_close ( + BackendDB *b0 ) { - BackendDB *be; - int rc; - - be = glue_back_select (b0, e->e_ndn); + int rc = 0; - if (be && be->be_add) { - rc = be->be_add (be, conn, op, e); - } else { - rc = LDAP_UNWILLING_TO_PERFORM; - send_ldap_result (conn, op, rc, NULL, "No add target found", - NULL, NULL); + if (glueBack) { + if (!glueBack->be_entry_close) + return 0; + rc = glueBack->be_entry_close (glueBack); } return rc; } -static int -glue_back_delete ( - BackendDB *b0, - Connection *conn, - Operation *op, - struct berval *dn, - struct berval *ndn +static slap_overinst * +glue_tool_inst( + BackendInfo *bi ) { - BackendDB *be; - int rc; - - be = glue_back_select (b0, ndn->bv_val); + slap_overinfo *oi = (slap_overinfo *)bi; + slap_overinst *on; - if (be && be->be_delete) { - rc = be->be_delete (be, conn, op, dn, ndn); - } else { - rc = LDAP_UNWILLING_TO_PERFORM; - send_ldap_result (conn, op, rc, NULL, "No delete target found", - NULL, NULL); + 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 rc; + return NULL; } +/* This function will only be called in tool mode */ static int -glue_back_release_rw ( - BackendDB *b0, - Connection *conn, - Operation *op, - Entry *e, - int rw +glue_open ( + BackendInfo *bi ) { - BackendDB *be; - int rc; - - be = glue_back_select (b0, e->e_ndn); + 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 (be && be->be_release) { - rc = be->be_release (be, conn, op, e, rw); - } else { - entry_free (e); - rc = 0; - } - return rc; -} + if (glueOpened) return 0; -static int -glue_back_group ( - BackendDB *b0, - Connection *conn, - Operation *op, - Entry *target, - struct berval *ndn, - struct berval *ondn, - ObjectClass *oc, - AttributeDescription * ad -) -{ - BackendDB *be; - int rc; + glueOpened = 1; - be = glue_back_select (b0, ndn->bv_val); + /* 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 bi_open as our main backend? */ + if ( gi->gi_n[i].gn_be->bd_info->bi_open == + on->on_info->oi_orig->bi_open ) + 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->bi_open == + gi->gi_n[j].gn_be->bd_info->bi_open ) { + 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 ); - if (be && be->be_group) { - rc = be->be_group (be, conn, op, target, ndn, ondn, oc, ad); - } else { - rc = LDAP_UNWILLING_TO_PERFORM; - } + } /* other case is impossible */ return rc; } +/* This function will only be called in tool mode */ static int -glue_back_attribute ( - BackendDB *b0, - Connection *conn, - Operation *op, - Entry *target, - struct berval *ndn, - AttributeDescription *ad, - BVarray *vals +glue_close ( + BackendInfo *bi ) { - BackendDB *be; - int rc; - - be = glue_back_select (b0, ndn->bv_val); - - if (be && be->be_attribute) { - rc = be->be_attribute (be, conn, op, target, ndn, ad, vals); - } else { - rc = LDAP_UNWILLING_TO_PERFORM; - } - return rc; -} + static int glueClosed = 0; + int rc = 0; -static int -glue_back_referrals ( - BackendDB *b0, - Connection *conn, - Operation *op, - struct berval *dn, - struct berval *ndn, - const char **text -) -{ - BackendDB *be; - int rc; + if (glueClosed) return 0; - be = glue_back_select (b0, ndn->bv_val); + glueClosed = 1; - if (be && be->be_chk_referrals) { - rc = be->be_chk_referrals (be, conn, op, dn, ndn, text); - } else { - rc = LDAP_SUCCESS;; + if (slapMode & SLAP_TOOL_MODE) { + rc = backend_shutdown( NULL ); } return rc; } static int -glue_tool_entry_open ( - BackendDB *b0, - int mode +glue_entry_release_rw ( + Operation *op, + Entry *e, + int rw ) { - /* We don't know which backend to talk to yet, so just - * remember the mode and move on... - */ - - glueMode = mode; - glueBack = NULL; + BackendDB *b0, b2; + int rc = -1; - return 0; -} + 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); -static int -glue_tool_entry_close ( - BackendDB *b0 -) -{ - int rc = 0; + if ( op->o_bd->be_release ) { + rc = op->o_bd->be_release( op, e, rw ); - if (glueBack) { - if (!glueBack->be_entry_close) - return 0; - rc = glueBack->be_entry_close (glueBack); + } 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; } @@ -650,21 +644,26 @@ glue_tool_entry_first ( BackendDB *b0 ) { - glueinfo *gi = (glueinfo *) b0->be_private; + 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) { - for (i = gi->nodes-1; i >= 0; i--) { - if (gi->n[i].be->be_entry_open && - gi->n[i].be->be_entry_first) { - glueBack = gi->n[i].be; - break; + 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, glueMode) != 0) + 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); @@ -675,7 +674,8 @@ glue_tool_entry_next ( BackendDB *b0 ) { - glueinfo *gi = (glueinfo *) b0->be_private; + slap_overinst *on = glue_tool_inst( b0->bd_info ); + glueinfo *gi = on->on_bi.bi_private; int i; ID rc; @@ -685,17 +685,18 @@ glue_tool_entry_next ( rc = glueBack->be_entry_next (glueBack); /* If we ran out of entries in one database, move on to the next */ - if (rc == NOID) { - glueBack->be_entry_close (glueBack); - for (i=0; inodes; i++) { - if (gi->n[i].be == glueBack) + 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; - rc = NOID; + break; } else { - glueBack = gi->n[i-1].be; + glueBack = gi->gi_n[i-1].gn_be; rc = glue_tool_entry_first (b0); } } @@ -721,26 +722,38 @@ glue_tool_entry_put ( struct berval *text ) { - BackendDB *be; - int rc; + 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; - be = glue_back_select (b0, e->e_ndn); if (!be->be_entry_put) return NOID; if (!glueBack) { - rc = be->be_entry_open (be, glueMode); - if (rc != 0) + 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. */ - glueBack->be_entry_close (glueBack); - rc = be->be_entry_open (be, glueMode); - if (rc != 0) + 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); @@ -763,118 +776,264 @@ glue_tool_sync ( BackendDB *b0 ) { - glueinfo *gi = (glueinfo *) b0->be_private; + 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; inodes; i++) - if (gi->n[i].be->be_sync) - gi->n[i].be->be_sync (gi->n[i].be); + 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; } -int -glue_sub_init( ) +static int +glue_db_init( + BackendDB *be +) { - int i, j; - int cont = num_subordinates; - BackendDB *b1, *be; - BackendInfo *bi; + slap_overinst *on = (slap_overinst *)be->bd_info; + slap_overinfo *oi = on->on_info; + BackendInfo *bi = oi->oi_orig; glueinfo *gi; - /* While there are subordinate backends, search backwards through the - * backends and connect them to their superior. + if ( SLAP_GLUE_SUBORDINATE( be )) { + Debug( LDAP_DEBUG_ANY, "glue: backend %s is already subordinate, " + "cannot have glue overlay!\n", + be->be_suffix[0].bv_val, 0, 0 ); + return LDAP_OTHER; + } + + 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.... */ - for (i = nBackendDB - 1, b1=&backendDB[i]; cont && i>=0; b1--,i--) { - if (b1->be_flags & SLAP_BFLAG_GLUE_SUBORDINATE) { - /* The last database cannot be a subordinate of noone */ - if (i == nBackendDB - 1) { - b1->be_flags ^= SLAP_BFLAG_GLUE_SUBORDINATE; - } + 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; + + /* Only advertise these if the root DB supports them */ + if ( bi->bi_tool_entry_open ) + oi->oi_bi.bi_tool_entry_open = glue_tool_entry_open; + if ( bi->bi_tool_entry_close ) + oi->oi_bi.bi_tool_entry_close = glue_tool_entry_close; + if ( bi->bi_tool_entry_first ) + oi->oi_bi.bi_tool_entry_first = glue_tool_entry_first; + if ( bi->bi_tool_entry_next ) + oi->oi_bi.bi_tool_entry_next = glue_tool_entry_next; + if ( bi->bi_tool_entry_get ) + oi->oi_bi.bi_tool_entry_get = glue_tool_entry_get; + if ( bi->bi_tool_entry_put ) + oi->oi_bi.bi_tool_entry_put = glue_tool_entry_put; + if ( bi->bi_tool_entry_reindex ) + oi->oi_bi.bi_tool_entry_reindex = glue_tool_entry_reindex; + if ( bi->bi_tool_sync ) + 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 = 0; + 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 )) != NULL ) { + 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; } - gi = NULL; - for (j = i-1, be=&backendDB[j]; j>=0; be--,j--) { - if (!(be->be_flags & SLAP_BFLAG_GLUE_SUBORDINATE)) { - continue; + 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--; } - /* We will only link it once */ - if (be->be_flags & SLAP_BFLAG_GLUE_LINKED) { + } + } + 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 */ +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 )) != NULL ) { + slap_overinfo *oi; + slap_overinst *on; + glueinfo *gi; + + if ( SLAP_GLUE_SUBORDINATE( be )) continue; - } - if (!dnIsSuffix(be->be_nsuffix[0], b1->be_nsuffix[0])) { + 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; } - cont--; - be->be_flags |= SLAP_BFLAG_GLUE_LINKED; - if (gi == NULL) { - /* We create a copy of the superior's be - * structure, pointing to all of its original - * information. Then we replace elements of - * the superior's info with our own. The copy - * is used whenever we have operations to pass - * down to the real database. - */ - b1->be_flags |= SLAP_BFLAG_GLUE_INSTANCE; - gi = (glueinfo *)ch_malloc(sizeof(glueinfo)); - gi->be = (BackendDB *)ch_malloc( - sizeof(BackendDB) + sizeof(BackendInfo)); - bi = (BackendInfo *)(gi->be+1); - *gi->be = *b1; - gi->nodes = 0; - *bi = *b1->bd_info; - bi->bi_open = glue_back_open; - bi->bi_close = glue_back_close; - bi->bi_db_open = glue_back_db_open; - bi->bi_db_close = glue_back_db_close; - bi->bi_db_destroy = glue_back_db_destroy; - - bi->bi_op_bind = glue_back_bind; - bi->bi_op_search = glue_back_search; - bi->bi_op_compare = glue_back_compare; - bi->bi_op_modify = glue_back_modify; - bi->bi_op_modrdn = glue_back_modrdn; - bi->bi_op_add = glue_back_add; - bi->bi_op_delete = glue_back_delete; - - bi->bi_entry_release_rw = glue_back_release_rw; - bi->bi_acl_group = glue_back_group; - bi->bi_acl_attribute = glue_back_attribute; - bi->bi_chk_referrals = glue_back_referrals; - - /* - * hooks for slap tools - */ - bi->bi_tool_entry_open = glue_tool_entry_open; - bi->bi_tool_entry_close = glue_tool_entry_close; - bi->bi_tool_entry_first = glue_tool_entry_first; - bi->bi_tool_entry_next = glue_tool_entry_next; - bi->bi_tool_entry_get = glue_tool_entry_get; - bi->bi_tool_entry_put = glue_tool_entry_put; - bi->bi_tool_entry_reindex = glue_tool_entry_reindex; - bi->bi_tool_sync = glue_tool_sync; - } else { - gi = (glueinfo *)ch_realloc(gi, - sizeof(glueinfo) + - gi->nodes * sizeof(gluenode)); + /* 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; } - gi->n[gi->nodes].be = be; - gi->n[gi->nodes].pdn = dn_parent(NULL, - be->be_nsuffix[0]->bv_val); - gi->nodes++; + 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 (gi) { - /* One more node for the master */ - gi = (glueinfo *)ch_realloc(gi, - sizeof(glueinfo) + gi->nodes * sizeof(gluenode)); - gi->n[gi->nodes].be = gi->be; - gi->n[gi->nodes].pdn = dn_parent(NULL, - b1->be_nsuffix[0]->bv_val); - gi->nodes++; - b1->be_private = gi; - b1->bd_info = bi; + 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; + + if ( overlay_is_inst( be, "glue" )) { + Debug( LDAP_DEBUG_ANY, "glue: backend %s already has glue overlay, " + "cannot be a subordinate!\n", + be->be_suffix[0].bv_val, 0, 0 ); + return LDAP_OTHER; } - /* If there are any unresolved subordinates left, something is wrong */ - return cont; + 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 = ga_list; + ga->ga_be = be; + ga_list = ga; + + if ( online ) + rc = glue_sub_attach(); + + return rc; +} + +int +glue_sub_init() +{ + 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_extended = glue_op_func; + + glue.on_bi.bi_chk_referrals = glue_chk_referrals; + glue.on_bi.bi_chk_controls = glue_chk_controls; + glue.on_response = glue_response; + + return overlay_register( &glue ); }