Use Gnulib's `inet_ntop' and `inet_pton' modules.
[bpt/guile.git] / lib / localcharset.c
index c3e3937..769a1db 100644 (file)
@@ -1,6 +1,6 @@
 /* Determine a canonical name for the current locale's character encoding.
 
-   Copyright (C) 2000-2006, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2000-2006, 2008-2009 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
 /* Specification.  */
 #include "localcharset.h"
 
+#include <fcntl.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
+#if defined __APPLE__ && defined __MACH__ && HAVE_LANGINFO_CODESET
+# define DARWIN7 /* Darwin 7 or newer, i.e. MacOS X 10.3 or newer */
+#endif
+
 #if defined _WIN32 || defined __WIN32__
 # define WIN32_NATIVE
 #endif
@@ -40,6 +45,7 @@
 #endif
 
 #if !defined WIN32_NATIVE
+# include <unistd.h>
 # if HAVE_LANGINFO_CODESET
 #  include <langinfo.h>
 # else
 # include "configmake.h"
 #endif
 
+/* Define O_NOFOLLOW to 0 on platforms where it does not exist.  */
+#ifndef O_NOFOLLOW
+# define O_NOFOLLOW 0
+#endif
+
 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
   /* Win32, Cygwin, OS/2, DOS */
 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
@@ -112,8 +123,7 @@ get_charset_aliases (void)
   cp = charset_aliases;
   if (cp == NULL)
     {
-#if !(defined VMS || defined WIN32_NATIVE || defined __CYGWIN__)
-      FILE *fp;
+#if !(defined DARWIN7 || defined VMS || defined WIN32_NATIVE || defined __CYGWIN__)
       const char *dir;
       const char *base = "charset.alias";
       char *file_name;
@@ -139,80 +149,141 @@ get_charset_aliases (void)
          }
       }
 
-      if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL)
-       /* Out of memory or file not found, treat it as empty.  */
+      if (file_name == NULL)
+       /* Out of memory.  Treat the file as empty.  */
        cp = "";
       else
        {
-         /* Parse the file's contents.  */
-         char *res_ptr = NULL;
-         size_t res_size = 0;
-
-         for (;;)
+         int fd;
+
+         /* Open the file.  Reject symbolic links on platforms that support
+            O_NOFOLLOW.  This is a security feature.  Without it, an attacker
+            could retrieve parts of the contents (namely, the tail of the
+            first line that starts with "* ") of an arbitrary file by placing
+            a symbolic link to that file under the name "charset.alias" in
+            some writable directory and defining the environment variable
+            CHARSETALIASDIR to point to that directory.  */
+         fd = open (file_name,
+                    O_RDONLY | (HAVE_WORKING_O_NOFOLLOW ? O_NOFOLLOW : 0));
+         if (fd < 0)
+           /* File not found.  Treat it as empty.  */
+           cp = "";
+         else
            {
-             int c;
-             char buf1[50+1];
-             char buf2[50+1];
-             size_t l1, l2;
-             char *old_res_ptr;
-
-             c = getc (fp);
-             if (c == EOF)
-               break;
-             if (c == '\n' || c == ' ' || c == '\t')
-               continue;
-             if (c == '#')
-               {
-                 /* Skip comment, to end of line.  */
-                 do
-                   c = getc (fp);
-                 while (!(c == EOF || c == '\n'));
-                 if (c == EOF)
-                   break;
-                 continue;
-               }
-             ungetc (c, fp);
-             if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
-               break;
-             l1 = strlen (buf1);
-             l2 = strlen (buf2);
-             old_res_ptr = res_ptr;
-             if (res_size == 0)
+             FILE *fp;
+
+             fp = fdopen (fd, "r");
+             if (fp == NULL)
                {
-                 res_size = l1 + 1 + l2 + 1;
-                 res_ptr = (char *) malloc (res_size + 1);
+                 /* Out of memory.  Treat the file as empty.  */
+                 close (fd);
+                 cp = "";
                }
              else
                {
-                 res_size += l1 + 1 + l2 + 1;
-                 res_ptr = (char *) realloc (res_ptr, res_size + 1);
+                 /* Parse the file's contents.  */
+                 char *res_ptr = NULL;
+                 size_t res_size = 0;
+
+                 for (;;)
+                   {
+                     int c;
+                     char buf1[50+1];
+                     char buf2[50+1];
+                     size_t l1, l2;
+                     char *old_res_ptr;
+
+                     c = getc (fp);
+                     if (c == EOF)
+                       break;
+                     if (c == '\n' || c == ' ' || c == '\t')
+                       continue;
+                     if (c == '#')
+                       {
+                         /* Skip comment, to end of line.  */
+                         do
+                           c = getc (fp);
+                         while (!(c == EOF || c == '\n'));
+                         if (c == EOF)
+                           break;
+                         continue;
+                       }
+                     ungetc (c, fp);
+                     if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
+                       break;
+                     l1 = strlen (buf1);
+                     l2 = strlen (buf2);
+                     old_res_ptr = res_ptr;
+                     if (res_size == 0)
+                       {
+                         res_size = l1 + 1 + l2 + 1;
+                         res_ptr = (char *) malloc (res_size + 1);
+                       }
+                     else
+                       {
+                         res_size += l1 + 1 + l2 + 1;
+                         res_ptr = (char *) realloc (res_ptr, res_size + 1);
+                       }
+                     if (res_ptr == NULL)
+                       {
+                         /* Out of memory. */
+                         res_size = 0;
+                         if (old_res_ptr != NULL)
+                           free (old_res_ptr);
+                         break;
+                       }
+                     strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
+                     strcpy (res_ptr + res_size - (l2 + 1), buf2);
+                   }
+                 fclose (fp);
+                 if (res_size == 0)
+                   cp = "";
+                 else
+                   {
+                     *(res_ptr + res_size) = '\0';
+                     cp = res_ptr;
+                   }
                }
-             if (res_ptr == NULL)
-               {
-                 /* Out of memory. */
-                 res_size = 0;
-                 if (old_res_ptr != NULL)
-                   free (old_res_ptr);
-                 break;
-               }
-             strcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1);
-             strcpy (res_ptr + res_size - (l2 + 1), buf2);
            }
-         fclose (fp);
-         if (res_size == 0)
-           cp = "";
-         else
-           {
-             *(res_ptr + res_size) = '\0';
-             cp = res_ptr;
-           }
-       }
 
-      if (file_name != NULL)
-       free (file_name);
+         free (file_name);
+       }
 
 #else
 
+# if defined DARWIN7
+      /* To avoid the trouble of installing a file that is shared by many
+        GNU packages -- many packaging systems have problems with this --,
+        simply inline the aliases here.  */
+      cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
+          "ISO8859-2" "\0" "ISO-8859-2" "\0"
+          "ISO8859-4" "\0" "ISO-8859-4" "\0"
+          "ISO8859-5" "\0" "ISO-8859-5" "\0"
+          "ISO8859-7" "\0" "ISO-8859-7" "\0"
+          "ISO8859-9" "\0" "ISO-8859-9" "\0"
+          "ISO8859-13" "\0" "ISO-8859-13" "\0"
+          "ISO8859-15" "\0" "ISO-8859-15" "\0"
+          "KOI8-R" "\0" "KOI8-R" "\0"
+          "KOI8-U" "\0" "KOI8-U" "\0"
+          "CP866" "\0" "CP866" "\0"
+          "CP949" "\0" "CP949" "\0"
+          "CP1131" "\0" "CP1131" "\0"
+          "CP1251" "\0" "CP1251" "\0"
+          "eucCN" "\0" "GB2312" "\0"
+          "GB2312" "\0" "GB2312" "\0"
+          "eucJP" "\0" "EUC-JP" "\0"
+          "eucKR" "\0" "EUC-KR" "\0"
+          "Big5" "\0" "BIG5" "\0"
+          "Big5HKSCS" "\0" "BIG5-HKSCS" "\0"
+          "GBK" "\0" "GBK" "\0"
+          "GB18030" "\0" "GB18030" "\0"
+          "SJIS" "\0" "SHIFT_JIS" "\0"
+          "ARMSCII-8" "\0" "ARMSCII-8" "\0"
+          "PT154" "\0" "PT154" "\0"
+        /*"ISCII-DEV" "\0" "?" "\0"*/
+          "*" "\0" "UTF-8" "\0";
+# endif
+
 # if defined VMS
       /* To avoid the troubles of an extra file charset.alias_vms in the
         sources of many GNU packages, simply inline the aliases here.  */