-/* $OpenBSD: localtime.c,v 1.64 2022/09/23 17:29:22 millert Exp $ */
+/* $OpenBSD: localtime.c,v 1.65 2022/10/03 15:34:39 millert Exp $ */
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.
}
static int
-tzload(const char *name, struct state *sp, int doextend)
+tzpath_ok(const char *name)
{
- const char * p;
- int i;
- int fid;
- int stored;
- int nread;
- typedef union {
- struct tzhead tzhead;
- char buf[2 * sizeof(struct tzhead) +
- 2 * sizeof *sp +
- 4 * TZ_MAX_TIMES];
- } u_t;
- u_t * up;
- char fullname[PATH_MAX];
+ /* Reject absolute paths that don't start with TZDIR. */
+ if (name[0] == '/' && (strncmp(name, TZDIR, sizeof(TZDIR) - 1) != 0 ||
+ name[sizeof(TZDIR) - 1] != '/'))
+ return 0;
- up = calloc(1, sizeof *up);
- if (up == NULL)
- return -1;
+ /* Reject paths that contain "../". */
+ if (strstr(name, "../") != NULL)
+ return 0;
- sp->goback = sp->goahead = FALSE;
+ return 1;
+}
+
+static int
+open_tzfile(const char *name)
+{
+ char fullname[PATH_MAX];
+ int i;
if (name != NULL) {
/*
*/
if (name[0] == ':')
name++;
- /* Ignore absolute paths or names that contain "../". */
- if (name[0] == '/' || strstr(name, "../") != NULL)
+
+ /*
+ * Ignore absolute paths that don't start with TZDIR
+ * or that contain "../".
+ */
+ if (!tzpath_ok(name))
name = NULL;
}
+
if (name == NULL) {
name = TZDEFAULT;
- } else {
+ } else if (name[0] != '/') {
/* Time zone data path is relative to TZDIR. */
i = snprintf(fullname, sizeof(fullname), "%s/%s", TZDIR, name);
if (i < 0 || i >= sizeof(fullname)) {
errno = ENAMETOOLONG;
- goto oops;
+ return -1;
}
name = fullname;
}
- if ((fid = open(name, O_RDONLY)) == -1) {
+
+ return open(name, O_RDONLY);
+}
+
+static int
+tzload(const char *name, struct state *sp, int doextend)
+{
+ const char * p;
+ int i;
+ int fid;
+ int stored;
+ int nread;
+ typedef union {
+ struct tzhead tzhead;
+ char buf[2 * sizeof(struct tzhead) +
+ 2 * sizeof *sp +
+ 4 * TZ_MAX_TIMES];
+ } u_t;
+ u_t * up;
+
+ up = calloc(1, sizeof *up);
+ if (up == NULL)
+ return -1;
+
+ sp->goback = sp->goahead = FALSE;
+
+ if ((fid = open_tzfile(name)) == -1) {
/* Could be a POSIX section 8-style TZ string. */
goto oops;
}