]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#10369 Merge duplicate attributes properly
authorOndřej Kuzník <ondra@mistotebe.net>
Tue, 26 Aug 2025 15:26:44 +0000 (16:26 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Tue, 2 Sep 2025 15:27:06 +0000 (15:27 +0000)
servers/slapd/entry.c

index eb6502cfa82d84694cf7cd4388f7f8caf0dfc67c..827a64194be24bebe40e1cef783bc0fa829534b3 100644 (file)
@@ -114,7 +114,7 @@ str2entry2( char *s, int checkvals )
        char    *next;
        int             attr_cnt;
        int             i, lines;
-       Attribute       ahead, *atail;
+       Attribute       ahead, *atail, *a;
 
        /*
         * LDIF is used as the string format.
@@ -277,46 +277,65 @@ str2entry2( char *s, int checkvals )
        
                        if (( ad_prev && ad != ad_prev ) || ( i == lines )) {
                                int j, k;
-                               atail->a_next = attr_alloc( NULL );
-                               atail = atail->a_next;
-                               atail->a_flags = 0;
-                               atail->a_numvals = attr_cnt;
-                               atail->a_desc = ad_prev;
-                               atail->a_vals = ch_malloc( (attr_cnt + 1) * sizeof(struct berval));
-                               if( ad_prev->ad_type->sat_equality &&
-                                       ad_prev->ad_type->sat_equality->smr_normalize )
-                                       atail->a_nvals = ch_malloc( (attr_cnt + 1) * sizeof(struct berval));
-                               else
-                                       atail->a_nvals = NULL;
+
+                               a = attr_find( ahead.a_next, ad );
+                               if ( a == NULL ) {
+                                       a = atail->a_next = attr_alloc( NULL );
+                                       atail = atail->a_next;
+                                       a->a_flags = 0;
+                                       a->a_numvals = attr_cnt;
+                                       a->a_desc = ad_prev;
+                                       a->a_vals = ch_malloc( (a->a_numvals + 1) * sizeof(struct berval) );
+                                       a->a_nvals = NULL;
+                               } else {
+                                       /* Duplicate attribute detected */
+                                       if ( checkvals && is_at_single_value( ad->ad_type ) ) {
+                                               Debug( LDAP_DEBUG_ANY,
+                                                       "str2entry: single-value attributeType %s "
+                                                       "presented under multiple names\n",
+                                                       ad->ad_cname.bv_val );
+                                               goto fail;
+                                       }
+                                       a->a_numvals += attr_cnt;
+                                       a->a_vals = ch_realloc( a->a_vals,
+                                                       (a->a_numvals + 1) * sizeof(struct berval) );
+                               }
+                               if ( a->a_nvals ) {
+                                       a->a_nvals = ch_realloc( a->a_nvals,
+                                                       (a->a_numvals + 1) * sizeof(struct berval) );
+                               } else if ( ad_prev->ad_type->sat_equality &&
+                                       ad_prev->ad_type->sat_equality->smr_normalize ) {
+                                       a->a_nvals = ch_malloc( (a->a_numvals + 1) * sizeof(struct berval) );
+                               }
                                k = i - attr_cnt;
-                               for ( j=0; j<attr_cnt; j++ ) {
+                               for ( j = a->a_numvals - attr_cnt; j < a->a_numvals; j++ ) {
                                        if ( freeval[k] )
-                                               atail->a_vals[j] = vals[k];
+                                               a->a_vals[j] = vals[k];
                                        else
-                                               ber_dupbv( atail->a_vals+j, &vals[k] );
+                                               ber_dupbv( a->a_vals+j, &vals[k] );
                                        vals[k].bv_val = NULL;
-                                       if ( atail->a_nvals ) {
-                                               atail->a_nvals[j] = nvals[k];
+                                       if ( a->a_nvals ) {
+                                               a->a_nvals[j] = nvals[k];
                                                nvals[k].bv_val = NULL;
                                        }
                                        k++;
                                }
-                               BER_BVZERO( &atail->a_vals[j] );
-                               if ( atail->a_nvals ) {
-                                       BER_BVZERO( &atail->a_nvals[j] );
+                               BER_BVZERO( &a->a_vals[j] );
+                               if ( a->a_nvals ) {
+                                       BER_BVZERO( &a->a_nvals[j] );
                                } else {
-                                       atail->a_nvals = atail->a_vals;
+                                       a->a_nvals = a->a_vals;
                                }
                                attr_cnt = 0;
                                /* FIXME: we only need this when migrating from an unsorted DB */
-                               if ( atail->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
-                                       rc = slap_sort_vals( (Modifications *)atail, &text, &j, NULL );
+                               if ( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
+                                       rc = slap_sort_vals( (Modifications *)a, &text, &j, NULL );
                                        if ( rc == LDAP_SUCCESS ) {
-                                               atail->a_flags |= SLAP_ATTR_SORTED_VALS;
+                                               a->a_flags |= SLAP_ATTR_SORTED_VALS;
                                        } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
                                                Debug( LDAP_DEBUG_ANY,
                                                        "str2entry: attributeType %s value #%d provided more than once\n",
-                                                       atail->a_desc->ad_cname.bv_val, j );
+                                                       a->a_desc->ad_cname.bv_val, j );
                                                goto fail;
                                        }
                                }