From 82fad7d0c81c062f00337536db3cb89749000bcc Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Fri, 26 Oct 2001 02:05:14 +0000 Subject: [PATCH] First stable an implementing latest namedref specification. Includes rewriting of URLs where the DN of the referral object and the DN of the ref attribute attribute are not the same. Also, always returns explicit DN and scope. Currently, back-ldbm only. Needs to be ported to back-bdb. --- servers/slapd/Makefile.in | 4 +- servers/slapd/add.c | 17 +- servers/slapd/back-ldbm/add.c | 31 ++- servers/slapd/back-ldbm/bind.c | 17 +- servers/slapd/back-ldbm/compare.c | 14 +- servers/slapd/back-ldbm/delete.c | 23 +- servers/slapd/back-ldbm/modify.c | 44 ++-- servers/slapd/back-ldbm/modrdn.c | 52 ++--- servers/slapd/back-ldbm/referral.c | 51 +++-- servers/slapd/back-ldbm/search.c | 87 +++++--- servers/slapd/bind.c | 7 +- servers/slapd/compare.c | 7 +- servers/slapd/config.c | 67 ++++-- servers/slapd/delete.c | 16 +- servers/slapd/extended.c | 7 +- servers/slapd/modify.c | 17 +- servers/slapd/modrdn.c | 16 +- servers/slapd/passwd.c | 3 +- servers/slapd/proto-slap.h | 18 +- servers/slapd/referral.c | 336 +++++++++++++++++++++++++++++ servers/slapd/result.c | 122 ++--------- servers/slapd/search.c | 6 +- servers/slapd/tools/Makefile.in | 3 +- servers/slapd/tools/mimic.c | 8 - tests/data/slapd-repl-slave.conf | 2 +- 25 files changed, 676 insertions(+), 299 deletions(-) create mode 100644 servers/slapd/referral.c 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 ); + } - ber_bvecfree( refs ); - free( matched_dn ); + 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 ); + } + 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 + return 1; + } - } else { - vals[0]->bv_val = cargv[1]; - vals[0]->bv_len = strlen( vals[0]->bv_val ); - value_add( &be->be_update_refs, vals ); + 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 ) { + struct berval **ref = referral_rewrite( default_referral, + NULL, base, scope ); + send_ldap_result( conn, op, rc = LDAP_REFERRAL, - NULL, NULL, default_referral, NULL ); + 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 -- 2.39.5