Blame SOURCES/0001-Fix-timestamp-handling-in-MDTM.patch

f22e83
From 6a4dc470e569df38b8a7ea09ee6aace3c73b7353 Mon Sep 17 00:00:00 2001
f22e83
From: =?UTF-8?q?Ond=C5=99ej=20Lyson=C4=9Bk?= <olysonek@redhat.com>
f22e83
Date: Wed, 28 Mar 2018 09:06:34 +0200
f22e83
Subject: [PATCH 1/2] Fix timestamp handling in MDTM
f22e83
f22e83
There were two problems with the timestamp handling with MDTM:
f22e83
f22e83
1. In vsf_sysutil_parse_time(), the `the_time.tm_isdst` attribute was
f22e83
   always set to 0, regardless of whether DST (daylight saving time)
f22e83
   is active on the given date or not.
f22e83
f22e83
   This made glibc shift the timestamp when DST was in fact active on
f22e83
   the given date, in an attempt to correct the discrepancy between
f22e83
   the given timestamp and the `tm_isdst` attribute. The shifting
f22e83
   produced incorrect results however.
f22e83
f22e83
   We fix this by setting `tm_isdst` to -1 to let glibc decide if DST
f22e83
   is active or not at the time of the timestamp. glibc won't touch
f22e83
   the timestamp then.
f22e83
f22e83
2. vsftpd used to record the offset from UTC of the current timezone
f22e83
   in the global variable `s_timezone`. This variable was then
f22e83
   subtracted from the variable `the_time` in vsf_sysutil_setmodtime()
f22e83
   when the config option use_localtime=NO was set. This was done to
f22e83
   compensate for the fact that mktime(), used in
f22e83
   vsf_sysutil_parse_time(), expects a timestamp expressed as local
f22e83
   time, whereas vsftpd is dealing with universal time.
f22e83
f22e83
   However, this did not work in the case when the offset stored in
f22e83
   `s_timezone` did not match the timezone of the timestamp given to
f22e83
   mktime() - this happens when DST is active at the current time, but
f22e83
   DST is not active at the time of the timestamp, or vice versa.
f22e83
f22e83
   We fix this by subtracting the real timezone offset directly in
f22e83
   vsf_sysutil_parse_time().
f22e83
f22e83
   Note that the `tm_gmtoff` attribute, used in this fix, is a
f22e83
   BSD/glic extension. However, using `tm_gmtoff` seems like the
f22e83
   simplest solution and we need to make this work only with glibc
f22e83
   anyway.
f22e83
f22e83
The fix was tested in the following way. We checked that the timestamp
f22e83
given to the MDTM command when setting modification time exactly
f22e83
matches the timestamp received as response from MDTM when reading back
f22e83
the modification time. Additionally, we checked that the modification
f22e83
time was set correctly on the given file on disk.
f22e83
f22e83
These two checks were performed under various conditions - all the
f22e83
combinations of DST/non-DST system time, DST/non-DST modification
f22e83
time, use_localtime=YES/NO.
f22e83
f22e83
Note that (I think) this will still not work if the rules for when DST
f22e83
is active change. For example, if DST is ever completely cancelled in
f22e83
the Europe/Prague timezone, and vsftpd is dealing with a timestamp
f22e83
from a time when DST was active, it will produce incorrect results. I
f22e83
think we would need the full zone file to fix this, but the zone file
f22e83
is hard to provide when we're chroot-ed.
f22e83
f22e83
Resolves: rhbz#1567855
f22e83
---
f22e83
 postlogin.c |  5 +++--
f22e83
 sysutil.c   | 17 ++++++++++-------
f22e83
 sysutil.h   |  4 ++--
f22e83
 3 files changed, 15 insertions(+), 11 deletions(-)
f22e83
f22e83
diff --git a/postlogin.c b/postlogin.c
f22e83
index 7c749ef..8a3d9d2 100644
f22e83
--- a/postlogin.c
f22e83
+++ b/postlogin.c
f22e83
@@ -1788,7 +1788,8 @@ handle_mdtm(struct vsf_session* p_sess)
f22e83
   if (do_write != 0)
