From: gdt@GINGER.LCS.MIT.EDU (Greg Troxel)
Newsgroups: comp.protocols.time.ntp
Subject: Patch to xntpd to make xntpres-style config easier to deal with
Date: 6 Apr 92 19:30:28 GMT
Distribution: inet
Organization: The Internet

A major problem I have with the xntpd release is the difficulty of
managing installing it on a group of workstations.  I wish to use
symbolic names for local ntp servers, but don't want to 1) have 2
binaries on each machine and 2) have to have a key file on each
workstation.  The key file problem is actually quite serious because
using a common key file is a security problem (anyone with root on one
workstation can change the config of any workstation), and maintaining
separate ones is a pain.

The following patch merges xntpres into xntpd, so that a separate
binary is not needed.  The nature of the configuration scheme is not
changed; a separate process is still forked, and that process uses
mode 7 messages to configure peers into xntpd.

In addition, if key 65535 does not exist, it is created with a random
value, and this key is used as the request key for the mode 7 messages
sent by the xntpres routines.

If a 'resolver' line is present in the config file, the external
resolver should still be called as before.  Also, if a 'requestkey'
line appears, that key should be used for requests.  By default, key
65535 is created if it does not exist and is then used.  By default
the internal resolver is used.

I have only tried this on a Vax running BSD 4.3.  I haven't tried to
link the whole xntpd and run it with RESOLVE_INTERNAL turned off.  I
didn't bother making this a Config option, since I don't think anyone
would ever not want it (gizmos aside).

Bug reports about this patch can be sent to <gdt@lcs.mit.edu>.  As
usual, I make no promises that I will fix any of them.

The configuration should probably be done more simply, with a unix
pipe and a lot less hair, but it was easier for me to make the changes
I did rather than re-engineer the entire configuration process.  I
have not removed support for an external resolver, but I think this is

	Greg Troxel, N1DAM
	MIT Laboratory for Computer Science
	<gdt@lcs.mit.edu>


---------------------------------------------------------------------------
First, execute the following command (from the top-level source
directory).  Then, run 'patch -p', with the rest of the file as input.
You will need to 'make makefiles' as well; this patch creates an
additional source file.

cp xntpres/xntpres.c xntpd/ntp_intres.c

*** xntpd-dist/ntp_config.c	Mon Apr  6 14:38:48 1992
--- xntpd/ntp_config.c	Mon Apr  6 14:38:58 1992
***************
*** 15,20 ****
--- 15,26 ----
  #include "ntp.h"
  #include "ntp_refclock.h"
  
+ #define RESOLVE_INTERNAL	/* gdt */
+ 
+ #ifdef RESOLVE_INTERNAL
+ #include  <sys/time.h>
+ #endif
+ 
  /*
   * These routines are used to read the configuration file at
   * startup time.  An entry in the file must fit on a single line.
***************
*** 311,316 ****
--- 317,325 ----
  	char *config_file;
  	struct refclockstat clock;
  	int have_resolver;
+ #ifdef RESOLVE_INTERNAL
+ 	int resolve_internal;
+ #endif
  	char resolver_name[MAXFILENAME];
  	int have_keyfile;
  	char keyfile[MAXFILENAME];
***************
*** 330,335 ****
--- 339,347 ----
  	extern char *ntoa();
  	static void save_resolve();
  	static void do_resolve();
+ #ifdef RESOLVE_INTERNAL
+ 	static void do_resolve_internal();
+ #endif
  	static void abort_resolve();
  	extern u_long info_auth_keyid;
  
***************
*** 345,350 ****
--- 357,366 ----
  	res_fp = NULL;
  	have_resolver = have_keyfile = 0;
  
+ #ifdef RESOLVE_INTERNALR
+ 	resolve_internal = 1;
+ #endif
+ 
  	/*
  	 * Decode argument list
  	 */
