diff options
Diffstat (limited to 'ntpdate')
-rw-r--r-- | ntpdate/Makefile.am | 22 | ||||
-rw-r--r-- | ntpdate/Makefile.in | 481 | ||||
-rw-r--r-- | ntpdate/README | 7 | ||||
-rw-r--r-- | ntpdate/ntpdate.c | 2225 | ||||
-rw-r--r-- | ntpdate/ntpdate.h | 104 | ||||
-rw-r--r-- | ntpdate/ntptime_config.c | 552 | ||||
-rw-r--r-- | ntpdate/ntptimeset.c | 2171 |
7 files changed, 5562 insertions, 0 deletions
diff --git a/ntpdate/Makefile.am b/ntpdate/Makefile.am new file mode 100644 index 000000000000..bfe3fea664c5 --- /dev/null +++ b/ntpdate/Makefile.am @@ -0,0 +1,22 @@ +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +#bin_PROGRAMS = ntpdate ntptimeset +bin_PROGRAMS = ntpdate +EXTRA_PROGRAMS = ntptimeset +ntptimeset_SOURCES = ntptimeset.c ntptime_config.c +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o ../libntp/libntp.a +DISTCLEANFILES = .version version.c stamp-v +noinst_HEADERS = ntpdate.h +#EXTRA_DIST = ntpdate.mak +ETAGS_ARGS = Makefile.am + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +version.o: $(ntpdate_OBJECTS) ../libntp/libntp.a Makefile $(top_srcdir)/version + env CSET=`cat $(top_srcdir)/version` $(top_builddir)/scripts/mkver ntpdate + $(COMPILE) -c version.c diff --git a/ntpdate/Makefile.in b/ntpdate/Makefile.in new file mode 100644 index 000000000000..391f494a01e5 --- /dev/null +++ b/ntpdate/Makefile.in @@ -0,0 +1,481 @@ +# Makefile.in generated by automake 1.7.7 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +ARLIB_DIR = @ARLIB_DIR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DCFD = @DCFD@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EF_LIBS = @EF_LIBS@ +EF_PROGS = @EF_PROGS@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LCRYPTO = @LCRYPTO@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBPARSE = @LIBPARSE@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBNTPSIM = @MAKE_LIBNTPSIM@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_NTPDSIM = @MAKE_NTPDSIM@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_NTP_KEYGEN = @MAKE_NTP_KEYGEN@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_SNTP = @MAKE_SNTP@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +MAKE_TIMETRIM = @MAKE_TIMETRIM@ +OBJEXT = @OBJEXT@ +OPENSSL = @OPENSSL@ +OPENSSL_INC = @OPENSSL_INC@ +OPENSSL_LIB = @OPENSSL_LIB@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PERL = @PATH_PERL@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +READLINE_LIBS = @READLINE_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ + +#AUTOMAKE_OPTIONS = ../util/ansi2knr no-dependencies +AUTOMAKE_OPTIONS = ../util/ansi2knr +#bin_PROGRAMS = ntpdate ntptimeset +bin_PROGRAMS = ntpdate +EXTRA_PROGRAMS = ntptimeset +ntptimeset_SOURCES = ntptimeset.c ntptime_config.c +INCLUDES = -I$(top_srcdir)/include +# LDADD might need RESLIB and ADJLIB +LDADD = version.o ../libntp/libntp.a +DISTCLEANFILES = .version version.c stamp-v +noinst_HEADERS = ntpdate.h +#EXTRA_DIST = ntpdate.mak +ETAGS_ARGS = Makefile.am +subdir = ntpdate +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +EXTRA_PROGRAMS = ntptimeset$(EXEEXT) +bin_PROGRAMS = ntpdate$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) + +ntpdate_SOURCES = ntpdate.c +ntpdate_OBJECTS = ntpdate$U.$(OBJEXT) +ntpdate_LDADD = $(LDADD) +ntpdate_DEPENDENCIES = version.o ../libntp/libntp.a +ntpdate_LDFLAGS = +am_ntptimeset_OBJECTS = ntptimeset$U.$(OBJEXT) \ + ntptime_config$U.$(OBJEXT) +ntptimeset_OBJECTS = $(am_ntptimeset_OBJECTS) +ntptimeset_LDADD = $(LDADD) +ntptimeset_DEPENDENCIES = version.o ../libntp/libntp.a +ntptimeset_LDFLAGS = + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ntpdate$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntptime_config$U.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/ntptimeset$U.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = ntpdate.c $(ntptimeset_SOURCES) +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) $(srcdir)/Makefile.in \ + Makefile.am +SOURCES = ntpdate.c $(ntptimeset_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu ntpdate/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +ntpdate$(EXEEXT): $(ntpdate_OBJECTS) $(ntpdate_DEPENDENCIES) + @rm -f ntpdate$(EXEEXT) + $(LINK) $(ntpdate_LDFLAGS) $(ntpdate_OBJECTS) $(ntpdate_LDADD) $(LIBS) +ntptimeset$(EXEEXT): $(ntptimeset_OBJECTS) $(ntptimeset_DEPENDENCIES) + @rm -f ntptimeset$(EXEEXT) + $(LINK) $(ntptimeset_LDFLAGS) $(ntptimeset_OBJECTS) $(ntptimeset_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +ANSI2KNR = ../util/ansi2knr +../util/ansi2knr: + cd ../util && $(MAKE) $(AM_MAKEFLAGS) ansi2knr + +mostlyclean-kr: + -test "$U" = "" || rm -f *_.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntpdate$U.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntptime_config$U.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntptimeset$U.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` +ntpdate_.c: ntpdate.c $(ANSI2KNR) + $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntpdate.c; then echo $(srcdir)/ntpdate.c; else echo ntpdate.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ +ntptime_config_.c: ntptime_config.c $(ANSI2KNR) + $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntptime_config.c; then echo $(srcdir)/ntptime_config.c; else echo ntptime_config.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ +ntptimeset_.c: ntptimeset.c $(ANSI2KNR) + $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/ntptimeset.c; then echo $(srcdir)/ntptimeset.c; else echo ntptimeset.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@ +ntpdate_.$(OBJEXT) ntptime_config_.$(OBJEXT) ntptimeset_.$(OBJEXT) : \ +$(ANSI2KNR) +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile + +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic mostlyclean-kr + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am info \ + info-am install install-am install-binPROGRAMS install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-kr pdf pdf-am ps ps-am tags \ + uninstall uninstall-am uninstall-binPROGRAMS uninstall-info-am + + +$(PROGRAMS): $(LDADD) + +../libntp/libntp.a: + cd ../libntp && $(MAKE) + +version.o: $(ntpdate_OBJECTS) ../libntp/libntp.a Makefile $(top_srcdir)/version + env CSET=`cat $(top_srcdir)/version` $(top_builddir)/scripts/mkver ntpdate + $(COMPILE) -c version.c +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ntpdate/README b/ntpdate/README new file mode 100644 index 000000000000..27b51ed363ac --- /dev/null +++ b/ntpdate/README @@ -0,0 +1,7 @@ +README file for directory ./ntpdate of the NTP Version 4 distribution + +This directory contains the sources for the ntpdate utility program. See +the README and RELNOTES files in the parent directory for directions on +how to make and install this program. The current version number of this +program is in the version.c file. + diff --git a/ntpdate/ntpdate.c b/ntpdate/ntpdate.c new file mode 100644 index 000000000000..b2cbe7e7e356 --- /dev/null +++ b/ntpdate/ntpdate.c @@ -0,0 +1,2225 @@ +/* + * ntpdate - set the time of day by polling one or more NTP servers + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef HAVE_NETINFO +#include <netinfo/ni.h> +#endif + +#include "ntp_machine.h" +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntpdate.h" +#include "ntp_string.h" +#include "ntp_syslog.h" +#include "ntp_select.h" +#include "ntp_stdlib.h" + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#ifdef HAVE_POLL_H +# include <poll.h> +#endif +#ifndef SYS_WINNT +# include <netdb.h> +# ifdef HAVE_SYS_SIGNAL_H +# include <sys/signal.h> +# else +# include <signal.h> +# endif +# ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +# endif +#endif /* SYS_WINNT */ +#ifdef HAVE_SYS_RESOURCE_H +# include <sys/resource.h> +#endif /* HAVE_SYS_RESOURCE_H */ + +#include <arpa/inet.h> + +#ifdef __QNXNTO__ +# include "adjtime.h" +#endif + +#ifdef SYS_VXWORKS +# include "ioLib.h" +# include "sockLib.h" +# include "timers.h" + +/* select wants a zero structure ... */ +struct timeval timeout = {0,0}; +#else +struct timeval timeout = {60,0}; +#endif + +#ifdef HAVE_NETINFO +#include <netinfo/ni.h> +#endif + +#include "recvbuff.h" + +#ifdef SYS_WINNT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#define TARGET_RESOLUTION 1 /* Try for 1-millisecond accuracy + on Windows NT timers. */ +#pragma comment(lib, "winmm") +#endif /* SYS_WINNT */ + +/* + * Scheduling priority we run at + */ +#ifndef SYS_VXWORKS +# define NTPDATE_PRIO (-12) +#else +# define NTPDATE_PRIO (100) +#endif + +#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE) +/* POSIX TIMERS - vxWorks doesn't have itimer - casey */ +static timer_t ntpdate_timerid; +#endif + +/* + * Compatibility stuff for Version 2 + */ +#define NTP_MAXSKW 0x28f /* 0.01 sec in fp format */ +#define NTP_MINDIST 0x51f /* 0.02 sec in fp format */ +#define PEER_MAXDISP (64*FP_SECOND) /* maximum dispersion (fp 64) */ +#define NTP_INFIN 15 /* max stratum, infinity a la Bellman-Ford */ +#define NTP_MAXWGT (8*FP_SECOND) /* maximum select weight 8 seconds */ +#define NTP_MAXLIST 5 /* maximum select list size */ +#define PEER_SHIFT 8 /* 8 suitable for crystal time base */ + +/* + * Debugging flag + */ +volatile int debug = 0; + +/* + * File descriptor masks etc. for call to select + */ + +int ai_fam_templ; +int nbsock; +SOCKET fd[MAX_AF]; /* support up to 2 sockets */ +int fd_family[MAX_AF]; /* to remember the socket family */ +#ifdef HAVE_POLL_H +struct pollfd fdmask[MAX_AF]; +#else +fd_set fdmask; +int maxfd; +#endif +int polltest = 0; + +/* + * Initializing flag. All async routines watch this and only do their + * thing when it is clear. + */ +int initializing = 1; + +/* + * Alarm flag. Set when an alarm occurs + */ +volatile int alarm_flag = 0; + +/* + * Simple query flag. + */ +int simple_query = 0; + +/* + * Unpriviledged port flag. + */ +int unpriv_port = 0; + +/* + * Time to spend measuring drift rate + */ +int rate = 0; + +/* + * Program name. + */ +char *progname; + +/* + * Systemwide parameters and flags + */ +int sys_samples = DEFSAMPLES; /* number of samples/server */ +u_long sys_timeout = DEFTIMEOUT; /* timeout time, in TIMER_HZ units */ +struct server *sys_servers; /* the server list */ +int sys_numservers = 0; /* number of servers to poll */ +int sys_authenticate = 0; /* true when authenticating */ +u_int32 sys_authkey = 0; /* set to authentication key in use */ +u_long sys_authdelay = 0; /* authentication delay */ +int sys_version = NTP_VERSION; /* version to poll with */ + +/* + * The current internal time + */ +u_long current_time = 0; + +/* + * Counter for keeping track of completed servers + */ +int complete_servers = 0; + +/* + * File of encryption keys + */ + +#ifndef KEYFILE +# ifndef SYS_WINNT +#define KEYFILE "/etc/ntp.keys" +# else +#define KEYFILE "%windir%\\ntp.keys" +# endif /* SYS_WINNT */ +#endif /* KEYFILE */ + +#ifndef SYS_WINNT +const char *key_file = KEYFILE; +#else +char key_file_storage[MAX_PATH+1], *key_file ; +#endif /* SYS_WINNT */ + +/* + * Miscellaneous flags + */ +int verbose = 0; +int always_step = 0; +int never_step = 0; + +int ntpdatemain P((int, char **)); + +static void transmit P((struct server *)); +static void receive P((struct recvbuf *)); +static void server_data P((struct server *, s_fp, l_fp *, u_fp)); +static void clock_filter P((struct server *)); +static struct server *clock_select P((void)); +static int clock_adjust P((void)); +static void addserver P((char *)); +static struct server *findserver P((struct sockaddr_storage *)); + void timer P((void)); +static void init_alarm P((void)); +#ifndef SYS_WINNT +static RETSIGTYPE alarming P((int)); +#endif /* SYS_WINNT */ +static void init_io P((void)); +static void sendpkt P((struct sockaddr_storage *, struct pkt *, int)); +void input_handler P((void)); + +static int l_adj_systime P((l_fp *)); +static int l_step_systime P((l_fp *)); + +static void printserver P((struct server *, FILE *)); + +#ifdef SYS_WINNT +int on = 1; +WORD wVersionRequested; +WSADATA wsaData; +HANDLE TimerThreadHandle = NULL; +#endif /* SYS_WINNT */ + +#ifdef NO_MAIN_ALLOWED +CALL(ntpdate,"ntpdate",ntpdatemain); + +void clear_globals() +{ + /* + * Debugging flag + */ + debug = 0; + + ntp_optind = 0; + /* + * Initializing flag. All async routines watch this and only do their + * thing when it is clear. + */ + initializing = 1; + + /* + * Alarm flag. Set when an alarm occurs + */ + alarm_flag = 0; + + /* + * Simple query flag. + */ + simple_query = 0; + + /* + * Unpriviledged port flag. + */ + unpriv_port = 0; + + /* + * Time to spend measuring drift rate + */ + rate = 0; + /* + * Systemwide parameters and flags + */ + sys_numservers = 0; /* number of servers to poll */ + sys_authenticate = 0; /* true when authenticating */ + sys_authkey = 0; /* set to authentication key in use */ + sys_authdelay = 0; /* authentication delay */ + sys_version = NTP_VERSION; /* version to poll with */ + + /* + * The current internal time + */ + current_time = 0; + + /* + * Counter for keeping track of completed servers + */ + complete_servers = 0; + verbose = 0; + always_step = 0; + never_step = 0; +} +#endif + +#ifdef HAVE_NETINFO +static ni_namelist *getnetinfoservers P((void)); +#endif + +/* + * Main program. Initialize us and loop waiting for I/O and/or + * timer expiries. + */ +#ifndef NO_MAIN_ALLOWED +int +main( + int argc, + char *argv[] + ) +{ + return ntpdatemain (argc, argv); +} +#endif /* NO_MAIN_ALLOWED */ + +int +ntpdatemain ( + int argc, + char *argv[] + ) +{ + int was_alarmed; + struct recvbuf *rbuflist; + struct recvbuf *rbuf; + l_fp tmp; + int errflg; + int c; + int nfound; + +#ifdef HAVE_NETINFO + ni_namelist *netinfoservers; +#endif +#ifdef SYS_WINNT + HANDLE process_handle; + + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) { + netsyslog(LOG_ERR, "No useable winsock.dll: %m"); + exit(1); + } + + key_file = key_file_storage; + + if (!ExpandEnvironmentStrings(KEYFILE, key_file, MAX_PATH)) + { + msyslog(LOG_ERR, "ExpandEnvironmentStrings(KEYFILE) failed: %m\n"); + } +#endif /* SYS_WINNT */ + +#ifdef NO_MAIN_ALLOWED + clear_globals(); +#endif + + errflg = 0; + progname = argv[0]; + syslogit = 0; + + /* + * Decode argument list + */ + while ((c = ntp_getopt(argc, argv, "46a:bBde:k:o:p:qr:st:uv")) != EOF) + switch (c) + { + case '4': + ai_fam_templ = AF_INET; + break; + case '6': + ai_fam_templ = AF_INET6; + break; + case 'a': + c = atoi(ntp_optarg); + sys_authenticate = 1; + sys_authkey = c; + break; + case 'b': + always_step++; + never_step = 0; + break; + case 'B': + never_step++; + always_step = 0; + break; + case 'd': + ++debug; + break; + case 'e': + if (!atolfp(ntp_optarg, &tmp) + || tmp.l_ui != 0) { + (void) fprintf(stderr, + "%s: encryption delay %s is unlikely\n", + progname, ntp_optarg); + errflg++; + } else { + sys_authdelay = tmp.l_uf; + } + break; + case 'k': + key_file = ntp_optarg; + break; + case 'o': + sys_version = atoi(ntp_optarg); + break; + case 'p': + c = atoi(ntp_optarg); + if (c <= 0 || c > NTP_SHIFT) { + (void) fprintf(stderr, + "%s: number of samples (%d) is invalid\n", + progname, c); + errflg++; + } else { + sys_samples = c; + } + break; + case 'q': + simple_query = 1; + break; + case 'r': + c = atoi(ntp_optarg); + if (c <= 0 || c > (60 * 60)) { + (void) fprintf(stderr, + "%s: rate (%d) is invalid: 0 - %d\n", + progname, c, (60 * 60)); + errflg++; + } else { + rate = c; + } + break; + case 's': + syslogit = 1; + break; + case 't': + if (!atolfp(ntp_optarg, &tmp)) { + (void) fprintf(stderr, + "%s: timeout %s is undecodeable\n", + progname, ntp_optarg); + errflg++; + } else { + sys_timeout = ((LFPTOFP(&tmp) * TIMER_HZ) + + 0x8000) >> 16; + if (sys_timeout == 0) + sys_timeout = 1; + } + break; + case 'v': + verbose = 1; + break; + case 'u': + unpriv_port = 1; + break; + case '?': + ++errflg; + break; + default: + break; + } + + if (errflg) { + (void) fprintf(stderr, + "usage: %s [-46bBdqsuv] [-a key#] [-e delay] [-k file] [-p samples] [-o version#] [-r rate] [-t timeo] server ...\n", + progname); + exit(2); + } + + if (debug || simple_query) { +#ifdef HAVE_SETVBUF + static char buf[BUFSIZ]; + setvbuf(stdout, buf, _IOLBF, BUFSIZ); +#else + setlinebuf(stdout); +#endif + } + + /* + * Logging. Open the syslog if we have to + */ + if (syslogit) { +#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32 +# ifndef LOG_DAEMON + openlog("ntpdate", LOG_PID); +# else + +# ifndef LOG_NTP +# define LOG_NTP LOG_DAEMON +# endif + openlog("ntpdate", LOG_PID | LOG_NDELAY, LOG_NTP); + if (debug) + setlogmask(LOG_UPTO(LOG_DEBUG)); + else + setlogmask(LOG_UPTO(LOG_INFO)); +# endif /* LOG_DAEMON */ +#endif /* SYS_WINNT */ + } + + if (debug || verbose) + msyslog(LOG_NOTICE, "%s", Version); + + /* + * Add servers we are going to be polling + */ +#ifdef HAVE_NETINFO + netinfoservers = getnetinfoservers(); +#endif + + for ( ; ntp_optind < argc; ntp_optind++) + addserver(argv[ntp_optind]); + +#ifdef HAVE_NETINFO + if (netinfoservers) { + if ( netinfoservers->ni_namelist_len && + *netinfoservers->ni_namelist_val ) { + u_int servercount = 0; + while (servercount < netinfoservers->ni_namelist_len) { + if (debug) msyslog(LOG_DEBUG, + "Adding time server %s from NetInfo configuration.", + netinfoservers->ni_namelist_val[servercount]); + addserver(netinfoservers->ni_namelist_val[servercount++]); + } + } + ni_namelist_free(netinfoservers); + free(netinfoservers); + } +#endif + + if (sys_numservers == 0) { + msyslog(LOG_ERR, "no servers can be used, exiting"); + exit(1); + } + + /* + * Initialize the time of day routines and the I/O subsystem + */ + if (sys_authenticate) { + init_auth(); + if (!authreadkeys(key_file)) { + msyslog(LOG_ERR, "no key file <%s>, exiting", key_file); + exit(1); + } + authtrust(sys_authkey, 1); + if (!authistrusted(sys_authkey)) { + char buf[10]; + + (void) sprintf(buf, "%lu", (unsigned long)sys_authkey); + msyslog(LOG_ERR, "authentication key %s unknown", buf); + exit(1); + } + } + init_io(); + init_alarm(); + + /* + * Set the priority. + */ +#ifdef SYS_VXWORKS + taskPrioritySet( taskIdSelf(), NTPDATE_PRIO); +#endif +#if defined(HAVE_ATT_NICE) + nice (NTPDATE_PRIO); +#endif +#if defined(HAVE_BSD_NICE) + (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO); +#endif +#ifdef SYS_WINNT + process_handle = GetCurrentProcess(); + if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) { + msyslog(LOG_ERR, "SetPriorityClass failed: %m"); + } +#endif /* SYS_WINNT */ + + + + initializing = 0; + was_alarmed = 0; + rbuflist = (struct recvbuf *)0; + + while (complete_servers < sys_numservers) { +#ifdef HAVE_POLL_H + struct pollfd* rdfdes; + rdfdes = fdmask; +#else + fd_set rdfdes; + rdfdes = fdmask; +#endif + + if (alarm_flag) { /* alarmed? */ + was_alarmed = 1; + alarm_flag = 0; + } + rbuflist = getrecvbufs(); /* get received buffers */ + + if (!was_alarmed && rbuflist == (struct recvbuf *)0) { + /* + * Nothing to do. Wait for something. + */ +#ifdef HAVE_POLL_H + nfound = poll(rdfdes, (unsigned int)nbsock, timeout.tv_sec * 1000); + +#else + nfound = select(maxfd, &rdfdes, (fd_set *)0, + (fd_set *)0, &timeout); +#endif + if (nfound > 0) + input_handler(); + else if ( +#ifndef SYS_WINNT + nfound == -1 +#else + nfound == SOCKET_ERROR +#endif /* SYS_WINNT */ + ) { +#ifndef SYS_WINNT + if (errno != EINTR) +#endif + netsyslog(LOG_ERR, +#ifdef HAVE_POLL_H + "poll() error: %m" +#else + "select() error: %m" +#endif + ); + } else { +#ifndef SYS_VXWORKS + netsyslog(LOG_DEBUG, +#ifdef HAVE_POLL_H + "poll(): nfound = %d, error: %m", +#else + "select(): nfound = %d, error: %m", +#endif + nfound); +#endif + } + if (alarm_flag) { /* alarmed? */ + was_alarmed = 1; + alarm_flag = 0; + } + rbuflist = getrecvbufs(); /* get received buffers */ + } + + /* + * Out here, signals are unblocked. Call receive + * procedure for each incoming packet. + */ + while (rbuflist != (struct recvbuf *)0) { + rbuf = rbuflist; + rbuflist = rbuf->next; + receive(rbuf); + freerecvbuf(rbuf); + } + + /* + * Call timer to process any timeouts + */ + if (was_alarmed) { + timer(); + was_alarmed = 0; + } + + /* + * Go around again + */ + } + + /* + * When we get here we've completed the polling of all servers. + * Adjust the clock, then exit. + */ +#ifdef SYS_WINNT + WSACleanup(); +#endif +#ifdef SYS_VXWORKS + close (fd); + timer_delete(ntpdate_timerid); +#endif + + return clock_adjust(); +} + + +/* + * transmit - transmit a packet to the given server, or mark it completed. + * This is called by the timeout routine and by the receive + * procedure. + */ +static void +transmit( + register struct server *server + ) +{ + struct pkt xpkt; + + if (debug) + printf("transmit(%s)\n", stoa(&(server->srcadr))); + + if (server->filter_nextpt < server->xmtcnt) { + l_fp ts; + /* + * Last message to this server timed out. Shift + * zeros into the filter. + */ + L_CLR(&ts); + server_data(server, 0, &ts, 0); + } + + if ((int)server->filter_nextpt >= sys_samples) { + /* + * Got all the data we need. Mark this guy + * completed and return. + */ + server->event_time = 0; + complete_servers++; + return; + } + + /* + * If we're here, send another message to the server. Fill in + * the packet and let 'er rip. + */ + xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC, + sys_version, MODE_CLIENT); + xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC); + xpkt.ppoll = NTP_MINPOLL; + xpkt.precision = NTPDATE_PRECISION; + xpkt.rootdelay = htonl(NTPDATE_DISTANCE); + xpkt.rootdispersion = htonl(NTPDATE_DISP); + xpkt.refid = htonl(NTPDATE_REFID); + L_CLR(&xpkt.reftime); + L_CLR(&xpkt.org); + L_CLR(&xpkt.rec); + + /* + * Determine whether to authenticate or not. If so, + * fill in the extended part of the packet and do it. + * If not, just timestamp it and send it away. + */ + if (sys_authenticate) { + int len; + + xpkt.exten[0] = htonl(sys_authkey); + get_systime(&server->xmt); + L_ADDUF(&server->xmt, sys_authdelay); + HTONL_FP(&server->xmt, &xpkt.xmt); + len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC); + sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len)); + + if (debug > 1) + printf("transmit auth to %s\n", + stoa(&(server->srcadr))); + } else { + get_systime(&(server->xmt)); + HTONL_FP(&server->xmt, &xpkt.xmt); + sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC); + + if (debug > 1) + printf("transmit to %s\n", stoa(&(server->srcadr))); + } + + /* + * Update the server timeout and transmit count + */ + server->event_time = current_time + sys_timeout; + server->xmtcnt++; +} + + +/* + * receive - receive and process an incoming frame + */ +static void +receive( + struct recvbuf *rbufp + ) +{ + register struct pkt *rpkt; + register struct server *server; + register s_fp di; + l_fp t10, t23, tmp; + l_fp org; + l_fp rec; + l_fp ci; + int has_mac; + int is_authentic; + + if (debug) + printf("receive(%s)\n", stoa(&rbufp->recv_srcadr)); + /* + * Check to see if the packet basically looks like something + * intended for us. + */ + if (rbufp->recv_length == LEN_PKT_NOMAC) + has_mac = 0; + else if (rbufp->recv_length >= LEN_PKT_NOMAC) + has_mac = 1; + else { + if (debug) + printf("receive: packet length %d\n", + rbufp->recv_length); + return; /* funny length packet */ + } + + rpkt = &(rbufp->recv_pkt); + if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION || + PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) { + return; + } + + if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER + && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) + || rpkt->stratum >= STRATUM_UNSPEC) { + if (debug) + printf("receive: mode %d stratum %d\n", + PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); + return; + } + + /* + * So far, so good. See if this is from a server we know. + */ + server = findserver(&(rbufp->recv_srcadr)); + if (server == NULL) { + if (debug) + printf("receive: server not found\n"); + return; + } + + /* + * Decode the org timestamp and make sure we're getting a response + * to our last request. + */ + NTOHL_FP(&rpkt->org, &org); + if (!L_ISEQU(&org, &server->xmt)) { + if (debug) + printf("receive: pkt.org and peer.xmt differ\n"); + return; + } + + /* + * Check out the authenticity if we're doing that. + */ + if (!sys_authenticate) + is_authentic = 1; + else { + is_authentic = 0; + + if (debug > 3) + printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n", + (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey, + (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt, + LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC))); + + if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey && + authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC, + (int)(rbufp->recv_length - LEN_PKT_NOMAC))) + is_authentic = 1; + if (debug) + printf("receive: authentication %s\n", + is_authentic ? "passed" : "failed"); + } + server->trust <<= 1; + if (!is_authentic) + server->trust |= 1; + + /* + * Looks good. Record info from the packet. + */ + server->leap = PKT_LEAP(rpkt->li_vn_mode); + server->stratum = PKT_TO_STRATUM(rpkt->stratum); + server->precision = rpkt->precision; + server->rootdelay = ntohl(rpkt->rootdelay); + server->rootdispersion = ntohl(rpkt->rootdispersion); + server->refid = rpkt->refid; + NTOHL_FP(&rpkt->reftime, &server->reftime); + NTOHL_FP(&rpkt->rec, &rec); + NTOHL_FP(&rpkt->xmt, &server->org); + + /* + * Make sure the server is at least somewhat sane. If not, try + * again. + */ + if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) { + transmit(server); + return; + } + + /* + * Calculate the round trip delay (di) and the clock offset (ci). + * We use the equations (reordered from those in the spec): + * + * d = (t2 - t3) - (t1 - t0) + * c = ((t2 - t3) + (t1 - t0)) / 2 + */ + t10 = server->org; /* pkt.xmt == t1 */ + L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/ + + t23 = rec; /* pkt.rec == t2 */ + L_SUB(&t23, &org); /* pkt->org == t3 */ + + /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */ + /* + * Calculate (ci) = ((t1 - t0) / 2) + ((t2 - t3) / 2) + * For large offsets this may prevent an overflow on '+' + */ + ci = t10; + L_RSHIFT(&ci); + tmp = t23; + L_RSHIFT(&tmp); + L_ADD(&ci, &tmp); + + /* + * Calculate di in t23 in full precision, then truncate + * to an s_fp. + */ + L_SUB(&t23, &t10); + di = LFPTOFP(&t23); + + if (debug > 3) + printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5)); + + di += (FP_SECOND >> (-(int)NTPDATE_PRECISION)) + + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW; + + if (di <= 0) { /* value still too raunchy to use? */ + L_CLR(&ci); + di = 0; + } else { + di = max(di, NTP_MINDIST); + } + + /* + * Shift this data in, then transmit again. + */ + server_data(server, (s_fp) di, &ci, 0); + transmit(server); +} + + +/* + * server_data - add a sample to the server's filter registers + */ +static void +server_data( + register struct server *server, + s_fp d, + l_fp *c, + u_fp e + ) +{ + u_short i; + + i = server->filter_nextpt; + if (i < NTP_SHIFT) { + server->filter_delay[i] = d; + server->filter_offset[i] = *c; + server->filter_soffset[i] = LFPTOFP(c); + server->filter_error[i] = e; + server->filter_nextpt = (u_short)(i + 1); + } +} + + +/* + * clock_filter - determine a server's delay, dispersion and offset + */ +static void +clock_filter( + register struct server *server + ) +{ + register int i, j; + int ord[NTP_SHIFT]; + + /* + * Sort indices into increasing delay order + */ + for (i = 0; i < sys_samples; i++) + ord[i] = i; + + for (i = 0; i < (sys_samples-1); i++) { + for (j = i+1; j < sys_samples; j++) { + if (server->filter_delay[ord[j]] == 0) + continue; + if (server->filter_delay[ord[i]] == 0 + || (server->filter_delay[ord[i]] + > server->filter_delay[ord[j]])) { + register int tmp; + + tmp = ord[i]; + ord[i] = ord[j]; + ord[j] = tmp; + } + } + } + + /* + * Now compute the dispersion, and assign values to delay and + * offset. If there are no samples in the register, delay and + * offset go to zero and dispersion is set to the maximum. + */ + if (server->filter_delay[ord[0]] == 0) { + server->delay = 0; + L_CLR(&server->offset); + server->soffset = 0; + server->dispersion = PEER_MAXDISP; + } else { + register s_fp d; + + server->delay = server->filter_delay[ord[0]]; + server->offset = server->filter_offset[ord[0]]; + server->soffset = LFPTOFP(&server->offset); + server->dispersion = 0; + for (i = 1; i < sys_samples; i++) { + if (server->filter_delay[ord[i]] == 0) + d = PEER_MAXDISP; + else { + d = server->filter_soffset[ord[i]] + - server->filter_soffset[ord[0]]; + if (d < 0) + d = -d; + if (d > PEER_MAXDISP) + d = PEER_MAXDISP; + } + /* + * XXX This *knows* PEER_FILTER is 1/2 + */ + server->dispersion += (u_fp)(d) >> i; + } + } + /* + * We're done + */ +} + + +/* + * clock_select - select the pick-of-the-litter clock from the samples + * we've got. + */ +static struct server * +clock_select(void) +{ + register struct server *server; + register int i; + register int nlist; + register s_fp d; + register int j; + register int n; + s_fp local_threshold; + struct server *server_list[NTP_MAXCLOCK]; + u_fp server_badness[NTP_MAXCLOCK]; + struct server *sys_server; + + /* + * This first chunk of code is supposed to go through all + * servers we know about to find the NTP_MAXLIST servers which + * are most likely to succeed. We run through the list + * doing the sanity checks and trying to insert anyone who + * looks okay. We are at all times aware that we should + * only keep samples from the top two strata and we only need + * NTP_MAXLIST of them. + */ + nlist = 0; /* none yet */ + for (server = sys_servers; server != NULL; server = server->next_server) { + if (server->delay == 0) { + if (debug) + printf("%s: Server dropped: no data\n", ntoa(&server->srcadr)); + continue; /* no data */ + } + if (server->stratum > NTP_INFIN) { + if (debug) + printf("%s: Server dropped: strata too high\n", ntoa(&server->srcadr)); + continue; /* stratum no good */ + } + if (server->delay > NTP_MAXWGT) { + if (debug) + printf("%s: Server dropped: server too far away\n", + ntoa(&server->srcadr)); + continue; /* too far away */ + } + if (server->leap == LEAP_NOTINSYNC) { + if (debug) + printf("%s: Server dropped: Leap not in sync\n", ntoa(&server->srcadr)); + continue; /* he's in trouble */ + } + if (!L_ISHIS(&server->org, &server->reftime)) { + if (debug) + printf("%s: Server dropped: server is very broken\n", + ntoa(&server->srcadr)); + continue; /* very broken host */ + } + if ((server->org.l_ui - server->reftime.l_ui) + >= NTP_MAXAGE) { + if (debug) + printf("%s: Server dropped: Server has gone too long without sync\n", + ntoa(&server->srcadr)); + continue; /* too long without sync */ + } + if (server->trust != 0) { + if (debug) + printf("%s: Server dropped: Server is untrusted\n", + ntoa(&server->srcadr)); + continue; + } + + /* + * This one seems sane. Find where he belongs + * on the list. + */ + d = server->dispersion + server->dispersion; + for (i = 0; i < nlist; i++) + if (server->stratum <= server_list[i]->stratum) + break; + for ( ; i < nlist; i++) { + if (server->stratum < server_list[i]->stratum) + break; + if (d < (s_fp) server_badness[i]) + break; + } + + /* + * If i points past the end of the list, this + * guy is a loser, else stick him in. + */ + if (i >= NTP_MAXLIST) + continue; + for (j = nlist; j > i; j--) + if (j < NTP_MAXLIST) { + server_list[j] = server_list[j-1]; + server_badness[j] + = server_badness[j-1]; + } + + server_list[i] = server; + server_badness[i] = d; + if (nlist < NTP_MAXLIST) + nlist++; + } + + /* + * Got the five-or-less best. Cut the list where the number of + * strata exceeds two. + */ + j = 0; + for (i = 1; i < nlist; i++) + if (server_list[i]->stratum > server_list[i-1]->stratum) + if (++j == 2) { + nlist = i; + break; + } + + /* + * Whew! What we should have by now is 0 to 5 candidates for + * the job of syncing us. If we have none, we're out of luck. + * If we have one, he's a winner. If we have more, do falseticker + * detection. + */ + + if (nlist == 0) + sys_server = 0; + else if (nlist == 1) { + sys_server = server_list[0]; + } else { + /* + * Re-sort by stratum, bdelay estimate quality and + * server.delay. + */ + for (i = 0; i < nlist-1; i++) + for (j = i+1; j < nlist; j++) { + if (server_list[i]->stratum + < server_list[j]->stratum) + break; /* already sorted by stratum */ + if (server_list[i]->delay + < server_list[j]->delay) + continue; + server = server_list[i]; + server_list[i] = server_list[j]; + server_list[j] = server; + } + + /* + * Calculate the fixed part of the dispersion limit + */ + local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION)) + + NTP_MAXSKW; + + /* + * Now drop samples until we're down to one. + */ + while (nlist > 1) { + for (n = 0; n < nlist; n++) { + server_badness[n] = 0; + for (j = 0; j < nlist; j++) { + if (j == n) /* with self? */ + continue; + d = server_list[j]->soffset + - server_list[n]->soffset; + if (d < 0) /* absolute value */ + d = -d; + /* + * XXX This code *knows* that + * NTP_SELECT is 3/4 + */ + for (i = 0; i < j; i++) + d = (d>>1) + (d>>2); + server_badness[n] += d; + } + } + + /* + * We now have an array of nlist badness + * coefficients. Find the badest. Find + * the minimum precision while we're at + * it. + */ + i = 0; + n = server_list[0]->precision;; + for (j = 1; j < nlist; j++) { + if (server_badness[j] >= server_badness[i]) + i = j; + if (n > server_list[j]->precision) + n = server_list[j]->precision; + } + + /* + * i is the index of the server with the worst + * dispersion. If his dispersion is less than + * the threshold, stop now, else delete him and + * continue around again. + */ + if ( (s_fp) server_badness[i] < (local_threshold + + (FP_SECOND >> (-n)))) + break; + for (j = i + 1; j < nlist; j++) + server_list[j-1] = server_list[j]; + nlist--; + } + + /* + * What remains is a list of less than 5 servers. Take + * the best. + */ + sys_server = server_list[0]; + } + + /* + * That's it. Return our server. + */ + return sys_server; +} + + +/* + * clock_adjust - process what we've received, and adjust the time + * if we got anything decent. + */ +static int +clock_adjust(void) +{ + register struct server *sp, *server; + s_fp absoffset; + int dostep; + + for (sp = sys_servers; sp != NULL; sp = sp->next_server) + clock_filter(sp); + server = clock_select(); + + if (debug || simple_query) { + for (sp = sys_servers; sp != NULL; sp = sp->next_server) + printserver(sp, stdout); + } + + if (server == 0) { + msyslog(LOG_ERR, + "no server suitable for synchronization found"); + return(1); + } + + if (always_step) { + dostep = 1; + } else if (never_step) { + dostep = 0; + } else { + absoffset = server->soffset; + if (absoffset < 0) + absoffset = -absoffset; + dostep = (absoffset >= NTPDATE_THRESHOLD || absoffset < 0); + } + + if (dostep) { + if (simple_query || l_step_systime(&server->offset)) { + msyslog(LOG_NOTICE, "step time server %s offset %s sec", + stoa(&server->srcadr), + lfptoa(&server->offset, 6)); + } + } else { +#if !defined SYS_WINNT && !defined SYS_CYGWIN32 + if (simple_query || l_adj_systime(&server->offset)) { + msyslog(LOG_NOTICE, "adjust time server %s offset %s sec", + stoa(&server->srcadr), + lfptoa(&server->offset, 6)); + } +#else + /* The NT SetSystemTimeAdjustment() call achieves slewing by + * changing the clock frequency. This means that we cannot specify + * it to slew the clock by a definite amount and then stop like + * the Unix adjtime() routine. We can technically adjust the clock + * frequency, have ntpdate sleep for a while, and then wake + * up and reset the clock frequency, but this might cause some + * grief if the user attempts to run ntpd immediately after + * ntpdate and the socket is in use. + */ + printf("\nThe -b option is required by ntpdate on Windows NT platforms\n"); + exit(1); +#endif /* SYS_WINNT */ + } + return(0); +} + + +/* XXX ELIMINATE: merge BIG slew into adj_systime in lib/systime.c */ +/* + * addserver - determine a server's address and allocate a new structure + * for it. + */ +static void +addserver( + char *serv + ) +{ + register struct server *server; + /* Address infos structure to store result of getaddrinfo */ + struct addrinfo *addrResult; + /* Address infos structure to store hints for getaddrinfo */ + struct addrinfo hints; + /* Error variable for getaddrinfo */ + int error; + /* Service name */ + char service[5]; + strcpy(service, "ntp"); + + /* Get host address. Looking for UDP datagram connection. */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ai_fam_templ; + hints.ai_socktype = SOCK_DGRAM; + +#ifdef DEBUG + if (debug) + printf("Looking for host %s and service %s\n", serv, service); +#endif + + error = getaddrinfo(serv, service, &hints, &addrResult); + if (error != 0) { + fprintf(stderr, "Error : %s\n", gai_strerror(error)); + msyslog(LOG_ERR, "can't find host %s\n", serv); + return; + } +#ifdef DEBUG + else if (debug) { + fprintf(stderr, "host found : %s\n", stohost((struct sockaddr_storage*)addrResult->ai_addr)); + } +#endif + + server = (struct server *)emalloc(sizeof(struct server)); + memset((char *)server, 0, sizeof(struct server)); + + /* For now we only get the first returned server of the addrinfo list */ + memset(&(server->srcadr), 0, sizeof(struct sockaddr_storage)); + memcpy(&(server->srcadr), addrResult->ai_addr, addrResult->ai_addrlen); + server->event_time = ++sys_numservers; + if (sys_servers == NULL) + sys_servers = server; + else { + struct server *sp; + + for (sp = sys_servers; sp->next_server != NULL; + sp = sp->next_server) ; + sp->next_server = server; + } +} + + +/* + * findserver - find a server in the list given its address + * ***(For now it isn't totally AF-Independant, to check later..) + */ +static struct server * +findserver( + struct sockaddr_storage *addr + ) +{ + struct server *server; + struct server *mc_server; + + mc_server = NULL; + if (htons(((struct sockaddr_in*)addr)->sin_port) != NTP_PORT) + return 0; + + for (server = sys_servers; server != NULL; + server = server->next_server) { + + if (memcmp(addr, &server->srcadr, SOCKLEN(addr))==0) + return server; + /* Multicast compatibility to verify here... I'm not sure it's working */ + if(addr->ss_family == AF_INET) { + if (IN_MULTICAST(ntohl(((struct sockaddr_in*)addr)->sin_addr.s_addr))) + mc_server = server; + } + else { +#ifdef AF_INET6 + if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)(&server->srcadr))->sin6_addr)) + mc_server = server; +#else + return 0; +#endif + } + } + + if (mc_server != NULL) { + + struct server *sp; + + if (mc_server->event_time != 0) { + mc_server->event_time = 0; + complete_servers++; + } + + server = (struct server *)emalloc(sizeof(struct server)); + memset((char *)server, 0, sizeof(struct server)); + + memcpy(&server->srcadr, &addr, sizeof(struct sockaddr_storage)); + + server->event_time = ++sys_numservers; + + for (sp = sys_servers; sp->next_server != NULL; + sp = sp->next_server) ; + sp->next_server = server; + transmit(server); + } + return NULL; +} + + +/* + * timer - process a timer interrupt + */ +void +timer(void) +{ + struct server *server; + + /* + * Bump the current idea of the time + */ + current_time++; + + /* + * Search through the server list looking for guys + * who's event timers have expired. Give these to + * the transmit routine. + */ + for (server = sys_servers; server != NULL; + server = server->next_server) { + if (server->event_time != 0 + && server->event_time <= current_time) + transmit(server); + } +} + + +/* + * The code duplication in the following subroutine sucks, but + * we need to appease ansi2knr. + */ + +#ifndef SYS_WINNT +/* + * alarming - record the occurance of an alarm interrupt + */ +static RETSIGTYPE +alarming( + int sig + ) +{ + alarm_flag++; +} +#else +void CALLBACK +alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) +{ + alarm_flag++; +} +#endif /* SYS_WINNT */ + + +/* + * init_alarm - set up the timer interrupt + */ +static void +init_alarm(void) +{ +#ifndef SYS_WINNT +# ifndef HAVE_TIMER_SETTIME + struct itimerval itimer; +# else + struct itimerspec ntpdate_itimer; +# endif +#else + TIMECAPS tc; + UINT wTimerRes, wTimerID; +# endif /* SYS_WINNT */ +#if defined SYS_CYGWIN32 || defined SYS_WINNT + HANDLE hToken; + TOKEN_PRIVILEGES tkp; + DWORD dwUser = 0; +#endif /* SYS_WINNT */ + + alarm_flag = 0; + +#ifndef SYS_WINNT +# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) + alarm_flag = 0; + /* this code was put in as setitimer() is non existant this us the + * POSIX "equivalents" setup - casey + */ + /* ntpdate_timerid is global - so we can kill timer later */ + if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) == +# ifdef SYS_VXWORKS + ERROR +# else + -1 +# endif + ) + { + fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n"); + return; + } + + /* TIMER_HZ = (5) + * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ) + * seconds from now and they continue on every 1/TIMER_HZ seconds. + */ + (void) signal_no_reset(SIGALRM, alarming); + ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0; + ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ; + ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1); + timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL); +# else + /* + * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ) + * seconds from now and they continue on every 1/TIMER_HZ seconds. + */ + (void) signal_no_reset(SIGALRM, alarming); + itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; + itimer.it_interval.tv_usec = 1000000/TIMER_HZ; + itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1); + + setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); +# endif +#if defined SYS_CYGWIN32 + /* + * Get previleges needed for fiddling with the clock + */ + + /* get the current process token handle */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + msyslog(LOG_ERR, "OpenProcessToken failed: %m"); + exit(1); + } + /* get the LUID for system-time privilege. */ + LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; /* one privilege to set */ + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + /* get set-time privilege for this process. */ + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); + /* cannot test return value of AdjustTokenPrivileges. */ + if (GetLastError() != ERROR_SUCCESS) + msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); +#endif +#else /* SYS_WINNT */ + _tzset(); + + /* + * Get previleges needed for fiddling with the clock + */ + + /* get the current process token handle */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + msyslog(LOG_ERR, "OpenProcessToken failed: %m"); + exit(1); + } + /* get the LUID for system-time privilege. */ + LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; /* one privilege to set */ + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + /* get set-time privilege for this process. */ + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); + /* cannot test return value of AdjustTokenPrivileges. */ + if (GetLastError() != ERROR_SUCCESS) + msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); + + /* + * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds + * Under Win/NT, expiry of timer interval leads to invocation + * of a callback function (on a different thread) rather than + * generating an alarm signal + */ + + /* determine max and min resolution supported */ + if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) { + msyslog(LOG_ERR, "timeGetDevCaps failed: %m"); + exit(1); + } + wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax); + /* establish the minimum timer resolution that we'll use */ + timeBeginPeriod(wTimerRes); + + /* start the timer event */ + wTimerID = timeSetEvent( + (UINT) (1000/TIMER_HZ), /* Delay */ + wTimerRes, /* Resolution */ + (LPTIMECALLBACK) alarming, /* Callback function */ + (DWORD) dwUser, /* User data */ + TIME_PERIODIC); /* Event type (periodic) */ + if (wTimerID == 0) { + msyslog(LOG_ERR, "timeSetEvent failed: %m"); + exit(1); + } +#endif /* SYS_WINNT */ +} + + + + +/* + * We do asynchronous input using the SIGIO facility. A number of + * recvbuf buffers are preallocated for input. In the signal + * handler we poll to see if the socket is ready and read the + * packets from it into the recvbuf's along with a time stamp and + * an indication of the source host and the interface it was received + * through. This allows us to get as accurate receive time stamps + * as possible independent of other processing going on. + * + * We allocate a number of recvbufs equal to the number of servers + * plus 2. This should be plenty. + */ + + +/* + * init_io - initialize I/O data and open socket + */ +static void +init_io(void) +{ + struct addrinfo *res, *ressave; + struct addrinfo hints; + char service[5]; + int optval = 1; + + /* + * Init buffer free list and stat counters + */ + init_recvbuff(sys_numservers + 2); + + /* + * Open the socket + */ + + strcpy(service, "ntp"); + + /* + * Init hints addrinfo structure + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_socktype = SOCK_DGRAM; + + if(getaddrinfo(NULL, service, &hints, &res) != 0) { + msyslog(LOG_ERR, "getaddrinfo() failed: %m"); + exit(1); + /*NOTREACHED*/ + } + + /* Remember the address of the addrinfo structure chain */ + ressave = res; + + /* + * For each structure returned, open and bind socket + */ + for(nbsock = 0; (nbsock < MAX_AF) && res ; res = res->ai_next) { + /* create a datagram (UDP) socket */ + if ((fd[nbsock] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) { + if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT || + errno == EPFNOSUPPORT) + continue; + netsyslog(LOG_ERR, "socket() failed: %m"); + exit(1); + /*NOTREACHED*/ + } + /* set socket to reuse address */ + if (setsockopt(fd[nbsock], SOL_SOCKET, SO_REUSEADDR, (void*) &optval, sizeof(optval)) < 0) { + netsyslog(LOG_ERR, "setsockopt() SO_REUSEADDR failed: %m"); + exit(1); + /*NOTREACHED*/ + } +#ifdef IPV6_V6ONLY + /* Restricts AF_INET6 socket to IPv6 communications (see RFC 2553bis-03) */ + if (res->ai_family == AF_INET6) + if (setsockopt(fd[nbsock], IPPROTO_IPV6, IPV6_V6ONLY, (void*) &optval, sizeof(optval)) < 0) { + netsyslog(LOG_ERR, "setsockopt() IPV6_V6ONLY failed: %m"); + exit(1); + /*NOTREACHED*/ + } +#endif + + /* Remember the socket family in fd_family structure */ + fd_family[nbsock] = res->ai_family; + + /* + * bind the socket to the NTP port + */ + if (!debug && !simple_query && !unpriv_port) { + if (bind(fd[nbsock], res->ai_addr, SOCKLEN(res->ai_addr)) < 0) { +#ifndef SYS_WINNT + if (errno == EADDRINUSE) +#else + if (WSAGetLastError() == WSAEADDRINUSE) +#endif /* SYS_WINNT */ + netsyslog(LOG_ERR, + "the NTP socket is in use, exiting"); + else + netsyslog(LOG_ERR, "bind() fails: %m"); + exit(1); + } + } + +#ifdef HAVE_POLL_H + fdmask[nbsock].fd = fd[nbsock]; + fdmask[nbsock].events = POLLIN; +#else + FD_SET(fd[nbsock], &fdmask); + if ((SOCKET) maxfd < fd[nbsock]+1) { + maxfd = fd[nbsock]+1; + } +#endif + + /* + * set non-blocking, + */ +#ifndef SYS_WINNT +# ifdef SYS_VXWORKS + { + int on = TRUE; + + if (ioctl(fd[nbsock],FIONBIO, &on) == ERROR) { + netsyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m"); + exit(1); + } + } +# else /* not SYS_VXWORKS */ +# if defined(O_NONBLOCK) + if (fcntl(fd[nbsock], F_SETFL, O_NONBLOCK) < 0) { + netsyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# else /* not O_NONBLOCK */ +# if defined(FNDELAY) + if (fcntl(fd[nbsock], F_SETFL, FNDELAY) < 0) { + netsyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# else /* FNDELAY */ +# include "Bletch: Need non blocking I/O" +# endif /* FNDELAY */ +# endif /* not O_NONBLOCK */ +# endif /* SYS_VXWORKS */ +#else /* SYS_WINNT */ + if (ioctlsocket(fd[nbsock], FIONBIO, (u_long *) &on) == SOCKET_ERROR) { + netsyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m"); + exit(1); + } +#endif /* SYS_WINNT */ + nbsock++; + } + freeaddrinfo(ressave); +} + +/* + * sendpkt - send a packet to the specified destination + */ +static void +sendpkt( + struct sockaddr_storage *dest, + struct pkt *pkt, + int len + ) +{ + int i; + int cc; + SOCKET sock = 0; + +#ifdef SYS_WINNT + DWORD err; +#endif /* SYS_WINNT */ + + /* Find a local family compatible socket to send ntp packet to ntp server */ + for(i = 0; (i < MAX_AF); i++) { + if(dest->ss_family == fd_family[i]) { + sock = fd[i]; + break; + } + } + + if ( sock == 0 ) { + netsyslog(LOG_ERR, "cannot find family compatible socket to send ntp packet"); + exit(1); + /*NOTREACHED*/ + } + + cc = sendto(sock, (char *)pkt, len, 0, (struct sockaddr *)dest, + SOCKLEN(dest)); + +#ifndef SYS_WINNT + if (cc == -1) { + if (errno != EWOULDBLOCK && errno != ENOBUFS) +#else + if (cc == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAENOBUFS) +#endif /* SYS_WINNT */ + netsyslog(LOG_ERR, "sendto(%s): %m", stohost(dest)); + } +} + + +/* + * input_handler - receive packets asynchronously + */ +void +input_handler(void) +{ + register int n; + register struct recvbuf *rb; + struct timeval tvzero; + int fromlen; + l_fp ts; + int i; +#ifdef HAVE_POLL_H + struct pollfd fds[MAX_AF]; +#else + fd_set fds; +#endif + int fdc = 0; + + /* + * Do a poll to see if we have data + */ + for (;;) { + tvzero.tv_sec = tvzero.tv_usec = 0; +#ifdef HAVE_POLL_H + memcpy(fds, fdmask, sizeof(fdmask)); + n = poll(fds, (unsigned int)nbsock, tvzero.tv_sec * 1000); + + /* + * Determine which socket received data + */ + + for(i=0; i < nbsock; i++) { + if(fds[i].revents & POLLIN) { + fdc = fd[i]; + break; + } + } + +#else + fds = fdmask; + n = select(maxfd, &fds, (fd_set *)0, (fd_set *)0, &tvzero); + + /* + * Determine which socket received data + */ + + for(i=0; i < maxfd; i++) { + if(FD_ISSET(fd[i], &fds)) { + fdc = fd[i]; + break; + } + } + +#endif + + /* + * If nothing to do, just return. If an error occurred, + * complain and return. If we've got some, freeze a + * timestamp. + */ + if (n == 0) + return; + else if (n == -1) { + if (errno != EINTR) + netsyslog(LOG_ERR, +#ifdef HAVE_POLL_H + "poll() error: %m" +#else + "select() error: %m" +#endif + ); + return; + } + get_systime(&ts); + + /* + * Get a buffer and read the frame. If we + * haven't got a buffer, or this is received + * on the wild card socket, just dump the packet. + */ + if (initializing || free_recvbuffs() == 0) { + char buf[100]; + + +#ifndef SYS_WINNT + (void) read(fdc, buf, sizeof buf); +#else + /* NT's _read does not operate on nonblocking sockets + * either recvfrom or ReadFile() has to be used here. + * ReadFile is used in [ntpd]ntp_intres() and ntpdc, + * just to be different use recvfrom() here + */ + recvfrom(fdc, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL); +#endif /* SYS_WINNT */ + continue; + } + + rb = get_free_recv_buffer(); + + fromlen = sizeof(struct sockaddr_storage); + rb->recv_length = recvfrom(fdc, (char *)&rb->recv_pkt, + sizeof(rb->recv_pkt), 0, + (struct sockaddr *)&rb->recv_srcadr, &fromlen); + if (rb->recv_length == -1) { + freerecvbuf(rb); + continue; + } + + /* + * Got one. Mark how and when it got here, + * put it on the full list. + */ + rb->recv_time = ts; + add_full_recv_buffer(rb); + } +} + + +#if !defined SYS_WINNT && !defined SYS_CYGWIN32 +/* + * adj_systime - do a big long slew of the system time + */ +static int +l_adj_systime( + l_fp *ts + ) +{ + struct timeval adjtv, oadjtv; + int isneg = 0; + l_fp offset; +#ifndef STEP_SLEW + l_fp overshoot; +#endif + + /* + * Take the absolute value of the offset + */ + offset = *ts; + if (L_ISNEG(&offset)) { + isneg = 1; + L_NEG(&offset); + } + +#ifndef STEP_SLEW + /* + * Calculate the overshoot. XXX N.B. This code *knows* + * ADJ_OVERSHOOT is 1/2. + */ + overshoot = offset; + L_RSHIFTU(&overshoot); + if (overshoot.l_ui != 0 || (overshoot.l_uf > ADJ_MAXOVERSHOOT)) { + overshoot.l_ui = 0; + overshoot.l_uf = ADJ_MAXOVERSHOOT; + } + L_ADD(&offset, &overshoot); +#endif + TSTOTV(&offset, &adjtv); + + if (isneg) { + adjtv.tv_sec = -adjtv.tv_sec; + adjtv.tv_usec = -adjtv.tv_usec; + } + + if (adjtv.tv_usec != 0 && !debug) { + if (adjtime(&adjtv, &oadjtv) < 0) { + msyslog(LOG_ERR, "Can't adjust the time of day: %m"); + return 0; + } + } + return 1; +} +#endif /* SYS_WINNT */ + + +/* + * This fuction is not the same as lib/systime step_systime!!! + */ +static int +l_step_systime( + l_fp *ts + ) +{ + double dtemp; + +#ifdef SLEWALWAYS +#ifdef STEP_SLEW + l_fp ftmp; + int isneg; + int n; + + if (debug) return 1; + /* + * Take the absolute value of the offset + */ + ftmp = *ts; + if (L_ISNEG(&ftmp)) { + L_NEG(&ftmp); + isneg = 1; + } else + isneg = 0; + + if (ftmp.l_ui >= 3) { /* Step it and slew - we might win */ + LFPTOD(ts, dtemp); + n = step_systime(dtemp); + if (!n) + return n; + if (isneg) + ts->l_ui = ~0; + else + ts->l_ui = ~0; + } + /* + * Just add adjustment into the current offset. The update + * routine will take care of bringing the system clock into + * line. + */ +#endif + if (debug) + return 1; +#ifdef FORCE_NTPDATE_STEP + LFPTOD(ts, dtemp); + return step_systime(dtemp); +#else + l_adj_systime(ts); + return 1; +#endif +#else /* SLEWALWAYS */ + if (debug) + return 1; + LFPTOD(ts, dtemp); + return step_systime(dtemp); +#endif /* SLEWALWAYS */ +} + + +/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */ +/* + * printserver - print detail information for a server + */ +static void +printserver( + register struct server *pp, + FILE *fp + ) +{ + register int i; + char junk[5]; + char *str; + + if (!debug) { + (void) fprintf(fp, "server %s, stratum %d, offset %s, delay %s\n", + stoa(&pp->srcadr), pp->stratum, + lfptoa(&pp->offset, 6), fptoa((s_fp)pp->delay, 5)); + return; + } + + (void) fprintf(fp, "server %s, port %d\n", + stoa(&pp->srcadr), ntohs(((struct sockaddr_in*)&(pp->srcadr))->sin_port)); + + (void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n", + pp->stratum, pp->precision, + pp->leap & 0x2 ? '1' : '0', + pp->leap & 0x1 ? '1' : '0', + pp->trust); + + if (pp->stratum == 1) { + junk[4] = 0; + memmove(junk, (char *)&pp->refid, 4); + str = junk; + } else { + str = stoa(&pp->srcadr); + } + (void) fprintf(fp, + "refid [%s], delay %s, dispersion %s\n", + str, fptoa((s_fp)pp->delay, 5), + ufptoa(pp->dispersion, 5)); + + (void) fprintf(fp, "transmitted %d, in filter %d\n", + pp->xmtcnt, pp->filter_nextpt); + + (void) fprintf(fp, "reference time: %s\n", + prettydate(&pp->reftime)); + (void) fprintf(fp, "originate timestamp: %s\n", + prettydate(&pp->org)); + (void) fprintf(fp, "transmit timestamp: %s\n", + prettydate(&pp->xmt)); + + (void) fprintf(fp, "filter delay: "); + for (i = 0; i < NTP_SHIFT; i++) { + (void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5)); + if (i == (NTP_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "filter offset:"); + for (i = 0; i < PEER_SHIFT; i++) { + (void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6)); + if (i == (PEER_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "delay %s, dispersion %s\n", + fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5)); + + (void) fprintf(fp, "offset %s\n\n", + lfptoa(&pp->offset, 6)); +} + +#if !defined(HAVE_VSPRINTF) +int +vsprintf( + char *str, + const char *fmt, + va_list ap + ) +{ + FILE f; + int len; + + f._flag = _IOWRT+_IOSTRG; + f._ptr = str; + f._cnt = 32767; + len = _doprnt(fmt, ap, &f); + *f._ptr = 0; + return (len); +} +#endif + +#if 0 +/* override function in library since SA_RESTART makes ALL syscalls restart */ +#ifdef SA_RESTART +void +signal_no_reset( + int sig, + void (*func)() + ) +{ + int n; + struct sigaction vec; + + vec.sa_handler = func; + sigemptyset(&vec.sa_mask); + vec.sa_flags = 0; + + while (1) + { + n = sigaction(sig, &vec, NULL); + if (n == -1 && errno == EINTR) + continue; + break; + } + if (n == -1) + { + perror("sigaction"); + exit(1); + } +} +#endif +#endif + +#ifdef HAVE_NETINFO +static ni_namelist * +getnetinfoservers(void) +{ + ni_status status; + void *domain; + ni_id confdir; + ni_namelist *namelist = (ni_namelist*)malloc(sizeof(ni_namelist)); + + /* Find a time server in NetInfo */ + if ((status = ni_open(NULL, ".", &domain)) != NI_OK) return NULL; + + while (status = ni_pathsearch(domain, &confdir, NETINFO_CONFIG_DIR) == NI_NODIR) { + void *next_domain; + if (ni_open(domain, "..", &next_domain) != NI_OK) break; + ni_free(domain); + domain = next_domain; + } + if (status != NI_OK) return NULL; + + NI_INIT(namelist); + if (ni_lookupprop(domain, &confdir, "server", namelist) != NI_OK) { + ni_namelist_free(namelist); + free(namelist); + return NULL; + } + + return(namelist); +} +#endif diff --git a/ntpdate/ntpdate.h b/ntpdate/ntpdate.h new file mode 100644 index 000000000000..f3531b3f2434 --- /dev/null +++ b/ntpdate/ntpdate.h @@ -0,0 +1,104 @@ +/* + * ntpdate.h - declarations for the ntpdate and ntptimeset programs + */ + +#include "ntp_malloc.h" + +extern void loadservers P((char *cfgpath)); + +/* + * The server structure is a much simplified version of the + * peer structure, for ntpdate's use. Since we always send + * in client mode and expect to receive in server mode, this + * leaves only a very limited number of things we need to + * remember about the server. + */ +struct server { + struct server *next_server; /* next server in build list */ + struct sockaddr_storage srcadr; /* address of remote host */ + u_char version; /* version to use */ + u_char leap; /* leap indicator */ + u_char stratum; /* stratum of remote server */ + s_char precision; /* server's clock precision */ + u_char trust; /* trustability of the filtered data */ + u_fp rootdelay; /* distance from primary clock */ + u_fp rootdispersion; /* peer clock dispersion */ + u_int32 refid; /* peer reference ID */ + l_fp reftime; /* time of peer's last update */ + u_long event_time; /* time for next timeout */ + u_long last_xmit; /* time of last transmit */ + u_short xmtcnt; /* number of packets transmitted */ + u_short rcvcnt; /* number of packets received */ + u_char reach; /* reachability, NTP_WINDOW bits */ + u_short filter_nextpt; /* index into filter shift register */ + s_fp filter_delay[NTP_SHIFT]; /* delay part of shift register */ + l_fp filter_offset[NTP_SHIFT]; /* offset part of shift register */ + s_fp filter_soffset[NTP_SHIFT]; /* offset in s_fp format, for disp */ + u_fp filter_error[NTP_SHIFT]; /* error part of shift register */ + l_fp org; /* peer's originate time stamp */ + l_fp xmt; /* transmit time stamp */ + u_fp delay; /* filter estimated delay */ + u_fp dispersion; /* filter estimated dispersion */ + l_fp offset; /* filter estimated clock offset */ + s_fp soffset; /* fp version of above */ +}; + + +/* + * ntpdate runs everything on a simple, short timeout. It sends a + * packet and sets the timeout (by default, to a small value suitable + * for a LAN). If it receives a response it sends another request. + * If it times out it shifts zeroes into the filter and sends another + * request. + * + * The timer routine is run often (once every 1/5 second currently) + * so that time outs are done with reasonable precision. + */ +#define TIMER_HZ (5) /* 5 per second */ + +/* + * ntpdate will make a long adjustment using adjtime() if the times + * are close, or step the time if the times are farther apart. The + * following defines what is "close". + */ +#define NTPDATE_THRESHOLD (FP_SECOND >> 1) /* 1/2 second */ + +#define NTP_MAXAGE 86400 /* one day in seconds */ + +/* + * When doing adjustments, ntpdate actually overadjusts (currently + * by 50%, though this may change). While this will make it take longer + * to reach a steady state condition, it will typically result in + * the clock keeping more accurate time, on average. The amount of + * overshoot is limited. + */ +#ifdef NOTNOW +#define ADJ_OVERSHOOT 1/2 /* this is hard coded */ +#endif /* NOTNOW */ +#define ADJ_MAXOVERSHOOT 0x10000000 /* 50 ms as a ts fraction */ + +/* + * Since ntpdate isn't aware of some of the things that normally get + * put in an NTP packet, we fix some values. + */ +#define NTPDATE_PRECISION (-6) /* use this precision */ +#define NTPDATE_DISTANCE FP_SECOND /* distance is 1 sec */ +#define NTPDATE_DISP FP_SECOND /* so is the dispersion */ +#define NTPDATE_REFID (0) /* reference ID to use */ +#define PEER_MAXDISP (64*FP_SECOND) /* maximum dispersion (fp 64) */ + + +/* + * Some defaults + */ +#define DEFTIMEOUT 5 /* 5 timer increments */ +#define DEFSAMPLES 4 /* get 4 samples per server */ +#define DEFPRECISION (-5) /* the precision we claim */ +#define DEFMAXPERIOD 60 /* maximum time to wait */ +#define DEFMINSERVERS 3 /* minimum responding servers */ +#define DEFMINVALID 1 /* mimimum servers with valid time */ + +/* + * Define the max number of sockets we can open + */ +#define MAX_AF 2 diff --git a/ntpdate/ntptime_config.c b/ntpdate/ntptime_config.c new file mode 100644 index 000000000000..e784d28034f0 --- /dev/null +++ b/ntpdate/ntptime_config.c @@ -0,0 +1,552 @@ +/* + * ntptime_config.c + * + * What follows is a simplified version of the config parsing code + * in ntpd/ntp_config.c. We only parse a subset of the configuration + * syntax, and don't bother whining about things we don't understand. + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "ntp_unixtime.h" +#include "ntp_filegen.h" +#include "ntpdate.h" +#include "ntp_syslog.h" +#include "ntp_stdlib.h" + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> + +/* + * These routines are used to read the configuration file at + * startup time. An entry in the file must fit on a single line. + * Entries are processed as multiple tokens separated by white space + * Lines are considered terminated when a '#' is encountered. Blank + * lines are ignored. + */ + +/* + * Configuration file name + */ +#ifndef CONFIG_FILE +# ifndef SYS_WINNT +# define CONFIG_FILE "/etc/ntp.conf" +# else /* SYS_WINNT */ +# define CONFIG_FILE "%windir%\\ntp.conf" +# define ALT_CONFIG_FILE "%windir%\\ntp.ini" +# endif /* SYS_WINNT */ +#endif /* not CONFIG_FILE */ + +/* + * + * We understand the following configuration entries and defaults. + * + * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * server [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ] + * keys file_name + */ + +#define CONFIG_UNKNOWN 0 + +#define CONFIG_PEER 1 +#define CONFIG_SERVER 2 +#define CONFIG_KEYS 8 + +#define CONF_MOD_VERSION 1 +#define CONF_MOD_KEY 2 +#define CONF_MOD_MINPOLL 3 +#define CONF_MOD_MAXPOLL 4 +#define CONF_MOD_PREFER 5 +#define CONF_MOD_BURST 6 +#define CONF_MOD_SKEY 7 +#define CONF_MOD_TTL 8 +#define CONF_MOD_MODE 9 + +/* + * Translation table - keywords to function index + */ +struct keyword { + const char *text; + int keytype; +}; + +/* + * Command keywords + */ +static struct keyword keywords[] = { + { "peer", CONFIG_PEER }, + { "server", CONFIG_SERVER }, + { "keys", CONFIG_KEYS }, + { "", CONFIG_UNKNOWN } +}; + +/* + * "peer", "server", "broadcast" modifier keywords + */ +static struct keyword mod_keywords[] = { + { "version", CONF_MOD_VERSION }, + { "key", CONF_MOD_KEY }, + { "minpoll", CONF_MOD_MINPOLL }, + { "maxpoll", CONF_MOD_MAXPOLL }, + { "prefer", CONF_MOD_PREFER }, + { "burst", CONF_MOD_BURST }, + { "autokey", CONF_MOD_SKEY }, + { "mode", CONF_MOD_MODE }, /* reference clocks */ + { "ttl", CONF_MOD_TTL }, /* NTP peers */ + { "", CONFIG_UNKNOWN } +}; + +/* + * Limits on things + */ +#define MAXTOKENS 20 /* 20 tokens on line */ +#define MAXLINE 1024 /* maximum length of line */ +#define MAXFILENAME 128 /* maximum length of a file name (alloca()?) */ + +/* + * Miscellaneous macros + */ +#define STRSAME(s1, s2) (*(s1) == *(s2) && strcmp((s1), (s2)) == 0) +#define ISEOL(c) ((c) == '#' || (c) == '\n' || (c) == '\0') +#define ISSPACE(c) ((c) == ' ' || (c) == '\t') +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +/* + * Systemwide parameters and flags + */ +extern struct server **sys_servers; /* the server list */ +extern int sys_numservers; /* number of servers to poll */ +extern char *key_file; + +/* + * Function prototypes + */ +static int gettokens P((FILE *, char *, char **, int *)); +static int matchkey P((char *, struct keyword *)); +static int getnetnum P((const char *num, struct sockaddr_in *addr, + int complain)); + + +/* + * loadservers - load list of NTP servers from configuration file + */ +void +loadservers( + char *cfgpath + ) +{ + register int i; + int errflg; + int peerversion; + int minpoll; + int maxpoll; + /* int ttl; */ + int srvcnt; + /* u_long peerkey; */ + int peerflags; + struct sockaddr_in peeraddr; + FILE *fp; + char line[MAXLINE]; + char *(tokens[MAXTOKENS]); + int ntokens; + int tok; + const char *config_file; +#ifdef SYS_WINNT + char *alt_config_file; + LPTSTR temp; + char config_file_storage[MAX_PATH]; + char alt_config_file_storage[MAX_PATH]; +#endif /* SYS_WINNT */ + struct server *server, *srvlist; + + /* + * Initialize, initialize + */ + srvcnt = 0; + srvlist = 0; + errflg = 0; +#ifdef DEBUG + debug = 0; +#endif /* DEBUG */ +#ifndef SYS_WINNT + config_file = cfgpath ? cfgpath : CONFIG_FILE; +#else + if (cfgpath) { + config_file = cfgpath; + } else { + temp = CONFIG_FILE; + if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)config_file_storage, (DWORD)sizeof(config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings CONFIG_FILE failed: %m\n"); + exit(1); + } + config_file = config_file_storage; + } + + temp = ALT_CONFIG_FILE; + if (!ExpandEnvironmentStrings((LPCTSTR)temp, (LPTSTR)alt_config_file_storage, (DWORD)sizeof(alt_config_file_storage))) { + msyslog(LOG_ERR, "ExpandEnvironmentStrings ALT_CONFIG_FILE failed: %m\n"); + exit(1); + } + alt_config_file = alt_config_file_storage; +M +#endif /* SYS_WINNT */ + + if ((fp = fopen(FindConfig(config_file), "r")) == NULL) + { + fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(config_file)); + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(config_file)); +#ifdef SYS_WINNT + /* Under WinNT try alternate_config_file name, first NTP.CONF, then NTP.INI */ + + if ((fp = fopen(FindConfig(alt_config_file), "r")) == NULL) { + + /* + * Broadcast clients can sometimes run without + * a configuration file. + */ + + fprintf(stderr, "getconfig: Couldn't open <%s>\n", FindConfig(alt_config_file)); + msyslog(LOG_INFO, "getconfig: Couldn't open <%s>", FindConfig(alt_config_file)); + return; + } +#else /* not SYS_WINNT */ + return; +#endif /* not SYS_WINNT */ + } + + while ((tok = gettokens(fp, line, tokens, &ntokens)) + != CONFIG_UNKNOWN) { + switch(tok) { + case CONFIG_PEER: + case CONFIG_SERVER: + + if (ntokens < 2) { + msyslog(LOG_ERR, + "No address for %s, line ignored", + tokens[0]); + break; + } + + if (!getnetnum(tokens[1], &peeraddr, 1)) { + /* Resolve now, or lose! */ + break; + } else { + errflg = 0; + + /* Shouldn't be able to specify multicast */ + if (IN_CLASSD(ntohl(peeraddr.sin_addr.s_addr)) + || ISBADADR(&peeraddr)) { + msyslog(LOG_ERR, + "attempt to configure invalid address %s", + ntoa(&peeraddr)); + break; + } + } + + peerversion = NTP_VERSION; + minpoll = NTP_MINDPOLL; + maxpoll = NTP_MAXDPOLL; + /* peerkey = 0; */ + peerflags = 0; + /* ttl = 0; */ + for (i = 2; i < ntokens; i++) + switch (matchkey(tokens[i], mod_keywords)) { + case CONF_MOD_VERSION: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "peer/server version requires an argument"); + errflg = 1; + break; + } + peerversion = atoi(tokens[++i]); + if ((u_char)peerversion > NTP_VERSION + || (u_char)peerversion < NTP_OLDVERSION) { + msyslog(LOG_ERR, + "inappropriate version number %s, line ignored", + tokens[i]); + errflg = 1; + } + break; + + case CONF_MOD_KEY: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "key: argument required"); + errflg = 1; + break; + } + ++i; + /* peerkey = (int)atol(tokens[i]); */ + peerflags |= FLAG_AUTHENABLE; + break; + + case CONF_MOD_MINPOLL: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "minpoll: argument required"); + errflg = 1; + break; + } + minpoll = atoi(tokens[++i]); + if (minpoll < NTP_MINPOLL) + minpoll = NTP_MINPOLL; + break; + + case CONF_MOD_MAXPOLL: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "maxpoll: argument required" + ); + errflg = 1; + break; + } + maxpoll = atoi(tokens[++i]); + if (maxpoll > NTP_MAXPOLL) + maxpoll = NTP_MAXPOLL; + break; + + case CONF_MOD_PREFER: + peerflags |= FLAG_PREFER; + break; + + case CONF_MOD_BURST: + peerflags |= FLAG_BURST; + break; + + case CONF_MOD_SKEY: + peerflags |= FLAG_SKEY | FLAG_AUTHENABLE; + break; + + case CONF_MOD_TTL: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "ttl: argument required"); + errflg = 1; + break; + } + ++i; + /* ttl = atoi(tokens[i]); */ + break; + + case CONF_MOD_MODE: + if (i >= ntokens-1) { + msyslog(LOG_ERR, + "mode: argument required"); + errflg = 1; + break; + } + ++i; + /* ttl = atoi(tokens[i]); */ + break; + + case CONFIG_UNKNOWN: + errflg = 1; + break; + } + if (minpoll > maxpoll) { + msyslog(LOG_ERR, "config error: minpoll > maxpoll"); + errflg = 1; + } + if (errflg == 0) { + server = (struct server *)emalloc(sizeof(struct server)); + memset((char *)server, 0, sizeof(struct server)); + server->srcadr = peeraddr; + server->version = peerversion; + server->dispersion = PEER_MAXDISP; + server->next_server = srvlist; + srvlist = server; + srvcnt++; + } + break; + + case CONFIG_KEYS: + if (ntokens >= 2) { + key_file = (char *) emalloc(strlen(tokens[1]) + 1); + strcpy(key_file, tokens[1]); + } + break; + } + } + (void) fclose(fp); + + /* build final list */ + sys_numservers = srvcnt; + sys_servers = (struct server **) + emalloc(sys_numservers * sizeof(struct server *)); + for(i=0;i<sys_numservers;i++) { + sys_servers[i] = srvlist; + srvlist = srvlist->next_server; + } +} + + + +/* + * gettokens - read a line and return tokens + */ +static int +gettokens( + FILE *fp, + char *line, + char **tokenlist, + int *ntokens + ) +{ + register char *cp; + register int eol; + register int ntok; + register int quoted = 0; + + /* + * Find start of first token + */ + again: + while ((cp = fgets(line, MAXLINE, fp)) != NULL) { + cp = line; + while (ISSPACE(*cp)) + cp++; + if (!ISEOL(*cp)) + break; + } + if (cp == NULL) { + *ntokens = 0; + return CONFIG_UNKNOWN; /* hack. Is recognized as EOF */ + } + + /* + * Now separate out the tokens + */ + eol = 0; + ntok = 0; + while (!eol) { + tokenlist[ntok++] = cp; + while (!ISEOL(*cp) && (!ISSPACE(*cp) || quoted)) + quoted ^= (*cp++ == '"'); + + if (ISEOL(*cp)) { + *cp = '\0'; + eol = 1; + } else { /* must be space */ + *cp++ = '\0'; + while (ISSPACE(*cp)) + cp++; + if (ISEOL(*cp)) + eol = 1; + } + if (ntok == MAXTOKENS) + eol = 1; + } + + /* + * Return the match + */ + *ntokens = ntok; + ntok = matchkey(tokenlist[0], keywords); + if (ntok == CONFIG_UNKNOWN) + goto again; + return ntok; +} + + + +/* + * matchkey - match a keyword to a list + */ +static int +matchkey( + register char *word, + register struct keyword *keys + ) +{ + for (;;) { + if (keys->keytype == CONFIG_UNKNOWN) { + return CONFIG_UNKNOWN; + } + if (STRSAME(word, keys->text)) + return keys->keytype; + keys++; + } +} + + +/* + * getnetnum - return a net number (this is crude, but careful) + */ +static int +getnetnum( + const char *num, + struct sockaddr_in *addr, + int complain + ) +{ + register const char *cp; + register char *bp; + register int i; + register int temp; + char buf[80]; /* will core dump on really stupid stuff */ + u_int32 netnum; + + /* XXX ELIMINATE replace with decodenetnum */ + cp = num; + netnum = 0; + for (i = 0; i < 4; i++) { + bp = buf; + while (isdigit((int)*cp)) + *bp++ = *cp++; + if (bp == buf) + break; + + if (i < 3) { + if (*cp++ != '.') + break; + } else if (*cp != '\0') + break; + + *bp = '\0'; + temp = atoi(buf); + if (temp > 255) + break; + netnum <<= 8; + netnum += temp; +#ifdef DEBUG + if (debug > 3) + printf("getnetnum %s step %d buf %s temp %d netnum %lu\n", + num, i, buf, temp, (u_long)netnum); +#endif + } + + if (i < 4) { + if (complain) + msyslog(LOG_ERR, + "getnetnum: \"%s\" invalid host number, line ignored", + num); +#ifdef DEBUG + if (debug > 3) + printf( + "getnetnum: \"%s\" invalid host number, line ignored\n", + num); +#endif + return 0; + } + + /* + * make up socket address. Clear it out for neatness. + */ + memset((void *)addr, 0, sizeof(struct sockaddr_in)); + addr->sin_family = AF_INET; + addr->sin_port = htons(NTP_PORT); + addr->sin_addr.s_addr = htonl(netnum); +#ifdef DEBUG + if (debug > 1) + printf("getnetnum given %s, got %s (%lx)\n", + num, ntoa(addr), (u_long)netnum); +#endif + return 1; +} diff --git a/ntpdate/ntptimeset.c b/ntpdate/ntptimeset.c new file mode 100644 index 000000000000..6d9332f05a77 --- /dev/null +++ b/ntpdate/ntptimeset.c @@ -0,0 +1,2171 @@ +/* + * ntptimeset - get/set the time via ntp + * + * GOAL: + * The goal of ntptime is to set the current time on system startup + * to the best possible time using the network very wisely. It is assumed + * that after a resonable time has been sett then ntp daemon will + * maintain it. + * + * PROBLEM DOMAIN: + * We have three sets of issues related to acheiving the goal. The first + * issue is using the network when normal traffic is happening or when + * the entire network world is recovering from a campus wide power failure + * and is restarting. The second issue is the class of machine whether it + * is a user's office workstation being handled by an uneducated user or + * a server computer being handled by a trained operations staff. The third + * issue is whether the ratio of people to computers and whether the + * environment is stable and viable or not. + * + * NETWORK USAGE: + * The first issue of using the network wisely is a question of whether + * the network load and time server load and state are normal. If things + * are normal ntptime can do what ntpdate does of sending out 4 packets + * quickly to each server (new transmit done with each ack). However + * if network or time load is high then this scheme will simply contribute + * to problems. Given we have minimal state, we simply weight lost packets + * significantly and make sure we throttle output as much as possible + * without performance lost for quick startups. + * + * TRAINING AND KNOWLEDGE: + * The second issue of uneducated user of a office workstation versus a + * trained operation staff of a server machine translates into simply an + * issue of untrained and trained users. + * + * The training issue implies that for the sake of the users involved in the + * handling of their office workstation, problems and options should be + * communicated simply and effectively and not in terse expert related + * descriptions without possible options to be taken. The operator's training + * and education enables them to deal with either type of communication and + * control. + * + * AUTOMATION AND MANUAL CONTROL: + * The last issue boils down to a design problem. If the design tends to go + * into a manual mode when the environment is non-viable then one person + * handling many computers all at the same time will be heavily impacted. On + * the other hand, if the design tends to be automatic and does not indicate + * a way for the user to take over control then the computer will be + * unavailable for the user until the proble is resolved by someone else or + * the user. + * + * NOTE: Please do not have this program print out every minute some line, + * of output. If this happens and the environment is in trouble then + * many pages of paper on many different machines will be filled up. + * Save some tress in your lifetime. + * + * CONCLUSION: + * The behavior of the program derived from these three issues should be + * that during normal situations it quickly sets the time and allow the + * system to startup. + * + * However during abnormal conditions as detected by unresponsive servers, + * out-of-sync or bad responses and other detections, it should print out + * a simple but clear message and continue in a mellow way to get the best + * possible time. It may never get the time and if so should also indicate + * this. + * + * Rudy Nedved + * 18-May-1993 + * + **************************************************************** + * + * Much of the above is confusing or no longer relevant. For example, + * it is rare these days for a machine's console to be a printing terminal, + * so the comment about saving trees doesn't mean much. Nonetheless, + * the basic principles still stand: + * + * - Work automatically, without human control or intervention. To + * this end, we use the same configuration file as ntpd itself, so + * you don't have to specify servers or other information on the + * command line. We also recognize that sometimes we won't be able + * to contact any servers, and give up in that event instead of + * hanging forever. + * + * - Behave in a sane way, both internally and externally, even in the + * face of insane conditions. That means we back off quickly when + * we don't hear a response, to avoid network congestion. Like + * ntpd, we verify responses from several servers before accepting + * the new time data. + * + * However, we don't assume that the local clock is right, or even + * close, because it might not be at boot time, and we want to catch + * and correct that situation. This behaviour has saved us in several + * instances. On HP-UX 9.0x, there used to be a bug in adjtimed which + * would cause the time to be set to some wild value, making the machine + * essentially unusable (we use Kerberos authentication pervasively, + * and it requires workstations and servers to have a time within five + * minutes of the Kerberos server). We also have problems on PC's + * running both Linux and some Microsoft OS -- they tend to disagree + * on what the BIOS clock should say, and who should update it, and + * when. On those systems, we not only run ntptimeset at boot, we + * also reset the BIOS clock based on the result, so the correct + * time will be retained across reboots. + * + * For these reasons, and others, we have continued to use this tool + * rather than ntpdate. It is run automatically at boot time on every + * workstation and server in our facility. + * + * In the past, we called this program 'ntptime'. Unfortunately, the + * ntp v4 distribution also includes a program with that name. In + * order to avoid confusion, we have renamed our program 'ntptimeset', + * which more accurately describes what it does. + * + * Jeffrey T. Hutzelman (N3NHS) <jhutz+@cmu.edu> + * School of Computer Science - Research Computing Facility + * Carnegie Mellon University - Pittsburgh, PA + * 16-Aug-1999 + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ntp_machine.h" +#include "ntp_fp.h" +#include "ntp.h" +#include "ntp_io.h" +#include "iosignal.h" +#include "ntp_unixtime.h" +#include "ntpdate.h" +#include "ntp_string.h" +#include "ntp_syslog.h" +#include "ntp_select.h" +#include "ntp_stdlib.h" + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#ifndef SYS_WINNT +# include <netdb.h> +# ifdef HAVE_SYS_SIGNAL_H +# include <sys/signal.h> +# else +# include <signal.h> +# endif +# include <sys/ioctl.h> +#endif /* SYS_WINNT */ + +#ifdef HAVE_SYS_RESOURCE_H +# include <sys/resource.h> +#endif /* HAVE_SYS_RESOURCE_H */ + +#ifdef SYS_VXWORKS +# include "ioLib.h" +# include "sockLib.h" +# include "timers.h" +#endif + +#include "recvbuff.h" + +#ifdef SYS_WINNT +# define TARGET_RESOLUTION 1 /* Try for 1-millisecond accuracy + on Windows NT timers. */ +#pragma comment(lib, "winmm") +#endif /* SYS_WINNT */ + +/* + * Scheduling priority we run at + */ +#ifndef SYS_VXWORKS +# define NTPDATE_PRIO (-12) +#else +# define NTPDATE_PRIO (100) +#endif + +#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE) +/* POSIX TIMERS - vxWorks doesn't have itimer - casey */ +static timer_t ntpdate_timerid; +#endif + +/* + * Compatibility stuff for Version 2 + */ +#define NTP_MAXSKW 0x28f /* 0.01 sec in fp format */ +#define NTP_MINDIST 0x51f /* 0.02 sec in fp format */ +#define NTP_INFIN 15 /* max stratum, infinity a la Bellman-Ford */ +#define NTP_MAXWGT (8*FP_SECOND) /* maximum select weight 8 seconds */ +#define NTP_MAXLIST 5 /* maximum select list size */ +#define PEER_SHIFT 8 /* 8 suitable for crystal time base */ + +/* + * Debugging flag + */ +volatile int debug = 0; + +/* + * File descriptor masks etc. for call to select + */ +int fd; +fd_set fdmask; + +/* + * Initializing flag. All async routines watch this and only do their + * thing when it is clear. + */ +int initializing = 1; + +/* + * Alarm flag. Set when an alarm occurs + */ +volatile int alarm_flag = 0; + +/* + * Set the time if valid time determined + */ +int set_time = 0; + +/* + * transmission rate control + */ +#define MINTRANSMITS (3) /* minimum total packets per server */ +#define MAXXMITCOUNT (2) /* maximum packets per time interrupt */ + +/* + * time setting constraints + */ +#define DESIREDDISP (4*FP_SECOND) /* desired dispersion, (fp 4) */ +int max_period = DEFMAXPERIOD; +int min_servers = DEFMINSERVERS; +int min_valid = DEFMINVALID; + +/* + * counters related to time setting constraints + */ +int contacted = 0; /* # of servers we have sent to */ +int responding = 0; /* servers responding */ +int validcount = 0; /* servers with valid time */ +int valid_n_low = 0; /* valid time servers with low dispersion */ + +/* + * Unpriviledged port flag. + */ +int unpriv_port = 0; + +/* + * Program name. + */ +char *progname; + +/* + * Systemwide parameters and flags + */ +struct server **sys_servers; /* the server list */ +int sys_numservers = 0; /* number of servers to poll */ +int sys_authenticate = 0; /* true when authenticating */ +u_int32 sys_authkey = 0; /* set to authentication key in use */ +u_long sys_authdelay = 0; /* authentication delay */ + +/* + * The current internal time + */ +u_long current_time = 0; + +/* + * File of encryption keys + */ + +#ifndef KEYFILE +# ifndef SYS_WINNT +#define KEYFILE "/etc/ntp.keys" +# else +#define KEYFILE "%windir%\\ntp.keys" +# endif /* SYS_WINNT */ +#endif /* KEYFILE */ + +#ifndef SYS_WINNT +const char *key_file = KEYFILE; +#else +char key_file_storage[MAX_PATH+1], *key_file ; +#endif /* SYS_WINNT */ + +/* + * total packet counts + */ +u_long total_xmit = 0; +u_long total_recv = 0; + +/* + * Miscellaneous flags + */ +int verbose = 0; +#define HORRIBLEOK 3 /* how many packets to let out */ +int horrible = 0; /* how many packets we drop for testing */ +int secondhalf = 0; /* second half of timeout period */ +int printmsg = 0; /* print time response analysis */ + +/* + * The half time and finish time in internal time + */ +u_long half_time = 0; +u_long finish_time = 0; + + +int ntptimesetmain P((int argc, char *argv[])); +static void analysis P((int final)); +static int have_enough P((void)); +static void transmit P((register struct server *server)); +static void receive P((struct recvbuf *rbufp)); +static void clock_filter P((register struct server *server, s_fp d, l_fp *c)); +static void clock_count P((void)); +static struct server *clock_select P((void)); +static void set_local_clock P((void)); +static struct server *findserver P((struct sockaddr_in *addr)); +static void timer P((void)); +#ifndef SYS_WINNT +static RETSIGTYPE alarming P((int sig)); +#endif /* SYS_WINNT */ +static void init_alarm P((void)); +static void init_io P((void)); +static int sendpkt P((struct sockaddr_in *dest, struct pkt *pkt, int len)); + void input_handler P((l_fp *xts)); +static void printserver P((register struct server *pp, FILE *fp)); +#if !defined(HAVE_VSPRINTF) +int vsprintf P((char *str, const char *fmt, va_list ap)); +#endif + +#ifdef HAVE_SIGNALED_IO +extern void wait_for_signal P((void)); +extern void unblock_io_and_alarm P((void)); +extern void block_io_and_alarm P((void)); +#endif + + +#ifdef NO_MAIN_ALLOWED +CALL(ntptimeset,"ntptimeset",ntptimesetmain); + +void clear_globals() +{ + /* + * Debugging flag + */ + debug = 0; + + ntp_optind = 0; + + /* + * Initializing flag. All async routines watch this and only do their + * thing when it is clear. + */ + initializing = 1; + + /* + * Alarm flag. Set when an alarm occurs + */ + alarm_flag = 0; + + /* + * Unpriviledged port flag. + */ + unpriv_port = 0; + + /* + * Systemwide parameters and flags + */ + sys_numservers = 0; /* number of servers to poll */ + sys_authenticate = 0; /* true when authenticating */ + sys_authkey = 0; /* set to authentication key in use */ + sys_authdelay = 0; /* authentication delay */ + + /* + * The current internal time + */ + current_time = 0; + + verbose = 0; +} +#endif /* NO_MAIN_ALLOWED */ + +/* + * Main program. Initialize us and loop waiting for I/O and/or + * timer expiries. + */ +#ifndef NO_MAIN_ALLOWED +int +main( + int argc, + char *argv[] + ) +{ + return ntptimesetmain(argc, argv); +} +#endif /* NO_MAIN_ALLOWED */ + + +int +ntptimesetmain( + int argc, + char *argv[] + ) +{ + int was_alarmed; + struct recvbuf *rbuflist; + struct recvbuf *rbuf; + l_fp tmp; + int errflg; + int c; + extern char *ntp_optarg; + extern int ntp_optind; + int ltmp; + char *cfgpath; + +#ifdef SYS_WINNT + HANDLE process_handle; + + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) { + msyslog(LOG_ERR, "No useable winsock.dll: %m"); + exit(1); + } +#endif /* SYS_WINNT */ + +#ifdef NO_MAIN_ALLOWED + clear_globals(); +#endif + + errflg = 0; + cfgpath = 0; + progname = argv[0]; + syslogit = 0; + + /* + * Decode argument list + */ + while ((c = ntp_getopt(argc, argv, "a:c:de:slt:uvHS:V:")) != EOF) + switch (c) + { + case 'a': + c = atoi(ntp_optarg); + sys_authenticate = 1; + sys_authkey = c; + break; + case 'c': + cfgpath = ntp_optarg; + break; + case 'd': + ++debug; + break; + case 'e': + if (!atolfp(ntp_optarg, &tmp) + || tmp.l_ui != 0) { + (void) fprintf(stderr, + "%s: encryption delay %s is unlikely\n", + progname, ntp_optarg); + errflg++; + } else { + sys_authdelay = tmp.l_uf; + } + break; + case 's': + set_time = 1; + break; + case 'l': + syslogit = 1; + break; + case 't': + ltmp = atoi(ntp_optarg); + if (ltmp <= 0) { + (void) fprintf(stderr, + "%s: maximum time period (%d) is invalid\n", + progname, ltmp); + errflg++; + } + else + max_period = ltmp; + break; + case 'u': + unpriv_port = 1; + break; + case 'v': + ++verbose; + break; + case 'H': + horrible++; + break; + case 'S': + ltmp = atoi(ntp_optarg); + if (ltmp <= 0) { + (void) fprintf(stderr, + "%s: minimum responding (%d) is invalid\n", + progname, ltmp); + errflg++; + } + else + min_servers = ltmp; + break; + case 'V': + ltmp = atoi(ntp_optarg); + if (ltmp <= 0) { + (void) fprintf(stderr, + "%s: minimum valid (%d) is invalid\n", + progname, ltmp); + errflg++; + } + else + min_valid = ltmp; + break; + case '?': + ++errflg; + break; + default: + break; + } + + + if (errflg || ntp_optind < argc) { + fprintf(stderr,"usage: %s [switches...]\n",progname); + fprintf(stderr," -v (verbose)\n"); + fprintf(stderr," -c path (set config file path)\n"); + fprintf(stderr," -a key (authenticate using key)\n"); + fprintf(stderr," -e delay (authentication delay)\n"); + fprintf(stderr," -S num (# of servers that must respond)\n"); + fprintf(stderr," -V num (# of servers that must valid)\n"); + fprintf(stderr," -s (set the time based if okay)\n"); + fprintf(stderr," -t secs (time period before ending)\n"); + fprintf(stderr," -l (use syslog facility)\n"); + fprintf(stderr," -u (use unprivileged port)\n"); + fprintf(stderr," -H (drop packets for debugging)\n"); + fprintf(stderr," -d (debug output)\n"); + exit(2); + } + + /* + * Logging. Open the syslog if we have to + */ + if (syslogit) { +#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32 +# ifndef LOG_DAEMON + openlog("ntptimeset", LOG_PID); +# else + +# ifndef LOG_NTP +# define LOG_NTP LOG_DAEMON +# endif + openlog("ntptimeset", LOG_PID | LOG_NDELAY, LOG_NTP); + if (debug) + setlogmask(LOG_UPTO(LOG_DEBUG)); + else + setlogmask(LOG_UPTO(LOG_INFO)); +# endif /* LOG_DAEMON */ +#endif /* SYS_WINNT */ + } + + if (debug || verbose) + msyslog(LOG_INFO, "%s", Version); + + if (horrible) + msyslog(LOG_INFO, "Dropping %d out of %d packets", + horrible,horrible+HORRIBLEOK); + /* + * Add servers we are going to be polling + */ + loadservers(cfgpath); + + if (sys_numservers < min_servers) { + msyslog(LOG_ERR, "Found %d servers, require %d servers", + sys_numservers,min_servers); + exit(2); + } + + /* + * determine when we will end at least + */ + finish_time = max_period * TIMER_HZ; + half_time = finish_time >> 1; + + /* + * Initialize the time of day routines and the I/O subsystem + */ + if (sys_authenticate) { + init_auth(); +#ifdef SYS_WINNT + if (!key_file) key_file = KEYFILE; + if (!ExpandEnvironmentStrings(key_file, key_file_storage, MAX_PATH)) + { + msyslog(LOG_ERR, "ExpandEnvironmentStrings(%s) failed: %m\n", + key_file); + } else { + key_file = key_file_storage; + } +#endif /* SYS_WINNT */ + + if (!authreadkeys(key_file)) { + msyslog(LOG_ERR, "no key file, exiting"); + exit(1); + } + if (!authistrusted(sys_authkey)) { + char buf[10]; + + (void) sprintf(buf, "%lu", (unsigned long)sys_authkey); + msyslog(LOG_ERR, "authentication key %s unknown", buf); + exit(1); + } + } + init_io(); + init_alarm(); + + /* + * Set the priority. + */ +#ifdef SYS_VXWORKS + taskPrioritySet( taskIdSelf(), NTPDATE_PRIO); +#endif +#if defined(HAVE_ATT_NICE) + nice (NTPDATE_PRIO); +#endif +#if defined(HAVE_BSD_NICE) + (void) setpriority(PRIO_PROCESS, 0, NTPDATE_PRIO); +#endif +#ifdef SYS_WINNT + process_handle = GetCurrentProcess(); + if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS)) { + msyslog(LOG_ERR, "SetPriorityClass failed: %m"); + } +#endif /* SYS_WINNT */ + + initializing = 0; + + /* + * Use select() on all on all input fd's for unlimited + * time. select() will terminate on SIGALARM or on the + * reception of input. Using select() means we can't do + * robust signal handling and we get a potential race + * between checking for alarms and doing the select(). + * Mostly harmless, I think. + * Keep going until we have enough information, or time is up. + */ + /* On VMS, I suspect that select() can't be interrupted + * by a "signal" either, so I take the easy way out and + * have select() time out after one second. + * System clock updates really aren't time-critical, + * and - lacking a hardware reference clock - I have + * yet to learn about anything else that is. + */ + was_alarmed = 0; + rbuflist = (struct recvbuf *)0; + while (finish_time > current_time) { +#if !defined(HAVE_SIGNALED_IO) + fd_set rdfdes; + int nfound; +#elif defined(HAVE_SIGNALED_IO) + block_io_and_alarm(); +#endif + + rbuflist = getrecvbufs(); /* get received buffers */ + if (printmsg) { + printmsg = 0; + analysis(0); + } + if (alarm_flag) { /* alarmed? */ + was_alarmed = 1; + alarm_flag = 0; + } + + if (!was_alarmed && rbuflist == (struct recvbuf *)0) { + /* + * Nothing to do. Wait for something. + */ +#ifndef HAVE_SIGNALED_IO + rdfdes = fdmask; +# if defined(VMS) || defined(SYS_VXWORKS) + /* make select() wake up after one second */ + { + struct timeval t1; + + t1.tv_sec = 1; t1.tv_usec = 0; + nfound = select(fd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, &t1); + } +# else + nfound = select(fd+1, &rdfdes, (fd_set *)0, + (fd_set *)0, (struct timeval *)0); +# endif /* VMS */ + if (nfound > 0) { + l_fp ts; + get_systime(&ts); + (void)input_handler(&ts); + } + else if (nfound == -1 && errno != EINTR) + msyslog(LOG_ERR, "select() error: %m"); + else if (debug) { +# if !defined SYS_VXWORKS && !defined SYS_CYGWIN32 /* to unclutter log */ + msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound); +# endif + } +#else /* HAVE_SIGNALED_IO */ + + wait_for_signal(); +#endif /* HAVE_SIGNALED_IO */ + if (alarm_flag) /* alarmed? */ + { + 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) + { + timer(); + was_alarmed = 0; + } + + /* + * Call the data procedure to handle each received + * packet. + */ + while (rbuflist != (struct recvbuf *)0) + { + rbuf = rbuflist; + rbuflist = rbuf->next; + receive(rbuf); + freerecvbuf(rbuf); + } +#if defined DEBUG && defined SYS_WINNT + if (debug > 4) + printf("getrecvbufs: %ld handler interrupts, %ld frames\n", + handler_calls, handler_pkts); +#endif + + /* + * Do we have enough information to stop now? + */ + if (have_enough()) + break; /* time to end */ + + /* + * Go around again + */ + } + + /* + * adjust the clock and exit accordingly + */ + set_local_clock(); + + /* + * if we get here then we are in trouble + */ + return(1); +} + + +/* + * analysis - print a message indicating what is happening with time service + * must mimic have_enough() procedure. + */ +static void +analysis( + int final + ) +{ + if (contacted < sys_numservers) { + printf("%d servers of %d have been probed with %d packets\n", + contacted,sys_numservers,MINTRANSMITS); + return; + } + if (!responding) { + printf("No response from any of %d servers, network problem?\n", + sys_numservers); + return; + } + else if (responding < min_servers) { + printf("%d servers out of %d responding, need at least %d.\n", + responding, sys_numservers, min_servers); + return; + } + if (!validcount) { + printf("%d servers responding but none have valid time\n", + responding); + return; + } + else if (validcount < min_valid) { + printf("%d servers responding, %d are valid, need %d valid\n", + responding,validcount,min_valid); + return; + } + if (!final && valid_n_low != validcount) { + printf("%d valid servers but only %d have low dispersion\n", + validcount,valid_n_low); + return; + } +} + + +/* have_enough - see if we have enough information to terminate probing + */ +static int +have_enough(void) +{ + /* have we contacted all servers yet? */ + if (contacted < sys_numservers) + return 0; /* no...try some more */ + + /* have we got at least minimum servers responding? */ + if (responding < min_servers) + return 0; /* no...try some more */ + + /* count the clocks */ + (void) clock_count(); + + /* have we got at least minimum valid clocks? */ + if (validcount <= 0 || validcount < min_valid) + return 0; /* no...try some more */ + + /* do we have all valid servers with low dispersion */ + if (!secondhalf && valid_n_low != validcount) + return 0; + + /* if we get into the secondhalf then we ignore dispersion */ + + /* all conditions have been met...end */ + return 1; +} + + +/* + * transmit - transmit a packet to the given server, or mark it completed. + * This is called by the timeout routine and by the receive + * procedure. + */ +static void +transmit( + register struct server *server + ) +{ + struct pkt xpkt; + int timeout; + + if (debug > 2) + printf("transmit(%s)\n", ntoa(&server->srcadr)); + + if ((server->reach & 01) == 0) { + l_fp ts; + /* + * Last message to this server timed out. Shift + * zeros into the filter. + */ + L_CLR(&ts); + clock_filter(server, 0, &ts); + } + + /* + * shift reachable register over + */ + server->reach <<= 1; + + /* + * If we're here, send another message to the server. Fill in + * the packet and let 'er rip. + */ + xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC, + server->version, MODE_CLIENT); + xpkt.stratum = STRATUM_TO_PKT(STRATUM_UNSPEC); + xpkt.ppoll = NTP_MINPOLL; + xpkt.precision = NTPDATE_PRECISION; + xpkt.rootdelay = htonl(NTPDATE_DISTANCE); + xpkt.rootdispersion = htonl(NTPDATE_DISP); + xpkt.refid = htonl(NTPDATE_REFID); + L_CLR(&xpkt.reftime); + L_CLR(&xpkt.org); + L_CLR(&xpkt.rec); + + /* + * Determine whether to authenticate or not. If so, + * fill in the extended part of the packet and do it. + * If not, just timestamp it and send it away. + */ + if (sys_authenticate) { + int len; + + xpkt.exten[0] = htonl(sys_authkey); + get_systime(&server->xmt); + L_ADDUF(&server->xmt, sys_authdelay); + HTONL_FP(&server->xmt, &xpkt.xmt); + len = authencrypt(sys_authkey, (u_int32 *)&xpkt, LEN_PKT_NOMAC); + if (sendpkt(&(server->srcadr), &xpkt, (int)(LEN_PKT_NOMAC + len))) { + if (debug > 1) + printf("failed transmit auth to %s\n", + ntoa(&(server->srcadr))); + return; + } + + if (debug > 1) + printf("transmit auth to %s\n", + ntoa(&(server->srcadr))); + } else { + get_systime(&(server->xmt)); + HTONL_FP(&server->xmt, &xpkt.xmt); + if (sendpkt(&(server->srcadr), &xpkt, LEN_PKT_NOMAC)) { + if (debug > 1) + printf("failed transmit to %s\n", + ntoa(&(server->srcadr))); + return; + } + + if (debug > 1) + printf("transmit to %s\n", ntoa(&(server->srcadr))); + } + + /* + * count transmits, record contacted count and set transmit time + */ + if (++server->xmtcnt == MINTRANSMITS) + contacted++; + server->last_xmit = current_time; + + /* + * determine timeout for this packet. The more packets we send + * to the host, the slower we get. If the host indicates that + * it is not "sane" then we expect even less. + */ + if (server->xmtcnt < MINTRANSMITS) { + /* we have not sent enough */ + timeout = TIMER_HZ; /* 1 second probe */ + } + else if (server->rcvcnt <= 0) { + /* we have heard nothing */ + if (secondhalf) + timeout = TIMER_HZ<<4; /* 16 second probe */ + else + timeout = TIMER_HZ<<3; /* 8 second probe */ + } + else { + /* if we have low dispersion then probe infrequently */ + if (server->dispersion <= DESIREDDISP) + timeout = TIMER_HZ<<4; /* 16 second probe */ + /* if the server is not in sync then let it alone */ + else if (server->leap == LEAP_NOTINSYNC) + timeout = TIMER_HZ<<4; /* 16 second probe */ + /* if the server looks broken ignore it */ + else if (server->org.l_ui < server->reftime.l_ui) + timeout = TIMER_HZ<<5; /* 32 second probe */ + else if (secondhalf) + timeout = TIMER_HZ<<2; /* 4 second probe */ + else + timeout = TIMER_HZ<<1; /* 2 second probe */ + } + + /* + * set next transmit time based on timeout + */ + server->event_time = current_time + timeout; +} + + +/* + * receive - receive and process an incoming frame + */ +static void +receive( + struct recvbuf *rbufp + ) +{ + register struct pkt *rpkt; + register struct server *server; + register s_fp di; + l_fp t10, t23; + l_fp org; + l_fp rec; + l_fp ci; + int has_mac; + int is_authentic; + + if (debug > 2) + printf("receive(%s)\n", ntoa(&rbufp->srcadr)); + /* + * Check to see if the packet basically looks like something + * intended for us. + */ + if (rbufp->recv_length == LEN_PKT_NOMAC) + has_mac = 0; + else if (rbufp->recv_length >= LEN_PKT_NOMAC) + has_mac = 1; + else { + if (debug > 2) + printf("receive: packet length %d\n", + rbufp->recv_length); + return; /* funny length packet */ + } + + rpkt = &(rbufp->recv_pkt); + if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION || + PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) { + if (debug > 1) + printf("receive: bad version %d\n", + PKT_VERSION(rpkt->li_vn_mode)); + return; + } + + if ((PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER + && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) + || rpkt->stratum >=STRATUM_UNSPEC) { + if (debug > 1) + printf("receive: mode %d stratum %d\n", + PKT_MODE(rpkt->li_vn_mode), rpkt->stratum); + return; + } + + /* + * So far, so good. See if this is from a server we know. + */ + server = findserver(&(rbufp->srcadr)); + if (server == NULL) { + if (debug > 1) + printf("receive: server not found\n"); + return; + } + + /* + * Decode the org timestamp and make sure we're getting a response + * to our last request. + */ + NTOHL_FP(&rpkt->org, &org); + if (!L_ISEQU(&org, &server->xmt)) { + if (debug > 1) + printf("receive: pkt.org and peer.xmt differ\n"); + return; + } + + /* + * Check out the authenticity if we're doing that. + */ + if (!sys_authenticate) + is_authentic = 1; + else { + is_authentic = 0; + + if (debug > 3) + printf("receive: rpkt keyid=%ld sys_authkey=%ld decrypt=%ld\n", + (long int)ntohl(rpkt->exten[0]), (long int)sys_authkey, + (long int)authdecrypt(sys_authkey, (u_int32 *)rpkt, + LEN_PKT_NOMAC, (int)(rbufp->recv_length - LEN_PKT_NOMAC))); + + if (has_mac && ntohl(rpkt->exten[0]) == sys_authkey && + authdecrypt(sys_authkey, (u_int32 *)rpkt, LEN_PKT_NOMAC, + (int)(rbufp->recv_length - LEN_PKT_NOMAC))) + is_authentic = 1; + if (debug) + printf("receive: authentication %s\n", + is_authentic ? "passed" : "failed"); + } + server->trust <<= 1; + if (!is_authentic) + server->trust |= 1; + + /* + * Looks good. Record info from the packet. + */ + server->leap = PKT_LEAP(rpkt->li_vn_mode); + server->stratum = PKT_TO_STRATUM(rpkt->stratum); + server->precision = rpkt->precision; + server->rootdelay = ntohl(rpkt->rootdelay); + server->rootdispersion = ntohl(rpkt->rootdispersion); + server->refid = rpkt->refid; + NTOHL_FP(&rpkt->reftime, &server->reftime); + NTOHL_FP(&rpkt->rec, &rec); + NTOHL_FP(&rpkt->xmt, &server->org); + + /* + * count this guy as responding + */ + server->reach |= 1; + if (server->rcvcnt++ == 0) + responding++; + + /* + * Make sure the server is at least somewhat sane. If not, ignore + * it for later. + */ + if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) { + if (debug > 1) + printf("receive: pkt insane\n"); + return; + } + + /* + * Calculate the round trip delay (di) and the clock offset (ci). + * We use the equations (reordered from those in the spec): + * + * d = (t2 - t3) - (t1 - t0) + * c = ((t2 - t3) + (t1 - t0)) / 2 + */ + t10 = server->org; /* pkt.xmt == t1 */ + L_SUB(&t10, &rbufp->recv_time); /* recv_time == t0*/ + + t23 = rec; /* pkt.rec == t2 */ + L_SUB(&t23, &org); /* pkt->org == t3 */ + + /* now have (t2 - t3) and (t0 - t1). Calculate (ci) and (di) */ + ci = t10; + L_ADD(&ci, &t23); + L_RSHIFT(&ci); + + /* + * Calculate di in t23 in full precision, then truncate + * to an s_fp. + */ + L_SUB(&t23, &t10); + di = LFPTOFP(&t23); + + if (debug > 3) + printf("offset: %s, delay %s\n", lfptoa(&ci, 6), fptoa(di, 5)); + + di += (FP_SECOND >> (-(int)NTPDATE_PRECISION)) + + (FP_SECOND >> (-(int)server->precision)) + NTP_MAXSKW; + + if (di <= 0) { /* value still too raunchy to use? */ + L_CLR(&ci); + di = 0; + } else { + di = max(di, NTP_MINDIST); + } + + + /* + * This one is valid. Give it to clock_filter(), + */ + clock_filter(server, di, &ci); + if (debug > 1) + printf("receive from %s\n", ntoa(&rbufp->srcadr)); + + /* + * See if we should goes the transmission. If not return now + * otherwise have the next event time be shortened + */ + if (server->stratum <= NTP_INFIN) + return; /* server does not have a stratum */ + if (server->leap == LEAP_NOTINSYNC) + return; /* just booted server or out of sync */ + if (!L_ISHIS(&server->org, &server->reftime)) + return; /* broken host */ + if (server->trust != 0) + return; /* can not trust it */ + + if (server->dispersion < DESIREDDISP) + return; /* we have the desired dispersion */ + + server->event_time -= (TIMER_HZ+1); +} + + +/* + * clock_filter - add clock sample, determine a server's delay, dispersion + * and offset + */ +static void +clock_filter( + register struct server *server, + s_fp di, + l_fp *c + ) +{ + register int i, j; + int ord[NTP_SHIFT]; + + /* + * Insert sample and increment nextpt + */ + + i = server->filter_nextpt; + server->filter_delay[i] = di; + server->filter_offset[i] = *c; + server->filter_soffset[i] = LFPTOFP(c); + server->filter_nextpt++; + if (server->filter_nextpt >= NTP_SHIFT) + server->filter_nextpt = 0; + + /* + * Sort indices into increasing delay order + */ + for (i = 0; i < NTP_SHIFT; i++) + ord[i] = i; + + for (i = 0; i < (NTP_SHIFT-1); i++) { + for (j = i+1; j < NTP_SHIFT; j++) { + if (server->filter_delay[ord[j]] == 0) + continue; + if (server->filter_delay[ord[i]] == 0 + || (server->filter_delay[ord[i]] + > server->filter_delay[ord[j]])) { + register int tmp; + + tmp = ord[i]; + ord[i] = ord[j]; + ord[j] = tmp; + } + } + } + + /* + * Now compute the dispersion, and assign values to delay and + * offset. If there are no samples in the register, delay and + * offset go to zero and dispersion is set to the maximum. + */ + if (server->filter_delay[ord[0]] == 0) { + server->delay = 0; + L_CLR(&server->offset); + server->soffset = 0; + server->dispersion = PEER_MAXDISP; + } else { + register s_fp d; + + server->delay = server->filter_delay[ord[0]]; + server->offset = server->filter_offset[ord[0]]; + server->soffset = LFPTOFP(&server->offset); + server->dispersion = 0; + for (i = 1; i < NTP_SHIFT; i++) { + if (server->filter_delay[ord[i]] == 0) + d = PEER_MAXDISP; + else { + d = server->filter_soffset[ord[i]] + - server->filter_soffset[ord[0]]; + if (d < 0) + d = -d; + if (d > PEER_MAXDISP) + d = PEER_MAXDISP; + } + /* + * XXX This *knows* PEER_FILTER is 1/2 + */ + server->dispersion += (u_fp)(d) >> i; + } + } + /* + * We're done + */ +} + + +/* clock_count - count the clock sources we have + */ +static void +clock_count(void) +{ + register struct server *server; + register int n; + + /* reset counts */ + validcount = valid_n_low = 0; + + /* go through the list of servers and count the clocks we believe + * and that have low dispersion + */ + for (n = 0; n < sys_numservers; n++) { + server = sys_servers[n]; + if (server->delay == 0) { + continue; /* no data */ + } + if (server->stratum > NTP_INFIN) { + continue; /* stratum no good */ + } + if (server->delay > NTP_MAXWGT) { + continue; /* too far away */ + } + if (server->leap == LEAP_NOTINSYNC) + continue; /* he's in trouble */ + if (!L_ISHIS(&server->org, &server->reftime)) { + continue; /* very broken host */ + } + if ((server->org.l_ui - server->reftime.l_ui) >= NTP_MAXAGE) { + continue; /* too long without sync */ + } + if (server->trust != 0) { + continue; + } + + /* + * This one is a valid time source.. + */ + validcount++; + + /* + * See if this one has a okay low dispersion + */ + if (server->dispersion <= DESIREDDISP) + valid_n_low++; + } + + if (debug > 1) + printf("have %d, valid %d, low %d\n", + responding, validcount, valid_n_low); +} + + +/* + * clock_select - select the pick-of-the-litter clock from the samples + * we've got. + */ +static struct server * +clock_select(void) +{ + register struct server *server; + register int i; + register int nlist; + register s_fp d; + register int j; + register int n; + s_fp local_threshold; + struct server *server_list[NTP_MAXCLOCK]; + u_fp server_badness[NTP_MAXCLOCK]; + struct server *sys_server; + + /* + * This first chunk of code is supposed to go through all + * servers we know about to find the NTP_MAXLIST servers which + * are most likely to succeed. We run through the list + * doing the sanity checks and trying to insert anyone who + * looks okay. We are at all times aware that we should + * only keep samples from the top two strata and we only need + * NTP_MAXLIST of them. + */ + nlist = 0; /* none yet */ + for (n = 0; n < sys_numservers; n++) { + server = sys_servers[n]; + if (server->delay == 0) + continue; /* no data */ + if (server->stratum > NTP_INFIN) + continue; /* stratum no good */ + if (server->delay > NTP_MAXWGT) { + continue; /* too far away */ + } + if (server->leap == LEAP_NOTINSYNC) + continue; /* he's in trouble */ + if (!L_ISHIS(&server->org, &server->reftime)) { + continue; /* very broken host */ + } + if ((server->org.l_ui - server->reftime.l_ui) + >= NTP_MAXAGE) { + continue; /* too long without sync */ + } + if (server->trust != 0) { + continue; + } + + /* + * This one seems sane. Find where he belongs + * on the list. + */ + d = server->dispersion + server->dispersion; + for (i = 0; i < nlist; i++) + if (server->stratum <= server_list[i]->stratum) + break; + for ( ; i < nlist; i++) { + if (server->stratum < server_list[i]->stratum) + break; + if (d < (s_fp) server_badness[i]) + break; + } + + /* + * If i points past the end of the list, this + * guy is a loser, else stick him in. + */ + if (i >= NTP_MAXLIST) + continue; + for (j = nlist; j > i; j--) + if (j < NTP_MAXLIST) { + server_list[j] = server_list[j-1]; + server_badness[j] + = server_badness[j-1]; + } + + server_list[i] = server; + server_badness[i] = d; + if (nlist < NTP_MAXLIST) + nlist++; + } + + /* + * Got the five-or-less best. Cut the list where the number of + * strata exceeds two. + */ + j = 0; + for (i = 1; i < nlist; i++) + if (server_list[i]->stratum > server_list[i-1]->stratum) + if (++j == 2) { + nlist = i; + break; + } + + /* + * Whew! What we should have by now is 0 to 5 candidates for + * the job of syncing us. If we have none, we're out of luck. + * If we have one, he's a winner. If we have more, do falseticker + * detection. + */ + + if (nlist == 0) + sys_server = 0; + else if (nlist == 1) { + sys_server = server_list[0]; + } else { + /* + * Re-sort by stratum, bdelay estimate quality and + * server.delay. + */ + for (i = 0; i < nlist-1; i++) + for (j = i+1; j < nlist; j++) { + if (server_list[i]->stratum + < server_list[j]->stratum) + break; /* already sorted by stratum */ + if (server_list[i]->delay + < server_list[j]->delay) + continue; + server = server_list[i]; + server_list[i] = server_list[j]; + server_list[j] = server; + } + + /* + * Calculate the fixed part of the dispersion limit + */ + local_threshold = (FP_SECOND >> (-(int)NTPDATE_PRECISION)) + + NTP_MAXSKW; + + /* + * Now drop samples until we're down to one. + */ + while (nlist > 1) { + for (n = 0; n < nlist; n++) { + server_badness[n] = 0; + for (j = 0; j < nlist; j++) { + if (j == n) /* with self? */ + continue; + d = server_list[j]->soffset + - server_list[n]->soffset; + if (d < 0) /* absolute value */ + d = -d; + /* + * XXX This code *knows* that + * NTP_SELECT is 3/4 + */ + for (i = 0; i < j; i++) + d = (d>>1) + (d>>2); + server_badness[n] += d; + } + } + + /* + * We now have an array of nlist badness + * coefficients. Find the badest. Find + * the minimum precision while we're at + * it. + */ + i = 0; + n = server_list[0]->precision;; + for (j = 1; j < nlist; j++) { + if (server_badness[j] >= server_badness[i]) + i = j; + if (n > server_list[j]->precision) + n = server_list[j]->precision; + } + + /* + * i is the index of the server with the worst + * dispersion. If his dispersion is less than + * the threshold, stop now, else delete him and + * continue around again. + */ + if (server_badness[i] < (local_threshold + + (FP_SECOND >> (-n)))) + break; + for (j = i + 1; j < nlist; j++) + server_list[j-1] = server_list[j]; + nlist--; + } + + /* + * What remains is a list of less than 5 servers. Take + * the best. + */ + sys_server = server_list[0]; + } + + /* + * That's it. Return our server. + */ + return sys_server; +} + + +/* + * set_local_clock -- handle setting the local clock or displaying info. + */ +static void +set_local_clock(void) +{ + register int i; + register struct server *server; + time_t tmp; + double dtemp; + + /* + * if setting time then print final analysis + */ + if (set_time) + analysis(1); + + /* + * pick a clock + */ + server = clock_select(); + + /* + * do some display of information + */ + if (debug || verbose) { + for (i = 0; i < sys_numservers; i++) + printserver(sys_servers[i], stdout); + if (debug) + printf("packets sent %ld, received %ld\n", + total_xmit, total_recv); + } + + /* + * see if we have a server to set the time with + */ + if (server == 0) { + if (!set_time || verbose) + fprintf(stdout,"No servers available to sync time with\n"); + exit(1); + } + + /* + * we have a valid and selected time to use!!!!! + */ + + /* + * if we are not setting the time then display offset and exit + */ + if (!set_time) { + fprintf(stdout, + "Your clock is off by %s seconds. (%s) [%ld/%ld]\n", + lfptoa(&server->offset, 7), + ntoa(&server->srcadr), + total_xmit, total_recv); + exit(0); + } + + /* + * set the clock + * XXX: Examine the more flexible approach used by ntpdate. + * Note that a design consideration here is that we sometimes + * _want_ to step the clock by a _huge_ amount in either + * direction, because the local clock is completely bogus. + * This condition must be recognized and dealt with, so + * that we always get a good time when this completes. + * -- jhutz+@cmu.edu, 16-Aug-1999 + */ + LFPTOD(&server->offset, dtemp); + step_systime(dtemp); + time(&tmp); + fprintf(stdout,"Time set to %.20s [%s %s %ld/%ld]\n", + ctime(&tmp)+4, + ntoa(&server->srcadr), + lfptoa(&server->offset, 7), + total_xmit, total_recv); + exit(0); +} + + +/* + * findserver - find a server in the list given its address + */ +static struct server * +findserver( + struct sockaddr_in *addr + ) +{ + register int i; + register u_int32 netnum; + + if (htons(addr->sin_port) != NTP_PORT) + return 0; + netnum = addr->sin_addr.s_addr; + + for (i = 0; i < sys_numservers; i++) { + if (netnum == sys_servers[i]->srcadr.sin_addr.s_addr) + return sys_servers[i]; + } + return 0; +} + + +/* + * timer - process a timer interrupt + */ +static void +timer(void) +{ + register int k; + + /* + * Bump the current idea of the time + */ + current_time++; + + /* + * see if we have reached half time + */ + if (current_time >= half_time && !secondhalf) { + secondhalf++; + if (debug) + printf("\nSecond Half of Timeout!\n"); + printmsg++; + } + + /* + * We only want to send a few packets per transmit interrupt + * to throttle things + */ + for(k = 0;k < MAXXMITCOUNT;k++) { + register int i, oldi; + register u_long oldxtime; + + /* + * We want to send a packet out for a server that has an + * expired event time. However to be mellow about this, we only + * use one expired event timer and to avoid starvation we use + * the one with the oldest last transmit time. + */ + oldi = -1; + oldxtime = 0; + for (i = 0; i < sys_numservers; i++) { + if (sys_servers[i]->event_time <= current_time) { + if (oldi < 0 || oldxtime > sys_servers[i]->last_xmit) { + oldxtime = sys_servers[i]->last_xmit; + oldi = i; + } + } + } + if (oldi >= 0) + transmit(sys_servers[oldi]); + else + break; /* no expired event */ + } /* end of transmit loop */ +} + + +#ifndef SYS_WINNT +/* + * alarming - record the occurance of an alarm interrupt + */ +static RETSIGTYPE +alarming( + int sig + ) +#else +void CALLBACK +alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) +#endif /* SYS_WINNT */ +{ + alarm_flag++; +} + + +/* + * init_alarm - set up the timer interrupt + */ +static void +init_alarm(void) +{ +#ifndef SYS_WINNT +# ifndef HAVE_TIMER_SETTIME + struct itimerval itimer; +# else + struct itimerspec ntpdate_itimer; +# endif +#else + TIMECAPS tc; + UINT wTimerRes, wTimerID; +# endif /* SYS_WINNT */ +#if defined SYS_CYGWIN32 || defined SYS_WINNT + HANDLE hToken; + TOKEN_PRIVILEGES tkp; + DWORD dwUser = 0; +#endif /* SYS_WINNT */ + + alarm_flag = 0; + +#ifndef SYS_WINNT +# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) + alarm_flag = 0; + /* this code was put in as setitimer() is non existant this us the + * POSIX "equivalents" setup - casey + */ + /* ntpdate_timerid is global - so we can kill timer later */ + if (timer_create (CLOCK_REALTIME, NULL, &ntpdate_timerid) == +# ifdef SYS_VXWORKS + ERROR +# else + -1 +# endif + ) + { + fprintf (stderr, "init_alarm(): timer_create (...) FAILED\n"); + return; + } + + /* TIMER_HZ = (5) + * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ) + * seconds from now and they continue on every 1/TIMER_HZ seconds. + */ + (void) signal_no_reset(SIGALRM, alarming); + ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0; + ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ; + ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1); + timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL); +# else + /* + * Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ) + * seconds from now and they continue on every 1/TIMER_HZ seconds. + */ + (void) signal_no_reset(SIGALRM, alarming); + itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; + itimer.it_interval.tv_usec = 1000000/TIMER_HZ; + itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1); + setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); +# endif +#if defined SYS_CYGWIN32 + /* + * Get previleges needed for fiddling with the clock + */ + + /* get the current process token handle */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + msyslog(LOG_ERR, "OpenProcessToken failed: %m"); + exit(1); + } + /* get the LUID for system-time privilege. */ + LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; /* one privilege to set */ + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + /* get set-time privilege for this process. */ + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); + /* cannot test return value of AdjustTokenPrivileges. */ + if (GetLastError() != ERROR_SUCCESS) + msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); +#endif +#else /* SYS_WINNT */ + _tzset(); + + /* + * Get previleges needed for fiddling with the clock + */ + + /* get the current process token handle */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + msyslog(LOG_ERR, "OpenProcessToken failed: %m"); + exit(1); + } + /* get the LUID for system-time privilege. */ + LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; /* one privilege to set */ + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + /* get set-time privilege for this process. */ + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0); + /* cannot test return value of AdjustTokenPrivileges. */ + if (GetLastError() != ERROR_SUCCESS) + msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m"); + + /* + * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds + * Under Win/NT, expiry of timer interval leads to invocation + * of a callback function (on a different thread) rather than + * generating an alarm signal + */ + + /* determine max and min resolution supported */ + if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) { + msyslog(LOG_ERR, "timeGetDevCaps failed: %m"); + exit(1); + } + wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax); + /* establish the minimum timer resolution that we'll use */ + timeBeginPeriod(wTimerRes); + + /* start the timer event */ + wTimerID = timeSetEvent( + (UINT) (1000/TIMER_HZ), /* Delay */ + wTimerRes, /* Resolution */ + (LPTIMECALLBACK) alarming, /* Callback function */ + (DWORD) dwUser, /* User data */ + TIME_PERIODIC); /* Event type (periodic) */ + if (wTimerID == 0) { + msyslog(LOG_ERR, "timeSetEvent failed: %m"); + exit(1); + } +#endif /* SYS_WINNT */ +} + + +/* + * init_io - initialize I/O data and open socket + */ +static void +init_io(void) +{ +#ifdef SYS_WINNT + WORD wVersionRequested; + WSADATA wsaData; + init_transmitbuff(); +#endif /* SYS_WINNT */ + + /* + * Init buffer free list and stat counters + */ + init_recvbuff(sys_numservers + 2); + +#if defined(HAVE_SIGNALED_IO) + set_signal(); +#endif + +#ifdef SYS_WINNT + wVersionRequested = MAKEWORD(1,1); + if (WSAStartup(wVersionRequested, &wsaData)) + { + msyslog(LOG_ERR, "No useable winsock.dll: %m"); + exit(1); + } +#endif /* SYS_WINNT */ + + BLOCKIO(); + + /* create a datagram (UDP) socket */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + msyslog(LOG_ERR, "socket() failed: %m"); + exit(1); + /*NOTREACHED*/ + } + + /* + * bind the socket to the NTP port + */ + if (!debug && set_time && !unpriv_port) { + struct sockaddr_in addr; + + memset((char *)&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(NTP_PORT); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { +#ifndef SYS_WINNT + if (errno == EADDRINUSE) +#else + if (WSAGetLastError() == WSAEADDRINUSE) +#endif + msyslog(LOG_ERR, + "the NTP socket is in use, exiting"); + else + msyslog(LOG_ERR, "bind() fails: %m"); + exit(1); + } + } + + FD_ZERO(&fdmask); + FD_SET(fd, &fdmask); + + /* + * set non-blocking, + */ + +#ifdef USE_FIONBIO + /* in vxWorks we use FIONBIO, but the others are defined for old systems, so + * all hell breaks loose if we leave them defined + */ +#undef O_NONBLOCK +#undef FNDELAY +#undef O_NDELAY +#endif + +#if defined(O_NONBLOCK) /* POSIX */ + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + { + msyslog(LOG_ERR, "fcntl(O_NONBLOCK) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FNDELAY) + if (fcntl(fd, F_SETFL, FNDELAY) < 0) + { + msyslog(LOG_ERR, "fcntl(FNDELAY) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(O_NDELAY) /* generally the same as FNDELAY */ + if (fcntl(fd, F_SETFL, O_NDELAY) < 0) + { + msyslog(LOG_ERR, "fcntl(O_NDELAY) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FIONBIO) + if ( +# if defined(VMS) + (ioctl(fd,FIONBIO,&1) < 0) +# elif defined(SYS_WINNT) + (ioctlsocket(fd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) +# else + (ioctl(fd,FIONBIO,&on) < 0) +# endif + ) + { + msyslog(LOG_ERR, "ioctl(FIONBIO) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#elif defined(FIOSNBIO) + if (ioctl(fd,FIOSNBIO,&on) < 0) + { + msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +#else +# include "Bletch: Need non-blocking I/O!" +#endif + +#ifdef HAVE_SIGNALED_IO + init_socket_sig(fd); +#endif /* not HAVE_SIGNALED_IO */ + + UNBLOCKIO(); +} + + +/* + * sendpkt - send a packet to the specified destination + */ +static int +sendpkt( + struct sockaddr_in *dest, + struct pkt *pkt, + int len + ) +{ + int cc; + static int horriblecnt = 0; +#ifdef SYS_WINNT + DWORD err; +#endif /* SYS_WINNT */ + + total_xmit++; /* count it */ + + if (horrible) { + if (++horriblecnt > HORRIBLEOK) { + if (debug > 3) + printf("dropping send (%s)\n", ntoa(dest)); + if (horriblecnt >= HORRIBLEOK+horrible) + horriblecnt = 0; + return 0; + } + } + + + cc = sendto(fd, (char *)pkt, (size_t)len, 0, (struct sockaddr *)dest, + sizeof(struct sockaddr_in)); +#ifndef SYS_WINNT + if (cc == -1) { + if (errno != EWOULDBLOCK && errno != ENOBUFS) +#else + if (cc == SOCKET_ERROR) { + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAENOBUFS) +#endif /* SYS_WINNT */ + msyslog(LOG_ERR, "sendto(%s): %m", ntoa(dest)); + return -1; + } + return 0; +} + + +/* + * input_handler - receive packets asynchronously + */ +void +input_handler(l_fp *xts) +{ + register int n; + register struct recvbuf *rb; + struct timeval tvzero; + int fromlen; + fd_set fds; + l_fp ts; + ts = *xts; /* we ignore xts, but make the compiler happy */ + + /* + * Do a poll to see if we have data + */ + for (;;) { + fds = fdmask; + tvzero.tv_sec = tvzero.tv_usec = 0; + n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero); + + /* + * If nothing to do, just return. If an error occurred, + * complain and return. If we've got some, freeze a + * timestamp. + */ + if (n == 0) + return; + else if (n == -1) { + if (errno != EINTR) { + msyslog(LOG_ERR, "select() error: %m"); + } + return; + } + get_systime(&ts); + + /* + * Get a buffer and read the frame. If we + * haven't got a buffer, or this is received + * on the wild card socket, just dump the packet. + */ + if (initializing || free_recvbuffs == 0) { + char buf[100]; + +#ifndef SYS_WINNT + (void) read(fd, buf, sizeof buf); +#else + /* NT's _read does not operate on nonblocking sockets + * either recvfrom or ReadFile() has to be used here. + * ReadFile is used in [ntpd]ntp_intres() and ntpdc, + * just to be different use recvfrom() here + */ + recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)0, NULL); +#endif /* SYS_WINNT */ + continue; + } + + rb = get_free_recv_buffer(); + + fromlen = sizeof(struct sockaddr_in); + rb->recv_length = recvfrom(fd, (char *)&rb->recv_pkt, + sizeof(rb->recv_pkt), 0, + (struct sockaddr *)&rb->srcadr, &fromlen); + if (rb->recv_length == -1) { + freerecvbuf(rb); + continue; + } + + /* + * Got one. Mark how and when it got here, + * put it on the full list. + */ + rb->recv_time = ts; + add_full_recv_buffer(rb); + total_recv++; /* count it */ + } +} + + +/* XXX ELIMINATE printserver similar in ntptrace.c, ntpdate.c */ +/* + * printserver - print detail information for a server + */ +static void +printserver( + register struct server *pp, + FILE *fp + ) +{ + register int i; + char junk[5]; + char *str; + + if (!debug) { + (void) fprintf(fp, + "%-15s %d/%d %03o v%d s%d offset %9s delay %s disp %s\n", + ntoa(&pp->srcadr), + pp->xmtcnt,pp->rcvcnt,pp->reach, + pp->version,pp->stratum, + lfptoa(&pp->offset, 6), ufptoa(pp->delay, 5), + ufptoa(pp->dispersion, 4)); + return; + } + + (void) fprintf(fp, "server %s, port %d\n", + ntoa(&pp->srcadr), ntohs(pp->srcadr.sin_port)); + + (void) fprintf(fp, "stratum %d, precision %d, leap %c%c, trust %03o\n", + pp->stratum, pp->precision, + pp->leap & 0x2 ? '1' : '0', + pp->leap & 0x1 ? '1' : '0', + pp->trust); + + if (pp->stratum == 1) { + junk[4] = 0; + memmove(junk, (char *)&pp->refid, 4); + str = junk; + } else { + str = numtoa(pp->refid); + } + (void) fprintf(fp, + "refid [%s], delay %s, dispersion %s\n", + str, fptoa((s_fp)pp->delay, 5), + ufptoa(pp->dispersion, 5)); + + (void) fprintf(fp, "transmitted %d, received %d, reachable %03o\n", + pp->xmtcnt, pp->rcvcnt, pp->reach); + + (void) fprintf(fp, "reference time: %s\n", + prettydate(&pp->reftime)); + (void) fprintf(fp, "originate timestamp: %s\n", + prettydate(&pp->org)); + (void) fprintf(fp, "transmit timestamp: %s\n", + prettydate(&pp->xmt)); + + (void) fprintf(fp, "filter delay: "); + for (i = 0; i < NTP_SHIFT; i++) { + (void) fprintf(fp, " %-8.8s", fptoa(pp->filter_delay[i], 5)); + if (i == (NTP_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "filter offset:"); + for (i = 0; i < PEER_SHIFT; i++) { + (void) fprintf(fp, " %-8.8s", lfptoa(&pp->filter_offset[i], 6)); + if (i == (PEER_SHIFT>>1)-1) + (void) fprintf(fp, "\n "); + } + (void) fprintf(fp, "\n"); + + (void) fprintf(fp, "delay %s, dispersion %s\n", + fptoa((s_fp)pp->delay, 5), ufptoa(pp->dispersion, 5)); + + (void) fprintf(fp, "offset %s\n\n", + lfptoa(&pp->offset, 6)); +} + +#if !defined(HAVE_VSPRINTF) +int +vsprintf( + char *str, + const char *fmt, + va_list ap + ) +{ + FILE f; + int len; + + f._flag = _IOWRT+_IOSTRG; + f._ptr = str; + f._cnt = 32767; + len = _doprnt(fmt, ap, &f); + *f._ptr = 0; + return (len); +} +#endif |