]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/getdn.c
#if 0 RDN debugging
[openldap] / libraries / libldap / getdn.c
index e2104d8aef16a752956d7ffa5abf141105e0a8a7..945d42d2b2af6478f3015641740cf241020e9c2d 100644 (file)
@@ -25,7 +25,7 @@
 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
  * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
 #define DC_IN_UFN
-/* #define PRETTY_ESCAPE */
+#define PRETTY_ESCAPE
 
 /* parsing/printing routines */
 static int str2strval( const char *str, struct berval *val, 
@@ -384,10 +384,12 @@ ldap_dn_normalize( LDAP_CONST char *dnin,
 #define LDAP_DN_NE(c) \
        ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
          || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
+#define LDAP_DN_MAYESCAPE(c) \
+       ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \
+         || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) )
 #define LDAP_DN_NEEDESCAPE(c) \
        ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
-#define LDAP_DN_NEEDESCAPE_LEAD(c) \
-       ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
+#define LDAP_DN_NEEDESCAPE_LEAD(c)     LDAP_DN_MAYESCAPE(c)
 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
        ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
 #define LDAP_DN_WILLESCAPE_CHAR(c) \
@@ -587,7 +589,14 @@ ldap_dnfree( LDAPDN *dn )
  * and readable as soon as it works as expected.
  */
 
-#define        TMP_SLOTS       1024
+/*
+ * Default sizes of AVA and RDN static working arrays; if required
+ * the are dynamically resized.  The values can be tuned in case
+ * of special requirements (e.g. very deep DN trees or high number 
+ * of AVAs per RDN).
+ */
+#define        TMP_AVA_SLOTS   8
+#define        TMP_RDN_SLOTS   32
 
 int
 ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags )
@@ -597,7 +606,8 @@ ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags )
        int             nrdns = 0;
 
        LDAPDN          *newDN = NULL;
-       LDAPRDN         *newRDN = NULL, *tmpDN[TMP_SLOTS];
+       LDAPRDN         *newRDN = NULL, *tmpDN_[TMP_RDN_SLOTS], **tmpDN = tmpDN_;
+       int             num_slots = TMP_RDN_SLOTS;
        
        assert( str );
        assert( dn );
@@ -638,7 +648,12 @@ ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags )
                        goto parsing_error;
                }
                p++;
