154359Sroberto/* 254359Sroberto * ntp_control.c - respond to control messages and send async traps 354359Sroberto */ 475202Sphk 575202Sphk/* 675202Sphk * $FreeBSD$ 775202Sphk */ 875202Sphk 954359Sroberto#ifdef HAVE_CONFIG_H 1054359Sroberto#include <config.h> 1154359Sroberto#endif 1254359Sroberto 1354359Sroberto#include "ntpd.h" 1454359Sroberto#include "ntp_io.h" 1554359Sroberto#include "ntp_refclock.h" 1654359Sroberto#include "ntp_control.h" 17182007Sroberto#include "ntp_unixtime.h" 1854359Sroberto#include "ntp_stdlib.h" 1954359Sroberto 2082502Sroberto#include <stdio.h> 2182502Sroberto#include <ctype.h> 2282502Sroberto#include <signal.h> 2382502Sroberto 2482502Sroberto#include <netinet/in.h> 2582502Sroberto#include <arpa/inet.h> 2682502Sroberto 27276158Sdes#ifndef MIN 28276158Sdes#define MIN(a, b) (((a) <= (b)) ? (a) : (b)) 29276158Sdes#endif 30276158Sdes 3154359Sroberto/* 3254359Sroberto * Structure to hold request procedure information 3354359Sroberto */ 3454359Sroberto#define NOAUTH 0 3554359Sroberto#define AUTH 1 3654359Sroberto 3754359Sroberto#define NO_REQUEST (-1) 3854359Sroberto 3954359Srobertostruct ctl_proc { 4082502Sroberto short control_code; /* defined request code */ 4182502Sroberto u_short flags; /* flags word */ 4282502Sroberto void (*handler) P((struct recvbuf *, int)); /* handle request */ 4354359Sroberto}; 4454359Sroberto 4554359Sroberto/* 4654359Sroberto * Only one flag. Authentication required or not. 4754359Sroberto */ 4854359Sroberto#define NOAUTH 0 4954359Sroberto#define AUTH 1 5054359Sroberto 5154359Sroberto/* 5254359Sroberto * Request processing routines 5354359Sroberto */ 5454359Srobertostatic void ctl_error P((int)); 55132455Sroberto#ifdef REFCLOCK 5654359Srobertostatic u_short ctlclkstatus P((struct refclockstat *)); 57132455Sroberto#endif 5854359Srobertostatic void ctl_flushpkt P((int)); 5954359Srobertostatic void ctl_putdata P((const char *, unsigned int, int)); 6082502Srobertostatic void ctl_putstr P((const char *, const char *, 6182502Sroberto unsigned int)); 6254359Srobertostatic void ctl_putdbl P((const char *, double)); 6382502Srobertostatic void ctl_putuint P((const char *, u_long)); 6454359Srobertostatic void ctl_puthex P((const char *, u_long)); 6554359Srobertostatic void ctl_putint P((const char *, long)); 6654359Srobertostatic void ctl_putts P((const char *, l_fp *)); 67132455Srobertostatic void ctl_putadr P((const char *, u_int32, struct sockaddr_storage*)); 6854359Srobertostatic void ctl_putid P((const char *, char *)); 6954359Srobertostatic void ctl_putarray P((const char *, double *, int)); 7054359Srobertostatic void ctl_putsys P((int)); 7182502Srobertostatic void ctl_putpeer P((int, struct peer *)); 72182007Sroberto#ifdef OPENSSL 73182007Srobertostatic void ctl_putfs P((const char *, tstamp_t)); 74182007Sroberto#endif 7554359Sroberto#ifdef REFCLOCK 7654359Srobertostatic void ctl_putclock P((int, struct refclockstat *, int)); 7754359Sroberto#endif /* REFCLOCK */ 7854359Srobertostatic struct ctl_var *ctl_getitem P((struct ctl_var *, char **)); 7982502Srobertostatic u_long count_var P((struct ctl_var *)); 8054359Srobertostatic void control_unspec P((struct recvbuf *, int)); 8182502Srobertostatic void read_status P((struct recvbuf *, int)); 8254359Srobertostatic void read_variables P((struct recvbuf *, int)); 8354359Srobertostatic void write_variables P((struct recvbuf *, int)); 8482502Srobertostatic void read_clock_status P((struct recvbuf *, int)); 8582502Srobertostatic void write_clock_status P((struct recvbuf *, int)); 8654359Srobertostatic void set_trap P((struct recvbuf *, int)); 8754359Srobertostatic void unset_trap P((struct recvbuf *, int)); 88132455Srobertostatic struct ctl_trap *ctlfindtrap P((struct sockaddr_storage *, 8982502Sroberto struct interface *)); 9054359Sroberto 9154359Srobertostatic struct ctl_proc control_codes[] = { 9254359Sroberto { CTL_OP_UNSPEC, NOAUTH, control_unspec }, 9354359Sroberto { CTL_OP_READSTAT, NOAUTH, read_status }, 9454359Sroberto { CTL_OP_READVAR, NOAUTH, read_variables }, 9554359Sroberto { CTL_OP_WRITEVAR, AUTH, write_variables }, 9654359Sroberto { CTL_OP_READCLOCK, NOAUTH, read_clock_status }, 9754359Sroberto { CTL_OP_WRITECLOCK, NOAUTH, write_clock_status }, 9854359Sroberto { CTL_OP_SETTRAP, NOAUTH, set_trap }, 9954359Sroberto { CTL_OP_UNSETTRAP, NOAUTH, unset_trap }, 10054359Sroberto { NO_REQUEST, 0 } 10154359Sroberto}; 10254359Sroberto 10354359Sroberto/* 10482502Sroberto * System variable values. The array can be indexed by the variable 10582502Sroberto * index to find the textual name. 10654359Sroberto */ 10782502Srobertostatic struct ctl_var sys_var[] = { 10854359Sroberto { 0, PADDING, "" }, /* 0 */ 10954359Sroberto { CS_LEAP, RW, "leap" }, /* 1 */ 11054359Sroberto { CS_STRATUM, RO, "stratum" }, /* 2 */ 11154359Sroberto { CS_PRECISION, RO, "precision" }, /* 3 */ 11254359Sroberto { CS_ROOTDELAY, RO, "rootdelay" }, /* 4 */ 11354359Sroberto { CS_ROOTDISPERSION, RO, "rootdispersion" }, /* 5 */ 11454359Sroberto { CS_REFID, RO, "refid" }, /* 6 */ 11554359Sroberto { CS_REFTIME, RO, "reftime" }, /* 7 */ 11654359Sroberto { CS_POLL, RO, "poll" }, /* 8 */ 11754359Sroberto { CS_PEERID, RO, "peer" }, /* 9 */ 11854359Sroberto { CS_STATE, RO, "state" }, /* 10 */ 11982502Sroberto { CS_OFFSET, RO, "offset" }, /* 11 */ 12054359Sroberto { CS_DRIFT, RO, "frequency" }, /* 12 */ 12182502Sroberto { CS_JITTER, RO, "jitter" }, /* 13 */ 122182007Sroberto { CS_ERROR, RO, "noise" }, /* 14 */ 123182007Sroberto { CS_CLOCK, RO, "clock" }, /* 15 */ 124182007Sroberto { CS_PROCESSOR, RO, "processor" }, /* 16 */ 125182007Sroberto { CS_SYSTEM, RO, "system" }, /* 17 */ 126182007Sroberto { CS_VERSION, RO, "version" }, /* 18 */ 127182007Sroberto { CS_STABIL, RO, "stability" }, /* 19 */ 128182007Sroberto { CS_VARLIST, RO, "sys_var_list" }, /* 20 */ 129132455Sroberto#ifdef OPENSSL 130182007Sroberto { CS_FLAGS, RO, "flags" }, /* 21 */ 131182007Sroberto { CS_HOST, RO, "hostname" }, /* 22 */ 132182007Sroberto { CS_PUBLIC, RO, "update" }, /* 23 */ 133182007Sroberto { CS_CERTIF, RO, "cert" }, /* 24 */ 134182007Sroberto { CS_REVTIME, RO, "expire" }, /* 25 */ 135182007Sroberto { CS_LEAPTAB, RO, "leapsec" }, /* 26 */ 136182007Sroberto { CS_TAI, RO, "tai" }, /* 27 */ 137182007Sroberto { CS_DIGEST, RO, "signature" }, /* 28 */ 138182007Sroberto { CS_IDENT, RO, "ident" }, /* 29 */ 139182007Sroberto { CS_REVOKE, RO, "expire" }, /* 30 */ 140132455Sroberto#endif /* OPENSSL */ 141182007Sroberto { 0, EOV, "" } /* 21/31 */ 14254359Sroberto}; 14354359Sroberto 14482502Srobertostatic struct ctl_var *ext_sys_var = (struct ctl_var *)0; 14554359Sroberto 14654359Sroberto/* 14782502Sroberto * System variables we print by default (in fuzzball order, 14882502Sroberto * more-or-less) 14954359Sroberto */ 15054359Srobertostatic u_char def_sys_var[] = { 15182502Sroberto CS_VERSION, 15254359Sroberto CS_PROCESSOR, 15354359Sroberto CS_SYSTEM, 15454359Sroberto CS_LEAP, 15554359Sroberto CS_STRATUM, 15654359Sroberto CS_PRECISION, 15754359Sroberto CS_ROOTDELAY, 15854359Sroberto CS_ROOTDISPERSION, 15954359Sroberto CS_PEERID, 16054359Sroberto CS_REFID, 16154359Sroberto CS_REFTIME, 16254359Sroberto CS_POLL, 16354359Sroberto CS_CLOCK, 16454359Sroberto CS_STATE, 16554359Sroberto CS_OFFSET, 16654359Sroberto CS_DRIFT, 16782502Sroberto CS_JITTER, 168182007Sroberto CS_ERROR, 16954359Sroberto CS_STABIL, 170132455Sroberto#ifdef OPENSSL 171132455Sroberto CS_HOST, 172132455Sroberto CS_DIGEST, 17382502Sroberto CS_FLAGS, 174132455Sroberto CS_PUBLIC, 175182007Sroberto CS_IDENT, 17682502Sroberto CS_LEAPTAB, 177182007Sroberto CS_TAI, 178132455Sroberto CS_CERTIF, 179132455Sroberto#endif /* OPENSSL */ 18054359Sroberto 0 18154359Sroberto}; 18254359Sroberto 18354359Sroberto 18454359Sroberto/* 18554359Sroberto * Peer variable list 18654359Sroberto */ 18782502Srobertostatic struct ctl_var peer_var[] = { 18882502Sroberto { 0, PADDING, "" }, /* 0 */ 18982502Sroberto { CP_CONFIG, RO, "config" }, /* 1 */ 19082502Sroberto { CP_AUTHENABLE, RO, "authenable" }, /* 2 */ 19182502Sroberto { CP_AUTHENTIC, RO, "authentic" }, /* 3 */ 19282502Sroberto { CP_SRCADR, RO, "srcadr" }, /* 4 */ 19382502Sroberto { CP_SRCPORT, RO, "srcport" }, /* 5 */ 19482502Sroberto { CP_DSTADR, RO, "dstadr" }, /* 6 */ 19582502Sroberto { CP_DSTPORT, RO, "dstport" }, /* 7 */ 19682502Sroberto { CP_LEAP, RO, "leap" }, /* 8 */ 19782502Sroberto { CP_HMODE, RO, "hmode" }, /* 9 */ 19882502Sroberto { CP_STRATUM, RO, "stratum" }, /* 10 */ 19982502Sroberto { CP_PPOLL, RO, "ppoll" }, /* 11 */ 20082502Sroberto { CP_HPOLL, RO, "hpoll" }, /* 12 */ 20182502Sroberto { CP_PRECISION, RO, "precision" }, /* 13 */ 20282502Sroberto { CP_ROOTDELAY, RO, "rootdelay" }, /* 14 */ 20354359Sroberto { CP_ROOTDISPERSION, RO, "rootdispersion" }, /* 15 */ 20482502Sroberto { CP_REFID, RO, "refid" }, /* 16 */ 20582502Sroberto { CP_REFTIME, RO, "reftime" }, /* 17 */ 20682502Sroberto { CP_ORG, RO, "org" }, /* 18 */ 20782502Sroberto { CP_REC, RO, "rec" }, /* 19 */ 20882502Sroberto { CP_XMT, RO, "xmt" }, /* 20 */ 20982502Sroberto { CP_REACH, RO, "reach" }, /* 21 */ 210182007Sroberto { CP_UNREACH, RO, "unreach" }, /* 22 */ 21182502Sroberto { CP_TIMER, RO, "timer" }, /* 23 */ 21282502Sroberto { CP_DELAY, RO, "delay" }, /* 24 */ 21382502Sroberto { CP_OFFSET, RO, "offset" }, /* 25 */ 21482502Sroberto { CP_JITTER, RO, "jitter" }, /* 26 */ 21582502Sroberto { CP_DISPERSION, RO, "dispersion" }, /* 27 */ 21682502Sroberto { CP_KEYID, RO, "keyid" }, /* 28 */ 21782502Sroberto { CP_FILTDELAY, RO, "filtdelay=" }, /* 29 */ 21882502Sroberto { CP_FILTOFFSET, RO, "filtoffset=" }, /* 30 */ 21982502Sroberto { CP_PMODE, RO, "pmode" }, /* 31 */ 22082502Sroberto { CP_RECEIVED, RO, "received"}, /* 32 */ 22182502Sroberto { CP_SENT, RO, "sent" }, /* 33 */ 22282502Sroberto { CP_FILTERROR, RO, "filtdisp=" }, /* 34 */ 22382502Sroberto { CP_FLASH, RO, "flash" }, /* 35 */ 22482502Sroberto { CP_TTL, RO, "ttl" }, /* 36 */ 225182007Sroberto { CP_VARLIST, RO, "peer_var_list" }, /* 37 */ 226132455Sroberto#ifdef OPENSSL 227182007Sroberto { CP_FLAGS, RO, "flags" }, /* 38 */ 228182007Sroberto { CP_HOST, RO, "hostname" }, /* 39 */ 229182007Sroberto { CP_VALID, RO, "valid" }, /* 40 */ 230132455Sroberto { CP_INITSEQ, RO, "initsequence" }, /* 41 */ 231132455Sroberto { CP_INITKEY, RO, "initkey" }, /* 42 */ 232132455Sroberto { CP_INITTSP, RO, "timestamp" }, /* 43 */ 233132455Sroberto { CP_DIGEST, RO, "signature" }, /* 44 */ 234182007Sroberto { CP_IDENT, RO, "trust" }, /* 45 */ 235132455Sroberto#endif /* OPENSSL */ 236182007Sroberto { 0, EOV, "" } /* 38/46 */ 23754359Sroberto}; 23854359Sroberto 23954359Sroberto 24054359Sroberto/* 24154359Sroberto * Peer variables we print by default 24254359Sroberto */ 24382502Srobertostatic u_char def_peer_var[] = { 24454359Sroberto CP_SRCADR, 24554359Sroberto CP_SRCPORT, 24654359Sroberto CP_DSTADR, 24754359Sroberto CP_DSTPORT, 24882502Sroberto CP_LEAP, 24954359Sroberto CP_STRATUM, 25054359Sroberto CP_PRECISION, 25154359Sroberto CP_ROOTDELAY, 25254359Sroberto CP_ROOTDISPERSION, 25354359Sroberto CP_REFID, 25454359Sroberto CP_REACH, 255182007Sroberto CP_UNREACH, 25654359Sroberto CP_HMODE, 25754359Sroberto CP_PMODE, 25854359Sroberto CP_HPOLL, 25954359Sroberto CP_PPOLL, 26054359Sroberto CP_FLASH, 26182502Sroberto CP_KEYID, 26282502Sroberto CP_TTL, 26382502Sroberto CP_OFFSET, 26482502Sroberto CP_DELAY, 26582502Sroberto CP_DISPERSION, 26682502Sroberto CP_JITTER, 26782502Sroberto CP_REFTIME, 26854359Sroberto CP_ORG, 26954359Sroberto CP_REC, 27054359Sroberto CP_XMT, 27154359Sroberto CP_FILTDELAY, 27254359Sroberto CP_FILTOFFSET, 27354359Sroberto CP_FILTERROR, 274132455Sroberto#ifdef OPENSSL 275132455Sroberto CP_HOST, 276132455Sroberto CP_DIGEST, 277182007Sroberto CP_VALID, 27882502Sroberto CP_FLAGS, 279132455Sroberto CP_IDENT, 28082502Sroberto CP_INITSEQ, 281132455Sroberto#endif /* OPENSSL */ 28254359Sroberto 0 28354359Sroberto}; 28454359Sroberto 28554359Sroberto 28654359Sroberto#ifdef REFCLOCK 28754359Sroberto/* 28854359Sroberto * Clock variable list 28954359Sroberto */ 29082502Srobertostatic struct ctl_var clock_var[] = { 29182502Sroberto { 0, PADDING, "" }, /* 0 */ 29282502Sroberto { CC_TYPE, RO, "type" }, /* 1 */ 29382502Sroberto { CC_TIMECODE, RO, "timecode" }, /* 2 */ 29482502Sroberto { CC_POLL, RO, "poll" }, /* 3 */ 29582502Sroberto { CC_NOREPLY, RO, "noreply" }, /* 4 */ 29682502Sroberto { CC_BADFORMAT, RO, "badformat" }, /* 5 */ 29782502Sroberto { CC_BADDATA, RO, "baddata" }, /* 6 */ 29882502Sroberto { CC_FUDGETIME1, RO, "fudgetime1" }, /* 7 */ 29982502Sroberto { CC_FUDGETIME2, RO, "fudgetime2" }, /* 8 */ 30082502Sroberto { CC_FUDGEVAL1, RO, "stratum" }, /* 9 */ 30182502Sroberto { CC_FUDGEVAL2, RO, "refid" }, /* 10 */ 30282502Sroberto { CC_FLAGS, RO, "flags" }, /* 11 */ 30382502Sroberto { CC_DEVICE, RO, "device" }, /* 12 */ 30482502Sroberto { CC_VARLIST, RO, "clock_var_list" }, /* 13 */ 30582502Sroberto { 0, EOV, "" } /* 14 */ 30654359Sroberto}; 30754359Sroberto 30854359Sroberto 30954359Sroberto/* 31054359Sroberto * Clock variables printed by default 31154359Sroberto */ 31282502Srobertostatic u_char def_clock_var[] = { 31354359Sroberto CC_DEVICE, 31482502Sroberto CC_TYPE, /* won't be output if device = known */ 31554359Sroberto CC_TIMECODE, 31654359Sroberto CC_POLL, 31754359Sroberto CC_NOREPLY, 31854359Sroberto CC_BADFORMAT, 31954359Sroberto CC_BADDATA, 32054359Sroberto CC_FUDGETIME1, 32154359Sroberto CC_FUDGETIME2, 32254359Sroberto CC_FUDGEVAL1, 32354359Sroberto CC_FUDGEVAL2, 32454359Sroberto CC_FLAGS, 32554359Sroberto 0 32654359Sroberto}; 32754359Sroberto#endif 32854359Sroberto 32954359Sroberto 33054359Sroberto/* 33182502Sroberto * System and processor definitions. 33254359Sroberto */ 33354359Sroberto#ifndef HAVE_UNAME 33454359Sroberto# ifndef STR_SYSTEM 33582502Sroberto# define STR_SYSTEM "UNIX" 33654359Sroberto# endif 33754359Sroberto# ifndef STR_PROCESSOR 33882502Sroberto# define STR_PROCESSOR "unknown" 33954359Sroberto# endif 34054359Sroberto 34154359Srobertostatic char str_system[] = STR_SYSTEM; 34254359Srobertostatic char str_processor[] = STR_PROCESSOR; 34354359Sroberto#else 34454359Sroberto# include <sys/utsname.h> 34554359Srobertostatic struct utsname utsnamebuf; 34654359Sroberto#endif /* HAVE_UNAME */ 34754359Sroberto 34854359Sroberto/* 34982502Sroberto * Trap structures. We only allow a few of these, and send a copy of 35082502Sroberto * each async message to each live one. Traps time out after an hour, it 35182502Sroberto * is up to the trap receipient to keep resetting it to avoid being 35282502Sroberto * timed out. 35354359Sroberto */ 35454359Sroberto/* ntp_request.c */ 35554359Srobertostruct ctl_trap ctl_trap[CTL_MAXTRAPS]; 35654359Srobertoint num_ctl_traps; 35754359Sroberto 35854359Sroberto/* 35954359Sroberto * Type bits, for ctlsettrap() call. 36054359Sroberto */ 36154359Sroberto#define TRAP_TYPE_CONFIG 0 /* used by configuration code */ 36254359Sroberto#define TRAP_TYPE_PRIO 1 /* priority trap */ 36354359Sroberto#define TRAP_TYPE_NONPRIO 2 /* nonpriority trap */ 36454359Sroberto 36554359Sroberto 36654359Sroberto/* 36754359Sroberto * List relating reference clock types to control message time sources. 36882502Sroberto * Index by the reference clock type. This list will only be used iff 36982502Sroberto * the reference clock driver doesn't set peer->sstclktype to something 37082502Sroberto * different than CTL_SST_TS_UNSPEC. 37154359Sroberto */ 37254359Srobertostatic u_char clocktypes[] = { 37354359Sroberto CTL_SST_TS_NTP, /* REFCLK_NONE (0) */ 37454359Sroberto CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */ 375182007Sroberto CTL_SST_TS_UHF, /* deprecated REFCLK_GPS_TRAK (2) */ 37654359Sroberto CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */ 37754359Sroberto CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */ 37854359Sroberto CTL_SST_TS_UHF, /* REFCLK_TRUETIME (5) */ 379182007Sroberto CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) IRIG_AUDIO? */ 38054359Sroberto CTL_SST_TS_HF, /* REFCLK_CHU (7) */ 38154359Sroberto CTL_SST_TS_LF, /* REFCLOCK_PARSE (default) (8) */ 38254359Sroberto CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */ 38354359Sroberto CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */ 38454359Sroberto CTL_SST_TS_UHF, /* REFCLK_GPS_ARBITER (11) */ 38554359Sroberto CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */ 38654359Sroberto CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */ 387182007Sroberto CTL_SST_TS_LF, /* deprecated REFCLK_MSF_EES (14) */ 388182007Sroberto CTL_SST_TS_NTP, /* not used (15) */ 38954359Sroberto CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */ 39054359Sroberto CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */ 39154359Sroberto CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACTS (18) */ 39254359Sroberto CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */ 39354359Sroberto CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */ 39454359Sroberto CTL_SST_TS_UHF, /* REFCLK_GPS_VME (21) */ 39554359Sroberto CTL_SST_TS_ATOM, /* REFCLK_ATOM_PPS (22) */ 396182007Sroberto CTL_SST_TS_NTP, /* not used (23) */ 397182007Sroberto CTL_SST_TS_NTP, /* not used (24) */ 398182007Sroberto CTL_SST_TS_NTP, /* not used (25) */ 39954359Sroberto CTL_SST_TS_UHF, /* REFCLK_GPS_HP (26) */ 40054359Sroberto CTL_SST_TS_TELEPHONE, /* REFCLK_ARCRON_MSF (27) */ 40154359Sroberto CTL_SST_TS_TELEPHONE, /* REFCLK_SHM (28) */ 40254359Sroberto CTL_SST_TS_UHF, /* REFCLK_PALISADE (29) */ 40354359Sroberto CTL_SST_TS_UHF, /* REFCLK_ONCORE (30) */ 40454359Sroberto CTL_SST_TS_UHF, /* REFCLK_JUPITER (31) */ 40554359Sroberto CTL_SST_TS_LF, /* REFCLK_CHRONOLOG (32) */ 406182007Sroberto CTL_SST_TS_LF, /* REFCLK_DUMBCLOCK (33) */ 407182007Sroberto CTL_SST_TS_LF, /* REFCLK_ULINK (34) */ 40856746Sroberto CTL_SST_TS_LF, /* REFCLK_PCF (35) */ 40982502Sroberto CTL_SST_TS_LF, /* REFCLK_WWV (36) */ 41056746Sroberto CTL_SST_TS_LF, /* REFCLK_FG (37) */ 41182502Sroberto CTL_SST_TS_UHF, /* REFCLK_HOPF_SERIAL (38) */ 41282502Sroberto CTL_SST_TS_UHF, /* REFCLK_HOPF_PCI (39) */ 413106166Sroberto CTL_SST_TS_LF, /* REFCLK_JJY (40) */ 414106166Sroberto CTL_SST_TS_UHF, /* REFCLK_TT560 (41) */ 415106166Sroberto CTL_SST_TS_UHF, /* REFCLK_ZYFER (42) */ 416106427Sroberto CTL_SST_TS_UHF, /* REFCLK_RIPENCC (43) */ 417106427Sroberto CTL_SST_TS_UHF, /* REFCLK_NEOCLOCK4X (44) */ 41854359Sroberto}; 41954359Sroberto 42054359Sroberto 42154359Sroberto/* 42254359Sroberto * Keyid used for authenticating write requests. 42354359Sroberto */ 42482502Srobertokeyid_t ctl_auth_keyid; 42554359Sroberto 42654359Sroberto/* 42754359Sroberto * We keep track of the last error reported by the system internally 42854359Sroberto */ 42954359Srobertostatic u_char ctl_sys_last_event; 43054359Srobertostatic u_char ctl_sys_num_events; 43154359Sroberto 43254359Sroberto 43354359Sroberto/* 43454359Sroberto * Statistic counters to keep track of requests and responses. 43554359Sroberto */ 43654359Srobertou_long ctltimereset; /* time stats reset */ 43754359Srobertou_long numctlreq; /* number of requests we've received */ 43854359Srobertou_long numctlbadpkts; /* number of bad control packets */ 43954359Srobertou_long numctlresponses; /* number of resp packets sent with data */ 44082502Srobertou_long numctlfrags; /* number of fragments sent */ 44154359Srobertou_long numctlerrors; /* number of error responses sent */ 44254359Srobertou_long numctltooshort; /* number of too short input packets */ 44354359Srobertou_long numctlinputresp; /* number of responses on input */ 44454359Srobertou_long numctlinputfrag; /* number of fragments on input */ 44554359Srobertou_long numctlinputerr; /* number of input pkts with err bit set */ 44654359Srobertou_long numctlbadoffset; /* number of input pkts with nonzero offset */ 44754359Srobertou_long numctlbadversion; /* number of input pkts with unknown version */ 44854359Srobertou_long numctldatatooshort; /* data too short for count */ 44982502Srobertou_long numctlbadop; /* bad op code found in packet */ 45054359Srobertou_long numasyncmsgs; /* number of async messages we've sent */ 45154359Sroberto 45254359Sroberto/* 45382502Sroberto * Response packet used by these routines. Also some state information 45454359Sroberto * so that we can handle packet formatting within a common set of 45554359Sroberto * subroutines. Note we try to enter data in place whenever possible, 45654359Sroberto * but the need to set the more bit correctly means we occasionally 45754359Sroberto * use the extra buffer and copy. 45854359Sroberto */ 45954359Srobertostatic struct ntp_control rpkt; 46054359Srobertostatic u_char res_version; 46154359Srobertostatic u_char res_opcode; 46282502Srobertostatic associd_t res_associd; 46354359Srobertostatic int res_offset; 46454359Srobertostatic u_char * datapt; 46554359Srobertostatic u_char * dataend; 46654359Srobertostatic int datalinelen; 46754359Srobertostatic int datanotbinflag; 468132455Srobertostatic struct sockaddr_storage *rmt_addr; 46954359Srobertostatic struct interface *lcl_inter; 47054359Sroberto 47154359Srobertostatic u_char res_authenticate; 47254359Srobertostatic u_char res_authokay; 47382502Srobertostatic keyid_t res_keyid; 47454359Sroberto 47554359Sroberto#define MAXDATALINELEN (72) 47654359Sroberto 47754359Srobertostatic u_char res_async; /* set to 1 if this is async trap response */ 47854359Sroberto 47954359Sroberto/* 48054359Sroberto * Pointers for saving state when decoding request packets 48154359Sroberto */ 48254359Srobertostatic char *reqpt; 48354359Srobertostatic char *reqend; 48454359Sroberto 48554359Sroberto/* 48654359Sroberto * init_control - initialize request data 48754359Sroberto */ 48854359Srobertovoid 48954359Srobertoinit_control(void) 49054359Sroberto{ 49154359Sroberto int i; 49254359Sroberto 49354359Sroberto#ifdef HAVE_UNAME 49454359Sroberto uname(&utsnamebuf); 49554359Sroberto#endif /* HAVE_UNAME */ 49654359Sroberto 49754359Sroberto ctl_clr_stats(); 49854359Sroberto 49954359Sroberto ctl_auth_keyid = 0; 50054359Sroberto ctl_sys_last_event = EVNT_UNSPEC; 50154359Sroberto ctl_sys_num_events = 0; 50254359Sroberto 50354359Sroberto num_ctl_traps = 0; 50454359Sroberto for (i = 0; i < CTL_MAXTRAPS; i++) 50554359Sroberto ctl_trap[i].tr_flags = 0; 50654359Sroberto} 50754359Sroberto 50854359Sroberto 50954359Sroberto/* 51054359Sroberto * ctl_error - send an error response for the current request 51154359Sroberto */ 51254359Srobertostatic void 51354359Srobertoctl_error( 51454359Sroberto int errcode 51554359Sroberto ) 51654359Sroberto{ 51754359Sroberto#ifdef DEBUG 51854359Sroberto if (debug >= 4) 51954359Sroberto printf("sending control error %d\n", errcode); 52054359Sroberto#endif 52154359Sroberto /* 52282502Sroberto * Fill in the fields. We assume rpkt.sequence and rpkt.associd 52354359Sroberto * have already been filled in. 52454359Sroberto */ 52582502Sroberto rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode & 52682502Sroberto CTL_OP_MASK)); 52754359Sroberto rpkt.status = htons((u_short) ((errcode<<8) & 0xff00)); 52854359Sroberto rpkt.count = 0; 52954359Sroberto 53054359Sroberto /* 53154359Sroberto * send packet and bump counters 53254359Sroberto */ 53354359Sroberto if (res_authenticate && sys_authenticate) { 53454359Sroberto int maclen; 53554359Sroberto 53682502Sroberto *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) = 53782502Sroberto htonl(res_keyid); 53854359Sroberto maclen = authencrypt(res_keyid, (u_int32 *)&rpkt, 53982502Sroberto CTL_HEADER_LEN); 54054359Sroberto sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt, 54182502Sroberto CTL_HEADER_LEN + maclen); 54254359Sroberto } else { 54354359Sroberto sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt, 54482502Sroberto CTL_HEADER_LEN); 54554359Sroberto } 54654359Sroberto numctlerrors++; 54754359Sroberto} 54854359Sroberto 54954359Sroberto 55054359Sroberto/* 55154359Sroberto * process_control - process an incoming control message 55254359Sroberto */ 55354359Srobertovoid 55454359Srobertoprocess_control( 55554359Sroberto struct recvbuf *rbufp, 55654359Sroberto int restrict_mask 55754359Sroberto ) 55854359Sroberto{ 55954359Sroberto register struct ntp_control *pkt; 56054359Sroberto register int req_count; 56154359Sroberto register int req_data; 56254359Sroberto register struct ctl_proc *cc; 56354359Sroberto int properlen; 56454359Sroberto int maclen; 56554359Sroberto 56654359Sroberto#ifdef DEBUG 56782502Sroberto if (debug > 2) 56854359Sroberto printf("in process_control()\n"); 56954359Sroberto#endif 57054359Sroberto 57154359Sroberto /* 57254359Sroberto * Save the addresses for error responses 57354359Sroberto */ 57454359Sroberto numctlreq++; 57554359Sroberto rmt_addr = &rbufp->recv_srcadr; 57654359Sroberto lcl_inter = rbufp->dstadr; 57754359Sroberto pkt = (struct ntp_control *)&rbufp->recv_pkt; 57854359Sroberto 57954359Sroberto /* 58054359Sroberto * If the length is less than required for the header, or 58154359Sroberto * it is a response or a fragment, ignore this. 58254359Sroberto */ 58354359Sroberto if (rbufp->recv_length < CTL_HEADER_LEN 58482502Sroberto || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR) 58582502Sroberto || pkt->offset != 0) { 58654359Sroberto#ifdef DEBUG 58754359Sroberto if (debug) 58854359Sroberto printf("invalid format in control packet\n"); 58954359Sroberto#endif 59054359Sroberto if (rbufp->recv_length < CTL_HEADER_LEN) 59154359Sroberto numctltooshort++; 59254359Sroberto if (pkt->r_m_e_op & CTL_RESPONSE) 59354359Sroberto numctlinputresp++; 59454359Sroberto if (pkt->r_m_e_op & CTL_MORE) 59554359Sroberto numctlinputfrag++; 59654359Sroberto if (pkt->r_m_e_op & CTL_ERROR) 59754359Sroberto numctlinputerr++; 59854359Sroberto if (pkt->offset != 0) 59954359Sroberto numctlbadoffset++; 60054359Sroberto return; 60154359Sroberto } 60254359Sroberto res_version = PKT_VERSION(pkt->li_vn_mode); 60354359Sroberto if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) { 60454359Sroberto#ifdef DEBUG 60554359Sroberto if (debug) 60654359Sroberto printf("unknown version %d in control packet\n", 60754359Sroberto res_version); 60854359Sroberto#endif 60954359Sroberto numctlbadversion++; 61054359Sroberto return; 61154359Sroberto } 61254359Sroberto 61354359Sroberto /* 61482502Sroberto * Pull enough data from the packet to make intelligent 61582502Sroberto * responses 61654359Sroberto */ 61782502Sroberto rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version, 61882502Sroberto MODE_CONTROL); 61954359Sroberto res_opcode = pkt->r_m_e_op; 62054359Sroberto rpkt.sequence = pkt->sequence; 62154359Sroberto rpkt.associd = pkt->associd; 62254359Sroberto rpkt.status = 0; 62354359Sroberto res_offset = 0; 62454359Sroberto res_associd = htons(pkt->associd); 62554359Sroberto res_async = 0; 62654359Sroberto res_authenticate = 0; 62754359Sroberto res_keyid = 0; 62854359Sroberto res_authokay = 0; 62954359Sroberto req_count = (int)htons(pkt->count); 63054359Sroberto datanotbinflag = 0; 63154359Sroberto datalinelen = 0; 63254359Sroberto datapt = rpkt.data; 63354359Sroberto dataend = &(rpkt.data[CTL_MAX_DATA_LEN]); 63454359Sroberto 63554359Sroberto /* 63682502Sroberto * We're set up now. Make sure we've got at least enough 63782502Sroberto * incoming data space to match the count. 63854359Sroberto */ 63954359Sroberto req_data = rbufp->recv_length - CTL_HEADER_LEN; 64054359Sroberto if (req_data < req_count || rbufp->recv_length & 0x3) { 64154359Sroberto ctl_error(CERR_BADFMT); 64254359Sroberto numctldatatooshort++; 64354359Sroberto return; 64454359Sroberto } 64554359Sroberto 64654359Sroberto properlen = req_count + CTL_HEADER_LEN; 64754359Sroberto#ifdef DEBUG 64882502Sroberto if (debug > 2 && (rbufp->recv_length & 0x3) != 0) 64982502Sroberto printf("Packet length %d unrounded\n", 65082502Sroberto rbufp->recv_length); 65154359Sroberto#endif 65254359Sroberto /* round up proper len to a 8 octet boundary */ 65354359Sroberto 65454359Sroberto properlen = (properlen + 7) & ~7; 65554359Sroberto maclen = rbufp->recv_length - properlen; 65654359Sroberto if ((rbufp->recv_length & (sizeof(u_long) - 1)) == 0 && 65782502Sroberto maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN && 65882502Sroberto sys_authenticate) { 65954359Sroberto res_authenticate = 1; 66082502Sroberto res_keyid = ntohl(*(u_int32 *)((u_char *)pkt + 66182502Sroberto properlen)); 66254359Sroberto 66354359Sroberto#ifdef DEBUG 66482502Sroberto if (debug > 2) 66554359Sroberto printf( 66682502Sroberto "recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n", 66782502Sroberto rbufp->recv_length, properlen, res_keyid, maclen); 66854359Sroberto#endif 66954359Sroberto if (!authistrusted(res_keyid)) { 67054359Sroberto#ifdef DEBUG 67182502Sroberto if (debug > 2) 67282502Sroberto printf("invalid keyid %08x\n", 67382502Sroberto res_keyid); 67454359Sroberto#endif 67554359Sroberto } else if (authdecrypt(res_keyid, (u_int32 *)pkt, 67682502Sroberto rbufp->recv_length - maclen, maclen)) { 67754359Sroberto#ifdef DEBUG 67882502Sroberto if (debug > 2) 67954359Sroberto printf("authenticated okay\n"); 68054359Sroberto#endif 68154359Sroberto res_authokay = 1; 68254359Sroberto } else { 68354359Sroberto#ifdef DEBUG 68482502Sroberto if (debug > 2) 68554359Sroberto printf("authentication failed\n"); 68654359Sroberto#endif 68754359Sroberto res_keyid = 0; 68854359Sroberto } 68954359Sroberto } 69054359Sroberto 69154359Sroberto /* 69254359Sroberto * Set up translate pointers 69354359Sroberto */ 69454359Sroberto reqpt = (char *)pkt->data; 69554359Sroberto reqend = reqpt + req_count; 69654359Sroberto 69754359Sroberto /* 69854359Sroberto * Look for the opcode processor 69954359Sroberto */ 70054359Sroberto for (cc = control_codes; cc->control_code != NO_REQUEST; cc++) { 70154359Sroberto if (cc->control_code == res_opcode) { 70254359Sroberto#ifdef DEBUG 70382502Sroberto if (debug > 2) 70454359Sroberto printf("opcode %d, found command handler\n", 70582502Sroberto res_opcode); 70654359Sroberto#endif 70782502Sroberto if (cc->flags == AUTH && (!res_authokay || 70882502Sroberto res_keyid != ctl_auth_keyid)) { 70954359Sroberto ctl_error(CERR_PERMISSION); 71054359Sroberto return; 71154359Sroberto } 71254359Sroberto (cc->handler)(rbufp, restrict_mask); 71354359Sroberto return; 71454359Sroberto } 71554359Sroberto } 71654359Sroberto 71754359Sroberto /* 71854359Sroberto * Can't find this one, return an error. 71954359Sroberto */ 72054359Sroberto numctlbadop++; 72154359Sroberto ctl_error(CERR_BADOP); 72254359Sroberto return; 72354359Sroberto} 72454359Sroberto 72554359Sroberto 72654359Sroberto/* 72754359Sroberto * ctlpeerstatus - return a status word for this peer 72854359Sroberto */ 72954359Srobertou_short 73054359Srobertoctlpeerstatus( 73154359Sroberto register struct peer *peer 73254359Sroberto ) 73354359Sroberto{ 73454359Sroberto register u_short status; 73554359Sroberto 73654359Sroberto status = peer->status; 73754359Sroberto if (peer->flags & FLAG_CONFIG) 73854359Sroberto status |= CTL_PST_CONFIG; 73954359Sroberto if (peer->flags & FLAG_AUTHENABLE) 74054359Sroberto status |= CTL_PST_AUTHENABLE; 74154359Sroberto if (peer->flags & FLAG_AUTHENTIC) 74254359Sroberto status |= CTL_PST_AUTHENTIC; 74354359Sroberto if (peer->reach != 0) 74454359Sroberto status |= CTL_PST_REACH; 74554359Sroberto return (u_short)CTL_PEER_STATUS(status, peer->num_events, 74682502Sroberto peer->last_event); 74754359Sroberto} 74854359Sroberto 74954359Sroberto 75054359Sroberto/* 75154359Sroberto * ctlclkstatus - return a status word for this clock 75254359Sroberto */ 753132455Sroberto#ifdef REFCLOCK 75454359Srobertostatic u_short 75554359Srobertoctlclkstatus( 75654359Sroberto struct refclockstat *this_clock 75754359Sroberto ) 75854359Sroberto{ 759132455Sroberto return ((u_short)(((this_clock->currentstatus) << 8) | 760132455Sroberto (this_clock->lastevent))); 76154359Sroberto} 762132455Sroberto#endif 76354359Sroberto 76454359Sroberto 76554359Sroberto/* 76654359Sroberto * ctlsysstatus - return the system status word 76754359Sroberto */ 76854359Srobertou_short 76954359Srobertoctlsysstatus(void) 77054359Sroberto{ 77154359Sroberto register u_char this_clock; 77254359Sroberto 77354359Sroberto this_clock = CTL_SST_TS_UNSPEC; 774182007Sroberto#ifdef REFCLOCK 77554359Sroberto if (sys_peer != 0) { 77654359Sroberto if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) { 77754359Sroberto this_clock = sys_peer->sstclktype; 77854359Sroberto if (pps_control) 77954359Sroberto this_clock |= CTL_SST_TS_PPS; 78054359Sroberto } else { 78154359Sroberto if (sys_peer->refclktype < sizeof(clocktypes)) 78282502Sroberto this_clock = 78382502Sroberto clocktypes[sys_peer->refclktype]; 78454359Sroberto if (pps_control) 78554359Sroberto this_clock |= CTL_SST_TS_PPS; 78654359Sroberto } 78754359Sroberto } 788182007Sroberto#endif /* REFCLOCK */ 78954359Sroberto return (u_short)CTL_SYS_STATUS(sys_leap, this_clock, 79082502Sroberto ctl_sys_num_events, ctl_sys_last_event); 79154359Sroberto} 79254359Sroberto 79354359Sroberto 79454359Sroberto/* 79554359Sroberto * ctl_flushpkt - write out the current packet and prepare 79654359Sroberto * another if necessary. 79754359Sroberto */ 79854359Srobertostatic void 79954359Srobertoctl_flushpkt( 80054359Sroberto int more 80154359Sroberto ) 80254359Sroberto{ 80354359Sroberto int dlen; 80454359Sroberto int sendlen; 80554359Sroberto 80654359Sroberto if (!more && datanotbinflag) { 80754359Sroberto /* 80854359Sroberto * Big hack, output a trailing \r\n 80954359Sroberto */ 81054359Sroberto *datapt++ = '\r'; 81154359Sroberto *datapt++ = '\n'; 81254359Sroberto } 81354359Sroberto dlen = datapt - (u_char *)rpkt.data; 81454359Sroberto sendlen = dlen + CTL_HEADER_LEN; 81554359Sroberto 81654359Sroberto /* 81754359Sroberto * Pad to a multiple of 32 bits 81854359Sroberto */ 81954359Sroberto while (sendlen & 0x3) { 82054359Sroberto *datapt++ = '\0'; 82154359Sroberto sendlen++; 82254359Sroberto } 82354359Sroberto 82454359Sroberto /* 82554359Sroberto * Fill in the packet with the current info 82654359Sroberto */ 82782502Sroberto rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode & 82882502Sroberto CTL_OP_MASK)); 82954359Sroberto rpkt.count = htons((u_short) dlen); 83054359Sroberto rpkt.offset = htons( (u_short) res_offset); 83154359Sroberto if (res_async) { 83254359Sroberto register int i; 83354359Sroberto 83454359Sroberto for (i = 0; i < CTL_MAXTRAPS; i++) { 83554359Sroberto if (ctl_trap[i].tr_flags & TRAP_INUSE) { 83682502Sroberto rpkt.li_vn_mode = 83782502Sroberto PKT_LI_VN_MODE(sys_leap, 83882502Sroberto ctl_trap[i].tr_version, 83982502Sroberto MODE_CONTROL); 84082502Sroberto rpkt.sequence = 84182502Sroberto htons(ctl_trap[i].tr_sequence); 84254359Sroberto sendpkt(&ctl_trap[i].tr_addr, 84382502Sroberto ctl_trap[i].tr_localaddr, -4, 84454359Sroberto (struct pkt *)&rpkt, sendlen); 84554359Sroberto if (!more) 84654359Sroberto ctl_trap[i].tr_sequence++; 84754359Sroberto numasyncmsgs++; 84854359Sroberto } 84954359Sroberto } 85054359Sroberto } else { 85154359Sroberto if (res_authenticate && sys_authenticate) { 85254359Sroberto int maclen; 85354359Sroberto int totlen = sendlen; 85482502Sroberto keyid_t keyid = htonl(res_keyid); 85554359Sroberto 85654359Sroberto /* 85782502Sroberto * If we are going to authenticate, then there 85882502Sroberto * is an additional requirement that the MAC 85982502Sroberto * begin on a 64 bit boundary. 86054359Sroberto */ 86154359Sroberto while (totlen & 7) { 86254359Sroberto *datapt++ = '\0'; 86354359Sroberto totlen++; 86454359Sroberto } 86554359Sroberto memcpy(datapt, &keyid, sizeof keyid); 86682502Sroberto maclen = authencrypt(res_keyid, 86782502Sroberto (u_int32 *)&rpkt, totlen); 86882502Sroberto sendpkt(rmt_addr, lcl_inter, -5, 86982502Sroberto (struct pkt *)&rpkt, totlen + maclen); 87054359Sroberto } else { 87182502Sroberto sendpkt(rmt_addr, lcl_inter, -6, 87282502Sroberto (struct pkt *)&rpkt, sendlen); 87354359Sroberto } 87454359Sroberto if (more) 87554359Sroberto numctlfrags++; 87654359Sroberto else 87754359Sroberto numctlresponses++; 87854359Sroberto } 87954359Sroberto 88054359Sroberto /* 88154359Sroberto * Set us up for another go around. 88254359Sroberto */ 88354359Sroberto res_offset += dlen; 88454359Sroberto datapt = (u_char *)rpkt.data; 88554359Sroberto} 88654359Sroberto 88754359Sroberto 88854359Sroberto/* 88982502Sroberto * ctl_putdata - write data into the packet, fragmenting and starting 89082502Sroberto * another if this one is full. 89154359Sroberto */ 89254359Srobertostatic void 89354359Srobertoctl_putdata( 89454359Sroberto const char *dp, 89554359Sroberto unsigned int dlen, 89654359Sroberto int bin /* set to 1 when data is binary */ 89754359Sroberto ) 89854359Sroberto{ 89954359Sroberto int overhead; 900276158Sdes unsigned int currentlen; 90154359Sroberto 90254359Sroberto overhead = 0; 90354359Sroberto if (!bin) { 90454359Sroberto datanotbinflag = 1; 90554359Sroberto overhead = 3; 90654359Sroberto if (datapt != rpkt.data) { 90754359Sroberto *datapt++ = ','; 90854359Sroberto datalinelen++; 90982502Sroberto if ((dlen + datalinelen + 1) >= MAXDATALINELEN) 91082502Sroberto { 91154359Sroberto *datapt++ = '\r'; 91254359Sroberto *datapt++ = '\n'; 91354359Sroberto datalinelen = 0; 91454359Sroberto } else { 91554359Sroberto *datapt++ = ' '; 91654359Sroberto datalinelen++; 91754359Sroberto } 91854359Sroberto } 91954359Sroberto } 92054359Sroberto 92154359Sroberto /* 92254359Sroberto * Save room for trailing junk 92354359Sroberto */ 924276158Sdes while (dlen + overhead + datapt > dataend) { 92554359Sroberto /* 92654359Sroberto * Not enough room in this one, flush it out. 92754359Sroberto */ 928276158Sdes currentlen = MIN(dlen, dataend - datapt); 929276158Sdes 930276158Sdes memcpy(datapt, dp, currentlen); 931276158Sdes 932276158Sdes datapt += currentlen; 933276158Sdes dp += currentlen; 934276158Sdes dlen -= currentlen; 935276158Sdes datalinelen += currentlen; 936276158Sdes 93754359Sroberto ctl_flushpkt(CTL_MORE); 93854359Sroberto } 939276158Sdes 94054359Sroberto memmove((char *)datapt, dp, (unsigned)dlen); 94154359Sroberto datapt += dlen; 94254359Sroberto datalinelen += dlen; 94354359Sroberto} 94454359Sroberto 94554359Sroberto 94654359Sroberto/* 94754359Sroberto * ctl_putstr - write a tagged string into the response packet 94854359Sroberto */ 94954359Srobertostatic void 95054359Srobertoctl_putstr( 95154359Sroberto const char *tag, 95254359Sroberto const char *data, 95354359Sroberto unsigned int len 95454359Sroberto ) 95554359Sroberto{ 95654359Sroberto register char *cp; 95754359Sroberto register const char *cq; 95854359Sroberto char buffer[400]; 95954359Sroberto 96054359Sroberto cp = buffer; 96154359Sroberto cq = tag; 96254359Sroberto while (*cq != '\0') 96354359Sroberto *cp++ = *cq++; 96454359Sroberto if (len > 0) { 96554359Sroberto *cp++ = '='; 96654359Sroberto *cp++ = '"'; 96754359Sroberto if (len > (int) (sizeof(buffer) - (cp - buffer) - 1)) 96854359Sroberto len = sizeof(buffer) - (cp - buffer) - 1; 96954359Sroberto memmove(cp, data, (unsigned)len); 97054359Sroberto cp += len; 97154359Sroberto *cp++ = '"'; 97254359Sroberto } 97354359Sroberto ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); 97454359Sroberto} 97554359Sroberto 97654359Sroberto 97754359Sroberto/* 97854359Sroberto * ctl_putdbl - write a tagged, signed double into the response packet 97954359Sroberto */ 98054359Srobertostatic void 98154359Srobertoctl_putdbl( 98254359Sroberto const char *tag, 98354359Sroberto double ts 98454359Sroberto ) 98554359Sroberto{ 98654359Sroberto register char *cp; 98754359Sroberto register const char *cq; 98854359Sroberto char buffer[200]; 98954359Sroberto 99054359Sroberto cp = buffer; 99154359Sroberto cq = tag; 99254359Sroberto while (*cq != '\0') 99354359Sroberto *cp++ = *cq++; 99454359Sroberto *cp++ = '='; 99554359Sroberto (void)sprintf(cp, "%.3f", ts); 99654359Sroberto while (*cp != '\0') 99754359Sroberto cp++; 99854359Sroberto ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); 99954359Sroberto} 100054359Sroberto 100154359Sroberto/* 100254359Sroberto * ctl_putuint - write a tagged unsigned integer into the response 100354359Sroberto */ 100454359Srobertostatic void 100554359Srobertoctl_putuint( 100654359Sroberto const char *tag, 100754359Sroberto u_long uval 100854359Sroberto ) 100954359Sroberto{ 101054359Sroberto register char *cp; 101154359Sroberto register const char *cq; 101254359Sroberto char buffer[200]; 101354359Sroberto 101454359Sroberto cp = buffer; 101554359Sroberto cq = tag; 101654359Sroberto while (*cq != '\0') 101754359Sroberto *cp++ = *cq++; 101854359Sroberto 101954359Sroberto *cp++ = '='; 102054359Sroberto (void) sprintf(cp, "%lu", uval); 102154359Sroberto while (*cp != '\0') 102254359Sroberto cp++; 102354359Sroberto ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); 102454359Sroberto} 102554359Sroberto 1026182007Sroberto/* 1027182007Sroberto * ctl_putfs - write a decoded filestamp into the response 1028182007Sroberto */ 1029182007Sroberto#ifdef OPENSSL 1030182007Srobertostatic void 1031182007Srobertoctl_putfs( 1032182007Sroberto const char *tag, 1033182007Sroberto tstamp_t uval 1034182007Sroberto ) 1035182007Sroberto{ 1036182007Sroberto register char *cp; 1037182007Sroberto register const char *cq; 1038182007Sroberto char buffer[200]; 1039182007Sroberto struct tm *tm = NULL; 1040182007Sroberto time_t fstamp; 104154359Sroberto 1042182007Sroberto cp = buffer; 1043182007Sroberto cq = tag; 1044182007Sroberto while (*cq != '\0') 1045182007Sroberto *cp++ = *cq++; 1046182007Sroberto 1047182007Sroberto *cp++ = '='; 1048182007Sroberto fstamp = uval - JAN_1970; 1049182007Sroberto tm = gmtime(&fstamp); 1050182007Sroberto if (tm == NULL) 1051182007Sroberto return; 1052182007Sroberto 1053182007Sroberto sprintf(cp, "%04d%02d%02d%02d%02d", tm->tm_year + 1900, 1054182007Sroberto tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min); 1055182007Sroberto while (*cp != '\0') 1056182007Sroberto cp++; 1057182007Sroberto ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); 1058182007Sroberto} 1059182007Sroberto#endif 1060182007Sroberto 1061182007Sroberto 106254359Sroberto/* 106354359Sroberto * ctl_puthex - write a tagged unsigned integer, in hex, into the response 106454359Sroberto */ 106554359Srobertostatic void 106654359Srobertoctl_puthex( 106754359Sroberto const char *tag, 106854359Sroberto u_long uval 106954359Sroberto ) 107054359Sroberto{ 107154359Sroberto register char *cp; 107254359Sroberto register const char *cq; 107354359Sroberto char buffer[200]; 107454359Sroberto 107554359Sroberto cp = buffer; 107654359Sroberto cq = tag; 107754359Sroberto while (*cq != '\0') 107854359Sroberto *cp++ = *cq++; 107954359Sroberto 108054359Sroberto *cp++ = '='; 108154359Sroberto (void) sprintf(cp, "0x%lx", uval); 108254359Sroberto while (*cp != '\0') 108354359Sroberto cp++; 108454359Sroberto ctl_putdata(buffer,(unsigned)( cp - buffer ), 0); 108554359Sroberto} 108654359Sroberto 108754359Sroberto 108854359Sroberto/* 108954359Sroberto * ctl_putint - write a tagged signed integer into the response 109054359Sroberto */ 109154359Srobertostatic void 109254359Srobertoctl_putint( 109354359Sroberto const char *tag, 109454359Sroberto long ival 109554359Sroberto ) 109654359Sroberto{ 109754359Sroberto register char *cp; 109854359Sroberto register const char *cq; 109954359Sroberto char buffer[200]; 110054359Sroberto 110154359Sroberto cp = buffer; 110254359Sroberto cq = tag; 110354359Sroberto while (*cq != '\0') 110454359Sroberto *cp++ = *cq++; 110554359Sroberto 110654359Sroberto *cp++ = '='; 110754359Sroberto (void) sprintf(cp, "%ld", ival); 110854359Sroberto while (*cp != '\0') 110954359Sroberto cp++; 111054359Sroberto ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); 111154359Sroberto} 111254359Sroberto 111354359Sroberto 111454359Sroberto/* 111554359Sroberto * ctl_putts - write a tagged timestamp, in hex, into the response 111654359Sroberto */ 111754359Srobertostatic void 111854359Srobertoctl_putts( 111954359Sroberto const char *tag, 112054359Sroberto l_fp *ts 112154359Sroberto ) 112254359Sroberto{ 112354359Sroberto register char *cp; 112454359Sroberto register const char *cq; 112554359Sroberto char buffer[200]; 112654359Sroberto 112754359Sroberto cp = buffer; 112854359Sroberto cq = tag; 112954359Sroberto while (*cq != '\0') 113054359Sroberto *cp++ = *cq++; 113154359Sroberto 113254359Sroberto *cp++ = '='; 1133182007Sroberto (void) sprintf(cp, "0x%08lx.%08lx", 1134182007Sroberto ts->l_ui & ULONG_CONST(0xffffffff), 1135182007Sroberto ts->l_uf & ULONG_CONST(0xffffffff)); 113654359Sroberto while (*cp != '\0') 113754359Sroberto cp++; 113854359Sroberto ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); 113954359Sroberto} 114054359Sroberto 114154359Sroberto 114254359Sroberto/* 1143132455Sroberto * ctl_putadr - write an IP address into the response 114454359Sroberto */ 114554359Srobertostatic void 114654359Srobertoctl_putadr( 114754359Sroberto const char *tag, 1148132455Sroberto u_int32 addr32, 1149132455Sroberto struct sockaddr_storage* addr 115054359Sroberto ) 115154359Sroberto{ 115254359Sroberto register char *cp; 115354359Sroberto register const char *cq; 115454359Sroberto char buffer[200]; 115554359Sroberto 115654359Sroberto cp = buffer; 115754359Sroberto cq = tag; 115854359Sroberto while (*cq != '\0') 115954359Sroberto *cp++ = *cq++; 116054359Sroberto 116154359Sroberto *cp++ = '='; 1162132455Sroberto if (addr == NULL) 1163132455Sroberto cq = numtoa(addr32); 1164132455Sroberto else 1165132455Sroberto cq = stoa(addr); 116654359Sroberto while (*cq != '\0') 116754359Sroberto *cp++ = *cq++; 116854359Sroberto ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); 116954359Sroberto} 117054359Sroberto 117154359Sroberto/* 117254359Sroberto * ctl_putid - write a tagged clock ID into the response 117354359Sroberto */ 117454359Srobertostatic void 117554359Srobertoctl_putid( 117654359Sroberto const char *tag, 117754359Sroberto char *id 117854359Sroberto ) 117954359Sroberto{ 118054359Sroberto register char *cp; 118154359Sroberto register const char *cq; 118254359Sroberto char buffer[200]; 118354359Sroberto 118454359Sroberto cp = buffer; 118554359Sroberto cq = tag; 118654359Sroberto while (*cq != '\0') 118754359Sroberto *cp++ = *cq++; 118854359Sroberto 118954359Sroberto *cp++ = '='; 119054359Sroberto cq = id; 119154359Sroberto while (*cq != '\0' && (cq - id) < 4) 119254359Sroberto *cp++ = *cq++; 119354359Sroberto ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); 119454359Sroberto} 119554359Sroberto 119654359Sroberto 119754359Sroberto/* 119854359Sroberto * ctl_putarray - write a tagged eight element double array into the response 119954359Sroberto */ 120054359Srobertostatic void 120154359Srobertoctl_putarray( 120254359Sroberto const char *tag, 120354359Sroberto double *arr, 120454359Sroberto int start 120554359Sroberto ) 120654359Sroberto{ 120754359Sroberto register char *cp; 120854359Sroberto register const char *cq; 120954359Sroberto char buffer[200]; 121054359Sroberto int i; 121154359Sroberto cp = buffer; 121254359Sroberto cq = tag; 121354359Sroberto while (*cq != '\0') 121454359Sroberto *cp++ = *cq++; 121554359Sroberto i = start; 121654359Sroberto do { 121754359Sroberto if (i == 0) 121854359Sroberto i = NTP_SHIFT; 121954359Sroberto i--; 122054359Sroberto (void)sprintf(cp, " %.2f", arr[i] * 1e3); 122154359Sroberto while (*cp != '\0') 122254359Sroberto cp++; 122354359Sroberto } while(i != start); 122454359Sroberto ctl_putdata(buffer, (unsigned)(cp - buffer), 0); 122554359Sroberto} 122654359Sroberto 122754359Sroberto 122854359Sroberto/* 122954359Sroberto * ctl_putsys - output a system variable 123054359Sroberto */ 123154359Srobertostatic void 123254359Srobertoctl_putsys( 123354359Sroberto int varid 123454359Sroberto ) 123554359Sroberto{ 123654359Sroberto l_fp tmp; 123782502Sroberto char str[256]; 1238132455Sroberto#ifdef OPENSSL 1239132455Sroberto struct cert_info *cp; 1240132455Sroberto char cbuf[256]; 1241132455Sroberto#endif /* OPENSSL */ 124254359Sroberto 124354359Sroberto switch (varid) { 124482502Sroberto 124582502Sroberto case CS_LEAP: 124654359Sroberto ctl_putuint(sys_var[CS_LEAP].text, sys_leap); 124754359Sroberto break; 124882502Sroberto 124982502Sroberto case CS_STRATUM: 125054359Sroberto ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum); 125154359Sroberto break; 125282502Sroberto 125382502Sroberto case CS_PRECISION: 125454359Sroberto ctl_putint(sys_var[CS_PRECISION].text, sys_precision); 125554359Sroberto break; 125682502Sroberto 125782502Sroberto case CS_ROOTDELAY: 125882502Sroberto ctl_putdbl(sys_var[CS_ROOTDELAY].text, sys_rootdelay * 125982502Sroberto 1e3); 126054359Sroberto break; 126182502Sroberto 126282502Sroberto case CS_ROOTDISPERSION: 126354359Sroberto ctl_putdbl(sys_var[CS_ROOTDISPERSION].text, 126454359Sroberto sys_rootdispersion * 1e3); 126554359Sroberto break; 126682502Sroberto 126782502Sroberto case CS_REFID: 1268132455Sroberto if (sys_stratum > 1 && sys_stratum < STRATUM_UNSPEC) 1269132455Sroberto ctl_putadr(sys_var[CS_REFID].text, sys_refid, NULL); 127054359Sroberto else 127182502Sroberto ctl_putid(sys_var[CS_REFID].text, 127282502Sroberto (char *)&sys_refid); 127354359Sroberto break; 127482502Sroberto 127582502Sroberto case CS_REFTIME: 127654359Sroberto ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime); 127754359Sroberto break; 127882502Sroberto 127982502Sroberto case CS_POLL: 128054359Sroberto ctl_putuint(sys_var[CS_POLL].text, sys_poll); 128154359Sroberto break; 128282502Sroberto 128382502Sroberto case CS_PEERID: 128454359Sroberto if (sys_peer == NULL) 128554359Sroberto ctl_putuint(sys_var[CS_PEERID].text, 0); 128654359Sroberto else 128754359Sroberto ctl_putuint(sys_var[CS_PEERID].text, 128854359Sroberto sys_peer->associd); 128954359Sroberto break; 129082502Sroberto 129182502Sroberto case CS_STATE: 129254359Sroberto ctl_putuint(sys_var[CS_STATE].text, (unsigned)state); 129354359Sroberto break; 129482502Sroberto 129582502Sroberto case CS_OFFSET: 129654359Sroberto ctl_putdbl(sys_var[CS_OFFSET].text, last_offset * 1e3); 129754359Sroberto break; 129882502Sroberto 129982502Sroberto case CS_DRIFT: 130054359Sroberto ctl_putdbl(sys_var[CS_DRIFT].text, drift_comp * 1e6); 130154359Sroberto break; 130282502Sroberto 130382502Sroberto case CS_JITTER: 130482502Sroberto ctl_putdbl(sys_var[CS_JITTER].text, sys_jitter * 1e3); 130554359Sroberto break; 130682502Sroberto 1307182007Sroberto case CS_ERROR: 1308182007Sroberto ctl_putdbl(sys_var[CS_ERROR].text, clock_jitter * 1e3); 1309182007Sroberto break; 1310182007Sroberto 131182502Sroberto case CS_CLOCK: 131254359Sroberto get_systime(&tmp); 131354359Sroberto ctl_putts(sys_var[CS_CLOCK].text, &tmp); 131454359Sroberto break; 131582502Sroberto 131682502Sroberto case CS_PROCESSOR: 131754359Sroberto#ifndef HAVE_UNAME 131854359Sroberto ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor, 131982502Sroberto sizeof(str_processor) - 1); 132054359Sroberto#else 132182502Sroberto ctl_putstr(sys_var[CS_PROCESSOR].text, 132282502Sroberto utsnamebuf.machine, strlen(utsnamebuf.machine)); 132354359Sroberto#endif /* HAVE_UNAME */ 132454359Sroberto break; 132582502Sroberto 132682502Sroberto case CS_SYSTEM: 132754359Sroberto#ifndef HAVE_UNAME 132854359Sroberto ctl_putstr(sys_var[CS_SYSTEM].text, str_system, 132982502Sroberto sizeof(str_system) - 1); 133054359Sroberto#else 1331132455Sroberto sprintf(str, "%s/%s", utsnamebuf.sysname, utsnamebuf.release); 133254359Sroberto ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str)); 133354359Sroberto#endif /* HAVE_UNAME */ 133454359Sroberto break; 133582502Sroberto 133682502Sroberto case CS_VERSION: 133782502Sroberto ctl_putstr(sys_var[CS_VERSION].text, Version, 133882502Sroberto strlen(Version)); 133954359Sroberto break; 134054359Sroberto 134182502Sroberto case CS_STABIL: 134282502Sroberto ctl_putdbl(sys_var[CS_STABIL].text, clock_stability * 134382502Sroberto 1e6); 134482502Sroberto break; 134554359Sroberto 134682502Sroberto case CS_VARLIST: 134782502Sroberto { 134882502Sroberto char buf[CTL_MAX_DATA_LEN]; 134982502Sroberto register char *s, *t, *be; 135082502Sroberto register const char *ss; 135182502Sroberto register int i; 135282502Sroberto register struct ctl_var *k; 135354359Sroberto 135482502Sroberto s = buf; 135582502Sroberto be = buf + sizeof(buf) - 135682502Sroberto strlen(sys_var[CS_VARLIST].text) - 4; 135782502Sroberto if (s > be) 135882502Sroberto break; /* really long var name */ 135982502Sroberto 136082502Sroberto strcpy(s, sys_var[CS_VARLIST].text); 136182502Sroberto strcat(s, "=\""); 136282502Sroberto s += strlen(s); 136382502Sroberto t = s; 136482502Sroberto for (k = sys_var; !(k->flags &EOV); k++) { 136582502Sroberto if (k->flags & PADDING) 136654359Sroberto continue; 136782502Sroberto i = strlen(k->text); 136882502Sroberto if (s+i+1 >= be) 136982502Sroberto break; 137054359Sroberto 137182502Sroberto if (s != t) 137282502Sroberto *s++ = ','; 137382502Sroberto strcpy(s, k->text); 137482502Sroberto s += i; 137582502Sroberto } 137654359Sroberto 137782502Sroberto for (k = ext_sys_var; k && !(k->flags &EOV); 137882502Sroberto k++) { 137982502Sroberto if (k->flags & PADDING) 138054359Sroberto continue; 138154359Sroberto 138282502Sroberto ss = k->text; 138382502Sroberto if (!ss) 138454359Sroberto continue; 138554359Sroberto 138682502Sroberto while (*ss && *ss != '=') 138754359Sroberto ss++; 138882502Sroberto i = ss - k->text; 138982502Sroberto if (s + i + 1 >= be) 139054359Sroberto break; 139154359Sroberto 139282502Sroberto if (s != t) 139382502Sroberto *s++ = ','; 139482502Sroberto strncpy(s, k->text, 139582502Sroberto (unsigned)i); 139682502Sroberto s += i; 139782502Sroberto } 139882502Sroberto if (s+2 >= be) 139954359Sroberto break; 140054359Sroberto 140182502Sroberto *s++ = '"'; 140282502Sroberto *s = '\0'; 140354359Sroberto 140482502Sroberto ctl_putdata(buf, (unsigned)( s - buf ), 140582502Sroberto 0); 140682502Sroberto } 140782502Sroberto break; 140882502Sroberto 1409132455Sroberto#ifdef OPENSSL 141082502Sroberto case CS_FLAGS: 1411132455Sroberto if (crypto_flags) { 1412132455Sroberto ctl_puthex(sys_var[CS_FLAGS].text, crypto_flags); 1413132455Sroberto } 141482502Sroberto break; 141582502Sroberto 1416132455Sroberto case CS_DIGEST: 1417132455Sroberto if (crypto_flags) { 1418132455Sroberto const EVP_MD *dp; 1419132455Sroberto 1420132455Sroberto dp = EVP_get_digestbynid(crypto_flags >> 16); 1421132455Sroberto strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp))); 1422132455Sroberto ctl_putstr(sys_var[CS_DIGEST].text, str, 1423132455Sroberto strlen(str)); 1424132455Sroberto } 1425132455Sroberto break; 1426132455Sroberto 142782502Sroberto case CS_HOST: 1428132455Sroberto if (sys_hostname != NULL) 1429132455Sroberto ctl_putstr(sys_var[CS_HOST].text, sys_hostname, 1430132455Sroberto strlen(sys_hostname)); 143182502Sroberto break; 143282502Sroberto 143382502Sroberto case CS_CERTIF: 1434132455Sroberto for (cp = cinfo; cp != NULL; cp = cp->link) { 1435182007Sroberto sprintf(cbuf, "%s %s 0x%x", cp->subject, 1436182007Sroberto cp->issuer, cp->flags); 1437132455Sroberto ctl_putstr(sys_var[CS_CERTIF].text, cbuf, 1438132455Sroberto strlen(cbuf)); 1439182007Sroberto ctl_putfs(sys_var[CS_REVOKE].text, cp->last); 1440132455Sroberto } 144182502Sroberto break; 144282502Sroberto 1443132455Sroberto case CS_PUBLIC: 1444132455Sroberto if (hostval.fstamp != 0) 1445182007Sroberto ctl_putfs(sys_var[CS_PUBLIC].text, 1446182007Sroberto ntohl(hostval.tstamp)); 144782502Sroberto break; 144882502Sroberto 144982502Sroberto case CS_REVTIME: 1450132455Sroberto if (hostval.tstamp != 0) 1451182007Sroberto ctl_putfs(sys_var[CS_REVTIME].text, 1452132455Sroberto ntohl(hostval.tstamp)); 145382502Sroberto break; 145482502Sroberto 1455182007Sroberto case CS_IDENT: 1456182007Sroberto if (iffpar_pkey != NULL) 1457182007Sroberto ctl_putstr(sys_var[CS_IDENT].text, 1458182007Sroberto iffpar_file, strlen(iffpar_file)); 1459182007Sroberto if (gqpar_pkey != NULL) 1460182007Sroberto ctl_putstr(sys_var[CS_IDENT].text, 1461182007Sroberto gqpar_file, strlen(gqpar_file)); 1462182007Sroberto if (mvpar_pkey != NULL) 1463182007Sroberto ctl_putstr(sys_var[CS_IDENT].text, 1464182007Sroberto mvpar_file, strlen(mvpar_file)); 1465182007Sroberto break; 1466182007Sroberto 146782502Sroberto case CS_LEAPTAB: 146882502Sroberto if (tai_leap.fstamp != 0) 1469182007Sroberto ctl_putfs(sys_var[CS_LEAPTAB].text, 147082502Sroberto ntohl(tai_leap.fstamp)); 147182502Sroberto break; 1472182007Sroberto 1473182007Sroberto case CS_TAI: 1474182007Sroberto ctl_putuint(sys_var[CS_TAI].text, sys_tai); 1475182007Sroberto break; 1476132455Sroberto#endif /* OPENSSL */ 147754359Sroberto } 147854359Sroberto} 147954359Sroberto 148054359Sroberto 148154359Sroberto/* 148254359Sroberto * ctl_putpeer - output a peer variable 148354359Sroberto */ 148454359Srobertostatic void 148554359Srobertoctl_putpeer( 148654359Sroberto int varid, 148754359Sroberto struct peer *peer 148854359Sroberto ) 148954359Sroberto{ 1490182007Sroberto int temp; 1491132455Sroberto#ifdef OPENSSL 1492132455Sroberto char str[256]; 1493132455Sroberto struct autokey *ap; 1494132455Sroberto#endif /* OPENSSL */ 1495132455Sroberto 149654359Sroberto switch (varid) { 149782502Sroberto 149882502Sroberto case CP_CONFIG: 149954359Sroberto ctl_putuint(peer_var[CP_CONFIG].text, 150082502Sroberto (unsigned)((peer->flags & FLAG_CONFIG) != 0)); 150154359Sroberto break; 150282502Sroberto 150382502Sroberto case CP_AUTHENABLE: 150454359Sroberto ctl_putuint(peer_var[CP_AUTHENABLE].text, 150582502Sroberto (unsigned)((peer->flags & FLAG_AUTHENABLE) != 0)); 150654359Sroberto break; 150782502Sroberto 150882502Sroberto case CP_AUTHENTIC: 150954359Sroberto ctl_putuint(peer_var[CP_AUTHENTIC].text, 151082502Sroberto (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0)); 151154359Sroberto break; 151282502Sroberto 151382502Sroberto case CP_SRCADR: 1514132455Sroberto ctl_putadr(peer_var[CP_SRCADR].text, 0, 1515132455Sroberto &peer->srcadr); 151654359Sroberto break; 151782502Sroberto 151882502Sroberto case CP_SRCPORT: 151954359Sroberto ctl_putuint(peer_var[CP_SRCPORT].text, 1520132455Sroberto ntohs(((struct sockaddr_in*)&peer->srcadr)->sin_port)); 152154359Sroberto break; 152282502Sroberto 152382502Sroberto case CP_DSTADR: 1524182007Sroberto if (peer->dstadr) { 1525182007Sroberto ctl_putadr(peer_var[CP_DSTADR].text, 0, 1526182007Sroberto &(peer->dstadr->sin)); 1527182007Sroberto } else { 1528182007Sroberto ctl_putadr(peer_var[CP_DSTADR].text, 0, 1529182007Sroberto NULL); 1530182007Sroberto } 153154359Sroberto break; 153282502Sroberto 153382502Sroberto case CP_DSTPORT: 153454359Sroberto ctl_putuint(peer_var[CP_DSTPORT].text, 153582502Sroberto (u_long)(peer->dstadr ? 1536132455Sroberto ntohs(((struct sockaddr_in*)&peer->dstadr->sin)->sin_port) : 0)); 153754359Sroberto break; 153882502Sroberto 153982502Sroberto case CP_LEAP: 154054359Sroberto ctl_putuint(peer_var[CP_LEAP].text, peer->leap); 154154359Sroberto break; 154282502Sroberto 154382502Sroberto case CP_HMODE: 154454359Sroberto ctl_putuint(peer_var[CP_HMODE].text, peer->hmode); 154554359Sroberto break; 154682502Sroberto 154782502Sroberto case CP_STRATUM: 154854359Sroberto ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum); 154954359Sroberto break; 155082502Sroberto 155182502Sroberto case CP_PPOLL: 155254359Sroberto ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll); 155354359Sroberto break; 155482502Sroberto 155582502Sroberto case CP_HPOLL: 155654359Sroberto ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll); 155754359Sroberto break; 155882502Sroberto 155982502Sroberto case CP_PRECISION: 156082502Sroberto ctl_putint(peer_var[CP_PRECISION].text, 156182502Sroberto peer->precision); 156254359Sroberto break; 156382502Sroberto 156482502Sroberto case CP_ROOTDELAY: 156582502Sroberto ctl_putdbl(peer_var[CP_ROOTDELAY].text, 156682502Sroberto peer->rootdelay * 1e3); 156754359Sroberto break; 156882502Sroberto 156982502Sroberto case CP_ROOTDISPERSION: 157054359Sroberto ctl_putdbl(peer_var[CP_ROOTDISPERSION].text, 157182502Sroberto peer->rootdispersion * 1e3); 157254359Sroberto break; 157382502Sroberto 157482502Sroberto case CP_REFID: 1575132455Sroberto if (peer->flags & FLAG_REFCLOCK) { 1576182007Sroberto ctl_putid(peer_var[CP_REFID].text, 1577182007Sroberto (char *)&peer->refid); 157882502Sroberto } else { 1579132455Sroberto if (peer->stratum > 1 && peer->stratum < 1580132455Sroberto STRATUM_UNSPEC) 1581132455Sroberto ctl_putadr(peer_var[CP_REFID].text, 1582132455Sroberto peer->refid, NULL); 1583132455Sroberto else 1584132455Sroberto ctl_putid(peer_var[CP_REFID].text, 1585132455Sroberto (char *)&peer->refid); 158682502Sroberto } 158754359Sroberto break; 158882502Sroberto 158982502Sroberto case CP_REFTIME: 159054359Sroberto ctl_putts(peer_var[CP_REFTIME].text, &peer->reftime); 159154359Sroberto break; 159282502Sroberto 159382502Sroberto case CP_ORG: 159454359Sroberto ctl_putts(peer_var[CP_ORG].text, &peer->org); 159554359Sroberto break; 159682502Sroberto 159782502Sroberto case CP_REC: 159854359Sroberto ctl_putts(peer_var[CP_REC].text, &peer->rec); 159954359Sroberto break; 160082502Sroberto 160182502Sroberto case CP_XMT: 160254359Sroberto ctl_putts(peer_var[CP_XMT].text, &peer->xmt); 160354359Sroberto break; 160482502Sroberto 160582502Sroberto case CP_REACH: 160654359Sroberto ctl_puthex(peer_var[CP_REACH].text, peer->reach); 160754359Sroberto break; 160882502Sroberto 160982502Sroberto case CP_FLASH: 1610182007Sroberto temp = peer->flash; 1611182007Sroberto ctl_puthex(peer_var[CP_FLASH].text, temp); 161254359Sroberto break; 161382502Sroberto 161482502Sroberto case CP_TTL: 1615132455Sroberto ctl_putint(peer_var[CP_TTL].text, sys_ttl[peer->ttl]); 161654359Sroberto break; 161782502Sroberto 1618182007Sroberto case CP_UNREACH: 1619182007Sroberto ctl_putuint(peer_var[CP_UNREACH].text, peer->unreach); 162082502Sroberto break; 162182502Sroberto 162282502Sroberto case CP_TIMER: 162354359Sroberto ctl_putuint(peer_var[CP_TIMER].text, 162454359Sroberto peer->nextdate - current_time); 162554359Sroberto break; 162682502Sroberto 162782502Sroberto case CP_DELAY: 162854359Sroberto ctl_putdbl(peer_var[CP_DELAY].text, peer->delay * 1e3); 162954359Sroberto break; 163082502Sroberto 163182502Sroberto case CP_OFFSET: 163282502Sroberto ctl_putdbl(peer_var[CP_OFFSET].text, peer->offset * 163382502Sroberto 1e3); 163454359Sroberto break; 163582502Sroberto 163682502Sroberto case CP_JITTER: 1637182007Sroberto ctl_putdbl(peer_var[CP_JITTER].text, peer->jitter * 1e3); 163854359Sroberto break; 163982502Sroberto 164082502Sroberto case CP_DISPERSION: 164182502Sroberto ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp * 164282502Sroberto 1e3); 164354359Sroberto break; 164482502Sroberto 164582502Sroberto case CP_KEYID: 164654359Sroberto ctl_putuint(peer_var[CP_KEYID].text, peer->keyid); 164754359Sroberto break; 164882502Sroberto 164982502Sroberto case CP_FILTDELAY: 165054359Sroberto ctl_putarray(peer_var[CP_FILTDELAY].text, 165154359Sroberto peer->filter_delay, (int)peer->filter_nextpt); 165254359Sroberto break; 165382502Sroberto 165482502Sroberto case CP_FILTOFFSET: 165554359Sroberto ctl_putarray(peer_var[CP_FILTOFFSET].text, 165654359Sroberto peer->filter_offset, (int)peer->filter_nextpt); 165754359Sroberto break; 165882502Sroberto 165982502Sroberto case CP_FILTERROR: 166054359Sroberto ctl_putarray(peer_var[CP_FILTERROR].text, 166154359Sroberto peer->filter_disp, (int)peer->filter_nextpt); 166254359Sroberto break; 166382502Sroberto 166482502Sroberto case CP_PMODE: 166554359Sroberto ctl_putuint(peer_var[CP_PMODE].text, peer->pmode); 166654359Sroberto break; 166782502Sroberto 166882502Sroberto case CP_RECEIVED: 166954359Sroberto ctl_putuint(peer_var[CP_RECEIVED].text, peer->received); 167054359Sroberto break; 167182502Sroberto 167282502Sroberto case CP_SENT: 167354359Sroberto ctl_putuint(peer_var[CP_SENT].text, peer->sent); 167454359Sroberto break; 167554359Sroberto 167682502Sroberto case CP_VARLIST: 167782502Sroberto { 167882502Sroberto char buf[CTL_MAX_DATA_LEN]; 167982502Sroberto register char *s, *t, *be; 168082502Sroberto register int i; 168182502Sroberto register struct ctl_var *k; 168254359Sroberto 168382502Sroberto s = buf; 168482502Sroberto be = buf + sizeof(buf) - 168582502Sroberto strlen(peer_var[CP_VARLIST].text) - 4; 168682502Sroberto if (s > be) 168782502Sroberto break; /* really long var name */ 168854359Sroberto 168982502Sroberto strcpy(s, peer_var[CP_VARLIST].text); 169082502Sroberto strcat(s, "=\""); 169182502Sroberto s += strlen(s); 169282502Sroberto t = s; 169382502Sroberto for (k = peer_var; !(k->flags &EOV); k++) { 169482502Sroberto if (k->flags & PADDING) 169554359Sroberto continue; 169654359Sroberto 169782502Sroberto i = strlen(k->text); 169882502Sroberto if (s + i + 1 >= be) 169982502Sroberto break; 170082502Sroberto 170182502Sroberto if (s != t) 170254359Sroberto *s++ = ','; 170382502Sroberto strcpy(s, k->text); 170482502Sroberto s += i; 170582502Sroberto } 170682502Sroberto if (s+2 >= be) 170754359Sroberto break; 170854359Sroberto 170982502Sroberto *s++ = '"'; 171082502Sroberto *s = '\0'; 171182502Sroberto ctl_putdata(buf, (unsigned)(s - buf), 0); 171282502Sroberto } 171382502Sroberto break; 1714132455Sroberto#ifdef OPENSSL 171582502Sroberto case CP_FLAGS: 171682502Sroberto if (peer->crypto) 171782502Sroberto ctl_puthex(peer_var[CP_FLAGS].text, peer->crypto); 171882502Sroberto break; 171954359Sroberto 1720132455Sroberto case CP_DIGEST: 1721132455Sroberto if (peer->crypto) { 1722132455Sroberto const EVP_MD *dp; 1723132455Sroberto 1724132455Sroberto dp = EVP_get_digestbynid(peer->crypto >> 16); 1725132455Sroberto strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp))); 1726132455Sroberto ctl_putstr(peer_var[CP_DIGEST].text, str, 1727132455Sroberto strlen(str)); 1728132455Sroberto } 172982502Sroberto break; 173082502Sroberto 1731132455Sroberto case CP_HOST: 1732132455Sroberto if (peer->subject != NULL) 1733182007Sroberto ctl_putstr(peer_var[CP_HOST].text, 1734182007Sroberto peer->subject, strlen(peer->subject)); 173582502Sroberto break; 173682502Sroberto 1737182007Sroberto case CP_VALID: /* not used */ 1738182007Sroberto break; 1739182007Sroberto 1740132455Sroberto case CP_IDENT: 1741132455Sroberto if (peer->issuer != NULL) 1742182007Sroberto ctl_putstr(peer_var[CP_IDENT].text, 1743182007Sroberto peer->issuer, strlen(peer->issuer)); 174482502Sroberto break; 174582502Sroberto 174682502Sroberto case CP_INITSEQ: 1747132455Sroberto if ((ap = (struct autokey *)peer->recval.ptr) == NULL) 174854359Sroberto break; 1749132455Sroberto ctl_putint(peer_var[CP_INITSEQ].text, ap->seq); 1750132455Sroberto ctl_puthex(peer_var[CP_INITKEY].text, ap->key); 1751182007Sroberto ctl_putfs(peer_var[CP_INITTSP].text, 1752132455Sroberto ntohl(peer->recval.tstamp)); 175382502Sroberto break; 1754132455Sroberto#endif /* OPENSSL */ 175554359Sroberto } 175654359Sroberto} 175754359Sroberto 175854359Sroberto 175954359Sroberto#ifdef REFCLOCK 176054359Sroberto/* 176154359Sroberto * ctl_putclock - output clock variables 176254359Sroberto */ 176354359Srobertostatic void 176454359Srobertoctl_putclock( 176554359Sroberto int varid, 176654359Sroberto struct refclockstat *clock_stat, 176754359Sroberto int mustput 176854359Sroberto ) 176954359Sroberto{ 177054359Sroberto switch(varid) { 177182502Sroberto 177282502Sroberto case CC_TYPE: 177354359Sroberto if (mustput || clock_stat->clockdesc == NULL 177454359Sroberto || *(clock_stat->clockdesc) == '\0') { 177554359Sroberto ctl_putuint(clock_var[CC_TYPE].text, clock_stat->type); 177654359Sroberto } 177754359Sroberto break; 177882502Sroberto case CC_TIMECODE: 177982502Sroberto ctl_putstr(clock_var[CC_TIMECODE].text, 178082502Sroberto clock_stat->p_lastcode, 178182502Sroberto (unsigned)clock_stat->lencode); 178254359Sroberto break; 178382502Sroberto 178482502Sroberto case CC_POLL: 178554359Sroberto ctl_putuint(clock_var[CC_POLL].text, clock_stat->polls); 178654359Sroberto break; 178782502Sroberto 178882502Sroberto case CC_NOREPLY: 178982502Sroberto ctl_putuint(clock_var[CC_NOREPLY].text, 179082502Sroberto clock_stat->noresponse); 179154359Sroberto break; 179282502Sroberto 179382502Sroberto case CC_BADFORMAT: 179482502Sroberto ctl_putuint(clock_var[CC_BADFORMAT].text, 179582502Sroberto clock_stat->badformat); 179654359Sroberto break; 179782502Sroberto 179882502Sroberto case CC_BADDATA: 179982502Sroberto ctl_putuint(clock_var[CC_BADDATA].text, 180082502Sroberto clock_stat->baddata); 180154359Sroberto break; 180282502Sroberto 180382502Sroberto case CC_FUDGETIME1: 180482502Sroberto if (mustput || (clock_stat->haveflags & CLK_HAVETIME1)) 180554359Sroberto ctl_putdbl(clock_var[CC_FUDGETIME1].text, 180682502Sroberto clock_stat->fudgetime1 * 1e3); 180754359Sroberto break; 180882502Sroberto 180982502Sroberto case CC_FUDGETIME2: 181082502Sroberto if (mustput || (clock_stat->haveflags & CLK_HAVETIME2)) ctl_putdbl(clock_var[CC_FUDGETIME2].text, 181182502Sroberto clock_stat->fudgetime2 * 1e3); 181254359Sroberto break; 181382502Sroberto 181482502Sroberto case CC_FUDGEVAL1: 181554359Sroberto if (mustput || (clock_stat->haveflags & CLK_HAVEVAL1)) 181654359Sroberto ctl_putint(clock_var[CC_FUDGEVAL1].text, 181782502Sroberto clock_stat->fudgeval1); 181854359Sroberto break; 181982502Sroberto 182082502Sroberto case CC_FUDGEVAL2: 182154359Sroberto if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) { 182254359Sroberto if (clock_stat->fudgeval1 > 1) 182382502Sroberto ctl_putadr(clock_var[CC_FUDGEVAL2].text, 1824132455Sroberto (u_int32)clock_stat->fudgeval2, NULL); 182554359Sroberto else 182682502Sroberto ctl_putid(clock_var[CC_FUDGEVAL2].text, 182782502Sroberto (char *)&clock_stat->fudgeval2); 182854359Sroberto } 182954359Sroberto break; 183082502Sroberto 183182502Sroberto case CC_FLAGS: 183282502Sroberto if (mustput || (clock_stat->haveflags & (CLK_HAVEFLAG1 | 183382502Sroberto CLK_HAVEFLAG2 | CLK_HAVEFLAG3 | CLK_HAVEFLAG4))) 183482502Sroberto ctl_putuint(clock_var[CC_FLAGS].text, 183582502Sroberto clock_stat->flags); 183654359Sroberto break; 183782502Sroberto 183882502Sroberto case CC_DEVICE: 183982502Sroberto if (clock_stat->clockdesc == NULL || 184082502Sroberto *(clock_stat->clockdesc) == '\0') { 184154359Sroberto if (mustput) 184282502Sroberto ctl_putstr(clock_var[CC_DEVICE].text, 184382502Sroberto "", 0); 184454359Sroberto } else { 184582502Sroberto ctl_putstr(clock_var[CC_DEVICE].text, 184682502Sroberto clock_stat->clockdesc, 184782502Sroberto strlen(clock_stat->clockdesc)); 184854359Sroberto } 184954359Sroberto break; 185054359Sroberto 185182502Sroberto case CC_VARLIST: 185282502Sroberto { 185382502Sroberto char buf[CTL_MAX_DATA_LEN]; 185482502Sroberto register char *s, *t, *be; 185582502Sroberto register const char *ss; 185682502Sroberto register int i; 185782502Sroberto register struct ctl_var *k; 185854359Sroberto 185982502Sroberto s = buf; 186082502Sroberto be = buf + sizeof(buf); 186182502Sroberto if (s + strlen(clock_var[CC_VARLIST].text) + 4 > 186282502Sroberto be) 186382502Sroberto break; /* really long var name */ 186454359Sroberto 186582502Sroberto strcpy(s, clock_var[CC_VARLIST].text); 186682502Sroberto strcat(s, "=\""); 186782502Sroberto s += strlen(s); 186882502Sroberto t = s; 186982502Sroberto 187082502Sroberto for (k = clock_var; !(k->flags &EOV); k++) { 187182502Sroberto if (k->flags & PADDING) 187254359Sroberto continue; 187354359Sroberto 187482502Sroberto i = strlen(k->text); 187582502Sroberto if (s + i + 1 >= be) 187654359Sroberto break; 187754359Sroberto 187882502Sroberto if (s != t) 187982502Sroberto *s++ = ','; 188082502Sroberto strcpy(s, k->text); 188182502Sroberto s += i; 188282502Sroberto } 188382502Sroberto 188482502Sroberto for (k = clock_stat->kv_list; k && !(k->flags & 188582502Sroberto EOV); k++) { 188682502Sroberto if (k->flags & PADDING) 188754359Sroberto continue; 188854359Sroberto 188982502Sroberto ss = k->text; 189082502Sroberto if (!ss) 189154359Sroberto continue; 189254359Sroberto 189382502Sroberto while (*ss && *ss != '=') 189454359Sroberto ss++; 189582502Sroberto i = ss - k->text; 189682502Sroberto if (s+i+1 >= be) 189782502Sroberto break; 189854359Sroberto 189982502Sroberto if (s != t) 190054359Sroberto *s++ = ','; 190182502Sroberto strncpy(s, k->text, (unsigned)i); 190282502Sroberto s += i; 190382502Sroberto *s = '\0'; 190482502Sroberto } 190582502Sroberto if (s+2 >= be) 190654359Sroberto break; 190754359Sroberto 190882502Sroberto *s++ = '"'; 190982502Sroberto *s = '\0'; 191082502Sroberto ctl_putdata(buf, (unsigned)( s - buf ), 0); 191182502Sroberto } 191282502Sroberto break; 191354359Sroberto } 191454359Sroberto} 191554359Sroberto#endif 191654359Sroberto 191754359Sroberto 191854359Sroberto 191954359Sroberto/* 192054359Sroberto * ctl_getitem - get the next data item from the incoming packet 192154359Sroberto */ 192254359Srobertostatic struct ctl_var * 192354359Srobertoctl_getitem( 192454359Sroberto struct ctl_var *var_list, 192554359Sroberto char **data 192654359Sroberto ) 192754359Sroberto{ 192854359Sroberto register struct ctl_var *v; 192954359Sroberto register char *cp; 193054359Sroberto register char *tp; 193154359Sroberto static struct ctl_var eol = { 0, EOV, }; 193254359Sroberto static char buf[128]; 193354359Sroberto 193454359Sroberto /* 193554359Sroberto * Delete leading commas and white space 193654359Sroberto */ 193782502Sroberto while (reqpt < reqend && (*reqpt == ',' || 193882502Sroberto isspace((unsigned char)*reqpt))) 193954359Sroberto reqpt++; 194054359Sroberto if (reqpt >= reqend) 194182502Sroberto return (0); 194254359Sroberto 194354359Sroberto if (var_list == (struct ctl_var *)0) 194482502Sroberto return (&eol); 194554359Sroberto 194654359Sroberto /* 194754359Sroberto * Look for a first character match on the tag. If we find 194854359Sroberto * one, see if it is a full match. 194954359Sroberto */ 195054359Sroberto v = var_list; 195154359Sroberto cp = reqpt; 195254359Sroberto while (!(v->flags & EOV)) { 195354359Sroberto if (!(v->flags & PADDING) && *cp == *(v->text)) { 195454359Sroberto tp = v->text; 195582502Sroberto while (*tp != '\0' && *tp != '=' && cp < 195682502Sroberto reqend && *cp == *tp) { 195754359Sroberto cp++; 195854359Sroberto tp++; 195954359Sroberto } 196054359Sroberto if ((*tp == '\0') || (*tp == '=')) { 196175259Sjedgar while (cp < reqend && isspace((unsigned char)*cp)) 196254359Sroberto cp++; 196354359Sroberto if (cp == reqend || *cp == ',') { 196454359Sroberto buf[0] = '\0'; 196554359Sroberto *data = buf; 196654359Sroberto if (cp < reqend) 196754359Sroberto cp++; 196854359Sroberto reqpt = cp; 196954359Sroberto return v; 197054359Sroberto } 197154359Sroberto if (*cp == '=') { 197254359Sroberto cp++; 197354359Sroberto tp = buf; 1974132455Sroberto while (cp < reqend && isspace((unsigned char)*cp)) 197554359Sroberto cp++; 197675202Sphk while (cp < reqend && *cp != ',') { 197754359Sroberto *tp++ = *cp++; 1978182007Sroberto if (tp >= buf + sizeof(buf)) { 1979182007Sroberto ctl_error(CERR_BADFMT); 1980182007Sroberto numctlbadpkts++; 1981182007Sroberto#if 0 /* Avoid possible DOS attack */ 1982182007Sroberto/* If we get a smarter msyslog we can re-enable this */ 1983182007Sroberto msyslog(LOG_WARNING, 1984182007Sroberto "Possible 'ntpdx' exploit from %s:%d (possibly spoofed)\n", 1985182007Sroberto stoa(rmt_addr), SRCPORT(rmt_addr) 1986182007Sroberto ); 1987182007Sroberto#endif 198875202Sphk return (0); 1989182007Sroberto } 199075202Sphk } 199154359Sroberto if (cp < reqend) 199254359Sroberto cp++; 199382502Sroberto *tp-- = '\0'; 1994132455Sroberto while (tp >= buf) { 1995182007Sroberto if (!isspace((unsigned int)(*tp))) 199682502Sroberto break; 1997132455Sroberto *tp-- = '\0'; 199882502Sroberto } 199954359Sroberto reqpt = cp; 200054359Sroberto *data = buf; 200182502Sroberto return (v); 200254359Sroberto } 200354359Sroberto } 200454359Sroberto cp = reqpt; 200554359Sroberto } 200654359Sroberto v++; 200754359Sroberto } 200854359Sroberto return v; 200954359Sroberto} 201054359Sroberto 201154359Sroberto 201254359Sroberto/* 201354359Sroberto * control_unspec - response to an unspecified op-code 201454359Sroberto */ 201554359Sroberto/*ARGSUSED*/ 201654359Srobertostatic void 201754359Srobertocontrol_unspec( 201854359Sroberto struct recvbuf *rbufp, 201954359Sroberto int restrict_mask 202054359Sroberto ) 202154359Sroberto{ 202254359Sroberto struct peer *peer; 202354359Sroberto 202454359Sroberto /* 202554359Sroberto * What is an appropriate response to an unspecified op-code? 202654359Sroberto * I return no errors and no data, unless a specified assocation 202754359Sroberto * doesn't exist. 202854359Sroberto */ 202954359Sroberto if (res_associd != 0) { 203082502Sroberto if ((peer = findpeerbyassoc(res_associd)) == 0) { 203154359Sroberto ctl_error(CERR_BADASSOC); 203254359Sroberto return; 203354359Sroberto } 203454359Sroberto rpkt.status = htons(ctlpeerstatus(peer)); 203554359Sroberto } else { 203654359Sroberto rpkt.status = htons(ctlsysstatus()); 203754359Sroberto } 203854359Sroberto ctl_flushpkt(0); 203954359Sroberto} 204054359Sroberto 204154359Sroberto 204254359Sroberto/* 204354359Sroberto * read_status - return either a list of associd's, or a particular 204482502Sroberto * peer's status. 204554359Sroberto */ 204654359Sroberto/*ARGSUSED*/ 204754359Srobertostatic void 204854359Srobertoread_status( 204954359Sroberto struct recvbuf *rbufp, 205054359Sroberto int restrict_mask 205154359Sroberto ) 205254359Sroberto{ 205354359Sroberto register int i; 205454359Sroberto register struct peer *peer; 205582502Sroberto u_short ass_stat[CTL_MAX_DATA_LEN / sizeof(u_short)]; 205654359Sroberto 205754359Sroberto#ifdef DEBUG 205882502Sroberto if (debug > 2) 205954359Sroberto printf("read_status: ID %d\n", res_associd); 206054359Sroberto#endif 206154359Sroberto /* 206282502Sroberto * Two choices here. If the specified association ID is 206354359Sroberto * zero we return all known assocation ID's. Otherwise 206454359Sroberto * we return a bunch of stuff about the particular peer. 206554359Sroberto */ 206654359Sroberto if (res_associd == 0) { 206754359Sroberto register int n; 206854359Sroberto 206954359Sroberto n = 0; 207054359Sroberto rpkt.status = htons(ctlsysstatus()); 2071182007Sroberto for (i = 0; i < NTP_HASH_SIZE; i++) { 207254359Sroberto for (peer = assoc_hash[i]; peer != 0; 207382502Sroberto peer = peer->ass_next) { 207454359Sroberto ass_stat[n++] = htons(peer->associd); 207582502Sroberto ass_stat[n++] = 207682502Sroberto htons(ctlpeerstatus(peer)); 207782502Sroberto if (n == 207882502Sroberto CTL_MAX_DATA_LEN/sizeof(u_short)) { 207954359Sroberto ctl_putdata((char *)ass_stat, 208082502Sroberto n * sizeof(u_short), 1); 208154359Sroberto n = 0; 208254359Sroberto } 208354359Sroberto } 208454359Sroberto } 208554359Sroberto 208654359Sroberto if (n != 0) 208782502Sroberto ctl_putdata((char *)ass_stat, n * 208882502Sroberto sizeof(u_short), 1); 208954359Sroberto ctl_flushpkt(0); 209054359Sroberto } else { 209182502Sroberto peer = findpeerbyassoc(res_associd); 209254359Sroberto if (peer == 0) { 209354359Sroberto ctl_error(CERR_BADASSOC); 209454359Sroberto } else { 209554359Sroberto register u_char *cp; 209654359Sroberto 209754359Sroberto rpkt.status = htons(ctlpeerstatus(peer)); 209854359Sroberto if (res_authokay) 209954359Sroberto peer->num_events = 0; 210054359Sroberto /* 210182502Sroberto * For now, output everything we know about the 210282502Sroberto * peer. May be more selective later. 210354359Sroberto */ 210454359Sroberto for (cp = def_peer_var; *cp != 0; cp++) 210554359Sroberto ctl_putpeer((int)*cp, peer); 210654359Sroberto ctl_flushpkt(0); 210754359Sroberto } 210854359Sroberto } 210954359Sroberto} 211054359Sroberto 211154359Sroberto 211254359Sroberto/* 211354359Sroberto * read_variables - return the variables the caller asks for 211454359Sroberto */ 211554359Sroberto/*ARGSUSED*/ 211654359Srobertostatic void 211754359Srobertoread_variables( 211854359Sroberto struct recvbuf *rbufp, 211954359Sroberto int restrict_mask 212054359Sroberto ) 212154359Sroberto{ 212254359Sroberto register struct ctl_var *v; 212354359Sroberto register int i; 212454359Sroberto char *valuep; 212554359Sroberto u_char *wants; 212682502Sroberto unsigned int gotvar = (CS_MAXCODE > CP_MAXCODE) ? (CS_MAXCODE + 212782502Sroberto 1) : (CP_MAXCODE + 1); 212854359Sroberto if (res_associd == 0) { 212954359Sroberto /* 213082502Sroberto * Wants system variables. Figure out which he wants 213154359Sroberto * and give them to him. 213254359Sroberto */ 213354359Sroberto rpkt.status = htons(ctlsysstatus()); 213454359Sroberto if (res_authokay) 213554359Sroberto ctl_sys_num_events = 0; 213654359Sroberto gotvar += count_var(ext_sys_var); 213754359Sroberto wants = (u_char *)emalloc(gotvar); 213854359Sroberto memset((char *)wants, 0, gotvar); 213954359Sroberto gotvar = 0; 214054359Sroberto while ((v = ctl_getitem(sys_var, &valuep)) != 0) { 214154359Sroberto if (v->flags & EOV) { 214282502Sroberto if ((v = ctl_getitem(ext_sys_var, 214382502Sroberto &valuep)) != 0) { 214454359Sroberto if (v->flags & EOV) { 214554359Sroberto ctl_error(CERR_UNKNOWNVAR); 214654359Sroberto free((char *)wants); 214754359Sroberto return; 214854359Sroberto } 214982502Sroberto wants[CS_MAXCODE + 1 + 215082502Sroberto v->code] = 1; 215154359Sroberto gotvar = 1; 215254359Sroberto continue; 215354359Sroberto } else { 215454359Sroberto break; /* shouldn't happen ! */ 215554359Sroberto } 215654359Sroberto } 215754359Sroberto wants[v->code] = 1; 215854359Sroberto gotvar = 1; 215954359Sroberto } 216054359Sroberto if (gotvar) { 216154359Sroberto for (i = 1; i <= CS_MAXCODE; i++) 216254359Sroberto if (wants[i]) 216382502Sroberto ctl_putsys(i); 216482502Sroberto for (i = 0; ext_sys_var && 216582502Sroberto !(ext_sys_var[i].flags & EOV); i++) 216682502Sroberto if (wants[i + CS_MAXCODE + 1]) 216782502Sroberto ctl_putdata(ext_sys_var[i].text, 216882502Sroberto strlen(ext_sys_var[i].text), 216982502Sroberto 0); 217054359Sroberto } else { 217154359Sroberto register u_char *cs; 217254359Sroberto register struct ctl_var *kv; 217354359Sroberto 217454359Sroberto for (cs = def_sys_var; *cs != 0; cs++) 217554359Sroberto ctl_putsys((int)*cs); 217682502Sroberto for (kv = ext_sys_var; kv && !(kv->flags & EOV); 217782502Sroberto kv++) 217854359Sroberto if (kv->flags & DEF) 217982502Sroberto ctl_putdata(kv->text, 218082502Sroberto strlen(kv->text), 0); 218154359Sroberto } 218254359Sroberto free((char *)wants); 218354359Sroberto } else { 218454359Sroberto register struct peer *peer; 218554359Sroberto 218654359Sroberto /* 218782502Sroberto * Wants info for a particular peer. See if we know 218854359Sroberto * the guy. 218954359Sroberto */ 219082502Sroberto peer = findpeerbyassoc(res_associd); 219154359Sroberto if (peer == 0) { 219254359Sroberto ctl_error(CERR_BADASSOC); 219354359Sroberto return; 219454359Sroberto } 219554359Sroberto rpkt.status = htons(ctlpeerstatus(peer)); 219654359Sroberto if (res_authokay) 219754359Sroberto peer->num_events = 0; 219854359Sroberto wants = (u_char *)emalloc(gotvar); 219954359Sroberto memset((char*)wants, 0, gotvar); 220054359Sroberto gotvar = 0; 220154359Sroberto while ((v = ctl_getitem(peer_var, &valuep)) != 0) { 220254359Sroberto if (v->flags & EOV) { 220354359Sroberto ctl_error(CERR_UNKNOWNVAR); 220454359Sroberto free((char *)wants); 220554359Sroberto return; 220654359Sroberto } 220754359Sroberto wants[v->code] = 1; 220854359Sroberto gotvar = 1; 220954359Sroberto } 221054359Sroberto if (gotvar) { 221154359Sroberto for (i = 1; i <= CP_MAXCODE; i++) 221254359Sroberto if (wants[i]) 221382502Sroberto ctl_putpeer(i, peer); 221454359Sroberto } else { 221554359Sroberto register u_char *cp; 221654359Sroberto 221754359Sroberto for (cp = def_peer_var; *cp != 0; cp++) 221854359Sroberto ctl_putpeer((int)*cp, peer); 221954359Sroberto } 222054359Sroberto free((char *)wants); 222154359Sroberto } 222254359Sroberto ctl_flushpkt(0); 222354359Sroberto} 222454359Sroberto 222554359Sroberto 222654359Sroberto/* 222782502Sroberto * write_variables - write into variables. We only allow leap bit 222882502Sroberto * writing this way. 222954359Sroberto */ 223054359Sroberto/*ARGSUSED*/ 223154359Srobertostatic void 223254359Srobertowrite_variables( 223354359Sroberto struct recvbuf *rbufp, 223454359Sroberto int restrict_mask 223554359Sroberto ) 223654359Sroberto{ 223754359Sroberto register struct ctl_var *v; 223854359Sroberto register int ext_var; 223954359Sroberto char *valuep; 2240132455Sroberto long val = 0; 224154359Sroberto 224254359Sroberto /* 224354359Sroberto * If he's trying to write into a peer tell him no way 224454359Sroberto */ 224554359Sroberto if (res_associd != 0) { 224654359Sroberto ctl_error(CERR_PERMISSION); 224754359Sroberto return; 224854359Sroberto } 224954359Sroberto 225054359Sroberto /* 225154359Sroberto * Set status 225254359Sroberto */ 225354359Sroberto rpkt.status = htons(ctlsysstatus()); 225454359Sroberto 225554359Sroberto /* 225682502Sroberto * Look through the variables. Dump out at the first sign of 225782502Sroberto * trouble. 225854359Sroberto */ 225954359Sroberto while ((v = ctl_getitem(sys_var, &valuep)) != 0) { 226054359Sroberto ext_var = 0; 226154359Sroberto if (v->flags & EOV) { 226282502Sroberto if ((v = ctl_getitem(ext_sys_var, &valuep)) != 226382502Sroberto 0) { 226454359Sroberto if (v->flags & EOV) { 226554359Sroberto ctl_error(CERR_UNKNOWNVAR); 226654359Sroberto return; 226754359Sroberto } 226854359Sroberto ext_var = 1; 226954359Sroberto } else { 227054359Sroberto break; 227154359Sroberto } 227254359Sroberto } 227354359Sroberto if (!(v->flags & CAN_WRITE)) { 227454359Sroberto ctl_error(CERR_PERMISSION); 227554359Sroberto return; 227654359Sroberto } 227782502Sroberto if (!ext_var && (*valuep == '\0' || !atoint(valuep, 227882502Sroberto &val))) { 227954359Sroberto ctl_error(CERR_BADFMT); 228054359Sroberto return; 228154359Sroberto } 228254359Sroberto if (!ext_var && (val & ~LEAP_NOTINSYNC) != 0) { 228354359Sroberto ctl_error(CERR_BADVALUE); 228454359Sroberto return; 228554359Sroberto } 228654359Sroberto 228754359Sroberto if (ext_var) { 228882502Sroberto char *s = (char *)emalloc(strlen(v->text) + 228982502Sroberto strlen(valuep) + 2); 229054359Sroberto const char *t; 229154359Sroberto char *tt = s; 229254359Sroberto 229354359Sroberto t = v->text; 229454359Sroberto while (*t && *t != '=') 229554359Sroberto *tt++ = *t++; 229654359Sroberto 229754359Sroberto *tt++ = '='; 229854359Sroberto strcat(tt, valuep); 229954359Sroberto set_sys_var(s, strlen(s)+1, v->flags); 230054359Sroberto free(s); 230154359Sroberto } else { 230254359Sroberto /* 230382502Sroberto * This one seems sane. Save it. 230454359Sroberto */ 230554359Sroberto switch(v->code) { 230682502Sroberto 230782502Sroberto case CS_LEAP: 230882502Sroberto default: 230982502Sroberto ctl_error(CERR_UNSPEC); /* really */ 231054359Sroberto return; 231154359Sroberto } 231254359Sroberto } 231354359Sroberto } 231454359Sroberto 231554359Sroberto /* 231682502Sroberto * If we got anything, do it. xxx nothing to do *** 231754359Sroberto */ 231854359Sroberto /* 231954359Sroberto if (leapind != ~0 || leapwarn != ~0) { 232054359Sroberto if (!leap_setleap((int)leapind, (int)leapwarn)) { 232154359Sroberto ctl_error(CERR_PERMISSION); 232254359Sroberto return; 232354359Sroberto } 232454359Sroberto } 232554359Sroberto */ 232654359Sroberto ctl_flushpkt(0); 232754359Sroberto} 232854359Sroberto 232954359Sroberto 233054359Sroberto/* 233154359Sroberto * read_clock_status - return clock radio status 233254359Sroberto */ 233354359Sroberto/*ARGSUSED*/ 233454359Srobertostatic void 233554359Srobertoread_clock_status( 233654359Sroberto struct recvbuf *rbufp, 233754359Sroberto int restrict_mask 233854359Sroberto ) 233954359Sroberto{ 234054359Sroberto#ifndef REFCLOCK 234154359Sroberto /* 234254359Sroberto * If no refclock support, no data to return 234354359Sroberto */ 234454359Sroberto ctl_error(CERR_BADASSOC); 234554359Sroberto#else 234654359Sroberto register struct ctl_var *v; 234754359Sroberto register int i; 234854359Sroberto register struct peer *peer; 234954359Sroberto char *valuep; 235054359Sroberto u_char *wants; 235154359Sroberto unsigned int gotvar; 235254359Sroberto struct refclockstat clock_stat; 235354359Sroberto 235454359Sroberto if (res_associd == 0) { 235582502Sroberto 235654359Sroberto /* 235754359Sroberto * Find a clock for this jerk. If the system peer 235854359Sroberto * is a clock use it, else search the hash tables 235954359Sroberto * for one. 236054359Sroberto */ 236182502Sroberto if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK)) 236282502Sroberto { 236354359Sroberto peer = sys_peer; 236454359Sroberto } else { 236554359Sroberto peer = 0; 2366182007Sroberto for (i = 0; peer == 0 && i < NTP_HASH_SIZE; i++) { 236754359Sroberto for (peer = assoc_hash[i]; peer != 0; 236882502Sroberto peer = peer->ass_next) { 236954359Sroberto if (peer->flags & FLAG_REFCLOCK) 237054359Sroberto break; 237154359Sroberto } 237254359Sroberto } 237354359Sroberto if (peer == 0) { 237454359Sroberto ctl_error(CERR_BADASSOC); 237554359Sroberto return; 237654359Sroberto } 237754359Sroberto } 237854359Sroberto } else { 237982502Sroberto peer = findpeerbyassoc(res_associd); 238054359Sroberto if (peer == 0 || !(peer->flags & FLAG_REFCLOCK)) { 238154359Sroberto ctl_error(CERR_BADASSOC); 238254359Sroberto return; 238354359Sroberto } 238454359Sroberto } 238554359Sroberto 238654359Sroberto /* 238782502Sroberto * If we got here we have a peer which is a clock. Get his 238882502Sroberto * status. 238954359Sroberto */ 239054359Sroberto clock_stat.kv_list = (struct ctl_var *)0; 239182502Sroberto refclock_control(&peer->srcadr, (struct refclockstat *)0, 239282502Sroberto &clock_stat); 239354359Sroberto 239454359Sroberto /* 239554359Sroberto * Look for variables in the packet. 239654359Sroberto */ 239754359Sroberto rpkt.status = htons(ctlclkstatus(&clock_stat)); 239882502Sroberto gotvar = CC_MAXCODE + 1 + count_var(clock_stat.kv_list); 239954359Sroberto wants = (u_char *)emalloc(gotvar); 240054359Sroberto memset((char*)wants, 0, gotvar); 240154359Sroberto gotvar = 0; 240254359Sroberto while ((v = ctl_getitem(clock_var, &valuep)) != 0) { 240354359Sroberto if (v->flags & EOV) { 240482502Sroberto if ((v = ctl_getitem(clock_stat.kv_list, 240582502Sroberto &valuep)) != 0) { 240654359Sroberto if (v->flags & EOV) { 240754359Sroberto ctl_error(CERR_UNKNOWNVAR); 240854359Sroberto free((char*)wants); 240954359Sroberto free_varlist(clock_stat.kv_list); 241054359Sroberto return; 241154359Sroberto } 241282502Sroberto wants[CC_MAXCODE + 1 + v->code] = 1; 241354359Sroberto gotvar = 1; 241454359Sroberto continue; 241554359Sroberto } else { 241654359Sroberto break; /* shouldn't happen ! */ 241754359Sroberto } 241854359Sroberto } 241954359Sroberto wants[v->code] = 1; 242054359Sroberto gotvar = 1; 242154359Sroberto } 242254359Sroberto 242354359Sroberto if (gotvar) { 242454359Sroberto for (i = 1; i <= CC_MAXCODE; i++) 242554359Sroberto if (wants[i]) 242654359Sroberto ctl_putclock(i, &clock_stat, 1); 242782502Sroberto for (i = 0; clock_stat.kv_list && 242882502Sroberto !(clock_stat.kv_list[i].flags & EOV); i++) 242982502Sroberto if (wants[i + CC_MAXCODE + 1]) 243082502Sroberto ctl_putdata(clock_stat.kv_list[i].text, 243182502Sroberto strlen(clock_stat.kv_list[i].text), 243282502Sroberto 0); 243354359Sroberto } else { 243454359Sroberto register u_char *cc; 243554359Sroberto register struct ctl_var *kv; 243654359Sroberto 243754359Sroberto for (cc = def_clock_var; *cc != 0; cc++) 243854359Sroberto ctl_putclock((int)*cc, &clock_stat, 0); 243982502Sroberto for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV); 244082502Sroberto kv++) 244154359Sroberto if (kv->flags & DEF) 244282502Sroberto ctl_putdata(kv->text, strlen(kv->text), 244382502Sroberto 0); 244454359Sroberto } 244554359Sroberto 244654359Sroberto free((char*)wants); 244754359Sroberto free_varlist(clock_stat.kv_list); 244854359Sroberto 244954359Sroberto ctl_flushpkt(0); 245054359Sroberto#endif 245154359Sroberto} 245254359Sroberto 245354359Sroberto 245454359Sroberto/* 245554359Sroberto * write_clock_status - we don't do this 245654359Sroberto */ 245754359Sroberto/*ARGSUSED*/ 245854359Srobertostatic void 245954359Srobertowrite_clock_status( 246054359Sroberto struct recvbuf *rbufp, 246154359Sroberto int restrict_mask 246254359Sroberto ) 246354359Sroberto{ 246454359Sroberto ctl_error(CERR_PERMISSION); 246554359Sroberto} 246654359Sroberto 246754359Sroberto/* 246882502Sroberto * Trap support from here on down. We send async trap messages when the 246982502Sroberto * upper levels report trouble. Traps can by set either by control 247054359Sroberto * messages or by configuration. 247154359Sroberto */ 247254359Sroberto/* 247354359Sroberto * set_trap - set a trap in response to a control message 247454359Sroberto */ 247554359Srobertostatic void 247654359Srobertoset_trap( 247754359Sroberto struct recvbuf *rbufp, 247854359Sroberto int restrict_mask 247954359Sroberto ) 248054359Sroberto{ 248154359Sroberto int traptype; 248254359Sroberto 248354359Sroberto /* 248454359Sroberto * See if this guy is allowed 248554359Sroberto */ 248654359Sroberto if (restrict_mask & RES_NOTRAP) { 248754359Sroberto ctl_error(CERR_PERMISSION); 248854359Sroberto return; 248954359Sroberto } 249054359Sroberto 249154359Sroberto /* 249254359Sroberto * Determine his allowed trap type. 249354359Sroberto */ 249454359Sroberto traptype = TRAP_TYPE_PRIO; 249554359Sroberto if (restrict_mask & RES_LPTRAP) 249654359Sroberto traptype = TRAP_TYPE_NONPRIO; 249754359Sroberto 249854359Sroberto /* 249954359Sroberto * Call ctlsettrap() to do the work. Return 250054359Sroberto * an error if it can't assign the trap. 250154359Sroberto */ 250254359Sroberto if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype, 250382502Sroberto (int)res_version)) 250454359Sroberto ctl_error(CERR_NORESOURCE); 250554359Sroberto ctl_flushpkt(0); 250654359Sroberto} 250754359Sroberto 250854359Sroberto 250954359Sroberto/* 251054359Sroberto * unset_trap - unset a trap in response to a control message 251154359Sroberto */ 251254359Srobertostatic void 251354359Srobertounset_trap( 251454359Sroberto struct recvbuf *rbufp, 251554359Sroberto int restrict_mask 251654359Sroberto ) 251754359Sroberto{ 251854359Sroberto int traptype; 251954359Sroberto 252054359Sroberto /* 252182502Sroberto * We don't prevent anyone from removing his own trap unless the 252282502Sroberto * trap is configured. Note we also must be aware of the 252382502Sroberto * possibility that restriction flags were changed since this 252482502Sroberto * guy last set his trap. Set the trap type based on this. 252554359Sroberto */ 252654359Sroberto traptype = TRAP_TYPE_PRIO; 252754359Sroberto if (restrict_mask & RES_LPTRAP) 252854359Sroberto traptype = TRAP_TYPE_NONPRIO; 252954359Sroberto 253054359Sroberto /* 253154359Sroberto * Call ctlclrtrap() to clear this out. 253254359Sroberto */ 253354359Sroberto if (!ctlclrtrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype)) 253454359Sroberto ctl_error(CERR_BADASSOC); 253554359Sroberto ctl_flushpkt(0); 253654359Sroberto} 253754359Sroberto 253854359Sroberto 253954359Sroberto/* 254054359Sroberto * ctlsettrap - called to set a trap 254154359Sroberto */ 254254359Srobertoint 254354359Srobertoctlsettrap( 2544132455Sroberto struct sockaddr_storage *raddr, 254554359Sroberto struct interface *linter, 254654359Sroberto int traptype, 254754359Sroberto int version 254854359Sroberto ) 254954359Sroberto{ 255054359Sroberto register struct ctl_trap *tp; 255154359Sroberto register struct ctl_trap *tptouse; 255254359Sroberto 255354359Sroberto /* 255454359Sroberto * See if we can find this trap. If so, we only need update 255554359Sroberto * the flags and the time. 255654359Sroberto */ 255754359Sroberto if ((tp = ctlfindtrap(raddr, linter)) != NULL) { 255854359Sroberto switch (traptype) { 255982502Sroberto 256082502Sroberto case TRAP_TYPE_CONFIG: 256154359Sroberto tp->tr_flags = TRAP_INUSE|TRAP_CONFIGURED; 256254359Sroberto break; 256382502Sroberto 256482502Sroberto case TRAP_TYPE_PRIO: 256554359Sroberto if (tp->tr_flags & TRAP_CONFIGURED) 256682502Sroberto return (1); /* don't change anything */ 256754359Sroberto tp->tr_flags = TRAP_INUSE; 256854359Sroberto break; 256982502Sroberto 257082502Sroberto case TRAP_TYPE_NONPRIO: 257154359Sroberto if (tp->tr_flags & TRAP_CONFIGURED) 257282502Sroberto return (1); /* don't change anything */ 257354359Sroberto tp->tr_flags = TRAP_INUSE|TRAP_NONPRIO; 257454359Sroberto break; 257554359Sroberto } 257654359Sroberto tp->tr_settime = current_time; 257754359Sroberto tp->tr_resets++; 257882502Sroberto return (1); 257954359Sroberto } 258054359Sroberto 258154359Sroberto /* 258254359Sroberto * First we heard of this guy. Try to find a trap structure 258354359Sroberto * for him to use, clearing out lesser priority guys if we 258482502Sroberto * have to. Clear out anyone who's expired while we're at it. 258554359Sroberto */ 258654359Sroberto tptouse = NULL; 258754359Sroberto for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) { 258854359Sroberto if ((tp->tr_flags & TRAP_INUSE) && 258982502Sroberto !(tp->tr_flags & TRAP_CONFIGURED) && 259082502Sroberto ((tp->tr_settime + CTL_TRAPTIME) > current_time)) { 259154359Sroberto tp->tr_flags = 0; 259254359Sroberto num_ctl_traps--; 259354359Sroberto } 259454359Sroberto if (!(tp->tr_flags & TRAP_INUSE)) { 259554359Sroberto tptouse = tp; 259654359Sroberto } else if (!(tp->tr_flags & TRAP_CONFIGURED)) { 259754359Sroberto switch (traptype) { 259882502Sroberto 259982502Sroberto case TRAP_TYPE_CONFIG: 260054359Sroberto if (tptouse == NULL) { 260154359Sroberto tptouse = tp; 260254359Sroberto break; 260354359Sroberto } 260482502Sroberto if (tptouse->tr_flags & TRAP_NONPRIO && 260582502Sroberto !(tp->tr_flags & TRAP_NONPRIO)) 260654359Sroberto break; 260782502Sroberto 260854359Sroberto if (!(tptouse->tr_flags & TRAP_NONPRIO) 260982502Sroberto && tp->tr_flags & TRAP_NONPRIO) { 261054359Sroberto tptouse = tp; 261154359Sroberto break; 261254359Sroberto } 261382502Sroberto if (tptouse->tr_origtime < 261482502Sroberto tp->tr_origtime) 261554359Sroberto tptouse = tp; 261654359Sroberto break; 261782502Sroberto 261882502Sroberto case TRAP_TYPE_PRIO: 261954359Sroberto if (tp->tr_flags & TRAP_NONPRIO) { 262054359Sroberto if (tptouse == NULL || 262182502Sroberto (tptouse->tr_flags & 262282502Sroberto TRAP_INUSE && 262382502Sroberto tptouse->tr_origtime < 262482502Sroberto tp->tr_origtime)) 262554359Sroberto tptouse = tp; 262654359Sroberto } 262754359Sroberto break; 262882502Sroberto 262982502Sroberto case TRAP_TYPE_NONPRIO: 263054359Sroberto break; 263154359Sroberto } 263254359Sroberto } 263354359Sroberto } 263454359Sroberto 263554359Sroberto /* 263654359Sroberto * If we don't have room for him return an error. 263754359Sroberto */ 263854359Sroberto if (tptouse == NULL) 263982502Sroberto return (0); 264054359Sroberto 264154359Sroberto /* 264254359Sroberto * Set up this structure for him. 264354359Sroberto */ 264454359Sroberto tptouse->tr_settime = tptouse->tr_origtime = current_time; 264554359Sroberto tptouse->tr_count = tptouse->tr_resets = 0; 264654359Sroberto tptouse->tr_sequence = 1; 264754359Sroberto tptouse->tr_addr = *raddr; 264854359Sroberto tptouse->tr_localaddr = linter; 2649132455Sroberto tptouse->tr_version = (u_char) version; 265054359Sroberto tptouse->tr_flags = TRAP_INUSE; 265154359Sroberto if (traptype == TRAP_TYPE_CONFIG) 265254359Sroberto tptouse->tr_flags |= TRAP_CONFIGURED; 265354359Sroberto else if (traptype == TRAP_TYPE_NONPRIO) 265454359Sroberto tptouse->tr_flags |= TRAP_NONPRIO; 265554359Sroberto num_ctl_traps++; 265682502Sroberto return (1); 265754359Sroberto} 265854359Sroberto 265954359Sroberto 266054359Sroberto/* 266182502Sroberto * ctlclrtrap - called to clear a trap 266254359Sroberto */ 266354359Srobertoint 266454359Srobertoctlclrtrap( 2665132455Sroberto struct sockaddr_storage *raddr, 266654359Sroberto struct interface *linter, 266754359Sroberto int traptype 266854359Sroberto ) 266954359Sroberto{ 267054359Sroberto register struct ctl_trap *tp; 267154359Sroberto 267254359Sroberto if ((tp = ctlfindtrap(raddr, linter)) == NULL) 267382502Sroberto return (0); 267454359Sroberto 267554359Sroberto if (tp->tr_flags & TRAP_CONFIGURED 267654359Sroberto && traptype != TRAP_TYPE_CONFIG) 267782502Sroberto return (0); 267854359Sroberto 267954359Sroberto tp->tr_flags = 0; 268054359Sroberto num_ctl_traps--; 268182502Sroberto return (1); 268254359Sroberto} 268354359Sroberto 268454359Sroberto 268554359Sroberto/* 268654359Sroberto * ctlfindtrap - find a trap given the remote and local addresses 268754359Sroberto */ 268854359Srobertostatic struct ctl_trap * 268954359Srobertoctlfindtrap( 2690132455Sroberto struct sockaddr_storage *raddr, 269154359Sroberto struct interface *linter 269254359Sroberto ) 269354359Sroberto{ 269454359Sroberto register struct ctl_trap *tp; 269554359Sroberto 269654359Sroberto for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) { 2697132455Sroberto if ((tp->tr_flags & TRAP_INUSE) 2698132455Sroberto && (NSRCPORT(raddr) == NSRCPORT(&tp->tr_addr)) 2699132455Sroberto && SOCKCMP(raddr, &tp->tr_addr) 2700132455Sroberto && (linter == tp->tr_localaddr) ) 2701132455Sroberto return (tp); 270254359Sroberto } 270354359Sroberto return (struct ctl_trap *)NULL; 270454359Sroberto} 270554359Sroberto 270654359Sroberto 270754359Sroberto/* 270854359Sroberto * report_event - report an event to the trappers 270954359Sroberto */ 271054359Srobertovoid 271154359Srobertoreport_event( 271254359Sroberto int err, 271354359Sroberto struct peer *peer 271454359Sroberto ) 271554359Sroberto{ 271654359Sroberto register int i; 271754359Sroberto 271854359Sroberto /* 271954359Sroberto * Record error code in proper spots, but have mercy on the 272054359Sroberto * log file. 272154359Sroberto */ 2722132455Sroberto if (!(err & (PEER_EVENT | CRPT_EVENT))) { 272354359Sroberto if (ctl_sys_num_events < CTL_SYS_MAXEVENTS) 272454359Sroberto ctl_sys_num_events++; 272554359Sroberto if (ctl_sys_last_event != (u_char)err) { 272654359Sroberto NLOG(NLOG_SYSEVENT) 272782502Sroberto msyslog(LOG_INFO, "system event '%s' (0x%02x) status '%s' (0x%02x)", 272882502Sroberto eventstr(err), err, 272982502Sroberto sysstatstr(ctlsysstatus()), ctlsysstatus()); 273054359Sroberto#ifdef DEBUG 273154359Sroberto if (debug) 273254359Sroberto printf("report_event: system event '%s' (0x%02x) status '%s' (0x%02x)\n", 273382502Sroberto eventstr(err), err, 273482502Sroberto sysstatstr(ctlsysstatus()), 273582502Sroberto ctlsysstatus()); 273654359Sroberto#endif 273754359Sroberto ctl_sys_last_event = (u_char)err; 273854359Sroberto } 273954359Sroberto } else if (peer != 0) { 274054359Sroberto char *src; 274154359Sroberto 274254359Sroberto#ifdef REFCLOCK 274354359Sroberto if (ISREFCLOCKADR(&peer->srcadr)) 2744132455Sroberto src = refnumtoa(&peer->srcadr); 274554359Sroberto else 274654359Sroberto#endif 2747132455Sroberto src = stoa(&peer->srcadr); 274854359Sroberto 274954359Sroberto peer->last_event = (u_char)(err & ~PEER_EVENT); 275054359Sroberto if (peer->num_events < CTL_PEER_MAXEVENTS) 275154359Sroberto peer->num_events++; 275254359Sroberto NLOG(NLOG_PEEREVENT) 275382502Sroberto msyslog(LOG_INFO, "peer %s event '%s' (0x%02x) status '%s' (0x%02x)", 275482502Sroberto src, eventstr(err), err, 275582502Sroberto peerstatstr(ctlpeerstatus(peer)), 275682502Sroberto ctlpeerstatus(peer)); 275754359Sroberto#ifdef DEBUG 275854359Sroberto if (debug) 275954359Sroberto printf( "peer %s event '%s' (0x%02x) status '%s' (0x%02x)\n", 276082502Sroberto src, eventstr(err), err, 276182502Sroberto peerstatstr(ctlpeerstatus(peer)), 276282502Sroberto ctlpeerstatus(peer)); 276354359Sroberto#endif 276454359Sroberto } else { 276582502Sroberto msyslog(LOG_ERR, 276682502Sroberto "report_event: err '%s' (0x%02x), no peer", 276782502Sroberto eventstr(err), err); 276854359Sroberto#ifdef DEBUG 276982502Sroberto printf( 277082502Sroberto "report_event: peer event '%s' (0x%02x), no peer\n", 277182502Sroberto eventstr(err), err); 277254359Sroberto#endif 277354359Sroberto return; 277454359Sroberto } 277554359Sroberto 277654359Sroberto /* 277754359Sroberto * If no trappers, return. 277854359Sroberto */ 277954359Sroberto if (num_ctl_traps <= 0) 278054359Sroberto return; 278154359Sroberto 278254359Sroberto /* 278354359Sroberto * Set up the outgoing packet variables 278454359Sroberto */ 278554359Sroberto res_opcode = CTL_OP_ASYNCMSG; 278654359Sroberto res_offset = 0; 278754359Sroberto res_async = 1; 278854359Sroberto res_authenticate = 0; 278954359Sroberto datapt = rpkt.data; 279054359Sroberto dataend = &(rpkt.data[CTL_MAX_DATA_LEN]); 279154359Sroberto if (!(err & PEER_EVENT)) { 279254359Sroberto rpkt.associd = 0; 279354359Sroberto rpkt.status = htons(ctlsysstatus()); 279454359Sroberto 279554359Sroberto /* 279654359Sroberto * For now, put everything we know about system 279782502Sroberto * variables. Don't send crypto strings. 279854359Sroberto */ 279982502Sroberto for (i = 1; i <= CS_MAXCODE; i++) { 2800132455Sroberto#ifdef OPENSSL 280182502Sroberto if (i > CS_VARLIST) 280282502Sroberto continue; 2803132455Sroberto#endif /* OPENSSL */ 280454359Sroberto ctl_putsys(i); 280582502Sroberto } 280654359Sroberto#ifdef REFCLOCK 280754359Sroberto /* 280882502Sroberto * for clock exception events: add clock variables to 280982502Sroberto * reflect info on exception 281054359Sroberto */ 281154359Sroberto if (err == EVNT_CLOCKEXCPT) { 281254359Sroberto struct refclockstat clock_stat; 281354359Sroberto struct ctl_var *kv; 281454359Sroberto 281554359Sroberto clock_stat.kv_list = (struct ctl_var *)0; 281654359Sroberto refclock_control(&peer->srcadr, 281782502Sroberto (struct refclockstat *)0, &clock_stat); 281882502Sroberto ctl_puthex("refclockstatus", 281982502Sroberto ctlclkstatus(&clock_stat)); 282054359Sroberto for (i = 1; i <= CC_MAXCODE; i++) 282154359Sroberto ctl_putclock(i, &clock_stat, 0); 282282502Sroberto for (kv = clock_stat.kv_list; kv && 282382502Sroberto !(kv->flags & EOV); kv++) 282454359Sroberto if (kv->flags & DEF) 282582502Sroberto ctl_putdata(kv->text, 282682502Sroberto strlen(kv->text), 0); 282754359Sroberto free_varlist(clock_stat.kv_list); 282854359Sroberto } 2829132455Sroberto#endif /* REFCLOCK */ 283054359Sroberto } else { 283154359Sroberto rpkt.associd = htons(peer->associd); 283254359Sroberto rpkt.status = htons(ctlpeerstatus(peer)); 283354359Sroberto 283454359Sroberto /* 283582502Sroberto * Dump it all. Later, maybe less. 283654359Sroberto */ 2837132455Sroberto for (i = 1; i <= CP_MAXCODE; i++) { 2838132455Sroberto#ifdef OPENSSL 283982502Sroberto if (i > CP_VARLIST) 284082502Sroberto continue; 2841132455Sroberto#endif /* OPENSSL */ 284254359Sroberto ctl_putpeer(i, peer); 2843132455Sroberto } 284454359Sroberto#ifdef REFCLOCK 284554359Sroberto /* 284682502Sroberto * for clock exception events: add clock variables to 284782502Sroberto * reflect info on exception 284854359Sroberto */ 284954359Sroberto if (err == EVNT_PEERCLOCK) { 285054359Sroberto struct refclockstat clock_stat; 285154359Sroberto struct ctl_var *kv; 285254359Sroberto 285354359Sroberto clock_stat.kv_list = (struct ctl_var *)0; 285454359Sroberto refclock_control(&peer->srcadr, 285582502Sroberto (struct refclockstat *)0, &clock_stat); 285654359Sroberto 285754359Sroberto ctl_puthex("refclockstatus", 285882502Sroberto ctlclkstatus(&clock_stat)); 285954359Sroberto 286054359Sroberto for (i = 1; i <= CC_MAXCODE; i++) 286154359Sroberto ctl_putclock(i, &clock_stat, 0); 286282502Sroberto for (kv = clock_stat.kv_list; kv && 286382502Sroberto !(kv->flags & EOV); kv++) 286454359Sroberto if (kv->flags & DEF) 286582502Sroberto ctl_putdata(kv->text, 286682502Sroberto strlen(kv->text), 0); 286754359Sroberto free_varlist(clock_stat.kv_list); 286854359Sroberto } 2869132455Sroberto#endif /* REFCLOCK */ 287054359Sroberto } 287154359Sroberto 287254359Sroberto /* 287354359Sroberto * We're done, return. 287454359Sroberto */ 287554359Sroberto ctl_flushpkt(0); 287654359Sroberto} 287754359Sroberto 287854359Sroberto 287954359Sroberto/* 288054359Sroberto * ctl_clr_stats - clear stat counters 288154359Sroberto */ 288254359Srobertovoid 288354359Srobertoctl_clr_stats(void) 288454359Sroberto{ 288554359Sroberto ctltimereset = current_time; 288654359Sroberto numctlreq = 0; 288754359Sroberto numctlbadpkts = 0; 288854359Sroberto numctlresponses = 0; 288954359Sroberto numctlfrags = 0; 289054359Sroberto numctlerrors = 0; 289154359Sroberto numctlfrags = 0; 289254359Sroberto numctltooshort = 0; 289354359Sroberto numctlinputresp = 0; 289454359Sroberto numctlinputfrag = 0; 289554359Sroberto numctlinputerr = 0; 289654359Sroberto numctlbadoffset = 0; 289754359Sroberto numctlbadversion = 0; 289854359Sroberto numctldatatooshort = 0; 289954359Sroberto numctlbadop = 0; 290054359Sroberto numasyncmsgs = 0; 290154359Sroberto} 290254359Sroberto 290354359Srobertostatic u_long 290454359Srobertocount_var( 290554359Sroberto struct ctl_var *k 290654359Sroberto ) 290754359Sroberto{ 290854359Sroberto register u_long c; 290954359Sroberto 291054359Sroberto if (!k) 291182502Sroberto return (0); 291254359Sroberto 291354359Sroberto c = 0; 291454359Sroberto while (!(k++->flags & EOV)) 291582502Sroberto c++; 291682502Sroberto return (c); 291754359Sroberto} 291854359Sroberto 291954359Srobertochar * 292054359Srobertoadd_var( 292154359Sroberto struct ctl_var **kv, 292254359Sroberto u_long size, 2923132455Sroberto u_short def 292454359Sroberto ) 292554359Sroberto{ 292654359Sroberto register u_long c; 292754359Sroberto register struct ctl_var *k; 292854359Sroberto 292954359Sroberto c = count_var(*kv); 293054359Sroberto 293154359Sroberto k = *kv; 293254359Sroberto *kv = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var)); 293382502Sroberto if (k) { 293482502Sroberto memmove((char *)*kv, (char *)k, 293582502Sroberto sizeof(struct ctl_var)*c); 293654359Sroberto free((char *)k); 293754359Sroberto } 293854359Sroberto (*kv)[c].code = (u_short) c; 293954359Sroberto (*kv)[c].text = (char *)emalloc(size); 294054359Sroberto (*kv)[c].flags = def; 294154359Sroberto (*kv)[c+1].code = 0; 294254359Sroberto (*kv)[c+1].text = (char *)0; 294354359Sroberto (*kv)[c+1].flags = EOV; 294454359Sroberto return (char *)(*kv)[c].text; 294554359Sroberto} 294654359Sroberto 294754359Srobertovoid 294854359Srobertoset_var( 294954359Sroberto struct ctl_var **kv, 295054359Sroberto const char *data, 295154359Sroberto u_long size, 2952132455Sroberto u_short def 295354359Sroberto ) 295454359Sroberto{ 295554359Sroberto register struct ctl_var *k; 295654359Sroberto register const char *s; 295754359Sroberto register const char *t; 295854359Sroberto char *td; 295954359Sroberto 296054359Sroberto if (!data || !size) 296154359Sroberto return; 296254359Sroberto 2963132455Sroberto k = *kv; 2964132455Sroberto if (k != NULL) { 296582502Sroberto while (!(k->flags & EOV)) { 296654359Sroberto s = data; 296754359Sroberto t = k->text; 296882502Sroberto if (t) { 296982502Sroberto while (*t != '=' && *s - *t == 0) { 297054359Sroberto s++; 297154359Sroberto t++; 297254359Sroberto } 297382502Sroberto if (*s == *t && ((*t == '=') || !*t)) { 297454359Sroberto free((void *)k->text); 297554359Sroberto td = (char *)emalloc(size); 297654359Sroberto memmove(td, data, size); 297754359Sroberto k->text =td; 297854359Sroberto k->flags = def; 297954359Sroberto return; 298054359Sroberto } 298182502Sroberto } else { 298254359Sroberto td = (char *)emalloc(size); 298354359Sroberto memmove(td, data, size); 298454359Sroberto k->text = td; 298554359Sroberto k->flags = def; 298654359Sroberto return; 298754359Sroberto } 298854359Sroberto k++; 298954359Sroberto } 299054359Sroberto } 299154359Sroberto td = add_var(kv, size, def); 299254359Sroberto memmove(td, data, size); 299354359Sroberto} 299454359Sroberto 299554359Srobertovoid 299654359Srobertoset_sys_var( 2997182007Sroberto const char *data, 299854359Sroberto u_long size, 2999132455Sroberto u_short def 300054359Sroberto ) 300154359Sroberto{ 300254359Sroberto set_var(&ext_sys_var, data, size, def); 300354359Sroberto} 300454359Sroberto 300554359Srobertovoid 300654359Srobertofree_varlist( 300754359Sroberto struct ctl_var *kv 300854359Sroberto ) 300954359Sroberto{ 301054359Sroberto struct ctl_var *k; 301182502Sroberto if (kv) { 301254359Sroberto for (k = kv; !(k->flags & EOV); k++) 301382502Sroberto free((void *)k->text); 301454359Sroberto free((void *)kv); 301554359Sroberto } 301654359Sroberto} 3017