ntp_request.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright (c) 1996 by Sun Microsystems, Inc.
* All Rights Reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ntp_request.c - respond to information requests
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_request.h"
#include "ntp_control.h"
#include "ntp_refclock.h"
#include "ntp_if.h"
#include "ntp_stdlib.h"
#ifdef KERNEL_PLL
# ifdef NTP_SYSCALLS_STD
# else /* NOT NTP_SYSCALLS_STD */
# ifdef HAVE___NTP_GETTIME
# define ntp_gettime(t) __ntp_gettime((t))
# endif
# ifdef HAVE___ADJTIMEX
# define ntp_adjtime(t) __adjtimex((t))
# endif
# endif /* NOT NTP_SYSCALLS_STD */
#endif /* KERNEL_PLL */
/*
* Structure to hold request procedure information
*/
#define NOAUTH 0
#define AUTH 1
#define NO_REQUEST (-1)
struct req_proc {
short request_code; /* defined request code */
short needs_auth; /* true when authentication needed */
short sizeofitem; /* size of request data item */
struct req_pkt *)); /* routine to handle request */
};
/*
* Universal request codes
*/
static struct req_proc univ_codes[] = {
{ NO_REQUEST, NOAUTH, 0, 0 }
};
static char * more_pkt P((void));
static void flush_pkt P((void));
static void reset_auth_stats P((void));
#ifdef KERNEL_PLL
#endif /* KERNEL_PLL */
#ifdef REFCLOCK
#endif /* REFCLOCK */
#ifdef REFCLOCK
#endif /* REFCLOCK */
/*
* Xntpd request codes
*/
static struct req_proc xntp_codes[] = {
#ifdef KERNEL_PLL
#endif
#ifdef REFCLOCK
#endif
{ NO_REQUEST, NOAUTH, 0, 0 }
};
/*
* Authentication keyid used to authenticate requests. Zero means we
* don't allow writing anything.
*/
/*
* Statistic counters to keep track of requests and responses.
*/
/* by the error code */
/*
* Imported from the I/O module
*/
extern struct interface *any_interface;
/*
* Imported from the main routines
*/
extern int debug;
/*
* Imported from the timer module
*/
extern u_long current_time;
/*
* Imported from ntp_loopfilter.c
*/
extern int pll_control;
extern int pll_enable;
extern int pps_control;
extern int pps_enable;
/*
* Imported from ntp_monitor.c
*/
extern int mon_enabled;
/*
* Imported from ntp_util.c
*/
extern int stats_control;
#ifdef NTP_SYSCALLS_STD
# ifdef DECL_SYSCALL
extern int syscall P((int, void *, ...));
# endif /* DECL_SYSCALL */
#endif /* NTP_SYSCALLS_STD */
/*
* A hack. To keep the authentication module clear of xntp-ism's, we
* include a time reset variable for its stats here.
*/
static u_long auth_timereset;
/*
* Response packet used by these routines. Also some state information
* so that we can handle packet formatting within a common set of
* subroutines. Note we try to enter data in place whenever possible,
* but the need to set the more bit correctly means we occasionally
* use the extra buffer and copy.
*/
static int seqno;
static int nitems;
static int itemsize;
static int databytes;
static char exbuf[RESP_DATA_SIZE];
static int usingexbuf;
static struct sockaddr_in *toaddr;
/*
* init_request - initialize request data
*/
void
{
int i;
numrequests = 0;
numresppkts = 0;
auth_timereset = 0;
info_auth_keyid = 0; /* by default, can't do this */
for (i = 0; i < sizeof(errorcounter)/sizeof(errorcounter[0]); i++)
errorcounter[i] = 0;
}
/*
* req_ack - acknowledge request with no data
*/
static void
struct sockaddr_in *srcadr;
int errcode;
{
/*
* fill in the fields
*/
/*
* send packet and bump counters
*/
errorcounter[errcode]++;
}
/*
* prepare_pkt - prepare response packet for transmission, return pointer
* to storage for data item.
*/
static char *
struct sockaddr_in *srcadr;
{
#ifdef DEBUG
if (debug > 3)
printf("request: preparing pkt\n");
#endif
/*
* Fill in the implementation, reqest and itemsize fields
* since these won't change.
*/
/*
* Compute the static data needed to carry on.
*/
seqno = 0;
nitems = 0;
databytes = 0;
usingexbuf = 0;
/*
* return the beginning of the packet buffer.
*/
}
/*
* more_pkt - return a data pointer for a new item.
*/
static char *
more_pkt()
{
/*
* If we were using the extra buffer, send the packet.
*/
if (usingexbuf) {
#ifdef DEBUG
if (debug > 2)
printf("request: sending pkt\n");
#endif
numresppkts++;
/*
* Copy data out of exbuf into the packet.
*/
seqno++;
databytes = 0;
nitems = 0;
usingexbuf = 0;
}
nitems++;
#ifdef DEBUG
if (debug > 3)
printf("request: giving him more data\n");
#endif
/*
* More room in packet. Give him the
* next address.
*/
} else {
/*
* No room in packet. Give him the extra
* buffer unless this was the last in the sequence.
*/
#ifdef DEBUG
if (debug > 3)
printf("request: into extra buffer\n");
#endif
return (char *)0;
else {
usingexbuf = 1;
return exbuf;
}
}
}
/*
* flush_pkt - we're done, return remaining information.
*/
static void
{
#ifdef DEBUG
if (debug > 2)
#endif
/*
* Must send the last packet. If nothing in here and nothing
* has been sent, send an error saying no data to be found.
*/
else {
numresppkts++;
}
}
/*
* process_private - process private mode (7) packets
*/
void
int mod_okay;
{
struct sockaddr_in *srcadr;
/*
* Initialize pointers, for convenience
*/
#ifdef DEBUG
if (debug > 2)
printf("prepare_pkt: impl %d req %d\n",
#endif
/*
* Do some sanity checks on the packet. Return a format
* error if it fails.
*/
return;
}
/*
* Get the appropriate procedure list to search.
*/
proc = univ_codes;
proc = xntp_codes;
else {
return;
}
/*
* Search the list for the request codes. If it isn't one
* we know, return an error.
*/
break;
proc++;
}
return;
}
#ifdef DEBUG
if (debug > 3)
printf("found request in tables\n");
#endif
/*
* If we need to authenticate, do so. Note that an
* authenticatable packet must include a mac field, must
* have used key info_auth_keyid and must have included
* a time stamp in the appropriate field. The time stamp
* must be within INFO_TS_MAXSKEW of the receive
* time stamp.
*/
if (proc->needs_auth) {
/*
* If this guy is restricted from doing this, don't let him
* If wrong key was used, or packet doesn't have mac, return.
*/
#ifdef DEBUG
if (debug > 4)
printf("failed auth %d info_auth_keyid %lu pkt keyid %lu\n",
#endif
return;
}
#ifdef DEBUG
if (debug > 4)
printf("bad pkt length %d\n",
rbufp->recv_length);
#endif
return;
}
#ifdef DEBUG
if (debug > 4)
#endif
return;
}
/*
* calculate absolute time difference between xmit time stamp
* and receive time stamp. If too large, too bad.
*/
/*
* He's a loser. Tell him.
*/
return;
}
/*
* So far so good. See if decryption works out okay.
*/
REQ_LEN_NOMAC)) {
return;
}
}
/*
* If we need data, check to see if we have some. If we
* don't, check to see that there is none (picky, picky).
*/
return;
}
if (proc->sizeofitem != 0)
return;
}
#ifdef DEBUG
if (debug > 3)
printf("process_private: all okay, into handler\n");
#endif
/*
* Packet is okay. Call the handler to send him data.
*/
}
/*
* peer_list - send a list of the peers
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_peer_list *ip;
register int i;
sizeof(struct info_peer_list));
}
}
flush_pkt();
}
/*
* peer_list_sum - return extended peer list
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_peer_summary *ips;
register int i;
#ifdef DEBUG
if (debug > 2)
printf("wants peer list summary\n");
#endif
sizeof(struct info_peer_summary));
#ifdef DEBUG
if (debug > 3)
printf("sum: got one\n");
#endif
pp->cast_flags ?
1 : 5;
}
}
flush_pkt();
}
/*
* peer_info - send information for one or more peers
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_peer_list *ipl;
register int items;
register int i, j;
struct sockaddr_in addr;
sizeof(struct info_peer));
ipl++;
continue;
pp->cast_flags ?
2 : 6;
for (i = 0; i < NTP_SHIFT; i++, j--) {
if (j < 0)
j = NTP_SHIFT-1;
- pp->filter_order[i];
}
}
flush_pkt();
}
/*
* peer_stats - send statistics for one or more peers
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_peer_list *ipl;
register struct info_peer_stats *ip;
register int items;
struct sockaddr_in addr;
sizeof(struct info_peer_stats));
ipl++;
continue;
pp->cast_flags ?
3 : 7;
}
flush_pkt();
}
/*
* sys_info - return system info
*/
static void
struct sockaddr_in *srcadr;
{
/*
* Importations from the protocol module
*/
extern u_char sys_stratum;
extern s_char sys_precision;
extern s_fp sys_rootdelay;
extern u_fp sys_rootdispersion;
extern l_fp sys_reftime;
extern int sys_bclient;
extern s_fp sys_bdelay;
extern int sys_authenticate;
extern l_fp sys_authdelay;
extern u_fp clock_stability;
extern s_fp clock_frequency;
sizeof(struct info_sys));
if (sys_peer != 0) {
} else {
}
if (sys_bclient)
if (sys_authenticate)
if (pll_enable)
if (pps_enable)
if (pll_control)
if (pps_control)
if (mon_enabled != MON_OFF)
if (stats_control)
(void) more_pkt();
flush_pkt();
}
/*
* sys_stats - return system statistics
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_sys_stats *ss;
/*
* Importations from the protocol module
*/
extern u_long sys_stattime;
extern u_long sys_badstratum;
extern u_long sys_oldversionpkt;
extern u_long sys_newversionpkt;
extern u_long sys_unknownversion;
extern u_long sys_badlength;
extern u_long sys_processed;
extern u_long sys_badauth;
extern u_long sys_limitrejected;
sizeof(struct info_sys_stats));
(void) more_pkt();
flush_pkt();
}
/*
* mem_stats - return memory statistics
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_mem_stats *ms;
register int i;
/*
* Importations from the peer module
*/
extern int peer_hash_count[HASH_SIZE];
extern int peer_free_count;
extern u_long peer_timereset;
extern u_long findpeer_calls;
extern u_long peer_allocations;
extern u_long peer_demobilizations;
extern int total_peer_structs;
sizeof(struct info_mem_stats));
for (i = 0; i < HASH_SIZE; i++) {
if (peer_hash_count[i] > 255)
else
}
(void) more_pkt();
flush_pkt();
}
/*
* io_stats - return io statistics
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_io_stats *io;
/*
* Importations from the io module
*/
extern u_long io_timereset;
volatile extern u_long full_recvbufs;
volatile extern u_long free_recvbufs;
extern u_long total_recvbufs;
extern u_long lowater_additions;
volatile extern u_long packets_dropped;
volatile extern u_long packets_ignored;
volatile extern u_long packets_received;
extern u_long packets_sent;
extern u_long packets_notsent;
volatile extern u_long handler_calls;
volatile extern u_long handler_pkts;
sizeof(struct info_io_stats));
(void) more_pkt();
flush_pkt();
}
/*
* timer_stats - return timer statistics
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_timer_stats *ts;
/*
* Importations from the timer module
*/
extern u_long alarm_overflow;
extern u_long timer_timereset;
extern u_long timer_overflows;
extern u_long timer_xmtcalls;
sizeof(struct info_timer_stats));
(void) more_pkt();
flush_pkt();
}
/*
* loop_info - return the current state of the loop filter
*/
static void
struct sockaddr_in *srcadr;
{
/*
* Importations from the loop filter module
*/
extern l_fp last_offset;
extern s_fp drift_comp;
extern int tc_counter;
sizeof(struct info_loop));
(void) more_pkt();
flush_pkt();
}
/*
* do_conf - add a peer to the configuration list
*/
static void
struct sockaddr_in *srcadr;
{
register int items;
struct sockaddr_in peeraddr;
int fl;
/*
* Do a check of everything to see that it looks
* okay. If not, complain about it. Note we are
* very picky here.
*/
fl = 0;
fl = 1;
fl = 1;
fl = 1;
cp++;
}
if (fl) {
return;
}
/*
* Looks okay, try it out
*/
/*
* Make sure the address is valid
*/
#ifdef REFCLOCK
#else
#endif
return;
}
while (items-- > 0) {
fl = 0;
fl |= FLAG_AUTHENABLE;
fl |= FLAG_PREFER;
return;
}
cp++;
}
}
/*
* do_unconf - remove a peer from the configuration list
*/
static void
struct sockaddr_in *srcadr;
{
register struct conf_unpeer *cp;
register int items;
struct sockaddr_in peeraddr;
/*
* This is a bit unstructured, but I like to be careful.
* We check to see that every peer exists and is actually
* configured. If so, we remove them. If not, we return
* an error.
*/
bad = 0;
found = 0;
while (!found) {
break;
found = 1;
}
if (!found)
bad = 1;
cp++;
}
if (bad) {
return;
}
/*
* Now do it in earnest.
*/
while (items-- > 0) {
cp++;
}
}
/*
* set_sys_flag - set system flags
*/
static void
struct sockaddr_in *srcadr;
{
}
/*
* clr_sys_flag - clear system flags
*/
static void
struct sockaddr_in *srcadr;
{
}
/*
*/
static void
struct sockaddr_in *srcadr;
{
return;
}
SYS_FLAG_FILEGEN)) {
return;
}
if (flags & SYS_FLAG_BCLIENT)
if (flags & SYS_FLAG_AUTHENTICATE)
if (flags & SYS_FLAG_PLL)
if (flags & SYS_FLAG_PPS)
if (flags & SYS_FLAG_MONITOR)
if (flags & SYS_FLAG_FILEGEN)
}
/*
* list_restrict - return the restrict list
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_restrict *ir;
register struct restrictlist *rl;
extern struct restrictlist *restrictlist;
#ifdef DEBUG
if (debug > 2)
printf("wants peer list summary\n");
#endif
sizeof(struct info_restrict));
}
flush_pkt();
}
/*
* do_resaddflags - add flags to a restrict entry (or create one)
*/
static void
struct sockaddr_in *srcadr;
{
}
/*
* do_ressubflags - remove flags from a restrict entry
*/
static void
struct sockaddr_in *srcadr;
{
}
/*
* do_unrestrict - remove a restrict entry from the list
*/
static void
struct sockaddr_in *srcadr;
{
}
/*
* do_restrict - do the dirty stuff of dealing with restrictions
*/
static void
struct sockaddr_in *srcadr;
int op;
{
register struct conf_restrict *cr;
register int items;
struct sockaddr_in matchaddr;
struct sockaddr_in matchmask;
int bad;
/*
* Do a check of the flags to make sure that only
* the NTPPORT flag is set, if any. If not, complain
* about it. Note we are very picky here.
*/
bad = 0;
bad = 1;
bad = 1;
bad = 1;
cr++;
}
if (bad) {
return;
}
/*
* Looks okay, try it out
*/
while (items-- > 0) {
cr++;
}
}
/*
* mon_getlist - return monitor data
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_monitor *im;
extern struct mon_data mon_mru_list;
extern int mon_enabled;
#ifdef DEBUG
if (debug > 2)
printf("wants monitor 0 list\n");
#endif
if (!mon_enabled) {
return;
}
sizeof(struct info_monitor));
else
}
flush_pkt();
}
/*
* mon_getlist - return monitor data
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_monitor_1 *im;
extern struct mon_data mon_mru_list;
extern int mon_enabled;
#ifdef DEBUG
if (debug > 2)
printf("wants monitor 1 list\n");
#endif
if (!mon_enabled) {
return;
}
sizeof(struct info_monitor_1));
else
: (md->cast_flags
)
: 4);
}
flush_pkt();
}
/*
* Module entry points and the flags they correspond with
*/
struct reset_entry {
int flag; /* flag this corresponds to */
void (*handler) P((void)); /* routine to handle request */
};
struct reset_entry reset_entries[] = {
{ RESET_FLAG_IO, io_clr_stats },
{ RESET_FLAG_MEM, peer_clr_stats },
{ RESET_FLAG_CTL, ctl_clr_stats },
{ 0, 0 }
};
/*
* reset_stats - reset statistic counters here and there
*/
static void
struct sockaddr_in *srcadr;
{
struct reset_entry *rent;
return;
}
if (flags & ~RESET_ALLFLAGS) {
return;
}
}
}
/*
* reset_peer - clear a peer's statistics
*/
static void
struct sockaddr_in *srcadr;
{
register struct conf_unpeer *cp;
register int items;
struct sockaddr_in peeraddr;
int bad;
/*
* We check first to see that every peer exists. If not,
* we return an error.
*/
bad = 0;
bad++;
cp++;
}
if (bad) {
return;
}
/*
* Now do it in earnest.
*/
while (items-- > 0) {
cp++;
}
}
/*
* do_key_reread - reread the encryption key file
*/
static void
struct sockaddr_in *srcadr;
{
rereadkeys();
}
/*
* trust_key - make one or more keys trusted
*/
static void
struct sockaddr_in *srcadr;
{
}
/*
* untrust_key - make one or more keys untrusted
*/
static void
struct sockaddr_in *srcadr;
{
}
/*
* do_trustkey - make keys either trustable or untrustable
*/
static void
struct sockaddr_in *srcadr;
int trust;
{
register int items;
while (items-- > 0) {
kp++;
}
}
/*
* get_auth_info - return some stats concerning the authentication module
*/
static void
struct sockaddr_in *srcadr;
{
/*
* Importations from the authentication module
*/
extern u_long authnumkeys;
extern u_long authnumfreekeys;
extern u_long authkeylookups;
extern u_long authkeynotfound;
extern u_long authencryptions;
extern u_long authdecryptions;
extern u_long authkeyuncached;
sizeof(struct info_auth));
(void) more_pkt();
flush_pkt();
}
/*
* reset_auth_stats - reset the authentication stat counters. Done here
* to keep xntp-isms out of the authentication module
*/
static void
{
/*
* Importations from the authentication module
*/
extern u_long authkeylookups;
extern u_long authkeynotfound;
extern u_long authencryptions;
extern u_long authdecryptions;
extern u_long authkeyuncached;
authkeylookups = 0;
authkeynotfound = 0;
authencryptions = 0;
authdecryptions = 0;
authkeyuncached = 0;
}
/*
* req_get_traps - return information about current trap holders
*/
static void
struct sockaddr_in *srcadr;
{
register int i;
/*
* Imported from the control module
*/
extern int num_ctl_traps;
if (num_ctl_traps == 0) {
return;
}
sizeof(struct info_trap));
it->local_address = 0;
else
}
}
flush_pkt();
}
/*
* req_set_trap - configure a trap
*/
static void
struct sockaddr_in *srcadr;
{
}
/*
* req_clr_trap - unconfigure a trap
*/
static void
struct sockaddr_in *srcadr;
{
}
/*
* do_setclr_trap - do the grunge work of (un)configuring a trap
*/
static void
struct sockaddr_in *srcadr;
int set;
{
int res;
struct sockaddr_in laddr;
/*
* Prepare sockaddr_in structure
*/
/*
* Restrict ourselves to one item only. This eliminates
* the error reporting problem.
*/
return;
}
/*
* Look for the local interface. If none, use the default.
*/
if (ct->local_address == 0) {
} else {
return;
}
}
else
if (set) {
} else {
}
if (!res) {
} else {
}
return;
}
/*
* set_request_keyid - set the keyid used to authenticate requests
*/
static void
struct sockaddr_in *srcadr;
{
/*
* Restrict ourselves to one item only.
*/
return;
}
}
/*
* set_control_keyid - set the keyid used to authenticate requests
*/
static void
struct sockaddr_in *srcadr;
{
extern u_int32 ctl_auth_keyid;
/*
* Restrict ourselves to one item only.
*/
return;
}
}
/*
* get_ctl_stats - return some stats concerning the control message module
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_control *ic;
/*
* Importations from the control module
*/
extern u_long ctltimereset;
extern u_long numctlbadpkts;
extern u_long numctlresponses;
extern u_long numctlfrags;
extern u_long numctlerrors;
extern u_long numctltooshort;
extern u_long numctlinputresp;
extern u_long numctlinputfrag;
extern u_long numctlinputerr;
extern u_long numctlbadoffset;
extern u_long numctlbadversion;
extern u_long numctldatatooshort;
extern u_long numctlbadop;
extern u_long numasyncmsgs;
sizeof(struct info_control));
(void) more_pkt();
flush_pkt();
}
/*
* get_leap_info - return some stats concerning the control message module
*/
static void
struct sockaddr_in *srcadr;
{
/*
* Imported from the protocol module
*/
/*
* Importations from the leap module
*/
extern u_char leap_indicator;
extern u_char leap_warning;
extern u_long leap_timer;
extern u_long leap_processcalls;
extern u_long leap_notclose;
extern u_long leap_monthofleap;
extern u_long leap_dayofleap;
extern u_long leap_hoursfromleap;
extern u_long leap_happened;
sizeof(struct info_leap));
(void) more_pkt();
flush_pkt();
}
#ifdef KERNEL_PLL
/*
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_kernel *ik;
if (!pll_control) {
return;
}
if (ntp_adjtime(&ntx) < 0)
{
}
sizeof(struct info_kernel));
/*
* pll variables
*/
/*
* pps variables
*/
(void) more_pkt();
flush_pkt();
}
#endif /* KERNEL_PLL */
#ifdef REFCLOCK
/*
* get_clock_info - get info about a clock
*/
static void
struct sockaddr_in *srcadr;
{
register struct info_clock *ic;
register int items;
struct refclockstat clock;
struct sockaddr_in addr;
sizeof(struct info_clock));
while (items-- > 0) {
if (!ISREFCLOCKADR(&addr) ||
return;
}
}
flush_pkt();
}
/*
* set_clock_fudge - get a clock's fudge factors
*/
static void
struct sockaddr_in *srcadr;
{
register struct conf_fudge *cf;
register int items;
struct refclockstat clock;
struct sockaddr_in addr;
while (items-- > 0) {
if (!ISREFCLOCKADR(&addr) ||
return;
}
case FUDGE_TIME1:
break;
case FUDGE_TIME2:
break;
case FUDGE_VAL1:
break;
case FUDGE_VAL2:
break;
case FUDGE_FLAGS:
break;
default:
return;
}
}
}
#endif
#ifdef REFCLOCK
/*
* get_clkbug_info - get debugging info about a clock
*/
static void
struct sockaddr_in *srcadr;
{
register int i;
register struct info_clkbug *ic;
register int items;
struct refclockbug bug;
struct sockaddr_in addr;
sizeof(struct info_clkbug));
while (items-- > 0) {
if (!ISREFCLOCKADR(&addr) ||
return;
}
return;
}
if (i > NUMCBUGVALUES)
i = NUMCBUGVALUES;
while (--i >= 0)
if (i > NUMCBUGTIMES)
i = NUMCBUGTIMES;
while (--i >= 0) {
}
}
flush_pkt();
}
#endif