-/* 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
#include <time.h>
#include <string.h>
#include <limits.h>
+#include <unistd.h>
#define NOID
#include <tzfile.h>
long int change; /* Seconds of correction to apply. */
};
-static struct ttinfo *find_transition (time_t timer);
-static void compute_tzname_max (size_t);
+extern char * __tzstring (const char *); /* Defined in tzset.c. */
+
+static struct ttinfo *find_transition (time_t timer) internal_function;
+static void compute_tzname_max (size_t) internal_function;
static size_t num_transitions;
static time_t *transitions = NULL;
void
__tzfile_read (const char *file)
{
+ static const char default_tzdir[] = TZDIR;
size_t num_isstd, num_isgmt;
register FILE *f;
struct tzhead tzhead;
/* No user specification; use the site-wide default. */
file = TZDEFAULT;
else if (*file == '\0')
- /* User specified the empty string; use UTC explicitly. */
- file = "Universal";
+ /* User specified the empty string; use UTC with no leap seconds. */
+ return;
+ else
+ {
+ /* We must not allow to read an arbitrary file in a setuid
+ program. So we fail for any file which is not in the
+ directory hierachy starting at TZDIR
+ and which is not the system wide default TZDEFAULT. */
+ if (__libc_enable_secure
+ && ((*file == '/'
+ && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
+ && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
+ || strstr (file, "../") != NULL))
+ /* This test is certainly a bit too restrictive but it should
+ catch all critical cases. */
+ return;
+ }
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);
+ 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;
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
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);
}
for (i = 0; i < num_isstd; ++i)
{
- char c = getc (f);
+ int c = getc (f);
if (c == EOF)
goto lose;
types[i].isstd = c != 0;
for (i = 0; i < num_isgmt; ++i)
{
- char c = getc (f);
+ int c = getc (f);
if (c == EOF)
goto lose;
types[i].isgmt = c != 0;
info = find_transition (0);
for (i = 0; i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
++i)
- __tzname[types[i].isdst] = &zone_names[types[i].idx];
+ __tzname[types[i].isdst] = __tzstring (&zone_names[types[i].idx]);
if (info->isdst < sizeof (__tzname) / sizeof (__tzname[0]))
- __tzname[info->isdst] = &zone_names[info->idx];
+ __tzname[info->isdst] = __tzstring (&zone_names[info->idx]);
compute_tzname_max (chars);
from the TZDEFRULES file. */
void
-__tzfile_default (char *std, char *dst, long int stdoff, long int dstoff)
+__tzfile_default (const char *std, const char *dst,
+ long int stdoff, long int dstoff)
{
size_t stdlen, dstlen, i;
long int rule_offset, rule_stdoff, rule_dstoff;
types[1].offset = dstoff;
types[1].isdst = 1;
+ /* Reset the zone names to point to the user's names. */
+ __tzname[0] = (char *) std;
+ __tzname[1] = (char *) dst;
+
compute_tzname_max (stdlen + dstlen);
}
\f
static struct ttinfo *
+internal_function
find_transition (time_t timer)
{
size_t i;
}
\f
int
-__tzfile_compute (time_t timer, long int *leap_correct, int *leap_hit)
+__tzfile_compute (time_t timer, int use_localtime,
+ long int *leap_correct, int *leap_hit)
{
- struct ttinfo *info;
register size_t i;
- info = find_transition (timer);
- __daylight = info->isdst;
- __timezone = info->offset;
- for (i = 0; i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
- ++i)
- __tzname[types[i].isdst] = &zone_names[types[i].idx];
- if (info->isdst < sizeof (__tzname) / sizeof (__tzname[0]))
- __tzname[info->isdst] = &zone_names[info->idx];
+ if (use_localtime)
+ {
+ struct ttinfo *info = find_transition (timer);
+ __daylight = info->isdst;
+ __timezone = info->offset;
+ for (i = 0;
+ i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
+ ++i)
+ __tzname[types[i].isdst] = &zone_names[types[i].idx];
+ if (info->isdst < sizeof (__tzname) / sizeof (__tzname[0]))
+ __tzname[info->isdst] = &zone_names[info->idx];
+ }
*leap_correct = 0L;
*leap_hit = 0;
return 1;
}
\f
-void
+static void
+internal_function
compute_tzname_max (size_t chars)
{
- extern size_t __tzname_cur_max; /* Defined in __tzset.c. */
+ extern size_t __tzname_cur_max; /* Defined in tzset.c. */
const char *p;
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]);
}