diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-12-02 09:01:21 +0000 |
---|---|---|
committer | <> | 2014-12-04 16:11:25 +0000 |
commit | bdab5265fcbf3f472545073a23f8999749a9f2b9 (patch) | |
tree | c6018dd03dea906f8f1fb5f105f05b71a7dc250a /util | |
download | ntp-d4b7cd9723cce9561fa15f74b90b85a3a61b5ef8.tar.gz |
Imported from /home/lorry/working-area/delta_ntp/ntp-dev-4.2.7p482.tar.gz.ntp-dev-4.2.7p482
Diffstat (limited to 'util')
-rw-r--r-- | util/Makefile.am | 135 | ||||
-rw-r--r-- | util/Makefile.in | 1289 | ||||
-rw-r--r-- | util/README | 44 | ||||
-rw-r--r-- | util/audio-pcm.c | 154 | ||||
-rw-r--r-- | util/byteorder.c | 56 | ||||
-rw-r--r-- | util/hist.c | 110 | ||||
-rw-r--r-- | util/invoke-ntp-keygen.menu | 1 | ||||
-rw-r--r-- | util/invoke-ntp-keygen.texi | 1354 | ||||
-rw-r--r-- | util/jitter.c | 136 | ||||
-rw-r--r-- | util/jitter.h | 401 | ||||
-rw-r--r-- | util/kern.c | 225 | ||||
-rw-r--r-- | util/longsize.c | 11 | ||||
-rw-r--r-- | util/ntp-keygen-opts.c | 1719 | ||||
-rw-r--r-- | util/ntp-keygen-opts.def | 1144 | ||||
-rw-r--r-- | util/ntp-keygen-opts.h | 386 | ||||
-rw-r--r-- | util/ntp-keygen.1ntp-keygenman | 1221 | ||||
-rw-r--r-- | util/ntp-keygen.1ntp-keygenmdoc | 1071 | ||||
-rw-r--r-- | util/ntp-keygen.c | 2181 | ||||
-rw-r--r-- | util/ntp-keygen.html | 1811 | ||||
-rw-r--r-- | util/ntp-keygen.man.in | 1221 | ||||
-rw-r--r-- | util/ntp-keygen.mdoc.in | 1071 | ||||
-rw-r--r-- | util/ntp-keygen.texi | 307 | ||||
-rw-r--r-- | util/ntptime.c | 474 | ||||
-rw-r--r-- | util/pps-api.c | 100 | ||||
-rw-r--r-- | util/precision.c | 171 | ||||
-rw-r--r-- | util/sht.c | 260 | ||||
-rw-r--r-- | util/testrs6000.c | 55 | ||||
-rw-r--r-- | util/tg.c | 653 | ||||
-rw-r--r-- | util/tg2.c | 2506 | ||||
-rw-r--r-- | util/tickadj.c | 908 | ||||
-rw-r--r-- | util/timetrim.c | 116 |
31 files changed, 21291 insertions, 0 deletions
diff --git a/util/Makefile.am b/util/Makefile.am new file mode 100644 index 0000000..4265e0b --- /dev/null +++ b/util/Makefile.am @@ -0,0 +1,135 @@ +NULL= + +bin_PROGRAMS= $(NTP_KEYGEN_DB) $(NTPTIME_DB) $(TICKADJ_DB) $(TIMETRIM_DB) +libexec_PROGRAMS= $(NTP_KEYGEN_DL) $(NTPTIME_DL) $(TICKADJ_DL) $(TIMETRIM_DL) +sbin_PROGRAMS= $(NTP_KEYGEN_DS) $(NTPTIME_DS) $(TICKADJ_DS) $(TIMETRIM_DS) + +EXTRA_PROGRAMS= audio-pcm byteorder hist jitter kern longsize ntp-keygen \ + ntptime pps-api precision sht testrs6000 tg tg2 tickadj timetrim + +AM_CFLAGS = $(CFLAGS_NTP) + +AM_CPPFLAGS = $(NTP_INCS) +AM_CPPFLAGS += $(LIBOPTS_CFLAGS) +AM_CPPFLAGS += $(CPPFLAGS_NTP) + +AM_LDFLAGS = $(LDFLAGS_NTP) + +# LDADD might need RESLIB and ADJLIB +LDADD= ../libntp/libntp.a $(LDADD_LIBNTP) $(LIBM) $(PTHREAD_LIBS) +tg2_LDADD= ../libntp/libntp.a $(LDADD_LIBNTP) $(LIBM) +ntp_keygen_LDADD = version.o $(LIBOPTS_LDADD) ../libntp/libntp.a +ntp_keygen_LDADD += $(LDADD_LIBNTP) $(PTHREAD_LIBS) $(LDADD_NTP) $(LIBM) +ntp_keygen_SOURCES = ntp-keygen.c ntp-keygen-opts.c ntp-keygen-opts.h + +tickadj_LDADD= ../libntp/libntp.a $(LDADD_LIBNTP) $(LIBM) $(PTHREAD_LIBS) $(LDADD_NLIST) + +EXTRA_DIST= \ + invoke-ntp-keygen.menu \ + invoke-ntp-keygen.texi \ + ntp-keygen-opts.def \ + ntp-keygen.1ntp-keygenman \ + ntp-keygen.1ntp-keygenmdoc \ + ntp-keygen.man.in \ + ntp-keygen.mdoc.in \ + ntp-keygen.mdoc.in \ + ntp-keygen.html \ + ntp-keygen.texi \ + $(NULL) + +BUILT_SOURCES= ntp-keygen-opts.c ntp-keygen-opts.h +CLEANFILES= +DISTCLEANFILES= .version version.c config.log $(man_MANS) + +html_DATA= \ + $(srcdir)/ntp-keygen.html \ + $(NULL) + +noinst_DATA= \ + $(srcdir)/invoke-ntp-keygen.menu \ + $(srcdir)/invoke-ntp-keygen.texi \ + $(srcdir)/ntp-keygen.man.in \ + $(srcdir)/ntp-keygen.mdoc.in \ + $(man_MANS) \ + $(NULL) + +man1_MANS= +man8_MANS= +man_MANS= ntp-keygen.$(NTP_KEYGEN_MS) + +run_ag= cd $(srcdir) && env PATH="$(abs_builddir):$(PATH)" AUTOGEN_DNE_DATE=-D \ + autogen -L ../sntp/include -L ../sntp/ag-tpl --writable +std_def_list = \ + $(top_srcdir)/sntp/include/debug-opt.def \ + $(top_srcdir)/sntp/include/autogen-version.def \ + $(top_srcdir)/sntp/include/copyright.def \ + $(top_srcdir)/sntp/include/homerc.def \ + $(top_srcdir)/sntp/include/ntp.lic \ + $(top_srcdir)/sntp/include/version.def \ + $(NULL) + +$(srcdir)/ntp-keygen-opts.h: $(srcdir)/ntp-keygen-opts.c + @: do-nothing action to avoid default SCCS get, .h built with .c + +$(srcdir)/ntp-keygen-opts.c: $(srcdir)/ntp-keygen-opts.def $(std_def_list) + $(run_ag) ntp-keygen-opts.def + +### + +$(srcdir)/ntp-keygen.1ntp-keygenman: $(srcdir)/ntp-keygen-opts.def $(std_def_list) + $(run_ag) -DMAN_SECTION=1ntp-keygenman -Tagman-cmd.tpl ntp-keygen-opts.def + +$(srcdir)/ntp-keygen.man.in: $(srcdir)/ntp-keygen.1ntp-keygenman $(top_srcdir)/sntp/scripts/mansec2subst.sed + sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp-keygen.1ntp-keygenman > $(srcdir)/ntp-keygen.man.in+ + mv $(srcdir)/ntp-keygen.man.in+ $(srcdir)/ntp-keygen.man.in + +### + +$(srcdir)/ntp-keygen.1ntp-keygenmdoc: $(srcdir)/ntp-keygen-opts.def $(std_def_list) + $(run_ag) -DMAN_SECTION=1ntp-keygenmdoc -Tagmdoc-cmd.tpl ntp-keygen-opts.def + +$(srcdir)/ntp-keygen.mdoc.in: $(srcdir)/ntp-keygen.1ntp-keygenmdoc $(top_srcdir)/sntp/scripts/mansec2subst.sed + sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp-keygen.1ntp-keygenmdoc > $(srcdir)/ntp-keygen.mdoc.in+ + mv $(srcdir)/ntp-keygen.mdoc.in+ $(srcdir)/ntp-keygen.mdoc.in + +### + +ntp-keygen.$(NTP_KEYGEN_MS): $(srcdir)/ntp-keygen.$(MANTAGFMT).in $(top_builddir)/config.status + $(top_builddir)/config.status --file=ntp-keygen.$(NTP_KEYGEN_MS)+:$(srcdir)/ntp-keygen.$(MANTAGFMT).in + mv ntp-keygen.$(NTP_KEYGEN_MS)+ ntp-keygen.$(NTP_KEYGEN_MS) + +### + +$(srcdir)/invoke-ntp-keygen.menu: $(srcdir)/invoke-ntp-keygen.texi + @: do-nothing action to avoid default SCCS get, .menu built with .texi + +$(srcdir)/invoke-ntp-keygen.texi: $(srcdir)/ntp-keygen-opts.def $(std_def_list) + $(run_ag) -Tagtexi-cmd.tpl -DLEVEL=section ntp-keygen-opts.def + $(top_srcdir)/scripts/build/check--help $@ + +$(srcdir)/ntp-keygen.html: $(srcdir)/ntp-keygen.texi $(top_srcdir)/sntp/include/version.texi + cd $(srcdir) && ( makeinfo --force --html --no-split -o ntp-keygen.html ntp-keygen.texi || true ) + + +jitter_SOURCES= jitter.c jitter.h +jitter_LDADD= + +kern.o: kern.c + $(COMPILE) -DHAVE_TIMEX_H -c kern.c + +$(PROGRAMS): version.o + +$(top_srcdir)/sntp/scm-rev: + cd ../sntp && $(MAKE) $(AM_MAKEFLAGS) check-scm-rev + +version.c: $(ntp_keygen_OBJECTS) ../libntp/libntp.a Makefile $(top_srcdir)/sntp/scm-rev + env CSET=`cat $(top_srcdir)/sntp/scm-rev` $(top_builddir)/scripts/build/mkver ntp-keygen + +version.o: version.c + env CCACHE_DISABLE=1 $(COMPILE) -c version.c -o version.o + +include $(top_srcdir)/bincheck.mf +include $(top_srcdir)/sntp/check-libntp.mf +include $(top_srcdir)/check-libopts.mf +include $(top_srcdir)/depsver.mf +include $(top_srcdir)/includes.mf diff --git a/util/Makefile.in b/util/Makefile.in new file mode 100644 index 0000000..06293ac --- /dev/null +++ b/util/Makefile.in @@ -0,0 +1,1289 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@ + +# we traditionally installed software in bindir, while it should have gone +# in sbindir. Now that we offer a choice, look in the "other" installation +# subdir to warn folks if there is another version there. + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +EXTRA_PROGRAMS = audio-pcm$(EXEEXT) byteorder$(EXEEXT) hist$(EXEEXT) \ + jitter$(EXEEXT) kern$(EXEEXT) longsize$(EXEEXT) \ + ntp-keygen$(EXEEXT) ntptime$(EXEEXT) pps-api$(EXEEXT) \ + precision$(EXEEXT) sht$(EXEEXT) testrs6000$(EXEEXT) \ + tg$(EXEEXT) tg2$(EXEEXT) tickadj$(EXEEXT) timetrim$(EXEEXT) +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/bincheck.mf $(top_srcdir)/check-libopts.mf \ + $(top_srcdir)/depsver.mf $(top_srcdir)/includes.mf \ + $(top_srcdir)/sntp/check-libntp.mf +subdir = util +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/sntp/libopts/m4/libopts.m4 \ + $(top_srcdir)/sntp/libopts/m4/stdnoreturn.m4 \ + $(top_srcdir)/sntp/libevent/m4/openldap-thread-check.m4 \ + $(top_srcdir)/sntp/libevent/m4/openldap.m4 \ + $(top_srcdir)/sntp/m4/define_dir.m4 \ + $(top_srcdir)/sntp/m4/hms_search_lib.m4 \ + $(top_srcdir)/sntp/m4/libtool.m4 \ + $(top_srcdir)/sntp/m4/ltoptions.m4 \ + $(top_srcdir)/sntp/m4/ltsugar.m4 \ + $(top_srcdir)/sntp/m4/ltversion.m4 \ + $(top_srcdir)/sntp/m4/lt~obsolete.m4 \ + $(top_srcdir)/sntp/m4/ntp_cacheversion.m4 \ + $(top_srcdir)/sntp/m4/ntp_compiler.m4 \ + $(top_srcdir)/sntp/m4/ntp_crosscompile.m4 \ + $(top_srcdir)/sntp/m4/ntp_debug.m4 \ + $(top_srcdir)/sntp/m4/ntp_dir_sep.m4 \ + $(top_srcdir)/sntp/m4/ntp_facilitynames.m4 \ + $(top_srcdir)/sntp/m4/ntp_googletest.m4 \ + $(top_srcdir)/sntp/m4/ntp_ipv6.m4 \ + $(top_srcdir)/sntp/m4/ntp_lib_m.m4 \ + $(top_srcdir)/sntp/m4/ntp_libevent.m4 \ + $(top_srcdir)/sntp/m4/ntp_libntp.m4 \ + $(top_srcdir)/sntp/m4/ntp_lineeditlibs.m4 \ + $(top_srcdir)/sntp/m4/ntp_locinfo.m4 \ + $(top_srcdir)/sntp/m4/ntp_openssl.m4 \ + $(top_srcdir)/sntp/m4/ntp_pkg_config.m4 \ + $(top_srcdir)/sntp/m4/ntp_prog_cc.m4 \ + $(top_srcdir)/sntp/m4/ntp_rlimit.m4 \ + $(top_srcdir)/sntp/m4/ntp_sntp.m4 \ + $(top_srcdir)/sntp/m4/ntp_ver_suffix.m4 \ + $(top_srcdir)/sntp/m4/ntp_vpathhack.m4 \ + $(top_srcdir)/sntp/m4/os_cflags.m4 \ + $(top_srcdir)/sntp/m4/snprintf.m4 \ + $(top_srcdir)/sntp/m4/version.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" \ + "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" \ + "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(htmldir)" +PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS) $(sbin_PROGRAMS) +audio_pcm_SOURCES = audio-pcm.c +audio_pcm_OBJECTS = audio-pcm.$(OBJEXT) +audio_pcm_LDADD = $(LDADD) +am__DEPENDENCIES_1 = +audio_pcm_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +byteorder_SOURCES = byteorder.c +byteorder_OBJECTS = byteorder.$(OBJEXT) +byteorder_LDADD = $(LDADD) +byteorder_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +hist_SOURCES = hist.c +hist_OBJECTS = hist.$(OBJEXT) +hist_LDADD = $(LDADD) +hist_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_jitter_OBJECTS = jitter.$(OBJEXT) +jitter_OBJECTS = $(am_jitter_OBJECTS) +jitter_DEPENDENCIES = +kern_SOURCES = kern.c +kern_OBJECTS = kern.$(OBJEXT) +kern_LDADD = $(LDADD) +kern_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +longsize_SOURCES = longsize.c +longsize_OBJECTS = longsize.$(OBJEXT) +longsize_LDADD = $(LDADD) +longsize_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_ntp_keygen_OBJECTS = ntp-keygen.$(OBJEXT) ntp-keygen-opts.$(OBJEXT) +ntp_keygen_OBJECTS = $(am_ntp_keygen_OBJECTS) +ntp_keygen_DEPENDENCIES = version.o $(am__DEPENDENCIES_1) \ + ../libntp/libntp.a $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +ntptime_SOURCES = ntptime.c +ntptime_OBJECTS = ntptime.$(OBJEXT) +ntptime_LDADD = $(LDADD) +ntptime_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +pps_api_SOURCES = pps-api.c +pps_api_OBJECTS = pps-api.$(OBJEXT) +pps_api_LDADD = $(LDADD) +pps_api_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +precision_SOURCES = precision.c +precision_OBJECTS = precision.$(OBJEXT) +precision_LDADD = $(LDADD) +precision_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +sht_SOURCES = sht.c +sht_OBJECTS = sht.$(OBJEXT) +sht_LDADD = $(LDADD) +sht_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +testrs6000_SOURCES = testrs6000.c +testrs6000_OBJECTS = testrs6000.$(OBJEXT) +testrs6000_LDADD = $(LDADD) +testrs6000_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +tg_SOURCES = tg.c +tg_OBJECTS = tg.$(OBJEXT) +tg_LDADD = $(LDADD) +tg_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +tg2_SOURCES = tg2.c +tg2_OBJECTS = tg2.$(OBJEXT) +tg2_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +tickadj_SOURCES = tickadj.c +tickadj_OBJECTS = tickadj.$(OBJEXT) +tickadj_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +timetrim_SOURCES = timetrim.c +timetrim_OBJECTS = timetrim.$(OBJEXT) +timetrim_LDADD = $(LDADD) +timetrim_DEPENDENCIES = ../libntp/libntp.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/sntp/libevent/build-aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = audio-pcm.c byteorder.c hist.c $(jitter_SOURCES) kern.c \ + longsize.c $(ntp_keygen_SOURCES) ntptime.c pps-api.c \ + precision.c sht.c testrs6000.c tg.c tg2.c tickadj.c timetrim.c +DIST_SOURCES = audio-pcm.c byteorder.c hist.c $(jitter_SOURCES) kern.c \ + longsize.c $(ntp_keygen_SOURCES) ntptime.c pps-api.c \ + precision.c sht.c testrs6000.c tg.c tg2.c tickadj.c timetrim.c +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +man1dir = $(mandir)/man1 +man8dir = $(mandir)/man8 +NROFF = nroff +MANS = $(man1_MANS) $(man8_MANS) $(man_MANS) +DATA = $(html_DATA) $(noinst_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CALC_TICKADJ_DB = @CALC_TICKADJ_DB@ +CALC_TICKADJ_DL = @CALC_TICKADJ_DL@ +CALC_TICKADJ_DS = @CALC_TICKADJ_DS@ +CALC_TICKADJ_MS = @CALC_TICKADJ_MS@ +CALC_TICKADJ_NI = @CALC_TICKADJ_NI@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CFLAGS_NTP = @CFLAGS_NTP@ +CHUTEST = @CHUTEST@ +CONFIG_SHELL = @CONFIG_SHELL@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_NTP = @CPPFLAGS_NTP@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DCFD = @DCFD@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EDITLINE_LIBS = @EDITLINE_LIBS@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_CPPFLAGS = @GTEST_CPPFLAGS@ +GTEST_CXXFLAGS = @GTEST_CXXFLAGS@ +GTEST_LDFLAGS = @GTEST_LDFLAGS@ +GTEST_LIBS = @GTEST_LIBS@ +HAVE_INLINE = @HAVE_INLINE@ +HAVE_RLIMIT_MEMLOCK = @HAVE_RLIMIT_MEMLOCK@ +HAVE_RLIMIT_STACK = @HAVE_RLIMIT_STACK@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDADD_LIBNTP = @LDADD_LIBNTP@ +LDADD_NLIST = @LDADD_NLIST@ +LDADD_NTP = @LDADD_NTP@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_NTP = @LDFLAGS_NTP@ +LIBISC_PTHREADS_NOTHREADS = @LIBISC_PTHREADS_NOTHREADS@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBOPTS_CFLAGS = @LIBOPTS_CFLAGS@ +LIBOPTS_DIR = @LIBOPTS_DIR@ +LIBOPTS_LDADD = @LIBOPTS_LDADD@ +LIBPARSE = @LIBPARSE@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LSCF = @LSCF@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_LAYOUT = @MAKE_CHECK_LAYOUT@ +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_NTPSNMPD = @MAKE_NTPSNMPD@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +MAKE_TIMETRIM = @MAKE_TIMETRIM@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MANTAGFMT = @MANTAGFMT@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NTPDATE_DB = @NTPDATE_DB@ +NTPDATE_DL = @NTPDATE_DL@ +NTPDATE_DS = @NTPDATE_DS@ +NTPDATE_MS = @NTPDATE_MS@ +NTPDATE_NI = @NTPDATE_NI@ +NTPDC_DB = @NTPDC_DB@ +NTPDC_DL = @NTPDC_DL@ +NTPDC_DS = @NTPDC_DS@ +NTPDC_MS = @NTPDC_MS@ +NTPDC_NI = @NTPDC_NI@ +NTPDSIM_DB = @NTPDSIM_DB@ +NTPDSIM_DL = @NTPDSIM_DL@ +NTPDSIM_DS = @NTPDSIM_DS@ +NTPDSIM_MS = @NTPDSIM_MS@ +NTPDSIM_NI = @NTPDSIM_NI@ +NTPD_DB = @NTPD_DB@ +NTPD_DL = @NTPD_DL@ +NTPD_DS = @NTPD_DS@ +NTPD_MS = @NTPD_MS@ +NTPD_NI = @NTPD_NI@ +NTPQ_DB = @NTPQ_DB@ +NTPQ_DL = @NTPQ_DL@ +NTPQ_DS = @NTPQ_DS@ +NTPQ_MS = @NTPQ_MS@ +NTPQ_NI = @NTPQ_NI@ +NTPSNMPD_DB = @NTPSNMPD_DB@ +NTPSNMPD_DL = @NTPSNMPD_DL@ +NTPSNMPD_DS = @NTPSNMPD_DS@ +NTPSNMPD_MS = @NTPSNMPD_MS@ +NTPSNMPD_NI = @NTPSNMPD_NI@ +NTPSWEEP_DB = @NTPSWEEP_DB@ +NTPSWEEP_DL = @NTPSWEEP_DL@ +NTPSWEEP_DS = @NTPSWEEP_DS@ +NTPSWEEP_MS = @NTPSWEEP_MS@ +NTPSWEEP_NI = @NTPSWEEP_NI@ +NTPTIME_DB = @NTPTIME_DB@ +NTPTIME_DL = @NTPTIME_DL@ +NTPTIME_DS = @NTPTIME_DS@ +NTPTIME_MS = @NTPTIME_MS@ +NTPTIME_NI = @NTPTIME_NI@ +NTPTRACE_DB = @NTPTRACE_DB@ +NTPTRACE_DL = @NTPTRACE_DL@ +NTPTRACE_DS = @NTPTRACE_DS@ +NTPTRACE_MS = @NTPTRACE_MS@ +NTPTRACE_NI = @NTPTRACE_NI@ +NTP_KEYGEN_DB = @NTP_KEYGEN_DB@ +NTP_KEYGEN_DL = @NTP_KEYGEN_DL@ +NTP_KEYGEN_DS = @NTP_KEYGEN_DS@ +NTP_KEYGEN_MS = @NTP_KEYGEN_MS@ +NTP_KEYGEN_NI = @NTP_KEYGEN_NI@ +NTP_KEYSDIR = @NTP_KEYSDIR@ +NTP_WAIT_DB = @NTP_WAIT_DB@ +NTP_WAIT_DL = @NTP_WAIT_DL@ +NTP_WAIT_DS = @NTP_WAIT_DS@ +NTP_WAIT_MS = @NTP_WAIT_MS@ +NTP_WAIT_NI = @NTP_WAIT_NI@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_NET_SNMP_CONFIG = @PATH_NET_SNMP_CONFIG@ +PATH_PERL = @PATH_PERL@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PATH_TEST = @PATH_TEST@ +PERLLIBDIR = @PERLLIBDIR@ +PKG_CONFIG = @PKG_CONFIG@ +POSIX_SHELL = @POSIX_SHELL@ +PROPDELAY = @PROPDELAY@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SNMP_CFLAGS = @SNMP_CFLAGS@ +SNMP_CPPFLAGS = @SNMP_CPPFLAGS@ +SNMP_LIBS = @SNMP_LIBS@ +SNTP = @SNTP@ +SNTP_DB = @SNTP_DB@ +SNTP_DL = @SNTP_DL@ +SNTP_DS = @SNTP_DS@ +SNTP_MS = @SNTP_MS@ +SNTP_NI = @SNTP_NI@ +STDNORETURN_H = @STDNORETURN_H@ +STRIP = @STRIP@ +TESTDCF = @TESTDCF@ +TICKADJ_DB = @TICKADJ_DB@ +TICKADJ_DL = @TICKADJ_DL@ +TICKADJ_DS = @TICKADJ_DS@ +TICKADJ_MS = @TICKADJ_MS@ +TICKADJ_NI = @TICKADJ_NI@ +TIMETRIM_DB = @TIMETRIM_DB@ +TIMETRIM_DL = @TIMETRIM_DL@ +TIMETRIM_DS = @TIMETRIM_DS@ +TIMETRIM_MS = @TIMETRIM_MS@ +TIMETRIM_NI = @TIMETRIM_NI@ +VERSION = @VERSION@ +VER_SUFFIX = @VER_SUFFIX@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +NULL = +bin_PROGRAMS = $(NTP_KEYGEN_DB) $(NTPTIME_DB) $(TICKADJ_DB) $(TIMETRIM_DB) +libexec_PROGRAMS = $(NTP_KEYGEN_DL) $(NTPTIME_DL) $(TICKADJ_DL) $(TIMETRIM_DL) +sbin_PROGRAMS = $(NTP_KEYGEN_DS) $(NTPTIME_DS) $(TICKADJ_DS) $(TIMETRIM_DS) +AM_CFLAGS = $(CFLAGS_NTP) +AM_CPPFLAGS = $(NTP_INCS) $(LIBOPTS_CFLAGS) $(CPPFLAGS_NTP) +AM_LDFLAGS = $(LDFLAGS_NTP) + +# LDADD might need RESLIB and ADJLIB +LDADD = ../libntp/libntp.a $(LDADD_LIBNTP) $(LIBM) $(PTHREAD_LIBS) +tg2_LDADD = ../libntp/libntp.a $(LDADD_LIBNTP) $(LIBM) +ntp_keygen_LDADD = version.o $(LIBOPTS_LDADD) ../libntp/libntp.a \ + $(LDADD_LIBNTP) $(PTHREAD_LIBS) $(LDADD_NTP) $(LIBM) +ntp_keygen_SOURCES = ntp-keygen.c ntp-keygen-opts.c ntp-keygen-opts.h +tickadj_LDADD = ../libntp/libntp.a $(LDADD_LIBNTP) $(LIBM) $(PTHREAD_LIBS) $(LDADD_NLIST) +EXTRA_DIST = \ + invoke-ntp-keygen.menu \ + invoke-ntp-keygen.texi \ + ntp-keygen-opts.def \ + ntp-keygen.1ntp-keygenman \ + ntp-keygen.1ntp-keygenmdoc \ + ntp-keygen.man.in \ + ntp-keygen.mdoc.in \ + ntp-keygen.mdoc.in \ + ntp-keygen.html \ + ntp-keygen.texi \ + $(NULL) + +BUILT_SOURCES = ntp-keygen-opts.c ntp-keygen-opts.h check-libntp \ + check-libopts .deps-ver +CLEANFILES = check-libntp check-libopts .deps-ver +DISTCLEANFILES = .version version.c config.log $(man_MANS) +html_DATA = \ + $(srcdir)/ntp-keygen.html \ + $(NULL) + +noinst_DATA = \ + $(srcdir)/invoke-ntp-keygen.menu \ + $(srcdir)/invoke-ntp-keygen.texi \ + $(srcdir)/ntp-keygen.man.in \ + $(srcdir)/ntp-keygen.mdoc.in \ + $(man_MANS) \ + $(NULL) + +man1_MANS = +man8_MANS = +man_MANS = ntp-keygen.$(NTP_KEYGEN_MS) +run_ag = cd $(srcdir) && env PATH="$(abs_builddir):$(PATH)" AUTOGEN_DNE_DATE=-D \ + autogen -L ../sntp/include -L ../sntp/ag-tpl --writable + +std_def_list = \ + $(top_srcdir)/sntp/include/debug-opt.def \ + $(top_srcdir)/sntp/include/autogen-version.def \ + $(top_srcdir)/sntp/include/copyright.def \ + $(top_srcdir)/sntp/include/homerc.def \ + $(top_srcdir)/sntp/include/ntp.lic \ + $(top_srcdir)/sntp/include/version.def \ + $(NULL) + +jitter_SOURCES = jitter.c jitter.h +jitter_LDADD = +NTP_INCS = -I$(top_srcdir)/include -I$(top_srcdir)/lib/isc/include \ + -I$(top_srcdir)/lib/isc/$(LIBISC_PTHREADS_NOTHREADS)/include \ + -I$(top_srcdir)/lib/isc/unix/include +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/bincheck.mf $(top_srcdir)/sntp/check-libntp.mf $(top_srcdir)/check-libopts.mf $(top_srcdir)/depsver.mf $(top_srcdir)/includes.mf $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign util/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign util/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-libexecPROGRAMS: $(libexec_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)" + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-libexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(libexecdir)" && rm -f $$files + +clean-libexecPROGRAMS: + @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)" + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +audio-pcm$(EXEEXT): $(audio_pcm_OBJECTS) $(audio_pcm_DEPENDENCIES) + @rm -f audio-pcm$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(audio_pcm_OBJECTS) $(audio_pcm_LDADD) $(LIBS) +byteorder$(EXEEXT): $(byteorder_OBJECTS) $(byteorder_DEPENDENCIES) + @rm -f byteorder$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(byteorder_OBJECTS) $(byteorder_LDADD) $(LIBS) +hist$(EXEEXT): $(hist_OBJECTS) $(hist_DEPENDENCIES) + @rm -f hist$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(hist_OBJECTS) $(hist_LDADD) $(LIBS) +jitter$(EXEEXT): $(jitter_OBJECTS) $(jitter_DEPENDENCIES) + @rm -f jitter$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(jitter_OBJECTS) $(jitter_LDADD) $(LIBS) +kern$(EXEEXT): $(kern_OBJECTS) $(kern_DEPENDENCIES) + @rm -f kern$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(kern_OBJECTS) $(kern_LDADD) $(LIBS) +longsize$(EXEEXT): $(longsize_OBJECTS) $(longsize_DEPENDENCIES) + @rm -f longsize$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(longsize_OBJECTS) $(longsize_LDADD) $(LIBS) +ntp-keygen$(EXEEXT): $(ntp_keygen_OBJECTS) $(ntp_keygen_DEPENDENCIES) + @rm -f ntp-keygen$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(ntp_keygen_OBJECTS) $(ntp_keygen_LDADD) $(LIBS) +ntptime$(EXEEXT): $(ntptime_OBJECTS) $(ntptime_DEPENDENCIES) + @rm -f ntptime$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(ntptime_OBJECTS) $(ntptime_LDADD) $(LIBS) +pps-api$(EXEEXT): $(pps_api_OBJECTS) $(pps_api_DEPENDENCIES) + @rm -f pps-api$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(pps_api_OBJECTS) $(pps_api_LDADD) $(LIBS) +precision$(EXEEXT): $(precision_OBJECTS) $(precision_DEPENDENCIES) + @rm -f precision$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(precision_OBJECTS) $(precision_LDADD) $(LIBS) +sht$(EXEEXT): $(sht_OBJECTS) $(sht_DEPENDENCIES) + @rm -f sht$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(sht_OBJECTS) $(sht_LDADD) $(LIBS) +testrs6000$(EXEEXT): $(testrs6000_OBJECTS) $(testrs6000_DEPENDENCIES) + @rm -f testrs6000$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(testrs6000_OBJECTS) $(testrs6000_LDADD) $(LIBS) +tg$(EXEEXT): $(tg_OBJECTS) $(tg_DEPENDENCIES) + @rm -f tg$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tg_OBJECTS) $(tg_LDADD) $(LIBS) +tg2$(EXEEXT): $(tg2_OBJECTS) $(tg2_DEPENDENCIES) + @rm -f tg2$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tg2_OBJECTS) $(tg2_LDADD) $(LIBS) +tickadj$(EXEEXT): $(tickadj_OBJECTS) $(tickadj_DEPENDENCIES) + @rm -f tickadj$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tickadj_OBJECTS) $(tickadj_LDADD) $(LIBS) +timetrim$(EXEEXT): $(timetrim_OBJECTS) $(timetrim_DEPENDENCIES) + @rm -f timetrim$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(timetrim_OBJECTS) $(timetrim_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audio-pcm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/byteorder.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kern.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/longsize.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp-keygen-opts.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntp-keygen.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntptime.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pps-api.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/precision.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sht.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testrs6000.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tg2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tickadj.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timetrim.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } +install-man8: $(man8_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" + @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.8[a-z]*$$/p'; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ + done; } + +uninstall-man8: + @$(NORMAL_UNINSTALL) + @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.8[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man8dir)" && rm -f $$files; } +install-htmlDATA: $(html_DATA) + @$(NORMAL_INSTALL) + test -z "$(htmldir)" || $(MKDIR_P) "$(DESTDIR)$(htmldir)" + @list='$(html_DATA)'; test -n "$(htmldir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ + done + +uninstall-htmlDATA: + @$(NORMAL_UNINSTALL) + @list='$(html_DATA)'; test -n "$(htmldir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(htmldir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(htmldir)" && rm -f $$files + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(PROGRAMS) $(MANS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(htmldir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) 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_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_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." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libexecPROGRAMS \ + clean-libtool clean-sbinPROGRAMS 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: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-htmlDATA install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libexecPROGRAMS \ + install-sbinPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man1 install-man8 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +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-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-htmlDATA \ + uninstall-libexecPROGRAMS uninstall-man uninstall-sbinPROGRAMS + +uninstall-man: uninstall-man1 uninstall-man8 + +.MAKE: all check install install-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libexecPROGRAMS clean-libtool \ + clean-sbinPROGRAMS ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-exec-hook \ + install-html install-html-am install-htmlDATA install-info \ + install-info-am install-libexecPROGRAMS install-man \ + install-man1 install-man8 install-pdf install-pdf-am \ + install-ps install-ps-am install-sbinPROGRAMS install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-htmlDATA uninstall-libexecPROGRAMS uninstall-man \ + uninstall-man1 uninstall-man8 uninstall-sbinPROGRAMS + + +$(srcdir)/ntp-keygen-opts.h: $(srcdir)/ntp-keygen-opts.c + @: do-nothing action to avoid default SCCS get, .h built with .c + +$(srcdir)/ntp-keygen-opts.c: $(srcdir)/ntp-keygen-opts.def $(std_def_list) + $(run_ag) ntp-keygen-opts.def + +### + +$(srcdir)/ntp-keygen.1ntp-keygenman: $(srcdir)/ntp-keygen-opts.def $(std_def_list) + $(run_ag) -DMAN_SECTION=1ntp-keygenman -Tagman-cmd.tpl ntp-keygen-opts.def + +$(srcdir)/ntp-keygen.man.in: $(srcdir)/ntp-keygen.1ntp-keygenman $(top_srcdir)/sntp/scripts/mansec2subst.sed + sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp-keygen.1ntp-keygenman > $(srcdir)/ntp-keygen.man.in+ + mv $(srcdir)/ntp-keygen.man.in+ $(srcdir)/ntp-keygen.man.in + +### + +$(srcdir)/ntp-keygen.1ntp-keygenmdoc: $(srcdir)/ntp-keygen-opts.def $(std_def_list) + $(run_ag) -DMAN_SECTION=1ntp-keygenmdoc -Tagmdoc-cmd.tpl ntp-keygen-opts.def + +$(srcdir)/ntp-keygen.mdoc.in: $(srcdir)/ntp-keygen.1ntp-keygenmdoc $(top_srcdir)/sntp/scripts/mansec2subst.sed + sed -f $(top_srcdir)/sntp/scripts/mansec2subst.sed $(srcdir)/ntp-keygen.1ntp-keygenmdoc > $(srcdir)/ntp-keygen.mdoc.in+ + mv $(srcdir)/ntp-keygen.mdoc.in+ $(srcdir)/ntp-keygen.mdoc.in + +### + +ntp-keygen.$(NTP_KEYGEN_MS): $(srcdir)/ntp-keygen.$(MANTAGFMT).in $(top_builddir)/config.status + $(top_builddir)/config.status --file=ntp-keygen.$(NTP_KEYGEN_MS)+:$(srcdir)/ntp-keygen.$(MANTAGFMT).in + mv ntp-keygen.$(NTP_KEYGEN_MS)+ ntp-keygen.$(NTP_KEYGEN_MS) + +### + +$(srcdir)/invoke-ntp-keygen.menu: $(srcdir)/invoke-ntp-keygen.texi + @: do-nothing action to avoid default SCCS get, .menu built with .texi + +$(srcdir)/invoke-ntp-keygen.texi: $(srcdir)/ntp-keygen-opts.def $(std_def_list) + $(run_ag) -Tagtexi-cmd.tpl -DLEVEL=section ntp-keygen-opts.def + $(top_srcdir)/scripts/build/check--help $@ + +$(srcdir)/ntp-keygen.html: $(srcdir)/ntp-keygen.texi $(top_srcdir)/sntp/include/version.texi + cd $(srcdir) && ( makeinfo --force --html --no-split -o ntp-keygen.html ntp-keygen.texi || true ) + +kern.o: kern.c + $(COMPILE) -DHAVE_TIMEX_H -c kern.c + +$(PROGRAMS): version.o + +$(top_srcdir)/sntp/scm-rev: + cd ../sntp && $(MAKE) $(AM_MAKEFLAGS) check-scm-rev + +version.c: $(ntp_keygen_OBJECTS) ../libntp/libntp.a Makefile $(top_srcdir)/sntp/scm-rev + env CSET=`cat $(top_srcdir)/sntp/scm-rev` $(top_builddir)/scripts/build/mkver ntp-keygen + +version.o: version.c + env CCACHE_DISABLE=1 $(COMPILE) -c version.c -o version.o + +install-exec-hook: + @test -z "${bin_PROGRAMS}${bin_SCRIPTS}" \ + || for i in ${bin_PROGRAMS} ${bin_SCRIPTS} " "; do \ + test ! -f ${sbindir}/$$i \ + || echo "*** $$i is also in ${sbindir}!"; \ + done + @test -z "${sbin_PROGRAMS}${asbin_SCRIPTS}" \ + || for i in ${sbin_PROGRAMS} ${sbin_SCRIPTS} " "; do \ + test ! -f ${bindir}/$$i \ + || echo "*** $$i is also in ${bindir}!"; \ + done + +# + +check-libntp: ../libntp/libntp.a + @echo stamp > $@ + +../libntp/libntp.a: + cd ../libntp && $(MAKE) $(AM_MAKEFLAGS) libntp.a + +check-libopts: ../sntp/libopts/libopts.la + @echo stamp > $@ + +../sntp/libopts/libopts.la: + -cd ../sntp/libopts && $(MAKE) $(AM_MAKEFLAGS) libopts.la +$(DEPDIR)/deps-ver: $(top_srcdir)/deps-ver + @[ -f $@ ] || \ + cp $(top_srcdir)/deps-ver $@ + @[ -w $@ ] || \ + chmod ug+w $@ + @cmp $(top_srcdir)/deps-ver $@ > /dev/null || ( \ + $(MAKE) $(AM_MAKEFLAGS) clean && \ + echo -n "Prior $(subdir)/$(DEPDIR) version " && \ + cat $@ && \ + rm -rf $(DEPDIR) && \ + mkdir $(DEPDIR) && \ + case "$(top_builddir)" in \ + .) \ + ./config.status Makefile depfiles \ + ;; \ + *) \ + cd "$(top_builddir)" && \ + ./config.status $(subdir)/Makefile depfiles && \ + cd $(subdir) \ + ;; \ + esac && \ + echo -n "Cleaned $(subdir)/$(DEPDIR) version " && \ + cat $(top_srcdir)/deps-ver \ + ) + cp $(top_srcdir)/deps-ver $@ + +.deps-ver: $(top_srcdir)/deps-ver + @[ ! -d $(DEPDIR) ] || $(MAKE) $(AM_MAKEFLAGS) $(DEPDIR)/deps-ver + @touch $@ + +# +# depsver.mf included in Makefile.am for directories with .deps +# +# When building in the same directory with sources that change over +# time, such as when tracking using bk, the .deps files can become +# stale with respect to moved, deleted, or superceded headers. Most +# commonly, this would exhibit as make reporting a failure to make a +# header file which is no longer in the location given. To address +# this issue, we use a deps-ver file which is updated with each change +# that breaks old .deps files. A copy of deps-ver is made into +# $(DEPDIR) if not already present. If $(DEPDIR)/deps-ver is present +# with different contents than deps-ver, we make clean to ensure all +# .o files built before the incompatible change are rebuilt along with +# their updated .deps files, then remove $(DEPDIR) and recreate it as +# empty stubs. +# +# It is normal when configured with --disable-dependency-tracking for +# the DEPDIR to not have been created. For this reason, we use the +# intermediate target .deps-ver, which invokes make recursively if +# DEPDIR exists. +# +# If you modify depsver.mf, please make the changes to the master +# copy, the one in sntp is copied by the bootstrap script from it. +# +# This comment block follows rather than leads the related code so that +# it stays with it in the generated Makefile.in and Makefile. +# + +# 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/util/README b/util/README new file mode 100644 index 0000000..d67b4c1 --- /dev/null +++ b/util/README @@ -0,0 +1,44 @@ +README file for directory ./util of the NTP Version 4 distribution + +This directory contains the sources for the various utility programs. +See the README and RELNOTES files in the parent directory for directions +on how to make and install these programs. + +The ntptime.c program checks the kernel configuration for the NTP user +interface syscalls ntp_gettime() and ntp_adjtime(). If present, the +current timekeeping data are displayed. If not, a dissapointment is +displayed. See the kernel page file in the HTML documentation in +distribution for further details. ntptime will be built be if configure +believes your system can use it. + +The jitter.c program can be used to determine the timing jitter due to +the operating system in a gettimeofday() call. For most systems the +dominant contribution to the jitter budget is the period of the hardware +interrupt, usually in the range 10 us-1 ms. For those systems with +microsecond counters, such as recent Sun and certain HP and DEC systems, +the jitter is dominated only by the operating system. + +The timetrim.c program can be used with SGI machines to implement a +scheme to discipline the hardware clock frequency. See the source code +for further information. + +The byteorder.c and longsize.c programs are used during the configuration +process to determine the byte order (little or big endian) and longword +size (32 or 64 bits). See the configure scripts for further details. + +The testrs6000.c program is used for testing purposes with the IBM +RS/6000 AIX machines. Bill Jones <jones@chpc.utexas.edu> reports: +"I could not get a tickadj of less than 40 us to work on a RS6000. +If you set it less than 40 us do so at your own risk!" + +The tickadj.c program can be used to read and set various kernel +parameters affecting NTP operations. See the tickadj page in the HTML +documentation for further details. tickadj will be built if configure +believes your system can use it. + +tg.c and tg2.c are tone generators. They make audio signals +that emulate WWV or IRIG (-B and -E). tg runs on Solaris. +tg2 is a clone that runs on Linux, FreeBSD, and NetBSD. +Read the source for the fine print. tg2 has a help option +available via -h. + diff --git a/util/audio-pcm.c b/util/audio-pcm.c new file mode 100644 index 0000000..cbaf0f2 --- /dev/null +++ b/util/audio-pcm.c @@ -0,0 +1,154 @@ +/* + * audio-pcm.c - Scope out the PCM audio stuff + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined(HAVE_MACHINE_SOUNDCARD_H) || defined(HAVE_SYS_SOUNDCARD_H) + +#include "audio.h" +#include "ntp_stdlib.h" +#include "ntp_syslog.h" +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <stdio.h> +#include "ntp_string.h" + +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif /* HAVE_SYS_IOCTL_H */ + +#include <fcntl.h> + +#ifdef HAVE_MACHINE_SOUNDCARD_H +# include <machine/soundcard.h> +# define PCM_STYLE_SOUND +#else +# ifdef HAVE_SYS_SOUNDCARD_H +# include <sys/soundcard.h> +# define PCM_STYLE_SOUND +# endif +#endif + +/* + * Global variables + */ +static int ctl_fd; /* audio control file descriptor */ + +const char *m_names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES ; + +void +d_fmt( + unsigned int format + ) +{ + + if (format & AFMT_MU_LAW) printf("MU_LAW "); + if (format & AFMT_A_LAW) printf("A_LAW "); + if (format & AFMT_IMA_ADPCM) printf("IMA_ADPCM "); + if (format & AFMT_U8) printf("U8 "); + if (format & AFMT_S16_LE) printf("S16_LE "); + if (format & AFMT_S16_BE) printf("S16_BE "); + if (format & AFMT_S8) printf("S8 "); + if (format & AFMT_U16_LE) printf("U16_LE "); + if (format & AFMT_U16_BE) printf("U16_BE "); + if (format & AFMT_MPEG) printf("MPEG "); + if (format & AFMT_AC3) printf("AC3 "); + printf("\n"); +} + +void +d_mixer( + unsigned int mixer + ) +{ + int i; + int n = 0; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; ++i) + if ((1 << i) & mixer) { + if (n) + printf(", "); + printf("%s", m_names[i]); + n = 1; + } + printf("\n"); +} + +int +main( ) +{ + int unit = 0; /* device unit (0-3) */ +# define AI_DEV "/dev/audio%d" +# define AC_DEV "/dev/mixer%d" + char ai_dev[30]; + char ac_dev[30]; + struct snd_size s_size; + snd_chan_param s_c_p; + snd_capabilities s_c; + int fd; + int rval; + char *dname = ai_dev; /* device name */ + char *actl = ac_dev; + int devmask = 0, recmask = 0, recsrc = 0; + + snprintf(ai_dev, sizeof(ai_dev), AI_DEV, unit); + snprintf(ac_dev, sizeof(ac_dev), AC_DEV, unit); + + /* + * Open audio device. Do not complain if not there. + */ + fd = open(dname, O_RDWR | O_NONBLOCK, 0777); + if (fd < 0) + return (fd); + + /* + * Open audio control device. + */ + ctl_fd = open(actl, O_RDWR); + if (ctl_fd < 0) { + fprintf(stderr, "invalid control device <%s>\n", actl); + close(fd); + return(ctl_fd); + } + + printf("input: <%s> %d\n", dname, fd); + printf("control: <%s> %d\n", actl, ctl_fd); + + if (ioctl(ctl_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) + printf("SOUND_MIXER_READ_DEVMASK: %s\n", strerror(errno)); + if (ioctl(ctl_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1) + printf("SOUND_MIXER_READ_RECMASK: %s\n", strerror(errno)); + if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) + printf("SOUND_MIXER_READ_RECSRC: %s\n", strerror(errno)); + + printf("devmask: %#x recmask: %#x recsrc: %#x\n", + devmask, recmask, recsrc); + printf("Devmask: "); d_mixer(devmask); + printf("Recmask: "); d_mixer(recmask); + printf("RecSrc: "); d_mixer(recsrc); + + /* + * Set audio device parameters. + */ + rval = fd; + + if (ioctl(fd, AIOGSIZE, &s_size) == -1) + printf("AIOGSIZE: %s\n", strerror(errno)); + else + printf("play_size %d, rec_size %d\n", + s_size.play_size, s_size.rec_size); + + if (ioctl(fd, AIOGFMT, &s_c_p) == -1) + printf("AIOGFMT: %s\n", strerror(errno)); + else { + printf("play_rate %lu, rec_rate %lu, play_format %#lx, rec_format %#lx\n", + s_c_p.play_rate, s_c_p.rec_rate, s_c_p.play_format, s_c_p.rec_format); + printf("Play format: "); d_fmt(s_c_p.play_format); + printf("Rec format: "); d_fmt(s_c_p.rec_format); + } + +} +#endif /* HAVE_{MACHINE_SOUNDCARD,SYS_SOUNDCARD}_H */ diff --git a/util/byteorder.c b/util/byteorder.c new file mode 100644 index 0000000..188536f --- /dev/null +++ b/util/byteorder.c @@ -0,0 +1,56 @@ +/* + * This works on: + * Crays + * Conven + * sparc's + * Dec mip machines + * Dec alpha machines + * RS6000 + * SGI's + */ + +#include <stdio.h> + +int +main( + int argc, + char *argv[] + ) +{ + int i; + int big; + union { + unsigned long l; + char c[sizeof(long)]; + } u; + +#if defined(LONG8) + u.l = (((long)0x08070605) << 32) | (long)0x04030201; +#else + u.l = 0x04030201; +#endif + if (sizeof(long) > 4) { + if (u.c[0] == 0x08) big = 1; + else big = 0; + } else { + if (u.c[0] == 0x04) big = 1; + else big = 0; + } + for (i=0; i< sizeof(long); i++) { + if (big == 1 && (u.c[i] == (sizeof(long) - i))) { + continue; + } else if (big == 0 && (u.c[i] == (i+1))) { + continue; + } else { + big = -1; + break; + } + } + + if (big == 1) { + printf("XNTP_BIG_ENDIAN\n"); + } else if (big == 0) { + printf("XNTP_LITTLE_ENDIAN\n"); + } + exit(0); +} diff --git a/util/hist.c b/util/hist.c new file mode 100644 index 0000000..c8cbe49 --- /dev/null +++ b/util/hist.c @@ -0,0 +1,110 @@ +/* + * This program can be used to calibrate the clock reading jitter of a + * particular CPU and operating system. It first tickles every element + * of an array, in order to force pages into memory, then repeatedly calls + * gettimeofday() and, finally, writes out the time values for later + * analysis. From this you can determine the jitter and if the clock ever + * runs backwards. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ntp_types.h" + +#include <stdio.h> +#include <stdlib.h> + +#define NBUF 100001 /* size of basic histogram */ +#define NSRT 20000 /* size of overflow histogram */ +#define NCNT (600 * 1000000) /* sample interval (us) */ + +int col (const void *, const void *); + +int +main( + int argc, + char *argv[] + ) +{ + struct timeval ts, tr, tp; + struct timezone tzp; + int i, j, n; + long t, u, v, w, gtod[NBUF], ovfl[NSRT]; + + /* + * Force pages into memory + */ + for (i = 0; i < NBUF; i++) + gtod[i] = 0; + for (i = 0; i < NSRT; i++) + ovfl[i] = 0; + + /* + * Construct histogram + */ + n = 0; + gettimeofday(&ts, &tzp); + t = ts.tv_sec * 1000000 + ts.tv_usec; + v = t; + while (1) { + gettimeofday(&tr, &tzp); + u = tr.tv_sec * 1000000 + tr.tv_usec; + if (u - v > NCNT) + break; + w = u - t; + if (w <= 0) { +/* + printf("error <= 0 %ld %d %d, %d %d\n", w, ts.tv_sec, + ts.tv_usec, tr.tv_sec, tr.tv_usec); +*/ + } else if (w > NBUF - 1) { + ovfl[n] = w; + if (n < NSRT - 1) + n++; + } else { + gtod[w]++; + } + ts = tr; + t = u; + } + + /* + * Write out histogram + */ + for (i = 0; i < NBUF - 1; i++) { + if (gtod[i] > 0) + printf("%ld %ld\n", i, gtod[i]); + } + if (n == 0) + return; + qsort(&ovfl, (size_t)n, sizeof(ovfl[0]), col); + w = 0; + j = 0; + for (i = 0; i < n; i++) { + if (ovfl[i] != w) { + if (j > 0) + printf("%ld %ld\n", w, j); + w = ovfl[i]; + j = 1; + } else + j++; + } + if (j > 0) + printf("%ld %ld\n", w, j); + + exit(0); +} + +int +col( + const void *vx, + const void *vy + ) +{ + const long *x = vx; + const long *y = vy; + + return (*x - *y); +} diff --git a/util/invoke-ntp-keygen.menu b/util/invoke-ntp-keygen.menu new file mode 100644 index 0000000..bc5cfe9 --- /dev/null +++ b/util/invoke-ntp-keygen.menu @@ -0,0 +1 @@ +* ntp-keygen Invocation:: Invoking ntp-keygen diff --git a/util/invoke-ntp-keygen.texi b/util/invoke-ntp-keygen.texi new file mode 100644 index 0000000..99266fa --- /dev/null +++ b/util/invoke-ntp-keygen.texi @@ -0,0 +1,1354 @@ +@node ntp-keygen Invocation +@section Invoking ntp-keygen +@pindex ntp-keygen +@cindex Create a NTP host key +@ignore +# +# EDIT THIS FILE WITH CAUTION (invoke-ntp-keygen.texi) +# +# It has been AutoGen-ed December 2, 2014 at 08:58:48 AM by AutoGen 5.18.5pre4 +# From the definitions ntp-keygen-opts.def +# and the template file agtexi-cmd.tpl +@end ignore + + + +This program generates cryptographic data files used by the NTPv4 +authentication and identification schemes. +It generates MD5 key files used in symmetric key cryptography. +In addition, if the OpenSSL software library has been installed, +it generates keys, certificate and identity files used in public key +cryptography. +These files are used for cookie encryption, +digital signature and challenge/response identification algorithms +compatible with the Internet standard security infrastructure. + +All files are in PEM-encoded printable ASCII format, +so they can be embedded as MIME attachments in mail to other sites +and certificate authorities. +By default, files are not encrypted. + +When used to generate message digest keys, the program produces a file +containing ten pseudo-random printable ASCII strings suitable for the +MD5 message digest algorithm included in the distribution. +If the OpenSSL library is installed, it produces an additional ten +hex-encoded random bit strings suitable for the SHA1 and other message +digest algorithms. +The message digest keys file must be distributed and stored +using secure means beyond the scope of NTP itself. +Besides the keys used for ordinary NTP associations, additional keys +can be defined as passwords for the +@code{ntpq(1ntpqmdoc)} +and +@code{ntpdc(1ntpdcmdoc)} +utility programs. + +The remaining generated files are compatible with other OpenSSL +applications and other Public Key Infrastructure (PKI) resources. +Certificates generated by this program are compatible with extant +industry practice, although some users might find the interpretation of +X509v3 extension fields somewhat liberal. +However, the identity keys are probably not compatible with anything +other than Autokey. + +Some files used by this program are encrypted using a private password. +The +@code{-p} +option specifies the password for local encrypted files and the +@code{-q} +option the password for encrypted files sent to remote sites. +If no password is specified, the host name returned by the Unix +@code{gethostname()} +function, normally the DNS name of the host is used. + +The +@kbd{pw} +option of the +@kbd{crypto} +configuration command specifies the read +password for previously encrypted local files. +This must match the local password used by this program. +If not specified, the host name is used. +Thus, if files are generated by this program without password, +they can be read back by +@kbd{ntpd} +without password but only on the same host. + +Normally, encrypted files for each host are generated by that host and +used only by that host, although exceptions exist as noted later on +this page. +The symmetric keys file, normally called +@kbd{ntp.keys}, +is usually installed in +@file{/etc}. +Other files and links are usually installed in +@file{/usr/local/etc}, +which is normally in a shared filesystem in +NFS-mounted networks and cannot be changed by shared clients. +The location of the keys directory can be changed by the +@kbd{keysdir} +configuration command in such cases. +Normally, this is in +@file{/etc}. + +This program directs commentary and error messages to the standard +error stream +@kbd{stderr} +and remote files to the standard output stream +@kbd{stdout} +where they can be piped to other applications or redirected to files. +The names used for generated files and links all begin with the +string +@kbd{ntpkey} +and include the file type, generating host and filestamp, +as described in the +@quotedblleft{}Cryptographic Data Files@quotedblright{} +section below. +@subsubsection Running the Program +To test and gain experience with Autokey concepts, log in as root and +change to the keys directory, usually +@file{/usr/local/etc} +When run for the first time, or if all files with names beginning with +@kbd{ntpkey} +have been removed, use the +@code{ntp-keygen} +command without arguments to generate a +default RSA host key and matching RSA-MD5 certificate with expiration +date one year hence. +If run again without options, the program uses the +existing keys and parameters and generates only a new certificate with +new expiration date one year hence. + +Run the command on as many hosts as necessary. +Designate one of them as the trusted host (TH) using +@code{ntp-keygen} +with the +@code{-T} +option and configure it to synchronize from reliable Internet servers. +Then configure the other hosts to synchronize to the TH directly or +indirectly. +A certificate trail is created when Autokey asks the immediately +ascendant host towards the TH to sign its certificate, which is then +provided to the immediately descendant host on request. +All group hosts should have acyclic certificate trails ending on the TH. + +The host key is used to encrypt the cookie when required and so must be +RSA type. +By default, the host key is also the sign key used to encrypt +signatures. +A different sign key can be assigned using the +@code{-S} +option and this can be either RSA or DSA type. +By default, the signature +message digest type is MD5, but any combination of sign key type and +message digest type supported by the OpenSSL library can be specified +using the +@code{-c} +option. +The rules say cryptographic media should be generated with proventic +filestamps, which means the host should already be synchronized before +this program is run. +This of course creates a chicken-and-egg problem +when the host is started for the first time. +Accordingly, the host time +should be set by some other means, such as eyeball-and-wristwatch, at +least so that the certificate lifetime is within the current year. +After that and when the host is synchronized to a proventic source, the +certificate should be re-generated. + +Additional information on trusted groups and identity schemes is on the +@quotedblleft{}Autokey Public-Key Authentication@quotedblright{} +page. + + + +The +@code{ntpd(1ntpdmdoc)} +configuration command +@code{crypto} @code{pw} @kbd{password} +specifies the read password for previously encrypted files. +The daemon expires on the spot if the password is missing +or incorrect. +For convenience, if a file has been previously encrypted, +the default read password is the name of the host running +the program. +If the previous write password is specified as the host name, +these files can be read by that host with no explicit password. + + +File names begin with the prefix +@code{ntpkey_} +and end with the postfix +@kbd{_hostname.filestamp}, +where +@kbd{hostname} +is the owner name, usually the string returned +by the Unix gethostname() routine, and +@kbd{filestamp} +is the NTP seconds when the file was generated, in decimal digits. +This both guarantees uniqueness and simplifies maintenance +procedures, since all files can be quickly removed +by a +@code{rm} @code{ntpkey*} +command or all files generated +at a specific time can be removed by a +@code{rm} +@kbd{*filestamp} +command. +To further reduce the risk of misconfiguration, +the first two lines of a file contain the file name +and generation date and time as comments. + +All files are installed by default in the keys directory +@file{/usr/local/etc}, +which is normally in a shared filesystem +in NFS-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. + +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. + +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +@code{ntpd(1ntpdmdoc)} +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +@code{ntp-keygen} +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +@subsubsection Running the program +The safest way to run the +@code{ntp-keygen} +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +@file{/usr/local/etc}, +then run the program. +When run for the first time, +or if all +@code{ntpkey} +files have been removed, +the program generates a RSA host key file and matching RSA-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. + +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. + +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. + +Running the program as other than root and using the Unix +@code{su} +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +@code{.rnd} +in the user home directory. +However, there should be only one +@code{.rnd}, +most conveniently +in the root directory, so it is convenient to define the +@code{$RANDFILE} +environment variable used by the OpenSSL library as the path to +@code{/.rnd}. + +Installing the keys as root might not work in NFS-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +@file{/etc} +using the +@code{keysdir} +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. + +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. + + +All files are installed by default in the keys directory +@file{/usr/local/etc}, +which is normally in a shared filesystem +in NFS-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. + +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. + +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +@code{ntpd(1ntpdmdoc)} +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +@code{ntp-keygen} +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +@subsubsection Running the program +The safest way to run the +@code{ntp-keygen} +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +@file{/usr/local/etc}, +then run the program. +When run for the first time, +or if all +@code{ntpkey} +files have been removed, +the program generates a RSA host key file and matching RSA-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. + +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. + +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. + +Running the program as other than root and using the Unix +@code{su} +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +@code{.rnd} +in the user home directory. +However, there should be only one +@code{.rnd}, +most conveniently +in the root directory, so it is convenient to define the +@code{$RANDFILE} +environment variable used by the OpenSSL library as the path to +@code{/.rnd}. + +Installing the keys as root might not work in NFS-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +@file{/etc} +using the +@code{keysdir} +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. + +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +seconds. +seconds. + +s Trusted Hosts and Groups +Each cryptographic configuration involves selection of a signature scheme +and identification scheme, called a cryptotype, +as explained in the +@ref{Authentication Options} +section of +@code{ntp.conf(5)}. +The default cryptotype uses RSA encryption, MD5 message digest +and TC identification. +First, configure a NTP subnet including one or more low-stratum +trusted hosts from which all other hosts derive synchronization +directly or indirectly. +Trusted hosts have trusted certificates; +all other hosts have nontrusted certificates. +These hosts will automatically and dynamically build authoritative +certificate trails to one or more trusted hosts. +A trusted group is the set of all hosts that have, directly or indirectly, +a certificate trail ending at a trusted host. +The trail is defined by static configuration file entries +or dynamic means described on the +@ref{Automatic NTP Configuration Options} +section of +@code{ntp.conf(5)}. + +On each trusted host as root, change to the keys directory. +To insure a fresh fileset, remove all +@code{ntpkey} +files. +Then run +@code{ntp-keygen} +@code{-T} +to generate keys and a trusted certificate. +On all other hosts do the same, but leave off the +@code{-T} +flag to generate keys and nontrusted certificates. +When complete, start the NTP daemons beginning at the lowest stratum +and working up the tree. +It may take some time for Autokey to instantiate the certificate trails +throughout the subnet, but setting up the environment is completely automatic. + +If it is necessary to use a different sign key or different digest/signature +scheme than the default, run +@code{ntp-keygen} +with the +@code{-S} @kbd{type} +option, where +@kbd{type} +is either +@code{RSA} +or +@code{DSA}. +The most often need to do this is when a DSA-signed certificate is used. +If it is necessary to use a different certificate scheme than the default, +run +@code{ntp-keygen} +with the +@code{-c} @kbd{scheme} +option and selected +@kbd{scheme} +as needed. +f +@code{ntp-keygen} +is run again without these options, it generates a new certificate +using the same scheme and sign key. + +After setting up the environment it is advisable to update certificates +from time to time, if only to extend the validity interval. +Simply run +@code{ntp-keygen} +with the same flags as before to generate new certificates +using existing keys. +However, if the host or sign key is changed, +@code{ntpd(1ntpdmdoc)} +should be restarted. +When +@code{ntpd(1ntpdmdoc)} +is restarted, it loads any new files and restarts the protocol. +Other dependent hosts will continue as usual until signatures are refreshed, +at which time the protocol is restarted. +@subsubsection Identity Schemes +As mentioned on the Autonomous Authentication page, +the default TC identity scheme is vulnerable to a middleman attack. +However, there are more secure identity schemes available, +including PC, IFF, GQ and MV described on the +"Identification Schemes" +page +(maybe available at +@code{http://www.eecis.udel.edu/%7emills/keygen.html}). +These schemes are based on a TA, one or more trusted hosts +and some number of nontrusted hosts. +Trusted hosts prove identity using values provided by the TA, +while the remaining hosts prove identity using values provided +by a trusted host and certificate trails that end on that host. +The name of a trusted host is also the name of its sugroup +and also the subject and issuer name on its trusted certificate. +The TA is not necessarily a trusted host in this sense, but often is. + +In some schemes there are separate keys for servers and clients. +A server can also be a client of another server, +but a client can never be a server for another client. +In general, trusted hosts and nontrusted hosts that operate +as both server and client have parameter files that contain +both server and client keys. +Hosts that operate +only as clients have key files that contain only client keys. + +The PC scheme supports only one trusted host in the group. +On trusted host alice run +@code{ntp-keygen} +@code{-P} +@code{-p} @kbd{password} +to generate the host key file +@file{ntpkey_RSAkey_}@kbd{alice.filestamp} +and trusted private certificate file +@file{ntpkey_RSA-MD5_cert_}@kbd{alice.filestamp}. +Copy both files to all group hosts; +they replace the files which would be generated in other schemes. +On each host bob install a soft link from the generic name +@file{ntpkey_host_}@kbd{bob} +to the host key file and soft link +@file{ntpkey_cert_}@kbd{bob} +to the private certificate file. +Note the generic links are on bob, but point to files generated +by trusted host alice. +In this scheme it is not possible to refresh +either the keys or certificates without copying them +to all other hosts in the group. + +For the IFF scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host in the group, +generate the IFF parameter file. +On trusted host alice run +@code{ntp-keygen} +@code{-T} +@code{-I} +@code{-p} @kbd{password} +to produce her parameter file +@file{ntpkey_IFFpar_}@kbd{alice.filestamp}, +which includes both server and client keys. +Copy this file to all group hosts that operate as both servers +and clients and install a soft link from the generic +@file{ntpkey_iff_}@kbd{alice} +to this file. +If there are no hosts restricted to operate only as clients, +there is nothing further to do. +As the IFF scheme is independent +of keys and certificates, these files can be refreshed as needed. + +If a rogue client has the parameter file, it could masquerade +as a legitimate server and present a middleman threat. +To eliminate this threat, the client keys can be extracted +from the parameter file and distributed to all restricted clients. +After generating the parameter file, on alice run +@code{ntp-keygen} +@code{-e} +and pipe the output to a file or mail program. +Copy or mail this file to all restricted clients. +On these clients install a soft link from the generic +@file{ntpkey_iff_}@kbd{alice} +to this file. +To further protect the integrity of the keys, +each file can be encrypted with a secret password. + +For the GQ scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host +in the group, generate the IFF parameter file. +On trusted host alice run +@code{ntp-keygen} +@code{-T} +@code{-G} +@code{-p} @kbd{password} +to produce her parameter file +@file{ntpkey_GQpar_}@kbd{alice.filestamp}, +which includes both server and client keys. +Copy this file to all group hosts and install a soft link +from the generic +@file{ntpkey_gq_}@kbd{alice} +to this file. +In addition, on each host bob install a soft link +from generic +@file{ntpkey_gq_}@kbd{bob} +to this file. +As the GQ scheme updates the GQ parameters file and certificate +at the same time, keys and certificates can be regenerated as needed. + +For the MV scheme, proceed as in the TC scheme to generate keys +and certificates for all group hosts. +For illustration assume trish is the TA, alice one of several trusted hosts +and bob one of her clients. +On TA trish run +@code{ntp-keygen} +@code{-V} @kbd{n} +@code{-p} @kbd{password}, +where +@kbd{n} +is the number of revokable keys (typically 5) to produce +the parameter file +@file{ntpkeys_MVpar_}@kbd{trish.filestamp} +and client key files +@file{ntpkeys_MVkeyd_}@kbd{trish.filestamp} +where +@kbd{d} +is the key number (0 < +@kbd{d} +< +@kbd{n}). +Copy the parameter file to alice and install a soft link +from the generic +@file{ntpkey_mv_}@kbd{alice} +to this file. +Copy one of the client key files to alice for later distribution +to her clients. +It doesn't matter which client key file goes to alice, +since they all work the same way. +Alice copies the client key file to all of her cliens. +On client bob install a soft link from generic +@file{ntpkey_mvkey_}@kbd{bob} +to the client key file. +As the MV scheme is independent of keys and certificates, +these files can be refreshed as needed. +@subsubsection Command Line Options +@table @asis +@item @code{-c} @kbd{scheme} +Select certificate message digest/signature encryption scheme. +The +@kbd{scheme} +can be one of the following: +. Cm RSA-MD2 , RSA-MD5 , RSA-SHA , RSA-SHA1 , RSA-MDC2 , RSA-RIPEMD160 , DSA-SHA , +or +@code{DSA-SHA1}. +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. +The default without this option is +@code{RSA-MD5}. +@item @code{-d} +Enable debugging. +This option displays the cryptographic data produced in eye-friendly billboards. +@item @code{-e} +Write the IFF client keys to the standard output. +This is intended for automatic key distribution by mail. +@item @code{-G} +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +@item @code{-g} +Generate keys for the GQ identification scheme +using the existing GQ parameters. +If the GQ parameters do not yet exist, create them first. +@item @code{-H} +Generate new host keys, obsoleting any that may exist. +@item @code{-I} +Generate parameters for the IFF identification scheme, +obsoleting any that may exist. +@item @code{-i} @kbd{name} +Set the suject name to +@kbd{name}. +This is used as the subject field in certificates +and in the file name for host and sign keys. +@item @code{-M} +Generate MD5 keys, obsoleting any that may exist. +@item @code{-P} +Generate a private certificate. +By default, the program generates public certificates. +@item @code{-p} @kbd{password} +Encrypt generated files containing private data with +@kbd{password} +and the DES-CBC algorithm. +@item @code{-q} +Set the password for reading files to password. +@item @code{-S} @code{[@code{RSA} | @code{DSA}]} +Generate a new sign key of the designated type, +obsoleting any that may exist. +By default, the program uses the host key as the sign key. +@item @code{-s} @kbd{name} +Set the issuer name to +@kbd{name}. +This is used for the issuer field in certificates +and in the file name for identity files. +@item @code{-T} +Generate a trusted certificate. +By default, the program generates a non-trusted certificate. +@item @code{-V} @kbd{nkeys} +Generate parameters and keys for the Mu-Varadharajan (MV) identification scheme. +@end table +@subsubsection Random Seed File +All cryptographically sound key generation schemes must have means +to randomize the entropy seed used to initialize +the internal pseudo-random number generator used +by the library routines. +The OpenSSL library uses a designated random seed file for this purpose. +The file must be available when starting the NTP daemon and +@code{ntp-keygen} +program. +If a site supports OpenSSL or its companion OpenSSH, +it is very likely that means to do this are already available. + +It is important to understand that entropy must be evolved +for each generation, for otherwise the random number sequence +would be predictable. +Various means dependent on external events, such as keystroke intervals, +can be used to do this and some systems have built-in entropy sources. +Suitable means are described in the OpenSSL software documentation, +but are outside the scope of this page. + +The entropy seed used by the OpenSSL library is contained in a file, +usually called +@code{.rnd}, +which must be available when starting the NTP daemon +or the +@code{ntp-keygen} +program. +The NTP daemon will first look for the file +using the path specified by the +@code{randfile} +subcommand of the +@code{crypto} +configuration command. +If not specified in this way, or when starting the +@code{ntp-keygen} +program, +the OpenSSL library will look for the file using the path specified +by the +.Ev RANDFILE +environment variable in the user home directory, +whether root or some other user. +If the +.Ev RANDFILE +environment variable is not present, +the library will look for the +@code{.rnd} +file in the user home directory. +If the file is not available or cannot be written, +the daemon exits with a message to the system log and the program +exits with a suitable error message. +@subsubsection Cryptographic Data Files +All other file formats begin with two lines. +The first contains the file name, including the generated host name +and filestamp. +The second contains the datestamp in conventional Unix date format. +Lines beginning with # are considered comments and ignored by the +@code{ntp-keygen} +program and +@code{ntpd(1ntpdmdoc)} +daemon. +Cryptographic values are encoded first using ASN.1 rules, +then encrypted if necessary, and finally written PEM-encoded +printable ASCII format preceded and followed by MIME content identifier lines. + +The format of the symmetric keys file is somewhat different +than the other files in the interest of backward compatibility. +Since DES-CBC is deprecated in NTPv4, the only key format of interest +is MD5 alphanumeric strings. +Following hte heard the keys are +entered one per line in the format +@example +@kbd{keyno} @kbd{type} @kbd{key} +@end example +where +@kbd{keyno} +is a positive integer in the range 1-65,535, +@kbd{type} +is the string MD5 defining the key format and +@kbd{key} +is the key itself, +which is a printable ASCII string 16 characters or less in length. +Each character is chosen from the 93 printable characters +in the range 0x21 through 0x7f excluding space and the +@quoteleft{}#@quoteright{} +character. + +Note that the keys used by the +@code{ntpq(1ntpqmdoc)} +and +@code{ntpdc(1ntpdcmdoc)} +programs +are checked against passwords requested by the programs +and entered by hand, so it is generally appropriate to specify these keys +in human readable ASCII format. + +The +@code{ntp-keygen} +program generates a MD5 symmetric keys file +@file{ntpkey_MD5key_}@kbd{hostname.filestamp}. +Since the file contains private shared keys, +it should be visible only to root and distributed by secure means +to other subnet hosts. +The NTP daemon loads the file +@file{ntp.keys}, +so +@code{ntp-keygen} +installs a soft link from this name to the generated file. +Subsequently, similar soft links must be installed by manual +or automated means on the other subnet hosts. +While this file is not used with the Autokey Version 2 protocol, +it is needed to authenticate some remote configuration commands +used by the +@code{ntpq(1ntpqmdoc)} +and +@code{ntpdc(1ntpdcmdoc)} +utilities. + +This section was generated by @strong{AutoGen}, +using the @code{agtexi-cmd} template and the option descriptions for the @code{ntp-keygen} program. +This software is released under the NTP license, <http://ntp.org/license>. + +@menu +* ntp-keygen usage:: ntp-keygen help/usage (@option{--help}) +* ntp-keygen imbits:: imbits option (-b) +* ntp-keygen certificate:: certificate option (-c) +* ntp-keygen cipher:: cipher option (-C) +* ntp-keygen id-key:: id-key option (-e) +* ntp-keygen gq-params:: gq-params option (-G) +* ntp-keygen host-key:: host-key option (-H) +* ntp-keygen iffkey:: iffkey option (-I) +* ntp-keygen ident:: ident option (-i) +* ntp-keygen lifetime:: lifetime option (-l) +* ntp-keygen md5key:: md5key option (-M) +* ntp-keygen modulus:: modulus option (-m) +* ntp-keygen pvt-cert:: pvt-cert option (-P) +* ntp-keygen password:: password option (-p) +* ntp-keygen export-passwd:: export-passwd option (-q) +* ntp-keygen sign-key:: sign-key option (-S) +* ntp-keygen subject-name:: subject-name option (-s) +* ntp-keygen trusted-cert:: trusted-cert option (-T) +* ntp-keygen mv-params:: mv-params option (-V) +* ntp-keygen mv-keys:: mv-keys option (-v) +* ntp-keygen config:: presetting/configuring ntp-keygen +* ntp-keygen exit status:: exit status +* ntp-keygen Usage:: Usage +* ntp-keygen Notes:: Notes +* ntp-keygen Bugs:: Bugs +@end menu + +@node ntp-keygen usage +@subsection ntp-keygen help/usage (@option{--help}) +@cindex ntp-keygen help + +This is the automatically generated usage text for ntp-keygen. + +The text printed is the same whether selected with the @code{help} option +(@option{--help}) or the @code{more-help} option (@option{--more-help}). @code{more-help} will print +the usage text by passing it through a pager program. +@code{more-help} is disabled on platforms without a working +@code{fork(2)} function. The @code{PAGER} environment variable is +used to select the program, defaulting to @file{more}. Both will exit +with a status code of 0. + +@exampleindent 0 +@example +ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.7p482 +Usage: ntp-keygen [ -<flag> [<val>] | --<name>[@{=| @}<val>] ]... + Flg Arg Option-Name Description + -b Num imbits identity modulus bits + - it must be in the range: + 256 to 2048 + -c Str certificate certificate scheme + -C Str cipher privatekey cipher + -d no debug-level Increase debug verbosity level + - may appear multiple times + -D Num set-debug-level Set the debug verbosity level + - may appear multiple times + -e no id-key Write IFF or GQ identity keys + -G no gq-params Generate GQ parameters and keys + -H no host-key generate RSA host key + -I no iffkey generate IFF parameters + -i Str ident set Autokey group name + -l Num lifetime set certificate lifetime + -M no md5key generate MD5 keys + -m Num modulus modulus + - it must be in the range: + 256 to 2048 + -P no pvt-cert generate PC private certificate + -p Str password local private password + -q Str export-passwd export IFF or GQ group keys with password + -S Str sign-key generate sign key (RSA or DSA) + -s Str subject-name set host and optionally group name + -T no trusted-cert trusted certificate (TC scheme) + -V Num mv-params generate <num> MV parameters + -v Num mv-keys update <num> MV keys + opt version output version information and exit + -? no help display extended usage information and exit + -! no more-help extended usage information passed thru pager + -> opt save-opts save the option state to a config file + -< Str load-opts load options from a config file + - disabled as '--no-load-opts' + - may appear multiple times + +Options are specified by doubled hyphens and their name or by a single +hyphen and the flag character. + + +The following option preset mechanisms are supported: + - reading file $HOME/.ntprc + - reading file ./.ntprc + - examining environment variables named NTP_KEYGEN_* + +Please send bug reports to: <http://bugs.ntp.org, bugs@@ntp.org> +@end example +@exampleindent 4 + +@node ntp-keygen imbits +@subsection imbits option (-b) +@cindex ntp-keygen-imbits + +This is the ``identity modulus bits'' option. +This option takes a number argument @file{imbits}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +The number of bits in the identity modulus. The default is 256. +@node ntp-keygen certificate +@subsection certificate option (-c) +@cindex ntp-keygen-certificate + +This is the ``certificate scheme'' option. +This option takes a string argument @file{scheme}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +scheme is one of +RSA-MD2, RSA-MD5, RSA-SHA, RSA-SHA1, RSA-MDC2, RSA-RIPEMD160, +DSA-SHA, or DSA-SHA1. + +Select the certificate message digest/signature encryption scheme. +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. The default without +this option is RSA-MD5. +@node ntp-keygen cipher +@subsection cipher option (-C) +@cindex ntp-keygen-cipher + +This is the ``privatekey cipher'' option. +This option takes a string argument @file{cipher}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Select the cipher which is used to encrypt the files containing +private keys. The default is three-key triple DES in CBC mode, +equivalent to "@code{-C des-ede3-cbc". The openssl tool lists ciphers +available in "@code{openssl -h}" output. +@node ntp-keygen id-key +@subsection id-key option (-e) +@cindex ntp-keygen-id-key + +This is the ``write iff or gq identity keys'' option. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Write the IFF or GQ client keys to the standard output. This is +intended for automatic key distribution by mail. +@node ntp-keygen gq-params +@subsection gq-params option (-G) +@cindex ntp-keygen-gq-params + +This is the ``generate gq parameters and keys'' option. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +@node ntp-keygen host-key +@subsection host-key option (-H) +@cindex ntp-keygen-host-key + +This is the ``generate rsa host key'' option. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Generate new host keys, obsoleting any that may exist. +@node ntp-keygen iffkey +@subsection iffkey option (-I) +@cindex ntp-keygen-iffkey + +This is the ``generate iff parameters'' option. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Generate parameters for the IFF identification scheme, obsoleting +any that may exist. +@node ntp-keygen ident +@subsection ident option (-i) +@cindex ntp-keygen-ident + +This is the ``set autokey group name'' option. +This option takes a string argument @file{group}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Set the optional Autokey group name to name. This is used in +the file name of IFF, GQ, and MV client parameters files. In +that role, the default is the host name if this option is not +provided. The group name, if specified using @code{-i/--ident} or +using @code{-s/--subject-name} following an '@code{@}' character, +is also a part of the self-signed host certificate's subject and +issuer names in the form @code{host@group} and should match the +'@code{crypto ident}' or '@code{server ident}' configuration in +@code{ntpd}'s configuration file. +@node ntp-keygen lifetime +@subsection lifetime option (-l) +@cindex ntp-keygen-lifetime + +This is the ``set certificate lifetime'' option. +This option takes a number argument @file{lifetime}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Set the certificate expiration to lifetime days from now. +@node ntp-keygen md5key +@subsection md5key option (-M) +@cindex ntp-keygen-md5key + +This is the ``generate md5 keys'' option. +Generate MD5 keys, obsoleting any that may exist. +@node ntp-keygen modulus +@subsection modulus option (-m) +@cindex ntp-keygen-modulus + +This is the ``modulus'' option. +This option takes a number argument @file{modulus}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +The number of bits in the prime modulus. The default is 512. +@node ntp-keygen pvt-cert +@subsection pvt-cert option (-P) +@cindex ntp-keygen-pvt-cert + +This is the ``generate pc private certificate'' option. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Generate a private certificate. By default, the program generates +public certificates. +@node ntp-keygen password +@subsection password option (-p) +@cindex ntp-keygen-password + +This is the ``local private password'' option. +This option takes a string argument @file{passwd}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Local files containing private data are encrypted with the +DES-CBC algorithm and the specified password. The same password +must be specified to the local ntpd via the "crypto pw password" +configuration command. The default password is the local +hostname. +@node ntp-keygen export-passwd +@subsection export-passwd option (-q) +@cindex ntp-keygen-export-passwd + +This is the ``export iff or gq group keys with password'' option. +This option takes a string argument @file{passwd}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Export IFF or GQ identity group keys to the standard output, +encrypted with the DES-CBC algorithm and the specified password. +The same password must be specified to the remote ntpd via the +"crypto pw password" configuration command. See also the option +--id-key (-e) for unencrypted exports. +@node ntp-keygen sign-key +@subsection sign-key option (-S) +@cindex ntp-keygen-sign-key + +This is the ``generate sign key (rsa or dsa)'' option. +This option takes a string argument @file{sign}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Generate a new sign key of the designated type, obsoleting any +that may exist. By default, the program uses the host key as the +sign key. +@node ntp-keygen subject-name +@subsection subject-name option (-s) +@cindex ntp-keygen-subject-name + +This is the ``set host and optionally group name'' option. +This option takes a string argument @file{host@@group}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Set the Autokey host name, and optionally, group name specified +following an '@code{@}' character. The host name is used in the file +name of generated host and signing certificates, without the +group name. The host name, and if provided, group name are used +in @code{host@group} form for the host certificate's subject and issuer +fields. Specifying '@code{-s @group}' is allowed, and results in +leaving the host name unchanged while appending @code{@group} to the +subject and issuer fields, as with @code{-i group}. The group name, or +if not provided, the host name are also used in the file names +of IFF, GQ, and MV client parameter files. +@node ntp-keygen trusted-cert +@subsection trusted-cert option (-T) +@cindex ntp-keygen-trusted-cert + +This is the ``trusted certificate (tc scheme)'' option. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Generate a trusted certificate. By default, the program generates +a non-trusted certificate. +@node ntp-keygen mv-params +@subsection mv-params option (-V) +@cindex ntp-keygen-mv-params + +This is the ``generate <num> mv parameters'' option. +This option takes a number argument @file{num}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +Generate parameters and keys for the Mu-Varadharajan (MV) +identification scheme. +@node ntp-keygen mv-keys +@subsection mv-keys option (-v) +@cindex ntp-keygen-mv-keys + +This is the ``update <num> mv keys'' option. +This option takes a number argument @file{num}. + +@noindent +This option has some usage constraints. It: +@itemize @bullet +@item +must be compiled in by defining @code{AUTOKEY} during the compilation. +@end itemize + +This option has no @samp{doc} documentation. + + +@node ntp-keygen config +@subsection presetting/configuring ntp-keygen + +Any option that is not marked as @i{not presettable} may be preset by +loading values from configuration ("rc" or "ini") files, and values from environment variables named @code{NTP-KEYGEN} and @code{NTP-KEYGEN_<OPTION_NAME>}. @code{<OPTION_NAME>} must be one of +the options listed above in upper case and segmented with underscores. +The @code{NTP-KEYGEN} variable will be tokenized and parsed like +the command line. The remaining variables are tested for existence and their +values are treated like option arguments. + + +@noindent +@code{libopts} will search in 2 places for configuration files: +@itemize @bullet +@item +$HOME +@item +$PWD +@end itemize +The environment variables @code{HOME}, and @code{PWD} +are expanded and replaced when @file{ntp-keygen} runs. +For any of these that are plain files, they are simply processed. +For any that are directories, then a file named @file{.ntprc} is searched for +within that directory and processed. + +Configuration files may be in a wide variety of formats. +The basic format is an option name followed by a value (argument) on the +same line. Values may be separated from the option name with a colon, +equal sign or simply white space. Values may be continued across multiple +lines by escaping the newline with a backslash. + +Multiple programs may also share the same initialization file. +Common options are collected at the top, followed by program specific +segments. The segments are separated by lines like: +@example +[NTP-KEYGEN] +@end example +@noindent +or by +@example +<?program ntp-keygen> +@end example +@noindent +Do not mix these styles within one configuration file. + +Compound values and carefully constructed string values may also be +specified using XML syntax: +@example +<option-name> + <sub-opt>...<...>...</sub-opt> +</option-name> +@end example +@noindent +yielding an @code{option-name.sub-opt} string value of +@example +"...<...>..." +@end example +@code{AutoOpts} does not track suboptions. You simply note that it is a +hierarchicly valued option. @code{AutoOpts} does provide a means for searching +the associated name/value pair list (see: optionFindValue). + +The command line options relating to configuration and/or usage help are: + +@subsubheading version (-) + +Print the program version to standard out, optionally with licensing +information, then exit 0. The optional argument specifies how much licensing +detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument. +Only the first letter of the argument is examined: + +@table @samp +@item version +Only print the version. This is the default. +@item copyright +Name the copyright usage licensing terms. +@item verbose +Print the full copyright usage licensing terms. +@end table + +@node ntp-keygen exit status +@subsection ntp-keygen exit status + +One of the following exit values will be returned: +@table @samp +@item 0 (EXIT_SUCCESS) +Successful program execution. +@item 1 (EXIT_FAILURE) +The operation failed or the command syntax was not valid. +@item 66 (EX_NOINPUT) +A specified configuration file could not be loaded. +@item 70 (EX_SOFTWARE) +libopts had an internal operational error. Please report +it to autogen-users@@lists.sourceforge.net. Thank you. +@end table +@node ntp-keygen Usage +@subsection ntp-keygen Usage +@node ntp-keygen Notes +@subsection ntp-keygen Notes +@node ntp-keygen Bugs +@subsection ntp-keygen Bugs diff --git a/util/jitter.c b/util/jitter.c new file mode 100644 index 0000000..62a84ad --- /dev/null +++ b/util/jitter.c @@ -0,0 +1,136 @@ +/* + * This program can be used to calibrate the clock reading jitter of a + * particular CPU and operating system. It first tickles every element + * of an array, in order to force pages into memory, then repeatedly + * reads the system clock and, finally, writes out the time values for + * later analysis. From this you can determine the jitter and if the + * clock ever runs backwards. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <sys/time.h> +#include <stdlib.h> +#include "jitter.h" + +#define NBUF 800002 +#define FRAC 4294967296. /* a bbbbillion */ +#define JAN_1970 2208988800UL /* Unix base epoch */ +#define CLOCK_GETTIME /* Solaris hires clock */ + +char progname[10]; +double sys_residual; +double average; +void sys_gettime(l_fp *); + +int +main( + int argc, + char *argv[] + ) +{ + l_fp tr; + int i, j; + double dtemp, gtod[NBUF]; + + /* + * Force pages into memory + */ + for (i = 0; i < NBUF; i ++) + gtod[i] = 0; + + /* + * Construct gtod array + */ + for (i = 0; i < NBUF; i ++) { + get_systime(&tr); + LFPTOD(&tr, gtod[i]); + } + + /* + * Write out gtod array for later processing with Matlab + */ + average = 0; + for (i = 0; i < NBUF - 2; i++) { + gtod[i] = gtod[i + 1] - gtod[i]; + printf("%13.9f\n", gtod[i]); + average += gtod[i]; + } + + /* + * Sort the gtod array and display deciles + */ + for (i = 0; i < NBUF - 2; i++) { + for (j = 0; j <= i; j++) { + if (gtod[j] > gtod[i]) { + dtemp = gtod[j]; + gtod[j] = gtod[i]; + gtod[i] = dtemp; + } + } + } + average = average / (NBUF - 2); + fprintf(stderr, "Average %13.9f\n", average); + fprintf(stderr, "First rank\n"); + for (i = 0; i < 10; i++) + fprintf(stderr, "%2d %13.9f\n", i, gtod[i]); + fprintf(stderr, "Last rank\n"); + for (i = NBUF - 12; i < NBUF - 2; i++) + fprintf(stderr, "%2d %13.9f\n", i, gtod[i]); + exit(0); +} + + +/* + * get_systime - return system time in NTP timestamp format. + */ +void +get_systime( + l_fp *now /* system time */ + ) +{ + double dtemp; + +#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) + struct timespec ts; /* seconds and nanoseconds */ + + /* + * Convert Unix clock from seconds and nanoseconds to seconds. + */ +# ifdef HAVE_CLOCK_GETTIME + clock_gettime(CLOCK_REALTIME, &ts); +# else + getclock(TIMEOFDAY, &ts); +# endif + now->l_i = ts.tv_sec + JAN_1970; + dtemp = ts.tv_nsec / 1e9; + +#else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ + struct timeval tv; /* seconds and microseconds */ + + /* + * Convert Unix clock from seconds and microseconds to seconds. + */ + gettimeofday(&tv, NULL); + now->l_i = tv.tv_sec + JAN_1970; + dtemp = tv.tv_usec / 1e6; + +#endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */ + + /* + * Renormalize to seconds past 1900 and fraction. + */ + dtemp += sys_residual; + if (dtemp >= 1) { + dtemp -= 1; + now->l_i++; + } else if (dtemp < -1) { + dtemp += 1; + now->l_i--; + } + dtemp *= FRAC; + now->l_uf = (u_int32)dtemp; +} diff --git a/util/jitter.h b/util/jitter.h new file mode 100644 index 0000000..8c774b0 --- /dev/null +++ b/util/jitter.h @@ -0,0 +1,401 @@ +/* + * ntp_types.h - defines how int32 and u_int32 are treated. + * For 64 bit systems like the DEC Alpha, they have to be defined + * as int and u_int. + * For 32 bit systems, define them as long and u_long + */ +#define SIZEOF_INT 4 + +/* + * VMS DECC (v4.1), {u_char,u_short,u_long} are only in SOCKET.H, + * and u_int isn't defined anywhere + */ +#if defined(VMS) +#include <socket.h> +typedef unsigned int u_int; +/* + * Note: VMS DECC has long == int (even on __alpha), + * so the distinction below doesn't matter + */ +#endif /* VMS */ + +#if (SIZEOF_INT == 4) +# ifndef int32 +# define int32 int +# endif +# ifndef u_int32 +# define u_int32 unsigned int +# endif +#else /* not sizeof(int) == 4 */ +# if (SIZEOF_LONG == 4) +# else /* not sizeof(long) == 4 */ +# ifndef int32 +# define int32 long +# endif +# ifndef u_int32 +# define u_int32 unsigned long +# endif +# endif /* not sizeof(long) == 4 */ +# include "Bletch: what's 32 bits on this machine?" +#endif /* not sizeof(int) == 4 */ + +typedef unsigned short associd_t; /* association ID */ +typedef u_int32 keyid_t; /* cryptographic key ID */ +typedef u_int32 tstamp_t; /* NTP seconds timestamp */ + +/* + * NTP uses two fixed point formats. The first (l_fp) is the "long" + * format and is 64 bits long with the decimal between bits 31 and 32. + * This is used for time stamps in the NTP packet header (in network + * byte order) and for internal computations of offsets (in local host + * byte order). We use the same structure for both signed and unsigned + * values, which is a big hack but saves rewriting all the operators + * twice. Just to confuse this, we also sometimes just carry the + * fractional part in calculations, in both signed and unsigned forms. + * Anyway, an l_fp looks like: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Integral Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Fractional Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +typedef struct { + union { + u_int32 Xl_ui; + int32 Xl_i; + } Ul_i; + union { + u_int32 Xl_uf; + int32 Xl_f; + } Ul_f; +} l_fp; + +#define l_ui Ul_i.Xl_ui /* unsigned integral part */ +#define l_i Ul_i.Xl_i /* signed integral part */ +#define l_uf Ul_f.Xl_uf /* unsigned fractional part */ +#define l_f Ul_f.Xl_f /* signed fractional part */ + +/* + * Fractional precision (of an l_fp) is actually the number of + * bits in a long. + */ +#define FRACTION_PREC (32) + + +/* + * The second fixed point format is 32 bits, with the decimal between + * bits 15 and 16. There is a signed version (s_fp) and an unsigned + * version (u_fp). This is used to represent synchronizing distance + * and synchronizing dispersion in the NTP packet header (again, in + * network byte order) and internally to hold both distance and + * dispersion values (in local byte order). In network byte order + * it looks like: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Integer Part | Fraction Part | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +typedef int32 s_fp; +typedef u_int32 u_fp; + +/* + * A unit second in fp format. Actually 2**(half_the_bits_in_a_long) + */ +#define FP_SECOND (0x10000) + +/* + * Byte order conversions + */ +#define HTONS_FP(x) (htonl(x)) +#define HTONL_FP(h, n) do { (n)->l_ui = htonl((h)->l_ui); \ + (n)->l_uf = htonl((h)->l_uf); } while (0) +#define NTOHS_FP(x) (ntohl(x)) +#define NTOHL_FP(n, h) do { (h)->l_ui = ntohl((n)->l_ui); \ + (h)->l_uf = ntohl((n)->l_uf); } while (0) +#define NTOHL_MFP(ni, nf, hi, hf) \ + do { (hi) = ntohl(ni); (hf) = ntohl(nf); } while (0) +#define HTONL_MFP(hi, hf, ni, nf) \ + do { (ni) = ntohl(hi); (nf) = ntohl(hf); } while (0) + +/* funny ones. Converts ts fractions to net order ts */ +#define HTONL_UF(uf, nts) \ + do { (nts)->l_ui = 0; (nts)->l_uf = htonl(uf); } while (0) +#define HTONL_F(f, nts) do { (nts)->l_uf = htonl(f); \ + if ((f) & 0x80000000) \ + (nts)->l_i = -1; \ + else \ + (nts)->l_i = 0; \ + } while (0) + +/* + * Conversions between the two fixed point types + */ +#define MFPTOFP(x_i, x_f) (((x_i) >= 0x00010000) ? 0x7fffffff : \ + (((x_i) <= -0x00010000) ? 0x80000000 : \ + (((x_i)<<16) | (((x_f)>>16)&0xffff)))) +#define LFPTOFP(v) MFPTOFP((v)->l_i, (v)->l_f) + +#define UFPTOLFP(x, v) ((v)->l_ui = (u_fp)(x)>>16, (v)->l_uf = (x)<<16) +#define FPTOLFP(x, v) (UFPTOLFP((x), (v)), (x) < 0 ? (v)->l_ui -= 0x10000 : 0) + +#define MAXLFP(v) ((v)->l_ui = 0x7fffffff, (v)->l_uf = 0xffffffff) +#define MINLFP(v) ((v)->l_ui = 0x80000000, (v)->l_uf = 0) + +/* + * Primitive operations on long fixed point values. If these are + * reminiscent of assembler op codes it's only because some may + * be replaced by inline assembler for particular machines someday. + * These are the (kind of inefficient) run-anywhere versions. + */ +#define M_NEG(v_i, v_f) /* v = -v */ \ + do { \ + if ((v_f) == 0) \ + (v_i) = -((s_fp)(v_i)); \ + else { \ + (v_f) = -((s_fp)(v_f)); \ + (v_i) = ~(v_i); \ + } \ + } while(0) + +#define M_NEGM(r_i, r_f, a_i, a_f) /* r = -a */ \ + do { \ + if ((a_f) == 0) { \ + (r_f) = 0; \ + (r_i) = -(a_i); \ + } else { \ + (r_f) = -(a_f); \ + (r_i) = ~(a_i); \ + } \ + } while(0) + +#define M_ADD(r_i, r_f, a_i, a_f) /* r += a */ \ + do { \ + register u_int32 lo_tmp; \ + register u_int32 hi_tmp; \ + \ + lo_tmp = ((r_f) & 0xffff) + ((a_f) & 0xffff); \ + hi_tmp = (((r_f) >> 16) & 0xffff) + (((a_f) >> 16) & 0xffff); \ + if (lo_tmp & 0x10000) \ + hi_tmp++; \ + (r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \ + \ + (r_i) += (a_i); \ + if (hi_tmp & 0x10000) \ + (r_i)++; \ + } while (0) + +#define M_ADD3(r_ovr, r_i, r_f, a_ovr, a_i, a_f) /* r += a, three word */ \ + do { \ + register u_int32 lo_tmp; \ + register u_int32 hi_tmp; \ + \ + lo_tmp = ((r_f) & 0xffff) + ((a_f) & 0xffff); \ + hi_tmp = (((r_f) >> 16) & 0xffff) + (((a_f) >> 16) & 0xffff); \ + if (lo_tmp & 0x10000) \ + hi_tmp++; \ + (r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \ + \ + lo_tmp = ((r_i) & 0xffff) + ((a_i) & 0xffff); \ + if (hi_tmp & 0x10000) \ + lo_tmp++; \ + hi_tmp = (((r_i) >> 16) & 0xffff) + (((a_i) >> 16) & 0xffff); \ + if (lo_tmp & 0x10000) \ + hi_tmp++; \ + (r_i) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \ + \ + (r_ovr) += (a_ovr); \ + if (hi_tmp & 0x10000) \ + (r_ovr)++; \ + } while (0) + +#define M_SUB(r_i, r_f, a_i, a_f) /* r -= a */ \ + do { \ + register u_int32 lo_tmp; \ + register u_int32 hi_tmp; \ + \ + if ((a_f) == 0) { \ + (r_i) -= (a_i); \ + } else { \ + lo_tmp = ((r_f) & 0xffff) + ((-((s_fp)(a_f))) & 0xffff); \ + hi_tmp = (((r_f) >> 16) & 0xffff) \ + + (((-((s_fp)(a_f))) >> 16) & 0xffff); \ + if (lo_tmp & 0x10000) \ + hi_tmp++; \ + (r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \ + \ + (r_i) += ~(a_i); \ + if (hi_tmp & 0x10000) \ + (r_i)++; \ + } \ + } while (0) + +#define M_RSHIFTU(v_i, v_f) /* v >>= 1, v is unsigned */ \ + do { \ + (v_f) = (u_int32)(v_f) >> 1; \ + if ((v_i) & 01) \ + (v_f) |= 0x80000000; \ + (v_i) = (u_int32)(v_i) >> 1; \ + } while (0) + +#define M_RSHIFT(v_i, v_f) /* v >>= 1, v is signed */ \ + do { \ + (v_f) = (u_int32)(v_f) >> 1; \ + if ((v_i) & 01) \ + (v_f) |= 0x80000000; \ + if ((v_i) & 0x80000000) \ + (v_i) = ((v_i) >> 1) | 0x80000000; \ + else \ + (v_i) = (v_i) >> 1; \ + } while (0) + +#define M_LSHIFT(v_i, v_f) /* v <<= 1 */ \ + do { \ + (v_i) <<= 1; \ + if ((v_f) & 0x80000000) \ + (v_i) |= 0x1; \ + (v_f) <<= 1; \ + } while (0) + +#define M_LSHIFT3(v_ovr, v_i, v_f) /* v <<= 1, with overflow */ \ + do { \ + (v_ovr) <<= 1; \ + if ((v_i) & 0x80000000) \ + (v_ovr) |= 0x1; \ + (v_i) <<= 1; \ + if ((v_f) & 0x80000000) \ + (v_i) |= 0x1; \ + (v_f) <<= 1; \ + } while (0) + +#define M_ADDUF(r_i, r_f, uf) /* r += uf, uf is u_int32 fraction */ \ + M_ADD((r_i), (r_f), 0, (uf)) /* let optimizer worry about it */ + +#define M_SUBUF(r_i, r_f, uf) /* r -= uf, uf is u_int32 fraction */ \ + M_SUB((r_i), (r_f), 0, (uf)) /* let optimizer worry about it */ + +#define M_ADDF(r_i, r_f, f) /* r += f, f is a int32 fraction */ \ + do { \ + if ((f) > 0) \ + M_ADD((r_i), (r_f), 0, (f)); \ + else if ((f) < 0) \ + M_ADD((r_i), (r_f), (-1), (f));\ + } while(0) + +#define M_ISNEG(v_i, v_f) /* v < 0 */ \ + (((v_i) & 0x80000000) != 0) + +#define M_ISHIS(a_i, a_f, b_i, b_f) /* a >= b unsigned */ \ + (((u_int32)(a_i)) > ((u_int32)(b_i)) || \ + ((a_i) == (b_i) && ((u_int32)(a_f)) >= ((u_int32)(b_f)))) + +#define M_ISGEQ(a_i, a_f, b_i, b_f) /* a >= b signed */ \ + (((int32)(a_i)) > ((int32)(b_i)) || \ + ((a_i) == (b_i) && ((u_int32)(a_f)) >= ((u_int32)(b_f)))) + +#define M_ISEQU(a_i, a_f, b_i, b_f) /* a == b unsigned */ \ + ((a_i) == (b_i) && (a_f) == (b_f)) + +/* + * Operations on the long fp format + */ +#define L_ADD(r, a) M_ADD((r)->l_ui, (r)->l_uf, (a)->l_ui, (a)->l_uf) +#define L_SUB(r, a) M_SUB((r)->l_ui, (r)->l_uf, (a)->l_ui, (a)->l_uf) +#define L_NEG(v) M_NEG((v)->l_ui, (v)->l_uf) +#define L_ADDUF(r, uf) M_ADDUF((r)->l_ui, (r)->l_uf, (uf)) +#define L_SUBUF(r, uf) M_SUBUF((r)->l_ui, (r)->l_uf, (uf)) +#define L_ADDF(r, f) M_ADDF((r)->l_ui, (r)->l_uf, (f)) +#define L_RSHIFT(v) M_RSHIFT((v)->l_i, (v)->l_uf) +#define L_RSHIFTU(v) M_RSHIFT((v)->l_ui, (v)->l_uf) +#define L_LSHIFT(v) M_LSHIFT((v)->l_ui, (v)->l_uf) +#define L_CLR(v) ((v)->l_ui = (v)->l_uf = 0) + +#define L_ISNEG(v) (((v)->l_ui & 0x80000000) != 0) +#define L_ISZERO(v) ((v)->l_ui == 0 && (v)->l_uf == 0) +#define L_ISHIS(a, b) ((a)->l_ui > (b)->l_ui || \ + ((a)->l_ui == (b)->l_ui && (a)->l_uf >= (b)->l_uf)) +#define L_ISGEQ(a, b) ((a)->l_i > (b)->l_i || \ + ((a)->l_i == (b)->l_i && (a)->l_uf >= (b)->l_uf)) +#define L_ISEQU(a, b) M_ISEQU((a)->l_ui, (a)->l_uf, (b)->l_ui, (b)->l_uf) + +/* + * s_fp/double and u_fp/double conversions + */ +#define FRIC 65536. /* 2^16 as a double */ +#define DTOFP(r) ((s_fp)((r) * FRIC)) +#define DTOUFP(r) ((u_fp)((r) * FRIC)) +#define FPTOD(r) ((double)(r) / FRIC) + +/* + * l_fp/double conversions + */ +#define FRAC 4294967296. /* 2^32 as a double */ +#define M_DTOLFP(d, r_i, r_uf) /* double to l_fp */ \ + do { \ + register double d_tmp; \ + \ + d_tmp = (d); \ + if (d_tmp < 0) { \ + d_tmp = -d_tmp; \ + (r_i) = (int32)(d_tmp); \ + (r_uf) = (u_int32)(((d_tmp) - (double)(r_i)) * FRAC); \ + M_NEG((r_i), (r_uf)); \ + } else { \ + (r_i) = (int32)(d_tmp); \ + (r_uf) = (u_int32)(((d_tmp) - (double)(r_i)) * FRAC); \ + } \ + } while (0) +#define M_LFPTOD(r_i, r_uf, d) /* l_fp to double */ \ + do { \ + register l_fp l_tmp; \ + \ + l_tmp.l_i = (r_i); \ + l_tmp.l_f = (r_uf); \ + if (l_tmp.l_i < 0) { \ + M_NEG(l_tmp.l_i, l_tmp.l_uf); \ + (d) = -((double)l_tmp.l_i + ((double)l_tmp.l_uf) / FRAC); \ + } else { \ + (d) = (double)l_tmp.l_i + ((double)l_tmp.l_uf) / FRAC; \ + } \ + } while (0) +#define DTOLFP(d, v) M_DTOLFP((d), (v)->l_ui, (v)->l_uf) +#define LFPTOD(v, d) M_LFPTOD((v)->l_ui, (v)->l_uf, (d)) + +/* + * Prototypes + */ +#if 0 +extern char * dofptoa (u_fp, int, short, int); +extern char * dolfptoa (u_long, u_long, int, short, int); +#endif + +extern int atolfp (const char *, l_fp *); +extern int buftvtots (const char *, l_fp *); +extern char * fptoa (s_fp, short); +extern char * fptoms (s_fp, short); +extern int hextolfp (const char *, l_fp *); +extern void gpstolfp (int, int, unsigned long, l_fp *); +extern int mstolfp (const char *, l_fp *); +extern char * prettydate (l_fp *); +extern char * gmprettydate (l_fp *); +extern char * uglydate (l_fp *); +extern void mfp_mul (int32 *, u_int32 *, int32, u_int32, int32, u_int32); + +extern void get_systime (l_fp *); +extern int step_systime (double); +extern int adj_systime (double); + +#define lfptoa(_fpv, _ndec) mfptoa((_fpv)->l_ui, (_fpv)->l_uf, (_ndec)) +#define lfptoms(_fpv, _ndec) mfptoms((_fpv)->l_ui, (_fpv)->l_uf, (_ndec)) + +#define ufptoa(_fpv, _ndec) dofptoa((_fpv), 0, (_ndec), 0) +#define ufptoms(_fpv, _ndec) dofptoa((_fpv), 0, (_ndec), 1) +#define ulfptoa(_fpv, _ndec) dolfptoa((_fpv)->l_ui, (_fpv)->l_uf, 0, (_ndec), 0) +#define ulfptoms(_fpv, _ndec) dolfptoa((_fpv)->l_ui, (_fpv)->l_uf, 0, (_ndec), 1) +#define umfptoa(_fpi, _fpf, _ndec) dolfptoa((_fpi), (_fpf), 0, (_ndec), 0) diff --git a/util/kern.c b/util/kern.c new file mode 100644 index 0000000..b193d6f --- /dev/null +++ b/util/kern.c @@ -0,0 +1,225 @@ +/* + * This program simulates a first-order, type-II phase-lock loop using + * actual code segments from modified kernel distributions for SunOS, + * Ultrix and OSF/1 kernels. These segments do not use any licensed code. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <ctype.h> +#include <math.h> +#include <sys/time.h> + +#ifdef HAVE_TIMEX_H +# include "timex.h" +#endif + +/* + * Phase-lock loop definitions + */ +#define HZ 100 /* timer interrupt frequency (Hz) */ +#define MAXPHASE 512000 /* max phase error (us) */ +#define MAXFREQ 200 /* max frequency error (ppm) */ +#define TAU 2 /* time constant (shift 0 - 6) */ +#define POLL 16 /* interval between updates (s) */ +#define MAXSEC 1200 /* max interval between updates (s) */ + +/* + * Function declarations + */ +void hardupdate(); +void hardclock(); +void second_overflow(); + +/* + * Kernel variables + */ +int tick; /* timer interrupt period (us) */ +int fixtick; /* amortization constant (ppm) */ +struct timeval timex; /* ripoff of kernel time variable */ + +/* + * Phase-lock loop variables + */ +int time_status = TIME_BAD; /* clock synchronization status */ +long time_offset = 0; /* time adjustment (us) */ +long time_constant = 0; /* pll time constant */ +long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */ +long time_precision = 1000000 / HZ; /* clock precision (us) */ +long time_maxerror = MAXPHASE; /* maximum error (us) */ +long time_esterror = MAXPHASE; /* estimated error (us) */ +long time_phase = 0; /* phase offset (scaled us) */ +long time_freq = 0; /* frequency offset (scaled ppm) */ +long time_adj = 0; /* tick adjust (scaled 1 / HZ) */ +long time_reftime = 0; /* time at last adjustment (s) */ + +/* + * Simulation variables + */ +double timey = 0; /* simulation time (us) */ +long timez = 0; /* current error (us) */ +long poll_interval = 0; /* poll counter */ + +/* + * Simulation test program + */ +int +main( + int argc, + char *argv[] + ) +{ + tick = 1000000 / HZ; + fixtick = 1000000 % HZ; + timex.tv_sec = 0; + timex.tv_usec = MAXPHASE; + time_freq = 0; + time_constant = TAU; + printf("tick %d us, fixtick %d us\n", tick, fixtick); + printf(" time offset freq _offset _freq _adj\n"); + + /* + * Grind the loop until ^C + */ + while (1) { + timey += (double)(1000000) / HZ; + if (timey >= 1000000) + timey -= 1000000; + hardclock(); + if (timex.tv_usec >= 1000000) { + timex.tv_usec -= 1000000; + timex.tv_sec++; + second_overflow(); + poll_interval++; + if (!(poll_interval % POLL)) { + timez = (long)timey - timex.tv_usec; + if (timez > 500000) + timez -= 1000000; + if (timez < -500000) + timez += 1000000; + hardupdate(timez); + printf("%10li%10li%10.2f %08lx %08lx %08lx\n", + timex.tv_sec, timez, + (double)time_freq / (1 << SHIFT_KF), + time_offset, time_freq, time_adj); + } + } + } +} + +/* + * This routine simulates the ntp_adjtime() call + * + * For default SHIFT_UPDATE = 12, offset is limited to +-512 ms, the + * maximum interval between updates is 4096 s and the maximum frequency + * offset is +-31.25 ms/s. + */ +void +hardupdate( + long offset + ) +{ + long ltemp, mtemp; + + time_offset = offset << SHIFT_UPDATE; + mtemp = timex.tv_sec - time_reftime; + time_reftime = timex.tv_sec; + if (mtemp > MAXSEC) + mtemp = 0; + + /* ugly multiply should be replaced */ + if (offset < 0) + time_freq -= (-offset * mtemp) >> + (time_constant + time_constant); + else + time_freq += (offset * mtemp) >> + (time_constant + time_constant); + ltemp = time_tolerance << SHIFT_KF; + if (time_freq > ltemp) + time_freq = ltemp; + else if (time_freq < -ltemp) + time_freq = -ltemp; + if (time_status == TIME_BAD) + time_status = TIME_OK; +} + +/* + * This routine simulates the timer interrupt + */ +void +hardclock(void) +{ + int ltemp, time_update; + + time_update = tick; /* computed by adjtime() */ + time_phase += time_adj; + if (time_phase < -FINEUSEC) { + ltemp = -time_phase >> SHIFT_SCALE; + time_phase += ltemp << SHIFT_SCALE; + time_update -= ltemp; + } + else if (time_phase > FINEUSEC) { + ltemp = time_phase >> SHIFT_SCALE; + time_phase -= ltemp << SHIFT_SCALE; + time_update += ltemp; + } + timex.tv_usec += time_update; +} + +/* + * This routine simulates the overflow of the microsecond field + * + * With SHIFT_SCALE = 23, the maximum frequency adjustment is +-256 us + * per tick, or 25.6 ms/s at a clock frequency of 100 Hz. The time + * contribution is shifted right a minimum of two bits, while the frequency + * contribution is a right shift. Thus, overflow is prevented if the + * frequency contribution is limited to half the maximum or 15.625 ms/s. + */ +void +second_overflow(void) +{ + int ltemp; + + time_maxerror += time_tolerance; + if (time_offset < 0) { + ltemp = -time_offset >> + (SHIFT_KG + time_constant); + time_offset += ltemp; + time_adj = -(ltemp << + (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE)); + } else { + ltemp = time_offset >> + (SHIFT_KG + time_constant); + time_offset -= ltemp; + time_adj = ltemp << + (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE); + } + if (time_freq < 0) + time_adj -= -time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE); + else + time_adj += time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE); + time_adj += fixtick << (SHIFT_SCALE - SHIFT_HZ); + + /* ugly divide should be replaced */ + if (timex.tv_sec % 86400 == 0) { + switch (time_status) { + + case TIME_INS: + timex.tv_sec--; /* !! */ + time_status = TIME_OOP; + break; + + case TIME_DEL: + timex.tv_sec++; + time_status = TIME_OK; + break; + + case TIME_OOP: + time_status = TIME_OK; + break; + } + } +} diff --git a/util/longsize.c b/util/longsize.c new file mode 100644 index 0000000..bba1955 --- /dev/null +++ b/util/longsize.c @@ -0,0 +1,11 @@ +#include <stdio.h> + +main() +{ + if (sizeof(long) == 8) { + printf("-DLONG8\n"); + } else if (sizeof(long) == 4) { + printf("-DLONG4\n"); + } + exit(0); +} diff --git a/util/ntp-keygen-opts.c b/util/ntp-keygen-opts.c new file mode 100644 index 0000000..718588f --- /dev/null +++ b/util/ntp-keygen-opts.c @@ -0,0 +1,1719 @@ +/* + * EDIT THIS FILE WITH CAUTION (ntp-keygen-opts.c) + * + * It has been AutoGen-ed December 2, 2014 at 08:58:32 AM by AutoGen 5.18.5pre4 + * From the definitions ntp-keygen-opts.def + * and the template file options + * + * Generated from AutoOpts 41:0:16 templates. + * + * AutoOpts is a copyrighted work. This source file is not encumbered + * by AutoOpts licensing, but is provided under the licensing terms chosen + * by the ntp-keygen author or copyright holder. AutoOpts is + * licensed under the terms of the LGPL. The redistributable library + * (``libopts'') is licensed under the terms of either the LGPL or, at the + * users discretion, the BSD license. See the AutoOpts and/or libopts sources + * for details. + * + * The ntp-keygen program is copyrighted and licensed + * under the following terms: + * + * Copyright (C) 1970-2014 The University of Delaware, all rights reserved. + * This is free software. It is licensed for use, modification and + * redistribution under the terms of the NTP License, copies of which + * can be seen at: + * <http://ntp.org/license> + * <http://opensource.org/licenses/ntp-license.php> + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appears in all copies and that + * both the copyright notice and this permission notice appear in + * supporting documentation, and that the name The University of Delaware not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The University of Delaware makes no + * representations about the suitability this software for any purpose. It + * is provided "as is" without express or implied warranty. + */ + +#ifndef __doxygen__ +#define OPTION_CODE_COMPILE 1 +#include "ntp-keygen-opts.h" +#include <sys/types.h> + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#ifdef __cplusplus +extern "C" { +#endif +extern FILE * option_usage_fp; +#define zCopyright (ntp_keygen_opt_strs+0) +#define zLicenseDescrip (ntp_keygen_opt_strs+326) + +/* + * global included definitions + */ +#include <stdlib.h> + +#ifdef __windows + extern int atoi(const char*); +#else +# include <stdlib.h> +#endif + +#ifndef NULL +# define NULL 0 +#endif + +/** + * static const strings for ntp-keygen options + */ +static char const ntp_keygen_opt_strs[2369] = +/* 0 */ "ntp-keygen (ntp) 4.2.7p482\n" + "Copyright (C) 1970-2014 The University of Delaware, all rights reserved.\n" + "This is free software. It is licensed for use, modification and\n" + "redistribution under the terms of the NTP License, copies of which\n" + "can be seen at:\n" + " <http://ntp.org/license>\n" + " <http://opensource.org/licenses/ntp-license.php>\n\0" +/* 326 */ "Permission to use, copy, modify, and distribute this software and its\n" + "documentation for any purpose with or without fee is hereby granted,\n" + "provided that the above copyright notice appears in all copies and that\n" + "both the copyright notice and this permission notice appear in supporting\n" + "documentation, and that the name The University of Delaware not be used in\n" + "advertising or publicity pertaining to distribution of the software without\n" + "specific, written prior permission. The University of Delaware makes no\n" + "representations about the suitability this software for any purpose. It is\n" + "provided \"as is\" without express or implied warranty.\n\0" +/* 966 */ "identity modulus bits\0" +/* 988 */ "IMBITS\0" +/* 995 */ "imbits\0" +/* 1002 */ "certificate scheme\0" +/* 1021 */ "CERTIFICATE\0" +/* 1033 */ "certificate\0" +/* 1045 */ "privatekey cipher\0" +/* 1063 */ "CIPHER\0" +/* 1070 */ "cipher\0" +/* 1077 */ "Increase debug verbosity level\0" +/* 1108 */ "DEBUG_LEVEL\0" +/* 1120 */ "debug-level\0" +/* 1132 */ "Set the debug verbosity level\0" +/* 1162 */ "SET_DEBUG_LEVEL\0" +/* 1178 */ "set-debug-level\0" +/* 1194 */ "Write IFF or GQ identity keys\0" +/* 1224 */ "ID_KEY\0" +/* 1231 */ "id-key\0" +/* 1238 */ "Generate GQ parameters and keys\0" +/* 1270 */ "GQ_PARAMS\0" +/* 1280 */ "gq-params\0" +/* 1290 */ "generate RSA host key\0" +/* 1312 */ "HOST_KEY\0" +/* 1321 */ "host-key\0" +/* 1330 */ "generate IFF parameters\0" +/* 1354 */ "IFFKEY\0" +/* 1361 */ "iffkey\0" +/* 1368 */ "set Autokey group name\0" +/* 1391 */ "IDENT\0" +/* 1397 */ "ident\0" +/* 1403 */ "set certificate lifetime\0" +/* 1428 */ "LIFETIME\0" +/* 1437 */ "lifetime\0" +/* 1446 */ "generate MD5 keys\0" +/* 1464 */ "MD5KEY\0" +/* 1471 */ "md5key\0" +/* 1478 */ "modulus\0" +/* 1486 */ "MODULUS\0" +/* 1494 */ "generate PC private certificate\0" +/* 1526 */ "PVT_CERT\0" +/* 1535 */ "pvt-cert\0" +/* 1544 */ "local private password\0" +/* 1567 */ "PASSWORD\0" +/* 1576 */ "password\0" +/* 1585 */ "export IFF or GQ group keys with password\0" +/* 1627 */ "EXPORT_PASSWD\0" +/* 1641 */ "export-passwd\0" +/* 1655 */ "generate sign key (RSA or DSA)\0" +/* 1686 */ "SIGN_KEY\0" +/* 1695 */ "sign-key\0" +/* 1704 */ "set host and optionally group name\0" +/* 1739 */ "SUBJECT_NAME\0" +/* 1752 */ "subject-name\0" +/* 1765 */ "trusted certificate (TC scheme)\0" +/* 1797 */ "TRUSTED_CERT\0" +/* 1810 */ "trusted-cert\0" +/* 1823 */ "generate <num> MV parameters\0" +/* 1852 */ "MV_PARAMS\0" +/* 1862 */ "mv-params\0" +/* 1872 */ "update <num> MV keys\0" +/* 1893 */ "MV_KEYS\0" +/* 1901 */ "mv-keys\0" +/* 1909 */ "display extended usage information and exit\0" +/* 1953 */ "help\0" +/* 1958 */ "extended usage information passed thru pager\0" +/* 2003 */ "more-help\0" +/* 2013 */ "output version information and exit\0" +/* 2049 */ "version\0" +/* 2057 */ "save the option state to a config file\0" +/* 2096 */ "save-opts\0" +/* 2106 */ "load options from a config file\0" +/* 2138 */ "LOAD_OPTS\0" +/* 2148 */ "no-load-opts\0" +/* 2161 */ "no\0" +/* 2164 */ "NTP_KEYGEN\0" +/* 2175 */ "ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.7p482\n" + "Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n\0" +/* 2291 */ "$HOME\0" +/* 2297 */ ".\0" +/* 2299 */ ".ntprc\0" +/* 2306 */ "http://bugs.ntp.org, bugs@ntp.org\0" +/* 2340 */ "\n\0" +/* 2342 */ "ntp-keygen (ntp) 4.2.7p482"; + +/** + * imbits option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the imbits option */ +#define IMBITS_DESC (ntp_keygen_opt_strs+966) +/** Upper-cased name for the imbits option */ +#define IMBITS_NAME (ntp_keygen_opt_strs+988) +/** Name string for the imbits option */ +#define IMBITS_name (ntp_keygen_opt_strs+995) +/** Compiled in flag settings for the imbits option */ +#define IMBITS_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC)) + +#else /* disable imbits */ +#define IMBITS_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define IMBITS_NAME NULL +#define IMBITS_DESC NULL +#define IMBITS_name NULL +#endif /* AUTOKEY */ + +/** + * certificate option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the certificate option */ +#define CERTIFICATE_DESC (ntp_keygen_opt_strs+1002) +/** Upper-cased name for the certificate option */ +#define CERTIFICATE_NAME (ntp_keygen_opt_strs+1021) +/** Name string for the certificate option */ +#define CERTIFICATE_name (ntp_keygen_opt_strs+1033) +/** Compiled in flag settings for the certificate option */ +#define CERTIFICATE_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING)) + +#else /* disable certificate */ +#define CERTIFICATE_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define CERTIFICATE_NAME NULL +#define CERTIFICATE_DESC NULL +#define CERTIFICATE_name NULL +#endif /* AUTOKEY */ + +/** + * cipher option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the cipher option */ +#define CIPHER_DESC (ntp_keygen_opt_strs+1045) +/** Upper-cased name for the cipher option */ +#define CIPHER_NAME (ntp_keygen_opt_strs+1063) +/** Name string for the cipher option */ +#define CIPHER_name (ntp_keygen_opt_strs+1070) +/** Compiled in flag settings for the cipher option */ +#define CIPHER_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING)) + +#else /* disable cipher */ +#define CIPHER_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define CIPHER_NAME NULL +#define CIPHER_DESC NULL +#define CIPHER_name NULL +#endif /* AUTOKEY */ + +/** + * debug-level option description: + */ +/** Descriptive text for the debug-level option */ +#define DEBUG_LEVEL_DESC (ntp_keygen_opt_strs+1077) +/** Upper-cased name for the debug-level option */ +#define DEBUG_LEVEL_NAME (ntp_keygen_opt_strs+1108) +/** Name string for the debug-level option */ +#define DEBUG_LEVEL_name (ntp_keygen_opt_strs+1120) +/** Compiled in flag settings for the debug-level option */ +#define DEBUG_LEVEL_FLAGS (OPTST_DISABLED) + +/** + * set-debug-level option description: + */ +/** Descriptive text for the set-debug-level option */ +#define SET_DEBUG_LEVEL_DESC (ntp_keygen_opt_strs+1132) +/** Upper-cased name for the set-debug-level option */ +#define SET_DEBUG_LEVEL_NAME (ntp_keygen_opt_strs+1162) +/** Name string for the set-debug-level option */ +#define SET_DEBUG_LEVEL_name (ntp_keygen_opt_strs+1178) +/** Compiled in flag settings for the set-debug-level option */ +#define SET_DEBUG_LEVEL_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC)) + +/** + * id-key option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the id-key option */ +#define ID_KEY_DESC (ntp_keygen_opt_strs+1194) +/** Upper-cased name for the id-key option */ +#define ID_KEY_NAME (ntp_keygen_opt_strs+1224) +/** Name string for the id-key option */ +#define ID_KEY_name (ntp_keygen_opt_strs+1231) +/** Compiled in flag settings for the id-key option */ +#define ID_KEY_FLAGS (OPTST_DISABLED) + +#else /* disable id-key */ +#define ID_KEY_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define ID_KEY_NAME NULL +#define ID_KEY_DESC NULL +#define ID_KEY_name NULL +#endif /* AUTOKEY */ + +/** + * gq-params option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the gq-params option */ +#define GQ_PARAMS_DESC (ntp_keygen_opt_strs+1238) +/** Upper-cased name for the gq-params option */ +#define GQ_PARAMS_NAME (ntp_keygen_opt_strs+1270) +/** Name string for the gq-params option */ +#define GQ_PARAMS_name (ntp_keygen_opt_strs+1280) +/** Compiled in flag settings for the gq-params option */ +#define GQ_PARAMS_FLAGS (OPTST_DISABLED) + +#else /* disable gq-params */ +#define GQ_PARAMS_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define GQ_PARAMS_NAME NULL +#define GQ_PARAMS_DESC NULL +#define GQ_PARAMS_name NULL +#endif /* AUTOKEY */ + +/** + * host-key option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the host-key option */ +#define HOST_KEY_DESC (ntp_keygen_opt_strs+1290) +/** Upper-cased name for the host-key option */ +#define HOST_KEY_NAME (ntp_keygen_opt_strs+1312) +/** Name string for the host-key option */ +#define HOST_KEY_name (ntp_keygen_opt_strs+1321) +/** Compiled in flag settings for the host-key option */ +#define HOST_KEY_FLAGS (OPTST_DISABLED) + +#else /* disable host-key */ +#define HOST_KEY_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define HOST_KEY_NAME NULL +#define HOST_KEY_DESC NULL +#define HOST_KEY_name NULL +#endif /* AUTOKEY */ + +/** + * iffkey option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the iffkey option */ +#define IFFKEY_DESC (ntp_keygen_opt_strs+1330) +/** Upper-cased name for the iffkey option */ +#define IFFKEY_NAME (ntp_keygen_opt_strs+1354) +/** Name string for the iffkey option */ +#define IFFKEY_name (ntp_keygen_opt_strs+1361) +/** Compiled in flag settings for the iffkey option */ +#define IFFKEY_FLAGS (OPTST_DISABLED) + +#else /* disable iffkey */ +#define IFFKEY_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define IFFKEY_NAME NULL +#define IFFKEY_DESC NULL +#define IFFKEY_name NULL +#endif /* AUTOKEY */ + +/** + * ident option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the ident option */ +#define IDENT_DESC (ntp_keygen_opt_strs+1368) +/** Upper-cased name for the ident option */ +#define IDENT_NAME (ntp_keygen_opt_strs+1391) +/** Name string for the ident option */ +#define IDENT_name (ntp_keygen_opt_strs+1397) +/** Compiled in flag settings for the ident option */ +#define IDENT_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING)) + +#else /* disable ident */ +#define IDENT_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define IDENT_NAME NULL +#define IDENT_DESC NULL +#define IDENT_name NULL +#endif /* AUTOKEY */ + +/** + * lifetime option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the lifetime option */ +#define LIFETIME_DESC (ntp_keygen_opt_strs+1403) +/** Upper-cased name for the lifetime option */ +#define LIFETIME_NAME (ntp_keygen_opt_strs+1428) +/** Name string for the lifetime option */ +#define LIFETIME_name (ntp_keygen_opt_strs+1437) +/** Compiled in flag settings for the lifetime option */ +#define LIFETIME_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC)) + +#else /* disable lifetime */ +#define LIFETIME_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define LIFETIME_NAME NULL +#define LIFETIME_DESC NULL +#define LIFETIME_name NULL +#endif /* AUTOKEY */ + +/** + * md5key option description: + */ +/** Descriptive text for the md5key option */ +#define MD5KEY_DESC (ntp_keygen_opt_strs+1446) +/** Upper-cased name for the md5key option */ +#define MD5KEY_NAME (ntp_keygen_opt_strs+1464) +/** Name string for the md5key option */ +#define MD5KEY_name (ntp_keygen_opt_strs+1471) +/** Compiled in flag settings for the md5key option */ +#define MD5KEY_FLAGS (OPTST_DISABLED) + +/** + * modulus option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the modulus option */ +#define MODULUS_DESC (ntp_keygen_opt_strs+1478) +/** Upper-cased name for the modulus option */ +#define MODULUS_NAME (ntp_keygen_opt_strs+1486) +/** Name string for the modulus option */ +#define MODULUS_name (ntp_keygen_opt_strs+1478) +/** Compiled in flag settings for the modulus option */ +#define MODULUS_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC)) + +#else /* disable modulus */ +#define MODULUS_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define MODULUS_NAME NULL +#define MODULUS_DESC NULL +#define MODULUS_name NULL +#endif /* AUTOKEY */ + +/** + * pvt-cert option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the pvt-cert option */ +#define PVT_CERT_DESC (ntp_keygen_opt_strs+1494) +/** Upper-cased name for the pvt-cert option */ +#define PVT_CERT_NAME (ntp_keygen_opt_strs+1526) +/** Name string for the pvt-cert option */ +#define PVT_CERT_name (ntp_keygen_opt_strs+1535) +/** Compiled in flag settings for the pvt-cert option */ +#define PVT_CERT_FLAGS (OPTST_DISABLED) + +#else /* disable pvt-cert */ +#define PVT_CERT_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define PVT_CERT_NAME NULL +#define PVT_CERT_DESC NULL +#define PVT_CERT_name NULL +#endif /* AUTOKEY */ + +/** + * password option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the password option */ +#define PASSWORD_DESC (ntp_keygen_opt_strs+1544) +/** Upper-cased name for the password option */ +#define PASSWORD_NAME (ntp_keygen_opt_strs+1567) +/** Name string for the password option */ +#define PASSWORD_name (ntp_keygen_opt_strs+1576) +/** Compiled in flag settings for the password option */ +#define PASSWORD_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING)) + +#else /* disable password */ +#define PASSWORD_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define PASSWORD_NAME NULL +#define PASSWORD_DESC NULL +#define PASSWORD_name NULL +#endif /* AUTOKEY */ + +/** + * export-passwd option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the export-passwd option */ +#define EXPORT_PASSWD_DESC (ntp_keygen_opt_strs+1585) +/** Upper-cased name for the export-passwd option */ +#define EXPORT_PASSWD_NAME (ntp_keygen_opt_strs+1627) +/** Name string for the export-passwd option */ +#define EXPORT_PASSWD_name (ntp_keygen_opt_strs+1641) +/** Compiled in flag settings for the export-passwd option */ +#define EXPORT_PASSWD_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING)) + +#else /* disable export-passwd */ +#define EXPORT_PASSWD_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define EXPORT_PASSWD_NAME NULL +#define EXPORT_PASSWD_DESC NULL +#define EXPORT_PASSWD_name NULL +#endif /* AUTOKEY */ + +/** + * sign-key option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the sign-key option */ +#define SIGN_KEY_DESC (ntp_keygen_opt_strs+1655) +/** Upper-cased name for the sign-key option */ +#define SIGN_KEY_NAME (ntp_keygen_opt_strs+1686) +/** Name string for the sign-key option */ +#define SIGN_KEY_name (ntp_keygen_opt_strs+1695) +/** Compiled in flag settings for the sign-key option */ +#define SIGN_KEY_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING)) + +#else /* disable sign-key */ +#define SIGN_KEY_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define SIGN_KEY_NAME NULL +#define SIGN_KEY_DESC NULL +#define SIGN_KEY_name NULL +#endif /* AUTOKEY */ + +/** + * subject-name option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the subject-name option */ +#define SUBJECT_NAME_DESC (ntp_keygen_opt_strs+1704) +/** Upper-cased name for the subject-name option */ +#define SUBJECT_NAME_NAME (ntp_keygen_opt_strs+1739) +/** Name string for the subject-name option */ +#define SUBJECT_NAME_name (ntp_keygen_opt_strs+1752) +/** Compiled in flag settings for the subject-name option */ +#define SUBJECT_NAME_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_STRING)) + +#else /* disable subject-name */ +#define SUBJECT_NAME_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define SUBJECT_NAME_NAME NULL +#define SUBJECT_NAME_DESC NULL +#define SUBJECT_NAME_name NULL +#endif /* AUTOKEY */ + +/** + * trusted-cert option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the trusted-cert option */ +#define TRUSTED_CERT_DESC (ntp_keygen_opt_strs+1765) +/** Upper-cased name for the trusted-cert option */ +#define TRUSTED_CERT_NAME (ntp_keygen_opt_strs+1797) +/** Name string for the trusted-cert option */ +#define TRUSTED_CERT_name (ntp_keygen_opt_strs+1810) +/** Compiled in flag settings for the trusted-cert option */ +#define TRUSTED_CERT_FLAGS (OPTST_DISABLED) + +#else /* disable trusted-cert */ +#define TRUSTED_CERT_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define TRUSTED_CERT_NAME NULL +#define TRUSTED_CERT_DESC NULL +#define TRUSTED_CERT_name NULL +#endif /* AUTOKEY */ + +/** + * mv-params option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the mv-params option */ +#define MV_PARAMS_DESC (ntp_keygen_opt_strs+1823) +/** Upper-cased name for the mv-params option */ +#define MV_PARAMS_NAME (ntp_keygen_opt_strs+1852) +/** Name string for the mv-params option */ +#define MV_PARAMS_name (ntp_keygen_opt_strs+1862) +/** Compiled in flag settings for the mv-params option */ +#define MV_PARAMS_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC)) + +#else /* disable mv-params */ +#define MV_PARAMS_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define MV_PARAMS_NAME NULL +#define MV_PARAMS_DESC NULL +#define MV_PARAMS_name NULL +#endif /* AUTOKEY */ + +/** + * mv-keys option description: + */ +#ifdef AUTOKEY +/** Descriptive text for the mv-keys option */ +#define MV_KEYS_DESC (ntp_keygen_opt_strs+1872) +/** Upper-cased name for the mv-keys option */ +#define MV_KEYS_NAME (ntp_keygen_opt_strs+1893) +/** Name string for the mv-keys option */ +#define MV_KEYS_name (ntp_keygen_opt_strs+1901) +/** Compiled in flag settings for the mv-keys option */ +#define MV_KEYS_FLAGS (OPTST_DISABLED \ + | OPTST_SET_ARGTYPE(OPARG_TYPE_NUMERIC)) + +#else /* disable mv-keys */ +#define MV_KEYS_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#define MV_KEYS_NAME NULL +#define MV_KEYS_DESC NULL +#define MV_KEYS_name NULL +#endif /* AUTOKEY */ + +/* + * Help/More_Help/Version option descriptions: + */ +#define HELP_DESC (ntp_keygen_opt_strs+1909) +#define HELP_name (ntp_keygen_opt_strs+1953) +#ifdef HAVE_WORKING_FORK +#define MORE_HELP_DESC (ntp_keygen_opt_strs+1958) +#define MORE_HELP_name (ntp_keygen_opt_strs+2003) +#define MORE_HELP_FLAGS (OPTST_IMM | OPTST_NO_INIT) +#else +#define MORE_HELP_DESC HELP_DESC +#define MORE_HELP_name HELP_name +#define MORE_HELP_FLAGS (OPTST_OMITTED | OPTST_NO_INIT) +#endif +#ifdef NO_OPTIONAL_OPT_ARGS +# define VER_FLAGS (OPTST_IMM | OPTST_NO_INIT) +#else +# define VER_FLAGS (OPTST_SET_ARGTYPE(OPARG_TYPE_STRING) | \ + OPTST_ARG_OPTIONAL | OPTST_IMM | OPTST_NO_INIT) +#endif +#define VER_DESC (ntp_keygen_opt_strs+2013) +#define VER_name (ntp_keygen_opt_strs+2049) +#define SAVE_OPTS_DESC (ntp_keygen_opt_strs+2057) +#define SAVE_OPTS_name (ntp_keygen_opt_strs+2096) +#define LOAD_OPTS_DESC (ntp_keygen_opt_strs+2106) +#define LOAD_OPTS_NAME (ntp_keygen_opt_strs+2138) +#define NO_LOAD_OPTS_name (ntp_keygen_opt_strs+2148) +#define LOAD_OPTS_pfx (ntp_keygen_opt_strs+2161) +#define LOAD_OPTS_name (NO_LOAD_OPTS_name + 3) +/** + * Declare option callback procedures + */ +#ifdef AUTOKEY + static tOptProc doOptImbits; +#else /* not AUTOKEY */ +# define doOptImbits NULL +#endif /* def/not AUTOKEY */ +#ifdef AUTOKEY + static tOptProc doOptModulus; +#else /* not AUTOKEY */ +# define doOptModulus NULL +#endif /* def/not AUTOKEY */ +extern tOptProc + ntpOptionPrintVersion, optionBooleanVal, optionNestedVal, + optionNumericVal, optionPagedUsage, optionResetOpt, + optionStackArg, optionTimeDate, optionTimeVal, + optionUnstackArg, optionVendorOption; +static tOptProc + doOptDebug_Level, doUsageOpt; +#define VER_PROC ntpOptionPrintVersion + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/** + * Define the ntp-keygen Option Descriptions. + * This is an array of OPTION_CT entries, one for each + * option that the ntp-keygen program responds to. + */ +static tOptDesc optDesc[OPTION_CT] = { + { /* entry idx, value */ 0, VALUE_OPT_IMBITS, + /* equiv idx, value */ 0, VALUE_OPT_IMBITS, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ IMBITS_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --imbits */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ doOptImbits, + /* desc, NAME, name */ IMBITS_DESC, IMBITS_NAME, IMBITS_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 1, VALUE_OPT_CERTIFICATE, + /* equiv idx, value */ 1, VALUE_OPT_CERTIFICATE, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ CERTIFICATE_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --certificate */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ CERTIFICATE_DESC, CERTIFICATE_NAME, CERTIFICATE_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 2, VALUE_OPT_CIPHER, + /* equiv idx, value */ 2, VALUE_OPT_CIPHER, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ CIPHER_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --cipher */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ CIPHER_DESC, CIPHER_NAME, CIPHER_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 3, VALUE_OPT_DEBUG_LEVEL, + /* equiv idx, value */ 3, VALUE_OPT_DEBUG_LEVEL, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, NOLIMIT, 0, + /* opt state flags */ DEBUG_LEVEL_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --debug-level */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ doOptDebug_Level, + /* desc, NAME, name */ DEBUG_LEVEL_DESC, DEBUG_LEVEL_NAME, DEBUG_LEVEL_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 4, VALUE_OPT_SET_DEBUG_LEVEL, + /* equiv idx, value */ 4, VALUE_OPT_SET_DEBUG_LEVEL, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, NOLIMIT, 0, + /* opt state flags */ SET_DEBUG_LEVEL_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --set-debug-level */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ optionNumericVal, + /* desc, NAME, name */ SET_DEBUG_LEVEL_DESC, SET_DEBUG_LEVEL_NAME, SET_DEBUG_LEVEL_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 5, VALUE_OPT_ID_KEY, + /* equiv idx, value */ 5, VALUE_OPT_ID_KEY, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ ID_KEY_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --id-key */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ ID_KEY_DESC, ID_KEY_NAME, ID_KEY_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 6, VALUE_OPT_GQ_PARAMS, + /* equiv idx, value */ 6, VALUE_OPT_GQ_PARAMS, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ GQ_PARAMS_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --gq-params */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ GQ_PARAMS_DESC, GQ_PARAMS_NAME, GQ_PARAMS_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 7, VALUE_OPT_HOST_KEY, + /* equiv idx, value */ 7, VALUE_OPT_HOST_KEY, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ HOST_KEY_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --host-key */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ HOST_KEY_DESC, HOST_KEY_NAME, HOST_KEY_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 8, VALUE_OPT_IFFKEY, + /* equiv idx, value */ 8, VALUE_OPT_IFFKEY, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ IFFKEY_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --iffkey */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ IFFKEY_DESC, IFFKEY_NAME, IFFKEY_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 9, VALUE_OPT_IDENT, + /* equiv idx, value */ 9, VALUE_OPT_IDENT, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ IDENT_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --ident */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ IDENT_DESC, IDENT_NAME, IDENT_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 10, VALUE_OPT_LIFETIME, + /* equiv idx, value */ 10, VALUE_OPT_LIFETIME, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ LIFETIME_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --lifetime */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ optionNumericVal, + /* desc, NAME, name */ LIFETIME_DESC, LIFETIME_NAME, LIFETIME_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 11, VALUE_OPT_MD5KEY, + /* equiv idx, value */ 11, VALUE_OPT_MD5KEY, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ MD5KEY_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --md5key */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ MD5KEY_DESC, MD5KEY_NAME, MD5KEY_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 12, VALUE_OPT_MODULUS, + /* equiv idx, value */ 12, VALUE_OPT_MODULUS, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ MODULUS_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --modulus */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ doOptModulus, + /* desc, NAME, name */ MODULUS_DESC, MODULUS_NAME, MODULUS_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 13, VALUE_OPT_PVT_CERT, + /* equiv idx, value */ 13, VALUE_OPT_PVT_CERT, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ PVT_CERT_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --pvt-cert */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ PVT_CERT_DESC, PVT_CERT_NAME, PVT_CERT_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 14, VALUE_OPT_PASSWORD, + /* equiv idx, value */ 14, VALUE_OPT_PASSWORD, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ PASSWORD_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --password */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ PASSWORD_DESC, PASSWORD_NAME, PASSWORD_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 15, VALUE_OPT_EXPORT_PASSWD, + /* equiv idx, value */ 15, VALUE_OPT_EXPORT_PASSWD, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ EXPORT_PASSWD_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --export-passwd */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ EXPORT_PASSWD_DESC, EXPORT_PASSWD_NAME, EXPORT_PASSWD_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 16, VALUE_OPT_SIGN_KEY, + /* equiv idx, value */ 16, VALUE_OPT_SIGN_KEY, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ SIGN_KEY_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --sign-key */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ SIGN_KEY_DESC, SIGN_KEY_NAME, SIGN_KEY_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 17, VALUE_OPT_SUBJECT_NAME, + /* equiv idx, value */ 17, VALUE_OPT_SUBJECT_NAME, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ SUBJECT_NAME_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --subject-name */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ SUBJECT_NAME_DESC, SUBJECT_NAME_NAME, SUBJECT_NAME_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 18, VALUE_OPT_TRUSTED_CERT, + /* equiv idx, value */ 18, VALUE_OPT_TRUSTED_CERT, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ TRUSTED_CERT_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --trusted-cert */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ TRUSTED_CERT_DESC, TRUSTED_CERT_NAME, TRUSTED_CERT_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 19, VALUE_OPT_MV_PARAMS, + /* equiv idx, value */ 19, VALUE_OPT_MV_PARAMS, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ MV_PARAMS_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --mv-params */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ optionNumericVal, + /* desc, NAME, name */ MV_PARAMS_DESC, MV_PARAMS_NAME, MV_PARAMS_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ 20, VALUE_OPT_MV_KEYS, + /* equiv idx, value */ 20, VALUE_OPT_MV_KEYS, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ MV_KEYS_FLAGS, 0, + /* last opt argumnt */ { NULL }, /* --mv-keys */ + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ optionNumericVal, + /* desc, NAME, name */ MV_KEYS_DESC, MV_KEYS_NAME, MV_KEYS_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ INDEX_OPT_VERSION, VALUE_OPT_VERSION, + /* equiv idx value */ NO_EQUIVALENT, VALUE_OPT_VERSION, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ VER_FLAGS, AOUSE_VERSION, + /* last opt argumnt */ { NULL }, + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ VER_PROC, + /* desc, NAME, name */ VER_DESC, NULL, VER_name, + /* disablement strs */ NULL, NULL }, + + + + { /* entry idx, value */ INDEX_OPT_HELP, VALUE_OPT_HELP, + /* equiv idx value */ NO_EQUIVALENT, VALUE_OPT_HELP, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ OPTST_IMM | OPTST_NO_INIT, AOUSE_HELP, + /* last opt argumnt */ { NULL }, + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ doUsageOpt, + /* desc, NAME, name */ HELP_DESC, NULL, HELP_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ INDEX_OPT_MORE_HELP, VALUE_OPT_MORE_HELP, + /* equiv idx value */ NO_EQUIVALENT, VALUE_OPT_MORE_HELP, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ MORE_HELP_FLAGS, AOUSE_MORE_HELP, + /* last opt argumnt */ { NULL }, + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ optionPagedUsage, + /* desc, NAME, name */ MORE_HELP_DESC, NULL, MORE_HELP_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ INDEX_OPT_SAVE_OPTS, VALUE_OPT_SAVE_OPTS, + /* equiv idx value */ NO_EQUIVALENT, VALUE_OPT_SAVE_OPTS, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, 1, 0, + /* opt state flags */ OPTST_SET_ARGTYPE(OPARG_TYPE_STRING) + | OPTST_ARG_OPTIONAL | OPTST_NO_INIT, AOUSE_SAVE_OPTS, + /* last opt argumnt */ { NULL }, + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ NULL, + /* desc, NAME, name */ SAVE_OPTS_DESC, NULL, SAVE_OPTS_name, + /* disablement strs */ NULL, NULL }, + + { /* entry idx, value */ INDEX_OPT_LOAD_OPTS, VALUE_OPT_LOAD_OPTS, + /* equiv idx value */ NO_EQUIVALENT, VALUE_OPT_LOAD_OPTS, + /* equivalenced to */ NO_EQUIVALENT, + /* min, max, act ct */ 0, NOLIMIT, 0, + /* opt state flags */ OPTST_SET_ARGTYPE(OPARG_TYPE_STRING) + | OPTST_DISABLE_IMM, AOUSE_LOAD_OPTS, + /* last opt argumnt */ { NULL }, + /* arg list/cookie */ NULL, + /* must/cannot opts */ NULL, NULL, + /* option proc */ optionLoadOpt, + /* desc, NAME, name */ LOAD_OPTS_DESC, LOAD_OPTS_NAME, LOAD_OPTS_name, + /* disablement strs */ NO_LOAD_OPTS_name, LOAD_OPTS_pfx } +}; + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/** Reference to the upper cased version of ntp-keygen. */ +#define zPROGNAME (ntp_keygen_opt_strs+2164) +/** Reference to the title line for ntp-keygen usage. */ +#define zUsageTitle (ntp_keygen_opt_strs+2175) +/** ntp-keygen configuration file name. */ +#define zRcName (ntp_keygen_opt_strs+2299) +/** Directories to search for ntp-keygen config files. */ +static char const * const apzHomeList[3] = { + ntp_keygen_opt_strs+2291, + ntp_keygen_opt_strs+2297, + NULL }; +/** The ntp-keygen program bug email address. */ +#define zBugsAddr (ntp_keygen_opt_strs+2306) +/** Clarification/explanation of what ntp-keygen does. */ +#define zExplain (ntp_keygen_opt_strs+2340) +/** Extra detail explaining what ntp-keygen does. */ +#define zDetail (NULL) +/** The full version string for ntp-keygen. */ +#define zFullVersion (ntp_keygen_opt_strs+2342) +/* extracted from optcode.tlib near line 364 */ + +#if defined(ENABLE_NLS) +# define OPTPROC_BASE OPTPROC_TRANSLATE + static tOptionXlateProc translate_option_strings; +#else +# define OPTPROC_BASE OPTPROC_NONE +# define translate_option_strings NULL +#endif /* ENABLE_NLS */ + +#define ntp_keygen_full_usage (NULL) +#define ntp_keygen_short_usage (NULL) + +#endif /* not defined __doxygen__ */ + +/* + * Create the static procedure(s) declared above. + */ +/** + * The callout function that invokes the optionUsage function. + * + * @param[in] opts the AutoOpts option description structure + * @param[in] od the descriptor for the "help" (usage) option. + * @noreturn + */ +static void +doUsageOpt(tOptions * opts, tOptDesc * od) +{ + int ex_code; + ex_code = NTP_KEYGEN_EXIT_SUCCESS; + optionUsage(&ntp_keygenOptions, ex_code); + /* NOTREACHED */ + exit(1); + (void)opts; + (void)od; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/** + * Code to handle the imbits option, when AUTOKEY is #define-d. + * The number of bits in the identity modulus. The default is 256. + * @param[in] pOptions the ntp-keygen options data structure + * @param[in,out] pOptDesc the option descriptor for this option. + */ +#ifdef AUTOKEY +static void +doOptImbits(tOptions* pOptions, tOptDesc* pOptDesc) +{ + static struct {long rmin, rmax;} const rng[1] = { + { 256, 2048 } }; + int ix; + + if (pOptions <= OPTPROC_EMIT_LIMIT) + goto emit_ranges; + optionNumericVal(pOptions, pOptDesc); + + for (ix = 0; ix < 1; ix++) { + if (pOptDesc->optArg.argInt < rng[ix].rmin) + continue; /* ranges need not be ordered. */ + if (pOptDesc->optArg.argInt == rng[ix].rmin) + return; + if (rng[ix].rmax == LONG_MIN) + continue; + if (pOptDesc->optArg.argInt <= rng[ix].rmax) + return; + } + + option_usage_fp = stderr; + + emit_ranges: + optionShowRange(pOptions, pOptDesc, (void *)rng, 1); +} +#endif /* defined AUTOKEY */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/** + * Code to handle the debug-level option. + * + * @param[in] pOptions the ntp-keygen options data structure + * @param[in,out] pOptDesc the option descriptor for this option. + */ +static void +doOptDebug_Level(tOptions* pOptions, tOptDesc* pOptDesc) +{ + /* + * Be sure the flag-code[0] handles special values for the options pointer + * viz. (poptions <= OPTPROC_EMIT_LIMIT) *and also* the special flag bit + * ((poptdesc->fOptState & OPTST_RESET) != 0) telling the option to + * reset its state. + */ + /* extracted from debug-opt.def, line 15 */ +OPT_VALUE_SET_DEBUG_LEVEL++; + (void)pOptDesc; + (void)pOptions; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/** + * Code to handle the modulus option, when AUTOKEY is #define-d. + * The number of bits in the prime modulus. The default is 512. + * @param[in] pOptions the ntp-keygen options data structure + * @param[in,out] pOptDesc the option descriptor for this option. + */ +#ifdef AUTOKEY +static void +doOptModulus(tOptions* pOptions, tOptDesc* pOptDesc) +{ + static struct {long rmin, rmax;} const rng[1] = { + { 256, 2048 } }; + int ix; + + if (pOptions <= OPTPROC_EMIT_LIMIT) + goto emit_ranges; + optionNumericVal(pOptions, pOptDesc); + + for (ix = 0; ix < 1; ix++) { + if (pOptDesc->optArg.argInt < rng[ix].rmin) + continue; /* ranges need not be ordered. */ + if (pOptDesc->optArg.argInt == rng[ix].rmin) + return; + if (rng[ix].rmax == LONG_MIN) + continue; + if (pOptDesc->optArg.argInt <= rng[ix].rmax) + return; + } + + option_usage_fp = stderr; + + emit_ranges: + optionShowRange(pOptions, pOptDesc, (void *)rng, 1); +} +#endif /* defined AUTOKEY */ +/* extracted from optmain.tlib near line 1245 */ + +/** + * The directory containing the data associated with ntp-keygen. + */ +#ifndef PKGDATADIR +# define PKGDATADIR "" +#endif + +/** + * Information about the person or institution that packaged ntp-keygen + * for the current distribution. + */ +#ifndef WITH_PACKAGER +# define ntp_keygen_packager_info NULL +#else +/** Packager information for ntp-keygen. */ +static char const ntp_keygen_packager_info[] = + "Packaged by " WITH_PACKAGER + +# ifdef WITH_PACKAGER_VERSION + " ("WITH_PACKAGER_VERSION")" +# endif + +# ifdef WITH_PACKAGER_BUG_REPORTS + "\nReport ntp_keygen bugs to " WITH_PACKAGER_BUG_REPORTS +# endif + "\n"; +#endif +#ifndef __doxygen__ + +#endif /* __doxygen__ */ +/** + * The option definitions for ntp-keygen. The one structure that + * binds them all. + */ +tOptions ntp_keygenOptions = { + OPTIONS_STRUCT_VERSION, + 0, NULL, /* original argc + argv */ + ( OPTPROC_BASE + + OPTPROC_ERRSTOP + + OPTPROC_SHORTOPT + + OPTPROC_LONGOPT + + OPTPROC_NO_REQ_OPT + + OPTPROC_ENVIRON + + OPTPROC_NO_ARGS + + OPTPROC_MISUSE ), + 0, NULL, /* current option index, current option */ + NULL, NULL, zPROGNAME, + zRcName, zCopyright, zLicenseDescrip, + zFullVersion, apzHomeList, zUsageTitle, + zExplain, zDetail, optDesc, + zBugsAddr, /* address to send bugs to */ + NULL, NULL, /* extensions/saved state */ + optionUsage, /* usage procedure */ + translate_option_strings, /* translation procedure */ + /* + * Indexes to special options + */ + { INDEX_OPT_MORE_HELP, /* more-help option index */ + INDEX_OPT_SAVE_OPTS, /* save option index */ + NO_EQUIVALENT, /* '-#' option index */ + NO_EQUIVALENT /* index of default opt */ + }, + 26 /* full option count */, 21 /* user option count */, + ntp_keygen_full_usage, ntp_keygen_short_usage, + NULL, NULL, + PKGDATADIR, ntp_keygen_packager_info +}; + +#if ENABLE_NLS +/** + * This code is designed to translate translatable option text for the + * ntp-keygen program. These translations happen upon entry + * to optionProcess(). + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#ifdef HAVE_DCGETTEXT +# include <gettext.h> +#endif +#include <autoopts/usage-txt.h> + +static char * AO_gettext(char const * pz); +static void coerce_it(void ** s); + +/** + * AutoGen specific wrapper function for gettext. It relies on the macro _() + * to convert from English to the target language, then strdup-duplicates the + * result string. It tries the "libopts" domain first, then whatever has been + * set via the \a textdomain(3) call. + * + * @param[in] pz the input text used as a lookup key. + * @returns the translated text (if there is one), + * or the original text (if not). + */ +static char * +AO_gettext(char const * pz) +{ + char * res; + if (pz == NULL) + return NULL; +#ifdef HAVE_DCGETTEXT + /* + * While processing the option_xlateable_txt data, try to use the + * "libopts" domain. Once we switch to the option descriptor data, + * do *not* use that domain. + */ + if (option_xlateable_txt.field_ct != 0) { + res = dgettext("libopts", pz); + if (res == pz) + res = (char *)(void *)_(pz); + } else + res = (char *)(void *)_(pz); +#else + res = (char *)(void *)_(pz); +#endif + if (res == pz) + return res; + res = strdup(res); + if (res == NULL) { + fputs(_("No memory for duping translated strings\n"), stderr); + exit(NTP_KEYGEN_EXIT_FAILURE); + } + return res; +} + +/** + * All the pointers we use are marked "* const", but they are stored in + * writable memory. Coerce the mutability and set the pointer. + */ +static void coerce_it(void ** s) { *s = AO_gettext(*s); +} + +/** + * Translate all the translatable strings in the ntp_keygenOptions + * structure defined above. This is done only once. + */ +static void +translate_option_strings(void) +{ + tOptions * const opts = &ntp_keygenOptions; + + /* + * Guard against re-translation. It won't work. The strings will have + * been changed by the first pass through this code. One shot only. + */ + if (option_xlateable_txt.field_ct != 0) { + /* + * Do the translations. The first pointer follows the field count + * field. The field count field is the size of a pointer. + */ + char ** ppz = (char**)(void*)&(option_xlateable_txt); + int ix = option_xlateable_txt.field_ct; + + do { + ppz++; /* skip over field_ct */ + *ppz = AO_gettext(*ppz); + } while (--ix > 0); + /* prevent re-translation and disable "libopts" domain lookup */ + option_xlateable_txt.field_ct = 0; + + coerce_it((void*)&(opts->pzCopyright)); + coerce_it((void*)&(opts->pzCopyNotice)); + coerce_it((void*)&(opts->pzFullVersion)); + coerce_it((void*)&(opts->pzUsageTitle)); + coerce_it((void*)&(opts->pzExplain)); + coerce_it((void*)&(opts->pzDetail)); + { + tOptDesc * od = opts->pOptDesc; + for (ix = opts->optCt; ix > 0; ix--, od++) + coerce_it((void*)&(od->pzText)); + } + } +} +#endif /* ENABLE_NLS */ + +#ifdef DO_NOT_COMPILE_THIS_CODE_IT_IS_FOR_GETTEXT +/** I18N function strictly for xgettext. Do not compile. */ +static void bogus_function(void) { + /* TRANSLATORS: + + The following dummy function was crated solely so that xgettext can + extract the correct strings. These strings are actually referenced + by a field name in the ntp_keygenOptions structure noted in the + comments below. The literal text is defined in ntp_keygen_opt_strs. + + NOTE: the strings below are segmented with respect to the source string + ntp_keygen_opt_strs. The strings above are handed off for translation + at run time a paragraph at a time. Consequently, they are presented here + for translation a paragraph at a time. + + ALSO: often the description for an option will reference another option + by name. These are set off with apostrophe quotes (I hope). Do not + translate option names. + */ + /* referenced via ntp_keygenOptions.pzCopyright */ + puts(_("ntp-keygen (ntp) 4.2.7p482\n\ +Copyright (C) 1970-2014 The University of Delaware, all rights reserved.\n\ +This is free software. It is licensed for use, modification and\n\ +redistribution under the terms of the NTP License, copies of which\n\ +can be seen at:\n")); + puts(_(" <http://ntp.org/license>\n\ + <http://opensource.org/licenses/ntp-license.php>\n")); + + /* referenced via ntp_keygenOptions.pzCopyNotice */ + puts(_("Permission to use, copy, modify, and distribute this software and its\n\ +documentation for any purpose with or without fee is hereby granted,\n\ +provided that the above copyright notice appears in all copies and that\n\ +both the copyright notice and this permission notice appear in supporting\n\ +documentation, and that the name The University of Delaware not be used in\n\ +advertising or publicity pertaining to distribution of the software without\n\ +specific, written prior permission. The University of Delaware makes no\n\ +representations about the suitability this software for any purpose. It is\n\ +provided \"as is\" without express or implied warranty.\n")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("identity modulus bits")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("certificate scheme")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("privatekey cipher")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("Increase debug verbosity level")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("Set the debug verbosity level")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("Write IFF or GQ identity keys")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("Generate GQ parameters and keys")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("generate RSA host key")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("generate IFF parameters")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("set Autokey group name")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("set certificate lifetime")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("generate MD5 keys")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("modulus")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("generate PC private certificate")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("local private password")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("export IFF or GQ group keys with password")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("generate sign key (RSA or DSA)")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("set host and optionally group name")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("trusted certificate (TC scheme)")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("generate <num> MV parameters")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("update <num> MV keys")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("display extended usage information and exit")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("extended usage information passed thru pager")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("output version information and exit")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("save the option state to a config file")); + + /* referenced via ntp_keygenOptions.pOptDesc->pzText */ + puts(_("load options from a config file")); + + /* referenced via ntp_keygenOptions.pzUsageTitle */ + puts(_("ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.7p482\n\ +Usage: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n")); + + /* referenced via ntp_keygenOptions.pzExplain */ + puts(_("\n")); + + /* referenced via ntp_keygenOptions.pzFullVersion */ + puts(_("ntp-keygen (ntp) 4.2.7p482")); + + /* referenced via ntp_keygenOptions.pzFullUsage */ + puts(_("<<<NOT-FOUND>>>")); + + /* referenced via ntp_keygenOptions.pzShortUsage */ + puts(_("<<<NOT-FOUND>>>")); + /* LIBOPTS-MESSAGES: */ +#line 67 "../autoopts.c" + puts(_("allocation of %d bytes failed\n")); +#line 93 "../autoopts.c" + puts(_("allocation of %d bytes failed\n")); +#line 53 "../init.c" + puts(_("AutoOpts function called without option descriptor\n")); +#line 86 "../init.c" + puts(_("\tThis exceeds the compiled library version: ")); +#line 84 "../init.c" + puts(_("Automated Options Processing Error!\n" + "\t%s called AutoOpts function with structure version %d:%d:%d.\n")); +#line 80 "../autoopts.c" + puts(_("realloc of %d bytes at 0x%p failed\n")); +#line 88 "../init.c" + puts(_("\tThis is less than the minimum library version: ")); +#line 121 "../version.c" + puts(_("Automated Options version %s\n" + "\tCopyright (C) 1999-2014 by Bruce Korb - all rights reserved\n")); +#line 82 "../makeshell.c" + puts(_("(AutoOpts bug): %s.\n")); +#line 90 "../reset.c" + puts(_("optionResetOpt() called, but reset-option not configured")); +#line 292 "../usage.c" + puts(_("could not locate the 'help' option")); +#line 336 "../autoopts.c" + puts(_("optionProcess() was called with invalid data")); +#line 748 "../usage.c" + puts(_("invalid argument type specified")); +#line 598 "../find.c" + puts(_("defaulted to option with optional arg")); +#line 76 "../alias.c" + puts(_("aliasing option is out of range.")); +#line 234 "../enum.c" + puts(_("%s error: the keyword '%s' is ambiguous for %s\n")); +#line 108 "../find.c" + puts(_(" The following options match:\n")); +#line 293 "../find.c" + puts(_("%s: ambiguous option name: %s (matches %d options)\n")); +#line 161 "../check.c" + puts(_("%s: Command line arguments required\n")); +#line 43 "../alias.c" + puts(_("%d %s%s options allowed\n")); +#line 89 "../makeshell.c" + puts(_("%s error %d (%s) calling %s for '%s'\n")); +#line 301 "../makeshell.c" + puts(_("interprocess pipe")); +#line 168 "../version.c" + puts(_("error: version option argument '%c' invalid. Use:\n" + "\t'v' - version only\n" + "\t'c' - version and copyright\n" + "\t'n' - version and full copyright notice\n")); +#line 58 "../check.c" + puts(_("%s error: the '%s' and '%s' options conflict\n")); +#line 217 "../find.c" + puts(_("%s: The '%s' option has been disabled.")); +#line 430 "../find.c" + puts(_("%s: The '%s' option has been disabled.")); +#line 38 "../alias.c" + puts(_("-equivalence")); +#line 469 "../find.c" + puts(_("%s: illegal option -- %c\n")); +#line 110 "../reset.c" + puts(_("%s: illegal option -- %c\n")); +#line 271 "../find.c" + puts(_("%s: illegal option -- %s\n")); +#line 755 "../find.c" + puts(_("%s: illegal option -- %s\n")); +#line 118 "../reset.c" + puts(_("%s: illegal option -- %s\n")); +#line 335 "../find.c" + puts(_("%s: unknown vendor extension option -- %s\n")); +#line 159 "../enum.c" + puts(_(" or an integer from %d through %d\n")); +#line 169 "../enum.c" + puts(_(" or an integer from %d through %d\n")); +#line 747 "../usage.c" + puts(_("%s error: invalid option descriptor for %s\n")); +#line 1081 "../usage.c" + puts(_("%s error: invalid option descriptor for %s\n")); +#line 385 "../find.c" + puts(_("%s: invalid option name: %s\n")); +#line 527 "../find.c" + puts(_("%s: The '%s' option requires an argument.\n")); +#line 156 "../autoopts.c" + puts(_("(AutoOpts bug): Equivalenced option '%s' was equivalenced to both\n" + "\t'%s' and '%s'.")); +#line 94 "../check.c" + puts(_("%s error: The %s option is required\n")); +#line 632 "../find.c" + puts(_("%s: The '%s' option cannot have an argument.\n")); +#line 151 "../check.c" + puts(_("%s: Command line arguments are not allowed.\n")); +#line 535 "../save.c" + puts(_("error %d (%s) creating %s\n")); +#line 234 "../enum.c" + puts(_("%s error: '%s' does not match any %s keywords.\n")); +#line 93 "../reset.c" + puts(_("%s error: The '%s' option requires an argument.\n")); +#line 184 "../save.c" + puts(_("error %d (%s) stat-ing %s\n")); +#line 238 "../save.c" + puts(_("error %d (%s) stat-ing %s\n")); +#line 143 "../restore.c" + puts(_("%s error: no saved option state\n")); +#line 231 "../autoopts.c" + puts(_("'%s' is not a command line option.\n")); +#line 111 "../time.c" + puts(_("%s error: '%s' is not a recognizable date/time.\n")); +#line 132 "../save.c" + puts(_("'%s' not defined\n")); +#line 50 "../time.c" + puts(_("%s error: '%s' is not a recognizable time duration.\n")); +#line 92 "../check.c" + puts(_("%s error: The %s option must appear %d times.\n")); +#line 164 "../numeric.c" + puts(_("%s error: '%s' is not a recognizable number.\n")); +#line 200 "../enum.c" + puts(_("%s error: %s exceeds %s keyword count\n")); +#line 330 "../usage.c" + puts(_("Try '%s %s' for more information.\n")); +#line 45 "../alias.c" + puts(_("one %s%s option allowed\n")); +#line 203 "../makeshell.c" + puts(_("standard output")); +#line 938 "../makeshell.c" + puts(_("standard output")); +#line 274 "../usage.c" + puts(_("standard output")); +#line 415 "../usage.c" + puts(_("standard output")); +#line 625 "../usage.c" + puts(_("standard output")); +#line 175 "../version.c" + puts(_("standard output")); +#line 274 "../usage.c" + puts(_("standard error")); +#line 415 "../usage.c" + puts(_("standard error")); +#line 625 "../usage.c" + puts(_("standard error")); +#line 175 "../version.c" + puts(_("standard error")); +#line 203 "../makeshell.c" + puts(_("write")); +#line 938 "../makeshell.c" + puts(_("write")); +#line 273 "../usage.c" + puts(_("write")); +#line 414 "../usage.c" + puts(_("write")); +#line 624 "../usage.c" + puts(_("write")); +#line 174 "../version.c" + puts(_("write")); +#line 60 "../numeric.c" + puts(_("%s error: %s option value %ld is out of range.\n")); +#line 44 "../check.c" + puts(_("%s error: %s option requires the %s option\n")); +#line 131 "../save.c" + puts(_("%s warning: cannot save options - %s not regular file\n")); +#line 183 "../save.c" + puts(_("%s warning: cannot save options - %s not regular file\n")); +#line 237 "../save.c" + puts(_("%s warning: cannot save options - %s not regular file\n")); +#line 256 "../save.c" + puts(_("%s warning: cannot save options - %s not regular file\n")); +#line 534 "../save.c" + puts(_("%s warning: cannot save options - %s not regular file\n")); + /* END-LIBOPTS-MESSAGES */ + + /* USAGE-TEXT: */ +#line 873 "../usage.c" + puts(_("\t\t\t\t- an alternate for '%s'\n")); +#line 1148 "../usage.c" + puts(_("Version, usage and configuration options:")); +#line 924 "../usage.c" + puts(_("\t\t\t\t- default option for unnamed options\n")); +#line 837 "../usage.c" + puts(_("\t\t\t\t- disabled as '--%s'\n")); +#line 1117 "../usage.c" + puts(_(" --- %-14s %s\n")); +#line 1115 "../usage.c" + puts(_("This option has been disabled")); +#line 864 "../usage.c" + puts(_("\t\t\t\t- enabled by default\n")); +#line 40 "../alias.c" + puts(_("%s error: only ")); +#line 1194 "../usage.c" + puts(_(" - examining environment variables named %s_*\n")); +#line 168 "../file.c" + puts(_("\t\t\t\t- file must not pre-exist\n")); +#line 172 "../file.c" + puts(_("\t\t\t\t- file must pre-exist\n")); +#line 380 "../usage.c" + puts(_("Options are specified by doubled hyphens and their name or by a single\n" + "hyphen and the flag character.\n")); +#line 916 "../makeshell.c" + puts(_("\n" + "= = = = = = = =\n\n" + "This incarnation of genshell will produce\n" + "a shell script to parse the options for %s:\n\n")); +#line 166 "../enum.c" + puts(_(" or an integer mask with any of the lower %d bits set\n")); +#line 897 "../usage.c" + puts(_("\t\t\t\t- is a set membership option\n")); +#line 918 "../usage.c" + puts(_("\t\t\t\t- must appear between %d and %d times\n")); +#line 382 "../usage.c" + puts(_("Options are specified by single or double hyphens and their name.\n")); +#line 904 "../usage.c" + puts(_("\t\t\t\t- may appear multiple times\n")); +#line 891 "../usage.c" + puts(_("\t\t\t\t- may not be preset\n")); +#line 1309 "../usage.c" + puts(_(" Arg Option-Name Description\n")); +#line 1245 "../usage.c" + puts(_(" Flg Arg Option-Name Description\n")); +#line 1303 "../usage.c" + puts(_(" Flg Arg Option-Name Description\n")); +#line 1304 "../usage.c" + puts(_(" %3s %s")); +#line 1310 "../usage.c" + puts(_(" %3s %s")); +#line 387 "../usage.c" + puts(_("The '-#<number>' option may omit the hash char\n")); +#line 383 "../usage.c" + puts(_("All arguments are named options.\n")); +#line 971 "../usage.c" + puts(_(" - reading file %s")); +#line 409 "../usage.c" + puts(_("\n" + "Please send bug reports to: <%s>\n")); +#line 100 "../version.c" + puts(_("\n" + "Please send bug reports to: <%s>\n")); +#line 129 "../version.c" + puts(_("\n" + "Please send bug reports to: <%s>\n")); +#line 903 "../usage.c" + puts(_("\t\t\t\t- may NOT appear - preset only\n")); +#line 944 "../usage.c" + puts(_("\n" + "The following option preset mechanisms are supported:\n")); +#line 1192 "../usage.c" + puts(_("\n" + "The following option preset mechanisms are supported:\n")); +#line 682 "../usage.c" + puts(_("prohibits these options:\n")); +#line 677 "../usage.c" + puts(_("prohibits the option '%s'\n")); +#line 81 "../numeric.c" + puts(_("%s%ld to %ld")); +#line 79 "../numeric.c" + puts(_("%sgreater than or equal to %ld")); +#line 75 "../numeric.c" + puts(_("%s%ld exactly")); +#line 68 "../numeric.c" + puts(_("%sit must lie in one of the ranges:\n")); +#line 68 "../numeric.c" + puts(_("%sit must be in the range:\n")); +#line 88 "../numeric.c" + puts(_(", or\n")); +#line 66 "../numeric.c" + puts(_("%sis scalable with a suffix: k/K/m/M/g/G/t/T\n")); +#line 77 "../numeric.c" + puts(_("%sless than or equal to %ld")); +#line 390 "../usage.c" + puts(_("Operands and options may be intermixed. They will be reordered.\n")); +#line 652 "../usage.c" + puts(_("requires the option '%s'\n")); +#line 655 "../usage.c" + puts(_("requires these options:\n")); +#line 1321 "../usage.c" + puts(_(" Arg Option-Name Req? Description\n")); +#line 1315 "../usage.c" + puts(_(" Flg Arg Option-Name Req? Description\n")); +#line 167 "../enum.c" + puts(_("or you may use a numeric representation. Preceding these with a '!'\n" + "will clear the bits, specifying 'none' will clear all bits, and 'all'\n" + "will set them all. Multiple entries may be passed as an option\n" + "argument list.\n")); +#line 910 "../usage.c" + puts(_("\t\t\t\t- may appear up to %d times\n")); +#line 77 "../enum.c" + puts(_("The valid \"%s\" option keywords are:\n")); +#line 1152 "../usage.c" + puts(_("The next option supports vendor supported extra options:")); +#line 773 "../usage.c" + puts(_("These additional options are:")); + /* END-USAGE-TEXT */ +} +#endif /* uncompilable code */ +#ifdef __cplusplus +} +#endif +/* ntp-keygen-opts.c ends here */ diff --git a/util/ntp-keygen-opts.def b/util/ntp-keygen-opts.def new file mode 100644 index 0000000..3088cf5 --- /dev/null +++ b/util/ntp-keygen-opts.def @@ -0,0 +1,1144 @@ +/* -*- Mode: Text -*- */ + +autogen definitions options; + +#include copyright.def +#include homerc.def +#include autogen-version.def + +prog-name = "ntp-keygen"; +prog-title = "Create a NTP host key"; +package = ntp; + +include = '#include <stdlib.h>'; +#include version.def + +flag = { + value = b; + name = imbits; + arg-type = number; + arg-name = imbits; + arg-range = '256->2048'; + ifdef = AUTOKEY; + descrip = "identity modulus bits"; + doc = <<- _EndOfDoc_ + The number of bits in the identity modulus. The default is 256. + _EndOfDoc_; +}; + +flag = { + value = c; + name = certificate; + arg-type = string; + arg-name = scheme; + ifdef = AUTOKEY; + descrip = "certificate scheme"; + doc = <<- _EndOfDoc_ + scheme is one of + RSA-MD2, RSA-MD5, RSA-SHA, RSA-SHA1, RSA-MDC2, RSA-RIPEMD160, + DSA-SHA, or DSA-SHA1. + + Select the certificate message digest/signature encryption scheme. + Note that RSA schemes must be used with a RSA sign key and DSA + schemes must be used with a DSA sign key. The default without + this option is RSA-MD5. + _EndOfDoc_; +}; + +flag = { + value = C; + name = cipher; + arg-type = string; + arg-name = cipher; + ifdef = AUTOKEY; + descrip = "privatekey cipher"; + doc = <<- _EndOfDoc_ + Select the cipher which is used to encrypt the files containing + private keys. The default is three-key triple DES in CBC mode, + equivalent to "@code{-C des-ede3-cbc". The openssl tool lists ciphers + available in "@code{openssl -h}" output. + _EndOfDoc_; +}; + +#include debug-opt.def + +flag = { + value = e; + name = id-key; + ifdef = AUTOKEY; + descrip = "Write IFF or GQ identity keys"; + doc = <<- _EndOfDoc_ + Write the IFF or GQ client keys to the standard output. This is + intended for automatic key distribution by mail. + _EndOfDoc_; +}; + +flag = { + value = G; + name = gq-params; + ifdef = AUTOKEY; + descrip = "Generate GQ parameters and keys"; + doc = <<- _EndOfDoc_ + Generate parameters and keys for the GQ identification scheme, + obsoleting any that may exist. + _EndOfDoc_; +}; + +flag = { + value = H; + name = host-key; + ifdef = AUTOKEY; + descrip = "generate RSA host key"; + doc = <<- _EndOfDoc_ + Generate new host keys, obsoleting any that may exist. + _EndOfDoc_; +}; + +flag = { + value = I; + name = iffkey; + ifdef = AUTOKEY; + descrip = "generate IFF parameters"; + doc = <<- _EndOfDoc_ + Generate parameters for the IFF identification scheme, obsoleting + any that may exist. + _EndOfDoc_; +}; + +flag = { + value = i; + name = ident; + ifdef = AUTOKEY; + arg-type = string; + arg-name = group; + descrip = "set Autokey group name"; + doc = <<- _EndOfDoc_ + Set the optional Autokey group name to name. This is used in + the file name of IFF, GQ, and MV client parameters files. In + that role, the default is the host name if this option is not + provided. The group name, if specified using @code{-i/--ident} or + using @code{-s/--subject-name} following an '@code{@}' character, + is also a part of the self-signed host certificate's subject and + issuer names in the form @code{host@group} and should match the + '@code{crypto ident}' or '@code{server ident}' configuration in + @code{ntpd}'s configuration file. + _EndOfDoc_; +}; + +flag = { + value = l; + name = lifetime; + ifdef = AUTOKEY; + arg-type = number; + arg-name = lifetime; + descrip = "set certificate lifetime"; + doc = <<- _EndOfDoc_ + Set the certificate expiration to lifetime days from now. + _EndOfDoc_; +}; + +flag = { + value = M; + name = md5key; + descrip = "generate MD5 keys"; + doc = <<- _EndOfDoc_ + Generate MD5 keys, obsoleting any that may exist. + _EndOfDoc_; +}; + +flag = { + value = m; + name = modulus; + arg-type = number; + arg-name = modulus; + arg-range = '256->2048'; + ifdef = AUTOKEY; + descrip = "modulus"; + doc = <<- _EndOfDoc_ + The number of bits in the prime modulus. The default is 512. + _EndOfDoc_; +}; + +flag = { + value = P; + name = pvt-cert; + ifdef = AUTOKEY; + descrip = "generate PC private certificate"; + doc = <<- _EndOfDoc_ + Generate a private certificate. By default, the program generates + public certificates. + _EndOfDoc_; +}; + +flag = { + value = p; + name = password; // was: pvt-passwd; + ifdef = AUTOKEY; + arg-type = string; + arg-name = passwd; + descrip = "local private password"; + doc = <<- _EndOfDoc_ + Local files containing private data are encrypted with the + DES-CBC algorithm and the specified password. The same password + must be specified to the local ntpd via the "crypto pw password" + configuration command. The default password is the local + hostname. + _EndOfDoc_; +}; + +flag = { + value = q; + name = export-passwd; // Was: get-pvt-passwd; + ifdef = AUTOKEY; + arg-type = string; + arg-name = passwd; + descrip = "export IFF or GQ group keys with password"; + doc = <<- _EndOfDoc_ + Export IFF or GQ identity group keys to the standard output, + encrypted with the DES-CBC algorithm and the specified password. + The same password must be specified to the remote ntpd via the + "crypto pw password" configuration command. See also the option + --id-key (-e) for unencrypted exports. + _EndOfDoc_; +}; + +flag = { + value = S; + name = sign-key; + arg-type = string; + arg-name = sign; + ifdef = AUTOKEY; + descrip = "generate sign key (RSA or DSA)"; + doc = <<- _EndOfDoc_ + Generate a new sign key of the designated type, obsoleting any + that may exist. By default, the program uses the host key as the + sign key. + _EndOfDoc_; +}; + +flag = { + value = s; + name = subject-name; + arg-type = string; + arg-name = host@group; + ifdef = AUTOKEY; + descrip = "set host and optionally group name"; + doc = <<- _EndOfDoc_ + Set the Autokey host name, and optionally, group name specified + following an '@code{@}' character. The host name is used in the file + name of generated host and signing certificates, without the + group name. The host name, and if provided, group name are used + in @code{host@group} form for the host certificate's subject and issuer + fields. Specifying '@code{-s @group}' is allowed, and results in + leaving the host name unchanged while appending @code{@group} to the + subject and issuer fields, as with @code{-i group}. The group name, or + if not provided, the host name are also used in the file names + of IFF, GQ, and MV client parameter files. + _EndOfDoc_; +}; + +flag = { + value = T; + name = trusted-cert; + ifdef = AUTOKEY; + descrip = "trusted certificate (TC scheme)"; + doc = <<- _EndOfDoc_ + Generate a trusted certificate. By default, the program generates + a non-trusted certificate. + _EndOfDoc_; +}; + +flag = { + value = V; + name = mv-params; + arg-type = number; + arg-name = num; + ifdef = AUTOKEY; + descrip = "generate <num> MV parameters"; + doc = <<- _EndOfDoc_ + Generate parameters and keys for the Mu-Varadharajan (MV) + identification scheme. + _EndOfDoc_; +}; + +flag = { + value = v; + name = mv-keys; + arg-type = number; + arg-name = num; + ifdef = AUTOKEY; + descrip = "update <num> MV keys"; +}; + +/* explain: Additional information whenever the usage routine is invoked */ +explain = <<- _END_EXPLAIN + _END_EXPLAIN; + +doc-section = { + ds-type = 'DESCRIPTION'; + ds-format = 'mdoc'; + ds-text = <<- _END_PROG_MDOC_DESCRIP +This program generates cryptographic data files used by the NTPv4 +authentication and identification schemes. +It generates MD5 key files used in symmetric key cryptography. +In addition, if the OpenSSL software library has been installed, +it generates keys, certificate and identity files used in public key +cryptography. +These files are used for cookie encryption, +digital signature and challenge/response identification algorithms +compatible with the Internet standard security infrastructure. +.Pp +All files are in PEM-encoded printable ASCII format, +so they can be embedded as MIME attachments in mail to other sites +and certificate authorities. +By default, files are not encrypted. +.Pp +When used to generate message digest keys, the program produces a file +containing ten pseudo-random printable ASCII strings suitable for the +MD5 message digest algorithm included in the distribution. +If the OpenSSL library is installed, it produces an additional ten +hex-encoded random bit strings suitable for the SHA1 and other message +digest algorithms. +The message digest keys file must be distributed and stored +using secure means beyond the scope of NTP itself. +Besides the keys used for ordinary NTP associations, additional keys +can be defined as passwords for the +.Xr ntpq 1ntpqmdoc +and +.Xr ntpdc 1ntpdcmdoc +utility programs. +.Pp +The remaining generated files are compatible with other OpenSSL +applications and other Public Key Infrastructure (PKI) resources. +Certificates generated by this program are compatible with extant +industry practice, although some users might find the interpretation of +X509v3 extension fields somewhat liberal. +However, the identity keys are probably not compatible with anything +other than Autokey. +.Pp +Some files used by this program are encrypted using a private password. +The +.Fl p +option specifies the password for local encrypted files and the +.Fl q +option the password for encrypted files sent to remote sites. +If no password is specified, the host name returned by the Unix +.Fn gethostname +function, normally the DNS name of the host is used. +.Pp +The +.Ar pw +option of the +.Ar crypto +configuration command specifies the read +password for previously encrypted local files. +This must match the local password used by this program. +If not specified, the host name is used. +Thus, if files are generated by this program without password, +they can be read back by +.Ar ntpd +without password but only on the same host. +.Pp +Normally, encrypted files for each host are generated by that host and +used only by that host, although exceptions exist as noted later on +this page. +The symmetric keys file, normally called +.Ar ntp.keys , +is usually installed in +.Pa /etc . +Other files and links are usually installed in +.Pa /usr/local/etc , +which is normally in a shared filesystem in +NFS-mounted networks and cannot be changed by shared clients. +The location of the keys directory can be changed by the +.Ar keysdir +configuration command in such cases. +Normally, this is in +.Pa /etc . +.Pp +This program directs commentary and error messages to the standard +error stream +.Ar stderr +and remote files to the standard output stream +.Ar stdout +where they can be piped to other applications or redirected to files. +The names used for generated files and links all begin with the +string +.Ar ntpkey +and include the file type, generating host and filestamp, +as described in the +.Dq Cryptographic Data Files +section below. +.Ss Running the Program +To test and gain experience with Autokey concepts, log in as root and +change to the keys directory, usually +.Pa /usr/local/etc +When run for the first time, or if all files with names beginning with +.Ar ntpkey +have been removed, use the +.Nm +command without arguments to generate a +default RSA host key and matching RSA-MD5 certificate with expiration +date one year hence. +If run again without options, the program uses the +existing keys and parameters and generates only a new certificate with +new expiration date one year hence. +.Pp +Run the command on as many hosts as necessary. +Designate one of them as the trusted host (TH) using +.Nm +with the +.Fl T +option and configure it to synchronize from reliable Internet servers. +Then configure the other hosts to synchronize to the TH directly or +indirectly. +A certificate trail is created when Autokey asks the immediately +ascendant host towards the TH to sign its certificate, which is then +provided to the immediately descendant host on request. +All group hosts should have acyclic certificate trails ending on the TH. +.Pp +The host key is used to encrypt the cookie when required and so must be +RSA type. +By default, the host key is also the sign key used to encrypt +signatures. +A different sign key can be assigned using the +.Fl S +option and this can be either RSA or DSA type. +By default, the signature +message digest type is MD5, but any combination of sign key type and +message digest type supported by the OpenSSL library can be specified +using the +.Fl c +option. +The rules say cryptographic media should be generated with proventic +filestamps, which means the host should already be synchronized before +this program is run. +This of course creates a chicken-and-egg problem +when the host is started for the first time. +Accordingly, the host time +should be set by some other means, such as eyeball-and-wristwatch, at +least so that the certificate lifetime is within the current year. +After that and when the host is synchronized to a proventic source, the +certificate should be re-generated. +.Pp +Additional information on trusted groups and identity schemes is on the +.Dq Autokey Public-Key Authentication +page. + + +.Pp +The +.Xr ntpd 1ntpdmdoc +configuration command +.Ic crypto pw Ar password +specifies the read password for previously encrypted files. +The daemon expires on the spot if the password is missing +or incorrect. +For convenience, if a file has been previously encrypted, +the default read password is the name of the host running +the program. +If the previous write password is specified as the host name, +these files can be read by that host with no explicit password. + +.Pp +File names begin with the prefix +.Cm ntpkey_ +and end with the postfix +.Ar _hostname.filestamp , +where +.Ar hostname +is the owner name, usually the string returned +by the Unix gethostname() routine, and +.Ar filestamp +is the NTP seconds when the file was generated, in decimal digits. +This both guarantees uniqueness and simplifies maintenance +procedures, since all files can be quickly removed +by a +.Ic rm ntpkey\&* +command or all files generated +at a specific time can be removed by a +.Ic rm +.Ar \&*filestamp +command. +To further reduce the risk of misconfiguration, +the first two lines of a file contain the file name +and generation date and time as comments. +.Pp +All files are installed by default in the keys directory +.Pa /usr/local/etc , +which is normally in a shared filesystem +in NFS-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. +.Pp +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. +.Pp +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +.Xr ntpd 1ntpdmdoc +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +.Nm +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +.Ss Running the program +The safest way to run the +.Nm +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +.Pa /usr/local/etc , +then run the program. +When run for the first time, +or if all +.Cm ntpkey +files have been removed, +the program generates a RSA host key file and matching RSA-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. +.Pp +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. +.Pp +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. +.Pp +Running the program as other than root and using the Unix +.Ic su +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +.Cm .rnd +in the user home directory. +However, there should be only one +.Cm .rnd , +most conveniently +in the root directory, so it is convenient to define the +.Cm $RANDFILE +environment variable used by the OpenSSL library as the path to +.Cm /.rnd . +.Pp +Installing the keys as root might not work in NFS-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +.Pa /etc +using the +.Ic keysdir +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. +.Pp +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. + +.Pp +All files are installed by default in the keys directory +.Pa /usr/local/etc , +which is normally in a shared filesystem +in NFS-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. +.Pp +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. +.Pp +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +.Xr ntpd 1ntpdmdoc +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +.Nm +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +.Ss Running the program +The safest way to run the +.Nm +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +.Pa /usr/local/etc , +then run the program. +When run for the first time, +or if all +.Cm ntpkey +files have been removed, +the program generates a RSA host key file and matching RSA-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. +.Pp +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. +.Pp +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. +.Pp +Running the program as other than root and using the Unix +.Ic su +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +.Cm .rnd +in the user home directory. +However, there should be only one +.Cm .rnd , +most conveniently +in the root directory, so it is convenient to define the +.Cm $RANDFILE +environment variable used by the OpenSSL library as the path to +.Cm /.rnd . +.Pp +Installing the keys as root might not work in NFS-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +.Pa /etc +using the +.Ic keysdir +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. +.Pp +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +seconds. +seconds. + +s Trusted Hosts and Groups +Each cryptographic configuration involves selection of a signature scheme +and identification scheme, called a cryptotype, +as explained in the +.Sx Authentication Options +section of +.Xr ntp.conf 5 . +The default cryptotype uses RSA encryption, MD5 message digest +and TC identification. +First, configure a NTP subnet including one or more low-stratum +trusted hosts from which all other hosts derive synchronization +directly or indirectly. +Trusted hosts have trusted certificates; +all other hosts have nontrusted certificates. +These hosts will automatically and dynamically build authoritative +certificate trails to one or more trusted hosts. +A trusted group is the set of all hosts that have, directly or indirectly, +a certificate trail ending at a trusted host. +The trail is defined by static configuration file entries +or dynamic means described on the +.Sx Automatic NTP Configuration Options +section of +.Xr ntp.conf 5 . +.Pp +On each trusted host as root, change to the keys directory. +To insure a fresh fileset, remove all +.Cm ntpkey +files. +Then run +.Nm +.Fl T +to generate keys and a trusted certificate. +On all other hosts do the same, but leave off the +.Fl T +flag to generate keys and nontrusted certificates. +When complete, start the NTP daemons beginning at the lowest stratum +and working up the tree. +It may take some time for Autokey to instantiate the certificate trails +throughout the subnet, but setting up the environment is completely automatic. +.Pp +If it is necessary to use a different sign key or different digest/signature +scheme than the default, run +.Nm +with the +.Fl S Ar type +option, where +.Ar type +is either +.Cm RSA +or +.Cm DSA . +The most often need to do this is when a DSA-signed certificate is used. +If it is necessary to use a different certificate scheme than the default, +run +.Nm +with the +.Fl c Ar scheme +option and selected +.Ar scheme +as needed. +f +.Nm +is run again without these options, it generates a new certificate +using the same scheme and sign key. +.Pp +After setting up the environment it is advisable to update certificates +from time to time, if only to extend the validity interval. +Simply run +.Nm +with the same flags as before to generate new certificates +using existing keys. +However, if the host or sign key is changed, +.Xr ntpd 1ntpdmdoc +should be restarted. +When +.Xr ntpd 1ntpdmdoc +is restarted, it loads any new files and restarts the protocol. +Other dependent hosts will continue as usual until signatures are refreshed, +at which time the protocol is restarted. +.Ss Identity Schemes +As mentioned on the Autonomous Authentication page, +the default TC identity scheme is vulnerable to a middleman attack. +However, there are more secure identity schemes available, +including PC, IFF, GQ and MV described on the +.Qq Identification Schemes +page +(maybe available at +.Li http://www.eecis.udel.edu/%7emills/keygen.html ) . +These schemes are based on a TA, one or more trusted hosts +and some number of nontrusted hosts. +Trusted hosts prove identity using values provided by the TA, +while the remaining hosts prove identity using values provided +by a trusted host and certificate trails that end on that host. +The name of a trusted host is also the name of its sugroup +and also the subject and issuer name on its trusted certificate. +The TA is not necessarily a trusted host in this sense, but often is. +.Pp +In some schemes there are separate keys for servers and clients. +A server can also be a client of another server, +but a client can never be a server for another client. +In general, trusted hosts and nontrusted hosts that operate +as both server and client have parameter files that contain +both server and client keys. +Hosts that operate +only as clients have key files that contain only client keys. +.Pp +The PC scheme supports only one trusted host in the group. +On trusted host alice run +.Nm +.Fl P +.Fl p Ar password +to generate the host key file +.Pa ntpkey_RSAkey_ Ns Ar alice.filestamp +and trusted private certificate file +.Pa ntpkey_RSA-MD5_cert_ Ns Ar alice.filestamp . +Copy both files to all group hosts; +they replace the files which would be generated in other schemes. +On each host bob install a soft link from the generic name +.Pa ntpkey_host_ Ns Ar bob +to the host key file and soft link +.Pa ntpkey_cert_ Ns Ar bob +to the private certificate file. +Note the generic links are on bob, but point to files generated +by trusted host alice. +In this scheme it is not possible to refresh +either the keys or certificates without copying them +to all other hosts in the group. +.Pp +For the IFF scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host in the group, +generate the IFF parameter file. +On trusted host alice run +.Nm +.Fl T +.Fl I +.Fl p Ar password +to produce her parameter file +.Pa ntpkey_IFFpar_ Ns Ar alice.filestamp , +which includes both server and client keys. +Copy this file to all group hosts that operate as both servers +and clients and install a soft link from the generic +.Pa ntpkey_iff_ Ns Ar alice +to this file. +If there are no hosts restricted to operate only as clients, +there is nothing further to do. +As the IFF scheme is independent +of keys and certificates, these files can be refreshed as needed. +.Pp +If a rogue client has the parameter file, it could masquerade +as a legitimate server and present a middleman threat. +To eliminate this threat, the client keys can be extracted +from the parameter file and distributed to all restricted clients. +After generating the parameter file, on alice run +.Nm +.Fl e +and pipe the output to a file or mail program. +Copy or mail this file to all restricted clients. +On these clients install a soft link from the generic +.Pa ntpkey_iff_ Ns Ar alice +to this file. +To further protect the integrity of the keys, +each file can be encrypted with a secret password. +.Pp +For the GQ scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host +in the group, generate the IFF parameter file. +On trusted host alice run +.Nm +.Fl T +.Fl G +.Fl p Ar password +to produce her parameter file +.Pa ntpkey_GQpar_ Ns Ar alice.filestamp , +which includes both server and client keys. +Copy this file to all group hosts and install a soft link +from the generic +.Pa ntpkey_gq_ Ns Ar alice +to this file. +In addition, on each host bob install a soft link +from generic +.Pa ntpkey_gq_ Ns Ar bob +to this file. +As the GQ scheme updates the GQ parameters file and certificate +at the same time, keys and certificates can be regenerated as needed. +.Pp +For the MV scheme, proceed as in the TC scheme to generate keys +and certificates for all group hosts. +For illustration assume trish is the TA, alice one of several trusted hosts +and bob one of her clients. +On TA trish run +.Nm +.Fl V Ar n +.Fl p Ar password , +where +.Ar n +is the number of revokable keys (typically 5) to produce +the parameter file +.Pa ntpkeys_MVpar_ Ns Ar trish.filestamp +and client key files +.Pa ntpkeys_MVkeyd_ Ns Ar trish.filestamp +where +.Ar d +is the key number (0 \&< +.Ar d +\&< +.Ar n ) . +Copy the parameter file to alice and install a soft link +from the generic +.Pa ntpkey_mv_ Ns Ar alice +to this file. +Copy one of the client key files to alice for later distribution +to her clients. +It doesn't matter which client key file goes to alice, +since they all work the same way. +Alice copies the client key file to all of her cliens. +On client bob install a soft link from generic +.Pa ntpkey_mvkey_ Ns Ar bob +to the client key file. +As the MV scheme is independent of keys and certificates, +these files can be refreshed as needed. +.Ss Command Line Options +.Bl -tag -width indent +.It Fl c Ar scheme +Select certificate message digest/signature encryption scheme. +The +.Ar scheme +can be one of the following: +. Cm RSA-MD2 , RSA-MD5 , RSA-SHA , RSA-SHA1 , RSA-MDC2 , RSA-RIPEMD160 , DSA-SHA , +or +.Cm DSA-SHA1 . +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. +The default without this option is +.Cm RSA-MD5 . +.It Fl d +Enable debugging. +This option displays the cryptographic data produced in eye-friendly billboards. +.It Fl e +Write the IFF client keys to the standard output. +This is intended for automatic key distribution by mail. +.It Fl G +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +.It Fl g +Generate keys for the GQ identification scheme +using the existing GQ parameters. +If the GQ parameters do not yet exist, create them first. +.It Fl H +Generate new host keys, obsoleting any that may exist. +.It Fl I +Generate parameters for the IFF identification scheme, +obsoleting any that may exist. +.It Fl i Ar name +Set the suject name to +.Ar name . +This is used as the subject field in certificates +and in the file name for host and sign keys. +.It Fl M +Generate MD5 keys, obsoleting any that may exist. +.It Fl P +Generate a private certificate. +By default, the program generates public certificates. +.It Fl p Ar password +Encrypt generated files containing private data with +.Ar password +and the DES-CBC algorithm. +.It Fl q +Set the password for reading files to password. +.It Fl S Oo Cm RSA | DSA Oc +Generate a new sign key of the designated type, +obsoleting any that may exist. +By default, the program uses the host key as the sign key. +.It Fl s Ar name +Set the issuer name to +.Ar name . +This is used for the issuer field in certificates +and in the file name for identity files. +.It Fl T +Generate a trusted certificate. +By default, the program generates a non-trusted certificate. +.It Fl V Ar nkeys +Generate parameters and keys for the Mu-Varadharajan (MV) identification scheme. +.El +.Ss Random Seed File +All cryptographically sound key generation schemes must have means +to randomize the entropy seed used to initialize +the internal pseudo-random number generator used +by the library routines. +The OpenSSL library uses a designated random seed file for this purpose. +The file must be available when starting the NTP daemon and +.Nm +program. +If a site supports OpenSSL or its companion OpenSSH, +it is very likely that means to do this are already available. +.Pp +It is important to understand that entropy must be evolved +for each generation, for otherwise the random number sequence +would be predictable. +Various means dependent on external events, such as keystroke intervals, +can be used to do this and some systems have built-in entropy sources. +Suitable means are described in the OpenSSL software documentation, +but are outside the scope of this page. +.Pp +The entropy seed used by the OpenSSL library is contained in a file, +usually called +.Cm .rnd , +which must be available when starting the NTP daemon +or the +.Nm +program. +The NTP daemon will first look for the file +using the path specified by the +.Ic randfile +subcommand of the +.Ic crypto +configuration command. +If not specified in this way, or when starting the +.Nm +program, +the OpenSSL library will look for the file using the path specified +by the +.Ev RANDFILE +environment variable in the user home directory, +whether root or some other user. +If the +.Ev RANDFILE +environment variable is not present, +the library will look for the +.Cm .rnd +file in the user home directory. +If the file is not available or cannot be written, +the daemon exits with a message to the system log and the program +exits with a suitable error message. +.Ss Cryptographic Data Files +All other file formats begin with two lines. +The first contains the file name, including the generated host name +and filestamp. +The second contains the datestamp in conventional Unix date format. +Lines beginning with # are considered comments and ignored by the +.Nm +program and +.Xr ntpd 1ntpdmdoc +daemon. +Cryptographic values are encoded first using ASN.1 rules, +then encrypted if necessary, and finally written PEM-encoded +printable ASCII format preceded and followed by MIME content identifier lines. +.Pp +The format of the symmetric keys file is somewhat different +than the other files in the interest of backward compatibility. +Since DES-CBC is deprecated in NTPv4, the only key format of interest +is MD5 alphanumeric strings. +Following hte heard the keys are +entered one per line in the format +.D1 Ar keyno type key +where +.Ar keyno +is a positive integer in the range 1-65,535, +.Ar type +is the string MD5 defining the key format and +.Ar key +is the key itself, +which is a printable ASCII string 16 characters or less in length. +Each character is chosen from the 93 printable characters +in the range 0x21 through 0x7f excluding space and the +.Ql # +character. +.Pp +Note that the keys used by the +.Xr ntpq 1ntpqmdoc +and +.Xr ntpdc 1ntpdcmdoc +programs +are checked against passwords requested by the programs +and entered by hand, so it is generally appropriate to specify these keys +in human readable ASCII format. +.Pp +The +.Nm +program generates a MD5 symmetric keys file +.Pa ntpkey_MD5key_ Ns Ar hostname.filestamp . +Since the file contains private shared keys, +it should be visible only to root and distributed by secure means +to other subnet hosts. +The NTP daemon loads the file +.Pa ntp.keys , +so +.Nm +installs a soft link from this name to the generated file. +Subsequently, similar soft links must be installed by manual +or automated means on the other subnet hosts. +While this file is not used with the Autokey Version 2 protocol, +it is needed to authenticate some remote configuration commands +used by the +.Xr ntpq 1ntpqmdoc +and +.Xr ntpdc 1ntpdcmdoc +utilities. + _END_PROG_MDOC_DESCRIP; +}; + +doc-section = { + ds-type = 'USAGE'; + ds-format = 'mdoc'; + ds-text = <<- _END_MDOC_USAGE +The +.Fl p Ar password +option specifies the write password and +.Fl q Ar password +option the read password for previously encrypted files. +The +.Nm +program prompts for the password if it reads an encrypted file +and the password is missing or incorrect. +If an encrypted file is read successfully and +no write password is specified, the read password is used +as the write password by default. + _END_MDOC_USAGE; +}; + +doc-section = { + ds-type = 'NOTES'; + ds-format = 'mdoc'; + ds-text = <<- _END_MDOC_NOTES +Portions of this document came from FreeBSD. + _END_MDOC_NOTES; +}; + +doc-section = { + ds-type = 'BUGS'; + ds-format = 'mdoc'; + ds-text = <<- _END_MDOC_BUGS +It can take quite a while to generate some cryptographic values, +from one to several minutes with modern architectures +such as UltraSPARC and up to tens of minutes to an hour +with older architectures such as SPARC IPC. +.Pp +Please report bugs to http://bugs.ntp.org . + _END_MDOC_BUGS; +}; diff --git a/util/ntp-keygen-opts.h b/util/ntp-keygen-opts.h new file mode 100644 index 0000000..48a9998 --- /dev/null +++ b/util/ntp-keygen-opts.h @@ -0,0 +1,386 @@ +/* + * EDIT THIS FILE WITH CAUTION (ntp-keygen-opts.h) + * + * It has been AutoGen-ed December 2, 2014 at 08:58:31 AM by AutoGen 5.18.5pre4 + * From the definitions ntp-keygen-opts.def + * and the template file options + * + * Generated from AutoOpts 41:0:16 templates. + * + * AutoOpts is a copyrighted work. This header file is not encumbered + * by AutoOpts licensing, but is provided under the licensing terms chosen + * by the ntp-keygen author or copyright holder. AutoOpts is + * licensed under the terms of the LGPL. The redistributable library + * (``libopts'') is licensed under the terms of either the LGPL or, at the + * users discretion, the BSD license. See the AutoOpts and/or libopts sources + * for details. + * + * The ntp-keygen program is copyrighted and licensed + * under the following terms: + * + * Copyright (C) 1970-2014 The University of Delaware, all rights reserved. + * This is free software. It is licensed for use, modification and + * redistribution under the terms of the NTP License, copies of which + * can be seen at: + * <http://ntp.org/license> + * <http://opensource.org/licenses/ntp-license.php> + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appears in all copies and that + * both the copyright notice and this permission notice appear in + * supporting documentation, and that the name The University of Delaware not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The University of Delaware makes no + * representations about the suitability this software for any purpose. It + * is provided "as is" without express or implied warranty. + */ +/** + * This file contains the programmatic interface to the Automated + * Options generated for the ntp-keygen program. + * These macros are documented in the AutoGen info file in the + * "AutoOpts" chapter. Please refer to that doc for usage help. + */ +#ifndef AUTOOPTS_NTP_KEYGEN_OPTS_H_GUARD +#define AUTOOPTS_NTP_KEYGEN_OPTS_H_GUARD 1 +#include "config.h" +#include <autoopts/options.h> + +/** + * Ensure that the library used for compiling this generated header is at + * least as new as the version current when the header template was released + * (not counting patch version increments). Also ensure that the oldest + * tolerable version is at least as old as what was current when the header + * template was released. + */ +#define AO_TEMPLATE_VERSION 167936 +#if (AO_TEMPLATE_VERSION < OPTIONS_MINIMUM_VERSION) \ + || (AO_TEMPLATE_VERSION > OPTIONS_STRUCT_VERSION) +# error option template version mismatches autoopts/options.h header + Choke Me. +#endif + +/** + * Enumeration of each option type for ntp-keygen + */ +typedef enum { + INDEX_OPT_IMBITS = 0, + INDEX_OPT_CERTIFICATE = 1, + INDEX_OPT_CIPHER = 2, + INDEX_OPT_DEBUG_LEVEL = 3, + INDEX_OPT_SET_DEBUG_LEVEL = 4, + INDEX_OPT_ID_KEY = 5, + INDEX_OPT_GQ_PARAMS = 6, + INDEX_OPT_HOST_KEY = 7, + INDEX_OPT_IFFKEY = 8, + INDEX_OPT_IDENT = 9, + INDEX_OPT_LIFETIME = 10, + INDEX_OPT_MD5KEY = 11, + INDEX_OPT_MODULUS = 12, + INDEX_OPT_PVT_CERT = 13, + INDEX_OPT_PASSWORD = 14, + INDEX_OPT_EXPORT_PASSWD = 15, + INDEX_OPT_SIGN_KEY = 16, + INDEX_OPT_SUBJECT_NAME = 17, + INDEX_OPT_TRUSTED_CERT = 18, + INDEX_OPT_MV_PARAMS = 19, + INDEX_OPT_MV_KEYS = 20, + INDEX_OPT_VERSION = 21, + INDEX_OPT_HELP = 22, + INDEX_OPT_MORE_HELP = 23, + INDEX_OPT_SAVE_OPTS = 24, + INDEX_OPT_LOAD_OPTS = 25 +} teOptIndex; +/** count of all options for ntp-keygen */ +#define OPTION_CT 26 +/** ntp-keygen version */ +#define NTP_KEYGEN_VERSION "4.2.7p482" +/** Full ntp-keygen version text */ +#define NTP_KEYGEN_FULL_VERSION "ntp-keygen (ntp) 4.2.7p482" + +/** + * Interface defines for all options. Replace "n" with the UPPER_CASED + * option name (as in the teOptIndex enumeration above). + * e.g. HAVE_OPT(IMBITS) + */ +#define DESC(n) (ntp_keygenOptions.pOptDesc[INDEX_OPT_## n]) +/** 'true' if an option has been specified in any way */ +#define HAVE_OPT(n) (! UNUSED_OPT(& DESC(n))) +/** The string argument to an option. The argument type must be \"string\". */ +#define OPT_ARG(n) (DESC(n).optArg.argString) +/** Mask the option state revealing how an option was specified. + * It will be one and only one of \a OPTST_SET, \a OPTST_PRESET, + * \a OPTST_DEFINED, \a OPTST_RESET or zero. + */ +#define STATE_OPT(n) (DESC(n).fOptState & OPTST_SET_MASK) +/** Count of option's occurrances *on the command line*. */ +#define COUNT_OPT(n) (DESC(n).optOccCt) +/** mask of \a OPTST_SET and \a OPTST_DEFINED. */ +#define ISSEL_OPT(n) (SELECTED_OPT(&DESC(n))) +/** 'true' if \a HAVE_OPT would yield 'false'. */ +#define ISUNUSED_OPT(n) (UNUSED_OPT(& DESC(n))) +/** 'true' if OPTST_DISABLED bit not set. */ +#define ENABLED_OPT(n) (! DISABLED_OPT(& DESC(n))) +/** number of stacked option arguments. + * Valid only for stacked option arguments. */ +#define STACKCT_OPT(n) (((tArgList*)(DESC(n).optCookie))->useCt) +/** stacked argument vector. + * Valid only for stacked option arguments. */ +#define STACKLST_OPT(n) (((tArgList*)(DESC(n).optCookie))->apzArgs) +/** Reset an option. */ +#define CLEAR_OPT(n) STMTS( \ + DESC(n).fOptState &= OPTST_PERSISTENT_MASK; \ + if ((DESC(n).fOptState & OPTST_INITENABLED) == 0) \ + DESC(n).fOptState |= OPTST_DISABLED; \ + DESC(n).optCookie = NULL ) +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/** + * Enumeration of ntp-keygen exit codes + */ +typedef enum { + NTP_KEYGEN_EXIT_SUCCESS = 0, + NTP_KEYGEN_EXIT_FAILURE = 1, + NTP_KEYGEN_EXIT_USAGE_ERROR = 64, + NTP_KEYGEN_EXIT_NO_CONFIG_INPUT = 66, + NTP_KEYGEN_EXIT_LIBOPTS_FAILURE = 70 +} ntp_keygen_exit_code_t; +/** @} */ +/** + * Make sure there are no #define name conflicts with the option names + */ +#ifndef NO_OPTION_NAME_WARNINGS +# ifdef IMBITS +# warning undefining IMBITS due to option name conflict +# undef IMBITS +# endif +# ifdef CERTIFICATE +# warning undefining CERTIFICATE due to option name conflict +# undef CERTIFICATE +# endif +# ifdef CIPHER +# warning undefining CIPHER due to option name conflict +# undef CIPHER +# endif +# ifdef DEBUG_LEVEL +# warning undefining DEBUG_LEVEL due to option name conflict +# undef DEBUG_LEVEL +# endif +# ifdef SET_DEBUG_LEVEL +# warning undefining SET_DEBUG_LEVEL due to option name conflict +# undef SET_DEBUG_LEVEL +# endif +# ifdef ID_KEY +# warning undefining ID_KEY due to option name conflict +# undef ID_KEY +# endif +# ifdef GQ_PARAMS +# warning undefining GQ_PARAMS due to option name conflict +# undef GQ_PARAMS +# endif +# ifdef HOST_KEY +# warning undefining HOST_KEY due to option name conflict +# undef HOST_KEY +# endif +# ifdef IFFKEY +# warning undefining IFFKEY due to option name conflict +# undef IFFKEY +# endif +# ifdef IDENT +# warning undefining IDENT due to option name conflict +# undef IDENT +# endif +# ifdef LIFETIME +# warning undefining LIFETIME due to option name conflict +# undef LIFETIME +# endif +# ifdef MD5KEY +# warning undefining MD5KEY due to option name conflict +# undef MD5KEY +# endif +# ifdef MODULUS +# warning undefining MODULUS due to option name conflict +# undef MODULUS +# endif +# ifdef PVT_CERT +# warning undefining PVT_CERT due to option name conflict +# undef PVT_CERT +# endif +# ifdef PASSWORD +# warning undefining PASSWORD due to option name conflict +# undef PASSWORD +# endif +# ifdef EXPORT_PASSWD +# warning undefining EXPORT_PASSWD due to option name conflict +# undef EXPORT_PASSWD +# endif +# ifdef SIGN_KEY +# warning undefining SIGN_KEY due to option name conflict +# undef SIGN_KEY +# endif +# ifdef SUBJECT_NAME +# warning undefining SUBJECT_NAME due to option name conflict +# undef SUBJECT_NAME +# endif +# ifdef TRUSTED_CERT +# warning undefining TRUSTED_CERT due to option name conflict +# undef TRUSTED_CERT +# endif +# ifdef MV_PARAMS +# warning undefining MV_PARAMS due to option name conflict +# undef MV_PARAMS +# endif +# ifdef MV_KEYS +# warning undefining MV_KEYS due to option name conflict +# undef MV_KEYS +# endif +#else /* NO_OPTION_NAME_WARNINGS */ +# undef IMBITS +# undef CERTIFICATE +# undef CIPHER +# undef DEBUG_LEVEL +# undef SET_DEBUG_LEVEL +# undef ID_KEY +# undef GQ_PARAMS +# undef HOST_KEY +# undef IFFKEY +# undef IDENT +# undef LIFETIME +# undef MD5KEY +# undef MODULUS +# undef PVT_CERT +# undef PASSWORD +# undef EXPORT_PASSWD +# undef SIGN_KEY +# undef SUBJECT_NAME +# undef TRUSTED_CERT +# undef MV_PARAMS +# undef MV_KEYS +#endif /* NO_OPTION_NAME_WARNINGS */ + +/** + * Interface defines for specific options. + * @{ + */ +#define VALUE_OPT_IMBITS 'b' +#ifdef AUTOKEY +#define OPT_VALUE_IMBITS (DESC(IMBITS).optArg.argInt) +#endif /* AUTOKEY */ +#define VALUE_OPT_CERTIFICATE 'c' +#define VALUE_OPT_CIPHER 'C' +#define VALUE_OPT_DEBUG_LEVEL 'd' +#define VALUE_OPT_SET_DEBUG_LEVEL 'D' + +#define OPT_VALUE_SET_DEBUG_LEVEL (DESC(SET_DEBUG_LEVEL).optArg.argInt) +#define VALUE_OPT_ID_KEY 'e' +#define VALUE_OPT_GQ_PARAMS 'G' +#define VALUE_OPT_HOST_KEY 'H' +#define VALUE_OPT_IFFKEY 'I' +#define VALUE_OPT_IDENT 'i' +#define VALUE_OPT_LIFETIME 'l' +#ifdef AUTOKEY +#define OPT_VALUE_LIFETIME (DESC(LIFETIME).optArg.argInt) +#endif /* AUTOKEY */ +#define VALUE_OPT_MD5KEY 'M' +#define VALUE_OPT_MODULUS 'm' +#ifdef AUTOKEY +#define OPT_VALUE_MODULUS (DESC(MODULUS).optArg.argInt) +#endif /* AUTOKEY */ +#define VALUE_OPT_PVT_CERT 'P' +#define VALUE_OPT_PASSWORD 'p' +#define VALUE_OPT_EXPORT_PASSWD 'q' +#define VALUE_OPT_SIGN_KEY 'S' +#define VALUE_OPT_SUBJECT_NAME 's' +#define VALUE_OPT_TRUSTED_CERT 'T' +#define VALUE_OPT_MV_PARAMS 'V' +#ifdef AUTOKEY +#define OPT_VALUE_MV_PARAMS (DESC(MV_PARAMS).optArg.argInt) +#endif /* AUTOKEY */ +#define VALUE_OPT_MV_KEYS 'v' +#ifdef AUTOKEY +#define OPT_VALUE_MV_KEYS (DESC(MV_KEYS).optArg.argInt) +#endif /* AUTOKEY */ +/** option flag (value) for help-value option */ +#define VALUE_OPT_HELP '?' +/** option flag (value) for more-help-value option */ +#define VALUE_OPT_MORE_HELP '!' +/** option flag (value) for version-value option */ +#define VALUE_OPT_VERSION 0x1001 +/** option flag (value) for save-opts-value option */ +#define VALUE_OPT_SAVE_OPTS '>' +/** option flag (value) for load-opts-value option */ +#define VALUE_OPT_LOAD_OPTS '<' +#define SET_OPT_SAVE_OPTS(a) STMTS( \ + DESC(SAVE_OPTS).fOptState &= OPTST_PERSISTENT_MASK; \ + DESC(SAVE_OPTS).fOptState |= OPTST_SET; \ + DESC(SAVE_OPTS).optArg.argString = (char const*)(a)) +/* + * Interface defines not associated with particular options + */ +#define ERRSKIP_OPTERR STMTS(ntp_keygenOptions.fOptSet &= ~OPTPROC_ERRSTOP) +#define ERRSTOP_OPTERR STMTS(ntp_keygenOptions.fOptSet |= OPTPROC_ERRSTOP) +#define RESTART_OPT(n) STMTS( \ + ntp_keygenOptions.curOptIdx = (n); \ + ntp_keygenOptions.pzCurOpt = NULL ) +#define START_OPT RESTART_OPT(1) +#define USAGE(c) (*ntp_keygenOptions.pUsageProc)(&ntp_keygenOptions, c) + +#ifdef __cplusplus +extern "C" { +#endif + + +/* * * * * * + * + * Declare the ntp-keygen option descriptor. + */ +extern tOptions ntp_keygenOptions; + +#if defined(ENABLE_NLS) +# ifndef _ +# include <stdio.h> +# ifndef HAVE_GETTEXT + extern char * gettext(char const *); +# else +# include <libintl.h> +# endif + +# ifndef ATTRIBUTE_FORMAT_ARG +# define ATTRIBUTE_FORMAT_ARG(_a) +# endif + +static inline char* aoGetsText(char const* pz) ATTRIBUTE_FORMAT_ARG(1); +static inline char* aoGetsText(char const* pz) { + if (pz == NULL) return NULL; + return (char*)gettext(pz); +} +# define _(s) aoGetsText(s) +# endif /* _() */ + +# define OPT_NO_XLAT_CFG_NAMES STMTS(ntp_keygenOptions.fOptSet |= \ + OPTPROC_NXLAT_OPT_CFG;) +# define OPT_NO_XLAT_OPT_NAMES STMTS(ntp_keygenOptions.fOptSet |= \ + OPTPROC_NXLAT_OPT|OPTPROC_NXLAT_OPT_CFG;) + +# define OPT_XLAT_CFG_NAMES STMTS(ntp_keygenOptions.fOptSet &= \ + ~(OPTPROC_NXLAT_OPT|OPTPROC_NXLAT_OPT_CFG);) +# define OPT_XLAT_OPT_NAMES STMTS(ntp_keygenOptions.fOptSet &= \ + ~OPTPROC_NXLAT_OPT;) + +#else /* ENABLE_NLS */ +# define OPT_NO_XLAT_CFG_NAMES +# define OPT_NO_XLAT_OPT_NAMES + +# define OPT_XLAT_CFG_NAMES +# define OPT_XLAT_OPT_NAMES + +# ifndef _ +# define _(_s) _s +# endif +#endif /* ENABLE_NLS */ + +#ifdef __cplusplus +} +#endif +#endif /* AUTOOPTS_NTP_KEYGEN_OPTS_H_GUARD */ + +/* ntp-keygen-opts.h ends here */ diff --git a/util/ntp-keygen.1ntp-keygenman b/util/ntp-keygen.1ntp-keygenman new file mode 100644 index 0000000..28dc6ad --- /dev/null +++ b/util/ntp-keygen.1ntp-keygenman @@ -0,0 +1,1221 @@ +.de1 NOP +. it 1 an-trap +. if \\n[.$] \,\\$*\/ +.. +.ie t \ +.ds B-Font [CB] +.ds I-Font [CI] +.ds R-Font [CR] +.el \ +.ds B-Font B +.ds I-Font I +.ds R-Font R +.TH ntp-keygen 1ntp-keygenman "02 Dec 2014" "ntp (4.2.7p482)" "User Commands" +.\" +.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-znaynR/ag-LnaqmR) +.\" +.\" It has been AutoGen-ed December 2, 2014 at 08:58:44 AM by AutoGen 5.18.5pre4 +.\" From the definitions ntp-keygen-opts.def +.\" and the template file agman-cmd.tpl +.SH NAME +\f\*[B-Font]ntp-keygen\fP +\- Create a NTP host key +.SH SYNOPSIS +\f\*[B-Font]ntp-keygen\fP +.\" Mixture of short (flag) options and long options +[\f\*[B-Font]\-flags\f[]] +[\f\*[B-Font]\-flag\f[] [\f\*[I-Font]value\f[]]] +[\f\*[B-Font]\-\-option-name\f[][[=| ]\f\*[I-Font]value\f[]]] +.sp \n(Ppu +.ne 2 + +All arguments must be options. +.sp \n(Ppu +.ne 2 + +.SH DESCRIPTION +This program generates cryptographic data files used by the NTPv4 +authentication and identification schemes. +It generates MD5 key files used in symmetric key cryptography. +In addition, if the OpenSSL software library has been installed, +it generates keys, certificate and identity files used in public key +cryptography. +These files are used for cookie encryption, +digital signature and challenge/response identification algorithms +compatible with the Internet standard security infrastructure. +.sp \n(Ppu +.ne 2 + +All files are in PEM-encoded printable ASCII format, +so they can be embedded as MIME attachments in mail to other sites +and certificate authorities. +By default, files are not encrypted. +.sp \n(Ppu +.ne 2 + +When used to generate message digest keys, the program produces a file +containing ten pseudo-random printable ASCII strings suitable for the +MD5 message digest algorithm included in the distribution. +If the OpenSSL library is installed, it produces an additional ten +hex-encoded random bit strings suitable for the SHA1 and other message +digest algorithms. +The message digest keys file must be distributed and stored +using secure means beyond the scope of NTP itself. +Besides the keys used for ordinary NTP associations, additional keys +can be defined as passwords for the +\fCntpq\fR(1ntpqmdoc)\f[] +and +\fCntpdc\fR(1ntpdcmdoc)\f[] +utility programs. +.sp \n(Ppu +.ne 2 + +The remaining generated files are compatible with other OpenSSL +applications and other Public Key Infrastructure (PKI) resources. +Certificates generated by this program are compatible with extant +industry practice, although some users might find the interpretation of +X509v3 extension fields somewhat liberal. +However, the identity keys are probably not compatible with anything +other than Autokey. +.sp \n(Ppu +.ne 2 + +Some files used by this program are encrypted using a private password. +The +\f\*[B-Font]\-p\f[] +option specifies the password for local encrypted files and the +\f\*[B-Font]\-q\f[] +option the password for encrypted files sent to remote sites. +If no password is specified, the host name returned by the Unix +\fBgethostname\fR()\f[] +function, normally the DNS name of the host is used. +.sp \n(Ppu +.ne 2 + +The +\f\*[I-Font]pw\f[] +option of the +\f\*[I-Font]crypto\f[] +configuration command specifies the read +password for previously encrypted local files. +This must match the local password used by this program. +If not specified, the host name is used. +Thus, if files are generated by this program without password, +they can be read back by +\f\*[I-Font]ntpd\f[] +without password but only on the same host. +.sp \n(Ppu +.ne 2 + +Normally, encrypted files for each host are generated by that host and +used only by that host, although exceptions exist as noted later on +this page. +The symmetric keys file, normally called +\f\*[I-Font]ntp.keys\f[], +is usually installed in +\fI/etc\f[]. +Other files and links are usually installed in +\fI/usr/local/etc\f[], +which is normally in a shared filesystem in +NFS-mounted networks and cannot be changed by shared clients. +The location of the keys directory can be changed by the +\f\*[I-Font]keysdir\f[] +configuration command in such cases. +Normally, this is in +\fI/etc\f[]. +.sp \n(Ppu +.ne 2 + +This program directs commentary and error messages to the standard +error stream +\f\*[I-Font]stderr\f[] +and remote files to the standard output stream +\f\*[I-Font]stdout\f[] +where they can be piped to other applications or redirected to files. +The names used for generated files and links all begin with the +string +\f\*[I-Font]ntpkey\f[] +and include the file type, generating host and filestamp, +as described in the +\*[Lq]Cryptographic Data Files\*[Rq] +section below. +.SS Running the Program +To test and gain experience with Autokey concepts, log in as root and +change to the keys directory, usually +\fI/usr/local/etc\f[] +When run for the first time, or if all files with names beginning with +\f\*[I-Font]ntpkey\f[] +have been removed, use the +\f\*[B-Font]ntp-keygen\fP +command without arguments to generate a +default RSA host key and matching RSA-MD5 certificate with expiration +date one year hence. +If run again without options, the program uses the +existing keys and parameters and generates only a new certificate with +new expiration date one year hence. +.sp \n(Ppu +.ne 2 + +Run the command on as many hosts as necessary. +Designate one of them as the trusted host (TH) using +\f\*[B-Font]ntp-keygen\fP +with the +\f\*[B-Font]\-T\f[] +option and configure it to synchronize from reliable Internet servers. +Then configure the other hosts to synchronize to the TH directly or +indirectly. +A certificate trail is created when Autokey asks the immediately +ascendant host towards the TH to sign its certificate, which is then +provided to the immediately descendant host on request. +All group hosts should have acyclic certificate trails ending on the TH. +.sp \n(Ppu +.ne 2 + +The host key is used to encrypt the cookie when required and so must be +RSA type. +By default, the host key is also the sign key used to encrypt +signatures. +A different sign key can be assigned using the +\f\*[B-Font]\-S\f[] +option and this can be either RSA or DSA type. +By default, the signature +message digest type is MD5, but any combination of sign key type and +message digest type supported by the OpenSSL library can be specified +using the +\f\*[B-Font]\-c\f[] +option. +The rules say cryptographic media should be generated with proventic +filestamps, which means the host should already be synchronized before +this program is run. +This of course creates a chicken-and-egg problem +when the host is started for the first time. +Accordingly, the host time +should be set by some other means, such as eyeball-and-wristwatch, at +least so that the certificate lifetime is within the current year. +After that and when the host is synchronized to a proventic source, the +certificate should be re-generated. +.sp \n(Ppu +.ne 2 + +Additional information on trusted groups and identity schemes is on the +\*[Lq]Autokey Public-Key Authentication\*[Rq] +page. +.sp \n(Ppu +.ne 2 + +The +\fCntpd\fR(1ntpdmdoc)\f[] +configuration command +\f\*[B-Font]crypto\f[] \f\*[B-Font]pw\f[] \f\*[I-Font]password\f[] +specifies the read password for previously encrypted files. +The daemon expires on the spot if the password is missing +or incorrect. +For convenience, if a file has been previously encrypted, +the default read password is the name of the host running +the program. +If the previous write password is specified as the host name, +these files can be read by that host with no explicit password. +.sp \n(Ppu +.ne 2 + +File names begin with the prefix +\f\*[B-Font]ntpkey_\f[] +and end with the postfix +\f\*[I-Font]_hostname.filestamp\f[], +where +\f\*[I-Font]hostname\f[] +is the owner name, usually the string returned +by the Unix gethostname() routine, and +\f\*[I-Font]filestamp\f[] +is the NTP seconds when the file was generated, in decimal digits. +This both guarantees uniqueness and simplifies maintenance +procedures, since all files can be quickly removed +by a +\f\*[B-Font]rm\f[] \f\*[B-Font]ntpkey\&*\f[] +command or all files generated +at a specific time can be removed by a +\f\*[B-Font]rm\f[] +\f\*[I-Font]\&*filestamp\f[] +command. +To further reduce the risk of misconfiguration, +the first two lines of a file contain the file name +and generation date and time as comments. +.sp \n(Ppu +.ne 2 + +All files are installed by default in the keys directory +\fI/usr/local/etc\f[], +which is normally in a shared filesystem +in NFS-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. +.sp \n(Ppu +.ne 2 + +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. +.sp \n(Ppu +.ne 2 + +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +\fCntpd\fR(1ntpdmdoc)\f[] +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +\f\*[B-Font]ntp-keygen\fP +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +.SS Running the program +The safest way to run the +\f\*[B-Font]ntp-keygen\fP +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +\fI/usr/local/etc\f[], +then run the program. +When run for the first time, +or if all +\f\*[B-Font]ntpkey\f[] +files have been removed, +the program generates a RSA host key file and matching RSA-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. +.sp \n(Ppu +.ne 2 + +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. +.sp \n(Ppu +.ne 2 + +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. +.sp \n(Ppu +.ne 2 + +Running the program as other than root and using the Unix +\f\*[B-Font]su\f[] +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +\f\*[B-Font].rnd\f[] +in the user home directory. +However, there should be only one +\f\*[B-Font].rnd\f[], +most conveniently +in the root directory, so it is convenient to define the +\f\*[B-Font]$RANDFILE\f[] +environment variable used by the OpenSSL library as the path to +\f\*[B-Font]/.rnd\f[]. +.sp \n(Ppu +.ne 2 + +Installing the keys as root might not work in NFS-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +\fI/etc\f[] +using the +\f\*[B-Font]keysdir\f[] +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. +.sp \n(Ppu +.ne 2 + +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +.sp \n(Ppu +.ne 2 + +All files are installed by default in the keys directory +\fI/usr/local/etc\f[], +which is normally in a shared filesystem +in NFS-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. +.sp \n(Ppu +.ne 2 + +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. +.sp \n(Ppu +.ne 2 + +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +\fCntpd\fR(1ntpdmdoc)\f[] +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +\f\*[B-Font]ntp-keygen\fP +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +.SS Running the program +The safest way to run the +\f\*[B-Font]ntp-keygen\fP +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +\fI/usr/local/etc\f[], +then run the program. +When run for the first time, +or if all +\f\*[B-Font]ntpkey\f[] +files have been removed, +the program generates a RSA host key file and matching RSA-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. +.sp \n(Ppu +.ne 2 + +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. +.sp \n(Ppu +.ne 2 + +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. +.sp \n(Ppu +.ne 2 + +Running the program as other than root and using the Unix +\f\*[B-Font]su\f[] +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +\f\*[B-Font].rnd\f[] +in the user home directory. +However, there should be only one +\f\*[B-Font].rnd\f[], +most conveniently +in the root directory, so it is convenient to define the +\f\*[B-Font]$RANDFILE\f[] +environment variable used by the OpenSSL library as the path to +\f\*[B-Font]/.rnd\f[]. +.sp \n(Ppu +.ne 2 + +Installing the keys as root might not work in NFS-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +\fI/etc\f[] +using the +\f\*[B-Font]keysdir\f[] +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. +.sp \n(Ppu +.ne 2 + +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +seconds. +seconds. +s Trusted Hosts and Groups +Each cryptographic configuration involves selection of a signature scheme +and identification scheme, called a cryptotype, +as explained in the +\fIAuthentication\f[] \fIOptions\f[] +section of +\fCntp.conf\fR(5)\f[]. +The default cryptotype uses RSA encryption, MD5 message digest +and TC identification. +First, configure a NTP subnet including one or more low-stratum +trusted hosts from which all other hosts derive synchronization +directly or indirectly. +Trusted hosts have trusted certificates; +all other hosts have nontrusted certificates. +These hosts will automatically and dynamically build authoritative +certificate trails to one or more trusted hosts. +A trusted group is the set of all hosts that have, directly or indirectly, +a certificate trail ending at a trusted host. +The trail is defined by static configuration file entries +or dynamic means described on the +\fIAutomatic\f[] \fINTP\f[] \fIConfiguration\f[] \fIOptions\f[] +section of +\fCntp.conf\fR(5)\f[]. +.sp \n(Ppu +.ne 2 + +On each trusted host as root, change to the keys directory. +To insure a fresh fileset, remove all +\f\*[B-Font]ntpkey\f[] +files. +Then run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-T\f[] +to generate keys and a trusted certificate. +On all other hosts do the same, but leave off the +\f\*[B-Font]\-T\f[] +flag to generate keys and nontrusted certificates. +When complete, start the NTP daemons beginning at the lowest stratum +and working up the tree. +It may take some time for Autokey to instantiate the certificate trails +throughout the subnet, but setting up the environment is completely automatic. +.sp \n(Ppu +.ne 2 + +If it is necessary to use a different sign key or different digest/signature +scheme than the default, run +\f\*[B-Font]ntp-keygen\fP +with the +\f\*[B-Font]\-S\f[] \f\*[I-Font]type\f[] +option, where +\f\*[I-Font]type\f[] +is either +\f\*[B-Font]RSA\f[] +or +\f\*[B-Font]DSA\f[]. +The most often need to do this is when a DSA-signed certificate is used. +If it is necessary to use a different certificate scheme than the default, +run +\f\*[B-Font]ntp-keygen\fP +with the +\f\*[B-Font]\-c\f[] \f\*[I-Font]scheme\f[] +option and selected +\f\*[I-Font]scheme\f[] +as needed. +f +\f\*[B-Font]ntp-keygen\fP +is run again without these options, it generates a new certificate +using the same scheme and sign key. +.sp \n(Ppu +.ne 2 + +After setting up the environment it is advisable to update certificates +from time to time, if only to extend the validity interval. +Simply run +\f\*[B-Font]ntp-keygen\fP +with the same flags as before to generate new certificates +using existing keys. +However, if the host or sign key is changed, +\fCntpd\fR(1ntpdmdoc)\f[] +should be restarted. +When +\fCntpd\fR(1ntpdmdoc)\f[] +is restarted, it loads any new files and restarts the protocol. +Other dependent hosts will continue as usual until signatures are refreshed, +at which time the protocol is restarted. +.SS Identity Schemes +As mentioned on the Autonomous Authentication page, +the default TC identity scheme is vulnerable to a middleman attack. +However, there are more secure identity schemes available, +including PC, IFF, GQ and MV described on the +"Identification Schemes" +page +(maybe available at +\f[C]http://www.eecis.udel.edu/%7emills/keygen.html\f[]). +These schemes are based on a TA, one or more trusted hosts +and some number of nontrusted hosts. +Trusted hosts prove identity using values provided by the TA, +while the remaining hosts prove identity using values provided +by a trusted host and certificate trails that end on that host. +The name of a trusted host is also the name of its sugroup +and also the subject and issuer name on its trusted certificate. +The TA is not necessarily a trusted host in this sense, but often is. +.sp \n(Ppu +.ne 2 + +In some schemes there are separate keys for servers and clients. +A server can also be a client of another server, +but a client can never be a server for another client. +In general, trusted hosts and nontrusted hosts that operate +as both server and client have parameter files that contain +both server and client keys. +Hosts that operate +only as clients have key files that contain only client keys. +.sp \n(Ppu +.ne 2 + +The PC scheme supports only one trusted host in the group. +On trusted host alice run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-P\f[] +\f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[] +to generate the host key file +\fIntpkey_RSAkey_\f[]\f\*[I-Font]alice.filestamp\f[] +and trusted private certificate file +\fIntpkey_RSA-MD5_cert_\f[]\f\*[I-Font]alice.filestamp\f[]. +Copy both files to all group hosts; +they replace the files which would be generated in other schemes. +On each host bob install a soft link from the generic name +\fIntpkey_host_\f[]\f\*[I-Font]bob\f[] +to the host key file and soft link +\fIntpkey_cert_\f[]\f\*[I-Font]bob\f[] +to the private certificate file. +Note the generic links are on bob, but point to files generated +by trusted host alice. +In this scheme it is not possible to refresh +either the keys or certificates without copying them +to all other hosts in the group. +.sp \n(Ppu +.ne 2 + +For the IFF scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host in the group, +generate the IFF parameter file. +On trusted host alice run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-T\f[] +\f\*[B-Font]\-I\f[] +\f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[] +to produce her parameter file +\fIntpkey_IFFpar_\f[]\f\*[I-Font]alice.filestamp\f[], +which includes both server and client keys. +Copy this file to all group hosts that operate as both servers +and clients and install a soft link from the generic +\fIntpkey_iff_\f[]\f\*[I-Font]alice\f[] +to this file. +If there are no hosts restricted to operate only as clients, +there is nothing further to do. +As the IFF scheme is independent +of keys and certificates, these files can be refreshed as needed. +.sp \n(Ppu +.ne 2 + +If a rogue client has the parameter file, it could masquerade +as a legitimate server and present a middleman threat. +To eliminate this threat, the client keys can be extracted +from the parameter file and distributed to all restricted clients. +After generating the parameter file, on alice run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-e\f[] +and pipe the output to a file or mail program. +Copy or mail this file to all restricted clients. +On these clients install a soft link from the generic +\fIntpkey_iff_\f[]\f\*[I-Font]alice\f[] +to this file. +To further protect the integrity of the keys, +each file can be encrypted with a secret password. +.sp \n(Ppu +.ne 2 + +For the GQ scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host +in the group, generate the IFF parameter file. +On trusted host alice run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-T\f[] +\f\*[B-Font]\-G\f[] +\f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[] +to produce her parameter file +\fIntpkey_GQpar_\f[]\f\*[I-Font]alice.filestamp\f[], +which includes both server and client keys. +Copy this file to all group hosts and install a soft link +from the generic +\fIntpkey_gq_\f[]\f\*[I-Font]alice\f[] +to this file. +In addition, on each host bob install a soft link +from generic +\fIntpkey_gq_\f[]\f\*[I-Font]bob\f[] +to this file. +As the GQ scheme updates the GQ parameters file and certificate +at the same time, keys and certificates can be regenerated as needed. +.sp \n(Ppu +.ne 2 + +For the MV scheme, proceed as in the TC scheme to generate keys +and certificates for all group hosts. +For illustration assume trish is the TA, alice one of several trusted hosts +and bob one of her clients. +On TA trish run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-V\f[] \f\*[I-Font]n\f[] +\f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[], +where +\f\*[I-Font]n\f[] +is the number of revokable keys (typically 5) to produce +the parameter file +\fIntpkeys_MVpar_\f[]\f\*[I-Font]trish.filestamp\f[] +and client key files +\fIntpkeys_MVkeyd_\f[]\f\*[I-Font]trish.filestamp\f[] +where +\f\*[I-Font]d\f[] +is the key number (0 \&< +\f\*[I-Font]d\f[] +\&< +\f\*[I-Font]n\f[]). +Copy the parameter file to alice and install a soft link +from the generic +\fIntpkey_mv_\f[]\f\*[I-Font]alice\f[] +to this file. +Copy one of the client key files to alice for later distribution +to her clients. +It doesn't matter which client key file goes to alice, +since they all work the same way. +Alice copies the client key file to all of her cliens. +On client bob install a soft link from generic +\fIntpkey_mvkey_\f[]\f\*[I-Font]bob\f[] +to the client key file. +As the MV scheme is independent of keys and certificates, +these files can be refreshed as needed. +.SS Command Line Options +.TP 7 +.NOP \f\*[B-Font]\-c\f[] \f\*[I-Font]scheme\f[] +Select certificate message digest/signature encryption scheme. +The +\f\*[I-Font]scheme\f[] +can be one of the following: +. Cm RSA-MD2 , RSA-MD5 , RSA-SHA , RSA-SHA1 , RSA-MDC2 , RSA-RIPEMD160 , DSA-SHA , +or +\f\*[B-Font]DSA-SHA1\f[]. +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. +The default without this option is +\f\*[B-Font]RSA-MD5\f[]. +.TP 7 +.NOP \f\*[B-Font]\-d\f[] +Enable debugging. +This option displays the cryptographic data produced in eye-friendly billboards. +.TP 7 +.NOP \f\*[B-Font]\-e\f[] +Write the IFF client keys to the standard output. +This is intended for automatic key distribution by mail. +.TP 7 +.NOP \f\*[B-Font]\-G\f[] +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +.TP 7 +.NOP \f\*[B-Font]\-g\f[] +Generate keys for the GQ identification scheme +using the existing GQ parameters. +If the GQ parameters do not yet exist, create them first. +.TP 7 +.NOP \f\*[B-Font]\-H\f[] +Generate new host keys, obsoleting any that may exist. +.TP 7 +.NOP \f\*[B-Font]\-I\f[] +Generate parameters for the IFF identification scheme, +obsoleting any that may exist. +.TP 7 +.NOP \f\*[B-Font]\-i\f[] \f\*[I-Font]name\f[] +Set the suject name to +\f\*[I-Font]name\f[]. +This is used as the subject field in certificates +and in the file name for host and sign keys. +.TP 7 +.NOP \f\*[B-Font]\-M\f[] +Generate MD5 keys, obsoleting any that may exist. +.TP 7 +.NOP \f\*[B-Font]\-P\f[] +Generate a private certificate. +By default, the program generates public certificates. +.TP 7 +.NOP \f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[] +Encrypt generated files containing private data with +\f\*[I-Font]password\f[] +and the DES-CBC algorithm. +.TP 7 +.NOP \f\*[B-Font]\-q\f[] +Set the password for reading files to password. +.TP 7 +.NOP \f\*[B-Font]\-S\f[] [\f\*[B-Font]RSA\f[] | \f\*[B-Font]DSA\f[]] +Generate a new sign key of the designated type, +obsoleting any that may exist. +By default, the program uses the host key as the sign key. +.TP 7 +.NOP \f\*[B-Font]\-s\f[] \f\*[I-Font]name\f[] +Set the issuer name to +\f\*[I-Font]name\f[]. +This is used for the issuer field in certificates +and in the file name for identity files. +.TP 7 +.NOP \f\*[B-Font]\-T\f[] +Generate a trusted certificate. +By default, the program generates a non-trusted certificate. +.TP 7 +.NOP \f\*[B-Font]\-V\f[] \f\*[I-Font]nkeys\f[] +Generate parameters and keys for the Mu-Varadharajan (MV) identification scheme. +.PP +.SS Random Seed File +All cryptographically sound key generation schemes must have means +to randomize the entropy seed used to initialize +the internal pseudo-random number generator used +by the library routines. +The OpenSSL library uses a designated random seed file for this purpose. +The file must be available when starting the NTP daemon and +\f\*[B-Font]ntp-keygen\fP +program. +If a site supports OpenSSL or its companion OpenSSH, +it is very likely that means to do this are already available. +.sp \n(Ppu +.ne 2 + +It is important to understand that entropy must be evolved +for each generation, for otherwise the random number sequence +would be predictable. +Various means dependent on external events, such as keystroke intervals, +can be used to do this and some systems have built-in entropy sources. +Suitable means are described in the OpenSSL software documentation, +but are outside the scope of this page. +.sp \n(Ppu +.ne 2 + +The entropy seed used by the OpenSSL library is contained in a file, +usually called +\f\*[B-Font].rnd\f[], +which must be available when starting the NTP daemon +or the +\f\*[B-Font]ntp-keygen\fP +program. +The NTP daemon will first look for the file +using the path specified by the +\f\*[B-Font]randfile\f[] +subcommand of the +\f\*[B-Font]crypto\f[] +configuration command. +If not specified in this way, or when starting the +\f\*[B-Font]ntp-keygen\fP +program, +the OpenSSL library will look for the file using the path specified +by the +RANDFILE +environment variable in the user home directory, +whether root or some other user. +If the +RANDFILE +environment variable is not present, +the library will look for the +\f\*[B-Font].rnd\f[] +file in the user home directory. +If the file is not available or cannot be written, +the daemon exits with a message to the system log and the program +exits with a suitable error message. +.SS Cryptographic Data Files +All other file formats begin with two lines. +The first contains the file name, including the generated host name +and filestamp. +The second contains the datestamp in conventional Unix date format. +Lines beginning with # are considered comments and ignored by the +\f\*[B-Font]ntp-keygen\fP +program and +\fCntpd\fR(1ntpdmdoc)\f[] +daemon. +Cryptographic values are encoded first using ASN.1 rules, +then encrypted if necessary, and finally written PEM-encoded +printable ASCII format preceded and followed by MIME content identifier lines. +.sp \n(Ppu +.ne 2 + +The format of the symmetric keys file is somewhat different +than the other files in the interest of backward compatibility. +Since DES-CBC is deprecated in NTPv4, the only key format of interest +is MD5 alphanumeric strings. +Following hte heard the keys are +entered one per line in the format +.in +4 +\f\*[I-Font]keyno\f[] \f\*[I-Font]type\f[] \f\*[I-Font]key\f[] +.in -4 +where +\f\*[I-Font]keyno\f[] +is a positive integer in the range 1-65,535, +\f\*[I-Font]type\f[] +is the string MD5 defining the key format and +\f\*[I-Font]key\f[] +is the key itself, +which is a printable ASCII string 16 characters or less in length. +Each character is chosen from the 93 printable characters +in the range 0x21 through 0x7f excluding space and the +\[oq]#\[cq] +character. +.sp \n(Ppu +.ne 2 + +Note that the keys used by the +\fCntpq\fR(1ntpqmdoc)\f[] +and +\fCntpdc\fR(1ntpdcmdoc)\f[] +programs +are checked against passwords requested by the programs +and entered by hand, so it is generally appropriate to specify these keys +in human readable ASCII format. +.sp \n(Ppu +.ne 2 + +The +\f\*[B-Font]ntp-keygen\fP +program generates a MD5 symmetric keys file +\fIntpkey_MD5key_\f[]\f\*[I-Font]hostname.filestamp\f[]. +Since the file contains private shared keys, +it should be visible only to root and distributed by secure means +to other subnet hosts. +The NTP daemon loads the file +\fIntp.keys\f[], +so +\f\*[B-Font]ntp-keygen\fP +installs a soft link from this name to the generated file. +Subsequently, similar soft links must be installed by manual +or automated means on the other subnet hosts. +While this file is not used with the Autokey Version 2 protocol, +it is needed to authenticate some remote configuration commands +used by the +\fCntpq\fR(1ntpqmdoc)\f[] +and +\fCntpdc\fR(1ntpdcmdoc)\f[] +utilities. +.SH "OPTIONS" +.TP +.NOP \f\*[B-Font]\-b\f[] \f\*[I-Font]imbits\f[], \f\*[B-Font]\-\-imbits\f[]=\f\*[I-Font]imbits\f[] +identity modulus bits. +This option takes an integer number as its argument. +The value of +\f\*[I-Font]imbits\f[] +is constrained to being: +.in +4 +.nf +.na +in the range 256 through 2048 +.fi +.in -4 +.sp +The number of bits in the identity modulus. The default is 256. +.TP +.NOP \f\*[B-Font]\-c\f[] \f\*[I-Font]scheme\f[], \f\*[B-Font]\-\-certificate\f[]=\f\*[I-Font]scheme\f[] +certificate scheme. +.sp +scheme is one of +RSA-MD2, RSA-MD5, RSA-SHA, RSA-SHA1, RSA-MDC2, RSA-RIPEMD160, +DSA-SHA, or DSA-SHA1. +.sp +Select the certificate message digest/signature encryption scheme. +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. The default without +this option is RSA-MD5. +.TP +.NOP \f\*[B-Font]\-C\f[] \f\*[I-Font]cipher\f[], \f\*[B-Font]\-\-cipher\f[]=\f\*[I-Font]cipher\f[] +privatekey cipher. +.sp +Select the cipher which is used to encrypt the files containing +private keys. The default is three-key triple DES in CBC mode, +equivalent to "@code{-C des-ede3-cbc". The openssl tool lists ciphers +available in "\fBopenssl \-h\fP" output. +.TP +.NOP \f\*[B-Font]\-d\f[], \f\*[B-Font]\-\-debug\-level\f[] +Increase debug verbosity level. +This option may appear an unlimited number of times. +.sp +.TP +.NOP \f\*[B-Font]\-D\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-set\-debug\-level\f[]=\f\*[I-Font]number\f[] +Set the debug verbosity level. +This option may appear an unlimited number of times. +This option takes an integer number as its argument. +.sp +.TP +.NOP \f\*[B-Font]\-e\f[], \f\*[B-Font]\-\-id\-key\f[] +Write IFF or GQ identity keys. +.sp +Write the IFF or GQ client keys to the standard output. This is +intended for automatic key distribution by mail. +.TP +.NOP \f\*[B-Font]\-G\f[], \f\*[B-Font]\-\-gq\-params\f[] +Generate GQ parameters and keys. +.sp +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +.TP +.NOP \f\*[B-Font]\-H\f[], \f\*[B-Font]\-\-host\-key\f[] +generate RSA host key. +.sp +Generate new host keys, obsoleting any that may exist. +.TP +.NOP \f\*[B-Font]\-I\f[], \f\*[B-Font]\-\-iffkey\f[] +generate IFF parameters. +.sp +Generate parameters for the IFF identification scheme, obsoleting +any that may exist. +.TP +.NOP \f\*[B-Font]\-i\f[] \f\*[I-Font]group\f[], \f\*[B-Font]\-\-ident\f[]=\f\*[I-Font]group\f[] +set Autokey group name. +.sp +Set the optional Autokey group name to name. This is used in +the file name of IFF, GQ, and MV client parameters files. In +that role, the default is the host name if this option is not +provided. The group name, if specified using \fB-i/--ident\fP or +using \fB-s/--subject-name\fP following an '\fB@\fP' character, +is also a part of the self-signed host certificate's subject and +issuer names in the form \fBhost@group\fP and should match the +'\fBcrypto ident\fP' or '\fBserver ident\fP' configuration in +\fBntpd\fP's configuration file. +.TP +.NOP \f\*[B-Font]\-l\f[] \f\*[I-Font]lifetime\f[], \f\*[B-Font]\-\-lifetime\f[]=\f\*[I-Font]lifetime\f[] +set certificate lifetime. +This option takes an integer number as its argument. +.sp +Set the certificate expiration to lifetime days from now. +.TP +.NOP \f\*[B-Font]\-M\f[], \f\*[B-Font]\-\-md5key\f[] +generate MD5 keys. +.sp +Generate MD5 keys, obsoleting any that may exist. +.TP +.NOP \f\*[B-Font]\-m\f[] \f\*[I-Font]modulus\f[], \f\*[B-Font]\-\-modulus\f[]=\f\*[I-Font]modulus\f[] +modulus. +This option takes an integer number as its argument. +The value of +\f\*[I-Font]modulus\f[] +is constrained to being: +.in +4 +.nf +.na +in the range 256 through 2048 +.fi +.in -4 +.sp +The number of bits in the prime modulus. The default is 512. +.TP +.NOP \f\*[B-Font]\-P\f[], \f\*[B-Font]\-\-pvt\-cert\f[] +generate PC private certificate. +.sp +Generate a private certificate. By default, the program generates +public certificates. +.TP +.NOP \f\*[B-Font]\-p\f[] \f\*[I-Font]passwd\f[], \f\*[B-Font]\-\-password\f[]=\f\*[I-Font]passwd\f[] +local private password. +.sp +Local files containing private data are encrypted with the +DES-CBC algorithm and the specified password. The same password +must be specified to the local ntpd via the "crypto pw password" +configuration command. The default password is the local +hostname. +.TP +.NOP \f\*[B-Font]\-q\f[] \f\*[I-Font]passwd\f[], \f\*[B-Font]\-\-export\-passwd\f[]=\f\*[I-Font]passwd\f[] +export IFF or GQ group keys with password. +.sp +Export IFF or GQ identity group keys to the standard output, +encrypted with the DES-CBC algorithm and the specified password. +The same password must be specified to the remote ntpd via the +"crypto pw password" configuration command. See also the option +--id-key (-e) for unencrypted exports. +.TP +.NOP \f\*[B-Font]\-S\f[] \f\*[I-Font]sign\f[], \f\*[B-Font]\-\-sign\-key\f[]=\f\*[I-Font]sign\f[] +generate sign key (RSA or DSA). +.sp +Generate a new sign key of the designated type, obsoleting any +that may exist. By default, the program uses the host key as the +sign key. +.TP +.NOP \f\*[B-Font]\-s\f[] \f\*[I-Font]host@group\f[], \f\*[B-Font]\-\-subject\-name\f[]=\f\*[I-Font]host@group\f[] +set host and optionally group name. +.sp +Set the Autokey host name, and optionally, group name specified +following an '\fB@\fP' character. The host name is used in the file +name of generated host and signing certificates, without the +group name. The host name, and if provided, group name are used +in \fBhost@group\fP form for the host certificate's subject and issuer +fields. Specifying '\fB-s @group\fP' is allowed, and results in +leaving the host name unchanged while appending \fB@group\fP to the +subject and issuer fields, as with \fB-i group\fP. The group name, or +if not provided, the host name are also used in the file names +of IFF, GQ, and MV client parameter files. +.TP +.NOP \f\*[B-Font]\-T\f[], \f\*[B-Font]\-\-trusted\-cert\f[] +trusted certificate (TC scheme). +.sp +Generate a trusted certificate. By default, the program generates +a non-trusted certificate. +.TP +.NOP \f\*[B-Font]\-V\f[] \f\*[I-Font]num\f[], \f\*[B-Font]\-\-mv\-params\f[]=\f\*[I-Font]num\f[] +generate <num> MV parameters. +This option takes an integer number as its argument. +.sp +Generate parameters and keys for the Mu-Varadharajan (MV) +identification scheme. +.TP +.NOP \f\*[B-Font]\-v\f[] \f\*[I-Font]num\f[], \f\*[B-Font]\-\-mv\-keys\f[]=\f\*[I-Font]num\f[] +update <num> MV keys. +This option takes an integer number as its argument. +.sp +This option has not been fully documented. +.TP +.NOP \f\*[B-Font]\-\&?\f[], \f\*[B-Font]\-\-help\f[] +Display usage information and exit. +.TP +.NOP \f\*[B-Font]\-\&!\f[], \f\*[B-Font]\-\-more-help\f[] +Pass the extended usage information through a pager. +.TP +.NOP \f\*[B-Font]\->\f[] [\f\*[I-Font]cfgfile\f[]], \f\*[B-Font]\-\-save-opts\f[] [=\f\*[I-Font]cfgfile\f[]] +Save the option state to \fIcfgfile\fP. The default is the \fIlast\fP +configuration file listed in the \fBOPTION PRESETS\fP section, below. +The command will exit after updating the config file. +.TP +.NOP \f\*[B-Font]\-<\f[] \f\*[I-Font]cfgfile\f[], \f\*[B-Font]\-\-load-opts\f[]=\f\*[I-Font]cfgfile\f[], \f\*[B-Font]\-\-no-load-opts\f[] +Load options from \fIcfgfile\fP. +The \fIno-load-opts\fP form will disable the loading +of earlier config/rc/ini files. \fI\-\-no-load-opts\fP is handled early, +out of order. +.TP +.NOP \f\*[B-Font]\-\-version\f[] [{\f\*[I-Font]v|c|n\f[]}] +Output version of program and exit. The default mode is `v', a simple +version. The `c' mode will print copyright information and `n' will +print the full copyright notice. +.PP +.SH "OPTION PRESETS" +Any option that is not marked as \fInot presettable\fP may be preset +by loading values from configuration ("RC" or ".INI") file(s) and values from +environment variables named: +.nf + \fBNTP_KEYGEN_<option-name>\fP or \fBNTP_KEYGEN\fP +.fi +.ad +The environmental presets take precedence (are processed later than) +the configuration files. +The \fIhomerc\fP files are "\fI$HOME\fP", and "\fI.\fP". +If any of these are directories, then the file \fI.ntprc\fP +is searched for within those directories. +.SH USAGE +The +\f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[] +option specifies the write password and +\f\*[B-Font]\-q\f[] \f\*[I-Font]password\f[] +option the read password for previously encrypted files. +The +\f\*[B-Font]ntp-keygen\fP +program prompts for the password if it reads an encrypted file +and the password is missing or incorrect. +If an encrypted file is read successfully and +no write password is specified, the read password is used +as the write password by default. +.SH "ENVIRONMENT" +See \fBOPTION PRESETS\fP for configuration environment variables. +.SH "FILES" +See \fBOPTION PRESETS\fP for configuration files. +.SH "EXIT STATUS" +One of the following exit values will be returned: +.TP +.NOP 0 " (EXIT_SUCCESS)" +Successful program execution. +.TP +.NOP 1 " (EXIT_FAILURE)" +The operation failed or the command syntax was not valid. +.TP +.NOP 66 " (EX_NOINPUT)" +A specified configuration file could not be loaded. +.TP +.NOP 70 " (EX_SOFTWARE)" +libopts had an internal operational error. Please report +it to autogen-users@lists.sourceforge.net. Thank you. +.PP +.SH "AUTHORS" +The University of Delaware +.SH "COPYRIGHT" +Copyright (C) 1970-2014 The University of Delaware all rights reserved. +This program is released under the terms of the NTP license, <http://ntp.org/license>. +.SH BUGS +It can take quite a while to generate some cryptographic values, +from one to several minutes with modern architectures +such as UltraSPARC and up to tens of minutes to an hour +with older architectures such as SPARC IPC. +.sp \n(Ppu +.ne 2 + +Please report bugs to http://bugs.ntp.org . +.sp \n(Ppu +.ne 2 + +Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org +.SH NOTES +Portions of this document came from FreeBSD. +.sp \n(Ppu +.ne 2 + +This manual page was \fIAutoGen\fP-erated from the \fBntp-keygen\fP +option definitions. diff --git a/util/ntp-keygen.1ntp-keygenmdoc b/util/ntp-keygen.1ntp-keygenmdoc new file mode 100644 index 0000000..9b3dabb --- /dev/null +++ b/util/ntp-keygen.1ntp-keygenmdoc @@ -0,0 +1,1071 @@ +.Dd December 2 2014 +.Dt NTP_KEYGEN 1ntp-keygenmdoc User Commands +.Os +.\" EDIT THIS FILE WITH CAUTION (ntp-keygen-opts.mdoc) +.\" +.\" It has been AutoGen-ed December 2, 2014 at 08:58:51 AM by AutoGen 5.18.5pre4 +.\" From the definitions ntp-keygen-opts.def +.\" and the template file agmdoc-cmd.tpl +.Sh NAME +.Nm ntp-keygen +.Nd Create a NTP host key +.Sh SYNOPSIS +.Nm +.\" Mixture of short (flag) options and long options +.Op Fl flags +.Op Fl flag Op Ar value +.Op Fl \-option\-name Ns Oo Oo Ns "=| " Oc Ns Ar value Oc +.Pp +All arguments must be options. +.Pp +.Sh DESCRIPTION +This program generates cryptographic data files used by the NTPv4 +authentication and identification schemes. +It generates MD5 key files used in symmetric key cryptography. +In addition, if the OpenSSL software library has been installed, +it generates keys, certificate and identity files used in public key +cryptography. +These files are used for cookie encryption, +digital signature and challenge/response identification algorithms +compatible with the Internet standard security infrastructure. +.Pp +All files are in PEM\-encoded printable ASCII format, +so they can be embedded as MIME attachments in mail to other sites +and certificate authorities. +By default, files are not encrypted. +.Pp +When used to generate message digest keys, the program produces a file +containing ten pseudo\-random printable ASCII strings suitable for the +MD5 message digest algorithm included in the distribution. +If the OpenSSL library is installed, it produces an additional ten +hex\-encoded random bit strings suitable for the SHA1 and other message +digest algorithms. +The message digest keys file must be distributed and stored +using secure means beyond the scope of NTP itself. +Besides the keys used for ordinary NTP associations, additional keys +can be defined as passwords for the +.Xr ntpq 1ntpqmdoc +and +.Xr ntpdc 1ntpdcmdoc +utility programs. +.Pp +The remaining generated files are compatible with other OpenSSL +applications and other Public Key Infrastructure (PKI) resources. +Certificates generated by this program are compatible with extant +industry practice, although some users might find the interpretation of +X509v3 extension fields somewhat liberal. +However, the identity keys are probably not compatible with anything +other than Autokey. +.Pp +Some files used by this program are encrypted using a private password. +The +.Fl p +option specifies the password for local encrypted files and the +.Fl q +option the password for encrypted files sent to remote sites. +If no password is specified, the host name returned by the Unix +.Fn gethostname +function, normally the DNS name of the host is used. +.Pp +The +.Ar pw +option of the +.Ar crypto +configuration command specifies the read +password for previously encrypted local files. +This must match the local password used by this program. +If not specified, the host name is used. +Thus, if files are generated by this program without password, +they can be read back by +.Ar ntpd +without password but only on the same host. +.Pp +Normally, encrypted files for each host are generated by that host and +used only by that host, although exceptions exist as noted later on +this page. +The symmetric keys file, normally called +.Ar ntp.keys , +is usually installed in +.Pa /etc . +Other files and links are usually installed in +.Pa /usr/local/etc , +which is normally in a shared filesystem in +NFS\-mounted networks and cannot be changed by shared clients. +The location of the keys directory can be changed by the +.Ar keysdir +configuration command in such cases. +Normally, this is in +.Pa /etc . +.Pp +This program directs commentary and error messages to the standard +error stream +.Ar stderr +and remote files to the standard output stream +.Ar stdout +where they can be piped to other applications or redirected to files. +The names used for generated files and links all begin with the +string +.Ar ntpkey +and include the file type, generating host and filestamp, +as described in the +.Dq Cryptographic Data Files +section below. +.Ss Running the Program +To test and gain experience with Autokey concepts, log in as root and +change to the keys directory, usually +.Pa /usr/local/etc +When run for the first time, or if all files with names beginning with +.Ar ntpkey +have been removed, use the +.Nm +command without arguments to generate a +default RSA host key and matching RSA\-MD5 certificate with expiration +date one year hence. +If run again without options, the program uses the +existing keys and parameters and generates only a new certificate with +new expiration date one year hence. +.Pp +Run the command on as many hosts as necessary. +Designate one of them as the trusted host (TH) using +.Nm +with the +.Fl T +option and configure it to synchronize from reliable Internet servers. +Then configure the other hosts to synchronize to the TH directly or +indirectly. +A certificate trail is created when Autokey asks the immediately +ascendant host towards the TH to sign its certificate, which is then +provided to the immediately descendant host on request. +All group hosts should have acyclic certificate trails ending on the TH. +.Pp +The host key is used to encrypt the cookie when required and so must be +RSA type. +By default, the host key is also the sign key used to encrypt +signatures. +A different sign key can be assigned using the +.Fl S +option and this can be either RSA or DSA type. +By default, the signature +message digest type is MD5, but any combination of sign key type and +message digest type supported by the OpenSSL library can be specified +using the +.Fl c +option. +The rules say cryptographic media should be generated with proventic +filestamps, which means the host should already be synchronized before +this program is run. +This of course creates a chicken\-and\-egg problem +when the host is started for the first time. +Accordingly, the host time +should be set by some other means, such as eyeball\-and\-wristwatch, at +least so that the certificate lifetime is within the current year. +After that and when the host is synchronized to a proventic source, the +certificate should be re\-generated. +.Pp +Additional information on trusted groups and identity schemes is on the +.Dq Autokey Public\-Key Authentication +page. +.Pp +The +.Xr ntpd 1ntpdmdoc +configuration command +.Ic crypto pw Ar password +specifies the read password for previously encrypted files. +The daemon expires on the spot if the password is missing +or incorrect. +For convenience, if a file has been previously encrypted, +the default read password is the name of the host running +the program. +If the previous write password is specified as the host name, +these files can be read by that host with no explicit password. +.Pp +File names begin with the prefix +.Cm ntpkey_ +and end with the postfix +.Ar _hostname.filestamp , +where +.Ar hostname +is the owner name, usually the string returned +by the Unix gethostname() routine, and +.Ar filestamp +is the NTP seconds when the file was generated, in decimal digits. +This both guarantees uniqueness and simplifies maintenance +procedures, since all files can be quickly removed +by a +.Ic rm ntpkey\&* +command or all files generated +at a specific time can be removed by a +.Ic rm +.Ar \&*filestamp +command. +To further reduce the risk of misconfiguration, +the first two lines of a file contain the file name +and generation date and time as comments. +.Pp +All files are installed by default in the keys directory +.Pa /usr/local/etc , +which is normally in a shared filesystem +in NFS\-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. +.Pp +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write\-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. +.Pp +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +.Xr ntpd 1ntpdmdoc +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +.Nm +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +.Ss Running the program +The safest way to run the +.Nm +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +.Pa /usr/local/etc , +then run the program. +When run for the first time, +or if all +.Cm ntpkey +files have been removed, +the program generates a RSA host key file and matching RSA\-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. +.Pp +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. +.Pp +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. +.Pp +Running the program as other than root and using the Unix +.Ic su +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +.Cm .rnd +in the user home directory. +However, there should be only one +.Cm .rnd , +most conveniently +in the root directory, so it is convenient to define the +.Cm $RANDFILE +environment variable used by the OpenSSL library as the path to +.Cm /.rnd . +.Pp +Installing the keys as root might not work in NFS\-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +.Pa /etc +using the +.Ic keysdir +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. +.Pp +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +.Pp +All files are installed by default in the keys directory +.Pa /usr/local/etc , +which is normally in a shared filesystem +in NFS\-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. +.Pp +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write\-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. +.Pp +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +.Xr ntpd 1ntpdmdoc +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +.Nm +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +.Ss Running the program +The safest way to run the +.Nm +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +.Pa /usr/local/etc , +then run the program. +When run for the first time, +or if all +.Cm ntpkey +files have been removed, +the program generates a RSA host key file and matching RSA\-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. +.Pp +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. +.Pp +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. +.Pp +Running the program as other than root and using the Unix +.Ic su +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +.Cm .rnd +in the user home directory. +However, there should be only one +.Cm .rnd , +most conveniently +in the root directory, so it is convenient to define the +.Cm $RANDFILE +environment variable used by the OpenSSL library as the path to +.Cm /.rnd . +.Pp +Installing the keys as root might not work in NFS\-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +.Pa /etc +using the +.Ic keysdir +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. +.Pp +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +seconds. +seconds. +s Trusted Hosts and Groups +Each cryptographic configuration involves selection of a signature scheme +and identification scheme, called a cryptotype, +as explained in the +.Sx Authentication Options +section of +.Xr ntp.conf 5 . +The default cryptotype uses RSA encryption, MD5 message digest +and TC identification. +First, configure a NTP subnet including one or more low\-stratum +trusted hosts from which all other hosts derive synchronization +directly or indirectly. +Trusted hosts have trusted certificates; +all other hosts have nontrusted certificates. +These hosts will automatically and dynamically build authoritative +certificate trails to one or more trusted hosts. +A trusted group is the set of all hosts that have, directly or indirectly, +a certificate trail ending at a trusted host. +The trail is defined by static configuration file entries +or dynamic means described on the +.Sx Automatic NTP Configuration Options +section of +.Xr ntp.conf 5 . +.Pp +On each trusted host as root, change to the keys directory. +To insure a fresh fileset, remove all +.Cm ntpkey +files. +Then run +.Nm +.Fl T +to generate keys and a trusted certificate. +On all other hosts do the same, but leave off the +.Fl T +flag to generate keys and nontrusted certificates. +When complete, start the NTP daemons beginning at the lowest stratum +and working up the tree. +It may take some time for Autokey to instantiate the certificate trails +throughout the subnet, but setting up the environment is completely automatic. +.Pp +If it is necessary to use a different sign key or different digest/signature +scheme than the default, run +.Nm +with the +.Fl S Ar type +option, where +.Ar type +is either +.Cm RSA +or +.Cm DSA . +The most often need to do this is when a DSA\-signed certificate is used. +If it is necessary to use a different certificate scheme than the default, +run +.Nm +with the +.Fl c Ar scheme +option and selected +.Ar scheme +as needed. +f +.Nm +is run again without these options, it generates a new certificate +using the same scheme and sign key. +.Pp +After setting up the environment it is advisable to update certificates +from time to time, if only to extend the validity interval. +Simply run +.Nm +with the same flags as before to generate new certificates +using existing keys. +However, if the host or sign key is changed, +.Xr ntpd 1ntpdmdoc +should be restarted. +When +.Xr ntpd 1ntpdmdoc +is restarted, it loads any new files and restarts the protocol. +Other dependent hosts will continue as usual until signatures are refreshed, +at which time the protocol is restarted. +.Ss Identity Schemes +As mentioned on the Autonomous Authentication page, +the default TC identity scheme is vulnerable to a middleman attack. +However, there are more secure identity schemes available, +including PC, IFF, GQ and MV described on the +.Qq Identification Schemes +page +(maybe available at +.Li http://www.eecis.udel.edu/%7emills/keygen.html ) . +These schemes are based on a TA, one or more trusted hosts +and some number of nontrusted hosts. +Trusted hosts prove identity using values provided by the TA, +while the remaining hosts prove identity using values provided +by a trusted host and certificate trails that end on that host. +The name of a trusted host is also the name of its sugroup +and also the subject and issuer name on its trusted certificate. +The TA is not necessarily a trusted host in this sense, but often is. +.Pp +In some schemes there are separate keys for servers and clients. +A server can also be a client of another server, +but a client can never be a server for another client. +In general, trusted hosts and nontrusted hosts that operate +as both server and client have parameter files that contain +both server and client keys. +Hosts that operate +only as clients have key files that contain only client keys. +.Pp +The PC scheme supports only one trusted host in the group. +On trusted host alice run +.Nm +.Fl P +.Fl p Ar password +to generate the host key file +.Pa ntpkey_RSAkey_ Ns Ar alice.filestamp +and trusted private certificate file +.Pa ntpkey_RSA\-MD5_cert_ Ns Ar alice.filestamp . +Copy both files to all group hosts; +they replace the files which would be generated in other schemes. +On each host bob install a soft link from the generic name +.Pa ntpkey_host_ Ns Ar bob +to the host key file and soft link +.Pa ntpkey_cert_ Ns Ar bob +to the private certificate file. +Note the generic links are on bob, but point to files generated +by trusted host alice. +In this scheme it is not possible to refresh +either the keys or certificates without copying them +to all other hosts in the group. +.Pp +For the IFF scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host in the group, +generate the IFF parameter file. +On trusted host alice run +.Nm +.Fl T +.Fl I +.Fl p Ar password +to produce her parameter file +.Pa ntpkey_IFFpar_ Ns Ar alice.filestamp , +which includes both server and client keys. +Copy this file to all group hosts that operate as both servers +and clients and install a soft link from the generic +.Pa ntpkey_iff_ Ns Ar alice +to this file. +If there are no hosts restricted to operate only as clients, +there is nothing further to do. +As the IFF scheme is independent +of keys and certificates, these files can be refreshed as needed. +.Pp +If a rogue client has the parameter file, it could masquerade +as a legitimate server and present a middleman threat. +To eliminate this threat, the client keys can be extracted +from the parameter file and distributed to all restricted clients. +After generating the parameter file, on alice run +.Nm +.Fl e +and pipe the output to a file or mail program. +Copy or mail this file to all restricted clients. +On these clients install a soft link from the generic +.Pa ntpkey_iff_ Ns Ar alice +to this file. +To further protect the integrity of the keys, +each file can be encrypted with a secret password. +.Pp +For the GQ scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host +in the group, generate the IFF parameter file. +On trusted host alice run +.Nm +.Fl T +.Fl G +.Fl p Ar password +to produce her parameter file +.Pa ntpkey_GQpar_ Ns Ar alice.filestamp , +which includes both server and client keys. +Copy this file to all group hosts and install a soft link +from the generic +.Pa ntpkey_gq_ Ns Ar alice +to this file. +In addition, on each host bob install a soft link +from generic +.Pa ntpkey_gq_ Ns Ar bob +to this file. +As the GQ scheme updates the GQ parameters file and certificate +at the same time, keys and certificates can be regenerated as needed. +.Pp +For the MV scheme, proceed as in the TC scheme to generate keys +and certificates for all group hosts. +For illustration assume trish is the TA, alice one of several trusted hosts +and bob one of her clients. +On TA trish run +.Nm +.Fl V Ar n +.Fl p Ar password , +where +.Ar n +is the number of revokable keys (typically 5) to produce +the parameter file +.Pa ntpkeys_MVpar_ Ns Ar trish.filestamp +and client key files +.Pa ntpkeys_MVkeyd_ Ns Ar trish.filestamp +where +.Ar d +is the key number (0 \&< +.Ar d +\&< +.Ar n ) . +Copy the parameter file to alice and install a soft link +from the generic +.Pa ntpkey_mv_ Ns Ar alice +to this file. +Copy one of the client key files to alice for later distribution +to her clients. +It doesn't matter which client key file goes to alice, +since they all work the same way. +Alice copies the client key file to all of her cliens. +On client bob install a soft link from generic +.Pa ntpkey_mvkey_ Ns Ar bob +to the client key file. +As the MV scheme is independent of keys and certificates, +these files can be refreshed as needed. +.Ss Command Line Options +.Bl -tag -width indent +.It Fl c Ar scheme +Select certificate message digest/signature encryption scheme. +The +.Ar scheme +can be one of the following: +. Cm RSA\-MD2 , RSA\-MD5 , RSA\-SHA , RSA\-SHA1 , RSA\-MDC2 , RSA\-RIPEMD160 , DSA\-SHA , +or +.Cm DSA\-SHA1 . +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. +The default without this option is +.Cm RSA\-MD5 . +.It Fl d +Enable debugging. +This option displays the cryptographic data produced in eye\-friendly billboards. +.It Fl e +Write the IFF client keys to the standard output. +This is intended for automatic key distribution by mail. +.It Fl G +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +.It Fl g +Generate keys for the GQ identification scheme +using the existing GQ parameters. +If the GQ parameters do not yet exist, create them first. +.It Fl H +Generate new host keys, obsoleting any that may exist. +.It Fl I +Generate parameters for the IFF identification scheme, +obsoleting any that may exist. +.It Fl i Ar name +Set the suject name to +.Ar name . +This is used as the subject field in certificates +and in the file name for host and sign keys. +.It Fl M +Generate MD5 keys, obsoleting any that may exist. +.It Fl P +Generate a private certificate. +By default, the program generates public certificates. +.It Fl p Ar password +Encrypt generated files containing private data with +.Ar password +and the DES\-CBC algorithm. +.It Fl q +Set the password for reading files to password. +.It Fl S Oo Cm RSA | DSA Oc +Generate a new sign key of the designated type, +obsoleting any that may exist. +By default, the program uses the host key as the sign key. +.It Fl s Ar name +Set the issuer name to +.Ar name . +This is used for the issuer field in certificates +and in the file name for identity files. +.It Fl T +Generate a trusted certificate. +By default, the program generates a non\-trusted certificate. +.It Fl V Ar nkeys +Generate parameters and keys for the Mu\-Varadharajan (MV) identification scheme. +.El +.Ss Random Seed File +All cryptographically sound key generation schemes must have means +to randomize the entropy seed used to initialize +the internal pseudo\-random number generator used +by the library routines. +The OpenSSL library uses a designated random seed file for this purpose. +The file must be available when starting the NTP daemon and +.Nm +program. +If a site supports OpenSSL or its companion OpenSSH, +it is very likely that means to do this are already available. +.Pp +It is important to understand that entropy must be evolved +for each generation, for otherwise the random number sequence +would be predictable. +Various means dependent on external events, such as keystroke intervals, +can be used to do this and some systems have built\-in entropy sources. +Suitable means are described in the OpenSSL software documentation, +but are outside the scope of this page. +.Pp +The entropy seed used by the OpenSSL library is contained in a file, +usually called +.Cm .rnd , +which must be available when starting the NTP daemon +or the +.Nm +program. +The NTP daemon will first look for the file +using the path specified by the +.Ic randfile +subcommand of the +.Ic crypto +configuration command. +If not specified in this way, or when starting the +.Nm +program, +the OpenSSL library will look for the file using the path specified +by the +.Ev RANDFILE +environment variable in the user home directory, +whether root or some other user. +If the +.Ev RANDFILE +environment variable is not present, +the library will look for the +.Cm .rnd +file in the user home directory. +If the file is not available or cannot be written, +the daemon exits with a message to the system log and the program +exits with a suitable error message. +.Ss Cryptographic Data Files +All other file formats begin with two lines. +The first contains the file name, including the generated host name +and filestamp. +The second contains the datestamp in conventional Unix date format. +Lines beginning with # are considered comments and ignored by the +.Nm +program and +.Xr ntpd 1ntpdmdoc +daemon. +Cryptographic values are encoded first using ASN.1 rules, +then encrypted if necessary, and finally written PEM\-encoded +printable ASCII format preceded and followed by MIME content identifier lines. +.Pp +The format of the symmetric keys file is somewhat different +than the other files in the interest of backward compatibility. +Since DES\-CBC is deprecated in NTPv4, the only key format of interest +is MD5 alphanumeric strings. +Following hte heard the keys are +entered one per line in the format +.D1 Ar keyno type key +where +.Ar keyno +is a positive integer in the range 1\-65,535, +.Ar type +is the string MD5 defining the key format and +.Ar key +is the key itself, +which is a printable ASCII string 16 characters or less in length. +Each character is chosen from the 93 printable characters +in the range 0x21 through 0x7f excluding space and the +.Ql # +character. +.Pp +Note that the keys used by the +.Xr ntpq 1ntpqmdoc +and +.Xr ntpdc 1ntpdcmdoc +programs +are checked against passwords requested by the programs +and entered by hand, so it is generally appropriate to specify these keys +in human readable ASCII format. +.Pp +The +.Nm +program generates a MD5 symmetric keys file +.Pa ntpkey_MD5key_ Ns Ar hostname.filestamp . +Since the file contains private shared keys, +it should be visible only to root and distributed by secure means +to other subnet hosts. +The NTP daemon loads the file +.Pa ntp.keys , +so +.Nm +installs a soft link from this name to the generated file. +Subsequently, similar soft links must be installed by manual +or automated means on the other subnet hosts. +While this file is not used with the Autokey Version 2 protocol, +it is needed to authenticate some remote configuration commands +used by the +.Xr ntpq 1ntpqmdoc +and +.Xr ntpdc 1ntpdcmdoc +utilities. +.Sh "OPTIONS" +.Bl -tag +.It Fl b Ar imbits , Fl \-imbits Ns = Ns Ar imbits +identity modulus bits. +This option takes an integer number as its argument. +The value of +.Ar imbits +is constrained to being: +.in +4 +.nf +.na +in the range 256 through 2048 +.fi +.in -4 +.sp +The number of bits in the identity modulus. The default is 256. +.It Fl c Ar scheme , Fl \-certificate Ns = Ns Ar scheme +certificate scheme. +.sp +scheme is one of +RSA\-MD2, RSA\-MD5, RSA\-SHA, RSA\-SHA1, RSA\-MDC2, RSA\-RIPEMD160, +DSA\-SHA, or DSA\-SHA1. +.sp +Select the certificate message digest/signature encryption scheme. +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. The default without +this option is RSA\-MD5. +.It Fl C Ar cipher , Fl \-cipher Ns = Ns Ar cipher +privatekey cipher. +.sp +Select the cipher which is used to encrypt the files containing +private keys. The default is three\-key triple DES in CBC mode, +equivalent to "@code{\-C des\-ede3\-cbc". The openssl tool lists ciphers +available in "\fBopenssl \-h\fP" output. +.It Fl d , Fl \-debug\-level +Increase debug verbosity level. +This option may appear an unlimited number of times. +.sp +.It Fl D Ar number , Fl \-set\-debug\-level Ns = Ns Ar number +Set the debug verbosity level. +This option may appear an unlimited number of times. +This option takes an integer number as its argument. +.sp +.It Fl e , Fl \-id\-key +Write IFF or GQ identity keys. +.sp +Write the IFF or GQ client keys to the standard output. This is +intended for automatic key distribution by mail. +.It Fl G , Fl \-gq\-params +Generate GQ parameters and keys. +.sp +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +.It Fl H , Fl \-host\-key +generate RSA host key. +.sp +Generate new host keys, obsoleting any that may exist. +.It Fl I , Fl \-iffkey +generate IFF parameters. +.sp +Generate parameters for the IFF identification scheme, obsoleting +any that may exist. +.It Fl i Ar group , Fl \-ident Ns = Ns Ar group +set Autokey group name. +.sp +Set the optional Autokey group name to name. This is used in +the file name of IFF, GQ, and MV client parameters files. In +that role, the default is the host name if this option is not +provided. The group name, if specified using \fB\-i/\-\-ident\fP or +using \fB\-s/\-\-subject\-name\fP following an '\fB@\fP' character, +is also a part of the self\-signed host certificate's subject and +issuer names in the form \fBhost@group\fP and should match the +\'\fBcrypto ident\fP' or '\fBserver ident\fP' configuration in +\fBntpd\fP's configuration file. +.It Fl l Ar lifetime , Fl \-lifetime Ns = Ns Ar lifetime +set certificate lifetime. +This option takes an integer number as its argument. +.sp +Set the certificate expiration to lifetime days from now. +.It Fl M , Fl \-md5key +generate MD5 keys. +.sp +Generate MD5 keys, obsoleting any that may exist. +.It Fl m Ar modulus , Fl \-modulus Ns = Ns Ar modulus +modulus. +This option takes an integer number as its argument. +The value of +.Ar modulus +is constrained to being: +.in +4 +.nf +.na +in the range 256 through 2048 +.fi +.in -4 +.sp +The number of bits in the prime modulus. The default is 512. +.It Fl P , Fl \-pvt\-cert +generate PC private certificate. +.sp +Generate a private certificate. By default, the program generates +public certificates. +.It Fl p Ar passwd , Fl \-password Ns = Ns Ar passwd +local private password. +.sp +Local files containing private data are encrypted with the +DES\-CBC algorithm and the specified password. The same password +must be specified to the local ntpd via the "crypto pw password" +configuration command. The default password is the local +hostname. +.It Fl q Ar passwd , Fl \-export\-passwd Ns = Ns Ar passwd +export IFF or GQ group keys with password. +.sp +Export IFF or GQ identity group keys to the standard output, +encrypted with the DES\-CBC algorithm and the specified password. +The same password must be specified to the remote ntpd via the +"crypto pw password" configuration command. See also the option +-\-id\-key (\-e) for unencrypted exports. +.It Fl S Ar sign , Fl \-sign\-key Ns = Ns Ar sign +generate sign key (RSA or DSA). +.sp +Generate a new sign key of the designated type, obsoleting any +that may exist. By default, the program uses the host key as the +sign key. +.It Fl s Ar host@group , Fl \-subject\-name Ns = Ns Ar host@group +set host and optionally group name. +.sp +Set the Autokey host name, and optionally, group name specified +following an '\fB@\fP' character. The host name is used in the file +name of generated host and signing certificates, without the +group name. The host name, and if provided, group name are used +in \fBhost@group\fP form for the host certificate's subject and issuer +fields. Specifying '\fB\-s @group\fP' is allowed, and results in +leaving the host name unchanged while appending \fB@group\fP to the +subject and issuer fields, as with \fB\-i group\fP. The group name, or +if not provided, the host name are also used in the file names +of IFF, GQ, and MV client parameter files. +.It Fl T , Fl \-trusted\-cert +trusted certificate (TC scheme). +.sp +Generate a trusted certificate. By default, the program generates +a non\-trusted certificate. +.It Fl V Ar num , Fl \-mv\-params Ns = Ns Ar num +generate <num> MV parameters. +This option takes an integer number as its argument. +.sp +Generate parameters and keys for the Mu\-Varadharajan (MV) +identification scheme. +.It Fl v Ar num , Fl \-mv\-keys Ns = Ns Ar num +update <num> MV keys. +This option takes an integer number as its argument. +.sp +This option has not been fully documented. +.It Fl \&? , Fl \-help +Display usage information and exit. +.It Fl \&! , Fl \-more\-help +Pass the extended usage information through a pager. +.It Fl > Oo Ar cfgfile Oc , Fl \-save\-opts Oo Ns = Ns Ar cfgfile Oc +Save the option state to \fIcfgfile\fP. The default is the \fIlast\fP +configuration file listed in the \fBOPTION PRESETS\fP section, below. +The command will exit after updating the config file. +.It Fl < Ar cfgfile , Fl \-load\-opts Ns = Ns Ar cfgfile , Fl \-no\-load\-opts +Load options from \fIcfgfile\fP. +The \fIno\-load\-opts\fP form will disable the loading +of earlier config/rc/ini files. \fI\-\-no\-load\-opts\fP is handled early, +out of order. +.It Fl \-version Op Brq Ar v|c|n +Output version of program and exit. The default mode is `v', a simple +version. The `c' mode will print copyright information and `n' will +print the full copyright notice. +.El +.Sh "OPTION PRESETS" +Any option that is not marked as \fInot presettable\fP may be preset +by loading values from configuration ("RC" or ".INI") file(s) and values from +environment variables named: +.nf + \fBNTP_KEYGEN_<option\-name>\fP or \fBNTP_KEYGEN\fP +.fi +.ad +The environmental presets take precedence (are processed later than) +the configuration files. +The \fIhomerc\fP files are "\fI$HOME\fP", and "\fI.\fP". +If any of these are directories, then the file \fI.ntprc\fP +is searched for within those directories. +.Sh USAGE +The +.Fl p Ar password +option specifies the write password and +.Fl q Ar password +option the read password for previously encrypted files. +The +.Nm +program prompts for the password if it reads an encrypted file +and the password is missing or incorrect. +If an encrypted file is read successfully and +no write password is specified, the read password is used +as the write password by default. +.Sh "ENVIRONMENT" +See \fBOPTION PRESETS\fP for configuration environment variables. +.Sh "FILES" +See \fBOPTION PRESETS\fP for configuration files. +.Sh "EXIT STATUS" +One of the following exit values will be returned: +.Bl -tag +.It 0 " (EXIT_SUCCESS)" +Successful program execution. +.It 1 " (EXIT_FAILURE)" +The operation failed or the command syntax was not valid. +.It 66 " (EX_NOINPUT)" +A specified configuration file could not be loaded. +.It 70 " (EX_SOFTWARE)" +libopts had an internal operational error. Please report +it to autogen\-users@lists.sourceforge.net. Thank you. +.El +.Sh "AUTHORS" +The University of Delaware +.Sh "COPYRIGHT" +Copyright (C) 1970\-2014 The University of Delaware all rights reserved. +This program is released under the terms of the NTP license, <http://ntp.org/license>. +.Sh BUGS +It can take quite a while to generate some cryptographic values, +from one to several minutes with modern architectures +such as UltraSPARC and up to tens of minutes to an hour +with older architectures such as SPARC IPC. +.Pp +Please report bugs to http://bugs.ntp.org . +.Pp +Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org +.Sh NOTES +Portions of this document came from FreeBSD. +.Pp +This manual page was \fIAutoGen\fP\-erated from the \fBntp\-keygen\fP +option definitions. diff --git a/util/ntp-keygen.c b/util/ntp-keygen.c new file mode 100644 index 0000000..d55a357 --- /dev/null +++ b/util/ntp-keygen.c @@ -0,0 +1,2181 @@ +/* + * Program to generate cryptographic keys for ntp clients and servers + * + * This program generates password encrypted data files for use with the + * Autokey security protocol and Network Time Protocol Version 4. Files + * are prefixed with a header giving the name and date of creation + * followed by a type-specific descriptive label and PEM-encoded data + * structure compatible with programs of the OpenSSL library. + * + * All file names are like "ntpkey_<type>_<hostname>.<filestamp>", where + * <type> is the file type, <hostname> the generating host name and + * <filestamp> the generation time in NTP seconds. The NTP programs + * expect generic names such as "ntpkey_<type>_whimsy.udel.edu" with the + * association maintained by soft links. Following is a list of file + * types; the first line is the file name and the second link name. + * + * ntpkey_MD5key_<hostname>.<filestamp> + * MD5 (128-bit) keys used to compute message digests in symmetric + * key cryptography + * + * ntpkey_RSAhost_<hostname>.<filestamp> + * ntpkey_host_<hostname> + * RSA private/public host key pair used for public key signatures + * + * ntpkey_RSAsign_<hostname>.<filestamp> + * ntpkey_sign_<hostname> + * RSA private/public sign key pair used for public key signatures + * + * ntpkey_DSAsign_<hostname>.<filestamp> + * ntpkey_sign_<hostname> + * DSA Private/public sign key pair used for public key signatures + * + * Available digest/signature schemes + * + * RSA: RSA-MD2, RSA-MD5, RSA-SHA, RSA-SHA1, RSA-MDC2, EVP-RIPEMD160 + * DSA: DSA-SHA, DSA-SHA1 + * + * ntpkey_XXXcert_<hostname>.<filestamp> + * ntpkey_cert_<hostname> + * X509v3 certificate using RSA or DSA public keys and signatures. + * XXX is a code identifying the message digest and signature + * encryption algorithm + * + * Identity schemes. The key type par is used for the challenge; the key + * type key is used for the response. + * + * ntpkey_IFFkey_<groupname>.<filestamp> + * ntpkey_iffkey_<groupname> + * Schnorr (IFF) identity parameters and keys + * + * ntpkey_GQkey_<groupname>.<filestamp>, + * ntpkey_gqkey_<groupname> + * Guillou-Quisquater (GQ) identity parameters and keys + * + * ntpkey_MVkeyX_<groupname>.<filestamp>, + * ntpkey_mvkey_<groupname> + * Mu-Varadharajan (MV) identity parameters and keys + * + * Note: Once in a while because of some statistical fluke this program + * fails to generate and verify some cryptographic data, as indicated by + * exit status -1. In this case simply run the program again. If the + * program does complete with exit code 0, the data are correct as + * verified. + * + * These cryptographic routines are characterized by the prime modulus + * size in bits. The default value of 512 bits is a compromise between + * cryptographic strength and computing time and is ordinarily + * considered adequate for this application. The routines have been + * tested with sizes of 256, 512, 1024 and 2048 bits. Not all message + * digest and signature encryption schemes work with sizes less than 512 + * bits. The computing time for sizes greater than 2048 bits is + * prohibitive on all but the fastest processors. An UltraSPARC Blade + * 1000 took something over nine minutes to generate and verify the + * values with size 2048. An old SPARC IPC would take a week. + * + * The OpenSSL library used by this program expects a random seed file. + * As described in the OpenSSL documentation, the file name defaults to + * first the RANDFILE environment variable in the user's home directory + * and then .rnd in the user's home directory. + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> + +#include "ntp.h" +#include "ntp_random.h" +#include "ntp_stdlib.h" +#include "ntp_assert.h" +#include "ntp_libopts.h" +#include "ntp_unixtime.h" +#include "ntp-keygen-opts.h" + +#ifdef OPENSSL +#include "openssl/bn.h" +#include "openssl/evp.h" +#include "openssl/err.h" +#include "openssl/rand.h" +#include "openssl/pem.h" +#include "openssl/x509v3.h" +#include <openssl/objects.h> +#endif /* OPENSSL */ +#include <ssl_applink.c> + +/* + * Cryptodefines + */ +#define MD5KEYS 10 /* number of keys generated of each type */ +#define MD5SIZE 20 /* maximum key size */ +#ifdef AUTOKEY +#define PLEN 512 /* default prime modulus size (bits) */ +#define ILEN 256 /* default identity modulus size (bits) */ +#define MVMAX 100 /* max MV parameters */ + +/* + * Strings used in X509v3 extension fields + */ +#define KEY_USAGE "digitalSignature,keyCertSign" +#define BASIC_CONSTRAINTS "critical,CA:TRUE" +#define EXT_KEY_PRIVATE "private" +#define EXT_KEY_TRUST "trustRoot" +#endif /* AUTOKEY */ + +/* + * Prototypes + */ +FILE *fheader (const char *, const char *, const char *); +int gen_md5 (char *); +void followlink (char *, size_t); +#ifdef AUTOKEY +EVP_PKEY *gen_rsa (char *); +EVP_PKEY *gen_dsa (char *); +EVP_PKEY *gen_iffkey (char *); +EVP_PKEY *gen_gqkey (char *); +EVP_PKEY *gen_mvkey (char *, EVP_PKEY **); +void gen_mvserv (char *, EVP_PKEY **); +int x509 (EVP_PKEY *, const EVP_MD *, char *, char *, + char *); +void cb (int, int, void *); +EVP_PKEY *genkey (char *, char *); +EVP_PKEY *readkey (char *, char *, u_int *, EVP_PKEY **); +void writekey (char *, char *, u_int *, EVP_PKEY **); +u_long asn2ntp (ASN1_TIME *); +#endif /* AUTOKEY */ + +/* + * Program variables + */ +extern char *optarg; /* command line argument */ +char *progname; +u_int lifetime = DAYSPERYEAR; /* certificate lifetime (days) */ +int nkeys; /* MV keys */ +time_t epoch; /* Unix epoch (seconds) since 1970 */ +u_int fstamp; /* NTP filestamp */ +char hostbuf[MAXHOSTNAME + 1]; +char *hostname = NULL; /* host, used in cert filenames */ +char *groupname = NULL; /* group name */ +char certnamebuf[2 * sizeof(hostbuf)]; +char *certname = NULL; /* certificate subject/issuer name */ +char *passwd1 = NULL; /* input private key password */ +char *passwd2 = NULL; /* output private key password */ +char filename[MAXFILENAME + 1]; /* file name */ +#ifdef AUTOKEY +u_int modulus = PLEN; /* prime modulus size (bits) */ +u_int modulus2 = ILEN; /* identity modulus size (bits) */ +long d0, d1, d2, d3; /* callback counters */ +const EVP_CIPHER * cipher = NULL; +#endif /* AUTOKEY */ + +#ifdef SYS_WINNT +BOOL init_randfile(); + +/* + * Don't try to follow symbolic links on Windows. Assume link == file. + */ +int +readlink( + char * link, + char * file, + int len + ) +{ + return strlen(file); +} + +/* + * Don't try to create symbolic links on Windows, that is supported on + * Vista and later only. Instead, if CreateHardLink is available (XP + * and later), hardlink the linkname to the original filename. On + * earlier systems, user must rename file to match expected link for + * ntpd to find it. To allow building a ntp-keygen.exe which loads on + * Windows pre-XP, runtime link to CreateHardLinkA(). + */ +int +symlink( + char * filename, + char* linkname + ) +{ + typedef BOOL (WINAPI *PCREATEHARDLINKA)( + __in LPCSTR lpFileName, + __in LPCSTR lpExistingFileName, + __reserved LPSECURITY_ATTRIBUTES lpSA + ); + static PCREATEHARDLINKA pCreateHardLinkA; + static int tried; + HMODULE hDll; + FARPROC pfn; + int link_created; + int saved_errno; + + if (!tried) { + tried = TRUE; + hDll = LoadLibrary("kernel32"); + pfn = GetProcAddress(hDll, "CreateHardLinkA"); + pCreateHardLinkA = (PCREATEHARDLINKA)pfn; + } + + if (NULL == pCreateHardLinkA) { + errno = ENOSYS; + return -1; + } + + link_created = (*pCreateHardLinkA)(linkname, filename, NULL); + + if (link_created) + return 0; + + saved_errno = GetLastError(); /* yes we play loose */ + mfprintf(stderr, "Create hard link %s to %s failed: %m\n", + linkname, filename); + errno = saved_errno; + return -1; +} + +void +InitWin32Sockets() { + WORD wVersionRequested; + WSADATA wsaData; + wVersionRequested = MAKEWORD(2,0); + if (WSAStartup(wVersionRequested, &wsaData)) + { + fprintf(stderr, "No useable winsock.dll\n"); + exit(1); + } +} +#endif /* SYS_WINNT */ + + +/* + * followlink() - replace filename with its target if symlink. + * + * Some readlink() implementations do not null-terminate the result. + */ +void +followlink( + char * fname, + size_t bufsiz + ) +{ + int len; + + REQUIRE(bufsiz > 0); + + len = readlink(fname, fname, (int)bufsiz); + if (len < 0 ) { + fname[0] = '\0'; + return; + } + if (len > (int)bufsiz - 1) + len = (int)bufsiz - 1; + fname[len] = '\0'; +} + + +/* + * Main program + */ +int +main( + int argc, /* command line options */ + char **argv + ) +{ + struct timeval tv; /* initialization vector */ + int md5key = 0; /* generate MD5 keys */ + int optct; /* option count */ +#ifdef AUTOKEY + X509 *cert = NULL; /* X509 certificate */ + X509_EXTENSION *ext; /* X509v3 extension */ + EVP_PKEY *pkey_host = NULL; /* host key */ + EVP_PKEY *pkey_sign = NULL; /* sign key */ + EVP_PKEY *pkey_iffkey = NULL; /* IFF sever keys */ + EVP_PKEY *pkey_gqkey = NULL; /* GQ server keys */ + EVP_PKEY *pkey_mvkey = NULL; /* MV trusted agen keys */ + EVP_PKEY *pkey_mvpar[MVMAX]; /* MV cleient keys */ + int hostkey = 0; /* generate RSA keys */ + int iffkey = 0; /* generate IFF keys */ + int gqkey = 0; /* generate GQ keys */ + int mvkey = 0; /* update MV keys */ + int mvpar = 0; /* generate MV parameters */ + char *sign = NULL; /* sign key */ + EVP_PKEY *pkey = NULL; /* temp key */ + const EVP_MD *ectx; /* EVP digest */ + char pathbuf[MAXFILENAME + 1]; + const char *scheme = NULL; /* digest/signature scheme */ + const char *ciphername = NULL; /* to encrypt priv. key */ + char *exten = NULL; /* private extension */ + char *grpkey = NULL; /* identity extension */ + int nid; /* X509 digest/signature scheme */ + FILE *fstr = NULL; /* file handle */ + char groupbuf[MAXHOSTNAME + 1]; + u_int temp; + BIO * bp; + int i, cnt; + char * ptr; +#endif /* AUTOKEY */ + + progname = argv[0]; + +#ifdef SYS_WINNT + /* Initialize before OpenSSL checks */ + InitWin32Sockets(); + if (!init_randfile()) + fprintf(stderr, "Unable to initialize .rnd file\n"); + ssl_applink(); +#endif + +#ifdef OPENSSL + ssl_check_version(); +#endif /* OPENSSL */ + + /* + * Process options, initialize host name and timestamp. + * gethostname() won't null-terminate if hostname is exactly the + * length provided for the buffer. + */ + gethostname(hostbuf, sizeof(hostbuf) - 1); + hostbuf[COUNTOF(hostbuf) - 1] = '\0'; + hostname = hostbuf; + groupname = hostbuf; + passwd1 = hostbuf; + passwd2 = NULL; + GETTIMEOFDAY(&tv, NULL); + ntp_srandom((u_long)(tv.tv_sec + tv.tv_usec)); + epoch = tv.tv_sec; + fstamp = (u_int)(epoch + JAN_1970); + + optct = ntpOptionProcess(&ntp_keygenOptions, argc, argv); + argc -= optct; + argv += optct; + +#ifdef OPENSSL + if (SSLeay() == SSLEAY_VERSION_NUMBER) + fprintf(stderr, "Using OpenSSL version %s\n", + SSLeay_version(SSLEAY_VERSION)); + else + fprintf(stderr, "Built against OpenSSL %s, using version %s\n", + OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); +#endif /* OPENSSL */ + + debug = OPT_VALUE_SET_DEBUG_LEVEL; + + if (HAVE_OPT( MD5KEY )) + md5key++; +#ifdef AUTOKEY + if (HAVE_OPT( PASSWORD )) + passwd1 = estrdup(OPT_ARG( PASSWORD )); + + if (HAVE_OPT( EXPORT_PASSWD )) + passwd2 = estrdup(OPT_ARG( EXPORT_PASSWD )); + + if (HAVE_OPT( HOST_KEY )) + hostkey++; + + if (HAVE_OPT( SIGN_KEY )) + sign = estrdup(OPT_ARG( SIGN_KEY )); + + if (HAVE_OPT( GQ_PARAMS )) + gqkey++; + + if (HAVE_OPT( IFFKEY )) + iffkey++; + + if (HAVE_OPT( MV_PARAMS )) { + mvkey++; + nkeys = OPT_VALUE_MV_PARAMS; + } + if (HAVE_OPT( MV_KEYS )) { + mvpar++; + nkeys = OPT_VALUE_MV_KEYS; + } + + if (HAVE_OPT( IMBITS )) + modulus2 = OPT_VALUE_IMBITS; + + if (HAVE_OPT( MODULUS )) + modulus = OPT_VALUE_MODULUS; + + if (HAVE_OPT( CERTIFICATE )) + scheme = OPT_ARG( CERTIFICATE ); + + if (HAVE_OPT( CIPHER )) + ciphername = OPT_ARG( CIPHER ); + + if (HAVE_OPT( SUBJECT_NAME )) + hostname = estrdup(OPT_ARG( SUBJECT_NAME )); + + if (HAVE_OPT( IDENT )) + groupname = estrdup(OPT_ARG( IDENT )); + + if (HAVE_OPT( LIFETIME )) + lifetime = OPT_VALUE_LIFETIME; + + if (HAVE_OPT( PVT_CERT )) + exten = EXT_KEY_PRIVATE; + + if (HAVE_OPT( TRUSTED_CERT )) + exten = EXT_KEY_TRUST; + + /* + * Remove the group name from the hostname variable used + * in host and sign certificate file names. + */ + if (hostname != hostbuf) + ptr = strchr(hostname, '@'); + else + ptr = NULL; + if (ptr != NULL) { + *ptr = '\0'; + groupname = estrdup(ptr + 1); + /* -s @group is equivalent to -i group, host unch. */ + if (ptr == hostname) + hostname = hostbuf; + } + + /* + * Derive host certificate issuer/subject names from host name + * and optional group. If no groupname is provided, the issuer + * and subject is the hostname with no '@group', and the + * groupname variable is pointed to hostname for use in IFF, GQ, + * and MV parameters file names. + */ + if (groupname == hostbuf) { + certname = hostname; + } else { + snprintf(certnamebuf, sizeof(certnamebuf), "%s@%s", + hostname, groupname); + certname = certnamebuf; + } + + /* + * Seed random number generator and grow weeds. + */ + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + if (!RAND_status()) { + if (RAND_file_name(pathbuf, sizeof(pathbuf)) == NULL) { + fprintf(stderr, "RAND_file_name %s\n", + ERR_error_string(ERR_get_error(), NULL)); + exit (-1); + } + temp = RAND_load_file(pathbuf, -1); + if (temp == 0) { + fprintf(stderr, + "RAND_load_file %s not found or empty\n", + pathbuf); + exit (-1); + } + fprintf(stderr, + "Random seed file %s %u bytes\n", pathbuf, temp); + RAND_add(&epoch, sizeof(epoch), 4.0); + } +#endif /* AUTOKEY */ + + /* + * Create new unencrypted MD5 keys file if requested. If this + * option is selected, ignore all other options. + */ + if (md5key) { + gen_md5("md5"); + exit (0); + } + +#ifdef AUTOKEY + /* + * Load previous certificate if available. + */ + snprintf(filename, sizeof(filename), "ntpkey_cert_%s", hostname); + if ((fstr = fopen(filename, "r")) != NULL) { + cert = PEM_read_X509(fstr, NULL, NULL, NULL); + fclose(fstr); + } + if (cert != NULL) { + + /* + * Extract subject name. + */ + X509_NAME_oneline(X509_get_subject_name(cert), groupbuf, + MAXFILENAME); + + /* + * Extract digest/signature scheme. + */ + if (scheme == NULL) { + nid = OBJ_obj2nid(cert->cert_info-> + signature->algorithm); + scheme = OBJ_nid2sn(nid); + } + + /* + * If a key_usage extension field is present, determine + * whether this is a trusted or private certificate. + */ + if (exten == NULL) { + ptr = strstr(groupbuf, "CN="); + cnt = X509_get_ext_count(cert); + for (i = 0; i < cnt; i++) { + ext = X509_get_ext(cert, i); + if (OBJ_obj2nid(ext->object) == + NID_ext_key_usage) { + bp = BIO_new(BIO_s_mem()); + X509V3_EXT_print(bp, ext, 0, 0); + BIO_gets(bp, pathbuf, + MAXFILENAME); + BIO_free(bp); + if (strcmp(pathbuf, + "Trust Root") == 0) + exten = EXT_KEY_TRUST; + else if (strcmp(pathbuf, + "Private") == 0) + exten = EXT_KEY_PRIVATE; + certname = estrdup(ptr + 3); + } + } + } + } + if (scheme == NULL) + scheme = "RSA-MD5"; + if (ciphername == NULL) + ciphername = "des-ede3-cbc"; + cipher = EVP_get_cipherbyname(ciphername); + if (cipher == NULL) { + fprintf(stderr, "Unknown cipher %s\n", ciphername); + exit(-1); + } + fprintf(stderr, "Using host %s group %s\n", hostname, + groupname); + + /* + * Create a new encrypted RSA host key file if requested; + * otherwise, look for an existing host key file. If not found, + * create a new encrypted RSA host key file. If that fails, go + * no further. + */ + if (hostkey) + pkey_host = genkey("RSA", "host"); + if (pkey_host == NULL) { + snprintf(filename, sizeof(filename), "ntpkey_host_%s", hostname); + pkey_host = readkey(filename, passwd1, &fstamp, NULL); + if (pkey_host != NULL) { + followlink(filename, sizeof(filename)); + fprintf(stderr, "Using host key %s\n", + filename); + } else { + pkey_host = genkey("RSA", "host"); + } + } + if (pkey_host == NULL) { + fprintf(stderr, "Generating host key fails\n"); + exit(-1); + } + + /* + * Create new encrypted RSA or DSA sign keys file if requested; + * otherwise, look for an existing sign key file. If not found, + * use the host key instead. + */ + if (sign != NULL) + pkey_sign = genkey(sign, "sign"); + if (pkey_sign == NULL) { + snprintf(filename, sizeof(filename), "ntpkey_sign_%s", + hostname); + pkey_sign = readkey(filename, passwd1, &fstamp, NULL); + if (pkey_sign != NULL) { + followlink(filename, sizeof(filename)); + fprintf(stderr, "Using sign key %s\n", + filename); + } else { + pkey_sign = pkey_host; + fprintf(stderr, "Using host key as sign key\n"); + } + } + + /* + * Create new encrypted GQ server keys file if requested; + * otherwise, look for an exisiting file. If found, fetch the + * public key for the certificate. + */ + if (gqkey) + pkey_gqkey = gen_gqkey("gqkey"); + if (pkey_gqkey == NULL) { + snprintf(filename, sizeof(filename), "ntpkey_gqkey_%s", + groupname); + pkey_gqkey = readkey(filename, passwd1, &fstamp, NULL); + if (pkey_gqkey != NULL) { + followlink(filename, sizeof(filename)); + fprintf(stderr, "Using GQ parameters %s\n", + filename); + } + } + if (pkey_gqkey != NULL) + grpkey = BN_bn2hex(pkey_gqkey->pkey.rsa->q); + + /* + * Write the nonencrypted GQ client parameters to the stdout + * stream. The parameter file is the server key file with the + * private key obscured. + */ + if (pkey_gqkey != NULL && HAVE_OPT(ID_KEY)) { + RSA *rsa; + + snprintf(filename, sizeof(filename), + "ntpkey_gqpar_%s.%u", groupname, fstamp); + fprintf(stderr, "Writing GQ parameters %s to stdout\n", + filename); + fprintf(stdout, "# %s\n# %s\n", filename, + ctime(&epoch)); + rsa = pkey_gqkey->pkey.rsa; + BN_copy(rsa->p, BN_value_one()); + BN_copy(rsa->q, BN_value_one()); + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pkey, rsa); + PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, + NULL, NULL); + fflush(stdout); + if (debug) + RSA_print_fp(stderr, rsa, 0); + } + + /* + * Write the encrypted GQ server keys to the stdout stream. + */ + if (pkey_gqkey != NULL && passwd2 != NULL) { + RSA *rsa; + + snprintf(filename, sizeof(filename), + "ntpkey_gqkey_%s.%u", groupname, fstamp); + fprintf(stderr, "Writing GQ keys %s to stdout\n", + filename); + fprintf(stdout, "# %s\n# %s\n", filename, + ctime(&epoch)); + rsa = pkey_gqkey->pkey.rsa; + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pkey, rsa); + PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, + NULL, passwd2); + fflush(stdout); + if (debug) + RSA_print_fp(stderr, rsa, 0); + } + + /* + * Create new encrypted IFF server keys file if requested; + * otherwise, look for existing file. + */ + if (iffkey) + pkey_iffkey = gen_iffkey("iffkey"); + if (pkey_iffkey == NULL) { + snprintf(filename, sizeof(filename), "ntpkey_iffkey_%s", + groupname); + pkey_iffkey = readkey(filename, passwd1, &fstamp, NULL); + if (pkey_iffkey != NULL) { + followlink(filename, sizeof(filename)); + fprintf(stderr, "Using IFF keys %s\n", + filename); + } + } + + /* + * Write the nonencrypted IFF client parameters to the stdout + * stream. The parameter file is the server key file with the + * private key obscured. + */ + if (pkey_iffkey != NULL && HAVE_OPT(ID_KEY)) { + DSA *dsa; + + snprintf(filename, sizeof(filename), + "ntpkey_iffpar_%s.%u", groupname, fstamp); + fprintf(stderr, "Writing IFF parameters %s to stdout\n", + filename); + fprintf(stdout, "# %s\n# %s\n", filename, + ctime(&epoch)); + dsa = pkey_iffkey->pkey.dsa; + BN_copy(dsa->priv_key, BN_value_one()); + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DSA(pkey, dsa); + PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, + NULL, NULL); + fflush(stdout); + if (debug) + DSA_print_fp(stderr, dsa, 0); + } + + /* + * Write the encrypted IFF server keys to the stdout stream. + */ + if (pkey_iffkey != NULL && passwd2 != NULL) { + DSA *dsa; + + snprintf(filename, sizeof(filename), + "ntpkey_iffkey_%s.%u", groupname, fstamp); + fprintf(stderr, "Writing IFF keys %s to stdout\n", + filename); + fprintf(stdout, "# %s\n# %s\n", filename, + ctime(&epoch)); + dsa = pkey_iffkey->pkey.dsa; + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DSA(pkey, dsa); + PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, + NULL, passwd2); + fflush(stdout); + if (debug) + DSA_print_fp(stderr, dsa, 0); + } + + /* + * Create new encrypted MV trusted-authority keys file if + * requested; otherwise, look for existing keys file. + */ + if (mvkey) + pkey_mvkey = gen_mvkey("mv", pkey_mvpar); + if (pkey_mvkey == NULL) { + snprintf(filename, sizeof(filename), "ntpkey_mvta_%s", + groupname); + pkey_mvkey = readkey(filename, passwd1, &fstamp, + pkey_mvpar); + if (pkey_mvkey != NULL) { + followlink(filename, sizeof(filename)); + fprintf(stderr, "Using MV keys %s\n", + filename); + } + } + + /* + * Write the nonencrypted MV client parameters to the stdout + * stream. For the moment, we always use the client parameters + * associated with client key 1. + */ + if (pkey_mvkey != NULL && HAVE_OPT(ID_KEY)) { + snprintf(filename, sizeof(filename), + "ntpkey_mvpar_%s.%u", groupname, fstamp); + fprintf(stderr, "Writing MV parameters %s to stdout\n", + filename); + fprintf(stdout, "# %s\n# %s\n", filename, + ctime(&epoch)); + pkey = pkey_mvpar[2]; + PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, + NULL, NULL); + fflush(stdout); + if (debug) + DSA_print_fp(stderr, pkey->pkey.dsa, 0); + } + + /* + * Write the encrypted MV server keys to the stdout stream. + */ + if (pkey_mvkey != NULL && passwd2 != NULL) { + snprintf(filename, sizeof(filename), + "ntpkey_mvkey_%s.%u", groupname, fstamp); + fprintf(stderr, "Writing MV keys %s to stdout\n", + filename); + fprintf(stdout, "# %s\n# %s\n", filename, + ctime(&epoch)); + pkey = pkey_mvpar[1]; + PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, + NULL, passwd2); + fflush(stdout); + if (debug) + DSA_print_fp(stderr, pkey->pkey.dsa, 0); + } + + /* + * Decode the digest/signature scheme and create the + * certificate. Do this every time we run the program. + */ + ectx = EVP_get_digestbyname(scheme); + if (ectx == NULL) { + fprintf(stderr, + "Invalid digest/signature combination %s\n", + scheme); + exit (-1); + } + x509(pkey_sign, ectx, grpkey, exten, certname); +#endif /* AUTOKEY */ + exit(0); +} + + +/* + * Generate semi-random MD5 keys compatible with NTPv3 and NTPv4. Also, + * if OpenSSL is around, generate random SHA1 keys compatible with + * symmetric key cryptography. + */ +int +gen_md5( + char *id /* file name id */ + ) +{ + u_char md5key[MD5SIZE + 1]; /* MD5 key */ + FILE *str; + int i, j; +#ifdef OPENSSL + u_char keystr[MD5SIZE]; + u_char hexstr[2 * MD5SIZE + 1]; + u_char hex[] = "0123456789abcdef"; +#endif /* OPENSSL */ + + str = fheader("MD5key", id, groupname); + for (i = 1; i <= MD5KEYS; i++) { + for (j = 0; j < MD5SIZE; j++) { + int temp; + + while (1) { + temp = ntp_random() & 0xff; + if (temp == '#') + continue; + + if (temp > 0x20 && temp < 0x7f) + break; + } + md5key[j] = (u_char)temp; + } + md5key[j] = '\0'; + fprintf(str, "%2d MD5 %s # MD5 key\n", i, + md5key); + } +#ifdef OPENSSL + for (i = 1; i <= MD5KEYS; i++) { + RAND_bytes(keystr, 20); + for (j = 0; j < MD5SIZE; j++) { + hexstr[2 * j] = hex[keystr[j] >> 4]; + hexstr[2 * j + 1] = hex[keystr[j] & 0xf]; + } + hexstr[2 * MD5SIZE] = '\0'; + fprintf(str, "%2d SHA1 %s # SHA1 key\n", i + MD5KEYS, + hexstr); + } +#endif /* OPENSSL */ + fclose(str); + return (1); +} + + +#ifdef AUTOKEY +/* + * readkey - load cryptographic parameters and keys + * + * This routine loads a PEM-encoded file of given name and password and + * extracts the filestamp from the file name. It returns a pointer to + * the first key if valid, NULL if not. + */ +EVP_PKEY * /* public/private key pair */ +readkey( + char *cp, /* file name */ + char *passwd, /* password */ + u_int *estamp, /* file stamp */ + EVP_PKEY **evpars /* parameter list pointer */ + ) +{ + FILE *str; /* file handle */ + EVP_PKEY *pkey = NULL; /* public/private key */ + u_int gstamp; /* filestamp */ + char linkname[MAXFILENAME]; /* filestamp buffer) */ + EVP_PKEY *parkey; + char *ptr; + int i; + + /* + * Open the key file. + */ + str = fopen(cp, "r"); + if (str == NULL) + return (NULL); + + /* + * Read the filestamp, which is contained in the first line. + */ + if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) { + fprintf(stderr, "Empty key file %s\n", cp); + fclose(str); + return (NULL); + } + if ((ptr = strrchr(ptr, '.')) == NULL) { + fprintf(stderr, "No filestamp found in %s\n", cp); + fclose(str); + return (NULL); + } + if (sscanf(++ptr, "%u", &gstamp) != 1) { + fprintf(stderr, "Invalid filestamp found in %s\n", cp); + fclose(str); + return (NULL); + } + + /* + * Read and decrypt PEM-encoded private keys. The first one + * found is returned. If others are expected, add them to the + * parameter list. + */ + for (i = 0; i <= MVMAX - 1;) { + parkey = PEM_read_PrivateKey(str, NULL, NULL, passwd); + if (evpars != NULL) { + evpars[i++] = parkey; + evpars[i] = NULL; + } + if (parkey == NULL) + break; + + if (pkey == NULL) + pkey = parkey; + if (debug) { + if (parkey->type == EVP_PKEY_DSA) + DSA_print_fp(stderr, parkey->pkey.dsa, + 0); + else if (parkey->type == EVP_PKEY_RSA) + RSA_print_fp(stderr, parkey->pkey.rsa, + 0); + } + } + fclose(str); + if (pkey == NULL) { + fprintf(stderr, "Corrupt file %s or wrong key %s\n%s\n", + cp, passwd, ERR_error_string(ERR_get_error(), + NULL)); + exit (-1); + } + *estamp = gstamp; + return (pkey); +} + + +/* + * Generate RSA public/private key pair + */ +EVP_PKEY * /* public/private key pair */ +gen_rsa( + char *id /* file name id */ + ) +{ + EVP_PKEY *pkey; /* private key */ + RSA *rsa; /* RSA parameters and key pair */ + FILE *str; + + fprintf(stderr, "Generating RSA keys (%d bits)...\n", modulus); + rsa = RSA_generate_key(modulus, 3, cb, "RSA"); + fprintf(stderr, "\n"); + if (rsa == NULL) { + fprintf(stderr, "RSA generate keys fails\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (NULL); + } + + /* + * For signature encryption it is not necessary that the RSA + * parameters be strictly groomed and once in a while the + * modulus turns out to be non-prime. Just for grins, we check + * the primality. + */ + if (!RSA_check_key(rsa)) { + fprintf(stderr, "Invalid RSA key\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + RSA_free(rsa); + return (NULL); + } + + /* + * Write the RSA parameters and keys as a RSA private key + * encoded in PEM. + */ + if (strcmp(id, "sign") == 0) + str = fheader("RSAsign", id, hostname); + else + str = fheader("RSAhost", id, hostname); + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pkey, rsa); + PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, + passwd1); + fclose(str); + if (debug) + RSA_print_fp(stderr, rsa, 0); + return (pkey); +} + + +/* + * Generate DSA public/private key pair + */ +EVP_PKEY * /* public/private key pair */ +gen_dsa( + char *id /* file name id */ + ) +{ + EVP_PKEY *pkey; /* private key */ + DSA *dsa; /* DSA parameters */ + u_char seed[20]; /* seed for parameters */ + FILE *str; + + /* + * Generate DSA parameters. + */ + fprintf(stderr, + "Generating DSA parameters (%d bits)...\n", modulus); + RAND_bytes(seed, sizeof(seed)); + dsa = DSA_generate_parameters(modulus, seed, sizeof(seed), NULL, + NULL, cb, "DSA"); + fprintf(stderr, "\n"); + if (dsa == NULL) { + fprintf(stderr, "DSA generate parameters fails\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (NULL); + } + + /* + * Generate DSA keys. + */ + fprintf(stderr, "Generating DSA keys (%d bits)...\n", modulus); + if (!DSA_generate_key(dsa)) { + fprintf(stderr, "DSA generate keys fails\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + DSA_free(dsa); + return (NULL); + } + + /* + * Write the DSA parameters and keys as a DSA private key + * encoded in PEM. + */ + str = fheader("DSAsign", id, hostname); + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DSA(pkey, dsa); + PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, + passwd1); + fclose(str); + if (debug) + DSA_print_fp(stderr, dsa, 0); + return (pkey); +} + + +/* + *********************************************************************** + * * + * The following routines implement the Schnorr (IFF) identity scheme * + * * + *********************************************************************** + * + * The Schnorr (IFF) identity scheme is intended for use when + * certificates are generated by some other trusted certificate + * authority and the certificate cannot be used to convey public + * parameters. There are two kinds of files: encrypted server files that + * contain private and public values and nonencrypted client files that + * contain only public values. New generations of server files must be + * securely transmitted to all servers of the group; client files can be + * distributed by any means. The scheme is self contained and + * independent of new generations of host keys, sign keys and + * certificates. + * + * The IFF values hide in a DSA cuckoo structure which uses the same + * parameters. The values are used by an identity scheme based on DSA + * cryptography and described in Stimson p. 285. The p is a 512-bit + * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1 + * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a + * private random group key b (0 < b < q) and public key v = g^b, then + * sends (p, q, g, b) to the servers and (p, q, g, v) to the clients. + * Alice challenges Bob to confirm identity using the protocol described + * below. + * + * How it works + * + * The scheme goes like this. Both Alice and Bob have the public primes + * p, q and generator g. The TA gives private key b to Bob and public + * key v to Alice. + * + * Alice rolls new random challenge r (o < r < q) and sends to Bob in + * the IFF request message. Bob rolls new random k (0 < k < q), then + * computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x)) + * to Alice in the response message. Besides making the response + * shorter, the hash makes it effectivey impossible for an intruder to + * solve for b by observing a number of these messages. + * + * Alice receives the response and computes g^y v^r mod p. After a bit + * of algebra, this simplifies to g^k. If the hash of this result + * matches hash(x), Alice knows that Bob has the group key b. The signed + * response binds this knowledge to Bob's private key and the public key + * previously received in his certificate. + */ +/* + * Generate Schnorr (IFF) keys. + */ +EVP_PKEY * /* DSA cuckoo nest */ +gen_iffkey( + char *id /* file name id */ + ) +{ + EVP_PKEY *pkey; /* private key */ + DSA *dsa; /* DSA parameters */ + u_char seed[20]; /* seed for parameters */ + BN_CTX *ctx; /* BN working space */ + BIGNUM *b, *r, *k, *u, *v, *w; /* BN temp */ + FILE *str; + u_int temp; + + /* + * Generate DSA parameters for use as IFF parameters. + */ + fprintf(stderr, "Generating IFF keys (%d bits)...\n", + modulus2); + RAND_bytes(seed, sizeof(seed)); + dsa = DSA_generate_parameters(modulus2, seed, sizeof(seed), NULL, + NULL, cb, "IFF"); + fprintf(stderr, "\n"); + if (dsa == NULL) { + fprintf(stderr, "DSA generate parameters fails\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (NULL);; + } + + /* + * Generate the private and public keys. The DSA parameters and + * private key are distributed to the servers, while all except + * the private key are distributed to the clients. + */ + b = BN_new(); r = BN_new(); k = BN_new(); + u = BN_new(); v = BN_new(); w = BN_new(); ctx = BN_CTX_new(); + BN_rand(b, BN_num_bits(dsa->q), -1, 0); /* a */ + BN_mod(b, b, dsa->q, ctx); + BN_sub(v, dsa->q, b); + BN_mod_exp(v, dsa->g, v, dsa->p, ctx); /* g^(q - b) mod p */ + BN_mod_exp(u, dsa->g, b, dsa->p, ctx); /* g^b mod p */ + BN_mod_mul(u, u, v, dsa->p, ctx); + temp = BN_is_one(u); + fprintf(stderr, + "Confirm g^(q - b) g^b = 1 mod p: %s\n", temp == 1 ? + "yes" : "no"); + if (!temp) { + BN_free(b); BN_free(r); BN_free(k); + BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); + return (NULL); + } + dsa->priv_key = BN_dup(b); /* private key */ + dsa->pub_key = BN_dup(v); /* public key */ + + /* + * Here is a trial round of the protocol. First, Alice rolls + * random nonce r mod q and sends it to Bob. She needs only + * q from parameters. + */ + BN_rand(r, BN_num_bits(dsa->q), -1, 0); /* r */ + BN_mod(r, r, dsa->q, ctx); + + /* + * Bob rolls random nonce k mod q, computes y = k + b r mod q + * and x = g^k mod p, then sends (y, x) to Alice. He needs + * p, q and b from parameters and r from Alice. + */ + BN_rand(k, BN_num_bits(dsa->q), -1, 0); /* k, 0 < k < q */ + BN_mod(k, k, dsa->q, ctx); + BN_mod_mul(v, dsa->priv_key, r, dsa->q, ctx); /* b r mod q */ + BN_add(v, v, k); + BN_mod(v, v, dsa->q, ctx); /* y = k + b r mod q */ + BN_mod_exp(u, dsa->g, k, dsa->p, ctx); /* x = g^k mod p */ + + /* + * Alice verifies x = g^y v^r to confirm that Bob has group key + * b. She needs p, q, g from parameters, (y, x) from Bob and the + * original r. We omit the detail here thatt only the hash of y + * is sent. + */ + BN_mod_exp(v, dsa->g, v, dsa->p, ctx); /* g^y mod p */ + BN_mod_exp(w, dsa->pub_key, r, dsa->p, ctx); /* v^r */ + BN_mod_mul(v, w, v, dsa->p, ctx); /* product mod p */ + temp = BN_cmp(u, v); + fprintf(stderr, + "Confirm g^k = g^(k + b r) g^(q - b) r: %s\n", temp == + 0 ? "yes" : "no"); + BN_free(b); BN_free(r); BN_free(k); + BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); + if (temp != 0) { + DSA_free(dsa); + return (NULL); + } + + /* + * Write the IFF keys as an encrypted DSA private key encoded in + * PEM. + * + * p modulus p + * q modulus q + * g generator g + * priv_key b + * public_key v + * kinv not used + * r not used + */ + str = fheader("IFFkey", id, groupname); + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DSA(pkey, dsa); + PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, + passwd1); + fclose(str); + if (debug) + DSA_print_fp(stderr, dsa, 0); + return (pkey); +} + + +/* + *********************************************************************** + * * + * The following routines implement the Guillou-Quisquater (GQ) * + * identity scheme * + * * + *********************************************************************** + * + * The Guillou-Quisquater (GQ) identity scheme is intended for use when + * the certificate can be used to convey public parameters. The scheme + * uses a X509v3 certificate extension field do convey the public key of + * a private key known only to servers. There are two kinds of files: + * encrypted server files that contain private and public values and + * nonencrypted client files that contain only public values. New + * generations of server files must be securely transmitted to all + * servers of the group; client files can be distributed by any means. + * The scheme is self contained and independent of new generations of + * host keys and sign keys. The scheme is self contained and independent + * of new generations of host keys and sign keys. + * + * The GQ parameters hide in a RSA cuckoo structure which uses the same + * parameters. The values are used by an identity scheme based on RSA + * cryptography and described in Stimson p. 300 (with errors). The 512- + * bit public modulus is n = p q, where p and q are secret large primes. + * The TA rolls private random group key b as RSA exponent. These values + * are known to all group members. + * + * When rolling new certificates, a server recomputes the private and + * public keys. The private key u is a random roll, while the public key + * is the inverse obscured by the group key v = (u^-1)^b. These values + * replace the private and public keys normally generated by the RSA + * scheme. Alice challenges Bob to confirm identity using the protocol + * described below. + * + * How it works + * + * The scheme goes like this. Both Alice and Bob have the same modulus n + * and some random b as the group key. These values are computed and + * distributed in advance via secret means, although only the group key + * b is truly secret. Each has a private random private key u and public + * key (u^-1)^b, although not necessarily the same ones. Bob and Alice + * can regenerate the key pair from time to time without affecting + * operations. The public key is conveyed on the certificate in an + * extension field; the private key is never revealed. + * + * Alice rolls new random challenge r and sends to Bob in the GQ + * request message. Bob rolls new random k, then computes y = k u^r mod + * n and x = k^b mod n and sends (y, hash(x)) to Alice in the response + * message. Besides making the response shorter, the hash makes it + * effectivey impossible for an intruder to solve for b by observing + * a number of these messages. + * + * Alice receives the response and computes y^b v^r mod n. After a bit + * of algebra, this simplifies to k^b. If the hash of this result + * matches hash(x), Alice knows that Bob has the group key b. The signed + * response binds this knowledge to Bob's private key and the public key + * previously received in his certificate. + */ +/* + * Generate Guillou-Quisquater (GQ) parameters file. + */ +EVP_PKEY * /* RSA cuckoo nest */ +gen_gqkey( + char *id /* file name id */ + ) +{ + EVP_PKEY *pkey; /* private key */ + RSA *rsa; /* RSA parameters */ + BN_CTX *ctx; /* BN working space */ + BIGNUM *u, *v, *g, *k, *r, *y; /* BN temps */ + FILE *str; + u_int temp; + + /* + * Generate RSA parameters for use as GQ parameters. + */ + fprintf(stderr, + "Generating GQ parameters (%d bits)...\n", + modulus2); + rsa = RSA_generate_key(modulus2, 3, cb, "GQ"); + fprintf(stderr, "\n"); + if (rsa == NULL) { + fprintf(stderr, "RSA generate keys fails\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (NULL); + } + u = BN_new(); v = BN_new(); g = BN_new(); + k = BN_new(); r = BN_new(); y = BN_new(); + + /* + * Generate the group key b, which is saved in the e member of + * the RSA structure. The group key is transmitted to each group + * member encrypted by the member private key. + */ + ctx = BN_CTX_new(); + BN_rand(rsa->e, BN_num_bits(rsa->n), -1, 0); /* b */ + BN_mod(rsa->e, rsa->e, rsa->n, ctx); + + /* + * When generating his certificate, Bob rolls random private key + * u, then computes inverse v = u^-1. + */ + BN_rand(u, BN_num_bits(rsa->n), -1, 0); /* u */ + BN_mod(u, u, rsa->n, ctx); + BN_mod_inverse(v, u, rsa->n, ctx); /* u^-1 mod n */ + BN_mod_mul(k, v, u, rsa->n, ctx); + + /* + * Bob computes public key v = (u^-1)^b, which is saved in an + * extension field on his certificate. We check that u^b v = + * 1 mod n. + */ + BN_mod_exp(v, v, rsa->e, rsa->n, ctx); + BN_mod_exp(g, u, rsa->e, rsa->n, ctx); /* u^b */ + BN_mod_mul(g, g, v, rsa->n, ctx); /* u^b (u^-1)^b */ + temp = BN_is_one(g); + fprintf(stderr, + "Confirm u^b (u^-1)^b = 1 mod n: %s\n", temp ? "yes" : + "no"); + if (!temp) { + BN_free(u); BN_free(v); + BN_free(g); BN_free(k); BN_free(r); BN_free(y); + BN_CTX_free(ctx); + RSA_free(rsa); + return (NULL); + } + BN_copy(rsa->p, u); /* private key */ + BN_copy(rsa->q, v); /* public key */ + + /* + * Here is a trial run of the protocol. First, Alice rolls + * random nonce r mod n and sends it to Bob. She needs only n + * from parameters. + */ + BN_rand(r, BN_num_bits(rsa->n), -1, 0); /* r */ + BN_mod(r, r, rsa->n, ctx); + + /* + * Bob rolls random nonce k mod n, computes y = k u^r mod n and + * g = k^b mod n, then sends (y, g) to Alice. He needs n, u, b + * from parameters and r from Alice. + */ + BN_rand(k, BN_num_bits(rsa->n), -1, 0); /* k */ + BN_mod(k, k, rsa->n, ctx); + BN_mod_exp(y, rsa->p, r, rsa->n, ctx); /* u^r mod n */ + BN_mod_mul(y, k, y, rsa->n, ctx); /* y = k u^r mod n */ + BN_mod_exp(g, k, rsa->e, rsa->n, ctx); /* g = k^b mod n */ + + /* + * Alice verifies g = v^r y^b mod n to confirm that Bob has + * private key u. She needs n, g from parameters, public key v = + * (u^-1)^b from the certificate, (y, g) from Bob and the + * original r. We omit the detaul here that only the hash of g + * is sent. + */ + BN_mod_exp(v, rsa->q, r, rsa->n, ctx); /* v^r mod n */ + BN_mod_exp(y, y, rsa->e, rsa->n, ctx); /* y^b mod n */ + BN_mod_mul(y, v, y, rsa->n, ctx); /* v^r y^b mod n */ + temp = BN_cmp(y, g); + fprintf(stderr, "Confirm g^k = v^r y^b mod n: %s\n", temp == 0 ? + "yes" : "no"); + BN_CTX_free(ctx); BN_free(u); BN_free(v); + BN_free(g); BN_free(k); BN_free(r); BN_free(y); + if (temp != 0) { + RSA_free(rsa); + return (NULL); + } + + /* + * Write the GQ parameter file as an encrypted RSA private key + * encoded in PEM. + * + * n modulus n + * e group key b + * d not used + * p private key u + * q public key (u^-1)^b + * dmp1 not used + * dmq1 not used + * iqmp not used + */ + BN_copy(rsa->d, BN_value_one()); + BN_copy(rsa->dmp1, BN_value_one()); + BN_copy(rsa->dmq1, BN_value_one()); + BN_copy(rsa->iqmp, BN_value_one()); + str = fheader("GQkey", id, groupname); + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pkey, rsa); + PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, + passwd1); + fclose(str); + if (debug) + RSA_print_fp(stderr, rsa, 0); + return (pkey); +} + + +/* + *********************************************************************** + * * + * The following routines implement the Mu-Varadharajan (MV) identity * + * scheme * + * * + *********************************************************************** + * + * The Mu-Varadharajan (MV) cryptosystem was originally intended when + * servers broadcast messages to clients, but clients never send + * messages to servers. There is one encryption key for the server and a + * separate decryption key for each client. It operated something like a + * pay-per-view satellite broadcasting system where the session key is + * encrypted by the broadcaster and the decryption keys are held in a + * tamperproof set-top box. + * + * The MV parameters and private encryption key hide in a DSA cuckoo + * structure which uses the same parameters, but generated in a + * different way. The values are used in an encryption scheme similar to + * El Gamal cryptography and a polynomial formed from the expansion of + * product terms (x - x[j]), as described in Mu, Y., and V. + * Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001, + * 223-231. The paper has significant errors and serious omissions. + * + * Let q be the product of n distinct primes s1[j] (j = 1...n), where + * each s1[j] has m significant bits. Let p be a prime p = 2 * q + 1, so + * that q and each s1[j] divide p - 1 and p has M = n * m + 1 + * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1) + * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then + * project into Zp* as exponents of g. Sometimes we have to compute an + * inverse b^-1 of random b in Zq, but for that purpose we require + * gcd(b, q) = 1. We expect M to be in the 500-bit range and n + * relatively small, like 30. These are the parameters of the scheme and + * they are expensive to compute. + * + * We set up an instance of the scheme as follows. A set of random + * values x[j] mod q (j = 1...n), are generated as the zeros of a + * polynomial of order n. The product terms (x - x[j]) are expanded to + * form coefficients a[i] mod q (i = 0...n) in powers of x. These are + * used as exponents of the generator g mod p to generate the private + * encryption key A. The pair (gbar, ghat) of public server keys and the + * pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used + * to construct the decryption keys. The devil is in the details. + * + * This routine generates a private server encryption file including the + * private encryption key E and partial decryption keys gbar and ghat. + * It then generates public client decryption files including the public + * keys xbar[j] and xhat[j] for each client j. The partial decryption + * files are used to compute the inverse of E. These values are suitably + * blinded so secrets are not revealed. + * + * The distinguishing characteristic of this scheme is the capability to + * revoke keys. Included in the calculation of E, gbar and ghat is the + * product s = prod(s1[j]) (j = 1...n) above. If the factor s1[j] is + * subsequently removed from the product and E, gbar and ghat + * recomputed, the jth client will no longer be able to compute E^-1 and + * thus unable to decrypt the messageblock. + * + * How it works + * + * The scheme goes like this. Bob has the server values (p, E, q, + * gbar, ghat) and Alice has the client values (p, xbar, xhat). + * + * Alice rolls new random nonce r mod p and sends to Bob in the MV + * request message. Bob rolls random nonce k mod q, encrypts y = r E^k + * mod p and sends (y, gbar^k, ghat^k) to Alice. + * + * Alice receives the response and computes the inverse (E^k)^-1 from + * the partial decryption keys gbar^k, ghat^k, xbar and xhat. She then + * decrypts y and verifies it matches the original r. The signed + * response binds this knowledge to Bob's private key and the public key + * previously received in his certificate. + */ +EVP_PKEY * /* DSA cuckoo nest */ +gen_mvkey( + char *id, /* file name id */ + EVP_PKEY **evpars /* parameter list pointer */ + ) +{ + EVP_PKEY *pkey, *pkey1; /* private keys */ + DSA *dsa, *dsa2, *sdsa; /* DSA parameters */ + BN_CTX *ctx; /* BN working space */ + BIGNUM *a[MVMAX]; /* polynomial coefficient vector */ + BIGNUM *g[MVMAX]; /* public key vector */ + BIGNUM *s1[MVMAX]; /* private enabling keys */ + BIGNUM *x[MVMAX]; /* polynomial zeros vector */ + BIGNUM *xbar[MVMAX], *xhat[MVMAX]; /* private keys vector */ + BIGNUM *b; /* group key */ + BIGNUM *b1; /* inverse group key */ + BIGNUM *s; /* enabling key */ + BIGNUM *biga; /* master encryption key */ + BIGNUM *bige; /* session encryption key */ + BIGNUM *gbar, *ghat; /* public key */ + BIGNUM *u, *v, *w; /* BN scratch */ + int i, j, n; + FILE *str; + u_int temp; + + /* + * Generate MV parameters. + * + * The object is to generate a multiplicative group Zp* modulo a + * prime p and a subset Zq mod q, where q is the product of n + * distinct primes s1[j] (j = 1...n) and q divides p - 1. We + * first generate n m-bit primes, where the product n m is in + * the order of 512 bits. One or more of these may have to be + * replaced later. As a practical matter, it is tough to find + * more than 31 distinct primes for 512 bits or 61 primes for + * 1024 bits. The latter can take several hundred iterations + * and several minutes on a Sun Blade 1000. + */ + n = nkeys; + fprintf(stderr, + "Generating MV parameters for %d keys (%d bits)...\n", n, + modulus2 / n); + ctx = BN_CTX_new(); u = BN_new(); v = BN_new(); w = BN_new(); + b = BN_new(); b1 = BN_new(); + dsa = DSA_new(); + dsa->p = BN_new(); dsa->q = BN_new(); dsa->g = BN_new(); + dsa->priv_key = BN_new(); dsa->pub_key = BN_new(); + temp = 0; + for (j = 1; j <= n; j++) { + s1[j] = BN_new(); + while (1) { + BN_generate_prime(s1[j], modulus2 / n, 0, NULL, + NULL, NULL, NULL); + for (i = 1; i < j; i++) { + if (BN_cmp(s1[i], s1[j]) == 0) + break; + } + if (i == j) + break; + temp++; + } + } + fprintf(stderr, "Birthday keys regenerated %d\n", temp); + + /* + * Compute the modulus q as the product of the primes. Compute + * the modulus p as 2 * q + 1 and test p for primality. If p + * is composite, replace one of the primes with a new distinct + * one and try again. Note that q will hardly be a secret since + * we have to reveal p to servers, but not clients. However, + * factoring q to find the primes should be adequately hard, as + * this is the same problem considered hard in RSA. Question: is + * it as hard to find n small prime factors totalling n bits as + * it is to find two large prime factors totalling n bits? + * Remember, the bad guy doesn't know n. + */ + temp = 0; + while (1) { + BN_one(dsa->q); + for (j = 1; j <= n; j++) + BN_mul(dsa->q, dsa->q, s1[j], ctx); + BN_copy(dsa->p, dsa->q); + BN_add(dsa->p, dsa->p, dsa->p); + BN_add_word(dsa->p, 1); + if (BN_is_prime(dsa->p, BN_prime_checks, NULL, ctx, + NULL)) + break; + + temp++; + j = temp % n + 1; + while (1) { + BN_generate_prime(u, modulus2 / n, 0, 0, NULL, + NULL, NULL); + for (i = 1; i <= n; i++) { + if (BN_cmp(u, s1[i]) == 0) + break; + } + if (i > n) + break; + } + BN_copy(s1[j], u); + } + fprintf(stderr, "Defective keys regenerated %d\n", temp); + + /* + * Compute the generator g using a random roll such that + * gcd(g, p - 1) = 1 and g^q = 1. This is a generator of p, not + * q. This may take several iterations. + */ + BN_copy(v, dsa->p); + BN_sub_word(v, 1); + while (1) { + BN_rand(dsa->g, BN_num_bits(dsa->p) - 1, 0, 0); + BN_mod(dsa->g, dsa->g, dsa->p, ctx); + BN_gcd(u, dsa->g, v, ctx); + if (!BN_is_one(u)) + continue; + + BN_mod_exp(u, dsa->g, dsa->q, dsa->p, ctx); + if (BN_is_one(u)) + break; + } + + /* + * Setup is now complete. Roll random polynomial roots x[j] + * (j = 1...n) for all j. While it may not be strictly + * necessary, Make sure each root has no factors in common with + * q. + */ + fprintf(stderr, + "Generating polynomial coefficients for %d roots (%d bits)\n", + n, BN_num_bits(dsa->q)); + for (j = 1; j <= n; j++) { + x[j] = BN_new(); + + while (1) { + BN_rand(x[j], BN_num_bits(dsa->q), 0, 0); + BN_mod(x[j], x[j], dsa->q, ctx); + BN_gcd(u, x[j], dsa->q, ctx); + if (BN_is_one(u)) + break; + } + } + + /* + * Generate polynomial coefficients a[i] (i = 0...n) from the + * expansion of root products (x - x[j]) mod q for all j. The + * method is a present from Charlie Boncelet. + */ + for (i = 0; i <= n; i++) { + a[i] = BN_new(); + BN_one(a[i]); + } + for (j = 1; j <= n; j++) { + BN_zero(w); + for (i = 0; i < j; i++) { + BN_copy(u, dsa->q); + BN_mod_mul(v, a[i], x[j], dsa->q, ctx); + BN_sub(u, u, v); + BN_add(u, u, w); + BN_copy(w, a[i]); + BN_mod(a[i], u, dsa->q, ctx); + } + } + + /* + * Generate g[i] = g^a[i] mod p for all i and the generator g. + */ + for (i = 0; i <= n; i++) { + g[i] = BN_new(); + BN_mod_exp(g[i], dsa->g, a[i], dsa->p, ctx); + } + + /* + * Verify prod(g[i]^(a[i] x[j]^i)) = 1 for all i, j. Note the + * a[i] x[j]^i exponent is computed mod q, but the g[i] is + * computed mod p. also note the expression given in the paper + * is incorrect. + */ + temp = 1; + for (j = 1; j <= n; j++) { + BN_one(u); + for (i = 0; i <= n; i++) { + BN_set_word(v, i); + BN_mod_exp(v, x[j], v, dsa->q, ctx); + BN_mod_mul(v, v, a[i], dsa->q, ctx); + BN_mod_exp(v, dsa->g, v, dsa->p, ctx); + BN_mod_mul(u, u, v, dsa->p, ctx); + } + if (!BN_is_one(u)) + temp = 0; + } + fprintf(stderr, + "Confirm prod(g[i]^(x[j]^i)) = 1 for all i, j: %s\n", temp ? + "yes" : "no"); + if (!temp) { + return (NULL); + } + + /* + * Make private encryption key A. Keep it around for awhile, + * since it is expensive to compute. + */ + biga = BN_new(); + + BN_one(biga); + for (j = 1; j <= n; j++) { + for (i = 0; i < n; i++) { + BN_set_word(v, i); + BN_mod_exp(v, x[j], v, dsa->q, ctx); + BN_mod_exp(v, g[i], v, dsa->p, ctx); + BN_mod_mul(biga, biga, v, dsa->p, ctx); + } + } + + /* + * Roll private random group key b mod q (0 < b < q), where + * gcd(b, q) = 1 to guarantee b^-1 exists, then compute b^-1 + * mod q. If b is changed, the client keys must be recomputed. + */ + while (1) { + BN_rand(b, BN_num_bits(dsa->q), 0, 0); + BN_mod(b, b, dsa->q, ctx); + BN_gcd(u, b, dsa->q, ctx); + if (BN_is_one(u)) + break; + } + BN_mod_inverse(b1, b, dsa->q, ctx); + + /* + * Make private client keys (xbar[j], xhat[j]) for all j. Note + * that the keys for the jth client do not s1[j] or the product + * s1[j]) (j = 1...n) which is q by construction. + * + * Compute the factor w such that w s1[j] = s1[j] for all j. The + * easy way to do this is to compute (q + s1[j]) / s1[j]. + * Exercise for the student: prove the remainder is always zero. + */ + for (j = 1; j <= n; j++) { + xbar[j] = BN_new(); xhat[j] = BN_new(); + + BN_add(w, dsa->q, s1[j]); + BN_div(w, u, w, s1[j], ctx); + BN_zero(xbar[j]); + BN_set_word(v, n); + for (i = 1; i <= n; i++) { + if (i == j) + continue; + + BN_mod_exp(u, x[i], v, dsa->q, ctx); + BN_add(xbar[j], xbar[j], u); + } + BN_mod_mul(xbar[j], xbar[j], b1, dsa->q, ctx); + BN_mod_exp(xhat[j], x[j], v, dsa->q, ctx); + BN_mod_mul(xhat[j], xhat[j], w, dsa->q, ctx); + } + + /* + * We revoke client j by dividing q by s1[j]. The quotient + * becomes the enabling key s. Note we always have to revoke + * one key; otherwise, the plaintext and cryptotext would be + * identical. For the present there are no provisions to revoke + * additional keys, so we sail on with only token revocations. + */ + s = BN_new(); + BN_copy(s, dsa->q); + BN_div(s, u, s, s1[n], ctx); + + /* + * For each combination of clients to be revoked, make private + * encryption key E = A^s and partial decryption keys gbar = g^s + * and ghat = g^(s b), all mod p. The servers use these keys to + * compute the session encryption key and partial decryption + * keys. These values must be regenerated if the enabling key is + * changed. + */ + bige = BN_new(); gbar = BN_new(); ghat = BN_new(); + BN_mod_exp(bige, biga, s, dsa->p, ctx); + BN_mod_exp(gbar, dsa->g, s, dsa->p, ctx); + BN_mod_mul(v, s, b, dsa->q, ctx); + BN_mod_exp(ghat, dsa->g, v, dsa->p, ctx); + + /* + * Notes: We produce the key media in three steps. The first + * step is to generate the system parameters p, q, g, b, A and + * the enabling keys s1[j]. Associated with each s1[j] are + * parameters xbar[j] and xhat[j]. All of these parameters are + * retained in a data structure protecteted by the trusted-agent + * password. The p, xbar[j] and xhat[j] paremeters are + * distributed to the j clients. When the client keys are to be + * activated, the enabled keys are multipied together to form + * the master enabling key s. This and the other parameters are + * used to compute the server encryption key E and the partial + * decryption keys gbar and ghat. + * + * In the identity exchange the client rolls random r and sends + * it to the server. The server rolls random k, which is used + * only once, then computes the session key E^k and partial + * decryption keys gbar^k and ghat^k. The server sends the + * encrypted r along with gbar^k and ghat^k to the client. The + * client completes the decryption and verifies it matches r. + */ + /* + * Write the MV trusted-agent parameters and keys as a DSA + * private key encoded in PEM. + * + * p modulus p + * q modulus q + * g generator g + * priv_key A mod p + * pub_key b mod q + * (remaining values are not used) + */ + i = 0; + str = fheader("MVta", "mvta", groupname); + fprintf(stderr, "Generating MV trusted-authority keys\n"); + BN_copy(dsa->priv_key, biga); + BN_copy(dsa->pub_key, b); + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DSA(pkey, dsa); + PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, + passwd1); + evpars[i++] = pkey; + if (debug) + DSA_print_fp(stderr, dsa, 0); + + /* + * Append the MV server parameters and keys as a DSA key encoded + * in PEM. + * + * p modulus p + * q modulus q (used only when generating k) + * g bige + * priv_key gbar + * pub_key ghat + * (remaining values are not used) + */ + fprintf(stderr, "Generating MV server keys\n"); + dsa2 = DSA_new(); + dsa2->p = BN_dup(dsa->p); + dsa2->q = BN_dup(dsa->q); + dsa2->g = BN_dup(bige); + dsa2->priv_key = BN_dup(gbar); + dsa2->pub_key = BN_dup(ghat); + pkey1 = EVP_PKEY_new(); + EVP_PKEY_assign_DSA(pkey1, dsa2); + PEM_write_PKCS8PrivateKey(str, pkey1, cipher, NULL, 0, NULL, + passwd1); + evpars[i++] = pkey1; + if (debug) + DSA_print_fp(stderr, dsa2, 0); + + /* + * Append the MV client parameters for each client j as DSA keys + * encoded in PEM. + * + * p modulus p + * priv_key xbar[j] mod q + * pub_key xhat[j] mod q + * (remaining values are not used) + */ + fprintf(stderr, "Generating %d MV client keys\n", n); + for (j = 1; j <= n; j++) { + sdsa = DSA_new(); + sdsa->p = BN_dup(dsa->p); + sdsa->q = BN_dup(BN_value_one()); + sdsa->g = BN_dup(BN_value_one()); + sdsa->priv_key = BN_dup(xbar[j]); + sdsa->pub_key = BN_dup(xhat[j]); + pkey1 = EVP_PKEY_new(); + EVP_PKEY_set1_DSA(pkey1, sdsa); + PEM_write_PKCS8PrivateKey(str, pkey1, cipher, NULL, 0, + NULL, passwd1); + evpars[i++] = pkey1; + if (debug) + DSA_print_fp(stderr, sdsa, 0); + + /* + * The product gbar^k)^xbar[j] (ghat^k)^xhat[j] and E + * are inverses of each other. We check that the product + * is one for each client except the ones that have been + * revoked. + */ + BN_mod_exp(v, dsa2->priv_key, sdsa->pub_key, dsa->p, + ctx); + BN_mod_exp(u, dsa2->pub_key, sdsa->priv_key, dsa->p, + ctx); + BN_mod_mul(u, u, v, dsa->p, ctx); + BN_mod_mul(u, u, bige, dsa->p, ctx); + if (!BN_is_one(u)) { + fprintf(stderr, "Revoke key %d\n", j); + continue; + } + } + evpars[i++] = NULL; + fclose(str); + + /* + * Free the countries. + */ + for (i = 0; i <= n; i++) { + BN_free(a[i]); BN_free(g[i]); + } + for (j = 1; j <= n; j++) { + BN_free(x[j]); BN_free(xbar[j]); BN_free(xhat[j]); + BN_free(s1[j]); + } + return (pkey); +} + + +/* + * Generate X509v3 certificate. + * + * The certificate consists of the version number, serial number, + * validity interval, issuer name, subject name and public key. For a + * self-signed certificate, the issuer name is the same as the subject + * name and these items are signed using the subject private key. The + * validity interval extends from the current time to the same time one + * year hence. For NTP purposes, it is convenient to use the NTP seconds + * of the current time as the serial number. + */ +int +x509 ( + EVP_PKEY *pkey, /* signing key */ + const EVP_MD *md, /* signature/digest scheme */ + char *gqpub, /* identity extension (hex string) */ + char *exten, /* private cert extension */ + char *name /* subject/issuer name */ + ) +{ + X509 *cert; /* X509 certificate */ + X509_NAME *subj; /* distinguished (common) name */ + X509_EXTENSION *ex; /* X509v3 extension */ + FILE *str; /* file handle */ + ASN1_INTEGER *serial; /* serial number */ + const char *id; /* digest/signature scheme name */ + char pathbuf[MAXFILENAME + 1]; + + /* + * Generate X509 self-signed certificate. + * + * Set the certificate serial to the NTP seconds for grins. Set + * the version to 3. Set the initial validity to the current + * time and the finalvalidity one year hence. + */ + id = OBJ_nid2sn(md->pkey_type); + fprintf(stderr, "Generating new certificate %s %s\n", name, id); + cert = X509_new(); + X509_set_version(cert, 2L); + serial = ASN1_INTEGER_new(); + ASN1_INTEGER_set(serial, (long)epoch + JAN_1970); + X509_set_serialNumber(cert, serial); + ASN1_INTEGER_free(serial); + X509_time_adj(X509_get_notBefore(cert), 0L, &epoch); + X509_time_adj(X509_get_notAfter(cert), lifetime * SECSPERDAY, &epoch); + subj = X509_get_subject_name(cert); + X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, + (u_char *)name, strlen(name), -1, 0); + subj = X509_get_issuer_name(cert); + X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, + (u_char *)name, strlen(name), -1, 0); + if (!X509_set_pubkey(cert, pkey)) { + fprintf(stderr, "Assign certificate signing key fails\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + X509_free(cert); + return (0); + } + + /* + * Add X509v3 extensions if present. These represent the minimum + * set defined in RFC3280 less the certificate_policy extension, + * which is seriously obfuscated in OpenSSL. + */ + /* + * The basic_constraints extension CA:TRUE allows servers to + * sign client certficitates. + */ + fprintf(stderr, "%s: %s\n", LN_basic_constraints, + BASIC_CONSTRAINTS); + ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, + BASIC_CONSTRAINTS); + if (!X509_add_ext(cert, ex, -1)) { + fprintf(stderr, "Add extension field fails\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (0); + } + X509_EXTENSION_free(ex); + + /* + * The key_usage extension designates the purposes the key can + * be used for. + */ + fprintf(stderr, "%s: %s\n", LN_key_usage, KEY_USAGE); + ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, KEY_USAGE); + if (!X509_add_ext(cert, ex, -1)) { + fprintf(stderr, "Add extension field fails\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (0); + } + X509_EXTENSION_free(ex); + /* + * The subject_key_identifier is used for the GQ public key. + * This should not be controversial. + */ + if (gqpub != NULL) { + fprintf(stderr, "%s\n", LN_subject_key_identifier); + ex = X509V3_EXT_conf_nid(NULL, NULL, + NID_subject_key_identifier, gqpub); + if (!X509_add_ext(cert, ex, -1)) { + fprintf(stderr, + "Add extension field fails\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (0); + } + X509_EXTENSION_free(ex); + } + + /* + * The extended key usage extension is used for special purpose + * here. The semantics probably do not conform to the designer's + * intent and will likely change in future. + * + * "trustRoot" designates a root authority + * "private" designates a private certificate + */ + if (exten != NULL) { + fprintf(stderr, "%s: %s\n", LN_ext_key_usage, exten); + ex = X509V3_EXT_conf_nid(NULL, NULL, + NID_ext_key_usage, exten); + if (!X509_add_ext(cert, ex, -1)) { + fprintf(stderr, + "Add extension field fails\n%s\n", + ERR_error_string(ERR_get_error(), NULL)); + return (0); + } + X509_EXTENSION_free(ex); + } + + /* + * Sign and verify. + */ + X509_sign(cert, pkey, md); + if (X509_verify(cert, pkey) <= 0) { + fprintf(stderr, "Verify %s certificate fails\n%s\n", id, + ERR_error_string(ERR_get_error(), NULL)); + X509_free(cert); + return (0); + } + + /* + * Write the certificate encoded in PEM. + */ + snprintf(pathbuf, sizeof(pathbuf), "%scert", id); + str = fheader(pathbuf, "cert", hostname); + PEM_write_X509(str, cert); + fclose(str); + if (debug) + X509_print_fp(stderr, cert); + X509_free(cert); + return (1); +} + +#if 0 /* asn2ntp is used only with commercial certificates */ +/* + * asn2ntp - convert ASN1_TIME time structure to NTP time + */ +u_long +asn2ntp ( + ASN1_TIME *asn1time /* pointer to ASN1_TIME structure */ + ) +{ + char *v; /* pointer to ASN1_TIME string */ + struct tm tm; /* time decode structure time */ + + /* + * Extract time string YYMMDDHHMMSSZ from ASN.1 time structure. + * Note that the YY, MM, DD fields start with one, the HH, MM, + * SS fiels start with zero and the Z character should be 'Z' + * for UTC. Also note that years less than 50 map to years + * greater than 100. Dontcha love ASN.1? + */ + if (asn1time->length > 13) + return (-1); + v = (char *)asn1time->data; + tm.tm_year = (v[0] - '0') * 10 + v[1] - '0'; + if (tm.tm_year < 50) + tm.tm_year += 100; + tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1; + tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0'; + tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0'; + tm.tm_min = (v[8] - '0') * 10 + v[9] - '0'; + tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0'; + tm.tm_wday = 0; + tm.tm_yday = 0; + tm.tm_isdst = 0; + return (mktime(&tm) + JAN_1970); +} +#endif + +/* + * Callback routine + */ +void +cb ( + int n1, /* arg 1 */ + int n2, /* arg 2 */ + void *chr /* arg 3 */ + ) +{ + switch (n1) { + case 0: + d0++; + fprintf(stderr, "%s %d %d %lu\r", (char *)chr, n1, n2, + d0); + break; + case 1: + d1++; + fprintf(stderr, "%s\t\t%d %d %lu\r", (char *)chr, n1, + n2, d1); + break; + case 2: + d2++; + fprintf(stderr, "%s\t\t\t\t%d %d %lu\r", (char *)chr, + n1, n2, d2); + break; + case 3: + d3++; + fprintf(stderr, "%s\t\t\t\t\t\t%d %d %lu\r", + (char *)chr, n1, n2, d3); + break; + } +} + + +/* + * Generate key + */ +EVP_PKEY * /* public/private key pair */ +genkey( + char *type, /* key type (RSA or DSA) */ + char *id /* file name id */ + ) +{ + if (type == NULL) + return (NULL); + if (strcmp(type, "RSA") == 0) + return (gen_rsa(id)); + + else if (strcmp(type, "DSA") == 0) + return (gen_dsa(id)); + + fprintf(stderr, "Invalid %s key type %s\n", id, type); + return (NULL); +} +#endif /* AUTOKEY */ + + +/* + * Generate file header and link + */ +FILE * +fheader ( + const char *file, /* file name id */ + const char *ulink, /* linkname */ + const char *owner /* owner name */ + ) +{ + FILE *str; /* file handle */ + char linkname[MAXFILENAME]; /* link name */ + int temp; + + snprintf(filename, sizeof(filename), "ntpkey_%s_%s.%u", file, + owner, fstamp); + if ((str = fopen(filename, "w")) == NULL) { + perror("Write"); + exit (-1); + } + snprintf(linkname, sizeof(linkname), "ntpkey_%s_%s", ulink, + hostname); + (void)remove(linkname); /* The symlink() line below matters */ + temp = symlink(filename, linkname); + if (temp < 0) + perror(file); + fprintf(stderr, "Generating new %s file and link\n", ulink); + fprintf(stderr, "%s->%s\n", linkname, filename); + fprintf(str, "# %s\n# %s\n", filename, ctime(&epoch)); + return (str); +} diff --git a/util/ntp-keygen.html b/util/ntp-keygen.html new file mode 100644 index 0000000..b5315d2 --- /dev/null +++ b/util/ntp-keygen.html @@ -0,0 +1,1811 @@ +<html lang="en"> +<head> +<title>Ntp-keygen User's Manual</title> +<meta http-equiv="Content-Type" content="text/html"> +<meta name="description" content="Ntp-keygen User's Manual"> +<meta name="generator" content="makeinfo 4.7"> +<link title="Top" rel="top" href="#Top"> +<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage"> +<meta http-equiv="Content-Style-Type" content="text/css"> +<style type="text/css"><!-- + pre.display { font-family:inherit } + pre.format { font-family:inherit } + pre.smalldisplay { font-family:inherit; font-size:smaller } + pre.smallformat { font-family:inherit; font-size:smaller } + pre.smallexample { font-size:smaller } + pre.smalllisp { font-size:smaller } + span.sc { font-variant:small-caps } + span.roman { font-family: serif; font-weight: normal; } +--></style> +</head> +<body> +<h1 class="settitle">Ntp-keygen User's Manual</h1> + <div class="shortcontents"> +<h2>Short Contents</h2> +<ul> +<a href="#Top">Top</a> +<a href="#Top">NTP Key Generation Program User Manual</a> +</ul> +</div> + + + +<div class="node"> +<p><hr> +<a name="Top"></a>Up: <a rel="up" accesskey="u" href="#dir">(dir)</a> +<br> +</div> + +<h2 class="unnumbered">Top</h2> + +<ul class="menu"> +<li><a accesskey="1" href="#Description">Description</a> +<li><a accesskey="2" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a>: Invoking ntp-keygen +<li><a accesskey="3" href="#Running-the-Program">Running the Program</a> +<li><a accesskey="4" href="#Random-Seed-File">Random Seed File</a> +<li><a accesskey="5" href="#Cryptographic-Data-Files">Cryptographic Data Files</a> +</ul> + +<div class="node"> +<p><hr> +<a name="Top"></a>Next: <a rel="next" accesskey="n" href="#Description">Description</a>, +Previous: <a rel="previous" accesskey="p" href="#dir">(dir)</a>, +Up: <a rel="up" accesskey="u" href="#dir">(dir)</a> +<br> +</div> + +<h2 class="unnumbered">NTP Key Generation Program User Manual</h2> + +<p>This document describes the use of the NTP Project's <code>ntp-keygen</code> +program, that generates cryptographic data files used by the NTPv4 +authentication and identity schemes. +It can generate message digest keys used in symmetric key cryptography and, +if the OpenSSL software +library has been installed, it can generate host keys, sign keys, +certificates, and identity keys and parameters used by the Autokey +public key cryptography. +The message digest keys file is generated in a +format compatible with NTPv3. +All other files are in PEM-encoded +printable ASCII format so they can be embedded as MIME attachments in +mail to other sites. + + <p>This document applies to version 4.2.7p482 of <code>ntp-keygen</code>. + +<div class="node"> +<p><hr> +<a name="Description"></a>Next: <a rel="next" accesskey="n" href="#Running-the-Program">Running the Program</a>, +Previous: <a rel="previous" accesskey="p" href="#Top">Top</a>, +Up: <a rel="up" accesskey="u" href="#Top">Top</a> +<br> +</div> + +<!-- node-name, next, previous, up --> +<h3 class="section">Description</h3> + +<p>This program generates cryptographic data files used by the NTPv4 +authentication and identity schemes. It can generate message digest +keys used in symmetric key cryptography and, if the OpenSSL software +library has been installed, it can generate host keys, sign keys, +certificates, and identity keys and parameters used by the Autokey +public key cryptography. The message digest keys file is generated in a +format compatible with NTPv3. All other files are in PEM-encoded +printable ASCII format so they can be embedded as MIME attachments in +mail to other sites. + + <p>When used to generate message digest keys, the program produces a file +containing ten pseudo-random printable ASCII strings suitable for the +MD5 message digest algorithm included in the distribution. +If the +OpenSSL library is installed, it produces an additional ten hex-encoded +random bit strings suitable for the SHA1 and other message digest +algorithms. +The message digest keys file must be distributed and stored +using secure means beyond the scope of NTP itself. +Besides the keys +used for ordinary NTP associations, additional keys can be defined as +passwords for the ntpq and ntpdc utility programs. + + <p>The remaining generated files are compatible with other OpenSSL +applications and other Public Key Infrastructure (PKI) resources. +Certificates generated by this program are compatible with extant +industry practice, although some users might find the interpretation of +X509v3 extension fields somewhat liberal. +However, the identity keys +are probably not compatible with anything other than Autokey. + + <p>Some files used by this program are encrypted using a private password. +The <code>-p</code> option specifies the password for local encrypted files and the +<code>-q</code> option the password for encrypted files sent to remote sites. +If no password is specified, the host name returned by the Unix +<code>gethostname()</code> function, normally the DNS name of the host, is used. + + <p>The <kbd>pw</kbd> option of the <code>crypto</code> configuration command +specifies the read password for previously encrypted local files. +This must match the local password used by this program. +If not specified, the host name is used. +Thus, if files are generated by this program without password, +they can be read back by ntpd without password, but only on the same +host. + + <p>Normally, encrypted files for each host are generated by that host and +used only by that host, although exceptions exist as noted later on +this page. +The symmetric keys file, normally called <code>ntp.keys</code>, is +usually installed in <code>/etc</code>. +Other files and links are usually installed +in <code>/usr/local/etc</code>, which is normally in a shared filesystem in +NFS-mounted networks and cannot be changed by shared clients. +The location of the keys directory can be changed by the keysdir +configuration command in such cases. +Normally, this is in <code>/etc</code>. + + <p>This program directs commentary and error messages to the standard +error stream <code>stderr</code> and remote files to the standard output stream +<code>stdout</code> where they can be piped to other applications or redirected to +files. +The names used for generated files and links all begin with the +string <code>ntpkey</code> and include the file type, +generating host and filestamp, +as described in the <a href="#Cryptographic-Data-Files">Cryptographic Data Files</a> section below. + +<div class="node"> +<p><hr> +<a name="Running-the-Program"></a>Next: <a rel="next" accesskey="n" href="#Random-Seed-File">Random Seed File</a>, +Previous: <a rel="previous" accesskey="p" href="#Description">Description</a>, +Up: <a rel="up" accesskey="u" href="#Top">Top</a> +<br> +</div> + +<!-- node-name, next, previous, up --> +<h3 class="section">Running the Program</h3> + +<p>To test and gain experience with Autokey concepts, log in as root and +change to the keys directory, usually <code>/usr/local/etc</code>. +When run for the +first time, or if all files with names beginning <code>ntpkey</code>] have been +removed, use the <code>ntp-keygen</code> command without arguments to generate a +default RSA host key and matching RSA-MD5 certificate with expiration +date one year hence. +If run again without options, the program uses the +existing keys and parameters and generates only a new certificate with +new expiration date one year hence. + + <p>Run the command on as many hosts as necessary. +Designate one of them as the trusted host (TH) using <code>ntp-keygen</code> +with the <code>-T</code> option and configure +it to synchronize from reliable Internet servers. +Then configure the other hosts to synchronize to the TH directly or indirectly. +A certificate trail is created when Autokey asks the immediately +ascendant host towards the TH to sign its certificate, which is then +provided to the immediately descendant host on request. +All group hosts should have acyclic certificate trails ending on the TH. + + <p>The host key is used to encrypt the cookie when required and so must be +RSA type. +By default, the host key is also the sign key used to encrypt signatures. +A different sign key can be assigned using the <code>-S</code> option +and this can be either RSA or DSA type. +By default, the signature +message digest type is MD5, but any combination of sign key type and +message digest type supported by the OpenSSL library can be specified +using the <code>-c</code> option. + + <p>The rules say cryptographic media should be generated with proventic +filestamps, which means the host should already be synchronized before +this program is run. +This of course creates a chicken-and-egg problem +when the host is started for the first time. +Accordingly, the host time +should be set by some other means, such as eyeball-and-wristwatch, at +least so that the certificate lifetime is within the current year. +After that and when the host is synchronized to a proventic source, the +certificate should be re-generated. + + <p>Additional information on trusted groups and identity schemes is on the +Autokey Public-Key Authentication page. + +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-Invocation"></a> +<br> +</div> + +<h3 class="section">Invoking ntp-keygen</h3> + +<p><a name="index-ntp_002dkeygen-1"></a><a name="index-Create-a-NTP-host-key-2"></a> + + <p>This program generates cryptographic data files used by the NTPv4 +authentication and identification schemes. +It generates MD5 key files used in symmetric key cryptography. +In addition, if the OpenSSL software library has been installed, +it generates keys, certificate and identity files used in public key +cryptography. +These files are used for cookie encryption, +digital signature and challenge/response identification algorithms +compatible with the Internet standard security infrastructure. + + <p>All files are in PEM-encoded printable ASCII format, +so they can be embedded as MIME attachments in mail to other sites +and certificate authorities. +By default, files are not encrypted. + + <p>When used to generate message digest keys, the program produces a file +containing ten pseudo-random printable ASCII strings suitable for the +MD5 message digest algorithm included in the distribution. +If the OpenSSL library is installed, it produces an additional ten +hex-encoded random bit strings suitable for the SHA1 and other message +digest algorithms. +The message digest keys file must be distributed and stored +using secure means beyond the scope of NTP itself. +Besides the keys used for ordinary NTP associations, additional keys +can be defined as passwords for the +<code>ntpq(1ntpqmdoc)</code> +and +<code>ntpdc(1ntpdcmdoc)</code> +utility programs. + + <p>The remaining generated files are compatible with other OpenSSL +applications and other Public Key Infrastructure (PKI) resources. +Certificates generated by this program are compatible with extant +industry practice, although some users might find the interpretation of +X509v3 extension fields somewhat liberal. +However, the identity keys are probably not compatible with anything +other than Autokey. + + <p>Some files used by this program are encrypted using a private password. +The +<code>-p</code> +option specifies the password for local encrypted files and the +<code>-q</code> +option the password for encrypted files sent to remote sites. +If no password is specified, the host name returned by the Unix +<code>gethostname()</code> +function, normally the DNS name of the host is used. + + <p>The +<kbd>pw</kbd> +option of the +<kbd>crypto</kbd> +configuration command specifies the read +password for previously encrypted local files. +This must match the local password used by this program. +If not specified, the host name is used. +Thus, if files are generated by this program without password, +they can be read back by +<kbd>ntpd</kbd> +without password but only on the same host. + + <p>Normally, encrypted files for each host are generated by that host and +used only by that host, although exceptions exist as noted later on +this page. +The symmetric keys file, normally called +<kbd>ntp.keys</kbd>, +is usually installed in +<span class="file">/etc</span>. +Other files and links are usually installed in +<span class="file">/usr/local/etc</span>, +which is normally in a shared filesystem in +NFS-mounted networks and cannot be changed by shared clients. +The location of the keys directory can be changed by the +<kbd>keysdir</kbd> +configuration command in such cases. +Normally, this is in +<span class="file">/etc</span>. + + <p>This program directs commentary and error messages to the standard +error stream +<kbd>stderr</kbd> +and remote files to the standard output stream +<kbd>stdout</kbd> +where they can be piped to other applications or redirected to files. +The names used for generated files and links all begin with the +string +<kbd>ntpkey</kbd> +and include the file type, generating host and filestamp, +as described in the +Cryptographic Data Files +section below. + +<h5 class="subsubsection">Running the Program</h5> + +<p>To test and gain experience with Autokey concepts, log in as root and +change to the keys directory, usually +<span class="file">/usr/local/etc</span> +When run for the first time, or if all files with names beginning with +<kbd>ntpkey</kbd> +have been removed, use the +<code>ntp-keygen</code> +command without arguments to generate a +default RSA host key and matching RSA-MD5 certificate with expiration +date one year hence. +If run again without options, the program uses the +existing keys and parameters and generates only a new certificate with +new expiration date one year hence. + + <p>Run the command on as many hosts as necessary. +Designate one of them as the trusted host (TH) using +<code>ntp-keygen</code> +with the +<code>-T</code> +option and configure it to synchronize from reliable Internet servers. +Then configure the other hosts to synchronize to the TH directly or +indirectly. +A certificate trail is created when Autokey asks the immediately +ascendant host towards the TH to sign its certificate, which is then +provided to the immediately descendant host on request. +All group hosts should have acyclic certificate trails ending on the TH. + + <p>The host key is used to encrypt the cookie when required and so must be +RSA type. +By default, the host key is also the sign key used to encrypt +signatures. +A different sign key can be assigned using the +<code>-S</code> +option and this can be either RSA or DSA type. +By default, the signature +message digest type is MD5, but any combination of sign key type and +message digest type supported by the OpenSSL library can be specified +using the +<code>-c</code> +option. +The rules say cryptographic media should be generated with proventic +filestamps, which means the host should already be synchronized before +this program is run. +This of course creates a chicken-and-egg problem +when the host is started for the first time. +Accordingly, the host time +should be set by some other means, such as eyeball-and-wristwatch, at +least so that the certificate lifetime is within the current year. +After that and when the host is synchronized to a proventic source, the +certificate should be re-generated. + + <p>Additional information on trusted groups and identity schemes is on the +Autokey Public-Key Authentication +page. + + <p>The +<code>ntpd(1ntpdmdoc)</code> +configuration command +<code>crypto</code> <code>pw</code> <kbd>password</kbd> +specifies the read password for previously encrypted files. +The daemon expires on the spot if the password is missing +or incorrect. +For convenience, if a file has been previously encrypted, +the default read password is the name of the host running +the program. +If the previous write password is specified as the host name, +these files can be read by that host with no explicit password. + + <p>File names begin with the prefix +<code>ntpkey_</code> +and end with the postfix +<kbd>_hostname.filestamp</kbd>, +where +<kbd>hostname</kbd> +is the owner name, usually the string returned +by the Unix gethostname() routine, and +<kbd>filestamp</kbd> +is the NTP seconds when the file was generated, in decimal digits. +This both guarantees uniqueness and simplifies maintenance +procedures, since all files can be quickly removed +by a +<code>rm</code> <code>ntpkey*</code> +command or all files generated +at a specific time can be removed by a +<code>rm</code> +<kbd>*filestamp</kbd> +command. +To further reduce the risk of misconfiguration, +the first two lines of a file contain the file name +and generation date and time as comments. + + <p>All files are installed by default in the keys directory +<span class="file">/usr/local/etc</span>, +which is normally in a shared filesystem +in NFS-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. + + <p>Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. + + <p>The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +<code>ntpd(1ntpdmdoc)</code> +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +<code>ntp-keygen</code> +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. + +<h5 class="subsubsection">Running the program</h5> + +<p>The safest way to run the +<code>ntp-keygen</code> +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +<span class="file">/usr/local/etc</span>, +then run the program. +When run for the first time, +or if all +<code>ntpkey</code> +files have been removed, +the program generates a RSA host key file and matching RSA-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. + + <p>The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. + + <p>Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. + + <p>Running the program as other than root and using the Unix +<code>su</code> +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +<code>.rnd</code> +in the user home directory. +However, there should be only one +<code>.rnd</code>, +most conveniently +in the root directory, so it is convenient to define the +<code>$RANDFILE</code> +environment variable used by the OpenSSL library as the path to +<code>/.rnd</code>. + + <p>Installing the keys as root might not work in NFS-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +<span class="file">/etc</span> +using the +<code>keysdir</code> +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. + + <p>Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. + + <p>All files are installed by default in the keys directory +<span class="file">/usr/local/etc</span>, +which is normally in a shared filesystem +in NFS-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. + + <p>Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. + + <p>The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +<code>ntpd(1ntpdmdoc)</code> +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +<code>ntp-keygen</code> +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. + +<h5 class="subsubsection">Running the program</h5> + +<p>The safest way to run the +<code>ntp-keygen</code> +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +<span class="file">/usr/local/etc</span>, +then run the program. +When run for the first time, +or if all +<code>ntpkey</code> +files have been removed, +the program generates a RSA host key file and matching RSA-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. + + <p>The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. + + <p>Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. + + <p>Running the program as other than root and using the Unix +<code>su</code> +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +<code>.rnd</code> +in the user home directory. +However, there should be only one +<code>.rnd</code>, +most conveniently +in the root directory, so it is convenient to define the +<code>$RANDFILE</code> +environment variable used by the OpenSSL library as the path to +<code>/.rnd</code>. + + <p>Installing the keys as root might not work in NFS-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +<span class="file">/etc</span> +using the +<code>keysdir</code> +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. + + <p>Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +seconds. +seconds. + + <p>s Trusted Hosts and Groups +Each cryptographic configuration involves selection of a signature scheme +and identification scheme, called a cryptotype, +as explained in the +<a href="#Authentication-Options">Authentication Options</a> +section of +<code>ntp.conf(5)</code>. +The default cryptotype uses RSA encryption, MD5 message digest +and TC identification. +First, configure a NTP subnet including one or more low-stratum +trusted hosts from which all other hosts derive synchronization +directly or indirectly. +Trusted hosts have trusted certificates; +all other hosts have nontrusted certificates. +These hosts will automatically and dynamically build authoritative +certificate trails to one or more trusted hosts. +A trusted group is the set of all hosts that have, directly or indirectly, +a certificate trail ending at a trusted host. +The trail is defined by static configuration file entries +or dynamic means described on the +<a href="#Automatic-NTP-Configuration-Options">Automatic NTP Configuration Options</a> +section of +<code>ntp.conf(5)</code>. + + <p>On each trusted host as root, change to the keys directory. +To insure a fresh fileset, remove all +<code>ntpkey</code> +files. +Then run +<code>ntp-keygen</code> +<code>-T</code> +to generate keys and a trusted certificate. +On all other hosts do the same, but leave off the +<code>-T</code> +flag to generate keys and nontrusted certificates. +When complete, start the NTP daemons beginning at the lowest stratum +and working up the tree. +It may take some time for Autokey to instantiate the certificate trails +throughout the subnet, but setting up the environment is completely automatic. + + <p>If it is necessary to use a different sign key or different digest/signature +scheme than the default, run +<code>ntp-keygen</code> +with the +<code>-S</code> <kbd>type</kbd> +option, where +<kbd>type</kbd> +is either +<code>RSA</code> +or +<code>DSA</code>. +The most often need to do this is when a DSA-signed certificate is used. +If it is necessary to use a different certificate scheme than the default, +run +<code>ntp-keygen</code> +with the +<code>-c</code> <kbd>scheme</kbd> +option and selected +<kbd>scheme</kbd> +as needed. +f +<code>ntp-keygen</code> +is run again without these options, it generates a new certificate +using the same scheme and sign key. + + <p>After setting up the environment it is advisable to update certificates +from time to time, if only to extend the validity interval. +Simply run +<code>ntp-keygen</code> +with the same flags as before to generate new certificates +using existing keys. +However, if the host or sign key is changed, +<code>ntpd(1ntpdmdoc)</code> +should be restarted. +When +<code>ntpd(1ntpdmdoc)</code> +is restarted, it loads any new files and restarts the protocol. +Other dependent hosts will continue as usual until signatures are refreshed, +at which time the protocol is restarted. + +<h5 class="subsubsection">Identity Schemes</h5> + +<p>As mentioned on the Autonomous Authentication page, +the default TC identity scheme is vulnerable to a middleman attack. +However, there are more secure identity schemes available, +including PC, IFF, GQ and MV described on the +"Identification Schemes" +page +(maybe available at +<code>http://www.eecis.udel.edu/%7emills/keygen.html</code>). +These schemes are based on a TA, one or more trusted hosts +and some number of nontrusted hosts. +Trusted hosts prove identity using values provided by the TA, +while the remaining hosts prove identity using values provided +by a trusted host and certificate trails that end on that host. +The name of a trusted host is also the name of its sugroup +and also the subject and issuer name on its trusted certificate. +The TA is not necessarily a trusted host in this sense, but often is. + + <p>In some schemes there are separate keys for servers and clients. +A server can also be a client of another server, +but a client can never be a server for another client. +In general, trusted hosts and nontrusted hosts that operate +as both server and client have parameter files that contain +both server and client keys. +Hosts that operate +only as clients have key files that contain only client keys. + + <p>The PC scheme supports only one trusted host in the group. +On trusted host alice run +<code>ntp-keygen</code> +<code>-P</code> +<code>-p</code> <kbd>password</kbd> +to generate the host key file +<span class="file">ntpkey_RSAkey_</span><kbd>alice.filestamp</kbd> +and trusted private certificate file +<span class="file">ntpkey_RSA-MD5_cert_</span><kbd>alice.filestamp</kbd>. +Copy both files to all group hosts; +they replace the files which would be generated in other schemes. +On each host bob install a soft link from the generic name +<span class="file">ntpkey_host_</span><kbd>bob</kbd> +to the host key file and soft link +<span class="file">ntpkey_cert_</span><kbd>bob</kbd> +to the private certificate file. +Note the generic links are on bob, but point to files generated +by trusted host alice. +In this scheme it is not possible to refresh +either the keys or certificates without copying them +to all other hosts in the group. + + <p>For the IFF scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host in the group, +generate the IFF parameter file. +On trusted host alice run +<code>ntp-keygen</code> +<code>-T</code> +<code>-I</code> +<code>-p</code> <kbd>password</kbd> +to produce her parameter file +<span class="file">ntpkey_IFFpar_</span><kbd>alice.filestamp</kbd>, +which includes both server and client keys. +Copy this file to all group hosts that operate as both servers +and clients and install a soft link from the generic +<span class="file">ntpkey_iff_</span><kbd>alice</kbd> +to this file. +If there are no hosts restricted to operate only as clients, +there is nothing further to do. +As the IFF scheme is independent +of keys and certificates, these files can be refreshed as needed. + + <p>If a rogue client has the parameter file, it could masquerade +as a legitimate server and present a middleman threat. +To eliminate this threat, the client keys can be extracted +from the parameter file and distributed to all restricted clients. +After generating the parameter file, on alice run +<code>ntp-keygen</code> +<code>-e</code> +and pipe the output to a file or mail program. +Copy or mail this file to all restricted clients. +On these clients install a soft link from the generic +<span class="file">ntpkey_iff_</span><kbd>alice</kbd> +to this file. +To further protect the integrity of the keys, +each file can be encrypted with a secret password. + + <p>For the GQ scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host +in the group, generate the IFF parameter file. +On trusted host alice run +<code>ntp-keygen</code> +<code>-T</code> +<code>-G</code> +<code>-p</code> <kbd>password</kbd> +to produce her parameter file +<span class="file">ntpkey_GQpar_</span><kbd>alice.filestamp</kbd>, +which includes both server and client keys. +Copy this file to all group hosts and install a soft link +from the generic +<span class="file">ntpkey_gq_</span><kbd>alice</kbd> +to this file. +In addition, on each host bob install a soft link +from generic +<span class="file">ntpkey_gq_</span><kbd>bob</kbd> +to this file. +As the GQ scheme updates the GQ parameters file and certificate +at the same time, keys and certificates can be regenerated as needed. + + <p>For the MV scheme, proceed as in the TC scheme to generate keys +and certificates for all group hosts. +For illustration assume trish is the TA, alice one of several trusted hosts +and bob one of her clients. +On TA trish run +<code>ntp-keygen</code> +<code>-V</code> <kbd>n</kbd> +<code>-p</code> <kbd>password</kbd>, +where +<kbd>n</kbd> +is the number of revokable keys (typically 5) to produce +the parameter file +<span class="file">ntpkeys_MVpar_</span><kbd>trish.filestamp</kbd> +and client key files +<span class="file">ntpkeys_MVkeyd_</span><kbd>trish.filestamp</kbd> +where +<kbd>d</kbd> +is the key number (0 < +<kbd>d</kbd> +< +<kbd>n</kbd>). +Copy the parameter file to alice and install a soft link +from the generic +<span class="file">ntpkey_mv_</span><kbd>alice</kbd> +to this file. +Copy one of the client key files to alice for later distribution +to her clients. +It doesn't matter which client key file goes to alice, +since they all work the same way. +Alice copies the client key file to all of her cliens. +On client bob install a soft link from generic +<span class="file">ntpkey_mvkey_</span><kbd>bob</kbd> +to the client key file. +As the MV scheme is independent of keys and certificates, +these files can be refreshed as needed. + +<h5 class="subsubsection">Command Line Options</h5> + + <dl> +<dt><code>-c</code> <kbd>scheme</kbd><dd>Select certificate message digest/signature encryption scheme. +The +<kbd>scheme</kbd> +can be one of the following: +. Cm RSA-MD2 , RSA-MD5 , RSA-SHA , RSA-SHA1 , RSA-MDC2 , RSA-RIPEMD160 , DSA-SHA , +or +<code>DSA-SHA1</code>. +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. +The default without this option is +<code>RSA-MD5</code>. +<br><dt><code>-d</code><dd>Enable debugging. +This option displays the cryptographic data produced in eye-friendly billboards. +<br><dt><code>-e</code><dd>Write the IFF client keys to the standard output. +This is intended for automatic key distribution by mail. +<br><dt><code>-G</code><dd>Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +<br><dt><code>-g</code><dd>Generate keys for the GQ identification scheme +using the existing GQ parameters. +If the GQ parameters do not yet exist, create them first. +<br><dt><code>-H</code><dd>Generate new host keys, obsoleting any that may exist. +<br><dt><code>-I</code><dd>Generate parameters for the IFF identification scheme, +obsoleting any that may exist. +<br><dt><code>-i</code> <kbd>name</kbd><dd>Set the suject name to +<kbd>name</kbd>. +This is used as the subject field in certificates +and in the file name for host and sign keys. +<br><dt><code>-M</code><dd>Generate MD5 keys, obsoleting any that may exist. +<br><dt><code>-P</code><dd>Generate a private certificate. +By default, the program generates public certificates. +<br><dt><code>-p</code> <kbd>password</kbd><dd>Encrypt generated files containing private data with +<kbd>password</kbd> +and the DES-CBC algorithm. +<br><dt><code>-q</code><dd>Set the password for reading files to password. +<br><dt><code>-S</code> <code>[RSA | DSA]</code><dd>Generate a new sign key of the designated type, +obsoleting any that may exist. +By default, the program uses the host key as the sign key. +<br><dt><code>-s</code> <kbd>name</kbd><dd>Set the issuer name to +<kbd>name</kbd>. +This is used for the issuer field in certificates +and in the file name for identity files. +<br><dt><code>-T</code><dd>Generate a trusted certificate. +By default, the program generates a non-trusted certificate. +<br><dt><code>-V</code> <kbd>nkeys</kbd><dd>Generate parameters and keys for the Mu-Varadharajan (MV) identification scheme. +</dl> + +<h5 class="subsubsection">Random Seed File</h5> + +<p>All cryptographically sound key generation schemes must have means +to randomize the entropy seed used to initialize +the internal pseudo-random number generator used +by the library routines. +The OpenSSL library uses a designated random seed file for this purpose. +The file must be available when starting the NTP daemon and +<code>ntp-keygen</code> +program. +If a site supports OpenSSL or its companion OpenSSH, +it is very likely that means to do this are already available. + + <p>It is important to understand that entropy must be evolved +for each generation, for otherwise the random number sequence +would be predictable. +Various means dependent on external events, such as keystroke intervals, +can be used to do this and some systems have built-in entropy sources. +Suitable means are described in the OpenSSL software documentation, +but are outside the scope of this page. + + <p>The entropy seed used by the OpenSSL library is contained in a file, +usually called +<code>.rnd</code>, +which must be available when starting the NTP daemon +or the +<code>ntp-keygen</code> +program. +The NTP daemon will first look for the file +using the path specified by the +<code>randfile</code> +subcommand of the +<code>crypto</code> +configuration command. +If not specified in this way, or when starting the +<code>ntp-keygen</code> +program, +the OpenSSL library will look for the file using the path specified +by the +.Ev RANDFILE +environment variable in the user home directory, +whether root or some other user. +If the +.Ev RANDFILE +environment variable is not present, +the library will look for the +<code>.rnd</code> +file in the user home directory. +If the file is not available or cannot be written, +the daemon exits with a message to the system log and the program +exits with a suitable error message. + +<h5 class="subsubsection">Cryptographic Data Files</h5> + +<p>All other file formats begin with two lines. +The first contains the file name, including the generated host name +and filestamp. +The second contains the datestamp in conventional Unix date format. +Lines beginning with # are considered comments and ignored by the +<code>ntp-keygen</code> +program and +<code>ntpd(1ntpdmdoc)</code> +daemon. +Cryptographic values are encoded first using ASN.1 rules, +then encrypted if necessary, and finally written PEM-encoded +printable ASCII format preceded and followed by MIME content identifier lines. + + <p>The format of the symmetric keys file is somewhat different +than the other files in the interest of backward compatibility. +Since DES-CBC is deprecated in NTPv4, the only key format of interest +is MD5 alphanumeric strings. +Following hte heard the keys are +entered one per line in the format +<pre class="example"> <kbd>keyno</kbd> <kbd>type</kbd> <kbd>key</kbd> +</pre> + <p>where +<kbd>keyno</kbd> +is a positive integer in the range 1-65,535, +<kbd>type</kbd> +is the string MD5 defining the key format and +<kbd>key</kbd> +is the key itself, +which is a printable ASCII string 16 characters or less in length. +Each character is chosen from the 93 printable characters +in the range 0x21 through 0x7f excluding space and the +# +character. + + <p>Note that the keys used by the +<code>ntpq(1ntpqmdoc)</code> +and +<code>ntpdc(1ntpdcmdoc)</code> +programs +are checked against passwords requested by the programs +and entered by hand, so it is generally appropriate to specify these keys +in human readable ASCII format. + + <p>The +<code>ntp-keygen</code> +program generates a MD5 symmetric keys file +<span class="file">ntpkey_MD5key_</span><kbd>hostname.filestamp</kbd>. +Since the file contains private shared keys, +it should be visible only to root and distributed by secure means +to other subnet hosts. +The NTP daemon loads the file +<span class="file">ntp.keys</span>, +so +<code>ntp-keygen</code> +installs a soft link from this name to the generated file. +Subsequently, similar soft links must be installed by manual +or automated means on the other subnet hosts. +While this file is not used with the Autokey Version 2 protocol, +it is needed to authenticate some remote configuration commands +used by the +<code>ntpq(1ntpqmdoc)</code> +and +<code>ntpdc(1ntpdcmdoc)</code> +utilities. + + <p>This section was generated by <strong>AutoGen</strong>, +using the <code>agtexi-cmd</code> template and the option descriptions for the <code>ntp-keygen</code> program. +This software is released under the NTP license, <http://ntp.org/license>. + +<ul class="menu"> +<li><a accesskey="1" href="#ntp_002dkeygen-usage">ntp-keygen usage</a>: ntp-keygen help/usage (<span class="option">--help</span>) +<li><a accesskey="2" href="#ntp_002dkeygen-imbits">ntp-keygen imbits</a>: imbits option (-b) +<li><a accesskey="3" href="#ntp_002dkeygen-certificate">ntp-keygen certificate</a>: certificate option (-c) +<li><a accesskey="4" href="#ntp_002dkeygen-cipher">ntp-keygen cipher</a>: cipher option (-C) +<li><a accesskey="5" href="#ntp_002dkeygen-id_002dkey">ntp-keygen id-key</a>: id-key option (-e) +<li><a accesskey="6" href="#ntp_002dkeygen-gq_002dparams">ntp-keygen gq-params</a>: gq-params option (-G) +<li><a accesskey="7" href="#ntp_002dkeygen-host_002dkey">ntp-keygen host-key</a>: host-key option (-H) +<li><a accesskey="8" href="#ntp_002dkeygen-iffkey">ntp-keygen iffkey</a>: iffkey option (-I) +<li><a accesskey="9" href="#ntp_002dkeygen-ident">ntp-keygen ident</a>: ident option (-i) +<li><a href="#ntp_002dkeygen-lifetime">ntp-keygen lifetime</a>: lifetime option (-l) +<li><a href="#ntp_002dkeygen-md5key">ntp-keygen md5key</a>: md5key option (-M) +<li><a href="#ntp_002dkeygen-modulus">ntp-keygen modulus</a>: modulus option (-m) +<li><a href="#ntp_002dkeygen-pvt_002dcert">ntp-keygen pvt-cert</a>: pvt-cert option (-P) +<li><a href="#ntp_002dkeygen-password">ntp-keygen password</a>: password option (-p) +<li><a href="#ntp_002dkeygen-export_002dpasswd">ntp-keygen export-passwd</a>: export-passwd option (-q) +<li><a href="#ntp_002dkeygen-sign_002dkey">ntp-keygen sign-key</a>: sign-key option (-S) +<li><a href="#ntp_002dkeygen-subject_002dname">ntp-keygen subject-name</a>: subject-name option (-s) +<li><a href="#ntp_002dkeygen-trusted_002dcert">ntp-keygen trusted-cert</a>: trusted-cert option (-T) +<li><a href="#ntp_002dkeygen-mv_002dparams">ntp-keygen mv-params</a>: mv-params option (-V) +<li><a href="#ntp_002dkeygen-mv_002dkeys">ntp-keygen mv-keys</a>: mv-keys option (-v) +<li><a href="#ntp_002dkeygen-config">ntp-keygen config</a>: presetting/configuring ntp-keygen +<li><a href="#ntp_002dkeygen-exit-status">ntp-keygen exit status</a>: exit status +<li><a href="#ntp_002dkeygen-Usage">ntp-keygen Usage</a>: Usage +<li><a href="#ntp_002dkeygen-Notes">ntp-keygen Notes</a>: Notes +<li><a href="#ntp_002dkeygen-Bugs">ntp-keygen Bugs</a>: Bugs +</ul> + +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-usage"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-imbits">ntp-keygen imbits</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">ntp-keygen help/usage (<span class="option">--help</span>)</h4> + +<p><a name="index-ntp_002dkeygen-help-3"></a> +This is the automatically generated usage text for ntp-keygen. + + <p>The text printed is the same whether selected with the <code>help</code> option +(<span class="option">--help</span>) or the <code>more-help</code> option (<span class="option">--more-help</span>). <code>more-help</code> will print +the usage text by passing it through a pager program. +<code>more-help</code> is disabled on platforms without a working +<code>fork(2)</code> function. The <code>PAGER</code> environment variable is +used to select the program, defaulting to <span class="file">more</span>. Both will exit +with a status code of 0. + +<pre class="example">ntp-keygen (ntp) - Create a NTP host key - Ver. 4.2.7p481 +Usage: ntp-keygen [ -<flag> [<val>] | --<name>[{=| }<val>] ]... + Flg Arg Option-Name Description + -b Num imbits identity modulus bits + - it must be in the range: + 256 to 2048 + -c Str certificate certificate scheme + -C Str cipher privatekey cipher + -d no debug-level Increase debug verbosity level + - may appear multiple times + -D Num set-debug-level Set the debug verbosity level + - may appear multiple times + -e no id-key Write IFF or GQ identity keys + -G no gq-params Generate GQ parameters and keys + -H no host-key generate RSA host key + -I no iffkey generate IFF parameters + -i Str ident set Autokey group name + -l Num lifetime set certificate lifetime + -M no md5key generate MD5 keys + -m Num modulus modulus + - it must be in the range: + 256 to 2048 + -P no pvt-cert generate PC private certificate + -p Str password local private password + -q Str export-passwd export IFF or GQ group keys with password + -S Str sign-key generate sign key (RSA or DSA) + -s Str subject-name set host and optionally group name + -T no trusted-cert trusted certificate (TC scheme) + -V Num mv-params generate <num> MV parameters + -v Num mv-keys update <num> MV keys + opt version output version information and exit + -? no help display extended usage information and exit + -! no more-help extended usage information passed thru pager + -> opt save-opts save the option state to a config file + -< Str load-opts load options from a config file + - disabled as '--no-load-opts' + - may appear multiple times + +Options are specified by doubled hyphens and their name or by a single +hyphen and the flag character. + + +The following option preset mechanisms are supported: + - reading file $HOME/.ntprc + - reading file ./.ntprc + - examining environment variables named NTP_KEYGEN_* + +Please send bug reports to: <http://bugs.ntp.org, bugs@ntp.org> +</pre> + <div class="node"> +<p><hr> +<a name="ntp_002dkeygen-imbits"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-certificate">ntp-keygen certificate</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-usage">ntp-keygen usage</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">imbits option (-b)</h4> + +<p><a name="index-ntp_002dkeygen_002dimbits-4"></a> +This is the “identity modulus bits” option. +This option takes a number argument <span class="file">imbits</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>The number of bits in the identity modulus. The default is 256. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-certificate"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-cipher">ntp-keygen cipher</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-imbits">ntp-keygen imbits</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">certificate option (-c)</h4> + +<p><a name="index-ntp_002dkeygen_002dcertificate-5"></a> +This is the “certificate scheme” option. +This option takes a string argument <span class="file">scheme</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>scheme is one of +RSA-MD2, RSA-MD5, RSA-SHA, RSA-SHA1, RSA-MDC2, RSA-RIPEMD160, +DSA-SHA, or DSA-SHA1. + + <p>Select the certificate message digest/signature encryption scheme. +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. The default without +this option is RSA-MD5. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-cipher"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-id_002dkey">ntp-keygen id-key</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-certificate">ntp-keygen certificate</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">cipher option (-C)</h4> + +<p><a name="index-ntp_002dkeygen_002dcipher-6"></a> +This is the “privatekey cipher” option. +This option takes a string argument <span class="file">cipher</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Select the cipher which is used to encrypt the files containing +private keys. The default is three-key triple DES in CBC mode, +equivalent to "<code>-C des-ede3-cbc". The openssl tool lists ciphers +available in "openssl -h" output. +</code><div class="node"> +<p><hr> +<a name="ntp_002dkeygen-id_002dkey"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-gq_002dparams">ntp-keygen gq-params</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-cipher">ntp-keygen cipher</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">id-key option (-e)</h4> + +<p><a name="index-ntp_002dkeygen_002did_002dkey-7"></a> +This is the “write iff or gq identity keys” option. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Write the IFF or GQ client keys to the standard output. This is +intended for automatic key distribution by mail. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-gq_002dparams"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-host_002dkey">ntp-keygen host-key</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-id_002dkey">ntp-keygen id-key</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">gq-params option (-G)</h4> + +<p><a name="index-ntp_002dkeygen_002dgq_002dparams-8"></a> +This is the “generate gq parameters and keys” option. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-host_002dkey"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-iffkey">ntp-keygen iffkey</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-gq_002dparams">ntp-keygen gq-params</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">host-key option (-H)</h4> + +<p><a name="index-ntp_002dkeygen_002dhost_002dkey-9"></a> +This is the “generate rsa host key” option. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Generate new host keys, obsoleting any that may exist. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-iffkey"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-ident">ntp-keygen ident</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-host_002dkey">ntp-keygen host-key</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">iffkey option (-I)</h4> + +<p><a name="index-ntp_002dkeygen_002diffkey-10"></a> +This is the “generate iff parameters” option. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Generate parameters for the IFF identification scheme, obsoleting +any that may exist. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-ident"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-lifetime">ntp-keygen lifetime</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-iffkey">ntp-keygen iffkey</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">ident option (-i)</h4> + +<p><a name="index-ntp_002dkeygen_002dident-11"></a> +This is the “set autokey group name” option. +This option takes a string argument <span class="file">group</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Set the optional Autokey group name to name. This is used in +the file name of IFF, GQ, and MV client parameters files. In +that role, the default is the host name if this option is not +provided. The group name, if specified using <code>-i/--ident</code> or +using <code>-s/--subject-name</code> following an '<code>}' character, +is also a part of the self-signed host certificate's subject and +issuer names in the form host + <p>'crypto ident' or 'server ident' configuration in +ntpd's configuration file. +</code><div class="node"> +<p><hr> +<a name="ntp_002dkeygen-lifetime"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-md5key">ntp-keygen md5key</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-ident">ntp-keygen ident</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">lifetime option (-l)</h4> + +<p><a name="index-ntp_002dkeygen_002dlifetime-12"></a> +This is the ``set certificate lifetime'' option. +This option takes a number argument <span class="file">lifetime</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Set the certificate expiration to lifetime days from now. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-md5key"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-modulus">ntp-keygen modulus</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-lifetime">ntp-keygen lifetime</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">md5key option (-M)</h4> + +<p><a name="index-ntp_002dkeygen_002dmd5key-13"></a> +This is the ``generate md5 keys'' option. +Generate MD5 keys, obsoleting any that may exist. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-modulus"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-pvt_002dcert">ntp-keygen pvt-cert</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-md5key">ntp-keygen md5key</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">modulus option (-m)</h4> + +<p><a name="index-ntp_002dkeygen_002dmodulus-14"></a> +This is the ``modulus'' option. +This option takes a number argument <span class="file">modulus</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>The number of bits in the prime modulus. The default is 512. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-pvt_002dcert"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-password">ntp-keygen password</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-modulus">ntp-keygen modulus</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">pvt-cert option (-P)</h4> + +<p><a name="index-ntp_002dkeygen_002dpvt_002dcert-15"></a> +This is the ``generate pc private certificate'' option. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Generate a private certificate. By default, the program generates +public certificates. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-password"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-export_002dpasswd">ntp-keygen export-passwd</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-pvt_002dcert">ntp-keygen pvt-cert</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">password option (-p)</h4> + +<p><a name="index-ntp_002dkeygen_002dpassword-16"></a> +This is the ``local private password'' option. +This option takes a string argument <span class="file">passwd</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Local files containing private data are encrypted with the +DES-CBC algorithm and the specified password. The same password +must be specified to the local ntpd via the "crypto pw password" +configuration command. The default password is the local +hostname. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-export_002dpasswd"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-sign_002dkey">ntp-keygen sign-key</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-password">ntp-keygen password</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">export-passwd option (-q)</h4> + +<p><a name="index-ntp_002dkeygen_002dexport_002dpasswd-17"></a> +This is the ``export iff or gq group keys with password'' option. +This option takes a string argument <span class="file">passwd</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Export IFF or GQ identity group keys to the standard output, +encrypted with the DES-CBC algorithm and the specified password. +The same password must be specified to the remote ntpd via the +"crypto pw password" configuration command. See also the option +--id-key (-e) for unencrypted exports. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-sign_002dkey"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-subject_002dname">ntp-keygen subject-name</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-export_002dpasswd">ntp-keygen export-passwd</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">sign-key option (-S)</h4> + +<p><a name="index-ntp_002dkeygen_002dsign_002dkey-18"></a> +This is the ``generate sign key (rsa or dsa)'' option. +This option takes a string argument <span class="file">sign</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Generate a new sign key of the designated type, obsoleting any +that may exist. By default, the program uses the host key as the +sign key. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-subject_002dname"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-trusted_002dcert">ntp-keygen trusted-cert</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-sign_002dkey">ntp-keygen sign-key</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">subject-name option (-s)</h4> + +<p><a name="index-ntp_002dkeygen_002dsubject_002dname-19"></a> +This is the ``set host and optionally group name'' option. +This option takes a string argument <span class="file">host@group</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Set the Autokey host name, and optionally, group name specified +following an '<code>}' character. The host name is used in the file +name of generated host and signing certificates, without the +group name. The host name, and if provided, group name are used +in host + <p>fields. Specifying '-s + <p>leaving the host name unchanged while appending + <p>subject and issuer fields, as with -i group. The group name, or +if not provided, the host name are also used in the file names +of IFF, GQ, and MV client parameter files. +</code><div class="node"> +<p><hr> +<a name="ntp_002dkeygen-trusted_002dcert"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-mv_002dparams">ntp-keygen mv-params</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-subject_002dname">ntp-keygen subject-name</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">trusted-cert option (-T)</h4> + +<p><a name="index-ntp_002dkeygen_002dtrusted_002dcert-20"></a> +This is the ``trusted certificate (tc scheme)'' option. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Generate a trusted certificate. By default, the program generates +a non-trusted certificate. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-mv_002dparams"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-mv_002dkeys">ntp-keygen mv-keys</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-trusted_002dcert">ntp-keygen trusted-cert</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">mv-params option (-V)</h4> + +<p><a name="index-ntp_002dkeygen_002dmv_002dparams-21"></a> +This is the ``generate <num> mv parameters'' option. +This option takes a number argument <span class="file">num</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>Generate parameters and keys for the Mu-Varadharajan (MV) +identification scheme. +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-mv_002dkeys"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-config">ntp-keygen config</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-mv_002dparams">ntp-keygen mv-params</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">mv-keys option (-v)</h4> + +<p><a name="index-ntp_002dkeygen_002dmv_002dkeys-22"></a> +This is the ``update <num> mv keys'' option. +This option takes a number argument <span class="file">num</span>. + +<p class="noindent">This option has some usage constraints. It: + <ul> +<li>must be compiled in by defining <code>AUTOKEY</code> during the compilation. +</ul> + + <p>This option has no <span class="samp">doc</span> documentation. + +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-config"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-exit-status">ntp-keygen exit status</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-mv_002dkeys">ntp-keygen mv-keys</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">presetting/configuring ntp-keygen</h4> + +<p>Any option that is not marked as <i>not presettable</i> may be preset by +loading values from configuration ("rc" or "ini") files, and values from environment variables named <code>NTP-KEYGEN</code> and <code>NTP-KEYGEN_<OPTION_NAME></code>. <code><OPTION_NAME></code> must be one of +the options listed above in upper case and segmented with underscores. +The <code>NTP-KEYGEN</code> variable will be tokenized and parsed like +the command line. The remaining variables are tested for existence and their +values are treated like option arguments. + +<p class="noindent"><code>libopts</code> will search in 2 places for configuration files: + <ul> +<li>$HOME +<li>$PWD +</ul> + The environment variables <code>HOME</code>, and <code>PWD</code> +are expanded and replaced when <span class="file">ntp-keygen</span> runs. +For any of these that are plain files, they are simply processed. +For any that are directories, then a file named <span class="file">.ntprc</span> is searched for +within that directory and processed. + + <p>Configuration files may be in a wide variety of formats. +The basic format is an option name followed by a value (argument) on the +same line. Values may be separated from the option name with a colon, +equal sign or simply white space. Values may be continued across multiple +lines by escaping the newline with a backslash. + + <p>Multiple programs may also share the same initialization file. +Common options are collected at the top, followed by program specific +segments. The segments are separated by lines like: +<pre class="example"> [NTP-KEYGEN] +</pre> + <p class="noindent">or by +<pre class="example"> <?program ntp-keygen> +</pre> + <p class="noindent">Do not mix these styles within one configuration file. + + <p>Compound values and carefully constructed string values may also be +specified using XML syntax: +<pre class="example"> <option-name> + <sub-opt>...&lt;...&gt;...</sub-opt> + </option-name> +</pre> + <p class="noindent">yielding an <code>option-name.sub-opt</code> string value of +<pre class="example"> "...<...>..." +</pre> + <p><code>AutoOpts</code> does not track suboptions. You simply note that it is a +hierarchicly valued option. <code>AutoOpts</code> does provide a means for searching +the associated name/value pair list (see: optionFindValue). + + <p>The command line options relating to configuration and/or usage help are: + +<h5 class="subsubheading">version (-)</h5> + +<p>Print the program version to standard out, optionally with licensing +information, then exit 0. The optional argument specifies how much licensing +detail to provide. The default is to print just the version. The licensing infomation may be selected with an option argument. +Only the first letter of the argument is examined: + + <dl> +<dt><span class="samp">version</span><dd>Only print the version. This is the default. +<br><dt><span class="samp">copyright</span><dd>Name the copyright usage licensing terms. +<br><dt><span class="samp">verbose</span><dd>Print the full copyright usage licensing terms. +</dl> + +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-exit-status"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-Usage">ntp-keygen Usage</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-config">ntp-keygen config</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">ntp-keygen exit status</h4> + +<p>One of the following exit values will be returned: + <dl> +<dt><span class="samp">0 (EXIT_SUCCESS)</span><dd>Successful program execution. +<br><dt><span class="samp">1 (EXIT_FAILURE)</span><dd>The operation failed or the command syntax was not valid. +<br><dt><span class="samp">66 (EX_NOINPUT)</span><dd>A specified configuration file could not be loaded. +<br><dt><span class="samp">70 (EX_SOFTWARE)</span><dd>libopts had an internal operational error. Please report +it to autogen-users@lists.sourceforge.net. Thank you. +</dl> + <div class="node"> +<p><hr> +<a name="ntp_002dkeygen-Usage"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-Notes">ntp-keygen Notes</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-exit-status">ntp-keygen exit status</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">ntp-keygen Usage</h4> + +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-Notes"></a>Next: <a rel="next" accesskey="n" href="#ntp_002dkeygen-Bugs">ntp-keygen Bugs</a>, +Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-Usage">ntp-keygen Usage</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">ntp-keygen Notes</h4> + +<div class="node"> +<p><hr> +<a name="ntp_002dkeygen-Bugs"></a>Previous: <a rel="previous" accesskey="p" href="#ntp_002dkeygen-Notes">ntp-keygen Notes</a>, +Up: <a rel="up" accesskey="u" href="#ntp_002dkeygen-Invocation">ntp-keygen Invocation</a> +<br> +</div> + +<h4 class="subsection">ntp-keygen Bugs</h4> + +<div class="node"> +<p><hr> +<a name="Random-Seed-File"></a>Next: <a rel="next" accesskey="n" href="#Cryptographic-Data-Files">Cryptographic Data Files</a>, +Previous: <a rel="previous" accesskey="p" href="#Running-the-Program">Running the Program</a>, +Up: <a rel="up" accesskey="u" href="#Top">Top</a> +<br> +</div> + +<!-- node-name, next, previous, up --> +<h3 class="section">Random Seed File</h3> + +<p>All cryptographically sound key generation schemes must have means to +randomize the entropy seed used to initialize the internal +pseudo-random number generator used by the OpenSSL library routines. +If a site supports ssh, it is very likely that means to do this are +already available. +The entropy seed used by the OpenSSL library is contained in a file, +usually called <code>.rnd</code>, which must be available when +starting the <code>ntp-keygen</code> program or <code>ntpd</code> daemon. + + <p>The OpenSSL library looks for the file using the path specified by the +<code>RANDFILE</code> environment variable in the user home directory, whether root +or some other user. +If the <code>RANDFILE</code> environment variable is not +present, the library looks for the <code>.rnd</code> file in the user home +directory. +Since both the <code>ntp-keygen</code> program and <code>ntpd</code> daemon must run +as root, the logical place to put this file is in <code>/.rnd</code> or +<code>/root/.rnd</code>. +If the file is not available or cannot be written, the program exits +with a message to the system log. + +<div class="node"> +<p><hr> +<a name="Cryptographic-Data-Files"></a>Previous: <a rel="previous" accesskey="p" href="#Random-Seed-File">Random Seed File</a>, +Up: <a rel="up" accesskey="u" href="#Top">Top</a> +<br> +</div> + +<!-- node-name, next, previous, up --> +<h3 class="section">Cryptographic Data Files</h3> + +<p>File and link names are in the <code>form ntpkey_key_name.fstamp</code>, +where <code>key</code> is the key or parameter type, +<code>name</code> is the host or group name and +<code>fstamp</code> is the filestamp (NTP seconds) when the file was created). +By convention, key names in generated file names include both upper and +lower case characters, while key names in generated link names include +only lower case characters. The filestamp is not used in generated link +names. + + <p>The key name is a string defining the cryptographic key type. +Key types include public/private keys host and sign, certificate cert +and several challenge/response key types. +By convention, client files used for +challenges have a par subtype, as in the IFF challenge IFFpar, while +server files for responses have a key subtype, as in the GQ response +GQkey. + + <p>All files begin with two nonencrypted lines. The first line contains +the file name in the format <code>ntpkey_key_host.fstamp</code>. +The second line contains the datestamp in conventional Unix date format. +Lines beginning with <code>#</code> are ignored. + + <p>The remainder of the file contains cryptographic data encoded first +using ASN.1 rules, then encrypted using the DES-CBC algorithm with +given password and finally written in PEM-encoded printable ASCII text +preceded and followed by MIME content identifier lines. + + <p>The format of the symmetric keys file, ordinarily named <code>ntp.keys</code>, +is somewhat different than the other files in the interest of backward +compatibility. +Ordinarily, the file is generated by this program, but +it can be constructed and edited using an ordinary text editor. + +<pre class="example"> # ntpkey_MD5key_hms.local.3564038757 + # Sun Dec 9 02:45:57 2012 + + 1 MD5 "]!ghT%O;3)WJ,/Nc:>I # MD5 key + 2 MD5 lu+H^tF46BKR-6~pV_5 # MD5 key + 3 MD5 :lnoVsE%Yz*avh%EtNC # MD5 key + 4 MD5 |fdZrf0sF~^V # MD5 key + 5 MD5 IyAG>O"y"LmCRS!*bHC # MD5 key + 6 MD5 ">e\A # MD5 key + 7 MD5 c9x=M'CfLxax9v)PV-si # MD5 key + 8 MD5 E|=jvFVov?Bn|Ev=&aK\ # MD5 key + 9 MD5 T!c4UT&`(m$+m+B6,`Q0 # MD5 key + 10 MD5 JVF/1=)=IFbHbJQz..Cd # MD5 key + 11 SHA1 6dea311109529e436c2b4fccae9bc753c16d1b48 # SHA1 key + 12 SHA1 7076f373d86c4848c59ff8046e49cb7d614ec394 # SHA1 key + 13 SHA1 5f48b1b60591eb01b7cf1d33b7774f08d20262d3 # SHA1 key + 14 SHA1 eed5ab9d9497319ec60cf3781d52607e76720178 # SHA1 key + 15 SHA1 f283562611a04c964da8126296f5f8e58c3f85de # SHA1 key + 16 SHA1 1930da171297dd63549af50b29449de17dcf341f # SHA1 key + 17 SHA1 fee892110358cd4382322b889869e750db8e8a8f # SHA1 key + 18 SHA1 b5520c9fadd7ad3fd8bfa061c8821b65d029bb37 # SHA1 key + 19 SHA1 8c74fb440ec80f453ec6aaa62b9baed0ab723b92 # SHA1 key + 20 SHA1 6bc05f734306a189326000970c19b3910f403795 # SHA1 key +</pre> + <p>Figure 1. Typical Symmetric Key File + + <p>Figure 1 shows a typical symmetric keys file used by the reference +implementation. +Each line of the file contains three fields, first an +integer between 1 and 65534, inclusive, representing the key identifier +used in the server and peer configuration commands. +Next is the key type for the message digest algorithm, +which in the absence of the +OpenSSL library must be MD5 to designate the MD5 message digest +algorithm. +If the OpenSSL library is installed, the key type can be any +message digest algorithm supported by that library. +However, if +compatibility with FIPS 140-2 is required, the key type must be either +SHA or SHA1. +The key type can be changed using an ASCII text editor. + + <p>An MD5 key consists of a printable ASCII string less than or equal to +16 characters and terminated by whitespace or a # character. +An OpenSSL +key consists of a hex-encoded ASCII string of 40 characters, which is +truncated as necessary. + + <p>Note that the keys used by the <code>ntpq</code> and <code>ntpdc</code> programs are +checked against passwords requested by the programs and entered by hand, +so it +is generally appropriate to specify these keys in human readable ASCII +format. + + <p>The <code>ntp-keygen</code> program generates a MD5 symmetric keys file +<code>ntpkey_MD5key_hostname.filestamp</code>. +Since the file contains private +shared keys, it should be visible only to root and distributed by +secure means to other subnet hosts. +The NTP daemon loads the file <code>ntp.keys</code>, so <code>ntp-keygen</code> +installs a soft link from this name to the generated file. +Subsequently, similar soft links must be installed by +manual or automated means on the other subnet hosts. +While this file is +not used with the Autokey Version 2 protocol, it is needed to +authenticate some remote configuration commands used by the <code>ntpq</code> and +<code>ntpdc</code> utilities. + +</body></html> + diff --git a/util/ntp-keygen.man.in b/util/ntp-keygen.man.in new file mode 100644 index 0000000..69fcfaa --- /dev/null +++ b/util/ntp-keygen.man.in @@ -0,0 +1,1221 @@ +.de1 NOP +. it 1 an-trap +. if \\n[.$] \,\\$*\/ +.. +.ie t \ +.ds B-Font [CB] +.ds I-Font [CI] +.ds R-Font [CR] +.el \ +.ds B-Font B +.ds I-Font I +.ds R-Font R +.TH ntp-keygen @NTP_KEYGEN_MS@ "02 Dec 2014" "ntp (4.2.7p482)" "User Commands" +.\" +.\" EDIT THIS FILE WITH CAUTION (/tmp/.ag-znaynR/ag-LnaqmR) +.\" +.\" It has been AutoGen-ed December 2, 2014 at 08:58:44 AM by AutoGen 5.18.5pre4 +.\" From the definitions ntp-keygen-opts.def +.\" and the template file agman-cmd.tpl +.SH NAME +\f\*[B-Font]ntp-keygen\fP +\- Create a NTP host key +.SH SYNOPSIS +\f\*[B-Font]ntp-keygen\fP +.\" Mixture of short (flag) options and long options +[\f\*[B-Font]\-flags\f[]] +[\f\*[B-Font]\-flag\f[] [\f\*[I-Font]value\f[]]] +[\f\*[B-Font]\-\-option-name\f[][[=| ]\f\*[I-Font]value\f[]]] +.sp \n(Ppu +.ne 2 + +All arguments must be options. +.sp \n(Ppu +.ne 2 + +.SH DESCRIPTION +This program generates cryptographic data files used by the NTPv4 +authentication and identification schemes. +It generates MD5 key files used in symmetric key cryptography. +In addition, if the OpenSSL software library has been installed, +it generates keys, certificate and identity files used in public key +cryptography. +These files are used for cookie encryption, +digital signature and challenge/response identification algorithms +compatible with the Internet standard security infrastructure. +.sp \n(Ppu +.ne 2 + +All files are in PEM-encoded printable ASCII format, +so they can be embedded as MIME attachments in mail to other sites +and certificate authorities. +By default, files are not encrypted. +.sp \n(Ppu +.ne 2 + +When used to generate message digest keys, the program produces a file +containing ten pseudo-random printable ASCII strings suitable for the +MD5 message digest algorithm included in the distribution. +If the OpenSSL library is installed, it produces an additional ten +hex-encoded random bit strings suitable for the SHA1 and other message +digest algorithms. +The message digest keys file must be distributed and stored +using secure means beyond the scope of NTP itself. +Besides the keys used for ordinary NTP associations, additional keys +can be defined as passwords for the +\fCntpq\fR(@NTPQ_MS@)\f[] +and +\fCntpdc\fR(@NTPDC_MS@)\f[] +utility programs. +.sp \n(Ppu +.ne 2 + +The remaining generated files are compatible with other OpenSSL +applications and other Public Key Infrastructure (PKI) resources. +Certificates generated by this program are compatible with extant +industry practice, although some users might find the interpretation of +X509v3 extension fields somewhat liberal. +However, the identity keys are probably not compatible with anything +other than Autokey. +.sp \n(Ppu +.ne 2 + +Some files used by this program are encrypted using a private password. +The +\f\*[B-Font]\-p\f[] +option specifies the password for local encrypted files and the +\f\*[B-Font]\-q\f[] +option the password for encrypted files sent to remote sites. +If no password is specified, the host name returned by the Unix +\fBgethostname\fR()\f[] +function, normally the DNS name of the host is used. +.sp \n(Ppu +.ne 2 + +The +\f\*[I-Font]pw\f[] +option of the +\f\*[I-Font]crypto\f[] +configuration command specifies the read +password for previously encrypted local files. +This must match the local password used by this program. +If not specified, the host name is used. +Thus, if files are generated by this program without password, +they can be read back by +\f\*[I-Font]ntpd\f[] +without password but only on the same host. +.sp \n(Ppu +.ne 2 + +Normally, encrypted files for each host are generated by that host and +used only by that host, although exceptions exist as noted later on +this page. +The symmetric keys file, normally called +\f\*[I-Font]ntp.keys\f[], +is usually installed in +\fI/etc\f[]. +Other files and links are usually installed in +\fI/usr/local/etc\f[], +which is normally in a shared filesystem in +NFS-mounted networks and cannot be changed by shared clients. +The location of the keys directory can be changed by the +\f\*[I-Font]keysdir\f[] +configuration command in such cases. +Normally, this is in +\fI/etc\f[]. +.sp \n(Ppu +.ne 2 + +This program directs commentary and error messages to the standard +error stream +\f\*[I-Font]stderr\f[] +and remote files to the standard output stream +\f\*[I-Font]stdout\f[] +where they can be piped to other applications or redirected to files. +The names used for generated files and links all begin with the +string +\f\*[I-Font]ntpkey\f[] +and include the file type, generating host and filestamp, +as described in the +\*[Lq]Cryptographic Data Files\*[Rq] +section below. +.SS Running the Program +To test and gain experience with Autokey concepts, log in as root and +change to the keys directory, usually +\fI/usr/local/etc\f[] +When run for the first time, or if all files with names beginning with +\f\*[I-Font]ntpkey\f[] +have been removed, use the +\f\*[B-Font]ntp-keygen\fP +command without arguments to generate a +default RSA host key and matching RSA-MD5 certificate with expiration +date one year hence. +If run again without options, the program uses the +existing keys and parameters and generates only a new certificate with +new expiration date one year hence. +.sp \n(Ppu +.ne 2 + +Run the command on as many hosts as necessary. +Designate one of them as the trusted host (TH) using +\f\*[B-Font]ntp-keygen\fP +with the +\f\*[B-Font]\-T\f[] +option and configure it to synchronize from reliable Internet servers. +Then configure the other hosts to synchronize to the TH directly or +indirectly. +A certificate trail is created when Autokey asks the immediately +ascendant host towards the TH to sign its certificate, which is then +provided to the immediately descendant host on request. +All group hosts should have acyclic certificate trails ending on the TH. +.sp \n(Ppu +.ne 2 + +The host key is used to encrypt the cookie when required and so must be +RSA type. +By default, the host key is also the sign key used to encrypt +signatures. +A different sign key can be assigned using the +\f\*[B-Font]\-S\f[] +option and this can be either RSA or DSA type. +By default, the signature +message digest type is MD5, but any combination of sign key type and +message digest type supported by the OpenSSL library can be specified +using the +\f\*[B-Font]\-c\f[] +option. +The rules say cryptographic media should be generated with proventic +filestamps, which means the host should already be synchronized before +this program is run. +This of course creates a chicken-and-egg problem +when the host is started for the first time. +Accordingly, the host time +should be set by some other means, such as eyeball-and-wristwatch, at +least so that the certificate lifetime is within the current year. +After that and when the host is synchronized to a proventic source, the +certificate should be re-generated. +.sp \n(Ppu +.ne 2 + +Additional information on trusted groups and identity schemes is on the +\*[Lq]Autokey Public-Key Authentication\*[Rq] +page. +.sp \n(Ppu +.ne 2 + +The +\fCntpd\fR(@NTPD_MS@)\f[] +configuration command +\f\*[B-Font]crypto\f[] \f\*[B-Font]pw\f[] \f\*[I-Font]password\f[] +specifies the read password for previously encrypted files. +The daemon expires on the spot if the password is missing +or incorrect. +For convenience, if a file has been previously encrypted, +the default read password is the name of the host running +the program. +If the previous write password is specified as the host name, +these files can be read by that host with no explicit password. +.sp \n(Ppu +.ne 2 + +File names begin with the prefix +\f\*[B-Font]ntpkey_\f[] +and end with the postfix +\f\*[I-Font]_hostname.filestamp\f[], +where +\f\*[I-Font]hostname\f[] +is the owner name, usually the string returned +by the Unix gethostname() routine, and +\f\*[I-Font]filestamp\f[] +is the NTP seconds when the file was generated, in decimal digits. +This both guarantees uniqueness and simplifies maintenance +procedures, since all files can be quickly removed +by a +\f\*[B-Font]rm\f[] \f\*[B-Font]ntpkey\&*\f[] +command or all files generated +at a specific time can be removed by a +\f\*[B-Font]rm\f[] +\f\*[I-Font]\&*filestamp\f[] +command. +To further reduce the risk of misconfiguration, +the first two lines of a file contain the file name +and generation date and time as comments. +.sp \n(Ppu +.ne 2 + +All files are installed by default in the keys directory +\fI/usr/local/etc\f[], +which is normally in a shared filesystem +in NFS-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. +.sp \n(Ppu +.ne 2 + +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. +.sp \n(Ppu +.ne 2 + +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +\fCntpd\fR(@NTPD_MS@)\f[] +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +\f\*[B-Font]ntp-keygen\fP +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +.SS Running the program +The safest way to run the +\f\*[B-Font]ntp-keygen\fP +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +\fI/usr/local/etc\f[], +then run the program. +When run for the first time, +or if all +\f\*[B-Font]ntpkey\f[] +files have been removed, +the program generates a RSA host key file and matching RSA-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. +.sp \n(Ppu +.ne 2 + +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. +.sp \n(Ppu +.ne 2 + +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. +.sp \n(Ppu +.ne 2 + +Running the program as other than root and using the Unix +\f\*[B-Font]su\f[] +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +\f\*[B-Font].rnd\f[] +in the user home directory. +However, there should be only one +\f\*[B-Font].rnd\f[], +most conveniently +in the root directory, so it is convenient to define the +\f\*[B-Font]$RANDFILE\f[] +environment variable used by the OpenSSL library as the path to +\f\*[B-Font]/.rnd\f[]. +.sp \n(Ppu +.ne 2 + +Installing the keys as root might not work in NFS-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +\fI/etc\f[] +using the +\f\*[B-Font]keysdir\f[] +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. +.sp \n(Ppu +.ne 2 + +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +.sp \n(Ppu +.ne 2 + +All files are installed by default in the keys directory +\fI/usr/local/etc\f[], +which is normally in a shared filesystem +in NFS-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. +.sp \n(Ppu +.ne 2 + +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. +.sp \n(Ppu +.ne 2 + +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +\fCntpd\fR(@NTPD_MS@)\f[] +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +\f\*[B-Font]ntp-keygen\fP +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +.SS Running the program +The safest way to run the +\f\*[B-Font]ntp-keygen\fP +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +\fI/usr/local/etc\f[], +then run the program. +When run for the first time, +or if all +\f\*[B-Font]ntpkey\f[] +files have been removed, +the program generates a RSA host key file and matching RSA-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. +.sp \n(Ppu +.ne 2 + +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. +.sp \n(Ppu +.ne 2 + +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. +.sp \n(Ppu +.ne 2 + +Running the program as other than root and using the Unix +\f\*[B-Font]su\f[] +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +\f\*[B-Font].rnd\f[] +in the user home directory. +However, there should be only one +\f\*[B-Font].rnd\f[], +most conveniently +in the root directory, so it is convenient to define the +\f\*[B-Font]$RANDFILE\f[] +environment variable used by the OpenSSL library as the path to +\f\*[B-Font]/.rnd\f[]. +.sp \n(Ppu +.ne 2 + +Installing the keys as root might not work in NFS-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +\fI/etc\f[] +using the +\f\*[B-Font]keysdir\f[] +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. +.sp \n(Ppu +.ne 2 + +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +seconds. +seconds. +s Trusted Hosts and Groups +Each cryptographic configuration involves selection of a signature scheme +and identification scheme, called a cryptotype, +as explained in the +\fIAuthentication\f[] \fIOptions\f[] +section of +\fCntp.conf\fR(5)\f[]. +The default cryptotype uses RSA encryption, MD5 message digest +and TC identification. +First, configure a NTP subnet including one or more low-stratum +trusted hosts from which all other hosts derive synchronization +directly or indirectly. +Trusted hosts have trusted certificates; +all other hosts have nontrusted certificates. +These hosts will automatically and dynamically build authoritative +certificate trails to one or more trusted hosts. +A trusted group is the set of all hosts that have, directly or indirectly, +a certificate trail ending at a trusted host. +The trail is defined by static configuration file entries +or dynamic means described on the +\fIAutomatic\f[] \fINTP\f[] \fIConfiguration\f[] \fIOptions\f[] +section of +\fCntp.conf\fR(5)\f[]. +.sp \n(Ppu +.ne 2 + +On each trusted host as root, change to the keys directory. +To insure a fresh fileset, remove all +\f\*[B-Font]ntpkey\f[] +files. +Then run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-T\f[] +to generate keys and a trusted certificate. +On all other hosts do the same, but leave off the +\f\*[B-Font]\-T\f[] +flag to generate keys and nontrusted certificates. +When complete, start the NTP daemons beginning at the lowest stratum +and working up the tree. +It may take some time for Autokey to instantiate the certificate trails +throughout the subnet, but setting up the environment is completely automatic. +.sp \n(Ppu +.ne 2 + +If it is necessary to use a different sign key or different digest/signature +scheme than the default, run +\f\*[B-Font]ntp-keygen\fP +with the +\f\*[B-Font]\-S\f[] \f\*[I-Font]type\f[] +option, where +\f\*[I-Font]type\f[] +is either +\f\*[B-Font]RSA\f[] +or +\f\*[B-Font]DSA\f[]. +The most often need to do this is when a DSA-signed certificate is used. +If it is necessary to use a different certificate scheme than the default, +run +\f\*[B-Font]ntp-keygen\fP +with the +\f\*[B-Font]\-c\f[] \f\*[I-Font]scheme\f[] +option and selected +\f\*[I-Font]scheme\f[] +as needed. +f +\f\*[B-Font]ntp-keygen\fP +is run again without these options, it generates a new certificate +using the same scheme and sign key. +.sp \n(Ppu +.ne 2 + +After setting up the environment it is advisable to update certificates +from time to time, if only to extend the validity interval. +Simply run +\f\*[B-Font]ntp-keygen\fP +with the same flags as before to generate new certificates +using existing keys. +However, if the host or sign key is changed, +\fCntpd\fR(@NTPD_MS@)\f[] +should be restarted. +When +\fCntpd\fR(@NTPD_MS@)\f[] +is restarted, it loads any new files and restarts the protocol. +Other dependent hosts will continue as usual until signatures are refreshed, +at which time the protocol is restarted. +.SS Identity Schemes +As mentioned on the Autonomous Authentication page, +the default TC identity scheme is vulnerable to a middleman attack. +However, there are more secure identity schemes available, +including PC, IFF, GQ and MV described on the +"Identification Schemes" +page +(maybe available at +\f[C]http://www.eecis.udel.edu/%7emills/keygen.html\f[]). +These schemes are based on a TA, one or more trusted hosts +and some number of nontrusted hosts. +Trusted hosts prove identity using values provided by the TA, +while the remaining hosts prove identity using values provided +by a trusted host and certificate trails that end on that host. +The name of a trusted host is also the name of its sugroup +and also the subject and issuer name on its trusted certificate. +The TA is not necessarily a trusted host in this sense, but often is. +.sp \n(Ppu +.ne 2 + +In some schemes there are separate keys for servers and clients. +A server can also be a client of another server, +but a client can never be a server for another client. +In general, trusted hosts and nontrusted hosts that operate +as both server and client have parameter files that contain +both server and client keys. +Hosts that operate +only as clients have key files that contain only client keys. +.sp \n(Ppu +.ne 2 + +The PC scheme supports only one trusted host in the group. +On trusted host alice run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-P\f[] +\f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[] +to generate the host key file +\fIntpkey_RSAkey_\f[]\f\*[I-Font]alice.filestamp\f[] +and trusted private certificate file +\fIntpkey_RSA-MD5_cert_\f[]\f\*[I-Font]alice.filestamp\f[]. +Copy both files to all group hosts; +they replace the files which would be generated in other schemes. +On each host bob install a soft link from the generic name +\fIntpkey_host_\f[]\f\*[I-Font]bob\f[] +to the host key file and soft link +\fIntpkey_cert_\f[]\f\*[I-Font]bob\f[] +to the private certificate file. +Note the generic links are on bob, but point to files generated +by trusted host alice. +In this scheme it is not possible to refresh +either the keys or certificates without copying them +to all other hosts in the group. +.sp \n(Ppu +.ne 2 + +For the IFF scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host in the group, +generate the IFF parameter file. +On trusted host alice run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-T\f[] +\f\*[B-Font]\-I\f[] +\f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[] +to produce her parameter file +\fIntpkey_IFFpar_\f[]\f\*[I-Font]alice.filestamp\f[], +which includes both server and client keys. +Copy this file to all group hosts that operate as both servers +and clients and install a soft link from the generic +\fIntpkey_iff_\f[]\f\*[I-Font]alice\f[] +to this file. +If there are no hosts restricted to operate only as clients, +there is nothing further to do. +As the IFF scheme is independent +of keys and certificates, these files can be refreshed as needed. +.sp \n(Ppu +.ne 2 + +If a rogue client has the parameter file, it could masquerade +as a legitimate server and present a middleman threat. +To eliminate this threat, the client keys can be extracted +from the parameter file and distributed to all restricted clients. +After generating the parameter file, on alice run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-e\f[] +and pipe the output to a file or mail program. +Copy or mail this file to all restricted clients. +On these clients install a soft link from the generic +\fIntpkey_iff_\f[]\f\*[I-Font]alice\f[] +to this file. +To further protect the integrity of the keys, +each file can be encrypted with a secret password. +.sp \n(Ppu +.ne 2 + +For the GQ scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host +in the group, generate the IFF parameter file. +On trusted host alice run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-T\f[] +\f\*[B-Font]\-G\f[] +\f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[] +to produce her parameter file +\fIntpkey_GQpar_\f[]\f\*[I-Font]alice.filestamp\f[], +which includes both server and client keys. +Copy this file to all group hosts and install a soft link +from the generic +\fIntpkey_gq_\f[]\f\*[I-Font]alice\f[] +to this file. +In addition, on each host bob install a soft link +from generic +\fIntpkey_gq_\f[]\f\*[I-Font]bob\f[] +to this file. +As the GQ scheme updates the GQ parameters file and certificate +at the same time, keys and certificates can be regenerated as needed. +.sp \n(Ppu +.ne 2 + +For the MV scheme, proceed as in the TC scheme to generate keys +and certificates for all group hosts. +For illustration assume trish is the TA, alice one of several trusted hosts +and bob one of her clients. +On TA trish run +\f\*[B-Font]ntp-keygen\fP +\f\*[B-Font]\-V\f[] \f\*[I-Font]n\f[] +\f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[], +where +\f\*[I-Font]n\f[] +is the number of revokable keys (typically 5) to produce +the parameter file +\fIntpkeys_MVpar_\f[]\f\*[I-Font]trish.filestamp\f[] +and client key files +\fIntpkeys_MVkeyd_\f[]\f\*[I-Font]trish.filestamp\f[] +where +\f\*[I-Font]d\f[] +is the key number (0 \&< +\f\*[I-Font]d\f[] +\&< +\f\*[I-Font]n\f[]). +Copy the parameter file to alice and install a soft link +from the generic +\fIntpkey_mv_\f[]\f\*[I-Font]alice\f[] +to this file. +Copy one of the client key files to alice for later distribution +to her clients. +It doesn't matter which client key file goes to alice, +since they all work the same way. +Alice copies the client key file to all of her cliens. +On client bob install a soft link from generic +\fIntpkey_mvkey_\f[]\f\*[I-Font]bob\f[] +to the client key file. +As the MV scheme is independent of keys and certificates, +these files can be refreshed as needed. +.SS Command Line Options +.TP 7 +.NOP \f\*[B-Font]\-c\f[] \f\*[I-Font]scheme\f[] +Select certificate message digest/signature encryption scheme. +The +\f\*[I-Font]scheme\f[] +can be one of the following: +. Cm RSA-MD2 , RSA-MD5 , RSA-SHA , RSA-SHA1 , RSA-MDC2 , RSA-RIPEMD160 , DSA-SHA , +or +\f\*[B-Font]DSA-SHA1\f[]. +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. +The default without this option is +\f\*[B-Font]RSA-MD5\f[]. +.TP 7 +.NOP \f\*[B-Font]\-d\f[] +Enable debugging. +This option displays the cryptographic data produced in eye-friendly billboards. +.TP 7 +.NOP \f\*[B-Font]\-e\f[] +Write the IFF client keys to the standard output. +This is intended for automatic key distribution by mail. +.TP 7 +.NOP \f\*[B-Font]\-G\f[] +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +.TP 7 +.NOP \f\*[B-Font]\-g\f[] +Generate keys for the GQ identification scheme +using the existing GQ parameters. +If the GQ parameters do not yet exist, create them first. +.TP 7 +.NOP \f\*[B-Font]\-H\f[] +Generate new host keys, obsoleting any that may exist. +.TP 7 +.NOP \f\*[B-Font]\-I\f[] +Generate parameters for the IFF identification scheme, +obsoleting any that may exist. +.TP 7 +.NOP \f\*[B-Font]\-i\f[] \f\*[I-Font]name\f[] +Set the suject name to +\f\*[I-Font]name\f[]. +This is used as the subject field in certificates +and in the file name for host and sign keys. +.TP 7 +.NOP \f\*[B-Font]\-M\f[] +Generate MD5 keys, obsoleting any that may exist. +.TP 7 +.NOP \f\*[B-Font]\-P\f[] +Generate a private certificate. +By default, the program generates public certificates. +.TP 7 +.NOP \f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[] +Encrypt generated files containing private data with +\f\*[I-Font]password\f[] +and the DES-CBC algorithm. +.TP 7 +.NOP \f\*[B-Font]\-q\f[] +Set the password for reading files to password. +.TP 7 +.NOP \f\*[B-Font]\-S\f[] [\f\*[B-Font]RSA\f[] | \f\*[B-Font]DSA\f[]] +Generate a new sign key of the designated type, +obsoleting any that may exist. +By default, the program uses the host key as the sign key. +.TP 7 +.NOP \f\*[B-Font]\-s\f[] \f\*[I-Font]name\f[] +Set the issuer name to +\f\*[I-Font]name\f[]. +This is used for the issuer field in certificates +and in the file name for identity files. +.TP 7 +.NOP \f\*[B-Font]\-T\f[] +Generate a trusted certificate. +By default, the program generates a non-trusted certificate. +.TP 7 +.NOP \f\*[B-Font]\-V\f[] \f\*[I-Font]nkeys\f[] +Generate parameters and keys for the Mu-Varadharajan (MV) identification scheme. +.PP +.SS Random Seed File +All cryptographically sound key generation schemes must have means +to randomize the entropy seed used to initialize +the internal pseudo-random number generator used +by the library routines. +The OpenSSL library uses a designated random seed file for this purpose. +The file must be available when starting the NTP daemon and +\f\*[B-Font]ntp-keygen\fP +program. +If a site supports OpenSSL or its companion OpenSSH, +it is very likely that means to do this are already available. +.sp \n(Ppu +.ne 2 + +It is important to understand that entropy must be evolved +for each generation, for otherwise the random number sequence +would be predictable. +Various means dependent on external events, such as keystroke intervals, +can be used to do this and some systems have built-in entropy sources. +Suitable means are described in the OpenSSL software documentation, +but are outside the scope of this page. +.sp \n(Ppu +.ne 2 + +The entropy seed used by the OpenSSL library is contained in a file, +usually called +\f\*[B-Font].rnd\f[], +which must be available when starting the NTP daemon +or the +\f\*[B-Font]ntp-keygen\fP +program. +The NTP daemon will first look for the file +using the path specified by the +\f\*[B-Font]randfile\f[] +subcommand of the +\f\*[B-Font]crypto\f[] +configuration command. +If not specified in this way, or when starting the +\f\*[B-Font]ntp-keygen\fP +program, +the OpenSSL library will look for the file using the path specified +by the +RANDFILE +environment variable in the user home directory, +whether root or some other user. +If the +RANDFILE +environment variable is not present, +the library will look for the +\f\*[B-Font].rnd\f[] +file in the user home directory. +If the file is not available or cannot be written, +the daemon exits with a message to the system log and the program +exits with a suitable error message. +.SS Cryptographic Data Files +All other file formats begin with two lines. +The first contains the file name, including the generated host name +and filestamp. +The second contains the datestamp in conventional Unix date format. +Lines beginning with # are considered comments and ignored by the +\f\*[B-Font]ntp-keygen\fP +program and +\fCntpd\fR(@NTPD_MS@)\f[] +daemon. +Cryptographic values are encoded first using ASN.1 rules, +then encrypted if necessary, and finally written PEM-encoded +printable ASCII format preceded and followed by MIME content identifier lines. +.sp \n(Ppu +.ne 2 + +The format of the symmetric keys file is somewhat different +than the other files in the interest of backward compatibility. +Since DES-CBC is deprecated in NTPv4, the only key format of interest +is MD5 alphanumeric strings. +Following hte heard the keys are +entered one per line in the format +.in +4 +\f\*[I-Font]keyno\f[] \f\*[I-Font]type\f[] \f\*[I-Font]key\f[] +.in -4 +where +\f\*[I-Font]keyno\f[] +is a positive integer in the range 1-65,535, +\f\*[I-Font]type\f[] +is the string MD5 defining the key format and +\f\*[I-Font]key\f[] +is the key itself, +which is a printable ASCII string 16 characters or less in length. +Each character is chosen from the 93 printable characters +in the range 0x21 through 0x7f excluding space and the +\[oq]#\[cq] +character. +.sp \n(Ppu +.ne 2 + +Note that the keys used by the +\fCntpq\fR(@NTPQ_MS@)\f[] +and +\fCntpdc\fR(@NTPDC_MS@)\f[] +programs +are checked against passwords requested by the programs +and entered by hand, so it is generally appropriate to specify these keys +in human readable ASCII format. +.sp \n(Ppu +.ne 2 + +The +\f\*[B-Font]ntp-keygen\fP +program generates a MD5 symmetric keys file +\fIntpkey_MD5key_\f[]\f\*[I-Font]hostname.filestamp\f[]. +Since the file contains private shared keys, +it should be visible only to root and distributed by secure means +to other subnet hosts. +The NTP daemon loads the file +\fIntp.keys\f[], +so +\f\*[B-Font]ntp-keygen\fP +installs a soft link from this name to the generated file. +Subsequently, similar soft links must be installed by manual +or automated means on the other subnet hosts. +While this file is not used with the Autokey Version 2 protocol, +it is needed to authenticate some remote configuration commands +used by the +\fCntpq\fR(@NTPQ_MS@)\f[] +and +\fCntpdc\fR(@NTPDC_MS@)\f[] +utilities. +.SH "OPTIONS" +.TP +.NOP \f\*[B-Font]\-b\f[] \f\*[I-Font]imbits\f[], \f\*[B-Font]\-\-imbits\f[]=\f\*[I-Font]imbits\f[] +identity modulus bits. +This option takes an integer number as its argument. +The value of +\f\*[I-Font]imbits\f[] +is constrained to being: +.in +4 +.nf +.na +in the range 256 through 2048 +.fi +.in -4 +.sp +The number of bits in the identity modulus. The default is 256. +.TP +.NOP \f\*[B-Font]\-c\f[] \f\*[I-Font]scheme\f[], \f\*[B-Font]\-\-certificate\f[]=\f\*[I-Font]scheme\f[] +certificate scheme. +.sp +scheme is one of +RSA-MD2, RSA-MD5, RSA-SHA, RSA-SHA1, RSA-MDC2, RSA-RIPEMD160, +DSA-SHA, or DSA-SHA1. +.sp +Select the certificate message digest/signature encryption scheme. +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. The default without +this option is RSA-MD5. +.TP +.NOP \f\*[B-Font]\-C\f[] \f\*[I-Font]cipher\f[], \f\*[B-Font]\-\-cipher\f[]=\f\*[I-Font]cipher\f[] +privatekey cipher. +.sp +Select the cipher which is used to encrypt the files containing +private keys. The default is three-key triple DES in CBC mode, +equivalent to "@code{-C des-ede3-cbc". The openssl tool lists ciphers +available in "\fBopenssl \-h\fP" output. +.TP +.NOP \f\*[B-Font]\-d\f[], \f\*[B-Font]\-\-debug\-level\f[] +Increase debug verbosity level. +This option may appear an unlimited number of times. +.sp +.TP +.NOP \f\*[B-Font]\-D\f[] \f\*[I-Font]number\f[], \f\*[B-Font]\-\-set\-debug\-level\f[]=\f\*[I-Font]number\f[] +Set the debug verbosity level. +This option may appear an unlimited number of times. +This option takes an integer number as its argument. +.sp +.TP +.NOP \f\*[B-Font]\-e\f[], \f\*[B-Font]\-\-id\-key\f[] +Write IFF or GQ identity keys. +.sp +Write the IFF or GQ client keys to the standard output. This is +intended for automatic key distribution by mail. +.TP +.NOP \f\*[B-Font]\-G\f[], \f\*[B-Font]\-\-gq\-params\f[] +Generate GQ parameters and keys. +.sp +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +.TP +.NOP \f\*[B-Font]\-H\f[], \f\*[B-Font]\-\-host\-key\f[] +generate RSA host key. +.sp +Generate new host keys, obsoleting any that may exist. +.TP +.NOP \f\*[B-Font]\-I\f[], \f\*[B-Font]\-\-iffkey\f[] +generate IFF parameters. +.sp +Generate parameters for the IFF identification scheme, obsoleting +any that may exist. +.TP +.NOP \f\*[B-Font]\-i\f[] \f\*[I-Font]group\f[], \f\*[B-Font]\-\-ident\f[]=\f\*[I-Font]group\f[] +set Autokey group name. +.sp +Set the optional Autokey group name to name. This is used in +the file name of IFF, GQ, and MV client parameters files. In +that role, the default is the host name if this option is not +provided. The group name, if specified using \fB-i/--ident\fP or +using \fB-s/--subject-name\fP following an '\fB@\fP' character, +is also a part of the self-signed host certificate's subject and +issuer names in the form \fBhost@group\fP and should match the +'\fBcrypto ident\fP' or '\fBserver ident\fP' configuration in +\fBntpd\fP's configuration file. +.TP +.NOP \f\*[B-Font]\-l\f[] \f\*[I-Font]lifetime\f[], \f\*[B-Font]\-\-lifetime\f[]=\f\*[I-Font]lifetime\f[] +set certificate lifetime. +This option takes an integer number as its argument. +.sp +Set the certificate expiration to lifetime days from now. +.TP +.NOP \f\*[B-Font]\-M\f[], \f\*[B-Font]\-\-md5key\f[] +generate MD5 keys. +.sp +Generate MD5 keys, obsoleting any that may exist. +.TP +.NOP \f\*[B-Font]\-m\f[] \f\*[I-Font]modulus\f[], \f\*[B-Font]\-\-modulus\f[]=\f\*[I-Font]modulus\f[] +modulus. +This option takes an integer number as its argument. +The value of +\f\*[I-Font]modulus\f[] +is constrained to being: +.in +4 +.nf +.na +in the range 256 through 2048 +.fi +.in -4 +.sp +The number of bits in the prime modulus. The default is 512. +.TP +.NOP \f\*[B-Font]\-P\f[], \f\*[B-Font]\-\-pvt\-cert\f[] +generate PC private certificate. +.sp +Generate a private certificate. By default, the program generates +public certificates. +.TP +.NOP \f\*[B-Font]\-p\f[] \f\*[I-Font]passwd\f[], \f\*[B-Font]\-\-password\f[]=\f\*[I-Font]passwd\f[] +local private password. +.sp +Local files containing private data are encrypted with the +DES-CBC algorithm and the specified password. The same password +must be specified to the local ntpd via the "crypto pw password" +configuration command. The default password is the local +hostname. +.TP +.NOP \f\*[B-Font]\-q\f[] \f\*[I-Font]passwd\f[], \f\*[B-Font]\-\-export\-passwd\f[]=\f\*[I-Font]passwd\f[] +export IFF or GQ group keys with password. +.sp +Export IFF or GQ identity group keys to the standard output, +encrypted with the DES-CBC algorithm and the specified password. +The same password must be specified to the remote ntpd via the +"crypto pw password" configuration command. See also the option +--id-key (-e) for unencrypted exports. +.TP +.NOP \f\*[B-Font]\-S\f[] \f\*[I-Font]sign\f[], \f\*[B-Font]\-\-sign\-key\f[]=\f\*[I-Font]sign\f[] +generate sign key (RSA or DSA). +.sp +Generate a new sign key of the designated type, obsoleting any +that may exist. By default, the program uses the host key as the +sign key. +.TP +.NOP \f\*[B-Font]\-s\f[] \f\*[I-Font]host@group\f[], \f\*[B-Font]\-\-subject\-name\f[]=\f\*[I-Font]host@group\f[] +set host and optionally group name. +.sp +Set the Autokey host name, and optionally, group name specified +following an '\fB@\fP' character. The host name is used in the file +name of generated host and signing certificates, without the +group name. The host name, and if provided, group name are used +in \fBhost@group\fP form for the host certificate's subject and issuer +fields. Specifying '\fB-s @group\fP' is allowed, and results in +leaving the host name unchanged while appending \fB@group\fP to the +subject and issuer fields, as with \fB-i group\fP. The group name, or +if not provided, the host name are also used in the file names +of IFF, GQ, and MV client parameter files. +.TP +.NOP \f\*[B-Font]\-T\f[], \f\*[B-Font]\-\-trusted\-cert\f[] +trusted certificate (TC scheme). +.sp +Generate a trusted certificate. By default, the program generates +a non-trusted certificate. +.TP +.NOP \f\*[B-Font]\-V\f[] \f\*[I-Font]num\f[], \f\*[B-Font]\-\-mv\-params\f[]=\f\*[I-Font]num\f[] +generate <num> MV parameters. +This option takes an integer number as its argument. +.sp +Generate parameters and keys for the Mu-Varadharajan (MV) +identification scheme. +.TP +.NOP \f\*[B-Font]\-v\f[] \f\*[I-Font]num\f[], \f\*[B-Font]\-\-mv\-keys\f[]=\f\*[I-Font]num\f[] +update <num> MV keys. +This option takes an integer number as its argument. +.sp +This option has not been fully documented. +.TP +.NOP \f\*[B-Font]\-\&?\f[], \f\*[B-Font]\-\-help\f[] +Display usage information and exit. +.TP +.NOP \f\*[B-Font]\-\&!\f[], \f\*[B-Font]\-\-more-help\f[] +Pass the extended usage information through a pager. +.TP +.NOP \f\*[B-Font]\->\f[] [\f\*[I-Font]cfgfile\f[]], \f\*[B-Font]\-\-save-opts\f[] [=\f\*[I-Font]cfgfile\f[]] +Save the option state to \fIcfgfile\fP. The default is the \fIlast\fP +configuration file listed in the \fBOPTION PRESETS\fP section, below. +The command will exit after updating the config file. +.TP +.NOP \f\*[B-Font]\-<\f[] \f\*[I-Font]cfgfile\f[], \f\*[B-Font]\-\-load-opts\f[]=\f\*[I-Font]cfgfile\f[], \f\*[B-Font]\-\-no-load-opts\f[] +Load options from \fIcfgfile\fP. +The \fIno-load-opts\fP form will disable the loading +of earlier config/rc/ini files. \fI\-\-no-load-opts\fP is handled early, +out of order. +.TP +.NOP \f\*[B-Font]\-\-version\f[] [{\f\*[I-Font]v|c|n\f[]}] +Output version of program and exit. The default mode is `v', a simple +version. The `c' mode will print copyright information and `n' will +print the full copyright notice. +.PP +.SH "OPTION PRESETS" +Any option that is not marked as \fInot presettable\fP may be preset +by loading values from configuration ("RC" or ".INI") file(s) and values from +environment variables named: +.nf + \fBNTP_KEYGEN_<option-name>\fP or \fBNTP_KEYGEN\fP +.fi +.ad +The environmental presets take precedence (are processed later than) +the configuration files. +The \fIhomerc\fP files are "\fI$HOME\fP", and "\fI.\fP". +If any of these are directories, then the file \fI.ntprc\fP +is searched for within those directories. +.SH USAGE +The +\f\*[B-Font]\-p\f[] \f\*[I-Font]password\f[] +option specifies the write password and +\f\*[B-Font]\-q\f[] \f\*[I-Font]password\f[] +option the read password for previously encrypted files. +The +\f\*[B-Font]ntp-keygen\fP +program prompts for the password if it reads an encrypted file +and the password is missing or incorrect. +If an encrypted file is read successfully and +no write password is specified, the read password is used +as the write password by default. +.SH "ENVIRONMENT" +See \fBOPTION PRESETS\fP for configuration environment variables. +.SH "FILES" +See \fBOPTION PRESETS\fP for configuration files. +.SH "EXIT STATUS" +One of the following exit values will be returned: +.TP +.NOP 0 " (EXIT_SUCCESS)" +Successful program execution. +.TP +.NOP 1 " (EXIT_FAILURE)" +The operation failed or the command syntax was not valid. +.TP +.NOP 66 " (EX_NOINPUT)" +A specified configuration file could not be loaded. +.TP +.NOP 70 " (EX_SOFTWARE)" +libopts had an internal operational error. Please report +it to autogen-users@lists.sourceforge.net. Thank you. +.PP +.SH "AUTHORS" +The University of Delaware +.SH "COPYRIGHT" +Copyright (C) 1970-2014 The University of Delaware all rights reserved. +This program is released under the terms of the NTP license, <http://ntp.org/license>. +.SH BUGS +It can take quite a while to generate some cryptographic values, +from one to several minutes with modern architectures +such as UltraSPARC and up to tens of minutes to an hour +with older architectures such as SPARC IPC. +.sp \n(Ppu +.ne 2 + +Please report bugs to http://bugs.ntp.org . +.sp \n(Ppu +.ne 2 + +Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org +.SH NOTES +Portions of this document came from FreeBSD. +.sp \n(Ppu +.ne 2 + +This manual page was \fIAutoGen\fP-erated from the \fBntp-keygen\fP +option definitions. diff --git a/util/ntp-keygen.mdoc.in b/util/ntp-keygen.mdoc.in new file mode 100644 index 0000000..80c6009 --- /dev/null +++ b/util/ntp-keygen.mdoc.in @@ -0,0 +1,1071 @@ +.Dd December 2 2014 +.Dt NTP_KEYGEN @NTP_KEYGEN_MS@ User Commands +.Os +.\" EDIT THIS FILE WITH CAUTION (ntp-keygen-opts.mdoc) +.\" +.\" It has been AutoGen-ed December 2, 2014 at 08:58:51 AM by AutoGen 5.18.5pre4 +.\" From the definitions ntp-keygen-opts.def +.\" and the template file agmdoc-cmd.tpl +.Sh NAME +.Nm ntp-keygen +.Nd Create a NTP host key +.Sh SYNOPSIS +.Nm +.\" Mixture of short (flag) options and long options +.Op Fl flags +.Op Fl flag Op Ar value +.Op Fl \-option\-name Ns Oo Oo Ns "=| " Oc Ns Ar value Oc +.Pp +All arguments must be options. +.Pp +.Sh DESCRIPTION +This program generates cryptographic data files used by the NTPv4 +authentication and identification schemes. +It generates MD5 key files used in symmetric key cryptography. +In addition, if the OpenSSL software library has been installed, +it generates keys, certificate and identity files used in public key +cryptography. +These files are used for cookie encryption, +digital signature and challenge/response identification algorithms +compatible with the Internet standard security infrastructure. +.Pp +All files are in PEM\-encoded printable ASCII format, +so they can be embedded as MIME attachments in mail to other sites +and certificate authorities. +By default, files are not encrypted. +.Pp +When used to generate message digest keys, the program produces a file +containing ten pseudo\-random printable ASCII strings suitable for the +MD5 message digest algorithm included in the distribution. +If the OpenSSL library is installed, it produces an additional ten +hex\-encoded random bit strings suitable for the SHA1 and other message +digest algorithms. +The message digest keys file must be distributed and stored +using secure means beyond the scope of NTP itself. +Besides the keys used for ordinary NTP associations, additional keys +can be defined as passwords for the +.Xr ntpq @NTPQ_MS@ +and +.Xr ntpdc @NTPDC_MS@ +utility programs. +.Pp +The remaining generated files are compatible with other OpenSSL +applications and other Public Key Infrastructure (PKI) resources. +Certificates generated by this program are compatible with extant +industry practice, although some users might find the interpretation of +X509v3 extension fields somewhat liberal. +However, the identity keys are probably not compatible with anything +other than Autokey. +.Pp +Some files used by this program are encrypted using a private password. +The +.Fl p +option specifies the password for local encrypted files and the +.Fl q +option the password for encrypted files sent to remote sites. +If no password is specified, the host name returned by the Unix +.Fn gethostname +function, normally the DNS name of the host is used. +.Pp +The +.Ar pw +option of the +.Ar crypto +configuration command specifies the read +password for previously encrypted local files. +This must match the local password used by this program. +If not specified, the host name is used. +Thus, if files are generated by this program without password, +they can be read back by +.Ar ntpd +without password but only on the same host. +.Pp +Normally, encrypted files for each host are generated by that host and +used only by that host, although exceptions exist as noted later on +this page. +The symmetric keys file, normally called +.Ar ntp.keys , +is usually installed in +.Pa /etc . +Other files and links are usually installed in +.Pa /usr/local/etc , +which is normally in a shared filesystem in +NFS\-mounted networks and cannot be changed by shared clients. +The location of the keys directory can be changed by the +.Ar keysdir +configuration command in such cases. +Normally, this is in +.Pa /etc . +.Pp +This program directs commentary and error messages to the standard +error stream +.Ar stderr +and remote files to the standard output stream +.Ar stdout +where they can be piped to other applications or redirected to files. +The names used for generated files and links all begin with the +string +.Ar ntpkey +and include the file type, generating host and filestamp, +as described in the +.Dq Cryptographic Data Files +section below. +.Ss Running the Program +To test and gain experience with Autokey concepts, log in as root and +change to the keys directory, usually +.Pa /usr/local/etc +When run for the first time, or if all files with names beginning with +.Ar ntpkey +have been removed, use the +.Nm +command without arguments to generate a +default RSA host key and matching RSA\-MD5 certificate with expiration +date one year hence. +If run again without options, the program uses the +existing keys and parameters and generates only a new certificate with +new expiration date one year hence. +.Pp +Run the command on as many hosts as necessary. +Designate one of them as the trusted host (TH) using +.Nm +with the +.Fl T +option and configure it to synchronize from reliable Internet servers. +Then configure the other hosts to synchronize to the TH directly or +indirectly. +A certificate trail is created when Autokey asks the immediately +ascendant host towards the TH to sign its certificate, which is then +provided to the immediately descendant host on request. +All group hosts should have acyclic certificate trails ending on the TH. +.Pp +The host key is used to encrypt the cookie when required and so must be +RSA type. +By default, the host key is also the sign key used to encrypt +signatures. +A different sign key can be assigned using the +.Fl S +option and this can be either RSA or DSA type. +By default, the signature +message digest type is MD5, but any combination of sign key type and +message digest type supported by the OpenSSL library can be specified +using the +.Fl c +option. +The rules say cryptographic media should be generated with proventic +filestamps, which means the host should already be synchronized before +this program is run. +This of course creates a chicken\-and\-egg problem +when the host is started for the first time. +Accordingly, the host time +should be set by some other means, such as eyeball\-and\-wristwatch, at +least so that the certificate lifetime is within the current year. +After that and when the host is synchronized to a proventic source, the +certificate should be re\-generated. +.Pp +Additional information on trusted groups and identity schemes is on the +.Dq Autokey Public\-Key Authentication +page. +.Pp +The +.Xr ntpd @NTPD_MS@ +configuration command +.Ic crypto pw Ar password +specifies the read password for previously encrypted files. +The daemon expires on the spot if the password is missing +or incorrect. +For convenience, if a file has been previously encrypted, +the default read password is the name of the host running +the program. +If the previous write password is specified as the host name, +these files can be read by that host with no explicit password. +.Pp +File names begin with the prefix +.Cm ntpkey_ +and end with the postfix +.Ar _hostname.filestamp , +where +.Ar hostname +is the owner name, usually the string returned +by the Unix gethostname() routine, and +.Ar filestamp +is the NTP seconds when the file was generated, in decimal digits. +This both guarantees uniqueness and simplifies maintenance +procedures, since all files can be quickly removed +by a +.Ic rm ntpkey\&* +command or all files generated +at a specific time can be removed by a +.Ic rm +.Ar \&*filestamp +command. +To further reduce the risk of misconfiguration, +the first two lines of a file contain the file name +and generation date and time as comments. +.Pp +All files are installed by default in the keys directory +.Pa /usr/local/etc , +which is normally in a shared filesystem +in NFS\-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. +.Pp +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write\-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. +.Pp +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +.Xr ntpd @NTPD_MS@ +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +.Nm +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +.Ss Running the program +The safest way to run the +.Nm +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +.Pa /usr/local/etc , +then run the program. +When run for the first time, +or if all +.Cm ntpkey +files have been removed, +the program generates a RSA host key file and matching RSA\-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. +.Pp +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. +.Pp +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. +.Pp +Running the program as other than root and using the Unix +.Ic su +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +.Cm .rnd +in the user home directory. +However, there should be only one +.Cm .rnd , +most conveniently +in the root directory, so it is convenient to define the +.Cm $RANDFILE +environment variable used by the OpenSSL library as the path to +.Cm /.rnd . +.Pp +Installing the keys as root might not work in NFS\-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +.Pa /etc +using the +.Ic keysdir +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. +.Pp +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +.Pp +All files are installed by default in the keys directory +.Pa /usr/local/etc , +which is normally in a shared filesystem +in NFS\-mounted networks. +The actual location of the keys directory +and each file can be overridden by configuration commands, +but this is not recommended. +Normally, the files for each host are generated by that host +and used only by that host, although exceptions exist +as noted later on this page. +.Pp +Normally, files containing private values, +including the host key, sign key and identification parameters, +are permitted root read/write\-only; +while others containing public values are permitted world readable. +Alternatively, files containing private values can be encrypted +and these files permitted world readable, +which simplifies maintenance in shared file systems. +Since uniqueness is insured by the hostname and +file name extensions, the files for a NFS server and +dependent clients can all be installed in the same shared directory. +.Pp +The recommended practice is to keep the file name extensions +when installing a file and to install a soft link +from the generic names specified elsewhere on this page +to the generated files. +This allows new file generations to be activated simply +by changing the link. +If a link is present, ntpd follows it to the file name +to extract the filestamp. +If a link is not present, +.Xr ntpd @NTPD_MS@ +extracts the filestamp from the file itself. +This allows clients to verify that the file and generation times +are always current. +The +.Nm +program uses the same timestamp extension for all files generated +at one time, so each generation is distinct and can be readily +recognized in monitoring data. +.Ss Running the program +The safest way to run the +.Nm +program is logged in directly as root. +The recommended procedure is change to the keys directory, +usually +.Pa /usr/local/etc , +then run the program. +When run for the first time, +or if all +.Cm ntpkey +files have been removed, +the program generates a RSA host key file and matching RSA\-MD5 certificate file, +which is all that is necessary in many cases. +The program also generates soft links from the generic names +to the respective files. +If run again, the program uses the same host key file, +but generates a new certificate file and link. +.Pp +The host key is used to encrypt the cookie when required and so must be RSA type. +By default, the host key is also the sign key used to encrypt signatures. +When necessary, a different sign key can be specified and this can be +either RSA or DSA type. +By default, the message digest type is MD5, but any combination +of sign key type and message digest type supported by the OpenSSL library +can be specified, including those using the MD2, MD5, SHA, SHA1, MDC2 +and RIPE160 message digest algorithms. +However, the scheme specified in the certificate must be compatible +with the sign key. +Certificates using any digest algorithm are compatible with RSA sign keys; +however, only SHA and SHA1 certificates are compatible with DSA sign keys. +.Pp +Private/public key files and certificates are compatible with +other OpenSSL applications and very likely other libraries as well. +Certificates or certificate requests derived from them should be compatible +with extant industry practice, although some users might find +the interpretation of X509v3 extension fields somewhat liberal. +However, the identification parameter files, although encoded +as the other files, are probably not compatible with anything other than Autokey. +.Pp +Running the program as other than root and using the Unix +.Ic su +command +to assume root may not work properly, since by default the OpenSSL library +looks for the random seed file +.Cm .rnd +in the user home directory. +However, there should be only one +.Cm .rnd , +most conveniently +in the root directory, so it is convenient to define the +.Cm $RANDFILE +environment variable used by the OpenSSL library as the path to +.Cm /.rnd . +.Pp +Installing the keys as root might not work in NFS\-mounted +shared file systems, as NFS clients may not be able to write +to the shared keys directory, even as root. +In this case, NFS clients can specify the files in another +directory such as +.Pa /etc +using the +.Ic keysdir +command. +There is no need for one client to read the keys and certificates +of other clients or servers, as these data are obtained automatically +by the Autokey protocol. +.Pp +Ordinarily, cryptographic files are generated by the host that uses them, +but it is possible for a trusted agent (TA) to generate these files +for other hosts; however, in such cases files should always be encrypted. +The subject name and trusted name default to the hostname +of the host generating the files, but can be changed by command line options. +It is convenient to designate the owner name and trusted name +as the subject and issuer fields, respectively, of the certificate. +The owner name is also used for the host and sign key files, +while the trusted name is used for the identity files. +seconds. +seconds. +s Trusted Hosts and Groups +Each cryptographic configuration involves selection of a signature scheme +and identification scheme, called a cryptotype, +as explained in the +.Sx Authentication Options +section of +.Xr ntp.conf 5 . +The default cryptotype uses RSA encryption, MD5 message digest +and TC identification. +First, configure a NTP subnet including one or more low\-stratum +trusted hosts from which all other hosts derive synchronization +directly or indirectly. +Trusted hosts have trusted certificates; +all other hosts have nontrusted certificates. +These hosts will automatically and dynamically build authoritative +certificate trails to one or more trusted hosts. +A trusted group is the set of all hosts that have, directly or indirectly, +a certificate trail ending at a trusted host. +The trail is defined by static configuration file entries +or dynamic means described on the +.Sx Automatic NTP Configuration Options +section of +.Xr ntp.conf 5 . +.Pp +On each trusted host as root, change to the keys directory. +To insure a fresh fileset, remove all +.Cm ntpkey +files. +Then run +.Nm +.Fl T +to generate keys and a trusted certificate. +On all other hosts do the same, but leave off the +.Fl T +flag to generate keys and nontrusted certificates. +When complete, start the NTP daemons beginning at the lowest stratum +and working up the tree. +It may take some time for Autokey to instantiate the certificate trails +throughout the subnet, but setting up the environment is completely automatic. +.Pp +If it is necessary to use a different sign key or different digest/signature +scheme than the default, run +.Nm +with the +.Fl S Ar type +option, where +.Ar type +is either +.Cm RSA +or +.Cm DSA . +The most often need to do this is when a DSA\-signed certificate is used. +If it is necessary to use a different certificate scheme than the default, +run +.Nm +with the +.Fl c Ar scheme +option and selected +.Ar scheme +as needed. +f +.Nm +is run again without these options, it generates a new certificate +using the same scheme and sign key. +.Pp +After setting up the environment it is advisable to update certificates +from time to time, if only to extend the validity interval. +Simply run +.Nm +with the same flags as before to generate new certificates +using existing keys. +However, if the host or sign key is changed, +.Xr ntpd @NTPD_MS@ +should be restarted. +When +.Xr ntpd @NTPD_MS@ +is restarted, it loads any new files and restarts the protocol. +Other dependent hosts will continue as usual until signatures are refreshed, +at which time the protocol is restarted. +.Ss Identity Schemes +As mentioned on the Autonomous Authentication page, +the default TC identity scheme is vulnerable to a middleman attack. +However, there are more secure identity schemes available, +including PC, IFF, GQ and MV described on the +.Qq Identification Schemes +page +(maybe available at +.Li http://www.eecis.udel.edu/%7emills/keygen.html ) . +These schemes are based on a TA, one or more trusted hosts +and some number of nontrusted hosts. +Trusted hosts prove identity using values provided by the TA, +while the remaining hosts prove identity using values provided +by a trusted host and certificate trails that end on that host. +The name of a trusted host is also the name of its sugroup +and also the subject and issuer name on its trusted certificate. +The TA is not necessarily a trusted host in this sense, but often is. +.Pp +In some schemes there are separate keys for servers and clients. +A server can also be a client of another server, +but a client can never be a server for another client. +In general, trusted hosts and nontrusted hosts that operate +as both server and client have parameter files that contain +both server and client keys. +Hosts that operate +only as clients have key files that contain only client keys. +.Pp +The PC scheme supports only one trusted host in the group. +On trusted host alice run +.Nm +.Fl P +.Fl p Ar password +to generate the host key file +.Pa ntpkey_RSAkey_ Ns Ar alice.filestamp +and trusted private certificate file +.Pa ntpkey_RSA\-MD5_cert_ Ns Ar alice.filestamp . +Copy both files to all group hosts; +they replace the files which would be generated in other schemes. +On each host bob install a soft link from the generic name +.Pa ntpkey_host_ Ns Ar bob +to the host key file and soft link +.Pa ntpkey_cert_ Ns Ar bob +to the private certificate file. +Note the generic links are on bob, but point to files generated +by trusted host alice. +In this scheme it is not possible to refresh +either the keys or certificates without copying them +to all other hosts in the group. +.Pp +For the IFF scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host in the group, +generate the IFF parameter file. +On trusted host alice run +.Nm +.Fl T +.Fl I +.Fl p Ar password +to produce her parameter file +.Pa ntpkey_IFFpar_ Ns Ar alice.filestamp , +which includes both server and client keys. +Copy this file to all group hosts that operate as both servers +and clients and install a soft link from the generic +.Pa ntpkey_iff_ Ns Ar alice +to this file. +If there are no hosts restricted to operate only as clients, +there is nothing further to do. +As the IFF scheme is independent +of keys and certificates, these files can be refreshed as needed. +.Pp +If a rogue client has the parameter file, it could masquerade +as a legitimate server and present a middleman threat. +To eliminate this threat, the client keys can be extracted +from the parameter file and distributed to all restricted clients. +After generating the parameter file, on alice run +.Nm +.Fl e +and pipe the output to a file or mail program. +Copy or mail this file to all restricted clients. +On these clients install a soft link from the generic +.Pa ntpkey_iff_ Ns Ar alice +to this file. +To further protect the integrity of the keys, +each file can be encrypted with a secret password. +.Pp +For the GQ scheme proceed as in the TC scheme to generate keys +and certificates for all group hosts, then for every trusted host +in the group, generate the IFF parameter file. +On trusted host alice run +.Nm +.Fl T +.Fl G +.Fl p Ar password +to produce her parameter file +.Pa ntpkey_GQpar_ Ns Ar alice.filestamp , +which includes both server and client keys. +Copy this file to all group hosts and install a soft link +from the generic +.Pa ntpkey_gq_ Ns Ar alice +to this file. +In addition, on each host bob install a soft link +from generic +.Pa ntpkey_gq_ Ns Ar bob +to this file. +As the GQ scheme updates the GQ parameters file and certificate +at the same time, keys and certificates can be regenerated as needed. +.Pp +For the MV scheme, proceed as in the TC scheme to generate keys +and certificates for all group hosts. +For illustration assume trish is the TA, alice one of several trusted hosts +and bob one of her clients. +On TA trish run +.Nm +.Fl V Ar n +.Fl p Ar password , +where +.Ar n +is the number of revokable keys (typically 5) to produce +the parameter file +.Pa ntpkeys_MVpar_ Ns Ar trish.filestamp +and client key files +.Pa ntpkeys_MVkeyd_ Ns Ar trish.filestamp +where +.Ar d +is the key number (0 \&< +.Ar d +\&< +.Ar n ) . +Copy the parameter file to alice and install a soft link +from the generic +.Pa ntpkey_mv_ Ns Ar alice +to this file. +Copy one of the client key files to alice for later distribution +to her clients. +It doesn't matter which client key file goes to alice, +since they all work the same way. +Alice copies the client key file to all of her cliens. +On client bob install a soft link from generic +.Pa ntpkey_mvkey_ Ns Ar bob +to the client key file. +As the MV scheme is independent of keys and certificates, +these files can be refreshed as needed. +.Ss Command Line Options +.Bl -tag -width indent +.It Fl c Ar scheme +Select certificate message digest/signature encryption scheme. +The +.Ar scheme +can be one of the following: +. Cm RSA\-MD2 , RSA\-MD5 , RSA\-SHA , RSA\-SHA1 , RSA\-MDC2 , RSA\-RIPEMD160 , DSA\-SHA , +or +.Cm DSA\-SHA1 . +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. +The default without this option is +.Cm RSA\-MD5 . +.It Fl d +Enable debugging. +This option displays the cryptographic data produced in eye\-friendly billboards. +.It Fl e +Write the IFF client keys to the standard output. +This is intended for automatic key distribution by mail. +.It Fl G +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +.It Fl g +Generate keys for the GQ identification scheme +using the existing GQ parameters. +If the GQ parameters do not yet exist, create them first. +.It Fl H +Generate new host keys, obsoleting any that may exist. +.It Fl I +Generate parameters for the IFF identification scheme, +obsoleting any that may exist. +.It Fl i Ar name +Set the suject name to +.Ar name . +This is used as the subject field in certificates +and in the file name for host and sign keys. +.It Fl M +Generate MD5 keys, obsoleting any that may exist. +.It Fl P +Generate a private certificate. +By default, the program generates public certificates. +.It Fl p Ar password +Encrypt generated files containing private data with +.Ar password +and the DES\-CBC algorithm. +.It Fl q +Set the password for reading files to password. +.It Fl S Oo Cm RSA | DSA Oc +Generate a new sign key of the designated type, +obsoleting any that may exist. +By default, the program uses the host key as the sign key. +.It Fl s Ar name +Set the issuer name to +.Ar name . +This is used for the issuer field in certificates +and in the file name for identity files. +.It Fl T +Generate a trusted certificate. +By default, the program generates a non\-trusted certificate. +.It Fl V Ar nkeys +Generate parameters and keys for the Mu\-Varadharajan (MV) identification scheme. +.El +.Ss Random Seed File +All cryptographically sound key generation schemes must have means +to randomize the entropy seed used to initialize +the internal pseudo\-random number generator used +by the library routines. +The OpenSSL library uses a designated random seed file for this purpose. +The file must be available when starting the NTP daemon and +.Nm +program. +If a site supports OpenSSL or its companion OpenSSH, +it is very likely that means to do this are already available. +.Pp +It is important to understand that entropy must be evolved +for each generation, for otherwise the random number sequence +would be predictable. +Various means dependent on external events, such as keystroke intervals, +can be used to do this and some systems have built\-in entropy sources. +Suitable means are described in the OpenSSL software documentation, +but are outside the scope of this page. +.Pp +The entropy seed used by the OpenSSL library is contained in a file, +usually called +.Cm .rnd , +which must be available when starting the NTP daemon +or the +.Nm +program. +The NTP daemon will first look for the file +using the path specified by the +.Ic randfile +subcommand of the +.Ic crypto +configuration command. +If not specified in this way, or when starting the +.Nm +program, +the OpenSSL library will look for the file using the path specified +by the +.Ev RANDFILE +environment variable in the user home directory, +whether root or some other user. +If the +.Ev RANDFILE +environment variable is not present, +the library will look for the +.Cm .rnd +file in the user home directory. +If the file is not available or cannot be written, +the daemon exits with a message to the system log and the program +exits with a suitable error message. +.Ss Cryptographic Data Files +All other file formats begin with two lines. +The first contains the file name, including the generated host name +and filestamp. +The second contains the datestamp in conventional Unix date format. +Lines beginning with # are considered comments and ignored by the +.Nm +program and +.Xr ntpd @NTPD_MS@ +daemon. +Cryptographic values are encoded first using ASN.1 rules, +then encrypted if necessary, and finally written PEM\-encoded +printable ASCII format preceded and followed by MIME content identifier lines. +.Pp +The format of the symmetric keys file is somewhat different +than the other files in the interest of backward compatibility. +Since DES\-CBC is deprecated in NTPv4, the only key format of interest +is MD5 alphanumeric strings. +Following hte heard the keys are +entered one per line in the format +.D1 Ar keyno type key +where +.Ar keyno +is a positive integer in the range 1\-65,535, +.Ar type +is the string MD5 defining the key format and +.Ar key +is the key itself, +which is a printable ASCII string 16 characters or less in length. +Each character is chosen from the 93 printable characters +in the range 0x21 through 0x7f excluding space and the +.Ql # +character. +.Pp +Note that the keys used by the +.Xr ntpq @NTPQ_MS@ +and +.Xr ntpdc @NTPDC_MS@ +programs +are checked against passwords requested by the programs +and entered by hand, so it is generally appropriate to specify these keys +in human readable ASCII format. +.Pp +The +.Nm +program generates a MD5 symmetric keys file +.Pa ntpkey_MD5key_ Ns Ar hostname.filestamp . +Since the file contains private shared keys, +it should be visible only to root and distributed by secure means +to other subnet hosts. +The NTP daemon loads the file +.Pa ntp.keys , +so +.Nm +installs a soft link from this name to the generated file. +Subsequently, similar soft links must be installed by manual +or automated means on the other subnet hosts. +While this file is not used with the Autokey Version 2 protocol, +it is needed to authenticate some remote configuration commands +used by the +.Xr ntpq @NTPQ_MS@ +and +.Xr ntpdc @NTPDC_MS@ +utilities. +.Sh "OPTIONS" +.Bl -tag +.It Fl b Ar imbits , Fl \-imbits Ns = Ns Ar imbits +identity modulus bits. +This option takes an integer number as its argument. +The value of +.Ar imbits +is constrained to being: +.in +4 +.nf +.na +in the range 256 through 2048 +.fi +.in -4 +.sp +The number of bits in the identity modulus. The default is 256. +.It Fl c Ar scheme , Fl \-certificate Ns = Ns Ar scheme +certificate scheme. +.sp +scheme is one of +RSA\-MD2, RSA\-MD5, RSA\-SHA, RSA\-SHA1, RSA\-MDC2, RSA\-RIPEMD160, +DSA\-SHA, or DSA\-SHA1. +.sp +Select the certificate message digest/signature encryption scheme. +Note that RSA schemes must be used with a RSA sign key and DSA +schemes must be used with a DSA sign key. The default without +this option is RSA\-MD5. +.It Fl C Ar cipher , Fl \-cipher Ns = Ns Ar cipher +privatekey cipher. +.sp +Select the cipher which is used to encrypt the files containing +private keys. The default is three\-key triple DES in CBC mode, +equivalent to "@code{\-C des\-ede3\-cbc". The openssl tool lists ciphers +available in "\fBopenssl \-h\fP" output. +.It Fl d , Fl \-debug\-level +Increase debug verbosity level. +This option may appear an unlimited number of times. +.sp +.It Fl D Ar number , Fl \-set\-debug\-level Ns = Ns Ar number +Set the debug verbosity level. +This option may appear an unlimited number of times. +This option takes an integer number as its argument. +.sp +.It Fl e , Fl \-id\-key +Write IFF or GQ identity keys. +.sp +Write the IFF or GQ client keys to the standard output. This is +intended for automatic key distribution by mail. +.It Fl G , Fl \-gq\-params +Generate GQ parameters and keys. +.sp +Generate parameters and keys for the GQ identification scheme, +obsoleting any that may exist. +.It Fl H , Fl \-host\-key +generate RSA host key. +.sp +Generate new host keys, obsoleting any that may exist. +.It Fl I , Fl \-iffkey +generate IFF parameters. +.sp +Generate parameters for the IFF identification scheme, obsoleting +any that may exist. +.It Fl i Ar group , Fl \-ident Ns = Ns Ar group +set Autokey group name. +.sp +Set the optional Autokey group name to name. This is used in +the file name of IFF, GQ, and MV client parameters files. In +that role, the default is the host name if this option is not +provided. The group name, if specified using \fB\-i/\-\-ident\fP or +using \fB\-s/\-\-subject\-name\fP following an '\fB@\fP' character, +is also a part of the self\-signed host certificate's subject and +issuer names in the form \fBhost@group\fP and should match the +\'\fBcrypto ident\fP' or '\fBserver ident\fP' configuration in +\fBntpd\fP's configuration file. +.It Fl l Ar lifetime , Fl \-lifetime Ns = Ns Ar lifetime +set certificate lifetime. +This option takes an integer number as its argument. +.sp +Set the certificate expiration to lifetime days from now. +.It Fl M , Fl \-md5key +generate MD5 keys. +.sp +Generate MD5 keys, obsoleting any that may exist. +.It Fl m Ar modulus , Fl \-modulus Ns = Ns Ar modulus +modulus. +This option takes an integer number as its argument. +The value of +.Ar modulus +is constrained to being: +.in +4 +.nf +.na +in the range 256 through 2048 +.fi +.in -4 +.sp +The number of bits in the prime modulus. The default is 512. +.It Fl P , Fl \-pvt\-cert +generate PC private certificate. +.sp +Generate a private certificate. By default, the program generates +public certificates. +.It Fl p Ar passwd , Fl \-password Ns = Ns Ar passwd +local private password. +.sp +Local files containing private data are encrypted with the +DES\-CBC algorithm and the specified password. The same password +must be specified to the local ntpd via the "crypto pw password" +configuration command. The default password is the local +hostname. +.It Fl q Ar passwd , Fl \-export\-passwd Ns = Ns Ar passwd +export IFF or GQ group keys with password. +.sp +Export IFF or GQ identity group keys to the standard output, +encrypted with the DES\-CBC algorithm and the specified password. +The same password must be specified to the remote ntpd via the +"crypto pw password" configuration command. See also the option +-\-id\-key (\-e) for unencrypted exports. +.It Fl S Ar sign , Fl \-sign\-key Ns = Ns Ar sign +generate sign key (RSA or DSA). +.sp +Generate a new sign key of the designated type, obsoleting any +that may exist. By default, the program uses the host key as the +sign key. +.It Fl s Ar host@group , Fl \-subject\-name Ns = Ns Ar host@group +set host and optionally group name. +.sp +Set the Autokey host name, and optionally, group name specified +following an '\fB@\fP' character. The host name is used in the file +name of generated host and signing certificates, without the +group name. The host name, and if provided, group name are used +in \fBhost@group\fP form for the host certificate's subject and issuer +fields. Specifying '\fB\-s @group\fP' is allowed, and results in +leaving the host name unchanged while appending \fB@group\fP to the +subject and issuer fields, as with \fB\-i group\fP. The group name, or +if not provided, the host name are also used in the file names +of IFF, GQ, and MV client parameter files. +.It Fl T , Fl \-trusted\-cert +trusted certificate (TC scheme). +.sp +Generate a trusted certificate. By default, the program generates +a non\-trusted certificate. +.It Fl V Ar num , Fl \-mv\-params Ns = Ns Ar num +generate <num> MV parameters. +This option takes an integer number as its argument. +.sp +Generate parameters and keys for the Mu\-Varadharajan (MV) +identification scheme. +.It Fl v Ar num , Fl \-mv\-keys Ns = Ns Ar num +update <num> MV keys. +This option takes an integer number as its argument. +.sp +This option has not been fully documented. +.It Fl \&? , Fl \-help +Display usage information and exit. +.It Fl \&! , Fl \-more\-help +Pass the extended usage information through a pager. +.It Fl > Oo Ar cfgfile Oc , Fl \-save\-opts Oo Ns = Ns Ar cfgfile Oc +Save the option state to \fIcfgfile\fP. The default is the \fIlast\fP +configuration file listed in the \fBOPTION PRESETS\fP section, below. +The command will exit after updating the config file. +.It Fl < Ar cfgfile , Fl \-load\-opts Ns = Ns Ar cfgfile , Fl \-no\-load\-opts +Load options from \fIcfgfile\fP. +The \fIno\-load\-opts\fP form will disable the loading +of earlier config/rc/ini files. \fI\-\-no\-load\-opts\fP is handled early, +out of order. +.It Fl \-version Op Brq Ar v|c|n +Output version of program and exit. The default mode is `v', a simple +version. The `c' mode will print copyright information and `n' will +print the full copyright notice. +.El +.Sh "OPTION PRESETS" +Any option that is not marked as \fInot presettable\fP may be preset +by loading values from configuration ("RC" or ".INI") file(s) and values from +environment variables named: +.nf + \fBNTP_KEYGEN_<option\-name>\fP or \fBNTP_KEYGEN\fP +.fi +.ad +The environmental presets take precedence (are processed later than) +the configuration files. +The \fIhomerc\fP files are "\fI$HOME\fP", and "\fI.\fP". +If any of these are directories, then the file \fI.ntprc\fP +is searched for within those directories. +.Sh USAGE +The +.Fl p Ar password +option specifies the write password and +.Fl q Ar password +option the read password for previously encrypted files. +The +.Nm +program prompts for the password if it reads an encrypted file +and the password is missing or incorrect. +If an encrypted file is read successfully and +no write password is specified, the read password is used +as the write password by default. +.Sh "ENVIRONMENT" +See \fBOPTION PRESETS\fP for configuration environment variables. +.Sh "FILES" +See \fBOPTION PRESETS\fP for configuration files. +.Sh "EXIT STATUS" +One of the following exit values will be returned: +.Bl -tag +.It 0 " (EXIT_SUCCESS)" +Successful program execution. +.It 1 " (EXIT_FAILURE)" +The operation failed or the command syntax was not valid. +.It 66 " (EX_NOINPUT)" +A specified configuration file could not be loaded. +.It 70 " (EX_SOFTWARE)" +libopts had an internal operational error. Please report +it to autogen\-users@lists.sourceforge.net. Thank you. +.El +.Sh "AUTHORS" +The University of Delaware +.Sh "COPYRIGHT" +Copyright (C) 1970\-2014 The University of Delaware all rights reserved. +This program is released under the terms of the NTP license, <http://ntp.org/license>. +.Sh BUGS +It can take quite a while to generate some cryptographic values, +from one to several minutes with modern architectures +such as UltraSPARC and up to tens of minutes to an hour +with older architectures such as SPARC IPC. +.Pp +Please report bugs to http://bugs.ntp.org . +.Pp +Please send bug reports to: http://bugs.ntp.org, bugs@ntp.org +.Sh NOTES +Portions of this document came from FreeBSD. +.Pp +This manual page was \fIAutoGen\fP\-erated from the \fBntp\-keygen\fP +option definitions. diff --git a/util/ntp-keygen.texi b/util/ntp-keygen.texi new file mode 100644 index 0000000..92cec48 --- /dev/null +++ b/util/ntp-keygen.texi @@ -0,0 +1,307 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename ntp-keygen.info +@settitle Ntp-keygen User's Manual +@include ../sntp/include/version.texi +@paragraphindent 2 +@c %**end of header + +@ifinfo +This file documents the use of the NTP Project's @code{ntp-keygen} +program, which generates various keys for @code{ntpd}, +@end ifinfo + +@direntry +* ntp-keygen: (ntp-keygen). NTP Key Generation +@end direntry + +@titlepage +@title NTP Key Generation User's Manual +@subtitle ntp-keygen, version @value{VERSION}, @value{UPDATED} +@c @author Max @email{foo@ntp.org} +@end titlepage + +@c @page +@c @vskip 0pt plus 1filll + +@shortcontents + +@menu +* Description:: +* ntp-keygen Invocation:: Invoking ntp-keygen +* Running the Program:: +* Random Seed File:: +* Cryptographic Data Files:: +@end menu + +@node Top, Description, (dir), (dir) +@top NTP Key Generation Program User Manual + +This document describes the use of the NTP Project's @code{ntp-keygen} +program, that generates cryptographic data files used by the NTPv4 +authentication and identity schemes. +It can generate message digest keys used in symmetric key cryptography and, +if the OpenSSL software +library has been installed, it can generate host keys, sign keys, +certificates, and identity keys and parameters used by the Autokey +public key cryptography. +The message digest keys file is generated in a +format compatible with NTPv3. +All other files are in PEM-encoded +printable ASCII format so they can be embedded as MIME attachments in +mail to other sites. + +This document applies to version @value{VERSION} of @code{ntp-keygen}. + +@node Description, Running the Program, Top, Top +@comment node-name, next, previous, up +@section Description + +This program generates cryptographic data files used by the NTPv4 +authentication and identity schemes. It can generate message digest +keys used in symmetric key cryptography and, if the OpenSSL software +library has been installed, it can generate host keys, sign keys, +certificates, and identity keys and parameters used by the Autokey +public key cryptography. The message digest keys file is generated in a +format compatible with NTPv3. All other files are in PEM-encoded +printable ASCII format so they can be embedded as MIME attachments in +mail to other sites. + +When used to generate message digest keys, the program produces a file +containing ten pseudo-random printable ASCII strings suitable for the +MD5 message digest algorithm included in the distribution. +If the +OpenSSL library is installed, it produces an additional ten hex-encoded +random bit strings suitable for the SHA1 and other message digest +algorithms. +The message digest keys file must be distributed and stored +using secure means beyond the scope of NTP itself. +Besides the keys +used for ordinary NTP associations, additional keys can be defined as +passwords for the ntpq and ntpdc utility programs. + +The remaining generated files are compatible with other OpenSSL +applications and other Public Key Infrastructure (PKI) resources. +Certificates generated by this program are compatible with extant +industry practice, although some users might find the interpretation of +X509v3 extension fields somewhat liberal. +However, the identity keys +are probably not compatible with anything other than Autokey. + +Some files used by this program are encrypted using a private password. +The @code{-p} option specifies the password for local encrypted files and the +@code{-q} option the password for encrypted files sent to remote sites. +If no password is specified, the host name returned by the Unix +@code{gethostname()} function, normally the DNS name of the host, is used. + +The @kbd{pw} option of the @code{crypto} configuration command +specifies the read password for previously encrypted local files. +This must match the local password used by this program. +If not specified, the host name is used. +Thus, if files are generated by this program without password, +they can be read back by ntpd without password, but only on the same +host. + +Normally, encrypted files for each host are generated by that host and +used only by that host, although exceptions exist as noted later on +this page. +The symmetric keys file, normally called @code{ntp.keys}, is +usually installed in @code{/etc}. +Other files and links are usually installed +in @code{/usr/local/etc}, which is normally in a shared filesystem in +NFS-mounted networks and cannot be changed by shared clients. +The location of the keys directory can be changed by the keysdir +configuration command in such cases. +Normally, this is in @code{/etc}. + +This program directs commentary and error messages to the standard +error stream @code{stderr} and remote files to the standard output stream +@code{stdout} where they can be piped to other applications or redirected to +files. +The names used for generated files and links all begin with the +string @code{ntpkey} and include the file type, +generating host and filestamp, +as described in the @ref{Cryptographic Data Files} section below. + +@node Running the Program, Random Seed File, Description, Top +@comment node-name, next, previous, up +@section Running the Program + +To test and gain experience with Autokey concepts, log in as root and +change to the keys directory, usually @code{/usr/local/etc}. +When run for the +first time, or if all files with names beginning @code{ntpkey}] have been +removed, use the @code{ntp-keygen} command without arguments to generate a +default RSA host key and matching RSA-MD5 certificate with expiration +date one year hence. +If run again without options, the program uses the +existing keys and parameters and generates only a new certificate with +new expiration date one year hence. + +Run the command on as many hosts as necessary. +Designate one of them as the trusted host (TH) using @code{ntp-keygen} +with the @code{-T} option and configure +it to synchronize from reliable Internet servers. +Then configure the other hosts to synchronize to the TH directly or indirectly. +A certificate trail is created when Autokey asks the immediately +ascendant host towards the TH to sign its certificate, which is then +provided to the immediately descendant host on request. +All group hosts should have acyclic certificate trails ending on the TH. + +The host key is used to encrypt the cookie when required and so must be +RSA type. +By default, the host key is also the sign key used to encrypt signatures. +A different sign key can be assigned using the @code{-S} option +and this can be either RSA or DSA type. +By default, the signature +message digest type is MD5, but any combination of sign key type and +message digest type supported by the OpenSSL library can be specified +using the @code{-c} option. + +The rules say cryptographic media should be generated with proventic +filestamps, which means the host should already be synchronized before +this program is run. +This of course creates a chicken-and-egg problem +when the host is started for the first time. +Accordingly, the host time +should be set by some other means, such as eyeball-and-wristwatch, at +least so that the certificate lifetime is within the current year. +After that and when the host is synchronized to a proventic source, the +certificate should be re-generated. + +Additional information on trusted groups and identity schemes is on the +Autokey Public-Key Authentication page. + +@include invoke-ntp-keygen.texi + +@node Random Seed File, Cryptographic Data Files, Running the Program, Top +@comment node-name, next, previous, up +@section Random Seed File + +All cryptographically sound key generation schemes must have means to +randomize the entropy seed used to initialize the internal +pseudo-random number generator used by the OpenSSL library routines. +If a site supports ssh, it is very likely that means to do this are +already available. +The entropy seed used by the OpenSSL library is contained in a file, +usually called @code{.rnd}, which must be available when +starting the @code{ntp-keygen} program or @code{ntpd} daemon. + +The OpenSSL library looks for the file using the path specified by the +@code{RANDFILE} environment variable in the user home directory, whether root +or some other user. +If the @code{RANDFILE} environment variable is not +present, the library looks for the @code{.rnd} file in the user home +directory. +Since both the @code{ntp-keygen} program and @code{ntpd} daemon must run +as root, the logical place to put this file is in @code{/.rnd} or +@code{/root/.rnd}. +If the file is not available or cannot be written, the program exits +with a message to the system log. + +@node Cryptographic Data Files, , Random Seed File, Top +@comment node-name, next, previous, up +@section Cryptographic Data Files + +File and link names are in the @code{form ntpkey_key_name.fstamp}, +where @code{key} is the key or parameter type, +@code{name} is the host or group name and +@code{fstamp} is the filestamp (NTP seconds) when the file was created). +By convention, key names in generated file names include both upper and +lower case characters, while key names in generated link names include +only lower case characters. The filestamp is not used in generated link +names. + +The key name is a string defining the cryptographic key type. +Key types include public/private keys host and sign, certificate cert +and several challenge/response key types. +By convention, client files used for +challenges have a par subtype, as in the IFF challenge IFFpar, while +server files for responses have a key subtype, as in the GQ response +GQkey. + +All files begin with two nonencrypted lines. The first line contains +the file name in the format @code{ntpkey_key_host.fstamp}. +The second line contains the datestamp in conventional Unix date format. +Lines beginning with @code{#} are ignored. + +The remainder of the file contains cryptographic data encoded first +using ASN.1 rules, then encrypted using the DES-CBC algorithm with +given password and finally written in PEM-encoded printable ASCII text +preceded and followed by MIME content identifier lines. + +The format of the symmetric keys file, ordinarily named @code{ntp.keys}, +is somewhat different than the other files in the interest of backward +compatibility. +Ordinarily, the file is generated by this program, but +it can be constructed and edited using an ordinary text editor. + +@example +# ntpkey_MD5key_hms.local.3564038757 +# Sun Dec 9 02:45:57 2012 + + 1 MD5 "]!ghT%O;3)WJ,/Nc:>I # MD5 key + 2 MD5 lu+H^tF46BKR-6~p{V_5 # MD5 key + 3 MD5 :lnoVsE%Y}z*avh%EtNC # MD5 key + 4 MD5 |fdZrf0sF~@PHZ;w-i^V # MD5 key + 5 MD5 IyAG>O"}y"LmCRS!*bHC # MD5 key + 6 MD5 ">e\A@>hT/661ri52,,H # MD5 key + 7 MD5 c9x=M'CfLxax9v)PV-si # MD5 key + 8 MD5 E|=jvFVov?Bn|Ev=&aK\ # MD5 key + 9 MD5 T!c4UT&`(m$+m+B6,`Q0 # MD5 key +10 MD5 JVF/1=)=IFbHbJQz..Cd # MD5 key +11 SHA1 6dea311109529e436c2b4fccae9bc753c16d1b48 # SHA1 key +12 SHA1 7076f373d86c4848c59ff8046e49cb7d614ec394 # SHA1 key +13 SHA1 5f48b1b60591eb01b7cf1d33b7774f08d20262d3 # SHA1 key +14 SHA1 eed5ab9d9497319ec60cf3781d52607e76720178 # SHA1 key +15 SHA1 f283562611a04c964da8126296f5f8e58c3f85de # SHA1 key +16 SHA1 1930da171297dd63549af50b29449de17dcf341f # SHA1 key +17 SHA1 fee892110358cd4382322b889869e750db8e8a8f # SHA1 key +18 SHA1 b5520c9fadd7ad3fd8bfa061c8821b65d029bb37 # SHA1 key +19 SHA1 8c74fb440ec80f453ec6aaa62b9baed0ab723b92 # SHA1 key +20 SHA1 6bc05f734306a189326000970c19b3910f403795 # SHA1 key +@end example + + Figure 1. Typical Symmetric Key File + +Figure 1 shows a typical symmetric keys file used by the reference +implementation. +Each line of the file contains three fields, first an +integer between 1 and 65534, inclusive, representing the key identifier +used in the server and peer configuration commands. +Next is the key type for the message digest algorithm, +which in the absence of the +OpenSSL library must be MD5 to designate the MD5 message digest +algorithm. +If the OpenSSL library is installed, the key type can be any +message digest algorithm supported by that library. +However, if +compatibility with FIPS 140-2 is required, the key type must be either +SHA or SHA1. +The key type can be changed using an ASCII text editor. + +An MD5 key consists of a printable ASCII string less than or equal to +16 characters and terminated by whitespace or a # character. +An OpenSSL +key consists of a hex-encoded ASCII string of 40 characters, which is +truncated as necessary. + +Note that the keys used by the @code{ntpq} and @code{ntpdc} programs are +checked against passwords requested by the programs and entered by hand, +so it +is generally appropriate to specify these keys in human readable ASCII +format. + +The @code{ntp-keygen} program generates a MD5 symmetric keys file +@code{ntpkey_MD5key_hostname.filestamp}. +Since the file contains private +shared keys, it should be visible only to root and distributed by +secure means to other subnet hosts. +The NTP daemon loads the file @code{ntp.keys}, so @code{ntp-keygen} +installs a soft link from this name to the generated file. +Subsequently, similar soft links must be installed by +manual or automated means on the other subnet hosts. +While this file is +not used with the Autokey Version 2 protocol, it is needed to +authenticate some remote configuration commands used by the @code{ntpq} and +@code{ntpdc} utilities. diff --git a/util/ntptime.c b/util/ntptime.c new file mode 100644 index 0000000..dd5605c --- /dev/null +++ b/util/ntptime.c @@ -0,0 +1,474 @@ +/* + * NTP test program + * + * This program tests to see if the NTP user interface routines + * ntp_gettime() and ntp_adjtime() have been implemented in the kernel. + * If so, each of these routines is called to display current timekeeping + * data. + * + * For more information, see the README.kern file in the doc directory + * of the xntp3 distribution. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include "ntp_fp.h" +#include "timevalops.h" +#include "ntp_syscall.h" +#include "ntp_stdlib.h" + +#include <stdio.h> +#include <ctype.h> +#include <signal.h> +#include <setjmp.h> + +#ifdef NTP_SYSCALLS_STD +# ifndef SYS_DECOSF1 +# define BADCALL -1 /* this is supposed to be a bad syscall */ +# endif /* SYS_DECOSF1 */ +#endif + +#ifdef HAVE_STRUCT_NTPTIMEVAL_TIME_TV_NSEC +#define tv_frac_sec tv_nsec +#else +#define tv_frac_sec tv_usec +#endif + + +#define TIMEX_MOD_BITS \ +"\20\1OFFSET\2FREQUENCY\3MAXERROR\4ESTERROR\5STATUS\6TIMECONST\ +\13PLL\14FLL\15MICRO\16NANO\17CLKB\20CLKA" + +#define TIMEX_STA_BITS \ +"\20\1PLL\2PPSFREQ\3PPSTIME\4FLL\5INS\6DEL\7UNSYNC\10FREQHOLD\ +\11PPSSIGNAL\12PPSJITTER\13PPSWANDER\14PPSERROR\15CLOCKERR\ +\16NANO\17MODE\20CLK" + +#define SCALE_FREQ 65536 /* frequency scale */ + +/* + * These constants are used to round the time stamps computed from + * a struct timeval to the microsecond (more or less). This keeps + * things neat. + */ +#define TS_MASK 0xfffff000 /* mask to usec, for time stamps */ +#define TS_ROUNDBIT 0x00000800 /* round at this bit */ + +/* + * Function prototypes + */ +const char * sprintb (u_int, const char *); +const char * timex_state (int); + +#ifdef SIGSYS +void pll_trap (int); + +static struct sigaction newsigsys; /* new sigaction status */ +static struct sigaction sigsys; /* current sigaction status */ +static sigjmp_buf env; /* environment var. for pll_trap() */ +#endif + +static volatile int pll_control; /* (0) daemon, (1) kernel loop */ +static volatile int status; /* most recent status bits */ +static volatile int flash; /* most recent ntp_adjtime() bits */ +char* progname; +static char optargs[] = "MNT:cde:f:hm:o:rs:t:"; + +int +main( + int argc, + char *argv[] + ) +{ + extern int ntp_optind; + extern char *ntp_optarg; +#ifdef SUBST_ADJTIMEX + struct timex ntv; +#else + struct ntptimeval ntv; +#endif + struct timeval tv; + struct timex ntx, _ntx; + int times[20]; + double ftemp, gtemp, htemp; + long time_frac; /* ntv.time.tv_frac_sec (us/ns) */ + l_fp ts; + volatile unsigned ts_mask = TS_MASK; /* defaults to 20 bits (us) */ + volatile unsigned ts_roundbit = TS_ROUNDBIT; /* defaults to 20 bits (us) */ + volatile int fdigits = 6; /* fractional digits for us */ + int c; + int errflg = 0; + int cost = 0; + volatile int rawtime = 0; + + ZERO(ntx); + progname = argv[0]; + while ((c = ntp_getopt(argc, argv, optargs)) != EOF) { + switch (c) { +#ifdef MOD_MICRO + case 'M': + ntx.modes |= MOD_MICRO; + break; +#endif +#ifdef MOD_NANO + case 'N': + ntx.modes |= MOD_NANO; + break; +#endif +#ifdef NTP_API +# if NTP_API > 3 + case 'T': + ntx.modes = MOD_TAI; + ntx.constant = atoi(ntp_optarg); + break; +# endif +#endif + case 'c': + cost++; + break; + + case 'e': + ntx.modes |= MOD_ESTERROR; + ntx.esterror = atoi(ntp_optarg); + break; + + case 'f': + ntx.modes |= MOD_FREQUENCY; + ntx.freq = (long)(atof(ntp_optarg) * SCALE_FREQ); + break; + + case 'm': + ntx.modes |= MOD_MAXERROR; + ntx.maxerror = atoi(ntp_optarg); + break; + + case 'o': + ntx.modes |= MOD_OFFSET; + ntx.offset = atoi(ntp_optarg); + break; + + case 'r': + rawtime++; + break; + + case 's': + ntx.modes |= MOD_STATUS; + ntx.status = atoi(ntp_optarg); + if (ntx.status < 0 || ntx.status >= 0x100) + errflg++; + break; + + case 't': + ntx.modes |= MOD_TIMECONST; + ntx.constant = atoi(ntp_optarg); + break; + + default: + errflg++; + } + } + if (errflg || (ntp_optind != argc)) { + fprintf(stderr, + "usage: %s [-%s]\n\n\ +%s%s%s\ +-c display the time taken to call ntp_gettime (us)\n\ +-e esterror estimate of the error (us)\n\ +-f frequency Frequency error (-500 .. 500) (ppm)\n\ +-h display this help info\n\ +-m maxerror max possible error (us)\n\ +-o offset current offset (ms)\n\ +-r print the unix and NTP time raw\n\ +-s status Set the status bits\n\ +-t timeconstant log2 of PLL time constant (0 .. %d)\n", + progname, optargs, +#ifdef MOD_MICRO +"-M switch to microsecond mode\n", +#else +"", +#endif +#ifdef MOD_NANO +"-N switch to nanosecond mode\n", +#else +"", +#endif +#ifdef NTP_API +# if NTP_API > 3 +"-T tai_offset set TAI offset\n", +# else +"", +# endif +#else +"", +#endif + MAXTC); + exit(2); + } + +#ifdef SIGSYS + /* + * Test to make sure the sigaction() works in case of invalid + * syscall codes. + */ + newsigsys.sa_handler = pll_trap; + newsigsys.sa_flags = 0; + if (sigaction(SIGSYS, &newsigsys, &sigsys)) { + perror("sigaction() fails to save SIGSYS trap"); + exit(1); + } +#endif /* SIGSYS */ + +#ifdef BADCALL + /* + * Make sure the trapcatcher works. + */ + pll_control = 1; +#ifdef SIGSYS + if (sigsetjmp(env, 1) == 0) { +#endif + status = syscall(BADCALL, &ntv); /* dummy parameter */ + if ((status < 0) && (errno == ENOSYS)) + --pll_control; +#ifdef SIGSYS + } +#endif + if (pll_control) + printf("sigaction() failed to catch an invalid syscall\n"); +#endif /* BADCALL */ + + if (cost) { +#ifdef SIGSYS + if (sigsetjmp(env, 1) == 0) { +#endif + for (c = 0; c < COUNTOF(times); c++) { + status = ntp_gettime(&ntv); + if ((status < 0) && (errno == ENOSYS)) + --pll_control; + if (pll_control < 0) + break; + times[c] = ntv.time.tv_frac_sec; + } +#ifdef SIGSYS + } +#endif + if (pll_control >= 0) { + printf("[ us %06d:", times[0]); + for (c = 1; c < COUNTOF(times); c++) + printf(" %d", times[c] - times[c - 1]); + printf(" ]\n"); + } + } +#ifdef SIGSYS + if (sigsetjmp(env, 1) == 0) { +#endif + status = ntp_gettime(&ntv); + if ((status < 0) && (errno == ENOSYS)) + --pll_control; +#ifdef SIGSYS + } +#endif + _ntx.modes = 0; /* Ensure nothing is set */ +#ifdef SIGSYS + if (sigsetjmp(env, 1) == 0) { +#endif + status = ntp_adjtime(&_ntx); + if ((status < 0) && (errno == ENOSYS)) + --pll_control; + flash = _ntx.status; +#ifdef SIGSYS + } +#endif + if (pll_control < 0) { + printf("NTP user interface routines are not configured in this kernel.\n"); + goto lexit; + } + + /* + * Fetch timekeeping data and display. + */ + status = ntp_gettime(&ntv); + if (status < 0) { + perror("ntp_gettime() call fails"); + } else { + printf("ntp_gettime() returns code %d (%s)\n", + status, timex_state(status)); + time_frac = ntv.time.tv_frac_sec; +#ifdef STA_NANO + if (flash & STA_NANO) { + ntv.time.tv_frac_sec /= 1000; + ts_mask = 0xfffffffc; /* 1/2^30 */ + ts_roundbit = 0x00000002; + fdigits = 9; + } +#endif + tv.tv_sec = ntv.time.tv_sec; + tv.tv_usec = ntv.time.tv_frac_sec; + TVTOTS(&tv, &ts); + ts.l_ui += JAN_1970; + ts.l_uf += ts_roundbit; + ts.l_uf &= ts_mask; + printf(" time %s, (.%0*d),\n", + prettydate(&ts), fdigits, (int)time_frac); + printf(" maximum error %lu us, estimated error %lu us", + (u_long)ntv.maxerror, (u_long)ntv.esterror); + if (rawtime) + printf(" ntptime=%x.%x unixtime=%x.%0*d %s", + (u_int)ts.l_ui, (u_int)ts.l_uf, + (int)ntv.time.tv_sec, fdigits, + (int)time_frac, + ctime((time_t *)&ntv.time.tv_sec)); +#if NTP_API > 3 + printf(", TAI offset %ld\n", (long)ntv.tai); +#else + printf("\n"); +#endif /* NTP_API */ + } + status = ntp_adjtime(&ntx); + if (status < 0) { + perror((errno == EPERM) ? + "Must be root to set kernel values\nntp_adjtime() call fails" : + "ntp_adjtime() call fails"); + } else { + flash = ntx.status; + printf("ntp_adjtime() returns code %d (%s)\n", + status, timex_state(status)); + printf(" modes %s,\n", sprintb(ntx.modes, TIMEX_MOD_BITS)); + ftemp = (double)ntx.offset; +#ifdef STA_NANO + if (flash & STA_NANO) + ftemp /= 1000.0; +#endif + printf(" offset %.3f", ftemp); + ftemp = (double)ntx.freq / SCALE_FREQ; + printf(" us, frequency %.3f ppm, interval %d s,\n", + ftemp, 1 << ntx.shift); + printf(" maximum error %lu us, estimated error %lu us,\n", + (u_long)ntx.maxerror, (u_long)ntx.esterror); + printf(" status %s,\n", sprintb((u_int)ntx.status, TIMEX_STA_BITS)); + ftemp = (double)ntx.tolerance / SCALE_FREQ; + gtemp = (double)ntx.precision; +#ifdef STA_NANO + if (flash & STA_NANO) + gtemp /= 1000.0; +#endif + printf( + " time constant %lu, precision %.3f us, tolerance %.0f ppm,\n", + (u_long)ntx.constant, gtemp, ftemp); + if (ntx.shift == 0) + exit(0); + ftemp = (double)ntx.ppsfreq / SCALE_FREQ; + gtemp = (double)ntx.stabil / SCALE_FREQ; + htemp = (double)ntx.jitter; +#ifdef STA_NANO + if (flash & STA_NANO) + htemp /= 1000.0; +#endif + printf( + " pps frequency %.3f ppm, stability %.3f ppm, jitter %.3f us,\n", + ftemp, gtemp, htemp); + printf(" intervals %lu, jitter exceeded %lu, stability exceeded %lu, errors %lu.\n", + (u_long)ntx.calcnt, (u_long)ntx.jitcnt, + (u_long)ntx.stbcnt, (u_long)ntx.errcnt); + return 0; + } + + /* + * Put things back together the way we found them. + */ + lexit: +#ifdef SIGSYS + if (sigaction(SIGSYS, &sigsys, (struct sigaction *)NULL)) { + perror("sigaction() fails to restore SIGSYS trap"); + exit(1); + } +#endif + exit(0); +} + +#ifdef SIGSYS +/* + * pll_trap - trap processor for undefined syscalls + */ +void +pll_trap( + int arg + ) +{ + pll_control--; + siglongjmp(env, 1); +} +#endif + +/* + * Print a value a la the %b format of the kernel's printf + */ +const char * +sprintb( + u_int v, + const char * bits + ) +{ + char *cp; + char *cplim; + int i; + int any; + char c; + static char buf[132]; + + if (bits != NULL && *bits == 8) + snprintf(buf, sizeof(buf), "0%o", v); + else + snprintf(buf, sizeof(buf), "0x%x", v); + cp = buf + strlen(buf); + cplim = buf + sizeof(buf); + if (bits != NULL) { + bits++; + *cp++ = ' '; + *cp++ = '('; + any = FALSE; + while ((i = *bits++) != 0) { + if (v & (1 << (i - 1))) { + if (any) { + *cp++ = ','; + if (cp >= cplim) + goto overrun; + } + any = TRUE; + for (; (c = *bits) > 32; bits++) { + *cp++ = c; + if (cp >= cplim) + goto overrun; + } + } else { + for (; *bits > 32; bits++) + continue; + } + } + *cp++ = ')'; + if (cp >= cplim) + goto overrun; + } + *cp = '\0'; + return buf; + + overrun: + return "sprintb buffer too small"; +} + +const char * const timex_states[] = { + "OK", "INS", "DEL", "OOP", "WAIT", "ERROR" +}; + +const char * +timex_state( + int s + ) +{ + static char buf[32]; + + if (s >= 0 && s < COUNTOF(timex_states)) + return timex_states[s]; + snprintf(buf, sizeof(buf), "TIME-#%d", s); + return buf; +} diff --git a/util/pps-api.c b/util/pps-api.c new file mode 100644 index 0000000..60c98b8 --- /dev/null +++ b/util/pps-api.c @@ -0,0 +1,100 @@ +/* + +Try to run this program to see what the PPS-API finds. You give it the +device as argument and you may have to modify the pp.mode = BLA assignment. + +Poul-Henning + +*/ + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <err.h> +#include <sys/types.h> +#include <time.h> +#include <sys/timepps.h> +#include <sys/termios.h> + +#define timespecsub(vvp, uvp) \ + do { \ + (vvp)->tv_sec -= (uvp)->tv_sec; \ + (vvp)->tv_nsec -= (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_nsec += 1000000000; \ + } \ + } while (0) + + +void +Chew(struct timespec *tsa, struct timespec *tsc, unsigned sa, unsigned sc) +{ + static int idx; + struct timespec ts; + + printf("%d.%09d ", tsa->tv_sec, tsa->tv_nsec); + printf("%d.%09d ", tsc->tv_sec, tsc->tv_nsec); + printf("%u %u ", sa, sc); + + ts = *tsc; + timespecsub(&ts,tsa); + printf("%.9f ", ts.tv_sec + ts.tv_nsec / 1e9); + printf("\n"); + fflush(stdout); +} + +int +main(int argc, char **argv) +{ + int fd; + pps_info_t pi; + pps_params_t pp; + pps_handle_t ph; + int i, mode; + u_int olda, oldc; + double d = 0; + struct timespec to; + + if (argc < 2) + argv[1] = "/dev/cuaa1"; + setbuf(stdout, 0); + fd = open(argv[1], O_RDONLY); + if (fd < 0) + err(1, argv[1]); + i = time_pps_create(fd, &ph); + if (i < 0) + err(1, "time_pps_create"); + + i = time_pps_getcap(ph, &mode); + if (i < 0) + err(1, "time_pps_getcap"); + + pp.mode = PPS_CAPTUREASSERT | PPS_ECHOASSERT; + pp.mode = PPS_CAPTUREBOTH; + /* pp.mode = PPS_CAPTUREASSERT; */ + + i = time_pps_setparams(ph, &pp); + if (i < 0) + err(1, "time_pps_setparams"); + + while (1) { + to.tv_nsec = 0; + to.tv_sec = 0; + i = time_pps_fetch(ph, PPS_TSFMT_TSPEC, &pi, &to); + if (i < 0) + err(1, "time_pps_fetch"); + if (olda == pi.assert_sequence && + oldc == pi.clear_sequence) { + usleep(10000); + continue; + } + + Chew(&pi.assert_timestamp, &pi.clear_timestamp, + pi.assert_sequence, pi.clear_sequence); + olda = pi.assert_sequence; + oldc = pi.clear_sequence; + } + + return(0); +} diff --git a/util/precision.c b/util/precision.c new file mode 100644 index 0000000..b1516b3 --- /dev/null +++ b/util/precision.c @@ -0,0 +1,171 @@ +#include "ntp_unixtime.h" + +#include <stdio.h> + +#define DEFAULT_SYS_PRECISION -99 + +int default_get_resolution(); +int default_get_precision(); + +int +main( + int argc, + char *argv[] + ) +{ + printf("log2(resolution) = %d, log2(precision) = %d\n", + default_get_resolution(), + default_get_precision()); + return 0; +} + +/* Find the resolution of the system clock by watching how the current time + * changes as we read it repeatedly. + * + * struct timeval is only good to 1us, which may cause problems as machines + * get faster, but until then the logic goes: + * + * If a machine has resolution (i.e. accurate timing info) > 1us, then it will + * probably use the "unused" low order bits as a counter (to force time to be + * a strictly increaing variable), incrementing it each time any process + * requests the time [[ or maybe time will stand still ? ]]. + * + * SO: the logic goes: + * + * IF the difference from the last time is "small" (< MINSTEP) + * THEN this machine is "counting" with the low order bits + * ELIF this is not the first time round the loop + * THEN this machine *WAS* counting, and has now stepped + * ELSE this machine has resolution < time to read clock + * + * SO: if it exits on the first loop, assume "full accuracy" (1us) + * otherwise, take the log2(observered difference, rounded UP) + * + * MINLOOPS > 1 ensures that even if there is a STEP between the initial call + * and the first loop, it doesn't stop too early. + * Making it even greater allows MINSTEP to be reduced, assuming that the + * chance of MINSTEP-1 other processes getting in and calling gettimeofday + * between this processes's calls. + * Reducing MINSTEP may be necessary as this sets an upper bound for the time + * to actually call gettimeofday. + */ + +#define DUSECS 1000000 +#define HUSECS (1024 * 1024) +#define MINSTEP 5 /* some systems increment uS on each call */ +/* Don't use "1" as some *other* process may read too*/ +/*We assume no system actually *ANSWERS* in this time*/ +#define MAXSTEP 20000 /* maximum clock increment (us) */ +#define MINLOOPS 5 /* minimum number of step samples */ +#define MAXLOOPS HUSECS /* Assume precision < .1s ! */ + +int +default_get_resolution(void) +{ + struct timeval tp; + struct timezone tzp; + long last; + int i; + long diff; + long val; + int minsteps = MINLOOPS; /* need at least this many steps */ + + gettimeofday(&tp, &tzp); + last = tp.tv_usec; + for (i = - --minsteps; i< MAXLOOPS; i++) { + gettimeofday(&tp, &tzp); + diff = tp.tv_usec - last; + if (diff < 0) diff += DUSECS; + if (diff > MINSTEP) if (minsteps-- <= 0) break; + last = tp.tv_usec; + } + + printf("resolution = %ld usec after %d loop%s\n", + diff, i, (i==1) ? "" : "s"); + + diff = (diff *3)/2; + if (i >= MAXLOOPS) { + printf( + " (Boy this machine is fast ! %d loops without a step)\n", + MAXLOOPS); + diff = 1; /* No STEP, so FAST machine */ + } + if (i == 0) { + printf( + " (The resolution is less than the time to read the clock -- Assume 1us)\n"); + diff = 1; /* time to read clock >= resolution */ + } + for (i=0, val=HUSECS; val>0; i--, val >>= 1) if (diff >= val) return i; + printf(" (Oh dear -- that wasn't expected ! I'll guess !)\n"); + return DEFAULT_SYS_PRECISION /* Something's BUST, so lie ! */; +} + +/* ===== Rest of this code lifted straight from xntpd/ntp_proto.c ! ===== */ + +/* + * This routine calculates the differences between successive calls to + * gettimeofday(). If a difference is less than zero, the us field + * has rolled over to the next second, so we add a second in us. If + * the difference is greater than zero and less than MINSTEP, the + * clock has been advanced by a small amount to avoid standing still. + * If the clock has advanced by a greater amount, then a timer interrupt + * has occurred and this amount represents the precision of the clock. + * In order to guard against spurious values, which could occur if we + * happen to hit a fat interrupt, we do this for MINLOOPS times and + * keep the minimum value obtained. + */ +int +default_get_precision(void) +{ + struct timeval tp; + struct timezone tzp; +#ifdef HAVE_GETCLOCK + struct timespec ts; +#endif + long last; + int i; + long diff; + long val; + long usec; + + usec = 0; + val = MAXSTEP; +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tp.tv_sec = ts.tv_sec; + tp.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tp, &tzp); +#endif /* not HAVE_GETCLOCK */ + last = tp.tv_usec; + for (i = 0; i < MINLOOPS && usec < HUSECS;) { +#ifdef HAVE_GETCLOCK + (void) getclock(TIMEOFDAY, &ts); + tp.tv_sec = ts.tv_sec; + tp.tv_usec = ts.tv_nsec / 1000; +#else /* not HAVE_GETCLOCK */ + GETTIMEOFDAY(&tp, &tzp); +#endif /* not HAVE_GETCLOCK */ + diff = tp.tv_usec - last; + last = tp.tv_usec; + if (diff < 0) + diff += DUSECS; + usec += diff; + if (diff > MINSTEP) { + i++; + if (diff < val) + val = diff; + } + } + printf("precision = %ld usec after %d loop%s\n", + val, i, (i == 1) ? "" : "s"); + if (usec >= HUSECS) { + printf(" (Boy this machine is fast ! usec was %ld)\n", + usec); + val = MINSTEP; /* val <= MINSTEP; fast machine */ + } + diff = HUSECS; + for (i = 0; diff > val; i--) + diff >>= 1; + return (i); +} diff --git a/util/sht.c b/util/sht.c new file mode 100644 index 0000000..dfd97ff --- /dev/null +++ b/util/sht.c @@ -0,0 +1,260 @@ +/* + * sht.c - Testprogram for shared memory refclock + * read/write shared memory segment; see usage + */ +#include "config.h" + +#ifndef SYS_WINNT +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <stdlib.h> +#else +#include <windows.h> +#include <time.h> +#include <stdlib.h> +#include <stdio.h> +#include <iostream.h> +#define sleep(x) Sleep(x*1000) +#endif +#include <assert.h> + +struct shmTime { + int mode; /* 0 - if valid set + * use values, + * clear valid + * 1 - if valid set + * if count before and after read of values is equal, + * use values + * clear valid + */ + volatile int count; + time_t clockTimeStampSec; + int clockTimeStampUSec; + time_t receiveTimeStampSec; + int receiveTimeStampUSec; + int leap; + int precision; + int nsamples; + volatile int valid; + unsigned clockTimeStampNSec; /* Unsigned ns timestamps */ + unsigned receiveTimeStampNSec; /* Unsigned ns timestamps */ +}; + +static struct shmTime * +getShmTime ( + int unit + ) +{ +#ifndef SYS_WINNT + int shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|0777); + if (shmid==-1) { + perror ("shmget"); + exit (1); + } + else { + struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0); + if ((int)(long)p==-1) { + perror ("shmat"); + p=0; + } + assert (p!=0); + return p; + } +#else + char buf[10]; + LPSECURITY_ATTRIBUTES psec=0; + snprintf (buf, sizeof(buf), "NTP%d", unit); + SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sa; + HANDLE shmid; + + assert (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)); + assert (SetSecurityDescriptorDacl(&sd,1,0,0)); + sa.nLength=sizeof (SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor=&sd; + sa.bInheritHandle=0; + shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE, + psec, sizeof (struct shmTime),buf); + if (!shmid) { + shmid=CreateFileMapping ((HANDLE)0xffffffff, 0, PAGE_READWRITE, + 0, sizeof (struct shmTime),buf); + cout <<"CreateFileMapping with psec!=0 failed"<<endl; + } + + if (!shmid) { + char mbuf[1000]; + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, + 0, GetLastError (), 0, mbuf, sizeof (mbuf), 0); + int x=GetLastError (); + cout <<"CreateFileMapping "<<buf<<":"<<mbuf<<endl; + exit (1); + } + else { + struct shmTime *p=(struct shmTime *) MapViewOfFile (shmid, + FILE_MAP_WRITE, 0, 0, sizeof (struct shmTime)); + if (p==0) { + char mbuf[1000]; + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, + 0, GetLastError (), 0, mbuf, sizeof (mbuf), 0); + cout <<"MapViewOfFile "<<buf<<":"<<mbuf<<endl; + exit (1); + } + return p; + } + return 0; +#endif +} + + +int +main ( + int argc, + char *argv[] + ) +{ + volatile struct shmTime *p; + int unit; + char *argp; + + if (argc<=1) { + usage: + printf ("usage: %s [uu:]{r[c][l]|w|snnn}\n",argv[0]); + printf (" uu use clock unit uu (default: 2)\n"); + printf (" r read shared memory\n"); + printf (" c clear valid-flag\n"); + printf (" l loop (so, rcl will read and clear in a loop\n"); + printf (" w write shared memory with current time\n"); + printf (" snnnn set nsamples to nnn\n"); + printf (" lnnnn set leap to nnn\n"); + printf (" pnnnn set precision to -nnn\n"); + exit (0); + } + + srand(time(NULL)); + + unit = strtoul(argv[1], &argp, 10); + if (argp == argv[1]) + unit = 2; + else if (*argp == ':') + argp++; + else + goto usage; + + p=getShmTime(unit); + switch (*argp) { + case 's': + p->nsamples=atoi(argp+1); + break; + + case 'l': + p->leap=atoi(argp+1); + break; + + case 'p': + p->precision=-atoi(argp+1); + break; + + case 'r': { + int clear=0; + int loop=0; + printf ("reader\n"); + while (*++argp) { + switch (*argp) { + case 'l': loop=1; break; + case 'c': clear=1; break; + default : goto usage; + } + } +again: + printf ("mode=%d, count=%d, clock=%ld.%09u, rec=%ld.%09u,\n", + p->mode,p->count, + (long)p->clockTimeStampSec,p->clockTimeStampNSec, + (long)p->receiveTimeStampSec,p->receiveTimeStampNSec); + printf (" leap=%d, precision=%d, nsamples=%d, valid=%d\n", + p->leap, p->precision, p->nsamples, p->valid); + if (!p->valid) + printf ("***\n"); + if (clear) { + p->valid=0; + printf ("cleared\n"); + } + if (loop) { + sleep (1); + goto again; + } + break; + } + + case 'w': { + /* To show some life action, we read the system + * clock and use a bit of fuzz from 'random()' to get a + * bit of wobbling into the values (so we can observe a + * certain jitter!) + */ + time_t clk_sec, rcv_sec; + uint clk_frc, rcv_frc; + +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) + + /* Here we have a high-resolution system clock, and + * we're not afraid to use it! + */ + struct timespec tmptime; + if (0 == clock_gettime(CLOCK_REALTIME, &tmptime)) { + rcv_sec = tmptime.tv_sec; + rcv_frc = (uint)tmptime.tv_nsec; + } + else +#endif + { + time(&rcv_sec); + rcv_frc = (uint)random() % 1000000000u; + } + /* add a wobble of ~3.5msec to the clock time */ + clk_sec = rcv_sec; + clk_frc = rcv_frc + (uint)(random()%7094713 - 3547356); + /* normalise result -- the SHM driver is picky! */ + while ((int)clk_frc < 0) { + clk_frc += 1000000000; + clk_sec -= 1; + } + while ((int)clk_frc >= 1000000000) { + clk_frc -= 1000000000; + clk_sec += 1; + } + + /* Most 'real' time sources would create a clock + * (reference) time stamp where the fraction is zero, + * but that's not an actual requirement. So we show how + * to deal with the time stamps in general; changing the + * behaviour for cases where the fraction of the + * clock time is zero should be trivial. + */ + printf ("writer\n"); + p->mode=0; + if (!p->valid) { + p->clockTimeStampSec = clk_sec; + p->clockTimeStampUSec = clk_frc / 1000; /* truncate! */ + p->clockTimeStampNSec = clk_frc; + p->receiveTimeStampSec = rcv_sec; + p->receiveTimeStampUSec = rcv_frc / 1000; /* truncate! */ + p->receiveTimeStampNSec = rcv_frc; + printf ("%ld.%09u %ld.%09u\n", + (long)p->clockTimeStampSec , p->clockTimeStampNSec , + (long)p->receiveTimeStampSec, p->receiveTimeStampNSec); + p->valid=1; + } + else { + printf ("p->valid still set\n"); /* not an error! */ + } + break; + } + default: + break; + } + return 0; +} diff --git a/util/testrs6000.c b/util/testrs6000.c new file mode 100644 index 0000000..e4d939a --- /dev/null +++ b/util/testrs6000.c @@ -0,0 +1,55 @@ +/* Checks for the RS/6000 AIX adjtime() bug, in which if a negative + * offset is given, the system gets messed up and never completes the + * adjustment. If the problem is fixed, this program will print the + * time, sit there for 10 seconds, and exit. If the problem isn't fixed, + * the program will print an occasional "result=nnnnnn" (the residual + * slew from adjtime()). + * + * Compile this with bsdcc and run it as root! + */ +#include <signal.h> +#include <sys/time.h> +#include <time.h> +#include <stdio.h> + +int timeout(); +struct timeval adjustment, result; + +int +main ( + int argc, + char *argv[] + ) +{ + struct itimerval value, oldvalue; + int i; + time_t curtime; + + curtime = time(0); + printf("Starting: %s", ctime(&curtime)); + value.it_interval.tv_sec = value.it_value.tv_sec = 1; + value.it_interval.tv_usec = value.it_value.tv_usec = 0; + adjustment.tv_sec = 0; + adjustment.tv_usec = -2000; + signal(SIGALRM, timeout); + setitimer(ITIMER_REAL, &value, &oldvalue); + for (i=0; i<10; i++) { + pause(); + } +} + +int +timeout( + int sig, + int code, + struct sigcontext *scp + ) +{ + signal (SIGALRM, timeout); + if (adjtime(&adjustment, &result)) + printf("adjtime call failed\n"); + if (result.tv_sec != 0 || result.tv_usec != 0) { + printf("result.u = %d.%06.6d ", (int) result.tv_sec, + (int) result.tv_usec); + } +} diff --git a/util/tg.c b/util/tg.c new file mode 100644 index 0000000..8a96a81 --- /dev/null +++ b/util/tg.c @@ -0,0 +1,653 @@ +/* + * tg.c generate WWV or IRIG signals for test + */ +/* + * This program can generate audio signals that simulate the WWV/H + * broadcast timecode. Alternatively, it can generate the IRIG-B + * timecode commonly used to synchronize laboratory equipment. It is + * intended to test the WWV/H driver (refclock_wwv.c) and the IRIG + * driver (refclock_irig.c) in the NTP driver collection. + * + * Besides testing the drivers themselves, this program can be used to + * synchronize remote machines over audio transmission lines or program + * feeds. The program reads the time on the local machine and sets the + * initial epoch of the signal generator within one millisecond. + * Alernatively, the initial epoch can be set to an arbitrary time. This + * is useful when searching for bugs and testing for correct response to + * a leap second in UTC. Note however, the ultimate accuracy is limited + * by the intrinsic frequency error of the codec sample clock, which can + # reach well over 100 PPM. + * + * The default is to route generated signals to the line output + * jack; the s option on the command line routes these signals to the + * internal speaker as well. The v option controls the speaker volume + * over the range 0-255. The signal generator by default uses WWV + * format; the h option switches to WWVH format and the i option + * switches to IRIG-B format. + * + * Once started the program runs continuously. The default initial epoch + * for the signal generator is read from the computer system clock when + * the program starts. The y option specifies an alternate epoch using a + * string yydddhhmmss, where yy is the year of century, ddd the day of + * year, hh the hour of day and mm the minute of hour. For instance, + * 1946Z on 1 January 2006 is 060011946. The l option lights the leap + * warning bit in the WWV/H timecode, so is handy to check for correct + * behavior at the next leap second epoch. The remaining options are + * specified below under the Parse Options heading. Most of these are + * for testing. + * + * During operation the program displays the WWV/H timecode (9 digits) + * or IRIG timecode (20 digits) as each new string is constructed. The + * display is followed by the BCD binary bits as transmitted. Note that + * the transmissionorder is low-order first as the frame is processed + * left to right. For WWV/H The leap warning L preceeds the first bit. + * For IRIG the on-time marker M preceeds the first (units) bit, so its + * code is delayed one bit and the next digit (tens) needs only three + * bits. + * + * The program has been tested with the Sun Blade 1500 running Solaris + * 10, but not yet with other machines. It uses no special features and + * should be readily portable to other hardware and operating systems. + */ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/audio.h> +#include <math.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +#define SECOND 8000 /* one second of 125-us samples */ +#define BUFLNG 400 /* buffer size */ +#define DEVICE "/dev/audio" /* default audio device */ +#define WWV 0 /* WWV encoder */ +#define IRIG 1 /* IRIG-B encoder */ +#define OFF 0 /* zero amplitude */ +#define LOW 1 /* low amplitude */ +#define HIGH 2 /* high amplitude */ +#define DATA0 200 /* WWV/H 0 pulse */ +#define DATA1 500 /* WWV/H 1 pulse */ +#define PI 800 /* WWV/H PI pulse */ +#define M2 2 /* IRIG 0 pulse */ +#define M5 5 /* IRIG 1 pulse */ +#define M8 8 /* IRIG PI pulse */ + +/* + * Companded sine table amplitude 3000 units + */ +int c3000[] = {1, 48, 63, 70, 78, 82, 85, 89, 92, 94, /* 0-9 */ + 96, 98, 99, 100, 101, 101, 102, 103, 103, 103, /* 10-19 */ + 103, 103, 103, 103, 102, 101, 101, 100, 99, 98, /* 20-29 */ + 96, 94, 92, 89, 85, 82, 78, 70, 63, 48, /* 30-39 */ + 129, 176, 191, 198, 206, 210, 213, 217, 220, 222, /* 40-49 */ + 224, 226, 227, 228, 229, 229, 230, 231, 231, 231, /* 50-59 */ + 231, 231, 231, 231, 230, 229, 229, 228, 227, 226, /* 60-69 */ + 224, 222, 220, 217, 213, 210, 206, 198, 191, 176}; /* 70-79 */ +/* + * Companded sine table amplitude 6000 units + */ +int c6000[] = {1, 63, 78, 86, 93, 98, 101, 104, 107, 110, /* 0-9 */ + 112, 113, 115, 116, 117, 117, 118, 118, 119, 119, /* 10-19 */ + 119, 119, 119, 118, 118, 117, 117, 116, 115, 113, /* 20-29 */ + 112, 110, 107, 104, 101, 98, 93, 86, 78, 63, /* 30-39 */ + 129, 191, 206, 214, 221, 226, 229, 232, 235, 238, /* 40-49 */ + 240, 241, 243, 244, 245, 245, 246, 246, 247, 247, /* 50-59 */ + 247, 247, 247, 246, 246, 245, 245, 244, 243, 241, /* 60-69 */ + 240, 238, 235, 232, 229, 226, 221, 214, 206, 191}; /* 70-79 */ + +/* + * Decoder operations at the end of each second are driven by a state + * machine. The transition matrix consists of a dispatch table indexed + * by second number. Each entry in the table contains a case switch + * number and argument. + */ +struct progx { + int sw; /* case switch number */ + int arg; /* argument */ +}; + +/* + * Case switch numbers + */ +#define DATA 0 /* send data (0, 1, PI) */ +#define COEF 1 /* send BCD bit */ +#define DEC 2 /* decrement to next digit */ +#define MIN 3 /* minute pulse */ +#define LEAP 4 /* leap warning */ +#define DUT1 5 /* DUT1 bits */ +#define DST1 6 /* DST1 bit */ +#define DST2 7 /* DST2 bit */ + +/* + * WWV/H format (100-Hz, 9 digits, 1 m frame) + */ +struct progx progx[] = { + {MIN, 800}, /* 0 minute sync pulse */ + {DATA, DATA0}, /* 1 */ + {DST2, 0}, /* 2 DST2 */ + {LEAP, 0}, /* 3 leap warning */ + {COEF, 1}, /* 4 1 year units */ + {COEF, 2}, /* 5 2 */ + {COEF, 4}, /* 6 4 */ + {COEF, 8}, /* 7 8 */ + {DEC, DATA0}, /* 8 */ + {DATA, PI}, /* 9 p1 */ + {COEF, 1}, /* 10 1 minute units */ + {COEF, 2}, /* 11 2 */ + {COEF, 4}, /* 12 4 */ + {COEF, 8}, /* 13 8 */ + {DEC, DATA0}, /* 14 */ + {COEF, 1}, /* 15 10 minute tens */ + {COEF, 2}, /* 16 20 */ + {COEF, 4}, /* 17 40 */ + {COEF, 8}, /* 18 80 (not used) */ + {DEC, PI}, /* 19 p2 */ + {COEF, 1}, /* 20 1 hour units */ + {COEF, 2}, /* 21 2 */ + {COEF, 4}, /* 22 4 */ + {COEF, 8}, /* 23 8 */ + {DEC, DATA0}, /* 24 */ + {COEF, 1}, /* 25 10 hour tens */ + {COEF, 2}, /* 26 20 */ + {COEF, 4}, /* 27 40 (not used) */ + {COEF, 8}, /* 28 80 (not used) */ + {DEC, PI}, /* 29 p3 */ + {COEF, 1}, /* 30 1 day units */ + {COEF, 2}, /* 31 2 */ + {COEF, 4}, /* 32 4 */ + {COEF, 8}, /* 33 8 */ + {DEC, DATA0}, /* 34 not used */ + {COEF, 1}, /* 35 10 day tens */ + {COEF, 2}, /* 36 20 */ + {COEF, 4}, /* 37 40 */ + {COEF, 8}, /* 38 80 */ + {DEC, PI}, /* 39 p4 */ + {COEF, 1}, /* 40 100 day hundreds */ + {COEF, 2}, /* 41 200 */ + {COEF, 4}, /* 42 400 (not used) */ + {COEF, 8}, /* 43 800 (not used) */ + {DEC, DATA0}, /* 44 */ + {DATA, DATA0}, /* 45 */ + {DATA, DATA0}, /* 46 */ + {DATA, DATA0}, /* 47 */ + {DATA, DATA0}, /* 48 */ + {DATA, PI}, /* 49 p5 */ + {DUT1, 8}, /* 50 DUT1 sign */ + {COEF, 1}, /* 51 10 year tens */ + {COEF, 2}, /* 52 20 */ + {COEF, 4}, /* 53 40 */ + {COEF, 8}, /* 54 80 */ + {DST1, 0}, /* 55 DST1 */ + {DUT1, 1}, /* 56 0.1 DUT1 fraction */ + {DUT1, 2}, /* 57 0.2 */ + {DUT1, 4}, /* 58 0.4 */ + {DATA, PI}, /* 59 p6 */ + {DATA, DATA0}, /* 60 leap */ +}; + +/* + * IRIG format except first frame (1000 Hz, 20 digits, 1 s frame) + */ +struct progx progy[] = { + {COEF, 1}, /* 0 1 units */ + {COEF, 2}, /* 1 2 */ + {COEF, 4}, /* 2 4 */ + {COEF, 8}, /* 3 8 */ + {DEC, M2}, /* 4 im */ + {COEF, 1}, /* 5 10 tens */ + {COEF, 2}, /* 6 20 */ + {COEF, 4}, /* 7 40 */ + {COEF, 8}, /* 8 80 */ + {DEC, M8}, /* 9 pi */ +}; + +/* + * IRIG format first frame (1000 Hz, 20 digits, 1 s frame) + */ +struct progx progz[] = { + {MIN, M8}, /* 0 pi (second) */ + {COEF, 1}, /* 1 1 units */ + {COEF, 2}, /* 2 2 */ + {COEF, 4}, /* 3 4 */ + {COEF, 8}, /* 4 8 */ + {DEC, M2}, /* 5 im */ + {COEF, 1}, /* 6 10 tens */ + {COEF, 2}, /* 7 20 */ + {COEF, 4}, /* 8 40 */ + {DEC, M8}, /* 9 pi */ +}; + +/* + * Forward declarations + */ +void sec(int); /* send second */ +void digit(int); /* encode digit */ +void peep(int, int, int); /* send cycles */ +void delay(int); /* delay samples */ + +/* + * Global variables + */ +char buffer[BUFLNG]; /* output buffer */ +int bufcnt = 0; /* buffer counter */ +int second = 0; /* seconds counter */ +int fd; /* audio codec file descriptor */ +int tone = 1000; /* WWV sync frequency */ +int level = AUDIO_MAX_GAIN / 8; /* output level */ +int port = AUDIO_LINE_OUT; /* output port */ +int encode = WWV; /* encoder select */ +int leap = 0; /* leap indicator */ +int dst = 0; /* winter/summer time */ +int dut1 = 0; /* DUT1 correction (sign, magnitude) */ +int utc = 0; /* option epoch */ + +/* + * Main program + */ +int +main( + int argc, /* command line options */ + char **argv /* poiniter to list of tokens */ + ) +{ + struct timeval tv; /* system clock at startup */ + audio_info_t info; /* Sun audio structure */ + struct tm *tm = NULL; /* structure returned by gmtime */ + char device[50]; /* audio device */ + char code[100]; /* timecode */ + int rval, temp, arg, sw, ptr; + int minute, hour, day, year; + int i; + + /* + * Parse options + */ + strlcpy(device, DEVICE, sizeof(device)); + year = 0; + while ((temp = getopt(argc, argv, "a:dhilsu:v:y:")) != -1) { + switch (temp) { + + case 'a': /* specify audio device (/dev/audio) */ + strlcpy(device, optarg, sizeof(device)); + break; + + case 'd': /* set DST for summer (WWV/H only) */ + dst++; + break; + + case 'h': /* select WWVH sync frequency */ + tone = 1200; + break; + + case 'i': /* select irig format */ + encode = IRIG; + break; + + case 'l': /* set leap warning bit (WWV/H only) */ + leap++; + break; + + case 's': /* enable speaker */ + port |= AUDIO_SPEAKER; + break; + + case 'u': /* set DUT1 offset (-7 to +7) */ + sscanf(optarg, "%d", &dut1); + if (dut1 < 0) + dut1 = abs(dut1); + else + dut1 |= 0x8; + break; + + case 'v': /* set output level (0-255) */ + sscanf(optarg, "%d", &level); + break; + + case 'y': /* set initial date and time */ + sscanf(optarg, "%2d%3d%2d%2d", &year, &day, + &hour, &minute); + utc++; + break; + + defult: + printf("invalid option %c\n", temp); + break; + } + } + + /* + * Open audio device and set options + */ + fd = open("/dev/audio", O_WRONLY); + if (fd <= 0) { + printf("audio open %s\n", strerror(errno)); + exit(1); + } + rval = ioctl(fd, AUDIO_GETINFO, &info); + if (rval < 0) { + printf("audio control %s\n", strerror(errno)); + exit(0); + } + info.play.port = port; + info.play.gain = level; + info.play.sample_rate = SECOND; + info.play.channels = 1; + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_ULAW; + printf("port %d gain %d rate %d chan %d prec %d encode %d\n", + info.play.port, info.play.gain, info.play.sample_rate, + info.play.channels, info.play.precision, + info.play.encoding); + ioctl(fd, AUDIO_SETINFO, &info); + + /* + * Unless specified otherwise, read the system clock and + * initialize the time. + */ + if (!utc) { + gettimeofday(&tv, NULL); + tm = gmtime(&tv.tv_sec); + minute = tm->tm_min; + hour = tm->tm_hour; + day = tm->tm_yday + 1; + year = tm->tm_year % 100; + second = tm->tm_sec; + + /* + * Delay the first second so the generator is accurately + * aligned with the system clock within one sample (125 + * microseconds ). + */ + delay(SECOND - tv.tv_usec * 8 / 1000); + } + memset(code, 0, sizeof(code)); + switch (encode) { + + /* + * For WWV/H and default time, carefully set the signal + * generator seconds number to agree with the current time. + */ + case WWV: + printf("year %d day %d time %02d:%02d:%02d tone %d\n", + year, day, hour, minute, second, tone); + snprintf(code, sizeof(code), "%01d%03d%02d%02d%01d", + year / 10, day, hour, minute, year % 10); + printf("%s\n", code); + ptr = 8; + for (i = 0; i <= second; i++) { + if (progx[i].sw == DEC) + ptr--; + } + break; + + /* + * For IRIG the signal generator runs every second, so requires + * no additional alignment. + */ + case IRIG: + printf("sbs %x year %d day %d time %02d:%02d:%02d\n", + 0, year, day, hour, minute, second); + break; + } + + /* + * Run the signal generator to generate new timecode strings + * once per minute for WWV/H and once per second for IRIG. + */ + while(1) { + + /* + * Crank the state machine to propagate carries to the + * year of century. Note that we delayed up to one + * second for alignment after reading the time, so this + * is the next second. + */ + second = (second + 1) % 60; + if (second == 0) { + minute++; + if (minute >= 60) { + minute = 0; + hour++; + } + if (hour >= 24) { + hour = 0; + day++; + } + + /* + * At year rollover check for leap second. + */ + if (day >= (year & 0x3 ? 366 : 367)) { + if (leap) { + sec(DATA0); + printf("\nleap!"); + leap = 0; + } + day = 1; + year++; + } + if (encode == WWV) { + snprintf(code, sizeof(code), + "%01d%03d%02d%02d%01d", year / 10, + day, hour, minute, year % 10); + printf("\n%s\n", code); + ptr = 8; + } + } + if (encode == IRIG) { + snprintf(code, sizeof(code), + "%04x%04d%06d%02d%02d%02d", 0, year, day, + hour, minute, second); + printf("%s\n", code); + ptr = 19; + } + + /* + * Generate data for the second + */ + switch(encode) { + + /* + * The IRIG second consists of 20 BCD digits of width- + * modulateod pulses at 2, 5 and 8 ms and modulated 50 + * percent on the 1000-Hz carrier. + */ + case IRIG: + for (i = 0; i < 100; i++) { + if (i < 10) { + sw = progz[i].sw; + arg = progz[i].arg; + } else { + sw = progy[i % 10].sw; + arg = progy[i % 10].arg; + } + switch(sw) { + + case COEF: /* send BCD bit */ + if (code[ptr] & arg) { + peep(M5, 1000, HIGH); + peep(M5, 1000, LOW); + printf("1"); + } else { + peep(M2, 1000, HIGH); + peep(M8, 1000, LOW); + printf("0"); + } + break; + + case DEC: /* send IM/PI bit */ + ptr--; + printf(" "); + peep(arg, 1000, HIGH); + peep(10 - arg, 1000, LOW); + break; + + case MIN: /* send data bit */ + peep(arg, 1000, HIGH); + peep(10 - arg, 1000, LOW); + printf("M "); + break; + } + if (ptr < 0) + break; + } + printf("\n"); + break; + + /* + * The WWV/H second consists of 9 BCD digits of width- + * modulateod pulses 200, 500 and 800 ms at 100-Hz. + */ + case WWV: + sw = progx[second].sw; + arg = progx[second].arg; + switch(sw) { + + case DATA: /* send data bit */ + sec(arg); + break; + + case COEF: /* send BCD bit */ + if (code[ptr] & arg) { + sec(DATA1); + printf("1"); + } else { + sec(DATA0); + printf("0"); + } + break; + + case LEAP: /* send leap bit */ + if (leap) { + sec(DATA1); + printf("L "); + } else { + sec(DATA0); + printf(" "); + } + break; + + case DEC: /* send data bit */ + ptr--; + sec(arg); + printf(" "); + break; + + case MIN: /* send minute sync */ + peep(arg, tone, HIGH); + peep(1000 - arg, tone, OFF); + break; + + case DUT1: /* send DUT1 bits */ + if (dut1 & arg) + sec(DATA1); + else + sec(DATA0); + break; + + case DST1: /* send DST1 bit */ + ptr--; + if (dst) + sec(DATA1); + else + sec(DATA0); + printf(" "); + break; + + case DST2: /* send DST2 bit */ + if (dst) + sec(DATA1); + else + sec(DATA0); + break; + } + } + } +} + + +/* + * Generate WWV/H 0 or 1 data pulse. + */ +void sec( + int code /* DATA0, DATA1, PI */ + ) +{ + /* + * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a + * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at + * 100 Hz corresponding to 0, 1 or position indicator (PI), + * respectively. Note the 100-Hz data pulses are transmitted 6 + * dB below the 1000-Hz sync pulses. Originally the data pulses + * were transmited 10 dB below the sync pulses, but the station + * engineers increased that to 6 dB because the Heath GC-1000 + * WWV/H radio clock worked much better. + */ + peep(5, tone, HIGH); /* send seconds tick */ + peep(25, tone, OFF); + peep(code - 30, 100, LOW); /* send data */ + peep(1000 - code, 100, OFF); +} + + +/* + * Generate cycles of 100 Hz or any multiple of 100 Hz. + */ +void peep( + int pulse, /* pulse length (ms) */ + int freq, /* frequency (Hz) */ + int amp /* amplitude */ + ) +{ + int increm; /* phase increment */ + int i, j; + + if (amp == OFF || freq == 0) + increm = 10; + else + increm = freq / 100; + j = 0; + for (i = 0 ; i < pulse * 8; i++) { + switch (amp) { + + case HIGH: + buffer[bufcnt++] = ~c6000[j]; + break; + + case LOW: + buffer[bufcnt++] = ~c3000[j]; + break; + + default: + buffer[bufcnt++] = ~0; + } + if (bufcnt >= BUFLNG) { + write(fd, buffer, BUFLNG); + bufcnt = 0; + } + j = (j + increm) % 80; + } +} + + +/* + * Delay for initial phasing + */ +void delay ( + int delay /* delay in samples */ + ) +{ + int samples; /* samples remaining */ + + samples = delay; + memset(buffer, 0, BUFLNG); + while (samples >= BUFLNG) { + write(fd, buffer, BUFLNG); + samples -= BUFLNG; + } + write(fd, buffer, samples); +} diff --git a/util/tg2.c b/util/tg2.c new file mode 100644 index 0000000..6d52ef4 --- /dev/null +++ b/util/tg2.c @@ -0,0 +1,2506 @@ +/* + * tg.c generate WWV or IRIG signals for test + */ +/* + * This program can generate audio signals that simulate the WWV/H + * broadcast timecode. Alternatively, it can generate the IRIG-B + * timecode commonly used to synchronize laboratory equipment. It is + * intended to test the WWV/H driver (refclock_wwv.c) and the IRIG + * driver (refclock_irig.c) in the NTP driver collection. + * + * Besides testing the drivers themselves, this program can be used to + * synchronize remote machines over audio transmission lines or program + * feeds. The program reads the time on the local machine and sets the + * initial epoch of the signal generator within one millisecond. + * Alernatively, the initial epoch can be set to an arbitrary time. This + * is useful when searching for bugs and testing for correct response to + * a leap second in UTC. Note however, the ultimate accuracy is limited + * by the intrinsic frequency error of the codec sample clock, which can + # reach well over 100 PPM. + * + * The default is to route generated signals to the line output + * jack; the s option on the command line routes these signals to the + * internal speaker as well. The v option controls the speaker volume + * over the range 0-255. The signal generator by default uses WWV + * format; the h option switches to WWVH format and the i option + * switches to IRIG-B format. + * + * Once started the program runs continuously. The default initial epoch + * for the signal generator is read from the computer system clock when + * the program starts. The y option specifies an alternate epoch using a + * string yydddhhmmss, where yy is the year of century, ddd the day of + * year, hh the hour of day and mm the minute of hour. For instance, + * 1946Z on 1 January 2006 is 060011946. The l option lights the leap + * warning bit in the WWV/H timecode, so is handy to check for correct + * behavior at the next leap second epoch. The remaining options are + * specified below under the Parse Options heading. Most of these are + * for testing. + * + * During operation the program displays the WWV/H timecode (9 digits) + * or IRIG timecode (20 digits) as each new string is constructed. The + * display is followed by the BCD binary bits as transmitted. Note that + * the transmissionorder is low-order first as the frame is processed + * left to right. For WWV/H The leap warning L preceeds the first bit. + * For IRIG the on-time marker M preceeds the first (units) bit, so its + * code is delayed one bit and the next digit (tens) needs only three + * bits. + * + * The program has been tested with the Sun Blade 1500 running Solaris + * 10, but not yet with other machines. It uses no special features and + * should be readily portable to other hardware and operating systems. + * + * $Log: tg.c,v $ + * Revision 1.28 2007/02/12 23:57:45 dmw + * v0.23 2007-02-12 dmw: + * - Changed statistics to include calculated error + * of frequency, based on number of added or removed + * cycles over time. + * + * Revision 1.27 2007/02/09 02:28:59 dmw + * v0.22 2007-02-08 dmw: + * - Changed default for rate correction to "enabled", "-j" switch now disables. + * - Adjusted help message accordingly. + * - Added "2007" to modifications note at end of help message. + * + * Revision 1.26 2007/02/08 03:36:17 dmw + * v0.21 2007-02-07 dmw: + * - adjusted strings for shorten and lengthen to make + * fit on smaller screen. + * + * Revision 1.25 2007/02/01 06:08:09 dmw + * v0.20 2007-02-01 dmw: + * - Added periodic display of running time along with legend on IRIG-B, allows tracking how + * close IRIG output is to actual clock time. + * + * Revision 1.24 2007/01/31 19:24:11 dmw + * v0.19 2007-01-31 dmw: + * - Added tracking of how many seconds have been adjusted, + * how many cycles added (actually in milliseconds), how + * many cycles removed, print periodically if verbose is + * active. + * - Corrected lack of lengthen or shorten of minute & hour + * pulses for WWV format. + * + * Revision 1.23 2007/01/13 07:09:12 dmw + * v0.18 2007-01-13 dmw: + * - added -k option, which allows force of long or short + * cycles, to test against IRIG-B decoder. + * + * Revision 1.22 2007/01/08 16:27:23 dmw + * v0.17 2007-01-08 dmw: + * - Changed -j option to **enable** rate correction, not disable. + * + * Revision 1.21 2007/01/08 06:22:36 dmw + * v0.17 2007-01-08 dmw: + * - Run stability check versus ongoing system clock (assume NTP correction) + * and adjust time code rate to try to correct, if gets too far out of sync. + * Disable this algorithm with -j option. + * + * Revision 1.20 2006/12/19 04:59:04 dmw + * v0.16 2006-12-18 dmw + * - Corrected print of setting of output frequency, always + * showed 8000 samples/sec, now as specified on command line. + * - Modified to reflect new employer Norscan. + * + * Revision 1.19 2006/12/19 03:45:38 dmw + * v0.15 2006-12-18 dmw: + * - Added count of number of seconds to output then exit, + * default zero for forever. + * + * Revision 1.18 2006/12/18 05:43:36 dmw + * v0.14 2006-12-17 dmw: + * - Corrected WWV(H) signal to leave "tick" sound off of 29th and 59th second of minute. + * - Adjusted verbose output format for WWV(H). + * + * Revision 1.17 2006/12/18 02:31:33 dmw + * v0.13 2006-12-17 dmw: + * - Put SPARC code back in, hopefully will work, but I don't have + * a SPARC to try it on... + * - Reworked Verbose mode, different flag to initiate (x not v) + * and actually implement turn off of verbosity when this flag used. + * - Re-claimed v flag for output level. + * - Note that you must define OSS_MODS to get OSS to compile, + * otherwise will expect to compile using old SPARC options, as + * it used to be. + * + * Revision 1.16 2006/10/26 19:08:43 dmw + * v0.12 2006-10-26 dmw: + * - Reversed output binary dump for IRIG, makes it easier to read the numbers. + * + * Revision 1.15 2006/10/24 15:57:09 dmw + * v0.11 2006-10-24 dmw: + * - another tweak. + * + * Revision 1.14 2006/10/24 15:55:53 dmw + * v0.11 2006-10-24 dmw: + * - Curses a fix to the fix to the fix of the usaeg. + * + * Revision 1.13 2006/10/24 15:53:25 dmw + * v0.11 (still) 2006-10-24 dmw: + * - Messed with usage message that's all. + * + * Revision 1.12 2006/10/24 15:50:05 dmw + * v0.11 2006-10-24 dmw: + * - oops, needed to note "hours" in usage of that offset. + * + * Revision 1.11 2006/10/24 15:49:09 dmw + * v0.11 2006-10-24 dmw: + * - Added ability to offset actual time sent, from the UTC time + * as per the computer. + * + * Revision 1.10 2006/10/24 03:25:55 dmw + * v0.10 2006-10-23 dmw: + * - Corrected polarity of correction of offset when going into or out of DST. + * - Ensure that zero offset is always positive (pet peeve). + * + * Revision 1.9 2006/10/24 00:00:35 dmw + * v0.9 2006-10-23 dmw: + * - Shift time offset when DST in or out. + * + * Revision 1.8 2006/10/23 23:49:28 dmw + * v0.8 2006-10-23 dmw: + * - made offset of zero default positive. + * + * Revision 1.7 2006/10/23 23:44:13 dmw + * v0.7 2006-10-23 dmw: + * - Added unmodulated and inverted unmodulated output. + * + * Revision 1.6 2006/10/23 18:10:37 dmw + * v0.6 2006-10-23 dmw: + * - Cleaned up usage message. + * - Require at least one option, or prints usage message and exits. + * + * Revision 1.5 2006/10/23 16:58:10 dmw + * v0.5 2006-10-23 dmw: + * - Finally added a usage message. + * - Added leap second pending and DST change pending into IEEE 1344. + * - Default code type is now IRIG-B with IEEE 1344. + * + * Revision 1.4 2006/10/23 03:27:25 dmw + * v0.4 2006-10-22 dmw: + * - Added leap second addition and deletion. + * - Added DST changing forward and backward. + * - Changed date specification to more conventional year, month, and day of month + * (rather than day of year). + * + * Revision 1.3 2006/10/22 21:04:12 dmw + * v0.2 2006-10-22 dmw: + * - Corrected format of legend line. + * + * Revision 1.2 2006/10/22 21:01:07 dmw + * v0.1 2006-10-22 dmw: + * - Added some more verbose output (as is my style) + * - Corrected frame format - there were markers in the + * middle of frames, now correctly as "zero" bits. + * - Added header line to show fields of output. + * - Added straight binary seconds, were not implemented + * before. + * - Added IEEE 1344 with parity. + * + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#undef VERSION /* avoid conflict below */ +#endif + +#ifdef HAVE_SYS_SOUNDCARD_H +#include <sys/soundcard.h> +#else +# ifdef HAVE_SYS_AUDIOIO_H +# include <sys/audioio.h> +# else +# include <sys/audio.h> +# endif +#endif + +#include "ntp_stdlib.h" /* for strlcat(), strlcpy() */ + +#include <math.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/ioctl.h> +#include <sys/time.h> + +#define VERSION (0) +#define ISSUE (23) +#define ISSUE_DATE "2007-02-12" + +#define SECOND (8000) /* one second of 125-us samples */ +#define BUFLNG (400) /* buffer size */ +#define DEVICE "/dev/audio" /* default audio device */ +#define WWV (0) /* WWV encoder */ +#define IRIG (1) /* IRIG-B encoder */ +#define OFF (0) /* zero amplitude */ +#define LOW (1) /* low amplitude */ +#define HIGH (2) /* high amplitude */ +#define DATA0 (200) /* WWV/H 0 pulse */ +#define DATA1 (500) /* WWV/H 1 pulse */ +#define PI (800) /* WWV/H PI pulse */ +#define M2 (2) /* IRIG 0 pulse */ +#define M5 (5) /* IRIG 1 pulse */ +#define M8 (8) /* IRIG PI pulse */ + +#define NUL (0) + +#define SECONDS_PER_MINUTE (60) +#define SECONDS_PER_HOUR (3600) + +#define OUTPUT_DATA_STRING_LENGTH (200) + +/* Attempt at unmodulated - "high" */ +int u6000[] = { + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, /* 0- 9 */ + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, /* 10-19 */ + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, /* 20-29 */ + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, /* 30-39 */ + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, /* 40-49 */ + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, /* 50-59 */ + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, /* 60-69 */ + 247, 247, 247, 247, 247, 247, 247, 247, 247, 247}; /* 70-79 */ + +/* Attempt at unmodulated - "low" */ +int u3000[] = { + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, /* 0- 9 */ + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, /* 10-19 */ + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, /* 20-29 */ + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, /* 30-39 */ + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, /* 40-49 */ + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, /* 50-59 */ + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, /* 60-69 */ + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119}; /* 70-79 */ + +/* + * Companded sine table amplitude 3000 units + */ +int c3000[] = {1, 48, 63, 70, 78, 82, 85, 89, 92, 94, /* 0-9 */ + 96, 98, 99, 100, 101, 101, 102, 103, 103, 103, /* 10-19 */ + 103, 103, 103, 103, 102, 101, 101, 100, 99, 98, /* 20-29 */ + 96, 94, 92, 89, 85, 82, 78, 70, 63, 48, /* 30-39 */ + 129, 176, 191, 198, 206, 210, 213, 217, 220, 222, /* 40-49 */ + 224, 226, 227, 228, 229, 229, 230, 231, 231, 231, /* 50-59 */ + 231, 231, 231, 231, 230, 229, 229, 228, 227, 226, /* 60-69 */ + 224, 222, 220, 217, 213, 210, 206, 198, 191, 176}; /* 70-79 */ +/* + * Companded sine table amplitude 6000 units + */ +int c6000[] = {1, 63, 78, 86, 93, 98, 101, 104, 107, 110, /* 0-9 */ + 112, 113, 115, 116, 117, 117, 118, 118, 119, 119, /* 10-19 */ + 119, 119, 119, 118, 118, 117, 117, 116, 115, 113, /* 20-29 */ + 112, 110, 107, 104, 101, 98, 93, 86, 78, 63, /* 30-39 */ + 129, 191, 206, 214, 221, 226, 229, 232, 235, 238, /* 40-49 */ + 240, 241, 243, 244, 245, 245, 246, 246, 247, 247, /* 50-59 */ + 247, 247, 247, 246, 246, 245, 245, 244, 243, 241, /* 60-69 */ + 240, 238, 235, 232, 229, 226, 221, 214, 206, 191}; /* 70-79 */ + +/* + * Decoder operations at the end of each second are driven by a state + * machine. The transition matrix consists of a dispatch table indexed + * by second number. Each entry in the table contains a case switch + * number and argument. + */ +struct progx { + int sw; /* case switch number */ + int arg; /* argument */ +}; + +/* + * Case switch numbers + */ +#define DATA (0) /* send data (0, 1, PI) */ +#define COEF (1) /* send BCD bit */ +#define DEC (2) /* decrement to next digit and send PI */ +#define MIN (3) /* minute pulse */ +#define LEAP (4) /* leap warning */ +#define DUT1 (5) /* DUT1 bits */ +#define DST1 (6) /* DST1 bit */ +#define DST2 (7) /* DST2 bit */ +#define DECZ (8) /* decrement to next digit and send zero */ +#define DECC (9) /* decrement to next digit and send bit */ +#define NODEC (10) /* no decerement to next digit, send PI */ +#define DECX (11) /* decrement to next digit, send PI, but no tick */ +#define DATAX (12) /* send data (0, 1, PI), but no tick */ + +/* + * WWV/H format (100-Hz, 9 digits, 1 m frame) + */ +struct progx progx[] = { + {MIN, 800}, /* 0 minute sync pulse */ + {DATA, DATA0}, /* 1 */ + {DST2, 0}, /* 2 DST2 */ + {LEAP, 0}, /* 3 leap warning */ + {COEF, 1}, /* 4 1 year units */ + {COEF, 2}, /* 5 2 */ + {COEF, 4}, /* 6 4 */ + {COEF, 8}, /* 7 8 */ + {DEC, DATA0}, /* 8 */ + {DATA, PI}, /* 9 p1 */ + {COEF, 1}, /* 10 1 minute units */ + {COEF, 2}, /* 11 2 */ + {COEF, 4}, /* 12 4 */ + {COEF, 8}, /* 13 8 */ + {DEC, DATA0}, /* 14 */ + {COEF, 1}, /* 15 10 minute tens */ + {COEF, 2}, /* 16 20 */ + {COEF, 4}, /* 17 40 */ + {COEF, 8}, /* 18 80 (not used) */ + {DEC, PI}, /* 19 p2 */ + {COEF, 1}, /* 20 1 hour units */ + {COEF, 2}, /* 21 2 */ + {COEF, 4}, /* 22 4 */ + {COEF, 8}, /* 23 8 */ + {DEC, DATA0}, /* 24 */ + {COEF, 1}, /* 25 10 hour tens */ + {COEF, 2}, /* 26 20 */ + {COEF, 4}, /* 27 40 (not used) */ + {COEF, 8}, /* 28 80 (not used) */ + {DECX, PI}, /* 29 p3 */ + {COEF, 1}, /* 30 1 day units */ + {COEF, 2}, /* 31 2 */ + {COEF, 4}, /* 32 4 */ + {COEF, 8}, /* 33 8 */ + {DEC, DATA0}, /* 34 not used */ + {COEF, 1}, /* 35 10 day tens */ + {COEF, 2}, /* 36 20 */ + {COEF, 4}, /* 37 40 */ + {COEF, 8}, /* 38 80 */ + {DEC, PI}, /* 39 p4 */ + {COEF, 1}, /* 40 100 day hundreds */ + {COEF, 2}, /* 41 200 */ + {COEF, 4}, /* 42 400 (not used) */ + {COEF, 8}, /* 43 800 (not used) */ + {DEC, DATA0}, /* 44 */ + {DATA, DATA0}, /* 45 */ + {DATA, DATA0}, /* 46 */ + {DATA, DATA0}, /* 47 */ + {DATA, DATA0}, /* 48 */ + {DATA, PI}, /* 49 p5 */ + {DUT1, 8}, /* 50 DUT1 sign */ + {COEF, 1}, /* 51 10 year tens */ + {COEF, 2}, /* 52 20 */ + {COEF, 4}, /* 53 40 */ + {COEF, 8}, /* 54 80 */ + {DST1, 0}, /* 55 DST1 */ + {DUT1, 1}, /* 56 0.1 DUT1 fraction */ + {DUT1, 2}, /* 57 0.2 */ + {DUT1, 4}, /* 58 0.4 */ + {DATAX, PI}, /* 59 p6 */ + {DATA, DATA0}, /* 60 leap */ +}; + +/* + * IRIG format frames (1000 Hz, 1 second for 10 frames of data) + */ + +/* + * IRIG format frame 10 - MS straight binary seconds + */ +struct progx progu[] = { + {COEF, 2}, /* 0 0x0 0200 seconds */ + {COEF, 4}, /* 1 0x0 0400 */ + {COEF, 8}, /* 2 0x0 0800 */ + {DECC, 1}, /* 3 0x0 1000 */ + {COEF, 2}, /* 4 0x0 2000 */ + {COEF, 4}, /* 6 0x0 4000 */ + {COEF, 8}, /* 7 0x0 8000 */ + {DECC, 1}, /* 8 0x1 0000 */ + {COEF, 2}, /* 9 0x2 0000 - but only 86,401 / 0x1 5181 seconds in a day, so always zero */ + {NODEC, M8}, /* 9 PI */ +}; + +/* + * IRIG format frame 8 - MS control functions + */ +struct progx progv[] = { + {COEF, 2}, /* 0 CF # 19 */ + {COEF, 4}, /* 1 CF # 20 */ + {COEF, 8}, /* 2 CF # 21 */ + {DECC, 1}, /* 3 CF # 22 */ + {COEF, 2}, /* 4 CF # 23 */ + {COEF, 4}, /* 6 CF # 24 */ + {COEF, 8}, /* 7 CF # 25 */ + {DECC, 1}, /* 8 CF # 26 */ + {COEF, 2}, /* 9 CF # 27 */ + {DEC, M8}, /* 10 PI */ +}; + +/* + * IRIG format frames 7 & 9 - LS control functions & LS straight binary seconds + */ +struct progx progw[] = { + {COEF, 1}, /* 0 CF # 10, 0x0 0001 seconds */ + {COEF, 2}, /* 1 CF # 11, 0x0 0002 */ + {COEF, 4}, /* 2 CF # 12, 0x0 0004 */ + {COEF, 8}, /* 3 CF # 13, 0x0 0008 */ + {DECC, 1}, /* 4 CF # 14, 0x0 0010 */ + {COEF, 2}, /* 6 CF # 15, 0x0 0020 */ + {COEF, 4}, /* 7 CF # 16, 0x0 0040 */ + {COEF, 8}, /* 8 CF # 17, 0x0 0080 */ + {DECC, 1}, /* 9 CF # 18, 0x0 0100 */ + {NODEC, M8}, /* 10 PI */ +}; + +/* + * IRIG format frames 2 to 6 - minutes, hours, days, hundreds days, 2 digit years (also called control functions bits 1-9) + */ +struct progx progy[] = { + {COEF, 1}, /* 0 1 units, CF # 1 */ + {COEF, 2}, /* 1 2 units, CF # 2 */ + {COEF, 4}, /* 2 4 units, CF # 3 */ + {COEF, 8}, /* 3 8 units, CF # 4 */ + {DECZ, M2}, /* 4 zero bit, CF # 5 / unused, default zero in years */ + {COEF, 1}, /* 5 10 tens, CF # 6 */ + {COEF, 2}, /* 6 20 tens, CF # 7*/ + {COEF, 4}, /* 7 40 tens, CF # 8*/ + {COEF, 8}, /* 8 80 tens, CF # 9*/ + {DEC, M8}, /* 9 PI */ +}; + +/* + * IRIG format first frame, frame 1 - seconds + */ +struct progx progz[] = { + {MIN, M8}, /* 0 PI (on-time marker for the second at zero cross of 1st cycle) */ + {COEF, 1}, /* 1 1 units */ + {COEF, 2}, /* 2 2 */ + {COEF, 4}, /* 3 4 */ + {COEF, 8}, /* 4 8 */ + {DECZ, M2}, /* 5 zero bit */ + {COEF, 1}, /* 6 10 tens */ + {COEF, 2}, /* 7 20 */ + {COEF, 4}, /* 8 40 */ + {DEC, M8}, /* 9 PI */ +}; + +/* LeapState values. */ +#define LEAPSTATE_NORMAL (0) +#define LEAPSTATE_DELETING (1) +#define LEAPSTATE_INSERTING (2) +#define LEAPSTATE_ZERO_AFTER_INSERT (3) + + +/* + * Forward declarations + */ +void WWV_Second(int, int); /* send second */ +void WWV_SecondNoTick(int, int); /* send second with no tick */ +void digit(int); /* encode digit */ +void peep(int, int, int); /* send cycles */ +void poop(int, int, int, int); /* Generate unmodulated from similar tables */ +void delay(int); /* delay samples */ +int ConvertMonthDayToDayOfYear (int, int, int); /* Calc day of year from year month & day */ +void Help (void); /* Usage message */ +void ReverseString(char *); + +/* + * Extern declarations, don't know why not in headers + */ +//float round ( float ); + +/* + * Global variables + */ +char buffer[BUFLNG]; /* output buffer */ +int bufcnt = 0; /* buffer counter */ +int fd; /* audio codec file descriptor */ +int tone = 1000; /* WWV sync frequency */ +int HourTone = 1500; /* WWV hour on-time frequency */ +int encode = IRIG; /* encoder select */ +int leap = 0; /* leap indicator */ +int DstFlag = 0; /* winter/summer time */ +int dut1 = 0; /* DUT1 correction (sign, magnitude) */ +int utc = 0; /* option epoch */ +int IrigIncludeYear = FALSE; /* Whether to send year in first control functions area, between P5 and P6. */ +int IrigIncludeIeee = FALSE; /* Whether to send IEEE 1344 control functions extensions between P6 and P8. */ +int StraightBinarySeconds = 0; +int ControlFunctions = 0; +int Debug = FALSE; +int Verbose = TRUE; +char *CommandName; + +#ifndef HAVE_SYS_SOUNDCARD_H +int level = AUDIO_MAX_GAIN / 8; /* output level */ +int port = AUDIO_LINE_OUT; /* output port */ +#endif + +int TotalSecondsCorrected = 0; +int TotalCyclesAdded = 0; +int TotalCyclesRemoved = 0; + + +/* + * Main program + */ +int +main( + int argc, /* command line options */ + char **argv /* poiniter to list of tokens */ + ) +{ +#ifndef HAVE_SYS_SOUNDCARD_H + audio_info_t info; /* Sun audio structure */ + int rval; /* For IOCTL calls */ +#endif + + struct timeval TimeValue; /* System clock at startup */ + time_t SecondsPartOfTime; /* Sent to gmtime() for calculation of TimeStructure (can apply offset). */ + time_t BaseRealTime; /* Base realtime so can determine seconds since starting. */ + time_t NowRealTime; /* New realtime to can determine seconds as of now. */ + unsigned SecondsRunningRealTime; /* Difference between NowRealTime and BaseRealTime. */ + unsigned SecondsRunningSimulationTime; /* Time that the simulator has been running. */ + int SecondsRunningDifference; /* Difference between what real time says we have been running */ + /* and what simulator says we have been running - will slowly */ + /* change because of clock drift. */ + int ExpectedRunningDifference = 0; /* Stable value that we've obtained from check at initial start-up. */ + unsigned StabilityCount; /* Used to check stability of difference while starting */ +#define RUN_BEFORE_STABILITY_CHECK (30) // Must run this many seconds before even checking stability. +#define MINIMUM_STABILITY_COUNT (10) // Number of consecutive differences that need to be within initial stability band to say we are stable. +#define INITIAL_STABILITY_BAND ( 2) // Determining initial stability for consecutive differences within +/- this value. +#define RUNNING_STABILITY_BAND ( 5) // When running, stability is defined as difference within +/- this value. + + struct tm *TimeStructure = NULL; /* Structure returned by gmtime */ + char device[200]; /* audio device */ + char code[200]; /* timecode */ + int temp; + int arg = 0; + int sw = 0; + int ptr = 0; + + int Year; + int Month; + int DayOfMonth; + int Hour; + int Minute; + int Second = 0; + int DayOfYear; + + int BitNumber; +#ifdef HAVE_SYS_SOUNDCARD_H + int AudioFormat; + int MonoStereo; /* 0=mono, 1=stereo */ +#define MONO (0) +#define STEREO (1) + int SampleRate; + int SampleRateDifference; +#endif + int SetSampleRate; + char FormatCharacter = '3'; /* Default is IRIG-B with IEEE 1344 extensions */ + char AsciiValue; + int HexValue; + int OldPtr = 0; + int FrameNumber = 0; + + /* Time offset for IEEE 1344 indication. */ + float TimeOffset = 0.0; + int OffsetSignBit = 0; + int OffsetOnes = 0; + int OffsetHalf = 0; + + int TimeQuality = 0; /* Time quality for IEEE 1344 indication. */ + char ParityString[200]; /* Partial output string, to calculate parity on. */ + int ParitySum = 0; + int ParityValue; + char *StringPointer; + + /* Flags to indicate requested leap second addition or deletion by command line option. */ + /* Should be mutually exclusive - generally ensured by code which interprets command line option. */ + int InsertLeapSecond = FALSE; + int DeleteLeapSecond = FALSE; + + /* Date and time of requested leap second addition or deletion. */ + int LeapYear = 0; + int LeapMonth = 0; + int LeapDayOfMonth = 0; + int LeapHour = 0; + int LeapMinute = 0; + int LeapDayOfYear = 0; + + /* State flag for the insertion and deletion of leap seconds, esp. deletion, */ + /* where the logic gets a bit tricky. */ + int LeapState = LEAPSTATE_NORMAL; + + /* Flags for indication of leap second pending and leap secod polarity in IEEE 1344 */ + int LeapSecondPending = FALSE; + int LeapSecondPolarity = FALSE; + + /* Date and time of requested switch into or out of DST by command line option. */ + int DstSwitchYear = 0; + int DstSwitchMonth = 0; + int DstSwitchDayOfMonth = 0; + int DstSwitchHour = 0; + int DstSwitchMinute = 0; + int DstSwitchDayOfYear = 0; + + /* Indicate when we have been asked to switch into or out of DST by command line option. */ + int DstSwitchFlag = FALSE; + + /* To allow predict for DstPendingFlag in IEEE 1344 */ + int DstSwitchPendingYear = 0; /* Default value isn't valid, but I don't care. */ + int DstSwitchPendingDayOfYear = 0; + int DstSwitchPendingHour = 0; + int DstSwitchPendingMinute = 0; + + /* /Flag for indication of a DST switch pending in IEEE 1344 */ + int DstPendingFlag = FALSE; + + /* Attempt at unmodulated */ + int Unmodulated = FALSE; + int UnmodulatedInverted = FALSE; + + /* Offset to actual time value sent. */ + float UseOffsetHoursFloat; + int UseOffsetSecondsInt = 0; + float UseOffsetSecondsFloat; + + /* String to allow us to put out reversed data - so can read the binary numbers. */ + char OutputDataString[OUTPUT_DATA_STRING_LENGTH]; + + /* Number of seconds to send before exiting. Default = 0 = forever. */ + int SecondsToSend = 0; + int CountOfSecondsSent = 0; /* Counter of seconds */ + + /* Flags to indicate whether to add or remove a cycle for time adjustment. */ + int AddCycle = FALSE; // We are ahead, add cycle to slow down and get back in sync. + int RemoveCycle = FALSE; // We are behind, remove cycle to slow down and get back in sync. + int RateCorrection; // Aggregate flag for passing to subroutines. + int EnableRateCorrection = TRUE; + + float RatioError; + + + CommandName = argv[0]; + + if (argc < 1) + { + Help (); + exit (-1); + } + + /* + * Parse options + */ + strlcpy(device, DEVICE, sizeof(device)); + Year = 0; + SetSampleRate = SECOND; + +#if HAVE_SYS_SOUNDCARD_H + while ((temp = getopt(argc, argv, "a:b:c:df:g:hHi:jk:l:o:q:r:stu:xy:z?")) != -1) { +#else + while ((temp = getopt(argc, argv, "a:b:c:df:g:hHi:jk:l:o:q:r:stu:v:xy:z?")) != -1) { +#endif + switch (temp) { + + case 'a': /* specify audio device (/dev/audio) */ + strlcpy(device, optarg, sizeof(device)); + break; + + case 'b': /* Remove (delete) a leap second at the end of the specified minute. */ + sscanf(optarg, "%2d%2d%2d%2d%2d", &LeapYear, &LeapMonth, &LeapDayOfMonth, + &LeapHour, &LeapMinute); + InsertLeapSecond = FALSE; + DeleteLeapSecond = TRUE; + break; + + case 'c': /* specify number of seconds to send output for before exiting, 0 = forever */ + sscanf(optarg, "%d", &SecondsToSend); + break; + + case 'd': /* set DST for summer (WWV/H only) / start with DST active (IRIG) */ + DstFlag++; + break; + + case 'f': /* select format: i=IRIG-98 (default) 2=IRIG-2004 3-IRIG+IEEE-1344 w=WWV(H) */ + sscanf(optarg, "%c", &FormatCharacter); + break; + + case 'g': /* Date and time to switch back into / out of DST active. */ + sscanf(optarg, "%2d%2d%2d%2d%2d", &DstSwitchYear, &DstSwitchMonth, &DstSwitchDayOfMonth, + &DstSwitchHour, &DstSwitchMinute); + DstSwitchFlag = TRUE; + break; + + case 'h': + case 'H': + case '?': + Help (); + exit(-1); + break; + + case 'i': /* Insert (add) a leap second at the end of the specified minute. */ + sscanf(optarg, "%2d%2d%2d%2d%2d", &LeapYear, &LeapMonth, &LeapDayOfMonth, + &LeapHour, &LeapMinute); + InsertLeapSecond = TRUE; + DeleteLeapSecond = FALSE; + break; + + case 'j': + EnableRateCorrection = FALSE; + break; + + case 'k': + sscanf (optarg, "%d", &RateCorrection); + EnableRateCorrection = FALSE; + if (RateCorrection < 0) + { + RemoveCycle = TRUE; + AddCycle = FALSE; + + if (Verbose) + printf ("\n> Forcing rate correction removal of cycle...\n"); + } + else + { + if (RateCorrection > 0) + { + RemoveCycle = FALSE; + AddCycle = TRUE; + + if (Verbose) + printf ("\n> Forcing rate correction addition of cycle...\n"); + } + } + break; + + case 'l': /* use time offset from UTC */ + sscanf(optarg, "%f", &UseOffsetHoursFloat); + UseOffsetSecondsFloat = UseOffsetHoursFloat * (float) SECONDS_PER_HOUR; + UseOffsetSecondsInt = (int) (UseOffsetSecondsFloat + 0.5); + break; + + case 'o': /* Set IEEE 1344 time offset in hours - positive or negative, to the half hour */ + sscanf(optarg, "%f", &TimeOffset); + if (TimeOffset >= -0.2) + { + OffsetSignBit = 0; + + if (TimeOffset > 0) + { + OffsetOnes = TimeOffset; + + if ( (TimeOffset - floor(TimeOffset)) >= 0.4) + OffsetHalf = 1; + else + OffsetHalf = 0; + } + else + { + OffsetOnes = 0; + OffsetHalf = 0; + } + } + else + { + OffsetSignBit = 1; + OffsetOnes = -TimeOffset; + + if ( (ceil(TimeOffset) - TimeOffset) >= 0.4) + OffsetHalf = 1; + else + OffsetHalf = 0; + } + + /*printf ("\nGot TimeOffset = %3.1f, OffsetSignBit = %d, OffsetOnes = %d, OffsetHalf = %d...\n", + TimeOffset, OffsetSignBit, OffsetOnes, OffsetHalf); + */ + break; + + case 'q': /* Hex quality code 0 to 0x0F - 0 = maximum, 0x0F = no lock */ + sscanf(optarg, "%x", &TimeQuality); + TimeQuality &= 0x0F; + /*printf ("\nGot TimeQuality = 0x%1X...\n", TimeQuality); + */ + break; + + case 'r': /* sample rate (nominally 8000, integer close to 8000 I hope) */ + sscanf(optarg, "%d", &SetSampleRate); + break; + + case 's': /* set leap warning bit (WWV/H only) */ + leap++; + break; + + case 't': /* select WWVH sync frequency */ + tone = 1200; + break; + + case 'u': /* set DUT1 offset (-7 to +7) */ + sscanf(optarg, "%d", &dut1); + if (dut1 < 0) + dut1 = abs(dut1); + else + dut1 |= 0x8; + break; + +#ifndef HAVE_SYS_SOUNDCARD_H + case 'v': /* set output level (0-255) */ + sscanf(optarg, "%d", &level); + break; +#endif + + case 'x': /* Turn off verbose output. */ + Verbose = FALSE; + break; + + case 'y': /* Set initial date and time */ + sscanf(optarg, "%2d%2d%2d%2d%2d%2d", &Year, &Month, &DayOfMonth, + &Hour, &Minute, &Second); + utc++; + break; + + case 'z': /* Turn on Debug output (also turns on Verbose below) */ + Debug = TRUE; + break; + + default: + printf("Invalid option \"%c\", aborting...\n", temp); + exit (-1); + break; + } + } + + if (Debug) + Verbose = TRUE; + + if (InsertLeapSecond || DeleteLeapSecond) + { + LeapDayOfYear = ConvertMonthDayToDayOfYear (LeapYear, LeapMonth, LeapDayOfMonth); + + if (Debug) + { + printf ("\nHave request for leap second %s at year %4d day %3d at %2.2dh%2.2d....\n",\ + DeleteLeapSecond ? "DELETION" : (InsertLeapSecond ? "ADDITION" : "( error ! )" ), + LeapYear, LeapDayOfYear, LeapHour, LeapMinute); + } + } + + if (DstSwitchFlag) + { + DstSwitchDayOfYear = ConvertMonthDayToDayOfYear (DstSwitchYear, DstSwitchMonth, DstSwitchDayOfMonth); + + /* Figure out time of minute previous to DST switch, so can put up warning flag in IEEE 1344 */ + DstSwitchPendingYear = DstSwitchYear; + DstSwitchPendingDayOfYear = DstSwitchDayOfYear; + DstSwitchPendingHour = DstSwitchHour; + DstSwitchPendingMinute = DstSwitchMinute - 1; + if (DstSwitchPendingMinute < 0) + { + DstSwitchPendingMinute = 59; + DstSwitchPendingHour--; + if (DstSwitchPendingHour < 0) + { + DstSwitchPendingHour = 23; + DstSwitchPendingDayOfYear--; + if (DstSwitchPendingDayOfYear < 1) + { + DstSwitchPendingYear--; + } + } + } + + if (Debug) + { + printf ("\nHave DST switch request for year %4d day %3d at %2.2dh%2.2d,", + DstSwitchYear, DstSwitchDayOfYear, DstSwitchHour, DstSwitchMinute); + printf ("\n so will have warning at year %4d day %3d at %2.2dh%2.2d.\n", + DstSwitchPendingYear, DstSwitchPendingDayOfYear, DstSwitchPendingHour, DstSwitchPendingMinute); + } + } + + switch (tolower(FormatCharacter)) { + case 'i': + printf ("\nFormat is IRIG-1998 (no year coded)...\n\n"); + encode = IRIG; + IrigIncludeYear = FALSE; + IrigIncludeIeee = FALSE; + break; + + case '2': + printf ("\nFormat is IRIG-2004 (BCD year coded)...\n\n"); + encode = IRIG; + IrigIncludeYear = TRUE; + IrigIncludeIeee = FALSE; + break; + + case '3': + printf ("\nFormat is IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n"); + encode = IRIG; + IrigIncludeYear = TRUE; + IrigIncludeIeee = TRUE; + break; + + case '4': + printf ("\nFormat is unmodulated IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n"); + encode = IRIG; + IrigIncludeYear = TRUE; + IrigIncludeIeee = TRUE; + + Unmodulated = TRUE; + UnmodulatedInverted = FALSE; + break; + + case '5': + printf ("\nFormat is inverted unmodulated IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n"); + encode = IRIG; + IrigIncludeYear = TRUE; + IrigIncludeIeee = TRUE; + + Unmodulated = TRUE; + UnmodulatedInverted = TRUE; + break; + + case 'w': + printf ("\nFormat is WWV(H)...\n\n"); + encode = WWV; + break; + + default: + printf ("\n\nUnexpected format value of \'%c\', cannot parse, aborting...\n\n", FormatCharacter); + exit (-1); + break; + } + + /* + * Open audio device and set options + */ + fd = open(device, O_WRONLY); + if (fd <= 0) { + printf("Unable to open audio device \"%s\", aborting: %s\n", device, strerror(errno)); + exit(1); + } + +#ifdef HAVE_SYS_SOUNDCARD_H + /* First set coding type */ + AudioFormat = AFMT_MU_LAW; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &AudioFormat)==-1) + { /* Fatal error */ + printf ("\nUnable to set output format, aborting...\n\n"); + exit(-1); + } + + if (AudioFormat != AFMT_MU_LAW) + { + printf ("\nUnable to set output format for mu law, aborting...\n\n"); + exit(-1); + } + + /* Next set number of channels */ + MonoStereo = MONO; /* Mono */ + if (ioctl(fd, SNDCTL_DSP_STEREO, &MonoStereo)==-1) + { /* Fatal error */ + printf ("\nUnable to set mono/stereo, aborting...\n\n"); + exit(-1); + } + + if (MonoStereo != MONO) + { + printf ("\nUnable to set mono/stereo for mono, aborting...\n\n"); + exit(-1); + } + + /* Now set sample rate */ + SampleRate = SetSampleRate; + if (ioctl(fd, SNDCTL_DSP_SPEED, &SampleRate)==-1) + { /* Fatal error */ + printf ("\nUnable to set sample rate to %d, returned %d, aborting...\n\n", SetSampleRate, SampleRate); + exit(-1); + } + + SampleRateDifference = SampleRate - SetSampleRate; + + if (SampleRateDifference < 0) + SampleRateDifference = - SampleRateDifference; + + /* Fixed allowable sample rate error 0.1% */ + if (SampleRateDifference > (SetSampleRate/1000)) + { + printf ("\nUnable to set sample rate to %d, result was %d, more than 0.1 percent, aborting...\n\n", SetSampleRate, SampleRate); + exit(-1); + } + else + { + /* printf ("\nAttempt to set sample rate to %d, actual %d...\n\n", SetSampleRate, SampleRate); */ + } +#else + rval = ioctl(fd, AUDIO_GETINFO, &info); + if (rval < 0) { + printf("\naudio control %s", strerror(errno)); + exit(0); + } + info.play.port = port; + info.play.gain = level; + info.play.sample_rate = SetSampleRate; + info.play.channels = 1; + info.play.precision = 8; + info.play.encoding = AUDIO_ENCODING_ULAW; + printf("\nport %d gain %d rate %d chan %d prec %d encode %d\n", + info.play.port, info.play.gain, info.play.sample_rate, + info.play.channels, info.play.precision, + info.play.encoding); + ioctl(fd, AUDIO_SETINFO, &info); +#endif + + /* + * Unless specified otherwise, read the system clock and + * initialize the time. + */ + gettimeofday(&TimeValue, NULL); // Now always read the system time to keep "real time" of operation. + NowRealTime = BaseRealTime = SecondsPartOfTime = TimeValue.tv_sec; + SecondsRunningSimulationTime = 0; // Just starting simulation, running zero seconds as of now. + StabilityCount = 0; // No stability yet. + + if (utc) + { + DayOfYear = ConvertMonthDayToDayOfYear (Year, Month, DayOfMonth); + } + else + { + /* Apply offset to time. */ + if (UseOffsetSecondsInt >= 0) + SecondsPartOfTime += (time_t) UseOffsetSecondsInt; + else + SecondsPartOfTime -= (time_t) (-UseOffsetSecondsInt); + + TimeStructure = gmtime(&SecondsPartOfTime); + Minute = TimeStructure->tm_min; + Hour = TimeStructure->tm_hour; + DayOfYear = TimeStructure->tm_yday + 1; + Year = TimeStructure->tm_year % 100; + Second = TimeStructure->tm_sec; + + /* + * Delay the first second so the generator is accurately + * aligned with the system clock within one sample (125 + * microseconds ). + */ + delay(SECOND - TimeValue.tv_usec * 8 / 1000); + } + + StraightBinarySeconds = Second + (Minute * SECONDS_PER_MINUTE) + (Hour * SECONDS_PER_HOUR); + + memset(code, 0, sizeof(code)); + switch (encode) { + + /* + * For WWV/H and default time, carefully set the signal + * generator seconds number to agree with the current time. + */ + case WWV: + printf("WWV time signal, starting point:\n"); + printf(" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Minute tone = %d Hz, Hour tone = %d Hz.\n", + Year, DayOfYear, Hour, Minute, Second, tone, HourTone); + snprintf(code, sizeof(code), "%01d%03d%02d%02d%01d", + Year / 10, DayOfYear, Hour, Minute, Year % 10); + if (Verbose) + { + printf("\n Year = %2.2d, Day of year = %3d, Time = %2.2d:%2.2d:%2.2d, Code = %s", + Year, DayOfYear, Hour, Minute, Second, code); + + if ((EnableRateCorrection) || (RemoveCycle) || (AddCycle)) + printf (", CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved); + else + printf ("\n"); + } + + ptr = 8; + for (BitNumber = 0; BitNumber <= Second; BitNumber++) { + if (progx[BitNumber].sw == DEC) + ptr--; + } + break; + + /* + * For IRIG the signal generator runs every second, so requires + * no additional alignment. + */ + case IRIG: + printf ("IRIG-B time signal, starting point:\n"); + printf (" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Straight binary seconds (SBS) = %05d / 0x%04X.\n", + Year, DayOfYear, Hour, Minute, Second, StraightBinarySeconds, StraightBinarySeconds); + printf ("\n"); + if (Verbose) + { + printf ("Codes: \".\" = marker/position indicator, \"-\" = zero dummy bit, \"0\" = zero bit, \"1\" = one bit.\n"); + if ((EnableRateCorrection) || (AddCycle) || (RemoveCycle)) + { + printf (" \"o\" = short zero, \"*\" = long zero, \"x\" = short one, \"+\" = long one.\n"); + } + printf ("Numerical values are time order reversed in output to make it easier to read.\n"); + /* 111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999 */ + /* 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 */ + printf ("\n"); + printf ("Legend of output codes:\n"); + //printf ("\n"); + //printf ("| StraightBinSecs | IEEE_1344_Control | Year | Day_of_Year | Hours | Minutes |Seconds |\n"); + //printf ("| --------------- | ----------------- | ---- | ----------- | ----- | ------- |------- |\n"); + //printf ("| | | | | | | |\n"); + } + break; + } + + /* + * Run the signal generator to generate new timecode strings + * once per minute for WWV/H and once per second for IRIG. + */ + for (CountOfSecondsSent=0; ((SecondsToSend==0) || (CountOfSecondsSent<SecondsToSend)); CountOfSecondsSent++) + { + if ((encode == IRIG) && (((Second % 20) == 0) || (CountOfSecondsSent == 0))) + { + printf ("\n"); + + printf (" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Straight binary seconds (SBS) = %05d / 0x%04X.\n", + Year, DayOfYear, Hour, Minute, Second, StraightBinarySeconds, StraightBinarySeconds); + if ((EnableRateCorrection) || (RemoveCycle) || (AddCycle)) + { + printf (" CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved); + if ((CountOfSecondsSent != 0) && ((TotalCyclesAdded != 0) || (TotalCyclesRemoved != 0))) + { + RatioError = ((float) (TotalCyclesAdded - TotalCyclesRemoved)) / (1000.0 * (float) CountOfSecondsSent); + printf (" Adjusted by %2.1f%%, apparent send frequency is %4.2f Hz not %d Hz.\n\n", + RatioError*100.0, (1.0+RatioError)*((float) SetSampleRate), SetSampleRate); + } + } + else + printf ("\n"); + + /* printf ("|Seconds | Minutes | Hours | Day_of_Year | Year | IEEE_1344_Control | StraightBinSecs |\n"); + printf ("|------- | ------- | ----- | ----------- | ---- | ----------------- |-------------------|\n"); + printf ("| | | | | | | |\n");*/ + printf ("| StraightBinSecs | IEEE_1344_Control | Year | Day_of_Year | Hours | Minutes |Seconds |\n"); + printf ("| --------------- | ----------------- | ---- | ----------- | ----- | ------- |------- |\n"); + printf ("| | | | | | | |\n"); + } + + if (RemoveCycle) + { + RateCorrection = -1; + TotalSecondsCorrected ++; + } + else + { + if (AddCycle) + { + TotalSecondsCorrected ++; + RateCorrection = +1; + } + else + RateCorrection = 0; + } + + /* + * Crank the state machine to propagate carries to the + * year of century. Note that we delayed up to one + * second for alignment after reading the time, so this + * is the next second. + */ + + if (LeapState == LEAPSTATE_NORMAL) + { + /* If on the second of a leap (second 59 in the specified minute), then add or delete a second */ + if ((Year == LeapYear) && (DayOfYear == LeapDayOfYear) && (Hour == LeapHour) && (Minute == LeapMinute)) + { + /* To delete a second, which means we go from 58->60 instead of 58->59->00. */ + if ((DeleteLeapSecond) && (Second == 58)) + { + LeapState = LEAPSTATE_DELETING; + + if (Debug) + printf ("\n<--- Ready to delete a leap second...\n"); + } + else + { /* Delete takes precedence over insert. */ + /* To add a second, which means we go from 59->60->00 instead of 59->00. */ + if ((InsertLeapSecond) && (Second == 59)) + { + LeapState = LEAPSTATE_INSERTING; + + if (Debug) + printf ("\n<--- Ready to insert a leap second...\n"); + } + } + } + } + + switch (LeapState) + { + case LEAPSTATE_NORMAL: + Second = (Second + 1) % 60; + break; + + case LEAPSTATE_DELETING: + Second = 0; + LeapState = LEAPSTATE_NORMAL; + + if (Debug) + printf ("\n<--- Deleting a leap second...\n"); + break; + + case LEAPSTATE_INSERTING: + Second = 60; + LeapState = LEAPSTATE_ZERO_AFTER_INSERT; + + if (Debug) + printf ("\n<--- Inserting a leap second...\n"); + break; + + case LEAPSTATE_ZERO_AFTER_INSERT: + Second = 0; + LeapState = LEAPSTATE_NORMAL; + + if (Debug) + printf ("\n<--- Inserted a leap second, now back to zero...\n"); + break; + + default: + printf ("\n\nLeap second state invalid value of %d, aborting...", LeapState); + exit (-1); + break; + } + + /* Check for second rollover, increment minutes and ripple upward if required. */ + if (Second == 0) { + Minute++; + if (Minute >= 60) { + Minute = 0; + Hour++; + } + + /* Check for activation of DST switch. */ + /* If DST is active, this would mean that at the appointed time, we de-activate DST, */ + /* which translates to going backward an hour (repeating the last hour). */ + /* If DST is not active, this would mean that at the appointed time, we activate DST, */ + /* which translates to going forward an hour (skipping the next hour). */ + if (DstSwitchFlag) + { + /* The actual switch happens on the zero'th second of the actual minute specified. */ + if ((Year == DstSwitchYear) && (DayOfYear == DstSwitchDayOfYear) && (Hour == DstSwitchHour) && (Minute == DstSwitchMinute)) + { + if (DstFlag == 0) + { /* DST flag is zero, not in DST, going to DST, "spring ahead", so increment hour by two instead of one. */ + Hour++; + DstFlag = 1; + + /* Must adjust offset to keep consistent with UTC. */ + /* Here we have to increase offset by one hour. If it goes from negative to positive, then we fix that. */ + if (OffsetSignBit == 0) + { /* Offset is positive */ + if (OffsetOnes == 0x0F) + { + OffsetSignBit = 1; + OffsetOnes = (OffsetHalf == 0) ? 8 : 7; + } + else + OffsetOnes++; + } + else + { /* Offset is negative */ + if (OffsetOnes == 0) + { + OffsetSignBit = 0; + OffsetOnes = (OffsetHalf == 0) ? 1 : 0; + } + else + OffsetOnes--; + } + + if (Debug) + printf ("\n<--- DST activated, spring ahead an hour, new offset !...\n"); + } + else + { /* DST flag is non zero, in DST, going out of DST, "fall back", so no increment of hour. */ + Hour--; + DstFlag = 0; + + /* Must adjust offset to keep consistent with UTC. */ + /* Here we have to reduce offset by one hour. If it goes negative, then we fix that. */ + if (OffsetSignBit == 0) + { /* Offset is positive */ + if (OffsetOnes == 0) + { + OffsetSignBit = 1; + OffsetOnes = (OffsetHalf == 0) ? 1 : 0; + } + else + OffsetOnes--; + } + else + { /* Offset is negative */ + if (OffsetOnes == 0x0F) + { + OffsetSignBit = 0; + OffsetOnes = (OffsetHalf == 0) ? 8 : 7; + } + else + OffsetOnes++; + } + + if (Debug) + printf ("\n<--- DST de-activated, fall back an hour!...\n"); + } + + DstSwitchFlag = FALSE; /* One time deal, not intended to run this program past two switches... */ + } + } + + if (Hour >= 24) { + /* Modified, just in case dumb case where activating DST advances 23h59:59 -> 01h00:00 */ + Hour = Hour % 24; + DayOfYear++; + } + + /* + * At year rollover check for leap second. + */ + if (DayOfYear >= (Year & 0x3 ? 366 : 367)) { + if (leap) { + WWV_Second(DATA0, RateCorrection); + if (Verbose) + printf("\nLeap!"); + leap = 0; + } + DayOfYear = 1; + Year++; + } + if (encode == WWV) { + snprintf(code, sizeof(code), + "%01d%03d%02d%02d%01d", Year / 10, + DayOfYear, Hour, Minute, Year % 10); + if (Verbose) + printf("\n Year = %2.2d, Day of year = %3d, Time = %2.2d:%2.2d:%2.2d, Code = %s", + Year, DayOfYear, Hour, Minute, Second, code); + + if ((EnableRateCorrection) || (RemoveCycle) || (AddCycle)) + { + printf (", CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved); + if ((CountOfSecondsSent != 0) && ((TotalCyclesAdded != 0) || (TotalCyclesRemoved != 0))) + { + RatioError = ((float) (TotalCyclesAdded - TotalCyclesRemoved)) / (1000.0 * (float) CountOfSecondsSent); + printf (" Adjusted by %2.1f%%, apparent send frequency is %4.2f Hz not %d Hz.\n\n", + RatioError*100.0, (1.0+RatioError)*((float) SetSampleRate), SetSampleRate); + } + } + else + printf ("\n"); + + ptr = 8; + } + } /* End of "if (Second == 0)" */ + + /* After all that, if we are in the minute just prior to a leap second, warn of leap second pending */ + /* and of the polarity */ + if ((Year == LeapYear) && (DayOfYear == LeapDayOfYear) && (Hour == LeapHour) && (Minute == LeapMinute)) + { + LeapSecondPending = TRUE; + LeapSecondPolarity = DeleteLeapSecond; + } + else + { + LeapSecondPending = FALSE; + LeapSecondPolarity = FALSE; + } + + /* Notification through IEEE 1344 happens during the whole minute previous to the minute specified. */ + /* The time of that minute has been previously calculated. */ + if ((Year == DstSwitchPendingYear) && (DayOfYear == DstSwitchPendingDayOfYear) && + (Hour == DstSwitchPendingHour) && (Minute == DstSwitchPendingMinute)) + { + DstPendingFlag = TRUE; + } + else + { + DstPendingFlag = FALSE; + } + + + StraightBinarySeconds = Second + (Minute * SECONDS_PER_MINUTE) + (Hour * SECONDS_PER_HOUR); + + if (encode == IRIG) { + if (IrigIncludeIeee) + { + if ((OffsetOnes == 0) && (OffsetHalf == 0)) + OffsetSignBit = 0; + + ControlFunctions = (LeapSecondPending == 0 ? 0x00000 : 0x00001) | (LeapSecondPolarity == 0 ? 0x00000 : 0x00002) + | (DstPendingFlag == 0 ? 0x00000 : 0x00004) | (DstFlag == 0 ? 0x00000 : 0x00008) + | (OffsetSignBit == 0 ? 0x00000 : 0x00010) | ((OffsetOnes & 0x0F) << 5) | (OffsetHalf == 0 ? 0x00000 : 0x00200) + | ((TimeQuality & 0x0F) << 10); + /* if (Verbose) + printf ("\nDstFlag = %d, OffsetSignBit = %d, OffsetOnes = %d, OffsetHalf = %d, TimeQuality = 0x%1.1X ==> ControlFunctions = 0x%5.5X...", + DstFlag, OffsetSignBit, OffsetOnes, OffsetHalf, TimeQuality, ControlFunctions); + */ + } + else + ControlFunctions = 0; + + /* + YearDay HourMin Sec + snprintf(code, sizeof(code), "%04x%04d%06d%02d%02d%02d", + 0, Year, DayOfYear, Hour, Minute, Second); + */ + if (IrigIncludeYear) { + snprintf(ParityString, sizeof(ParityString), + "%04X%02d%04d%02d%02d%02d", + ControlFunctions & 0x7FFF, Year, + DayOfYear, Hour, Minute, Second); + } else { + snprintf(ParityString, sizeof(ParityString), + "%04X%02d%04d%02d%02d%02d", + ControlFunctions & 0x7FFF, + 0, DayOfYear, Hour, Minute, Second); + } + + if (IrigIncludeIeee) + { + ParitySum = 0; + for (StringPointer=ParityString; *StringPointer!=NUL; StringPointer++) + { + switch (toupper(*StringPointer)) + { + case '1': + case '2': + case '4': + case '8': + ParitySum += 1; + break; + + case '3': + case '5': + case '6': + case '9': + case 'A': + case 'C': + ParitySum += 2; + break; + + case '7': + case 'B': + case 'D': + case 'E': + ParitySum += 3; + break; + + case 'F': + ParitySum += 4; + break; + } + } + + if ((ParitySum & 0x01) == 0x01) + ParityValue = 0x01; + else + ParityValue = 0; + } + else + ParityValue = 0; + + ControlFunctions |= ((ParityValue & 0x01) << 14); + + if (IrigIncludeYear) { + snprintf(code, sizeof(code), + /* YearDay HourMin Sec */ + "%05X%05X%02d%04d%02d%02d%02d", + StraightBinarySeconds, + ControlFunctions, Year, DayOfYear, + Hour, Minute, Second); + } else { + snprintf(code, sizeof(code), + /* YearDay HourMin Sec */ + "%05X%05X%02d%04d%02d%02d%02d", + StraightBinarySeconds, + ControlFunctions, 0, DayOfYear, + Hour, Minute, Second); + } + + if (Debug) + printf("\nCode string: %s, ParityString = %s, ParitySum = 0x%2.2X, ParityValue = %d, DstFlag = %d...\n", code, ParityString, ParitySum, ParityValue, DstFlag); + + ptr = strlen(code)-1; + OldPtr = 0; + } + + /* + * Generate data for the second + */ + switch (encode) { + + /* + * The IRIG second consists of 20 BCD digits of width- + * modulateod pulses at 2, 5 and 8 ms and modulated 50 + * percent on the 1000-Hz carrier. + */ + case IRIG: + /* Initialize the output string */ + OutputDataString[0] = '\0'; + + for (BitNumber = 0; BitNumber < 100; BitNumber++) { + FrameNumber = (BitNumber/10) + 1; + switch (FrameNumber) + { + case 1: + /* bits 0 to 9, first frame */ + sw = progz[BitNumber % 10].sw; + arg = progz[BitNumber % 10].arg; + break; + + case 2: + case 3: + case 4: + case 5: + case 6: + /* bits 10 to 59, second to sixth frame */ + sw = progy[BitNumber % 10].sw; + arg = progy[BitNumber % 10].arg; + break; + + case 7: + /* bits 60 to 69, seventh frame */ + sw = progw[BitNumber % 10].sw; + arg = progw[BitNumber % 10].arg; + break; + + case 8: + /* bits 70 to 79, eighth frame */ + sw = progv[BitNumber % 10].sw; + arg = progv[BitNumber % 10].arg; + break; + + case 9: + /* bits 80 to 89, ninth frame */ + sw = progw[BitNumber % 10].sw; + arg = progw[BitNumber % 10].arg; + break; + + case 10: + /* bits 90 to 99, tenth frame */ + sw = progu[BitNumber % 10].sw; + arg = progu[BitNumber % 10].arg; + break; + + default: + /* , Unexpected values of FrameNumber */ + printf ("\n\nUnexpected value of FrameNumber = %d, cannot parse, aborting...\n\n", FrameNumber); + exit (-1); + break; + } + + switch(sw) { + + case DECC: /* decrement pointer and send bit. */ + ptr--; + case COEF: /* send BCD bit */ + AsciiValue = toupper(code[ptr]); + HexValue = isdigit(AsciiValue) ? AsciiValue - '0' : (AsciiValue - 'A')+10; + /* if (Debug) { + if (ptr != OldPtr) { + if (Verbose) + printf("\n(%c->%X)", AsciiValue, HexValue); + OldPtr = ptr; + } + } + */ + // OK, adjust all unused bits in hundreds of days. + if ((FrameNumber == 5) && ((BitNumber % 10) > 1)) + { + if (RateCorrection < 0) + { // Need to remove cycles to catch up. + if ((HexValue & arg) != 0) + { + if (Unmodulated) + { + poop(M5, 1000, HIGH, UnmodulatedInverted); + poop(M5-1, 1000, LOW, UnmodulatedInverted); + + TotalCyclesRemoved += 1; + } + else + { + peep(M5, 1000, HIGH); + peep(M5-1, 1000, LOW); + + TotalCyclesRemoved += 1; + } + strlcat(OutputDataString, "x", OUTPUT_DATA_STRING_LENGTH); + } + else + { + if (Unmodulated) + { + poop(M2, 1000, HIGH, UnmodulatedInverted); + poop(M8-1, 1000, LOW, UnmodulatedInverted); + + TotalCyclesRemoved += 1; + } + else + { + peep(M2, 1000, HIGH); + peep(M8-1, 1000, LOW); + + TotalCyclesRemoved += 1; + } + strlcat(OutputDataString, "o", OUTPUT_DATA_STRING_LENGTH); + } + } // End of true clause for "if (RateCorrection < 0)" + else + { // Else clause for "if (RateCorrection < 0)" + if (RateCorrection > 0) + { // Need to add cycles to slow back down. + if ((HexValue & arg) != 0) + { + if (Unmodulated) + { + poop(M5, 1000, HIGH, UnmodulatedInverted); + poop(M5+1, 1000, LOW, UnmodulatedInverted); + + TotalCyclesAdded += 1; + } + else + { + peep(M5, 1000, HIGH); + peep(M5+1, 1000, LOW); + + TotalCyclesAdded += 1; + } + strlcat(OutputDataString, "+", OUTPUT_DATA_STRING_LENGTH); + } + else + { + if (Unmodulated) + { + poop(M2, 1000, HIGH, UnmodulatedInverted); + poop(M8+1, 1000, LOW, UnmodulatedInverted); + + TotalCyclesAdded += 1; + } + else + { + peep(M2, 1000, HIGH); + peep(M8+1, 1000, LOW); + + TotalCyclesAdded += 1; + } + strlcat(OutputDataString, "*", OUTPUT_DATA_STRING_LENGTH); + } + } // End of true clause for "if (RateCorrection > 0)" + else + { // Else clause for "if (RateCorrection > 0)" + // Rate is OK, just do what you feel! + if ((HexValue & arg) != 0) + { + if (Unmodulated) + { + poop(M5, 1000, HIGH, UnmodulatedInverted); + poop(M5, 1000, LOW, UnmodulatedInverted); + } + else + { + peep(M5, 1000, HIGH); + peep(M5, 1000, LOW); + } + strlcat(OutputDataString, "1", OUTPUT_DATA_STRING_LENGTH); + } + else + { + if (Unmodulated) + { + poop(M2, 1000, HIGH, UnmodulatedInverted); + poop(M8, 1000, LOW, UnmodulatedInverted); + } + else + { + peep(M2, 1000, HIGH); + peep(M8, 1000, LOW); + } + strlcat(OutputDataString, "0", OUTPUT_DATA_STRING_LENGTH); + } + } // End of else clause for "if (RateCorrection > 0)" + } // End of else claues for "if (RateCorrection < 0)" + } // End of true clause for "if ((FrameNumber == 5) && (BitNumber == 8))" + else + { // Else clause for "if ((FrameNumber == 5) && (BitNumber == 8))" + if ((HexValue & arg) != 0) + { + if (Unmodulated) + { + poop(M5, 1000, HIGH, UnmodulatedInverted); + poop(M5, 1000, LOW, UnmodulatedInverted); + } + else + { + peep(M5, 1000, HIGH); + peep(M5, 1000, LOW); + } + strlcat(OutputDataString, "1", OUTPUT_DATA_STRING_LENGTH); + } + else + { + if (Unmodulated) + { + poop(M2, 1000, HIGH, UnmodulatedInverted); + poop(M8, 1000, LOW, UnmodulatedInverted); + } + else + { + peep(M2, 1000, HIGH); + peep(M8, 1000, LOW); + } + strlcat(OutputDataString, "0", OUTPUT_DATA_STRING_LENGTH); + } + } // end of else clause for "if ((FrameNumber == 5) && (BitNumber == 8))" + break; + + case DECZ: /* decrement pointer and send zero bit */ + ptr--; + if (Unmodulated) + { + poop(M2, 1000, HIGH, UnmodulatedInverted); + poop(M8, 1000, LOW, UnmodulatedInverted); + } + else + { + peep(M2, 1000, HIGH); + peep(M8, 1000, LOW); + } + strlcat(OutputDataString, "-", OUTPUT_DATA_STRING_LENGTH); + break; + + case DEC: /* send marker/position indicator IM/PI bit */ + ptr--; + case NODEC: /* send marker/position indicator IM/PI bit but no decrement pointer */ + case MIN: /* send "second start" marker/position indicator IM/PI bit */ + if (Unmodulated) + { + poop(arg, 1000, HIGH, UnmodulatedInverted); + poop(10 - arg, 1000, LOW, UnmodulatedInverted); + } + else + { + peep(arg, 1000, HIGH); + peep(10 - arg, 1000, LOW); + } + strlcat(OutputDataString, ".", OUTPUT_DATA_STRING_LENGTH); + break; + + default: + printf ("\n\nUnknown state machine value \"%d\", unable to continue, aborting...\n\n", sw); + exit (-1); + break; + } + if (ptr < 0) + break; + } + ReverseString ( OutputDataString ); + if (Verbose) + { + printf("%s", OutputDataString); + if (RateCorrection > 0) + printf(" fast\n"); + else + { + if (RateCorrection < 0) + printf (" slow\n"); + else + printf ("\n"); + } + } + break; + + /* + * The WWV/H second consists of 9 BCD digits of width- + * modulateod pulses 200, 500 and 800 ms at 100-Hz. + */ + case WWV: + sw = progx[Second].sw; + arg = progx[Second].arg; + switch(sw) { + + case DATA: /* send data bit */ + WWV_Second(arg, RateCorrection); + if (Verbose) + { + if (arg == DATA0) + printf ("0"); + else + { + if (arg == DATA1) + printf ("1"); + else + { + if (arg == PI) + printf ("P"); + else + printf ("?"); + } + } + } + break; + + case DATAX: /* send data bit */ + WWV_SecondNoTick(arg, RateCorrection); + if (Verbose) + { + if (arg == DATA0) + printf ("0"); + else + { + if (arg == DATA1) + printf ("1"); + else + { + if (arg == PI) + printf ("P"); + else + printf ("?"); + } + } + } + break; + + case COEF: /* send BCD bit */ + if (code[ptr] & arg) { + WWV_Second(DATA1, RateCorrection); + if (Verbose) + printf("1"); + } else { + WWV_Second(DATA0, RateCorrection); + if (Verbose) + printf("0"); + } + break; + + case LEAP: /* send leap bit */ + if (leap) { + WWV_Second(DATA1, RateCorrection); + if (Verbose) + printf("L"); + } else { + WWV_Second(DATA0, RateCorrection); + if (Verbose) + printf("0"); + } + break; + + case DEC: /* send data bit */ + ptr--; + WWV_Second(arg, RateCorrection); + if (Verbose) + { + if (arg == DATA0) + printf ("0"); + else + { + if (arg == DATA1) + printf ("1"); + else + { + if (arg == PI) + printf ("P"); + else + printf ("?"); + } + } + } + break; + + case DECX: /* send data bit with no tick */ + ptr--; + WWV_SecondNoTick(arg, RateCorrection); + if (Verbose) + { + if (arg == DATA0) + printf ("0"); + else + { + if (arg == DATA1) + printf ("1"); + else + { + if (arg == PI) + printf ("P"); + else + printf ("?"); + } + } + } + break; + + case MIN: /* send minute sync */ + if (Minute == 0) + { + peep(arg, HourTone, HIGH); + + if (RateCorrection < 0) + { + peep( 990 - arg, HourTone, OFF); + TotalCyclesRemoved += 10; + + if (Debug) + printf ("\n* Shorter Second: "); + } + else + { + if (RateCorrection > 0) + { + peep(1010 - arg, HourTone, OFF); + + TotalCyclesAdded += 10; + + if (Debug) + printf ("\n* Longer Second: "); + } + else + { + peep(1000 - arg, HourTone, OFF); + } + } + + if (Verbose) + printf("H"); + } + else + { + peep(arg, tone, HIGH); + + if (RateCorrection < 0) + { + peep( 990 - arg, tone, OFF); + TotalCyclesRemoved += 10; + + if (Debug) + printf ("\n* Shorter Second: "); + } + else + { + if (RateCorrection > 0) + { + peep(1010 - arg, tone, OFF); + + TotalCyclesAdded += 10; + + if (Debug) + printf ("\n* Longer Second: "); + } + else + { + peep(1000 - arg, tone, OFF); + } + } + + if (Verbose) + printf("M"); + } + break; + + case DUT1: /* send DUT1 bits */ + if (dut1 & arg) + { + WWV_Second(DATA1, RateCorrection); + if (Verbose) + printf("1"); + } + else + { + WWV_Second(DATA0, RateCorrection); + if (Verbose) + printf("0"); + } + break; + + case DST1: /* send DST1 bit */ + ptr--; + if (DstFlag) + { + WWV_Second(DATA1, RateCorrection); + if (Verbose) + printf("1"); + } + else + { + WWV_Second(DATA0, RateCorrection); + if (Verbose) + printf("0"); + } + break; + + case DST2: /* send DST2 bit */ + if (DstFlag) + { + WWV_Second(DATA1, RateCorrection); + if (Verbose) + printf("1"); + } + else + { + WWV_Second(DATA0, RateCorrection); + if (Verbose) + printf("0"); + } + break; + } + } + + if (EnableRateCorrection) + { + SecondsRunningSimulationTime++; + + gettimeofday(&TimeValue, NULL); + NowRealTime = TimeValue.tv_sec; + + if (NowRealTime >= BaseRealTime) // Just in case system time corrects backwards, do not blow up. + { + SecondsRunningRealTime = (unsigned) (NowRealTime - BaseRealTime); + SecondsRunningDifference = SecondsRunningSimulationTime - SecondsRunningRealTime; + + if (Debug) + { + printf ("> NowRealTime = 0x%8.8X, BaseRealtime = 0x%8.8X, SecondsRunningRealTime = 0x%8.8X, SecondsRunningSimulationTime = 0x%8.8X.\n", + (unsigned) NowRealTime, (unsigned) BaseRealTime, SecondsRunningRealTime, SecondsRunningSimulationTime); + printf ("> SecondsRunningDifference = 0x%8.8X, ExpectedRunningDifference = 0x%8.8X.\n", + SecondsRunningDifference, ExpectedRunningDifference); + } + + if (SecondsRunningSimulationTime > RUN_BEFORE_STABILITY_CHECK) + { + if (StabilityCount < MINIMUM_STABILITY_COUNT) + { + if (StabilityCount == 0) + { + ExpectedRunningDifference = SecondsRunningDifference; + StabilityCount++; + if (Debug) + printf ("> Starting stability check.\n"); + } + else + { // Else for "if (StabilityCount == 0)" + if ((ExpectedRunningDifference+INITIAL_STABILITY_BAND > SecondsRunningDifference) + && (ExpectedRunningDifference-INITIAL_STABILITY_BAND < SecondsRunningDifference)) + { // So far, still within stability band, increment count. + StabilityCount++; + if (Debug) + printf ("> StabilityCount = %d.\n", StabilityCount); + } + else + { // Outside of stability band, start over. + StabilityCount = 0; + if (Debug) + printf ("> Out of stability band, start over.\n"); + } + } // End of else for "if (StabilityCount == 0)" + } // End of true clause for "if (StabilityCount < MINIMUM_STABILITY_COUNT))" + else + { // Else clause for "if (StabilityCount < MINIMUM_STABILITY_COUNT))" - OK, so we are supposed to be stable. + if (AddCycle) + { + if (ExpectedRunningDifference >= SecondsRunningDifference) + { + if (Debug) + printf ("> Was adding cycles, ExpectedRunningDifference >= SecondsRunningDifference, can stop it now.\n"); + + AddCycle = FALSE; + RemoveCycle = FALSE; + } + else + { + if (Debug) + printf ("> Was adding cycles, not done yet.\n"); + } + } + else + { + if (RemoveCycle) + { + if (ExpectedRunningDifference <= SecondsRunningDifference) + { + if (Debug) + printf ("> Was removing cycles, ExpectedRunningDifference <= SecondsRunningDifference, can stop it now.\n"); + + AddCycle = FALSE; + RemoveCycle = FALSE; + } + else + { + if (Debug) + printf ("> Was removing cycles, not done yet.\n"); + } + } + else + { + if ((ExpectedRunningDifference+RUNNING_STABILITY_BAND > SecondsRunningDifference) + && (ExpectedRunningDifference-RUNNING_STABILITY_BAND < SecondsRunningDifference)) + { // All is well, within tolerances. + if (Debug) + printf ("> All is well, within tolerances.\n"); + } + else + { // Oops, outside tolerances. Else clause of "if ((ExpectedRunningDifference...SecondsRunningDifference)" + if (ExpectedRunningDifference > SecondsRunningDifference) + { + if (Debug) + printf ("> ExpectedRunningDifference > SecondsRunningDifference, running behind real time.\n"); + + // Behind real time, have to add a cycle to slow down and get back in sync. + AddCycle = FALSE; + RemoveCycle = TRUE; + } + else + { // Else clause of "if (ExpectedRunningDifference < SecondsRunningDifference)" + if (ExpectedRunningDifference < SecondsRunningDifference) + { + if (Debug) + printf ("> ExpectedRunningDifference < SecondsRunningDifference, running ahead of real time.\n"); + + // Ahead of real time, have to remove a cycle to speed up and get back in sync. + AddCycle = TRUE; + RemoveCycle = FALSE; + } + else + { + if (Debug) + printf ("> Oops, outside tolerances, but doesn't fit the profiles, how can this be?\n"); + } + } // End of else clause of "if (ExpectedRunningDifference > SecondsRunningDifference)" + } // End of else clause of "if ((ExpectedRunningDifference...SecondsRunningDifference)" + } // End of else clause of "if (RemoveCycle)". + } // End of else clause of "if (AddCycle)". + } // End of else clause for "if (StabilityCount < MINIMUM_STABILITY_COUNT))" + } // End of true clause for "if ((SecondsRunningSimulationTime > RUN_BEFORE_STABILITY_CHECK)" + } // End of true clause for "if (NowRealTime >= BaseRealTime)" + else + { + if (Debug) + printf ("> Hmm, time going backwards?\n"); + } + } // End of true clause for "if (EnableRateCorrection)" + + fflush (stdout); + } + + +printf ("\n\n>> Completed %d seconds, exiting...\n\n", SecondsToSend); +return (0); +} + + +/* + * Generate WWV/H 0 or 1 data pulse. + */ +void WWV_Second( + int code, /* DATA0, DATA1, PI */ + int Rate /* <0 -> do a short second, 0 -> normal second, >0 -> long second */ + ) +{ + /* + * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a + * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at + * 100 Hz corresponding to 0, 1 or position indicator (PI), + * respectively. Note the 100-Hz data pulses are transmitted 6 + * dB below the 1000-Hz sync pulses. Originally the data pulses + * were transmited 10 dB below the sync pulses, but the station + * engineers increased that to 6 dB because the Heath GC-1000 + * WWV/H radio clock worked much better. + */ + peep(5, tone, HIGH); /* send seconds tick */ + peep(25, tone, OFF); + peep(code - 30, 100, LOW); /* send data */ + + /* The quiet time is shortened or lengthened to get us back on time */ + if (Rate < 0) + { + peep( 990 - code, 100, OFF); + + TotalCyclesRemoved += 10; + + if (Debug) + printf ("\n* Shorter Second: "); + } + else + { + if (Rate > 0) + { + peep(1010 - code, 100, OFF); + + TotalCyclesAdded += 10; + + if (Debug) + printf ("\n* Longer Second: "); + } + else + peep(1000 - code, 100, OFF); + } +} + +/* + * Generate WWV/H 0 or 1 data pulse, with no tick, for 29th and 59th seconds + */ +void WWV_SecondNoTick( + int code, /* DATA0, DATA1, PI */ + int Rate /* <0 -> do a short second, 0 -> normal second, >0 -> long second */ + ) +{ + /* + * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a + * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at + * 100 Hz corresponding to 0, 1 or position indicator (PI), + * respectively. Note the 100-Hz data pulses are transmitted 6 + * dB below the 1000-Hz sync pulses. Originally the data pulses + * were transmited 10 dB below the sync pulses, but the station + * engineers increased that to 6 dB because the Heath GC-1000 + * WWV/H radio clock worked much better. + */ + peep(30, tone, OFF); /* send seconds non-tick */ + peep(code - 30, 100, LOW); /* send data */ + + /* The quiet time is shortened or lengthened to get us back on time */ + if (Rate < 0) + { + peep( 990 - code, 100, OFF); + + TotalCyclesRemoved += 10; + + if (Debug) + printf ("\n* Shorter Second: "); + } + else + { + if (Rate > 0) + { + peep(1010 - code, 100, OFF); + + TotalCyclesAdded += 10; + + if (Debug) + printf ("\n* Longer Second: "); + } + else + peep(1000 - code, 100, OFF); + } +} + +/* + * Generate cycles of 100 Hz or any multiple of 100 Hz. + */ +void peep( + int pulse, /* pulse length (ms) */ + int freq, /* frequency (Hz) */ + int amp /* amplitude */ + ) +{ + int increm; /* phase increment */ + int i, j; + + if (amp == OFF || freq == 0) + increm = 10; + else + increm = freq / 100; + j = 0; + for (i = 0 ; i < pulse * 8; i++) { + switch (amp) { + + case HIGH: + buffer[bufcnt++] = ~c6000[j]; + break; + + case LOW: + buffer[bufcnt++] = ~c3000[j]; + break; + + default: + buffer[bufcnt++] = ~0; + } + if (bufcnt >= BUFLNG) { + write(fd, buffer, BUFLNG); + bufcnt = 0; + } + j = (j + increm) % 80; + } +} + + +/* + * Generate unmodulated from similar tables. + */ +void poop( + int pulse, /* pulse length (ms) */ + int freq, /* frequency (Hz) */ + int amp, /* amplitude */ + int inverted /* is upside down */ + ) +{ + int increm; /* phase increment */ + int i, j; + + if (amp == OFF || freq == 0) + increm = 10; + else + increm = freq / 100; + j = 0; + for (i = 0 ; i < pulse * 8; i++) { + switch (amp) { + + case HIGH: + if (inverted) + buffer[bufcnt++] = ~u3000[j]; + else + buffer[bufcnt++] = ~u6000[j]; + break; + + case LOW: + if (inverted) + buffer[bufcnt++] = ~u6000[j]; + else + buffer[bufcnt++] = ~u3000[j]; + break; + + default: + buffer[bufcnt++] = ~0; + } + if (bufcnt >= BUFLNG) { + write(fd, buffer, BUFLNG); + bufcnt = 0; + } + j = (j + increm) % 80; + } +} + +/* + * Delay for initial phasing + */ +void delay ( + int Delay /* delay in samples */ + ) +{ + int samples; /* samples remaining */ + + samples = Delay; + memset(buffer, 0, BUFLNG); + while (samples >= BUFLNG) { + write(fd, buffer, BUFLNG); + samples -= BUFLNG; + } + write(fd, buffer, samples); +} + + +/* Calc day of year from year month & day */ +/* Year - 0 means 2000, 100 means 2100. */ +/* Month - 1 means January, 12 means December. */ +/* DayOfMonth - 1 is first day of month */ +int +ConvertMonthDayToDayOfYear (int YearValue, int MonthValue, int DayOfMonthValue) + { + int ReturnValue; + int LeapYear; + int MonthCounter; + + /* Array of days in a month. Note that here January is zero. */ + /* NB: have to add 1 to days in February in a leap year! */ + int DaysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + + LeapYear = FALSE; + if ((YearValue % 4) == 0) + { + if ((YearValue % 100) == 0) + { + if ((YearValue % 400) == 0) + { + LeapYear = TRUE; + } + } + else + { + LeapYear = TRUE; + } + } + + if (Debug) + printf ("\nConvertMonthDayToDayOfYear(): Year %d %s a leap year.\n", YearValue+2000, LeapYear ? "is" : "is not"); + + /* Day of month given us starts in this algorithm. */ + ReturnValue = DayOfMonthValue; + + /* Add in days in month for each month past January. */ + for (MonthCounter=1; MonthCounter<MonthValue; MonthCounter++) + { + ReturnValue += DaysInMonth [ MonthCounter - 1 ]; + } + + /* Add a day for leap years where we are past February. */ + if ((LeapYear) && (MonthValue > 2)) + { + ReturnValue++; + } + + if (Debug) + printf ("\nConvertMonthDayToDayOfYear(): %4.4d-%2.2d-%2.2d represents day %3d of year.\n", + YearValue+2000, MonthValue, DayOfMonthValue, ReturnValue); + + return (ReturnValue); + } + + +void +Help ( void ) + { + printf ("\n\nTime Code Generation - IRIG-B or WWV, v%d.%d, %s dmw", VERSION, ISSUE, ISSUE_DATE); + printf ("\n\nRCS Info:"); + printf ( "\n $Header: /home/dmw/src/IRIG_generation/ntp-4.2.2p3/util/RCS/tg.c,v 1.28 2007/02/12 23:57:45 dmw Exp $"); + printf ("\n\nUsage: %s [option]*", CommandName); + printf ("\n\nOptions: -a device_name Output audio device name (default /dev/audio)"); + printf ( "\n -b yymmddhhmm Remove leap second at end of minute specified"); + printf ( "\n -c seconds_to_send Number of seconds to send (default 0 = forever)"); + printf ( "\n -d Start with IEEE 1344 DST active"); + printf ( "\n -f format_type i = Modulated IRIG-B 1998 (no year coded)"); + printf ( "\n 2 = Modulated IRIG-B 2002 (year coded)"); + printf ( "\n 3 = Modulated IRIG-B w/IEEE 1344 (year & control funcs) (default)"); + printf ( "\n 4 = Unmodulated IRIG-B w/IEEE 1344 (year & control funcs)"); + printf ( "\n 5 = Inverted unmodulated IRIG-B w/IEEE 1344 (year & control funcs)"); + printf ( "\n w = WWV(H)"); + printf ( "\n -g yymmddhhmm Switch into/out of DST at beginning of minute specified"); + printf ( "\n -i yymmddhhmm Insert leap second at end of minute specified"); + printf ( "\n -j Disable time rate correction against system clock (default enabled)"); + printf ( "\n -k nn Force rate correction for testing (+1 = add cycle, -1 = remove cycle)"); + printf ( "\n -l time_offset Set offset of time sent to UTC as per computer, +/- float hours"); + printf ( "\n -o time_offset Set IEEE 1344 time offset, +/-, to 0.5 hour (default 0)"); + printf ( "\n -q quality_code_hex Set IEEE 1344 quality code (default 0)"); + printf ( "\n -r sample_rate Audio sample rate (default 8000)"); + printf ( "\n -s Set leap warning bit (WWV[H] only)"); + printf ( "\n -t sync_frequency WWV(H) on-time pulse tone frequency (default 1200)"); + printf ( "\n -u DUT1_offset Set WWV(H) DUT1 offset -7 to +7 (default 0)"); +#ifndef HAVE_SYS_SOUNDCARD_H + printf ( "\n -v initial_output_level Set initial output level (default %d, must be 0 to 255)", AUDIO_MAX_GAIN/8); +#endif + printf ( "\n -x Turn off verbose output (default on)"); + printf ( "\n -y yymmddhhmmss Set initial date and time as specified (default system time)"); + printf ("\n\nThis software licenced under the GPL, modifications performed 2006 & 2007 by Dean Weiten"); + printf ( "\nContact: Dean Weiten, Norscan Instruments Ltd., Winnipeg, MB, Canada, ph (204)-233-9138, E-mail dmw@norscan.com"); + printf ("\n\n"); + } + +/* Reverse string order for nicer print. */ +void +ReverseString(char *str) + { + int StringLength; + int IndexCounter; + int CentreOfString; + char TemporaryCharacter; + + + StringLength = strlen(str); + CentreOfString = (StringLength/2)+1; + for (IndexCounter = StringLength; IndexCounter >= CentreOfString; IndexCounter--) + { + TemporaryCharacter = str[IndexCounter-1]; + str[IndexCounter-1] = str[StringLength-IndexCounter]; + str[StringLength-IndexCounter] = TemporaryCharacter; + } + } + diff --git a/util/tickadj.c b/util/tickadj.c new file mode 100644 index 0000000..d54e9e6 --- /dev/null +++ b/util/tickadj.c @@ -0,0 +1,908 @@ +/* + * tickadj - read, and possibly modify, the kernel `tick' and + * `tickadj' variables, as well as `dosynctodr'. Note that + * this operates on the running kernel only. I'd like to be + * able to read and write the binary as well, but haven't + * mastered this yet. + * + * HMS: The #includes here are different from those in xntpd/ntp_unixclock.c + * These seem "worse". + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "ntp_types.h" +#include "l_stdlib.h" + +#include <stdio.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#ifdef HAVE_SYS_TIMEX_H +# include <sys/timex.h> +#endif + +#ifdef HAVE_ADJTIMEX /* Linux */ + +struct timex txc; + +#if 0 +int +main( + int argc, + char *argv[] + ) +{ + int c, i; + int quiet = 0; + int errflg = 0; + char *progname; + extern int ntp_optind; + extern char *ntp_optarg; + + progname = argv[0]; + if (argc==2 && argv[1][0] != '-') { /* old Linux format, for compatability */ + if ((i = atoi(argv[1])) > 0) { + txc.time_tick = i; + txc.modes = ADJ_TIMETICK; + } else { + fprintf(stderr, "Silly value for tick: %s\n", argv[1]); + errflg++; + } + } else { + while ((c = ntp_getopt(argc, argv, "a:qt:")) != EOF) { + switch (c) { + case 'a': + if ((i=atoi(ntp_optarg)) > 0) { + txc.tickadj = i; + txc.modes |= ADJ_TICKADJ; + } else { + fprintf(stderr, + "%s: unlikely value for tickadj: %s\n", + progname, ntp_optarg); + errflg++; + } + break; + + case 'q': + quiet = 1; + break; + + case 't': + if ((i=atoi(ntp_optarg)) > 0) { + txc.time_tick = i; + txc.modes |= ADJ_TIMETICK; + } else { + (void) fprintf(stderr, + "%s: unlikely value for tick: %s\n", + progname, ntp_optarg); + errflg++; + } + break; + + default: + fprintf(stderr, + "Usage: %s [tick_value]\n-or- %s [ -q ] [ -t tick ] [ -a tickadj ]\n", + progname, progname); + errflg++; + break; + } + } + } + + if (!errflg) { + if (adjtimex(&txc) < 0) + perror("adjtimex"); + else if (!quiet) + printf("tick = %ld\ntick_adj = %d\n", + txc.time_tick, txc.tickadj); + } + + exit(errflg ? 1 : 0); +} +#else +int +main( + int argc, + char *argv[] + ) +{ + if (argc > 2) + { + fprintf(stderr, "Usage: %s [tick_value]\n", argv[0]); + exit(-1); + } + else if (argc == 2) + { +#ifdef ADJ_TIMETICK + if ( (txc.time_tick = atoi(argv[1])) < 1 ) +#else + if ( (txc.tick = atoi(argv[1])) < 1 ) +#endif + { + fprintf(stderr, "Silly value for tick: %s\n", argv[1]); + exit(-1); + } +#ifdef ADJ_TIMETICK + txc.modes = ADJ_TIMETICK; +#else +#ifdef MOD_OFFSET + txc.modes = ADJ_TICK; +#else + txc.mode = ADJ_TICK; +#endif +#endif + } + else + { +#ifdef ADJ_TIMETICK + txc.modes = 0; +#else +#ifdef MOD_OFFSET + txc.modes = 0; +#else + txc.mode = 0; +#endif +#endif + } + + if (adjtimex(&txc) < 0) + { + perror("adjtimex"); + } + else + { +#ifdef ADJ_TIMETICK + printf("tick = %ld\ntick_adj = %ld\n", txc.time_tick, txc.tickadj); +#else + printf("tick = %ld\n", txc.tick); +#endif + } + + exit(0); +} +#endif + +#else /* not Linux... kmem tweaking: */ + +#ifdef HAVE_SYS_FILE_H +# include <sys/file.h> +#endif +#include <sys/stat.h> + +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +#endif + +#ifdef NLIST_STRUCT +# include <nlist.h> +#else /* not NLIST_STRUCT */ /* was defined(SYS_AUX3) || defined(SYS_AUX2) */ +# include <sys/resource.h> +# include <sys/file.h> +# include <a.out.h> +# ifdef HAVE_SYS_VAR_H +# include <sys/var.h> +# endif +#endif + +#include "ntp_stdlib.h" +#include "ntp_io.h" + +#ifdef hz /* Was: RS6000 */ +# undef hz +#endif /* hz */ + +#ifdef HAVE_KVM_OPEN +# include <kvm.h> +#endif + +#ifdef SYS_VXWORKS +/* vxWorks needs mode flag -casey*/ +#define open(name, flags) open(name, flags, 0777) +#endif + +#ifndef L_SET /* Was: defined(SYS_PTX) || defined(SYS_IX86OSF1) */ +# define L_SET SEEK_SET +#endif + +#ifndef HZ +# define HZ DEFAULT_HZ +#endif + +#define KMEM "/dev/kmem" +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +char *progname; + +int dokmem = 1; +int writetickadj = 0; +int writeopttickadj = 0; +int unsetdosync = 0; +int writetick = 0; +int quiet = 0; +int setnoprintf = 0; + +const char *kmem = KMEM; +const char *file = NULL; +int fd = -1; + +static void getoffsets (off_t *, off_t *, off_t *, off_t *); +static int openfile (const char *, int); +static void writevar (int, off_t, int); +static void readvar (int, off_t, int *); + +/* + * main - parse arguments and handle options + */ +int +main( + int argc, + char *argv[] + ) +{ + int c; + int errflg = 0; + off_t tickadj_offset; + off_t tick_offset; + off_t dosync_offset; + off_t noprintf_offset; + int tickadj, ktickadj; /* HMS: Why isn't this u_long? */ + int tick, ktick; /* HMS: Why isn't this u_long? */ + int dosynctodr; + int noprintf; + int hz; + int hz_int, hz_hundredths; + int recommend_tickadj; + long tmp; + + init_lib(); + + progname = argv[0]; + while ((c = ntp_getopt(argc, argv, "a:Adkpqst:")) != EOF) + { + switch (c) + { + case 'a': + writetickadj = atoi(ntp_optarg); + if (writetickadj <= 0) + { + (void) fprintf(stderr, + "%s: unlikely value for tickadj: %s\n", + progname, ntp_optarg); + errflg++; + } + +#if defined SCO5_CLOCK + if (writetickadj % HZ) + { + writetickadj = (writetickadj / HZ) * HZ; + (void) fprintf(stderr, + "tickadj truncated to: %d\n", writetickadj); + } +#endif /* SCO5_CLOCK */ + + break; + case 'A': + writeopttickadj = 1; + break; + case 'd': + ++debug; + break; + case 'k': + dokmem = 1; + break; + case 'p': + setnoprintf = 1; + break; + case 'q': + quiet = 1; + break; + case 's': + unsetdosync = 1; + break; + case 't': + writetick = atoi(ntp_optarg); + if (writetick <= 0) + { + (void) fprintf(stderr, + "%s: unlikely value for tick: %s\n", + progname, ntp_optarg); + errflg++; + } + break; + default: + errflg++; + break; + } + } + if (errflg || ntp_optind != argc) + { + (void) fprintf(stderr, + "usage: %s [-Adkpqs] [-a newadj] [-t newtick]\n", progname); + exit(2); + } + + getoffsets(&tick_offset, &tickadj_offset, &dosync_offset, &noprintf_offset); + + if (debug) + { + (void) printf("tick offset = %lu\n", (unsigned long)tick_offset); + (void) printf("tickadj offset = %lu\n", (unsigned long)tickadj_offset); + (void) printf("dosynctodr offset = %lu\n", (unsigned long)dosync_offset); + (void) printf("noprintf offset = %lu\n", (unsigned long)noprintf_offset); + } + + if (writetick && (tick_offset == 0)) + { + (void) fprintf(stderr, + "No tick kernel variable\n"); + errflg++; + } + + if (writeopttickadj && (tickadj_offset == 0)) + { + (void) fprintf(stderr, + "No tickadj kernel variable\n"); + errflg++; + } + + if (unsetdosync && (dosync_offset == 0)) + { + (void) fprintf(stderr, + "No dosynctodr kernel variable\n"); + errflg++; + } + + if (setnoprintf && (noprintf_offset == 0)) + { + (void) fprintf(stderr, + "No noprintf kernel variable\n"); + errflg++; + } + + if (tick_offset != 0) + { + readvar(fd, tick_offset, &tick); +#if defined(TICK_NANO) && defined(K_TICK_NAME) + if (!quiet) + (void) printf("KERNEL %s = %d nsec\n", K_TICK_NAME, tick); +#endif /* TICK_NANO && K_TICK_NAME */ + +#ifdef TICK_NANO + tick /= 1000; +#endif + } + else + { + tick = 0; + } + + if (tickadj_offset != 0) + { + readvar(fd, tickadj_offset, &tickadj); + +#ifdef SCO5_CLOCK + /* scale from nsec/sec to usec/tick */ + tickadj /= (1000L * HZ); +#endif /*SCO5_CLOCK */ + +#if defined(TICKADJ_NANO) && defined(K_TICKADJ_NAME) + if (!quiet) + (void) printf("KERNEL %s = %d nsec\n", K_TICKADJ_NAME, tickadj); +#endif /* TICKADJ_NANO && K_TICKADJ_NAME */ + +#ifdef TICKADJ_NANO + tickadj += 999; + tickadj /= 1000; +#endif + } + else + { + tickadj = 0; + } + + if (dosync_offset != 0) + { + readvar(fd, dosync_offset, &dosynctodr); + } + + if (noprintf_offset != 0) + { + readvar(fd, noprintf_offset, &noprintf); + } + + (void) close(fd); + + if (unsetdosync && dosync_offset == 0) + { + (void) fprintf(stderr, + "%s: can't find %s in namelist\n", + progname, +#ifdef K_DOSYNCTODR_NAME + K_DOSYNCTODR_NAME +#else /* not K_DOSYNCTODR_NAME */ + "dosynctodr" +#endif /* not K_DOSYNCTODR_NAME */ + ); + exit(1); + } + + hz = HZ; +#if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) + hz = (int) sysconf (_SC_CLK_TCK); +#endif /* not HAVE_SYSCONF && _SC_CLK_TCK */ +#ifdef OVERRIDE_HZ + hz = DEFAULT_HZ; +#endif + ktick = tick; +#ifdef PRESET_TICK + tick = PRESET_TICK; +#endif /* PRESET_TICK */ +#ifdef TICKADJ_NANO + tickadj /= 1000; + if (tickadj == 0) + tickadj = 1; +#endif + ktickadj = tickadj; +#ifdef PRESET_TICKADJ + tickadj = (PRESET_TICKADJ) ? PRESET_TICKADJ : 1; +#endif /* PRESET_TICKADJ */ + + if (!quiet) + { + if (tick_offset != 0) + { + (void) printf("KERNEL tick = %d usec (from %s kernel variable)\n", + ktick, +#ifdef K_TICK_NAME + K_TICK_NAME +#else + "<this can't happen>" +#endif + ); + } +#ifdef PRESET_TICK + (void) printf("PRESET tick = %d usec\n", tick); +#endif /* PRESET_TICK */ + if (tickadj_offset != 0) + { + (void) printf("KERNEL tickadj = %d usec (from %s kernel variable)\n", + ktickadj, +#ifdef K_TICKADJ_NAME + K_TICKADJ_NAME +#else + "<this can't happen>" +#endif + ); + } +#ifdef PRESET_TICKADJ + (void) printf("PRESET tickadj = %d usec\n", tickadj); +#endif /* PRESET_TICKADJ */ + if (dosync_offset != 0) + { + (void) printf("dosynctodr is %s\n", dosynctodr ? "on" : "off"); + } + if (noprintf_offset != 0) + { + (void) printf("kernel level printf's: %s\n", + noprintf ? "off" : "on"); + } + } + + if (tick <= 0) + { + (void) fprintf(stderr, "%s: the value of tick is silly!\n", + progname); + exit(1); + } + + hz_int = (int)(1000000L / (long)tick); + hz_hundredths = (int)((100000000L / (long)tick) - ((long)hz_int * 100L)); + if (!quiet) + { + (void) printf("KERNEL hz = %d\n", hz); + (void) printf("calculated hz = %d.%02d Hz\n", hz_int, + hz_hundredths); + } + +#if defined SCO5_CLOCK + recommend_tickadj = 100; +#else /* SCO5_CLOCK */ + tmp = (long) tick * 500L; + recommend_tickadj = (int)(tmp / 1000000L); + if (tmp % 1000000L > 0) + { + recommend_tickadj++; + } + +#ifdef MIN_REC_TICKADJ + if (recommend_tickadj < MIN_REC_TICKADJ) + { + recommend_tickadj = MIN_REC_TICKADJ; + } +#endif /* MIN_REC_TICKADJ */ +#endif /* SCO5_CLOCK */ + + + if ((!quiet) && (tickadj_offset != 0)) + { + (void) printf("recommended value of tickadj = %d us\n", + recommend_tickadj); + } + + if ( writetickadj == 0 + && !writeopttickadj + && !unsetdosync + && writetick == 0 + && !setnoprintf) + { + exit(errflg ? 1 : 0); + } + + if (writetickadj == 0 && writeopttickadj) + { + writetickadj = recommend_tickadj; + } + + fd = openfile(file, O_WRONLY); + + if (setnoprintf && (noprintf_offset != 0)) + { + if (!quiet) + { + (void) fprintf(stderr, "setting noprintf: "); + (void) fflush(stderr); + } + writevar(fd, noprintf_offset, 1); + if (!quiet) + { + (void) fprintf(stderr, "done!\n"); + } + } + + if ((writetick > 0) && (tick_offset != 0)) + { + if (!quiet) + { + (void) fprintf(stderr, "writing tick, value %d: ", + writetick); + (void) fflush(stderr); + } + writevar(fd, tick_offset, writetick); + if (!quiet) + { + (void) fprintf(stderr, "done!\n"); + } + } + + if ((writetickadj > 0) && (tickadj_offset != 0)) + { + if (!quiet) + { + (void) fprintf(stderr, "writing tickadj, value %d: ", + writetickadj); + (void) fflush(stderr); + } + +#ifdef SCO5_CLOCK + /* scale from usec/tick to nsec/sec */ + writetickadj *= (1000L * HZ); +#endif /* SCO5_CLOCK */ + + writevar(fd, tickadj_offset, writetickadj); + if (!quiet) + { + (void) fprintf(stderr, "done!\n"); + } + } + + if (unsetdosync && (dosync_offset != 0)) + { + if (!quiet) + { + (void) fprintf(stderr, "zeroing dosynctodr: "); + (void) fflush(stderr); + } + writevar(fd, dosync_offset, 0); + if (!quiet) + { + (void) fprintf(stderr, "done!\n"); + } + } + (void) close(fd); + return(errflg ? 1 : 0); +} + +/* + * getoffsets - read the magic offsets from the specified file + */ +static void +getoffsets( + off_t *tick_off, + off_t *tickadj_off, + off_t *dosync_off, + off_t *noprintf_off + ) +{ + +#ifndef NOKMEM +# ifndef HAVE_KVM_OPEN + const char **kname; +# endif +#endif + +#ifndef NOKMEM +# ifdef NLIST_NAME_UNION +# define NL_B {{ +# define NL_E }} +# else +# define NL_B { +# define NL_E } +# endif +#endif + +#define K_FILLER_NAME "DavidLetterman" + +#ifdef NLIST_EXTRA_INDIRECTION + int i; +#endif + +#ifndef NOKMEM + static struct nlist nl[] = + { + NL_B +#ifdef K_TICKADJ_NAME +#define N_TICKADJ 0 + K_TICKADJ_NAME +#else + K_FILLER_NAME +#endif + NL_E, + NL_B +#ifdef K_TICK_NAME +#define N_TICK 1 + K_TICK_NAME +#else + K_FILLER_NAME +#endif + NL_E, + NL_B +#ifdef K_DOSYNCTODR_NAME +#define N_DOSYNC 2 + K_DOSYNCTODR_NAME +#else + K_FILLER_NAME +#endif + NL_E, + NL_B +#ifdef K_NOPRINTF_NAME +#define N_NOPRINTF 3 + K_NOPRINTF_NAME +#else + K_FILLER_NAME +#endif + NL_E, + NL_B "" NL_E, + }; + +#ifndef HAVE_KVM_OPEN + static const char *kernels[] = + { +#ifdef HAVE_GETBOOTFILE + NULL, /* *** SEE BELOW! *** */ +#endif + "/kernel/unix", + "/kernel", + "/vmunix", + "/unix", + "/mach", + "/hp-ux", + "/386bsd", + "/netbsd", + "/stand/vmunix", + "/bsd", + NULL + }; +#endif /* not HAVE_KVM_OPEN */ + +#ifdef HAVE_KVM_OPEN + /* + * Solaris > 2.5 doesn't have a kernel file. Use the kvm_* interface + * to read the kernel name list. -- stolcke 3/4/96 + */ + kvm_t *kvm_handle = kvm_open(NULL, NULL, NULL, O_RDONLY, progname); + + if (kvm_handle == NULL) + { + (void) fprintf(stderr, + "%s: kvm_open failed\n", + progname); + exit(1); + } + if (kvm_nlist(kvm_handle, nl) == -1) + { + (void) fprintf(stderr, + "%s: kvm_nlist failed\n", + progname); + exit(1); + } + kvm_close(kvm_handle); +#else /* not HAVE_KVM_OPEN */ +#ifdef HAVE_GETBOOTFILE /* *** SEE HERE! *** */ + if (kernels[0] == NULL) + { + char * cp = (char *)getbootfile(); + + if (cp) + { + kernels[0] = cp; + } + else + { + kernels[0] = "/Placeholder"; + } + } +#endif /* HAVE_GETBOOTFILE */ + for (kname = kernels; *kname != NULL; kname++) + { + struct stat stbuf; + + if (stat(*kname, &stbuf) == -1) + { + continue; + } + if (nlist(*kname, nl) >= 0) + { + break; + } + else + { + (void) fprintf(stderr, + "%s: nlist didn't find needed symbols from <%s>: %s\n", + progname, *kname, strerror(errno)); + } + } + if (*kname == NULL) + { + (void) fprintf(stderr, + "%s: Couldn't find the kernel\n", + progname); + exit(1); + } +#endif /* HAVE_KVM_OPEN */ + + if (dokmem) + { + file = kmem; + + fd = openfile(file, O_RDONLY); +#ifdef NLIST_EXTRA_INDIRECTION + /* + * Go one more round of indirection. + */ + for (i = 0; i < (sizeof(nl) / sizeof(struct nlist)); i++) + { + if ((nl[i].n_value) && (nl[i].n_sclass == 0x6b)) + { + readvar(fd, nl[i].n_value, &nl[i].n_value); + } + } +#endif /* NLIST_EXTRA_INDIRECTION */ + } +#endif /* not NOKMEM */ + + *tickadj_off = 0; + *tick_off = 0; + *dosync_off = 0; + *noprintf_off = 0; + +#if defined(N_TICKADJ) + *tickadj_off = nl[N_TICKADJ].n_value; +#endif + +#if defined(N_TICK) + *tick_off = nl[N_TICK].n_value; +#endif + +#if defined(N_DOSYNC) + *dosync_off = nl[N_DOSYNC].n_value; +#endif + +#if defined(N_NOPRINTF) + *noprintf_off = nl[N_NOPRINTF].n_value; +#endif + return; +} + +#undef N_TICKADJ +#undef N_TICK +#undef N_DOSYNC +#undef N_NOPRINTF + + +/* + * openfile - open the file, check for errors + */ +static int +openfile( + const char *name, + int mode + ) +{ + int ifd; + + ifd = open(name, mode); + if (ifd < 0) + { + (void) fprintf(stderr, "%s: open %s: ", progname, name); + perror(""); + exit(1); + } + return ifd; +} + + +/* + * writevar - write a variable into the file + */ +static void +writevar( + int ofd, + off_t off, + int var + ) +{ + + if (lseek(ofd, off, L_SET) == -1) + { + (void) fprintf(stderr, "%s: lseek fails: ", progname); + perror(""); + exit(1); + } + if (write(ofd, (char *)&var, sizeof(int)) != sizeof(int)) + { + (void) fprintf(stderr, "%s: write fails: ", progname); + perror(""); + exit(1); + } + return; +} + + +/* + * readvar - read a variable from the file + */ +static void +readvar( + int ifd, + off_t off, + int *var + ) +{ + int i; + + if (lseek(ifd, off, L_SET) == -1) + { + (void) fprintf(stderr, "%s: lseek fails: ", progname); + perror(""); + exit(1); + } + i = read(ifd, (char *)var, sizeof(int)); + if (i < 0) + { + (void) fprintf(stderr, "%s: read fails: ", progname); + perror(""); + exit(1); + } + if (i != sizeof(int)) + { + (void) fprintf(stderr, "%s: read expected %d, got %d\n", + progname, (int)sizeof(int), i); + exit(1); + } + return; +} +#endif /* not Linux */ diff --git a/util/timetrim.c b/util/timetrim.c new file mode 100644 index 0000000..911ea28 --- /dev/null +++ b/util/timetrim.c @@ -0,0 +1,116 @@ +#if defined(sgi) || defined(_UNICOSMP) +/* + * timetrim.c + * + * "timetrim" allows setting and adjustment of the system clock frequency + * trim parameter on Silicon Graphics machines. The trim value native + * units are nanoseconds per second (10**-9), so a trim value of 1 makes + * the system clock step ahead 1 nanosecond more per second than a value + * of zero. Xntpd currently uses units of 2**-20 secs for its frequency + * offset (drift) values; to convert to a timetrim value, multiply by + * 1E9 / 2**20 (about 954). + * + * "timetrim" with no arguments just prints out the current kernel value. + * With a numeric argument, the kernel value is set to the supplied value. + * The "-i" flag causes the supplied value to be added to the kernel value. + * The "-n" option causes all input and output to be in xntpd units rather + * than timetrim native units. + * + * Note that there is a limit of +-3000000 (0.3%) on the timetrim value + * which is (silently?) enforced by the kernel. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#ifdef HAVE_SYS_SYSSGI_H +# include <sys/syssgi.h> +#endif +#ifdef HAVE_SYS_SYSTUNE_H +# include <sys/systune.h> +#endif + +#define abs(X) (((X) < 0) ? -(X) : (X)) +#define USAGE "usage: timetrim [-n] [[-i] value]\n" +#define SGITONTP(X) ((double)(X) * 1048576.0/1.0e9) +#define NTPTOSGI(X) ((long)((X) * 1.0e9/1048576.0)) + +int +main( + int argc, + char *argv[] + ) +{ + char *rem; + int incremental = 0, ntpunits = 0; + long timetrim; + double value; + + while (--argc && **++argv == '-' && isalpha((int)argv[0][1])) { + switch (argv[0][1]) { + case 'i': + incremental++; + break; + case 'n': + ntpunits++; + break; + default: + fprintf(stderr, USAGE); + exit(1); + } + } + +#ifdef HAVE_SYS_SYSSGI_H + if (syssgi(SGI_GETTIMETRIM, &timetrim) < 0) { + perror("syssgi"); + exit(2); + } +#endif +#ifdef HAVE_SYS_SYSTUNE_H + if (systune(SYSTUNE_GET, "timetrim", &timetrim) < 0) { + perror("systune"); + exit(2); + } +#endif + + if (argc == 0) { + if (ntpunits) + fprintf(stdout, "%0.5f\n", SGITONTP(timetrim)); + else + fprintf(stdout, "%ld\n", timetrim); + } else if (argc != 1) { + fprintf(stderr, USAGE); + exit(1); + } else { + value = strtod(argv[0], &rem); + if (*rem != '\0') { + fprintf(stderr, USAGE); + exit(1); + } + if (ntpunits) + value = NTPTOSGI(value); + if (incremental) + timetrim += value; + else + timetrim = value; +#ifdef HAVE_SYS_SYSSGI_H + if (syssgi(SGI_SETTIMETRIM, timetrim) < 0) { + perror("syssgi"); + exit(2); + } +#endif +#ifdef HAVE_SYS_SYSTUNE_H + if (systune(SYSTUNE_SET, "timer", "timetrim", &timetrim) < 0) { + perror("systune"); + exit(2); + } +#endif + } + return 0; +} +#endif |