(root)/
glibc-2.38/
inet/
idna.c
       1  /* IDNA functions, forwarding to implementations in libidn2.
       2     Copyright (C) 2018-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <allocate_once.h>
      20  #include <dlfcn.h>
      21  #include <inet/net-internal.h>
      22  #include <netdb.h>
      23  #include <stdbool.h>
      24  #include <pointer_guard.h>
      25  
      26  /* Use the soname and version to locate libidn2, to ensure a
      27     compatible ABI.  */
      28  #define LIBIDN2_SONAME "libidn2.so.0"
      29  #define LIBIDN2_VERSION "IDN2_0.0.0"
      30  
      31  /* Return codes from libidn2.  */
      32  enum
      33    {
      34      IDN2_OK = 0,
      35      IDN2_MALLOC = -100,
      36    };
      37  
      38  /* Functions from libidn2.  */
      39  struct functions
      40  {
      41    void *handle;
      42    int (*lookup_ul) (const char *src, char **result, int flags);
      43    int (*to_unicode_lzlz) (const char *name, char **result, int flags);
      44  };
      45  
      46  static void *
      47  functions_allocate (void *closure)
      48  {
      49    struct functions *result = malloc (sizeof (*result));
      50    if (result == NULL)
      51      return NULL;
      52  
      53    void *handle = __libc_dlopen (LIBIDN2_SONAME);
      54    if (handle == NULL)
      55      /* Do not cache open failures.  The library may appear
      56         later.  */
      57      {
      58        free (result);
      59        return NULL;
      60      }
      61  
      62    void *ptr_lookup_ul
      63      = __libc_dlvsym (handle, "idn2_lookup_ul", LIBIDN2_VERSION);
      64    void *ptr_to_unicode_lzlz
      65      = __libc_dlvsym (handle, "idn2_to_unicode_lzlz", LIBIDN2_VERSION);
      66    if (ptr_lookup_ul == NULL || ptr_to_unicode_lzlz == NULL)
      67      {
      68        __libc_dlclose (handle);
      69        free (result);
      70        return NULL;
      71      }
      72  
      73    result->handle = handle;
      74    result->lookup_ul = ptr_lookup_ul;
      75    result->to_unicode_lzlz = ptr_to_unicode_lzlz;
      76    PTR_MANGLE (result->lookup_ul);
      77    PTR_MANGLE (result->to_unicode_lzlz);
      78  
      79    return result;
      80  }
      81  
      82  static void
      83  functions_deallocate (void *closure, void *ptr)
      84  {
      85    struct functions *functions = ptr;
      86    __libc_dlclose (functions->handle);
      87    free (functions);
      88  }
      89  
      90  /* Ensure that *functions is initialized and return the value of the
      91     pointer.  If the library cannot be loaded, return NULL.  */
      92  static inline struct functions *
      93  get_functions (void)
      94  {
      95    static void *functions;
      96    return allocate_once (&functions, functions_allocate, functions_deallocate,
      97                          NULL);
      98  }
      99  
     100  /* strdup with an EAI_* error code.  */
     101  static int
     102  gai_strdup (const char *name, char **result)
     103  {
     104    char *ptr = __strdup (name);
     105    if (ptr == NULL)
     106      return EAI_MEMORY;
     107    *result = ptr;
     108    return 0;
     109  }
     110  
     111  int
     112  __idna_to_dns_encoding (const char *name, char **result)
     113  {
     114    switch (__idna_name_classify (name))
     115      {
     116      case idna_name_ascii:
     117        /* Nothing to convert.  */
     118        return gai_strdup (name, result);
     119      case idna_name_nonascii:
     120        /* Encoding needed.  Handled below.  */
     121        break;
     122      case idna_name_nonascii_backslash:
     123      case idna_name_encoding_error:
     124        return EAI_IDN_ENCODE;
     125      case idna_name_memory_error:
     126        return EAI_MEMORY;
     127      case idna_name_error:
     128        return EAI_SYSTEM;
     129      }
     130  
     131    struct functions *functions = get_functions ();
     132    if (functions == NULL)
     133      /* We report this as an encoding error (assuming that libidn2 is
     134         not installed), although the root cause may be a temporary
     135         error condition due to resource shortage.  */
     136      return EAI_IDN_ENCODE;
     137    char *ptr = NULL;
     138    __typeof__ (functions->lookup_ul) fptr = functions->lookup_ul;
     139    PTR_DEMANGLE (fptr);
     140    int ret = fptr (name, &ptr, 0);
     141    if (ret == 0)
     142      {
     143        /* Assume that idn2_free is equivalent to free.  */
     144        *result = ptr;
     145        return 0;
     146      }
     147    else if (ret == IDN2_MALLOC)
     148      return EAI_MEMORY;
     149    else
     150      return EAI_IDN_ENCODE;
     151  }
     152  libc_hidden_def (__idna_to_dns_encoding)
     153  
     154  int
     155  __idna_from_dns_encoding (const char *name, char **result)
     156  {
     157    struct functions *functions = get_functions ();
     158    if (functions == NULL)
     159      /* Simply use the encoded name, assuming that it is not punycode
     160         (but even a punycode name would be syntactically valid).  */
     161      return gai_strdup (name, result);
     162    char *ptr = NULL;
     163    __typeof__ (functions->to_unicode_lzlz) fptr = functions->to_unicode_lzlz;
     164    PTR_DEMANGLE (fptr);
     165    int ret = fptr (name, &ptr, 0);
     166    if (ret == 0)
     167      {
     168        /* Assume that idn2_free is equivalent to free.  */
     169        *result = ptr;
     170        return 0;
     171      }
     172    else if (ret == IDN2_MALLOC)
     173      return EAI_MEMORY;
     174    else
     175      return EAI_IDN_ENCODE;
     176  }
     177  libc_hidden_def (__idna_from_dns_encoding)