]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - inet/getnameinfo.c
(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
[thirdparty/glibc.git] / inet / getnameinfo.c
index 9f1a5c4f4597cb0e18ec7fb0857af353a7d9c829..493a423c1089f83434f7298685224070aa09db5b 100644 (file)
@@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <alloca.h>
 #include <errno.h>
 #include <netdb.h>
+#include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
@@ -51,16 +52,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <sys/utsname.h>
 #include <bits/libc-lock.h>
 
+#ifdef HAVE_LIBIDN
+# include <libidn/idna.h>
+extern int __idna_to_unicode_lzlz (const char *input, char **output,
+                                  int flags);
+#endif
+
 #ifndef min
 # define min(x,y) (((x) > (y)) ? (y) : (x))
 #endif /* min */
 
+libc_freeres_ptr (static char *domain);
+
 
 static char *
 internal_function
 nrl_domainname (void)
 {
-  static char *domain;
   static int not_first;
 
   if (! not_first)
@@ -82,10 +90,7 @@ nrl_domainname (void)
                                    &herror))
            {
              if (herror == NETDB_INTERNAL && errno == ERANGE)
-               {
-                 tmpbuflen *= 2;
-                 tmpbuf = alloca (tmpbuflen);
-               }
+               tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
              else
                break;
            }
@@ -97,10 +102,7 @@ nrl_domainname (void)
              /* The name contains no domain information.  Use the name
                 now to get more information.  */
              while (__gethostname (tmpbuf, tmpbuflen))
-               {
-                 tmpbuflen *= 2;
-                 tmpbuf = alloca (tmpbuflen);
-               }
+               tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
 
              if ((c = strchr (tmpbuf, '.')))
                domain = __strdup (++c);
@@ -113,10 +115,8 @@ nrl_domainname (void)
                                            &h, &herror))
                    {
                      if (herror == NETDB_INTERNAL && errno == ERANGE)
-                       {
-                         tmpbuflen *= 2;
-                         tmpbuf = alloca (tmpbuflen);
-                       }
+                       tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+                                               2 * tmpbuflen);
                      else
                        break;
                    }
@@ -135,10 +135,8 @@ nrl_domainname (void)
                                                tmpbuflen, &h, &herror))
                        {
                          if (herror == NETDB_INTERNAL && errno == ERANGE)
-                           {
-                             tmpbuflen *= 2;
-                             tmpbuf = alloca (tmpbuflen);
-                           }
+                           tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+                                                   2 * tmpbuflen);
                          else
                            break;
                        }
@@ -169,7 +167,11 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
   struct hostent th;
   int ok = 0;
 
-  if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
+  if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
+#ifdef HAVE_LIBIDN
+               |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
+#endif
+               ))
     return EAI_BADFLAGS;
 
   if (sa == NULL || addrlen < sizeof (sa_family_t))
@@ -213,10 +215,8 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
                        if (herrno == NETDB_INTERNAL)
                          {
                            if (errno == ERANGE)
-                             {
-                               tmpbuflen *= 2;
-                               tmpbuf = alloca (tmpbuflen);
-                             }
+                             tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+                                                     2 * tmpbuflen);
                            else
                              {
                                __set_h_errno (herrno);
@@ -238,10 +238,8 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
                                              &h, &herrno))
                      {
                        if (errno == ERANGE)
-                         {
-                           tmpbuflen *= 2;
-                           tmpbuf = alloca (tmpbuflen);
-                         }
+                         tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+                                                 2 * tmpbuflen);
                        else
                          {
                            break;
@@ -257,18 +255,46 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
                    && (c = nrl_domainname ())
                    && (c = strstr (h->h_name, c))
                    && (c != h->h_name) && (*(--c) == '.'))
+                 /* Terminate the string after the prefix.  */
+                 *c = '\0';
+
+#ifdef HAVE_LIBIDN
+               /* If requested, convert from the IDN format.  */
+               if (flags & NI_IDN)
                  {
-                   strncpy (host, h->h_name,
-                            min(hostlen, (size_t) (c - h->h_name)));
-                   host[min(hostlen - 1, (size_t) (c - h->h_name))]
-                     = '\0';
-                   ok = 1;
-                 }
-               else
-                 {
-                   strncpy (host, h->h_name, hostlen);
-                   ok = 1;
+                   int idn_flags = 0;
+                   if  (flags & NI_IDN_ALLOW_UNASSIGNED)
+                     idn_flags |= IDNA_ALLOW_UNASSIGNED;
+                   if (flags & NI_IDN_USE_STD3_ASCII_RULES)
+                     idn_flags |= IDNA_USE_STD3_ASCII_RULES;
+
+                   char *out;
+                   int rc = __idna_to_unicode_lzlz (h->h_name, &out,
+                                                    idn_flags);
+                   if (rc != IDNA_SUCCESS)
+                     {
+                       if (rc == IDNA_MALLOC_ERROR)
+                         return EAI_MEMORY;
+                       if (rc == IDNA_DLOPEN_ERROR)
+                         return EAI_SYSTEM;
+                       return EAI_IDN_ENCODE;
+                     }
+
+                   if (out != h->h_name)
+                     {
+                       h->h_name = strdupa (out);
+                       free (out);
+                     }
                  }
+#endif
+
+               size_t len = strlen (h->h_name) + 1;
+               if (len > hostlen)
+                 return EAI_OVERFLOW;
+
+               memcpy (host, h->h_name, len);
+
+               ok = 1;
              }
          }
 
@@ -384,10 +410,8 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
                if (herrno == NETDB_INTERNAL)
                  {
                    if (errno == ERANGE)
-                     {
-                       tmpbuflen *= 2;
-                       tmpbuf = __alloca (tmpbuflen);
-                     }
+                     tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+                                             2 * tmpbuflen);
                    else
                      {
                        __set_errno (serrno);
@@ -405,8 +429,12 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
                break;
              }
          }
-       __snprintf (serv, servlen, "%d",
-                   ntohs (((const struct sockaddr_in *) sa)->sin_port));
+
+       if (__snprintf (serv, servlen, "%d",
+                       ntohs (((const struct sockaddr_in *) sa)->sin_port))
+           + 1 > servlen)
+         return EAI_OVERFLOW;
+
        break;
 
       case AF_LOCAL:
@@ -421,3 +449,4 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
   errno = serrno;
   return 0;
 }
+libc_hidden_def (getnameinfo)