From: Juergen Perlinger Date: Sun, 2 Jun 2019 12:02:24 +0000 (+0200) Subject: [Bug 2420] ntpd doesn't run and exits with retval 0 when invalid user is specified... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3fbf90de0f11ba6ffa260e3454cc4239f6ff8234;p=thirdparty%2Fntp.git [Bug 2420] ntpd doesn't run and exits with retval 0 when invalid user is specified with -u - monitor daemon child startup & propagate exit codes bk: 5cf3bad01g_eOcQ9z_pZqhf9XAGaHA --- diff --git a/ChangeLog b/ChangeLog index 9ff845c81..91fff56e4 100644 --- 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 + - monitor daemon child startup & propagate exit codes + --- (4.2.8p13) 2019/03/07 Released by Harlan Stenn diff --git a/configure.ac b/configure.ac index 7975d31a9..6805e8117 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/include/ntpd.h b/include/ntpd.h index ead0c2cf8..bf67fc644 100644 --- a/include/ntpd.h +++ b/include/ntpd.h @@ -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 */ diff --git a/ntpd/ntp_proto.c b/ntpd/ntp_proto.c index eb663515b..4eb55e33c 100644 --- a/ntpd/ntp_proto.c +++ b/ntpd/ntp_proto.c @@ -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 */ diff --git a/ntpd/ntpd.c b/ntpd/ntpd.c index 2b14431dc..27d16de95 100644 --- a/ntpd/ntpd.c +++ b/ntpd/ntpd.c @@ -45,6 +45,9 @@ #ifdef HAVE_SYS_STAT_H # include #endif +#ifdef HAVE_SYS_WAIT_H +# include +#endif #include #ifdef HAVE_SYS_PARAM_H # include @@ -82,6 +85,10 @@ # include #endif +#ifdef HAVE_SYSEXITS_H +# include +#endif + #ifdef HAVE_TERMIOS_H # include #endif @@ -143,6 +150,21 @@ 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 */