PageRenderTime 59ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/inet/idna.c

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