]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 2420] ntpd doesn't run and exits with retval 0 when invalid user is specified...
authorJuergen Perlinger <perlinger@ntp.org>
Sun, 2 Jun 2019 12:02:24 +0000 (14:02 +0200)
committerJuergen Perlinger <perlinger@ntp.org>
Sun, 2 Jun 2019 12:02:24 +0000 (14:02 +0200)
 - monitor daemon child startup & propagate exit codes

bk: 5cf3bad01g_eOcQ9z_pZqhf9XAGaHA

ChangeLog
configure.ac
include/ntpd.h
ntpd/ntp_proto.c
ntpd/ntpd.c

index 9ff845c81028eeecbd72fd587d28555bc5f781e5..91fff56e4f2f43026cd6d606afc4a8af5e02966b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+---
+* [Bug 2420] ntpd doesn't run and exits with retval 0 when invalid user
+             is specified with -u <perlinger@ntp.org>
+  - monitor daemon child startup & propagate exit codes
+
 ---
 (4.2.8p13) 2019/03/07 Released by Harlan Stenn <stenn@ntp.org>
 
index 7975d31a97e0c3d95b637d4857c84d8aeefe4fc4..6805e8117dbf739ad78825371ede897c1122638c 100644 (file)
@@ -382,6 +382,7 @@ case "$host" in
 esac
 AC_CHECK_HEADERS([sys/stat.h sys/stream.h stropts.h sys/stropts.h sys/syssgi.h])
 AC_CHECK_HEADERS([sys/systune.h sys/termios.h sys/tpro.h sys/wait.h])
+AC_CHECK_FUNCS([waitpid])
 case "$host" in
 *-convex-*)
     AC_CHECK_HEADERS([/sys/sync/queue.h /sys/sync/sema.h])
index ead0c2cf8171d6c3d8cd6c57674d186b313f80b6..bf67fc644ca2aa545f24efe53a6f9a72ab4e65c9 100644 (file)
@@ -568,7 +568,7 @@ extern char *group;         /* group to switch to */
 extern const char *chrootdir;  /* directory to chroot() to */
 #endif
 #ifdef HAVE_WORKING_FORK
-extern int     waitsync_fd_to_close;   /* -w/--wait-sync */
+extern int     daemon_pipe[2]; /* startup monitoring */
 #endif
 
 /* ntservice.c */
