From c25c3ed9e5cb691f559feb1507eb53bd8c4ffe55 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Tue, 29 Jun 2004 16:29:00 +0000 Subject: [PATCH] fix nameUID* and uniqueMember* stuff in a consistent manner (related to ITS#3210) --- servers/slapd/schema_init.c | 250 +++++++++++++++++++++++++++--------- 1 file changed, 187 insertions(+), 63 deletions(-) diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index 77e14e06df..b5f9a2b239 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -738,38 +738,172 @@ bitStringValidate( return LDAP_SUCCESS; } +/* + * Syntax is [RFC2252]: + * + +6.3. Bit String + + ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' ) + + Values in this syntax are encoded according to the following BNF: + + bitstring = "'" *binary-digit "'B" + + binary-digit = "0" / "1" + + ... + +6.21. Name And Optional UID + + ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' ) + + Values in this syntax are encoded according to the following BNF: + + NameAndOptionalUID = DistinguishedName [ "#" bitstring ] + + Although the '#' character may occur in a string representation of a + distinguished name, no additional special quoting is done. This + syntax has been added subsequent to RFC 1778. + + Example: + + 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B + + * + * draft-ietf-ldapbis-syntaxes-xx.txt says: + * + +3.3.2. Bit String + + A value of the Bit String syntax is a sequence of binary digits. The + LDAP-specific encoding of a value of this syntax is defined by the + following ABNF: + + BitString = SQUOTE *binary-digit SQUOTE "B" + + binary-digit = "0" / "1" + + The rule is defined in [MODELS]. + + Example: + '0101111101'B + + The LDAP definition for the Bit String syntax is: + + ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' ) + + This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1]. + + ... + +3.3.21. Name and Optional UID + + A value of the Name and Optional UID syntax is the distinguished name + [MODELS] of an entity optionally accompanied by a unique identifier + that serves to differentiate the entity from others with an identical + distinguished name. + + The LDAP-specific encoding of a value of this syntax is defined by + the following ABNF: + + NameAndOptionalUID = distinguishedName [ SHARP BitString ] + + The rule is defined in Section 3.3.2. The + rule is defined in [LDAPDN]. The rule is + defined in [MODELS]. + + Note that although the '#' character may occur in the string + representation of a distinguished name, no additional escaping of + this character is performed when a is encoded in + a . + + Example: + 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B + + The LDAP definition for the Name and Optional UID syntax is: + + ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' ) + + This syntax corresponds to the NameAndOptionalUID ASN.1 type from + [X.520]. + + * + * draft-ietf-ldapbis-models-xx.txt [MODELS] says: + * + +1.4. Common ABNF Productions + + ... + SHARP = %x23 ; octothorpe (or sharp sign) ("#") + ... + SQUOTE = %x27 ; single quote ("'") + ... + + * + * Note: normalization strips any leading "0"s, unless the + * bit string is exactly "'0'B", so the normalized example, + * in slapd, would result in + * + * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B + * + * Since draft-ietf-ldapbis-dn-xx.txt clarifies that SHARP, + * i.e. "#", doesn't have to be escaped except when at the + * beginning of a value, the definition of Name and Optional + * UID appears to be flawed, because there is no clear means + * to determine whether the UID part is present or not. + * + * Example: + * + * cn=Someone,dc=example,dc=com#'1'B + * + * could be either a NameAndOptionalUID with trailing UID, i.e. + * + * DN = "cn=Someone,dc=example,dc=com" + * UID = "'1'B" + * + * or a NameAndOptionalUID with no trailing UID, and the AVA + * in the last RDN made of + * + * attributeType = dc + * attributeValue = com#'1'B + * + * in fact "com#'1'B" is a valid IA5 string. + * + * As a consequence, current slapd code assumes that the + * presence of portions of a BitString at the end of the string + * representation of a NameAndOptionalUID means a BitString + * is expected, and cause an error otherwise. This is quite + * arbitrary, and might change in the future. + */ + + static int nameUIDValidate( Syntax *syntax, struct berval *in ) { int rc; - struct berval dn; + struct berval dn, uid; if( in->bv_len == 0 ) return LDAP_SUCCESS; ber_dupbv( &dn, in ); if( !dn.bv_val ) return LDAP_OTHER; - if( dn.bv_val[dn.bv_len-1] == 'B' - && dn.bv_val[dn.bv_len-2] == '\'' ) - { - /* assume presence of optional UID */ - ber_len_t i; + /* if there's a "#", try bitStringValidate()... */ + uid.bv_val = strrchr( dn.bv_val, '#' ); + if ( uid.bv_val ) { + uid.bv_val++; + uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val ); - for(i=dn.bv_len-3; i>1; i--) { - if( dn.bv_val[i] != '0' && dn.bv_val[i] != '1' ) { - break; - } + rc = bitStringValidate( NULL, &uid ); + if ( rc == LDAP_SUCCESS ) { + /* in case of success, trim the UID, + * otherwise treat it as part of the DN */ + dn.bv_len -= uid.bv_len + 1; + uid.bv_val[-1] = '\0'; } - if( dn.bv_val[i] != '\'' || dn.bv_val[i-1] != '#' ) { - ber_memfree( dn.bv_val ); - return LDAP_INVALID_SYNTAX; - } - - /* trim the UID to allow use of dnValidate */ - dn.bv_val[i-1] = '\0'; - dn.bv_len = i-1; } rc = dnValidate( NULL, &dn ); @@ -806,26 +940,21 @@ nameUIDPretty( struct berval dnval = *val; struct berval uidval = BER_BVNULL; - if( val->bv_val[val->bv_len-1] == 'B' - && val->bv_val[val->bv_len-2] == '\'' ) - { - uidval.bv_val = strrchr( val->bv_val, '#' ); - if( uidval.bv_val == NULL || - uidval.bv_val < val->bv_val || - ( uidval.bv_val > val->bv_val && uidval.bv_val[-1] == '\\' ) ) - { - return LDAP_INVALID_SYNTAX; - } - - ber_dupbv_x( &dnval, val, ctx ); + uidval.bv_val = strrchr( val->bv_val, '#' ); + if ( uidval.bv_val ) { + uidval.bv_val++; + uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val ); - dnval.bv_len = uidval.bv_val - val->bv_val; - uidval.bv_len = val->bv_len - dnval.bv_len; + rc = bitStringValidate( NULL, &uidval ); - dnval.bv_val[dnval.bv_len] = '\0'; + if ( rc == LDAP_SUCCESS ) { + ber_dupbv_x( &dnval, val, ctx ); + dnval.bv_len -= uidval.bv_len + 1; + dnval.bv_val[dnval.bv_len] = '\0'; - uidval.bv_len--; - uidval.bv_val++; + } else { + uidval.bv_val = NULL; + } } rc = dnPretty( syntax, &dnval, out, ctx ); @@ -840,7 +969,8 @@ nameUIDPretty( int i, c, got1; char *tmp; - tmp = slap_sl_realloc( out->bv_val, out->bv_len + uidval.bv_len + 2, + tmp = slap_sl_realloc( out->bv_val, out->bv_len + + STRLENOF( "#" ) + uidval.bv_len + 1, ctx ); if( tmp == NULL ) { ber_memfree_x( out->bv_val, ctx ); @@ -861,8 +991,6 @@ nameUIDPretty( got1 = 1; out->bv_val[out->bv_len++] = c; break; - default: - return LDAP_INVALID_SYNTAX; } } @@ -902,30 +1030,18 @@ uniqueMemberNormalize( } else { struct berval uid = BER_BVNULL; - if( out.bv_val[out.bv_len-1] == 'B' - && out.bv_val[out.bv_len-2] == '\'' ) - { - /* assume presence of optional UID */ - uid.bv_val = strrchr( out.bv_val, '#' ); - - /* if no '#', or '#' before the beginning - * of the string, or preceded - * by an escape char '\\'... - * (a string of "#''B" should be valid, - * since the empty "" DN is legal) */ - if( uid.bv_val == NULL - || uid.bv_val < out.bv_val - || ( uid.bv_val > out.bv_val && uid.bv_val[-1] == '\\' ) ) - { - slap_sl_free( out.bv_val, ctx ); - return LDAP_INVALID_SYNTAX; + uid.bv_val = strrchr( out.bv_val, '#' ); + if ( uid.bv_val ) { + uid.bv_val++; + uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val ); + + rc = bitStringValidate( NULL, &uid ); + if ( rc == LDAP_SUCCESS ) { + uid.bv_val[-1] = '\0'; + out.bv_len -= uid.bv_len + 1; + } else { + uid.bv_val = NULL; } - - uid.bv_len = out.bv_len - (uid.bv_val - out.bv_val); - out.bv_len -= uid.bv_len--; - - /* temporarily trim the UID */ - *(uid.bv_val++) = '\0'; } rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx ); @@ -935,10 +1051,18 @@ uniqueMemberNormalize( return LDAP_INVALID_SYNTAX; } - if( uid.bv_len ) { - normalized->bv_val = ch_realloc( normalized->bv_val, + if( uid.bv_val ) { + char *tmp; + + tmp = ch_realloc( normalized->bv_val, normalized->bv_len + uid.bv_len + STRLENOF("#") + 1 ); + if ( tmp == NULL ) { + ber_memfree_x( normalized->bv_val, ctx ); + return LDAP_OTHER; + } + + normalized->bv_val = tmp; /* insert the separator */ normalized->bv_val[normalized->bv_len++] = '#'; -- 2.39.5