-               
+
+       /*
+        * actually we do not want to accept by default the DCE form,
+        * we do not want to auto-detect it
+        */
+#if 0
        } else if ( LDAP_DN_LDAP( flags ) ) {
                /*
                 * if dn starts with '/' let's make it a DCE dn
@@ -647,6 +662,7 @@ ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags )
                        flags |= LDAP_DN_FORMAT_DCE;
                        p++;
                }
+#endif
        }
 
        for ( ; p[ 0 ]; p++ ) {
@@ -690,20 +706,31 @@ ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags )
                tmpDN[nrdns++] = newRDN;
                newRDN = NULL;
 
-#if 0
                /*
-                * prone to attacks?
+                * make the static RDN array dynamically rescalable
                 */
-               assert (nrdns < TMP_SLOTS);
-#else
-               /*
-                * make the static AVA array dynamically rescalable
-                */
-               if (nrdns >= TMP_SLOTS) {
-                       rc = LDAP_DECODING_ERROR;
-                       goto parsing_error;
+               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;
                }
-#endif
                                
                if ( p[ 0 ] == '\0' ) {
                        /* 
@@ -739,10 +766,16 @@ parsing_error:;
                ldap_rdnfree( newRDN );
        }
 
-       for (nrdns-- ;nrdns>=0; nrdns-- )
+       for ( nrdns-- ;nrdns >= 0; nrdns-- ) {
                ldap_rdnfree( tmpDN[nrdns] );
+       }
 
 return_result:;
+
+       if ( tmpDN != tmpDN_ ) {
+               LDAP_FREE( tmpDN );
+       }
+
        Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
        *dn = newDN;
        
@@ -773,13 +806,16 @@ ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn,
        struct berval   attrValue = { 0, NULL };
 
        LDAPRDN         *newRDN = NULL;
-       LDAPAVA         *tmpRDN[TMP_SLOTS];
+       LDAPAVA         *tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_;
+       int             num_slots = TMP_AVA_SLOTS;
        
        assert( str );
        assert( rdn || flags & LDAP_DN_SKIP );
        assert( n );
 
+#if 0
        Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
+#endif
 
        if ( rdn ) {
                *rdn = NULL;
@@ -1132,7 +1168,31 @@ ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn,
                                attrValue.bv_val = NULL;
                                attrValue.bv_len = 0;
 
-                               assert(navas < TMP_SLOTS);
+                               /*
+                                * prepare room for new AVAs if needed
+                                */
+                               if (navas == num_slots) {
+                                       LDAPAVA **tmp;
+                                       
+                                       if ( tmpRDN == tmpRDN_ ) {
+                                               tmp = LDAP_MALLOC( num_slots * 2 * sizeof( LDAPAVA * ) );
+                                               if ( tmp == NULL ) {
+                                                       rc = LDAP_NO_MEMORY;
+                                                       goto parsing_error;
+                                               }
+                                               AC_MEMCPY( tmp, tmpRDN, num_slots * sizeof( LDAPAVA * ) );
+
+                                       } else {
+                                               tmp = LDAP_REALLOC( tmpRDN, num_slots * 2 * sizeof( LDAPAVA * ) );
+                                               if ( tmp == NULL ) {
+                                                       rc = LDAP_NO_MEMORY;
+                                                       goto parsing_error;
+                                               }
+                                       }
+
+                                       tmpRDN = tmp;
+                                       num_slots *= 2;
+                               }
                        }
                        
                        /* 
@@ -1205,13 +1265,21 @@ parsing_error:;
                free( attrValue.bv_val );
        }
 
-       for (navas-- ; navas>=0; navas-- )
+       for ( navas-- ; navas >= 0; navas-- ) {
                ldap_avafree( tmpRDN[navas] );
+       }
 
 return_result:;
 
+       if ( tmpRDN != tmpRDN_ ) {
+               LDAP_FREE( tmpRDN );
+       }
+
+#if 0
        Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n", 
                        p - str, str, rc );
+#endif
+
        if ( rdn ) {
                *rdn = newRDN;
        }
@@ -1242,9 +1310,7 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla
                        if ( p[ 0 ] == '\0' ) {
                                return( 1 );
                        }
-                       if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
-                                       || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
-                                       || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
+                       if ( LDAP_DN_MAYESCAPE( p[ 0 ] ) ) {
                                escapes++;
                                continue;
                        }
@@ -1255,11 +1321,6 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla
                                hexstr2bin( p, &c );
                                escapes += 2;
 
-                               if ( c == 0 ) {
-                                       /* do not accept zero, right? */
-                                       return( 1 );
-                               }
-
                                if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
 
                                        /*
@@ -1340,9 +1401,7 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla
                for ( s = 0, d = 0; d < len; ) {
                        if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
                                s++;
-                               if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
-                                               || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
-                                               || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
+                               if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) {
                                        val->bv_val[ d++ ] = 
                                                startPos[ s++ ];
                                        
@@ -1364,7 +1423,7 @@ str2strval( const char *str, struct berval *val, const char **next, unsigned fla
                }
 
                val->bv_val[ d ] = '\0';
-               assert( strlen( val->bv_val ) == len );
+               assert( d == len );
        }
 
        return( 0 );
@@ -1834,8 +1893,18 @@ strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
                return( 0 );
        }
 
-       for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
-               cl = LDAP_UTF8_CHARLEN( p );
+       for ( l = 0, p = val->bv_val; p < val->bv_val + val->bv_len; p += cl ) {
+
+               /* 
+                * escape '%x00' 
+                */
+               if ( p[ 0 ] == '\0' ) {
+                       cl = 1;
+                       l += 3;
+                       continue;
+               }
+
+               cl = LDAP_UTF8_CHARLEN2( p, cl );
                if ( cl == 0 ) {
                        /* illegal utf-8 char! */
                        return( -1 );
@@ -1844,7 +1913,7 @@ strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
                        ber_len_t cnt;
 
                        for ( cnt = 1; cnt < cl; cnt++ ) {
-                               if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
+                               if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) {
                                        return( -1 );
                                }
                        }
