summaryrefslogtreecommitdiff
path: root/ares_getnameinfo.c
diff options
context:
space:
mode:
authorYang Tse <yangsita@gmail.com>2005-12-10 19:21:59 +0000
committerYang Tse <yangsita@gmail.com>2005-12-10 19:21:59 +0000
commit6681cc24e9a85990939e8dcd6a1536413354ae7b (patch)
tree288d0da84c23d68e578ad8329ad5c85249060b77 /ares_getnameinfo.c
parentbc727dff6a1c4c2bf405086f01991604d324505d (diff)
downloadc-ares-6681cc24e9a85990939e8dcd6a1536413354ae7b.tar.gz
c-ares-6681cc24e9a85990939e8dcd6a1536413354ae7b.tar.bz2
c-ares-6681cc24e9a85990939e8dcd6a1536413354ae7b.zip
Modified lookup_service() to avoid the risk of a potential buffer overflow
Diffstat (limited to 'ares_getnameinfo.c')
-rw-r--r--ares_getnameinfo.c102
1 files changed, 47 insertions, 55 deletions
diff --git a/ares_getnameinfo.c b/ares_getnameinfo.c
index 23ca0cb..d13b11d 100644
--- a/ares_getnameinfo.c
+++ b/ares_getnameinfo.c
@@ -70,7 +70,8 @@ struct nameinfo_query {
#endif
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
static void append_scopeid(struct sockaddr_in6 *addr6, unsigned int scopeid,
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;
else
port = addr6->sin6_port;
- service = lookup_service(port, flags, buf);
+ service = lookup_service(port, flags, buf, sizeof(buf));
callback(arg, ARES_SUCCESS, NULL, service);
return;
}
@@ -122,7 +123,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
{
unsigned int port = 0;
char ipbuf[IPBUFSIZ];
- char srvbuf[32];
+ char srvbuf[33];
char *service = NULL;
ipbuf[0] = 0;
@@ -150,7 +151,7 @@ void ares_getnameinfo(ares_channel channel, const struct sockaddr *sa, socklen_t
}
/* They also want a service */
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);
return;
}
@@ -198,10 +199,10 @@ static void nameinfo_callback(void *arg, int status, struct hostent *host)
{
if (niquery->family == AF_INET)
service = lookup_service(niquery->addr.addr4.sin_port,
- niquery->flags, srvbuf);
+ niquery->flags, srvbuf, sizeof(srvbuf));
else
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.
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)
service = lookup_service(niquery->addr.addr4.sin_port,
- niquery->flags, srvbuf);
+ niquery->flags, srvbuf, sizeof(srvbuf));
else
service = lookup_service(niquery->addr.addr6.sin6_port,
- niquery->flags, srvbuf);
+ niquery->flags, srvbuf, sizeof(srvbuf));
}
niquery->callback(niquery->arg, ARES_SUCCESS, ipbuf, service);
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,
- 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)
- {
- /* Just return the port as a string */
+ {
if (flags & ARES_NI_NUMERICSERV)
- sprintf(buf, "%u", ntohs(port));
+ sep = NULL;
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)
proto = "udp";
else if (flags & ARES_NI_SCTP)
@@ -287,39 +278,40 @@ static char *lookup_service(unsigned short port, int flags,
else
proto = "tcp";
#ifdef HAVE_GETSERVBYPORT_R
+ sep = &se;
+ memset(tmpbuf, 0, sizeof(tmpbuf));
#if GETSERVBYPORT_R_ARGS == 6
- se = &ret;
- if (getservbyport_r(port, proto, se, buf, len, &ret))
- se = NULL;
+ if (getservbyport_r(port, proto, &se, (void *)tmpbuf, sizeof(tmpbuf), &sep) != 0)
+ sep = NULL;
#elif GETSERVBYPORT_R_ARGS == 5
- se = &ret;
- se = getservbyport_r(port, proto, se, buf, len);
+ sep = getservbyport_r(port, proto, &se, (void *)tmpbuf, sizeof(tmpbuf));
#elif GETSERVBYPORT_R_ARGS == 4
- se = &ret;
- if (getservbyport_r(port, proto, se, &sed) == -1)
- se = NULL;
-#else
+ if (getservbyport_r(port, proto, &se, (void *)tmpbuf) != 0)
+ sep = NULL;
+#else
/* Lets just hope the OS uses TLS! */
- se = getservbyport(port, proto);
-#endif
-#else
+ sep = getservbyport(port, proto);
+#endif
+#else
/* Lets just hope the OS uses TLS! */
- se = getservbyport(port, proto);
-#endif
- if (se && se->s_name) {
- size_t len = strlen(se->s_name);
- if(len < 33) {
- strcpy(buf, se->s_name);
- }
- else
- /* too big name to fit the buffer */
- buf[0]=0;
- }
- else
- sprintf(buf, "%u", ntohs(port));
- }
+ sep = getservbyport(port, proto);
+#endif
+ }
+ if (sep && sep->s_name)
+ /* get service name */
+ strcpy(tmpbuf, sep->s_name);
+ else
+ /* get port as a string */
+ sprintf(tmpbuf, "%u", ntohs(port));
+ if (strlen(tmpbuf) < buflen)
+ /* return it if buffer big enough */
+ strcpy(buf, tmpbuf);
+ else
+ /* avoid reusing previous one */
+ buf[0] = '\0';
return buf;
}
+ buf[0] = '\0';
return NULL;
}