***************
*** 1058,1063 ****
--- 1074,1082 ----
  				}
  				strcpy(resolver_name, tokens[1]);
  				have_resolver = 1;
+ #ifdef RESOLVE_INTERNAL
+ 				resolve_internal = 0;
+ #endif
  			}
  			break;
  
***************
*** 1082,1087 ****
--- 1101,1113 ----
  		 * Need name resolution
  		 */
  		errflg = 0;
+ #ifdef RESOLVE_INTERNAL
+ 		if (  resolve_internal )
+ 		    do_resolve_internal();
+ 		else
+ 		  {
+ #endif
+ 
  		if (info_auth_keyid == 0) {
  			syslog(LOG_ERR,
  		"no request key defined, peer name resolution not possible");
***************
*** 1099,1107 ****
--- 1125,1137 ----
  		}
  
  		if (!errflg)
+ 
  			do_resolve(resolver_name, info_auth_keyid, keyfile);
  		else
  			abort_resolve();
+ #ifdef  RESOLVE_INTERNAL
+ 	      }
+ #endif
  	}
  }
  
***************
*** 1426,1428 ****
--- 1456,1542 ----
  		abort_resolve();
  	}
  }
+ 
+ 
+ #ifdef RESOLVE_INTERNAL
+ 
+ #define	KEY_TYPE_ASCII	3
+ 
+ /*
+  * do_resolve_internal - start up the resolver function (not program)
+  */
+ static void
+ do_resolve_internal()
+ {
+   int i;
+ 
+   extern u_long req_keyid;	/* request keyid */
+   extern char *req_file;	/* name of the file with configuration info */
+ 
+   extern u_long info_auth_keyid;
+ 
+ 
+   extern int authusekey();
+ 
+   if (res_fp == NULL) {
+     /* belch */
+     syslog(LOG_ERR, "internal error in do_resolve_internal: res_fp == NULL");
+     exit(1);
+   }
+ 
+   /* we are done with this now */
+   (void) fclose(res_fp);
+   res_fp = NULL;
+ 
+   /* find a keyid */
+   req_keyid = 65535;
+ 
+   /* if doesn't exist, make up one at random */
+   if ( ! authhavekey(req_keyid) )
+     {
+       char rankey[9];
+       struct timeval now;
+       extern long random();
+ 
+       /* generate random key */
+       gettimeofday(&now);
+       srandom(now.tv_sec * now.tv_usec);
+ 
+       for ( i = 0; i < 8; i++ )
+ 	rankey[i] = (random() % 255) + 1;
+       rankey[8] = 0;
+ 
+       authusekey(req_keyid, KEY_TYPE_ASCII, rankey);
+     }
+ 
+   /* save keyid so we will accept config requests with it */
+   info_auth_keyid = req_keyid;
+ 
+   req_file = res_file;	/* set up pointer to res file */
+ 
+   (void) signal(SIGCHLD, catchchild);
+ 
+   i = fork();
+   if (i == 0) {
+     /* this used to close everything
+      * I don't think this is necessary */
+     (void) signal(SIGCHLD, SIG_DFL);
+ 
+     ntp_intres();
+ 
+     /*
+      * If we got here, the intres code screwed up.
+      * Print something so we don't die without complaint
+      */
+     syslog(LOG_ERR, "call to ntp_intres lost");
+     abort_resolve();
+     exit(1);
+   }
+ 
+   if (i == -1) {
+     syslog(LOG_ERR, "fork() failed, can't start ntp_intres");
+     (void) signal(SIGCHLD, SIG_DFL);
+     abort_resolve();
+   }
+ }
+ #endif

