Red Hat issue 1021948: snprintf API change

This commit is contained in:
Gerhard Rieger 2014-01-26 17:45:09 +01:00
parent 52e8a5ec2b
commit cf39583b25
8 changed files with 74 additions and 53 deletions

View file

@ -62,6 +62,11 @@ porting:
use getgrouplist() when available instead of sequence of calls to use getgrouplist() when available instead of sequence of calls to
getgrent() getgrent()
Red Hat issue 1021948: snprintf API change;
Implemented xio_snprintf() function as wrapper that tries to emulate C99
behaviour on old glibc systems, and adapted all affected calls
appropriately
docu: docu:
libwrap always logs to syslog libwrap always logs to syslog

View file

@ -1,5 +1,5 @@
/* source: compat.h */ /* source: compat.h */
/* Copyright Gerhard Rieger 2001-2011 */ /* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __compat_h_included #ifndef __compat_h_included
@ -622,34 +622,4 @@
extern const char *hstrerror(int); extern const char *hstrerror(int);
#endif #endif
/*****************************************************************************/
/* here are the declarations of compat.c */
#if !HAVE_SIGACTION
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
} ;
struct siginfo {
int si_signo;
int si_errno;
int si_code;
pid_t si_pid;
uid_t si_uid;
int si_status;
/*clock_t si_utime;*/
/*clock_t si_stime;*/
sigval_t si_value;
int si_int;
void *si_ptr;
void *si_addr;
/*int si_band;*/
/*int si_fd;*/
} ;
extern int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
#endif /* !HAVE_SIGACTION */
#endif /* !defined(__compat_h_included) */ #endif /* !defined(__compat_h_included) */

View file

@ -439,6 +439,9 @@
/* is uint64_t already defined? */ /* is uint64_t already defined? */
#undef HAVE_TYPE_UINT64 #undef HAVE_TYPE_UINT64
/* Define if snprintf() returns required len on truncation (C-99 conform) */
#undef HAVE_C99_SNPRINTF
/* Define if you have the printf "Z" modifier */ /* Define if you have the printf "Z" modifier */
#undef HAVE_FORMAT_Z #undef HAVE_FORMAT_Z

View file

