## <http://www.OpenLDAP.org/license.html>.
SRCS = init.c config.c search.c bind.c unbind.c add.c compare.c \
- delete.c modify.c modrdn.c extended.c
+ delete.c modify.c modrdn.c extended.c chain.c
OBJS = init.lo config.lo search.lo bind.lo unbind.lo add.lo compare.lo \
- delete.lo modify.lo modrdn.lo extended.lo
+ delete.lo modify.lo modrdn.lo extended.lo chain.lo
LDAP_INCDIR= ../../../include
LDAP_LIBDIR= ../../../libraries
--- /dev/null
+/* chain.c - chain LDAP operations */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2003-2005 The OpenLDAP Foundation.
+ * Portions Copyright 2003 Howard Chu.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by the Howard Chu for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+#include "back-ldap.h"
+
+static BackendInfo *lback;
+
+static int
+ldap_chain_chk_referrals( Operation *op, SlapReply *rs )
+{
+ return LDAP_SUCCESS;
+}
+
+static int
+ldap_chain_operational( Operation *op, SlapReply *rs )
+{
+ /* trap entries generated by back-ldap.
+ * FIXME: we need a better way to recognize them; a cleaner
+ * solution would be to be able to intercept the response
+ * of be_operational(), so that we can divert only those
+ * calls that fail because operational attributes were
+ * requested for entries that do not belong to the underlying
+ * database. This fix is likely to intercept also entries
+ * generated by back-perl and so. */
+ if ( rs->sr_entry->e_private == NULL ) {
+ return 0;
+ }
+
+ return SLAP_CB_CONTINUE;
+}
+
+static int
+ldap_chain_cb_response( Operation *op, SlapReply *rs )
+{
+ assert( op->o_tag == LDAP_REQ_SEARCH );
+
+ if ( rs->sr_type == REP_SEARCH ) {
+ Attribute **ap = &rs->sr_entry->e_attrs;
+
+ for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
+ /* will be generated later by frontend
+ * (a cleaner solution would be that
+ * the frontend checks if it already exists */
+ if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
+ {
+ Attribute *a = *ap;
+
+ *ap = (*ap)->a_next;
+ attr_free( a );
+
+ /* there SHOULD be one only! */
+ break;
+ }
+ }
+
+ return SLAP_CB_CONTINUE;
+ }
+
+ return 0;
+}
+
+static int
+ldap_chain_response( Operation *op, SlapReply *rs )
+{
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ void *private = op->o_bd->be_private;
+ slap_callback *sc = op->o_callback;
+ LDAPControl **prev = op->o_ctrls;
+ LDAPControl **ctrls = NULL, authz;
+ int i, nctrls, rc = 0;
+ int cache = op->o_do_not_cache;
+ char *authzid = NULL;
+ BerVarray ref;
+ struct berval ndn = op->o_ndn;
+
+ struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private;
+
+ if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF )
+ return SLAP_CB_CONTINUE;
+
+ ref = rs->sr_ref;
+ rs->sr_ref = NULL;
+
+ op->o_callback = NULL;
+
+ if ( lip->url == NULL ) {
+ /* if we parse the URI then by no means
+ * we can cache stuff or reuse connections,
+ * because in back-ldap there's no caching
+ * based on the URI value, which is supposed
+ * to be set once for all (correct?) */
+ op->o_do_not_cache = 1;
+
+ /* FIXME: we're setting the URI of the first referral;
+ * what if there are more? Is this something we should
+ * worry about? */
+ li = *lip;
+ op->o_bd->be_private = &li;
+
+ if ( rs->sr_type != REP_SEARCHREF ) {
+ LDAPURLDesc *srv;
+ char *save_dn;
+
+ /* parse reference and use
+ * proto://[host][:port]/ only */
+ rc = ldap_url_parse_ext( ref[0].bv_val, &srv );
+ if ( rc != LDAP_URL_SUCCESS) {
+ /* error */
+ return 1;
+ }
+
+ /* remove DN essentially because later on
+ * ldap_initialize() will parse the URL
+ * as a comma-separated URL list */
+ save_dn = srv->lud_dn;
+ srv->lud_dn = "";
+ srv->lud_scope = LDAP_SCOPE_DEFAULT;
+ li.url = ldap_url_desc2str( srv );
+ srv->lud_dn = save_dn;
+ ldap_free_urldesc( srv );
+
+ if ( li.url == NULL ) {
+ /* error */
+ return 1;
+ }
+ }
+
+ } else {
+ op->o_bd->be_private = on->on_bi.bi_private;
+ }
+
+ /* Chaining is performed by a privileged user on behalf
+ * of a normal user, using the ProxyAuthz control. However,
+ * Binds are done separately, on an anonymous session.
+ */
+ if ( op->o_tag != LDAP_REQ_BIND ) {
+ for ( i = 0; prev && prev[i]; i++ )
+ /* count and set prev to the last one */ ;
+ nctrls = i;
+
+ /* Add an extra NULL slot */
+ if ( !prev ) {
+ i++;
+ }
+
+ ctrls = op->o_tmpalloc((i + 1)*sizeof(LDAPControl *),
+ op->o_tmpmemctx);
+ for ( i = 0; i < nctrls; i++ ) {
+ ctrls[i] = prev[i];
+ }
+ ctrls[nctrls] = &authz;
+ ctrls[nctrls + 1] = NULL;
+ authz.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
+ authz.ldctl_iscritical = 1;
+ authz.ldctl_value = op->o_dn;
+ if ( !BER_BVISEMPTY( &op->o_dn ) ) {
+ authzid = op->o_tmpalloc( op->o_dn.bv_len + STRLENOF("dn:"),
+ op->o_tmpmemctx );
+ strcpy(authzid, "dn:");
+ strcpy(authzid + STRLENOF("dn:"), op->o_dn.bv_val);
+ authz.ldctl_value.bv_len = op->o_dn.bv_len + STRLENOF("dn:");
+ authz.ldctl_value.bv_val = authzid;
+ }
+ op->o_ctrls = ctrls;
+ op->o_ndn = op->o_bd->be_rootndn;
+ }
+
+ switch ( op->o_tag ) {
+ case LDAP_REQ_BIND: {
+ struct berval rndn = op->o_req_ndn;
+ Connection *conn = op->o_conn;
+
+ op->o_req_ndn = slap_empty_bv;
+
+ op->o_conn = NULL;
+ rc = lback->bi_op_bind( op, rs );
+ op->o_req_ndn = rndn;
+ op->o_conn = conn;
+ }
+ break;
+ case LDAP_REQ_ADD:
+ {
+ int cleanup_attrs = 0;
+
+ if ( op->ora_e->e_attrs == NULL ) {
+ char textbuf[ SLAP_TEXT_BUFLEN ];
+ size_t textlen = sizeof( textbuf );
+
+ /* global overlay; create entry */
+ /* NOTE: this is a hack to use the chain overlay
+ * as global. I expect to be able to remove this
+ * soon by using slap_mods2entry() earlier in
+ * do_add(), adding the operational attrs later
+ * if required. */
+ rs->sr_err = slap_mods2entry( op->ora_modlist,
+ &op->ora_e, 0, 1,
+ &rs->sr_text, textbuf, textlen );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ send_ldap_result( op, rs );
+ rc = 1;
+ break;
+ }
+ }
+ rc = lback->bi_op_add( op, rs );
+ if ( cleanup_attrs ) {
+ attrs_free( op->ora_e->e_attrs );
+ op->ora_e->e_attrs = NULL;
+ }
+ break;
+ }
+ case LDAP_REQ_DELETE:
+ rc = lback->bi_op_delete( op, rs );
+ break;
+ case LDAP_REQ_MODRDN:
+ rc = lback->bi_op_modrdn( op, rs );
+ break;
+ case LDAP_REQ_MODIFY:
+ rc = lback->bi_op_modify( op, rs );
+ break;
+ case LDAP_REQ_COMPARE:
+ rc = lback->bi_op_compare( op, rs );
+ break;
+ case LDAP_REQ_SEARCH:
+ if ( rs->sr_type == REP_SEARCHREF ) {
+ struct berval *curr = ref,
+ odn = op->o_req_dn,
+ ondn = op->o_req_ndn;
+ slap_callback sc2 = { 0 };
+ int tmprc = 0;
+ ber_len_t refcnt = 0;
+ BerVarray newref = NULL;
+
+ sc2.sc_response = ldap_chain_cb_response;
+ op->o_callback = &sc2;
+
+ rs->sr_type = REP_SEARCH;
+
+ /* copy the private info because we need to modify it */
+ for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) {
+ LDAPURLDesc *srv;
+ char *save_dn;
+
+ /* parse reference and use
+ * proto://[host][:port]/ only */
+ tmprc = ldap_url_parse_ext( curr[0].bv_val, &srv );
+ if ( tmprc != LDAP_URL_SUCCESS ) {
+ /* error */
+ rc = 1;
+ goto end_of_searchref;
+ }
+
+ /* remove DN essentially because later on
+ * ldap_initialize() will parse the URL
+ * as a comma-separated URL list */
+ save_dn = srv->lud_dn;
+ srv->lud_dn = "";
+ srv->lud_scope = LDAP_SCOPE_DEFAULT;
+ li.url = ldap_url_desc2str( srv );
+ if ( li.url != NULL ) {
+ ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
+ op->o_tmpmemctx );
+ ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
+ op->o_tmpmemctx );
+ }
+
+ srv->lud_dn = save_dn;
+ ldap_free_urldesc( srv );
+
+ if ( li.url == NULL ) {
+ /* error */
+ rc = 1;
+ goto end_of_searchref;
+ }
+
+
+ /* FIXME: should we also copy filter and scope?
+ * according to RFC3296, no */
+ tmprc = lback->bi_op_search( op, rs );
+
+ ldap_memfree( li.url );
+ li.url = NULL;
+
+ op->o_tmpfree( op->o_req_dn.bv_val,
+ op->o_tmpmemctx );
+ op->o_tmpfree( op->o_req_ndn.bv_val,
+ op->o_tmpmemctx );
+
+ if ( tmprc ) {
+ /* error */
+ rc = 1;
+ goto end_of_searchref;
+ }
+
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ /* if search was not successful,
+ * at least return the referral! */
+ /* FIXME: assumes referrals
+ * are always created via
+ * referral_rewrite() and freed via
+ * ber_bvarray_free( rs->sr_ref ) */
+ newref = ch_realloc( newref, sizeof( struct berval ) * (refcnt + 2) );
+ ber_dupbv( &newref[ refcnt ], &curr[ 0 ] );
+ refcnt++;
+ BER_BVZERO( &newref[ refcnt ] );
+ }
+ }
+
+end_of_searchref:;
+ op->o_req_dn = odn;
+ op->o_req_ndn = ondn;
+ rs->sr_type = REP_SEARCHREF;
+ rs->sr_entry = NULL;
+
+ /* if the error was bad, it was already returned
+ * by back-ldap; destroy the referrals left;
+ * otherwise, let the frontend return them. */
+ if ( newref ) {
+ if ( rc == 0 ) {
+ rc = SLAP_CB_CONTINUE;
+ if ( ref != default_referral ) {
+ ber_bvarray_free( ref );
+ }
+ ref = newref;
+
+ } else {
+ ber_bvarray_free( newref );
+ }
+ }
+
+ } else {
+ rc = lback->bi_op_search( op, rs );
+ }
+ break;
+ case LDAP_REQ_EXTENDED:
+ rc = lback->bi_extended( op, rs );
+ break;
+ default:
+ rc = SLAP_CB_CONTINUE;
+ break;
+ }
+ op->o_do_not_cache = cache;
+ op->o_ctrls = prev;
+ op->o_bd->be_private = private;
+ op->o_callback = sc;
+ op->o_ndn = ndn;
+ if ( ctrls ) {
+ op->o_tmpfree( ctrls, op->o_tmpmemctx );
+ }
+ if ( authzid ) {
+ op->o_tmpfree( authzid, op->o_tmpmemctx );
+ }
+ rs->sr_ref = ref;
+ if ( lip->url == NULL && li.url != NULL ) {
+ ldap_memfree( li.url );
+ }
+
+ return rc;
+}
+
+static int
+ldap_chain_db_config(
+ BackendDB *be,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+)
+{
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ void *private = be->be_private;
+ char *argv0 = NULL;
+ int rc;
+
+ be->be_private = on->on_bi.bi_private;
+ if ( strncasecmp( argv[ 0 ], "chain-", sizeof( "chain-" ) - 1 ) == 0 ) {
+ argv0 = argv[ 0 ];
+ argv[ 0 ] = &argv[ 0 ][ sizeof( "chain-" ) - 1 ];
+ }
+ rc = lback->bi_db_config( be, fname, lineno, argc, argv );
+ if ( argv0 ) {
+ argv[ 0 ] = argv0;
+ }
+
+ be->be_private = private;
+ return rc;
+}
+
+static int
+ldap_chain_db_init(
+ BackendDB *be
+)
+{
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ void *private = be->be_private;
+ int rc;
+
+ if ( lback == NULL ) {
+ lback = backend_info( "ldap" );
+
+ if ( lback == NULL ) {
+ return -1;
+ }
+ }
+
+ be->be_private = NULL;
+ rc = lback->bi_db_init( be );
+ on->on_bi.bi_private = be->be_private;
+ be->be_private = private;
+
+ return rc;
+}
+
+static int
+ldap_chain_db_destroy(
+ BackendDB *be
+)
+{
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ void *private = be->be_private;
+ int rc;
+
+ be->be_private = on->on_bi.bi_private;
+ rc = lback->bi_db_destroy( be );
+ on->on_bi.bi_private = be->be_private;
+ be->be_private = private;
+ return rc;
+}
+
+static slap_overinst ldapchain;
+
+int
+chain_init( void )
+{
+ ldapchain.on_bi.bi_type = "chain";
+ ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
+ ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
+ ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
+
+ /* ... otherwise the underlying backend's function would be called,
+ * likely passing an invalid entry; on the contrary, the requested
+ * operational attributes should have been returned while chasing
+ * the referrals. This all in all is a bit messy, because part
+ * of the operational attributes are generated by they backend;
+ * part by the frontend; back-ldap should receive all the available
+ * ones from the remote server, but then, on it own, it strips those
+ * it assumes will be (re)generated by the frontend (e.g.
+ * subschemaSubentry.) */
+ ldapchain.on_bi.bi_operational = ldap_chain_operational;
+
+ ldapchain.on_response = ldap_chain_response;
+
+
+ ldapchain.on_bi.bi_chk_referrals = ldap_chain_chk_referrals;
+
+ return overlay_register( &ldapchain );
+}
+
bi->bi_connection_init = 0;
bi->bi_connection_destroy = ldap_back_conn_destroy;
+ if ( chain_init( ) ) {
+ return -1;
+ }
+
return 0;
}
## <http://www.OpenLDAP.org/license.html>.
SRCS = overlays.c \
- chain.c \
denyop.c \
dyngroup.c \
glue.c \
syncprov.c \
unique.c
OBJS = overlays.lo \
- chain.lo \
denyop.lo \
dyngroup.lo \
glue.lo \
XINCPATH = -I.. -I$(srcdir)/..
XDEFS = $(MODULES_CPPFLAGS)
-chain.la : chain.lo $(@PLAT@_LINK_LIBS)
- $(LTLINK_MOD) -module -o $@ chain.lo version.lo $(LINK_LIBS)
-
denyop.la : denyop.lo $(@PLAT@_LINK_LIBS)
$(LTLINK_MOD) -module -o $@ denyop.lo version.lo $(LINK_LIBS)
+++ /dev/null
-/* chain.c - chain LDAP operations */
-/* $OpenLDAP$ */
-/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
- *
- * Copyright 2003-2005 The OpenLDAP Foundation.
- * Portions Copyright 2003 Howard Chu.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-/* ACKNOWLEDGEMENTS:
- * This work was initially developed by the Howard Chu for inclusion
- * in OpenLDAP Software.
- */
-
-#include "portable.h"
-
-#if defined(SLAPD_LDAP)
-
-#ifdef SLAPD_OVER_CHAIN
-
-#include <stdio.h>
-
-#include <ac/string.h>
-#include <ac/socket.h>
-
-#include "slap.h"
-#include "../back-ldap/back-ldap.h"
-
-static BackendInfo *lback;
-
-static int
-ldap_chain_chk_referrals( Operation *op, SlapReply *rs )
-{
- return LDAP_SUCCESS;
-}
-
-static int
-ldap_chain_operational( Operation *op, SlapReply *rs )
-{
- /* trap entries generated by back-ldap.
- * FIXME: we need a better way to recognize them; a cleaner
- * solution would be to be able to intercept the response
- * of be_operational(), so that we can divert only those
- * calls that fail because operational attributes were
- * requested for entries that do not belong to the underlying
- * database. This fix is likely to intercept also entries
- * generated by back-perl and so. */
- if ( rs->sr_entry->e_private == NULL ) {
- return 0;
- }
-
- return SLAP_CB_CONTINUE;
-}
-
-static int
-ldap_chain_cb_response( Operation *op, SlapReply *rs )
-{
- assert( op->o_tag == LDAP_REQ_SEARCH );
-
- if ( rs->sr_type == REP_SEARCH ) {
- Attribute **ap = &rs->sr_entry->e_attrs;
-
- for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
- /* will be generated later by frontend
- * (a cleaner solution would be that
- * the frontend checks if it already exists */
- if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
- {
- Attribute *a = *ap;
-
- *ap = (*ap)->a_next;
- attr_free( a );
-
- /* there SHOULD be one only! */
- break;
- }
- }
-
- return SLAP_CB_CONTINUE;
- }
-
- return 0;
-}
-
-static int
-ldap_chain_response( Operation *op, SlapReply *rs )
-{
- slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
- void *private = op->o_bd->be_private;
- slap_callback *sc = op->o_callback;
- LDAPControl **prev = op->o_ctrls;
- LDAPControl **ctrls = NULL, authz;
- int i, nctrls, rc = 0;
- int cache = op->o_do_not_cache;
- char *authzid = NULL;
- BerVarray ref;
- struct berval ndn = op->o_ndn;
-
- struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private;
-
- if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF )
- return SLAP_CB_CONTINUE;
-
- ref = rs->sr_ref;
- rs->sr_ref = NULL;
-
- op->o_callback = NULL;
-
- if ( lip->url == NULL ) {
- /* if we parse the URI then by no means
- * we can cache stuff or reuse connections,
- * because in back-ldap there's no caching
- * based on the URI value, which is supposed
- * to be set once for all (correct?) */
- op->o_do_not_cache = 1;
-
- /* FIXME: we're setting the URI of the first referral;
- * what if there are more? Is this something we should
- * worry about? */
- li = *lip;
- op->o_bd->be_private = &li;
-
- if ( rs->sr_type != REP_SEARCHREF ) {
- LDAPURLDesc *srv;
- char *save_dn;
-
- /* parse reference and use
- * proto://[host][:port]/ only */
- rc = ldap_url_parse_ext( ref[0].bv_val, &srv );
- if ( rc != LDAP_URL_SUCCESS) {
- /* error */
- return 1;
- }
-
- /* remove DN essentially because later on
- * ldap_initialize() will parse the URL
- * as a comma-separated URL list */
- save_dn = srv->lud_dn;
- srv->lud_dn = "";
- srv->lud_scope = LDAP_SCOPE_DEFAULT;
- li.url = ldap_url_desc2str( srv );
- srv->lud_dn = save_dn;
- ldap_free_urldesc( srv );
-
- if ( li.url == NULL ) {
- /* error */
- return 1;
- }
- }
-
- } else {
- op->o_bd->be_private = on->on_bi.bi_private;
- }
-
- /* Chaining is performed by a privileged user on behalf
- * of a normal user, using the ProxyAuthz control. However,
- * Binds are done separately, on an anonymous session.
- */
- if ( op->o_tag != LDAP_REQ_BIND ) {
- for ( i = 0; prev && prev[i]; i++ )
- /* count and set prev to the last one */ ;
- nctrls = i;
-
- /* Add an extra NULL slot */
- if ( !prev ) {
- i++;
- }
-
- ctrls = op->o_tmpalloc((i + 1)*sizeof(LDAPControl *),
- op->o_tmpmemctx);
- for ( i = 0; i < nctrls; i++ ) {
- ctrls[i] = prev[i];
- }
- ctrls[nctrls] = &authz;
- ctrls[nctrls + 1] = NULL;
- authz.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
- authz.ldctl_iscritical = 1;
- authz.ldctl_value = op->o_dn;
- if ( !BER_BVISEMPTY( &op->o_dn ) ) {
- authzid = op->o_tmpalloc( op->o_dn.bv_len + STRLENOF("dn:"),
- op->o_tmpmemctx );
- strcpy(authzid, "dn:");
- strcpy(authzid + STRLENOF("dn:"), op->o_dn.bv_val);
- authz.ldctl_value.bv_len = op->o_dn.bv_len + STRLENOF("dn:");
- authz.ldctl_value.bv_val = authzid;
- }
- op->o_ctrls = ctrls;
- op->o_ndn = op->o_bd->be_rootndn;
- }
-
- switch ( op->o_tag ) {
- case LDAP_REQ_BIND: {
- struct berval rndn = op->o_req_ndn;
- Connection *conn = op->o_conn;
-
- op->o_req_ndn = slap_empty_bv;
-
- op->o_conn = NULL;
- rc = lback->bi_op_bind( op, rs );
- op->o_req_ndn = rndn;
- op->o_conn = conn;
- }
- break;
- case LDAP_REQ_ADD:
- {
- int cleanup_attrs = 0;
-
- if ( op->ora_e->e_attrs == NULL ) {
- char textbuf[ SLAP_TEXT_BUFLEN ];
- size_t textlen = sizeof( textbuf );
-
- /* global overlay; create entry */
- /* NOTE: this is a hack to use the chain overlay
- * as global. I expect to be able to remove this
- * soon by using slap_mods2entry() earlier in
- * do_add(), adding the operational attrs later
- * if required. */
- rs->sr_err = slap_mods2entry( op->ora_modlist,
- &op->ora_e, 0, 1,
- &rs->sr_text, textbuf, textlen );
- if ( rs->sr_err != LDAP_SUCCESS ) {
- send_ldap_result( op, rs );
- rc = 1;
- break;
- }
- }
- rc = lback->bi_op_add( op, rs );
- if ( cleanup_attrs ) {
- attrs_free( op->ora_e->e_attrs );
- op->ora_e->e_attrs = NULL;
- }
- break;
- }
- case LDAP_REQ_DELETE:
- rc = lback->bi_op_delete( op, rs );
- break;
- case LDAP_REQ_MODRDN:
- rc = lback->bi_op_modrdn( op, rs );
- break;
- case LDAP_REQ_MODIFY:
- rc = lback->bi_op_modify( op, rs );
- break;
- case LDAP_REQ_COMPARE:
- rc = lback->bi_op_compare( op, rs );
- break;
- case LDAP_REQ_SEARCH:
- if ( rs->sr_type == REP_SEARCHREF ) {
- struct berval *curr = ref,
- odn = op->o_req_dn,
- ondn = op->o_req_ndn;
- slap_callback sc2 = { 0 };
- int tmprc = 0;
- ber_len_t refcnt = 0;
- BerVarray newref = NULL;
-
- sc2.sc_response = ldap_chain_cb_response;
- op->o_callback = &sc2;
-
- rs->sr_type = REP_SEARCH;
-
- /* copy the private info because we need to modify it */
- for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) {
- LDAPURLDesc *srv;
- char *save_dn;
-
- /* parse reference and use
- * proto://[host][:port]/ only */
- tmprc = ldap_url_parse_ext( curr[0].bv_val, &srv );
- if ( tmprc != LDAP_URL_SUCCESS ) {
- /* error */
- rc = 1;
- goto end_of_searchref;
- }
-
- /* remove DN essentially because later on
- * ldap_initialize() will parse the URL
- * as a comma-separated URL list */
- save_dn = srv->lud_dn;
- srv->lud_dn = "";
- srv->lud_scope = LDAP_SCOPE_DEFAULT;
- li.url = ldap_url_desc2str( srv );
- if ( li.url != NULL ) {
- ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
- op->o_tmpmemctx );
- ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
- op->o_tmpmemctx );
- }
-
- srv->lud_dn = save_dn;
- ldap_free_urldesc( srv );
-
- if ( li.url == NULL ) {
- /* error */
- rc = 1;
- goto end_of_searchref;
- }
-
-
- /* FIXME: should we also copy filter and scope?
- * according to RFC3296, no */
- tmprc = lback->bi_op_search( op, rs );
-
- ldap_memfree( li.url );
- li.url = NULL;
-
- op->o_tmpfree( op->o_req_dn.bv_val,
- op->o_tmpmemctx );
- op->o_tmpfree( op->o_req_ndn.bv_val,
- op->o_tmpmemctx );
-
- if ( tmprc ) {
- /* error */
- rc = 1;
- goto end_of_searchref;
- }
-
- if ( rs->sr_err != LDAP_SUCCESS ) {
- /* if search was not successful,
- * at least return the referral! */
- /* FIXME: assumes referrals
- * are always created via
- * referral_rewrite() and freed via
- * ber_bvarray_free( rs->sr_ref ) */
- newref = ch_realloc( newref, sizeof( struct berval ) * (refcnt + 2) );
- ber_dupbv( &newref[ refcnt ], &curr[ 0 ] );
- refcnt++;
- BER_BVZERO( &newref[ refcnt ] );
- }
- }
-
-end_of_searchref:;
- op->o_req_dn = odn;
- op->o_req_ndn = ondn;
- rs->sr_type = REP_SEARCHREF;
- rs->sr_entry = NULL;
-
- /* if the error was bad, it was already returned
- * by back-ldap; destroy the referrals left;
- * otherwise, let the frontend return them. */
- if ( newref ) {
- if ( rc == 0 ) {
- rc = SLAP_CB_CONTINUE;
- if ( ref != default_referral ) {
- ber_bvarray_free( ref );
- }
- ref = newref;
-
- } else {
- ber_bvarray_free( newref );
- }
- }
-
- } else {
- rc = lback->bi_op_search( op, rs );
- }
- break;
- case LDAP_REQ_EXTENDED:
- rc = lback->bi_extended( op, rs );
- break;
- default:
- rc = SLAP_CB_CONTINUE;
- break;
- }
- op->o_do_not_cache = cache;
- op->o_ctrls = prev;
- op->o_bd->be_private = private;
- op->o_callback = sc;
- op->o_ndn = ndn;
- if ( ctrls ) {
- op->o_tmpfree( ctrls, op->o_tmpmemctx );
- }
- if ( authzid ) {
- op->o_tmpfree( authzid, op->o_tmpmemctx );
- }
- rs->sr_ref = ref;
- if ( lip->url == NULL && li.url != NULL ) {
- ldap_memfree( li.url );
- }
-
- return rc;
-}
-
-static int
-ldap_chain_config(
- BackendDB *be,
- const char *fname,
- int lineno,
- int argc,
- char **argv
-)
-{
- slap_overinst *on = (slap_overinst *) be->bd_info;
- void *private = be->be_private;
- char *argv0 = NULL;
- int rc;
-
- be->be_private = on->on_bi.bi_private;
- if ( strncasecmp( argv[ 0 ], "chain-", sizeof( "chain-" ) - 1 ) == 0 ) {
- argv0 = argv[ 0 ];
- argv[ 0 ] = &argv[ 0 ][ sizeof( "chain-" ) - 1 ];
- }
- rc = lback->bi_db_config( be, fname, lineno, argc, argv );
- if ( argv0 ) {
- argv[ 0 ] = argv0;
- }
-
- be->be_private = private;
- return rc;
-}
-
-static int
-ldap_chain_init(
- BackendDB *be
-)
-{
- slap_overinst *on = (slap_overinst *) be->bd_info;
- void *private = be->be_private;
- int rc;
-
- be->be_private = NULL;
- rc = lback->bi_db_init( be );
- on->on_bi.bi_private = be->be_private;
- be->be_private = private;
-
- return rc;
-}
-
-static int
-ldap_chain_destroy(
- BackendDB *be
-)
-{
- slap_overinst *on = (slap_overinst *) be->bd_info;
- void *private = be->be_private;
- int rc;
-
- be->be_private = on->on_bi.bi_private;
- rc = lback->bi_db_destroy( be );
- on->on_bi.bi_private = be->be_private;
- be->be_private = private;
- return rc;
-}
-
-static slap_overinst ldapchain;
-
-int
-chain_init()
-{
- lback = backend_info( "ldap" );
-
- if ( !lback ) {
- return -1;
- }
-
- ldapchain.on_bi.bi_type = "chain";
- ldapchain.on_bi.bi_db_init = ldap_chain_init;
- ldapchain.on_bi.bi_db_config = ldap_chain_config;
- ldapchain.on_bi.bi_db_destroy = ldap_chain_destroy;
-
- /* ... otherwise the underlying backend's function would be called,
- * likely passing an invalid entry; on the contrary, the requested
- * operational attributes should have been returned while chasing
- * the referrals. This all in all is a bit messy, because part
- * of the operational attributes are generated by they backend;
- * part by the frontend; back-ldap should receive all the available
- * ones from the remote server, but then, on it own, it strips those
- * it assumes will be (re)generated by the frontend (e.g.
- * subschemaSubentry.) */
- ldapchain.on_bi.bi_operational = ldap_chain_operational;
-
- ldapchain.on_response = ldap_chain_response;
-
-
- ldapchain.on_bi.bi_chk_referrals = ldap_chain_chk_referrals;
-
- return overlay_register( &ldapchain );
-}
-
-#if SLAPD_OVER_CHAIN == SLAPD_MOD_DYNAMIC
-int init_module(int argc, char *argv[]) {
- return chain_init();
-}
-#endif /* SLAPD_OVER_CHAIN == SLAPD_MOD_DYNAMIC */
-
-#endif /* SLAPD_OVER_CHAIN */
-
-#endif /* ! defined(SLAPD_LDAP) */
#include "slap.h"
-#if SLAPD_OVER_CHAIN == SLAPD_MOD_STATIC
-extern int chain_init();
-#endif
#if SLAPD_OVER_DENYOP == SLAPD_MOD_STATIC
extern int denyop_init();
#endif
char *name;
int (*func)();
} funcs[] = {
-#if SLAPD_OVER_CHAIN == SLAPD_MOD_STATIC
- { "LDAP Chain Response", chain_init },
-#endif
#if SLAPD_OVER_DENYOP == SLAPD_MOD_STATIC
{ "Deny Operation", denyop_init },
#endif