*** xntpd-dist/ntp_intres.c	Mon Apr  6 14:42:11 1992
--- xntpd/ntp_intres.c	Thu Apr  2 16:38:51 1992
***************
*** 1,3 ****
--- 1,9 ----
+ /* 
+  * ripped off from ../xnptres/xntpres.c by gdt 4/2/92
+  * routine callable from xntpd, rather than separate program
+  * also, key info passed in via a global, so no key file needed.
+  */
+ 
  /*
   * xntpres - process configuration entries which require use of the resolver
   *
***************
*** 8,16 ****
   * better than this).  Also might provide some ideas about how one
   * might go about autoconfiguring an NTP distribution network.
   *
-  * Usage is:
-  *   xntpres [-d] [-r] keyid keyfile configuration_data
   */
  #include <stdio.h>
  #include <strings.h>
  #include <ctype.h>
--- 14,21 ----
   * better than this).  Also might provide some ideas about how one
   * might go about autoconfiguring an NTP distribution network.
   *
   */
+ 
  #include <stdio.h>
  #include <strings.h>
  #include <ctype.h>
***************
*** 115,233 ****
   */
  int sockfd = -1;
  
! /*
!  * Misc. data from argument processing
!  */
! int removefile = 0;	/* remove configuration file when done */
  
  u_long req_keyid;	/* request keyid */
! char *keyfile;		/* file where keys are kept */
! char *conffile;		/* name of the file with configuration info */
  
! char *progname;
! int debug = 0;
! extern char *Version;
  extern int errno;
  
  /*
!  * main - parse arguments and handle options
   */
