]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/request.c
Fix NULL pointer deref bugs
[openldap] / libraries / libldap / request.c
index 2ea52590727b3eef3d865d0d61a0dbfb5a2d0b7a..56e5f492dc83bc5cb28ac7328b220ece609f9df3 100644 (file)
@@ -96,7 +96,6 @@ ldap_send_initial_request(
                        ( ld->ld_host == NULL ) ? "(null)" : ld->ld_host, 0, 0 );
        }
 
-
 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_DNS
        if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_DNS )
                && ldap_is_dns_dn( dn ) )
@@ -254,7 +253,6 @@ ldap_send_server_request(
        return( msgid );
 }
 
-
 LDAPConn *
 ldap_new_connection( LDAP *ld, LDAPURLDesc *srvlist, int use_ldsb,
        int connect, int bind )
@@ -568,7 +566,7 @@ ldap_free_request( LDAP *ld, LDAPRequest *lr )
 int
 ldap_chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp )
 {
-       int             rc, count, len, newdn = 0;
+       int             rc, count, len, newdn;
 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_DNS
        int             ldapref;
 #endif /* LDAP_API_FEATURE_X_OPENLDAP_V2_DNS */
@@ -629,7 +627,9 @@ ldap_chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp )
                        p = NULL;
                }
 
+               ldap_pvt_hex_unescape( ref );
                len = strlen( ref );
+
                if ( len > LDAP_LDAP_REF_STR_LEN && strncasecmp( ref,
                    LDAP_LDAP_REF_STR, LDAP_LDAP_REF_STR_LEN ) == 0 ) {
                        Debug( LDAP_DEBUG_TRACE,
@@ -653,16 +653,17 @@ ldap_chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp )
                        continue;
                }
 
+               /* NOTE! This code treats "ldap://host/" differently
+                * from "ldap://host". The behavior is wrong, but is
+                * left here intentionally to maintain compatibility
+                * with OpenLDAP 1.x and UMich 3.3 clients.
+                */
                *hadrefp = 1;
                if (( refdn = strchr( tmpref, '/' )) != NULL ) {
                        *refdn++ = '\0';
-                       if ( *refdn != '\0' )
-                       {
-                               newdn = 1;
-                       } else
-                       {
-                               refdn = NULL;
-                       }
+                       newdn = 1;
+               } else {
+                       newdn = 0;
                }
 
                if (( ber = re_encode_request( ld, origreq->lr_ber,
@@ -763,7 +764,6 @@ re_encode_request( LDAP *ld, BerElement *origber, ber_int_t msgid, char **dnp )
  * XXX this routine knows way too much about how the lber library works!
  */
        ber_int_t       along;
-       ber_len_t       len;
        ber_tag_t       tag;
        ber_int_t       ver;
        int             rc;
@@ -777,31 +777,33 @@ re_encode_request( LDAP *ld, BerElement *origber, ber_int_t msgid, char **dnp )
        tmpber = *origber;
 
        /*
-        * all LDAP requests are sequences that start with a message id,
-        * followed by a sequence that is tagged with the operation code
+        * all LDAP requests are sequences that start with a message id.
+        * For all except delete, this is followed by a sequence that is
+        * tagged with the operation code.  For delete, the provided DN
+        * is not wrapped by a sequence.
         */
-       if ( ber_scanf( &tmpber, "{i", /*}*/ &along ) != LDAP_TAG_MSGID ||
-           ( tag = ber_skip_tag( &tmpber, &len )) == LBER_DEFAULT ) {
-                ld->ld_errno = LDAP_DECODING_ERROR;
+       rc = ber_scanf( &tmpber, "{it", /*}*/ &along, &tag );
+
+       if ( rc == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
                return( NULL );
        }
 
-        if (( ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
-                return( NULL );
-        }
+       if ( tag == LDAP_REQ_BIND ) {
+               /* bind requests have a version number before the DN & other stuff */
+               rc = ber_scanf( &tmpber, "{ia" /*}*/, &ver, &orig_dn );
 
-       /* bind requests have a version number before the DN & other stuff */
-       if ( tag == LDAP_REQ_BIND && ber_get_int( &tmpber, &ver ) ==
-           LBER_DEFAULT ) {
-                ld->ld_errno = LDAP_DECODING_ERROR;
-               ber_free( ber, 1 );
-               return( NULL );
+       } else if ( tag == LDAP_REQ_DELETE ) {
+               /* delete requests don't have a DN wrapping sequence */
+               rc = ber_scanf( &tmpber, "a", &orig_dn );
+
+       } else {
+               rc = ber_scanf( &tmpber, "{a" /*}*/, &orig_dn );
        }
 
-       /* the rest of the request is the DN followed by other stuff */
-       if ( ber_get_stringa( &tmpber, &orig_dn ) == LBER_DEFAULT ) {
-               ber_free( ber, 1 );
-               return( NULL );
+       if( rc == LBER_ERROR ) {
+               ld->ld_errno = LDAP_DECODING_ERROR;
+               return NULL;
        }
 
        if ( *dnp == NULL ) {
@@ -810,20 +812,29 @@ re_encode_request( LDAP *ld, BerElement *origber, ber_int_t msgid, char **dnp )
                LDAP_FREE( orig_dn );
        }
 
+       if (( ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
+               return( NULL );
+       }
+
        if ( tag == LDAP_REQ_BIND ) {
                rc = ber_printf( ber, "{it{is" /*}}*/, msgid, tag, ver, *dnp );
+       } else if ( tag == LDAP_REQ_DELETE ) {
+               rc = ber_printf( ber, "{its}", msgid, tag, *dnp );
        } else {
                rc = ber_printf( ber, "{it{s" /*}}*/, msgid, tag, *dnp );
        }
 
        if ( rc == -1 ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
                ber_free( ber, 1 );
                return( NULL );
        }
 
-       if ( ber_write( ber, tmpber.ber_ptr, ( tmpber.ber_end -
-           tmpber.ber_ptr ), 0 ) != ( tmpber.ber_end - tmpber.ber_ptr ) ||
-           ber_printf( ber, /*{{*/ "}}" ) == -1 ) {
+       if ( tag != LDAP_REQ_DELETE && (
+               ber_write(ber, tmpber.ber_ptr, ( tmpber.ber_end - tmpber.ber_ptr ), 0)
+               != ( tmpber.ber_end - tmpber.ber_ptr ) ||
+           ber_printf( ber, /*{{*/ "}}" ) == -1 ) )
+       {
                ld->ld_errno = LDAP_ENCODING_ERROR;
                ber_free( ber, 1 );
                return( NULL );