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

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