about summary refs log tree commit diff
path: root/time/tzfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'time/tzfile.c')
-rw-r--r--time/tzfile.c42
1 files changed, 33 insertions, 9 deletions
diff --git a/time/tzfile.c b/time/tzfile.c
index d80789d570..761ddc9539 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 92, 93, 95, 96 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 92, 93, 95, 96, 97 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -113,16 +113,28 @@ __tzfile_read (const char *file)
 
   if (*file != '/')
     {
-      static const char tzdir[] = TZDIR;
-      register const unsigned int len = strlen (file) + 1;
-      char *new = (char *) __alloca (sizeof (tzdir) + len);
-      memcpy (new, tzdir, sizeof(tzdir) - 1);
-      new[sizeof (tzdir) - 1] = '/';
-      memcpy (&new[sizeof (tzdir)], file, len);
+      static const char default_tzdir[] = TZDIR;
+      const char *tzdir;
+      unsigned int len, tzdir_len;
+      char *new;
+
+      tzdir = __secure_getenv ("TZDIR");
+      if (tzdir == NULL || *tzdir == '\0')
+	{
+	  tzdir = default_tzdir;
+	  tzdir_len = sizeof (default_tzdir) - 1;
+	}
+      else
+	tzdir_len = strlen (tzdir);
+      len = strlen (file) + 1;
+      new = (char *) __alloca (tzdir_len + 1 + len);
+      memcpy (new, tzdir, tzdir_len);
+      new[tzdir_len] = '/';
+      memcpy (&new[tzdir_len + 1], file, len);
       file = new;
     }
 
-  f = fopen(file, "r");
+  f = fopen (file, "r");
   if (f == NULL)
     return;
 
@@ -171,6 +183,12 @@ __tzfile_read (const char *file)
       fread(type_idxs, 1, num_transitions, f) != num_transitions)
     goto lose;
 
+  /* Check for bogus indices in the data file, so we can hereafter
+     safely use type_idxs[T] as indices into `types' and never crash.  */
+  for (i = 0; i < num_transitions; ++i)
+    if (type_idxs[i] >= num_types)
+      goto lose;
+
   if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4)
     {
       /* Decode the transition times, stored as 4-byte integers in
@@ -189,6 +207,8 @@ __tzfile_read (const char *file)
 	  fread (&types[i].isdst, 1, 1, f) != 1 ||
 	  fread (&types[i].idx, 1, 1, f) != 1)
 	goto lose;
+      if (types[i].idx >= chars) /* Bogus index in data file.  */
+	goto lose;
       types[i].offset = (long int) decode (x);
     }
 
@@ -335,6 +355,10 @@ __tzfile_default (char *std, char *dst, long int stdoff, long int dstoff)
   types[1].offset = dstoff;
   types[1].isdst = 1;
 
+  /* Reset the zone names to point to the user's names.  */
+  __tzname[0] = &zone_names[0];
+  __tzname[1] = &zone_names[stdlen];
+
   compute_tzname_max (stdlen + dstlen);
 }
 
@@ -425,7 +449,7 @@ compute_tzname_max (size_t chars)
       const char *start = p;
       while (*p != '\0')
 	++p;
-      if (p - start > __tzname_cur_max)
+      if ((size_t) (p - start) > __tzname_cur_max)
 	__tzname_cur_max = p - start;
     } while (++p < &zone_names[chars]);
 }