GRand: move docs from tmpl to inline comments
[platform/upstream/glib.git] / glib / ghostutils.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* GLIB - Library of useful routines for C programming
4  * Copyright (C) 2008 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General
17  * Public License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23
24 #include "glib.h"
25 #include "glibintl.h"
26
27 #include <string.h>
28
29 #include "galias.h"
30
31 /**
32  * SECTION:ghostutils
33  * @short_description: Internet hostname utilities
34  * @include: glib.h
35  *
36  * Functions for manipulating internet hostnames; in particular, for
37  * converting between Unicode and ASCII-encoded forms of
38  * Internationalized Domain Names (IDNs).
39  *
40  * The <ulink
41  * url="http://www.ietf.org/rfc/rfc3490.txt">Internationalized Domain
42  * Names for Applications (IDNA)</ulink> standards allow for the use
43  * of Unicode domain names in applications, while providing
44  * backward-compatibility with the old ASCII-only DNS, by defining an
45  * ASCII-Compatible Encoding of any given Unicode name, which can be
46  * used with non-IDN-aware applications and protocols. (For example,
47  * "Παν語.org" maps to "xn--4wa8awb4637h.org".)
48  **/
49
50 #define IDNA_ACE_PREFIX     "xn--"
51 #define IDNA_ACE_PREFIX_LEN 4
52
53 /* Punycode constants, from RFC 3492. */
54
55 #define PUNYCODE_BASE          36
56 #define PUNYCODE_TMIN           1
57 #define PUNYCODE_TMAX          26
58 #define PUNYCODE_SKEW          38
59 #define PUNYCODE_DAMP         700
60 #define PUNYCODE_INITIAL_BIAS  72
61 #define PUNYCODE_INITIAL_N   0x80
62
63 #define PUNYCODE_IS_BASIC(cp) ((guint)(cp) < 0x80)
64
65 /* Encode/decode a single base-36 digit */
66 static inline gchar
67 encode_digit (guint dig)
68 {
69   if (dig < 26)
70     return dig + 'a';
71   else
72     return dig - 26 + '0';
73 }
74
75 static inline guint
76 decode_digit (gchar dig)
77 {
78   if (dig >= 'A' && dig <= 'Z')
79     return dig - 'A';
80   else if (dig >= 'a' && dig <= 'z')
81     return dig - 'a';
82   else if (dig >= '0' && dig <= '9')
83     return dig - '0' + 26;
84   else
85     return G_MAXUINT;
86 }
87
88 /* Punycode bias adaptation algorithm, RFC 3492 section 6.1 */
89 static guint
90 adapt (guint    delta,
91        guint    numpoints,
92        gboolean firsttime)
93 {
94   guint k;
95
96   delta = firsttime ? delta / PUNYCODE_DAMP : delta / 2;
97   delta += delta / numpoints;
98
99   k = 0;
100   while (delta > ((PUNYCODE_BASE - PUNYCODE_TMIN) * PUNYCODE_TMAX) / 2)
101     {
102       delta /= PUNYCODE_BASE - PUNYCODE_TMIN;
103       k += PUNYCODE_BASE;
104     }
105
106   return k + ((PUNYCODE_BASE - PUNYCODE_TMIN + 1) * delta /
107               (delta + PUNYCODE_SKEW));
108 }
109
110 /* Punycode encoder, RFC 3492 section 6.3. The algorithm is
111  * sufficiently bizarre that it's not really worth trying to explain
112  * here.
113  */
114 static gboolean
115 punycode_encode (const gchar *input_utf8,
116                  gsize        input_utf8_length,
117                  GString     *output)
118 {
119   guint delta, handled_chars, num_basic_chars, bias, j, q, k, t, digit;
120   gunichar n, m, *input;
121   glong input_length;
122   gboolean success = FALSE;
123
124   /* Convert from UTF-8 to Unicode code points */
125   input = g_utf8_to_ucs4 (input_utf8, input_utf8_length, NULL,
126                           &input_length, NULL);
127   if (!input)
128     return FALSE;
129
130   /* Copy basic chars */
131   for (j = num_basic_chars = 0; j < input_length; j++)
132     {
133       if (PUNYCODE_IS_BASIC (input[j]))
134         {
135           g_string_append_c (output, g_ascii_tolower (input[j]));
136           num_basic_chars++;
137         }
138     }
139   if (num_basic_chars)
140     g_string_append_c (output, '-');
141
142   handled_chars = num_basic_chars;
143
144   /* Encode non-basic chars */
145   delta = 0;
146   bias = PUNYCODE_INITIAL_BIAS;
147   n = PUNYCODE_INITIAL_N;
148   while (handled_chars < input_length)
149     {
150       /* let m = the minimum {non-basic} code point >= n in the input */
151       for (m = G_MAXUINT, j = 0; j < input_length; j++)
152         {
153           if (input[j] >= n && input[j] < m)
154             m = input[j];
155         }
156
157       if (m - n > (G_MAXUINT - delta) / (handled_chars + 1))
158         goto fail;
159       delta += (m - n) * (handled_chars + 1);
160       n = m;
161
162       for (j = 0; j < input_length; j++)
163         {
164           if (input[j] < n)
165             {
166               if (++delta == 0)
167                 goto fail;
168             }
169           else if (input[j] == n)
170             {
171               q = delta;
172               for (k = PUNYCODE_BASE; ; k += PUNYCODE_BASE)
173                 {
174                   if (k <= bias)
175                     t = PUNYCODE_TMIN;
176                   else if (k >= bias + PUNYCODE_TMAX)
177                     t = PUNYCODE_TMAX;
178                   else
179                     t = k - bias;
180                   if (q < t)
181                     break;
182                   digit = t + (q - t) % (PUNYCODE_BASE - t);
183                   g_string_append_c (output, encode_digit (digit));
184                   q = (q - t) / (PUNYCODE_BASE - t);
185                 }
186
187               g_string_append_c (output, encode_digit (q));
188               bias = adapt (delta, handled_chars + 1, handled_chars == num_basic_chars);
189               delta = 0;
190               handled_chars++;
191             }
192         }
193
194       delta++;
195       n++;
196     }
197
198   success = TRUE;
199
200  fail:
201   g_free (input);
202   return success;
203 }
204
205 /* From RFC 3454, Table B.1 */
206 #define idna_is_junk(ch) ((ch) == 0x00AD || (ch) == 0x1806 || (ch) == 0x200B || (ch) == 0x2060 || (ch) == 0xFEFF || (ch) == 0x034F || (ch) == 0x180B || (ch) == 0x180C || (ch) == 0x180D || (ch) == 0x200C || (ch) == 0x200D || ((ch) >= 0xFE00 && (ch) <= 0xFE0F))
207
208 /* Scan @str for "junk" and return a cleaned-up string if any junk
209  * is found. Else return %NULL.
210  */
211 static gchar *
212 remove_junk (const gchar *str,
213              gint         len)
214 {
215   GString *cleaned = NULL;
216   const gchar *p;
217   gunichar ch;
218
219   for (p = str; len == -1 ? *p : p < str + len; p = g_utf8_next_char (p))
220     {
221       ch = g_utf8_get_char (p);
222       if (idna_is_junk (ch))
223         {
224           if (!cleaned)
225             {
226               cleaned = g_string_new (NULL);
227               g_string_append_len (cleaned, str, p - str);
228             }
229         }
230       else if (cleaned)
231         g_string_append_unichar (cleaned, ch);
232     }
233
234   if (cleaned)
235     return g_string_free (cleaned, FALSE);
236   else
237     return NULL;
238 }
239
240 static inline gboolean
241 contains_uppercase_letters (const gchar *str,
242                             gint         len)
243 {
244   const gchar *p;
245
246   for (p = str; len == -1 ? *p : p < str + len; p = g_utf8_next_char (p))
247     {
248       if (g_unichar_isupper (g_utf8_get_char (p)))
249         return TRUE;
250     }
251   return FALSE;
252 }
253
254 static inline gboolean
255 contains_non_ascii (const gchar *str,
256                     gint         len)
257 {
258   const gchar *p;
259
260   for (p = str; len == -1 ? *p : p < str + len; p++)
261     {
262       if ((guchar)*p > 0x80)
263         return TRUE;
264     }
265   return FALSE;
266 }
267
268 /* RFC 3454, Appendix C. ish. */
269 static inline gboolean
270 idna_is_prohibited (gunichar ch)
271 {
272   switch (g_unichar_type (ch))
273     {
274     case G_UNICODE_CONTROL:
275     case G_UNICODE_FORMAT:
276     case G_UNICODE_UNASSIGNED:
277     case G_UNICODE_PRIVATE_USE:
278     case G_UNICODE_SURROGATE:
279     case G_UNICODE_LINE_SEPARATOR:
280     case G_UNICODE_PARAGRAPH_SEPARATOR:
281     case G_UNICODE_SPACE_SEPARATOR:
282       return TRUE;
283
284     case G_UNICODE_OTHER_SYMBOL:
285       if (ch == 0xFFFC || ch == 0xFFFD ||
286           (ch >= 0x2FF0 && ch <= 0x2FFB))
287         return TRUE;
288       return FALSE;
289
290     case G_UNICODE_NON_SPACING_MARK:
291       if (ch == 0x0340 || ch == 0x0341)
292         return TRUE;
293       return FALSE;
294
295     default:
296       return FALSE;
297     }
298 }
299
300 /* RFC 3491 IDN cleanup algorithm. */
301 static gchar *
302 nameprep (const gchar *hostname,
303           gint         len)
304 {
305   gchar *name, *tmp = NULL, *p;
306
307   /* It would be nice if we could do this without repeatedly
308    * allocating strings and converting back and forth between
309    * gunichars and UTF-8... The code does at least avoid doing most of
310    * the sub-operations when they would just be equivalent to a
311    * g_strdup().
312    */
313
314   /* Remove presentation-only characters */
315   name = remove_junk (hostname, len);
316   if (name)
317     {
318       tmp = name;
319       len = -1;
320     }
321   else
322     name = (gchar *)hostname;
323
324   /* Convert to lowercase */
325   if (contains_uppercase_letters (name, len))
326     {
327       name = g_utf8_strdown (name, len);
328       g_free (tmp);
329       tmp = name;
330       len = -1;
331     }
332
333   /* If there are no UTF8 characters, we're done. */
334   if (!contains_non_ascii (name, len))
335     {
336       if (name == (gchar *)hostname)
337         return len == -1 ? g_strdup (hostname) : g_strndup (hostname, len);
338       else
339         return name;
340     }
341
342   /* Normalize */
343   name = g_utf8_normalize (name, len, G_NORMALIZE_NFKC);
344   g_free (tmp);
345   tmp = name;
346
347   /* KC normalization may have created more capital letters (eg,
348    * angstrom -> capital A with ring). So we have to lowercasify a
349    * second time. (This is more-or-less how the nameprep algorithm
350    * does it. If tolower(nfkc(tolower(X))) is guaranteed to be the
351    * same as tolower(nfkc(X)), then we could skip the first tolower,
352    * but I'm not sure it is.)
353    */
354   if (contains_uppercase_letters (name, -1))
355     {
356       name = g_utf8_strdown (name, -1);
357       g_free (tmp);
358       tmp = name;
359     }
360
361   /* Check for prohibited characters */
362   for (p = name; *p; p = g_utf8_next_char (p))
363     {
364       if (idna_is_prohibited (g_utf8_get_char (p)))
365         {
366           name = NULL;
367           g_free (tmp);
368           goto done;
369         }
370     }
371
372   /* FIXME: We're supposed to verify certain constraints on bidi
373    * characters, but glib does not appear to have that information.
374    */
375
376  done:
377   return name;
378 }
379
380 /**
381  * g_hostname_to_ascii:
382  * @hostname: a valid UTF-8 or ASCII hostname
383  *
384  * Converts @hostname to its canonical ASCII form; an ASCII-only
385  * string containing no uppercase letters and not ending with a
386  * trailing dot.
387  *
388  * Return value: an ASCII hostname, which must be freed, or %NULL if
389  * @hostname is in some way invalid.
390  *
391  * Since: 2.22
392  **/
393 gchar *
394 g_hostname_to_ascii (const gchar *hostname)
395 {
396   gchar *name, *label, *p;
397   GString *out;
398   gssize llen, oldlen;
399   gboolean unicode;
400
401   out = g_string_new (NULL);
402   label = name = nameprep (hostname, -1);
403
404   do
405     {
406       unicode = FALSE;
407       for (p = label; *p && *p != '.'; p++)
408         {
409           if ((guchar)*p > 0x80)
410             unicode = TRUE;
411         }
412
413       oldlen = out->len;
414       llen = p - label;
415       if (unicode)
416         {
417           if (!strncmp (label, IDNA_ACE_PREFIX, IDNA_ACE_PREFIX_LEN))
418             goto fail;
419
420           g_string_append (out, IDNA_ACE_PREFIX);
421           if (!punycode_encode (label, llen, out))
422             goto fail;
423         }
424       else
425         g_string_append_len (out, label, llen);
426
427       if (out->len - oldlen > 63)
428         goto fail;
429
430       label += llen;
431       if (*label && *++label)
432         g_string_append_c (out, '.');
433     }
434   while (*label);
435
436   g_free (name);
437   return g_string_free (out, FALSE);
438
439  fail:
440   g_free (name);
441   g_string_free (out, TRUE);
442   return NULL;
443 }
444
445 /**
446  * g_hostname_is_non_ascii:
447  * @hostname: a hostname
448  *
449  * Tests if @hostname contains Unicode characters. If this returns
450  * %TRUE, you need to encode the hostname with g_hostname_to_ascii()
451  * before using it in non-IDN-aware contexts.
452  *
453  * Note that a hostname might contain a mix of encoded and unencoded
454  * segments, and so it is possible for g_hostname_is_non_ascii() and
455  * g_hostname_is_ascii_encoded() to both return %TRUE for a name.
456  *
457  * Return value: %TRUE if @hostname contains any non-ASCII characters
458  *
459  * Since: 2.22
460  **/
461 gboolean
462 g_hostname_is_non_ascii (const gchar *hostname)
463 {
464   return contains_non_ascii (hostname, -1);
465 }
466
467 /* Punycode decoder, RFC 3492 section 6.2. As with punycode_encode(),
468  * read the RFC if you want to understand what this is actually doing.
469  */
470 static gboolean
471 punycode_decode (const gchar *input,
472                  gsize        input_length,
473                  GString     *output)
474 {
475   GArray *output_chars;
476   gunichar n;
477   guint i, bias;
478   guint oldi, w, k, digit, t;
479   const gchar *split;
480
481   n = PUNYCODE_INITIAL_N;
482   i = 0;
483   bias = PUNYCODE_INITIAL_BIAS;
484
485   split = input + input_length - 1;
486   while (split > input && *split != '-')
487     split--;
488   if (split > input)
489     {
490       output_chars = g_array_sized_new (FALSE, FALSE, sizeof (gunichar),
491                                         split - input);
492       input_length -= (split - input) + 1;
493       while (input < split)
494         {
495           gunichar ch = (gunichar)*input++;
496           if (!PUNYCODE_IS_BASIC (ch))
497             goto fail;
498           g_array_append_val (output_chars, ch);
499         }
500       input++;
501     }
502   else
503     output_chars = g_array_new (FALSE, FALSE, sizeof (gunichar));
504
505   while (input_length)
506     {
507       oldi = i;
508       w = 1;
509       for (k = PUNYCODE_BASE; ; k += PUNYCODE_BASE)
510         {
511           if (!input_length--)
512             goto fail;
513           digit = decode_digit (*input++);
514           if (digit >= PUNYCODE_BASE)
515             goto fail;
516           if (digit > (G_MAXUINT - i) / w)
517             goto fail;
518           i += digit * w;
519           if (k <= bias)
520             t = PUNYCODE_TMIN;
521           else if (k >= bias + PUNYCODE_TMAX)
522             t = PUNYCODE_TMAX;
523           else
524             t = k - bias;
525           if (digit < t)
526             break;
527           if (w > G_MAXUINT / (PUNYCODE_BASE - t))
528             goto fail;
529           w *= (PUNYCODE_BASE - t);
530         }
531
532       bias = adapt (i - oldi, output_chars->len + 1, oldi == 0);
533
534       if (i / (output_chars->len + 1) > G_MAXUINT - n)
535         goto fail;
536       n += i / (output_chars->len + 1);
537       i %= (output_chars->len + 1);
538
539       g_array_insert_val (output_chars, i++, n);
540     }
541
542   for (i = 0; i < output_chars->len; i++)
543     g_string_append_unichar (output, g_array_index (output_chars, gunichar, i));
544   g_array_free (output_chars, TRUE);
545   return TRUE;
546
547  fail:
548   g_array_free (output_chars, TRUE);
549   return FALSE;
550 }
551
552 /**
553  * g_hostname_to_unicode:
554  * @hostname: a valid UTF-8 or ASCII hostname
555  *
556  * Converts @hostname to its canonical presentation form; a UTF-8
557  * string in Unicode normalization form C, containing no uppercase
558  * letters, no forbidden characters, and no ASCII-encoded segments,
559  * and not ending with a trailing dot.
560  *
561  * Of course if @hostname is not an internationalized hostname, then
562  * the canonical presentation form will be entirely ASCII.
563  *
564  * Return value: a UTF-8 hostname, which must be freed, or %NULL if
565  * @hostname is in some way invalid.
566  *
567  * Since: 2.22
568  **/
569 gchar *
570 g_hostname_to_unicode (const gchar *hostname)
571 {
572   GString *out;
573   gssize llen;
574
575   out = g_string_new (NULL);
576
577   do
578     {
579       llen = strcspn (hostname, ".");
580       if (!g_ascii_strncasecmp (hostname, IDNA_ACE_PREFIX, IDNA_ACE_PREFIX_LEN))
581         {
582           hostname += IDNA_ACE_PREFIX_LEN;
583           llen -= IDNA_ACE_PREFIX_LEN;
584           if (!punycode_decode (hostname, llen, out))
585             {
586               g_string_free (out, TRUE);
587               return NULL;
588             }
589         }
590       else
591         {
592           gchar *canonicalized = nameprep (hostname, llen);
593
594           g_string_append (out, canonicalized);
595           g_free (canonicalized);
596         }
597
598       hostname += llen;
599       if (*hostname && *++hostname)
600         g_string_append_c (out, '.');
601     }
602   while (*hostname);
603
604   return g_string_free (out, FALSE);
605 }
606
607 /**
608  * g_hostname_is_ascii_encoded:
609  * @hostname: a hostname
610  *
611  * Tests if @hostname contains segments with an ASCII-compatible
612  * encoding of an Internationalized Domain Name. If this returns
613  * %TRUE, you should decode the hostname with g_hostname_to_unicode()
614  * before displaying it to the user.
615  *
616  * Note that a hostname might contain a mix of encoded and unencoded
617  * segments, and so it is possible for g_hostname_is_non_ascii() and
618  * g_hostname_is_ascii_encoded() to both return %TRUE for a name.
619  *
620  * Return value: %TRUE if @hostname contains any ASCII-encoded
621  * segments.
622  *
623  * Since: 2.22
624  **/
625 gboolean
626 g_hostname_is_ascii_encoded (const gchar *hostname)
627 {
628   while (1)
629     {
630       if (!g_ascii_strncasecmp (hostname, IDNA_ACE_PREFIX, IDNA_ACE_PREFIX_LEN))
631         return TRUE;
632       hostname = strchr (hostname, '.');
633       if (!hostname++)
634         return FALSE;
635     }
636 }
637
638 /**
639  * g_hostname_is_ip_address:
640  * @hostname: a hostname (or IP address in string form)
641  *
642  * Tests if @hostname is the string form of an IPv4 or IPv6 address.
643  * (Eg, "192.168.0.1".)
644  *
645  * Return value: %TRUE if @hostname is an IP address
646  *
647  * Since: 2.22
648  **/
649 gboolean
650 g_hostname_is_ip_address (const gchar *hostname)
651 {
652   gchar *p, *end;
653   gint nsegments, octet;
654
655   /* On Linux we could implement this using inet_pton, but the Windows
656    * equivalent of that requires linking against winsock, so we just
657    * figure this out ourselves. Tested by tests/hostutils.c.
658    */
659
660   p = (char *)hostname;
661
662   if (strchr (p, ':'))
663     {
664       gboolean skipped;
665
666       /* If it contains a ':', it's an IPv6 address (assuming it's an
667        * IP address at all). This consists of eight ':'-separated
668        * segments, each containing a 1-4 digit hex number, except that
669        * optionally: (a) the last two segments can be replaced by an
670        * IPv4 address, and (b) a single span of 1 to 8 "0000" segments
671        * can be replaced with just "::".
672        */
673
674       nsegments = 0;
675       skipped = FALSE;
676       while (*p && nsegments < 8)
677         {
678           /* Each segment after the first must be preceded by a ':'.
679            * (We also handle half of the "string starts with ::" case
680            * here.)
681            */
682           if (p != (char *)hostname || (p[0] == ':' && p[1] == ':'))
683             {
684               if (*p != ':')
685                 return FALSE;
686               p++;
687             }
688
689           /* If there's another ':', it means we're skipping some segments */
690           if (*p == ':' && !skipped)
691             {
692               skipped = TRUE;
693               nsegments++;
694
695               /* Handle the "string ends with ::" case */
696               if (!p[1])
697                 p++;
698
699               continue;
700             }
701
702           /* Read the segment, make sure it's valid. */
703           for (end = p; g_ascii_isxdigit (*end); end++)
704             ;
705           if (end == p || end > p + 4)
706             return FALSE;
707
708           if (*end == '.')
709             {
710               if ((nsegments == 6 && !skipped) || (nsegments <= 6 && skipped))
711                 goto parse_ipv4;
712               else
713                 return FALSE;
714             }
715
716           nsegments++;
717           p = end;
718         }
719
720       return !*p && (nsegments == 8 || skipped);
721     }
722
723  parse_ipv4:
724
725   /* Parse IPv4: N.N.N.N, where each N <= 255 and doesn't have leading 0s. */
726   for (nsegments = 0; nsegments < 4; nsegments++)
727     {
728       if (nsegments != 0)
729         {
730           if (*p != '.')
731             return FALSE;
732           p++;
733         }
734
735       /* Check the segment; a little tricker than the IPv6 case since
736        * we can't allow extra leading 0s, and we can't assume that all
737        * strings of valid length are within range.
738        */
739       octet = 0;
740       if (*p == '0')
741         end = p + 1;
742       else
743         {
744           for (end = p; g_ascii_isdigit (*end); end++)
745             octet = 10 * octet + (*end - '0');
746         }
747       if (end == p || end > p + 3 || octet > 255)
748         return FALSE;
749
750       p = end;
751     }
752
753   /* If there's nothing left to parse, then it's ok. */
754   return !*p;
755 }
756
757 #define __G_HOST_UTILS_C__
758 #include "galiasdef.c"