X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldap%2Fsearch.c;h=85c334f9c98315df16e4eeae8aa1e08eca89b702;hb=99e2e5d8866aa0726f55726ee472b2d1a225005b;hp=469d1cea87aea52b3c425c9d034d803450ebe622;hpb=a11553c212a89293e8bad5468725958fdb3101e6;p=openldap diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 469d1cea87..85c334f9c9 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1999-2004 The OpenLDAP Foundation. + * Copyright 1999-2005 The OpenLDAP Foundation. * Portions Copyright 1999-2003 Howard Chu. * Portions Copyright 2000-2003 Pierangelo Masarati. * All rights reserved. @@ -38,118 +38,211 @@ static int ldap_build_entry( Operation *op, LDAPMessage *e, Entry *ent, - struct berval *bdn, int flags ); -#define LDAP_BUILD_ENTRY_PRIVATE 0x01 + struct berval *bdn ); -static struct berval dummy = BER_BVNULL; +/* + * Quick'n'dirty rewrite of filter in case of error, to deal with + * . + */ +static int +ldap_back_munge_filter( + Operation *op, + struct berval *filter ) +{ + struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private; + + char *ptr; + int gotit = 0; + + Debug( LDAP_DEBUG_ARGS, "=> ldap_back_munge_filter \"%s\"\n", + filter->bv_val, 0, 0 ); + + for ( ptr = strstr( filter->bv_val, "(?=" ); + ptr; + ptr = strstr( ptr, "(?=" ) ) + { + static struct berval + bv_true = BER_BVC( "(?=true)" ), + bv_false = BER_BVC( "(?=false)" ), + bv_undefined = BER_BVC( "(?=undefined)" ), + bv_t = BER_BVC( "(&)" ), + bv_f = BER_BVC( "(|)" ), + bv_T = BER_BVC( "(objectClass=*)" ), + bv_F = BER_BVC( "(!(objectClass=*))" ); + struct berval *oldbv = NULL, + *newbv = NULL, + oldfilter = BER_BVNULL; + + if ( strncmp( ptr, bv_true.bv_val, bv_true.bv_len ) == 0 ) { + oldbv = &bv_true; + if ( li->flags & LDAP_BACK_F_SUPPORT_T_F ) { + newbv = &bv_t; + + } else { + newbv = &bv_T; + } + + } else if ( strncmp( ptr, bv_false.bv_val, bv_false.bv_len ) == 0 ) + { + oldbv = &bv_false; + if ( li->flags & LDAP_BACK_F_SUPPORT_T_F ) { + newbv = &bv_f; + + } else { + newbv = &bv_F; + } + + } else if ( strncmp( ptr, bv_undefined.bv_val, bv_undefined.bv_len ) == 0 ) + { + oldbv = &bv_undefined; + newbv = &bv_F; + + } else { + gotit = 0; + goto done; + } + + oldfilter = *filter; + if ( newbv->bv_len > oldbv->bv_len ) { + filter->bv_len += newbv->bv_len - oldbv->bv_len; + if ( filter->bv_val == op->ors_filterstr.bv_val ) { + filter->bv_val = op->o_tmpalloc( filter->bv_len + 1, + op->o_tmpmemctx ); + + AC_MEMCPY( filter->bv_val, op->ors_filterstr.bv_val, + op->ors_filterstr.bv_len + 1 ); + + } else { + filter->bv_val = op->o_tmprealloc( filter->bv_val, + filter->bv_len + 1, op->o_tmpmemctx ); + } + + ptr = filter->bv_val + ( ptr - oldfilter.bv_val ); + } + + AC_MEMCPY( &ptr[ newbv->bv_len ], + &ptr[ oldbv->bv_len ], + oldfilter.bv_len - ( ptr - filter->bv_val ) - oldbv->bv_len + 1 ); + AC_MEMCPY( ptr, newbv->bv_val, newbv->bv_len ); + + ptr += newbv->bv_len; + gotit = 1; + } + +done:; + Debug( LDAP_DEBUG_ARGS, "<= ldap_back_munge_filter \"%s\" (%d)\n", + filter->bv_val, gotit, 0 ); + + return gotit; +} int ldap_back_search( - Operation *op, - SlapReply *rs ) + Operation *op, + SlapReply *rs ) { - struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private; struct ldapconn *lc; struct timeval tv; - LDAPMessage *res, *e; - int rc = 0, msgid; - struct berval match = BER_BVNULL; - char **mapped_attrs = NULL; - struct berval mbase; - struct berval mfilter = BER_BVNULL; - int dontfreetext = 0; - dncookie dc; - LDAPControl **ctrls = NULL; - - lc = ldap_back_getconn(op, rs); - if ( !lc ) { - return( -1 ); + time_t stoptime; + LDAPMessage *res, + *e; + int rc = 0, + msgid; + struct berval match = BER_BVNULL, + filter = BER_BVNULL; + int i; + char **attrs = NULL; + int freetext = 0; + int do_retry = 1; + LDAPControl **ctrls = NULL; + + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); + if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) { + return rs->sr_err; } /* * FIXME: in case of values return filter, we might want * to map attrs and maybe rewrite value */ - if ( !ldap_back_dobind( lc, op, rs ) ) { - return( -1 ); - } /* should we check return values? */ - if (op->ors_deref != -1) - ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&op->ors_deref); - if (op->ors_tlimit != -1) { + if ( op->ors_deref != -1 ) { + ldap_set_option( lc->lc_ld, LDAP_OPT_DEREF, + (void *)&op->ors_deref ); + } + + if ( op->ors_tlimit != SLAP_NO_LIMIT ) { tv.tv_sec = op->ors_tlimit; tv.tv_usec = 0; + stoptime = op->o_time + op->ors_tlimit; + } else { tv.tv_sec = 0; } - /* - * Rewrite the search base, if required - */ - dc.rwmap = &li->rwmap; -#ifdef ENABLE_REWRITE - dc.conn = op->o_conn; - dc.rs = rs; - dc.ctx = "searchBase"; -#else - dc.tofrom = 1; - dc.normalized = 0; -#endif - if ( ldap_back_dn_massage( &dc, &op->o_req_ndn, &mbase ) ) { - send_ldap_result( op, rs ); - return -1; - } - - rc = ldap_back_filter_map_rewrite( &dc, op->ors_filter, - &mfilter, BACKLDAP_MAP ); + if ( op->ors_attrs ) { + for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ ) + /* just count attrs */ ; - switch ( rc ) { - case LDAP_SUCCESS: - break; - - case LDAP_COMPARE_FALSE: - rs->sr_err = LDAP_SUCCESS; - rs->sr_text = NULL; - rc = 0; - goto finish; - - default: - rs->sr_err = LDAP_OTHER; - rs->sr_text = "Rewrite error"; - dontfreetext = 1; - rc = -1; - goto finish; - } - - rs->sr_err = ldap_back_map_attrs( &li->rwmap.rwm_at, - op->ors_attrs, - BACKLDAP_MAP, &mapped_attrs ); - if ( rs->sr_err ) { - rc = -1; - goto finish; + attrs = ch_malloc( ( i + 1 )*sizeof( char * ) ); + if ( attrs == NULL ) { + rs->sr_err = LDAP_NO_MEMORY; + rc = -1; + goto finish; + } + + for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ ) { + attrs[ i ] = op->ors_attrs[i].an_name.bv_val; + } + attrs[ i ] = NULL; } ctrls = op->o_ctrls; -#ifdef LDAP_BACK_PROXY_AUTHZ rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls ); if ( rc != LDAP_SUCCESS ) { - dontfreetext = 1; goto finish; } -#endif /* LDAP_BACK_PROXY_AUTHZ */ - - rs->sr_err = ldap_search_ext(lc->ld, mbase.bv_val, - op->ors_scope, mfilter.bv_val, - mapped_attrs, op->ors_attrsonly, - ctrls, NULL, - tv.tv_sec ? &tv : NULL, op->ors_slimit, - &msgid ); + + /* deal with filters */ + filter = op->ors_filterstr; +retry: + rs->sr_err = ldap_search_ext( lc->lc_ld, op->o_req_ndn.bv_val, + op->ors_scope, filter.bv_val, + attrs, op->ors_attrsonly, ctrls, NULL, + tv.tv_sec ? &tv : NULL, + op->ors_slimit, &msgid ); if ( rs->sr_err != LDAP_SUCCESS ) { fail:; - rc = ldap_back_op_result(lc, op, rs, msgid, 0); - goto finish; + switch ( rs->sr_err ) { + case LDAP_SERVER_DOWN: + if ( do_retry ) { + do_retry = 0; + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_DONTSEND ) ) { + goto retry; + } + } + rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_DONTSEND ); + ldap_back_freeconn( op, lc ); + lc = NULL; + goto finish; + + case LDAP_FILTER_ERROR: + if ( ldap_back_munge_filter( op, &filter ) ) { + goto retry; + } + + /* invalid filters return success with no data */ + rs->sr_err = LDAP_SUCCESS; + rs->sr_text = NULL; + goto finish; + + default: + rs->sr_err = slap_map_api2result( rs ); + rs->sr_text = NULL; + goto finish; + } } /* We pull apart the ber result, stuff it into a slapd entry, and @@ -157,84 +250,100 @@ fail:; * but this is necessary for version matching, and for ACL processing. */ - for ( rc=0; rc != -1; rc = ldap_result(lc->ld, msgid, 0, &tv, &res)) + for ( rc = 0; rc != -1; rc = ldap_result( lc->lc_ld, msgid, 0, &tv, &res ) ) { /* check for abandon */ - if (op->o_abandon) { - ldap_abandon(lc->ld, msgid); - rc = 0; + if ( op->o_abandon ) { + if ( rc > 0 ) { + ldap_msgfree( res ); + } + ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL ); + rc = SLAPD_ABANDON; goto finish; } - if (rc == 0) { + if ( rc == 0 ) { tv.tv_sec = 0; tv.tv_usec = 100000; ldap_pvt_thread_yield(); - } else if (rc == LDAP_RES_SEARCH_ENTRY) { - Entry ent = {0}; - struct berval bdn; - int abort = 0; - e = ldap_first_entry(lc->ld,res); - if ( ( rc = ldap_build_entry(op, e, &ent, &bdn, - LDAP_BUILD_ENTRY_PRIVATE)) == LDAP_SUCCESS ) { + /* check time limit */ + if ( op->ors_tlimit != SLAP_NO_LIMIT + && slap_get_time() > stoptime ) + { + ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL ); + rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED; + goto finish; + } + + } else if ( rc == LDAP_RES_SEARCH_ENTRY ) { + Entry ent = { 0 }; + struct berval bdn = BER_BVNULL; + int abort = 0; + + do_retry = 0; + + e = ldap_first_entry( lc->lc_ld, res ); + rc = ldap_build_entry( op, e, &ent, &bdn ); + if ( rc == LDAP_SUCCESS ) { rs->sr_entry = &ent; rs->sr_attrs = op->ors_attrs; + rs->sr_operational_attrs = NULL; rs->sr_flags = 0; abort = send_search_entry( op, rs ); - while (ent.e_attrs) { - Attribute *a; - BerVarray v; - - a = ent.e_attrs; - ent.e_attrs = a->a_next; - - v = a->a_vals; - if (a->a_vals != &dummy) - ber_bvarray_free(a->a_vals); - if (a->a_nvals != v) - ber_bvarray_free(a->a_nvals); - ch_free(a); + if ( !BER_BVISNULL( &ent.e_name ) ) { + assert( ent.e_name.bv_val != bdn.bv_val ); + free( ent.e_name.bv_val ); + BER_BVZERO( &ent.e_name ); } - - if ( ent.e_dn && ( ent.e_dn != bdn.bv_val ) ) - free( ent.e_dn ); - if ( ent.e_ndn ) - free( ent.e_ndn ); + if ( !BER_BVISNULL( &ent.e_nname ) ) { + free( ent.e_nname.bv_val ); + BER_BVZERO( &ent.e_nname ); + } + entry_clean( &ent ); } - ldap_msgfree(res); + ldap_msgfree( res ); if ( abort ) { - ldap_abandon(lc->ld, msgid); + ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL ); goto finish; } } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) { char **references = NULL; - int cnt; - rc = ldap_parse_reference( lc->ld, res, + do_retry = 0; + rc = ldap_parse_reference( lc->lc_ld, res, &references, &rs->sr_ctrls, 1 ); if ( rc != LDAP_SUCCESS ) { continue; } - if ( references == NULL ) { - continue; - } + /* FIXME: there MUST be at least one */ + if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) { + int cnt; - for ( cnt = 0; references[ cnt ]; cnt++ ) - /* NO OP */ ; - - rs->sr_ref = ch_calloc( cnt + 1, sizeof( struct berval ) ); + for ( cnt = 0; references[ cnt ]; cnt++ ) + /* NO OP */ ; - for ( cnt = 0; references[ cnt ]; cnt++ ) { - rs->sr_ref[ cnt ].bv_val = references[ cnt ]; - rs->sr_ref[ cnt ].bv_len = strlen( references[ cnt ] ); - } + /* FIXME: there MUST be at least one */ + rs->sr_ref = ch_malloc( ( cnt + 1 ) * sizeof( struct berval ) ); + + for ( cnt = 0; references[ cnt ]; cnt++ ) { + ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] ); + } + BER_BVZERO( &rs->sr_ref[ cnt ] ); - /* ignore return value by now */ - ( void )send_search_reference( op, rs ); + /* ignore return value by now */ + ( void )send_search_reference( op, rs ); + + } else { + Debug( LDAP_DEBUG_ANY, + "%s ldap_back_search: " + "got SEARCH_REFERENCE " + "with no referrals\n", + op->o_log_prefix, 0, 0 ); + } /* cleanup */ if ( references ) { @@ -249,118 +358,139 @@ fail:; } } else { - rc = ldap_parse_result(lc->ld, res, &rs->sr_err, + char **references = NULL; + + rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err, &match.bv_val, (char **)&rs->sr_text, - NULL, NULL, 1); - if (rc != LDAP_SUCCESS ) rs->sr_err = rc; + &references, &rs->sr_ctrls, 1 ); + freetext = 1; + if ( rc != LDAP_SUCCESS ) { + rs->sr_err = rc; + } rs->sr_err = slap_map_api2result( rs ); + + if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) { + int cnt; + + if ( rs->sr_err != LDAP_REFERRAL ) { + /* FIXME: error */ + Debug( LDAP_DEBUG_ANY, + "%s ldap_back_search: " + "got referrals with %d\n", + op->o_log_prefix, + rs->sr_err, 0 ); + rs->sr_err = LDAP_REFERRAL; + } + + for ( cnt = 0; references[ cnt ]; cnt++ ) + /* NO OP */ ; + + rs->sr_ref = ch_malloc( ( cnt + 1 ) * sizeof( struct berval ) ); + + for ( cnt = 0; references[ cnt ]; cnt++ ) { + /* duplicating ...*/ + ber_str2bv( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ] ); + } + BER_BVZERO( &rs->sr_ref[ cnt ] ); + } + + /* cleanup */ + if ( references ) { + ldap_value_free( references ); + } + rc = 0; break; } } - if (rc == -1) + if ( rc == -1 ) { + if ( do_retry ) { + do_retry = 0; + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) { + goto retry; + } + } + rs->sr_err = LDAP_SERVER_DOWN; goto fail; + } /* * Rewrite the matched portion of the search base, if required */ - if ( match.bv_val && *match.bv_val ) { - struct berval mdn; - -#ifdef ENABLE_REWRITE - dc.ctx = "matchedDN"; -#else - dc.tofrom = 0; - dc.normalized = 0; -#endif - match.bv_len = strlen( match.bv_val ); - ldap_back_dn_massage(&dc, &match, &mdn); - rs->sr_matched = mdn.bv_val; + if ( !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) { + rs->sr_matched = match.bv_val; } + if ( rs->sr_v2ref ) { rs->sr_err = LDAP_REFERRAL; } finish:; - send_ldap_result( op, rs ); + if ( rc != SLAPD_ABANDON ) { + send_ldap_result( op, rs ); + } -#ifdef LDAP_BACK_PROXY_AUTHZ - if ( ctrls && ctrls != op->o_ctrls ) { - free( ctrls[ 0 ] ); - free( ctrls ); + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + + if ( rs->sr_ctrls ) { + ldap_controls_free( rs->sr_ctrls ); + rs->sr_ctrls = NULL; } -#endif /* LDAP_BACK_PROXY_AUTHZ */ if ( match.bv_val ) { - if ( rs->sr_matched != match.bv_val ) { - free( (char *)rs->sr_matched ); - } rs->sr_matched = NULL; LDAP_FREE( match.bv_val ); } + + if ( !BER_BVISNULL( &filter ) && filter.bv_val != op->ors_filterstr.bv_val ) { + op->o_tmpfree( filter.bv_val, op->o_tmpmemctx ); + } + if ( rs->sr_text ) { - if ( !dontfreetext ) { + if ( freetext ) { LDAP_FREE( (char *)rs->sr_text ); } rs->sr_text = NULL; } - if ( mapped_attrs ) { - ch_free( mapped_attrs ); + + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; } - if ( mfilter.bv_val != op->ors_filterstr.bv_val ) { - ch_free( mfilter.bv_val ); + + if ( attrs ) { + ch_free( attrs ); } - if ( mbase.bv_val != op->o_req_ndn.bv_val ) { - free( mbase.bv_val ); + + if ( lc != NULL ) { + ldap_back_release_conn( op, rs, lc ); } - + return rc; } static int ldap_build_entry( - Operation *op, - LDAPMessage *e, - Entry *ent, - struct berval *bdn, - int flags -) + Operation *op, + LDAPMessage *e, + Entry *ent, + struct berval *bdn ) { - struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private; - struct berval a, mapped; - BerElement ber = *e->lm_ber; - Attribute *attr, **attrp; - struct berval *bv; - const char *text; - int last; - int private = flags & LDAP_BUILD_ENTRY_PRIVATE; - dncookie dc; + struct berval a; + BerElement ber = *e->lm_ber; + Attribute *attr, **attrp; + const char *text; + int last; /* safe assumptions ... */ - assert( ent ); - ent->e_bv.bv_val = NULL; + assert( ent != NULL ); + BER_BVZERO( &ent->e_bv ); if ( ber_scanf( &ber, "{m{", bdn ) == LBER_ERROR ) { return LDAP_DECODING_ERROR; } - /* - * Rewrite the dn of the result, if needed - */ - dc.rwmap = &li->rwmap; -#ifdef ENABLE_REWRITE - dc.conn = op->o_conn; - dc.rs = NULL; - dc.ctx = "searchResult"; -#else - dc.tofrom = 0; - dc.normalized = 0; -#endif - if ( ldap_back_dn_massage( &dc, bdn, &ent->e_name ) ) { - return LDAP_OTHER; - } - /* * Note: this may fail if the target host(s) schema differs * from the one known to the meta, and a DN with unknown @@ -368,39 +498,39 @@ ldap_build_entry( * * FIXME: should we log anything, or delegate to dnNormalize? */ - if ( dnNormalize( 0, NULL, NULL, &ent->e_name, &ent->e_nname, + /* Note: if the distinguished values or the naming attributes + * change, should we massage them as well? + */ + if ( dnPrettyNormal( NULL, bdn, &ent->e_name, &ent->e_nname, op->o_tmpmemctx ) != LDAP_SUCCESS ) { return LDAP_INVALID_DN_SYNTAX; } - + attrp = &ent->e_attrs; -#ifdef ENABLE_REWRITE - dc.ctx = "searchAttrDN"; -#endif while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { - ldap_back_map(&li->rwmap.rwm_at, &a, &mapped, BACKLDAP_REMAP); - if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') - continue; - attr = (Attribute *)ch_malloc( sizeof(Attribute) ); - if (attr == NULL) + int i; + slap_syntax_validate_func *validate; + slap_syntax_transform_func *pretty; + + attr = (Attribute *)ch_malloc( sizeof( Attribute ) ); + if ( attr == NULL ) { continue; + } attr->a_flags = 0; attr->a_next = 0; attr->a_desc = NULL; - if (slap_bv2ad(&mapped, &attr->a_desc, &text) != LDAP_SUCCESS) { - if (slap_bv2undef_ad(&mapped, &attr->a_desc, &text) - != LDAP_SUCCESS) { -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "slap_bv2undef_ad(%s): %s\n", mapped.bv_val, text, 0 ); -#else /* !NEW_LOGGING */ + if ( slap_bv2ad( &a, &attr->a_desc, &text ) + != LDAP_SUCCESS ) + { + if ( slap_bv2undef_ad( &a, &attr->a_desc, &text ) + != LDAP_SUCCESS ) + { Debug( LDAP_DEBUG_ANY, - "slap_bv2undef_ad(%s): " - "%s\n%s", mapped.bv_val, text, "" ); -#endif /* !NEW_LOGGING */ - ch_free(attr); + "slap_bv2undef_ad(%s): %s\n", + a.bv_val, text, 0 ); + ch_free( attr ); continue; } } @@ -417,95 +547,102 @@ ldap_build_entry( */ ( void )ber_scanf( &ber, "x" /* [W] */ ); - ch_free(attr); + ch_free( attr ); continue; } if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR - || attr->a_vals == NULL ) { + || attr->a_vals == NULL ) + { /* * Note: attr->a_vals can be null when using * values result filter */ - if (private) { - attr->a_vals = &dummy; - } else { - attr->a_vals = ch_malloc(sizeof(struct berval)); - attr->a_vals->bv_val = NULL; - attr->a_vals->bv_len = 0; - } + attr->a_vals = (struct berval *)&slap_dummy_bv; last = 0; + } else { - for ( last = 0; attr->a_vals[last].bv_val; last++ ); + for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); last++ ) + /* just count vals */ ; } - if ( last == 0 ) { - /* empty */ - } else if ( attr->a_desc == slap_schema.si_ad_objectClass - || attr->a_desc == slap_schema.si_ad_structuralObjectClass ) { - for ( bv = attr->a_vals; bv->bv_val; bv++ ) { - ldap_back_map(&li->rwmap.rwm_oc, bv, &mapped, - BACKLDAP_REMAP); - if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') { - LBER_FREE(bv->bv_val); - bv->bv_val = NULL; - if (--last < 0) - break; - *bv = attr->a_vals[last]; - attr->a_vals[last].bv_val = NULL; - bv--; - - } else if ( mapped.bv_val != bv->bv_val ) { - /* - * FIXME: after LBER_FREEing - * the value is replaced by - * ch_alloc'ed memory - */ - LBER_FREE(bv->bv_val); - ber_dupbv( bv, &mapped ); + + validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate; + pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty; + + if ( !validate && !pretty ) { + attr->a_nvals = NULL; + attr_free( attr ); + goto next_attr; + } + + for ( i = 0; i < last; i++ ) { + struct berval pval; + int rc; + + if ( pretty ) { + rc = pretty( attr->a_desc->ad_type->sat_syntax, + &attr->a_vals[i], &pval, NULL ); + + } else { + rc = validate( attr->a_desc->ad_type->sat_syntax, + &attr->a_vals[i] ); + } + + if ( rc != LDAP_SUCCESS ) { + /* check if, by chance, it's an undefined objectClass */ + if ( attr->a_desc == slap_schema.si_ad_objectClass && + oc_bvfind_undef( &attr->a_vals[i] ) != NULL ) + { + ber_dupbv( &pval, &attr->a_vals[i] ); + + } else { + attr->a_nvals = NULL; + attr_free( attr ); + goto next_attr; } } - /* - * It is necessary to try to rewrite attributes with - * dn syntax because they might be used in ACLs as - * members of groups; since ACLs are applied to the - * rewritten stuff, no dn-based subject clause could - * be used at the ldap backend side (see - * http://www.OpenLDAP.org/faq/data/cache/452.html) - * The problem can be overcome by moving the dn-based - * ACLs to the target directory server, and letting - * everything pass thru the ldap backend. - */ - } else if ( attr->a_desc->ad_type->sat_syntax == - slap_schema.si_syn_distinguishedName ) { - ldap_dnattr_result_rewrite( &dc, attr->a_vals ); + if ( pretty ) { + LBER_FREE( attr->a_vals[i].bv_val ); + attr->a_vals[i] = pval; + } } if ( last && attr->a_desc->ad_type->sat_equality && - attr->a_desc->ad_type->sat_equality->smr_normalize ) { - int i; - - attr->a_nvals = ch_malloc((last+1)*sizeof(struct berval)); - for (i=0; ia_desc->ad_type->sat_equality->smr_normalize( + attr->a_desc->ad_type->sat_equality->smr_normalize ) + { + attr->a_nvals = ch_malloc( ( last + 1 )*sizeof( struct berval ) ); + for ( i = 0; i < last; i++ ) { + int rc; + + /* + * check that each value is valid per syntax + * and pretty if appropriate + */ + rc = attr->a_desc->ad_type->sat_equality->smr_normalize( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, attr->a_desc->ad_type->sat_syntax, attr->a_desc->ad_type->sat_equality, &attr->a_vals[i], &attr->a_nvals[i], - NULL /* op->o_tmpmemctx */ ); + NULL ); + + if ( rc != LDAP_SUCCESS ) { + BER_BVZERO( &attr->a_nvals[i] ); + ch_free( attr ); + goto next_attr; + } } - attr->a_nvals[i].bv_val = NULL; - attr->a_nvals[i].bv_len = 0; + BER_BVZERO( &attr->a_nvals[i] ); + } else { attr->a_nvals = attr->a_vals; } *attrp = attr; attrp = &attr->a_next; + +next_attr:; } - /* make sure it's free'able */ - if (!private && ent->e_name.bv_val == bdn->bv_val) - ber_dupbv( &ent->e_name, bdn ); return LDAP_SUCCESS; } @@ -513,116 +650,108 @@ ldap_build_entry( */ int ldap_back_entry_get( - Operation *op, - struct berval *ndn, - ObjectClass *oc, - AttributeDescription *at, - int rw, - Entry **ent + Operation *op, + struct berval *ndn, + ObjectClass *oc, + AttributeDescription *at, + int rw, + Entry **ent ) { - struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private; struct ldapconn *lc; - int rc = 1, is_oc; - struct berval mapped = BER_BVNULL, bdn, mdn; - LDAPMessage *result = NULL, *e = NULL; - char *gattr[3]; - char *filter = NULL; - Connection *oconn; - SlapReply rs; - dncookie dc; + int rc = 1, + do_not_cache; + struct berval bdn; + LDAPMessage *result = NULL, + *e = NULL; + char *gattr[3]; + char *filter = NULL; + SlapReply rs; + int do_retry = 1; + LDAPControl **ctrls = NULL; /* Tell getconn this is a privileged op */ - is_oc = op->o_do_not_cache; + do_not_cache = op->o_do_not_cache; op->o_do_not_cache = 1; - lc = ldap_back_getconn(op, &rs); - oconn = op->o_conn; - op->o_conn = NULL; - if ( !lc || !ldap_back_dobind(lc, op, &rs) ) { - op->o_do_not_cache = is_oc; - op->o_conn = oconn; - return 1; - } - op->o_do_not_cache = is_oc; - op->o_conn = oconn; - - /* - * Rewrite the search base, if required - */ - dc.rwmap = &li->rwmap; -#ifdef ENABLE_REWRITE - dc.conn = op->o_conn; - dc.rs = &rs; - dc.ctx = "searchBase"; -#else - dc.tofrom = 1; - dc.normalized = 1; -#endif - if ( ldap_back_dn_massage( &dc, ndn, &mdn ) ) { - return 1; + lc = ldap_back_getconn( op, &rs, LDAP_BACK_DONTSEND ); + if ( !lc || !ldap_back_dobind( lc, op, &rs, LDAP_BACK_DONTSEND ) ) { + op->o_do_not_cache = do_not_cache; + return rs.sr_err; } + op->o_do_not_cache = do_not_cache; if ( at ) { - ldap_back_map(&li->rwmap.rwm_at, &at->ad_cname, &mapped, BACKLDAP_MAP); - if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') { - rc = 1; - goto cleanup; + if ( oc && at != slap_schema.si_ad_objectClass ) { + gattr[0] = slap_schema.si_ad_objectClass->ad_cname.bv_val; + gattr[1] = at->ad_cname.bv_val; + gattr[2] = NULL; + + } else { + gattr[0] = at->ad_cname.bv_val; + gattr[1] = NULL; } } - is_oc = (strcasecmp("objectclass", mapped.bv_val) == 0); - if (oc && !is_oc) { - gattr[0] = "objectclass"; - gattr[1] = mapped.bv_val; - gattr[2] = NULL; - } else { - gattr[0] = mapped.bv_val; - gattr[1] = NULL; - } - if (oc) { - char *ptr; - ldap_back_map(&li->rwmap.rwm_oc, &oc->soc_cname, &mapped, - BACKLDAP_MAP); - filter = ch_malloc(sizeof("(objectclass=)") + mapped.bv_len); - ptr = lutil_strcopy(filter, "(objectclass="); - ptr = lutil_strcopy(ptr, mapped.bv_val); + if ( oc ) { + char *ptr; + + filter = ch_malloc( STRLENOF( "(objectclass=)" ) + + oc->soc_cname.bv_len + 1 ); + ptr = lutil_strcopy( filter, "(objectclass=" ); + ptr = lutil_strcopy( ptr, oc->soc_cname.bv_val ); *ptr++ = ')'; *ptr++ = '\0'; } - if (ldap_search_ext_s(lc->ld, mdn.bv_val, LDAP_SCOPE_BASE, filter, - gattr, 0, NULL, NULL, LDAP_NO_LIMIT, - LDAP_NO_LIMIT, &result) != LDAP_SUCCESS) - { + ctrls = op->o_ctrls; + rc = ldap_back_proxy_authz_ctrl( lc, op, &rs, &ctrls ); + if ( rc != LDAP_SUCCESS ) { + goto cleanup; + } + +retry: + rc = ldap_search_ext_s( lc->lc_ld, ndn->bv_val, LDAP_SCOPE_BASE, filter, + at ? gattr : NULL, 0, ctrls, NULL, + LDAP_NO_LIMIT, LDAP_NO_LIMIT, &result ); + if ( rc != LDAP_SUCCESS ) { + if ( rc == LDAP_SERVER_DOWN && do_retry ) { + do_retry = 0; + if ( ldap_back_retry( lc, op, &rs, LDAP_BACK_DONTSEND ) ) { + goto retry; + } + } goto cleanup; } - if ((e = ldap_first_entry(lc->ld, result)) == NULL) { + e = ldap_first_entry( lc->lc_ld, result ); + if ( e == NULL ) { goto cleanup; } - *ent = ch_calloc(1,sizeof(Entry)); + *ent = ch_calloc( 1, sizeof( Entry ) ); - rc = ldap_build_entry(op, e, *ent, &bdn, 0); + rc = ldap_build_entry( op, e, *ent, &bdn ); - if (rc != LDAP_SUCCESS) { - ch_free(*ent); + if ( rc != LDAP_SUCCESS ) { + ch_free( *ent ); *ent = NULL; } cleanup: - if (result) { - ldap_msgfree(result); + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + + if ( result ) { + ldap_msgfree( result ); } if ( filter ) { ch_free( filter ); } - if ( mdn.bv_val != ndn->bv_val ) { - ch_free( mdn.bv_val ); + if ( lc != NULL ) { + ldap_back_release_conn( op, &rs, lc ); } - return(rc); + return rc; }