index eb663515b8a4b8a6dda1fdeff63543ad8d724504..4eb55e33cdf7bd28a4d16fcb8c2bebd855a915ea 100644 (file)
@@ -2883,9 +2883,10 @@ clock_update(
                         * first clock sync, send them home satisfied.
                         */
 #ifdef HAVE_WORKING_FORK
-                       if (waitsync_fd_to_close != -1) {
-                               close(waitsync_fd_to_close);
-                               waitsync_fd_to_close = -1;
+                       if (daemon_pipe[1] != -1) {
+                               write(daemon_pipe[1], "S\n", 2);
+                               close(daemon_pipe[1]);
+                               daemon_pipe[1] = -1;
                                DPRINTF(1, ("notified parent --wait-sync is done\n"));
                        }
 #endif /* HAVE_WORKING_FORK */
index 2b14431dc7b4113b2c4bca3b89e4be1185f2ef0b..27d16de951361400a47a8c40a5763ee7f467621f 100644 (file)
@@ -45,6 +45,9 @@
 #ifdef HAVE_SYS_STAT_H
 # include <sys/stat.h>
 #endif
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
 #include <stdio.h>
 #ifdef HAVE_SYS_PARAM_H
 # include <sys/param.h>
 # include <sys/mman.h>
 #endif
 
+#ifdef HAVE_SYSEXITS_H
+# include <sysexits.h>
+#endif
+
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
 #endif
 DNSServiceRef mdns;
 #endif
 
+/* In case 'sysexits.h' is unavailable, define some exit codes here: */
+#ifndef EX_SOFTWARE
+# define EX_SOFTWARE   70
+#endif
+#ifndef EX_OSERR
+# define EX_OSERR      71
+#endif
+#ifndef EX_IOERR
+# define EX_IOERR      74
+#endif
+#ifndef EX_PROTOCOL
+#define EX_PROTOCOL    76
+#endif
+
+
 #ifdef HAVE_SETPGRP_0
 # define ntp_setpgrp(x, y)     setpgrp()
 #else
@@ -194,7 +216,7 @@ struct passwd *pw;
 #endif /* HAVE_DROPROOT */
 
 #ifdef HAVE_WORKING_FORK
-int    waitsync_fd_to_close = -1;      /* -w/--wait-sync */
+int    daemon_pipe[2] = { -1, -1 };
 #endif
 
 /*
@@ -224,7 +246,8 @@ static      RETSIGTYPE      finish          (int);
 #endif
 
 #if !defined(SIM) && defined(HAVE_WORKING_FORK)
-static int     wait_child_sync_if      (int, long);
+static int     wait_child_sync_if      (int, unsigned long);
+static int     wait_child_exit_if      (pid_t, int);
 #endif
 
 #if !defined(SIM) && !defined(SYS_WINNT)
@@ -537,13 +560,13 @@ set_process_priority(void)
 # ifdef HAVE_WORKING_FORK
 static void
 detach_from_terminal(
-       int pipe_fds[2],
+       int pipe[2],
        long wait_sync,
        const char *logfilename
        )
 {
-       int rc;
-       int exit_code;
+       pid_t   cpid;
+       int     exit_code;
 #  if !defined(HAVE_SETSID) && !defined (HAVE_SETPGID) && defined(TIOCNOTTY)
        int             fid;
 #  endif
@@ -551,16 +574,28 @@ detach_from_terminal(
        struct sigaction sa;
 #  endif
 
-       rc = fork();
-       if (-1 == rc) {
-               exit_code = (errno) ? errno : -1;
-               msyslog(LOG_ERR, "fork: %m");
-               exit(exit_code);
-       }
-       if (rc > 0) {
+       cpid = fork();
+       if (0 != cpid) {
                /* parent */
-               exit_code = wait_child_sync_if(pipe_fds[0],
-                                              wait_sync);
+               if (-1 == cpid) {
+                       msyslog(LOG_ERR, "fork: %m");
+                       exit_code = EX_OSERR;
+               } else {
+                       close(pipe[1]);
+                       pipe[1] = -1;
+                       exit_code = wait_child_sync_if(
+                                       pipe[0], wait_sync);
+                       DPRINTF(1, ("sync_if: rc=%d\n", exit_code));
+                       if (exit_code <= 0) {
+                               /* probe daemon exit code -- wait for
+                                * child process if we have an unexpected
+                                * EOF on the monitor pipe.
+                                */
+                               exit_code = wait_child_exit_if(
+                                               cpid, (exit_code < 0));
+                               DPRINTF(1, ("exit_if: rc=%d\n", exit_code));
+                       }
+               }
                exit(exit_code);
        }
 
@@ -575,7 +610,8 @@ detach_from_terminal(
                syslog_file = NULL;
                syslogit = TRUE;
        }
-       close_all_except(waitsync_fd_to_close);
+       close_all_except(pipe[1]);
+       pipe[0] = -1;
        INSIST(0 == open("/dev/null", 0) && 1 == dup2(0, 1) \
                && 2 == dup2(0, 2));
 
@@ -782,9 +818,6 @@ ntpdmain(
 # endif
 # if defined(HAVE_WORKING_FORK)
        long            wait_sync = 0;
-       int             pipe_fds[2];
-       int             rc;
-       int             exit_code;
 # endif        /* HAVE_WORKING_FORK*/
 # ifdef SCO5_CLOCK
        int             fd;
@@ -927,27 +960,24 @@ ntpdmain(
 # endif
 
 # ifdef HAVE_WORKING_FORK
-       /* make sure the FDs are initialised */
-       pipe_fds[0] = -1;
-       pipe_fds[1] = -1;
-       do {                                    /* 'loop' once */
-               if (!HAVE_OPT( WAIT_SYNC ))
-                       break;
+       /* make sure the FDs are initialised
+        *
+        * note: if WAIT_SYNC is requested, we *have* to fork. This will
+        * overide any '-n' (nofork) or '-d' (debug) option presented on
+        * the command line!
+        */
+       if (HAVE_OPT(WAIT_SYNC)) {
                wait_sync = OPT_VALUE_WAIT_SYNC;
-               if (wait_sync <= 0) {
+               if (wait_sync <= 0)
                        wait_sync = 0;
-                       break;
-               }
-               /* -w requires a fork() even with debug > 0 */
-               nofork = FALSE;
-               if (pipe(pipe_fds)) {
-                       exit_code = (errno) ? errno : -1;
-                       msyslog(LOG_ERR,
-                               "Pipe creation failed for --wait-sync: %m");
-                       exit(exit_code);
-               }
-               waitsync_fd_to_close = pipe_fds[1];
-       } while (0);                            /* 'loop' once */
+               else
+                       nofork = FALSE;
+       }
+       if ( !nofork && pipe(daemon_pipe)) {
+               msyslog(LOG_ERR,
+                       "Pipe creation failed for --wait-sync/daemon: %m");
+               exit(EX_OSERR);
+       }
 # endif        /* HAVE_WORKING_FORK */
 
        init_lib();
@@ -973,12 +1003,11 @@ ntpdmain(
        /*
         * Detach us from the terminal.  May need an #ifndef GIZMO.
         */
-       if (!nofork) {
-
 # ifdef HAVE_WORKING_FORK
-               detach_from_terminal(pipe_fds, wait_sync, logfilename);
-# endif                /* HAVE_WORKING_FORK */
+       if (!nofork) {
+               detach_from_terminal(daemon_pipe, wait_sync, logfilename);
        }
+# endif                /* HAVE_WORKING_FORK */
 
 # ifdef SCO5_CLOCK
        /*
@@ -1364,9 +1393,13 @@ int scmp_sc[] = {
        }
 #endif /* LIBSECCOMP and KERN_SECCOMP */
 
-#ifdef SYS_WINNT
+#if defined(SYS_WINNT)
        ntservice_isup();
-#endif
+#elif defined(HAVE_WORKING_FORK)
+       if (daemon_pipe[1] != -1) {
+               write(daemon_pipe[1], "R\n", 2);
+       }
+#endif /* HAVE_WORKING_FORK */
 
 # ifdef HAVE_IO_COMPLETION_PORT
 
@@ -1550,26 +1583,30 @@ finish(
  * wait_child_sync_if - implements parent side of -w/--wait-sync
  */
 # ifdef HAVE_WORKING_FORK
+
 static int
 wait_child_sync_if(
-       int     pipe_read_fd,
-       long    wait_sync
+       int             pipe_read_fd,
+       unsigned long   wait_sync
        )
 {
        int     rc;
-       int     exit_code;
+       char    ch;
        time_t  wait_end_time;
        time_t  cur_time;
        time_t  wait_rem;
        fd_set  readset;
        struct timeval wtimeout;
 
-       if (0 == wait_sync) 
-               return 0;
+       /* we wait a bit for the child in *any* case, because on failure
+        * of the child we have to get and inspect the exit code!
+        */
+       wait_end_time = time(NULL);
+       if (wait_sync)
+               wait_end_time += wait_sync;
+       else
+               wait_end_time += 30;
 
-       /* waitsync_fd_to_close used solely by child */
-       close(waitsync_fd_to_close);
-       wait_end_time = time(NULL) + wait_sync;
        do {
                cur_time = time(NULL);
                wait_rem = (wait_end_time > cur_time)
@@ -1584,10 +1621,9 @@ wait_child_sync_if(
                if (-1 == rc) {
                        if (EINTR == errno)
                                continue;
-                       exit_code = (errno) ? errno : -1;
                        msyslog(LOG_ERR,
-                               "--wait-sync select failed: %m");
-                       return exit_code;
+                               "daemon startup: select failed: %m");
+                       return EX_IOERR;
                }
                if (0 == rc) {
                        /*
@@ -1604,16 +1640,70 @@ wait_child_sync_if(
                                    NULL, &wtimeout);
                        if (0 == rc)    /* select() timeout */
                                break;
-                       else            /* readable */
+               }
+               rc = read(pipe_read_fd, &ch, 1);
+               if (rc == 0) {
+                       DPRINTF(2, ("daemon control: got EOF\n"));
+                       return -1;      /* unexpected EOF, check daemon */
+               } else if (rc == 1) {
+                       DPRINTF(2, ("daemon control: got '%c'\n",
+                                   (ch >= ' ' ? ch : '.')));
+                       if (ch == 'R' && !wait_sync)
                                return 0;
-               } else                  /* readable */
-                       return 0;
+                       if (ch == 'S' && wait_sync)
+                               return 0;
+               } else {
+                       DPRINTF(2, ("daemon control: read 1 char failed: %s\n",
+                                   strerror(errno)));
+                       return EX_IOERR;
+               }
        } while (wait_rem > 0);
 
-       fprintf(stderr, "%s: -w/--wait-sync %ld timed out.\n",
-               progname, wait_sync);
-       return ETIMEDOUT;
+       if (wait_sync) {
+               fprintf(stderr, "%s: -w/--wait-sync %ld timed out.\n",
+                       progname, wait_sync);
+               return EX_PROTOCOL;
+       } else {
+               fprintf(stderr, "%s: daemon startup monitoring timed out.\n",
+                       progname);
+               return 0;
+       }
+}
+
+
+static int
+wait_child_exit_if(
+       pid_t   cpid,
+       int     blocking
+       )
+{
+#    ifdef HAVE_WAITPID
+       int     rc = 0;
+       int     wstatus;
+       if (cpid == waitpid(cpid, &wstatus, (blocking ? 0 : WNOHANG))) {
+               DPRINTF(1, ("child (pid=%d) dead now\n", cpid));
+               if (WIFEXITED(wstatus)) {
+                       rc = WEXITSTATUS(wstatus);
+                       msyslog(LOG_ERR, "daemon child exited with code %d",
+                               rc);
+               } else if (WIFSIGNALED(wstatus)) {
+                       rc = EX_SOFTWARE;
+                       msyslog(LOG_ERR, "daemon child died with signal %d",
+                               WTERMSIG(wstatus));
+               } else {
+                       rc = EX_SOFTWARE;
+                       msyslog(LOG_ERR, "daemon child died with unknown cause");
+               }
+       } else {
+               DPRINTF(1, ("child (pid=%d) still alive\n", cpid));
+       }
+       return rc;
+#    else
+       UNUSED_ARG(cpid);
+       return 0;
+#    endif
 }
+
 # endif        /* HAVE_WORKING_FORK */