! main(argc, argv)
! 	int argc;
! 	char *argv[];
  {
  	int c;
  	int errflg = 0;
  	char *cp;
  	FILE *in;
- 	extern int optind;
- 	extern char *optarg;
- 	extern char *rindex();
  	void bong();
  	void readconf();
  	void doconfigure();
  	void checkparent();
  
! 	progname = argv[0];
! 
! 	/*
! 	 * Better get syslog open early since stderr messages are likely
! 	 * ending up in the twilight zone
! 	 */
! 	cp = rindex(argv[0], '/');
! 	if (cp == 0)
! 		cp = argv[0];
! 	else
! 		cp++;
! 
! #ifndef	LOG_DAEMON
! 	openlog(cp, LOG_PID);
! #else
! 
! #ifndef	LOG_NTP
! #define	LOG_NTP	LOG_DAEMON
! #endif
! 	openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
! #ifdef	DEBUG
! 	if (debug)
! 		setlogmask(LOG_UPTO(LOG_DEBUG));
! 	else
! #endif	/* DEBUG */
! 		setlogmask(LOG_UPTO(LOG_INFO));
! #endif	/* LOG_DAEMON */
! 
! 	syslog(LOG_INFO, Version);
! 
! 	while ((c = getopt(argc, argv, "dr")) != EOF)
! 		switch (c) {
! 		case 'd':
! 			++debug;
! 			break;
! 		case 'r':
! 			++removefile;
! 			break;
! 		default:
! 			errflg++;
! 			break;
! 		}
! 	if (errflg || (optind + 3) != argc) {
! 		(void) fprintf(stderr,
! 		    "usage: %s [-d] [-r] keyid keyfile conffile\n", progname);
! 		syslog(LOG_ERR, "exiting due to usage error");
! 		exit(2);
! 	}
! 
! 	if (!atouint(argv[optind], &req_keyid)) {
! 		syslog(LOG_ERR, "undecodeable keyid %s", argv[optind]);
! 		exit(1);
! 	}
  
- 	keyfile = argv[optind+1];
- 	conffile = argv[optind+2];
  
! 	/*
! 	 * Make sure we have the key we need
! 	 */
! 	if (!authreadkeys(keyfile))
! 		exit(1);
  	if (!authhavekey(req_keyid)) {
! 		syslog(LOG_ERR, "request keyid %lu not found in %s",
! 		    req_keyid, keyfile);
  		exit(1);
  	}
  
  	/*
  	 * Read the configuration info
  	 */
! 	if ((in = fopen(conffile, "r")) == NULL) {
  		syslog(LOG_ERR, "can't open configuration file %s: %m",
! 		    conffile);
  		exit(1);
  	}
! 	readconf(in, conffile);
  	(void) fclose(in);
! 	if (removefile)
! 		(void) unlink(conffile);
  
  	/*
  	 * Sleep a little to make sure the server is completely up
--- 120,178 ----
   */
  int sockfd = -1;
  
! 
! /* stuff to be filled in by caller */
  
  u_long req_keyid;	/* request keyid */
! char *req_file;		/* name of the file with configuration info */
  
! /* end stuff to be filled in */
! 
! 
! extern int debug;		/* use global debug flag */
  extern int errno;
  
  /*
!  * assumes:  req_key, req_keyid, conffile valid
!  *  syslog still open
   */
! ntp_intres()
  {
  	int c;
  	int errflg = 0;
  	char *cp;
  	FILE *in;
  	void bong();
  	void readconf();
  	void doconfigure();
  	void checkparent();
  
! 	if ( debug )
! 	  syslog(LOG_INFO, "ntp_intres running");
  
  
! 	/* check out auth stuff */
  	if (!authhavekey(req_keyid)) {
! 		syslog(LOG_ERR, "request keyid %lu not found",
! 		    req_keyid );
  		exit(1);
  	}
  
  	/*
  	 * Read the configuration info
+ 	 * {this is bogus, since we are forked, but it is easier
+ 	 * to keep this code - gdt}
  	 */
! 	if ((in = fopen(req_file, "r")) == NULL) {
  		syslog(LOG_ERR, "can't open configuration file %s: %m",
! 		    req_file);
  		exit(1);
  	}
! 	readconf(in, req_file);
  	(void) fclose(in);
! 
! 	if ( ! debug )
! 		(void) unlink(req_file);
  
  	/*
  	 * Sleep a little to make sure the server is completely up

*** xntpd-dist/Makefile.tmpl	Mon Apr  6 15:15:05 1992
--- xntpd/Makefile.tmpl	Thu Apr  2 16:15:08 1992
***************
*** 24,30 ****
  	ntp_refclock.c ntp_request.c ntp_restrict.c ntp_timer.c \
  	ntp_unixclock.c ntp_util.c ntpd.c refclock_chu.c \
  	refclock_conf.c refclock_local.c refclock_pst.c \
! 	refclock_wwvb.c refclock_wwvb_hp.c
  
  OBJS=	ntp_config.o ntp_control.o ntp_io.o ntp_leap.o \
  	ntp_loopfilter.o ntp_monitor.o ntp_peer.o ntp_proto.o \
--- 24,30 ----
  	ntp_refclock.c ntp_request.c ntp_restrict.c ntp_timer.c \
  	ntp_unixclock.c ntp_util.c ntpd.c refclock_chu.c \
  	refclock_conf.c refclock_local.c refclock_pst.c \
! 	refclock_wwvb.c refclock_wwvb_hp.c ntp_intres.c
  
  OBJS=	ntp_config.o ntp_control.o ntp_io.o ntp_leap.o \
  	ntp_loopfilter.o ntp_monitor.o ntp_peer.o ntp_proto.o \
***************
*** 31,37 ****
  	ntp_refclock.o ntp_request.o ntp_restrict.o ntp_timer.o \
  	ntp_unixclock.o ntp_util.o ntpd.o refclock_chu.o \
  	refclock_conf.o refclock_local.o refclock_pst.o \
! 	refclock_wwvb.o refclock_wwvb_hp.o
  
  all:	$(PROGRAM)
  
--- 31,37 ----
  	ntp_refclock.o ntp_request.o ntp_restrict.o ntp_timer.o \
  	ntp_unixclock.o ntp_util.o ntpd.o refclock_chu.o \
  	refclock_conf.o refclock_local.o refclock_pst.o \
! 	refclock_wwvb.o refclock_wwvb_hp.o ntp_intres.o
  
  all:	$(PROGRAM)
  
Newsgroups: comp.protocols.time.ntp