From 1bb93f70de9907d88b2ebc5c6ffee14417d90fee Mon Sep 17 00:00:00 2001 From: Anton Bobrov Date: Mon, 19 Sep 2022 17:51:07 +0200 Subject: [PATCH] SUDO: Fix timezone issues with sudoNotBefore and sudoNotAfter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code does not respect generalized time as specified in related before/after attributes. The problem with the current implementation is that it essentially treats them as local time, with no regard to TZ and DST. This patch is using timegm(3) instead of mktime(3) to address said timezone issues and some bare minimum static unit tests with known verified values to make sure the API is consitent with them. Resolves: https://github.com/SSSD/sssd/issues/6354 Reviewed-by: Iker Pedrosa Reviewed-by: Pavel Březina (cherry picked from commit 0198f64ce231e9608b14152c64426fb9e015fd33) --- configure.ac | 3 +++ src/db/sysdb_sudo.c | 11 ++++++++++- src/tests/cmocka/test_sysdb_sudo.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 89abddef4..a90e16642 100644 --- a/configure.ac +++ b/configure.ac @@ -92,6 +92,9 @@ LIBS=$SAVE_LIBS AC_CHECK_FUNCS([ utimensat \ futimens ]) +# Check for the timegm() function (not part of POSIX / Open Group specs) +AC_CHECK_FUNC([timegm], [], [AC_MSG_ERROR([timegm() function not found])]) + #Check for endian headers AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h]) diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c index 59d6824c0..3a918e9c6 100644 --- a/src/db/sysdb_sudo.c +++ b/src/db/sysdb_sudo.c @@ -60,9 +60,18 @@ static errno_t sysdb_sudo_convert_time(const char *str, time_t *unix_time) for (format = formats; *format != NULL; format++) { /* strptime() may leave some fields uninitialized */ memset(&tm, 0, sizeof(struct tm)); + /* Let underlying implementation figure out DST */ + tm.tm_isdst = -1; tret = strptime(str, *format, &tm); if (tret != NULL && *tret == '\0') { - *unix_time = mktime(&tm); + /* Convert broken-down time to local time */ + if (tm.tm_gmtoff == 0) { + *unix_time = timegm(&tm); + } else { + long offset = tm.tm_gmtoff; + tm.tm_gmtoff = 0; + *unix_time = timegm(&tm) - offset; + } return EOK; } } diff --git a/src/tests/cmocka/test_sysdb_sudo.c b/src/tests/cmocka/test_sysdb_sudo.c index fc6a47a16..f852427fd 100644 --- a/src/tests/cmocka/test_sysdb_sudo.c +++ b/src/tests/cmocka/test_sysdb_sudo.c @@ -44,6 +44,12 @@ #define OVERRIDE_GROUP_NAME "group_sudo_test" #define OVERRIDE_UID 2112 +/* sysdb_sudo_convert_time function is static */ +extern char *strptime(const char *__restrict __s, + const char *__restrict __fmt, + struct tm *__tp); +#include "src/db/sysdb_sudo.c" + struct test_user { const char *name; uid_t uid; @@ -949,6 +955,26 @@ void test_filter_rules_by_time(void **state) talloc_zfree(_rules); } +void test_sudo_convert_time(void **state) +{ + /* Each ctime should map to its corresponding utime */ + const char *ctimes[] = {"20220715090000Z", + "20220715090000+0200", + "20220715090000-0200"}; + const time_t utimes[] = {1657875600, + 1657868400, + 1657882800}; + const int ntimes = sizeof(ctimes) / sizeof(ctimes[0]); + time_t converted; + errno_t ret; + + for (int i = 0; i < ntimes; i++) { + ret = sysdb_sudo_convert_time(ctimes[i], &converted); + assert_int_equal(ret, EOK); + assert_int_equal(converted, utimes[i]); + } +} + int main(int argc, const char *argv[]) { int rv; @@ -1029,6 +1055,9 @@ int main(int argc, const char *argv[]) cmocka_unit_test_setup_teardown(test_filter_rules_by_time, test_sysdb_setup, test_sysdb_teardown), + + /* sysdb_sudo_convert_time() */ + cmocka_unit_test(test_sudo_convert_time) }; /* Set debug level to invalid value so we can decide if -d 0 was used. */ -- 2.37.3