aboutsummaryrefslogtreecommitdiff
path: root/ntpd/ntpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'ntpd/ntpd.c')
-rw-r--r--ntpd/ntpd.c881
1 files changed, 419 insertions, 462 deletions
diff --git a/ntpd/ntpd.c b/ntpd/ntpd.c
index 0b052535e777..04e0d07f94c9 100644
--- a/ntpd/ntpd.c
+++ b/ntpd/ntpd.c
@@ -10,9 +10,13 @@
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_stdlib.h"
+#include <ntp_random.h>
#ifdef SIM
-#include "ntpsim.h"
+# include "ntpsim.h"
+# include "ntpdsim-opts.h"
+#else
+# include "ntpd-opts.h"
#endif
#ifdef HAVE_UNISTD_H
@@ -43,9 +47,8 @@
# include <signal.h>
# include <process.h>
# include <io.h>
-# include "../libntp/log.h"
# include <clockstuff.h>
-# include <crtdbg.h>
+#include "ntp_iocompletionport.h"
#endif /* SYS_WINNT */
#if defined(HAVE_RTPRIO)
# ifdef HAVE_SYS_RESOURCE_H
@@ -104,10 +107,14 @@
# include <sys/ci/ciioctl.h>
#endif
-#ifdef HAVE_CLOCKCTL
+#ifdef HAVE_DROPROOT
# include <ctype.h>
# include <grp.h>
# include <pwd.h>
+#ifdef HAVE_LINUX_CAPABILITIES
+# include <sys/capability.h>
+# include <sys/prctl.h>
+#endif
#endif
/*
@@ -126,18 +133,10 @@
# define SIGDIE4 SIGTERM
#endif /* SYS_WINNT */
-#if defined SYS_WINNT
-/* handles for various threads, process, and objects */
-HANDLE ResolverThreadHandle = NULL;
-/* variables used to inform the Service Control Manager of our current state */
-BOOL NoWinService = FALSE;
-SERVICE_STATUS ssStatus;
-SERVICE_STATUS_HANDLE sshStatusHandle;
-HANDLE WaitHandles[3] = { NULL, NULL, NULL };
-char szMsgPath[255];
-static BOOL WINAPI OnConsoleEvent(DWORD dwCtrlType);
-BOOL init_randfile();
-#endif /* SYS_WINNT */
+#ifdef HAVE_DNSREGISTRATION
+#include <dns_sd.h>
+DNSServiceRef mdns;
+#endif
/*
* Scheduling priority we run at
@@ -149,22 +148,23 @@ int priority_done = 2; /* 0 - Set priority */
/* 2 - Don't set priority */
/* 1 and 2 are pretty much the same */
+#ifdef DEBUG
/*
* Debugging flag
*/
-volatile int debug;
+volatile int debug = 0; /* No debugging by default */
+#endif
-/*
- * Set the processing not to be in the forground
- */
-int forground_process = FALSE;
+int listen_to_virtual_ips = 1;
+const char *specific_interface = NULL; /* interface name or IP address to bind to */
/*
* No-fork flag. If set, we do not become a background daemon.
*/
-int nofork;
+int nofork = 0; /* Fork by default */
-#ifdef HAVE_CLOCKCTL
+#ifdef HAVE_DROPROOT
+int droproot = 0;
char *user = NULL; /* User to switch to */
char *group = NULL; /* group to switch to */
char *chrootdir = NULL; /* directory to chroot to */
@@ -173,7 +173,7 @@ int sw_gid;
char *endp;
struct group *gr;
struct passwd *pw;
-#endif /* HAVE_CLOCKCTL */
+#endif /* HAVE_DROPROOT */
/*
* Initializing flag. All async routines watch this and only do their
@@ -186,6 +186,8 @@ int initializing;
*/
extern const char *Version;
+char const *progname;
+
int was_alarmed;
#ifdef DECL_SYSCALL
@@ -211,6 +213,86 @@ static RETSIGTYPE no_debug P((int));
int ntpdmain P((int, char **));
static void set_process_priority P((void));
+static void init_logging P((char const *));
+static void setup_logfile P((void));
+
+/*
+ * Initialize the logging
+ */
+void
+init_logging(char const *name)
+{
+ const char *cp;
+
+ /*
+ * Logging. This may actually work on the gizmo board. Find a name
+ * to log with by using the basename
+ */
+ cp = strrchr(name, '/');
+ if (cp == 0)
+ cp = name;
+ else
+ cp++;
+
+#if !defined(VMS)
+
+# ifndef LOG_DAEMON
+ openlog(cp, LOG_PID);
+# else /* LOG_DAEMON */
+
+# ifndef LOG_NTP
+# define LOG_NTP LOG_DAEMON
+# endif
+ openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
+# ifdef DEBUG
+ if (debug)
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ else
+# endif /* DEBUG */
+ setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
+# endif /* LOG_DAEMON */
+#endif /* !SYS_WINNT && !VMS */
+
+ NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
+ msyslog(LOG_NOTICE, "%s", Version);
+}
+
+
+/*
+ * See if we should redirect the logfile
+ */
+
+void
+setup_logfile(
+ void
+ )
+{
+ if (HAVE_OPT( LOGFILE )) {
+ const char *my_optarg = OPT_ARG( LOGFILE );
+ FILE *new_file;
+
+ if(strcmp(my_optarg, "stderr") == 0)
+ new_file = stderr;
+ else if(strcmp(my_optarg, "stdout") == 0)
+ new_file = stdout;
+ else
+ new_file = fopen(my_optarg, "a");
+ if (new_file != NULL) {
+ NLOG(NLOG_SYSINFO)
+ msyslog(LOG_NOTICE, "logging to file %s", my_optarg);
+ if (syslog_file != NULL &&
+ fileno(syslog_file) != fileno(new_file))
+ (void)fclose(syslog_file);
+
+ syslog_file = new_file;
+ syslogit = 0;
+ }
+ else
+ msyslog(LOG_ERR,
+ "Cannot open log file %s",
+ my_optarg);
+ }
+}
#ifdef SIM
int
@@ -225,6 +307,7 @@ main(
#ifdef NO_MAIN_ALLOWED
CALL(ntpd,"ntpd",ntpdmain);
#else
+#ifndef SYS_WINNT
int
main(
int argc,
@@ -233,7 +316,8 @@ main(
{
return ntpdmain(argc, argv);
}
-#endif
+#endif /* SYS_WINNT */
+#endif /* NO_MAIN_ALLOWED */
#endif /* SIM */
#ifdef _AIX
@@ -371,16 +455,30 @@ ntpdmain(
)
{
l_fp now;
- char *cp;
- struct recvbuf *rbuflist;
struct recvbuf *rbuf;
#ifdef _AIX /* HMS: ifdef SIGDANGER? */
struct sigaction sa;
#endif
+ progname = argv[0];
+
initializing = 1; /* mark that we are initializing */
- debug = 0; /* no debugging by default */
- nofork = 0; /* will fork by default */
+
+ {
+ int optct = optionProcess(
+#ifdef SIM
+ &ntpdsimOptions
+#else
+ &ntpdOptions
+#endif
+ , argc, argv);
+ argc -= optct;
+ argv += optct;
+ }
+
+ /* HMS: is this lame? Should we process -l first? */
+
+ init_logging(progname); /* Open the log file */
#ifdef HAVE_UMASK
{
@@ -402,45 +500,102 @@ ntpdmain(
if (uid)
{
msyslog(LOG_ERR, "ntpd: must be run as root, not uid %ld", (long)uid);
+ printf("must be run as root, not uid %ld", (long)uid);
exit(1);
}
}
#endif
-#ifdef SYS_WINNT
- /* Set the Event-ID message-file name. */
- if (!GetModuleFileName(NULL, szMsgPath, sizeof(szMsgPath))) {
- msyslog(LOG_ERR, "GetModuleFileName(PGM_EXE_FILE) failed: %m\n");
+#ifdef OPENSSL
+ if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) {
+ msyslog(LOG_ERR,
+ "ntpd: OpenSSL version mismatch. Built against %lx, you have %lx\n",
+ OPENSSL_VERSION_NUMBER, SSLeay());
exit(1);
}
- addSourceToRegistry("NTP", szMsgPath);
#endif
- getstartup(argc, argv); /* startup configuration, may set debug */
+ /* getstartup(argc, argv); / * startup configuration, may set debug */
+
+#ifdef DEBUG
+ debug = DESC(DEBUG_LEVEL).optOccCt;
if (debug)
printf("%s\n", Version);
+#endif
+
+/*
+ * Enable the Multi-Media Timer for Windows?
+ */
+#ifdef SYS_WINNT
+ if (HAVE_OPT( MODIFYMMTIMER ))
+ set_mm_timer(MM_TIMER_HIRES);
+#endif
+
+ if (HAVE_OPT( NOFORK ) || HAVE_OPT( QUIT ))
+ nofork = 1;
+
+ if (HAVE_OPT( NOVIRTUALIPS ))
+ listen_to_virtual_ips = 0;
+ if (HAVE_OPT( INTERFACE )) {
+#if 0
+ int ifacect = STACKCT_OPT( INTERFACE );
+ char** ifaces = STACKLST_OPT( INTERFACE );
+
+ /* malloc space for the array of names */
+ while (ifacect-- > 0) {
+ next_iface = *ifaces++;
+ }
+#else
+ specific_interface = OPT_ARG( INTERFACE );
+#endif
+ }
+
+ if (HAVE_OPT( NICE ))
+ priority_done = 0;
+
+#if defined(HAVE_SCHED_SETSCHEDULER)
+ if (HAVE_OPT( PRIORITY )) {
+ config_priority = OPT_VALUE_PRIORITY;
+ config_priority_override = 1;
+ priority_done = 0;
+ }
+#endif
+
+#ifdef SYS_WINNT
/*
- * Initialize random generator and public key pair
+ * Initialize the time structures and variables
*/
-#ifdef SYS_WINNT
- /* Initialize random file before OpenSSL checks */
- if(!init_randfile())
- msyslog(LOG_ERR, "Unable to initialize .rnd file\n");
+ init_winnt_time();
#endif
+
+ setup_logfile();
+
+ /*
+ * Initialize random generator and public key pair
+ */
get_systime(&now);
- SRANDOM((int)(now.l_i * now.l_uf));
+
+ ntp_srandom((int)(now.l_i * now.l_uf));
+
+#ifdef HAVE_DNSREGISTRATION
+ /* HMS: does this have to happen this early? */
+ msyslog(LOG_INFO, "Attemping to register mDNS");
+ if ( DNSServiceRegister (&mdns, 0, 0, NULL, "_ntp._udp", NULL, NULL, htons(NTP_PORT), 0, NULL, NULL, NULL) != kDNSServiceErr_NoError ) {
+ msyslog(LOG_ERR, "Unable to register mDNS");
+ }
+#endif
#if !defined(VMS)
# ifndef NODETACH
/*
* Detach us from the terminal. May need an #ifndef GIZMO.
*/
+ if (
# ifdef DEBUG
- if (!debug && !nofork)
-# else /* DEBUG */
- if (!nofork)
+ !debug &&
# endif /* DEBUG */
+ !nofork)
{
# ifndef SYS_WINNT
# ifdef HAVE_DAEMON
@@ -522,131 +677,12 @@ ntpdmain(
#endif /* _AIX */
}
# endif /* not HAVE_DAEMON */
-# else /* SYS_WINNT */
-
- {
- if (NoWinService == FALSE) {
- SERVICE_TABLE_ENTRY dispatchTable[] = {
- { TEXT("NetworkTimeProtocol"), (LPSERVICE_MAIN_FUNCTION)service_main },
- { NULL, NULL }
- };
-
- /* daemonize */
- if (!StartServiceCtrlDispatcher(dispatchTable))
- {
- msyslog(LOG_ERR, "StartServiceCtrlDispatcher: %m");
- ExitProcess(2);
- }
- }
- else {
- service_main(argc, argv);
- return 0;
- }
- }
# endif /* SYS_WINNT */
}
# endif /* NODETACH */
-# if defined(SYS_WINNT) && !defined(NODETACH)
- else
- service_main(argc, argv);
- return 0; /* must return a value */
-} /* end main */
-
-/*
- * If this runs as a service under NT, the main thread will block at
- * StartServiceCtrlDispatcher() and another thread will be started by the
- * Service Control Dispatcher which will begin execution at the routine
- * specified in that call (viz. service_main)
- */
-void
-service_main(
- DWORD argc,
- LPTSTR *argv
- )
-{
- char *cp;
- struct recvbuf *rbuflist;
- struct recvbuf *rbuf;
-
- if(!debug && NoWinService == FALSE)
- {
- /* register our service control handler */
- sshStatusHandle = RegisterServiceCtrlHandler( TEXT("NetworkTimeProtocol"),
- (LPHANDLER_FUNCTION)service_ctrl);
- if(sshStatusHandle == 0)
- {
- msyslog(LOG_ERR, "RegisterServiceCtrlHandler failed: %m");
- return;
- }
-
- /* report pending status to Service Control Manager */
- ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- ssStatus.dwCurrentState = SERVICE_START_PENDING;
- ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
- ssStatus.dwWin32ExitCode = NO_ERROR;
- ssStatus.dwServiceSpecificExitCode = 0;
- ssStatus.dwCheckPoint = 1;
- ssStatus.dwWaitHint = 5000;
- if (!SetServiceStatus(sshStatusHandle, &ssStatus))
- {
- msyslog(LOG_ERR, "SetServiceStatus: %m");
- ssStatus.dwCurrentState = SERVICE_STOPPED;
- SetServiceStatus(sshStatusHandle, &ssStatus);
- return;
- }
-
- } /* debug */
-# endif /* defined(SYS_WINNT) && !defined(NODETACH) */
#endif /* VMS */
- /*
- * Logging. This may actually work on the gizmo board. Find a name
- * to log with by using the basename of argv[0]
- */
- cp = strrchr(argv[0], '/');
- if (cp == 0)
- cp = argv[0];
- else
- cp++;
-
- debug = 0; /* will be immediately re-initialized 8-( */
- getstartup(argc, argv); /* startup configuration, catch logfile this time */
-
-#if !defined(VMS)
-
-# ifndef LOG_DAEMON
- openlog(cp, LOG_PID);
-# else /* LOG_DAEMON */
-
-# ifndef LOG_NTP
-# define LOG_NTP LOG_DAEMON
-# endif
- openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
-# ifdef DEBUG
- if (debug)
- setlogmask(LOG_UPTO(LOG_DEBUG));
- else
-# endif /* DEBUG */
- setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
-# endif /* LOG_DAEMON */
-#endif /* !SYS_WINNT && !VMS */
-
- NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
- msyslog(LOG_NOTICE, "%s", Version);
-
-#ifdef SYS_WINNT
- /* GMS 1/18/1997
- * TODO: lock the process in memory using SetProcessWorkingSetSize() and VirtualLock() functions
- *
- process_handle = GetCurrentProcess();
- if (SetProcessWorkingSetSize(process_handle, 2097152 , 4194304 ) == TRUE) {
- if (VirtualLock(0 , 4194304) == FALSE)
- msyslog(LOG_ERR, "VirtualLock() failed: %m");
- } else {
- msyslog(LOG_ERR, "SetProcessWorkingSetSize() failed: %m");
- }
- */
-#endif /* SYS_WINNT */
+ setup_logfile(); /* We lost any redirect when we daemonized */
#ifdef SCO5_CLOCK
/*
@@ -659,7 +695,7 @@ service_main(
if (fd >= 0) {
int zero = 0;
if (ioctl(fd, ACPU_LOCK, &zero) < 0)
- msyslog(LOG_ERR, "cannot lock to base CPU: %m\n");
+ msyslog(LOG_ERR, "cannot lock to base CPU: %m");
close( fd );
} /* else ...
* If we can't open the device, this probably just isn't
@@ -677,8 +713,9 @@ service_main(
{
struct rlimit rl;
+ /* HMS: must make the rlim_cur amount configurable */
if (getrlimit(RLIMIT_STACK, &rl) != -1
- && (rl.rlim_cur = 20 * 4096) < rl.rlim_max)
+ && (rl.rlim_cur = 50 * 4096) < rl.rlim_max)
{
if (setrlimit(RLIMIT_STACK, &rl) == -1)
{
@@ -686,6 +723,18 @@ service_main(
"Cannot adjust stack limit for mlockall: %m");
}
}
+# ifdef RLIMIT_MEMLOCK
+ /*
+ * The default RLIMIT_MEMLOCK is very low on Linux systems.
+ * Unless we increase this limit malloc calls are likely to
+ * fail if we drop root privlege. To be useful the value
+ * has to be larger than the largest ntpd resident set size.
+ */
+ rl.rlim_cur = rl.rlim_max = 32*1024*1024;
+ if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1) {
+ msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m");
+ }
+# endif /* RLIMIT_MEMLOCK */
}
# endif /* HAVE_SETRLIMIT */
/*
@@ -699,7 +748,7 @@ service_main(
# ifdef _AIX
/*
* set the stack limit for AIX for plock().
- * see get_aix_stack for more info.
+ * see get_aix_stack() for more info.
*/
if (ulimit(SET_STACKLIM, (get_aix_stack() - 8*4096)) < 0)
{
@@ -762,26 +811,20 @@ service_main(
(void) signal_no_reset(SIGPIPE, SIG_IGN);
#endif /* SIGPIPE */
-#if defined SYS_WINNT
- if (!SetConsoleCtrlHandler(OnConsoleEvent, TRUE)) {
- msyslog(LOG_ERR, "Can't set console control handler: %m");
- }
-#endif
-
/*
* Call the init_ routines to initialize the data structures.
+ *
+ * Exactly what command-line options are we expecting here?
*/
-#if defined (HAVE_IO_COMPLETION_PORT)
- init_io_completion_port();
- init_winnt_time();
-#endif
init_auth();
init_util();
init_restrict();
init_mon();
init_timer();
+#if defined (HAVE_IO_COMPLETION_PORT)
+ init_io_completion_port();
+#endif
init_lib();
- init_random();
init_request();
init_control();
init_peer();
@@ -796,102 +839,137 @@ service_main(
/* turn off in config if unwanted */
/*
- * Get configuration. This (including argument list parsing) is
- * done in a separate module since this will definitely be different
- * for the gizmo board. While at it, save the host name for later
- * along with the length. The crypto needs this.
+ * Get the configuration. This is done in a separate module
+ * since this will definitely be different for the gizmo board.
*/
-#ifdef DEBUG
- debug = 0;
-#endif
+
getconfig(argc, argv);
+
+ loop_config(LOOP_DRIFTCOMP, old_drift / 1e6);
#ifdef OPENSSL
crypto_setup();
#endif /* OPENSSL */
initializing = 0;
-#if defined(SYS_WINNT) && !defined(NODETACH)
-# if defined(DEBUG)
- if(!debug)
- {
-# endif
- if (NoWinService == FALSE) {
- /* report to the service control manager that the service is running */
- ssStatus.dwCurrentState = SERVICE_RUNNING;
- ssStatus.dwWin32ExitCode = NO_ERROR;
- if (!SetServiceStatus(sshStatusHandle, &ssStatus))
- {
- msyslog(LOG_ERR, "SetServiceStatus: %m");
- if (ResolverThreadHandle != NULL)
- CloseHandle(ResolverThreadHandle);
- ssStatus.dwCurrentState = SERVICE_STOPPED;
- SetServiceStatus(sshStatusHandle, &ssStatus);
- return;
- }
- }
-# if defined(DEBUG)
- }
-# endif
-#endif
+#ifdef HAVE_DROPROOT
+ if( droproot ) {
+ /* Drop super-user privileges and chroot now if the OS supports this */
-#ifdef HAVE_CLOCKCTL
- /*
- * Drop super-user privileges and chroot now if the OS supports
- * non root clock control (only NetBSD for now).
- */
- if (user != NULL) {
- if (isdigit((unsigned char)*user)) {
- sw_uid = (uid_t)strtoul(user, &endp, 0);
- if (*endp != '\0')
- goto getuser;
- } else {
+#ifdef HAVE_LINUX_CAPABILITIES
+ /* set flag: keep privileges accross setuid() call (we only really need cap_sys_time): */
+ if( prctl( PR_SET_KEEPCAPS, 1L, 0L, 0L, 0L ) == -1 ) {
+ msyslog( LOG_ERR, "prctl( PR_SET_KEEPCAPS, 1L ) failed: %m" );
+ exit(-1);
+ }
+#else
+ /* we need a user to switch to */
+ if( user == NULL ) {
+ msyslog(LOG_ERR, "Need user name to drop root privileges (see -u flag!)" );
+ exit(-1);
+ }
+#endif /* HAVE_LINUX_CAPABILITIES */
+
+ if (user != NULL) {
+ if (isdigit((unsigned char)*user)) {
+ sw_uid = (uid_t)strtoul(user, &endp, 0);
+ if (*endp != '\0')
+ goto getuser;
+ } else {
getuser:
- if ((pw = getpwnam(user)) != NULL) {
- sw_uid = pw->pw_uid;
- } else {
- errno = 0;
- msyslog(LOG_ERR, "Cannot find user `%s'", user);
- exit (-1);
- }
- }
- }
- if (group != NULL) {
- if (isdigit((unsigned char)*group)) {
- sw_gid = (gid_t)strtoul(group, &endp, 0);
- if (*endp != '\0')
- goto getgroup;
- } else {
+ if ((pw = getpwnam(user)) != NULL) {
+ sw_uid = pw->pw_uid;
+ } else {
+ errno = 0;
+ msyslog(LOG_ERR, "Cannot find user `%s'", user);
+ exit (-1);
+ }
+ }
+ }
+ if (group != NULL) {
+ if (isdigit((unsigned char)*group)) {
+ sw_gid = (gid_t)strtoul(group, &endp, 0);
+ if (*endp != '\0')
+ goto getgroup;
+ } else {
getgroup:
- if ((gr = getgrnam(group)) != NULL) {
- sw_gid = pw->pw_gid;
- } else {
- errno = 0;
- msyslog(LOG_ERR, "Cannot find group `%s'", group);
- exit (-1);
- }
- }
- }
- if (chrootdir && chroot(chrootdir)) {
- msyslog(LOG_ERR, "Cannot chroot to `%s': %m", chrootdir);
- exit (-1);
- }
- if (group && setgid(sw_gid)) {
- msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group);
- exit (-1);
- }
- if (group && setegid(sw_gid)) {
- msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group);
- exit (-1);
- }
- if (user && setuid(sw_uid)) {
- msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user);
- exit (-1);
- }
- if (user && seteuid(sw_uid)) {
- msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user);
- exit (-1);
- }
+ if ((gr = getgrnam(group)) != NULL) {
+ sw_gid = gr->gr_gid;
+ } else {
+ errno = 0;
+ msyslog(LOG_ERR, "Cannot find group `%s'", group);
+ exit (-1);
+ }
+ }
+ }
+
+ if( chrootdir ) {
+ /* make sure cwd is inside the jail: */
+ if( chdir(chrootdir) ) {
+ msyslog(LOG_ERR, "Cannot chdir() to `%s': %m", chrootdir);
+ exit (-1);
+ }
+ if( chroot(chrootdir) ) {
+ msyslog(LOG_ERR, "Cannot chroot() to `%s': %m", chrootdir);
+ exit (-1);
+ }
+ }
+ if (group && setgid(sw_gid)) {
+ msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group);
+ exit (-1);
+ }
+ if (group && setegid(sw_gid)) {
+ msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group);
+ exit (-1);
+ }
+ if (user && setuid(sw_uid)) {
+ msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user);
+ exit (-1);
+ }
+ if (user && seteuid(sw_uid)) {
+ msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user);
+ exit (-1);
+ }
+
+#ifndef HAVE_LINUX_CAPABILITIES
+ /*
+ * for now assume that the privilege to bind to privileged ports
+ * is associated with running with uid 0 - should be refined on
+ * ports that allow binding to NTP_PORT with uid != 0
+ */
+ disable_dynamic_updates |= (sw_uid != 0); /* also notifies routing message listener */
#endif
+
+ if (disable_dynamic_updates && interface_interval) {
+ interface_interval = 0;
+ msyslog(LOG_INFO, "running in unprivileged mode disables dynamic interface tracking");
+ }
+
+#ifdef HAVE_LINUX_CAPABILITIES
+ do {
+ /*
+ * We may be running under non-root uid now, but we still hold full root privileges!
+ * We drop all of them, except for the crucial one or two: cap_sys_time and
+ * cap_net_bind_service if doing dynamic interface tracking.
+ */
+ cap_t caps;
+ char *captext = interface_interval ?
+ "cap_sys_time,cap_net_bind_service=ipe" :
+ "cap_sys_time=ipe";
+ if( ! ( caps = cap_from_text( captext ) ) ) {
+ msyslog( LOG_ERR, "cap_from_text() failed: %m" );
+ exit(-1);
+ }
+ if( cap_set_proc( caps ) == -1 ) {
+ msyslog( LOG_ERR, "cap_set_proc() failed to drop root privileges: %m" );
+ exit(-1);
+ }
+ cap_free( caps );
+ } while(0);
+#endif /* HAVE_LINUX_CAPABILITIES */
+
+ } /* if( droproot ) */
+#endif /* HAVE_DROPROOT */
+
/*
* Report that we're up to any trappers
*/
@@ -913,48 +991,13 @@ getgroup:
* yet to learn about anything else that is.
*/
#if defined(HAVE_IO_COMPLETION_PORT)
- WaitHandles[0] = CreateEvent(NULL, FALSE, FALSE, NULL); /* exit reques */
- WaitHandles[1] = get_timer_handle();
- WaitHandles[2] = get_io_event();
-
- for (;;) {
- DWORD Index = WaitForMultipleObjectsEx(sizeof(WaitHandles)/sizeof(WaitHandles[0]), WaitHandles, FALSE, 1000, TRUE);
- switch (Index) {
- case WAIT_OBJECT_0 + 0 : /* exit request */
- exit(0);
- break;
-
- case WAIT_OBJECT_0 + 1 : /* timer */
- timer();
- break;
-
- case WAIT_OBJECT_0 + 2 : /* Io event */
-# ifdef DEBUG
- if ( debug > 3 )
- {
- printf( "IoEvent occurred\n" );
- }
-# endif
- break;
-
- case WAIT_IO_COMPLETION : /* loop */
- case WAIT_TIMEOUT :
- break;
- case WAIT_FAILED:
- msyslog(LOG_ERR, "ntpdc: WaitForMultipleObjectsEx Failed: Error: %m");
- break;
-
- /* For now do nothing if not expected */
- default:
- break;
-
- } /* switch */
- rbuflist = getrecvbufs(); /* get received buffers */
+ for (;;) {
+ int tot_full_recvbufs = GetReceivedBuffers();
#else /* normal I/O */
+ BLOCK_IO_AND_ALARM();
was_alarmed = 0;
- rbuflist = (struct recvbuf *)0;
for (;;)
{
# if !defined(HAVE_SIGNALED_IO)
@@ -963,18 +1006,15 @@ getgroup:
fd_set rdfdes;
int nfound;
-# elif defined(HAVE_SIGNALED_IO)
- block_io_and_alarm();
# endif
- rbuflist = getrecvbufs(); /* get received buffers */
if (alarm_flag) /* alarmed? */
{
was_alarmed = 1;
alarm_flag = 0;
}
- if (!was_alarmed && rbuflist == (struct recvbuf *)0)
+ if (!was_alarmed && has_full_recv_buffer() == ISC_FALSE)
{
/*
* Nothing to do. Wait for something.
@@ -1003,10 +1043,10 @@ getgroup:
(void)input_handler(&ts);
}
else if (nfound == -1 && errno != EINTR)
- msyslog(LOG_ERR, "select() error: %m");
+ netsyslog(LOG_ERR, "select() error: %m");
# ifdef DEBUG
- else if (debug > 2)
- msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
+ else if (debug > 5)
+ netsyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
# endif /* DEBUG */
# else /* HAVE_SIGNALED_IO */
@@ -1017,50 +1057,87 @@ getgroup:
was_alarmed = 1;
alarm_flag = 0;
}
- rbuflist = getrecvbufs(); /* get received buffers */
}
-# ifdef HAVE_SIGNALED_IO
- unblock_io_and_alarm();
-# endif /* HAVE_SIGNALED_IO */
- /*
- * Out here, signals are unblocked. Call timer routine
- * to process expiry.
- */
if (was_alarmed)
{
+ UNBLOCK_IO_AND_ALARM();
+ /*
+ * Out here, signals are unblocked. Call timer routine
+ * to process expiry.
+ */
timer();
was_alarmed = 0;
+ BLOCK_IO_AND_ALARM();
}
#endif /* HAVE_IO_COMPLETION_PORT */
- /*
- * Call the data procedure to handle each received
- * packet.
- */
- while (rbuflist != (struct recvbuf *)0)
+
+#ifdef DEBUG_TIMING
{
- rbuf = rbuflist;
- rbuflist = rbuf->next;
- (rbuf->receiver)(rbuf);
- freerecvbuf(rbuf);
+ l_fp pts;
+ l_fp tsa, tsb;
+ int bufcount = 0;
+
+ get_systime(&pts);
+ tsa = pts;
+#endif
+ rbuf = get_full_recv_buffer();
+ while (rbuf != NULL)
+ {
+ if (alarm_flag)
+ {
+ was_alarmed = 1;
+ alarm_flag = 0;
+ }
+ UNBLOCK_IO_AND_ALARM();
+
+ if (was_alarmed)
+ { /* avoid timer starvation during lengthy I/O handling */
+ timer();
+ was_alarmed = 0;
+ }
+
+ /*
+ * Call the data procedure to handle each received
+ * packet.
+ */
+ if (rbuf->receiver != NULL) /* This should always be true */
+ {
+#ifdef DEBUG_TIMING
+ l_fp dts = pts;
+
+ L_SUB(&dts, &rbuf->recv_time);
+ DPRINTF(2, ("processing timestamp delta %s (with prec. fuzz)\n", lfptoa(&dts, 9)));
+ collect_timing(rbuf, "buffer processing delay", 1, &dts);
+ bufcount++;
+#endif
+ (rbuf->receiver)(rbuf);
+ } else {
+ msyslog(LOG_ERR, "receive buffer corruption - receiver found to be NULL - ABORTING");
+ abort();
+ }
+
+ BLOCK_IO_AND_ALARM();
+ freerecvbuf(rbuf);
+ rbuf = get_full_recv_buffer();
+ }
+#ifdef DEBUG_TIMING
+ get_systime(&tsb);
+ L_SUB(&tsb, &tsa);
+ if (bufcount) {
+ collect_timing(NULL, "processing", bufcount, &tsb);
+ DPRINTF(2, ("processing time for %d buffers %s\n", bufcount, lfptoa(&tsb, 9)));
+ }
}
-#if defined DEBUG && defined SYS_WINNT
- if (debug > 4)
- printf("getrecvbufs: %ld handler interrupts, %ld frames\n",
- handler_calls, handler_pkts);
#endif
/*
* Go around again
*/
}
-#ifndef SYS_WINNT
- exit(1); /* unreachable */
-#endif
-#ifndef SYS_WINNT
- return 1; /* DEC OSF cc braindamage */
-#endif
+ UNBLOCK_IO_AND_ALARM();
+ return 1;
}
@@ -1075,6 +1152,11 @@ finish(
{
msyslog(LOG_NOTICE, "ntpd exiting on signal %d", sig);
+ write_stats();
+#ifdef HAVE_DNSREGISTRATION
+ if (mdns != NULL)
+ DNSServiceRefDeallocate(mdns);
+#endif
switch (sig)
{
@@ -1131,7 +1213,8 @@ lessdebug(
}
#endif
#else /* not DEBUG */
-#ifndef SYS_WINNT/*
+#ifndef SYS_WINNT
+/*
* no_debug - We don't do the debug here.
*/
static RETSIGTYPE
@@ -1146,129 +1229,3 @@ no_debug(
}
#endif /* not SYS_WINNT */
#endif /* not DEBUG */
-
-#ifdef SYS_WINNT
-/* service_ctrl - control handler for NTP service
- * signals the service_main routine of start/stop requests
- * from the control panel or other applications making
- * win32API calls
- */
-void
-service_ctrl(
- DWORD dwCtrlCode
- )
-{
- DWORD dwState = SERVICE_RUNNING;
-
- /* Handle the requested control code */
- switch(dwCtrlCode)
- {
- case SERVICE_CONTROL_PAUSE:
- /* see no reason to support this */
- break;
-
- case SERVICE_CONTROL_CONTINUE:
- /* see no reason to support this */
- break;
-
- case SERVICE_CONTROL_STOP:
- dwState = SERVICE_STOP_PENDING;
- /*
- * Report the status, specifying the checkpoint and waithint,
- * before setting the termination event.
- */
- ssStatus.dwCurrentState = dwState;
- ssStatus.dwWin32ExitCode = NO_ERROR;
- ssStatus.dwWaitHint = 3000;
- if (!SetServiceStatus(sshStatusHandle, &ssStatus))
- {
- msyslog(LOG_ERR, "SetServiceStatus: %m");
- }
- if (WaitHandles[0] != NULL) {
- SetEvent(WaitHandles[0]);
- }
- return;
-
- case SERVICE_CONTROL_INTERROGATE:
- /* Update the service status */
- break;
-
- default:
- /* invalid control code */
- break;
-
- }
-
- ssStatus.dwCurrentState = dwState;
- ssStatus.dwWin32ExitCode = NO_ERROR;
- if (!SetServiceStatus(sshStatusHandle, &ssStatus))
- {
- msyslog(LOG_ERR, "SetServiceStatus: %m");
- }
-}
-
-static BOOL WINAPI
-OnConsoleEvent(
- DWORD dwCtrlType
- )
-{
- switch (dwCtrlType) {
- case CTRL_BREAK_EVENT :
- if (debug > 0) {
- debug <<= 1;
- }
- else {
- debug = 1;
- }
- if (debug > 8) {
- debug = 0;
- }
- printf("debug level %d\n", debug);
- break ;
-
- case CTRL_C_EVENT :
- case CTRL_CLOSE_EVENT :
- case CTRL_SHUTDOWN_EVENT :
- if (WaitHandles[0] != NULL) {
- SetEvent(WaitHandles[0]);
- }
- break;
-
- default :
- return FALSE;
-
-
- }
- return TRUE;;
-}
-
-
-/*
- * NT version of exit() - all calls to exit() should be routed to
- * this function.
- */
-void
-service_exit(
- int status
- )
-{
- if (!debug) { /* did not become a service, simply exit */
- /* service mode, need to have the service_main routine
- * register with the service control manager that the
- * service has stopped running, before exiting
- */
- ssStatus.dwCurrentState = SERVICE_STOPPED;
- SetServiceStatus(sshStatusHandle, &ssStatus);
-
- }
- uninit_io_completion_port();
- reset_winnt_time();
-
-# if defined _MSC_VER
- _CrtDumpMemoryLeaks();
-# endif
-#undef exit
- exit(status);
-}
-
-#endif /* SYS_WINNT */