diff --git a/servers/slapd/Makefile.in b/servers/slapd/Makefile.in index 75d8f5d25a..a8bdfa687f 100644 --- a/servers/slapd/Makefile.in +++ b/servers/slapd/Makefile.in @@ -17,7 +17,7 @@ SRCS = main.c daemon.c connection.c search.c filter.c add.c charray.c \ repl.c lock.c controls.c extended.c kerberos.c passwd.c \ schema.c schema_check.c schema_init.c schema_prep.c \ schemaparse.c ad.c at.c mr.c syntax.c oc.c saslauthz.c \ - configinfo.c starttls.c index.c sets.c \ + configinfo.c starttls.c index.c sets.c referral.c \ root_dse.c sasl.c module.c suffixalias.c mra.c mods.c \ limits.c \ $(@PLAT@_SRCS) @@ -30,7 +30,7 @@ OBJS = main.o daemon.o connection.o search.o filter.o add.o charray.o \ repl.o lock.o controls.o extended.o kerberos.o passwd.o \ schema.o schema_check.o schema_init.o schema_prep.o \ schemaparse.o ad.o at.o mr.o syntax.o oc.o saslauthz.o \ - configinfo.o starttls.o index.o sets.o \ + configinfo.o starttls.o index.o sets.o referral.o \ root_dse.o sasl.o module.o suffixalias.o mra.o mods.o \ limits.o \ $(@PLAT@_OBJS) diff --git a/servers/slapd/add.c b/servers/slapd/add.c index 238c8f1d0b..6d733cf81d 100644 --- a/servers/slapd/add.c +++ b/servers/slapd/add.c @@ -209,8 +209,13 @@ do_add( Connection *conn, Operation *op ) */ be = select_backend( e->e_ndn, manageDSAit ); if ( be == NULL ) { + struct berval **ref = referral_rewrite( default_referral, + NULL, e->e_dn, LDAP_SCOPE_DEFAULT ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, - NULL, NULL, default_referral, NULL ); + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvecfree( ref ); goto done; } @@ -294,8 +299,15 @@ do_add( Connection *conn, Operation *op ) #ifndef SLAPD_MULTIMASTER } else { + struct berval **defref = be->be_update_refs + ? be->be_update_refs : default_referral; + struct berval **ref = referral_rewrite( defref, + NULL, e->e_dn, LDAP_SCOPE_DEFAULT ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, - be->be_update_refs ? be->be_update_refs : default_referral, NULL ); + ref ? ref : defref, NULL ); + + ber_bvecfree( ref ); #endif } } else { @@ -387,4 +399,3 @@ static int slap_mods2entry( return LDAP_SUCCESS; } - diff --git a/servers/slapd/back-ldbm/add.c b/servers/slapd/back-ldbm/add.c index 99dfe0fdb5..71fb24b185 100644 --- a/servers/slapd/back-ldbm/add.c +++ b/servers/slapd/back-ldbm/add.c @@ -37,12 +37,11 @@ ldbm_back_add( #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY,"ldbm_back_add: %s\n", - e->e_dn )); + e->e_dn )); #else Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_add: %s\n", e->e_dn, 0, 0); #endif - /* nobody else can add until we lock our parent */ ldap_pvt_thread_mutex_lock(&li->li_add_mutex); @@ -62,8 +61,8 @@ ldbm_back_add( #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ERR, - "ldbm_back_add: entry (%s) failed schema check.\n", - e->e_dn )); + "ldbm_back_add: entry (%s) failed schema check.\n", + e->e_dn )); #else Debug( LDAP_DEBUG_TRACE, "entry failed schema check: %s\n", text, 0, 0 ); @@ -90,7 +89,7 @@ ldbm_back_add( /* get parent with writer lock */ if ( (p = dn2entry_w( be, pdn, &matched )) == NULL ) { - char *matched_dn; + char *matched_dn = NULL; struct berval **refs; ldap_pvt_thread_mutex_unlock(&li->li_add_mutex); @@ -98,33 +97,31 @@ ldbm_back_add( if ( matched != NULL ) { matched_dn = ch_strdup( matched->e_dn ); refs = is_entry_referral( matched ) - ? get_entry_referrals( be, conn, op, matched ) + ? get_entry_referrals( be, conn, op, matched, + e->e_dn, LDAP_SCOPE_DEFAULT ) : NULL; cache_return_entry_r( &li->li_cache, matched ); } else { - matched_dn = NULL; - refs = default_referral; + refs = referral_rewrite( default_referral, + NULL, e->e_dn, LDAP_SCOPE_DEFAULT ); } #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ERR, - "ldbm_back_add: Parent of (%s) does not exist.\n", - e->e_dn )); + "ldbm_back_add: Parent of (%s) does not exist.\n", + e->e_dn )); #else Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0, 0, 0 ); #endif - send_ldap_result( conn, op, LDAP_REFERRAL, matched_dn, refs == NULL ? "parent does not exist" : "parent is referral", refs, NULL ); - if( matched != NULL ) { - ber_bvecfree( refs ); - free( matched_dn ); - } + ber_bvecfree( refs ); + free( matched_dn ); free( pdn ); return -1; @@ -182,7 +179,8 @@ ldbm_back_add( /* parent is a referral, don't allow add */ char *matched_dn = ch_strdup( p->e_dn ); struct berval **refs = is_entry_referral( p ) - ? get_entry_referrals( be, conn, op, p ) + ? get_entry_referrals( be, conn, op, p, + e->e_dn, LDAP_SCOPE_DEFAULT ) : NULL; /* free parent and writer lock */ @@ -290,7 +288,6 @@ ldbm_back_add( 0 ); #endif - send_ldap_result( conn, op, rc > 0 ? LDAP_ALREADY_EXISTS : LDAP_OTHER, NULL, rc > 0 ? NULL : "cache add failed", NULL, NULL ); diff --git a/servers/slapd/back-ldbm/bind.c b/servers/slapd/back-ldbm/bind.c index d33ea5fd30..af73ca9a0d 100644 --- a/servers/slapd/back-ldbm/bind.c +++ b/servers/slapd/back-ldbm/bind.c @@ -45,7 +45,7 @@ ldbm_back_bind( #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, - "ldbm_back_bind: dn: %s.\n", dn )); + "ldbm_back_bind: dn: %s.\n", dn )); #else Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_bind: dn: %s\n", dn, 0, 0); #endif @@ -63,12 +63,15 @@ ldbm_back_bind( matched_dn = ch_strdup( matched->e_dn ); refs = is_entry_referral( matched ) - ? get_entry_referrals( be, conn, op, matched ) + ? get_entry_referrals( be, conn, op, matched, + dn, LDAP_SCOPE_DEFAULT ) : NULL; cache_return_entry_r( &li->li_cache, matched ); + } else { - refs = default_referral; + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); } /* allow noauth binds */ @@ -96,10 +99,8 @@ ldbm_back_bind( NULL, NULL, NULL, NULL ); } - if ( matched != NULL ) { - ber_bvecfree( refs ); - free( matched_dn ); - } + ber_bvecfree( refs ); + free( matched_dn ); return( rc ); } @@ -128,7 +129,7 @@ ldbm_back_bind( if ( is_entry_referral( e ) ) { /* entry is a referral, don't allow bind */ struct berval **refs = get_entry_referrals( be, - conn, op, e ); + conn, op, e, dn, LDAP_SCOPE_DEFAULT ); #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, diff --git a/servers/slapd/back-ldbm/compare.c b/servers/slapd/back-ldbm/compare.c index b722de01fb..4134bb115f 100644 --- a/servers/slapd/back-ldbm/compare.c +++ b/servers/slapd/back-ldbm/compare.c @@ -41,20 +41,20 @@ ldbm_back_compare( if ( matched != NULL ) { matched_dn = ch_strdup( matched->e_dn ); refs = is_entry_referral( matched ) - ? get_entry_referrals( be, conn, op, matched ) + ? get_entry_referrals( be, conn, op, matched, + dn, LDAP_SCOPE_DEFAULT ) : NULL; cache_return_entry_r( &li->li_cache, matched ); } else { - refs = default_referral; + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); } send_ldap_result( conn, op, LDAP_REFERRAL, matched_dn, NULL, refs, NULL ); - if( matched != NULL ) { - ber_bvecfree( refs ); - free( matched_dn ); - } + ber_bvecfree( refs ); + free( matched_dn ); return( 1 ); } @@ -62,7 +62,7 @@ ldbm_back_compare( if (!manageDSAit && is_entry_referral( e ) ) { /* entry is a referral, don't allow add */ struct berval **refs = get_entry_referrals( be, - conn, op, e ); + conn, op, e, dn, LDAP_SCOPE_DEFAULT ); #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, diff --git a/servers/slapd/back-ldbm/delete.c b/servers/slapd/back-ldbm/delete.c index 9e14f260f3..1dd4696ed3 100644 --- a/servers/slapd/back-ldbm/delete.c +++ b/servers/slapd/back-ldbm/delete.c @@ -36,43 +36,42 @@ ldbm_back_delete( #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, - "ldbm_back_delete: %s\n", dn )); + "ldbm_back_delete: %s\n", dn )); #else Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_delete: %s\n", dn, 0, 0); #endif - /* get entry with writer lock */ if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) { char *matched_dn = NULL; - struct berval **refs = NULL; + struct berval **refs; #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_back_delete: no such object %s\n", dn )); + "ldbm_back_delete: no such object %s\n", dn )); #else Debug(LDAP_DEBUG_ARGS, "<=- ldbm_back_delete: no such object %s\n", dn, 0, 0); #endif - if ( matched != NULL ) { matched_dn = ch_strdup( matched->e_dn ); refs = is_entry_referral( matched ) - ? get_entry_referrals( be, conn, op, matched ) + ? get_entry_referrals( be, conn, op, matched, + dn, LDAP_SCOPE_DEFAULT ) : NULL; cache_return_entry_r( &li->li_cache, matched ); + } else { - refs = default_referral; + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); } send_ldap_result( conn, op, LDAP_REFERRAL, matched_dn, NULL, refs, NULL ); - if ( matched != NULL ) { - ber_bvecfree( refs ); - free( matched_dn ); - } + ber_bvecfree( refs ); + free( matched_dn ); return( -1 ); } @@ -81,7 +80,7 @@ ldbm_back_delete( /* parent is a referral, don't allow add */ /* parent is an alias, don't allow add */ struct berval **refs = get_entry_referrals( be, - conn, op, e ); + conn, op, e, dn, LDAP_SCOPE_DEFAULT ); #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, diff --git a/servers/slapd/back-ldbm/modify.c b/servers/slapd/back-ldbm/modify.c index 18c83efc7c..37fb844dd9 100644 --- a/servers/slapd/back-ldbm/modify.c +++ b/servers/slapd/back-ldbm/modify.c @@ -46,7 +46,7 @@ int ldbm_modify_internal( #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, - "ldbm_modify_internal: %s\n", dn )); + "ldbm_modify_internal: %s\n", dn )); #else Debug(LDAP_DEBUG_TRACE, "ldbm_modify_internal: %s\n", dn, 0, 0); #endif @@ -66,7 +66,7 @@ int ldbm_modify_internal( case LDAP_MOD_ADD: #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, - "ldbm_modify_internal: add\n" )); + "ldbm_modify_internal: add\n" )); #else Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: add\n", 0, 0, 0); #endif @@ -77,8 +77,8 @@ int ldbm_modify_internal( *text = "modify: add values failed"; #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_modify_internal: failed %d (%s)\n", - err, *text )); + "ldbm_modify_internal: failed %d (%s)\n", + err, *text )); #else Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n", err, *text, 0); @@ -89,7 +89,7 @@ int ldbm_modify_internal( case LDAP_MOD_DELETE: #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, - "ldbm_modify_internal: delete\n" )); + "ldbm_modify_internal: delete\n" )); #else Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: delete\n", 0, 0, 0); #endif @@ -100,7 +100,7 @@ int ldbm_modify_internal( *text = "modify: delete values failed"; #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_modify_internal: failed %d (%s)\n", err, *text )); + "ldbm_modify_internal: failed %d (%s)\n", err, *text )); #else Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n", err, *text, 0); @@ -111,7 +111,7 @@ int ldbm_modify_internal( case LDAP_MOD_REPLACE: #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, - "ldbm_modify_internal: replace\n" )); + "ldbm_modify_internal: replace\n" )); #else Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: replace\n", 0, 0, 0); #endif @@ -122,7 +122,7 @@ int ldbm_modify_internal( *text = "modify: replace values failed"; #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_modify_internal: failed %d (%s)\n", err, *text )); + "ldbm_modify_internal: failed %d (%s)\n", err, *text )); #else Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n", err, *text, 0); @@ -134,7 +134,7 @@ int ldbm_modify_internal( case SLAP_MOD_SOFTADD: #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, - "ldbm_modify_internal: softadd\n" )); + "ldbm_modify_internal: softadd\n" )); #else Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: softadd\n", 0, 0, 0); #endif @@ -165,7 +165,7 @@ int ldbm_modify_internal( default: #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ERR, - "ldbm_modify_internal: invalid op %d\n", mod->sm_op )); + "ldbm_modify_internal: invalid op %d\n", mod->sm_op )); #else Debug(LDAP_DEBUG_ANY, "ldbm_modify_internal: invalid op %d\n", mod->sm_op, 0, 0); @@ -175,7 +175,7 @@ int ldbm_modify_internal( *text = "Invalid modify operation"; #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_modify_internal: %d (%s)\n", err, *text )); + "ldbm_modify_internal: %d (%s)\n", err, *text )); #else Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n", err, *text, 0); @@ -208,8 +208,8 @@ int ldbm_modify_internal( e->e_attrs = save_attrs; #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ERR, - "ldbm_modify_internal: entry failed schema check: %s\n", - *text )); + "ldbm_modify_internal: entry failed schema check: %s\n", + *text )); #else Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n", *text, 0, 0 ); @@ -261,7 +261,7 @@ ldbm_back_modify( #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, - "ldbm_back_modify: enter\n" )); + "ldbm_back_modify: enter\n" )); #else Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0); #endif @@ -270,25 +270,25 @@ ldbm_back_modify( /* acquire and lock entry */ if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) { char* matched_dn = NULL; - struct berval **refs = NULL; + struct berval **refs; if ( matched != NULL ) { matched_dn = ch_strdup( matched->e_dn ); refs = is_entry_referral( matched ) - ? get_entry_referrals( be, conn, op, matched ) + ? get_entry_referrals( be, conn, op, matched, + dn, LDAP_SCOPE_DEFAULT ) : NULL; cache_return_entry_r( &li->li_cache, matched ); } else { - refs = default_referral; + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); } send_ldap_result( conn, op, LDAP_REFERRAL, matched_dn, NULL, refs, NULL ); - if ( matched != NULL ) { - ber_bvecfree( refs ); - free( matched_dn ); - } + ber_bvecfree( refs ); + free( matched_dn ); return( -1 ); } @@ -297,7 +297,7 @@ ldbm_back_modify( /* parent is a referral, don't allow add */ /* parent is an alias, don't allow add */ struct berval **refs = get_entry_referrals( be, - conn, op, e ); + conn, op, e, dn, LDAP_SCOPE_DEFAULT ); #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, diff --git a/servers/slapd/back-ldbm/modrdn.c b/servers/slapd/back-ldbm/modrdn.c index 0d1cd28f71..2851f80359 100644 --- a/servers/slapd/back-ldbm/modrdn.c +++ b/servers/slapd/back-ldbm/modrdn.c @@ -77,36 +77,36 @@ ldbm_back_modrdn( #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY, - "ldbm_back_modrdn: dn: %s newSuperior=%s\n", - dn ? dn : "NULL", newSuperior ? newSuperior : "NULL" )); + "ldbm_back_modrdn: dn: %s newSuperior=%s\n", + dn ? dn : "NULL", newSuperior ? newSuperior : "NULL" )); #else Debug( LDAP_DEBUG_TRACE, "==>ldbm_back_modrdn(newSuperior=%s)\n", - (newSuperior ? newSuperior : "NULL"), - 0, 0 ); + (newSuperior ? newSuperior : "NULL"), + 0, 0 ); #endif /* get entry with writer lock */ if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) { char* matched_dn = NULL; - struct berval** refs = NULL; + struct berval** refs; if( matched != NULL ) { matched_dn = strdup( matched->e_dn ); refs = is_entry_referral( matched ) - ? get_entry_referrals( be, conn, op, matched ) + ? get_entry_referrals( be, conn, op, matched, + dn, LDAP_SCOPE_DEFAULT ) : NULL; cache_return_entry_r( &li->li_cache, matched ); } else { - refs = default_referral; + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); } send_ldap_result( conn, op, LDAP_REFERRAL, matched_dn, NULL, refs, NULL ); - if ( matched != NULL ) { - ber_bvecfree( refs ); - free( matched_dn ); - } + ber_bvecfree( refs ); + free( matched_dn ); return( -1 ); } @@ -115,13 +115,13 @@ ldbm_back_modrdn( /* parent is a referral, don't allow add */ /* parent is an alias, don't allow add */ struct berval **refs = get_entry_referrals( be, - conn, op, e ); + conn, op, e, dn, LDAP_SCOPE_DEFAULT ); #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_back_modrdn: entry %s is a referral\n", e->e_dn )); + "ldbm_back_modrdn: entry %s is a referral\n", e->e_dn )); #else - Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, + Debug( LDAP_DEBUG_TRACE, "entry %s is referral\n", e->e_dn, 0, 0 ); #endif @@ -135,9 +135,9 @@ ldbm_back_modrdn( if ( has_children( be, e ) ) { #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_back_modrdn: entry %s has children\n", e->e_dn )); + "ldbm_back_modrdn: entry %s has children\n", e->e_dn )); #else - Debug( LDAP_DEBUG_TRACE, "entry %s referral\n", e->e_dn, + Debug( LDAP_DEBUG_TRACE, "entry %s has children\n", e->e_dn, 0, 0 ); #endif @@ -154,7 +154,7 @@ ldbm_back_modrdn( if( (p = dn2entry_w( be, p_ndn, NULL )) == NULL) { #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_back_modrdn: parent of %s does not exist\n", e->e_ndn )); + "ldbm_back_modrdn: parent of %s does not exist\n", e->e_ndn )); #else Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0, 0, 0); @@ -334,11 +334,11 @@ ldbm_back_modrdn( /* parent is an alias, don't allow add */ #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_back_modrdn: entry (%s) is a referral\n", - np->e_dn )); + "ldbm_back_modrdn: entry (%s) is a referral\n", + np->e_dn )); #else - Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, - 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "entry (%s) is referral\n", + np->e_dn, 0, 0 ); #endif send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, @@ -349,11 +349,11 @@ ldbm_back_modrdn( #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, - "ldbm_back_modrdn: wr to new parent's children OK.\n" )); + "ldbm_back_modrdn: wr to new parent's children OK.\n" )); #else Debug( LDAP_DEBUG_TRACE, - "ldbm_back_modrdn: wr to new parent's children OK\n", - 0, 0 , 0 ); + "ldbm_back_modrdn: wr to new parent's children OK\n", + 0, 0, 0 ); #endif new_parent_dn = np_dn; @@ -367,10 +367,10 @@ ldbm_back_modrdn( #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, - "ldbm_back_modrdn: new ndn=%s\n", new_ndn )); + "ldbm_back_modrdn: new ndn=%s\n", new_ndn )); #else Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n", - new_ndn, 0, 0 ); + new_ndn, 0, 0 ); #endif /* check for abandon */ diff --git a/servers/slapd/back-ldbm/referral.c b/servers/slapd/back-ldbm/referral.c index 678393aa46..ae80f3617f 100644 --- a/servers/slapd/back-ldbm/referral.c +++ b/servers/slapd/back-ldbm/referral.c @@ -42,65 +42,80 @@ ldbm_back_referrals( e = dn2entry_r( be, ndn, &matched ); if ( e == NULL ) { char *matched_dn = NULL; - struct berval **refs = default_referral; + struct berval **refs = NULL; if ( matched != NULL ) { matched_dn = ch_strdup( matched->e_dn ); #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, - "ldbm_back_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", - op->o_tag, dn, matched_dn )); + "ldbm_back_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", + op->o_tag, dn, matched_dn )); #else Debug( LDAP_DEBUG_TRACE, "ldbm_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", op->o_tag, dn, matched_dn ); #endif - - refs = is_entry_referral( matched ) - ? get_entry_referrals( be, conn, op, matched ) - : NULL; + if( is_entry_referral( matched ) ) { + rc = LDAP_OTHER; + refs = get_entry_referrals( be, conn, op, matched, + dn, LDAP_SCOPE_DEFAULT ); + } cache_return_entry_r( &li->li_cache, matched ); + + } else if ( default_referral != NULL ) { + rc = LDAP_OTHER; + refs = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); } if( refs != NULL ) { /* send referrals */ send_ldap_result( conn, op, rc = LDAP_REFERRAL, matched_dn, NULL, refs, NULL ); - } - - if( matched != NULL ) { ber_bvecfree( refs ); - free( matched_dn ); + + } else if ( rc != LDAP_SUCCESS ) { + send_ldap_result( conn, op, rc, matched_dn, + matched_dn ? "bad referral object" : "bad default referral", + NULL, NULL ); } + free( matched_dn ); return rc; } if ( is_entry_referral( e ) ) { /* entry is a referral */ struct berval **refs = get_entry_referrals( be, - conn, op, e ); + conn, op, e, dn, LDAP_SCOPE_DEFAULT ); + struct berval **rrefs = referral_rewrite( + refs, e->e_dn, dn, LDAP_SCOPE_DEFAULT ); #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, - "ldbm_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", - op->o_tag, dn, e->e_dn )); + "ldbm_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", + op->o_tag, dn, e->e_dn )); #else Debug( LDAP_DEBUG_TRACE, "ldbm_referrals: op=%ld target=\"%s\" matched=\"%s\"\n", op->o_tag, dn, e->e_dn ); #endif - - if( refs != NULL ) { + if( rrefs != NULL ) { send_ldap_result( conn, op, rc = LDAP_REFERRAL, - e->e_dn, NULL, refs, NULL ); + e->e_dn, NULL, rrefs, NULL ); + + ber_bvecfree( rrefs ); + + } else { + send_ldap_result( conn, op, rc = LDAP_OTHER, e->e_dn, + "bad referral object", NULL, NULL ); } - ber_bvecfree( refs ); + if( refs != NULL ) ber_bvecfree( refs ); } cache_return_entry_r( &li->li_cache, e ); diff --git a/servers/slapd/back-ldbm/search.c b/servers/slapd/back-ldbm/search.c index 5e0d46fd73..ef0b4ab268 100644 --- a/servers/slapd/back-ldbm/search.c +++ b/servers/slapd/back-ldbm/search.c @@ -52,6 +52,7 @@ ldbm_back_search( char *realbase = NULL; int nentries = 0; int manageDSAit = get_manageDSAit( op ); + int cscope = LDAP_SCOPE_DEFAULT; struct slap_limits_set *limit = NULL; int isroot = 0; @@ -95,54 +96,73 @@ ldbm_back_search( struct berval **refs = NULL; if ( matched != NULL ) { + struct berval **erefs; matched_dn = ch_strdup( matched->e_dn ); - refs = is_entry_referral( matched ) - ? get_entry_referrals( be, conn, op, matched ) + erefs = is_entry_referral( matched ) + ? get_entry_referrals( be, conn, op, matched, + base, scope ) : NULL; cache_return_entry_r( &li->li_cache, matched ); + if( erefs ) { + refs = referral_rewrite( erefs, matched_dn, + base, scope ); + + ber_bvecfree( erefs ); + } + } else { - refs = default_referral; + refs = referral_rewrite( default_referral, + NULL, base, scope ); } send_ldap_result( conn, op, err, matched_dn, text, refs, NULL ); - if( matched != NULL ) { - ber_bvecfree( refs ); - free( matched_dn ); - } - + ber_bvecfree( refs ); + free( matched_dn ); return 1; } if (!manageDSAit && is_entry_referral( e ) ) { /* entry is a referral, don't allow add */ char *matched_dn = ch_strdup( e->e_dn ); - struct berval **refs = get_entry_referrals( be, - conn, op, e ); + struct berval **erefs = get_entry_referrals( be, + conn, op, e, base, scope ); + struct berval **refs = NULL; cache_return_entry_r( &li->li_cache, e ); #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_search: entry (%s) is a referral.\n", - e->e_dn )); + "ldbm_search: entry (%s) is a referral.\n", + e->e_dn )); #else Debug( LDAP_DEBUG_TRACE, "ldbm_search: entry is referral\n", 0, 0, 0 ); #endif + if( erefs ) { + refs = referral_rewrite( erefs, matched_dn, + base, scope ); - send_ldap_result( conn, op, LDAP_REFERRAL, - matched_dn, NULL, refs, NULL ); + ber_bvecfree( erefs ); + } + + if( refs ) { + send_ldap_result( conn, op, LDAP_REFERRAL, + matched_dn, NULL, refs, NULL ); + ber_bvecfree( refs ); + + } else { + send_ldap_result( conn, op, LDAP_OTHER, matched_dn, + "bad referral object", NULL, NULL ); + } - ber_bvecfree( refs ); free( matched_dn ); - return 1; } @@ -152,9 +172,12 @@ ldbm_back_search( } if ( scope == LDAP_SCOPE_BASE ) { + cscope = LDAP_SCOPE_BASE; candidates = base_candidate( be, e ); } else { + cscope = ( scope != LDAP_SCOPE_SUBTREE ) + ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE; candidates = search_candidates( be, e, filter, scope, deref, manageDSAit ); } @@ -169,13 +192,12 @@ searchit: /* no candidates */ #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_search: no candidates\n" )); + "ldbm_search: no candidates\n" )); #else Debug( LDAP_DEBUG_TRACE, "ldbm_search: no candidates\n", 0, 0, 0 ); #endif - send_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, NULL, 0 ); @@ -257,7 +279,7 @@ searchit: for ( id = idl_firstid( candidates, &cursor ); id != NOID; id = idl_nextid( candidates, &cursor ) ) { - int scopeok = 0; + int scopeok = 0; /* check for abandon */ ldap_pvt_thread_mutex_lock( &op->o_abandonmutex ); @@ -284,14 +306,13 @@ searchit: if ( e == NULL ) { #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_INFO, - "ldbm_search: candidate %ld not found.\n", id )); + "ldbm_search: candidate %ld not found.\n", id )); #else Debug( LDAP_DEBUG_TRACE, "ldbm_search: candidate %ld not found\n", id, 0, 0 ); #endif - goto loop_continue; } @@ -327,10 +348,10 @@ searchit: /* alias is within scope */ #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1, - "ldbm_search: \"%s\" in subtree\n", e->e_dn )); + "ldbm_search: alias \"%s\" in subtree\n", e->e_dn )); #else Debug( LDAP_DEBUG_TRACE, - "ldbm_search: \"%s\" in subtree\n", + "ldbm_search: alias \"%s\" in subtree\n", e->e_dn, 0, 0 ); #endif @@ -373,11 +394,13 @@ searchit: } if( scopeok ) { - struct berval **refs = get_entry_referrals( - be, conn, op, e ); + struct berval **erefs = get_entry_referrals( + be, conn, op, e, NULL, cscope ); + struct berval **refs = referral_rewrite( erefs, e->e_dn, + NULL, scope ); send_search_reference( be, conn, op, - e, refs, scope, NULL, &v2refs ); + e, refs, NULL, &v2refs ); ber_bvecfree( refs ); @@ -452,24 +475,23 @@ searchit: } else { #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL2, - "ldbm_search: candidate %ld scope not okay\n", id )); + "ldbm_search: candidate entry %ld scope not okay\n", id )); #else Debug( LDAP_DEBUG_TRACE, - "ldbm_search: candidate %ld scope not okay\n", + "ldbm_search: candidate entry %ld scope not okay\n", id, 0, 0 ); #endif - } + } else { #ifdef NEW_LOGGING LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL2, - "ldbm_search: candidate %ld does not match filter\n", id )); + "ldbm_search: candidate entry %ld does not match filter\n", id )); #else Debug( LDAP_DEBUG_TRACE, - "ldbm_search: candidate %ld does not match filter\n", + "ldbm_search: candidate entry %ld does not match filter\n", id, 0, 0 ); #endif - } loop_continue: @@ -480,6 +502,7 @@ loop_continue: ldap_pvt_thread_yield(); } + send_search_result( conn, op, v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, NULL, NULL, v2refs, NULL, nentries ); diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c index a4a10047d1..6480cf7fb8 100644 --- a/servers/slapd/bind.c +++ b/servers/slapd/bind.c @@ -430,8 +430,13 @@ do_bind( if ( (be = select_backend( ndn, 0 )) == NULL ) { if ( default_referral ) { + struct berval **ref = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, - NULL, NULL, default_referral, NULL ); + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvecfree( ref ); } else { /* noSuchObject is not allowed to be returned by bind */ diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c index 1823ec18ba..2f4f03f6ae 100644 --- a/servers/slapd/compare.c +++ b/servers/slapd/compare.c @@ -224,8 +224,13 @@ do_compare( * if we don't hold it. */ if ( (be = select_backend( ndn, manageDSAit )) == NULL ) { + struct berval **ref = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, - NULL, NULL, default_referral, NULL ); + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvecfree( ref ); rc = 0; goto cleanup; } diff --git a/servers/slapd/config.c b/servers/slapd/config.c index cfeb8c1bae..e912ddfe3f 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -1487,6 +1487,19 @@ read_config( const char *fname ) return( 1 ); } + if( validate_global_referral( cargv[1] ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, "%s: line %d: " + "invalid URL (%s) in \"referral\" line.\n", + fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "invalid URL (%s) in \"referral\" line.\n", + fname, lineno, cargv[1] ); +#endif + return 1; + } + vals[0]->bv_val = cargv[1]; vals[0]->bv_len = strlen( vals[0]->bv_val ); value_add( &default_referral, vals ); @@ -1772,12 +1785,12 @@ read_config( const char *fname ) } else if ( strcasecmp( cargv[0], "updateref" ) == 0 ) { if ( cargc < 2 ) { #ifdef NEW_LOGGING - LDAP_LOG(( "config", LDAP_LEVEL_CRIT, - "%s: line %d: missing url in \"updateref \" " - "line.\n", fname, lineno )); + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, "%s: line %d: " + "missing url in \"updateref \" line.\n", + fname, lineno )); #else - Debug( LDAP_DEBUG_ANY, - "%s: line %d: missing url in \"updateref \" line\n", + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "missing url in \"updateref \" line\n", fname, lineno, 0 ); #endif @@ -1785,32 +1798,46 @@ read_config( const char *fname ) } if ( be == NULL ) { #ifdef NEW_LOGGING - LDAP_LOG(( "config", LDAP_LEVEL_INFO, - "%s: line %d: updateref line must appear inside " - "a database definition (ignored)\n", fname, lineno )); + LDAP_LOG(( "config", LDAP_LEVEL_INFO, "%s: line %d: " + "updateref line must appear inside a database definition " + "(ignored)\n", fname, lineno )); #else - Debug( LDAP_DEBUG_ANY, -"%s: line %d: updateref line must appear inside a database definition (ignored)\n", - fname, lineno, 0 ); + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "updateref line must appear inside a database definition " + "(ignored)\n", fname, lineno, 0 ); #endif + return 1; } else if ( be->be_update_ndn == NULL ) { #ifdef NEW_LOGGING - LDAP_LOG(( "config", LDAP_LEVEL_INFO, - "%s: line %d: updateref line must come after updatedn " - "(ignored).\n", fname, lineno )); + LDAP_LOG(( "config", LDAP_LEVEL_INFO, "%s: line %d: " + "updateref line must come after updatedn (ignored).\n", + fname, lineno )); #else - Debug( LDAP_DEBUG_ANY, -"%s: line %d: updateref line must after updatedn (ignored)\n", + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "updateref line must after updatedn (ignored)\n", fname, lineno, 0 ); #endif - - } else { - vals[0]->bv_val = cargv[1]; - vals[0]->bv_len = strlen( vals[0]->bv_val ); - value_add( &be->be_update_refs, vals ); + return 1; } + if( validate_global_referral( cargv[1] ) ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, "%s: line %d: " + "invalid URL (%s) in \"updateref\" line.\n", + fname, lineno, cargv[1] )); +#else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "invalid URL (%s) in \"updateref\" line.\n", + fname, lineno, cargv[1] ); +#endif + return 1; + } + + vals[0]->bv_val = cargv[1]; + vals[0]->bv_len = strlen( vals[0]->bv_val ); + value_add( &be->be_update_refs, vals ); + /* replication log file to which changes are appended */ } else if ( strcasecmp( cargv[0], "replogfile" ) == 0 ) { if ( cargc < 2 ) { diff --git a/servers/slapd/delete.c b/servers/slapd/delete.c index 89ca8964dc..433e20855b 100644 --- a/servers/slapd/delete.c +++ b/servers/slapd/delete.c @@ -125,8 +125,13 @@ do_delete( * if we don't hold it. */ if ( (be = select_backend( ndn, manageDSAit )) == NULL ) { + struct berval **ref = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, - NULL, NULL, default_referral, NULL ); + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvecfree( ref ); goto cleanup; } @@ -171,8 +176,15 @@ do_delete( } #ifndef SLAPD_MULTIMASTER } else { + struct berval **defref = be->be_update_refs + ? be->be_update_refs : default_referral; + struct berval **ref = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, - be->be_update_refs ? be->be_update_refs : default_referral, NULL ); + ref ? ref : defref, NULL ); + + ber_bvecfree( ref ); #endif } diff --git a/servers/slapd/extended.c b/servers/slapd/extended.c index 9a011b818e..5ac0a4e0d2 100644 --- a/servers/slapd/extended.c +++ b/servers/slapd/extended.c @@ -187,12 +187,15 @@ do_extended( &rspoid, &rspdata, &rspctrls, &text, &refs ); if( rc != SLAPD_ABANDON ) { - if (rc == LDAP_REFERRAL) { - refs = default_referral; + if ( rc == LDAP_REFERRAL && refs == NULL ) { + refs = referral_rewrite( default_referral, + NULL, NULL, LDAP_SCOPE_DEFAULT ); } send_ldap_extended( conn, op, rc, NULL, text, refs, rspoid, rspdata, rspctrls ); + + ber_bvecfree( refs ); } if ( rspoid != NULL ) { diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index c3e21d1b8e..e2086b81a5 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -252,8 +252,13 @@ do_modify( * if we don't hold it. */ if ( (be = select_backend( ndn, manageDSAit )) == NULL ) { + struct berval **ref = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, - NULL, NULL, default_referral, NULL ); + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvecfree( ref ); goto cleanup; } @@ -337,9 +342,15 @@ do_modify( #ifndef SLAPD_MULTIMASTER /* send a referral */ } else { + struct berval **defref = be->be_update_refs + ? be->be_update_refs : default_referral; + struct berval **ref = referral_rewrite( defref, + NULL, dn, LDAP_SCOPE_DEFAULT ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, - be->be_update_refs ? be->be_update_refs : default_referral, - NULL ); + ref ? ref : defref, NULL ); + + ber_bvecfree( ref ); #endif } } else { diff --git a/servers/slapd/modrdn.c b/servers/slapd/modrdn.c index 9e4422d7e7..82908716c7 100644 --- a/servers/slapd/modrdn.c +++ b/servers/slapd/modrdn.c @@ -250,8 +250,13 @@ do_modrdn( * if we don't hold it. */ if ( (be = select_backend( ndn, manageDSAit )) == NULL ) { + struct berval **ref = referral_rewrite( default_referral, + NULL, dn, LDAP_SCOPE_DEFAULT ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, - NULL, NULL, default_referral, NULL ); + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvecfree( ref ); goto cleanup; } @@ -321,8 +326,15 @@ do_modrdn( } #ifndef SLAPD_MULTIMASTER } else { + struct berval **defref = be->be_update_refs + ? be->be_update_refs : default_referral; + struct berval **ref = referral_rewrite( defref, + NULL, dn, LDAP_SCOPE_DEFAULT ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL, - be->be_update_refs ? be->be_update_refs : default_referral, NULL ); + ref ? ref : defref, NULL ); + + ber_bvecfree( ref ); #endif } } else { diff --git a/servers/slapd/passwd.c b/servers/slapd/passwd.c index 6e0b31b0e3..c5ada769ff 100644 --- a/servers/slapd/passwd.c +++ b/servers/slapd/passwd.c @@ -45,7 +45,8 @@ int passwd_extop( } else if( conn->c_authz_backend->be_update_ndn != NULL ) { /* we SHOULD return a referral in this case */ - *refs = conn->c_authz_backend->be_update_refs; + *refs = referral_rewrite( conn->c_authz_backend->be_update_refs, + NULL, NULL, LDAP_SCOPE_DEFAULT ); rc = LDAP_REFERRAL; } else { diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index fad2d895b4..4bf68057d6 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -503,12 +503,24 @@ LDAP_SLAPD_F (int) add_replica_suffix LDAP_P(( Backend *be, int nr, const char * LDAP_SLAPD_F (void) replog LDAP_P(( Backend *be, Operation *op, char *dn, void *change )); /* - * result.c + * referral.c */ +LDAP_SLAPD_F (int) validate_global_referral LDAP_P(( + const char *url )); LDAP_SLAPD_F (struct berval **) get_entry_referrals LDAP_P(( Backend *be, Connection *conn, Operation *op, - Entry *e )); + Entry *e, const char *target, int scope )); + +LDAP_SLAPD_F (struct berval **) referral_rewrite LDAP_P(( + struct berval **refs, + const char *base, + const char *target, + int scope )); + +/* + * result.c + */ LDAP_SLAPD_F (void) send_ldap_result LDAP_P(( Connection *conn, Operation *op, @@ -549,7 +561,7 @@ LDAP_SLAPD_F (void) send_search_result LDAP_P(( LDAP_SLAPD_F (int) send_search_reference LDAP_P(( Backend *be, Connection *conn, Operation *op, - Entry *e, struct berval **refs, int scope, + Entry *e, struct berval **refs, LDAPControl **ctrls, struct berval ***v2refs )); diff --git a/servers/slapd/referral.c b/servers/slapd/referral.c new file mode 100644 index 0000000000..178761ee7a --- /dev/null +++ b/servers/slapd/referral.c @@ -0,0 +1,336 @@ +/* referral.c - muck with referrals */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "slap.h" + +/* + * This routine generates the DN appropriate to return in + * an LDAP referral. + */ +static char * referral_dn_muck( + const char * refDN, + const char * baseDN, + const char * targetDN ) +{ + char *tmp; + char *nrefDN = NULL; + char *nbaseDN = NULL; + char *ntargetDN = NULL; + + if( !baseDN ) { + /* no base, return target */ + return targetDN ? ch_strdup( targetDN ) : NULL; + } + + if( refDN ) { + nrefDN = dn_validate( tmp = ch_strdup( refDN ) ); + if( !nrefDN ) { + /* Invalid refDN */ + ch_free( tmp ); + return NULL; + } + } + + if( !targetDN ) { + /* continuation reference + * if refDN present return refDN + * else return baseDN + */ + return nrefDN ? nrefDN : ch_strdup( baseDN ); + } + + ntargetDN = dn_validate( tmp = ch_strdup( targetDN ) ); + if( !ntargetDN ) { + ch_free( tmp ); + ch_free( nrefDN ); + return NULL; + } + + if( nrefDN ) { + nbaseDN = dn_validate( tmp = ch_strdup( baseDN ) ); + if( !nbaseDN ) { + /* Invalid baseDN */ + ch_free( ntargetDN ); + ch_free( nrefDN ); + ch_free( tmp ); + return NULL; + } + + if( strcasecmp( nbaseDN, nrefDN ) == 0 ) { + ch_free( nrefDN ); + ch_free( nbaseDN ); + return ntargetDN; + } + + { + /* + * FIXME: string based mucking + */ + char *muck; + size_t reflen, baselen, targetlen, mucklen; + + reflen = strlen( nrefDN ); + baselen = strlen( nbaseDN ); + targetlen = strlen( ntargetDN ); + + if( targetlen < baselen ) { + ch_free( nrefDN ); + ch_free( nbaseDN ); + return ntargetDN; + } + + if( strcasecmp( &ntargetDN[targetlen-baselen], nbaseDN ) ) { + /* target not subordinate to base */ + ch_free( nrefDN ); + ch_free( nbaseDN ); + return ntargetDN; + } + + mucklen = targetlen + reflen - baselen; + muck = ch_malloc( 1 + mucklen ); + + strncpy( muck, ntargetDN, targetlen-baselen ); + strcpy( &muck[targetlen-baselen], nrefDN ); + + ch_free( nrefDN ); + ch_free( nbaseDN ); + ch_free( ntargetDN ); + + return muck; + } + } + + return ntargetDN; +} + + +/* validate URL for global referral use + * LDAP URLs must not have: + * DN, attrs, scope, nor filter + * Any non-LDAP URL is okay + * + * XXYYZ: should return an error string + */ +int validate_global_referral( const char *url ) +{ + int rc; + LDAPURLDesc *lurl; + + rc = ldap_url_parse_ext( url, &lurl ); + + switch( rc ) { + case LDAP_URL_SUCCESS: + break; + + case LDAP_URL_ERR_BADSCHEME: + /* not LDAP hence valid */ + return 0; + + default: + /* other error, bail */ +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "referral: invalid URL (%s): %s (%d)\n", + url, "" /* ldap_url_error2str(rc) */, rc )); +#else + Debug( LDAP_DEBUG_ANY, + "referral: invalid URL (%s): %s (%d)\n", + url, "" /* ldap_url_error2str(rc) */, rc ); +#endif + return 1; + } + + rc = 0; + + if( lurl->lud_dn && *lurl->lud_dn ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "referral: URL (%s): contains DN\n", + url )); +#else + Debug( LDAP_DEBUG_ANY, + "referral: URL (%s): contains DN\n", + url, 0, 0 ); +#endif + rc = 1; + + } else if( lurl->lud_attrs ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "referral: URL (%s): requests attributes\n", + url )); +#else + Debug( LDAP_DEBUG_ANY, + "referral: URL (%s): requests attributes\n", + url, 0, 0 ); +#endif + rc = 1; + + } else if( lurl->lud_scope != LDAP_SCOPE_DEFAULT ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "referral: URL (%s): contains explicit scope\n", + url )); +#else + Debug( LDAP_DEBUG_ANY, + "referral: URL (%s): contains explicit scope\n", + url, 0, 0 ); +#endif + rc = 1; + + } else if( lurl->lud_filter ) { +#ifdef NEW_LOGGING + LDAP_LOG(( "config", LDAP_LEVEL_CRIT, + "referral: URL (%s): contains explicit filter\n", + url )); +#else + Debug( LDAP_DEBUG_ANY, + "referral: URL (%s): contains explicit filter\n", + url, 0, 0 ); +#endif + rc = 1; + } + + ldap_free_urldesc( lurl ); + return rc; +} + +struct berval ** referral_rewrite( + struct berval **in, + const char *base, + const char *target, + int scope ) +{ + int i, j; + struct berval **refs; + + if( in == NULL ) return NULL; + + for( i=0; in[i] != NULL ; i++ ) { + /* just count them */ + } + + if( i < 1 ) return NULL; + + refs = ch_malloc( (i+1) * sizeof( struct berval * ) ); + + for( i=0,j=0; in[i] != NULL ; i++ ) { + LDAPURLDesc *url; + int rc = ldap_url_parse_ext( in[i]->bv_val, &url ); + + if( rc == LDAP_URL_ERR_BADSCHEME ) { + refs[j++] = ber_bvdup( in[i] ); + continue; + + } else if( rc != LDAP_URL_SUCCESS ) { + continue; + } + + { + char *dn = url->lud_dn; + url->lud_dn = referral_dn_muck( + ( dn && *dn ) ? dn : NULL, base, target ); + + ldap_memfree( dn ); + } + + if( url->lud_scope == LDAP_SCOPE_DEFAULT ) { + url->lud_scope = scope; + } + + refs[j] = ch_malloc( sizeof( struct berval ) ); + + refs[j]->bv_val = ldap_url_desc2str( url ); + refs[j]->bv_len = strlen( refs[j]->bv_val ); + + ldap_free_urldesc( url ); + j++; + } + + if( j == 0 ) { + ch_free( refs ); + refs = NULL; + + } else { + refs[j] = NULL; + } + + return refs; +} + + +struct berval **get_entry_referrals( + Backend *be, + Connection *conn, + Operation *op, + Entry *e, + const char *dn, + int scope ) +{ + Attribute *attr; + struct berval **refs; + unsigned i, j; + + AttributeDescription *ad_ref = slap_schema.si_ad_ref; + + attr = attr_find( e->e_attrs, ad_ref ); + + if( attr == NULL ) return NULL; + + for( i=0; attr->a_vals[i] != NULL; i++ ) { + /* count references */ + } + + if( i < 1 ) return NULL; + + refs = ch_malloc( (i + 1) * sizeof(struct berval *)); + + for( i=0, j=0; attr->a_vals[i] != NULL; i++ ) { + unsigned k; + struct berval *ref = ber_bvdup( attr->a_vals[i] ); + + /* trim the label */ + for( k=0; kbv_len; k++ ) { + if( isspace(ref->bv_val[k]) ) { + ref->bv_val[k] = '\0'; + ref->bv_len = k; + break; + } + } + + if( ref->bv_len > 0 ) { + refs[j++] = ref; + + } else { + ber_bvfree( ref ); + } + } + + if( j == 0 ) { + ber_bvecfree( refs ); + refs = NULL; + + } else { + refs[j] = NULL; + } + + /* we should check that a referral value exists... */ + return refs; +} + diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 0248a659ac..c71972fe50 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -95,87 +95,6 @@ static ber_tag_t req2res( ber_tag_t tag ) return tag; } -static void trim_refs_urls( - struct berval **refs ) -{ - unsigned i; - - if( refs == NULL ) return; - - for( i=0; refs[i] != NULL; i++ ) { - if( refs[i]->bv_len > sizeof("ldap://")-1 && - strncasecmp( refs[i]->bv_val, "ldap://", - sizeof("ldap://")-1 ) == 0 ) - { - unsigned j; - for( j=sizeof("ldap://")-1; jbv_len ; j++ ) { - if( refs[i]->bv_val[j] == '/' ) { - refs[i]->bv_val[j] = '\0'; - refs[i]->bv_len = j; - break; - } - } - } - } -} - -struct berval **get_entry_referrals( - Backend *be, - Connection *conn, - Operation *op, - Entry *e ) -{ - Attribute *attr; - struct berval **refs; - unsigned i, j; - - AttributeDescription *ad_ref = slap_schema.si_ad_ref; - - attr = attr_find( e->e_attrs, ad_ref ); - - if( attr == NULL ) return NULL; - - for( i=0; attr->a_vals[i] != NULL; i++ ) { - /* count references */ - } - - if( i < 1 ) return NULL; - - refs = ch_malloc( (i + 1) * sizeof(struct berval *)); - - for( i=0, j=0; attr->a_vals[i] != NULL; i++ ) { - unsigned k; - struct berval *ref = ber_bvdup( attr->a_vals[i] ); - - /* trim the label */ - for( k=0; kbv_len; k++ ) { - if( isspace(ref->bv_val[k]) ) { - ref->bv_val[k] = '\0'; - ref->bv_len = k; - break; - } - } - - if( ref->bv_len > 0 ) { - refs[j++] = ref; - - } else { - ber_bvfree( ref ); - } - } - - refs[j] = NULL; - - if( j == 0 ) { - ber_bvecfree( refs ); - refs = NULL; - } - - /* we should check that a referral value exists... */ - - return refs; -} - static long send_ldap_ber( Connection *conn, BerElement *ber ) @@ -503,23 +422,18 @@ send_ldap_result( if( ref ) { #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_ARGS, - "send_ldap_result: referral=\"%s\"\n", - ref[0] && ref[0]->bv_val ? ref[0]->bv_val : "NULL" )); + "send_ldap_result: referral=\"%s\"\n", + ref[0] && ref[0]->bv_val ? ref[0]->bv_val : "NULL" )); #else Debug( LDAP_DEBUG_ARGS, "send_ldap_result: referral=\"%s\"\n", ref[0] && ref[0]->bv_val ? ref[0]->bv_val : "NULL", NULL, NULL ); #endif - } assert( err != LDAP_PARTIAL_RESULTS ); - if( op->o_tag != LDAP_REQ_SEARCH ) { - trim_refs_urls( ref ); - } - if ( err == LDAP_REFERRAL ) { if( ref == NULL ) { err = LDAP_NO_SUCH_OBJECT; @@ -654,8 +568,6 @@ send_search_result( assert( err != LDAP_PARTIAL_RESULTS ); - trim_refs_urls( refs ); - if( op->o_protocol < LDAP_VERSION3 ) { /* send references in search results */ if( err == LDAP_REFERRAL ) { @@ -1095,7 +1007,6 @@ send_search_reference( Operation *op, Entry *e, struct berval **refs, - int scope, LDAPControl **ctrls, struct berval ***v2refs ) @@ -1109,8 +1020,8 @@ send_search_reference( #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, - "send_search_reference: conn %d dn=\"%s\"\n", - op->o_connid, e->e_dn )); + "send_search_reference: conn %d dn=\"%s\"\n", + op->o_connid, e->e_dn )); #else Debug( LDAP_DEBUG_TRACE, "=> send_search_reference: dn=\"%s\"\n", @@ -1123,8 +1034,8 @@ send_search_reference( { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_INFO, - "send_search_reference: conn %d access to entry %s not allowed\n", - op->o_connid, e->e_dn )); + "send_search_reference: conn %d access to entry %s not allowed\n", + op->o_connid, e->e_dn )); #else Debug( LDAP_DEBUG_ACL, "send_search_reference: access to entry not allowed\n", @@ -1139,8 +1050,8 @@ send_search_reference( { #ifdef NEW_LOGGING LDAP_LOG(( "acl", LDAP_LEVEL_INFO, - "send_search_reference: conn %d access to reference not allowed.\n", - op->o_connid )); + "send_search_reference: conn %d access to reference not allowed.\n", + op->o_connid )); #else Debug( LDAP_DEBUG_ACL, "send_search_reference: access to reference not allowed\n", @@ -1153,8 +1064,8 @@ send_search_reference( if( refs == NULL ) { #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_ERR, - "send_search_reference: null ref in (%s).\n", - op->o_connid, e->e_dn )); + "send_search_reference: null ref in (%s).\n", + op->o_connid, e->e_dn )); #else Debug( LDAP_DEBUG_ANY, "send_search_reference: null ref in (%s)\n", @@ -1177,8 +1088,8 @@ send_search_reference( if ( ber == NULL ) { #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_ERR, - "send_search_reference: conn %d ber_alloc failed\n", - op->o_connid )); + "send_search_reference: conn %d ber_alloc failed\n", + op->o_connid )); #else Debug( LDAP_DEBUG_ANY, "send_search_reference: ber_alloc failed\n", 0, 0, 0 ); @@ -1195,8 +1106,8 @@ send_search_reference( if ( rc == -1 ) { #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_ERR, - "send_search_reference: conn %d ber_printf failed.\n", - op->o_connid )); + "send_search_reference: conn %d ber_printf failed.\n", + op->o_connid )); #else Debug( LDAP_DEBUG_ANY, "send_search_reference: ber_printf failed\n", 0, 0, 0 ); @@ -1218,16 +1129,15 @@ send_search_reference( ldap_pvt_thread_mutex_unlock( &num_sent_mutex ); Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld REF dn=\"%s\"\n", - (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 ); + (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 ); #ifdef NEW_LOGGING LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY, - "send_search_reference: conn %d exit.\n", op->o_connid )); + "send_search_reference: conn %d exit.\n", op->o_connid )); #else Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 ); #endif - return 0; } diff --git a/servers/slapd/search.c b/servers/slapd/search.c index 63379e60b6..086e924137 100644 --- a/servers/slapd/search.c +++ b/servers/slapd/search.c @@ -268,9 +268,13 @@ do_search( * if we don't hold it. */ if ( (be = select_backend( nbase, manageDSAit )) == NULL ) { - send_ldap_result( conn, op, rc = LDAP_REFERRAL, - NULL, NULL, default_referral, NULL ); + struct berval **ref = referral_rewrite( default_referral, + NULL, base, scope ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, + NULL, NULL, ref ? ref : default_referral, NULL ); + + ber_bvecfree( ref ); goto return_results; } diff --git a/servers/slapd/tools/Makefile.in b/servers/slapd/tools/Makefile.in index 3231855856..4cf42801d8 100644 --- a/servers/slapd/tools/Makefile.in +++ b/servers/slapd/tools/Makefile.in @@ -47,7 +47,8 @@ SLAPD_OBJS = ../config.o ../ch_malloc.o ../backend.o ../charray.o \ ../acl.o ../phonetic.o ../attr.o ../value.o ../entry.o \ ../dn.o ../filter.o ../str2filter.o ../ava.o ../init.o \ ../controls.o ../kerberos.o ../passwd.o ../index.o \ - ../extended.o ../starttls.o ../sets.o ../mra.o + ../extended.o ../starttls.o ../sets.o ../mra.o \ + ../referral.o SLAPOBJS = $(SLAPD_OBJS) slapcommon.o mimic.o diff --git a/servers/slapd/tools/mimic.c b/servers/slapd/tools/mimic.c index 6783a55402..b5dc9e24aa 100644 --- a/servers/slapd/tools/mimic.c +++ b/servers/slapd/tools/mimic.c @@ -123,7 +123,6 @@ int send_search_reference( Operation *op, Entry *e, struct berval **refs, - int scope, LDAPControl **ctrls, struct berval ***v2refs ) @@ -132,13 +131,6 @@ int send_search_reference( return -1; } -struct berval **get_entry_referrals( - Backend *be, Connection *conn, Operation *op, Entry *e ) -{ - assert(0); - return NULL; -} - int slap_sasl_init(void) { return LDAP_SUCCESS; diff --git a/tests/data/slapd-repl-slave.conf b/tests/data/slapd-repl-slave.conf index 9c4101c85e..925464dacf 100644 --- a/tests/data/slapd-repl-slave.conf +++ b/tests/data/slapd-repl-slave.conf @@ -24,7 +24,7 @@ directory ./test-repl rootdn "cn=Replica, o=University of Michigan, c=US" rootpw secret updatedn "cn=Replica, o=University of Michigan, c=US" -updateref "ldap://localhost:9009/o=University%20of%20Michigan,c=US" +updateref "ldap://localhost:9009" #ldbm#index objectClass eq #ldbm#index cn,sn,uid pres,eq,sub #bdb#index objectClass eq