diff -u sssd-1.11.8/debian/changelog sssd-1.11.8/debian/changelog --- sssd-1.11.8/debian/changelog +++ sssd-1.11.8/debian/changelog @@ -1,3 +1,19 @@ +sssd (1.11.8-0ubuntu0.5) trusty; urgency=medium + + * d/p/BUILD-Fix-linking-with-librt.patch: Upstream fix for FTBS on + ppc64el/arm64 after the implementation of timer functions in watchdog + (LP: #1641875). + + -- Victor Tapia Tue, 28 Feb 2017 10:20:19 +0100 + +sssd (1.11.8-0ubuntu0.4) trusty; urgency=medium + + * d/p/restart_providers_on_timeshift.patch: Implement watchdog and + use SIGUSR2 after watchdog detects time shift to execute pending + scheduled tasks that could be stuck (LP: #1641875) + + -- Victor Tapia Thu, 23 Feb 2017 11:15:01 +0100 + sssd (1.11.8-0ubuntu0.3) trusty; urgency=medium * d/p/fix-upstream-2519.diff SSSD should not fail authentication when only diff -u sssd-1.11.8/debian/control sssd-1.11.8/debian/control --- sssd-1.11.8/debian/control +++ sssd-1.11.8/debian/control @@ -1,7 +1,7 @@ Source: sssd Section: utils Priority: extra -Maintainer: Ubuntu Core Developers +Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Debian SSSD Team Uploaders: Timo Aaltonen Build-Depends: debhelper (>= 9), quilt, dh-autoreconf, autopoint, lsb-release, diff -u sssd-1.11.8/debian/patches/series sssd-1.11.8/debian/patches/series --- sssd-1.11.8/debian/patches/series +++ sssd-1.11.8/debian/patches/series @@ -5,0 +6,2 @@ +restart_providers_on_timeshift.patch +BUILD-Fix-linking-with-librt.patch only in patch2: unchanged: --- sssd-1.11.8.orig/debian/patches/BUILD-Fix-linking-with-librt.patch +++ sssd-1.11.8/debian/patches/BUILD-Fix-linking-with-librt.patch @@ -0,0 +1,50 @@ +From dc416984d92890f31122d32240d8bc0cbf48a48e Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 7 Nov 2016 11:53:21 +0100 +Subject: [PATCH] BUILD: Fix linking with librt + +The posix realime extensions defines timer_* functions +but it does not mention library with these functions. +http://www.unix.org/version2/whatsnew/realtime.html + +The autoconf macro AC_SEARCH_LIBS firstly check the function +timer_create with no libraries, then for each library listed +in 2nd parameter. Possible libraries librt and libposix4 +were used in nspr for similar detection. +--- + Makefile.am | 1 + + configure.ac | 13 +++++++++++++ + 2 files changed, 14 insertions(+) + +--- a/Makefile.am ++++ b/Makefile.am +@@ -623,6 +623,7 @@ + $(AM_CFLAGS) \ + $(SYSTEMD_LOGIN_CFLAGS) + libsss_util_la_LIBADD = \ ++ $(LIBADD_TIMER) \ + $(SSSD_LIBS) \ + $(UNICODE_LIBS) + if BUILD_SUDO +--- a/configure.ac ++++ b/configure.ac +@@ -64,6 +64,19 @@ + pthread_mutex_consistent_np ]) + LIBS=$SAVE_LIBS + ++# Check library for the timer_create function ++SAVE_LIBS=$LIBS ++LIBS= ++LIBADD_TIMER= ++AC_SEARCH_LIBS([timer_create], [rt posix4], ++ [AC_DEFINE([HAVE_LIBRT], [1], ++ [Define if you have the librt library or equivalent.]) ++ LIBADD_TIMER="$LIBS"], ++ [AC_MSG_ERROR([unable to find library fot the timer_create() function])]) ++ ++AC_SUBST([LIBADD_TIMER]) ++LIBS=$SAVE_LIBS ++ + # Check for presence of modern functions for setting file timestamps + AC_CHECK_FUNCS([ utimensat \ + futimens ]) only in patch2: unchanged: --- sssd-1.11.8.orig/debian/patches/restart_providers_on_timeshift.patch +++ sssd-1.11.8/debian/patches/restart_providers_on_timeshift.patch @@ -0,0 +1,406 @@ +Description: Restart the providers after a time shift has been detected + This patch implements the watchdog from upstream and restarts the providers + using the already implemented SIGUSR2 for method .resetOffline (used after + netlink detects an interface change). By doing this, events like LDAP + connection retries will be executed immediately instead of having to wait + the time shifted (potentially hours) to get to its normal schedule. + +Author: Victor Tapia +Bug: https://fedorahosted.org/sssd/ticket/3285 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1641875 +Last-Update: 2017-02-15 + +--- a/Makefile.am ++++ b/Makefile.am +@@ -617,6 +617,7 @@ + src/util/io.c \ + src/util/util_sss_idmap.c \ + src/util/string_utils.c \ ++ src/util/util_watchdog.c \ + $(NULL) + libsss_util_la_CFLAGS = \ + $(AM_CFLAGS) \ +--- a/src/monitor/monitor.c ++++ b/src/monitor/monitor.c +@@ -2805,6 +2805,8 @@ + + /* we want a pid file check */ + flags |= FLAGS_PID_FILE; ++ /* the monitor should not run a watchdog on itself */ ++ flags |= FLAGS_NO_WATCHDOG; + + /* Open before server_setup() does to have logging + * during configuration checking */ +--- a/src/util/server.c ++++ b/src/util/server.c +@@ -415,6 +415,7 @@ + bool dm; + struct tevent_signal *tes; + struct logrotate_ctx *lctx; ++ int watchdog_interval; + + debug_prg_name = strdup(name); + if (!debug_prg_name) { +@@ -571,6 +572,24 @@ + return ret; + } + } ++ ++ /* Setup the internal watchdog */ ++ ret = confdb_get_int(ctx->confdb_ctx, conf_entry, ++ CONFDB_DOMAIN_TIMEOUT, ++ 0, &watchdog_interval); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) [%s]\n", ++ ret, strerror(ret)); ++ return ret; ++ } ++ ++ if ((flags & FLAGS_NO_WATCHDOG) == 0) { ++ ret = setup_watchdog(ctx->event_ctx, watchdog_interval); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Watchdog setup failed.\n"); ++ return ret; ++ } ++ } + + sss_log(SSS_LOG_INFO, "Starting up"); + +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -158,6 +159,21 @@ + #define FLAGS_DAEMON 0x0001 + #define FLAGS_INTERACTIVE 0x0002 + #define FLAGS_PID_FILE 0x0004 ++#define FLAGS_NO_WATCHDOG 0x0010 ++ ++#define PIPE_INIT { -1, -1 } ++ ++#define PIPE_FD_CLOSE(fd) do { \ ++ if (fd != -1) { \ ++ close(fd); \ ++ fd = -1; \ ++ } \ ++} while(0); ++ ++#define PIPE_CLOSE(p) do { \ ++ PIPE_FD_CLOSE(p[0]); \ ++ PIPE_FD_CLOSE(p[1]); \ ++} while(0); + + #ifndef talloc_zfree + #define talloc_zfree(ptr) do { talloc_free(discard_const(ptr)); ptr = NULL; } while(0) +@@ -541,4 +557,19 @@ + const char *orig_name, + const char replace_char); + ++/** ++ * @brief set file descriptor as nonblocking ++ * ++ * Set the O_NONBLOCK flag for the input fd ++ * ++ * @param[in] fd The file descriptor to set as nonblocking ++ * ++ * @return EOK on success, errno code otherwise ++ */ ++errno_t sss_fd_nonblocking(int fd); ++ ++/* from util_watchdog.c */ ++int setup_watchdog(struct tevent_context *ev, int interval); ++void teardown_watchdog(void); ++ + #endif /* __SSSD_UTIL_H__ */ +--- a/src/util/util.c ++++ b/src/util/util.c +@@ -749,3 +749,27 @@ + + return false; + } ++ ++/* Set the nonblocking flag to the fd */ ++errno_t sss_fd_nonblocking(int fd) ++{ ++ int flags; ++ int ret; ++ ++ flags = fcntl(fd, F_GETFL, 0); ++ if (flags == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "F_GETFL failed [%d][%s].\n", ret, strerror(ret)); ++ return ret; ++ } ++ ++ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "F_SETFL failed [%d][%s].\n", ret, strerror(ret)); ++ return ret; ++ } ++ ++ return EOK; ++} +--- /dev/null ++++ b/src/util/util_watchdog.c +@@ -0,0 +1,253 @@ ++/* ++ SSSD ++ ++ Timer Watchdog routines ++ ++ Copyright (C) Simo Sorce 2016 ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include "util/util.h" ++ ++#define WATCHDOG_DEF_INTERVAL 10 ++#define WATCHDOG_MAX_TICKS 3 ++#define DEFAULT_BUFFER_SIZE 4096 ++ ++/* this is intentionally a global variable */ ++struct watchdog_ctx { ++ timer_t timerid; ++ struct timeval interval; ++ struct tevent_timer *te; ++ volatile int ticks; ++ ++ /* To detect time shift. */ ++ struct tevent_context *ev; ++ int input_interval; ++ time_t timestamp; ++ struct tevent_fd *tfd; ++ int pipefd[2]; ++} watchdog_ctx; ++ ++static void watchdog_detect_timeshift(void) ++{ ++ time_t prev_time; ++ time_t cur_time; ++ ++ prev_time = watchdog_ctx.timestamp; ++ cur_time = watchdog_ctx.timestamp = time(NULL); ++ if (cur_time < prev_time) { ++ /* Time shift detected. We need to restart watchdog. */ ++ if (write(watchdog_ctx.pipefd[1], "1", 1) != 1) { ++ if (getpid() == getpgrp()) { ++ kill(-getpgrp(), SIGTERM); ++ } else { ++ _exit(1); ++ } ++ } ++ } ++} ++ ++/* the watchdog is purposefully *not* handled by the tevent ++ * signal handler as it is meant to check if the daemon is ++ * still processing the event queue itself. A stuck process ++ * may not handle the event queue at all and thus not handle ++ * signals either */ ++static void watchdog_handler(int sig) ++{ ++ ++ watchdog_detect_timeshift(); ++ ++ /* if a pre-defined number of ticks passed by kills itself */ ++ if (__sync_add_and_fetch(&watchdog_ctx.ticks, 1) > WATCHDOG_MAX_TICKS) { ++ if (getpid() == getpgrp()) { ++ kill(-getpgrp(), SIGTERM); ++ } else { ++ _exit(1); ++ } ++ } ++} ++ ++static void watchdog_reset(void) ++{ ++ __sync_and_and_fetch(&watchdog_ctx.ticks, 0); ++} ++ ++static void watchdog_event_handler(struct tevent_context *ev, ++ struct tevent_timer *te, ++ struct timeval current_time, ++ void *private_data) ++{ ++ /* first thing reset the watchdog ticks */ ++ watchdog_reset(); ++ ++ /* then set a new watchodg event */ ++ watchdog_ctx.te = tevent_add_timer(ev, ev, ++ tevent_timeval_current_ofs(watchdog_ctx.interval.tv_sec, 0), ++ watchdog_event_handler, NULL); ++ /* if the function fails the watchdog will kill the ++ * process soon enough, so we just warn */ ++ if (!watchdog_ctx.te) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to create a watchdog timer event!\n"); ++ } ++} ++ ++static errno_t watchdog_fd_recv_data(int fd) ++{ ++ ssize_t len; ++ char buffer[DEFAULT_BUFFER_SIZE]; ++ errno_t ret; ++ ++ errno = 0; ++ len = read(fd, buffer, DEFAULT_BUFFER_SIZE); ++ if (len == -1) { ++ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { ++ return EAGAIN; ++ } else { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "write failed [%d]: %s\n", ret, strerror(ret)); ++ return ret; ++ } ++ } ++ ++ return EOK; ++} ++ ++static void watchdog_fd_read_handler(struct tevent_context *ev, ++ struct tevent_fd *fde, ++ uint16_t flags, ++ void *data) ++{ ++ errno_t ret; ++ ++ ret = watchdog_fd_recv_data(watchdog_ctx.pipefd[0]); ++ switch(ret) { ++ case EAGAIN: ++ DEBUG(SSSDBG_TRACE_ALL, ++ "Interrupted before any data could be read, retry later.\n"); ++ return; ++ case EOK: ++ /* all fine */ ++ break; ++ default: ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to receive data [%d]: %s. " ++ "sig_term() will be called.\n", ret, strerror(ret)); ++ sig_term(1); ++ } ++ ++ DEBUG(SSSDBG_IMPORTANT_INFO, "Time shift detected, " ++ "restarting watchdog!\n"); ++ if (getpid() == getpgrp()) { ++ kill(-getpgrp(), SIGUSR2); ++ } ++} ++ ++int setup_watchdog(struct tevent_context *ev, int interval) ++{ ++ struct sigevent sev; ++ struct itimerspec its; ++ struct tevent_fd *tfd; ++ int signum = SIGRTMIN; ++ int ret; ++ ++ ZERO_STRUCT(sev); ++ CatchSignal(signum, watchdog_handler); ++ ++ sev.sigev_notify = SIGEV_SIGNAL; ++ sev.sigev_signo = signum; ++ sev.sigev_value.sival_ptr = &watchdog_ctx.timerid; ++ errno = 0; ++ ret = timer_create(CLOCK_MONOTONIC, &sev, &watchdog_ctx.timerid); ++ if (ret == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to create watchdog timer (%d) [%s]\n", ++ ret, strerror(ret)); ++ return ret; ++ } ++ ++ if (interval == 0) { ++ interval = WATCHDOG_DEF_INTERVAL; ++ } ++ watchdog_ctx.interval.tv_sec = interval; ++ watchdog_ctx.interval.tv_usec = 0; ++ ++ watchdog_ctx.ev = ev; ++ watchdog_ctx.input_interval = interval; ++ watchdog_ctx.timestamp = time(NULL); ++ ++ ret = pipe(watchdog_ctx.pipefd); ++ if (ret == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "pipe failed [%d] [%s].\n", ret, strerror(ret)); ++ return ret; ++ } ++ ++ sss_fd_nonblocking(watchdog_ctx.pipefd[0]); ++ sss_fd_nonblocking(watchdog_ctx.pipefd[1]); ++ ++ tfd = tevent_add_fd(ev, (TALLOC_CTX *)ev, watchdog_ctx.pipefd[0], ++ TEVENT_FD_READ, watchdog_fd_read_handler, NULL); ++ watchdog_ctx.tfd = tfd; ++ ++ /* Start the timer */ ++ /* we give 1 second head start to the watchdog event */ ++ its.it_value.tv_sec = interval + 1; ++ its.it_value.tv_nsec = 0; ++ its.it_interval.tv_sec = interval; ++ its.it_interval.tv_nsec = 0; ++ errno = 0; ++ ret = timer_settime(watchdog_ctx.timerid, 0, &its, NULL); ++ if (ret == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to create watchdog timer (%d) [%s]\n", ++ ret, strerror(ret)); ++ return ret; ++ } ++ ++ /* Add the watchdog event and make it fire as fast as the timer */ ++ watchdog_event_handler(ev, NULL, tevent_timeval_zero(), NULL); ++ ++ return EOK; ++} ++ ++void teardown_watchdog(void) ++{ ++ int ret; ++ ++ /* Disarm the timer */ ++ errno = 0; ++ ret = timer_delete(watchdog_ctx.timerid); ++ if (ret == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to destroy watchdog timer (%d) [%s]\n", ++ ret, strerror(ret)); ++ } ++ ++ /* Free the tevent_fd */ ++ talloc_zfree(watchdog_ctx.tfd); ++ ++ /* Close the pipefds */ ++ PIPE_FD_CLOSE(watchdog_ctx.pipefd[0]); ++ PIPE_FD_CLOSE(watchdog_ctx.pipefd[1]); ++ ++ /* and kill the watchdog event */ ++ talloc_free(watchdog_ctx.te); ++}