]> git.ipfire.org Git - thirdparty/fcron.git/commitdiff
Add compilation option to allow faster or even instant reload for non-root users...
authorElliot Wolk <elliot.wolk@gmail.com>
Mon, 1 Apr 2024 19:04:32 +0000 (15:04 -0400)
committerGitHub <noreply@github.com>
Mon, 1 Apr 2024 19:04:32 +0000 (20:04 +0100)
* fcrontab: refactor sig_daemon() reload delay, add seconds to msg

* configure: add opt to decrease or remove non-root tab reload

* fcrontab: enforce max-fcrontab-delay-seconds in delay for non-root user

* configure: rename max-fcrontab-load => max-fcrontab-reload

* configure: expand usage for max-delay-reload

* fcrontab: refactor fcrontab reload delay calculation for clarity

config.h.in
configure.in
fcronsighup.c

index 61df7b05f33bf4b36b6362484523f93b1c0af72b..5d73f2a3eb848e8285d673141355b194bcfe2dc3 100644 (file)
 #undef FOREGROUND
 #undef RUN_NON_PRIVILEGED
 
+/* 0 for no delay for any user, 60s is the default */
+#undef MAX_FCRONTAB_RELOAD_DELAY_SECONDS
+
 /* Define if we should use sete[ug]id() funcs */
 #undef USE_SETE_ID
 
index 87bd2b805fda9cbe2343e12af13f3e0735015cf3..6fc44e155f9cf78b6669132584083748dff16270 100644 (file)
@@ -476,6 +476,33 @@ WARNING :
   AC_MSG_RESULT(no)
 )
 
+max_fcrontab_reload_delay_seconds=60
+AC_MSG_CHECKING(max fcrontab reload delay seconds)
+AC_ARG_WITH(max-fcrontab-reload-delay-seconds,
+[  --with-max-fcrontab-reload-delay-seconds=INTEGER
+       The maximum delay, in seconds, before (re)loading the fcrontab as a non-root user
+       (there is never any delay for root). By default, the delay to (re)load the fcrontab
+       for a non-root user is at least one full second and at most sixty seconds,
+       depending on circumstances when the (re)load happens.
+       A value of 0 for this argument means no delay for any user, ever.
+       A value between 1 and 59 (inclusive) will ensure that the non-root delay is always at least 1s,
+         and never more than the given number of seconds.
+       A value greater than or equal to 60 has no effect.],
+[
+  case "$withval" in
+    ("" | *[!0123456789]*)
+      AC_MSG_ERROR(Invalid argument : please use a non-negative integer.)
+      ;;
+    *)
+      max_fcrontab_reload_delay_seconds="$withval"
+      ;;
+  esac
+
+  AC_MSG_RESULT([$withval])
+])
+MAX_FCRONTAB_RELOAD_DELAY_SECONDS="$max_fcrontab_reload_delay_seconds"
+AC_SUBST(MAX_FCRONTAB_RELOAD_DELAY_SECONDS)
+AC_DEFINE_UNQUOTED([MAX_FCRONTAB_RELOAD_DELAY_SECONDS], [$max_fcrontab_reload_delay_seconds])
 
 if test "$fcrondyn" = ""; then
   dnl As it stands gettimeofday() is required to have fcrondyn
@@ -1096,6 +1123,21 @@ else
        echo "no"
 fi
 
+echo "Max fcrontab reload delay seconds : $max_fcrontab_reload_delay_seconds"
+
+if test "$max_fcrontab_reload_delay_seconds" -lt "1" ; then
+  AC_MSG_WARN([
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+WARNING:
+This option --with-max-fcrontab-reload-delay-seconds=0, allows a
+  non-privileged user to immediately (re)load fcrontab.
+This allows the possibility of SIGHUP denial of service to block the daemon.
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+  ])
+fi
+
 echo -n "Load average support :              "
 if test "$getloadavg" -eq 1 -o -n "$proc"; then
        echo "yes"
index 2bc1b28110d835720a7e03a5bfc3e1e58410236b..c75041b4b6ee5aee1ad2c16900ee29dbe8c76339 100644 (file)
@@ -86,37 +86,44 @@ sig_daemon(void)
     /* SIGHUP is sent once 10s before the next minute to avoid
      * some bad users to block daemon by sending it SIGHUP all the time */
 {
-    /* we don't need to make root wait */
-    if (uid != rootuid) {
-        time_t t = 0;
-        int sl = 0;
+    int max_delay_s = 60;
+#ifdef MAX_FCRONTAB_RELOAD_DELAY_SECONDS
+    max_delay_s = MAX_FCRONTAB_RELOAD_DELAY_SECONDS;
+#endif
+    if (uid == rootuid) {
+      /* we don't need to make root wait */
+      max_delay_s = 0;
+    }
+
+    if (max_delay_s > 0) {
+        time_t now_epoch = 0;
+        int delay_s = 0;
+        time_t *target_time_epoch = NULL;
+        struct tm *target_time_tm = NULL;
         FILE *fp = NULL;
         int fd = 0;
-        struct tm *tm = NULL;
         char sigfile[PATH_LEN];
-        char buf[PATH_LEN];
 
         sigfile[0] = '\0';
-        t = time(NULL);
-        tm = localtime(&t);
-
-        if ((sl = 60 - (t % 60) - 10) < 0) {
-            if ((tm->tm_min = tm->tm_min + 2) >= 60) {
-                tm->tm_hour++;
-                tm->tm_min -= 60;
-            }
-            snprintf(buf, sizeof(buf), "%02d:%02d", tm->tm_hour, tm->tm_min);
-            sl = 60 - (t % 60) + 50;
+        now_epoch = time(NULL);
+
+        if (now_epoch % 60 < 50) {
+          /* clocktime is < ##:##:50, so target 10s before the end of the current minute */
+          delay_s = 50 - (now_epoch % 60);
+        } else {
+          /* clocktime is >= ##:##:50, so target 10s before the end of the next minute */
+          delay_s = 50 + (60 - (now_epoch % 60));
         }
-        else {
-            if (++tm->tm_min >= 60) {
-                tm->tm_hour++;
-                tm->tm_min -= 60;
-            }
-            snprintf(buf, sizeof(buf), "%02d:%02d", tm->tm_hour, tm->tm_min);
+
+        if (delay_s > max_delay_s) {
+          delay_s = max_delay_s;
         }
-        fprintf(stderr, "Modifications will be taken into account"
-                " at %s.\n", buf);
+
+        target_time_epoch = now_epoch + delay_s;
+        target_time_tm = localtime(&target_time_epoch);
+
+        fprintf(stderr, "Modifications will be taken into account at %02d:%02d:%02d.\n",
+          target_time_tm->tm_hour, target_time_tm->tm_min, target_time_tm->tm_sec);
 
         /* if fcrontabs is too long, snprintf will not be able to add "/fcrontab.sig"
          * string at the end of sigfile */
@@ -167,7 +174,7 @@ sig_daemon(void)
         }
 #endif                          /* ! HAVE_FLOCK */
 
-        sleep(sl);
+        sleep(delay_s);
 
         /* also closes the underlying file descriptor fd: */
         xfclose_check(&fp, sigfile);
@@ -178,7 +185,7 @@ sig_daemon(void)
             error_e("Could not remove %s");
     }
     else
-        /* we are root */
+        /* we are root, or config MAX_FCRONTAB_RELOAD_DELAY_SECONDS=0 is set */
         fprintf(stderr,
                 "Modifications will be taken into account" " right now.\n");