+ break;
+
+ case LDAP_DN_FORMAT_LDAP:
+ case LDAP_DN_FORMAT_LDAPV2:
+ if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
+ rc = LDAP_DECODING_ERROR;
+ goto parsing_error;
+ }
+ break;
+
+ case LDAP_DN_FORMAT_DCE:
+ if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
+ rc = LDAP_DECODING_ERROR;
+ goto parsing_error;
+ }
+ break;
+ }
+ }
+
+
+ tmpDN[nrdns++] = newRDN;
+ newRDN = NULL;
+
+ /*
+ * make the static RDN array dynamically rescalable
+ */
+ if ( nrdns == num_slots ) {
+ LDAPRDN **tmp;
+
+ if ( tmpDN == tmpDN_ ) {
+ tmp = LDAP_MALLOC( num_slots * 2 * sizeof( LDAPRDN * ) );
+ if ( tmp == NULL ) {
+ rc = LDAP_NO_MEMORY;
+ goto parsing_error;
+ }
+ AC_MEMCPY( tmp, tmpDN, num_slots * sizeof( LDAPRDN * ) );
+
+ } else {
+ tmp = LDAP_REALLOC( tmpDN, num_slots * 2 * sizeof( LDAPRDN * ) );
+ if ( tmp == NULL ) {
+ rc = LDAP_NO_MEMORY;
+ goto parsing_error;
+ }
+ }
+
+ tmpDN = tmp;
+ num_slots *= 2;
+ }
+
+ if ( p >= end || p[ 0 ] == '\0' ) {
+ /*
+ * the DN is over, phew
+ */
+ newDN = (LDAPDN *)LDAP_MALLOC( sizeof(LDAPDN) +
+ sizeof(LDAPRDN *) * (nrdns+1));
+ if ( newDN == NULL ) {
+ rc = LDAP_NO_MEMORY;
+ goto parsing_error;
+ } else {
+ int i;
+
+ newDN[0] = (LDAPRDN **)(newDN+1);
+
+ if ( LDAP_DN_DCE( flags ) ) {
+ /* add in reversed order */
+ for ( i=0; i<nrdns; i++ )
+ newDN[0][i] = tmpDN[nrdns-1-i];
+ } else {
+ for ( i=0; i<nrdns; i++ )
+ newDN[0][i] = tmpDN[i];
+ }
+ newDN[0][nrdns] = NULL;
+ rc = LDAP_SUCCESS;
+ }
+ goto return_result;
+ }
+ }
+
+parsing_error:;
+ if ( newRDN ) {
+ ldap_rdnfree( newRDN );
+ }
+
+ for ( nrdns-- ;nrdns >= 0; nrdns-- ) {
+ ldap_rdnfree( tmpDN[nrdns] );
+ }
+
+return_result:;
+
+ if ( tmpDN != tmpDN_ ) {
+ LDAP_FREE( tmpDN );
+ }
+
+#ifdef NEW_LOGGING
+ LDAP_LOG (( "getdn", LDAP_LEVEL_RESULTS, "<= ldap_bv2dn(%s,%u)=%d\n",
+ str, flags, rc ));
+#else
+ Debug( LDAP_DEBUG_TRACE, "<= ldap_bv2dn(%s,%u)=%d\n", str, flags, rc );
+#endif
+ *dn = newDN;
+
+ return( rc );
+}
+
+/*
+ * ldap_str2rdn
+ *
+ * Parses a relative DN according to flags up to a rdn separator
+ * or to the end of str.
+ * Returns the rdn and a pointer to the string continuation, which
+ * corresponds to the rdn separator or to '\0' in case the string is over.
+ */
+int
+ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn,
+ char **n_in, unsigned flags )
+{
+ struct berval bv;
+
+ assert( str );
+ assert( str[ 0 ] != '\0' ); /* FIXME: is this required? */
+
+ bv.bv_len = strlen( str );
+ bv.bv_val = (char *) str;
+
+ return ldap_bv2rdn( &bv, rdn, n_in, flags );
+}
+
+int
+ldap_bv2rdn( struct berval *bv, LDAPRDN **rdn,
+ char **n_in, unsigned flags )
+{
+ const char **n = (const char **) n_in;
+ const char *p;
+ int navas = 0;
+ int state = B4AVA;
+ int rc = LDAP_DECODING_ERROR;
+ int attrTypeEncoding = LDAP_AVA_STRING,
+ attrValueEncoding = LDAP_AVA_STRING;
+
+ struct berval attrType = { 0, NULL };
+ struct berval attrValue = { 0, NULL };
+
+ LDAPRDN *newRDN = NULL;
+ LDAPAVA *tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_;
+ int num_slots = TMP_AVA_SLOTS;
+
+ char *str;
+ ber_len_t stoplen;
+
+ assert( bv );
+ assert( bv->bv_len );
+ assert( bv->bv_val );
+ assert( rdn || flags & LDAP_DN_SKIP );
+ assert( n );
+
+ str = bv->bv_val;
+ stoplen = bv->bv_len;
+
+ if ( rdn ) {
+ *rdn = NULL;
+ }
+ *n = NULL;
+
+ switch ( LDAP_DN_FORMAT( flags ) ) {
+ case LDAP_DN_FORMAT_LDAP:
+ case LDAP_DN_FORMAT_LDAPV3:
+ case LDAP_DN_FORMAT_LDAPV2:
+ case LDAP_DN_FORMAT_DCE:
+ break;
+
+ /* unsupported in str2dn */
+ case LDAP_DN_FORMAT_UFN:
+ case LDAP_DN_FORMAT_AD_CANONICAL:
+ return LDAP_PARAM_ERROR;
+
+ case LDAP_DN_FORMAT_LBER:
+ default:
+ return LDAP_PARAM_ERROR;
+ }
+
+ if ( bv->bv_len == 0 ) {
+ return LDAP_SUCCESS;
+
+ }
+
+ if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) {
+ /* value must have embedded NULs */
+ return LDAP_DECODING_ERROR;
+ }
+
+ p = str;
+ for ( ; p[ 0 ] || state == GOTAVA; ) {
+
+ /*
+ * The parser in principle advances one token a time,
+ * or toggles state if preferable.
+ */
+ switch (state) {
+
+ /*
+ * an AttributeType can be encoded as:
+ * - its string representation; in detail, implementations
+ * MUST recognize AttributeType string type names listed
+ * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
+ * MAY recognize other names.
+ * - its numeric OID (a dotted decimal string); in detail
+ * RFC 2253 asserts that ``Implementations MUST allow
+ * an oid in the attribute type to be prefixed by one
+ * of the character strings "oid." or "OID."''. As soon
+ * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
+ * I'm not sure whether this is required or not any
+ * longer; to be liberal, we still implement it.
+ */
+ case B4AVA:
+ if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
+ if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
+ /* error */
+ goto parsing_error;
+ }
+ p++;
+ }
+
+ if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
+ if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
+ /* error */
+ goto parsing_error;
+ }
+
+ /* whitespace is allowed (and trimmed) */
+ p++;
+ while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
+ p++;
+ }