#define LDAP_BACK_F_NONE 0x00U
#define LDAP_BACK_F_SAVECRED 0x01U
#define LDAP_BACK_F_USE_TLS 0x02U
-#define LDAP_BACK_F_TLS_CRITICAL ( 0x04U | LDAP_BACK_F_USE_TLS )
-#define LDAP_BACK_F_CHASE_REFERRALS 0x8U
+#define LDAP_BACK_F_PROPAGATE_TLS 0x04U
+#define LDAP_BACK_F_TLS_CRITICAL 0x08U
+#define LDAP_BACK_F_CHASE_REFERRALS 0x10U
+
+#define LDAP_BACK_SAVECRED(li) ( (li)->flags & LDAP_BACK_F_SAVECRED )
+#define LDAP_BACK_USE_TLS(li) ( (li)->flags & LDAP_BACK_F_USE_TLS )
+#define LDAP_BACK_PROPAGATE_TLS(li) ( (li)->flags & LDAP_BACK_F_PROPAGATE_TLS )
+#define LDAP_BACK_TLS_CRITICAL(li) ( (li)->flags & LDAP_BACK_F_TLS_CRITICAL )
+#define LDAP_BACK_CHASE_REFERRALS(li) ( (li)->flags & LDAP_BACK_F_CHASE_REFERRALS )
+
Avlnode *conntree;
int rwm_started;
lc->lc_bound = 1;
ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
- if ( li->flags & LDAP_BACK_F_SAVECRED ) {
+ if ( LDAP_BACK_SAVECRED( li ) ) {
if ( !BER_BVISNULL( &lc->lc_cred ) ) {
memset( lc->lc_cred.bv_val, 0,
lc->lc_cred.bv_len );
*/
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers );
- /* automatically chase referrals ("chase-referrals"/"dont-chase-referrals" statement) */
- if ( li->flags & LDAP_BACK_F_CHASE_REFERRALS ) {
+ /* automatically chase referrals ("[dont-]chase-referrals" statement) */
+ if ( LDAP_BACK_CHASE_REFERRALS( li ) ) {
ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
}
- /* start TLS ("start-tls"/"try-start-tls" statements) */
- if ( ( li->flags & LDAP_BACK_F_USE_TLS )
- && !ldap_is_ldaps_url( li->url )
- && ( rs->sr_err = ldap_start_tls_s( ld, NULL, NULL ) ) != LDAP_SUCCESS )
+#ifdef HAVE_TLS
+ /* start TLS ("tls-[try-]{start,propagate}" statements) */
+ if ( ( LDAP_BACK_USE_TLS( li ) || ( op->o_conn->c_is_tls && LDAP_BACK_PROPAGATE_TLS( li ) ) )
+ && !ldap_is_ldaps_url( li->url ) )
{
+#if 1
+ /*
+ * use asynchronous StartTLS
+ * in case, chase referral (not implemented yet)
+ */
+ int msgid;
+
+ rs->sr_err = ldap_start_tls( ld, NULL, NULL, &msgid );
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ LDAPMessage *res = NULL;
+ int rc, retries = 1;
+ struct timeval tv = { 0, 0 };
+
+retry:;
+ rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
+ if ( rc < 0 ) {
+ rs->sr_err = LDAP_OTHER;
+
+ } else if ( rc == 0 ) {
+ if ( retries ) {
+ retries--;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ goto retry;
+ }
+ rs->sr_err = LDAP_OTHER;
+
+ } else if ( rc == LDAP_RES_EXTENDED ) {
+ struct berval *data = NULL;
+
+ rs->sr_err = ldap_parse_extended_result( ld, res,
+ NULL, &data, 0 );
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ rs->sr_err = ldap_result2error( ld, res, 1 );
+ res = NULL;
+
+ /* FIXME: in case a referral
+ * is returned, should we try
+ * using it instead of the
+ * configured URI? */
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ ldap_install_tls( ld );
+
+ } else if ( rs->sr_err == LDAP_REFERRAL ) {
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "unwilling to chase referral returned by Start TLS exop";
+ }
+
+ if ( data ) {
+ if ( data->bv_val ) {
+ ber_memfree( data->bv_val );
+ }
+ ber_memfree( data );
+ }
+ }
+
+ } else {
+ rs->sr_err = LDAP_OTHER;
+ }
+
+ if ( res != NULL ) {
+ ldap_msgfree( res );
+ }
+ }
+#else
+ /*
+ * use synchronous StartTLS
+ */
+ rs->sr_err = ldap_start_tls_s( ld, NULL, NULL );
+#endif
+
/* if StartTLS is requested, only attempt it if the URL
* is not "ldaps://"; this may occur not only in case
* of misconfiguration, but also when used in the chain
* overlay, where the "uri" can be parsed out of a referral */
if ( rs->sr_err == LDAP_SERVER_DOWN
- || ( li->flags & LDAP_BACK_F_TLS_CRITICAL ) )
+ || ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( li ) ) )
{
ldap_unbind_ext_s( ld, NULL, NULL );
goto error_return;
}
}
+#endif /* HAVE_TLS */
if ( *lcp == NULL ) {
*lcp = (struct ldapconn *)ch_malloc( sizeof( struct ldapconn ) );
* If no server-side controls are defined for the operation,
* simply add the proxyAuthz control; otherwise, if the
* proxyAuthz control is not already set, add it as
- * the first one (FIXME: is controls order significant
- * for security?).
+ * the first one
+ *
+ * FIXME: is controls order significant for security?
+ * ANSWER: controls ordering and interoperability
+ * must be indicated by the specs of each control; if none
+ * is specified, the order is irrelevant.
*/
int
ldap_back_proxy_authz_ctrl(
#include "back-ldap.h"
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+#define SLAP_CHAINING_DEFAULT LDAP_CHAINING_PREFERRED
#define SLAP_CH_RESOLVE_SHIFT SLAP_CONTROL_SHIFT
#define SLAP_CH_RESOLVE_MASK (0x3 << SLAP_CH_RESOLVE_SHIFT)
#define SLAP_CH_RESOLVE_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
#define SLAP_CH_RESOLVE_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
#define SLAP_CH_RESOLVE_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
#define SLAP_CH_RESOLVE_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
-#define SLAP_CH_RESOLVE_DEFAULT SLAP_CH_RESOLVE_CHAINING_PREFERRED
+#define SLAP_CH_RESOLVE_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_RESOLVE_SHIFT)
#define SLAP_CH_CONTINUATION_SHIFT (SLAP_CH_RESOLVE_SHIFT + 2)
#define SLAP_CH_CONTINUATION_MASK (0x3 << SLAP_CH_CONTINUATION_SHIFT)
#define SLAP_CH_CONTINUATION_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
#define SLAP_CH_CONTINUATION_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
#define SLAP_CH_CONTINUATION_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
#define SLAP_CH_CONTINUATION_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
-#define SLAP_CH_CONTINUATION_DEFAULT SLAP_CH_CONTINUATION_CHAINING_PREFERRED
+#define SLAP_CH_CONTINUATION_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_CONTINUATION_SHIFT)
#define o_chaining o_ctrlflag[sc_chainingBehavior]
#define get_chaining(op) ((op)->o_chaining & SLAP_CONTROL_MASK)
#define get_chainingBehavior(op) ((op)->o_chaining & (SLAP_CH_RESOLVE_MASK|SLAP_CH_CONTINUATION_MASK))
#define get_resolveBehavior(op) ((op)->o_chaining & SLAP_CH_RESOLVE_MASK)
#define get_continuationBehavior(op) ((op)->o_chaining & SLAP_CH_CONTINUATION_MASK)
+
+static int sc_chainingBehavior;
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
#define LDAP_CH_NONE ((void *)(0))
#define LDAP_CH_RES ((void *)(1))
#define LDAP_CH_ERR ((void *)(2))
-static int sc_chainingBehavior;
static BackendInfo *lback;
+typedef struct ldap_chain_t {
+ struct ldapinfo *lc_li;
+ unsigned lc_flags;
+#define LDAP_CHAIN_F_NONE 0x00U
+#define LDAP_CHAIN_F_CHAINING 0x01U
+
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+ LDAPControl lc_chaining_ctrl;
+ char lc_chaining_ctrlflag;
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+} ldap_chain_t;
+
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+static int
+chaining_control_add(
+ ldap_chain_t *lc,
+ Operation *op,
+ LDAPControl ***oldctrlsp )
+{
+ LDAPControl **ctrls = NULL;
+ int c = 0;
+
+ *oldctrlsp = op->o_ctrls;
+
+ /* default chaining control not defined */
+ if ( !( lc->lc_flags & LDAP_CHAIN_F_CHAINING ) ) {
+ return 0;
+ }
+
+ /* already present */
+ if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
+ return 0;
+ }
+
+ /* FIXME: check other incompatibilities */
+
+ /* add to other controls */
+ if ( op->o_ctrls ) {
+ for ( c = 0; op->o_ctrls[ c ]; c++ )
+ /* count them */ ;
+ }
+
+ ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
+ ctrls[ 0 ] = &lc->lc_chaining_ctrl;
+ if ( op->o_ctrls ) {
+ for ( c = 0; op->o_ctrls[ c ]; c++ ) {
+ ctrls[ c + 1 ] = op->o_ctrls[ c ];
+ }
+ }
+ ctrls[ c + 1 ] = NULL;
+
+ op->o_ctrls = ctrls;
+
+ op->o_chaining = lc->lc_chaining_ctrlflag;
+
+ return 0;
+}
+
+static int
+chaining_control_remove(
+ Operation *op,
+ LDAPControl ***oldctrlsp )
+{
+ LDAPControl **oldctrls = *oldctrlsp;
+
+ /* we assume that the first control is the chaining control
+ * added by the chain overlay, so it's the only one we explicitly
+ * free */
+ if ( op->o_ctrls != oldctrls ) {
+ assert( op->o_ctrls );
+ assert( op->o_ctrls[ 0 ] );
+
+ free( op->o_ctrls );
+
+ op->o_chaining = 0;
+ op->o_ctrls = oldctrls;
+ }
+
+ *oldctrlsp = NULL;
+
+ return 0;
+}
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+
static int
ldap_chain_operational( Operation *op, SlapReply *rs )
{
BerVarray ref )
{
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
- struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private;
+ ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
+ struct ldapinfo li, *lip = lc->lc_li;
/* NOTE: returned if ref is empty... */
int rc = LDAP_OTHER;
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+ LDAPControl **ctrls = NULL;
+
+ (void)chaining_control_add( lc, op, &ctrls );
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+
if ( lip->url != NULL ) {
- op->o_bd->be_private = on->on_bi.bi_private;
- return ( *op_f )( op, rs );
+ op->o_bd->be_private = lip;
+ rc = ( *op_f )( op, rs );
+ goto done;
}
li = *lip;
}
}
+done:;
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+ (void)chaining_control_remove( op, &ctrls );
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+
return rc;
}
BerVarray ref;
struct berval ndn = op->o_ndn;
- struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private;
+ ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
+ struct ldapinfo li, *lip = lc->lc_li;
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
int sr_err = rs->sr_err;
odn = op->o_req_dn,
ondn = op->o_req_ndn;
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+ LDAPControl **ctrls = NULL;
+
+ (void)chaining_control_add( lc, op, &ctrls );
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+
rs->sr_type = REP_SEARCH;
sc2.sc_response = ldap_chain_cb_search_response;
rc = rs->sr_err;
}
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+ (void)chaining_control_remove( op, &ctrls );
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+
op->o_req_dn = odn;
op->o_req_ndn = ondn;
rs->sr_type = REP_SEARCHREF;
return rc;
}
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+static int
+ldap_chain_parse_ctrl(
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl );
+
+static int
+str2chain( const char *s )
+{
+ if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
+ return LDAP_CHAINING_PREFERRED;
+
+ } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
+ return LDAP_CHAINING_REQUIRED;
+
+ } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
+ return LDAP_REFERRALS_PREFERRED;
+
+ } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
+ return LDAP_REFERRALS_REQUIRED;
+ }
+
+ return -1;
+}
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+
static int
ldap_chain_db_config(
BackendDB *be,
)
{
slap_overinst *on = (slap_overinst *) be->bd_info;
+ ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
void *private = be->be_private;
char *argv0 = NULL;
int rc;
- be->be_private = on->on_bi.bi_private;
if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
argv0 = argv[ 0 ];
argv[ 0 ] = &argv[ 0 ][ STRLENOF( "chain-" ) ];
+
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+ if ( strcasecmp( argv[ 0 ], "chaining" ) == 0 ) {
+ char **tmpargv = argv;
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *)&berbuf;
+ int resolve = -1,
+ continuation = -1,
+ iscritical = 0;
+ Operation op = { 0 };
+ SlapReply rs = { 0 };
+
+ lc->lc_chaining_ctrlflag = 0;
+
+ for ( argc--, tmpargv++; argc > 0; argc--, tmpargv++ ) {
+ if ( strncasecmp( tmpargv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
+ resolve = str2chain( tmpargv[ 0 ] + STRLENOF( "resolve=" ) );
+ if ( resolve == -1 ) {
+ fprintf( stderr, "%s line %d: "
+ "illegal <resolve> value %s "
+ "in \"chain-chaining>\"\n",
+ fname, lineno, tmpargv[ 0 ] );
+ return 1;
+ }
+
+ } else if ( strncasecmp( tmpargv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
+ continuation = str2chain( tmpargv[ 0 ] + STRLENOF( "continuation=" ) );
+ if ( continuation == -1 ) {
+ fprintf( stderr, "%s line %d: "
+ "illegal <continuation> value %s "
+ "in \"chain-chaining\"\n",
+ fname, lineno, tmpargv[ 0 ] );
+ return 1;
+ }
+
+ } else if ( strcasecmp( tmpargv[ 0 ], "critical" ) == 0 ) {
+ iscritical = 1;
+
+ } else {
+ fprintf( stderr, "%s line %d: "
+ "unknown option in \"chain-chaining\"\n",
+ fname, lineno );
+ return 1;
+ }
+ }
+
+ if ( resolve != -1 || continuation != -1 ) {
+ int err;
+
+ if ( resolve == -1 ) {
+ /* default */
+ resolve = SLAP_CHAINING_DEFAULT;
+ }
+
+ ber_init2( ber, NULL, LBER_USE_DER );
+
+ err = ber_printf( ber, "{e" /* } */, resolve );
+ if ( err == -1 ) {
+ ber_free( ber, 1 );
+ fprintf( stderr, "%s line %d: "
+ "chaining behavior control encoding error!\n",
+ fname, lineno );
+ return 1;
+ }
+
+ if ( continuation > -1 ) {
+ err = ber_printf( ber, "e", continuation );
+ if ( err == -1 ) {
+ ber_free( ber, 1 );
+ fprintf( stderr, "%s line %d: "
+ "chaining behavior control encoding error!\n",
+ fname, lineno );
+ return 1;
+ }
+ }
+
+ err = ber_printf( ber, /* { */ "N}" );
+ if ( err == -1 ) {
+ ber_free( ber, 1 );
+ fprintf( stderr, "%s line %d: "
+ "chaining behavior control encoding error!\n",
+ fname, lineno );
+ return 1;
+ }
+
+ if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
+ exit( EXIT_FAILURE );
+ }
+
+ } else {
+ BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
+ }
+
+ lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
+ lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
+
+ if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
+ {
+ fprintf( stderr, "%s line %d: "
+ "unable to parse chaining control%s%s\n",
+ fname, lineno,
+ rs.sr_text ? ": " : "",
+ rs.sr_text ? rs.sr_text : "" );
+ return 1;
+ }
+
+ lc->lc_chaining_ctrlflag = op.o_chaining;
+
+ lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
+
+ rc = 0;
+ goto done;
+ }
+#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
}
+
+
+ be->be_private = lc->lc_li;
rc = lback->bi_db_config( be, fname, lineno, argc, argv );
+ be->be_private = private;
+
+done:;
if ( argv0 ) {
argv[ 0 ] = argv0;
}
-
- be->be_private = private;
+
return rc;
}
)
{
slap_overinst *on = (slap_overinst *)be->bd_info;
+ ldap_chain_t *lc = NULL;
int rc;
BackendDB bd = *be;
}
}
+ lc = ch_malloc( sizeof( ldap_chain_t ) );
+ memset( lc, 0, sizeof( ldap_chain_t ) );
+
bd.be_private = NULL;
rc = lback->bi_db_init( &bd );
- on->on_bi.bi_private = bd.be_private;
+ lc->lc_li = (struct ldapinfo *)bd.be_private;
+ on->on_bi.bi_private = (void *)lc;
return rc;
}
-#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
static int
ldap_chain_db_open(
BackendDB *be
)
{
- return overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
-}
+ int rc = 0;
+
+#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
+ rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
+ 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;
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
+ void *private = be->be_private;
+ int rc;
- be->be_private = on->on_bi.bi_private;
+ be->be_private = (void *)lc->lc_li;
rc = lback->bi_db_destroy( be );
- on->on_bi.bi_private = be->be_private;
+ lc->lc_li = be->be_private;
+ ch_free( lc );
+ on->on_bi.bi_private = NULL;
be->be_private = private;
return rc;
}
Connection *conn
)
{
- slap_overinst *on = (slap_overinst *) be->bd_info;
- void *private = be->be_private;
- int rc;
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
+ void *private = be->be_private;
+ int rc;
- be->be_private = on->on_bi.bi_private;
+ be->be_private = (void *)lc->lc_li;
rc = lback->bi_connection_destroy( be, conn );
- on->on_bi.bi_private = be->be_private;
be->be_private = private;
+
return rc;
}
ldapchain.on_bi.bi_type = "chain";
ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
-#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
-#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
li->url = ch_strdup( argv[ 1 ] );
#endif
- /* start tls */
- } else if ( strcasecmp( argv[0], "start-tls" ) == 0 ) {
- if ( argc != 1 ) {
- fprintf( stderr,
- "%s: line %d: start-tls takes no arguments\n",
- fname, lineno );
- return( 1 );
- }
- li->flags |= LDAP_BACK_F_TLS_CRITICAL;
+ } else if ( strncasecmp( argv[0], "tls-", STRLENOF( "tls-" ) ) == 0 ) {
+
+ /* start tls */
+ if ( strcasecmp( argv[0], "tls-start" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: tls-start takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->flags |= ( LDAP_BACK_F_USE_TLS | LDAP_BACK_F_TLS_CRITICAL );
- /* try start tls */
- } else if ( strcasecmp( argv[0], "try-start-tls" ) == 0 ) {
- if ( argc != 1 ) {
- fprintf( stderr,
- "%s: line %d: try-start-tls takes no arguments\n",
- fname, lineno );
- return( 1 );
+ /* try start tls */
+ } else if ( strcasecmp( argv[0], "tls-try-start" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: tls-try-start takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->flags &= ~LDAP_BACK_F_TLS_CRITICAL;
+ li->flags |= LDAP_BACK_F_USE_TLS;
+
+ /* propagate start tls */
+ } else if ( strcasecmp( argv[0], "tls-propagate" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: tls-propagate takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->flags |= ( LDAP_BACK_F_PROPAGATE_TLS | LDAP_BACK_F_TLS_CRITICAL );
+
+ /* try start tls */
+ } else if ( strcasecmp( argv[0], "tls-try-propagate" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: tls-try-propagate takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->flags &= ~LDAP_BACK_F_TLS_CRITICAL;
+ li->flags |= LDAP_BACK_F_PROPAGATE_TLS;
}
- li->flags &= ~LDAP_BACK_F_TLS_CRITICAL;
- li->flags |= LDAP_BACK_F_USE_TLS;
/* name to use for ldap_back_group */
} else if ( strcasecmp( argv[0], "acl-authcdn" ) == 0
li->idassert_flags |= LDAP_BACK_AUTH_NATIVE_AUTHZ;
} else {
- fprintf( stderr, "%s: line %s: "
+ fprintf( stderr, "%s: line %d: "
"unknown authz mode \"%s\"\n",
fname, lineno, val );
return 1;
int i;
char **attrs = NULL;
int dontfreetext = 0;
- int freeconn = 0;
int do_retry = 1;
LDAPControl **ctrls = NULL;
if ( rs->sr_err != LDAP_SUCCESS ) {
fail:;
- rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_SENDERR );
- if ( freeconn ) {
+ if ( rs->sr_err == LDAP_SERVER_DOWN ) {
+ if ( do_retry ) {
+ do_retry = 0;
+ if ( ldap_back_retry( lc, op, rs, LDAP_BACK_DONTSEND ) ) {
+ goto retry;
+ }
+ }
+ rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
ldap_back_freeconn( op, lc );
lc = NULL;
+ goto finish;
}
- goto finish;
}
/* We pull apart the ber result, stuff it into a slapd entry, and
/* check for abandon */
if ( op->o_abandon ) {
ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
- rc = 0;
+ rc = SLAPD_ABANDON;
goto finish;
}
rs->sr_ref = ch_calloc( cnt + 1, sizeof( struct berval ) );
for ( cnt = 0; references[ cnt ]; cnt++ ) {
- ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
+ ber_str2bv( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ] );
}
/* cleanup */
goto retry;
}
}
- /* FIXME: invalidate the connection? */
rs->sr_err = LDAP_SERVER_DOWN;
- freeconn = 1;
goto fail;
}
}
finish:;
- send_ldap_result( op, rs );
+ if ( rc != SLAPD_ABANDON ) {
+ send_ldap_result( op, rs );
+ }
(void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
/* check for abandon */
if ( op->o_abandon ) {
+ rs->sr_err = SLAPD_ABANDON;
goto return_results;
}
/* check for abandon */
if ( op->o_abandon ) {
+ rs->sr_err = SLAPD_ABANDON;
goto return_results;
}
/* check for abandon */
if ( op->o_abandon ) {
- rc = LDAP_SUCCESS;
+ rc = SLAPD_ABANDON;
goto done;
}
--- /dev/null
+# Makefile.in for back-ldif
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 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
+## <http://www.OpenLDAP.org/license.html>.
+
+SRCS = ldif.c
+OBJS = ldif.lo
+
+LDAP_INCDIR= ../../../include
+LDAP_LIBDIR= ../../../libraries
+
+BUILD_OPT = "--enable-ldif"
+BUILD_MOD = yes
+
+mod_DEFS = -DSLAPD_IMPORT
+MOD_DEFS = $(yes_DEFS)
+
+shared_LDAP_LIBS = $(LDAP_LIBLDAP_R_LA) $(LDAP_LIBLBER_LA)
+NT_LINK_LIBS = -L.. -lslapd $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
+UNIX_LINK_LIBS = $(@BUILD_LIBS_DYNAMIC@_LDAP_LIBS)
+
+LIBBASE = back_ldif
+
+XINCPATH = -I.. -I$(srcdir)/..
+XDEFS = $(MODULES_CPPFLAGS)
+
+all-local-lib: ../.backend
+
+../.backend: lib$(LIBBASE).a
+ @touch $@
+
--- /dev/null
+/* ldif.c - the ldif backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 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
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was originally developed by Eric Stokes for inclusion
+ * in OpenLDAP Software.
+ */
+
+#include "portable.h"
+#include <stdio.h>
+#include <ac/string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ac/dirent.h>
+#include <fcntl.h>
+#include <ac/errno.h>
+#include <ac/unistd.h>
+#include "slap.h"
+#include "lutil.h"
+
+struct ldif_info {
+ struct berval li_base_path;
+ ID tool_current;
+ Entry ** tool_entries;
+ int tool_put_entry_flag;
+ int tool_numentries;
+ ldap_pvt_thread_mutex_t li_mutex;
+};
+
+#define LDIF ".ldif"
+
+#define ENTRY_BUFF_INCREMENT 500
+
+static char *
+dn2path(struct berval * dn, struct berval * rootdn, struct berval * base_path)
+{
+ char *result = ch_malloc( dn->bv_len + base_path->bv_len + 2 +
+ STRLENOF( LDIF ));
+ char *ptr, *sep, *end;
+
+ ptr = lutil_strcopy( result, base_path->bv_val );
+ *ptr++ = LDAP_DIRSEP[0];
+ ptr = lutil_strcopy( ptr, rootdn->bv_val );
+ end = dn->bv_val + dn->bv_len - rootdn->bv_len - 1;
+ while ( end > dn->bv_val ) {
+ for (sep = end-1; sep >=dn->bv_val && !DN_SEPARATOR( *sep ); sep--);
+ *ptr++ = LDAP_DIRSEP[0];
+ ptr = lutil_strncopy( ptr, sep+1, end-sep-1 );
+ end = sep;
+ }
+ strcpy(ptr, LDIF);
+ return result;
+}
+
+static char * slurp_file(int fd) {
+ int entry_buf_size = 40 * ENTRY_BUFF_INCREMENT;
+ int read_chars_total = 0;
+ int read_chars = 0;
+ int entry_size = 40 * ENTRY_BUFF_INCREMENT;
+ char * entry = (char *) malloc(sizeof(char) * 40 * ENTRY_BUFF_INCREMENT);
+ char * entry_pos = entry;
+
+ while(1) {
+ if(entry_size - read_chars_total == 0) {
+ entry = (char *) realloc(entry, sizeof(char) * 2 * entry_size);
+ entry_size = 2 * entry_size;
+ }
+ read_chars = read(fd, (void *) entry_pos, entry_size - read_chars_total);
+ if(read_chars == -1) {
+ SLAP_FREE(entry);
+ return NULL;
+ }
+ entry_pos += read_chars;
+ if(read_chars == 0) {
+ if(entry_size - read_chars_total > 0)
+ entry[read_chars_total] = '\0';
+ else {
+ entry = (char *) realloc(entry, sizeof(char) * entry_size + 1);
+ entry_size = entry_size + 1;
+ entry[read_chars_total] = '\0';
+ }
+ break;
+ }
+ else {
+ read_chars_total += read_chars;
+ }
+ }
+ return entry;
+}
+
+static int spew_file(int fd, char * spew) {
+ int written = 0;
+ int writeres;
+ int len = strlen(spew);
+ char * spewptr = spew;
+
+ while(written < len) {
+ writeres = write(fd, spewptr, len - written);
+ if(writeres == -1) {
+ perror("could not spew write");
+ return -1;
+ }
+ else {
+ spewptr += writeres;
+ written += writeres;
+ }
+ }
+ return writeres;
+}
+
+static int spew_entry(Entry * e, char * path) {
+ int rs;
+ int openres;
+ int spew_res;
+ int entry_length;
+ char * entry_as_string;
+
+ openres = open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+ if(openres == -1) {
+ if(errno == ENOENT)
+ rs = LDAP_NO_SUCH_OBJECT;
+ else
+ rs = LDAP_UNWILLING_TO_PERFORM;
+ }
+ else {
+ entry_as_string = entry2str(e, &entry_length);
+ if(entry_as_string == NULL) {
+ rs = LDAP_UNWILLING_TO_PERFORM;
+ close(openres);
+ }
+ else {
+ spew_res = spew_file(openres, entry_as_string);
+ close(openres);
+ if(spew_res == -1)
+ rs = LDAP_UNWILLING_TO_PERFORM;
+ else
+ rs = LDAP_SUCCESS;
+ }
+ }
+ return rs;
+}
+
+static Entry * get_entry_for_fd(int fd) {
+ char * entry = (char *) slurp_file(fd);
+ Entry * ldentry = NULL;
+
+ /* error reading file */
+ if(entry == NULL) {
+ goto return_value;
+ }
+
+ ldentry = str2entry(entry);
+
+ return_value:
+ if(fd != -1) {
+ if(close(fd) != 0) {
+ /* log error */
+ }
+ }
+ if(entry != NULL)
+ SLAP_FREE(entry);
+ return ldentry;
+}
+
+static Entry * get_entry(struct berval * dn, struct berval * rootdn, struct berval * base_path) {
+ char * path = (char *) dn2path(dn, rootdn, base_path);
+ int fd = open(path, O_RDONLY);
+
+ /* error opening file (mebbe should log error) */
+ if(fd == -1) {
+ perror("failed to open file");
+ goto return_value;
+ }
+ goto return_value;
+
+ return_value:
+ if(path != NULL)
+ SLAP_FREE(path);
+ return get_entry_for_fd(fd);
+}
+
+/* takes a base path and a filename and opens that file */
+static int fd_for_path_components(char * base, char * name) {
+ char * absolutepath;
+ int fd;
+ absolutepath = (char *) SLAP_MALLOC(sizeof(char) *
+ (strlen(base) +
+ strlen(name) + 2));
+ absolutepath[0] = '\0';
+ strcat(absolutepath, base);
+ strcat(absolutepath, LDAP_DIRSEP);
+ strcat(absolutepath, name);
+ fd = open(absolutepath, O_RDONLY);
+ SLAP_FREE(absolutepath);
+ return fd;
+}
+
+static Entry ** r_enum_tree(Entry ** entries, int *elen, int *eind, char * path) {
+ DIR * dir_of_path = opendir(path);
+ int fd;
+ struct dirent * dir;
+ char * newpath;
+ Entry * e;
+
+ if(entries == NULL) {
+ entries = (Entry **) SLAP_MALLOC(sizeof(Entry *) * ENTRY_BUFF_INCREMENT);
+ *elen = ENTRY_BUFF_INCREMENT;
+ }
+ if(dir_of_path == NULL) {/* can't open directory */
+ perror("failed to open directory");
+ return entries;
+ }
+
+ while(1) {
+ dir = readdir(dir_of_path);
+ if(dir == NULL) break; /* end of the directory */
+ if(dir->d_type == DT_REG) { /* regular file, read the entry into memory */
+ if(! (*eind < *elen)) { /* grow entries if necessary */
+ entries = (Entry **) SLAP_REALLOC(entries, sizeof(Entry *) * (*elen) * 2);
+ *elen = *elen * 2;
+ }
+ fd = fd_for_path_components(path, dir->d_name);
+ if(fd != -1) {
+ e = get_entry_for_fd(fd);
+ if(e != NULL) {
+ entries[*eind] = e;
+ *eind = *eind + 1;
+ }
+ else
+ perror("failed to read entry");
+ }
+ else
+ perror("failed to open fd");
+ }
+ else if(dir->d_type == DT_DIR) {
+ if(! (strcasecmp(dir->d_name, ".") == 0 || strcasecmp(dir->d_name, "..") == 0)) {
+ newpath = (char *) SLAP_MALLOC(sizeof(char) *
+ (strlen(path) + strlen(dir->d_name) + 2));
+ newpath[0] = '\0';
+ strcat(newpath, path);
+ strcat(newpath, LDAP_DIRSEP);
+ strcat(newpath, dir->d_name);
+ entries = r_enum_tree(entries, elen, eind, newpath);
+ SLAP_FREE(newpath);
+ }
+ }
+ }
+ closedir(dir_of_path);
+ return entries;
+}
+
+static Entry ** enum_tree(struct berval * path, int * length) {
+ int index = 0;
+ return r_enum_tree(NULL, &index, length, path->bv_val);
+}
+
+static char * get_parent_path(char * dnpath) {
+ int dnpathlen = strlen(dnpath);
+ char * result;
+ int i;
+
+ for(i = dnpathlen;i>0;i--) /* find the first path seperator */
+ if(dnpath[i] == LDAP_DIRSEP[0])
+ break;
+ result = ch_malloc( i + 1 );
+ strncpy(result, dnpath, i);
+ result[i] = '\0';
+ return result;
+}
+
+static int apply_modify_to_entry(Entry * entry,
+ Modifications * modlist,
+ Operation * op,
+ SlapReply * rs)
+{
+ char textbuf[SLAP_TEXT_BUFLEN];
+ size_t textlen = sizeof textbuf;
+ int rc;
+ int tempdebug;
+ Modification *mods = NULL;
+ Attribute *save_attrs;
+
+ if (!acl_check_modlist(op, entry, modlist)) {
+ return LDAP_INSUFFICIENT_ACCESS;
+ }
+
+ /* save_attrs = entry->e_attrs; Why?
+ entry->e_attrs = attrs_dup(entry->e_attrs); */
+
+ for (; modlist != NULL; modlist = modlist->sml_next) {
+ mods = &modlist->sml_mod;
+
+ switch (mods->sm_op) {
+ case LDAP_MOD_ADD:
+ rc = modify_add_values(entry, mods,
+ get_permissiveModify(op),
+ &rs->sr_text, textbuf,
+ textlen);
+ break;
+
+ case LDAP_MOD_DELETE:
+ rc = modify_delete_values(entry, mods,
+ get_permissiveModify(op),
+ &rs->sr_text, textbuf,
+ textlen);
+
+ break;
+
+ case LDAP_MOD_REPLACE:
+ rc = modify_replace_values(entry, mods,
+ get_permissiveModify(op),
+ &rs->sr_text, textbuf,
+ textlen);
+
+ break;
+ case LDAP_MOD_INCREMENT:
+ break;
+ case SLAP_MOD_SOFTADD:
+ mods->sm_op = LDAP_MOD_ADD;
+ rc = modify_add_values(entry, mods,
+ get_permissiveModify(op),
+ &rs->sr_text, textbuf,
+ textlen);
+ mods->sm_op = SLAP_MOD_SOFTADD;
+ if (rc == LDAP_TYPE_OR_VALUE_EXISTS) {
+ rc = LDAP_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ if(rc != LDAP_SUCCESS) break;
+ }
+
+ if(rc == LDAP_SUCCESS) {
+ if ( mods->sm_desc == slap_schema.si_ad_objectClass ) {
+ entry->e_ocflags = 0;
+ }
+ /* check that the entry still obeys the schema */
+ rc = entry_schema_check(op->o_bd, entry,
+ save_attrs, &rs->sr_text,
+ textbuf, textlen);
+ }
+ return rc;
+}
+
+static int
+ldif_back_bind( Operation *op, SlapReply *rs )
+{
+ struct ldif_info *ni = NULL;
+ Attribute * a = NULL;
+ AttributeDescription *password = slap_schema.si_ad_userPassword;
+ int return_val = 0;
+ Entry * entry = NULL;
+
+ ni = (struct ldif_info *) op->o_bd->be_private;
+ ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ entry = (Entry *) get_entry(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path);
+
+ /* no object is found for them */
+ if(entry == NULL) {
+ if(be_isroot_pw(op)) {
+ return_val = LDAP_SUCCESS;
+ goto return_result;
+ }
+ else if(be_root_dn(op->o_bd)) {
+ return_val = LDAP_INVALID_CREDENTIALS;
+ rs->sr_err = LDAP_INVALID_CREDENTIALS;
+ goto return_result;
+ }
+ else {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ return_val = 1;
+ goto return_result;
+ }
+ }
+
+ /* they don't have userpassword */
+ if((a = attr_find(entry->e_attrs, password)) == NULL) {
+ rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
+ return_val = 1;
+ goto return_result;
+ }
+
+ /* authentication actually failed */
+ if(slap_passwd_check(op, entry, a, &op->oq_bind.rb_cred,
+ &rs->sr_text) != 0) {
+ rs->sr_err = LDAP_INVALID_CREDENTIALS;
+ return_val = 1;
+ goto return_result;
+ }
+
+ /* let the front-end send success */
+ return_val = 0;
+ goto return_result;
+
+ return_result:
+ ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ if(return_val != 0)
+ send_ldap_result( op, rs );
+ if(entry != NULL)
+ entry_free(entry);
+ return return_val;
+}
+
+static int ldif_back_search(Operation *op, SlapReply *rs)
+{
+ struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
+ int numentries = 0;
+ int i = 0;
+ Entry ** entries = NULL;
+
+ ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ entries = (Entry **) enum_tree(&ni->li_base_path, &numentries);
+
+ if(entries != NULL) {
+ for(i=0;i<numentries;i++) {
+ if(test_filter(op, entries[i], op->ors_filter) == LDAP_COMPARE_TRUE) {
+ rs->sr_entry = entries[i];
+ rs->sr_attrs = op->ors_attrs;
+ rs->sr_flags = REP_ENTRY_MODIFIABLE;
+ send_search_entry(op, rs);
+ }
+ entry_free(entries[i]);
+ }
+ SLAP_FREE(entries);
+ rs->sr_err = LDAP_SUCCESS;
+ ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ send_ldap_result(op, rs);
+ }
+ else {
+ rs->sr_err = LDAP_BUSY;
+ ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ send_ldap_result(op, rs);
+ }
+
+ return 0;
+}
+
+static int ldif_back_add(Operation *op, SlapReply *rs) {
+ struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
+ Entry * e = op->ora_e;
+ Attribute *save_attrs;
+ struct berval dn = e->e_nname;
+ char * leaf_path = NULL;
+ char * base = NULL;
+ char * base_ldif = NULL;
+ struct stat stats;
+ int statres;
+ char textbuf[SLAP_TEXT_BUFLEN];
+ size_t textlen = sizeof textbuf;
+
+ ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ ldap_pvt_thread_mutex_lock(&entry2str_mutex);
+
+ leaf_path = (char *) dn2path(&dn, &op->o_bd->be_nsuffix[0], &ni->li_base_path);
+
+ /* save_attrs = e->e_attrs; why?
+ e->e_attrs = attrs_dup(e->e_attrs);*/
+
+ if(leaf_path != NULL) {
+ char * tmp;
+ /* build path to container, and path to ldif of container */
+ base = (char *) get_parent_path(leaf_path);
+ base_ldif = (char *) SLAP_MALLOC(sizeof(char) * (strlen(base) + 6));
+ tmp = (char *) lutil_strcopy(base_ldif, base);
+ lutil_strcopy(tmp, LDIF);
+
+ rs->sr_err = entry_schema_check(op->o_bd, e,
+ save_attrs,
+ &rs->sr_text,
+ textbuf, textlen);
+ if(rs->sr_err == LDAP_SUCCESS) {
+ statres = stat(base, &stats); /* check if container exists */
+ if(statres == -1 && errno == ENOENT) { /* container missing */
+ statres = stat(base_ldif, &stats); /* check for leaf node */
+ if(statres == -1 && errno == ENOENT) {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
+ }
+ else if(statres != -1) { /* create parent */
+ int mkdirres = mkdir(base, 0750);
+ if(mkdirres == -1) {
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ }
+ }
+ else
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ }/* container was possibly created, move on to add the entry */
+ if(rs->sr_err == LDAP_SUCCESS) {
+ statres = stat(leaf_path, &stats);
+ if(statres == -1 && errno == ENOENT) {
+ rs->sr_err = (int) spew_entry(e, leaf_path);
+ }
+ else /* it already exists */
+ rs->sr_err = LDAP_ALREADY_EXISTS;
+ }
+ }
+ }
+
+ ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
+
+ send_ldap_result(op, rs);
+ if(leaf_path != NULL)
+ SLAP_FREE(leaf_path);
+ if(base != NULL)
+ SLAP_FREE(base);
+ if(base_ldif != NULL)
+ SLAP_FREE(base_ldif);
+ return 0;
+}
+
+static int ldif_back_modify(Operation *op, SlapReply *rs) {
+ struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
+ Modifications * modlst = op->orm_modlist;
+ char * path = NULL;
+ Entry * entry = NULL;
+ int spew_res;
+
+ ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ ldap_pvt_thread_mutex_lock(&entry2str_mutex);
+ path = (char *) dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path);
+ entry = (Entry *) get_entry(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path);
+
+ if(entry != NULL) {
+ rs->sr_err = apply_modify_to_entry(entry, modlst, op, rs);
+ if(rs->sr_err == LDAP_SUCCESS) {
+ spew_res = spew_entry(entry, path);
+ if(spew_res == -1) {
+ perror("could not output entry");
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ }
+ }
+ }
+ else {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ }
+
+ if(path != NULL)
+ SLAP_FREE(path);
+ if(entry != NULL)
+ entry_free(entry);
+ rs->sr_text = "";
+ ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
+ send_ldap_result(op, rs);
+ return 0;
+}
+
+static int ldif_back_delete(Operation *op, SlapReply *rs) {
+ struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
+ char * path = NULL;
+ int res = 0;
+
+ ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ path = (char *) dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path);
+ res = unlink(path);
+
+ if(res == -1) {
+ if(errno == ENOENT)
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ else
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ }
+ else
+ rs->sr_err = LDAP_SUCCESS;
+
+ SLAP_FREE(path);
+ ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ send_ldap_result(op, rs);
+ return 0;
+}
+
+static int is_leaf_node(char * path) {
+ DIR * nonleafnode;
+ int path_len = strlen(path);
+ char * nonleafpath = (char *) SLAP_MALLOC(sizeof(char) * path_len + 1);
+ int res;
+
+ strncpy(nonleafpath, path, path_len);
+ nonleafpath[path_len - 5] = '\0';
+ nonleafnode = opendir(nonleafpath);
+ if(nonleafnode == NULL) {
+ res = 1;
+ }
+ else {
+ closedir(nonleafnode);
+ res = 0;
+ }
+ SLAP_FREE(nonleafpath);
+ return res;
+}
+
+static int move_entry(Entry * entry, struct berval * ndn,
+ struct berval * newndn, struct berval * rootdn,
+ struct berval * base_path) {
+ int res;
+ int exists_res;
+ char * path = (char *) dn2path(ndn, rootdn, base_path);
+ char * newpath = (char *) dn2path(newndn, rootdn, base_path);
+ int path_len = strlen(path);
+
+ if((entry == NULL || path == NULL) || newpath == NULL) { /* some object doesn't exist */
+ res = LDAP_NO_SUCH_OBJECT;
+ }
+ else if(! is_leaf_node(path)) { /* entry is not a leaf node */
+ res = LDAP_NOT_ALLOWED_ON_NONLEAF;
+ }
+ else { /* do the modrdn */
+ exists_res = open(newpath, O_RDONLY);
+ if(exists_res == -1 && errno == ENOENT) {
+ res = spew_entry(entry, newpath);
+ if(res != -1) {
+ /* if this fails we should log something bad */
+ res = unlink(path);
+ res = LDAP_SUCCESS;
+ }
+ else {
+ if(errno == ENOENT)
+ res = LDAP_NO_SUCH_OBJECT;
+ else
+ res = LDAP_UNWILLING_TO_PERFORM;
+ unlink(newpath); /* in case file was created */
+ }
+ }
+ else if(exists_res) {
+ res = LDAP_ALREADY_EXISTS;
+ int close_res = close(exists_res);
+ if(close_res == -1) {
+ /* log heinous error */
+ }
+ }
+ else {
+ res = LDAP_UNWILLING_TO_PERFORM;
+ }
+ }
+
+ if(path != NULL)
+ SLAP_FREE(path);
+ if(newpath != NULL)
+ SLAP_FREE(newpath);
+ return res;
+}
+
+static int ldif_back_modrdn(Operation *op, SlapReply *rs) {
+ struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
+ struct berval new_dn = {0, NULL}, new_ndn = {0, NULL};
+ struct berval * new_parent_dn = NULL;
+ struct berval p_dn;
+ Entry * entry = NULL;
+ LDAPRDN new_rdn = NULL;
+ LDAPRDN old_rdn = NULL;
+ Modifications * mods = NULL;
+ int res;
+
+ ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ ldap_pvt_thread_mutex_lock(&entry2str_mutex);
+ entry = (Entry *) get_entry(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path);
+
+ /* build the mods to the entry */
+ if(entry != NULL) {
+ if(ldap_bv2rdn(&op->oq_modrdn.rs_newrdn, &new_rdn, (char **)&rs->sr_text,
+ LDAP_DN_FORMAT_LDAP)) {
+ rs->sr_err = LDAP_INVALID_DN_SYNTAX;
+ }
+ else if(op->oq_modrdn.rs_deleteoldrdn &&
+ ldap_bv2rdn(&op->o_req_dn, &old_rdn, (char **)&rs->sr_text,
+ LDAP_DN_FORMAT_LDAP)) {
+ rs->sr_err = LDAP_OTHER;
+ }
+ else { /* got both rdns successfully, ready to build mods */
+ if(slap_modrdn2mods(op, rs, entry, old_rdn, new_rdn, &mods) != LDAP_SUCCESS) {
+ rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+ }
+ else { /* built mods successfully */
+
+ /* build new dn, and new ndn for the entry */
+ if(op->oq_modrdn.rs_newSup != NULL) /* new superior */
+ p_dn = *op->oq_modrdn.rs_newSup;
+ else
+ p_dn = slap_empty_bv;
+ dnParent(&entry->e_name, &p_dn);
+ build_new_dn(&new_dn, &p_dn, &op->oq_modrdn.rs_newrdn, NULL);
+ struct berval bv = {0, NULL};
+ dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx );
+ ber_dupbv( &new_ndn, &bv );
+ entry->e_name = new_dn;
+ entry->e_nname = new_ndn;
+
+ /* perform the modifications */
+ res = apply_modify_to_entry(entry, mods, op, rs);
+ if(res == LDAP_SUCCESS) {
+ rs->sr_err = move_entry(entry, &op->o_req_ndn,
+ &new_ndn,
+ &op->o_bd->be_nsuffix[0],
+ &ni->li_base_path);
+ }
+ else
+ rs->sr_err = res;
+ }
+ }
+ }
+ else /* entry was null */
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+
+ if(entry != NULL)
+ entry_free(entry);
+ rs->sr_text = "";
+ ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
+ send_ldap_result(op, rs);
+ return 0;
+}
+
+static int ldif_back_compare(Operation *op, SlapReply *rs) {
+ struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
+ Entry * e = NULL;
+ Attribute *a;
+
+ ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+
+ e = (Entry *) get_entry(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path);
+ if(e != NULL) {
+ for(a = attrs_find( e->e_attrs, op->oq_compare.rs_ava->aa_desc );
+ a != NULL;
+ a = attrs_find( a->a_next, op->oq_compare.rs_ava->aa_desc ))
+ {
+ rs->sr_err = LDAP_COMPARE_FALSE;
+
+ if (value_find_ex(op->oq_compare.rs_ava->aa_desc,
+ SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
+ SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
+ a->a_nvals, &op->oq_compare.rs_ava->aa_value,
+ op->o_tmpmemctx ) == 0)
+ {
+ rs->sr_err = LDAP_COMPARE_TRUE;
+ break;
+ }
+ }
+ }
+ else {
+ rs->sr_err = LDAP_NO_SUCH_OBJECT;
+ }
+
+ if(e != NULL)
+ entry_free(e);
+ ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ send_ldap_result(op, rs);
+ return 0;
+}
+
+static int ldif_tool_entry_open(BackendDB * be, int mode) {
+ struct ldif_info *ni = (struct ldif_info *) be->be_private;
+ ni->tool_entries = NULL;
+ ni->tool_numentries = 0;
+ ni->tool_current = 0;
+ ni->tool_put_entry_flag = 0;
+ return 0;
+}
+
+static int ldif_tool_entry_close(BackendDB * be) {
+ struct ldif_info *ni = (struct ldif_info *) be->be_private;
+ int i;
+ /*if(ni->tool_entries != NULL) {
+ for(i=0;i<ni->tool_numentries;i++) {
+ SLAP_FREE(ni->tool_entries[i]);
+ }*/
+ SLAP_FREE(ni->tool_entries);
+ return 0;
+}
+
+static ID ldif_tool_entry_first(BackendDB *be) {
+ struct ldif_info *ni = (struct ldif_info *) be->be_private;
+ ID id = 1; /* first entry in the array of entries shifted by one */
+ ni->tool_current = 1;
+ if(ni->tool_entries == NULL || ni->tool_put_entry_flag) {
+ ni->tool_entries = (Entry **) enum_tree(&ni->li_base_path, &ni->tool_numentries);
+ ni->tool_put_entry_flag = 0;
+ }
+ return id;
+}
+
+static ID ldif_tool_entry_next(BackendDB *be) {
+ struct ldif_info *ni = (struct ldif_info *) be->be_private;
+ ni->tool_current += 1;
+ if(ni->tool_put_entry_flag) {
+ ni->tool_entries = (Entry **) enum_tree(&ni->li_base_path, &ni->tool_numentries);
+ ni->tool_put_entry_flag = 0;
+ }
+ if(ni->tool_current > ni->tool_numentries)
+ return NOID;
+ else
+ return ni->tool_current;
+}
+
+static Entry * ldif_tool_entry_get(BackendDB * be, ID id) {
+ struct ldif_info *ni = (struct ldif_info *) be->be_private;
+ Entry * e;
+
+ if(id > ni->tool_numentries || id < 1)
+ return NULL;
+ else {
+ e = ni->tool_entries[id - 1];
+ ni->tool_entries[id - 1] = NULL;
+ return e;
+ }
+}
+
+static ID ldif_tool_entry_put(BackendDB * be, Entry * e, struct berval *text) {
+ struct ldif_info *ni = (struct ldif_info *) be->be_private;
+ Attribute *save_attrs;
+ struct berval dn = e->e_nname;
+ char * leaf_path = NULL;
+ char * base = NULL;
+ char * base_ldif = NULL;
+ struct stat stats;
+ int statres;
+ char textbuf[SLAP_TEXT_BUFLEN];
+ size_t textlen = sizeof textbuf;
+ int res = LDAP_SUCCESS;
+
+ leaf_path = (char *) dn2path(&dn, &be->be_nsuffix[0], &ni->li_base_path);
+
+ /* save_attrs = e->e_attrs; why?
+ e->e_attrs = attrs_dup(e->e_attrs);*/
+
+ if(leaf_path != NULL) {
+ char * tmp;
+ /* build path to container, and path to ldif of container */
+ base = (char *) get_parent_path(leaf_path);
+ base_ldif = (char *) SLAP_MALLOC(sizeof(char) * (strlen(base) + 6));
+ tmp = (char *) lutil_strcopy(base_ldif, base);
+ lutil_strcopy(tmp, LDIF);
+
+ statres = stat(base, &stats); /* check if container exists */
+ if(statres == -1 && errno == ENOENT) { /* container missing */
+ statres = stat(base_ldif, &stats); /* check for leaf node */
+ if(statres == -1 && errno == ENOENT) {
+ res = LDAP_NO_SUCH_OBJECT; /* parent doesn't exist */
+ }
+ else if(statres != -1) { /* create parent */
+ int mkdirres = mkdir(base, 0750);
+ if(mkdirres == -1) {
+ res = LDAP_UNWILLING_TO_PERFORM;
+ }
+ }
+ else
+ res = LDAP_UNWILLING_TO_PERFORM;
+ }/* container was possibly created, move on to add the entry */
+ if(res == LDAP_SUCCESS) {
+ statres = stat(leaf_path, &stats);
+ if(statres == -1 && errno == ENOENT) {
+ res = (int) spew_entry(e, leaf_path);
+ }
+ else /* it already exists */
+ res = LDAP_ALREADY_EXISTS;
+ }
+ }
+
+ if(leaf_path != NULL)
+ SLAP_FREE(leaf_path);
+ if(base != NULL)
+ SLAP_FREE(base);
+ if(base_ldif != NULL)
+ SLAP_FREE(base_ldif);
+ if(res == LDAP_SUCCESS) {
+ ni->tool_put_entry_flag = 1;
+ return 1;
+ }
+ else
+ return NOID;
+}
+
+static int
+ldif_back_db_config(
+ BackendDB *be,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv )
+{
+ struct ldif_info *ni = (struct ldif_info *) be->be_private;
+
+ if ( strcasecmp( argv[0], "directory" ) == 0 ) {
+ if ( argc < 2 ) {
+ fprintf( stderr,
+ "%s: line %d: missing <path> in \"directory <path>\" line\n",
+ fname, lineno );
+ return 1;
+ }
+ ber_str2bv(argv[1], 0, 1, &ni->li_base_path);
+ } else {
+ return SLAP_CONF_UNKNOWN;
+ }
+ return 0;
+}
+
+
+static int
+ldif_back_db_init( BackendDB *be )
+{
+ struct ldif_info *ni;
+
+ ni = ch_calloc( 1, sizeof(struct ldif_info) );
+ be->be_private = ni;
+ ldap_pvt_thread_mutex_init(&ni->li_mutex);
+ return 0;
+}
+
+static int
+ldif_back_db_destroy(
+ Backend *be
+ )
+{
+ struct ldif_info *ni = be->be_private;
+ ldap_pvt_thread_mutex_destroy(&ni->li_mutex);
+ free( be->be_private );
+ return 0;
+}
+
+static int
+ldif_back_db_open(
+ Backend *be
+ )
+{
+ struct ldif_info *ni = (struct ldif_info *) be->be_private;
+ if( BER_BVISEMPTY(&ni->li_base_path)) {/* missing base path */
+ fprintf(stderr, "missing base path for back-ldif\n");
+ return 1;
+ }
+ return 0;
+}
+
+int
+ldif_back_initialize(
+ BackendInfo *bi
+ )
+{
+ bi->bi_open = 0;
+ bi->bi_close = 0;
+ bi->bi_config = 0;
+ bi->bi_destroy = 0;
+
+ bi->bi_db_init = ldif_back_db_init;
+ bi->bi_db_config = ldif_back_db_config;
+ bi->bi_db_open = ldif_back_db_open;
+ bi->bi_db_close = 0;
+ bi->bi_db_destroy = ldif_back_db_destroy;
+
+ bi->bi_op_bind = ldif_back_bind;
+ bi->bi_op_unbind = 0;
+ bi->bi_op_search = ldif_back_search;
+ bi->bi_op_compare = ldif_back_compare;
+ bi->bi_op_modify = ldif_back_modify;
+ bi->bi_op_modrdn = ldif_back_modrdn;
+ bi->bi_op_add = ldif_back_add;
+ bi->bi_op_delete = ldif_back_delete;
+ bi->bi_op_abandon = 0;
+
+ bi->bi_extended = 0;
+
+ bi->bi_chk_referrals = 0;
+
+ bi->bi_connection_init = 0;
+ bi->bi_connection_destroy = 0;
+
+ bi->bi_tool_entry_open = ldif_tool_entry_open;
+ bi->bi_tool_entry_close = ldif_tool_entry_close;
+ bi->bi_tool_entry_first = ldif_tool_entry_first;
+ bi->bi_tool_entry_next = ldif_tool_entry_next;
+ bi->bi_tool_entry_get = ldif_tool_entry_get;
+ bi->bi_tool_entry_put = ldif_tool_entry_put;
+ bi->bi_tool_entry_reindex = 0;
+ bi->bi_tool_sync = 0;
+
+ bi->bi_tool_dn2id_get = 0;
+ bi->bi_tool_id2entry_get = 0;
+ bi->bi_tool_entry_modify = 0;
+
+ return 0;
+}
* get the current connection
*/
lc = meta_back_getconn( op, rs, META_OP_REQUIRE_SINGLE,
- &op->o_req_ndn, &candidate );
- if ( !lc ) {
- send_ldap_result( op, rs );
+ &op->o_req_ndn, &candidate, LDAP_BACK_SENDERR );
+ if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) {
return rs->sr_err;
}
- if ( !meta_back_dobind( lc, op )
- || !meta_back_is_valid( lc, candidate ) ) {
+ if ( !meta_back_is_valid( lc, candidate ) ) {
rs->sr_err = LDAP_UNAVAILABLE;
send_ldap_result( op, rs );
return rs->sr_err;
ldap_pvt_thread_mutex_t conn_mutex;
Avlnode *conntree;
- int savecred;
+ unsigned flags;
+/* defined in <back-ldap/back-ldap.h>
+#define LDAP_BACK_F_NONE 0x00U
+#define LDAP_BACK_F_SAVECRED 0x01U
+#define LDAP_BACK_F_USE_TLS 0x02U
+#define LDAP_BACK_F_TLS_CRITICAL ( 0x04U | LDAP_BACK_F_USE_TLS )
+#define LDAP_BACK_F_CHASE_REFERRALS 0x8U
+*/
};
#define META_OP_ALLOW_MULTIPLE 0x00
SlapReply *rs,
int op_type,
struct berval *dn,
- int *candidate
+ int *candidate,
+ ldap_back_send_t sendok
);
extern int
meta_back_dobind(
struct metaconn *lc,
- Operation *op
+ Operation *op,
+ ldap_back_send_t sendok
);
extern int
op_type = META_OP_REQUIRE_ALL;
}
lc = meta_back_getconn( op, rs, op_type,
- &op->o_req_ndn, NULL );
+ &op->o_req_ndn, NULL, LDAP_BACK_SENDERR );
if ( !lc ) {
Debug( LDAP_DEBUG_ANY,
"meta_back_bind: no target for dn %s.\n%s%s",
lsc->msc_bound = META_BOUND;
lc->mc_bound_target = candidate;
- if ( li->savecred ) {
+ if ( LDAP_BACK_SAVECRED( li ) ) {
if ( !BER_BVISNULL( &lsc->msc_cred ) ) {
/* destroy sensitive data */
memset( lsc->msc_cred.bv_val, 0, lsc->msc_cred.bv_len );
* meta_back_dobind
*/
int
-meta_back_dobind( struct metaconn *lc, Operation *op )
+meta_back_dobind( struct metaconn *lc, Operation *op, ldap_back_send_t sendok )
{
struct metasingleconn *lsc;
int bound = 0, i;
BER_BVZERO( &lsc->msc_cred );
}
- /* FIXME: should be check if at least some of the op->o_ctrls
+ /* FIXME: should we check if at least some of the op->o_ctrls
* can/should be passed? */
rc = ldap_sasl_bind( lsc->msc_ld, "", LDAP_SASL_SIMPLE, &cred,
NULL, NULL, &msgid );
dncookie dc;
lc = meta_back_getconn( op, rs, META_OP_ALLOW_MULTIPLE,
- &op->o_req_ndn, NULL );
- if ( !lc ) {
- send_ldap_result( op, rs );
- return -1;
+ &op->o_req_ndn, NULL, LDAP_BACK_SENDERR );
+ if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) {
+ return rs->sr_err;
}
- if ( !meta_back_dobind( lc, op ) ) {
- rs->sr_err = LDAP_UNAVAILABLE;
- send_ldap_result( op, rs );
- return -1;
- }
-
msgid = ch_calloc( sizeof( int ), li->ntargets );
if ( msgid == NULL ) {
return -1;
fname, lineno );
return( 1 );
}
- li->savecred = 1;
+
+ li->flags |= LDAP_BACK_F_SAVECRED;
+
+ } else if ( strcasecmp( argv[0], "chase-referrals" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: \"chase-referrals\" takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+
+ li->flags |= LDAP_BACK_F_CHASE_REFERRALS;
+
+ } else if ( strcasecmp( argv[0], "dont-chase-referrals" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: \"dont-chase-referrals\" takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+
+ li->flags &= ~LDAP_BACK_F_CHASE_REFERRALS;
+
+ } else if ( strncasecmp( argv[0], "tls-", STRLENOF( "tls-" ) ) == 0 ) {
+
+ /* start tls */
+ if ( strcasecmp( argv[0], "tls-start" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: tls-start takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->flags |= ( LDAP_BACK_F_USE_TLS | LDAP_BACK_F_TLS_CRITICAL );
+
+ /* try start tls */
+ } else if ( strcasecmp( argv[0], "tls-try-start" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: tls-try-start takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->flags &= ~LDAP_BACK_F_TLS_CRITICAL;
+ li->flags |= LDAP_BACK_F_USE_TLS;
+
+ /* propagate start tls */
+ } else if ( strcasecmp( argv[0], "tls-propagate" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: tls-propagate takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->flags |= ( LDAP_BACK_F_PROPAGATE_TLS | LDAP_BACK_F_TLS_CRITICAL );
+
+ /* try start tls */
+ } else if ( strcasecmp( argv[0], "tls-try-propagate" ) == 0 ) {
+ if ( argc != 1 ) {
+ fprintf( stderr,
+ "%s: line %d: tls-try-propagate takes no arguments\n",
+ fname, lineno );
+ return( 1 );
+ }
+ li->flags &= ~LDAP_BACK_F_TLS_CRITICAL;
+ li->flags |= LDAP_BACK_F_PROPAGATE_TLS;
+ }
/* name to use as pseudo-root dn */
} else if ( strcasecmp( argv[ 0 ], "pseudorootdn" ) == 0 ) {
Operation *op,
SlapReply *rs,
struct metatarget *lt,
- struct metasingleconn *lsc
- )
+ struct metasingleconn *lsc,
+ ldap_back_send_t sendok )
{
struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
int vers;
*/
rs->sr_err = ldap_initialize( &lsc->msc_ld, lt->mt_uri );
if ( rs->sr_err != LDAP_SUCCESS ) {
- return slap_map_api2result( rs );
+ goto error_return;
}
/*
*/
vers = op->o_conn->c_protocol;
ldap_set_option( lsc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &vers );
- /* FIXME: configurable? */
- ldap_set_option( lsc->msc_ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
+
+ /* automatically chase referrals ("chase-referrals"/"dont-chase-referrals" statement) */
+ if ( LDAP_BACK_CHASE_REFERRALS( li ) ) {
+ ldap_set_option( lsc->msc_ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
+ }
+
+#ifdef HAVE_TLS
+ /* start TLS ("start-tls"/"try-start-tls" statements) */
+ if ( ( LDAP_BACK_USE_TLS( li ) || ( op->o_conn->c_is_tls && LDAP_BACK_PROPAGATE_TLS( li ) ) )
+ && !ldap_is_ldaps_url( lt->mt_uri ) )
+ {
+#if 1
+ /*
+ * use asynchronous StartTLS
+ * in case, chase referral (not implemented yet)
+ */
+ int msgid;
+
+ rs->sr_err = ldap_start_tls( lsc->msc_ld, NULL, NULL, &msgid );
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ LDAPMessage *res = NULL;
+ int rc, retries = 1;
+ struct timeval tv = { 0, 0 };
+
+retry:;
+ rc = ldap_result( lsc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
+ if ( rc < 0 ) {
+ rs->sr_err = LDAP_OTHER;
+
+ } else if ( rc == 0 ) {
+ if ( retries ) {
+ retries--;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ goto retry;
+ }
+ rs->sr_err = LDAP_OTHER;
+
+ } else if ( rc == LDAP_RES_EXTENDED ) {
+ struct berval *data = NULL;
+
+ rs->sr_err = ldap_parse_extended_result( lsc->msc_ld, res,
+ NULL, &data, 0 );
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ rs->sr_err = ldap_result2error( lsc->msc_ld, res, 1 );
+ res = NULL;
+
+ /* FIXME: in case a referral
+ * is returned, should we try
+ * using it instead of the
+ * configured URI? */
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ ldap_install_tls( lsc->msc_ld );
+
+ } else if ( rs->sr_err == LDAP_REFERRAL ) {
+ rs->sr_err = LDAP_OTHER;
+ rs->sr_text = "unwilling to chase referral returned by Start TLS exop";
+ }
+
+ if ( data ) {
+ if ( data->bv_val ) {
+ ber_memfree( data->bv_val );
+ }
+ ber_memfree( data );
+ }
+ }
+
+ } else {
+ rs->sr_err = LDAP_OTHER;
+ }
+
+ if ( res != NULL ) {
+ ldap_msgfree( res );
+ }
+ }
+#else
+ /*
+ * use synchronous StartTLS
+ */
+ rs->sr_err = ldap_start_tls_s( lsc->msc_ld, NULL, NULL );
+#endif
+
+ /* if StartTLS is requested, only attempt it if the URL
+ * is not "ldaps://"; this may occur not only in case
+ * of misconfiguration, but also when used in the chain
+ * overlay, where the "uri" can be parsed out of a referral */
+ if ( rs->sr_err == LDAP_SERVER_DOWN
+ || ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( li ) ) )
+ {
+ ldap_unbind_ext_s( lsc->msc_ld, NULL, NULL );
+ goto error_return;
+ }
+ }
+#endif /* HAVE_TLS */
/*
* Set the network timeout if set
/*
* If the connection DN is not null, an attempt to rewrite it is made
*/
- if ( op->o_conn->c_dn.bv_len != 0 ) {
+ if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
dc.rwmap = <->mt_rwmap;
dc.conn = op->o_conn;
dc.rs = rs;
if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn,
&lsc->msc_bound_ndn ) )
{
- send_ldap_result( op, rs );
- return rs->sr_err;
+ goto error_return;
}
/* copy the DN idf needed */
ber_dupbv( &lsc->msc_bound_ndn, &op->o_conn->c_dn );
}
- assert( lsc->msc_bound_ndn.bv_val );
+ assert( !BER_BVISNULL( &lsc->msc_bound_ndn ) );
} else {
ber_str2bv( "", 0, 1, &lsc->msc_bound_ndn );
lsc->msc_bound = META_UNBOUND;
- /*
- * The candidate is activated
- */
- lsc->msc_candidate = META_CANDIDATE;
- return LDAP_SUCCESS;
+error_return:;
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ rs->sr_err = slap_map_api2result( rs );
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ rs->sr_text = NULL;
+ }
+
+ } else {
+
+ /*
+ * The candidate is activated
+ */
+ lsc->msc_candidate = META_CANDIDATE;
+ }
+
+ return rs->sr_err;
}
/*
*/
struct metaconn *
meta_back_getconn(
- Operation *op,
- SlapReply *rs,
- int op_type,
- struct berval *ndn,
- int *candidate )
+ Operation *op,
+ SlapReply *rs,
+ int op_type,
+ struct berval *ndn,
+ int *candidate,
+ ldap_back_send_t sendok )
{
struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
struct metaconn *lc, lc_curr;
* also init'd
*/
int lerr = init_one_conn( op, rs, li->targets[ i ],
- &lc->mc_conns[ i ] );
+ &lc->mc_conns[ i ], sendok );
if ( lerr != LDAP_SUCCESS ) {
/*
* sends the appropriate result.
*/
err = init_one_conn( op, rs, li->targets[ i ],
- &lc->mc_conns[ i ] );
+ &lc->mc_conns[ i ], sendok );
if ( err != LDAP_SUCCESS ) {
/*
*/
int lerr = init_one_conn( op, rs,
li->targets[ i ],
- &lc->mc_conns[ i ] );
+ &lc->mc_conns[ i ], sendok );
if ( lerr != LDAP_SUCCESS ) {
/*
dncookie dc;
lc = meta_back_getconn( op, rs, META_OP_REQUIRE_SINGLE,
- &op->o_req_ndn, &candidate );
- if ( !lc ) {
- send_ldap_result( op, rs );
- return -1;
+ &op->o_req_ndn, &candidate, LDAP_BACK_SENDERR );
+ if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) {
+ return rs->sr_err;
}
-
- if ( !meta_back_dobind( lc, op ) ) {
- rs->sr_err = LDAP_UNAVAILABLE;
- } else if ( !meta_back_is_valid( lc, candidate ) ) {
+ if ( !meta_back_is_valid( lc, candidate ) ) {
rs->sr_err = LDAP_OTHER;
- }
-
- if ( rs->sr_err != LDAP_SUCCESS ) {
send_ldap_result( op, rs );
- return -1;
+ return rs->sr_err;
}
/*
dncookie dc;
lc = meta_back_getconn( op, rs, META_OP_REQUIRE_SINGLE,
- &op->o_req_ndn, &candidate );
- if ( !lc ) {
- rc = -1;
- goto cleanup;
+ &op->o_req_ndn, &candidate, LDAP_BACK_SENDERR );
+ if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) {
+ return rs->sr_err;
}
- if ( !meta_back_dobind( lc, op ) ) {
- rs->sr_err = LDAP_UNAVAILABLE;
-
- } else if ( !meta_back_is_valid( lc, candidate ) ) {
+ if ( !meta_back_is_valid( lc, candidate ) ) {
rs->sr_err = LDAP_OTHER;
- }
-
- if ( rs->sr_err != LDAP_SUCCESS ) {
- rc = -1;
- goto cleanup;
+ send_ldap_result( op, rs );
+ return rs->sr_err;
}
/*
dncookie dc;
lc = meta_back_getconn( op, rs, META_OP_REQUIRE_SINGLE,
- &op->o_req_ndn, &candidate );
+ &op->o_req_ndn, &candidate, LDAP_BACK_SENDERR );
if ( !lc ) {
- rc = -1;
- goto cleanup;
+ return rs->sr_err;
}
assert( candidate != META_TARGET_NONE );
- if ( !meta_back_dobind( lc, op ) ) {
- rs->sr_err = LDAP_UNAVAILABLE;
-
- } else if ( !meta_back_is_valid( lc, candidate ) ) {
- rs->sr_err = LDAP_OTHER;
+ if ( !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) {
+ return rs->sr_err;
}
-
- if ( rs->sr_err != LDAP_SUCCESS ) {
- rc = -1;
- goto cleanup;
+
+ if ( !meta_back_is_valid( lc, candidate ) ) {
+ rs->sr_err = LDAP_OTHER;
+ send_ldap_result( op, rs );
+ return rs->sr_err;
}
dc.conn = op->o_conn;
* to map attrs and maybe rewrite value
*/
lc = meta_back_getconn( op, rs, META_OP_ALLOW_MULTIPLE,
- &op->o_req_ndn, NULL );
- if ( !lc ) {
- send_ldap_result( op, rs );
- return -1;
- }
-
- if ( !meta_back_dobind( lc, op ) ) {
- rs->sr_err = LDAP_UNAVAILABLE;
- send_ldap_result( op, rs );
- return -1;
+ &op->o_req_ndn, NULL, LDAP_BACK_SENDERR );
+ if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) {
+ return rs->sr_err;
}
/*
if ( ab ) {
ldap_abandon_ext( lsc->msc_ld, msgid[ i ], NULL, NULL );
- rc = 0;
+ rc = SLAPD_ABANDON;
break;
}
#if defined(LDAP_SLAPI)
#include "slapi.h"
-static int monitor_back_add_plugin( Backend *be, Entry *e );
+static int monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e );
#endif /* defined(LDAP_SLAPI) */
#if defined(SLAPD_BDB)
}
#if defined(LDAP_SLAPI)
- monitor_back_add_plugin( be, e );
+ monitor_back_add_plugin( mi, be, e );
#endif /* defined(LDAP_SLAPI) */
if ( oi != NULL ) {
#if defined(LDAP_SLAPI)
static int
-monitor_back_add_plugin( Backend *be, Entry *e_database )
+monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e_database )
{
Slapi_PBlock *pCurrentPB;
int i, rc = LDAP_SUCCESS;
- monitor_info_t *mi = ( monitor_info_t * )be->be_private;
if ( slapi_int_pblock_get_first( be, &pCurrentPB ) != LDAP_SUCCESS ) {
/*
if ( op->o_abandon ) {
endpwent();
ldap_pvt_thread_mutex_unlock( &passwd_mutex );
- return( -1 );
+ return( SLAPD_ABANDON );
}
/* check time limit */
**bsi_id_listtail,
*bsi_c_eid;
int bsi_n_candidates;
- int bsi_abandon;
int bsi_status;
backsql_oc_map_rec *bsi_oc;
}
}
- bsi->bsi_abandon = 0;
bsi->bsi_id_list = NULL;
bsi->bsi_id_listtail = &bsi->bsi_id_list;
bsi->bsi_n_candidates = 0;
Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc=\"%s\"\n",
BACKSQL_OC_NAME( oc ), 0, 0 );
+ /* check for abandon */
+ if ( op->o_abandon ) {
+ bsi->bsi_status = SLAPD_ABANDON;
+ return BACKSQL_AVL_STOP;
+ }
+
if ( bsi->bsi_n_candidates == -1 ) {
Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
"unchecked limit has been overcome\n", 0, 0, 0 );
*/
avl_apply( bi->sql_oc_by_oc, backsql_oc_get_candidates,
&bsi, BACKSQL_AVL_STOP, AVL_INORDER );
+
+ /* check for abandon */
+ if ( op->o_abandon ) {
+ rs->sr_err = SLAPD_ABANDON;
+ goto send_results;
+ }
}
if ( op->ors_limit != NULL /* isroot == FALSE */
/* check for abandon */
if ( op->o_abandon ) {
- break;
+ rs->sr_err = SLAPD_ABANDON;
+ goto send_results;
}
/* check time limit */
rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
rs->sr_ctrls = NULL;
rs->sr_ref = rs->sr_v2ref;
- rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
- : LDAP_REFERRAL;
- send_ldap_result( op, rs );
- goto end_of_search;
+ goto send_results;
}
#ifdef BACKSQL_ARBITRARY_KEY
&& rs->sr_nentries >= op->ors_slimit )
{
rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
- send_ldap_result( op, rs );
- goto end_of_search;
+ goto send_results;
}
}
end_of_search:;
- entry_clean( &base_entry );
-
- /* in case we got here accidentally */
- entry_clean( &user_entry );
-
if ( rs->sr_nentries > 0 ) {
rs->sr_ref = rs->sr_v2ref;
rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
} else {
rs->sr_err = bsi.bsi_status;
}
- send_ldap_result( op, rs );
+
+send_results:;
+ if ( rs->sr_err != SLAPD_ABANDON ) {
+ send_ldap_result( op, rs );
+ }
+
+ entry_clean( &base_entry );
+
+ /* in case we got here accidentally */
+ entry_clean( &user_entry );
if ( rs->sr_v2ref ) {
ber_bvarray_free( rs->sr_v2ref );
}
Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 );
- return 0;
+
+ return rs->sr_err;
}
/* return LDAP_SUCCESS IFF we can retrieve the specified entry.
"NAME 'olcDatabaseConfig' "
"DESC 'OpenLDAP Database-specific options' "
"SUP olcConfig STRUCTURAL "
- "MAY ( olcDatabase $ olcAccess $ olcLastMod $ olcLimits $ "
+ "MAY ( olcDatabase $ olcLastMod $ olcLimits $ "
"olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ "
"olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ "
"olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSuffix $ olcSyncrepl $ "
oprev = ce;
}
}
-#if 0
/* Set up ACLs */
if ( bptr->be_acl ) {
Entry *ae;
}
opar->ce_kids = ce;
}
-#endif
}
return 0;
ber_dupbv( &dn, &be->be_rootdn );
ber_bvarray_add( &be->be_nsuffix, &dn );
- /* Hide from namingContexts */
- SLAP_BFLAGS(be) |= SLAP_BFLAG_CONFIG;
-
return 0;
}
refint.c \
rwm.c rwmconf.c rwmdn.c rwmmap.c \
syncprov.c \
+ translucent.c \
unique.c
OBJS = overlays.lo \
denyop.lo \
refint.lo \
rwm.lo rwmconf.lo rwmdn.lo rwmmap.lo \
syncprov.lo \
+ translucent.lo \
unique.lo
LDAP_INCDIR= ../../../include
syncprov.la : syncprov.lo $(@PLAT@_LINK_LIBS)
$(LTLINK_MOD) -module -o $@ syncprov.lo version.lo $(LINK_LIBS)
+translucent.la : translucent.lo $(@PLAT@_LINK_LIBS)
+ $(LTLINK_MOD) -module -o $@ translucent.lo version.lo $(LINK_LIBS)
+
unique.la : unique.lo $(@PLAT@_LINK_LIBS)
$(LTLINK_MOD) -module -o $@ unique.lo version.lo $(LINK_LIBS)
break;
}
- if ( !op->o_abandon ) {
+ 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;
#if SLAPD_OVER_SYNCPROV == SLAPD_MOD_STATIC
extern int syncprov_init();
#endif
+#if SLAPD_OVER_TRANSLUCENT == SLAPD_MOD_STATIC
+extern int translucent_init();
+#endif
#if SLAPD_OVER_UNIQUE == SLAPD_MOD_STATIC
extern int unique_init();
#endif
#if SLAPD_OVER_SYNCPROV == SLAPD_MOD_STATIC
{ "Syncrepl Provider", syncprov_init },
#endif
+#if SLAPD_OVER_TRANSLUCENT == SLAPD_MOD_STATIC
+ { "Translucent Proxy", translucent_init },
+#endif
#if SLAPD_OVER_UNIQUE == SLAPD_MOD_STATIC
{ "Attribute Uniqueness", unique_init },
#endif
}
}
- if ( (*ap)->a_desc->ad_type->sat_syntax
- == slap_schema.si_syn_distinguishedName )
+ if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
+ || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
{
/*
* FIXME: rewrite could fail; in this case
ad = mapping->m_dst_ad;
}
- if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
+ if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
+ || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
{
struct berval *mapped_valsp[2];
last--;
for ( j = 0; !BER_BVISNULL( &(*mlp)->sml_values[ j ] ); j++ ) {
- struct ldapmapping *mapping = NULL;
-
+ struct ldapmapping *oc_mapping = NULL;
+
( void )rwm_mapping( &rwmap->rwm_oc, &(*mlp)->sml_values[ j ],
- &mapping, RWM_MAP );
- if ( mapping == NULL ) {
+ &oc_mapping, RWM_MAP );
+ if ( oc_mapping == NULL ) {
if ( rwmap->rwm_at.drop_missing ) {
/* FIXME: we allow to remove objectClasses as well;
* if the resulting entry is inconsistent, that's
} else {
ch_free( (*mlp)->sml_values[ j ].bv_val );
- ber_dupbv( &(*mlp)->sml_values[ j ], &mapping->m_dst );
+ ber_dupbv( &(*mlp)->sml_values[ j ], &oc_mapping->m_dst );
}
}
} else {
- if ( (*mlp)->sml_desc->ad_type->sat_syntax ==
- slap_schema.si_syn_distinguishedName )
+ if ( (*mlp)->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
+ || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
{
#ifdef ENABLE_REWRITE
rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
free( ml );
}
- /* TODO: rewrite attribute types, values of DN-valued attributes ... */
return SLAP_CB_CONTINUE;
}
* about duplicate values?) */
isupdate = be_shadow_update( op );
for ( ap = a_first; *ap; ) {
- struct ldapmapping *mapping;
+ struct ldapmapping *mapping = NULL;
int drop_missing;
int last;
Attribute *a;
/* go on */ ;
} else {
+ if ( op->ors_attrs != NULL &&
+ !SLAP_USERATTRS( rs->sr_attr_flags ) &&
+ !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
+ {
+ goto cleanup_attr;
+ }
+
drop_missing = rwm_mapping( &rwmap->rwm_at,
&(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
if ( mapping != NULL ) {
(*ap)->a_desc = mapping->m_dst_ad;
}
-
- if ( op->ors_attrs != NULL &&
- !SLAP_USERATTRS( rs->sr_attr_flags ) &&
- !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
- {
- goto cleanup_attr;
- }
}
if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
* everything pass thru the ldap backend. */
/* FIXME: handle distinguishedName-like syntaxes, like
* nameAndOptionalUID */
- } else if ( (*ap)->a_desc->ad_type->sat_syntax ==
- slap_schema.si_syn_distinguishedName )
+ } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
+ || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
{
#ifdef ENABLE_REWRITE
dc.ctx = "searchAttrDN";
switch( op->o_tag ) {
case LDAP_REQ_SEARCH:
/* Note: the operation attrs are remapped */
- if ( op->ors_attrs != NULL && op->ors_attrs != rs->sr_attrs )
+ if ( rs->sr_type == REP_RESULT
+ && op->ors_attrs != NULL
+ && op->ors_attrs != rs->sr_attrs )
{
ch_free( op->ors_attrs );
op->ors_attrs = rs->sr_attrs;
if ( value != NULL ) {
assert( mapped_value != NULL );
- if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
+ if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
+ || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
{
dncookie fdc = *dc;
int rc;
return 0;
}
+static int
+syncprov_ab_cleanup( Operation *op, SlapReply *rs )
+{
+ slap_callback *sc = op->o_callback;
+ op->o_callback = sc->sc_next;
+ syncprov_drop_psearch( op->o_callback->sc_private, 0 );
+ op->o_tmpfree( sc, op->o_tmpmemctx );
+ return 0;
+}
+
static int
syncprov_op_abandon( Operation *op, SlapReply *rs )
{
if ( so ) {
/* Is this really a Cancel exop? */
if ( op->o_tag != LDAP_REQ_ABANDON ) {
+ so->s_op->o_cancel = SLAP_CANCEL_ACK;
rs->sr_err = LDAP_CANCELLED;
send_ldap_result( so->s_op, rs );
+ if ( so->s_flags & PS_IS_DETACHED ) {
+ slap_callback *cb;
+ cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
+ cb->sc_cleanup = syncprov_ab_cleanup;
+ cb->sc_next = op->o_callback;
+ cb->sc_private = so;
+ return SLAP_CB_CONTINUE;
+ }
}
syncprov_drop_psearch( so, 0 );
}
ldap_pvt_thread_mutex_unlock( &mt->mt_mutex );
ldap_pvt_thread_yield();
ldap_pvt_thread_mutex_lock( &mt->mt_mutex );
+
+ /* clean up if the caller is giving up */
+ if ( op->o_abandon ) {
+ modinst *m2;
+ for ( m2 = mt->mt_mods; m2->mi_next != mi;
+ m2 = m2->mi_next );
+ m2->mi_next = mi->mi_next;
+ if ( mt->mt_tail == mi ) mt->mt_tail = m2;
+ op->o_tmpfree( cb, op->o_tmpmemctx );
+ ldap_pvt_thread_mutex_unlock( &mt->mt_mutex );
+ return SLAPD_ABANDON;
+ }
}
ldap_pvt_thread_mutex_unlock( &mt->mt_mutex );
} else {
--- /dev/null
+/* Copyright 2004, Symas Corporation.
+ * All Rights Reserved.
+ */
+
+#include "portable.h"
+
+#ifdef SLAPD_OVER_TRANSLUCENT
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "slap.h"
+
+/* config block */
+
+typedef struct translucent_configuration {
+ int debug;
+ int strict;
+ int no_add;
+ int glue;
+} translucent_configuration;
+
+/* stack of captive backends */
+
+typedef struct overlay_stack {
+ BackendInfo *info; /* captive backend */
+ void *private; /* local backend_private */
+ translucent_configuration *config; /* our_private: configuration */
+} overlay_stack;
+
+/* for translucent_init() */
+
+static slap_overinst translucent;
+
+/*
+** glue_parent()
+** call syncrepl_add_glue() with the parent suffix;
+**
+*/
+
+static struct berval glue[] = { BER_BVC("top"), BER_BVC("glue"), BER_BVNULL };
+
+void glue_parent(Operation *op) {
+ Operation nop = *op;
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ struct berval dn = { 0, NULL };
+ char *odn = op->o_req_ndn.bv_val;
+ Attribute *a;
+ Entry *e;
+ int idn, ldn;
+
+ /* tis more work to use strchr() for a berval... */
+ for(idn = 0; odn[idn] && odn[idn] != ','; idn++);
+ if(!idn || !odn[idn]) return; /* because you never know */
+ idn++;
+ ldn = dn.bv_len = op->o_req_ndn.bv_len - idn;
+ dn.bv_val = ch_malloc(ldn + 1);
+ strcpy(dn.bv_val, odn + idn);
+
+ Debug(LDAP_DEBUG_TRACE, "=> glue_parent: fabricating glue for <%s>\n", dn.bv_val, 0, 0);
+
+ e = ch_calloc(1, sizeof(Entry));
+ e->e_id = NOID;
+ ber_dupbv(&e->e_name, &dn);
+ ber_dupbv(&e->e_nname, &dn);
+
+ a = ch_calloc(1, sizeof(Attribute));
+ a->a_desc = slap_schema.si_ad_objectClass;
+ a->a_vals = ch_malloc(sizeof(struct berval) * 3);
+ ber_dupbv(&a->a_vals[0], &glue[0]);
+ ber_dupbv(&a->a_vals[1], &glue[1]);
+ ber_dupbv(&a->a_vals[2], &glue[2]);
+ a->a_nvals = a->a_vals;
+ a->a_next = e->e_attrs;
+ e->e_attrs = a;
+
+ a = ch_calloc(1, sizeof(Attribute));
+ a->a_desc = slap_schema.si_ad_structuralObjectClass;
+ a->a_vals = ch_malloc(sizeof(struct berval) * 2);
+ ber_dupbv(&a->a_vals[0], &glue[1]);
+ ber_dupbv(&a->a_vals[1], &glue[2]);
+ a->a_nvals = a->a_vals;
+ a->a_next = e->e_attrs;
+ e->e_attrs = a;
+
+ nop.o_req_dn = dn;
+ nop.o_req_ndn = dn;
+ nop.ora_e = e;
+ nop.o_bd->bd_info = (BackendInfo *) on->on_info->oi_orig;
+
+ syncrepl_add_glue(&nop, e);
+ return;
+}
+
+/*
+** dup_bervarray()
+** copy a BerVarray;
+*/
+
+BerVarray dup_bervarray(BerVarray b) {
+ int i, len;
+ BerVarray nb;
+ for(len = 0; b[len].bv_val; len++);
+ nb = ch_malloc((len+1) * sizeof(BerValue));
+ for(i = 0; i < len; i++) ber_dupbv(&nb[i], &b[i]);
+ nb[len].bv_val = NULL;
+ nb[len].bv_len = 0;
+ return(nb);
+}
+
+/*
+** free_attr_chain()
+** free only the Attribute*, not the contents;
+**
+*/
+void free_attr_chain(Attribute *a) {
+ Attribute *ax;
+ for(ax = NULL; a; a = a->a_next) {
+ if(ax) ch_free(ax);
+ ax = a;
+ }
+ return;
+}
+
+/*
+** translucent_add()
+** if not bound as root, send ACCESS error;
+** if config.glue, glue_parent();
+** return CONTINUE;
+**
+*/
+
+static int translucent_add(Operation *op, SlapReply *rs) {
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ overlay_stack *ov = on->on_bi.bi_private;
+ Debug(LDAP_DEBUG_TRACE, "==> translucent_add: %s\n",
+ op->o_req_dn.bv_val, 0, 0);
+ if(!be_isroot(op)) {
+ op->o_bd->bd_info = (BackendInfo *) on->on_info;
+ send_ldap_error(op, rs, LDAP_INSUFFICIENT_ACCESS,
+ "user modification of overlay database not permitted");
+ return(rs->sr_err);
+ }
+ if(!ov->config->glue) glue_parent(op);
+ return(SLAP_CB_CONTINUE);
+}
+
+/*
+** translucent_modrdn()
+** if not bound as root, send ACCESS error;
+** if !config.glue, glue_parent();
+** else return CONTINUE;
+**
+*/
+
+static int translucent_modrdn(Operation *op, SlapReply *rs) {
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ overlay_stack *ov = on->on_bi.bi_private;
+ Debug(LDAP_DEBUG_TRACE, "==> translucent_modrdn: %s -> %s\n",
+ op->o_req_dn.bv_val, op->orr_newrdn.bv_val, 0);
+ if(!be_isroot(op)) {
+ op->o_bd->bd_info = (BackendInfo *) on->on_info;
+ send_ldap_error(op, rs, LDAP_INSUFFICIENT_ACCESS,
+ "user modification of overlay database not permitted");
+ return(rs->sr_err);
+ }
+ if(!ov->config->glue) glue_parent(op);
+ return(SLAP_CB_CONTINUE);
+}
+
+/*
+** translucent_delete()
+** if not bound as root, send ACCESS error;
+** else return CONTINUE;
+**
+*/
+
+static int translucent_delete(Operation *op, SlapReply *rs) {
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ Debug(LDAP_DEBUG_TRACE, "==> translucent_delete: %s\n",
+ op->o_req_dn.bv_val, 0, 0);
+ if(!be_isroot(op)) {
+ op->o_bd->bd_info = (BackendInfo *) on->on_info;
+ send_ldap_error(op, rs, LDAP_INSUFFICIENT_ACCESS,
+ "user modification of overlay database not permitted");
+ return(rs->sr_err);
+ }
+ return(SLAP_CB_CONTINUE);
+}
+
+/*
+** translucent_modify()
+** modify in local backend if exists in both;
+** otherwise, add to local backend;
+** fail if not defined in captive backend;
+**
+*/
+
+static int translucent_modify(Operation *op, SlapReply *rs) {
+ SlapReply nrs = { REP_RESULT };
+ Operation nop = *op;
+
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ overlay_stack *ov = on->on_bi.bi_private;
+ translucent_configuration *cf = ov->config;
+ void *private = op->o_bd->be_private;
+ Entry ne, *e, *re = NULL;
+ Attribute *a, *ax;
+ Modifications *m, *mm;
+ int del, rc, erc = 0;
+
+ Debug(LDAP_DEBUG_TRACE, "==> translucent_modify: %s\n",
+ op->o_req_dn.bv_val, 0, 0);
+
+/*
+** fetch entry from the captive backend;
+** if it did not exist, fail;
+** release it, if captive backend supports this;
+**
+*/
+
+ op->o_bd->bd_info = (BackendInfo *) on->on_info;
+ op->o_bd->be_private = ov->private;
+ rc = ov->info->bi_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &re);
+ op->o_bd->be_private = private;
+
+ /* if(ov->config->no_add && (!re || rc != LDAP_SUCCESS)) */
+ if(!re || rc != LDAP_SUCCESS) {
+ send_ldap_error(op, rs, LDAP_NO_SUCH_OBJECT,
+ "attempt to modify nonexistent local record");
+ return(rs->sr_err);
+ }
+
+/*
+** fetch entry from local backend;
+** if it exists:
+** foreach Modification:
+** if attr not present in local:
+** if Mod == LDAP_MOD_DELETE:
+** if remote attr not present, return NO_SUCH;
+** if remote attr present, drop this Mod;
+** else force this Mod to LDAP_MOD_ADD;
+** return CONTINUE;
+**
+*/
+
+ rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &e);
+
+ if(e && rc == LDAP_SUCCESS) {
+ Debug(LDAP_DEBUG_TRACE, "=> translucent_modify: found local entry\n", 0, 0, 0);
+ for(m = op->orm_modlist; m; m = m->sml_next) {
+ for(a = e->e_attrs; a; a = a->a_next)
+ if(a->a_desc == m->sml_desc) break;
+ if(a) continue; /* found local attr */
+ if(m->sml_op == LDAP_MOD_DELETE) {
+ for(a = re->e_attrs; a; a = a->a_next)
+ if(a->a_desc == m->sml_desc) break;
+ /* not found remote attr */
+ if(!a) {
+ erc = LDAP_NO_SUCH_ATTRIBUTE;
+ goto release;
+ }
+ if(ov->config->strict) {
+ erc = LDAP_CONSTRAINT_VIOLATION;
+ goto release;
+ }
+ Debug(LDAP_DEBUG_TRACE,
+ "=> translucent_modify: silently dropping delete: %s\n",
+ m->sml_desc->ad_cname.bv_val, 0, 0);
+ for(mm = op->orm_modlist; mm->sml_next != m; mm = mm->sml_next);
+ mm->sml_next = m->sml_next;
+ mm = m;
+ m = m->sml_next;
+ mm->sml_next = NULL; /* hack */
+ slap_mods_free(mm);
+ if(m) continue;
+ }
+ m->sml_op = LDAP_MOD_ADD;
+ }
+ erc = SLAP_CB_CONTINUE;
+release:
+ if(re) {
+ op->o_bd->be_private = ov->private;
+ if(ov->info->bi_entry_release_rw)
+ ov->info->bi_entry_release_rw(op, re, 0);
+ else
+ entry_free(re);
+ op->o_bd->be_private = private;
+ }
+ be_entry_release_r(op, e);
+ if(erc == SLAP_CB_CONTINUE) {
+ op->o_bd->bd_info = (BackendInfo *) on;
+ return(erc);
+ } else if(erc) {
+ send_ldap_error(op, rs, erc,
+ "attempt to delete nonexistent attribute");
+ return(erc);
+ }
+ }
+
+/*
+** foreach Modification:
+** if MOD_ADD or MOD_REPLACE, add Attribute;
+** if no Modifications were suitable:
+** if config.strict, throw CONSTRAINT_VIOLATION;
+** else, return early SUCCESS;
+** fabricate Entry with new Attribute chain;
+** glue_parent() for this Entry;
+** call bi_op_add() in local backend;
+**
+*/
+
+ Debug(LDAP_DEBUG_TRACE, "=> translucent_modify: fabricating local add\n", 0, 0, 0);
+ a = NULL;
+ for(del = 0, ax = NULL, m = op->orm_modlist; m; m = m->sml_next) {
+ if(((m->sml_op & LDAP_MOD_OP) != LDAP_MOD_ADD) &&
+ ((m->sml_op & LDAP_MOD_OP) != LDAP_MOD_REPLACE)) {
+ Debug(LDAP_DEBUG_ANY,
+ "=> translucent_modify: silently dropped modification(%d): %s\n",
+ m->sml_op, m->sml_desc->ad_cname.bv_val, 0);
+ if((m->sml_op & LDAP_MOD_OP) == LDAP_MOD_DELETE) del++;
+ continue;
+ }
+ a = ch_calloc(1, sizeof(Attribute));
+ a->a_desc = m->sml_desc;
+ a->a_vals = m->sml_values;
+ a->a_nvals = m->sml_nvalues;
+ a->a_next = ax;
+ ax = a;
+ }
+
+ if(del && ov->config->strict) {
+ free_attr_chain(a);
+ send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION,
+ "attempt to delete attributes from local database");
+ return(rs->sr_err);
+ }
+
+ if(!ax) {
+ if(ov->config->strict) {
+ send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION,
+ "modification contained other than ADD or REPLACE");
+ return(rs->sr_err);
+ }
+ op->o_bd->bd_info = (BackendInfo *) on;
+ /* rs->sr_text = "no valid modification found"; */
+ rs->sr_err = LDAP_SUCCESS;
+ send_ldap_result(op, rs);
+ return(rs->sr_err);
+ }
+
+ ne.e_id = NOID;
+ ne.e_name = op->o_req_dn;
+ ne.e_nname = op->o_req_ndn;
+ ne.e_attrs = a;
+ ne.e_ocflags = 0;
+ ne.e_bv.bv_len = 0;
+ ne.e_bv.bv_val = NULL;
+ ne.e_private = NULL;
+
+ nop.o_tag = LDAP_REQ_ADD;
+ nop.oq_add.rs_e = ≠
+
+ op->o_bd->bd_info = (BackendInfo *) on;
+ glue_parent(&nop);
+
+ rc = on->on_info->oi_orig->bi_op_add(&nop, &nrs);
+ free_attr_chain(a);
+
+ return(rc);
+}
+
+static int translucent_compare(Operation *op, SlapReply *rs) {
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ overlay_stack *ov = on->on_bi.bi_private;
+ void *private = op->o_bd->be_private;
+ translucent_configuration *cf = ov->config;
+
+ AttributeAssertion *ava = op->orc_ava;
+ Attribute *a, *an, *ra, *as = NULL;
+ Entry *e, *ee, *re;
+ int rc;
+
+ Debug(LDAP_DEBUG_TRACE, "==> translucent_compare: <%s> %s:%s\n",
+ op->o_req_dn.bv_val, ava->aa_desc->ad_cname.bv_val, ava->aa_value.bv_val);
+
+/*
+** if the local backend has an entry for this attribute:
+** CONTINUE and let it do the compare;
+**
+*/
+
+ op->o_bd->bd_info = (BackendInfo *) on->on_info;
+ rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, ava->aa_desc, 0, &e);
+ if(e && rc == LDAP_SUCCESS) {
+ be_entry_release_r(op, e);
+ op->o_bd->bd_info = (BackendInfo *) on;
+ return(SLAP_CB_CONTINUE);
+ }
+
+/*
+** call compare() in the captive backend;
+** return the result;
+**
+*/
+
+ op->o_bd->be_private = ov->private;
+ rc = ov->info->bi_op_compare(op, rs);
+ op->o_bd->be_private = private;
+ op->o_bd->bd_info = (BackendInfo *) on;
+ return(rc);
+}
+
+/*
+** translucent_search_cb()
+** merge local data with the search result
+**
+*/
+
+static int translucent_search_cb(Operation *op, SlapReply *rs) {
+ slap_overinst *on;
+ Entry *e, *re = NULL;
+ Attribute *a, *ax, *an, *as = NULL;
+ BerVarray b, bx;
+ void *private;
+ int i, rc, size;
+
+ if(!op || !rs || rs->sr_type != REP_SEARCH || !rs->sr_entry)
+ return(SLAP_CB_CONTINUE);
+
+ Debug(LDAP_DEBUG_TRACE, "==> tranclucent_search_cb: %s\n",
+ rs->sr_entry->e_name.bv_val, 0, 0);
+
+ on = (slap_overinst *) op->o_bd->bd_info;
+ op->o_bd->bd_info = (BackendInfo *) on->on_info;
+
+ private = op->o_bd->be_private;
+ op->o_bd->be_private = op->o_callback->sc_private;
+
+ rc = be_entry_get_rw(op, &rs->sr_entry->e_nname, NULL, NULL, 0, &e);
+
+/*
+** if we got an entry from local backend:
+** make a copy of this search result;
+** foreach local attr:
+** foreach search result attr:
+** if match, result attr with local attr;
+** if new local, add to list;
+** append new local attrs to search result;
+**
+*/
+
+ if(e && rc == LDAP_SUCCESS) {
+ re = entry_dup(rs->sr_entry);
+ for(ax = e->e_attrs; ax; ax = ax->a_next) {
+#if 0
+ if(is_at_operational(ax->a_desc->ad_type)) continue;
+#endif
+ for(a = re->e_attrs; a; a = a->a_next) {
+ if(a->a_desc == ax->a_desc) {
+ if(a->a_vals != a->a_nvals)
+ ber_bvarray_free(a->a_nvals);
+ ber_bvarray_free(a->a_vals);
+ a->a_vals = dup_bervarray(ax->a_vals);
+ a->a_nvals = (ax->a_vals == ax->a_nvals) ?
+ a->a_vals : dup_bervarray(ax->a_nvals);
+ break;
+ }
+ }
+ if(a) continue;
+ an = attr_dup(ax);
+ an->a_next = as;
+ as = an;
+ }
+ be_entry_release_r(op, e);
+
+ /* literally append, so locals are always last */
+ if(as) {
+ if(re->e_attrs) {
+ for(ax = re->e_attrs; ax->a_next; ax = ax->a_next);
+ ax->a_next = as;
+ } else {
+ re->e_attrs = as;
+ }
+ }
+ rs->sr_entry = re;
+ rs->sr_flags |= REP_ENTRY_MUSTBEFREED;
+ }
+
+ op->o_bd->be_private = private;
+ op->o_bd->bd_info = (BackendInfo *) on;
+
+ return(SLAP_CB_CONTINUE);
+}
+
+/*
+** translucent_search()
+** search via captive backend;
+** override results with any local data;
+**
+*/
+
+static int translucent_search(Operation *op, SlapReply *rs) {
+ Operation nop = *op;
+
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ slap_callback cb = { NULL, NULL, NULL, NULL };
+ overlay_stack *ov = on->on_bi.bi_private;
+ translucent_configuration *cf = ov->config;
+ void *private = op->o_bd->be_private;
+ int rc;
+
+ Debug(LDAP_DEBUG_TRACE, "==> translucent_search: <%s> %s\n",
+ op->o_req_dn.bv_val, op->ors_filterstr.bv_val, 0);
+ cb.sc_response = (slap_response *) translucent_search_cb;
+ cb.sc_private = private;
+
+ cb.sc_next = nop.o_callback;
+ nop.o_callback = &cb;
+
+ op->o_bd->be_private = ov->private;
+ rc = ov->info->bi_op_search(&nop, rs);
+ op->o_bd->be_private = private;
+
+ return(rs->sr_err);
+}
+
+
+/*
+** translucent_bind()
+** pass bind request to captive backend;
+**
+*/
+
+static int translucent_bind(Operation *op, SlapReply *rs) {
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ overlay_stack *ov = on->on_bi.bi_private;
+ void *private = op->o_bd->be_private;
+ int rc = 0;
+
+ Debug(LDAP_DEBUG_TRACE, "translucent_bind: <%s> method %d\n",
+ op->o_req_dn.bv_val, op->orb_method, 0);
+
+ op->o_bd->be_private = ov->private;
+ rc = ov->info->bi_op_bind(op, rs);
+ op->o_bd->be_private = private;
+
+ return(rc);
+}
+
+/*
+** translucent_config()
+** pass config directives to captive backend;
+** parse unrecognized directives ourselves;
+**
+*/
+
+static int translucent_config(
+ BackendDB *be,
+ const char *fname,
+ int lineno,
+ int argc,
+ char **argv
+)
+{
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ overlay_stack *ov = on->on_bi.bi_private;
+ void *private = be->be_private;
+ int rc;
+
+ /* "this should never happen" */
+ if(!ov->info) {
+ fprintf(stderr, "fatal: captive backend not initialized");
+ return(1);
+ }
+
+ be->be_private = ov->private;
+ rc = ov->info->bi_db_config ? ov->info->bi_db_config(be, fname, lineno, argc, argv) : 0;
+ be->be_private = private;
+
+ /* pass okay or error up, SLAP_CONF_UNKNOWN might be ours */
+ if(rc == 0 || rc == 1) return(rc);
+
+ rc = 0;
+ if(!strcasecmp(*argv, "translucent_strict")) {
+ ov->config->strict++;
+ } else if(!strcasecmp(*argv, "translucent_no_add")) {
+ ov->config->no_add++;
+ } else if(!strcasecmp(*argv, "translucent_no_glue")) {
+ ov->config->glue++;
+ } else if(!strcasecmp(*argv, "translucent_debug")) {
+ if(argc == 1) {
+ ov->config->debug = 0xFFFF;
+ rc = 0;
+ } else if(argc == 2) {
+ ov->config->debug = atoi(argv[1]);
+ rc = 0;
+ } else {
+ fprintf(stderr, "%s: line %d: too many arguments (%d) to debug\n",
+ fname, lineno, argc);
+ rc = 1;
+ }
+ } else {
+ fprintf(stderr, "%s: line %d: unknown keyword %s\n",
+ fname, lineno, *argv);
+ rc = SLAP_CONF_UNKNOWN;
+ }
+ return(rc);
+}
+
+/*
+** translucent_db_init()
+** initialize the captive backend;
+**
+*/
+
+static int translucent_db_init(BackendDB *be) {
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ void *private = be->be_private;
+ overlay_stack *ov;
+ int rc;
+
+ Debug(LDAP_DEBUG_TRACE, "==> translucent_init\n", 0, 0, 0);
+
+ ov = ch_calloc(1, sizeof(overlay_stack));
+ ov->config = ch_calloc(1, sizeof(translucent_configuration));
+ ov->info = backend_info("ldap");
+
+ if(!ov->info) {
+ Debug(LDAP_DEBUG_ANY, "translucent: backend_info failed!\n", 0, 0, 0);
+ return(1);
+ }
+
+ /* forcibly disable schema checking on the local backend */
+ SLAP_DBFLAGS(be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
+
+ be->be_private = NULL;
+ rc = ov->info->bi_db_init ? ov->info->bi_db_init(be) : 0;
+
+ if(rc) Debug(LDAP_DEBUG_TRACE,
+ "translucent: bi_db_init() returned error %d\n", rc, 0, 0);
+
+ ov->private = be->be_private;
+ be->be_private = private;
+ on->on_bi.bi_private = ov;
+ return(rc);
+}
+
+/*
+** translucent_open()
+** if the captive backend has an open() method, call it;
+**
+*/
+
+static int translucent_open(BackendDB *be) {
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ overlay_stack *ov = on->on_bi.bi_private;
+ void *private = be->be_private;
+ int rc;
+
+ /* "should never happen" */
+ if(!ov->info) {
+ Debug(LDAP_DEBUG_ANY, "translucent_open() called with bad ov->info\n", 0, 0, 0);
+ return(LDAP_OTHER);
+ }
+
+ Debug(LDAP_DEBUG_TRACE, "translucent_open\n", 0, 0, 0);
+
+ be->be_private = ov->private;
+ rc = ov->info->bi_db_open ? ov->info->bi_db_open(be) : 0;
+ be->be_private = private;
+
+ if(rc) Debug(LDAP_DEBUG_TRACE,
+ "translucent: bi_db_open() returned error %d\n", rc, 0, 0);
+
+ return(rc);
+}
+
+/*
+** translucent_close()
+** if the captive backend has a close() method, call it;
+** free any config data;
+**
+*/
+
+static int translucent_close(BackendDB *be) {
+ slap_overinst *on = (slap_overinst *) be->bd_info;
+ overlay_stack *ov = on->on_bi.bi_private;
+ translucent_configuration *cf = ov->config;
+ void *private = be->be_private;
+ int rc;
+
+ be->be_private = ov->private;
+ rc = (ov->info && ov->info->bi_db_close) ? ov->info->bi_db_close(be) : 0;
+ be->be_private = private;
+ if(ov->config) ch_free(ov->config);
+ ch_free(ov);
+ return(rc);
+}
+
+/*
+** translucent_init()
+** initialize the slap_overinst with our entry points;
+**
+*/
+
+int translucent_init() {
+
+ translucent.on_bi.bi_type = "translucent";
+ translucent.on_bi.bi_db_init = translucent_db_init;
+ translucent.on_bi.bi_db_config = translucent_config;
+ translucent.on_bi.bi_db_open = translucent_open;
+ translucent.on_bi.bi_db_close = translucent_close;
+ translucent.on_bi.bi_op_bind = translucent_bind;
+ translucent.on_bi.bi_op_add = translucent_add;
+ translucent.on_bi.bi_op_modify = translucent_modify;
+ translucent.on_bi.bi_op_modrdn = translucent_modrdn;
+ translucent.on_bi.bi_op_delete = translucent_delete;
+ translucent.on_bi.bi_op_search = translucent_search;
+ translucent.on_bi.bi_op_compare = translucent_compare;
+
+ return(overlay_register(&translucent));
+}
+
+#if SLAPD_OVER_TRANSLUCENT == SLAPD_MOD_DYNAMIC && defined(PIC)
+int init_module(int argc, char *argv[]) {
+ return translucent_init();
+}
+#endif
+
+#endif /* SLAPD_OVER_TRANSLUCENT */
+
} unique_data;
typedef struct unique_counter_s {
+ struct berval *ndn;
int count;
} unique_counter;
SlapReply *rs
)
{
+ unique_counter *uc;
+
/* because you never know */
if(!op || !rs) return(0);
/* Only search entries are interesting */
if(rs->sr_type != REP_SEARCH) return(0);
+ uc = op->o_callback->sc_private;
+
+ /* Ignore the current entry */
+ if ( dn_match( uc->ndn, &rs->sr_entry->e_nname )) return(0);
+
Debug(LDAP_DEBUG_TRACE, "==> count_attr_cb <%s>\n",
rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
- ((unique_counter*)op->o_callback->sc_private)->count++;
+ uc->count++;
return(0);
}
unique_data *ud = on->on_bi.bi_private;
SlapReply nrs = { REP_RESULT };
slap_callback cb = { NULL, NULL, NULL, NULL }; /* XXX */
- unique_counter uq = { 0 };
+ unique_counter uq = { NULL, 0 };
int rc;
nop->ors_filter = str2filter_x(nop, key);
nop->ors_attrs = slap_anlist_no_attrs;
nop->ors_attrsonly = 1;
+ uq.ndn = &op->o_req_ndn;
+
nop->o_req_ndn = ud->dn;
nop->o_ndn = op->o_bd->be_rootndn;
AttributeDescription *si_ad_monitorContext;
AttributeDescription *si_ad_vendorName;
AttributeDescription *si_ad_vendorVersion;
- AttributeDescription *si_ad_configContext;
/* subentry attribute descriptions */
AttributeDescription *si_ad_administrativeRole;
slap_mask_t bi_flags; /* backend flags */
#define SLAP_BFLAG_MONITOR 0x0001U /* a monitor backend */
-#define SLAP_BFLAG_CONFIG 0x0002U /* a config backend */
#define SLAP_BFLAG_NOLASTMODCMD 0x0010U
#define SLAP_BFLAG_INCREMENT 0x0100U
#define SLAP_BFLAG_ALIASES 0x1000U
#define SLAP_BFLAGS(be) ((be)->bd_info->bi_flags)
#define SLAP_MONITOR(be) (SLAP_BFLAGS(be) & SLAP_BFLAG_MONITOR)
-#define SLAP_CONFIG(be) (SLAP_BFLAGS(be) & SLAP_BFLAG_CONFIG)
#define SLAP_INCREMENT(be) (SLAP_BFLAGS(be) & SLAP_BFLAG_INCREMENT)
#define SLAP_ALIASES(be) (SLAP_BFLAGS(be) & SLAP_BFLAG_ALIASES)
#define SLAP_REFERRALS(be) (SLAP_BFLAGS(be) & SLAP_BFLAG_REFERRALS)
#include <ldap_pvt_thread.h>
#include <slap.h>
#include <slapi.h>
+#include <lutil.h>
/*
* Note: if ltdl.h is not available, slapi should not be compiled
static Slapi_PBlock *
plugin_pblock_new(
int type,
- const char *path,
- const char *initfunc,
int argc,
char *argv[] )
{
Slapi_PluginDesc *pPluginDesc = NULL;
lt_dlhandle hdLoadHandle;
int rc;
+ char **av2 = NULL, **ppPluginArgv;
+ char *path = argv[2];
+ char *initfunc = argv[3];
pPlugin = slapi_pblock_new();
if ( pPlugin == NULL ) {
goto done;
}
- rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)argv );
+ av2 = ldap_charray_dup( argv );
+ if ( !av2 ) {
+ rc = LDAP_NO_MEMORY;
+ goto done;
+ }
+
+ if ( argc > 0 ) {
+ ppPluginArgv = &av2[4];
+ } else {
+ ppPluginArgv = NULL;
+ }
+ rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)ppPluginArgv );
+ if ( rc != 0 ) {
+ goto done;
+ }
+
+ rc = slapi_pblock_set( pPlugin, SLAPI_X_CONFIG_ARGV, (void *)av2 );
if ( rc != 0 ) {
goto done;
}
if ( rc != 0 && pPlugin != NULL ) {
slapi_pblock_destroy( pPlugin );
pPlugin = NULL;
+ if ( av2 ) {
+ ldap_charray_free( av2 );
+ }
}
return pPlugin;
{
int iType = -1;
int numPluginArgc = 0;
- char **ppPluginArgv = NULL;
if ( argc < 4 ) {
fprintf( stderr,
}
numPluginArgc = argc - 4;
- if ( numPluginArgc > 0 ) {
- ppPluginArgv = &argv[4];
- } else {
- ppPluginArgv = NULL;
- }
if ( iType == SLAPI_PLUGIN_PREOPERATION ||
iType == SLAPI_PLUGIN_EXTENDEDOP ||
int rc;
Slapi_PBlock *pPlugin;
- pPlugin = plugin_pblock_new( iType, argv[2], argv[3],
- numPluginArgc, ppPluginArgv );
+ pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
if (pPlugin == NULL) {
return 1;
}
return 0;
}
+void
+slapi_int_plugin_unparse(
+ Backend *be,
+ BerVarray *out
+)
+{
+ Slapi_PBlock *pp;
+ int i, j, rc;
+ char **argv, ibuf[32], *ptr;
+ struct berval idx, bv;
+
+ *out = NULL;
+ idx.bv_val = ibuf;
+ i = 0;
+ for ( pp=be->be_pb; pp; slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) ) {
+ slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
+ idx.bv_len = sprintf( idx.bv_val, "{%d}", i );
+ bv.bv_len = idx.bv_len;
+ for (j=1; argv[j]; j++) {
+ bv.bv_len += strlen(argv[j]);
+ if ( j ) bv.bv_len++;
+ }
+ bv.bv_val = ch_malloc( bv.bv_len + 1 );
+ ptr = lutil_strcopy( bv.bv_val, ibuf );
+ for (j=1; argv[j]; j++) {
+ if ( j ) *ptr++ = ' ';
+ ptr = lutil_strcopy( ptr, argv[j] );
+ }
+ ber_bvarray_add( out, &bv );
+ }
+}
+
int
slapi_int_initialize(void)
{
extern int slapi_int_get_extop_plugin(struct berval *reqoid, SLAPI_FUNC *pFuncAddr );
extern int slapi_int_read_config(Backend *be, const char *fname, int lineno,
int argc, char **argv );
+extern void slapi_int_plugin_unparse(Backend *be, BerVarray *out );
extern int slapi_int_initialize(void);
#ifndef NO_PBLOCK_CLASS /* where's this test from? */
-#if 0 /* unused (yet?) */
-#define CMP_EQUAL 0
-#define CMP_GREATER 1
-#define CMP_LOWER (-1)
-#endif
+typedef enum slapi_pblock_class_e {
+ PBLOCK_CLASS_INVALID = 0,
+ PBLOCK_CLASS_INTEGER,
+ PBLOCK_CLASS_LONG_INTEGER,
+ PBLOCK_CLASS_POINTER,
+ PBLOCK_CLASS_FUNCTION_POINTER
+} slapi_pblock_class_t;
+
+#define PBLOCK_SUCCESS (0)
#define PBLOCK_ERROR (-1)
-#define INVALID_PARAM PBLOCK_ERROR
#define PBLOCK_MAX_PARAMS 100
struct slapi_pblock {
#define SLAPI_X_CONN_SSF 1303
#define SLAPI_X_CONN_SASL_CONTEXT 1304
+#define SLAPI_X_CONFIG_ARGV 1400
+
#define SLAPD_AUTH_NONE "none"
#define SLAPD_AUTH_SIMPLE "simple"
#define SLAPD_AUTH_SSL "SSL"
#include <slap.h>
#include <slapi.h>
-static int
-isOkNetscapeParam( int param )
+static slapi_pblock_class_t
+getPBlockClass( int param )
{
switch ( param ) {
- case SLAPI_BACKEND:
- case SLAPI_CONNECTION:
- case SLAPI_OPERATION:
- case SLAPI_OPERATION_PARAMETERS:
- case SLAPI_OPERATION_TYPE:
- case SLAPI_OPERATION_ID:
- case SLAPI_OPERATION_AUTHTYPE:
+ case SLAPI_PLUGIN_TYPE:
+ case SLAPI_PLUGIN_ARGC:
+ case SLAPI_PLUGIN_VERSION:
+ case SLAPI_PLUGIN_OPRETURN:
+ case SLAPI_PLUGIN_INTOP_RESULT:
+ case SLAPI_CONFIG_LINENO:
+ case SLAPI_CONFIG_ARGC:
+ case SLAPI_BIND_METHOD:
+ case SLAPI_MODRDN_DELOLDRDN:
+ case SLAPI_SEARCH_SCOPE:
+ case SLAPI_SEARCH_DEREF:
+ case SLAPI_SEARCH_SIZELIMIT:
+ case SLAPI_SEARCH_TIMELIMIT:
+ case SLAPI_SEARCH_ATTRSONLY:
+ case SLAPI_NENTRIES:
+ case SLAPI_CHANGENUMBER:
+ case SLAPI_DBSIZE:
case SLAPI_REQUESTOR_ISROOT:
- case SLAPI_BE_MONITORDN:
- case SLAPI_BE_TYPE:
case SLAPI_BE_READONLY:
case SLAPI_BE_LASTMOD:
- case SLAPI_CONN_ID:
- case SLAPI_OPINITIATED_TIME:
- case SLAPI_REQUESTOR_DN:
+ case SLAPI_DB2LDIF_PRINTKEY:
+ case SLAPI_LDIF2DB_REMOVEDUPVALS:
+ case SLAPI_MANAGEDSAIT:
+ case SLAPI_IBM_BROADCAST_BE:
+ case SLAPI_IBM_REPLICATE:
+ case SLAPI_IBM_CL_MAX_ENTRIES:
+ case SLAPI_IBM_CL_FIRST_ENTRY:
+ case SLAPI_IBM_CL_LAST_ENTRY:
+ case SLAPI_IBM_EVENT_ENABLED:
+ case SLAPI_IBM_EVENT_MAXREG:
+ case SLAPI_IBM_EVENT_REGPERCONN:
case SLAPI_REQUESTOR_ISUPDATEDN:
- case SLAPI_CONN_DN:
- case SLAPI_CONN_CLIENTIP:
- case SLAPI_CONN_SERVERIP:
- case SLAPI_CONN_AUTHTYPE:
- case SLAPI_CONN_AUTHMETHOD:
- case SLAPI_CONN_CERT:
case SLAPI_X_CONN_IS_UDP:
- case SLAPI_X_CONN_CLIENTPATH:
- case SLAPI_X_CONN_SERVERPATH:
case SLAPI_X_CONN_SSF:
- case SLAPI_X_CONN_SASL_CONTEXT:
- case SLAPI_IBM_CONN_DN_ALT:
- case SLAPI_IBM_CONN_DN_ORIG:
- case SLAPI_IBM_GSSAPI_CONTEXT:
- case SLAPI_PLUGIN:
- case SLAPI_PLUGIN_PRIVATE:
- case SLAPI_PLUGIN_TYPE:
- case SLAPI_PLUGIN_ARGV:
- case SLAPI_PLUGIN_ARGC:
- case SLAPI_PLUGIN_VERSION:
- case SLAPI_PLUGIN_OPRETURN:
- case SLAPI_PLUGIN_OBJECT:
+ case SLAPI_RESULT_CODE:
+ return PBLOCK_CLASS_INTEGER;
+ break;
+
+ case SLAPI_CONN_ID:
+ case SLAPI_OPERATION_ID:
+ case SLAPI_OPINITIATED_TIME:
+ case SLAPI_ABANDON_MSGID:
+ return PBLOCK_CLASS_LONG_INTEGER;
+ break;
+
+ case SLAPI_PLUGIN_DB_INIT_FN:
case SLAPI_PLUGIN_DESTROY_FN:
- case SLAPI_PLUGIN_DESCRIPTION:
- case SLAPI_PLUGIN_INTOP_RESULT:
- case SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES:
- case SLAPI_PLUGIN_INTOP_SEARCH_REFERRALS:
case SLAPI_PLUGIN_DB_BIND_FN:
case SLAPI_PLUGIN_DB_UNBIND_FN:
case SLAPI_PLUGIN_DB_SEARCH_FN:
case SLAPI_PLUGIN_MR_FILTER_INDEX_FN:
case SLAPI_PLUGIN_MR_FILTER_RESET_FN:
case SLAPI_PLUGIN_MR_INDEX_FN:
+ case SLAPI_PLUGIN_COMPUTE_EVALUATOR_FN:
+ case SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN:
+ case SLAPI_PLUGIN_ACL_ALLOW_ACCESS:
+ case SLAPI_X_PLUGIN_PRE_GROUP_FN:
+ case SLAPI_X_PLUGIN_POST_GROUP_FN:
+ case SLAPI_PLUGIN_AUDIT_FN:
+ return PBLOCK_CLASS_FUNCTION_POINTER;
+ break;
+
+ case SLAPI_BACKEND:
+ case SLAPI_CONNECTION:
+ case SLAPI_OPERATION:
+ case SLAPI_OPERATION_PARAMETERS:
+ case SLAPI_OPERATION_TYPE:
+ case SLAPI_OPERATION_AUTHTYPE:
+ case SLAPI_BE_MONITORDN:
+ case SLAPI_BE_TYPE:
+ case SLAPI_REQUESTOR_DN:
+ case SLAPI_CONN_DN:
+ case SLAPI_CONN_CLIENTIP:
+ case SLAPI_CONN_SERVERIP:
+ case SLAPI_CONN_AUTHTYPE:
+ case SLAPI_CONN_AUTHMETHOD:
+ case SLAPI_CONN_CERT:
+ case SLAPI_X_CONN_CLIENTPATH:
+ case SLAPI_X_CONN_SERVERPATH:
+ case SLAPI_X_CONN_SASL_CONTEXT:
+ case SLAPI_X_CONFIG_ARGV:
+ case SLAPI_IBM_CONN_DN_ALT:
+ case SLAPI_IBM_CONN_DN_ORIG:
+ case SLAPI_IBM_GSSAPI_CONTEXT:
case SLAPI_PLUGIN_MR_OID:
case SLAPI_PLUGIN_MR_TYPE:
case SLAPI_PLUGIN_MR_VALUE:
case SLAPI_PLUGIN_MR_VALUES:
case SLAPI_PLUGIN_MR_KEYS:
+ case SLAPI_PLUGIN:
+ case SLAPI_PLUGIN_PRIVATE:
+ case SLAPI_PLUGIN_ARGV:
+ case SLAPI_PLUGIN_OBJECT:
+ case SLAPI_PLUGIN_DESCRIPTION:
+ case SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES:
+ case SLAPI_PLUGIN_INTOP_SEARCH_REFERRALS:
case SLAPI_PLUGIN_MR_FILTER_REUSABLE:
case SLAPI_PLUGIN_MR_QUERY_OPERATOR:
case SLAPI_PLUGIN_MR_USAGE:
case SLAPI_PLUGIN_SYNTAX_OID:
case SLAPI_PLUGIN_SYNTAX_FLAGS:
case SLAPI_PLUGIN_SYNTAX_COMPARE:
- case SLAPI_MANAGEDSAIT:
case SLAPI_CONFIG_FILENAME:
- case SLAPI_CONFIG_LINENO:
- case SLAPI_CONFIG_ARGC:
case SLAPI_CONFIG_ARGV:
case SLAPI_TARGET_DN:
case SLAPI_REQCONTROLS:
case SLAPI_RESCONTROLS:
case SLAPI_ADD_RESCONTROL:
case SLAPI_ADD_ENTRY:
- case SLAPI_BIND_METHOD:
case SLAPI_BIND_CREDENTIALS:
case SLAPI_BIND_SASLMECHANISM:
case SLAPI_BIND_RET_SASLCREDS:
case SLAPI_COMPARE_VALUE:
case SLAPI_MODIFY_MODS:
case SLAPI_MODRDN_NEWRDN:
- case SLAPI_MODRDN_DELOLDRDN:
case SLAPI_MODRDN_NEWSUPERIOR:
- case SLAPI_SEARCH_SCOPE:
- case SLAPI_SEARCH_DEREF:
- case SLAPI_SEARCH_SIZELIMIT:
- case SLAPI_SEARCH_TIMELIMIT:
case SLAPI_SEARCH_FILTER:
case SLAPI_SEARCH_STRFILTER:
case SLAPI_SEARCH_ATTRS:
- case SLAPI_SEARCH_ATTRSONLY:
- case SLAPI_ABANDON_MSGID:
case SLAPI_SEQ_TYPE:
case SLAPI_SEQ_ATTRNAME:
case SLAPI_SEQ_VAL:
case SLAPI_MR_FILTER_OID:
case SLAPI_MR_FILTER_DNATTRS:
case SLAPI_LDIF2DB_FILE:
- case SLAPI_LDIF2DB_REMOVEDUPVALS:
- case SLAPI_DB2LDIF_PRINTKEY:
case SLAPI_PARENT_TXN:
case SLAPI_TXN:
case SLAPI_SEARCH_RESULT_SET:
case SLAPI_SEARCH_RESULT_ENTRY:
- case SLAPI_NENTRIES:
case SLAPI_SEARCH_REFERRALS:
- case SLAPI_CHANGENUMBER:
case SLAPI_LOG_OPERATION:
- case SLAPI_DBSIZE:
- case SLAPI_RESULT_CODE:
case SLAPI_RESULT_TEXT:
case SLAPI_RESULT_MATCHED:
- case SLAPI_PLUGIN_COMPUTE_EVALUATOR_FN:
- case SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN:
- case SLAPI_PLUGIN_ACL_ALLOW_ACCESS:
- case SLAPI_X_PLUGIN_PRE_GROUP_FN:
- case SLAPI_X_PLUGIN_POST_GROUP_FN:
case SLAPI_X_GROUP_ENTRY:
case SLAPI_X_GROUP_ATTRIBUTE:
case SLAPI_X_GROUP_OPERATION_DN:
case SLAPI_X_GROUP_TARGET_ENTRY:
- return LDAP_SUCCESS;
+ case SLAPI_PLUGIN_AUDIT_DATA:
+ case SLAPI_IBM_PBLOCK:
+ return PBLOCK_CLASS_POINTER;
+ break;
default:
- return INVALID_PARAM;
+ break;
}
-}
-static int
-isValidParam( Slapi_PBlock *pb, int param )
-{
- if ( !pb ) {
- return INVALID_PARAM;
- }
-
- if ( pb->ckParams == TRUE ) {
- if ( IBM_RESERVED( param ) ) return LDAP_SUCCESS;
- if (param == SLAPI_PLUGIN_AUDIT_FN ||
- param == SLAPI_PLUGIN_AUDIT_DATA )
- return LDAP_SUCCESS;
- if ( param < LAST_IBM_PARAM ) {
- return INVALID_PARAM;
- } else if ( NETSCAPE_RESERVED( param ) ) {
- return INVALID_PARAM;
- } else {
- return isOkNetscapeParam(param);
- }
- } else {
- return LDAP_SUCCESS;
- }
+ return PBLOCK_CLASS_INVALID;
}
static void
get( Slapi_PBlock *pb, int param, void **val )
{
int i;
+ slapi_pblock_class_t pbClass;
- if ( isValidParam( pb, param ) == INVALID_PARAM ) {
+ pbClass = getPBlockClass( param );
+ if ( pbClass == PBLOCK_CLASS_INVALID ) {
return PBLOCK_ERROR;
}
Lock( pb );
-
- *val = NULL;
+
+ switch ( pbClass ) {
+ case PBLOCK_CLASS_INTEGER:
+ *((int *)val) = 0;
+ break;
+ case PBLOCK_CLASS_LONG_INTEGER:
+ *((long *)val) = 0L;
+ break;
+ case PBLOCK_CLASS_POINTER:
+ case PBLOCK_CLASS_FUNCTION_POINTER:
+ *val = NULL;
+ break;
+ }
+
for ( i = 0; i < pb->numParams; i++ ) {
if ( pb->curParams[i] == param ) {
- *val = pb->curVals[i];
+ switch ( pbClass ) {
+ case PBLOCK_CLASS_INTEGER:
+ *((int *)val) = (int)pb->curVals[i];
+ break;
+ case PBLOCK_CLASS_LONG_INTEGER:
+ *((long *)val) = (long)pb->curVals[i];
+ break;
+ case PBLOCK_CLASS_POINTER:
+ case PBLOCK_CLASS_FUNCTION_POINTER:
+ *val = pb->curVals[i];
+ break;
+ default:
+ break;
+ }
break;
}
}
unLock( pb );
- return LDAP_SUCCESS;
+ return PBLOCK_SUCCESS;
}
static int
#if defined(LDAP_SLAPI)
int i, freeit;
int addcon = 0;
+ slapi_pblock_class_t pbClass;
- if ( isValidParam( pb, param ) == INVALID_PARAM ) {
+ pbClass = getPBlockClass( param );
+ if ( pbClass == PBLOCK_CLASS_INVALID ) {
return PBLOCK_ERROR;
}
case SLAPI_IBM_CONN_DN_ORIG:
case SLAPI_RESULT_TEXT:
case SLAPI_RESULT_MATCHED:
- freeit = 1; break;
+ freeit = 1;
+ break;
default:
- freeit = 0; break;
+ freeit = 0;
+ break;
}
for( i = 0; i < pb->numParams; i++ ) {
if ( pb->curParams[i] == param ) {
}
unLock( pb );
- return LDAP_SUCCESS;
+ return PBLOCK_SUCCESS;
#endif /* LDAP_SLAPI */
return PBLOCK_ERROR;
}
}
p->numParams--;
unLock( p );
- return LDAP_SUCCESS;
+ return PBLOCK_SUCCESS;
}
Slapi_PBlock *
dn: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example,dc=
com
-objectClass: OpenLDAPperson
+objectClass: testPerson
cn: Gern Jensen
sn: Jensen
uid: gjensen
telephoneNumber: +1 313 555 8343
mail: gjensen@mailgw.example.com
homePhone: +1 313 555 8844
+testTime: 20050304001801.234Z
dn: ou=Groups,dc=example,dc=com
objectClass: organizationalUnit
# refldap://localhost:9010/ou=Referrals,o=Beispiel,c=DE??sub
+# searching filter="(uid=example)"
+# attrs="uid"
+# base="o=Example,c=US"...
+dn: o=Example,c=US
+uid: example
+
+# refldap://localhost:9010/ou=Referrals,o=Beispiel,c=DE??sub
+
# searching filter="(member=cn=Another Added Group,ou=Groups,o=Example,c=US)"
# attrs="member"
# base="o=Example,c=US"...
pidfile ./testrun/slapd.3.pid
argsfile ./testrun/slapd.3.args
-# password-hash {md5}
-
#mod#modulepath ../servers/slapd/back-@BACKEND@/
#mod#moduleload back_@BACKEND@.la
#monitormod#modulepath ../servers/slapd/back-monitor/
pidfile ./testrun/slapd.2.pid
argsfile ./testrun/slapd.2.args
-# password-hash {md5}
-
#mod#modulepath ../servers/slapd/back-@BACKEND@/
#mod#moduleload back_@BACKEND@.la
#monitormod#modulepath ../servers/slapd/back-monitor/
pidfile ./testrun/slapd.1.pid
argsfile ./testrun/slapd.1.args
-# password-hash {md5}
-
#mod#modulepath ../servers/slapd/back-@BACKEND@/
#mod#moduleload back_@BACKEND@.la
#monitormod#modulepath ../servers/slapd/back-monitor/
--- /dev/null
+# stand-alone slapd config -- for testing (with translucent overlay)
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+ucdata-path ./ucdata
+include ./schema/core.schema
+include ./schema/cosine.schema
+include ./schema/inetorgperson.schema
+include ./schema/openldap.schema
+include ./schema/nis.schema
+
+#
+pidfile ./testrun/slapd.2.pid
+argsfile ./testrun/slapd.2.args
+
+#mod#modulepath ../servers/slapd/back-@BACKEND@/:../servers/slapd/back-ldap/:../servers/slapd/overlays
+#mod#moduleload back_@BACKEND@.la
+#mod#moduleload back_ldap.la
+#translucentmod#modulepath ../servers/slapd/overlays
+#translucentmod#moduleload translucent.la
+
+#######################################################################
+# database definitions
+#######################################################################
+
+database @BACKEND@
+suffix "o=translucent"
+directory ./testrun/db.2.a
+rootdn "o=translucent"
+rootpw secret
+index objectClass eq
+index cn,sn,uid pres,eq,sub
+
+overlay translucent
+translucent_no_glue
+
+# XXX this uri really shouldn't be hardcoded
+uri @URI1@
+lastmod off
+acl-authcDN uid=binder,o=translucent
+acl-passwd bindtest
--- /dev/null
+# stand-alone slapd config -- for testing (with translucent overlay)
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+ucdata-path ./ucdata
+include ./schema/core.schema
+include ./schema/cosine.schema
+include ./schema/inetorgperson.schema
+include ./schema/openldap.schema
+include ./schema/nis.schema
+
+#
+pidfile ./testrun/slapd.1.pid
+argsfile ./testrun/slapd.1.args
+
+#mod#modulepath ../servers/slapd/back-@BACKEND@/:../servers/slapd/overlays
+#mod#moduleload back_@BACKEND@.la
+
+#######################################################################
+# database definitions
+#######################################################################
+
+database @BACKEND@
+suffix "o=translucent"
+directory ./testrun/db.1.a
+rootdn "o=translucent"
+rootpw secret
+index objectClass eq
+index cn,sn,uid pres,eq,sub
+
pidfile ./testrun/slapd.1.pid
argsfile ./testrun/slapd.1.args
-# password-hash {md5}
-
#mod#modulepath ../servers/slapd/back-@BACKEND@/
#mod#moduleload back_@BACKEND@.la
#monitormod#modulepath ../servers/slapd/back-monitor/
include ./schema/inetorgperson.schema
include ./schema/openldap.schema
include ./schema/nis.schema
+include ./testdata/test.schema
#
pidfile ./testrun/slapd.1.pid
--- /dev/null
+dn: uid=danger,ou=users,o=translucent
+objectClass: inetOrgPerson
+uid: danger
+sn: danger
+cn: henry
+businessCategory: frontend-override
+carLicense: LIVID
+employeeType: special
+departmentNumber: 9999999
+roomNumber: 41L-535
--- /dev/null
+# toplevel
+
+dn: o=translucent
+objectClass: top
+objectClass: organization
+o: translucent
+description: backend database root
+
+# backend OU
+
+dn: ou=users,o=translucent
+objectClass: top
+objectClass: organizationalUnit
+ou: users
+description: backend user container root
+
+# bind user for frontend connection
+
+dn: uid=binder,o=translucent
+objectClass: inetOrgPerson
+uid: binder
+sn: test
+cn: binder
+businessCategory: binder-test-user
+displayName: Binder Test User
+userPassword: bindtest
--- /dev/null
+# typical user
+dn: uid=danger,ou=users,o=translucent
+objectClass: inetOrgPerson
+uid: danger
+sn: warning
+cn: danger
+businessCategory: backend-opaque
+carLicense: BACK
+departmentNumber: 7341
+displayName: Warning
+employeeNumber: 5150
+employeeType: contractor
+givenName: Danger Warning
+
+# another example
+dn: uid=example,ou=users,o=translucent
+objectClass: inetOrgPerson
+uid: example
+sn: user
+cn: example
+businessCategory: backend-opaque
+carLicense: SAMPLE
+departmentNumber: 7341
+displayName: Example
+employeeNumber: 5150
+employeeType: fulltime
+givenName: Example User
+
+#
+dn: uid=fred,ou=users,o=translucent
+objectClass: inetOrgPerson
+uid: fred
+sn: said
+cn: said
+businessCategory: backend-opaque
+carLicense: RIGHT
+departmentNumber: 9919
+displayName: Right Said Fred
+employeeNumber: 44199
+employeeType: fulltime
+givenName: Right Said
+
--- /dev/null
+dn: uid=danger,ou=users,o=translucent
+objectClass: inetOrgPerson
+uid: danger
+sn: danger
+cn: henry
+businessCategory: frontend-override
+carLicense: LIVID
+departmentNumber: 9999999
+displayName: Warning
+employeeNumber: 5150
+employeeType: special
+givenName: Danger Warning
+roomNumber: 41L-535
+
+dn: uid=example,ou=users,o=translucent
+objectClass: inetOrgPerson
+uid: example
+sn: user
+cn: example
+businessCategory: backend-opaque
+carLicense: SAMPLE
+departmentNumber: 7341
+displayName: Example
+employeeNumber: 5150
+employeeType: fulltime
+givenName: Example User
+
+dn: uid=fred,ou=users,o=translucent
+objectClass: inetOrgPerson
+uid: fred
+sn: said
+cn: said
+businessCategory: backend-opaque
+carLicense: RIGHT
+departmentNumber: 9919
+displayName: Right Said Fred
+employeeNumber: 44199
+employeeType: fulltime
+givenName: Right Said
+
# For testing purposes only.
# For Attribute Aliasing.
-attributetype ( 1.3.6.1.4.1.4203.666.1.34 NAME 'x509CertificateIssuer'
- EQUALITY distinguishedNameMatch
- DESC 'Aliasing attribute: Issuer, use'
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+attributetype ( 1.3.6.1.4.1.4203.666.1.34
+ NAME 'x509CertificateIssuer'
+ EQUALITY distinguishedNameMatch
+ DESC 'Aliasing attribute: Issuer, use'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
-attributetype ( 1.3.6.1.4.1.4203.666.1.35 NAME 'x509CertificateSerial'
- DESC 'Aliasing attribute: Serial, use'
- EQUALITY integerMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
+attributetype ( 1.3.6.1.4.1.4203.666.1.35
+ NAME 'x509CertificateSerial'
+ DESC 'Aliasing attribute: Serial, use'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
-attributetype ( 1.3.6.1.4.1.4203.666.1.36 NAME 'x509CertificateSerialAndIssuer'
- DESC 'Aliasing attribute: Serial and Issuer together, use'
- EQUALITY certificateExactMatch
- SYNTAX 1.2.826.0.1.3344810.7.1 )
+attributetype ( 1.3.6.1.4.1.4203.666.1.36
+ NAME 'x509CertificateSerialAndIssuer'
+ DESC 'Aliasing attribute: Serial and Issuer together, use'
+ EQUALITY certificateExactMatch
+ SYNTAX 1.2.826.0.1.3344810.7.1 )
+
+# generalized time testing
+
+attributetype ( 1.3.6.1.4.1.4203.666.1.37
+ name 'testTime'
+ equality generalizedTimeMatch
+ ordering generalizedTimeOrderingMatch
+ syntax 1.3.6.1.4.1.1466.115.121.1.24
+ single-value )
+
+objectClass ( 1.3.6.1.4.1.4203.666.1.38
+ name 'testPerson' sup OpenLDAPperson
+ may testTime )
AC_pcache=pcache@BUILD_PROXYCACHE@
AC_ppolicy=ppolicy@BUILD_PPOLICY@
AC_refint=refint@BUILD_REFINT@
+AC_translucent=translucent@BUILD_TRANSLUCENT@
AC_unique=unique@BUILD_UNIQUE@
AC_rwm=rwm@BUILD_RWM@
AC_syncprov=syncprov@BUILD_SYNCPROV@
export AC_bdb AC_hdb AC_ldap AC_ldbm AC_meta AC_monitor AC_relay AC_sql
export AC_glue AC_pcache AC_ppolicy AC_refint AC_unique AC_rwm AC_syncprov
-export AC_WITH_SASL AC_WITH_TLS AC_WITH_MODULES_ENABLED
+export AC_translucent AC_WITH_SASL AC_WITH_TLS AC_WITH_MODULES_ENABLED
if test ! -x ../servers/slapd/slapd ; then
echo "Could not locate slapd(8)"
-e "s/^#${AC_ppolicy}#//" \
-e "s/^#${AC_refint}#//" \
-e "s/^#${AC_syncprov}#//" \
+ -e "s/^#${AC_translucent}#//" \
-e "s/^#${AC_unique}#//" \
-e "s/^#${AC_rwm}#//" \
-e "s/^#${MON}#//" \
PPOLICY=${AC_ppolicy-ppolicyno}
REFINT=${AC_refint-refintno}
RWM=${AC_rwm-rwmno}
+TRANSLUCENT=${AC_translucent-translucentno}
UNIQUE=${AC_unique-uniqueno}
SYNCPROV=${AC_syncprov-syncprovno}
WITH_SASL=${AC_WITH_SASL-no}
GLUESYNCCONF1=$DATADIR/slapd-glue-syncrepl1.conf
GLUESYNCCONF2=$DATADIR/slapd-glue-syncrepl2.conf
SQLCONF=$DATADIR/slapd-sql.conf
+TRANSLUCENTLOCALCONF=$DATADIR/slapd-translucent-local.conf
+TRANSLUCENTREMOTECONF=$DATADIR/slapd-translucent-remote.conf
CONF1=$TESTDIR/slapd.1.conf
CONF2=$TESTDIR/slapd.2.conf
LDIFCOMPMATCH=$DATADIR/test-compmatch.ldif
LDIFCHAIN1=$DATADIR/test-chain1.ldif
LDIFCHAIN2=$DATADIR/test-chain2.ldif
+LDIFTRANSLUCENTDATA=$DATADIR/test-translucent-data.ldif
+LDIFTRANSLUCENTCONFIG=$DATADIR/test-translucent-config.ldif
+LDIFTRANSLUCENTADD=$DATADIR/test-translucent-add.ldif
+LDIFTRANSLUCENTMERGED=$DATADIR/test-translucent-merged.ldif
SQLADD=$DATADIR/sql-add.ldif
MONITOR=""
REFDN="c=US"
REFINTDN="cn=Manager,o=refint"
UNIQUEDN="cn=Manager,o=unique"
EMPTYDNDN="cn=Manager,c=US"
+TRANSLUCENTROOT="o=translucent"
+TRANSLUCENTUSER="ou=users,o=translucent"
+TRANSLUCENTDN="uid=binder,o=translucent"
+TRANSLUCENTPASSWD="bindtest"
LOG1=$TESTDIR/slapd.1.log
LOG2=$TESTDIR/slapd.2.log
GLUESYNCOUT=$DATADIR/gluesync.out
SQLREAD=$DATADIR/sql-read.out
SQLWRITE=$DATADIR/sql-write.out
+TRANSLUCENTOUT=$DATADIR/translucent.search.out
# Just in case we linked the binaries dynamically
LD_LIBRARY_PATH=`pwd`/../libraries:${LD_LIBRARY_PATH} export LD_LIBRARY_PATH
exit $RC
fi
-BASEDN="o=Example,c=US"
+FILTER="(uid=example)"
+echo "Searching filter=\"$FILTER\""
+echo " attrs=\"uid\""
+echo " base=\"$BASEDN\"..."
+echo "# searching filter=\"$FILTER\"" >> $SEARCHOUT
+echo "# attrs=\"uid\"" >> $SEARCHOUT
+echo "# base=\"$BASEDN\"..." >> $SEARCHOUT
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 -b "$BASEDN" "$FILTER" uid \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "Search failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
FILTER="(member=cn=Another Added Group,ou=Groups,$BASEDN)"
echo "Searching filter=\"$FILTER\""
echo " attrs=\"member\""
dn: cn=Gern Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com
changetype: add
-objectclass: OpenLDAPperson
+objectclass: testPerson
cn: Gern Jensen
sn: Jensen
uid: gjensen
telephonenumber: +1 313 555 8343
mail: gjensen@mailgw.example.com
homephone: +1 313 555 8844
+testTime: 20050304001801.234Z
dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=example,dc=com
changetype: delete
exit $RC
fi
+echo "Logging end state with ldapsearch..."
+echo "" >> $TESTOUT
+echo "++ Initial search" >> $TESTOUT
+$LDAPSEARCH -h $LOCALHOST -p $PORT1 \
+ -D "$MANAGERDN" -w $PASSWD \
+ -b "$BASEDN" \
+ 'objectclass=*' >> $TESTOUT 2>&1
+
+
test $KILLSERVERS != no && kill -HUP $KILLPIDS
echo ">>>>> Test succeeded"
exit $RC
fi
-FILTER="(x509CertificateIssuer:distinguishedNameMatch:=c=US)"
+FILTER="(x509CertificateIssuer=c=US)"
echo " f=$FILTER ..."
echo "# f=$FILTER ..." >> $SEARCHOUT
$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
exit $RC
fi
-FILTER="(x509CertificateSerial:integerMatch:=0)"
+FILTER="(x509CertificateSerial=0)"
echo " f=$FILTER ..."
echo "# f=$FILTER ..." >> $SEARCHOUT
$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
--- /dev/null
+#! /bin/sh
+# $OpenLDAP$
+## This work is part of OpenLDAP Software <http://www.openldap.org/>.
+##
+## Copyright 2004 The OpenLDAP Foundation.
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted only as authorized by the OpenLDAP
+## Public License.
+##
+## A copy of this license is available in the file LICENSE in the
+## top-level directory of the distribution or, alternatively, at
+## <http://www.OpenLDAP.org/license.html>.
+
+echo "running defines.sh"
+. $SRCDIR/scripts/defines.sh
+
+PERSONAL="(objectClass=inetOrgPerson)"
+NOWHERE="/dev/null"
+FAILURE="additional info:"
+
+if test $TRANSLUCENT = translucentno ; then
+ echo "Translucent Proxy overlay not available, test skipped"
+ exit 0
+fi
+
+if test $BACKEND = ldbm ; then
+ echo "Translucent Proxy overlay not qualified for use with LDBM, skipping"
+ exit 0
+fi
+
+if test $AC_ldap = ldapno ; then
+ echo "Translucent Proxy overlay requires back-ldap backend, test skipped"
+ exit 0
+fi
+
+# configure backside
+mkdir -p $TESTDIR $DBDIR1
+
+. $CONFFILTER $BACKEND $MONITORDB < $TRANSLUCENTREMOTECONF > $CONF1
+echo "Running slapadd to build remote slapd database..."
+$SLAPADD -f $CONF1 -l $LDIFTRANSLUCENTCONFIG
+RC=$?
+if test $RC != 0 ; then
+ echo "slapadd failed ($RC)!"
+ exit $RC
+fi
+
+echo "Starting remote slapd on TCP/IP port $PORT1..."
+$SLAPD -f $CONF1 -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+REMOTEPID="$PID"
+KILLPIDS="$PID"
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for remote slapd to start..."
+ sleep 5
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+# configure frontside
+mkdir -p $DBDIR2
+
+. $CONFFILTER $BACKEND $MONITORDB < $TRANSLUCENTLOCALCONF > $CONF2
+
+echo "Starting local slapd on TCP/IP port $PORT2..."
+$SLAPD -f $CONF2 -h $URI2 -d $LVL $TIMING > $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+LOCALPID="$PID"
+KILLPIDS="$LOCALPID $REMOTEPID"
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for local slapd to start..."
+ sleep 5
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing slapd Translucent Proxy operations..."
+
+echo "Testing search: no remote data defined..."
+
+$LDAPSEARCH -H $URI2 -b "$TRANSLUCENTUSER" "$PERSONAL" >$SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+if test -s $SEARCHOUT; then
+ echo "ldapsearch should have returned no records!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Populating remote database..."
+
+$LDAPADD -D "$TRANSLUCENTROOT" -H $URI1 \
+ -w $PASSWD < $LDIFTRANSLUCENTDATA > $NOWHERE 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing search: remote database via local slapd..."
+
+$LDAPSEARCH -H $URI2 -b "$TRANSLUCENTUSER" "$PERSONAL" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+. $LDIFFILTER < $SEARCHOUT > $SEARCHFLT
+. $LDIFFILTER < $LDIFTRANSLUCENTDATA > $LDIFFLT
+$CMP $SEARCHFLT $LDIFFLT > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed -- corruption from remote to local!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing add: prohibited local record..."
+
+$LDAPADD -D "$TRANSLUCENTDN" -H $URI2 \
+ -w $TRANSLUCENTPASSWD < $LDIFTRANSLUCENTADD > $TESTOUT 2>&1
+
+RC=$?
+if test $RC != 50 ; then
+ echo "ldapadd failed ($RC), expected INSUFFICIENT ACCESS!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing add: valid local record, no_glue..."
+
+$LDAPADD -v -v -v -D "$TRANSLUCENTROOT" -H $URI2 \
+ -w $PASSWD < $LDIFTRANSLUCENTADD > $TESTOUT 2>&1
+
+RC=$?
+if test $RC != 32 ; then
+ echo "ldapadd failed ($RC), expected NO SUCH OBJECT!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing modrdn: valid local record, no_glue..."
+
+$LDAPMODRDN -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 'uid=fred,ou=users,o=translucent' 'uid=someguy'
+
+RC=$?
+if test $RC != 32 ; then
+ echo "ldapmodrdn failed ($RC), expected NO SUCH OBJECT!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Shutting down local slapd..."
+kill -HUP $LOCALPID
+sleep 5
+
+echo "Configuring local slapd without translucent_no_glue..."
+. $CONFFILTER $BACKEND $MONITORDB < $TRANSLUCENTLOCALCONF | \
+ grep -v translucent_no_glue > $CONF2
+
+echo "Restarting local slapd on TCP/IP port $PORT2..."
+$SLAPD -f $CONF2 -h $URI2 -d $LVL $TIMING >> $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+LOCALPID="$PID"
+KILLPIDS="$REMOTEPID $PID"
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for local slapd to start..."
+ sleep 5
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing add: valid local record..."
+
+$LDAPADD -D "$TRANSLUCENTROOT" -H $URI2 \
+ -w $PASSWD < $LDIFTRANSLUCENTADD > $TESTOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapadd failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing search: data merging..."
+
+$LDAPSEARCH -H $URI2 -b "$TRANSLUCENTUSER" "$PERSONAL" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$CMP $SEARCHOUT $LDIFTRANSLUCENTMERGED > $CMPOUT
+
+if test $? != 0 ; then
+ echo "Comparison failed -- local data failed to merge with remote!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing compare: valid local..."
+
+$LDAPCOMPARE -z -H $URI2 -w $TRANSLUCENTPASSWD -D $TRANSLUCENTDN \
+ "uid=danger,ou=users,o=translucent" "carLicense:LIVID"
+
+RC=$?
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC), expected TRUE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing compare: valid remote..."
+
+$LDAPCOMPARE -z -x -H $URI2 -w $TRANSLUCENTPASSWD -D $TRANSLUCENTDN \
+ "uid=binder,o=translucent" "businessCategory:binder-test-user"
+
+RC=$?
+if test $RC != 6 ; then
+ echo "ldapcompare failed ($RC), expected TRUE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing compare: bogus local..."
+
+$LDAPCOMPARE -z -x -H $URI2 -w $TRANSLUCENTPASSWD -D $TRANSLUCENTDN \
+ "uid=danger,ou=users,o=translucent" "businessCategory:invalid-test-value"
+
+RC=$?
+if test $RC != 5 ; then
+ echo "ldapcompare failed ($RC), expected FALSE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing compare: bogus remote..."
+
+$LDAPCOMPARE -z -x -H $URI2 -w $TRANSLUCENTPASSWD -D $TRANSLUCENTDN \
+ "uid=binder,o=translucent" "businessCategory:invalid-test-value"
+
+RC=$?
+if test $RC != 5 ; then
+ echo "ldapcompare failed ($RC), expected FALSE!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing modify: nonexistent record..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD
+version: 1
+dn: uid=bogus,ou=users,o=translucent
+changetype: modify
+replace: roomNumber
+roomNumber: 31J-2112
+EOF_MOD
+
+RC=$?
+if test $RC != 32 ; then
+ echo "ldapmodify failed ($RC), expected NO SUCH OBJECT!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing modify: valid local record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD1
+version: 1
+dn: uid=danger,ou=users,o=translucent
+changetype: modify
+replace: roomNumber
+roomNumber: 9N-21
+EOF_MOD1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -H $URI2 -b "uid=danger,ou=users,o=translucent" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ATTR=`grep roomNumber $SEARCHOUT` > $NOWHERE 2>&1
+if test "$ATTR" != "roomNumber: 9N-21" ; then
+ echo "modification failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing search: specific nonexistent remote attribute..."
+
+$LDAPSEARCH -H $URI2 -b "uid=danger,ou=users,o=translucent" roomNumber > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing modify: nonexistent local record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD2
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: modify
+replace: roomNumber
+roomNumber: 31J-2112
+EOF_MOD2
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -H $URI2 -b "uid=fred,ou=users,o=translucent" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ATTR=`grep roomNumber $SEARCHOUT` > $NOWHERE 2>&1
+if test "$ATTR" != "roomNumber: 31J-2112" ; then
+ echo "modification failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Testing modify: valid remote record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD9
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: modify
+delete: preferredLanguage
+EOF_MOD9
+
+RC=$?
+if test $RC != 16 ; then
+ echo "ldapmodify failed ($RC), expected NO SUCH ATTRIBUTE!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing delete: valid local record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD4
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: modify
+delete: roomNumber
+EOF_MOD4
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing modrdn: prohibited local record..."
+
+$LDAPMODRDN -D "$TRANSLUCENTDN" -H $URI2 -w $TRANSLUCENTPASSWD > \
+ $TESTOUT 2>&1 'uid=fred,ou=users,o=translucent' 'uid=someguy'
+
+RC=$?
+if test $RC != 50 ; then
+ echo "ldapmodrdn failed ($RC), expected INSUFFICIENT ACCESS!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing modrdn: valid local record..."
+
+$LDAPMODRDN -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 'uid=fred,ou=users,o=translucent' 'uid=someguy'
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodrdn failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing delete: prohibited local record..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTDN" -H $URI2 -w $TRANSLUCENTPASSWD > \
+ $TESTOUT 2>&1 << EOF_DEL2
+version: 1
+dn: uid=someguy,ou=users,o=translucent
+changetype: delete
+EOF_DEL2
+
+RC=$?
+if test $RC != 50 ; then
+ echo "ldapadd failed ($RC), expected INSUFFICIENT ACCESS!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing delete: valid local record..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_DEL3
+version: 1
+dn: uid=someguy,ou=users,o=translucent
+changetype: delete
+EOF_DEL3
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing delete: valid remote record..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_DEL8
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: delete
+EOF_DEL8
+
+RC=$?
+if test $RC != 32 ; then
+ echo "ldapmodify failed ($RC), expected NO SUCH OBJECT!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing delete: nonexistent local record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_DEL1
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: modify
+delete: roomNumber
+EOF_DEL1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -H $URI2 -b "uid=fred,ou=users,o=translucent" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing delete: valid local record, nonexistent attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD8
+version: 1
+dn: uid=danger,ou=users,o=translucent
+changetype: modify
+delete: preferredLanguage
+EOF_MOD8
+
+RC=$?
+if test $RC != 16 ; then
+ echo "ldapmodify failed ($RC), expected NO SUCH ATTRIBUTE!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing modify: valid remote record, combination add-modify-delete..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD6
+version: 1
+dn: uid=fred,ou=users,o=translucent
+changetype: modify
+delete: carLicense
+-
+add: preferredLanguage
+preferredLanguage: ISO8859-1
+-
+replace: employeeType
+employeeType: consultant
+EOF_MOD6
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapmodify failed ($RC)!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -H $URI2 -b "uid=fred,ou=users,o=translucent" > $SEARCHOUT 2>&1
+
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+ATTR=`grep employeeType $SEARCHOUT` > $NOWHERE 2>&1
+if test "$ATTR" != "employeeType: consultant" ; then
+ echo "modification failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+ATTR=`grep preferredLanguage $SEARCHOUT` > $NOWHERE 2>&1
+if test "$ATTR" != "preferredLanguage: ISO8859-1" ; then
+ echo "modification failed!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit 1
+fi
+
+echo "Shutting down local slapd..."
+kill -HUP $LOCALPID
+sleep 5
+
+echo "Configuring local slapd with translucent_strict..."
+echo translucent_strict >> $CONF2
+
+echo "Restarting slapd on TCP/IP port $PORT2..."
+$SLAPD -f $CONF2 -h $URI2 -d $LVL $TIMING >> $LOG2 2>&1 &
+PID=$!
+if test $WAIT != 0 ; then
+ echo PID $PID
+ read foo
+fi
+LOCALPID="$PID"
+KILLPIDS="$REMOTEPID $PID"
+
+for i in 0 1 2 3 4 5; do
+ $LDAPSEARCH -s base -b "$MONITOR" -H $URI2 \
+ 'objectclass=*' > /dev/null 2>&1
+ RC=$?
+ if test $RC = 0 ; then
+ break
+ fi
+ echo "Waiting 5 seconds for local slapd to start..."
+ sleep 5
+done
+
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing strict mode delete: nonexistent local attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD5
+version: 1
+dn: uid=example,ou=users,o=translucent
+changetype: modify
+delete: preferredLanguage
+EOF_MOD5
+
+RC=$?
+if test $RC != 19 ; then
+ echo "ldapmodify failed ($RC), expected CONSTRAINT VIOLATION!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing strict mode delete: nonexistent remote attribute..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD3
+version: 1
+dn: uid=danger,ou=users,o=translucent
+changetype: modify
+delete: displayName
+EOF_MOD3
+
+RC=$?
+if test $RC != 19 ; then
+ echo "ldapmodify failed ($RC), expected CONSTRAINT VIOLATION!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing strict mode modify: combination add-modify-delete..."
+
+$LDAPMODIFY -v -D "$TRANSLUCENTROOT" -H $URI2 -w $PASSWD > \
+ $TESTOUT 2>&1 << EOF_MOD6
+version: 1
+dn: uid=example,ou=users,o=translucent
+changetype: modify
+delete: carLicense
+-
+add: preferredLanguage
+preferredLanguage: ISO8859-1
+-
+replace: employeeType
+employeeType: consultant
+EOF_MOD6
+
+RC=$?
+if test $RC != 19 ; then
+ echo "ldapmodify failed ($RC), expected CONSTRAINT VIOLATION!"
+ grep "$FAILURE" $TESTOUT
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+test $KILLSERVERS != no && kill -HUP $KILLPIDS
+
+echo ">>>>> Test succeeded"
+exit 0