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