@ -1284,11 +1284,29 @@ AC_CHECK_FUNC(SSLv2_server_method, AC_DEFINE(HAVE_SSLv2_server_method), AC_CHECK
dnl Run time checks dnl Run time checks
AC_MSG_CHECKING(if snprintf conforms to C99)
AC_CACHE_VAL(ac_cv_have_c99_snprintf,
[AC_TRY_RUN([
#include <stdio.h>
#include <stdlib.h>
int main(void){
char s[2];
exit(snprintf(s,2,"ab")!=2);
}],
[ac_cv_have_c99_snprintf=yes],
[ac_cv_have_c99_snprintf=no],
[ac_cv_have_c99_snprintf=no])])
if test $ac_cv_have_c99_snprintf = yes; then
AC_DEFINE(HAVE_C99_SNPRINTF)
fi
AC_MSG_RESULT($ac_cv_have_c99_snprintf)
AC_MSG_CHECKING(if printf has Z modifier) AC_MSG_CHECKING(if printf has Z modifier)
AC_CACHE_VAL(ac_cv_have_z_modifier, AC_CACHE_VAL(ac_cv_have_z_modifier,
[AC_TRY_RUN([ [AC_TRY_RUN([
#include <stdio.h> #include <stdio.h>
main(){ int main(void){
char s[16]; char s[16];
sprintf(s,"%Zu",1); sprintf(s,"%Zu",1);
exit(strcmp(s,"1")); exit(strcmp(s,"1"));

View file

@ -173,14 +173,16 @@ char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size
int n; int n;
#if HAVE_STRUCT_SOCKADDR_SALEN #if HAVE_STRUCT_SOCKADDR_SALEN
if ((n = snprintf(cp, blen, "LEN=%d ", sau->soa.sa_len)) < 0) { n = xio_snprintf(cp, blen, "LEN=%d ", sau->soa.sa_len);
if (n < 0 || n >= blen) {
Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen); Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
*buff = '\0'; *buff = '\0';
return buff; return buff;
} }
cp += n, blen -= n; cp += n, blen -= n;
#endif #endif
if ((n = snprintf(cp, blen, "AF=%d ", sau->soa.sa_family)) < 0) { n = xio_snprintf(cp, blen, "AF=%d ", sau->soa.sa_family);
if (n < 0 || n >= blen) {
Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen); Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
*buff = '\0'; *buff = '\0';
return buff; return buff;
@ -204,13 +206,14 @@ char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size
break; break;
#endif #endif
default: default:
if ((n = snprintf(cp, blen, "AF=%d ", sa->sa_family)) < 0) { n = xio_snprintf(cp, blen, "AF=%d ", sa->sa_family);
if (n < 0 || n >= blen) {
Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen); Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
*buff = '\0'; *buff = '\0';
return buff; return buff;
} }
cp += n, blen -= n; cp += n, blen -= n;
if ((snprintf(cp, blen, n = xio_snprintf(cp, blen,
"0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
((unsigned char *)sau->soa.sa_data)[0], ((unsigned char *)sau->soa.sa_data)[0],
((unsigned char *)sau->soa.sa_data)[1], ((unsigned char *)sau->soa.sa_data)[1],
@ -225,7 +228,8 @@ char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size
((unsigned char *)sau->soa.sa_data)[10], ((unsigned char *)sau->soa.sa_data)[10],
((unsigned char *)sau->soa.sa_data)[11], ((unsigned char *)sau->soa.sa_data)[11],
((unsigned char *)sau->soa.sa_data)[12], ((unsigned char *)sau->soa.sa_data)[12],
((unsigned char *)sau->soa.sa_data)[13])) < 0) { ((unsigned char *)sau->soa.sa_data)[13]);
if (n < 0 || n >= blen) {
Warn("sockaddr_info(): buffer too short"); Warn("sockaddr_info(): buffer too short");
*buff = '\0'; *buff = '\0';
return buff; return buff;
@ -268,9 +272,9 @@ char *sockaddr_unix_info(const struct sockaddr_un *sa, socklen_t salen, char *bu
#if WITH_IP4 #if WITH_IP4
/* addr in host byte order! */ /* addr in host byte order! */
char *inet4addr_info(uint32_t addr, char *buff, size_t blen) { char *inet4addr_info(uint32_t addr, char *buff, size_t blen) {
if (snprintf(buff, blen, "%u.%u.%u.%u", if (xio_snprintf(buff, blen, "%u.%u.%u.%u",
(unsigned int)(addr >> 24), (unsigned int)((addr >> 16) & 0xff), (unsigned int)(addr >> 24), (unsigned int)((addr >> 16) & 0xff),
(unsigned int)((addr >> 8) & 0xff), (unsigned int)(addr & 0xff)) < 0) { (unsigned int)((addr >> 8) & 0xff), (unsigned int)(addr & 0xff)) >= blen) {
Warn("inet4addr_info(): buffer too short"); Warn("inet4addr_info(): buffer too short");
buff[blen-1] = '\0'; buff[blen-1] = '\0';
} }
@ -280,12 +284,12 @@ char *inet4addr_info(uint32_t addr, char *buff, size_t blen) {
#if WITH_IP4 #if WITH_IP4
char *sockaddr_inet4_info(const struct sockaddr_in *sa, char *buff, size_t blen) { char *sockaddr_inet4_info(const struct sockaddr_in *sa, char *buff, size_t blen) {
if (snprintf(buff, blen, "%u.%u.%u.%u:%hu", if (xio_snprintf(buff, blen, "%u.%u.%u.%u:%hu",
((unsigned char *)&sa->sin_addr.s_addr)[0], ((unsigned char *)&sa->sin_addr.s_addr)[0],
((unsigned char *)&sa->sin_addr.s_addr)[1], ((unsigned char *)&sa->sin_addr.s_addr)[1],
((unsigned char *)&sa->sin_addr.s_addr)[2], ((unsigned char *)&sa->sin_addr.s_addr)[2],
((unsigned char *)&sa->sin_addr.s_addr)[3], ((unsigned char *)&sa->sin_addr.s_addr)[3],
htons(sa->sin_port)) < 0) { htons(sa->sin_port)) >= blen) {
Warn("sockaddr_inet4_info(): buffer too short"); Warn("sockaddr_inet4_info(): buffer too short");
buff[blen-1] = '\0'; buff[blen-1] = '\0';
} }
@ -301,19 +305,19 @@ const char *inet_ntop(int pf, const void *binaddr,
switch (pf) { switch (pf) {
case PF_INET: case PF_INET:
if ((retlen = if ((retlen =
snprintf(addrtext, textlen, "%u.%u.%u.%u", xio_snprintf(addrtext, textlen, "%u.%u.%u.%u",
((unsigned char *)binaddr)[0], ((unsigned char *)binaddr)[0],
((unsigned char *)binaddr)[1], ((unsigned char *)binaddr)[1],
((unsigned char *)binaddr)[2], ((unsigned char *)binaddr)[2],
((unsigned char *)binaddr)[3])) ((unsigned char *)binaddr)[3]))
< 0) { >= textlen) {
return NULL; /* errno is valid */ errno = ENOSPC; return NULL;
} }
break; break;
#if WITH_IP6 #if WITH_IP6
case PF_INET6: case PF_INET6:
if ((retlen = if ((retlen =
snprintf(addrtext, textlen, "%x:%x:%x:%x:%x:%x:%x:%x", xio_snprintf(addrtext, textlen, "%x:%x:%x:%x:%x:%x:%x:%x",
ntohs(((uint16_t *)binaddr)[0]), ntohs(((uint16_t *)binaddr)[0]),
ntohs(((uint16_t *)binaddr)[1]), ntohs(((uint16_t *)binaddr)[1]),
ntohs(((uint16_t *)binaddr)[2]), ntohs(((uint16_t *)binaddr)[2]),
@ -323,8 +327,8 @@ const char *inet_ntop(int pf, const void *binaddr,
ntohs(((uint16_t *)binaddr)[6]), ntohs(((uint16_t *)binaddr)[6]),
ntohs(((uint16_t *)binaddr)[7]) ntohs(((uint16_t *)binaddr)[7])
)) ))
< 0) { >= textlen) {
return NULL; /* errno is valid */ errno = ENOSPC; return NULL;
} }
break; break;
#endif /* WITH_IP6 */ #endif /* WITH_IP6 */
@ -341,7 +345,7 @@ const char *inet_ntop(int pf, const void *binaddr,
/* convert the IP6 socket address to human readable form. buff should be at /* convert the IP6 socket address to human readable form. buff should be at
least 50 chars long. output includes the port number */ least 50 chars long. output includes the port number */
char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen) { char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen) {
if (snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%hu", if (xio_snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%hu",
#if HAVE_IP6_SOCKADDR==0 #if HAVE_IP6_SOCKADDR==0
(sa->sin6_addr.s6_addr[0]<<8)+ (sa->sin6_addr.s6_addr[0]<<8)+
sa->sin6_addr.s6_addr[1], sa->sin6_addr.s6_addr[1],
@ -405,9 +409,8 @@ char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen
ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[6]), ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[6]),
ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[7]), ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[7]),
#endif #endif
ntohs(sa->sin6_port)) < 0) { ntohs(sa->sin6_port)) >= blen) {
Warn("sockaddr_inet6_info(): buffer too short"); Warn("sockaddr_inet6_info(): buffer too short");
buff[blen-1] = '\0';
} }
return buff; return buff;
} }

21
utils.c
View file

@ -1,5 +1,5 @@
/* source: utils.c */ /* source: utils.c */
/* Copyright Gerhard Rieger 2001-2009 */ /* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
/* useful additions to C library */ /* useful additions to C library */
@ -161,3 +161,22 @@ char *xiosubstr(char *scratch, const char *str, size_t from, size_t len) {
return scratch0; return scratch0;
} }
/* since version 1.7.2.4 socat supports C-99 behaviour of snprintf but still
can handle the old glibc case with -1 return on truncation.
Do not rely on exact return value in case of truncation
*/
int xio_snprintf(char *str, size_t size, const char *format, ...) {
va_list ap;
int result;
va_start(ap, format);
result = vsnprintf(str, size, format, ap);
#if ! HAVE_C99_SNPRINTF
if (result < 0) {
result = size+63; /* indicate truncation with just some guess */
}
#endif /* !HAVE_C99_SNPRINTF */
va_end(ap);
return result;
}

View file

@ -66,4 +66,7 @@ char *sanitize_string(const char *data, /* input data */
extern extern
char *xiosubstr(char *scratch, const char *str, size_t from, size_t len); char *xiosubstr(char *scratch, const char *str, size_t from, size_t len);
extern
int xio_snprintf(char *str, size_t size, const char *format, ...);
#endif /* !defined(__utils_h_included) */ #endif /* !defined(__utils_h_included) */

View file

@ -312,7 +312,7 @@ int xiolog_ancillary_ip6(struct cmsghdr *cmsg, int *num,
/* convert the IP6 socket address to human readable form. buff should be at /* convert the IP6 socket address to human readable form. buff should be at
least 50 chars long. output includes the port number */ least 50 chars long. output includes the port number */
static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen) { static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen) {
if (snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]", if (xio_snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
#if HAVE_IP6_SOCKADDR==0 #if HAVE_IP6_SOCKADDR==0
(sa->s6_addr[0]<<8)+sa->s6_addr[1], (sa->s6_addr[0]<<8)+sa->s6_addr[1],
(sa->s6_addr[2]<<8)+sa->s6_addr[3], (sa->s6_addr[2]<<8)+sa->s6_addr[3],
@ -368,7 +368,7 @@ static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen)
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[6]), ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[6]),
ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[7]) ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[7])
#endif #endif
) < 0) { ) >= blen) {
Warn("sockaddr_inet6_info(): buffer too short"); Warn("sockaddr_inet6_info(): buffer too short");
buff[blen-1] = '\0'; buff[blen-1] = '\0';
} }