diff options
Diffstat (limited to 'contrib/ntp/ntpd/ntp_control.c')
-rw-r--r-- | contrib/ntp/ntpd/ntp_control.c | 2928 |
1 files changed, 0 insertions, 2928 deletions
diff --git a/contrib/ntp/ntpd/ntp_control.c b/contrib/ntp/ntpd/ntp_control.c deleted file mode 100644 index 0ac0404..0000000 --- a/contrib/ntp/ntpd/ntp_control.c +++ /dev/null @@ -1,2928 +0,0 @@ -/* - * ntp_control.c - respond to control messages and send async traps - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "ntpd.h" -#include "ntp_io.h" -#include "ntp_refclock.h" -#include "ntp_control.h" -#include "ntp_stdlib.h" - -#include <stdio.h> -#include <ctype.h> -#include <signal.h> - -#include <netinet/in.h> -#include <arpa/inet.h> - -/* - * Structure to hold request procedure information - */ -#define NOAUTH 0 -#define AUTH 1 - -#define NO_REQUEST (-1) - -struct ctl_proc { - short control_code; /* defined request code */ - u_short flags; /* flags word */ - void (*handler) P((struct recvbuf *, int)); /* handle request */ -}; - -/* - * Only one flag. Authentication required or not. - */ -#define NOAUTH 0 -#define AUTH 1 - -/* - * Request processing routines - */ -static void ctl_error P((int)); -#ifdef REFCLOCK -static u_short ctlclkstatus P((struct refclockstat *)); -#endif -static void ctl_flushpkt P((int)); -static void ctl_putdata P((const char *, unsigned int, int)); -static void ctl_putstr P((const char *, const char *, - unsigned int)); -static void ctl_putdbl P((const char *, double)); -static void ctl_putuint P((const char *, u_long)); -static void ctl_puthex P((const char *, u_long)); -static void ctl_putint P((const char *, long)); -static void ctl_putts P((const char *, l_fp *)); -static void ctl_putadr P((const char *, u_int32, struct sockaddr_storage*)); -static void ctl_putid P((const char *, char *)); -static void ctl_putarray P((const char *, double *, int)); -static void ctl_putsys P((int)); -static void ctl_putpeer P((int, struct peer *)); -#ifdef REFCLOCK -static void ctl_putclock P((int, struct refclockstat *, int)); -#endif /* REFCLOCK */ -static struct ctl_var *ctl_getitem P((struct ctl_var *, char **)); -static u_long count_var P((struct ctl_var *)); -static void control_unspec P((struct recvbuf *, int)); -static void read_status P((struct recvbuf *, int)); -static void read_variables P((struct recvbuf *, int)); -static void write_variables P((struct recvbuf *, int)); -static void read_clock_status P((struct recvbuf *, int)); -static void write_clock_status P((struct recvbuf *, int)); -static void set_trap P((struct recvbuf *, int)); -static void unset_trap P((struct recvbuf *, int)); -static struct ctl_trap *ctlfindtrap P((struct sockaddr_storage *, - struct interface *)); - -static struct ctl_proc control_codes[] = { - { CTL_OP_UNSPEC, NOAUTH, control_unspec }, - { CTL_OP_READSTAT, NOAUTH, read_status }, - { CTL_OP_READVAR, NOAUTH, read_variables }, - { CTL_OP_WRITEVAR, AUTH, write_variables }, - { CTL_OP_READCLOCK, NOAUTH, read_clock_status }, - { CTL_OP_WRITECLOCK, NOAUTH, write_clock_status }, - { CTL_OP_SETTRAP, NOAUTH, set_trap }, - { CTL_OP_UNSETTRAP, NOAUTH, unset_trap }, - { NO_REQUEST, 0 } -}; - -/* - * System variable values. The array can be indexed by the variable - * index to find the textual name. - */ -static struct ctl_var sys_var[] = { - { 0, PADDING, "" }, /* 0 */ - { CS_LEAP, RW, "leap" }, /* 1 */ - { CS_STRATUM, RO, "stratum" }, /* 2 */ - { CS_PRECISION, RO, "precision" }, /* 3 */ - { CS_ROOTDELAY, RO, "rootdelay" }, /* 4 */ - { CS_ROOTDISPERSION, RO, "rootdispersion" }, /* 5 */ - { CS_REFID, RO, "refid" }, /* 6 */ - { CS_REFTIME, RO, "reftime" }, /* 7 */ - { CS_POLL, RO, "poll" }, /* 8 */ - { CS_PEERID, RO, "peer" }, /* 9 */ - { CS_STATE, RO, "state" }, /* 10 */ - { CS_OFFSET, RO, "offset" }, /* 11 */ - { CS_DRIFT, RO, "frequency" }, /* 12 */ - { CS_JITTER, RO, "jitter" }, /* 13 */ - { CS_CLOCK, RO, "clock" }, /* 14 */ - { CS_PROCESSOR, RO, "processor" }, /* 15 */ - { CS_SYSTEM, RO, "system" }, /* 16 */ - { CS_VERSION, RO, "version" }, /* 17 */ - { CS_STABIL, RO, "stability" }, /* 18 */ - { CS_VARLIST, RO, "sys_var_list" }, /* 19 */ -#ifdef OPENSSL - { CS_FLAGS, RO, "flags" }, /* 20 */ - { CS_HOST, RO, "hostname" }, /* 21 */ - { CS_PUBLIC, RO, "hostkey" }, /* 22 */ - { CS_CERTIF, RO, "cert" }, /* 23 */ - { CS_REVTIME, RO, "refresh" }, /* 24 */ - { CS_LEAPTAB, RO, "leapseconds" }, /* 25 */ - { CS_TAI, RO, "tai" }, /* 26 */ - { CS_DIGEST, RO, "signature" }, /* 27 */ -#endif /* OPENSSL */ - { 0, EOV, "" } /* 28 */ -}; - -static struct ctl_var *ext_sys_var = (struct ctl_var *)0; - -/* - * System variables we print by default (in fuzzball order, - * more-or-less) - */ -static u_char def_sys_var[] = { - CS_VERSION, - CS_PROCESSOR, - CS_SYSTEM, - CS_LEAP, - CS_STRATUM, - CS_PRECISION, - CS_ROOTDELAY, - CS_ROOTDISPERSION, - CS_PEERID, - CS_REFID, - CS_REFTIME, - CS_POLL, - CS_CLOCK, - CS_STATE, - CS_OFFSET, - CS_DRIFT, - CS_JITTER, - CS_STABIL, -#ifdef OPENSSL - CS_HOST, - CS_DIGEST, - CS_FLAGS, - CS_PUBLIC, - CS_REVTIME, - CS_LEAPTAB, - CS_CERTIF, -#endif /* OPENSSL */ - 0 -}; - - -/* - * Peer variable list - */ -static struct ctl_var peer_var[] = { - { 0, PADDING, "" }, /* 0 */ - { CP_CONFIG, RO, "config" }, /* 1 */ - { CP_AUTHENABLE, RO, "authenable" }, /* 2 */ - { CP_AUTHENTIC, RO, "authentic" }, /* 3 */ - { CP_SRCADR, RO, "srcadr" }, /* 4 */ - { CP_SRCPORT, RO, "srcport" }, /* 5 */ - { CP_DSTADR, RO, "dstadr" }, /* 6 */ - { CP_DSTPORT, RO, "dstport" }, /* 7 */ - { CP_LEAP, RO, "leap" }, /* 8 */ - { CP_HMODE, RO, "hmode" }, /* 9 */ - { CP_STRATUM, RO, "stratum" }, /* 10 */ - { CP_PPOLL, RO, "ppoll" }, /* 11 */ - { CP_HPOLL, RO, "hpoll" }, /* 12 */ - { CP_PRECISION, RO, "precision" }, /* 13 */ - { CP_ROOTDELAY, RO, "rootdelay" }, /* 14 */ - { CP_ROOTDISPERSION, RO, "rootdispersion" }, /* 15 */ - { CP_REFID, RO, "refid" }, /* 16 */ - { CP_REFTIME, RO, "reftime" }, /* 17 */ - { CP_ORG, RO, "org" }, /* 18 */ - { CP_REC, RO, "rec" }, /* 19 */ - { CP_XMT, RO, "xmt" }, /* 20 */ - { CP_REACH, RO, "reach" }, /* 21 */ - { CP_VALID, RO, "unreach" }, /* 22 */ - { CP_TIMER, RO, "timer" }, /* 23 */ - { CP_DELAY, RO, "delay" }, /* 24 */ - { CP_OFFSET, RO, "offset" }, /* 25 */ - { CP_JITTER, RO, "jitter" }, /* 26 */ - { CP_DISPERSION, RO, "dispersion" }, /* 27 */ - { CP_KEYID, RO, "keyid" }, /* 28 */ - { CP_FILTDELAY, RO, "filtdelay=" }, /* 29 */ - { CP_FILTOFFSET, RO, "filtoffset=" }, /* 30 */ - { CP_PMODE, RO, "pmode" }, /* 31 */ - { CP_RECEIVED, RO, "received"}, /* 32 */ - { CP_SENT, RO, "sent" }, /* 33 */ - { CP_FILTERROR, RO, "filtdisp=" }, /* 34 */ - { CP_FLASH, RO, "flash" }, /* 35 */ - { CP_TTL, RO, "ttl" }, /* 36 */ - { CP_RANK, RO, "rank" }, /* 37 */ - { CP_VARLIST, RO, "peer_var_list" }, /* 38 */ -#ifdef OPENSSL - { CP_FLAGS, RO, "flags" }, /* 39 */ - { CP_HOST, RO, "hostname" }, /* 40 */ - { CP_INITSEQ, RO, "initsequence" }, /* 41 */ - { CP_INITKEY, RO, "initkey" }, /* 42 */ - { CP_INITTSP, RO, "timestamp" }, /* 43 */ - { CP_DIGEST, RO, "signature" }, /* 44 */ - { CP_IDENT, RO, "identity" }, /* 45 */ -#endif /* OPENSSL */ - { 0, EOV, "" } /* 39/46 */ -}; - - -/* - * Peer variables we print by default - */ -static u_char def_peer_var[] = { - CP_SRCADR, - CP_SRCPORT, - CP_DSTADR, - CP_DSTPORT, - CP_LEAP, - CP_STRATUM, - CP_PRECISION, - CP_ROOTDELAY, - CP_ROOTDISPERSION, - CP_REFID, - CP_REACH, - CP_VALID, - CP_HMODE, - CP_PMODE, - CP_HPOLL, - CP_PPOLL, - CP_FLASH, - CP_KEYID, - CP_TTL, - CP_OFFSET, - CP_DELAY, - CP_DISPERSION, - CP_JITTER, - CP_REFTIME, - CP_ORG, - CP_REC, - CP_XMT, - CP_FILTDELAY, - CP_FILTOFFSET, - CP_FILTERROR, -#ifdef OPENSSL - CP_HOST, - CP_DIGEST, - CP_FLAGS, - CP_IDENT, - CP_INITSEQ, -#endif /* OPENSSL */ - 0 -}; - - -#ifdef REFCLOCK -/* - * Clock variable list - */ -static struct ctl_var clock_var[] = { - { 0, PADDING, "" }, /* 0 */ - { CC_TYPE, RO, "type" }, /* 1 */ - { CC_TIMECODE, RO, "timecode" }, /* 2 */ - { CC_POLL, RO, "poll" }, /* 3 */ - { CC_NOREPLY, RO, "noreply" }, /* 4 */ - { CC_BADFORMAT, RO, "badformat" }, /* 5 */ - { CC_BADDATA, RO, "baddata" }, /* 6 */ - { CC_FUDGETIME1, RO, "fudgetime1" }, /* 7 */ - { CC_FUDGETIME2, RO, "fudgetime2" }, /* 8 */ - { CC_FUDGEVAL1, RO, "stratum" }, /* 9 */ - { CC_FUDGEVAL2, RO, "refid" }, /* 10 */ - { CC_FLAGS, RO, "flags" }, /* 11 */ - { CC_DEVICE, RO, "device" }, /* 12 */ - { CC_VARLIST, RO, "clock_var_list" }, /* 13 */ - { 0, EOV, "" } /* 14 */ -}; - - -/* - * Clock variables printed by default - */ -static u_char def_clock_var[] = { - CC_DEVICE, - CC_TYPE, /* won't be output if device = known */ - CC_TIMECODE, - CC_POLL, - CC_NOREPLY, - CC_BADFORMAT, - CC_BADDATA, - CC_FUDGETIME1, - CC_FUDGETIME2, - CC_FUDGEVAL1, - CC_FUDGEVAL2, - CC_FLAGS, - 0 -}; -#endif - - -/* - * System and processor definitions. - */ -#ifndef HAVE_UNAME -# ifndef STR_SYSTEM -# define STR_SYSTEM "UNIX" -# endif -# ifndef STR_PROCESSOR -# define STR_PROCESSOR "unknown" -# endif - -static char str_system[] = STR_SYSTEM; -static char str_processor[] = STR_PROCESSOR; -#else -# include <sys/utsname.h> -static struct utsname utsnamebuf; -#endif /* HAVE_UNAME */ - -/* - * Trap structures. We only allow a few of these, and send a copy of - * each async message to each live one. Traps time out after an hour, it - * is up to the trap receipient to keep resetting it to avoid being - * timed out. - */ -/* ntp_request.c */ -struct ctl_trap ctl_trap[CTL_MAXTRAPS]; -int num_ctl_traps; - -/* - * Type bits, for ctlsettrap() call. - */ -#define TRAP_TYPE_CONFIG 0 /* used by configuration code */ -#define TRAP_TYPE_PRIO 1 /* priority trap */ -#define TRAP_TYPE_NONPRIO 2 /* nonpriority trap */ - - -/* - * List relating reference clock types to control message time sources. - * Index by the reference clock type. This list will only be used iff - * the reference clock driver doesn't set peer->sstclktype to something - * different than CTL_SST_TS_UNSPEC. - */ -static u_char clocktypes[] = { - CTL_SST_TS_NTP, /* REFCLK_NONE (0) */ - CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK (2) */ - CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */ - CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */ - CTL_SST_TS_UHF, /* REFCLK_TRUETIME (5) */ - CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) */ - CTL_SST_TS_HF, /* REFCLK_CHU (7) */ - CTL_SST_TS_LF, /* REFCLOCK_PARSE (default) (8) */ - CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_ARBITER (11) */ - CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */ - CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */ - CTL_SST_TS_LF, /* REFCLK_MSF_EES (14) */ - CTL_SST_TS_UHF, /* REFCLK_TRUETIME (15) */ - CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */ - CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACTS (18) */ - CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_VME (21) */ - CTL_SST_TS_ATOM, /* REFCLK_ATOM_PPS (22) */ - CTL_SST_TS_TELEPHONE, /* REFCLK_PTB_ACTS (23) */ - CTL_SST_TS_TELEPHONE, /* REFCLK_USNO (24) */ - CTL_SST_TS_UHF, /* REFCLK_TRUETIME (25) */ - CTL_SST_TS_UHF, /* REFCLK_GPS_HP (26) */ - CTL_SST_TS_TELEPHONE, /* REFCLK_ARCRON_MSF (27) */ - CTL_SST_TS_TELEPHONE, /* REFCLK_SHM (28) */ - CTL_SST_TS_UHF, /* REFCLK_PALISADE (29) */ - CTL_SST_TS_UHF, /* REFCLK_ONCORE (30) */ - CTL_SST_TS_UHF, /* REFCLK_JUPITER (31) */ - CTL_SST_TS_LF, /* REFCLK_CHRONOLOG (32) */ - CTL_SST_TS_LF, /* REFCLK_DUMBCLOCK (32) */ - CTL_SST_TS_LF, /* REFCLK_ULINK (33) */ - CTL_SST_TS_LF, /* REFCLK_PCF (35) */ - CTL_SST_TS_LF, /* REFCLK_WWV (36) */ - CTL_SST_TS_LF, /* REFCLK_FG (37) */ - CTL_SST_TS_UHF, /* REFCLK_HOPF_SERIAL (38) */ - CTL_SST_TS_UHF, /* REFCLK_HOPF_PCI (39) */ - CTL_SST_TS_LF, /* REFCLK_JJY (40) */ - CTL_SST_TS_UHF, /* REFCLK_TT560 (41) */ - CTL_SST_TS_UHF, /* REFCLK_ZYFER (42) */ - CTL_SST_TS_UHF, /* REFCLK_RIPENCC (43) */ - CTL_SST_TS_UHF, /* REFCLK_NEOCLOCK4X (44) */ -}; - - -/* - * Keyid used for authenticating write requests. - */ -keyid_t ctl_auth_keyid; - -/* - * We keep track of the last error reported by the system internally - */ -static u_char ctl_sys_last_event; -static u_char ctl_sys_num_events; - - -/* - * Statistic counters to keep track of requests and responses. - */ -u_long ctltimereset; /* time stats reset */ -u_long numctlreq; /* number of requests we've received */ -u_long numctlbadpkts; /* number of bad control packets */ -u_long numctlresponses; /* number of resp packets sent with data */ -u_long numctlfrags; /* number of fragments sent */ -u_long numctlerrors; /* number of error responses sent */ -u_long numctltooshort; /* number of too short input packets */ -u_long numctlinputresp; /* number of responses on input */ -u_long numctlinputfrag; /* number of fragments on input */ -u_long numctlinputerr; /* number of input pkts with err bit set */ -u_long numctlbadoffset; /* number of input pkts with nonzero offset */ -u_long numctlbadversion; /* number of input pkts with unknown version */ -u_long numctldatatooshort; /* data too short for count */ -u_long numctlbadop; /* bad op code found in packet */ -u_long numasyncmsgs; /* number of async messages we've sent */ - -/* - * Response packet used by these routines. Also some state information - * so that we can handle packet formatting within a common set of - * subroutines. Note we try to enter data in place whenever possible, - * but the need to set the more bit correctly means we occasionally - * use the extra buffer and copy. - */ -static struct ntp_control rpkt; -static u_char res_version; -static u_char res_opcode; -static associd_t res_associd; -static int res_offset; -static u_char * datapt; -static u_char * dataend; -static int datalinelen; -static int datanotbinflag; -static struct sockaddr_storage *rmt_addr; -static struct interface *lcl_inter; - -static u_char res_authenticate; -static u_char res_authokay; -static keyid_t res_keyid; - -#define MAXDATALINELEN (72) - -static u_char res_async; /* set to 1 if this is async trap response */ - -/* - * Pointers for saving state when decoding request packets - */ -static char *reqpt; -static char *reqend; - -/* - * init_control - initialize request data - */ -void -init_control(void) -{ - int i; - -#ifdef HAVE_UNAME - uname(&utsnamebuf); -#endif /* HAVE_UNAME */ - - ctl_clr_stats(); - - ctl_auth_keyid = 0; - ctl_sys_last_event = EVNT_UNSPEC; - ctl_sys_num_events = 0; - - num_ctl_traps = 0; - for (i = 0; i < CTL_MAXTRAPS; i++) - ctl_trap[i].tr_flags = 0; -} - - -/* - * ctl_error - send an error response for the current request - */ -static void -ctl_error( - int errcode - ) -{ -#ifdef DEBUG - if (debug >= 4) - printf("sending control error %d\n", errcode); -#endif - /* - * Fill in the fields. We assume rpkt.sequence and rpkt.associd - * have already been filled in. - */ - rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode & - CTL_OP_MASK)); - rpkt.status = htons((u_short) ((errcode<<8) & 0xff00)); - rpkt.count = 0; - - /* - * send packet and bump counters - */ - if (res_authenticate && sys_authenticate) { - int maclen; - - *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) = - htonl(res_keyid); - maclen = authencrypt(res_keyid, (u_int32 *)&rpkt, - CTL_HEADER_LEN); - sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt, - CTL_HEADER_LEN + maclen); - } else { - sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt, - CTL_HEADER_LEN); - } - numctlerrors++; -} - - -/* - * process_control - process an incoming control message - */ -void -process_control( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - register struct ntp_control *pkt; - register int req_count; - register int req_data; - register struct ctl_proc *cc; - int properlen; - int maclen; - -#ifdef DEBUG - if (debug > 2) - printf("in process_control()\n"); -#endif - - /* - * Save the addresses for error responses - */ - numctlreq++; - rmt_addr = &rbufp->recv_srcadr; - lcl_inter = rbufp->dstadr; - pkt = (struct ntp_control *)&rbufp->recv_pkt; - - /* - * If the length is less than required for the header, or - * it is a response or a fragment, ignore this. - */ - if (rbufp->recv_length < CTL_HEADER_LEN - || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR) - || pkt->offset != 0) { -#ifdef DEBUG - if (debug) - printf("invalid format in control packet\n"); -#endif - if (rbufp->recv_length < CTL_HEADER_LEN) - numctltooshort++; - if (pkt->r_m_e_op & CTL_RESPONSE) - numctlinputresp++; - if (pkt->r_m_e_op & CTL_MORE) - numctlinputfrag++; - if (pkt->r_m_e_op & CTL_ERROR) - numctlinputerr++; - if (pkt->offset != 0) - numctlbadoffset++; - return; - } - res_version = PKT_VERSION(pkt->li_vn_mode); - if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) { -#ifdef DEBUG - if (debug) - printf("unknown version %d in control packet\n", - res_version); -#endif - numctlbadversion++; - return; - } - - /* - * Pull enough data from the packet to make intelligent - * responses - */ - rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version, - MODE_CONTROL); - res_opcode = pkt->r_m_e_op; - rpkt.sequence = pkt->sequence; - rpkt.associd = pkt->associd; - rpkt.status = 0; - res_offset = 0; - res_associd = htons(pkt->associd); - res_async = 0; - res_authenticate = 0; - res_keyid = 0; - res_authokay = 0; - req_count = (int)htons(pkt->count); - datanotbinflag = 0; - datalinelen = 0; - datapt = rpkt.data; - dataend = &(rpkt.data[CTL_MAX_DATA_LEN]); - - /* - * We're set up now. Make sure we've got at least enough - * incoming data space to match the count. - */ - req_data = rbufp->recv_length - CTL_HEADER_LEN; - if (req_data < req_count || rbufp->recv_length & 0x3) { - ctl_error(CERR_BADFMT); - numctldatatooshort++; - return; - } - - properlen = req_count + CTL_HEADER_LEN; -#ifdef DEBUG - if (debug > 2 && (rbufp->recv_length & 0x3) != 0) - printf("Packet length %d unrounded\n", - rbufp->recv_length); -#endif - /* round up proper len to a 8 octet boundary */ - - properlen = (properlen + 7) & ~7; - maclen = rbufp->recv_length - properlen; - if ((rbufp->recv_length & (sizeof(u_long) - 1)) == 0 && - maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN && - sys_authenticate) { - res_authenticate = 1; - res_keyid = ntohl(*(u_int32 *)((u_char *)pkt + - properlen)); - -#ifdef DEBUG - if (debug > 2) - printf( - "recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n", - rbufp->recv_length, properlen, res_keyid, maclen); -#endif - if (!authistrusted(res_keyid)) { -#ifdef DEBUG - if (debug > 2) - printf("invalid keyid %08x\n", - res_keyid); -#endif - } else if (authdecrypt(res_keyid, (u_int32 *)pkt, - rbufp->recv_length - maclen, maclen)) { -#ifdef DEBUG - if (debug > 2) - printf("authenticated okay\n"); -#endif - res_authokay = 1; - } else { -#ifdef DEBUG - if (debug > 2) - printf("authentication failed\n"); -#endif - res_keyid = 0; - } - } - - /* - * Set up translate pointers - */ - reqpt = (char *)pkt->data; - reqend = reqpt + req_count; - - /* - * Look for the opcode processor - */ - for (cc = control_codes; cc->control_code != NO_REQUEST; cc++) { - if (cc->control_code == res_opcode) { -#ifdef DEBUG - if (debug > 2) - printf("opcode %d, found command handler\n", - res_opcode); -#endif - if (cc->flags == AUTH && (!res_authokay || - res_keyid != ctl_auth_keyid)) { - ctl_error(CERR_PERMISSION); - return; - } - (cc->handler)(rbufp, restrict_mask); - return; - } - } - - /* - * Can't find this one, return an error. - */ - numctlbadop++; - ctl_error(CERR_BADOP); - return; -} - - -/* - * ctlpeerstatus - return a status word for this peer - */ -u_short -ctlpeerstatus( - register struct peer *peer - ) -{ - register u_short status; - - status = peer->status; - if (peer->flags & FLAG_CONFIG) - status |= CTL_PST_CONFIG; - if (peer->flags & FLAG_AUTHENABLE) - status |= CTL_PST_AUTHENABLE; - if (peer->flags & FLAG_AUTHENTIC) - status |= CTL_PST_AUTHENTIC; - if (peer->reach != 0) - status |= CTL_PST_REACH; - return (u_short)CTL_PEER_STATUS(status, peer->num_events, - peer->last_event); -} - - -/* - * ctlclkstatus - return a status word for this clock - */ -#ifdef REFCLOCK -static u_short -ctlclkstatus( - struct refclockstat *this_clock - ) -{ - return ((u_short)(((this_clock->currentstatus) << 8) | - (this_clock->lastevent))); -} -#endif - - -/* - * ctlsysstatus - return the system status word - */ -u_short -ctlsysstatus(void) -{ - register u_char this_clock; - - this_clock = CTL_SST_TS_UNSPEC; - if (sys_peer != 0) { - if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) { - this_clock = sys_peer->sstclktype; - if (pps_control) - this_clock |= CTL_SST_TS_PPS; - } else { - if (sys_peer->refclktype < sizeof(clocktypes)) - this_clock = - clocktypes[sys_peer->refclktype]; - if (pps_control) - this_clock |= CTL_SST_TS_PPS; - } - } - return (u_short)CTL_SYS_STATUS(sys_leap, this_clock, - ctl_sys_num_events, ctl_sys_last_event); -} - - -/* - * ctl_flushpkt - write out the current packet and prepare - * another if necessary. - */ -static void -ctl_flushpkt( - int more - ) -{ - int dlen; - int sendlen; - - if (!more && datanotbinflag) { - /* - * Big hack, output a trailing \r\n - */ - *datapt++ = '\r'; - *datapt++ = '\n'; - } - dlen = datapt - (u_char *)rpkt.data; - sendlen = dlen + CTL_HEADER_LEN; - - /* - * Pad to a multiple of 32 bits - */ - while (sendlen & 0x3) { - *datapt++ = '\0'; - sendlen++; - } - - /* - * Fill in the packet with the current info - */ - rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode & - CTL_OP_MASK)); - rpkt.count = htons((u_short) dlen); - rpkt.offset = htons( (u_short) res_offset); - if (res_async) { - register int i; - - for (i = 0; i < CTL_MAXTRAPS; i++) { - if (ctl_trap[i].tr_flags & TRAP_INUSE) { - rpkt.li_vn_mode = - PKT_LI_VN_MODE(sys_leap, - ctl_trap[i].tr_version, - MODE_CONTROL); - rpkt.sequence = - htons(ctl_trap[i].tr_sequence); - sendpkt(&ctl_trap[i].tr_addr, - ctl_trap[i].tr_localaddr, -4, - (struct pkt *)&rpkt, sendlen); - if (!more) - ctl_trap[i].tr_sequence++; - numasyncmsgs++; - } - } - } else { - if (res_authenticate && sys_authenticate) { - int maclen; - int totlen = sendlen; - keyid_t keyid = htonl(res_keyid); - - /* - * If we are going to authenticate, then there - * is an additional requirement that the MAC - * begin on a 64 bit boundary. - */ - while (totlen & 7) { - *datapt++ = '\0'; - totlen++; - } - memcpy(datapt, &keyid, sizeof keyid); - maclen = authencrypt(res_keyid, - (u_int32 *)&rpkt, totlen); - sendpkt(rmt_addr, lcl_inter, -5, - (struct pkt *)&rpkt, totlen + maclen); - } else { - sendpkt(rmt_addr, lcl_inter, -6, - (struct pkt *)&rpkt, sendlen); - } - if (more) - numctlfrags++; - else - numctlresponses++; - } - - /* - * Set us up for another go around. - */ - res_offset += dlen; - datapt = (u_char *)rpkt.data; -} - - -/* - * ctl_putdata - write data into the packet, fragmenting and starting - * another if this one is full. - */ -static void -ctl_putdata( - const char *dp, - unsigned int dlen, - int bin /* set to 1 when data is binary */ - ) -{ - int overhead; - - overhead = 0; - if (!bin) { - datanotbinflag = 1; - overhead = 3; - if (datapt != rpkt.data) { - *datapt++ = ','; - datalinelen++; - if ((dlen + datalinelen + 1) >= MAXDATALINELEN) - { - *datapt++ = '\r'; - *datapt++ = '\n'; - datalinelen = 0; - } else { - *datapt++ = ' '; - datalinelen++; - } - } - } - - /* - * Save room for trailing junk - */ - if (dlen + overhead + datapt > dataend) { - /* - * Not enough room in this one, flush it out. - */ - ctl_flushpkt(CTL_MORE); - } - memmove((char *)datapt, dp, (unsigned)dlen); - datapt += dlen; - datalinelen += dlen; -} - - -/* - * ctl_putstr - write a tagged string into the response packet - */ -static void -ctl_putstr( - const char *tag, - const char *data, - unsigned int len - ) -{ - register char *cp; - register const char *cq; - char buffer[400]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - if (len > 0) { - *cp++ = '='; - *cp++ = '"'; - if (len > (int) (sizeof(buffer) - (cp - buffer) - 1)) - len = sizeof(buffer) - (cp - buffer) - 1; - memmove(cp, data, (unsigned)len); - cp += len; - *cp++ = '"'; - } - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putdbl - write a tagged, signed double into the response packet - */ -static void -ctl_putdbl( - const char *tag, - double ts - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - *cp++ = '='; - (void)sprintf(cp, "%.3f", ts); - while (*cp != '\0') - cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - -/* - * ctl_putuint - write a tagged unsigned integer into the response - */ -static void -ctl_putuint( - const char *tag, - u_long uval - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - (void) sprintf(cp, "%lu", uval); - while (*cp != '\0') - cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_puthex - write a tagged unsigned integer, in hex, into the response - */ -static void -ctl_puthex( - const char *tag, - u_long uval - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - (void) sprintf(cp, "0x%lx", uval); - while (*cp != '\0') - cp++; - ctl_putdata(buffer,(unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putint - write a tagged signed integer into the response - */ -static void -ctl_putint( - const char *tag, - long ival - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - (void) sprintf(cp, "%ld", ival); - while (*cp != '\0') - cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putts - write a tagged timestamp, in hex, into the response - */ -static void -ctl_putts( - const char *tag, - l_fp *ts - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - (void) sprintf(cp, "0x%08lx.%08lx", ts->l_ui & 0xffffffffL, - ts->l_uf & 0xffffffffL); - while (*cp != '\0') - cp++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putadr - write an IP address into the response - */ -static void -ctl_putadr( - const char *tag, - u_int32 addr32, - struct sockaddr_storage* addr - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - if (addr == NULL) - cq = numtoa(addr32); - else - cq = stoa(addr); - while (*cq != '\0') - *cp++ = *cq++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putid - write a tagged clock ID into the response - */ -static void -ctl_putid( - const char *tag, - char *id - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - - *cp++ = '='; - cq = id; - while (*cq != '\0' && (cq - id) < 4) - *cp++ = *cq++; - ctl_putdata(buffer, (unsigned)( cp - buffer ), 0); -} - - -/* - * ctl_putarray - write a tagged eight element double array into the response - */ -static void -ctl_putarray( - const char *tag, - double *arr, - int start - ) -{ - register char *cp; - register const char *cq; - char buffer[200]; - int i; - cp = buffer; - cq = tag; - while (*cq != '\0') - *cp++ = *cq++; - i = start; - do { - if (i == 0) - i = NTP_SHIFT; - i--; - (void)sprintf(cp, " %.2f", arr[i] * 1e3); - while (*cp != '\0') - cp++; - } while(i != start); - ctl_putdata(buffer, (unsigned)(cp - buffer), 0); -} - - -/* - * ctl_putsys - output a system variable - */ -static void -ctl_putsys( - int varid - ) -{ - l_fp tmp; - char str[256]; -#ifdef OPENSSL - struct cert_info *cp; - char cbuf[256]; -#endif /* OPENSSL */ - - switch (varid) { - - case CS_LEAP: - ctl_putuint(sys_var[CS_LEAP].text, sys_leap); - break; - - case CS_STRATUM: - ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum); - break; - - case CS_PRECISION: - ctl_putint(sys_var[CS_PRECISION].text, sys_precision); - break; - - case CS_ROOTDELAY: - ctl_putdbl(sys_var[CS_ROOTDELAY].text, sys_rootdelay * - 1e3); - break; - - case CS_ROOTDISPERSION: - ctl_putdbl(sys_var[CS_ROOTDISPERSION].text, - sys_rootdispersion * 1e3); - break; - - case CS_REFID: - if (sys_stratum > 1 && sys_stratum < STRATUM_UNSPEC) - ctl_putadr(sys_var[CS_REFID].text, sys_refid, NULL); - else - ctl_putid(sys_var[CS_REFID].text, - (char *)&sys_refid); - break; - - case CS_REFTIME: - ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime); - break; - - case CS_POLL: - ctl_putuint(sys_var[CS_POLL].text, sys_poll); - break; - - case CS_PEERID: - if (sys_peer == NULL) - ctl_putuint(sys_var[CS_PEERID].text, 0); - else - ctl_putuint(sys_var[CS_PEERID].text, - sys_peer->associd); - break; - - case CS_STATE: - ctl_putuint(sys_var[CS_STATE].text, (unsigned)state); - break; - - case CS_OFFSET: - ctl_putdbl(sys_var[CS_OFFSET].text, last_offset * 1e3); - break; - - case CS_DRIFT: - ctl_putdbl(sys_var[CS_DRIFT].text, drift_comp * 1e6); - break; - - case CS_JITTER: - ctl_putdbl(sys_var[CS_JITTER].text, sys_jitter * 1e3); - break; - - case CS_CLOCK: - get_systime(&tmp); - ctl_putts(sys_var[CS_CLOCK].text, &tmp); - break; - - case CS_PROCESSOR: -#ifndef HAVE_UNAME - ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor, - sizeof(str_processor) - 1); -#else - ctl_putstr(sys_var[CS_PROCESSOR].text, - utsnamebuf.machine, strlen(utsnamebuf.machine)); -#endif /* HAVE_UNAME */ - break; - - case CS_SYSTEM: -#ifndef HAVE_UNAME - ctl_putstr(sys_var[CS_SYSTEM].text, str_system, - sizeof(str_system) - 1); -#else - sprintf(str, "%s/%s", utsnamebuf.sysname, utsnamebuf.release); - ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str)); -#endif /* HAVE_UNAME */ - break; - - case CS_VERSION: - ctl_putstr(sys_var[CS_VERSION].text, Version, - strlen(Version)); - break; - - case CS_STABIL: - ctl_putdbl(sys_var[CS_STABIL].text, clock_stability * - 1e6); - break; - - case CS_VARLIST: - { - char buf[CTL_MAX_DATA_LEN]; - register char *s, *t, *be; - register const char *ss; - register int i; - register struct ctl_var *k; - - s = buf; - be = buf + sizeof(buf) - - strlen(sys_var[CS_VARLIST].text) - 4; - if (s > be) - break; /* really long var name */ - - strcpy(s, sys_var[CS_VARLIST].text); - strcat(s, "=\""); - s += strlen(s); - t = s; - for (k = sys_var; !(k->flags &EOV); k++) { - if (k->flags & PADDING) - continue; - i = strlen(k->text); - if (s+i+1 >= be) - break; - - if (s != t) - *s++ = ','; - strcpy(s, k->text); - s += i; - } - - for (k = ext_sys_var; k && !(k->flags &EOV); - k++) { - if (k->flags & PADDING) - continue; - - ss = k->text; - if (!ss) - continue; - - while (*ss && *ss != '=') - ss++; - i = ss - k->text; - if (s + i + 1 >= be) - break; - - if (s != t) - *s++ = ','; - strncpy(s, k->text, - (unsigned)i); - s += i; - } - if (s+2 >= be) - break; - - *s++ = '"'; - *s = '\0'; - - ctl_putdata(buf, (unsigned)( s - buf ), - 0); - } - break; - -#ifdef OPENSSL - case CS_FLAGS: - if (crypto_flags) { - ctl_puthex(sys_var[CS_FLAGS].text, crypto_flags); - } - break; - - case CS_DIGEST: - if (crypto_flags) { - const EVP_MD *dp; - - dp = EVP_get_digestbynid(crypto_flags >> 16); - strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp))); - ctl_putstr(sys_var[CS_DIGEST].text, str, - strlen(str)); - } - break; - - case CS_HOST: - if (sys_hostname != NULL) - ctl_putstr(sys_var[CS_HOST].text, sys_hostname, - strlen(sys_hostname)); - break; - - case CS_CERTIF: - for (cp = cinfo; cp != NULL; cp = cp->link) { - sprintf(cbuf, "%s %s 0x%x %u", cp->subject, - cp->issuer, cp->flags, - ntohl(cp->cert.fstamp)); - ctl_putstr(sys_var[CS_CERTIF].text, cbuf, - strlen(cbuf)); - } - break; - - case CS_PUBLIC: - if (hostval.fstamp != 0) - ctl_putuint(sys_var[CS_PUBLIC].text, - ntohl(hostval.fstamp)); - break; - - case CS_REVTIME: - if (hostval.tstamp != 0) - ctl_putuint(sys_var[CS_REVTIME].text, - ntohl(hostval.tstamp)); - break; - - case CS_LEAPTAB: - if (tai_leap.fstamp != 0) - ctl_putuint(sys_var[CS_LEAPTAB].text, - ntohl(tai_leap.fstamp)); - if (sys_tai != 0) - ctl_putuint(sys_var[CS_TAI].text, sys_tai); - break; -#endif /* OPENSSL */ - } -} - - -/* - * ctl_putpeer - output a peer variable - */ -static void -ctl_putpeer( - int varid, - struct peer *peer - ) -{ -#ifdef OPENSSL - char str[256]; - struct autokey *ap; -#endif /* OPENSSL */ - - switch (varid) { - - case CP_CONFIG: - ctl_putuint(peer_var[CP_CONFIG].text, - (unsigned)((peer->flags & FLAG_CONFIG) != 0)); - break; - - case CP_AUTHENABLE: - ctl_putuint(peer_var[CP_AUTHENABLE].text, - (unsigned)((peer->flags & FLAG_AUTHENABLE) != 0)); - break; - - case CP_AUTHENTIC: - ctl_putuint(peer_var[CP_AUTHENTIC].text, - (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0)); - break; - - case CP_SRCADR: - ctl_putadr(peer_var[CP_SRCADR].text, 0, - &peer->srcadr); - break; - - case CP_SRCPORT: - ctl_putuint(peer_var[CP_SRCPORT].text, - ntohs(((struct sockaddr_in*)&peer->srcadr)->sin_port)); - break; - - case CP_DSTADR: - ctl_putadr(peer_var[CP_DSTADR].text, 0, - &(peer->dstadr->sin)); - break; - - case CP_DSTPORT: - ctl_putuint(peer_var[CP_DSTPORT].text, - (u_long)(peer->dstadr ? - ntohs(((struct sockaddr_in*)&peer->dstadr->sin)->sin_port) : 0)); - break; - - case CP_LEAP: - ctl_putuint(peer_var[CP_LEAP].text, peer->leap); - break; - - case CP_HMODE: - ctl_putuint(peer_var[CP_HMODE].text, peer->hmode); - break; - - case CP_STRATUM: - ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum); - break; - - case CP_PPOLL: - ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll); - break; - - case CP_HPOLL: - ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll); - break; - - case CP_PRECISION: - ctl_putint(peer_var[CP_PRECISION].text, - peer->precision); - break; - - case CP_ROOTDELAY: - ctl_putdbl(peer_var[CP_ROOTDELAY].text, - peer->rootdelay * 1e3); - break; - - case CP_ROOTDISPERSION: - ctl_putdbl(peer_var[CP_ROOTDISPERSION].text, - peer->rootdispersion * 1e3); - break; - - case CP_REFID: - if (peer->flags & FLAG_REFCLOCK) { - if (peer->stratum > 0 && peer->stratum < - STRATUM_UNSPEC) - ctl_putadr(peer_var[CP_REFID].text, - peer->refid, NULL); - else - ctl_putid(peer_var[CP_REFID].text, - (char *)&peer->refid); - } else { - if (peer->stratum > 1 && peer->stratum < - STRATUM_UNSPEC) - ctl_putadr(peer_var[CP_REFID].text, - peer->refid, NULL); - else - ctl_putid(peer_var[CP_REFID].text, - (char *)&peer->refid); - } - break; - - case CP_REFTIME: - ctl_putts(peer_var[CP_REFTIME].text, &peer->reftime); - break; - - case CP_ORG: - ctl_putts(peer_var[CP_ORG].text, &peer->org); - break; - - case CP_REC: - ctl_putts(peer_var[CP_REC].text, &peer->rec); - break; - - case CP_XMT: - ctl_putts(peer_var[CP_XMT].text, &peer->xmt); - break; - - case CP_REACH: - ctl_puthex(peer_var[CP_REACH].text, peer->reach); - break; - - case CP_FLASH: - ctl_puthex(peer_var[CP_FLASH].text, peer->flash); - break; - - case CP_TTL: - ctl_putint(peer_var[CP_TTL].text, sys_ttl[peer->ttl]); - break; - - case CP_VALID: - ctl_putuint(peer_var[CP_VALID].text, peer->unreach); - break; - - case CP_RANK: - ctl_putuint(peer_var[CP_RANK].text, peer->rank); - break; - - case CP_TIMER: - ctl_putuint(peer_var[CP_TIMER].text, - peer->nextdate - current_time); - break; - - case CP_DELAY: - ctl_putdbl(peer_var[CP_DELAY].text, peer->delay * 1e3); - break; - - case CP_OFFSET: - ctl_putdbl(peer_var[CP_OFFSET].text, peer->offset * - 1e3); - break; - - case CP_JITTER: - ctl_putdbl(peer_var[CP_JITTER].text, - SQRT(peer->jitter) * 1e3); - break; - - case CP_DISPERSION: - ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp * - 1e3); - break; - - case CP_KEYID: - ctl_putuint(peer_var[CP_KEYID].text, peer->keyid); - break; - - case CP_FILTDELAY: - ctl_putarray(peer_var[CP_FILTDELAY].text, - peer->filter_delay, (int)peer->filter_nextpt); - break; - - case CP_FILTOFFSET: - ctl_putarray(peer_var[CP_FILTOFFSET].text, - peer->filter_offset, (int)peer->filter_nextpt); - break; - - case CP_FILTERROR: - ctl_putarray(peer_var[CP_FILTERROR].text, - peer->filter_disp, (int)peer->filter_nextpt); - break; - - case CP_PMODE: - ctl_putuint(peer_var[CP_PMODE].text, peer->pmode); - break; - - case CP_RECEIVED: - ctl_putuint(peer_var[CP_RECEIVED].text, peer->received); - break; - - case CP_SENT: - ctl_putuint(peer_var[CP_SENT].text, peer->sent); - break; - - case CP_VARLIST: - { - char buf[CTL_MAX_DATA_LEN]; - register char *s, *t, *be; - register int i; - register struct ctl_var *k; - - s = buf; - be = buf + sizeof(buf) - - strlen(peer_var[CP_VARLIST].text) - 4; - if (s > be) - break; /* really long var name */ - - strcpy(s, peer_var[CP_VARLIST].text); - strcat(s, "=\""); - s += strlen(s); - t = s; - for (k = peer_var; !(k->flags &EOV); k++) { - if (k->flags & PADDING) - continue; - - i = strlen(k->text); - if (s + i + 1 >= be) - break; - - if (s != t) - *s++ = ','; - strcpy(s, k->text); - s += i; - } - if (s+2 >= be) - break; - - *s++ = '"'; - *s = '\0'; - ctl_putdata(buf, (unsigned)(s - buf), 0); - } - break; -#ifdef OPENSSL - case CP_FLAGS: - if (peer->crypto) - ctl_puthex(peer_var[CP_FLAGS].text, peer->crypto); - break; - - case CP_DIGEST: - if (peer->crypto) { - const EVP_MD *dp; - - dp = EVP_get_digestbynid(peer->crypto >> 16); - strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp))); - ctl_putstr(peer_var[CP_DIGEST].text, str, - strlen(str)); - } - break; - - case CP_HOST: - if (peer->subject != NULL) - ctl_putstr(peer_var[CP_HOST].text, peer->subject, - strlen(peer->subject)); - break; - - case CP_IDENT: - if (peer->issuer != NULL) - ctl_putstr(peer_var[CP_IDENT].text, peer->issuer, - strlen(peer->issuer)); - break; - - case CP_INITSEQ: - if ((ap = (struct autokey *)peer->recval.ptr) == NULL) - break; - ctl_putint(peer_var[CP_INITSEQ].text, ap->seq); - ctl_puthex(peer_var[CP_INITKEY].text, ap->key); - ctl_putuint(peer_var[CP_INITTSP].text, - ntohl(peer->recval.tstamp)); - break; -#endif /* OPENSSL */ - } -} - - -#ifdef REFCLOCK -/* - * ctl_putclock - output clock variables - */ -static void -ctl_putclock( - int varid, - struct refclockstat *clock_stat, - int mustput - ) -{ - switch(varid) { - - case CC_TYPE: - if (mustput || clock_stat->clockdesc == NULL - || *(clock_stat->clockdesc) == '\0') { - ctl_putuint(clock_var[CC_TYPE].text, clock_stat->type); - } - break; - case CC_TIMECODE: - ctl_putstr(clock_var[CC_TIMECODE].text, - clock_stat->p_lastcode, - (unsigned)clock_stat->lencode); - break; - - case CC_POLL: - ctl_putuint(clock_var[CC_POLL].text, clock_stat->polls); - break; - - case CC_NOREPLY: - ctl_putuint(clock_var[CC_NOREPLY].text, - clock_stat->noresponse); - break; - - case CC_BADFORMAT: - ctl_putuint(clock_var[CC_BADFORMAT].text, - clock_stat->badformat); - break; - - case CC_BADDATA: - ctl_putuint(clock_var[CC_BADDATA].text, - clock_stat->baddata); - break; - - case CC_FUDGETIME1: - if (mustput || (clock_stat->haveflags & CLK_HAVETIME1)) - ctl_putdbl(clock_var[CC_FUDGETIME1].text, - clock_stat->fudgetime1 * 1e3); - break; - - case CC_FUDGETIME2: - if (mustput || (clock_stat->haveflags & CLK_HAVETIME2)) ctl_putdbl(clock_var[CC_FUDGETIME2].text, - clock_stat->fudgetime2 * 1e3); - break; - - case CC_FUDGEVAL1: - if (mustput || (clock_stat->haveflags & CLK_HAVEVAL1)) - ctl_putint(clock_var[CC_FUDGEVAL1].text, - clock_stat->fudgeval1); - break; - - case CC_FUDGEVAL2: - if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) { - if (clock_stat->fudgeval1 > 1) - ctl_putadr(clock_var[CC_FUDGEVAL2].text, - (u_int32)clock_stat->fudgeval2, NULL); - else - ctl_putid(clock_var[CC_FUDGEVAL2].text, - (char *)&clock_stat->fudgeval2); - } - break; - - case CC_FLAGS: - if (mustput || (clock_stat->haveflags & (CLK_HAVEFLAG1 | - CLK_HAVEFLAG2 | CLK_HAVEFLAG3 | CLK_HAVEFLAG4))) - ctl_putuint(clock_var[CC_FLAGS].text, - clock_stat->flags); - break; - - case CC_DEVICE: - if (clock_stat->clockdesc == NULL || - *(clock_stat->clockdesc) == '\0') { - if (mustput) - ctl_putstr(clock_var[CC_DEVICE].text, - "", 0); - } else { - ctl_putstr(clock_var[CC_DEVICE].text, - clock_stat->clockdesc, - strlen(clock_stat->clockdesc)); - } - break; - - case CC_VARLIST: - { - char buf[CTL_MAX_DATA_LEN]; - register char *s, *t, *be; - register const char *ss; - register int i; - register struct ctl_var *k; - - s = buf; - be = buf + sizeof(buf); - if (s + strlen(clock_var[CC_VARLIST].text) + 4 > - be) - break; /* really long var name */ - - strcpy(s, clock_var[CC_VARLIST].text); - strcat(s, "=\""); - s += strlen(s); - t = s; - - for (k = clock_var; !(k->flags &EOV); k++) { - if (k->flags & PADDING) - continue; - - i = strlen(k->text); - if (s + i + 1 >= be) - break; - - if (s != t) - *s++ = ','; - strcpy(s, k->text); - s += i; - } - - for (k = clock_stat->kv_list; k && !(k->flags & - EOV); k++) { - if (k->flags & PADDING) - continue; - - ss = k->text; - if (!ss) - continue; - - while (*ss && *ss != '=') - ss++; - i = ss - k->text; - if (s+i+1 >= be) - break; - - if (s != t) - *s++ = ','; - strncpy(s, k->text, (unsigned)i); - s += i; - *s = '\0'; - } - if (s+2 >= be) - break; - - *s++ = '"'; - *s = '\0'; - ctl_putdata(buf, (unsigned)( s - buf ), 0); - } - break; - } -} -#endif - - - -/* - * ctl_getitem - get the next data item from the incoming packet - */ -static struct ctl_var * -ctl_getitem( - struct ctl_var *var_list, - char **data - ) -{ - register struct ctl_var *v; - register char *cp; - register char *tp; - static struct ctl_var eol = { 0, EOV, }; - static char buf[128]; - - /* - * Delete leading commas and white space - */ - while (reqpt < reqend && (*reqpt == ',' || - isspace((int)*reqpt))) - reqpt++; - if (reqpt >= reqend) - return (0); - - if (var_list == (struct ctl_var *)0) - return (&eol); - - /* - * Look for a first character match on the tag. If we find - * one, see if it is a full match. - */ - v = var_list; - cp = reqpt; - while (!(v->flags & EOV)) { - if (!(v->flags & PADDING) && *cp == *(v->text)) { - tp = v->text; - while (*tp != '\0' && *tp != '=' && cp < - reqend && *cp == *tp) { - cp++; - tp++; - } - if ((*tp == '\0') || (*tp == '=')) { - while (cp < reqend && isspace((int)*cp)) - cp++; - if (cp == reqend || *cp == ',') { - buf[0] = '\0'; - *data = buf; - if (cp < reqend) - cp++; - reqpt = cp; - return v; - } - if (*cp == '=') { - cp++; - tp = buf; - while (cp < reqend && isspace((int)*cp)) - cp++; - while (cp < reqend && *cp != ',') { - *tp++ = *cp++; - if (tp >= buf + sizeof(buf)) { - ctl_error(CERR_BADFMT); - numctlbadpkts++; - msyslog(LOG_WARNING, - "Possible 'ntpdx' exploit from %s:%d (possibly spoofed)\n", - stoa(rmt_addr), SRCPORT(rmt_addr) - ); - return (0); - } - } - if (cp < reqend) - cp++; - *tp-- = '\0'; - while (tp >= buf) { - if (!isspace((int)(*tp))) - break; - *tp-- = '\0'; - } - reqpt = cp; - *data = buf; - return (v); - } - } - cp = reqpt; - } - v++; - } - return v; -} - - -/* - * control_unspec - response to an unspecified op-code - */ -/*ARGSUSED*/ -static void -control_unspec( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - struct peer *peer; - - /* - * What is an appropriate response to an unspecified op-code? - * I return no errors and no data, unless a specified assocation - * doesn't exist. - */ - if (res_associd != 0) { - if ((peer = findpeerbyassoc(res_associd)) == 0) { - ctl_error(CERR_BADASSOC); - return; - } - rpkt.status = htons(ctlpeerstatus(peer)); - } else { - rpkt.status = htons(ctlsysstatus()); - } - ctl_flushpkt(0); -} - - -/* - * read_status - return either a list of associd's, or a particular - * peer's status. - */ -/*ARGSUSED*/ -static void -read_status( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - register int i; - register struct peer *peer; - u_short ass_stat[CTL_MAX_DATA_LEN / sizeof(u_short)]; - -#ifdef DEBUG - if (debug > 2) - printf("read_status: ID %d\n", res_associd); -#endif - /* - * Two choices here. If the specified association ID is - * zero we return all known assocation ID's. Otherwise - * we return a bunch of stuff about the particular peer. - */ - if (res_associd == 0) { - register int n; - - n = 0; - rpkt.status = htons(ctlsysstatus()); - for (i = 0; i < HASH_SIZE; i++) { - for (peer = assoc_hash[i]; peer != 0; - peer = peer->ass_next) { - ass_stat[n++] = htons(peer->associd); - ass_stat[n++] = - htons(ctlpeerstatus(peer)); - if (n == - CTL_MAX_DATA_LEN/sizeof(u_short)) { - ctl_putdata((char *)ass_stat, - n * sizeof(u_short), 1); - n = 0; - } - } - } - - if (n != 0) - ctl_putdata((char *)ass_stat, n * - sizeof(u_short), 1); - ctl_flushpkt(0); - } else { - peer = findpeerbyassoc(res_associd); - if (peer == 0) { - ctl_error(CERR_BADASSOC); - } else { - register u_char *cp; - - rpkt.status = htons(ctlpeerstatus(peer)); - if (res_authokay) - peer->num_events = 0; - /* - * For now, output everything we know about the - * peer. May be more selective later. - */ - for (cp = def_peer_var; *cp != 0; cp++) - ctl_putpeer((int)*cp, peer); - ctl_flushpkt(0); - } - } -} - - -/* - * read_variables - return the variables the caller asks for - */ -/*ARGSUSED*/ -static void -read_variables( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - register struct ctl_var *v; - register int i; - char *valuep; - u_char *wants; - unsigned int gotvar = (CS_MAXCODE > CP_MAXCODE) ? (CS_MAXCODE + - 1) : (CP_MAXCODE + 1); - if (res_associd == 0) { - /* - * Wants system variables. Figure out which he wants - * and give them to him. - */ - rpkt.status = htons(ctlsysstatus()); - if (res_authokay) - ctl_sys_num_events = 0; - gotvar += count_var(ext_sys_var); - wants = (u_char *)emalloc(gotvar); - memset((char *)wants, 0, gotvar); - gotvar = 0; - while ((v = ctl_getitem(sys_var, &valuep)) != 0) { - if (v->flags & EOV) { - if ((v = ctl_getitem(ext_sys_var, - &valuep)) != 0) { - if (v->flags & EOV) { - ctl_error(CERR_UNKNOWNVAR); - free((char *)wants); - return; - } - wants[CS_MAXCODE + 1 + - v->code] = 1; - gotvar = 1; - continue; - } else { - break; /* shouldn't happen ! */ - } - } - wants[v->code] = 1; - gotvar = 1; - } - if (gotvar) { - for (i = 1; i <= CS_MAXCODE; i++) - if (wants[i]) - ctl_putsys(i); - for (i = 0; ext_sys_var && - !(ext_sys_var[i].flags & EOV); i++) - if (wants[i + CS_MAXCODE + 1]) - ctl_putdata(ext_sys_var[i].text, - strlen(ext_sys_var[i].text), - 0); - } else { - register u_char *cs; - register struct ctl_var *kv; - - for (cs = def_sys_var; *cs != 0; cs++) - ctl_putsys((int)*cs); - for (kv = ext_sys_var; kv && !(kv->flags & EOV); - kv++) - if (kv->flags & DEF) - ctl_putdata(kv->text, - strlen(kv->text), 0); - } - free((char *)wants); - } else { - register struct peer *peer; - - /* - * Wants info for a particular peer. See if we know - * the guy. - */ - peer = findpeerbyassoc(res_associd); - if (peer == 0) { - ctl_error(CERR_BADASSOC); - return; - } - rpkt.status = htons(ctlpeerstatus(peer)); - if (res_authokay) - peer->num_events = 0; - wants = (u_char *)emalloc(gotvar); - memset((char*)wants, 0, gotvar); - gotvar = 0; - while ((v = ctl_getitem(peer_var, &valuep)) != 0) { - if (v->flags & EOV) { - ctl_error(CERR_UNKNOWNVAR); - free((char *)wants); - return; - } - wants[v->code] = 1; - gotvar = 1; - } - if (gotvar) { - for (i = 1; i <= CP_MAXCODE; i++) - if (wants[i]) - ctl_putpeer(i, peer); - } else { - register u_char *cp; - - for (cp = def_peer_var; *cp != 0; cp++) - ctl_putpeer((int)*cp, peer); - } - free((char *)wants); - } - ctl_flushpkt(0); -} - - -/* - * write_variables - write into variables. We only allow leap bit - * writing this way. - */ -/*ARGSUSED*/ -static void -write_variables( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - register struct ctl_var *v; - register int ext_var; - char *valuep; - long val = 0; - - /* - * If he's trying to write into a peer tell him no way - */ - if (res_associd != 0) { - ctl_error(CERR_PERMISSION); - return; - } - - /* - * Set status - */ - rpkt.status = htons(ctlsysstatus()); - - /* - * Look through the variables. Dump out at the first sign of - * trouble. - */ - while ((v = ctl_getitem(sys_var, &valuep)) != 0) { - ext_var = 0; - if (v->flags & EOV) { - if ((v = ctl_getitem(ext_sys_var, &valuep)) != - 0) { - if (v->flags & EOV) { - ctl_error(CERR_UNKNOWNVAR); - return; - } - ext_var = 1; - } else { - break; - } - } - if (!(v->flags & CAN_WRITE)) { - ctl_error(CERR_PERMISSION); - return; - } - if (!ext_var && (*valuep == '\0' || !atoint(valuep, - &val))) { - ctl_error(CERR_BADFMT); - return; - } - if (!ext_var && (val & ~LEAP_NOTINSYNC) != 0) { - ctl_error(CERR_BADVALUE); - return; - } - - if (ext_var) { - char *s = (char *)emalloc(strlen(v->text) + - strlen(valuep) + 2); - const char *t; - char *tt = s; - - t = v->text; - while (*t && *t != '=') - *tt++ = *t++; - - *tt++ = '='; - strcat(tt, valuep); - set_sys_var(s, strlen(s)+1, v->flags); - free(s); - } else { - /* - * This one seems sane. Save it. - */ - switch(v->code) { - - case CS_LEAP: - default: - ctl_error(CERR_UNSPEC); /* really */ - return; - } - } - } - - /* - * If we got anything, do it. xxx nothing to do *** - */ - /* - if (leapind != ~0 || leapwarn != ~0) { - if (!leap_setleap((int)leapind, (int)leapwarn)) { - ctl_error(CERR_PERMISSION); - return; - } - } - */ - ctl_flushpkt(0); -} - - -/* - * read_clock_status - return clock radio status - */ -/*ARGSUSED*/ -static void -read_clock_status( - struct recvbuf *rbufp, - int restrict_mask - ) -{ -#ifndef REFCLOCK - /* - * If no refclock support, no data to return - */ - ctl_error(CERR_BADASSOC); -#else - register struct ctl_var *v; - register int i; - register struct peer *peer; - char *valuep; - u_char *wants; - unsigned int gotvar; - struct refclockstat clock_stat; - - if (res_associd == 0) { - - /* - * Find a clock for this jerk. If the system peer - * is a clock use it, else search the hash tables - * for one. - */ - if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK)) - { - peer = sys_peer; - } else { - peer = 0; - for (i = 0; peer == 0 && i < HASH_SIZE; i++) { - for (peer = assoc_hash[i]; peer != 0; - peer = peer->ass_next) { - if (peer->flags & FLAG_REFCLOCK) - break; - } - } - if (peer == 0) { - ctl_error(CERR_BADASSOC); - return; - } - } - } else { - peer = findpeerbyassoc(res_associd); - if (peer == 0 || !(peer->flags & FLAG_REFCLOCK)) { - ctl_error(CERR_BADASSOC); - return; - } - } - - /* - * If we got here we have a peer which is a clock. Get his - * status. - */ - clock_stat.kv_list = (struct ctl_var *)0; - refclock_control(&peer->srcadr, (struct refclockstat *)0, - &clock_stat); - - /* - * Look for variables in the packet. - */ - rpkt.status = htons(ctlclkstatus(&clock_stat)); - gotvar = CC_MAXCODE + 1 + count_var(clock_stat.kv_list); - wants = (u_char *)emalloc(gotvar); - memset((char*)wants, 0, gotvar); - gotvar = 0; - while ((v = ctl_getitem(clock_var, &valuep)) != 0) { - if (v->flags & EOV) { - if ((v = ctl_getitem(clock_stat.kv_list, - &valuep)) != 0) { - if (v->flags & EOV) { - ctl_error(CERR_UNKNOWNVAR); - free((char*)wants); - free_varlist(clock_stat.kv_list); - return; - } - wants[CC_MAXCODE + 1 + v->code] = 1; - gotvar = 1; - continue; - } else { - break; /* shouldn't happen ! */ - } - } - wants[v->code] = 1; - gotvar = 1; - } - - if (gotvar) { - for (i = 1; i <= CC_MAXCODE; i++) - if (wants[i]) - ctl_putclock(i, &clock_stat, 1); - for (i = 0; clock_stat.kv_list && - !(clock_stat.kv_list[i].flags & EOV); i++) - if (wants[i + CC_MAXCODE + 1]) - ctl_putdata(clock_stat.kv_list[i].text, - strlen(clock_stat.kv_list[i].text), - 0); - } else { - register u_char *cc; - register struct ctl_var *kv; - - for (cc = def_clock_var; *cc != 0; cc++) - ctl_putclock((int)*cc, &clock_stat, 0); - for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV); - kv++) - if (kv->flags & DEF) - ctl_putdata(kv->text, strlen(kv->text), - 0); - } - - free((char*)wants); - free_varlist(clock_stat.kv_list); - - ctl_flushpkt(0); -#endif -} - - -/* - * write_clock_status - we don't do this - */ -/*ARGSUSED*/ -static void -write_clock_status( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - ctl_error(CERR_PERMISSION); -} - -/* - * Trap support from here on down. We send async trap messages when the - * upper levels report trouble. Traps can by set either by control - * messages or by configuration. - */ -/* - * set_trap - set a trap in response to a control message - */ -static void -set_trap( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - int traptype; - - /* - * See if this guy is allowed - */ - if (restrict_mask & RES_NOTRAP) { - ctl_error(CERR_PERMISSION); - return; - } - - /* - * Determine his allowed trap type. - */ - traptype = TRAP_TYPE_PRIO; - if (restrict_mask & RES_LPTRAP) - traptype = TRAP_TYPE_NONPRIO; - - /* - * Call ctlsettrap() to do the work. Return - * an error if it can't assign the trap. - */ - if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype, - (int)res_version)) - ctl_error(CERR_NORESOURCE); - ctl_flushpkt(0); -} - - -/* - * unset_trap - unset a trap in response to a control message - */ -static void -unset_trap( - struct recvbuf *rbufp, - int restrict_mask - ) -{ - int traptype; - - /* - * We don't prevent anyone from removing his own trap unless the - * trap is configured. Note we also must be aware of the - * possibility that restriction flags were changed since this - * guy last set his trap. Set the trap type based on this. - */ - traptype = TRAP_TYPE_PRIO; - if (restrict_mask & RES_LPTRAP) - traptype = TRAP_TYPE_NONPRIO; - - /* - * Call ctlclrtrap() to clear this out. - */ - if (!ctlclrtrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype)) - ctl_error(CERR_BADASSOC); - ctl_flushpkt(0); -} - - -/* - * ctlsettrap - called to set a trap - */ -int -ctlsettrap( - struct sockaddr_storage *raddr, - struct interface *linter, - int traptype, - int version - ) -{ - register struct ctl_trap *tp; - register struct ctl_trap *tptouse; - - /* - * See if we can find this trap. If so, we only need update - * the flags and the time. - */ - if ((tp = ctlfindtrap(raddr, linter)) != NULL) { - switch (traptype) { - - case TRAP_TYPE_CONFIG: - tp->tr_flags = TRAP_INUSE|TRAP_CONFIGURED; - break; - - case TRAP_TYPE_PRIO: - if (tp->tr_flags & TRAP_CONFIGURED) - return (1); /* don't change anything */ - tp->tr_flags = TRAP_INUSE; - break; - - case TRAP_TYPE_NONPRIO: - if (tp->tr_flags & TRAP_CONFIGURED) - return (1); /* don't change anything */ - tp->tr_flags = TRAP_INUSE|TRAP_NONPRIO; - break; - } - tp->tr_settime = current_time; - tp->tr_resets++; - return (1); - } - - /* - * First we heard of this guy. Try to find a trap structure - * for him to use, clearing out lesser priority guys if we - * have to. Clear out anyone who's expired while we're at it. - */ - tptouse = NULL; - for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) { - if ((tp->tr_flags & TRAP_INUSE) && - !(tp->tr_flags & TRAP_CONFIGURED) && - ((tp->tr_settime + CTL_TRAPTIME) > current_time)) { - tp->tr_flags = 0; - num_ctl_traps--; - } - if (!(tp->tr_flags & TRAP_INUSE)) { - tptouse = tp; - } else if (!(tp->tr_flags & TRAP_CONFIGURED)) { - switch (traptype) { - - case TRAP_TYPE_CONFIG: - if (tptouse == NULL) { - tptouse = tp; - break; - } - if (tptouse->tr_flags & TRAP_NONPRIO && - !(tp->tr_flags & TRAP_NONPRIO)) - break; - - if (!(tptouse->tr_flags & TRAP_NONPRIO) - && tp->tr_flags & TRAP_NONPRIO) { - tptouse = tp; - break; - } - if (tptouse->tr_origtime < - tp->tr_origtime) - tptouse = tp; - break; - - case TRAP_TYPE_PRIO: - if (tp->tr_flags & TRAP_NONPRIO) { - if (tptouse == NULL || - (tptouse->tr_flags & - TRAP_INUSE && - tptouse->tr_origtime < - tp->tr_origtime)) - tptouse = tp; - } - break; - - case TRAP_TYPE_NONPRIO: - break; - } - } - } - - /* - * If we don't have room for him return an error. - */ - if (tptouse == NULL) - return (0); - - /* - * Set up this structure for him. - */ - tptouse->tr_settime = tptouse->tr_origtime = current_time; - tptouse->tr_count = tptouse->tr_resets = 0; - tptouse->tr_sequence = 1; - tptouse->tr_addr = *raddr; - tptouse->tr_localaddr = linter; - tptouse->tr_version = (u_char) version; - tptouse->tr_flags = TRAP_INUSE; - if (traptype == TRAP_TYPE_CONFIG) - tptouse->tr_flags |= TRAP_CONFIGURED; - else if (traptype == TRAP_TYPE_NONPRIO) - tptouse->tr_flags |= TRAP_NONPRIO; - num_ctl_traps++; - return (1); -} - - -/* - * ctlclrtrap - called to clear a trap - */ -int -ctlclrtrap( - struct sockaddr_storage *raddr, - struct interface *linter, - int traptype - ) -{ - register struct ctl_trap *tp; - - if ((tp = ctlfindtrap(raddr, linter)) == NULL) - return (0); - - if (tp->tr_flags & TRAP_CONFIGURED - && traptype != TRAP_TYPE_CONFIG) - return (0); - - tp->tr_flags = 0; - num_ctl_traps--; - return (1); -} - - -/* - * ctlfindtrap - find a trap given the remote and local addresses - */ -static struct ctl_trap * -ctlfindtrap( - struct sockaddr_storage *raddr, - struct interface *linter - ) -{ - register struct ctl_trap *tp; - - for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) { - if ((tp->tr_flags & TRAP_INUSE) - && (NSRCPORT(raddr) == NSRCPORT(&tp->tr_addr)) - && SOCKCMP(raddr, &tp->tr_addr) - && (linter == tp->tr_localaddr) ) - return (tp); - } - return (struct ctl_trap *)NULL; -} - - -/* - * report_event - report an event to the trappers - */ -void -report_event( - int err, - struct peer *peer - ) -{ - register int i; - - /* - * Record error code in proper spots, but have mercy on the - * log file. - */ - if (!(err & (PEER_EVENT | CRPT_EVENT))) { - if (ctl_sys_num_events < CTL_SYS_MAXEVENTS) - ctl_sys_num_events++; - if (ctl_sys_last_event != (u_char)err) { - NLOG(NLOG_SYSEVENT) - msyslog(LOG_INFO, "system event '%s' (0x%02x) status '%s' (0x%02x)", - eventstr(err), err, - sysstatstr(ctlsysstatus()), ctlsysstatus()); -#ifdef DEBUG - if (debug) - printf("report_event: system event '%s' (0x%02x) status '%s' (0x%02x)\n", - eventstr(err), err, - sysstatstr(ctlsysstatus()), - ctlsysstatus()); -#endif - ctl_sys_last_event = (u_char)err; - } - } else if (peer != 0) { - char *src; - -#ifdef REFCLOCK - if (ISREFCLOCKADR(&peer->srcadr)) - src = refnumtoa(&peer->srcadr); - else -#endif - src = stoa(&peer->srcadr); - - peer->last_event = (u_char)(err & ~PEER_EVENT); - if (peer->num_events < CTL_PEER_MAXEVENTS) - peer->num_events++; - NLOG(NLOG_PEEREVENT) - msyslog(LOG_INFO, "peer %s event '%s' (0x%02x) status '%s' (0x%02x)", - src, eventstr(err), err, - peerstatstr(ctlpeerstatus(peer)), - ctlpeerstatus(peer)); -#ifdef DEBUG - if (debug) - printf( "peer %s event '%s' (0x%02x) status '%s' (0x%02x)\n", - src, eventstr(err), err, - peerstatstr(ctlpeerstatus(peer)), - ctlpeerstatus(peer)); -#endif - } else { - msyslog(LOG_ERR, - "report_event: err '%s' (0x%02x), no peer", - eventstr(err), err); -#ifdef DEBUG - printf( - "report_event: peer event '%s' (0x%02x), no peer\n", - eventstr(err), err); -#endif - return; - } - - /* - * If no trappers, return. - */ - if (num_ctl_traps <= 0) - return; - - /* - * Set up the outgoing packet variables - */ - res_opcode = CTL_OP_ASYNCMSG; - res_offset = 0; - res_async = 1; - res_authenticate = 0; - datapt = rpkt.data; - dataend = &(rpkt.data[CTL_MAX_DATA_LEN]); - if (!(err & PEER_EVENT)) { - rpkt.associd = 0; - rpkt.status = htons(ctlsysstatus()); - - /* - * For now, put everything we know about system - * variables. Don't send crypto strings. - */ - for (i = 1; i <= CS_MAXCODE; i++) { -#ifdef OPENSSL - if (i > CS_VARLIST) - continue; -#endif /* OPENSSL */ - ctl_putsys(i); - } -#ifdef REFCLOCK - /* - * for clock exception events: add clock variables to - * reflect info on exception - */ - if (err == EVNT_CLOCKEXCPT) { - struct refclockstat clock_stat; - struct ctl_var *kv; - - clock_stat.kv_list = (struct ctl_var *)0; - refclock_control(&peer->srcadr, - (struct refclockstat *)0, &clock_stat); - ctl_puthex("refclockstatus", - ctlclkstatus(&clock_stat)); - for (i = 1; i <= CC_MAXCODE; i++) - ctl_putclock(i, &clock_stat, 0); - for (kv = clock_stat.kv_list; kv && - !(kv->flags & EOV); kv++) - if (kv->flags & DEF) - ctl_putdata(kv->text, - strlen(kv->text), 0); - free_varlist(clock_stat.kv_list); - } -#endif /* REFCLOCK */ - } else { - rpkt.associd = htons(peer->associd); - rpkt.status = htons(ctlpeerstatus(peer)); - - /* - * Dump it all. Later, maybe less. - */ - for (i = 1; i <= CP_MAXCODE; i++) { -#ifdef OPENSSL - if (i > CP_VARLIST) - continue; -#endif /* OPENSSL */ - ctl_putpeer(i, peer); - } -#ifdef REFCLOCK - /* - * for clock exception events: add clock variables to - * reflect info on exception - */ - if (err == EVNT_PEERCLOCK) { - struct refclockstat clock_stat; - struct ctl_var *kv; - - clock_stat.kv_list = (struct ctl_var *)0; - refclock_control(&peer->srcadr, - (struct refclockstat *)0, &clock_stat); - - ctl_puthex("refclockstatus", - ctlclkstatus(&clock_stat)); - - for (i = 1; i <= CC_MAXCODE; i++) - ctl_putclock(i, &clock_stat, 0); - for (kv = clock_stat.kv_list; kv && - !(kv->flags & EOV); kv++) - if (kv->flags & DEF) - ctl_putdata(kv->text, - strlen(kv->text), 0); - free_varlist(clock_stat.kv_list); - } -#endif /* REFCLOCK */ - } - - /* - * We're done, return. - */ - ctl_flushpkt(0); -} - - -/* - * ctl_clr_stats - clear stat counters - */ -void -ctl_clr_stats(void) -{ - ctltimereset = current_time; - numctlreq = 0; - numctlbadpkts = 0; - numctlresponses = 0; - numctlfrags = 0; - numctlerrors = 0; - numctlfrags = 0; - numctltooshort = 0; - numctlinputresp = 0; - numctlinputfrag = 0; - numctlinputerr = 0; - numctlbadoffset = 0; - numctlbadversion = 0; - numctldatatooshort = 0; - numctlbadop = 0; - numasyncmsgs = 0; -} - -static u_long -count_var( - struct ctl_var *k - ) -{ - register u_long c; - - if (!k) - return (0); - - c = 0; - while (!(k++->flags & EOV)) - c++; - return (c); -} - -char * -add_var( - struct ctl_var **kv, - u_long size, - u_short def - ) -{ - register u_long c; - register struct ctl_var *k; - - c = count_var(*kv); - - k = *kv; - *kv = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var)); - if (k) { - memmove((char *)*kv, (char *)k, - sizeof(struct ctl_var)*c); - free((char *)k); - } - (*kv)[c].code = (u_short) c; - (*kv)[c].text = (char *)emalloc(size); - (*kv)[c].flags = def; - (*kv)[c+1].code = 0; - (*kv)[c+1].text = (char *)0; - (*kv)[c+1].flags = EOV; - return (char *)(*kv)[c].text; -} - -void -set_var( - struct ctl_var **kv, - const char *data, - u_long size, - u_short def - ) -{ - register struct ctl_var *k; - register const char *s; - register const char *t; - char *td; - - if (!data || !size) - return; - - k = *kv; - if (k != NULL) { - while (!(k->flags & EOV)) { - s = data; - t = k->text; - if (t) { - while (*t != '=' && *s - *t == 0) { - s++; - t++; - } - if (*s == *t && ((*t == '=') || !*t)) { - free((void *)k->text); - td = (char *)emalloc(size); - memmove(td, data, size); - k->text =td; - k->flags = def; - return; - } - } else { - td = (char *)emalloc(size); - memmove(td, data, size); - k->text = td; - k->flags = def; - return; - } - k++; - } - } - td = add_var(kv, size, def); - memmove(td, data, size); -} - -void -set_sys_var( - char *data, - u_long size, - u_short def - ) -{ - set_var(&ext_sys_var, data, size, def); -} - -void -free_varlist( - struct ctl_var *kv - ) -{ - struct ctl_var *k; - if (kv) { - for (k = kv; !(k->flags & EOV); k++) - free((void *)k->text); - free((void *)kv); - } -} |