LCOV - code coverage report
Current view: top level - builds/libidn/libidn2/lib - register.c (source / functions) Hit Total Coverage
Test: Libidn2-2.3.8.3-7d33 Code Coverage Lines: 71 83 85.5 %
Date: 2025-03-14 23:15:33 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* register.c - implementation of IDNA2008 register functions
       2             :    Copyright (C) 2011-2025 Simon Josefsson
       3             : 
       4             :    Libidn2 is free software: you can redistribute it and/or modify it
       5             :    under the terms of either:
       6             : 
       7             :      * the GNU Lesser General Public License as published by the Free
       8             :        Software Foundation; either version 3 of the License, or (at
       9             :        your option) any later version.
      10             : 
      11             :    or
      12             : 
      13             :      * the GNU General Public License as published by the Free
      14             :        Software Foundation; either version 2 of the License, or (at
      15             :        your option) any later version.
      16             : 
      17             :    or both in parallel, as here.
      18             : 
      19             :    This program is distributed in the hope that it will be useful,
      20             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      21             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      22             :    GNU General Public License for more details.
      23             : 
      24             :    You should have received copies of the GNU General Public License and
      25             :    the GNU Lesser General Public License along with this program.  If
      26             :    not, see <http://www.gnu.org/licenses/>.
      27             : */
      28             : 
      29             : #include <config.h>
      30             : 
      31             : #include "idn2.h"
      32             : 
      33             : #include <errno.h>                /* errno */
      34             : #include <stdlib.h>               /* free */
      35             : 
      36             : #include <unitypes.h>
      37             : #include <uniconv.h>              /* u8_strconv_from_locale */
      38             : #include <unistr.h>               /* u32_to_u8 */
      39             : 
      40             : #include "idna.h"             /* _idn2_label_test */
      41             : 
      42             : /**
      43             :  * idn2_register_u8:
      44             :  * @ulabel: input zero-terminated UTF-8 and Unicode NFC string, or NULL.
      45             :  * @alabel: input zero-terminated ACE encoded string (xn--), or NULL.
      46             :  * @insertname: newly allocated output variable with name to register in DNS.
      47             :  * @flags: optional #idn2_flags to modify behaviour.
      48             :  *
      49             :  * Perform IDNA2008 register string conversion on domain label @ulabel
      50             :  * and @alabel, as described in section 4 of RFC 5891.  Note that the
      51             :  * input @ulabel must be encoded in UTF-8 and be in Unicode NFC form.
      52             :  *
      53             :  * Pass %IDN2_NFC_INPUT in @flags to convert input @ulabel to NFC form
      54             :  * before further processing.
      55             :  *
      56             :  * It is recommended to supply both @ulabel and @alabel for better
      57             :  * error checking, but supplying just one of them will work.  Passing
      58             :  * in only @alabel is better than only @ulabel.  See RFC 5891 section
      59             :  * 4 for more information.
      60             :  *
      61             :  * After version 0.11: @insertname may be NULL to test conversion of @src
      62             :  * without allocating memory.
      63             :  *
      64             :  * Returns: On successful conversion %IDN2_OK is returned, when the
      65             :  *   given @ulabel and @alabel does not match each other
      66             :  *   %IDN2_UALABEL_MISMATCH is returned, when either of the input
      67             :  *   labels are too long %IDN2_TOO_BIG_LABEL is returned, when @alabel
      68             :  *   does does not appear to be a proper A-label %IDN2_INVALID_ALABEL
      69             :  *   is returned, or another error code is returned.
      70             :  **/
      71             : int
      72        1017 : idn2_register_u8 (const uint8_t *ulabel, const uint8_t *alabel,
      73             :                   uint8_t **insertname, int flags)
      74             : {
      75             :   int rc;
      76             : 
      77        1017 :   if (ulabel == NULL && alabel == NULL)
      78             :     {
      79           0 :       if (insertname)
      80           0 :         *insertname = NULL;
      81           0 :       return IDN2_OK;
      82             :     }
      83             : 
      84        1017 :   if (alabel)
      85             :     {
      86         402 :       size_t alabellen = strlen ((char *) alabel), u32len =
      87             :         IDN2_LABEL_MAX_LENGTH * 4;
      88             :       uint32_t u32[IDN2_DOMAIN_MAX_LENGTH * 4];
      89             :       uint8_t *tmp;
      90             :       uint8_t u8[IDN2_DOMAIN_MAX_LENGTH + 1];
      91             :       size_t u8len;
      92             : 
      93         402 :       if (alabellen > IDN2_LABEL_MAX_LENGTH)
      94         381 :         return IDN2_TOO_BIG_LABEL;
      95             : 
      96         401 :       if (alabellen <= 4)
      97           5 :         return IDN2_INVALID_ALABEL;
      98         396 :       if (alabel[0] != 'x'
      99         396 :           || alabel[1] != 'n' || alabel[2] != '-' || alabel[3] != '-')
     100           0 :         return IDN2_INVALID_ALABEL;
     101             : 
     102         396 :       if (!_idn2_ascii_p (alabel, alabellen))
     103           1 :         return IDN2_INVALID_ALABEL;
     104             : 
     105         395 :       rc = idn2_punycode_decode ((char *) alabel + 4, alabellen - 4,
     106             :                                  u32, &u32len);
     107         395 :       if (rc != IDN2_OK)
     108          65 :         return rc;
     109             : 
     110         330 :       u8len = sizeof (u8);
     111         330 :       if (u32_to_u8 (u32, u32len, u8, &u8len) == NULL)
     112           1 :         return IDN2_ENCODING_ERROR;
     113         329 :       u8[u8len] = '\0';
     114             : 
     115         329 :       if (ulabel)
     116             :         {
     117           0 :           if (strcmp ((char *) ulabel, (char *) u8) != 0)
     118           0 :             return IDN2_UALABEL_MISMATCH;
     119             :         }
     120             : 
     121         329 :       rc = idn2_register_u8 (u8, NULL, &tmp, 0);
     122         329 :       if (rc != IDN2_OK)
     123         223 :         return rc;
     124             : 
     125         106 :       rc = strcmp ((char *) alabel, (char *) tmp);
     126         106 :       free (tmp);
     127         106 :       if (rc != 0)
     128          85 :         return IDN2_UALABEL_MISMATCH;
     129             : 
     130          21 :       if (insertname)
     131             :         {
     132          21 :           uint8_t *m = (uint8_t *) strdup ((char *) alabel);
     133          21 :           if (!m)
     134           0 :             return IDN2_MALLOC;
     135             : 
     136          21 :           *insertname = m;
     137             :         }
     138             :     }
     139             :   else                          /* ulabel only */
     140             :     {
     141         615 :       size_t ulabellen = u8_strlen (ulabel);
     142             :       uint32_t *u32;
     143             :       size_t u32len;
     144             :       size_t tmpl;
     145             :       uint8_t tmp[IDN2_LABEL_MAX_LENGTH + 1];
     146             : 
     147         615 :       if (_idn2_ascii_p (ulabel, ulabellen))
     148             :         {
     149         286 :           if (ulabellen > IDN2_LABEL_MAX_LENGTH)
     150         509 :             return IDN2_TOO_BIG_LABEL;
     151             : 
     152         285 :           if (insertname)
     153             :             {
     154         285 :               uint8_t *m = (uint8_t *) strdup ((char *) ulabel);
     155         285 :               if (!m)
     156           0 :                 return IDN2_MALLOC;
     157         285 :               *insertname = m;
     158             :             }
     159         285 :           return IDN2_OK;
     160             :         }
     161             : 
     162         329 :       rc = _idn2_u8_to_u32_nfc (ulabel, ulabellen, &u32, &u32len,
     163             :                                 flags & IDN2_NFC_INPUT);
     164         329 :       if (rc != IDN2_OK)
     165           0 :         return rc;
     166             : 
     167         329 :       rc = _idn2_label_test (TEST_NFC
     168             :                              | TEST_DISALLOWED
     169             :                              | TEST_UNASSIGNED
     170             :                              | TEST_2HYPHEN
     171             :                              | TEST_HYPHEN_STARTEND
     172             :                              | TEST_LEADING_COMBINING
     173             :                              | TEST_CONTEXTJ_RULE
     174             :                              | TEST_CONTEXTO_RULE | TEST_BIDI, u32, u32len);
     175         329 :       if (rc != IDN2_OK)
     176             :         {
     177         223 :           free (u32);
     178         223 :           return rc;
     179             :         }
     180             : 
     181         106 :       tmp[0] = 'x';
     182         106 :       tmp[1] = 'n';
     183         106 :       tmp[2] = '-';
     184         106 :       tmp[3] = '-';
     185             : 
     186         106 :       tmpl = IDN2_LABEL_MAX_LENGTH - 4;
     187         106 :       rc = idn2_punycode_encode (u32, u32len, (char *) tmp + 4, &tmpl);
     188         106 :       free (u32);
     189         106 :       if (rc != IDN2_OK)
     190           0 :         return rc;
     191             : 
     192         106 :       tmp[4 + tmpl] = '\0';
     193             : 
     194         106 :       if (insertname)
     195             :         {
     196         106 :           uint8_t *m = (uint8_t *) strdup ((char *) tmp);
     197         106 :           if (!m)
     198           0 :             return IDN2_MALLOC;
     199         106 :           *insertname = m;
     200             :         }
     201             :     }
     202             : 
     203         127 :   return IDN2_OK;
     204             : }
     205             : 
     206             : /**
     207             :  * idn2_register_ul:
     208             :  * @ulabel: input zero-terminated locale encoded string, or NULL.
     209             :  * @alabel: input zero-terminated ACE encoded string (xn--), or NULL.
     210             :  * @insertname: newly allocated output variable with name to register in DNS.
     211             :  * @flags: optional #idn2_flags to modify behaviour.
     212             :  *
     213             :  * Perform IDNA2008 register string conversion on domain label @ulabel
     214             :  * and @alabel, as described in section 4 of RFC 5891.  Note that the
     215             :  * input @ulabel is assumed to be encoded in the locale's default
     216             :  * coding system, and will be transcoded to UTF-8 and NFC normalized
     217             :  * by this function.
     218             :  *
     219             :  * It is recommended to supply both @ulabel and @alabel for better
     220             :  * error checking, but supplying just one of them will work.  Passing
     221             :  * in only @alabel is better than only @ulabel.  See RFC 5891 section
     222             :  * 4 for more information.
     223             :  *
     224             :  * After version 0.11: @insertname may be NULL to test conversion of @src
     225             :  * without allocating memory.
     226             :  *
     227             :  * Returns: On successful conversion %IDN2_OK is returned, when the
     228             :  *   given @ulabel and @alabel does not match each other
     229             :  *   %IDN2_UALABEL_MISMATCH is returned, when either of the input
     230             :  *   labels are too long %IDN2_TOO_BIG_LABEL is returned, when @alabel
     231             :  *   does does not appear to be a proper A-label %IDN2_INVALID_ALABEL
     232             :  *   is returned, when @ulabel locale to UTF-8 conversion failed
     233             :  *   %IDN2_ICONV_FAIL is returned, or another error code is returned.
     234             :  **/
     235             : int
     236         804 : idn2_register_ul (const char *ulabel, const char *alabel,
     237             :                   char **insertname, int flags)
     238             : {
     239         804 :   uint8_t *utf8ulabel = NULL;
     240             :   int rc;
     241             : 
     242         804 :   if (ulabel)
     243             :     {
     244         402 :       const char *encoding = locale_charset ();
     245             : 
     246         402 :       utf8ulabel = u8_strconv_from_encoding (ulabel, encoding, iconveh_error);
     247             : 
     248         402 :       if (utf8ulabel == NULL)
     249             :         {
     250         116 :           if (errno == ENOMEM)
     251           0 :             return IDN2_MALLOC;
     252         116 :           return IDN2_ICONV_FAIL;
     253             :         }
     254             :     }
     255             : 
     256         688 :   rc = idn2_register_u8 (utf8ulabel, (const uint8_t *) alabel,
     257             :                          (uint8_t **) insertname, flags | IDN2_NFC_INPUT);
     258             : 
     259         688 :   free (utf8ulabel);
     260             : 
     261         688 :   return rc;
     262             : }

Generated by: LCOV version 1.16