There were two problems with the timestamp handling with MDTM:
1. In vsf_sysutil_parse_time(), the `the_time.tm_isdst` attribute was
always set to 0, regardless of whether DST (daylight saving time)
is active on the given date or not.
This made glibc shift the timestamp when DST was in fact active on
the given date, in an attempt to correct the discrepancy between
the given timestamp and the `tm_isdst` attribute. The shifting
produced incorrect results however.
We fix this by setting `tm_isdst` to -1 to let glibc decide if DST
is active or not at the time of the timestamp. glibc won't touch
the timestamp then.
2. vsftpd used to record the offset from UTC of the current timezone
in the global variable `s_timezone`. This variable was then
subtracted from the variable `the_time` in vsf_sysutil_setmodtime()
when the config option use_localtime=NO was set. This was done to
compensate for the fact that mktime(), used in
vsf_sysutil_parse_time(), expects a timestamp expressed as local
time, whereas vsftpd is dealing with universal time.
However, this did not work in the case when the offset stored in
`s_timezone` did not match the timezone of the timestamp given to
mktime() - this happens when DST is active at the current time, but
DST is not active at the time of the timestamp, or vice versa.
We fix this by subtracting the real timezone offset directly in
vsf_sysutil_parse_time().
Note that the `tm_gmtoff` attribute, used in this fix, is a
BSD/glic extension. However, using `tm_gmtoff` seems like the
simplest solution and we need to make this work only with glibc
anyway.
The fix was tested in the following way. We checked that the timestamp
given to the MDTM command when setting modification time exactly
matches the timestamp received as response from MDTM when reading back
the modification time. Additionally, we checked that the modification
time was set correctly on the given file on disk.
These two checks were performed under various conditions - all the
combinations of DST/non-DST system time, DST/non-DST modification
time, use_localtime=YES/NO.
Note that (I think) this will still not work if the rules for when DST
is active change. For example, if DST is ever completely cancelled in
the Europe/Prague timezone, and vsftpd is dealing with a timestamp
from a time when DST was active, it will produce incorrect results. I
think we would need the full zone file to fix this, but the zone file
is hard to provide when we're chroot-ed.
Resolves: rhbz#1567855
The kVSFSysStrOpenUnknown enumerator is not part of the
EVSFSysUtilOpenMode enum. The assignment causes a build failure with
gcc 10.
The open_mode variable need not be initialized, because the switch
statement either sets the variable or causes us to exit.
Resolves: rhbz#1800239
Since the pututxline() bug rhbz#1749439 is now fixed in glibc in
Fedora and RHEL-8, we can implement a complete solution for the stale
utmp entries issue originally reported as rhbz#1688848.
This patch is a followup to commit 896b3694ca062d7.
Resolves: rhbz#1688852
Resolves: rhbz#1737433
pututxline() is the function that actually inserts the new record, so
setting 's_uwtmp_inserted' before calling pututxline() doesn't make
sense.
We'll need this change for other fixes.
The vsf_sysutil_close() calls need to be moved a bit further so that
die() works properly in case listen() fails.
I see no reason the calls should be placed before listen()
specifically, as they are now. My guess is that the author who added
the calls thought that listen() is a blocking call, which is not the
case. The only thing we need to satisfy is that close() is called
before accept, because that is a blocking call. That's all that is
needed to fix the bug that was fixed by adding the close() calls.
Resolves: rhbz#1666380
When vsftpd is running in a container as PID 1, it is possible
that it will get SIGCHILD for processes, which were not directly
created by it, but by some of its children. These processes will
not be in the s_p_pid_ip_hash hash table, and thus trying to
delete the entry from the hash table in standalone.c:handle_sigchld()
will result in segmentation fault.
I can quite easily reproduce it with the upstream vsftpd and default
configuration, except for isolate=NO and isolate_network=NO being set
(it seems to me that network namespaces take a long time to create
and destroy, which hides the race condition), on a quad-core machine.
When connecting to vsftpd in a loop like this:
$ while true; do echo -en '' | nc localhost 21; done
vsftpd crashes after a couple of seconds.
Pass messages given to die(), die2() and bug() to syslog. Currently this
functionality requires waiting for a short amount of time (1 second is
used) after logging the message and before exiting. This is a workaround
for the following systemd bug:
https://github.com/systemd/systemd/issues/2913
The need for this workaround is the main reason why I decided not to
enable this functionality by default.
Resolves: rhbz#1318198
Resolves: rhbz#1582672
Check the return value of syscalls. There's always the possibility that
they'll fail. (Failure of close() is not handled though, apart from EINTR.
The file is open read-only so it shouldn't fail, and even if it does,
it's not tragic.)
We return NULL in case of syscall failure. One might be tempted to simply
call die() when any kind of error occurs when parsing the timezone data,
but I think it's more in line with the behaviour of tzset(3) not to do
anything drastic in such a case (tzset() will silently use UTC when
the value given in the TZ environment variable is invalid).
Always do chdir("/") after chroot() to be more sure we'll never get out
of it. This will not affect the working directory after calling
vsf_sysutil_chroot(), because in the current state vsftpd always calls
vsf_sysutil_chroot(".").
Send 'AUTH SSL' in reply to the FEAT command when the ssl_tlsv1_1
or ssl_tlsv1_2 configuration option is enabled.
The patch was written by Martin Sehnoutka.
Resolves: rhbz#1432054