From 6de15ed19709833f6e3a6f1b68afbaa26d069e91 Mon Sep 17 00:00:00 2001 From: Jan Synacek Date: Mon, 14 Oct 2013 10:00:07 +0200 Subject: [PATCH] fix: CLDAP is broken for IPv6 Resolves: #1018688 --- openldap-cldap.patch | 257 +++++++++++++++++++++++++++++++++++++++++++ openldap.spec | 6 + 2 files changed, 263 insertions(+) create mode 100644 openldap-cldap.patch diff --git a/openldap-cldap.patch b/openldap-cldap.patch new file mode 100644 index 0000000..58cdb42 --- /dev/null +++ b/openldap-cldap.patch @@ -0,0 +1,257 @@ +This is a 3-part patch that fixes connectionless ldap when used with IPv6. +================================================================================ +Don't try to parse the result of a CLDAP bind request. Since these are +faked, no message is actually returned. + +Author: Stef Walter +Upstream commit: 5c919894779d67280fa26afdd94d99248fc38099 +ITS: #7695 +Backported-By: Jan Synacek + +--- a/clients/tools/common.c 2013-08-16 20:12:59.000000000 +0200 ++++ b/clients/tools/common.c 2013-10-14 09:35:50.817033451 +0200 +@@ -1521,11 +1521,13 @@ tool_bind( LDAP *ld ) + tool_exit( ld, LDAP_LOCAL_ERROR ); + } + +- rc = ldap_parse_result( ld, result, &err, &matched, &info, &refs, +- &ctrls, 1 ); +- if ( rc != LDAP_SUCCESS ) { +- tool_perror( "ldap_bind parse result", rc, NULL, matched, info, refs ); +- tool_exit( ld, LDAP_LOCAL_ERROR ); ++ if ( result ) { ++ rc = ldap_parse_result( ld, result, &err, &matched, &info, &refs, ++ &ctrls, 1 ); ++ if ( rc != LDAP_SUCCESS ) { ++ tool_perror( "ldap_bind parse result", rc, NULL, matched, info, refs ); ++ tool_exit( ld, LDAP_LOCAL_ERROR ); ++ } + } + + #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST +================================================================================ +commit d51ee964fc5e1f02b035811de0f95eee81c2789f +Author: Howard Chu +Date: Thu Oct 10 10:48:08 2013 -0700 + + ITS#7694 more for IPv6 CLDAP, slapd fix + +diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c +index e169494..7ed3f63 100644 +--- a/servers/slapd/connection.c ++++ b/servers/slapd/connection.c +@@ -1499,22 +1499,53 @@ connection_input( Connection *conn , conn_readinfo *cri ) + + #ifdef LDAP_CONNECTIONLESS + if ( conn->c_is_udp ) { ++#if defined(LDAP_PF_INET6) ++ char peername[sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535")]; ++ char addr[INET6_ADDRSTRLEN]; ++#else + char peername[sizeof("IP=255.255.255.255:65336")]; ++ char addr[INET_ADDRSTRLEN]; ++#endif + const char *peeraddr_string = NULL; + +- len = ber_int_sb_read(conn->c_sb, &peeraddr, sizeof(struct sockaddr)); +- if (len != sizeof(struct sockaddr)) return 1; ++ len = ber_int_sb_read(conn->c_sb, &peeraddr, sizeof(Sockaddr)); ++ if (len != sizeof(Sockaddr)) return 1; + ++#if defined(LDAP_PF_INET6) ++ if (peeraddr.sa_addr.sa_family == AF_INET6) { ++ if ( IN6_IS_ADDR_V4MAPPED(&peeraddr.sa_in6_addr.sin6_addr) ) { + #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) +- char addr[INET_ADDRSTRLEN]; +- peeraddr_string = inet_ntop( AF_INET, &peeraddr.sa_in_addr.sin_addr, ++ peeraddr_string = inet_ntop( AF_INET, ++ ((struct in_addr *)&peeraddr.sa_in6_addr.sin6_addr.s6_addr[12]), ++ addr, sizeof(addr) ); ++#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ ++ peeraddr_string = inet_ntoa( *((struct in_addr *) ++ &peeraddr.sa_in6_addr.sin6_addr.s6_addr[12]) ); ++#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ ++ if ( !peeraddr_string ) peeraddr_string = SLAP_STRING_UNKNOWN; ++ sprintf( peername, "IP=%s:%d", peeraddr_string, ++ (unsigned) ntohs( peeraddr.sa_in6_addr.sin6_port ) ); ++ } else { ++ peeraddr_string = inet_ntop( AF_INET6, ++ &peeraddr.sa_in6_addr.sin6_addr, ++ addr, sizeof addr ); ++ if ( !peeraddr_string ) peeraddr_string = SLAP_STRING_UNKNOWN; ++ sprintf( peername, "IP=[%s]:%d", peeraddr_string, ++ (unsigned) ntohs( peeraddr.sa_in6_addr.sin6_port ) ); ++ } ++ } else ++#endif ++#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) ++ { ++ peeraddr_string = inet_ntop( AF_INET, &peeraddr.sa_in_addr.sin_addr, + addr, sizeof(addr) ); + #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ +- peeraddr_string = inet_ntoa( peeraddr.sa_in_addr.sin_addr ); ++ peeraddr_string = inet_ntoa( peeraddr.sa_in_addr.sin_addr ); + #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ +- sprintf( peername, "IP=%s:%d", +- peeraddr_string, +- (unsigned) ntohs( peeraddr.sa_in_addr.sin_port ) ); ++ sprintf( peername, "IP=%s:%d", ++ peeraddr_string, ++ (unsigned) ntohs( peeraddr.sa_in_addr.sin_port ) ); ++ } + Statslog( LDAP_DEBUG_STATS, + "conn=%lu UDP request from %s (%s) accepted.\n", + conn->c_connid, peername, conn->c_sock_name.bv_val, 0, 0 ); +================================================================================ +commit 743a9783d57ea6b693e56f6545ac5d68dc9242c7 +Author: Stef Walter +Date: Thu Sep 12 15:49:36 2013 +0200 + + ITS#7694 Fix use of IPv6 with LDAP_CONNECTIONLESS + + LDAP_CONNECTIONLESS code assumed that the size of an peer address + is equal to or smaller than sizeof (struct sockaddr). + + Fix to use struct sockaddr_storage instead which is intended for + this purpose. Use getnameinfo() where appropriate so we don't + assume anything about the contents of struct sockaddr + +diff --git a/libraries/liblber/sockbuf.c b/libraries/liblber/sockbuf.c +index d997e92..858c942 100644 +--- a/libraries/liblber/sockbuf.c ++++ b/libraries/liblber/sockbuf.c +@@ -888,8 +888,8 @@ Sockbuf_IO ber_sockbuf_io_debug = { + * + * All I/O at this level must be atomic. For ease of use, the sb_readahead + * must be used above this module. All data reads and writes are prefixed +- * with a sockaddr containing the address of the remote entity. Upper levels +- * must read and write this sockaddr before doing the usual ber_printf/scanf ++ * with a sockaddr_storage containing the address of the remote entity. Upper levels ++ * must read and write this sockaddr_storage before doing the usual ber_printf/scanf + * operations on LDAP messages. + */ + +@@ -914,13 +914,13 @@ sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) + assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); + assert( buf != NULL ); + +- addrlen = sizeof( struct sockaddr ); ++ addrlen = sizeof( struct sockaddr_storage ); + src = buf; + buf = (char *) buf + addrlen; + len -= addrlen; + rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src, &addrlen ); + +- return rc > 0 ? rc+sizeof(struct sockaddr) : rc; ++ return rc > 0 ? rc+sizeof(struct sockaddr_storage) : rc; + } + + static ber_slen_t +@@ -934,11 +934,11 @@ sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) + assert( buf != NULL ); + + dst = buf; +- buf = (char *) buf + sizeof( struct sockaddr ); +- len -= sizeof( struct sockaddr ); ++ buf = (char *) buf + sizeof( struct sockaddr_storage ); ++ len -= sizeof( struct sockaddr_storage ); + + rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst, +- sizeof( struct sockaddr ) ); ++ sizeof( struct sockaddr_storage ) ); + + if ( rc < 0 ) return -1; + +@@ -949,7 +949,7 @@ sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) + # endif + return -1; + } +- rc = len + sizeof(struct sockaddr); ++ rc = len + sizeof(struct sockaddr_storage); + return rc; + } + +diff --git a/libraries/libldap/abandon.c b/libraries/libldap/abandon.c +index d999b07..8fd9bc2 100644 +--- a/libraries/libldap/abandon.c ++++ b/libraries/libldap/abandon.c +@@ -209,7 +209,7 @@ start_again:; + LDAP_NEXT_MSGID(ld, i); + #ifdef LDAP_CONNECTIONLESS + if ( LDAP_IS_UDP(ld) ) { +- struct sockaddr sa = {0}; ++ struct sockaddr_storage sa = {0}; + /* dummy, filled with ldo_peer in request.c */ + err = ber_write( ber, (char *) &sa, sizeof(sa), 0 ); + } +diff --git a/libraries/libldap/open.c b/libraries/libldap/open.c +index ba10939..ac35e99 100644 +--- a/libraries/libldap/open.c ++++ b/libraries/libldap/open.c +@@ -314,8 +314,8 @@ ldap_init_fd( + LDAP_IS_UDP(ld) = 1; + if( ld->ld_options.ldo_peer ) + ldap_memfree( ld->ld_options.ldo_peer ); +- ld->ld_options.ldo_peer = ldap_memalloc( sizeof( struct sockaddr ) ); +- len = sizeof( struct sockaddr ); ++ ld->ld_options.ldo_peer = ldap_memcalloc( 1, sizeof( struct sockaddr_storage ) ); ++ len = sizeof( struct sockaddr_storage ); + if( getpeername ( fd, ld->ld_options.ldo_peer, &len ) < 0) { + ldap_unbind_ext( ld, NULL, NULL ); + return( AC_SOCKET_ERROR ); +diff --git a/libraries/libldap/os-ip.c b/libraries/libldap/os-ip.c +index b31e05d..90b92df 100644 +--- a/libraries/libldap/os-ip.c ++++ b/libraries/libldap/os-ip.c +@@ -422,8 +422,8 @@ ldap_pvt_connect(LDAP *ld, ber_socket_t s, + if (LDAP_IS_UDP(ld)) { + if (ld->ld_options.ldo_peer) + ldap_memfree(ld->ld_options.ldo_peer); +- ld->ld_options.ldo_peer=ldap_memalloc(sizeof(struct sockaddr)); +- AC_MEMCPY(ld->ld_options.ldo_peer,sin,sizeof(struct sockaddr)); ++ ld->ld_options.ldo_peer=ldap_memcalloc(1, sizeof(struct sockaddr_storage)); ++ AC_MEMCPY(ld->ld_options.ldo_peer,sin,addrlen); + return ( 0 ); + } + #endif +diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c +index fc2f4d0..4822a63 100644 +--- a/libraries/libldap/request.c ++++ b/libraries/libldap/request.c +@@ -308,7 +308,7 @@ ldap_send_server_request( + ber_rewind( &tmpber ); + LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); + rc = ber_write( &tmpber, ld->ld_options.ldo_peer, +- sizeof( struct sockaddr ), 0 ); ++ sizeof( struct sockaddr_storage ), 0 ); + LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); + if ( rc == -1 ) { + ld->ld_errno = LDAP_ENCODING_ERROR; +diff --git a/libraries/libldap/result.c b/libraries/libldap/result.c +index f2a6c7b..d293299 100644 +--- a/libraries/libldap/result.c ++++ b/libraries/libldap/result.c +@@ -482,8 +482,8 @@ retry: + sock_errset(0); + #ifdef LDAP_CONNECTIONLESS + if ( LDAP_IS_UDP(ld) ) { +- struct sockaddr from; +- ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr) ); ++ struct sockaddr_storage from; ++ ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr_storage) ); + if ( ld->ld_options.ldo_version == LDAP_VERSION2 ) isv2 = 1; + } + nextresp3: +diff --git a/libraries/libldap/search.c b/libraries/libldap/search.c +index 3867b5b..b966d1a 100644 +--- a/libraries/libldap/search.c ++++ b/libraries/libldap/search.c +@@ -305,7 +305,7 @@ ldap_build_search_req( + LDAP_NEXT_MSGID( ld, *idp ); + #ifdef LDAP_CONNECTIONLESS + if ( LDAP_IS_UDP(ld) ) { +- struct sockaddr sa = {0}; ++ struct sockaddr_storage sa = {0}; + /* dummy, filled with ldo_peer in request.c */ + err = ber_write( ber, (char *) &sa, sizeof( sa ), 0 ); + } diff --git a/openldap.spec b/openldap.spec index 9db1ee5..53dbcf1 100644 --- a/openldap.spec +++ b/openldap.spec @@ -51,6 +51,8 @@ Patch19: openldap-switch-to-lt_dlopenadvise-to-get-RTLD_GLOBAL-set.patch Patch20: openldap-ldapi-sasl.patch # more documentation fixes, upstreamed Patch21: openldap-doc3.patch +# cldap fixes, upstreamed +Patch22: openldap-cldap.patch # Fedora specific patches Patch100: openldap-autoconf-pkgconfig-nss.patch @@ -169,6 +171,7 @@ AUTOMAKE=%{_bindir}/true autoreconf -fi %patch19 -p1 %patch20 -p1 %patch21 -p1 +%patch22 -p1 %patch102 -p1 @@ -598,6 +601,9 @@ exit 0 %{_mandir}/man3/* %changelog +* Mon Oct 14 2013 Jan Synáček - 2.4.36-2 +- fix: CLDAP is broken for IPv6 (#1018688) + * Wed Sep 4 2013 Jan Synáček - 2.4.36-2 - fix: typos in manpages