@@ -1854,7 +1923,11 @@ strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
                                || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
                                || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
 #ifdef PRETTY_ESCAPE
+#if 0
                        if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
+#else
+                       if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) {
+#endif
 
                                /* 
                                 * there might be some chars we want 
@@ -1903,7 +1976,26 @@ strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
         * of the value
         */
        for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
-               ber_len_t       cl = LDAP_UTF8_CHARLEN( &val->bv_val[ s ] );
+               ber_len_t       cl;
+
+               /* 
+                * escape '%x00' 
+                */
+               if ( val->bv_val[ s ] == '\0' ) {
+                       cl = 1;
+                       str[ d++ ] = '\\';
+                       str[ d++ ] = '0';
+                       str[ d++ ] = '0';
+                       s++;
+                       continue;
+               }
+               
+               /*
+                * The length was checked in strval2strlen();
+                * LDAP_UTF8_CHARLEN() should suffice
+                */
+               cl = LDAP_UTF8_CHARLEN2( &val->bv_val[ s ], cl );
+               assert( cl > 0 );
                
                /* 
                 * there might be some chars we want to escape in form
@@ -1911,7 +2003,11 @@ strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
                 */
                if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) ) 
 #ifdef PRETTY_ESCAPE
+#if 0
                                || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] ) 
+#else
+                               || LDAP_DN_WILLESCAPE_CHAR( val->bv_val[ s ] ) 
+#endif
 #else /* ! PRETTY_ESCAPE */
                                || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
                                || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
@@ -2772,7 +2868,6 @@ int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags )
        int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
 
        assert( bv );
-
        bv->bv_len = 0;
        bv->bv_val = NULL;
 
@@ -2791,13 +2886,13 @@ int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags )
        case LDAP_DN_FORMAT_LDAPV3:
                sv2l = strval2strlen;
                sv2s = strval2str;
-               goto got_funcs;
 
+               if( 0 ) {
        case LDAP_DN_FORMAT_LDAPV2:
-               sv2l = strval2IA5strlen;
-               sv2s = strval2IA5str;
-got_funcs:
-               
+                       sv2l = strval2IA5strlen;
+                       sv2s = strval2IA5str;
+               }
+
                for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
                        ber_len_t       rdnl;
                        LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
@@ -2840,7 +2935,6 @@ got_funcs:
                break;
 
        case LDAP_DN_FORMAT_UFN: {
-
                /*
                 * FIXME: quoting from RFC 1781:
                 *
@@ -2955,11 +3049,10 @@ got_funcs:
 #endif /* DC_IN_UFN */
                
                rc = LDAP_SUCCESS;
-               break;
-       }
 
-       case LDAP_DN_FORMAT_DCE:
+       } break;
 
+       case LDAP_DN_FORMAT_DCE:
                for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
                        ber_len_t       rdnl;
                        LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
@@ -2998,7 +3091,6 @@ got_funcs:
                break;
 
        case LDAP_DN_FORMAT_AD_CANONICAL: {
-               
                /*
                 * Sort of UFN for DCE DNs: a slash ('/') separated
                 * global->local DN with no types; strictly speaking,
@@ -3080,8 +3172,7 @@ got_funcs:
                bv->bv_val[ bv->bv_len ] = '\0';
 
                rc = LDAP_SUCCESS;
-               break;
-       }
+       } break;
 
        default:
                return LDAP_PARAM_ERROR;
@@ -3089,6 +3180,7 @@ got_funcs:
 
        Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s,%u)=%d\n",
                bv->bv_val, flags, rc );
+
 return_results:;
        return( rc );
 }