summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-12-02 09:01:21 +0000
committer <>2014-12-04 16:11:25 +0000
commitbdab5265fcbf3f472545073a23f8999749a9f2b9 (patch)
treec6018dd03dea906f8f1fb5f105f05b71a7dc250a /util
downloadntp-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.am135
-rw-r--r--util/Makefile.in1289
-rw-r--r--util/README44
-rw-r--r--util/audio-pcm.c154
-rw-r--r--util/byteorder.c56
-rw-r--r--util/hist.c110
-rw-r--r--util/invoke-ntp-keygen.menu1
-rw-r--r--util/invoke-ntp-keygen.texi1354
-rw-r--r--util/jitter.c136
-rw-r--r--util/jitter.h401
-rw-r--r--util/kern.c225
-rw-r--r--util/longsize.c11
-rw-r--r--util/ntp-keygen-opts.c1719
-rw-r--r--util/ntp-keygen-opts.def1144
-rw-r--r--util/ntp-keygen-opts.h386
-rw-r--r--util/ntp-keygen.1ntp-keygenman1221
-rw-r--r--util/ntp-keygen.1ntp-keygenmdoc1071
-rw-r--r--util/ntp-keygen.c2181
-rw-r--r--util/ntp-keygen.html1811
-rw-r--r--util/ntp-keygen.man.in1221
-rw-r--r--util/ntp-keygen.mdoc.in1071
-rw-r--r--util/ntp-keygen.texi307
-rw-r--r--util/ntptime.c474
-rw-r--r--util/pps-api.c100
-rw-r--r--util/precision.c171
-rw-r--r--util/sht.c260
-rw-r--r--util/testrs6000.c55
-rw-r--r--util/tg.c653
-rw-r--r--util/tg2.c2506
-rw-r--r--util/tickadj.c908
-rw-r--r--util/timetrim.c116
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>...&lt;...&gt;...</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:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#Description">Description</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#dir">(dir)</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#Running-the-Program">Running the Program</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Top">Top</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#Random-Seed-File">Random Seed File</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Description">Description</a>,
+Up:&nbsp;<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 &lt;
+<kbd>d</kbd>
+&lt;
+<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, &lt;http://ntp.org/license&gt;.
+
+<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-imbits">ntp-keygen imbits</a>,
+Up:&nbsp;<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 [ -&lt;flag&gt; [&lt;val&gt;] | --&lt;name&gt;[{=| }&lt;val&gt;] ]...
+ 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 &lt;num&gt; MV parameters
+ -v Num mv-keys update &lt;num&gt; 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
+ -&gt; opt save-opts save the option state to a config file
+ -&lt; 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: &lt;http://bugs.ntp.org, bugs@ntp.org&gt;
+</pre>
+ <div class="node">
+<p><hr>
+<a name="ntp_002dkeygen-imbits"></a>Next:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-certificate">ntp-keygen certificate</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-usage">ntp-keygen usage</a>,
+Up:&nbsp;<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 &ldquo;identity modulus bits&rdquo; 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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-cipher">ntp-keygen cipher</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-imbits">ntp-keygen imbits</a>,
+Up:&nbsp;<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 &ldquo;certificate scheme&rdquo; 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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-id_002dkey">ntp-keygen id-key</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-certificate">ntp-keygen certificate</a>,
+Up:&nbsp;<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 &ldquo;privatekey cipher&rdquo; 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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-gq_002dparams">ntp-keygen gq-params</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-cipher">ntp-keygen cipher</a>,
+Up:&nbsp;<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 &ldquo;write iff or gq identity keys&rdquo; 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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-host_002dkey">ntp-keygen host-key</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-id_002dkey">ntp-keygen id-key</a>,
+Up:&nbsp;<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 &ldquo;generate gq parameters and keys&rdquo; 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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-iffkey">ntp-keygen iffkey</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-gq_002dparams">ntp-keygen gq-params</a>,
+Up:&nbsp;<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 &ldquo;generate rsa host key&rdquo; 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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-ident">ntp-keygen ident</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-host_002dkey">ntp-keygen host-key</a>,
+Up:&nbsp;<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 &ldquo;generate iff parameters&rdquo; 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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-lifetime">ntp-keygen lifetime</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-iffkey">ntp-keygen iffkey</a>,
+Up:&nbsp;<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 &ldquo;set autokey group name&rdquo; 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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-md5key">ntp-keygen md5key</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-ident">ntp-keygen ident</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-modulus">ntp-keygen modulus</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-lifetime">ntp-keygen lifetime</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-pvt_002dcert">ntp-keygen pvt-cert</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-md5key">ntp-keygen md5key</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-password">ntp-keygen password</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-modulus">ntp-keygen modulus</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-export_002dpasswd">ntp-keygen export-passwd</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-pvt_002dcert">ntp-keygen pvt-cert</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-sign_002dkey">ntp-keygen sign-key</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-password">ntp-keygen password</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-subject_002dname">ntp-keygen subject-name</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-export_002dpasswd">ntp-keygen export-passwd</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-trusted_002dcert">ntp-keygen trusted-cert</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-sign_002dkey">ntp-keygen sign-key</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-mv_002dparams">ntp-keygen mv-params</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-subject_002dname">ntp-keygen subject-name</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-mv_002dkeys">ntp-keygen mv-keys</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-trusted_002dcert">ntp-keygen trusted-cert</a>,
+Up:&nbsp;<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 &lt;num&gt; 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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-config">ntp-keygen config</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-mv_002dparams">ntp-keygen mv-params</a>,
+Up:&nbsp;<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 &lt;num&gt; 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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-exit-status">ntp-keygen exit status</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-mv_002dkeys">ntp-keygen mv-keys</a>,
+Up:&nbsp;<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_&lt;OPTION_NAME&gt;</code>. <code>&lt;OPTION_NAME&gt;</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"> &lt;?program ntp-keygen&gt;
+</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"> &lt;option-name&gt;
+ &lt;sub-opt&gt;...&amp;lt;...&amp;gt;...&lt;/sub-opt&gt;
+ &lt;/option-name&gt;
+</pre>
+ <p class="noindent">yielding an <code>option-name.sub-opt</code> string value of
+<pre class="example"> "...&lt;...&gt;..."
+</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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-Usage">ntp-keygen Usage</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-config">ntp-keygen config</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-Notes">ntp-keygen Notes</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-exit-status">ntp-keygen exit status</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#ntp_002dkeygen-Bugs">ntp-keygen Bugs</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-Usage">ntp-keygen Usage</a>,
+Up:&nbsp;<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:&nbsp;<a rel="previous" accesskey="p" href="#ntp_002dkeygen-Notes">ntp-keygen Notes</a>,
+Up:&nbsp;<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:&nbsp;<a rel="next" accesskey="n" href="#Cryptographic-Data-Files">Cryptographic Data Files</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Running-the-Program">Running the Program</a>,
+Up:&nbsp;<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:&nbsp;<a rel="previous" accesskey="p" href="#Random-Seed-File">Random Seed File</a>,
+Up:&nbsp;<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:&gt;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&gt;O"y"LmCRS!*bHC # MD5 key
+ 6 MD5 "&gt;e\A # MD5 key
+ 7 MD5 c9x=M'CfLxax9v)PV-si # MD5 key
+ 8 MD5 E|=jvFVov?Bn|Ev=&amp;aK\ # MD5 key
+ 9 MD5 T!c4UT&amp;`(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