The first difference between FreeBSD and tzcode localtime.c that I'd like to address is that FreeBSD is more cautious about handling outlandish TZ settings like "../foo". It seems to me that tzcode should largely mimic FreeBSD's extra caution. In the long run I'd like tzcode localtime.c to be byte-for-byte identical to FreeBSD localtime.c but it's better to do this one step at a time and this security caution is a good first step. I noticed some minor issues with the FreeBSD implementation of this extra checking, so I propose implementing it in a somewhat different way in tzcode. I'm attaching proposed patches to do that, and have installed them in the tzcode development repository on GitHub. Here are issues I noticed: * With an environment variable setting like TZ="/usr/share/zoneinfo/America/Los_Angeles", in a privileged program FreeBSD first opens the directory /usr/share/zoneinfo to get a directory file descriptor, and then uses fstatat and openat, both with AT_RESOLVE_BENEATH. However, it passes the full name to fstatat which must be a typo; I can't see how that would work reliably for a setuid program, even though the neighboring code suggests it was intended to work. I assume it was intended to pass a relative name to fstatat. * As near as I can make out, in privileged programs FreeBSD rejects adjacent slashes in settings like TZ="/usr/share/zoneinfo//America/Los_Angeles", where there are two slashes after "zoneinfo". It would be nicer to treat those two slashes as if they were one, as the kernel does. * tzcode is intended to be portable to platforms lacking openat and AT_RESOLVE_BENEATH, so for now the attached patches mimic FreeBSD's extra checking without using these two features. There are efficiency motivations for using the two features if available, but I'd like to defer that to a later patchset. * Although FreeBSD takes some steps to treat TZ settings the same regardless of whether they come from the TZ environment variable, it doesn't take this idea to its logical conclusion. It seems to me that it's better to not care where the TZ setting came from, as that's easier to document, understand, and maintain, so the attached patches do that. * FreeBSD uses issetugid, which is not universally available. The attached patches work around this by supplying an issetugid substitute for platforms like GNU/Linux that lack it. The first attached patch is a minor indenting fixup. The second one is a minor efficiency improvement, to use strnlen instead of strlen when that improves asymptotic efficiency. The third patch adopts FreeBSD's idea of treating a TZ setting starting with "/usr/share/zoneinfo/" as if it lacked that prefix. And the fourth and main patch changes the tzcode security checks as described above. These tzcode patches do not address other differences between tzcode and FreeBSD, such as the multithreading differences or the check-for-changes differences. These can wait for later patchsets. Comments and suggestions are welcome as usual.