[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: libldap: too little space allocated for IPv6 address *patch* (ITS#2018)



Thanks, fixed in HEAD, please test.

Kurt

At 12:55 PM 2002-08-09, thorild@Update.UU.SE wrote:
>Full_Name: Thorild Selén
>Version: 2.0.23 and HEAD
>OS: Linux 2.4.19 (Debian)
>URL: 
>Submission from: (NULL) (130.238.19.17)
>
>
>(In brief: IPv6 address allocation problem; patch at end)
>
>I was using strace to examine a program that kept hanging, and saw:
>
>> connect(10, {sin_family=AF_INET6, sin6_port=htons(389),
>>       inet_pton(AF_INET6, "3ffe:200:66:8000::11", &sin6_addr),
>>       sin6_flowinfo=0 , sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation
>>       now in progress)
>> select(1024, NULL, [10], NULL, {16, 0}) = 1 (out [10], left {16, 0})
>
>(We connect to the LDAP server. All is well so far. From the data that follows,
>this looks like libnss_ldap checking which groups exist on the system.)
>And then:
>
>> getpeername(10, {sin_family=AF_INET6, sin6_port=htons(389),
>>       inet_pton(AF_INET6, "3ffe:200:66:8000:1cd3:ffbf:ac7c:5940",
>>       &sin6_addr), sin6_flowinfo=0, sin6_scope_id=137790328}, [28]) = 0
>> fcntl64(10, F_GETFL)                    = 0x802 (flags O_RDWR|O_NONBLOCK)
>> fcntl64(10, F_SETFL, O_RDWR)            = 0
>> getpeername(10, {sin_family=AF_INET6, sin6_port=htons(389),
>>       inet_pton(AF_INET6, "3ffe:200:66:8000:2cd4:ffbf:af7a:5840",
>>       &sin6_addr), sin6_flowinfo=0, sin6_scope_id=139343664}, [28]) = 0
>
>The second parts of these addresses are mangled; something isn't allocating
>enough space to store an IPv6 address. That made me look in the libldap
>source for a bug of this kind, and saw that in libraries/libldap/os-ip.c,
>in ldap_host_connected_to, an auto struct sockaddr is used to store an
>address; possibly an IPv6 address, which won't fit; a struct
>sockaddr_storage should be used instead (see RFC 2553). This bug is present
>in this version as well as in the present working version (HEAD).
>
>Below is a patch for HEAD. 
>
>/Thorild
>
>
>Patch copyright 2002 Thorild Selén, all rights reserved.
>Contains code copyright 1999-2001 the OpenLDAP Foundation,
> Redwood City, California, USA.
>This is free software; you can redistribute and use it
>under the same terms as OpenLDAP itself.
>
>=========================================================
>
>
>diff -Naur ldap/libraries/libldap/os-ip.c ldap-new/libraries/libldap/os-ip.c
>--- ldap/libraries/libldap/os-ip.c      Sun Jul 28 03:30:39 2002
>+++ ldap-new/libraries/libldap/os-ip.c  Fri Aug  9 17:50:51 2002
>@@ -1,4 +1,4 @@
>-/* $OpenLDAP: pkg/ldap/libraries/libldap/os-ip.c,v 1.79 2002/07/28 03:30:39
>kurt Exp $ */
>+/* $OpenLDAP: /libraries/libldap/os-ip.c,v 1.72.2.4 2002/07/28 19:10:46 kurt
>Exp $ */
> /*
>  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
>  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
>@@ -482,7 +482,13 @@
> {
>        struct hostent  *hp;
>        socklen_t               len;
>-       struct sockaddr sa;
>+#ifdef LDAP_PF_INET6
>+       struct sockaddr_storage sa_storage;
>+#else
>+       struct sockaddr         sa_storage;
>+#endif
>+       struct sockaddr *sa = (struct sockaddr *) &sa_storage;
>+
>        char                    *addr;
>        char                    *host;
> 
>@@ -492,11 +498,11 @@
>        char                    *ha_buf=NULL;
>        ber_socket_t    sd;
> 
>-       (void)memset( (char *)&sa, '\0', sizeof( struct sockaddr ));
>-       len = sizeof( sa );
>+       (void)memset( (char *)&sa_storage, '\0', sizeof( sa_storage ));
>+       len = sizeof( sa_storage );
> 
>        ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
>-       if ( getpeername( sd, &sa, &len ) == -1 ) {
>+       if ( getpeername( sd, sa, &len ) == -1 ) {
>                return( NULL );
>        }
> 
>@@ -506,19 +512,19 @@
>        * hostname is used as the kerberos instance.
>        */
> 
>-       switch (sa.sa_family) {
>+       switch (sa->sa_family) {
> #ifdef LDAP_PF_LOCAL
>        case AF_LOCAL:
>                return LDAP_STRDUP( ldap_int_hostname );
> #endif
> #ifdef LDAP_PF_INET6
>        case AF_INET6:
>-               addr = (char *) &((struct sockaddr_in6 *)&sa)->sin6_addr;
>+               addr = (char *) &((struct sockaddr_in6 *)sa)->sin6_addr;
>                len = sizeof( struct in6_addr );
>                break;
> #endif
>        case AF_INET:
>-               addr = (char *) &((struct sockaddr_in *)&sa)->sin_addr;
>+               addr = (char *) &((struct sockaddr_in *)sa)->sin_addr;
>                len = sizeof( struct in_addr );
> 
>                {
>@@ -526,7 +532,7 @@
>                        localhost.sin_addr.s_addr = htonl( INADDR_ANY );
> 
>                        if( memcmp ( &localhost.sin_addr,
>-                               &((struct sockaddr_in *)&sa)->sin_addr,
>+                               &((struct sockaddr_in *)sa)->sin_addr,
>                                sizeof(localhost.sin_addr) ) == 0 )
>                        {
>                                return LDAP_STRDUP( ldap_int_hostname );
>@@ -536,7 +542,7 @@
>                        localhost.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
> 
>                        if( memcmp ( &localhost.sin_addr,
>-                               &((struct sockaddr_in *)&sa)->sin_addr,
>+                               &((struct sockaddr_in *)sa)->sin_addr,
>                                sizeof(localhost.sin_addr) ) == 0 )
>                        {
>                                return LDAP_STRDUP( ldap_int_hostname );
>@@ -552,7 +558,7 @@
> 
>        host = NULL;
>        if ((ldap_pvt_gethostbyaddr_a( addr, len,
>-               sa.sa_family, &he_buf, &ha_buf,
>+               sa->sa_family, &he_buf, &ha_buf,
>                &hp,&local_h_errno ) == 0 ) &&
>                (hp != NULL) && ( hp->h_name != NULL ) )
>        {