int rwm_map_config( struct ldapmap *oc_map, struct ldapmap *at_map, const char *fname, int lineno, int argc, char **argv ) { struct ldapmap *map; struct ldapmapping *mapping; char *src, *dst; int is_oc = 0; int rc = 0; if ( argc < 3 || argc > 4 ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: syntax is \"map {objectclass | attribute} [<local> | *] {<foreign> | *}\"\n", fname, lineno, 0 ); return 1; } if ( strcasecmp( argv[1], "objectclass" ) == 0 ) { map = oc_map; is_oc = 1; } else if ( strcasecmp( argv[1], "attribute" ) == 0 ) { map = at_map; } else { Debug( LDAP_DEBUG_ANY, "%s: line %d: syntax is " "\"map {objectclass | attribute} [<local> | *] " "{<foreign> | *}\"\n", fname, lineno, 0 ); return 1; } if ( !is_oc && map->map == NULL ) { /* only init if required */ if ( rwm_map_init( map, &mapping ) != LDAP_SUCCESS ) { return 1; } } if ( strcmp( argv[2], "*" ) == 0 ) { if ( argc < 4 || strcmp( argv[3], "*" ) == 0 ) { map->drop_missing = ( argc < 4 ); goto success_return; } src = dst = argv[3]; } else if ( argc < 4 ) { src = ""; dst = argv[2]; } else { src = argv[2]; dst = ( strcmp( argv[3], "*" ) == 0 ? src : argv[3] ); } if ( ( map == at_map ) && ( strcasecmp( src, "objectclass" ) == 0 || strcasecmp( dst, "objectclass" ) == 0 ) ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: objectclass attribute cannot be mapped\n", fname, lineno, 0 ); return 1; } mapping = (struct ldapmapping *)ch_calloc( 2, sizeof(struct ldapmapping) ); if ( mapping == NULL ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: out of memory\n", fname, lineno, 0 ); return 1; } ber_str2bv( src, 0, 1, &mapping[0].m_src ); ber_str2bv( dst, 0, 1, &mapping[0].m_dst ); mapping[1].m_src = mapping[0].m_dst; mapping[1].m_dst = mapping[0].m_src; mapping[0].m_flags = RWMMAP_F_NONE; mapping[1].m_flags = RWMMAP_F_NONE; /* * schema check */ if ( is_oc ) { if ( src[0] != '\0' ) { mapping[0].m_src_oc = oc_bvfind( &mapping[0].m_src ); if ( mapping[0].m_src_oc == NULL ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: warning, source objectClass '%s' " "should be defined in schema\n", fname, lineno, src ); /* * FIXME: this should become an err */ mapping[0].m_src_oc = ch_malloc( sizeof( ObjectClass ) ); memset( mapping[0].m_src_oc, 0, sizeof( ObjectClass ) ); mapping[0].m_src_oc->soc_cname = mapping[0].m_src; mapping[0].m_flags |= RWMMAP_F_FREE_SRC; } mapping[1].m_dst_oc = mapping[0].m_src_oc; } mapping[0].m_dst_oc = oc_bvfind( &mapping[0].m_dst ); if ( mapping[0].m_dst_oc == NULL ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: warning, destination objectClass '%s' " "is not defined in schema\n", fname, lineno, dst ); mapping[0].m_dst_oc = oc_bvfind_undef( &mapping[0].m_dst ); if ( mapping[0].m_dst_oc == NULL ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: unable to mimic destination objectClass '%s'\n", fname, lineno, dst ); goto error_return; } } mapping[1].m_src_oc = mapping[0].m_dst_oc; mapping[0].m_flags |= RWMMAP_F_IS_OC; mapping[1].m_flags |= RWMMAP_F_IS_OC; } else { int rc; const char *text = NULL; if ( src[0] != '\0' ) { rc = slap_bv2ad( &mapping[0].m_src, &mapping[0].m_src_ad, &text ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: warning, source attributeType '%s' " "should be defined in schema\n", fname, lineno, src ); /* * we create a fake "proxied" ad * and add it here. */ rc = slap_bv2undef_ad( &mapping[0].m_src, &mapping[0].m_src_ad, &text, SLAP_AD_PROXIED ); if ( rc != LDAP_SUCCESS ) { char prefix[1024]; snprintf( prefix, sizeof(prefix), "%s: line %d: source attributeType '%s': %d", fname, lineno, src, rc ); Debug( LDAP_DEBUG_ANY, "%s (%s)\n", prefix, text ? text : "null", 0 ); goto error_return; } } mapping[1].m_dst_ad = mapping[0].m_src_ad; } rc = slap_bv2ad( &mapping[0].m_dst, &mapping[0].m_dst_ad, &text ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s: line %d: warning, destination attributeType '%s' " "is not defined in schema\n", fname, lineno, dst ); rc = slap_bv2undef_ad( &mapping[0].m_dst, &mapping[0].m_dst_ad, &text, SLAP_AD_PROXIED ); if ( rc != LDAP_SUCCESS ) { char prefix[1024]; snprintf( prefix, sizeof(prefix), "%s: line %d: destination attributeType '%s': %d", fname, lineno, dst, rc ); Debug( LDAP_DEBUG_ANY, "%s (%s)\n", prefix, text ? text : "null", 0 ); goto error_return; } } mapping[1].m_src_ad = mapping[0].m_dst_ad; } if ( ( src[0] != '\0' && avl_find( map->map, (caddr_t)mapping, rwm_mapping_cmp ) != NULL) || avl_find( map->remap, (caddr_t)&mapping[1], rwm_mapping_cmp ) != NULL) { Debug( LDAP_DEBUG_ANY, "%s: line %d: duplicate mapping found.\n", fname, lineno, 0 ); /* FIXME: free stuff */ goto error_return; } if ( src[0] != '\0' ) { avl_insert( &map->map, (caddr_t)&mapping[0], rwm_mapping_cmp, rwm_mapping_dup ); } avl_insert( &map->remap, (caddr_t)&mapping[1], rwm_mapping_cmp, rwm_mapping_dup ); success_return:; return rc; error_return:; if ( mapping ) { rwm_mapping_free( mapping ); } return 1; }
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; }