f22e83
   {
f22e83
     str_split_char(&p_sess->ftp_arg_str, &s_filename_str, ' ');
f22e83
-    modtime = vsf_sysutil_parse_time(str_getbuf(&p_sess->ftp_arg_str));
f22e83
+    modtime = vsf_sysutil_parse_time(
f22e83
+      str_getbuf(&p_sess->ftp_arg_str), tunable_use_localtime);
f22e83
     str_copy(&p_sess->ftp_arg_str, &s_filename_str);
f22e83
   }
f22e83
   resolve_tilde(&p_sess->ftp_arg_str, p_sess);
f22e83
@@ -1809,7 +1810,7 @@ handle_mdtm(struct vsf_session* p_sess)
f22e83
     else
f22e83
     {
f22e83
       retval = vsf_sysutil_setmodtime(
f22e83
-        str_getbuf(&p_sess->ftp_arg_str), modtime, tunable_use_localtime);
f22e83
+        str_getbuf(&p_sess->ftp_arg_str), modtime);
f22e83
       if (retval != 0)
f22e83
       {
f22e83
         vsf_cmdio_write(p_sess, FTP_FILEFAIL,
f22e83
diff --git a/sysutil.c b/sysutil.c
f22e83
index e847650..66d4c5e 100644
f22e83
--- a/sysutil.c
f22e83
+++ b/sysutil.c
f22e83
@@ -2819,11 +2819,13 @@ vsf_sysutil_syslog(const char* p_text, int severe)
f22e83
 }
f22e83
 
f22e83
 long
f22e83
-vsf_sysutil_parse_time(const char* p_text)
f22e83
+vsf_sysutil_parse_time(const char* p_text, int is_localtime)
f22e83
 {
f22e83
+  long res;
f22e83
   struct tm the_time;
f22e83
   unsigned int len = vsf_sysutil_strlen(p_text);
f22e83
   vsf_sysutil_memclr(&the_time, sizeof(the_time));
f22e83
+  the_time.tm_isdst = -1;
f22e83
   if (len >= 8)
f22e83
   {
f22e83
     char yr[5];
f22e83
@@ -2848,17 +2850,18 @@ vsf_sysutil_parse_time(const char* p_text)
f22e83
     the_time.tm_min = vsf_sysutil_atoi(mins);
f22e83
     the_time.tm_sec = vsf_sysutil_atoi(sec);
f22e83
   }
f22e83
-  return mktime(&the_time);
f22e83
+  res = mktime(&the_time);
f22e83
+  if (!is_localtime)
f22e83
+  {
f22e83
+    res += the_time.tm_gmtoff;
f22e83
+  }
f22e83
+  return res;
f22e83
 }
f22e83
 
f22e83
 int
f22e83
-vsf_sysutil_setmodtime(const char* p_file, long the_time, int is_localtime)
f22e83
+vsf_sysutil_setmodtime(const char* p_file, long the_time)
f22e83
 {
f22e83
   struct utimbuf new_times;
f22e83
-  if (!is_localtime)
f22e83
-  {
f22e83
-    the_time -= s_timezone;
f22e83
-  }
f22e83
   vsf_sysutil_memclr(&new_times, sizeof(new_times));
f22e83
   new_times.actime = the_time;
f22e83
   new_times.modtime = the_time;
f22e83
diff --git a/sysutil.h b/sysutil.h
f22e83
index 7a59f13..b90f6ca 100644
f22e83
--- a/sysutil.h
f22e83
+++ b/sysutil.h
f22e83
@@ -349,9 +349,9 @@ void vsf_sysutil_chroot(const char* p_root_path);
f22e83
  */
f22e83
 long vsf_sysutil_get_time_sec(void);
f22e83
 long vsf_sysutil_get_time_usec(void);
f22e83
-long vsf_sysutil_parse_time(const char* p_text);
f22e83
+long vsf_sysutil_parse_time(const char* p_text, int is_localtime);
f22e83
 void vsf_sysutil_sleep(double seconds);
f22e83
-int vsf_sysutil_setmodtime(const char* p_file, long the_time, int is_localtime);
f22e83
+int vsf_sysutil_setmodtime(const char* p_file, long the_time);
f22e83
 
f22e83
 /* Limits */
f22e83
 void vsf_sysutil_set_address_space_limit(unsigned long bytes);
f22e83
-- 
f22e83
2.24.1
f22e83