/* dn.c - routines for dealing with distinguished names */
/* $OpenLDAP$ */
/*
- * The functions normalize_unicode(), get_hexpair(), write_hex_pair(),
- * get_next_byte(), get_next_char(), get_ber_length(),
- * ber_parse_primitive_string(), ber_parse_string(), String_normalize(),
- * DirectoryString_normalize(), PrintableString_normalize(),
- * IA5String_normalize(), ber_parse_primitive_bitstring(),
- * ber_parse_bitstring(), getNext8bits(), bitString_normalize(), match_oid(),
- * match_key(), get_validated_av_in_dn(), get_validated_rdn_in_dn(),
- * and get_validated_dn() in this file were developed at the National Institute
- * of Standards and Technology by employees of the Federal Government in the
- * course of their official duties. Pursuant to title 17 Section 105 of the
- * United States Code the code in these functions is not subject to copyright
- * protection and is in the public domain. The copyright for all other code in
- * this file is as specified below.
- */
-/*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
#include "slap.h"
-#define B4LEADTYPE 0
-#define B4TYPE 1
-#define INOIDTYPE 2
-#define INKEYTYPE 3
-#define B4EQUAL 4
-#define B4VALUE 5
-#define INVALUE 6
-#define INQUOTEDVALUE 7
-#define B4SEPARATOR 8
-#define INBERENCODEDVALUE 9
-
-#define UTF8DN 1
-
-typedef int (*av_normalize_type)(char **, char **, int *, int, int, int, unsigned long *);
-
-#define PRINTABLE_STRING 1
-#define IA5_STRING 2
-#define TELETEX_STRING 3
-#define BMP_STRING 4
-#define UNIVERSAL_STRING 5
-#define UTF8_STRING 6
-#define DIRECTORY_STRING 7
-
-/* unnormalized_unicode contains a string of ucs4 encoded unicode characters of length
- * len. Place in *d a normalized UTF8 encoded version of unnormalized_unicode. If firstchar is
- * true, then the first character output by uccanoncomp is the first character of the
- * attribute value. If successful, return 1 and advance *d to the end of the UTF8 encoded string.
- * Otherwise, return 0.
- */
-static int
-normalize_unicode(unsigned long *unnormalized_unicode, int len, char **d, int *av_length) {
- unsigned long *normalized_unicode;
- int i, normalized_len, char_len;
- char tmp;
-
-#ifdef UTF8DN
- i = uccanondecomp(unnormalized_unicode, len, &normalized_unicode, &normalized_len);
- if ( (i == -1) || (normalized_unicode == NULL) )
- return 0;
- normalized_len = uccanoncomp(normalized_unicode, normalized_len);
-
- char_len = ldap_ucs4_to_utf8(normalized_unicode[0], *d);
- *d += char_len;
-
- for(i=1; i < normalized_len; i++) {
- char_len = ldap_ucs4_to_utf8(normalized_unicode[i], *d);
- tmp = **d;
- if ( RDN_NEEDSESCAPE( tmp ) || RDN_SPECIAL( tmp ) ) {
- **d = '\\';
- *d += 1;
- **d = tmp;
- *d+= 1;
- } else if ( ASCII_WHITESPACE( tmp ) && ASCII_SPACE( *(*d - 1) ) ) {
- /* There should not be two consequtive space characters in the
- * normalized string. */
- normalized_len--;
- } else {
- *d += char_len;
- }
- }
- *av_length += normalized_len;
+const struct berval slap_empty_bv = { 0, "" };
- ch_free(normalized_unicode);
-#endif
+#define SLAP_LDAPDN_PRETTY 0x1
- return 1;
-}
+/*
+ * The DN syntax-related functions take advantage of the dn representation
+ * handling functions ldap_str2dn/ldap_dn2str. The latter are not schema-
+ * aware, so the attributes and their values need be validated (and possibly
+ * normalized). In the current implementation the required validation/nor-
+ * malization/"pretty"ing are done on newly created DN structural represen-
+ * tations; however the idea is to move towards DN handling in structural
+ * representation instead of the current string representation. To this
+ * purpose, we need to do only the required operations and keep track of
+ * what has been done to minimize their impact on performances.
+ *
+ * Developers are strongly encouraged to use this feature, to speed-up
+ * its stabilization.
+ */
-/* The next two bytes in the string beginning at *sec should be
- * a pair of hexadecimal characters. If they are, the value of that
- * hexpair is placed in *out and 1 is returned. Otherwise, 0 is returned.
+#define AVA_PRIVATE( ava ) ( ( AttributeDescription * )(ava)->la_private )
+
+/*
+ * In-place, schema-aware validation of the
+ * structural representation of a distinguished name.
*/
static int
-get_hexpair(char **src, unsigned char *out)
+LDAPDN_validate( LDAPDN *dn )
{
- unsigned char ch;
+ int iRDN;
+ int rc;
- ch = **src;
+ assert( dn );
- if ( !ASCII_XDIGIT(ch) ) {
- return 0;
- }
+ for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
+ LDAPRDN *rdn = dn[ 0 ][ iRDN ];
+ int iAVA;
- if ( ASCII_DIGIT(ch) ) {
- *out = ch - '0';
- } else if ( ch >= 'A' && ch <= 'F' ) {
- *out = ch - 'A' + 10;
- } else {
- *out = ch - 'a' + 10;
- }
+ assert( rdn );
- *src += 1;
+ for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+ LDAPAVA *ava = rdn[ 0 ][ iAVA ];
+ AttributeDescription *ad;
+ slap_syntax_validate_func *validate = NULL;
- ch = **src;
+ assert( ava );
+
+ if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
+ const char *text = NULL;
- if ( !ASCII_XDIGIT(ch) ) {
- return 0;
- }
+ rc = slap_bv2ad( &ava->la_attr, &ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
- *out = *out << 4;
+ ava->la_private = ( void * )ad;
+ }
- if ( ASCII_DIGIT(ch) ) {
- *out += ch - '0';
- } else if ( ch >= 'A' && ch <= 'F' ) {
- *out += ch - 'A' + 10;
- } else {
- *out += ch - 'a' + 10;
- }
+ /*
+ * Replace attr oid/name with the canonical name
+ */
+ ava->la_attr = ad->ad_cname;
- *src += 1;
+ validate = ad->ad_type->sat_syntax->ssyn_validate;
- return 1;
-}
+ if ( validate ) {
+ /*
+ * validate value by validate function
+ */
+ rc = ( *validate )( ad->ad_type->sat_syntax,
+ &ava->la_value );
+
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+ }
+ }
+ return LDAP_SUCCESS;
+}
-/* output in as a hexadecimal pair to the string pointed to be *d and advance *d to the end
- * of the hexpair.
+/*
+ * dn validate routine
*/
-static void
-write_hex_pair(char **d, unsigned char in) {
- unsigned char upper_nibble, lower_nibble;
+int
+dnValidate(
+ Syntax *syntax,
+ struct berval *in )
+{
+ int rc;
+ LDAPDN *dn = NULL;
- upper_nibble = (in & 0xF0) >> 4;
- lower_nibble = in & 0x0F;
+ assert( in );
- if (upper_nibble < 10)
- **d = upper_nibble + '0';
- else
- **d = upper_nibble - 10 + 'A';
+ if ( in->bv_len == 0 ) {
+ return( LDAP_SUCCESS );
+ }
- *d += 1;
+ rc = ldap_str2dn( in->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
- if (lower_nibble < 10)
- **d = lower_nibble + '0';
- else
- **d = lower_nibble - 10 + 'A';
+ /*
+ * Schema-aware validate
+ */
+ if ( rc == LDAP_SUCCESS ) {
+ rc = LDAPDN_validate( dn );
+ ldap_dnfree( dn );
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ return( LDAP_INVALID_SYNTAX );
+ }
- *d += 1;
+ return( LDAP_SUCCESS );
}
-
-/* The string beginning at *src represents a octet.
- * The octet is either represented by a single byte or
- * a '\' followed by a 2-byte hexpair or a single byte.
- * Place the octet in *out, increment *src to the beginning
- * of the next character. If the representation of the octet
- * began with a '\' then *is_escaped is set to 1. Otherwise,
- * *is_escaped is set to 0. If the string beginning at *src
- * does not represent a well formed octet, then 0 is returned.
- * Otherwise 1 is returned.
+/*
+ * AVA sorting inside a RDN
+ *
+ * rule: sort attributeTypes in alphabetical order; in case of multiple
+ * occurrences of the same attributeType, sort values in byte order
+ * (use memcmp, which implies alphabetical order in case of IA5 value;
+ * this should guarantee the repeatability of the operation).
+ *
+ * Note: the sorting can be slightly improved by sorting first
+ * by attribute type length, then by alphabetical order.
+ *
+ * uses a linear search; should be fine since the number of AVAs in
+ * a RDN should be limited.
*/
-static int
-get_next_byte(char **src, unsigned char *out, int *is_escaped)
+static void
+AVA_Sort( LDAPRDN *rdn, int iAVA )
{
- unsigned char tmp;
- unsigned char s1, s2;
+ int i;
+ LDAPAVA *ava_in = rdn[ 0 ][ iAVA ];
- s1 = **src;
- if (s1 == '\0')
- return 0;
-
- *src += 1;
-
- if ( s1 != '\\' ) {
- *out = s1;
- *is_escaped = 0;
- return 1;
- }
+ assert( rdn );
+ assert( ava_in );
+
+ for ( i = 0; i < iAVA; i++ ) {
+ LDAPAVA *ava = rdn[ 0 ][ i ];
+ int a, j;
- *is_escaped = 1;
+ assert( ava );
- s1 = **src;
- if ( s1 == '\0' )
- return 0;
+ a = strcmp( ava_in->la_attr.bv_val, ava->la_attr.bv_val );
- if ( !ASCII_XDIGIT( s1 ) ) {
- *src += 1;
- *out = s1;
- return 1;
- } else {
- if ( get_hexpair(src, &s2) ) {
- *out = s2;
- return 1;
- } else {
- return 0;
+ if ( a > 0 ) {
+ break;
}
- }
-}
+ while ( a == 0 ) {
+ int v, d;
-/* If the string beginning at *src is a well formed UTF8 character,
- * then the value of that character is placed in *out and 1 is returned.
- * If the string is not a well formed UTF8 character, 0 is returned.
- * If the character is an ASCII character, and its representation began
- * with a '\', then *is_escaped is set to 1. Otherwise *is_escaped is set to 0.
- * When the function returns, *src points to the first byte after the character.
- */
-static int
-get_next_char(char **src, unsigned long int *out, int *is_escaped)
-{
- unsigned char tmp;
- int i, res, len;
- unsigned long int ch;
-
- static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
+ d = ava_in->la_value.bv_len - ava->la_value.bv_len;
- res = get_next_byte( src, &tmp, is_escaped );
+ v = memcmp( ava_in->la_value.bv_val,
+ ava->la_value.bv_val,
+ d <= 0 ? ava_in->la_value.bv_len
+ : ava->la_value.bv_len );
- *out = tmp;
-
-#ifndef UTF8DN
- return res;
-#else
- if ( ( res == 0 ) || ( tmp < 128 ) ) {
- return res;
- }
+ if ( v == 0 && d != 0 ) {
+ v = d;
+ }
- /* This is a UTF8 encoded, non-ASCII character */
- len = ldap_utf8_charlen( &tmp );
+ if ( v <= 0 ) {
+ /*
+ * got it!
+ */
+ break;
+ }
- if ( len == 0 )
- return 0;
+ if ( ++i == iAVA ) {
+ /*
+ * already sorted
+ */
+ return;
+ }
- ch = tmp & mask[len];
+ ava = rdn[ 0 ][ i ];
+ a = strcmp( ava_in->la_attr.bv_val,
+ ava->la_attr.bv_val );
+ }
- for(i=1; i < len; i++) {
- res = get_next_byte( src, &tmp, is_escaped );
- if ( ( res == 0) || ( ( tmp & 0xc0 ) != 0x80 ) ) return 0;
+ /*
+ * move ahead
+ */
+ for ( j = iAVA; j > i; j-- ) {
+ rdn[ 0 ][ j ] = rdn[ 0 ][ j - 1 ];
+ }
+ rdn[ 0 ][ i ] = ava_in;
- ch <<= 6;
- ch |= tmp & 0x3f;
+ return;
}
-
- *is_escaped = 0;
- *out = ch;
-#endif
}
-
-/* The string beginning at *s should be an ASCII-hex encoding of BER encoded
- * length data. If so, place the length in *length, add the length of the
- * length encoding to *encoded_length, advance *s to next byte after the end
- * of the length encoding, and return 1. Otherwise, return 0.
+/*
+ * In-place, schema-aware normalization / "pretty"ing of the
+ * structural representation of a distinguished name.
*/
static int
-get_ber_length(
- char **s,
- unsigned int *encoded_length,
- unsigned long int *length
-)
+LDAPDN_rewrite( LDAPDN *dn, unsigned flags )
{
- int res;
- unsigned char ch, ch2;
+ int iRDN;
+ int rc;
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+ assert( dn );
- *encoded_length += 1;
+ for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
+ LDAPRDN *rdn = dn[ 0 ][ iRDN ];
+ int iAVA;
- if ( (ch & 0x80) == 0) {
- /* Bit 8 is 0, so this byte gives the length */
- *length = ch;
- } else {
- /* This byte specifies the number of remaining length octets */
- ch = ch & 0x7F;
+ assert( rdn );
+
+ for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+ LDAPAVA *ava = rdn[ 0 ][ iAVA ];
+ AttributeDescription *ad;
+ slap_syntax_transform_func *transf = NULL;
+ MatchingRule *mr;
+ struct berval bv = { 0, NULL };
+ int do_sort = 0;
+
+ assert( ava );
+
+ if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
+ const char *text = NULL;
+
+ rc = slap_bv2ad( &ava->la_attr, &ad, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ ava->la_private = ( void * )ad;
+ do_sort = 1;
+ }
- if (ch > 4) {
- /* This assumes that length can hold up to a 32-bit
- * integer and that bit strings will always be shorter
- * than 2**32 bytes.
+ /*
+ * Replace attr oid/name with the canonical name
*/
- return 0;
- }
+ ava->la_attr = ad->ad_cname;
+
+ if( flags & SLAP_LDAPDN_PRETTY ) {
+ transf = ad->ad_type->sat_syntax->ssyn_pretty;
+ mr = NULL;
+ } else {
+ transf = ad->ad_type->sat_syntax->ssyn_normalize;
+ mr = ad->ad_type->sat_equality;
+ }
+
+ if ( transf ) {
+ /*
+ * transform value by normalize/pretty function
+ */
+ rc = ( *transf )( ad->ad_type->sat_syntax,
+ &ava->la_value, &bv );
+
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
- *length = 0;
- while (ch > 0) {
- *length = *length << 8;
+ if( mr && ( mr->smr_usage & SLAP_MR_DN_FOLD ) ) {
+ char *s = bv.bv_val;
- res = get_hexpair(s, &ch2);
- if (res == 0)
- return 0;
+ ber_str2bv( UTF8normalize( bv.bv_val ? &bv
+ : &ava->la_value, LDAP_UTF8_CASEFOLD ),
+ 0, 0, &bv );
+ free( s );
+ }
- *encoded_length += 1;
- *length = *length | ch2;
+ if( bv.bv_val ) {
+ free( ava->la_value.bv_val );
+ ava->la_value = bv;
+ }
- ch--;
+ if( do_sort ) AVA_Sort( rdn, iAVA );
}
}
- return 1;
+ return LDAP_SUCCESS;
}
-
-/* The string beginning at *s should be an ASCII-hex encoding of a BER
- * encoded string of type string_type (minus the "tag" octet) in which the
- * encoding is primitive, definite length. If it is, write a UTF8 encoding
- * of the string, according to RFC 2253, to *d, advance *s to one byte after
- * the end of the BER encoded string, advance *d to one byte after the UTF8
- * encoded string, add to *encoded_length the length of the BER encoding, add
- * to *av_length the number of UTF8 characters written to *d, set *firstchar
- * to 0 if any characters are written to *d, and return 1. Otherwise, return
- * 0. If make_uppercase is 1, write all of the characters in uppercase. If
- * not, write the characters as they occur in the BER encoding. If
- * normalize is 1, remove all leading and trailing whitespace, and
- * compress all whitespace between words to a single space. If not, transfer
- * whitespace from the BER encoding to the UTF8 encoding unchanged.
+/*
+ * dn normalize routine
*/
-static int
-ber_parse_primitive_string(
- char **s,
- char **d,
- int *av_length,
- int make_uppercase,
- int normalize,
- int string_type,
- unsigned int *encoded_length,
- int *firstchar,
- unsigned long *unnormalized_unicode,
- int *unnormalized_unicode_len
-)
+int
+dnNormalize(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval **normalized )
{
- int i, len, res;
- unsigned char ch;
- unsigned long int uch;
- unsigned long int length;
- char tmp;
+ struct berval *out;
+ int rc;
- static unsigned char mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
+ assert( normalized && *normalized == NULL );
- res = get_ber_length(s, encoded_length, &length);
- if (res == 0)
- return 0;
+ out = ch_malloc( sizeof( struct berval ) );
+ rc = dnNormalize2( syntax, val, out );
+ if ( rc != LDAP_SUCCESS )
+ free( out );
+ else
+ *normalized = out;
+ return rc;
+}
- while (length > 0) {
- /* read in next character */
- if (string_type == PRINTABLE_STRING) {
- /* each character is one byte */
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+int
+dnNormalize2(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *out )
+{
+ assert( val );
+ assert( out );
- *encoded_length += 1;
- length -= 1;
+ Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
- if ( !SLAP_PRINTABLE(ch) )
- return 0;
+ if ( val->bv_len != 0 ) {
+ LDAPDN *dn = NULL;
+ int rc;
+
+ /*
+ * Go to structural representation
+ */
+ rc = ldap_str2dn( val->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
- uch = ch;
+ /*
+ * Schema-aware rewrite
+ */
+ if ( LDAPDN_rewrite( dn, 0 ) != LDAP_SUCCESS ) {
+ ldap_dnfree( dn );
+ return LDAP_INVALID_SYNTAX;
+ }
- } else if (string_type == IA5_STRING) {
- /* each character is one byte */
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+ /*
+ * Back to string representation
+ */
+ rc = ldap_dn2bv( dn, out, LDAP_DN_FORMAT_LDAPV3 );
- *encoded_length += 1;
- length -= 1;
+ ldap_dnfree( dn );
- if ( !SLAP_IA5(ch) )
- return 0;
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ } else {
+ ber_dupbv( out, val );
+ }
- uch = ch;
+ Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val, 0, 0 );
- } else if (string_type == TELETEX_STRING) {
- /* This code is not correct. Each character is one byte.
- * However, the enocodings need to be transliterated to
- * unicode.
- */
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+ return LDAP_SUCCESS;
+}
- *encoded_length += 1;
- length -= 1;
+/*
+ * dn "pretty"ing routine
+ */
+int
+dnPretty(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval **pretty)
+{
+ struct berval *out;
+ int rc;
- uch = ch;
+ assert( pretty && *pretty == NULL );
- } else if (string_type == BMP_STRING) {
- /* This is a 2-byte unicode character */
- if (length < 2)
- return 0;
+ out = ch_malloc( sizeof( struct berval ) );
+ rc = dnPretty2( syntax, val, out );
+ if ( rc != LDAP_SUCCESS )
+ free( out );
+ else
+ *pretty = out;
+ return rc;
+}
- uch = 0;
+int
+dnPretty2(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *out)
+{
+ assert( val );
+ assert( out );
- for(i=0; i < 2; i++) {
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+ Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
- uch = uch << 8;
- uch = uch | ch;
- }
+ if ( val->bv_len != 0 ) {
+ LDAPDN *dn = NULL;
+ int rc;
- *encoded_length += 2;
- length -= 2;
- } else if (string_type == UNIVERSAL_STRING) {
- /* This is a 4-byte unicode character */
- if (length < 4)
- return 0;
+ /* FIXME: should be liberal in what we accept */
+ rc = ldap_str2dn( val->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
- uch = 0;
+ /*
+ * Schema-aware rewrite
+ */
+ if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY ) != LDAP_SUCCESS ) {
+ ldap_dnfree( dn );
+ return LDAP_INVALID_SYNTAX;
+ }
- for(i=0; i < 4; i++) {
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+ /* FIXME: not sure why the default isn't pretty */
+ /* RE: the default is the form that is used as
+ * an internal representation; the pretty form
+ * is a variant */
+ rc = ldap_dn2bv( dn, out,
+ LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY );
- uch = uch << 8;
- uch = uch | ch;
- }
+ ldap_dnfree( dn );
- *encoded_length += 4;
- length -= 4;
- } else if (string_type == UTF8_STRING) {
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ } else {
+ ber_dupbv( out, val );
+ }
- *encoded_length += 1;
+ Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
- #ifndef UTF8DN
- /* Not sure what to do here */
- uch = ch;
- length -= 1;
- #else
- len = ldap_utf8_charlen( &ch );
- if ( ( len == 0) || ( length < len ) )
- return 0;
+ return LDAP_SUCCESS;
+}
- uch = ch & mask[len];
+/*
+ * Combination of both dnPretty and dnNormalize
+ */
+int
+dnPrettyNormal(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *pretty,
+ struct berval *normal)
+{
+ Debug( LDAP_DEBUG_TRACE, ">>> dnPrettyNormal: <%s>\n", val->bv_val, 0, 0 );
- for(i=1; i < len; i++) {
- res = get_hexpair(s, &ch);
- if ( ( res == 0) || ( ( ch & 0xc0 ) != 0x80 ) ) return 0;
+ assert( val );
+ assert( pretty );
+ assert( normal );
- *encoded_length += 1;
+ if ( val->bv_len != 0 ) {
+ LDAPDN *dn = NULL;
+ int rc;
- uch <<= 6;
- uch |= ch & 0x3f;
- }
+ pretty->bv_val = NULL;
+ normal->bv_val = NULL;
+ pretty->bv_len = 0;
+ normal->bv_len = 0;
- length -= len;
- #endif
- } else {
- /* Unknown string type */
- return 0;
+ /* FIXME: should be liberal in what we accept */
+ rc = ldap_str2dn( val->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
+ if ( rc != LDAP_SUCCESS ) {
+ return LDAP_INVALID_SYNTAX;
}
- /* Now add character to *d */
+ /*
+ * Schema-aware rewrite
+ */
+ if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY ) != LDAP_SUCCESS ) {
+ ldap_dnfree( dn );
+ return LDAP_INVALID_SYNTAX;
+ }
- #ifdef UTF8DN
- if (make_uppercase) {
- uch = uctoupper( uch );
- }
+ rc = ldap_dn2bv( dn, pretty,
+ LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY );
- if ( (uch < 128) && (*unnormalized_unicode_len > 0) ) {
- res = normalize_unicode(unnormalized_unicode, *unnormalized_unicode_len, d, av_length);
- if (res == 0)
- return 0;
- *unnormalized_unicode_len = 0;
- }
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_dnfree( dn );
+ return LDAP_INVALID_SYNTAX;
+ }
- if ( !normalize || !ASCII_WHITESPACE(uch) ) {
- if ( (*firstchar) && ASCII_SPACE(uch) ) {
- **d = '\\';
- *d += 1;
- **d = '2';
- *d += 1;
- **d = '0';
- *d += 1;
- *av_length += 1;
- } else {
- if ( normalize && (uch > 127) ) {
- if (*unnormalized_unicode_len == 0) {
- /* The previous output character must be ASCII
- * and it should be normalized.
- */
- *d -= 1;
- unnormalized_unicode[0] = **d;
- *unnormalized_unicode_len = 1;
- *av_length -= 1;
- }
- unnormalized_unicode[*unnormalized_unicode_len] = uch;
- *unnormalized_unicode_len += 1;
- } else {
- len = ldap_ucs4_to_utf8( uch, *d );
- tmp = **d;
- if ( RDN_NEEDSESCAPE( tmp ) || RDN_SPECIAL( tmp ) ) {
- **d = '\\';
- *d += 1;
- **d = tmp;
- *d += 1;
- } else if ( (*firstchar) && ( uch == '#' ) ) {
- **d = '\\';
- *d += 1;
- **d = tmp;
- *d += 1;
- } else {
- *d += len;
- }
- *av_length += 1;
- }
- }
- *firstchar = 0;
- } else if ( !(*firstchar) && !ASCII_SPACE( *(*d - 1) ) ) {
- **d = ' ';
- *d += 1;
- *av_length += 1;
- }
- #else
- /* Not sure what to do here either */
- if (uch > 127)
- return 0;
+ if ( LDAPDN_rewrite( dn, 0 ) != LDAP_SUCCESS ) {
+ ldap_dnfree( dn );
+ free( pretty->bv_val );
+ pretty->bv_val = NULL;
+ pretty->bv_len = 0;
+ return LDAP_INVALID_SYNTAX;
+ }
- if (make_uppercase) {
- uch = TOUPPER( uch );
- }
+ rc = ldap_dn2bv( dn, normal, LDAP_DN_FORMAT_LDAPV3 );
- if ( !normalize || !ASCII_WHITESPACE(uch) ) {
- if ( (*firstchar) && ASCII_SPACE(uch) ) {
- **d = '\\';
- *d += 1;
- **d = '2';
- *d += 1;
- **d = '0';
- *d += 1;
- } else {
- if ( RDN_NEEDSESCAPE( uch ) || RDN_SPECIAL( uch ) ) {
- **d = '\\';
- *d += 1;
- } else if ( (*firstchar) && ( uch == '#' ) ) {
- **d = '\\';
- *d += 1;
- }
- **d = uch;
- *d += 1;
- }
- *firstchar = 0;
- *av_length += 1;
- } else if ( !(*firstchar) && !ASCII_SPACE( *(*d - 1) ) ) {
- **d = ' ';
- *d += 1;
- *av_length += 1;
- }
- #endif
+ ldap_dnfree( dn );
+ if ( rc != LDAP_SUCCESS ) {
+ free( pretty->bv_val );
+ pretty->bv_val = NULL;
+ pretty->bv_len = 0;
+ return LDAP_INVALID_SYNTAX;
+ }
+ } else {
+ ber_dupbv( pretty, val );
+ ber_dupbv( normal, val );
}
- return 1;
-}
+ Debug( LDAP_DEBUG_TRACE, "<<< dnPrettyNormal: <%s>, <%s>\n",
+ pretty->bv_val, normal->bv_val, 0 );
+ return LDAP_SUCCESS;
+}
-/* The string beginning at *s should be an ASCII-hex encoding of a BER
- * encoded string of type string_type. If it is, write a UTF8 encoding
- * of the string, according to RFC 2253, to *d, advance *s to one byte after
- * the end of the BER encoded string, advance *d to one byte after the UTF8
- * encoded string, add to *encoded_length the length of the BER encoding, add
- * to *av_length the number of UTF8 characters written to *d, set *firstchar
- * to 0 if any characters are written to *d, and return 1. Otherwise, return
- * 0. If make_uppercase is 1, write all of the characters in uppercase. If
- * not, write the characters as they occur in the BER encoding. If
- * normalize is 1, remove all leading and trailing whitespace, and
- * compress all whitespace between words to a single space. If not, transfer
- * whitespace from the BER encoding to the UTF8 encoding unchanged.
+/*
+ * dnMatch routine
*/
-static int
-ber_parse_string(
- char **s,
- char **d,
- int *av_length,
- int make_uppercase,
- int normalize,
- int string_type,
- unsigned int *encoded_length,
- int *firstchar,
- unsigned long *unnormalized_unicode,
- int *unnormalized_unicode_len
-)
+int
+dnMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
{
- int res;
- unsigned char ch, tag, encoding_method;
- int ber_string_type;
- unsigned long int length;
- unsigned int component_encoded_length;
-
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+ int match;
+ struct berval *asserted = (struct berval *) assertedValue;
- *encoded_length = 1;
-
- /* zero out bit 5 */
- tag = ch & 0xDF;
-
- if (tag == 12)
- ber_string_type = UTF8_STRING;
- else if (tag == 19)
- ber_string_type = PRINTABLE_STRING;
- else if (tag == 20)
- ber_string_type = TELETEX_STRING;
- else if (tag == 22)
- ber_string_type = IA5_STRING;
- else if (tag == 28)
- ber_string_type = UNIVERSAL_STRING;
- else if (tag == 30)
- ber_string_type = BMP_STRING;
- else {
- /* Unknown string type or not a string type */
- return 0;
- }
+ assert( matchp );
+ assert( value );
+ assert( assertedValue );
+
+ match = value->bv_len - asserted->bv_len;
- /* Check that this is an acceptable string type */
- if ( ber_string_type == string_type ) {
- /* OK */
- } else if ( ( string_type == DIRECTORY_STRING ) &&
- ( ( ber_string_type == PRINTABLE_STRING ) ||
- ( ber_string_type == TELETEX_STRING ) ||
- ( ber_string_type == BMP_STRING ) ||
- ( ber_string_type == UNIVERSAL_STRING ) ||
- ( ber_string_type == UTF8_STRING ) ) ) {
- /* OK */
- } else {
- /* Bad string type */
- return 0;
+ if ( match == 0 ) {
+ match = strcmp( value->bv_val, asserted->bv_val );
}
- /* Bit 5 specifies the encoding method */
- encoding_method = ch & 0x20;
-
- if (encoding_method == 0) {
- /* Primitive, definite-length encoding */
- res = ber_parse_primitive_string(s, d, av_length, make_uppercase, normalize, ber_string_type, encoded_length, firstchar, unnormalized_unicode, unnormalized_unicode_len);
- if (res == 0)
- return 0;
- } else {
- /* Constructed encoding */
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
+ "dnMatch: %d\n %s\n %s\n", match,
+ value->bv_val, asserted->bv_val ));
+#else
+ Debug( LDAP_DEBUG_ARGS, "dnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
+ match, value->bv_val, asserted->bv_val );
+#endif
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+ *matchp = match;
+ return( LDAP_SUCCESS );
+}
- if (ch == 128) {
- /* Constructed, indefinite-length */
- *encoded_length += 1;
+/*
+ * dnParent - dn's parent, in-place
+ *
+ * note: the incoming dn is assumed to be normalized/prettyfied,
+ * so that escaped rdn/ava separators are in '\'+hexpair form
+ */
+void
+dnParent(
+ struct berval *dn,
+ struct berval *pdn )
+{
+ char *p;
- while (ch != 0) {
- res = ber_parse_string(s, d, av_length, make_uppercase, normalize, ber_string_type, &component_encoded_length, firstchar, unnormalized_unicode, unnormalized_unicode_len);
- if (res == 0)
- return 0;
+ p = strchr( dn->bv_val, ',' );
- *encoded_length += component_encoded_length;
+ /* one-level dn */
+ if ( p == NULL ) {
+ *pdn = slap_empty_bv;
+ return;
+ }
- /* Must end in "0000" */
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+ assert( DN_SEPARATOR( p[ 0 ] ) );
+ p++;
- if (ch == 0) {
- res = get_hexpair(s, &ch);
- if ( (res == 0) || (ch != 0) )
- return 0;
+ assert( ATTR_LEADCHAR( p[ 0 ] ) );
+ pdn->bv_val = p;
+ pdn->bv_len = dn->bv_len - (p - dn->bv_val);
- *encoded_length += 2;
- } else {
- *s -= 2;
- }
- }
- } else {
- /* Constructed, definite-length */
- *s -= 2;
- res = get_ber_length(s, encoded_length, &length);
- if (res == 0)
- return 0;
-
- while (length > 0) {
- res = ber_parse_string(s, d, av_length, make_uppercase, normalize, ber_string_type, &component_encoded_length, firstchar, unnormalized_unicode, unnormalized_unicode_len);
- if ( (res == 0) || (component_encoded_length > length) )
- return 0;
-
- length -= component_encoded_length;
- *encoded_length += component_encoded_length;
- }
- }
- }
+ return;
}
-
-/* The string beginning at *s should be a string of type string_type encoded
- * as described in RFC 2253. If it is, write a UTF8 encoding
- * of the string, according to RFC 2253, to *d, advance *s to one byte after
- * the end of the BER encoded string, advance *d to one byte after the UTF8
- * encoded string, set *av_length the number of UTF8 characters written to *d,
- * and return 1. Otherwise, return 0. If make_uppercase is 1, write all of the
- * characters in uppercase. If not, write the characters as they occur. If
- * normalize is 1, remove all leading and trailing whitespace, and
- * compress all whitespace between words to a single space. If not, transfer
- * whitespace from the BER encoding to the UTF8 encoding unchanged.
- * representation specifies whether the string is encoding as ASCII-hex BER,
- * within quotation marks, or as a plain string.
- */
-static int
-String_normalize(
- char **s,
- char **d,
- int *av_length,
- int make_uppercase,
- int normalize,
- int representation,
- int string_type,
- unsigned long *unnormalized_unicode
-)
+int
+dnExtractRdn(
+ struct berval *dn,
+ struct berval *rdn )
{
- int done = 0;
- int firstchar = 1;
- int first_dstchar = 0;
- char *lastchar;
- unsigned long int tmp;
- int res, len;
- int is_escaped;
- unsigned int encoded_length;
- int unnormalized_unicode_len = 0;
-
- *av_length = 0;
- lastchar = *d;
-
- switch ( representation ) {
-
- case INVALUE:
- case INQUOTEDVALUE:
- if ( representation == INQUOTEDVALUE ) {
- *s += 1;
- if ( !normalize )
- firstchar = 0;
- }
-
- while( !done ) {
- if ( **s == '\0' ) {
- if (unnormalized_unicode_len > 0) {
- res = normalize_unicode(unnormalized_unicode, unnormalized_unicode_len, d, av_length);
- if (res == 0)
- return 0;
- } else {
- *av_length -= (*d - lastchar);
- if ( !normalize && ( ASCII_SPACE(*(lastchar - 1)) ) ) {
- /* a space at the end of the string must be escaped */
- *(lastchar - 1) = '\\';
- *lastchar++ = '2';
- *lastchar++ = '0';
- }
- *d = lastchar;
- }
-
- if (representation == INQUOTEDVALUE) {
- /* Missing end quote */
- return 0;
- }
- done = 1;
- } else if ( representation == INVALUE && RDN_SEPARATOR( **s ) ) {
- if (unnormalized_unicode_len > 0) {
- res = normalize_unicode(unnormalized_unicode, unnormalized_unicode_len, d, av_length);
- if (res == 0)
- return 0;
- } else {
- *av_length -= (*d - lastchar);
- if ( !normalize && ( ASCII_SPACE(*(lastchar - 1)) ) ) {
- /* a space at the end of the string must be escaped */
- *(lastchar - 1) = '\\';
- *lastchar++ = '2';
- *lastchar++ = '0';
- }
- *d = lastchar;
- }
- done = 1;
- } else if ( representation == INQUOTEDVALUE && **s == '"' ) {
- if (unnormalized_unicode_len > 0) {
- res = normalize_unicode(unnormalized_unicode, unnormalized_unicode_len, d, av_length);
- if (res == 0)
- return 0;
- } else {
- *av_length -= (*d - lastchar);
- if ( !normalize && ( ASCII_SPACE(*(lastchar - 1)) ) ) {
- /* a space at the end of the string must be escaped */
- *(lastchar - 1) = '\\';
- *lastchar++ = '2';
- *lastchar++ = '0';
- }
- *d = lastchar;
- }
- *s += 1;
- done = 1;
- } else {
- if ( !normalize && !ASCII_SPACE( **s ) )
- firstchar = 0;
-
- res = get_next_char( s, &tmp, &is_escaped );
- if (res == 0)
- return 0;
-
- if ( string_type == PRINTABLE_STRING ) {
- if ( !SLAP_PRINTABLE(tmp) )
- return 0;
- } else if (string_type == IA5_STRING ) {
- if ( !SLAP_IA5(tmp) )
- return 0;
- }
-
- if ( !ASCII_WHITESPACE( tmp ) )
- firstchar = 0;
+ LDAPRDN *tmpRDN;
+ const char *p;
+ int rc;
- if ( (tmp < 128) && (unnormalized_unicode_len > 0) ) {
- res = normalize_unicode(unnormalized_unicode, unnormalized_unicode_len, d, av_length);
- if (res == 0)
- return 0;
- unnormalized_unicode_len = 0;
- lastchar = *d;
- }
+ assert( dn );
+ assert( rdn );
- if ( RDN_NEEDSESCAPE( tmp ) ||
- RDN_SPECIAL( tmp ) ) {
- if ( ( representation == INVALUE ) && !is_escaped ) {
- /* This character should have been escaped according to
- * RFC 2253, but was not */
- return 0;
- }
- /* This must be an ASCII character */
- **d = '\\';
- *d += 1;
- **d = tmp;
- *d += 1;
- *av_length += 1;
- lastchar = *d;
- first_dstchar = 1;
- } else if ( tmp == 0 ) {
- strncpy(*d, "\\00", 3);
- *d += 3;
- *av_length += 1;
- lastchar = *d;
- first_dstchar = 1;
- } else if ( !first_dstchar && (tmp == '#') ) {
- **d = '\\';
- *d += 1;
- **d = tmp;
- *d += 1;
- *av_length += 1;
- lastchar = *d;
- first_dstchar = 1;
- } else if ( !normalize && !ASCII_SPACE( tmp ) ) {
- #ifdef UTF8DN
- if (make_uppercase) {
- tmp = uctoupper( tmp );
- }
- len = ldap_ucs4_to_utf8( tmp, *d );
- *d += len;
- #else
- if (make_uppercase) {
- **d = TOUPPER( tmp );
- } else {
- **d = tmp;
- }
- *d += 1;
- #endif
- *av_length += 1;
- lastchar = *d;
- first_dstchar = 1;
- } else if ( !ASCII_WHITESPACE( tmp ) ) {
- #ifdef UTF8DN
- if (make_uppercase) {
- tmp = uctoupper( tmp );
- }
- if ( normalize && (tmp > 127) ) {
- if ( (unnormalized_unicode_len == 0) && first_dstchar ) {
- /* The previous output character must be ASCII
- * and it should be normalized.
- */
- *d -= 1;
- unnormalized_unicode[unnormalized_unicode_len++] = **d;
- *av_length -= 1;
- }
- unnormalized_unicode[unnormalized_unicode_len++] = tmp;
- } else {
- len = ldap_ucs4_to_utf8( tmp, *d );
- *d += len;
- *av_length += 1;
- }
- #else
- if (make_uppercase) {
- **d = TOUPPER( tmp );
- } else {
- **d = tmp;
- }
- *d += 1;
- *av_length += 1;
- #endif
- lastchar = *d;
- first_dstchar = 1;
- } else if ( !firstchar && ( !normalize || !ASCII_SPACE( *(*d - 1) ) ) ) {
- if ( !first_dstchar ) {
- **d = '\\';
- *d += 1;
- **d = '2';
- *d += 1;
- **d = '0';
- *d += 1;
- first_dstchar = 1;
- } else {
- **d = ' ';
- *d +=1;
- }
- *av_length += 1;
- if ( !normalize && ( is_escaped || representation == INQUOTEDVALUE ) )
- lastchar = *d;
- }
- }
- }
- break;
-
- case INBERENCODEDVALUE:
- /* Skip over the '#' */
- *s += 1;
-
- encoded_length = 0;
-
- res = ber_parse_string(s, d, av_length, make_uppercase, normalize, string_type, &encoded_length, &firstchar, unnormalized_unicode, &unnormalized_unicode_len);
- if (res == 0)
- return 0;
-
- if (unnormalized_unicode_len > 0) {
- res = normalize_unicode(unnormalized_unicode, unnormalized_unicode_len, d, av_length);
- if (res == 0)
- return 0;
- } else if ( ASCII_SPACE( *(*d - 1) ) ) {
- if ( normalize ) {
- *d -= 1;
- *av_length -= 1;
- } else {
- *(*d - 1) = '\\';
- **d = '2';
- *d += 1;
- **d = '0';
- *d += 1;
- }
- }
+ if( dn->bv_len == 0 ) {
+ return LDAP_OTHER;
+ }
- break;
+ rc = ldap_str2rdn( dn->bv_val, &tmpRDN, (char **)&p, LDAP_DN_FORMAT_LDAP );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
+ }
- default:
- /* Something must be wrong, representation shouldn't
- * have any other value.
- */
- return 0;
- break;
+ rc = ldap_rdn2bv( tmpRDN, rdn, LDAP_DN_FORMAT_LDAPV3 );
+ ldap_rdnfree( tmpRDN );
+ if ( rc != LDAP_SUCCESS ) {
+ return rc;
}
- return 1;
+ return LDAP_SUCCESS;
}
-
-/* Normalize a directory string */
-static int
-DirectoryString_normalize(
- char **s,
- char **d,
- int *av_length,
- int make_uppercase,
- int normalize,
- int representation,
- unsigned long *unnormalized_unicode
-)
+/*
+ * We can assume the input is a prettied or normalized DN
+ */
+int
+dn_rdnlen(
+ Backend *be,
+ struct berval *dn_in )
{
- return String_normalize(s, d, av_length, make_uppercase, normalize, representation, DIRECTORY_STRING, unnormalized_unicode);
-}
+ const char *p;
+ assert( dn_in );
-/* Normalize a printable string */
-static int
-PrintableString_normalize(
- char **s,
- char **d,
- int *av_length,
- int make_uppercase,
- int normalize,
- int representation,
- unsigned long *unnormalized_unicode
-)
-{
- return String_normalize(s, d, av_length, make_uppercase, normalize, representation, PRINTABLE_STRING, unnormalized_unicode);
-}
+ if ( dn_in == NULL ) {
+ return 0;
+ }
+ if ( !dn_in->bv_len ) {
+ return 0;
+ }
-/* Normalize an IA5 string */
-static int
-IA5String_normalize(
- char **s,
- char **d,
- int *av_length,
- int make_uppercase,
- int normalize,
- int representation,
- unsigned long *unnormalized_unicode
-)
-{
- return String_normalize(s, d, av_length, make_uppercase, normalize, representation, IA5_STRING, unnormalized_unicode);
-}
+ if ( be != NULL && be_issuffix( be, dn_in ) ) {
+ return 0;
+ }
+
+ p = strchr( dn_in->bv_val, ',' );
+ return p ? p - dn_in->bv_val : dn_in->bv_len;
+}
-/* The string beginning at *s represents an ASCII-hex encoding of a BER
- * encoded bitstring, where the encoding is primitive, definite-length.
- * If the string is properly encoded, place the string in *d, advance *s
- * and *d, add the number of bits in the string to *av_length, add
- * the length of the BER encoding to *encoded_length, and return 1. Otherwise,
- * return 0.
+/* rdnValidate:
+ *
+ * LDAP_SUCCESS if rdn is a legal rdn;
+ * LDAP_INVALID_SYNTAX otherwise (including a sequence of rdns)
*/
-static int
-ber_parse_primitive_bitstring(
- char **s,
- char **d,
- int *av_length,
- unsigned int *encoded_length
-)
+int
+rdnValidate( struct berval *rdn )
{
- int res;
- unsigned char ch;
- unsigned long int length;
- unsigned char unused;
- int bit_pos;
+#if 1
+ /* Major cheat!
+ * input is a pretty or normalized DN
+ * hence, we can just search for ','
+ */
+ if( rdn == NULL || rdn->bv_len == 0 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
- static unsigned char mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+ return strchr( rdn->bv_val, ',' ) == NULL
+ ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
- res = get_ber_length(s, encoded_length, &length);
- if (res == 0)
- return 0;
+#else
+ LDAPRDN *RDN, **DN[ 2 ] = { &RDN, NULL };
+ const char *p;
+ int rc;
- if (length < 1) {
- /* There must be a least one byte containing the number of
- * unused bits.
- */
+ /*
+ * must be non-empty
+ */
+ if ( rdn == NULL || rdn == '\0' ) {
return 0;
}
- /* get number of unused bits */
- res = get_hexpair(s, &unused);
- if ( ( res == 0 ) || ( unused > 7 ) )
+ /*
+ * must be parsable
+ */
+ rc = ldap_str2rdn( rdn, &RDN, (char **)&p, LDAP_DN_FORMAT_LDAP );
+ if ( rc != LDAP_SUCCESS ) {
return 0;
+ }
- if ( (length == 0) && (unused != 0) ) {
- /* If there are no content bits, there can be no unused bits */
+ /*
+ * Must be one-level
+ */
+ if ( p[ 0 ] != '\0' ) {
return 0;
}
- *encoded_length += 1;
- length--;
-
- while( length > 1 ) {
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
-
- *encoded_length += 1;
- length--;
-
- for(bit_pos = 7; bit_pos >= 0; bit_pos--) {
- if ( (ch & mask[bit_pos]) == 0 ) {
- **d = '0';
- } else {
- **d = '1';
- }
- *d += 1;
- *av_length += 1;
- }
+ /*
+ * Schema-aware validate
+ */
+ if ( rc == LDAP_SUCCESS ) {
+ rc = LDAPDN_validate( DN );
}
+ ldap_rdnfree( RDN );
- if ( length == 1) {
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
+ /*
+ * Must validate (there's a repeated parsing ...)
+ */
+ return ( rc == LDAP_SUCCESS );
+#endif
+}
- *encoded_length += 1;
- for(bit_pos = 7; bit_pos >= unused; bit_pos--) {
- if ( (ch & mask[bit_pos]) == 0 ) {
- **d = '0';
- } else {
- **d = '1';
- }
- *d += 1;
- *av_length += 1;
- }
- }
-
- return 1;
-}
-
-
-/* The string beginning at *s represents an ASCII-hex encoding of a BER
- * encoded bitstring. If the string is properly encoded, place the string
- * in *d, advance *s and *d, add the number of bits in the string to
- * *av_length, add the length of the BER encoding to *encoded_length, and
- * return 1. Otherwise, return 0.
- */
-static int
-ber_parse_bitstring(
- char **s,
- char **d,
- int *av_length,
- unsigned int *encoded_length
-)
-{
- int res;
- unsigned char ch;
- unsigned long int length;
- unsigned int component_encoded_length;
-
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
-
- *encoded_length = 1;
-
- if (ch == '\x03') {
- /* Primitive, definite-length encoding */
- res = ber_parse_primitive_bitstring(s, d, av_length, encoded_length);
- if (res == 0)
- return 0;
- } else if ( ch == '\x23' ) {
- /* Constructed encoding */
-
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
-
- if ( ch == 128 ) {
- /* Constructed, indefinite-length */
- *encoded_length += 1;
-
- while ( ch != 0 ) {
- res = ber_parse_bitstring(s, d, av_length, &component_encoded_length);
- if (res == 0)
- return 0;
-
- *encoded_length += component_encoded_length;
-
- /* Must end in "0000" */
- res = get_hexpair(s, &ch);
- if (res == 0)
- return 0;
-
- if (ch == 0) {
- res = get_hexpair(s, &ch);
- if ( (res == 0) || (ch != 0) )
- return 0;
-
- *encoded_length += 2;
- } else {
- *s -= 2;
- }
- }
- } else {
- /* Constructed, definite-length */
- *s -= 2;
- res = get_ber_length(s, encoded_length, &length);
- if (res == 0)
- return 0;
-
- while (length > 0) {
- res = ber_parse_bitstring(s, d, av_length, &component_encoded_length);
- if ( (res == 0) || (component_encoded_length > length) )
- return 0;
-
- length -= component_encoded_length;
- *encoded_length += component_encoded_length;
- }
- }
- } else {
- /* Not a valid bitstring */
- return 0;
- }
-}
-
-
-/* *s is a pointer to a string of zero or more 0's and 1's. Return a binary encoding of the next 8 bits of *s and advance
- * *s to the end of the parsed sub-string. If the string is less than 8-bytes long, pad the binary encoding with 0's.
- */
-static unsigned char
-getNext8bits(
- char **s
-)
-{
- static unsigned char mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
- int pos;
- unsigned char output;
-
- output = 0;
- pos = 8;
-
- while ( ( pos > 0 ) && ( ( **s == '0' ) || ( **s == '1' ) ) ) {
- pos--;
-
- if ( **s == '1' ) {
- output = output | mask[pos];
- }
-
- *s += 1;
- }
-
- return output;
-}
-
-
-/* The string beginning at *s represents a bitstring encoded according to
- * RFC 2253. If the string is properly encoded, place the string
- * in *d, advance *s and *d, place the length of the string representation of
- * the bitstring in *av_length, and return 1. Otherwise, return 0.
- * representation specifies whether the string is encoding as ASCII-hex BER,
- * within quotation marks, or as a plain string.
- *
- * According to RFC 2252, the string representation for
- * bit strings is described by the following BNF:
+/* build_new_dn:
*
- * bitstring = "'" *binary-digit "'B"
+ * Used by ldbm/bdb2 back_modrdn to create the new dn of entries being
+ * renamed.
*
- * binary-digit = "0" / "1"
+ * new_dn = parent (p_dn) + separator + rdn (newrdn) + null.
*/
-static int
-bitString_normalize(
- char **s,
- char **d,
- int *av_length,
- int make_uppercase,
- int normalize,
- int representation,
- unsigned long *unnormalized_unicode /* not used in this function */
-)
-{
- int res;
- int is_escaped;
- unsigned char ch;
- unsigned int encoded_length;
-
- int DER_length;
- unsigned char unused_bits;
- unsigned char byte1, byte2, temp;
- char *src, *start_of_output;
-
- *av_length = 0;
- start_of_output = *d;
-
- switch ( representation ) {
-
- case INVALUE:
- case INQUOTEDVALUE:
- if ( representation == INQUOTEDVALUE ) {
- /* Skip over quotation mark */
- *s += 1;
- }
-
- /* First non-space character must be a "'" */
- res = get_next_byte(s, &ch, &is_escaped);
- if ( (res == 0) || (ch != '\'') )
- return 0;
-
- **d = '\'';
- *d += 1;
- *av_length += 1;
-
- /* Next should be a sequence of 0's and 1's followed by a "'" */
- res = get_next_byte(s, &ch, &is_escaped);
- if (res == 0)
- return 0;
-
- while ( ( ch == '0' ) || ( ch == '1' ) ) {
- **d = ch;
- *d += 1;
- *av_length += 1;
-
- res = get_next_byte(s, &ch, &is_escaped);
- if (res == 0)
- return 0;
- }
-
- if ( ch != '\'' )
- return 0;
-
- **d = '\'';
- *d += 1;
- *av_length += 1;
-
- /* The last character should be a 'B' */
- res = get_next_byte(s, &ch, &is_escaped);
- if ( (res == 0) || ( TOUPPER(ch) != 'B' ) )
- return 0;
- **d = 'B';
- *d += 1;
- *av_length += 1;
-
- if ( representation == INQUOTEDVALUE ) {
- if ( **s != '\"' )
- return 0;
- else
- *s += 1;
- }
- break;
-
- case INBERENCODEDVALUE:
- /* Skip over the '#' */
- *s += 1;
-
- **d = '\'';
- *d += 1;
- *av_length +=1;
-
- encoded_length = 0;
-
- ber_parse_bitstring(s, d, av_length, &encoded_length);
- if (res == 0)
- return 0;
-
- **d = '\'';
- *d += 1;
- **d = 'B';
- *d += 1;
- *av_length += 2;
-
- break;
-
- default:
- /* Something must be wrong, representation shouldn't
- * have any other value.
- */
- return 0;
- break;
- }
-
- if ( !normalize && (representation != INBERENCODEDVALUE) )
- return 1;
-
- *av_length -= 3;
-
- unused_bits = *av_length % 8;
- if ( unused_bits == 0 ) {
- DER_length = (*av_length / 8) + 1;
- } else {
- DER_length = (*av_length / 8) + 2;
- unused_bits = 8 - unused_bits;
- }
-
- *d = start_of_output;
- src = start_of_output + 1;
-
- if (DER_length > 1)
- byte1 = getNext8bits( &src );
- if (DER_length > 2)
- byte2 = getNext8bits( &src );
-
- **d = '#';
- *d += 1;
- **d = '0';
- *d += 1;
- **d = '3';
- *d += 1;
-
- /* Insert length into string */
- if (DER_length < 128) {
- temp = DER_length;
- write_hex_pair(d, temp);
- *av_length = 7 + 2 * DER_length;
- } else if (DER_length < 256) {
- **d = '8';
- *d += 1;
- **d = '1';
- *d += 1;
- temp = DER_length;
- write_hex_pair(d, temp);
- *av_length = 9 + 2 * DER_length;
- } else if (DER_length < 65536) {
- **d = '8';
- *d += 1;
- **d = '2';
- *d += 1;
- temp = (DER_length >> 8) & 0xFF;
- write_hex_pair(d, temp);
- temp = DER_length & 0xFF;
- write_hex_pair(d, temp);
- *av_length = 11 + 2 * DER_length;
- } else if (DER_length < 16777216) {
- **d = '8';
- *d += 1;
- **d = '3';
- *d += 1;
- temp = (DER_length >> 16) & 0xFF;
- write_hex_pair(d, temp);
- temp = (DER_length >> 8) & 0xFF;
- write_hex_pair(d, temp);
- temp = DER_length & 0xFF;
- write_hex_pair(d, temp);
- *av_length = 13 + 2 * DER_length;
- } else {
- /* NOTE: I am assuming that the length will always fit in 4 octets */
- **d = '8';
- *d += 1;
- **d = '4';
- *d += 1;
- temp = (DER_length >> 24) & 0xFF;
- write_hex_pair(d, temp);
- temp = (DER_length >> 16) & 0xFF;
- write_hex_pair(d, temp);
- temp = (DER_length >> 8) & 0xFF;
- write_hex_pair(d, temp);
- temp = DER_length & 0xFF;
- write_hex_pair(d, temp);
- *av_length = 15 + 2 * DER_length;
- }
-
- /* Insert number of unused bits into string */
- write_hex_pair(d, unused_bits);
-
- if (DER_length > 1)
- write_hex_pair(d, byte1);
- if (DER_length > 2)
- write_hex_pair(d, byte2);
-
- if (DER_length > 3) {
- DER_length -= 3;
-
- while (DER_length > 0) {
- byte1 = getNext8bits( &src );
- write_hex_pair(d, byte1);
- DER_length--;
- }
- }
-
- return 1;
-}
-
-
-/*
- * match_oid - determine if the OID represented by the string beginning
- * at *src and of length len is a known attribute type. If so, copy the
- * string representation to *dst and return a pointer to the normalization
- * function for the attribute value. If the attribute type places an
- * upper bound on the length of the attribute value, make *ub that
- * upper bound, otherwise set *ub to -1.
- * If the OID is unknown, copy the OID to *dst and return NULL.
- */
-static av_normalize_type
-match_oid(char **src, char **dst, int *ub, int len, int make_uppercase)
+void
+build_new_dn( struct berval * new_dn,
+ struct berval * parent_dn,
+ struct berval * newrdn )
{
- int i;
- int dst_len = 0;
- av_normalize_type normalize_function = NULL;
-
- *ub = -1;
-
- switch( len ) {
- case 7:
- if (strncmp(*src, "2.5.4.6", len) == 0) {
- /* Country */
- **dst = 'c';
- dst_len = 1;
- *ub = 2;
- normalize_function = PrintableString_normalize;
- } else if (strncmp(*src, "2.5.4.3", len) == 0) {
- /* Common Name */
- strncpy(*dst, "cn", 2);
- dst_len = 2;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncmp(*src, "2.5.4.8", len) == 0) {
- /* State or Province Name */
- strncpy(*dst, "st", 2);
- dst_len = 2;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else if (strncmp(*src, "2.5.4.7", len) == 0) {
- /* locality */
- **dst = 'l';
- dst_len = 1;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else if (strncmp(*src, "2.5.4.5", len) == 0) {
- /* serial number */
- strncpy(*dst, "snu", 3);
- dst_len = 3;
- *ub = 64;
- normalize_function = PrintableString_normalize;
- } else if (strncmp(*src, "2.5.4.4", len) == 0) {
- /* surname */
- strncpy(*dst, "sn", 2);
- dst_len = 2;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncmp(*src, "2.5.4.9", len) == 0) {
- /* street address */
- strncpy(*dst, "street", 6);
- dst_len = 6;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 8:
- if (strncmp(*src, "2.5.4.10", len) == 0) {
- /* Organization */
- **dst = 'o';
- dst_len = 1;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncmp(*src, "2.5.4.11", len) == 0) {
- /* Organizational Unit */
- strncpy(*dst, "ou", 2);
- dst_len = 2;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncmp(*src, "2.5.4.12", len) == 0) {
- /* title */
- strncpy(*dst, "title", 5);
- dst_len = 5;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncmp(*src, "2.5.4.42", len) == 0) {
- /* givenName */
- strncpy(*dst, "givenName", 9);
- dst_len = 9;
- *ub = -1;
- normalize_function = DirectoryString_normalize;
- } else if (strncmp(*src, "2.5.4.43", len) == 0) {
- /* initials */
- strncpy(*dst, "initials", 8);
- dst_len = 8;
- *ub = -1;
- normalize_function = DirectoryString_normalize;
- } else if (strncmp(*src, "2.5.4.44", len) == 0) {
- /* generationQualifier */
- strncpy(*dst, "generationQualifier", 19);
- dst_len = 19;
- *ub = -1;
- normalize_function = DirectoryString_normalize;
- } else if (strncmp(*src, "2.5.4.45", len) == 0) {
- /* uniqueIdentifier */
- strncpy(*dst, "uniqueIdentifier", 16);
- dst_len = 16;
- *ub = -1;
- normalize_function = bitString_normalize;
- } else if (strncmp(*src, "2.5.4.46", len) == 0) {
- /* dnQualifier */
- strncpy(*dst, "dnQualifier", 11);
- dst_len = 11;
- *ub = -1;
- normalize_function = PrintableString_normalize;
- } else if (strncmp(*src, "2.5.4.65", len) == 0) {
- /* Pseudonym */
- strncpy(*dst, "Pseudonym", 9);
- dst_len = 9;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 20:
- if (strncmp(*src, "1.2.840.113549.1.9.1", len) == 0) {
- /* email */
- **dst = 'e';
- dst_len = 1;
- *ub = 128;
- normalize_function = IA5String_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 17:
- if (strncmp(*src, "0.2.262.1.10.7.20", len) == 0) {
- /* name distinguisher */
- strncpy(*dst, "nameDistinguisher", 17);
- dst_len = 17;
- *ub = -1;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 25:
- if (strncmp(*src, "0.9.2342.19200300.100.1.1", len) == 0) {
- /* userID */
- strncpy(*dst, "uid", 3);
- dst_len = 3;
- *ub = 256;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
+ char *ptr;
- case 26:
- if (strncmp(*src, "0.9.2342.19200300.100.1.25", len) == 0) {
- /* domainComponent */
- strncpy(*dst, "dc", 2);
- dst_len = 2;
- *ub = -1;
- normalize_function = IA5String_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- default:
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- break;
+ if ( parent_dn == NULL ) {
+ ber_dupbv( new_dn, newrdn );
+ return;
}
- if (make_uppercase) {
- for(i=0; i < dst_len; i++) {
- **dst = TOUPPER( **dst );
- *dst += 1;
- }
- } else {
- *dst += dst_len;
- }
- *src += len;
- return normalize_function;
+ new_dn->bv_len = parent_dn->bv_len + newrdn->bv_len + 1;
+ new_dn->bv_val = (char *) ch_malloc( new_dn->bv_len + 1 );
+
+ ptr = slap_strcopy( new_dn->bv_val, newrdn->bv_val );
+ *ptr++ = ',';
+ strcpy( ptr, parent_dn->bv_val );
}
/*
- * match_key - determine if the attribute type represented by the string
- * beginning at *src and of length len is a known attribute type. If so,
- * copy the string representation to *dst and return a pointer to the
- * normalization function for the attribute value. If the attribute type
- * places an upper bound on the length of the attribute value, make *ub that
- * upper bound, otherwise set *ub to -1.
- * If the attribute type is unknown, copy the string representation of the
- * attribute type to *dst and return NULL.
+ * dnIsSuffix - tells whether suffix is a suffix of dn.
+ * Both dn and suffix must be normalized.
*/
-static av_normalize_type
-match_key(char **src, char **dst, int *ub, int len, int make_uppercase)
+int
+dnIsSuffix(
+ const struct berval *dn,
+ const struct berval *suffix )
{
- int i;
- int dst_len = 0;
- av_normalize_type normalize_function = NULL;
-
- *ub = -1;
-
- switch( len ) {
- case 1:
- if (strncasecmp(*src, "C", len) == 0) {
- /* country */
- **dst = 'c';
- dst_len = 1;
- *ub = 2;
- normalize_function = PrintableString_normalize;
- } else if (strncasecmp(*src, "O", len) == 0) {
- /* organization */
- **dst = 'o';
- dst_len = 1;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "T", len) == 0) {
- /* title */
- strncpy(*dst, "title", 5);
- dst_len = 5;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "S", len) == 0) {
- /* state or province */
- strncpy(*dst, "st", 2);
- dst_len = 2;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "L", len) == 0) {
- /* locality */
- **dst = 'l';
- dst_len = 1;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "E", len) == 0) {
- /* e-mail */
- **dst = 'e';
- dst_len = 1;
- *ub = 255;
- normalize_function = IA5String_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 2:
- if (strncasecmp(*src, "CN", len) == 0) {
- /* common name */
- strncpy(*dst, "cn", 2);
- dst_len = 2;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "OU", len) == 0) {
- /* organizational unit */
- strncpy(*dst, "ou", 2);
- dst_len = 2;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "DC", len) == 0) {
- /* domainComponent */
- strncpy(*dst, "dc", 2);
- dst_len = 2;
- *ub = -1;
- normalize_function = IA5String_normalize;
- } else if (strncasecmp(*src, "SN", len) == 0) {
- /* surname */
- strncpy(*dst, "sn", 2);
- dst_len = 2;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "ST", len) == 0) {
- /* state or province */
- strncpy(*dst, "st", 2);
- dst_len = 2;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 3:
- if (strncasecmp(*src, "SNU", len) == 0) {
- /* serial number */
- strncpy(*dst, "snu", 3);
- dst_len = 3;
- *ub = 64;
- normalize_function = PrintableString_normalize;
- } else if (strncasecmp(*src, "UID", len) == 0) {
- /* userID */
- strncpy(*dst, "uid", 3);
- dst_len = 3;
- *ub = 256;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 5:
- if (strncasecmp(*src, "TITLE", len) == 0) {
- /* title */
- strncpy(*dst, "title", 5);
- dst_len = 5;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "STATE", len) == 0) {
- /* state or province */
- strncpy(*dst, "st", 2);
- dst_len = 2;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 6:
- if (strncasecmp(*src, "USERID", len) == 0) {
- /* userID */
- strncpy(*dst, "uid", 3);
- dst_len = 3;
- *ub = 256;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "STREET", len) == 0) {
- /* street address */
- strncpy(*dst, "street", 6);
- dst_len = 6;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 7:
- if (strncasecmp(*src, "SURNAME", len) == 0) {
- /* surname */
- strncpy(*dst, "sn", 2);
- dst_len = 2;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 8:
- if (strncasecmp(*src, "INITIALS", len) == 0) {
- /* initials */
- strncpy(*dst, "initials", 8);
- dst_len = 8;
- *ub = -1;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "PROVINCE", len) == 0) {
- /* state or province */
- strncpy(*dst, "st", 2);
- dst_len = 2;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
+ int d = dn->bv_len - suffix->bv_len;
- case 9:
- if (strncasecmp(*src, "GIVENNAME", len) == 0) {
- /* givenName */
- strncpy(*dst, "givenName", 9);
- dst_len = 9;
- *ub = -1;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "PSEUDONYM", len) == 0) {
- /* Pseudonym */
- strncpy(*dst, "Pseudonym", 9);
- dst_len = 9;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
+ assert( dn );
+ assert( suffix );
- case 10:
- if (strncasecmp(*src, "COMMONNAME", len) == 0) {
- /* common name */
- strncpy(*dst, "cn", 2);
- dst_len = 2;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 11:
- if (strncasecmp(*src, "DNQUALIFIER", len) == 0) {
- /* Distinguished Name Quailifier */
- strncpy(*dst, "dnQualifier", 11);
- dst_len = 11;
- *ub = -1;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "COUNTRYNAME", len) == 0) {
- /* country */
- **dst = 'c';
- dst_len = 1;
- *ub = 2;
- normalize_function = PrintableString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 12:
- if (strncasecmp(*src, "SERIALNUMBER", len) == 0) {
- /* serial number */
- strncpy(*dst, "snu", 3);
- dst_len = 3;
- *ub = 64;
- normalize_function = PrintableString_normalize;
- } else if (strncasecmp(*src, "LOCALITYNAME", len) == 0) {
- /* locality */
- **dst = 'l';
- dst_len = 1;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "EMAILADDRESS", len) == 0) {
- /* e-mail */
- **dst = 'e';
- dst_len = 1;
- *ub = 255;
- normalize_function = IA5String_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 13:
- if (strncasecmp(*src, "STREETADDRESS", len) == 0) {
- /* street address */
- strncpy(*dst, "street", 6);
- dst_len = 6;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 15:
- if (strncasecmp(*src, "DOMAINCOMPONENT", len) == 0) {
- /* domainComponent */
- strncpy(*dst, "dc", 2);
- dst_len = 2;
- *ub = -1;
- normalize_function = IA5String_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 16:
- if (strncasecmp(*src, "UNIQUEIDENTIFIER", len) == 0) {
- /* uniqueIdentifier */
- strncpy(*dst, "uniqueIdentifier", 16);
- dst_len = 16;
- *ub = -1;
- normalize_function = bitString_normalize;
- } else if (strncasecmp(*src, "ORGANIZATIONNAME", len) == 0) {
- /* organization */
- **dst = 'o';
- dst_len = 1;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 17:
- if (strncasecmp(*src, "NAMEDISTINGUISHER", len) == 0) {
- /* name distinguisher */
- strncpy(*dst, "nameDistinguisher", 17);
- dst_len = 17;
- *ub = -1;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- case 19:
- if (strncasecmp(*src, "GENERATIONQUALIFIER", len) == 0) {
- /* Distinguished Name Quailifier */
- strncpy(*dst, "generationQualifier", 19);
- dst_len = 19;
- *ub = -1;
- normalize_function = DirectoryString_normalize;
- } else if (strncasecmp(*src, "STATEORPROVINCENAME", len) == 0) {
- /* state or province */
- strncpy(*dst, "st", 2);
- dst_len = 2;
- *ub = 128;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
-
- case 22:
- if (strncasecmp(*src, "ORGANIZATIONALUNITNAME", len) == 0) {
- /* organizational unit */
- strncpy(*dst, "ou", 2);
- dst_len = 2;
- *ub = 64;
- normalize_function = DirectoryString_normalize;
- } else {
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- }
- break;
-
- default:
- /* Unknown attributeType */
- strncpy(*dst, *src, len);
- dst_len = len;
- *ub = -1;
- normalize_function = NULL;
- break;
- }
-
- if (make_uppercase) {
- for(i=0; i < dst_len; i++) {
- **dst = TOUPPER( **dst );
- *dst += 1;
- }
- } else {
- *dst += dst_len;
+ /* empty suffix matches any dn */
+ if ( suffix->bv_len == 0 ) {
+ return 1;
}
- *src += len;
- return normalize_function;
-}
-
-static int
-get_validated_av_in_dn(char **s, char **d, int make_uppercase, int normalize, unsigned long *unnormalized_unicode) {
- char *i;
- int status, av_ub, len, av_length;
- av_normalize_type av_normalize;
-
- /* First skip over any leading spaces */
- while ( ASCII_SPACE( **s ) )
- *s += 1;
-
- /* Next get the attribute type */
- if ( OID_LEADCHAR(**s) ) {
- i = *s;
- while ( *i != '\0' && OID_CHAR(*i) )
- i++;
- if ( *i == '\0' )
- return 0;
-
- len = i - *s;
- av_normalize = match_oid(s, d, &av_ub, len, make_uppercase);
- } else if ( DESC_LEADCHAR(**s) ) {
- if ( TOUPPER ( **s ) == 'O' &&
- TOUPPER ( *(*s+1) ) == 'I' &&
- TOUPPER ( *(*s+2) ) == 'D' &&
- *(*s+3) == '.' ) {
- *s += 4;
- if ( !OID_LEADCHAR(**s) )
- return 0;
-
- i = *s;
- while ( *i != '\0' && OID_CHAR(*i) )
- i++;
- if ( *i == '\0' )
- return 0;
-
- len = i - *s;
- av_normalize = match_oid(s, d, &av_ub, len, make_uppercase);
- } else {
- i = *s;
- while ( *i != '\0' && DESC_CHAR(*i) )
- i++;
- if ( *i == '\0' )
- return 0;
-
- len = i - *s;
- av_normalize = match_key(s, d, &av_ub, len, make_uppercase);
- }
- } else {
+ /* suffix longer than dn */
+ if ( d < 0 ) {
return 0;
}
-
- /* Next should be the equal sign */
-
- while ( (**s != '=') && (**s != '\0') ) {
- if ( !ASCII_SPACE(**s) )
- return 0;
-
- *s += 1;
- }
-
- if (**s != '=')
+ /* no rdn separator or escaped rdn separator */
+ if ( d > 1 && !DN_SEPARATOR( dn->bv_val[ d - 1 ] ) ) {
return 0;
-
- *s += 1;
- **d = '=';
- *d += 1;
-
- while ( ASCII_SPACE(**s) )
- *s += 1;
-
- /* The final part is the attribute value */
- if ( **s == '"' ) {
- if (av_normalize == NULL) {
- av_ub = -1;
- av_normalize = DirectoryString_normalize;
- }
- status = (*av_normalize)(s, d, &av_length, make_uppercase, normalize, INQUOTEDVALUE, unnormalized_unicode);
- if (status == 0)
- return 0;
- if ( ( av_ub != -1 ) && ( av_length > av_ub ) ) {
- /* attribute value too long */
- return 0;
- }
- } else if ( **s == '#' ) {
- if (av_normalize == NULL) {
- /* Unknown attribute type. Since we don't know its string representation,
- * just leave it as a BER encoded value.
- */
- **d = **s;
- *s += 1; *d += 1;
- av_length = 1;
- while ( ASCII_XDIGIT(**s) ) {
- **d = TOUPPER(**s);
- *s += 1; *d += 1;
- av_length++;
- }
-
- /* The length must be odd, since there must be an even number of
- * hexadecimal charaters after the '#'.
- */
- if ( (av_length & 1) == 0)
- return 0;
- } else {
- status = (*av_normalize)(s, d, &av_length, make_uppercase, normalize, INBERENCODEDVALUE, unnormalized_unicode);
- if (status == 0)
- return 0;
- if ( ( av_ub != -1 ) && ( av_length > av_ub ) ) {
- /* attribute value too long */
- return 0;
- }
- }
- } else {
- if (av_normalize == NULL) {
- av_ub = -1;
- av_normalize = DirectoryString_normalize;
- }
- status = (*av_normalize)(s, d, &av_length, make_uppercase, normalize, INVALUE, unnormalized_unicode);
- if (status == 0)
- return 0;
- if ( ( av_ub != -1 ) && ( av_length > av_ub ) ) {
- /* attribute value too long */
- return 0;
- }
}
- return 1;
-}
-
-/* The string *s is a distinguished name encoded according to RFC 2253.
- * If the first RDN in *s is properly encoded, place in *d a normalized
- * version of the first RDN in *s, advance *d to the end of the normalized
- * RDN, advance *s to the end of the input string, and return 1.
- * If *s is not properly encoded, return 0.
- */
-static int
-get_validated_rdn_in_dn(char **s, char **d, int make_uppercase, int normalize, unsigned long *unnormalized_unicode) {
- char *av_pair[1001]; /* Assume there are less than 1000 attribute value pairs per RDN */
- int av_pair_len[1001];
- char *temp, *work_space;
- int i, j, num_av_pairs, status, state, len;
-
- /* An RDN is a set of 1 or more attribute/value pairs. Get the first AV pair */
- av_pair[0] = *d;
- status = get_validated_av_in_dn(s, d, make_uppercase, normalize, unnormalized_unicode);
- if (status == 0)
+ /* no possible match or malformed dn */
+ if ( d == 1 ) {
return 0;
-
- num_av_pairs = 1;
-
- state = B4SEPARATOR;
-
- while ( ASCII_SPACE( **s ) ) {
- *s += 1;
- }
-
- if ( **s != '+') {
- /* This RDN contains only 1 attribute value pair */
- return 1;
}
- /* Since RDNs with more than one attribute value pair are
- * rare, the above code was optimized for the case of an
- * RDN with only one AV pair. This RDN, however, contains
- * two or more AV pairs and they must be sorted to ensure
- * consistency when performing matches. The ordering does
- * not matter as long as it is consistent.
- */
-
- /* Create temporary space to hold the AV pairs before sorting */
- **d = '\0';
-
- /* Compute the length of the first AV pair */
- av_pair_len[0] = *d - av_pair[0];
-
- work_space = (char *)ch_malloc(4 * strlen( *s ) + av_pair_len[0] + 1000);
-
- /* Move *d back so that the whole RDN can be written in the proper order */
- *d = av_pair[0];
-
- av_pair[0] = work_space;
- bcopy(*d, av_pair[0], av_pair_len[0]+1);
-
- av_pair[1] = av_pair[0] + av_pair_len[0] + 1;
- while ( (num_av_pairs < 1000) && (**s != ',') && (**s != ';') && (**s != '\0') ) {
- if ( **s != '+' ) {
- ch_free(work_space);
- return 0;
- }
- *s += 1;
-
- temp = av_pair[num_av_pairs];
- status = get_validated_av_in_dn(s, &temp, make_uppercase, normalize, unnormalized_unicode);
- if (status == 0) {
- ch_free(work_space);
- return 0;
- }
- av_pair_len[num_av_pairs] = temp - av_pair[num_av_pairs];
-
- *temp++ = '\0';
- num_av_pairs++;
- av_pair[num_av_pairs] = temp;
-
- while ( ASCII_SPACE(**s) )
- *s += 1;
- }
-
- if (num_av_pairs == 1000) {
- ch_free(work_space);
- return 0;
- }
-
- if ( normalize ) {
- /* Sort the AV pairs. Since the number of AV pairs in an RDN should always
- * be very small, bubblesort is used.
- */
- for(i = 0; i < num_av_pairs; i++) {
- for(j = 1; j < num_av_pairs; j++) {
- if (strcasecmp(av_pair[j-1], av_pair[j]) > 0) {
- temp = av_pair[j-1];
- av_pair[j-1] = av_pair[j];
- av_pair[j] = temp;
-
- len = av_pair_len[j-1];
- av_pair_len[j-1] = av_pair_len[j];
- av_pair_len[j] = len;
- }
- }
- }
- }
-
- /* place the AV pairs in *d, separated by commas */
- for(i=0; i < num_av_pairs; i++) {
- bcopy(av_pair[i], *d, av_pair_len[i]);
- *d += av_pair_len[i];
- **d = '+';
- *d += 1;
- }
- *d -= 1;
-
- ch_free(work_space);
-
- return 1;
-}
-
-/* The string dn is a distinguished name encoded according to RFC 2253.
- * If dn is properly encoded, return a normalized version of the string.
- * If not, return NULL. If make_uppercase is 0, do not change the case of
- * characters in attribute values, otherwise make all characters in attribute
- * values uppercase. If normalize is 0, do not compress whitespace
- * within attribute values, otherwise remove any leading and trailing
- * whitespace characters from attribute values and replace any strings of
- * whitespace characters between "words" with a single space character.
- */
-char *
-get_validated_dn( char *dn, int make_uppercase, int normalize)
-{
- char *ret_val, *s, *d;
- unsigned long *unnormalized_unicode;
- int dn_len, status, state;
-
- state = B4LEADTYPE;
-
- dn_len = strlen(dn);
- d = ret_val = (char *)ch_malloc(4 * dn_len + 1);
- s = dn;
-
- /* Create temporary workspace to hold unicode characters before
- * they have been normalized.
- */
- if ( normalize )
- unnormalized_unicode = (unsigned long *)ch_malloc(dn_len * sizeof(unsigned long));
- else
- unnormalized_unicode = NULL;
-
- /* A DN consists of a sequence of 0 or more RDNs */
-
- while ( ret_val != NULL && *s != '\0' ) {
- if ( ASCII_SPACE( *s ) ) {
- s++;
- } else if ( (state == B4SEPARATOR) && ( (*s == ',') || (*s == ';') ) ) {
- *d++ = ',';
- s++;
- state = B4VALUE;
- } else {
- status = get_validated_rdn_in_dn(&s, &d, make_uppercase, normalize, unnormalized_unicode);
- if (status == 0) {
- /* not a valid RDN */
- ch_free(ret_val);
- ret_val = NULL;
- }
- state = B4SEPARATOR;
- }
- }
-
- if (state == B4VALUE) {
- /* not a valid DN */
- ch_free(ret_val);
- ret_val = NULL;
- }
-
- *d = '\0';
- return ret_val;
-}
-
-/*
- * dn_validate - validate and compress dn. the dn is
- * compressed in place are returned if valid.
- */
-
-char *
-dn_validate( char *dn_in )
-{
- char *dn_out;
- int len;
-
- len = strlen(dn_in);
-
- if (len != 0) {
- dn_out = get_validated_dn(dn_in, 0, 0);
- if (dn_out == NULL) {
- return NULL;
- } else if (strlen(dn_out) <= len) {
- strcpy(dn_in, dn_out);
- ch_free(dn_out);
- } else {
- ch_free(dn_out);
- return NULL;
- }
- }
- return( dn_in );
-}
-
-/*
- * dn_normalize - put dn into a canonical form suitable for storing
- * in a hash database. this involves normalizing the case as well as
- * the format. the dn is normalized in place as well as returned if valid.
- */
-
-char *
-dn_normalize( char *dn )
-{
- char *dn_out;
- int len;
-
- len = strlen(dn);
-
- if (len != 0) {
- dn_out = get_validated_dn(dn, 1, 1);
- if (dn_out == NULL) {
- return NULL;
- } else if (strlen(dn_out) <= len) {
- strcpy(dn, dn_out);
- ch_free(dn_out);
- } else {
- ch_free(dn_out);
- return NULL;
- }
- }
- return( dn );
-}
-
-/*
- * dn_parent - return a copy of the dn of dn's parent
- */
-
-char *
-dn_parent(
- Backend *be,
- const char *dn
-)
-{
- const char *s;
- int inquote;
-
- if( dn == NULL ) {
- return NULL;
- }
-
- while(*dn != '\0' && ASCII_SPACE(*dn)) {
- dn++;
- }
-
- if( *dn == '\0' ) {
- return NULL;
- }
-
- if ( be != NULL && be_issuffix( be, dn ) ) {
- return NULL;
- }
-
- /*
- * assume it is an X.500-style name, which looks like
- * foo=bar,sha=baz,...
- */
-
- inquote = 0;
- for ( s = dn; *s; s++ ) {
- if ( *s == '\\' ) {
- if ( *(s + 1) ) {
- s++;
- }
- continue;
- }
- if ( inquote ) {
- if ( *s == '"' ) {
- inquote = 0;
- }
- } else {
- if ( *s == '"' ) {
- inquote = 1;
- } else if ( DN_SEPARATOR( *s ) ) {
- return ch_strdup( &s[1] );
- }
- }
- }
-
- return ch_strdup( "" );
-}
-
-char * dn_rdn(
- Backend *be,
- const char *dn_in )
-{
- char *dn, *s;
- int inquote;
-
- if( dn_in == NULL ) {
- return NULL;
- }
-
- while(*dn_in && ASCII_SPACE(*dn_in)) {
- dn_in++;
- }
-
- if( *dn_in == '\0' ) {
- return( NULL );
- }
-
- if ( be != NULL && be_issuffix( be, dn_in ) ) {
- return( NULL );
- }
-
- dn = ch_strdup( dn_in );
-
- inquote = 0;
-
- for ( s = dn; *s; s++ ) {
- if ( *s == '\\' ) {
- if ( *(s + 1) ) {
- s++;
- }
- continue;
- }
- if ( inquote ) {
- if ( *s == '"' ) {
- inquote = 0;
- }
- } else {
- if ( *s == '"' ) {
- inquote = 1;
- } else if ( DN_SEPARATOR( *s ) ) {
- *s = '\0';
- return( dn );
- }
- }
- }
-
- return( dn );
-}
-
-
-/*
- * return a charray of all subtrees to which the DN resides in
- */
-char **dn_subtree(
- Backend *be,
- const char *dn )
-{
- char *child, *parent;
- char **subtree = NULL;
-
- child = ch_strdup( dn );
-
- do {
- charray_add( &subtree, child );
-
- parent = dn_parent( be, child );
-
- free( child );
-
- child = parent;
- } while ( child != NULL );
-
- return subtree;
-}
-
-
-/*
- * dn_issuffix - tells whether suffix is a suffix of dn. both dn
- * and suffix must be normalized.
- */
-
-int
-dn_issuffix(
- const char *dn,
- const char *suffix
-)
-{
- int dnlen, suffixlen;
-
- if ( dn == NULL ) {
- return( 0 );
- }
-
- suffixlen = strlen( suffix );
- dnlen = strlen( dn );
-
- if ( suffixlen > dnlen ) {
- return( 0 );
- }
-
- return( strcmp( dn + dnlen - suffixlen, suffix ) == 0 );
-}
-
-/*
- * get_next_substring(), rdn_attr_type(), rdn_attr_value(), and
- * build_new_dn().
- *
- * Copyright 1999, Juan C. Gomez, All rights reserved.
- * This software is not subject to any license of Silicon Graphics
- * Inc. or Purdue University.
- *
- * Redistribution and use in source and binary forms are permitted
- * without restriction or fee of any kind as long as this notice
- * is preserved.
- *
- */
-
-/* get_next_substring:
- *
- * Gets next substring in s, using d (or the end of the string '\0') as a
- * string delimiter, and places it in a duplicated memory space. Leading
- * spaces are ignored. String s **must** be null-terminated.
- */
-
-static char *
-get_next_substring( const char * s, char d )
-{
-
- char *str, *r;
-
- r = str = ch_malloc( strlen(s) + 1 );
-
- /* Skip leading spaces */
-
- while ( *s && ASCII_SPACE(*s) ) {
- s++;
- }
-
- /* Copy word */
-
- while ( *s && (*s != d) ) {
-
- /* Don't stop when you see trailing spaces may be a multi-word
- * string, i.e. name=John Doe!
- */
-
- *str++ = *s++;
-
- }
-
- *str = '\0';
-
- return r;
-
-}
-
-
-/* rdn_attr_type:
- *
- * Given a string (i.e. an rdn) of the form:
- * "attribute_type = attribute_value"
- * this function returns the type of an attribute, that is the
- * string "attribute_type" which is placed in newly allocated
- * memory. The returned string will be null-terminated.
- */
-
-char * rdn_attr_type( const char * s )
-{
- return get_next_substring( s, '=' );
-}
-
-
-/* rdn_attr_value:
- *
- * Given a string (i.e. an rdn) of the form:
- * "attribute_type = attribute_value"
- * this function returns "attribute_type" which is placed in newly allocated
- * memory. The returned string will be null-terminated and may contain
- * spaces (i.e. "John Doe\0").
- */
-
-char *
-rdn_attr_value( const char * rdn )
-{
-
- const char *str;
-
- if ( (str = strchr( rdn, '=' )) != NULL ) {
- return get_next_substring(++str, '\0');
- }
-
- return NULL;
-
-}
-
-
-/* rdn_attrs:
- *
- * Given a string (i.e. an rdn) of the form:
- * "attribute_type=attribute_value[+attribute_type=attribute_value[...]]"
- * this function stores the types of the attributes in ptypes, that is the
- * array of strings "attribute_type" which is placed in newly allocated
- * memory, and the values of the attributes in pvalues, that is the
- * array of strings "attribute_value" which is placed in newly allocated
- * memory. Returns 0 on success, -1 on failure.
- *
- * note: got part of the code from dn_validate
- */
-
-int
-rdn_attrs( const char * rdn_in, char ***ptypes, char ***pvalues)
-{
- char **parts, **p;
-
- *ptypes = NULL;
- *pvalues = NULL;
-
- /*
- * explode the rdn in parts
- */
- parts = ldap_explode_rdn( rdn_in, 0 );
-
- if ( parts == NULL ) {
- return( -1 );
- }
-
- for ( p = parts; p[0]; p++ ) {
- char *s, *e, *d;
-
- /* split each rdn part in type value */
- s = strchr( p[0], '=' );
- if ( s == NULL ) {
- charray_free( *ptypes );
- charray_free( *pvalues );
- charray_free( parts );
- return( -1 );
- }
-
- /* type should be fine */
- charray_add_n( ptypes, p[0], ( s-p[0] ) );
-
- /* value needs to be unescaped
- * (maybe this should be moved to ldap_explode_rdn?) */
- for ( e = d = s + 1; e[0]; e++ ) {
- if ( *e != '\\' ) {
- *d++ = *e;
- }
- }
- d[0] = '\0';
- charray_add( pvalues, s + 1 );
- }
-
- /* free array */
- charray_free( parts );
-
- return( 0 );
-}
-
-
-/* rdn_validate:
- *
- * 1 if rdn is a legal rdn;
- * 0 otherwise (including a sequence of rdns)
- *
- * note: got it from dn_rdn; it should be rewritten
- * according to dn_validate
- */
-int
-rdn_validate( const char * rdn )
-{
- int inquote;
-
- if ( rdn == NULL ) {
- return( 0 );
- }
-
- if ( strchr( rdn, '=' ) == NULL ) {
- return( 0 );
- }
-
- while ( *rdn && ASCII_SPACE( *rdn ) ) {
- rdn++;
- }
-
- if( *rdn == '\0' ) {
- return( 0 );
- }
-
- inquote = 0;
-
- for ( ; *rdn; rdn++ ) {
- if ( *rdn == '\\' ) {
- if ( *(rdn + 1) ) {
- rdn++;
- }
- continue;
- }
- if ( inquote ) {
- if ( *rdn == '"' ) {
- inquote = 0;
- }
- } else {
- if ( *rdn == '"' ) {
- inquote = 1;
- } else if ( DN_SEPARATOR( *rdn ) ) {
- return( 0 );
- }
- }
- }
-
- return( 1 );
-}
-
-
-/* build_new_dn:
- *
- * Used by ldbm/bdb2_back_modrdn to create the new dn of entries being
- * renamed.
- *
- * new_dn = parent (p_dn) + separator(s) + rdn (newrdn) + null.
- */
-
-void
-build_new_dn( char ** new_dn,
- const char *e_dn,
- const char * p_dn,
- const char * newrdn )
-{
-
- if ( p_dn == NULL ) {
- *new_dn = ch_strdup( newrdn );
- return;
- }
-
- *new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn ) + 3 );
-
- strcpy( *new_dn, newrdn );
- strcat( *new_dn, "," );
- strcat( *new_dn, p_dn );
+ /* compare */
+ return( strcmp( dn->bv_val + d, suffix->bv_val ) == 0 );
}