static int asyncmeta_send_entry( Operation *op, SlapReply *rs, a_metaconn_t *mc, int target, LDAPMessage *e ) { a_metainfo_t *mi = mc->mc_info; struct berval a, mapped = BER_BVNULL; int check_sorted_attrs = 0; Entry ent = {0}; BerElement ber = *ldap_get_message_ber( e ); Attribute *attr, **attrp; struct berval bdn, dn = BER_BVNULL; const char *text; a_dncookie dc; ber_len_t len; int rc; void *mem_mark; mem_mark = slap_sl_mark( op->o_tmpmemctx ); ber_set_option( &ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); if ( ber_scanf( &ber, "l{", &len ) == LBER_ERROR ) { return LDAP_DECODING_ERROR; } if ( ber_set_option( &ber, LBER_OPT_REMAINING_BYTES, &len ) != LBER_OPT_SUCCESS ) { return LDAP_OTHER; } if ( ber_scanf( &ber, "m{", &bdn ) == LBER_ERROR ) { return LDAP_DECODING_ERROR; } /* * Rewrite the dn of the result, if needed */ dc.op = op; dc.target = mi->mi_targets[ target ]; dc.memctx = op->o_tmpmemctx; dc.to_from = MASSAGE_REP; asyncmeta_dn_massage( &dc, &bdn, &dn ); /* * Note: this may fail if the target host(s) schema differs * from the one known to the meta, and a DN with unknown * attributes is returned. * * FIXME: should we log anything, or delegate to dnNormalize? */ rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname, op->o_tmpmemctx ); if ( dn.bv_val != bdn.bv_val ) { op->o_tmpfree( dn.bv_val, op->o_tmpmemctx ); } BER_BVZERO( &dn ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s asyncmeta_send_entry(\"%s\"): " "invalid DN syntax\n", op->o_log_prefix, ent.e_name.bv_val ); rc = LDAP_INVALID_DN_SYNTAX; goto done; } /* * cache dn */ if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) { ( void )asyncmeta_dncache_update_entry( &mi->mi_cache, &ent.e_nname, target ); } attrp = &ent.e_attrs; while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { int last = 0; slap_syntax_validate_func *validate; slap_syntax_transform_func *pretty; if ( ber_pvt_ber_remaining( &ber ) < 0 ) { Debug( LDAP_DEBUG_ANY, "%s asyncmeta_send_entry(\"%s\"): " "unable to parse attr \"%s\".\n", op->o_log_prefix, ent.e_name.bv_val, a.bv_val ); rc = LDAP_OTHER; goto done; } if ( ber_pvt_ber_remaining( &ber ) == 0 ) { break; } attr = op->o_tmpcalloc( 1, sizeof(Attribute), op->o_tmpmemctx ); if ( slap_bv2ad( &a, &attr->a_desc, &text ) != LDAP_SUCCESS) { if ( slap_bv2undef_ad( &a, &attr->a_desc, &text, SLAP_AD_PROXIED ) != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ANY, "%s meta_send_entry(\"%s\"): " "slap_bv2undef_ad(%s): %s\n", op->o_log_prefix, ent.e_name.bv_val, mapped.bv_val, text ); ( void )ber_scanf( &ber, "x" /* [W] */ ); op->o_tmpfree( attr, op->o_tmpmemctx ); continue; } } if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) check_sorted_attrs = 1; /* no subschemaSubentry */ if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry || attr->a_desc == slap_schema.si_ad_entryDN ) { /* * We eat target's subschemaSubentry because * a search for this value is likely not * to resolve to the appropriate backend; * later, the local subschemaSubentry is * added. * * We also eat entryDN because the frontend * will reattach it without checking if already * present... */ ( void )ber_scanf( &ber, "x" /* [W] */ ); op->o_tmpfree( attr, op->o_tmpmemctx ); continue; } if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR || attr->a_vals == NULL ) { attr->a_vals = (struct berval *)&slap_dummy_bv; } else { for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last ) ; } attr->a_numvals = last; validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate; pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty; if ( !validate && !pretty ) { ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); op->o_tmpfree( attr, op->o_tmpmemctx ); 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 subecj 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. */ { int i; if ( attr->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) { asyncmeta_dnattr_result_rewrite( &dc, attr->a_vals ); } else if ( attr->a_desc == slap_schema.si_ad_ref ) { asyncmeta_referral_result_rewrite( &dc, attr->a_vals ); } for ( i = 0; i < last; i++ ) { struct berval pval; int rc; if ( pretty ) { rc = ordered_value_pretty( attr->a_desc, &attr->a_vals[i], &pval, op->o_tmpmemctx ); } else { rc = ordered_value_validate( attr->a_desc, &attr->a_vals[i], 0 ); } if ( rc ) { ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); if ( --last == i ) { BER_BVZERO( &attr->a_vals[ i ] ); break; } attr->a_vals[i] = attr->a_vals[last]; BER_BVZERO( &attr->a_vals[last] ); i--; continue; } if ( pretty ) { ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); attr->a_vals[i] = pval; } } if ( last == 0 && attr->a_vals != &slap_dummy_bv ) { ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); op->o_tmpfree( attr, op->o_tmpmemctx ); goto next_attr; } } if ( last && attr->a_desc->ad_type->sat_equality && attr->a_desc->ad_type->sat_equality->smr_normalize ) { int i; attr->a_nvals = op->o_tmpalloc( ( last + 1 ) * sizeof( struct berval ), op->o_tmpmemctx ); for ( i = 0; i<last; i++ ) { /* if normalizer fails, drop this value */ if ( ordered_value_normalize( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, attr->a_desc, attr->a_desc->ad_type->sat_equality, &attr->a_vals[i], &attr->a_nvals[i], op->o_tmpmemctx )) { ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); if ( --last == i ) { BER_BVZERO( &attr->a_vals[ i ] ); break; } attr->a_vals[i] = attr->a_vals[last]; BER_BVZERO( &attr->a_vals[last] ); i--; } } BER_BVZERO( &attr->a_nvals[i] ); if ( last == 0 ) { ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx ); op->o_tmpfree( attr, op->o_tmpmemctx ); goto next_attr; } } else { attr->a_nvals = attr->a_vals; } attr->a_numvals = last; *attrp = attr; attrp = &attr->a_next; next_attr:; } /* Check for sorted attributes */ if ( check_sorted_attrs ) { for ( attr = ent.e_attrs; attr; attr = attr->a_next ) { if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) { while ( attr->a_numvals > 1 ) { int i; int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx ); if ( rc != LDAP_TYPE_OR_VALUE_EXISTS ) break; /* Strip duplicate values */ if ( attr->a_nvals != attr->a_vals ) ber_memfree_x( attr->a_nvals[i].bv_val, op->o_tmpmemctx ); ber_memfree_x( attr->a_vals[i].bv_val, op->o_tmpmemctx ); attr->a_numvals--; if ( (unsigned)i < attr->a_numvals ) { attr->a_vals[i] = attr->a_vals[attr->a_numvals]; if ( attr->a_nvals != attr->a_vals ) attr->a_nvals[i] = attr->a_nvals[attr->a_numvals]; } BER_BVZERO(&attr->a_vals[attr->a_numvals]); if ( attr->a_nvals != attr->a_vals ) BER_BVZERO(&attr->a_nvals[attr->a_numvals]); } attr->a_flags |= SLAP_ATTR_SORTED_VALS; } } } Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_send_entry(\"%s\"): " ".\n", op->o_log_prefix, ent.e_name.bv_val ); ldap_get_entry_controls( mc->mc_conns[target].msc_ldr, e, &rs->sr_ctrls ); rs->sr_entry = &ent; rs->sr_attrs = op->ors_attrs; rs->sr_operational_attrs = NULL; rs->sr_flags = mi->mi_targets[ target ]->mt_rep_flags; rs->sr_err = LDAP_SUCCESS; rc = send_search_entry( op, rs ); switch ( rc ) { case LDAP_UNAVAILABLE: rc = LDAP_OTHER; break; } done:; if ( rs->sr_ctrls != NULL ) { ldap_controls_free( rs->sr_ctrls ); rs->sr_ctrls = NULL; } #if 0 while ( ent.e_attrs ) { attr = ent.e_attrs; ent.e_attrs = attr->a_next; if ( attr->a_nvals != attr->a_vals ) ber_bvarray_free_x( attr->a_nvals, op->o_tmpmemctx ); ber_bvarray_free_x( attr->a_vals, op->o_tmpmemctx ); op->o_tmpfree( attr, op->o_tmpmemctx ); } if (ent.e_name.bv_val != NULL) { op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx ); } if (ent.e_nname.bv_val != NULL) { op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx ); } if (rs->sr_entry && rs->sr_entry != &ent) { entry_free( rs->sr_entry ); } #endif slap_sl_release( mem_mark, op->o_tmpmemctx ); rs->sr_entry = NULL; rs->sr_attrs = NULL; return rc; }
static int ldap_build_entry( Operation *op, LDAPMessage *e, Entry *ent, struct berval *bdn ) { struct berval a; BerElement ber = *ldap_get_message_ber( e ); Attribute *attr, **attrp; const char *text; int last; char *lastb; ber_len_t len; /* safe assumptions ... */ assert( ent != NULL ); BER_BVZERO( &ent->e_bv ); if ( ber_scanf( &ber, "{m", bdn ) == LBER_ERROR ) { return LDAP_DECODING_ERROR; } /* * Note: this may fail if the target host(s) schema differs * from the one known to the meta, and a DN with unknown * attributes is returned. * * FIXME: should we log anything, or delegate to dnNormalize? */ /* 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; } ent->e_attrs = NULL; if ( ber_first_element( &ber, &len, &lastb ) != LBER_SEQUENCE ) { return LDAP_SUCCESS; } attrp = &ent->e_attrs; while ( ber_next_element( &ber, &len, lastb ) == LBER_SEQUENCE && ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { int i; slap_syntax_validate_func *validate; slap_syntax_transform_func *pretty; attr = attr_alloc( NULL ); if ( attr == NULL ) { return LDAP_OTHER; } if ( slap_bv2ad( &a, &attr->a_desc, &text ) != LDAP_SUCCESS ) { if ( slap_bv2undef_ad( &a, &attr->a_desc, &text, SLAP_AD_PROXIED ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s ldap_build_entry: " "slap_bv2undef_ad(%s): %s\n", op->o_log_prefix, a.bv_val, text ); ( void )ber_scanf( &ber, "x" /* [W] */ ); attr_free( attr ); continue; } } /* no subschemaSubentry */ if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry || attr->a_desc == slap_schema.si_ad_entryDN ) { /* * We eat target's subschemaSubentry because * a search for this value is likely not * to resolve to the appropriate backend; * later, the local subschemaSubentry is * added. * * We also eat entryDN because the frontend * will reattach it without checking if already * present... */ ( void )ber_scanf( &ber, "x" /* [W] */ ); attr_free( attr ); continue; } if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR || attr->a_vals == NULL ) { /* * Note: attr->a_vals can be null when using * values result filter */ attr->a_vals = (struct berval *)&slap_dummy_bv; } 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; !BER_BVISNULL( &attr->a_vals[i] ); i++ ) ; last = i; /* * check that each value is valid per syntax * and pretty if appropriate */ for ( i = 0; i<last; i++ ) { struct berval pval; int rc; if ( pretty ) { rc = ordered_value_pretty( attr->a_desc, &attr->a_vals[i], &pval, NULL ); } else { rc = ordered_value_validate( attr->a_desc, &attr->a_vals[i], 0 ); } if ( rc != LDAP_SUCCESS ) { ObjectClass *oc; /* check if, by chance, it's an undefined objectClass */ if ( attr->a_desc == slap_schema.si_ad_objectClass && ( oc = oc_bvfind_undef( &attr->a_vals[i] ) ) != NULL ) { ber_dupbv( &pval, &oc->soc_cname ); rc = LDAP_SUCCESS; } else { ber_memfree( attr->a_vals[i].bv_val ); if ( --last == i ) { BER_BVZERO( &attr->a_vals[i] ); break; } attr->a_vals[i] = attr->a_vals[last]; BER_BVZERO( &attr->a_vals[last] ); i--; } } if ( rc == LDAP_SUCCESS && pretty ) { ber_memfree( attr->a_vals[i].bv_val ); attr->a_vals[i] = pval; } } attr->a_numvals = last = i; if ( last == 0 && attr->a_vals != &slap_dummy_bv ) { attr->a_nvals = NULL; attr_free( attr ); goto next_attr; } if ( last && attr->a_desc->ad_type->sat_equality && 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; rc = ordered_value_normalize( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, attr->a_desc, attr->a_desc->ad_type->sat_equality, &attr->a_vals[i], &attr->a_nvals[i], NULL ); if ( rc != LDAP_SUCCESS ) { ber_memfree( attr->a_vals[i].bv_val ); if ( --last == i ) { BER_BVZERO( &attr->a_vals[i] ); break; } attr->a_vals[i] = attr->a_vals[last]; BER_BVZERO( &attr->a_vals[last] ); i--; } } BER_BVZERO( &attr->a_nvals[i] ); if ( last == 0 ) { attr_free( attr ); goto next_attr; } } else { attr->a_nvals = attr->a_vals; } attr->a_numvals = last; /* Handle sorted vals, strip dups but keep the attr */ if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) { while ( attr->a_numvals > 1 ) { int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx ); if ( rc != LDAP_TYPE_OR_VALUE_EXISTS ) break; /* Strip duplicate values */ if ( attr->a_nvals != attr->a_vals ) ber_memfree( attr->a_nvals[i].bv_val ); ber_memfree( attr->a_vals[i].bv_val ); attr->a_numvals--; assert( i >= 0 ); if ( (unsigned)i < attr->a_numvals ) { attr->a_vals[i] = attr->a_vals[attr->a_numvals]; if ( attr->a_nvals != attr->a_vals ) attr->a_nvals[i] = attr->a_nvals[attr->a_numvals]; } BER_BVZERO(&attr->a_vals[attr->a_numvals]); if ( attr->a_nvals != attr->a_vals ) BER_BVZERO(&attr->a_nvals[attr->a_numvals]); } attr->a_flags |= SLAP_ATTR_SORTED_VALS; } *attrp = attr; attrp = &attr->a_next; next_attr:; } return LDAP_SUCCESS; }