1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05:00

Modified lookup_service() to avoid the risk of a potential buffer overflow

This commit is contained in:
Yang Tse 2005-12-10 19:21:59 +00:00
parent 4b1a91b64f
commit 2ae67c431c

View File

@ -70,7 +70,8 @@ struct nameinfo_query {
#endif #endif
static void nameinfo_callback(void *arg, int status, struct hostent *host); static void nameinfo_callback(void *arg, int status, struct hostent *host);
static char *lookup_service(unsigned short port, int flags, char *buf); static char *lookup_service(unsigned short port, int flags,
char *buf, size_t buflen);
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int scopeid, static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int scopeid,
char *buf, size_t buflen); char *buf, size_t buflen);
@ -109,7 +110,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
port = addr->sin_port; port = addr->sin_port;
else else
port = addr6->sin6_port; port = addr6->sin6_port;
service = lookup_service(port, flags, buf); service = lookup_service(port, flags, buf, sizeof(buf));
callback(arg, ARES_SUCCESS, NULL, service); callback(arg, ARES_SUCCESS, NULL, service);
return; return;
} }
@ -122,7 +123,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
{ {
unsigned int port = 0; unsigned int port = 0;
char ipbuf[IPBUFSIZ]; char ipbuf[IPBUFSIZ];
char srvbuf[32]; char srvbuf[33];
char *service = NULL; char *service = NULL;
ipbuf[0] = 0; ipbuf[0] = 0;
@ -150,7 +151,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
} }
/* They also want a service */ /* They also want a service */
if (flags & ARES_NI_LOOKUPSERVICE) if (flags & ARES_NI_LOOKUPSERVICE)
service = lookup_service(port, flags, srvbuf); service = lookup_service(port, flags, srvbuf, sizeof(srvbuf));
callback(arg, ARES_SUCCESS, ipbuf, service); callback(arg, ARES_SUCCESS, ipbuf, service);
return; return;
} }
@ -198,10 +199,10 @@ static void nameinfo_callback(void *arg, int status, struct hostent *host)
{ {
if (niquery->family == AF_INET) if (niquery->family == AF_INET)
service = lookup_service(niquery->addr.addr4.sin_port, service = lookup_service(niquery->addr.addr4.sin_port,
niquery->flags, srvbuf); niquery->flags, srvbuf, sizeof(srvbuf));
else else
service = lookup_service(niquery->addr.addr6.sin6_port, service = lookup_service(niquery->addr.addr6.sin6_port,
niquery->flags, srvbuf); niquery->flags, srvbuf, sizeof(srvbuf));
} }
/* NOFQDN means we have to strip off the domain name portion. /* NOFQDN means we have to strip off the domain name portion.
We do this by determining our own domain name, then searching the string We do this by determining our own domain name, then searching the string
@ -240,10 +241,10 @@ static void nameinfo_callback(void *arg, int status, struct hostent *host)
{ {
if (niquery->family == AF_INET) if (niquery->family == AF_INET)
service = lookup_service(niquery->addr.addr4.sin_port, service = lookup_service(niquery->addr.addr4.sin_port,
niquery->flags, srvbuf); niquery->flags, srvbuf, sizeof(srvbuf));
else else
service = lookup_service(niquery->addr.addr6.sin6_port, service = lookup_service(niquery->addr.addr6.sin6_port,
niquery->flags, srvbuf); niquery->flags, srvbuf, sizeof(srvbuf));
} }
niquery->callback(niquery->arg, ARES_SUCCESS, ipbuf, service); niquery->callback(niquery->arg, ARES_SUCCESS, ipbuf, service);
return; return;
@ -253,31 +254,21 @@ static void nameinfo_callback(void *arg, int status, struct hostent *host)
} }
static char *lookup_service(unsigned short port, int flags, static char *lookup_service(unsigned short port, int flags,
char *buf) /* 33 bytes buffer */ char *buf, size_t buflen)
{ {
const char *proto;
struct servent *sep;
#ifdef HAVE_GETSERVBYPORT_R
struct servent se;
#endif
char tmpbuf[4096];
if (port) if (port)
{ {
/* Just return the port as a string */
if (flags & ARES_NI_NUMERICSERV) if (flags & ARES_NI_NUMERICSERV)
sprintf(buf, "%u", ntohs(port)); sep = NULL;
else else
{ {
struct servent *se;
const char *proto;
#ifdef HAVE_GETSERVBYPORT_R
#if GETSERVBYPORT_R_ARGS == 6
struct servent ret;
char buf[4096];
int len = 4096;
#elif GETSERVBYPORT_R_ARGS == 5
struct servent ret;
char buf[4096];
int len = 4096;
#elif GETSERVBYPORT_R_ARGS == 4
struct servent ret;
struct servent_data sed;
#endif
#endif /* HAVE_GETSERVBYPORT_R */
if (flags & ARES_NI_UDP) if (flags & ARES_NI_UDP)
proto = "udp"; proto = "udp";
else if (flags & ARES_NI_SCTP) else if (flags & ARES_NI_SCTP)
@ -287,39 +278,40 @@ static char *lookup_service(unsigned short port, int flags,
else else
proto = "tcp"; proto = "tcp";
#ifdef HAVE_GETSERVBYPORT_R #ifdef HAVE_GETSERVBYPORT_R
sep = &se;
memset(tmpbuf, 0, sizeof(tmpbuf));
#if GETSERVBYPORT_R_ARGS == 6 #if GETSERVBYPORT_R_ARGS == 6
se = &ret; if (getservbyport_r(port, proto, &se, (void *)tmpbuf, sizeof(tmpbuf), &sep) != 0)
if (getservbyport_r(port, proto, se, buf, len, &ret)) sep = NULL;
se = NULL;
#elif GETSERVBYPORT_R_ARGS == 5 #elif GETSERVBYPORT_R_ARGS == 5
se = &ret; sep = getservbyport_r(port, proto, &se, (void *)tmpbuf, sizeof(tmpbuf));
se = getservbyport_r(port, proto, se, buf, len);
#elif GETSERVBYPORT_R_ARGS == 4 #elif GETSERVBYPORT_R_ARGS == 4
se = &ret; if (getservbyport_r(port, proto, &se, (void *)tmpbuf) != 0)
if (getservbyport_r(port, proto, se, &sed) == -1) sep = NULL;
se = NULL;
#else #else
/* Lets just hope the OS uses TLS! */ /* Lets just hope the OS uses TLS! */
se = getservbyport(port, proto); sep = getservbyport(port, proto);
#endif #endif
#else #else
/* Lets just hope the OS uses TLS! */ /* Lets just hope the OS uses TLS! */
se = getservbyport(port, proto); sep = getservbyport(port, proto);
#endif #endif
if (se && se->s_name) {
size_t len = strlen(se->s_name);
if(len < 33) {
strcpy(buf, se->s_name);
} }
if (sep && sep->s_name)
/* get service name */
strcpy(tmpbuf, sep->s_name);
else else
/* too big name to fit the buffer */ /* get port as a string */
buf[0]=0; sprintf(tmpbuf, "%u", ntohs(port));
} if (strlen(tmpbuf) < buflen)
/* return it if buffer big enough */
strcpy(buf, tmpbuf);
else else
sprintf(buf, "%u", ntohs(port)); /* avoid reusing previous one */
} buf[0] = '\0';
return buf; return buf;
} }
buf[0] = '\0';
return NULL; return NULL;
} }