File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / ntp_control.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * ntp_control.c - respond to control messages and send async traps
    3:  */
    4: 
    5: #ifdef HAVE_CONFIG_H
    6: # include <config.h>
    7: #endif
    8: 
    9: #include "ntpd.h"
   10: #include "ntp_io.h"
   11: #include "ntp_refclock.h"
   12: #include "ntp_control.h"
   13: #include "ntp_unixtime.h"
   14: #include "ntp_stdlib.h"
   15: #include "ntp_config.h"
   16: #include "ntp_crypto.h"
   17: #include "ntp_assert.h"
   18: 
   19: #include <stdio.h>
   20: #include <ctype.h>
   21: #include <signal.h>
   22: #include <sys/stat.h>
   23: 
   24: #ifdef HAVE_NETINET_IN_H
   25: #include <netinet/in.h>
   26: #endif
   27: #include <arpa/inet.h>
   28: 
   29: /*
   30:  * Structure to hold request procedure information
   31:  */
   32: 
   33: struct ctl_proc {
   34: 	short control_code;		/* defined request code */
   35: #define NO_REQUEST	(-1)
   36: 	u_short flags;			/* flags word */
   37: 	/* Only one flag.  Authentication required or not. */
   38: #define NOAUTH	0
   39: #define AUTH	1
   40: 	void (*handler) (struct recvbuf *, int); /* handle request */
   41: };
   42: 
   43: 
   44: /*
   45:  * Request processing routines
   46:  */
   47: static	void	ctl_error	(int);
   48: #ifdef REFCLOCK
   49: static	u_short ctlclkstatus	(struct refclockstat *);
   50: #endif
   51: static	void	ctl_flushpkt	(int);
   52: static	void	ctl_putdata	(const char *, unsigned int, int);
   53: static	void	ctl_putstr	(const char *, const char *,
   54: 				 unsigned int);
   55: static	void	ctl_putdbl	(const char *, double);
   56: static	void	ctl_putuint	(const char *, u_long);
   57: static	void	ctl_puthex	(const char *, u_long);
   58: static	void	ctl_putint	(const char *, long);
   59: static	void	ctl_putts	(const char *, l_fp *);
   60: static	void	ctl_putadr	(const char *, u_int32,
   61: 				 sockaddr_u *);
   62: static	void	ctl_putrefid	(const char *, u_int32);
   63: static	void	ctl_putarray	(const char *, double *, int);
   64: static	void	ctl_putsys	(int);
   65: static	void	ctl_putpeer	(int, struct peer *);
   66: static	void	ctl_putfs	(const char *, tstamp_t);
   67: #ifdef REFCLOCK
   68: static	void	ctl_putclock	(int, struct refclockstat *, int);
   69: #endif	/* REFCLOCK */
   70: static	struct ctl_var *ctl_getitem (struct ctl_var *, char **);
   71: static	u_long count_var	(struct ctl_var *);
   72: static	void	control_unspec	(struct recvbuf *, int);
   73: static	void	read_status	(struct recvbuf *, int);
   74: static	void	read_variables	(struct recvbuf *, int);
   75: static	void	write_variables (struct recvbuf *, int);
   76: static	void	read_clock_status (struct recvbuf *, int);
   77: static	void	write_clock_status (struct recvbuf *, int);
   78: static	void	set_trap	(struct recvbuf *, int);
   79: static	void	unset_trap	(struct recvbuf *, int);
   80: static	void	configure	(struct recvbuf *, int);
   81: static	void	save_config	(struct recvbuf *, int);
   82: static	struct ctl_trap *ctlfindtrap (sockaddr_u *,
   83: 				      struct interface *);
   84: 
   85: static	struct ctl_proc control_codes[] = {
   86: 	{ CTL_OP_UNSPEC,	NOAUTH, control_unspec },
   87: 	{ CTL_OP_READSTAT,	NOAUTH, read_status },
   88: 	{ CTL_OP_READVAR,	NOAUTH, read_variables },
   89: 	{ CTL_OP_WRITEVAR,	AUTH,	write_variables },
   90: 	{ CTL_OP_READCLOCK,	NOAUTH, read_clock_status },
   91: 	{ CTL_OP_WRITECLOCK,	NOAUTH, write_clock_status },
   92: 	{ CTL_OP_SETTRAP,	NOAUTH, set_trap },
   93: 	{ CTL_OP_UNSETTRAP,	NOAUTH, unset_trap },
   94: 	{ CTL_OP_SAVECONFIG,	AUTH,	save_config },
   95: 	{ CTL_OP_CONFIGURE,	AUTH,	configure },
   96: 	{ NO_REQUEST,		0 }
   97: };
   98: 
   99: /*
  100:  * System variable values. The array can be indexed by the variable
  101:  * index to find the textual name.
  102:  */
  103: static struct ctl_var sys_var[] = {
  104: 	{ 0,		PADDING, "" },		/* 0 */
  105: 	{ CS_LEAP,	RW, "leap" },		/* 1 */
  106: 	{ CS_STRATUM,	RO, "stratum" },	/* 2 */
  107: 	{ CS_PRECISION, RO, "precision" },	/* 3 */
  108: 	{ CS_ROOTDELAY, RO, "rootdelay" },	/* 4 */
  109: 	{ CS_ROOTDISPERSION, RO, "rootdisp" },	/* 5 */
  110: 	{ CS_REFID,	RO, "refid" },		/* 6 */
  111: 	{ CS_REFTIME,	RO, "reftime" },	/* 7 */
  112: 	{ CS_POLL,	RO, "tc" },		/* 8 */
  113: 	{ CS_PEERID,	RO, "peer" },		/* 9 */
  114: 	{ CS_OFFSET,	RO, "offset" },		/* 10 */
  115: 	{ CS_DRIFT,	RO, "frequency" },	/* 11 */
  116: 	{ CS_JITTER,	RO, "sys_jitter" },	/* 12 */
  117: 	{ CS_ERROR,	RO, "clk_jitter" },	/* 13 */
  118: 	{ CS_CLOCK,	RO, "clock" },		/* 14 */
  119: 	{ CS_PROCESSOR, RO, "processor" },	/* 15 */
  120: 	{ CS_SYSTEM,	RO, "system" },		/* 16 */
  121: 	{ CS_VERSION,	RO, "version" },	/* 17 */
  122: 	{ CS_STABIL,	RO, "clk_wander" },	/* 18 */
  123: 	{ CS_VARLIST,	RO, "sys_var_list" },	/* 19 */
  124: 	{ CS_TAI,	RO, "tai" },		/* 20 */
  125: 	{ CS_LEAPTAB,	RO, "leapsec" },	/* 21 */
  126: 	{ CS_LEAPEND,	RO, "expire" },		/* 22 */
  127: 	{ CS_RATE,	RO, "mintc" },		/* 23 */
  128: #ifdef OPENSSL
  129: 	{ CS_FLAGS,	RO, "flags" },		/* 24 */
  130: 	{ CS_HOST,	RO, "host" },		/* 25 */
  131: 	{ CS_PUBLIC,	RO, "update" },		/* 26 */
  132: 	{ CS_CERTIF,	RO, "cert" },		/* 27 */
  133: 	{ CS_SIGNATURE,	RO, "signature" },	/* 28 */
  134: 	{ CS_REVTIME,	RO, "until" },		/* 29 */
  135: 	{ CS_GROUP,	RO, "group" },		/* 30 */
  136: 	{ CS_DIGEST,	RO, "digest" },		/* 31 */
  137: #endif /* OPENSSL */
  138: 	{ 0,		EOV, "" }		/* 24/3 2*/
  139: };
  140: 
  141: static struct ctl_var *ext_sys_var = (struct ctl_var *)0;
  142: 
  143: /*
  144:  * System variables we print by default (in fuzzball order,
  145:  * more-or-less)
  146:  */
  147: static	u_char def_sys_var[] = {
  148: 	CS_VERSION,
  149: 	CS_PROCESSOR,
  150: 	CS_SYSTEM,
  151: 	CS_LEAP,
  152: 	CS_STRATUM,
  153: 	CS_PRECISION,
  154: 	CS_ROOTDELAY,
  155: 	CS_ROOTDISPERSION,
  156: 	CS_REFID,
  157: 	CS_REFTIME,
  158: 	CS_CLOCK,
  159: 	CS_PEERID,
  160: 	CS_POLL,
  161: 	CS_RATE,
  162: 	CS_OFFSET,
  163: 	CS_DRIFT,
  164: 	CS_JITTER,
  165: 	CS_ERROR,
  166: 	CS_STABIL,
  167: 	CS_TAI,
  168: 	CS_LEAPTAB,
  169: 	CS_LEAPEND,
  170: #ifdef OPENSSL
  171: 	CS_HOST,
  172: 	CS_GROUP,
  173: 	CS_FLAGS,
  174: 	CS_DIGEST,
  175: 	CS_SIGNATURE,
  176: 	CS_PUBLIC,
  177: 	CS_CERTIF,
  178: #endif /* OPENSSL */
  179: 	0
  180: };
  181: 
  182: 
  183: /*
  184:  * Peer variable list
  185:  */
  186: static struct ctl_var peer_var[] = {
  187: 	{ 0,		PADDING, "" },		/* 0 */
  188: 	{ CP_CONFIG,	RO, "config" },		/* 1 */
  189: 	{ CP_AUTHENABLE, RO,	"authenable" },	/* 2 */
  190: 	{ CP_AUTHENTIC, RO, "authentic" }, 	/* 3 */
  191: 	{ CP_SRCADR,	RO, "srcadr" },		/* 4 */
  192: 	{ CP_SRCPORT,	RO, "srcport" },	/* 5 */
  193: 	{ CP_DSTADR,	RO, "dstadr" },		/* 6 */
  194: 	{ CP_DSTPORT,	RO, "dstport" },	/* 7 */
  195: 	{ CP_LEAP,	RO, "leap" },		/* 8 */
  196: 	{ CP_HMODE,	RO, "hmode" },		/* 9 */
  197: 	{ CP_STRATUM,	RO, "stratum" },	/* 10 */
  198: 	{ CP_PPOLL,	RO, "ppoll" },		/* 11 */
  199: 	{ CP_HPOLL,	RO, "hpoll" },		/* 12 */
  200: 	{ CP_PRECISION,	RO, "precision" },	/* 13 */
  201: 	{ CP_ROOTDELAY,	RO, "rootdelay" },	/* 14 */
  202: 	{ CP_ROOTDISPERSION, RO, "rootdisp" },	/* 15 */
  203: 	{ CP_REFID,	RO, "refid" },		/* 16 */
  204: 	{ CP_REFTIME,	RO, "reftime" },	/* 17 */
  205: 	{ CP_ORG,	RO, "org" },		/* 18 */
  206: 	{ CP_REC,	RO, "rec" },		/* 19 */
  207: 	{ CP_XMT,	RO, "xleave" },		/* 20 */
  208: 	{ CP_REACH,	RO, "reach" },		/* 21 */
  209: 	{ CP_UNREACH,	RO, "unreach" },	/* 22 */
  210: 	{ CP_TIMER,	RO, "timer" },		/* 23 */
  211: 	{ CP_DELAY,	RO, "delay" },		/* 24 */
  212: 	{ CP_OFFSET,	RO, "offset" },		/* 25 */
  213: 	{ CP_JITTER,	RO, "jitter" },		/* 26 */
  214: 	{ CP_DISPERSION, RO, "dispersion" },	/* 27 */
  215: 	{ CP_KEYID,	RO, "keyid" },		/* 28 */
  216: 	{ CP_FILTDELAY,	RO, "filtdelay=" },	/* 29 */
  217: 	{ CP_FILTOFFSET, RO, "filtoffset=" },	/* 30 */
  218: 	{ CP_PMODE,	RO, "pmode" },		/* 31 */
  219: 	{ CP_RECEIVED,	RO, "received"},	/* 32 */
  220: 	{ CP_SENT,	RO, "sent" },		/* 33 */
  221: 	{ CP_FILTERROR,	RO, "filtdisp=" },	/* 34 */
  222: 	{ CP_FLASH,	RO, "flash" },		/* 35 */
  223: 	{ CP_TTL,	RO, "ttl" },		/* 36 */
  224: 	{ CP_VARLIST,	RO, "peer_var_list" },	/* 37 */
  225: 	{ CP_IN,	RO, "in" },		/* 38 */
  226: 	{ CP_OUT,	RO, "out" },		/* 39 */
  227: 	{ CP_RATE,	RO, "headway" },	/* 40 */
  228: 	{ CP_BIAS,	RO, "bias" },		/* 41 */
  229: #ifdef OPENSSL
  230: 	{ CP_FLAGS,	RO, "flags" },		/* 42 */
  231: 	{ CP_HOST,	RO, "host" },		/* 43 */
  232: 	{ CP_VALID,	RO, "valid" },		/* 44 */
  233: 	{ CP_INITSEQ,	RO, "initsequence" },   /* 45 */
  234: 	{ CP_INITKEY,	RO, "initkey" },	/* 46 */
  235: 	{ CP_INITTSP,	RO, "timestamp" },	/* 47 */
  236: 	{ CP_SIGNATURE,	RO, "signature" },	/* 48 */
  237: #endif /* OPENSSL */
  238: 	{ 0,		EOV, "" }		/* 42/49 */
  239: };
  240: 
  241: 
  242: /*
  243:  * Peer variables we print by default
  244:  */
  245: static u_char def_peer_var[] = {
  246: 	CP_SRCADR,
  247: 	CP_SRCPORT,
  248: 	CP_DSTADR,
  249: 	CP_DSTPORT,
  250: 	CP_OUT,
  251: 	CP_IN,
  252: 	CP_LEAP,
  253: 	CP_STRATUM,
  254: 	CP_PRECISION,
  255: 	CP_ROOTDELAY,
  256: 	CP_ROOTDISPERSION,
  257: 	CP_REFID,
  258: 	CP_REFTIME,
  259: 	CP_REC,
  260: 	CP_REACH,
  261: 	CP_UNREACH,
  262: 	CP_HMODE,
  263: 	CP_PMODE,
  264: 	CP_HPOLL,
  265: 	CP_PPOLL,
  266: 	CP_RATE,
  267: 	CP_FLASH,
  268: 	CP_KEYID,
  269: 	CP_TTL,
  270: 	CP_OFFSET,
  271: 	CP_DELAY,
  272: 	CP_DISPERSION,
  273: 	CP_JITTER,
  274: 	CP_XMT,
  275: 	CP_BIAS,
  276: 	CP_FILTDELAY,
  277: 	CP_FILTOFFSET,
  278: 	CP_FILTERROR,
  279: #ifdef OPENSSL
  280: 	CP_HOST,
  281: 	CP_FLAGS,
  282: 	CP_SIGNATURE,
  283: 	CP_VALID,
  284: 	CP_INITSEQ,
  285: #endif /* OPENSSL */
  286: 	0
  287: };
  288: 
  289: 
  290: #ifdef REFCLOCK
  291: /*
  292:  * Clock variable list
  293:  */
  294: static struct ctl_var clock_var[] = {
  295: 	{ 0,		PADDING, "" },		/* 0 */
  296: 	{ CC_TYPE,	RO, "type" },		/* 1 */
  297: 	{ CC_TIMECODE,	RO, "timecode" },	/* 2 */
  298: 	{ CC_POLL,	RO, "poll" },		/* 3 */
  299: 	{ CC_NOREPLY,	RO, "noreply" },	/* 4 */
  300: 	{ CC_BADFORMAT, RO, "badformat" },	/* 5 */
  301: 	{ CC_BADDATA,	RO, "baddata" },	/* 6 */
  302: 	{ CC_FUDGETIME1, RO, "fudgetime1" },	/* 7 */
  303: 	{ CC_FUDGETIME2, RO, "fudgetime2" },	/* 8 */
  304: 	{ CC_FUDGEVAL1, RO, "stratum" },	/* 9 */
  305: 	{ CC_FUDGEVAL2, RO, "refid" },		/* 10 */
  306: 	{ CC_FLAGS,	RO, "flags" },		/* 11 */
  307: 	{ CC_DEVICE,	RO, "device" },		/* 12 */
  308: 	{ CC_VARLIST,	RO, "clock_var_list" },	/* 13 */
  309: 	{ 0,		EOV, ""  }		/* 14 */
  310: };
  311: 
  312: 
  313: /*
  314:  * Clock variables printed by default
  315:  */
  316: static u_char def_clock_var[] = {
  317: 	CC_DEVICE,
  318: 	CC_TYPE,	/* won't be output if device = known */
  319: 	CC_TIMECODE,
  320: 	CC_POLL,
  321: 	CC_NOREPLY,
  322: 	CC_BADFORMAT,
  323: 	CC_BADDATA,
  324: 	CC_FUDGETIME1,
  325: 	CC_FUDGETIME2,
  326: 	CC_FUDGEVAL1,
  327: 	CC_FUDGEVAL2,
  328: 	CC_FLAGS,
  329: 	0
  330: };
  331: #endif
  332: 
  333: 
  334: /*
  335:  * System and processor definitions.
  336:  */
  337: #ifndef HAVE_UNAME
  338: # ifndef STR_SYSTEM
  339: #  define		STR_SYSTEM	"UNIX"
  340: # endif
  341: # ifndef STR_PROCESSOR
  342: #  define		STR_PROCESSOR	"unknown"
  343: # endif
  344: 
  345: static char str_system[] = STR_SYSTEM;
  346: static char str_processor[] = STR_PROCESSOR;
  347: #else
  348: # include <sys/utsname.h>
  349: static struct utsname utsnamebuf;
  350: #endif /* HAVE_UNAME */
  351: 
  352: /*
  353:  * Trap structures. We only allow a few of these, and send a copy of
  354:  * each async message to each live one. Traps time out after an hour, it
  355:  * is up to the trap receipient to keep resetting it to avoid being
  356:  * timed out.
  357:  */
  358: /* ntp_request.c */
  359: struct ctl_trap ctl_trap[CTL_MAXTRAPS];
  360: int num_ctl_traps;
  361: 
  362: /*
  363:  * Type bits, for ctlsettrap() call.
  364:  */
  365: #define TRAP_TYPE_CONFIG	0	/* used by configuration code */
  366: #define TRAP_TYPE_PRIO		1	/* priority trap */
  367: #define TRAP_TYPE_NONPRIO	2	/* nonpriority trap */
  368: 
  369: 
  370: /*
  371:  * List relating reference clock types to control message time sources.
  372:  * Index by the reference clock type. This list will only be used iff
  373:  * the reference clock driver doesn't set peer->sstclktype to something
  374:  * different than CTL_SST_TS_UNSPEC.
  375:  */
  376: static u_char clocktypes[] = {
  377: 	CTL_SST_TS_NTP, 	/* REFCLK_NONE (0) */
  378: 	CTL_SST_TS_LOCAL,	/* REFCLK_LOCALCLOCK (1) */
  379: 	CTL_SST_TS_UHF, 	/* deprecated REFCLK_GPS_TRAK (2) */
  380: 	CTL_SST_TS_HF,		/* REFCLK_WWV_PST (3) */
  381: 	CTL_SST_TS_LF,		/* REFCLK_WWVB_SPECTRACOM (4) */
  382: 	CTL_SST_TS_UHF, 	/* REFCLK_TRUETIME (5) */
  383: 	CTL_SST_TS_UHF, 	/* REFCLK_GOES_TRAK (6) IRIG_AUDIO? */
  384: 	CTL_SST_TS_HF,		/* REFCLK_CHU (7) */
  385: 	CTL_SST_TS_LF,		/* REFCLOCK_PARSE (default) (8) */
  386: 	CTL_SST_TS_LF,		/* REFCLK_GPS_MX4200 (9) */
  387: 	CTL_SST_TS_UHF, 	/* REFCLK_GPS_AS2201 (10) */
  388: 	CTL_SST_TS_UHF, 	/* REFCLK_GPS_ARBITER (11) */
  389: 	CTL_SST_TS_UHF, 	/* REFCLK_IRIG_TPRO (12) */
  390: 	CTL_SST_TS_ATOM,	/* REFCLK_ATOM_LEITCH (13) */
  391: 	CTL_SST_TS_LF,		/* deprecated REFCLK_MSF_EES (14) */
  392: 	CTL_SST_TS_NTP, 	/* not used (15) */
  393: 	CTL_SST_TS_UHF, 	/* REFCLK_IRIG_BANCOMM (16) */
  394: 	CTL_SST_TS_UHF, 	/* REFCLK_GPS_DATU (17) */
  395: 	CTL_SST_TS_TELEPHONE,	/* REFCLK_NIST_ACTS (18) */
  396: 	CTL_SST_TS_HF,		/* REFCLK_WWV_HEATH (19) */
  397: 	CTL_SST_TS_UHF, 	/* REFCLK_GPS_NMEA (20) */
  398: 	CTL_SST_TS_UHF, 	/* REFCLK_GPS_VME (21) */
  399: 	CTL_SST_TS_ATOM,	/* REFCLK_ATOM_PPS (22) */
  400: 	CTL_SST_TS_NTP,		/* not used (23) */
  401: 	CTL_SST_TS_NTP,		/* not used (24) */
  402: 	CTL_SST_TS_NTP, 	/* not used (25) */
  403: 	CTL_SST_TS_UHF, 	/* REFCLK_GPS_HP (26) */
  404: 	CTL_SST_TS_LF,		/* REFCLK_ARCRON_MSF (27) */
  405: 	CTL_SST_TS_UHF,		/* REFCLK_SHM (28) */
  406: 	CTL_SST_TS_UHF, 	/* REFCLK_PALISADE (29) */
  407: 	CTL_SST_TS_UHF, 	/* REFCLK_ONCORE (30) */
  408: 	CTL_SST_TS_UHF,		/* REFCLK_JUPITER (31) */
  409: 	CTL_SST_TS_LF,		/* REFCLK_CHRONOLOG (32) */
  410: 	CTL_SST_TS_LF,		/* REFCLK_DUMBCLOCK (33) */
  411: 	CTL_SST_TS_LF,		/* REFCLK_ULINK (34) */
  412: 	CTL_SST_TS_LF,		/* REFCLK_PCF (35) */
  413: 	CTL_SST_TS_HF,		/* REFCLK_WWV (36) */
  414: 	CTL_SST_TS_LF,		/* REFCLK_FG (37) */
  415: 	CTL_SST_TS_UHF, 	/* REFCLK_HOPF_SERIAL (38) */
  416: 	CTL_SST_TS_UHF,		/* REFCLK_HOPF_PCI (39) */
  417: 	CTL_SST_TS_LF,		/* REFCLK_JJY (40) */
  418: 	CTL_SST_TS_UHF,		/* REFCLK_TT560 (41) */
  419: 	CTL_SST_TS_UHF,		/* REFCLK_ZYFER (42) */
  420: 	CTL_SST_TS_UHF,		/* REFCLK_RIPENCC (43) */
  421: 	CTL_SST_TS_UHF,		/* REFCLK_NEOCLOCK4X (44) */
  422: };
  423: 
  424: 
  425: /*
  426:  * Keyid used for authenticating write requests.
  427:  */
  428: keyid_t ctl_auth_keyid;
  429: 
  430: /*
  431:  * We keep track of the last error reported by the system internally
  432:  */
  433: static	u_char ctl_sys_last_event;
  434: static	u_char ctl_sys_num_events;
  435: 
  436: 
  437: /*
  438:  * Statistic counters to keep track of requests and responses.
  439:  */
  440: u_long ctltimereset;		/* time stats reset */
  441: u_long numctlreq;		/* number of requests we've received */
  442: u_long numctlbadpkts;		/* number of bad control packets */
  443: u_long numctlresponses; 	/* number of resp packets sent with data */
  444: u_long numctlfrags; 		/* number of fragments sent */
  445: u_long numctlerrors;		/* number of error responses sent */
  446: u_long numctltooshort;		/* number of too short input packets */
  447: u_long numctlinputresp; 	/* number of responses on input */
  448: u_long numctlinputfrag; 	/* number of fragments on input */
  449: u_long numctlinputerr;		/* number of input pkts with err bit set */
  450: u_long numctlbadoffset; 	/* number of input pkts with nonzero offset */
  451: u_long numctlbadversion;	/* number of input pkts with unknown version */
  452: u_long numctldatatooshort;	/* data too short for count */
  453: u_long numctlbadop; 		/* bad op code found in packet */
  454: u_long numasyncmsgs;		/* number of async messages we've sent */
  455: 
  456: /*
  457:  * Response packet used by these routines. Also some state information
  458:  * so that we can handle packet formatting within a common set of
  459:  * subroutines.  Note we try to enter data in place whenever possible,
  460:  * but the need to set the more bit correctly means we occasionally
  461:  * use the extra buffer and copy.
  462:  */
  463: static struct ntp_control rpkt;
  464: static u_char	res_version;
  465: static u_char	res_opcode;
  466: static associd_t res_associd;
  467: static int	res_offset;
  468: static u_char * datapt;
  469: static u_char * dataend;
  470: static int	datalinelen;
  471: static int	datanotbinflag;
  472: static sockaddr_u *rmt_addr;
  473: static struct interface *lcl_inter;
  474: 
  475: static u_char	res_authenticate;
  476: static u_char	res_authokay;
  477: static keyid_t	res_keyid;
  478: 
  479: #define MAXDATALINELEN	(72)
  480: 
  481: static u_char	res_async;	/* set to 1 if this is async trap response */
  482: 
  483: /*
  484:  * Pointers for saving state when decoding request packets
  485:  */
  486: static	char *reqpt;
  487: static	char *reqend;
  488: 
  489: /*
  490:  * init_control - initialize request data
  491:  */
  492: void
  493: init_control(void)
  494: {
  495: 	int i;
  496: 
  497: #ifdef HAVE_UNAME
  498: 	uname(&utsnamebuf);
  499: #endif /* HAVE_UNAME */
  500: 
  501: 	ctl_clr_stats();
  502: 
  503: 	ctl_auth_keyid = 0;
  504: 	ctl_sys_last_event = EVNT_UNSPEC;
  505: 	ctl_sys_num_events = 0;
  506: 
  507: 	num_ctl_traps = 0;
  508: 	for (i = 0; i < CTL_MAXTRAPS; i++)
  509: 		ctl_trap[i].tr_flags = 0;
  510: }
  511: 
  512: 
  513: /*
  514:  * ctl_error - send an error response for the current request
  515:  */
  516: static void
  517: ctl_error(
  518: 	int errcode
  519: 	)
  520: {
  521: 	DPRINTF(3, ("sending control error %d\n", errcode));
  522: 
  523: 	/*
  524: 	 * Fill in the fields. We assume rpkt.sequence and rpkt.associd
  525: 	 * have already been filled in.
  526: 	 */
  527: 	rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode &
  528: 							  CTL_OP_MASK));
  529: 	rpkt.status = htons((u_short) ((errcode<<8) & 0xff00));
  530: 	rpkt.count = 0;
  531: 
  532: 	/*
  533: 	 * send packet and bump counters
  534: 	 */
  535: 	if (res_authenticate && sys_authenticate) {
  536: 		int maclen;
  537: 
  538: 		maclen = authencrypt(res_keyid, (u_int32 *)&rpkt,
  539: 				     CTL_HEADER_LEN);
  540: 		sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt,
  541: 			CTL_HEADER_LEN + maclen);
  542: 	} else {
  543: 		sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt,
  544: 			CTL_HEADER_LEN);
  545: 	}
  546: 	numctlerrors++;
  547: }
  548: 
  549: /* 
  550:  * save_config - Implements ntpq -c "saveconfig <filename>"
  551:  *		 Writes current configuration including any runtime
  552:  *		 changes by ntpq's :config or config-from-file
  553:  */
  554: void
  555: save_config(
  556: 	struct recvbuf *rbufp,
  557: 	int restrict_mask
  558: 	)
  559: {
  560: 	char reply[128];
  561: #ifdef SAVECONFIG
  562: 	char filespec[128];
  563: 	char filename[128];
  564: 	char fullpath[512];
  565: 	const char savedconfig_eq[] = "savedconfig=";
  566: 	char savedconfig[sizeof(savedconfig_eq) + sizeof(filename)];
  567: 	time_t now;
  568: 	int fd;
  569: 	FILE *fptr;
  570: #endif
  571: 
  572: 	if (restrict_mask & RES_NOMODIFY) {
  573: 		snprintf(reply, sizeof(reply),
  574: 			 "saveconfig prohibited by restrict ... nomodify");
  575: 		ctl_putdata(reply, strlen(reply), 0);
  576: 		ctl_flushpkt(0);
  577: 		msyslog(LOG_NOTICE,
  578: 			"saveconfig from %s rejected due to nomodify restriction",
  579: 			stoa(&rbufp->recv_srcadr));
  580: 		return;
  581: 	}
  582: 
  583: #ifdef SAVECONFIG
  584: 	if (NULL == saveconfigdir) {
  585: 		snprintf(reply, sizeof(reply),
  586: 			 "saveconfig prohibited, no saveconfigdir configured");
  587: 		ctl_putdata(reply, strlen(reply), 0);
  588: 		ctl_flushpkt(0);
  589: 		msyslog(LOG_NOTICE,
  590: 			"saveconfig from %s rejected, no saveconfigdir",
  591: 			stoa(&rbufp->recv_srcadr));
  592: 		return;
  593: 	}
  594: 
  595: 	if (0 == reqend - reqpt)
  596: 		return;
  597: 
  598: 	strncpy(filespec, reqpt, sizeof(filespec));
  599: 	filespec[sizeof(filespec) - 1] = '\0';
  600: 
  601: 	time(&now);
  602: 
  603: 	/*
  604: 	 * allow timestamping of the saved config filename with
  605: 	 * strftime() format such as:
  606: 	 *   ntpq -c "saveconfig ntp-%Y%m%d-%H%M%S.conf"
  607: 	 */
  608: 	if (0 == strftime(filename, sizeof(filename), filespec,
  609: 			       localtime(&now)))
  610: 		strncpy(filename, filespec, sizeof(filename));
  611: 
  612: 	filename[sizeof(filename) - 1] = '\0';
  613: 	
  614: 	if (strchr(filename, '\\') || strchr(filename, '/')) {
  615: 		snprintf(reply, sizeof(reply),
  616: 			 "saveconfig does not allow directory in filename");
  617: 		ctl_putdata(reply, strlen(reply), 0);
  618: 		ctl_flushpkt(0);
  619: 		msyslog(LOG_NOTICE,
  620: 			"saveconfig with path from %s rejected",
  621: 			stoa(&rbufp->recv_srcadr));
  622: 		return;
  623: 	}
  624: 
  625: 	snprintf(fullpath, sizeof(fullpath), "%s%s",
  626: 		 saveconfigdir, filename);
  627: 
  628: 	fd = open(fullpath, O_CREAT | O_TRUNC | O_WRONLY,
  629: 		  S_IRUSR | S_IWUSR);
  630: 	if (-1 == fd)
  631: 		fptr = NULL;
  632: 	else
  633: 		fptr = fdopen(fd, "w");
  634: 
  635: 	if (NULL == fptr || -1 == dump_all_config_trees(fptr, 1)) {
  636: 		snprintf(reply, sizeof(reply),
  637: 			 "Unable to save configuration to file %s",
  638: 			 filename);
  639: 		msyslog(LOG_ERR,
  640: 			"saveconfig %s from %s failed", filename,
  641: 			stoa(&rbufp->recv_srcadr));
  642: 	} else {
  643: 		snprintf(reply, sizeof(reply),
  644: 			 "Configuration saved to %s", filename);
  645: 		msyslog(LOG_NOTICE,
  646: 			"Configuration saved to %s (requested by %s)",
  647: 			fullpath, stoa(&rbufp->recv_srcadr));
  648: 		/*
  649: 		 * save the output filename in system variable
  650: 		 * savedconfig, retrieved with:
  651: 		 *   ntpq -c "rv 0 savedconfig"
  652: 		 */
  653: 		snprintf(savedconfig, sizeof(savedconfig), "%s%s",
  654: 			 savedconfig_eq, filename);
  655: 		set_sys_var(savedconfig, strlen(savedconfig) + 1, RO);
  656: 	}
  657: 
  658: 	if (NULL != fptr)
  659: 		fclose(fptr);
  660: #else	/* !SAVECONFIG follows */
  661: 	snprintf(reply, sizeof(reply),
  662: 		 "saveconfig unavailable, configured with --disable-saveconfig");
  663: #endif
  664: 
  665: 	ctl_putdata(reply, strlen(reply), 0);
  666: 	ctl_flushpkt(0);
  667: }
  668: 
  669: 
  670: /*
  671:  * process_control - process an incoming control message
  672:  */
  673: void
  674: process_control(
  675: 	struct recvbuf *rbufp,
  676: 	int restrict_mask
  677: 	)
  678: {
  679: 	register struct ntp_control *pkt;
  680: 	register int req_count;
  681: 	register int req_data;
  682: 	register struct ctl_proc *cc;
  683: 	int properlen;
  684: 	int maclen;
  685: 
  686: 	DPRINTF(3, ("in process_control()\n"));
  687: 
  688: 	/*
  689: 	 * Save the addresses for error responses
  690: 	 */
  691: 	numctlreq++;
  692: 	rmt_addr = &rbufp->recv_srcadr;
  693: 	lcl_inter = rbufp->dstadr;
  694: 	pkt = (struct ntp_control *)&rbufp->recv_pkt;
  695: 
  696: 	/*
  697: 	 * If the length is less than required for the header, or
  698: 	 * it is a response or a fragment, ignore this.
  699: 	 */
  700: 	if (rbufp->recv_length < CTL_HEADER_LEN
  701: 	    || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR)
  702: 	    || pkt->offset != 0) {
  703: 		DPRINTF(1, ("invalid format in control packet\n"));
  704: 		if (rbufp->recv_length < CTL_HEADER_LEN)
  705: 			numctltooshort++;
  706: 		if (pkt->r_m_e_op & CTL_RESPONSE)
  707: 			numctlinputresp++;
  708: 		if (pkt->r_m_e_op & CTL_MORE)
  709: 			numctlinputfrag++;
  710: 		if (pkt->r_m_e_op & CTL_ERROR)
  711: 			numctlinputerr++;
  712: 		if (pkt->offset != 0)
  713: 			numctlbadoffset++;
  714: 		return;
  715: 	}
  716: 	res_version = PKT_VERSION(pkt->li_vn_mode);
  717: 	if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) {
  718: 		DPRINTF(1, ("unknown version %d in control packet\n",
  719: 			    res_version));
  720: 		numctlbadversion++;
  721: 		return;
  722: 	}
  723: 
  724: 	/*
  725: 	 * Pull enough data from the packet to make intelligent
  726: 	 * responses
  727: 	 */
  728: 	rpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, res_version,
  729: 					 MODE_CONTROL);
  730: 	res_opcode = pkt->r_m_e_op;
  731: 	rpkt.sequence = pkt->sequence;
  732: 	rpkt.associd = pkt->associd;
  733: 	rpkt.status = 0;
  734: 	res_offset = 0;
  735: 	res_associd = htons(pkt->associd);
  736: 	res_async = 0;
  737: 	res_authenticate = 0;
  738: 	res_keyid = 0;
  739: 	res_authokay = 0;
  740: 	req_count = (int)ntohs(pkt->count);
  741: 	datanotbinflag = 0;
  742: 	datalinelen = 0;
  743: 	datapt = rpkt.data;
  744: 	dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
  745: 
  746: 	if ((rbufp->recv_length & 0x3) != 0)
  747: 		DPRINTF(3, ("Control packet length %d unrounded\n",
  748: 			    rbufp->recv_length));
  749: 
  750: 	/*
  751: 	 * We're set up now. Make sure we've got at least enough
  752: 	 * incoming data space to match the count.
  753: 	 */
  754: 	req_data = rbufp->recv_length - CTL_HEADER_LEN;
  755: 	if (req_data < req_count || rbufp->recv_length & 0x3) {
  756: 		ctl_error(CERR_BADFMT);
  757: 		numctldatatooshort++;
  758: 		return;
  759: 	}
  760: 
  761: 	properlen = req_count + CTL_HEADER_LEN;
  762: 	/* round up proper len to a 8 octet boundary */
  763: 
  764: 	properlen = (properlen + 7) & ~7;
  765: 	maclen = rbufp->recv_length - properlen;
  766: 	if ((rbufp->recv_length & 3) == 0 &&
  767: 	    maclen >= MIN_MAC_LEN && maclen <= MAX_MAC_LEN &&
  768: 	    sys_authenticate) {
  769: 		res_authenticate = 1;
  770: 		res_keyid = ntohl(*(u_int32 *)((u_char *)pkt +
  771: 					       properlen));
  772: 
  773: 		DPRINTF(3, ("recv_len %d, properlen %d, wants auth with keyid %08x, MAC length=%d\n",
  774: 			    rbufp->recv_length, properlen, res_keyid,
  775: 			    maclen));
  776: 
  777: 		if (!authistrusted(res_keyid))
  778: 			DPRINTF(3, ("invalid keyid %08x\n", res_keyid));
  779: 		else if (authdecrypt(res_keyid, (u_int32 *)pkt,
  780: 				     rbufp->recv_length - maclen,
  781: 				     maclen)) {
  782: 			DPRINTF(3, ("authenticated okay\n"));
  783: 			res_authokay = 1;
  784: 		} else {
  785: 			DPRINTF(3, ("authentication failed\n"));
  786: 			res_keyid = 0;
  787: 		}
  788: 	}
  789: 
  790: 	/*
  791: 	 * Set up translate pointers
  792: 	 */
  793: 	reqpt = (char *)pkt->data;
  794: 	reqend = reqpt + req_count;
  795: 
  796: 	/*
  797: 	 * Look for the opcode processor
  798: 	 */
  799: 	for (cc = control_codes; cc->control_code != NO_REQUEST; cc++) {
  800: 		if (cc->control_code == res_opcode) {
  801: 			DPRINTF(3, ("opcode %d, found command handler\n",
  802: 				    res_opcode));
  803: 			if (cc->flags == AUTH
  804: 			    && (!res_authokay
  805: 				|| res_keyid != ctl_auth_keyid)) {
  806: 				ctl_error(CERR_PERMISSION);
  807: 				return;
  808: 			}
  809: 			(cc->handler)(rbufp, restrict_mask);
  810: 			return;
  811: 		}
  812: 	}
  813: 
  814: 	/*
  815: 	 * Can't find this one, return an error.
  816: 	 */
  817: 	numctlbadop++;
  818: 	ctl_error(CERR_BADOP);
  819: 	return;
  820: }
  821: 
  822: 
  823: /*
  824:  * ctlpeerstatus - return a status word for this peer
  825:  */
  826: u_short
  827: ctlpeerstatus(
  828: 	register struct peer *peer
  829: 	)
  830: {
  831: 	u_short status;
  832: 
  833: 	status = peer->status;
  834: 	if (!(peer->flags & FLAG_PREEMPT))
  835: 		status |= CTL_PST_CONFIG;
  836: 	if (peer->keyid != 0)
  837: 		status |= CTL_PST_AUTHENABLE;
  838: 	if (peer->flags & FLAG_AUTHENTIC)
  839: 		status |= CTL_PST_AUTHENTIC;
  840: 	if (peer->reach != 0)
  841: 		status |= CTL_PST_REACH;
  842: 	if (peer->cast_flags & (MDF_BCAST | MDF_MCAST | MDF_ACAST))
  843: 		status |= CTL_PST_BCAST;
  844: 	return (u_short)CTL_PEER_STATUS(status, peer->num_events,
  845: 	    peer->last_event);
  846: }
  847: 
  848: 
  849: /*
  850:  * ctlclkstatus - return a status word for this clock
  851:  */
  852: #ifdef REFCLOCK
  853: static u_short
  854: ctlclkstatus(
  855: 	struct refclockstat *this_clock
  856: 	)
  857: {
  858: 	return (u_short)CTL_PEER_STATUS(0, this_clock->lastevent,
  859: 	    this_clock->currentstatus);
  860: }
  861: #endif
  862: 
  863: 
  864: /*
  865:  * ctlsysstatus - return the system status word
  866:  */
  867: u_short
  868: ctlsysstatus(void)
  869: {
  870: 	register u_char this_clock;
  871: 
  872: 	this_clock = CTL_SST_TS_UNSPEC;
  873: #ifdef REFCLOCK
  874: 	if (sys_peer != 0) {
  875: 		if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) {
  876: 			this_clock = sys_peer->sstclktype;
  877: 		} else {
  878: 			if (sys_peer->refclktype < sizeof(clocktypes))
  879: 				this_clock =
  880: 				    clocktypes[sys_peer->refclktype];
  881: 		}
  882: 	}
  883: #else /* REFCLOCK */
  884: 	if (sys_peer != 0)
  885: 		this_clock = CTL_SST_TS_NTP;
  886: #endif /* REFCLOCK */
  887: 	return (u_short)CTL_SYS_STATUS(sys_leap, this_clock,
  888: 	    ctl_sys_num_events, ctl_sys_last_event);
  889: }
  890: 
  891: 
  892: /*
  893:  * ctl_flushpkt - write out the current packet and prepare
  894:  *		  another if necessary.
  895:  */
  896: static void
  897: ctl_flushpkt(
  898: 	int more
  899: 	)
  900: {
  901: 	int dlen;
  902: 	int sendlen;
  903: 
  904: 	if (!more && datanotbinflag) {
  905: 		/*
  906: 		 * Big hack, output a trailing \r\n
  907: 		 */
  908: 		*datapt++ = '\r';
  909: 		*datapt++ = '\n';
  910: 	}
  911: 	dlen = datapt - (u_char *)rpkt.data;
  912: 	sendlen = dlen + CTL_HEADER_LEN;
  913: 
  914: 	/*
  915: 	 * Pad to a multiple of 32 bits
  916: 	 */
  917: 	while (sendlen & 0x3) {
  918: 		*datapt++ = '\0';
  919: 		sendlen++;
  920: 	}
  921: 
  922: 	/*
  923: 	 * Fill in the packet with the current info
  924: 	 */
  925: 	rpkt.r_m_e_op = (u_char)(CTL_RESPONSE|more|(res_opcode &
  926: 						    CTL_OP_MASK));
  927: 	rpkt.count = htons((u_short) dlen);
  928: 	rpkt.offset = htons( (u_short) res_offset);
  929: 	if (res_async) {
  930: 		register int i;
  931: 
  932: 		for (i = 0; i < CTL_MAXTRAPS; i++) {
  933: 			if (ctl_trap[i].tr_flags & TRAP_INUSE) {
  934: 				rpkt.li_vn_mode =
  935: 				    PKT_LI_VN_MODE(sys_leap,
  936: 						   ctl_trap[i].tr_version,
  937: 						   MODE_CONTROL);
  938: 				rpkt.sequence =
  939: 				    htons(ctl_trap[i].tr_sequence);
  940: 				sendpkt(&ctl_trap[i].tr_addr,
  941: 					ctl_trap[i].tr_localaddr, -4,
  942: 					(struct pkt *)&rpkt, sendlen);
  943: 				if (!more)
  944: 					ctl_trap[i].tr_sequence++;
  945: 				numasyncmsgs++;
  946: 			}
  947: 		}
  948: 	} else {
  949: 		if (res_authenticate && sys_authenticate) {
  950: 			int maclen;
  951: 			int totlen = sendlen;
  952: 			keyid_t keyid = htonl(res_keyid);
  953: 
  954: 			/*
  955: 			 * If we are going to authenticate, then there
  956: 			 * is an additional requirement that the MAC
  957: 			 * begin on a 64 bit boundary.
  958: 			 */
  959: 			while (totlen & 7) {
  960: 				*datapt++ = '\0';
  961: 				totlen++;
  962: 			}
  963: 			memcpy(datapt, &keyid, sizeof keyid);
  964: 			maclen = authencrypt(res_keyid,
  965: 					     (u_int32 *)&rpkt, totlen);
  966: 			sendpkt(rmt_addr, lcl_inter, -5,
  967: 				(struct pkt *)&rpkt, totlen + maclen);
  968: 		} else {
  969: 			sendpkt(rmt_addr, lcl_inter, -6,
  970: 				(struct pkt *)&rpkt, sendlen);
  971: 		}
  972: 		if (more)
  973: 			numctlfrags++;
  974: 		else
  975: 			numctlresponses++;
  976: 	}
  977: 
  978: 	/*
  979: 	 * Set us up for another go around.
  980: 	 */
  981: 	res_offset += dlen;
  982: 	datapt = (u_char *)rpkt.data;
  983: }
  984: 
  985: 
  986: /*
  987:  * ctl_putdata - write data into the packet, fragmenting and starting
  988:  * another if this one is full.
  989:  */
  990: static void
  991: ctl_putdata(
  992: 	const char *dp,
  993: 	unsigned int dlen,
  994: 	int bin 		/* set to 1 when data is binary */
  995: 	)
  996: {
  997: 	int overhead;
  998: 
  999: 	overhead = 0;
 1000: 	if (!bin) {
 1001: 		datanotbinflag = 1;
 1002: 		overhead = 3;
 1003: 		if (datapt != rpkt.data) {
 1004: 			*datapt++ = ',';
 1005: 			datalinelen++;
 1006: 			if ((dlen + datalinelen + 1) >= MAXDATALINELEN)
 1007: 			{
 1008: 				*datapt++ = '\r';
 1009: 				*datapt++ = '\n';
 1010: 				datalinelen = 0;
 1011: 			} else {
 1012: 				*datapt++ = ' ';
 1013: 				datalinelen++;
 1014: 			}
 1015: 		}
 1016: 	}
 1017: 
 1018: 	/*
 1019: 	 * Save room for trailing junk
 1020: 	 */
 1021: 	if (dlen + overhead + datapt > dataend) {
 1022: 		/*
 1023: 		 * Not enough room in this one, flush it out.
 1024: 		 */
 1025: 		ctl_flushpkt(CTL_MORE);
 1026: 	}
 1027: 	memmove((char *)datapt, dp, (unsigned)dlen);
 1028: 	datapt += dlen;
 1029: 	datalinelen += dlen;
 1030: }
 1031: 
 1032: 
 1033: /*
 1034:  * ctl_putstr - write a tagged string into the response packet
 1035:  */
 1036: static void
 1037: ctl_putstr(
 1038: 	const char *tag,
 1039: 	const char *data,
 1040: 	unsigned int len
 1041: 	)
 1042: {
 1043: 	register char *cp;
 1044: 	register const char *cq;
 1045: 	char buffer[400];
 1046: 
 1047: 	cp = buffer;
 1048: 	cq = tag;
 1049: 	while (*cq != '\0')
 1050: 		*cp++ = *cq++;
 1051: 	if (len > 0) {
 1052: 		*cp++ = '=';
 1053: 		*cp++ = '"';
 1054: 		if (len > (int) (sizeof(buffer) - (cp - buffer) - 1))
 1055: 			len = sizeof(buffer) - (cp - buffer) - 1;
 1056: 		memmove(cp, data, (unsigned)len);
 1057: 		cp += len;
 1058: 		*cp++ = '"';
 1059: 	}
 1060: 	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
 1061: }
 1062: 
 1063: 
 1064: /*
 1065:  * ctl_putdbl - write a tagged, signed double into the response packet
 1066:  */
 1067: static void
 1068: ctl_putdbl(
 1069: 	const char *tag,
 1070: 	double ts
 1071: 	)
 1072: {
 1073: 	register char *cp;
 1074: 	register const char *cq;
 1075: 	char buffer[200];
 1076: 
 1077: 	cp = buffer;
 1078: 	cq = tag;
 1079: 	while (*cq != '\0')
 1080: 		*cp++ = *cq++;
 1081: 	*cp++ = '=';
 1082: 	NTP_INSIST((cp - buffer) < sizeof(buffer));
 1083: 	snprintf(cp, sizeof(buffer) - (cp - buffer), "%.3f", ts);
 1084: 	cp += strlen(cp);
 1085: 	ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
 1086: }
 1087: 
 1088: /*
 1089:  * ctl_putuint - write a tagged unsigned integer into the response
 1090:  */
 1091: static void
 1092: ctl_putuint(
 1093: 	const char *tag,
 1094: 	u_long uval
 1095: 	)
 1096: {
 1097: 	register char *cp;
 1098: 	register const char *cq;
 1099: 	char buffer[200];
 1100: 
 1101: 	cp = buffer;
 1102: 	cq = tag;
 1103: 	while (*cq != '\0')
 1104: 		*cp++ = *cq++;
 1105: 
 1106: 	*cp++ = '=';
 1107: 	NTP_INSIST((cp - buffer) < sizeof(buffer));
 1108: 	snprintf(cp, sizeof(buffer) - (cp - buffer), "%lu", uval);
 1109: 	cp += strlen(cp);
 1110: 	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
 1111: }
 1112: 
 1113: /*
 1114:  * ctl_putfs - write a decoded filestamp into the response
 1115:  */
 1116: static void
 1117: ctl_putfs(
 1118: 	const char *tag,
 1119: 	tstamp_t uval
 1120: 	)
 1121: {
 1122: 	register char *cp;
 1123: 	register const char *cq;
 1124: 	char buffer[200];
 1125: 	struct tm *tm = NULL;
 1126: 	time_t fstamp;
 1127: 
 1128: 	cp = buffer;
 1129: 	cq = tag;
 1130: 	while (*cq != '\0')
 1131: 		*cp++ = *cq++;
 1132: 
 1133: 	*cp++ = '=';
 1134: 	fstamp = uval - JAN_1970;
 1135: 	tm = gmtime(&fstamp);
 1136: 	if (NULL ==  tm)
 1137: 		return;
 1138: 	NTP_INSIST((cp - buffer) < sizeof(buffer));
 1139: 	snprintf(cp, sizeof(buffer) - (cp - buffer),
 1140: 		 "%04d%02d%02d%02d%02d", tm->tm_year + 1900,
 1141: 		 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
 1142: 	cp += strlen(cp);
 1143: 	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
 1144: }
 1145: 
 1146: 
 1147: /*
 1148:  * ctl_puthex - write a tagged unsigned integer, in hex, into the
 1149:  * response
 1150:  */
 1151: static void
 1152: ctl_puthex(
 1153: 	const char *tag,
 1154: 	u_long uval
 1155: 	)
 1156: {
 1157: 	register char *cp;
 1158: 	register const char *cq;
 1159: 	char buffer[200];
 1160: 
 1161: 	cp = buffer;
 1162: 	cq = tag;
 1163: 	while (*cq != '\0')
 1164: 		*cp++ = *cq++;
 1165: 
 1166: 	*cp++ = '=';
 1167: 	NTP_INSIST((cp - buffer) < sizeof(buffer));
 1168: 	snprintf(cp, sizeof(buffer) - (cp - buffer), "0x%lx", uval);
 1169: 	cp += strlen(cp);
 1170: 	ctl_putdata(buffer,(unsigned)( cp - buffer ), 0);
 1171: }
 1172: 
 1173: 
 1174: /*
 1175:  * ctl_putint - write a tagged signed integer into the response
 1176:  */
 1177: static void
 1178: ctl_putint(
 1179: 	const char *tag,
 1180: 	long ival
 1181: 	)
 1182: {
 1183: 	register char *cp;
 1184: 	register const char *cq;
 1185: 	char buffer[200];
 1186: 
 1187: 	cp = buffer;
 1188: 	cq = tag;
 1189: 	while (*cq != '\0')
 1190: 		*cp++ = *cq++;
 1191: 
 1192: 	*cp++ = '=';
 1193: 	NTP_INSIST((cp - buffer) < sizeof(buffer));
 1194: 	snprintf(cp, sizeof(buffer) - (cp - buffer), "%ld", ival);
 1195: 	cp += strlen(cp);
 1196: 	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
 1197: }
 1198: 
 1199: 
 1200: /*
 1201:  * ctl_putts - write a tagged timestamp, in hex, into the response
 1202:  */
 1203: static void
 1204: ctl_putts(
 1205: 	const char *tag,
 1206: 	l_fp *ts
 1207: 	)
 1208: {
 1209: 	register char *cp;
 1210: 	register const char *cq;
 1211: 	char buffer[200];
 1212: 
 1213: 	cp = buffer;
 1214: 	cq = tag;
 1215: 	while (*cq != '\0')
 1216: 		*cp++ = *cq++;
 1217: 
 1218: 	*cp++ = '=';
 1219: 	NTP_INSIST((cp - buffer) < sizeof(buffer));
 1220: 	snprintf(cp, sizeof(buffer) - (cp - buffer), "0x%08lx.%08lx",
 1221: 		 ts->l_ui & 0xffffffffUL, ts->l_uf & 0xffffffffUL);
 1222: 	cp += strlen(cp);
 1223: 	ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
 1224: }
 1225: 
 1226: 
 1227: /*
 1228:  * ctl_putadr - write an IP address into the response
 1229:  */
 1230: static void
 1231: ctl_putadr(
 1232: 	const char *tag,
 1233: 	u_int32 addr32,
 1234: 	sockaddr_u *addr
 1235: 	)
 1236: {
 1237: 	register char *cp;
 1238: 	register const char *cq;
 1239: 	char buffer[200];
 1240: 
 1241: 	cp = buffer;
 1242: 	cq = tag;
 1243: 	while (*cq != '\0')
 1244: 		*cp++ = *cq++;
 1245: 
 1246: 	*cp++ = '=';
 1247: 	if (NULL == addr)
 1248: 		cq = numtoa(addr32);
 1249: 	else
 1250: 		cq = stoa(addr);
 1251: 	NTP_INSIST((cp - buffer) < sizeof(buffer));
 1252: 	snprintf(cp, sizeof(buffer) - (cp - buffer), "%s", cq);
 1253: 	cp += strlen(cp);
 1254: 	ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
 1255: }
 1256: 
 1257: 
 1258: /*
 1259:  * ctl_putrefid - send a u_int32 refid as printable text
 1260:  */
 1261: static void
 1262: ctl_putrefid(
 1263: 	const char *	tag,
 1264: 	u_int32		refid
 1265: 	)
 1266: {
 1267: 	char	output[16];
 1268: 	char *	optr;
 1269: 	char *	oplim;
 1270: 	char *	iptr;
 1271: 	char *	iplim;
 1272: 	char *	past_eq;
 1273: 
 1274: 	optr = output;
 1275: 	oplim = output + sizeof(output);
 1276: 	while (optr < oplim && '\0' != *tag)
 1277: 		*optr++ = *tag++;
 1278: 	if (optr < oplim) {
 1279: 		*optr++ = '=';
 1280: 		past_eq = optr;
 1281: 	}
 1282: 	if (!(optr < oplim))
 1283: 		return;
 1284: 	iptr = (char *)&refid;
 1285: 	iplim = iptr + sizeof(refid);
 1286: 	for ( ; optr < oplim && iptr < iplim && '\0' != *iptr; 
 1287: 	     iptr++, optr++)
 1288: 		if (isprint(*iptr))
 1289: 			*optr = *iptr;
 1290: 		else
 1291: 			*optr = '.';
 1292: 	if (!(optr <= oplim))
 1293: 		optr = past_eq;
 1294: 	ctl_putdata(output, (u_int)(optr - output), FALSE);
 1295: }
 1296: 
 1297: 
 1298: /*
 1299:  * ctl_putarray - write a tagged eight element double array into the response
 1300:  */
 1301: static void
 1302: ctl_putarray(
 1303: 	const char *tag,
 1304: 	double *arr,
 1305: 	int start
 1306: 	)
 1307: {
 1308: 	register char *cp;
 1309: 	register const char *cq;
 1310: 	char buffer[200];
 1311: 	int i;
 1312: 	cp = buffer;
 1313: 	cq = tag;
 1314: 	while (*cq != '\0')
 1315: 		*cp++ = *cq++;
 1316: 	i = start;
 1317: 	do {
 1318: 		if (i == 0)
 1319: 			i = NTP_SHIFT;
 1320: 		i--;
 1321: 		NTP_INSIST((cp - buffer) < sizeof(buffer));
 1322: 		snprintf(cp, sizeof(buffer) - (cp - buffer),
 1323: 			 " %.2f", arr[i] * 1e3);
 1324: 		cp += strlen(cp);
 1325: 	} while(i != start);
 1326: 	ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
 1327: }
 1328: 
 1329: 
 1330: /*
 1331:  * ctl_putsys - output a system variable
 1332:  */
 1333: static void
 1334: ctl_putsys(
 1335: 	int varid
 1336: 	)
 1337: {
 1338: 	l_fp tmp;
 1339: 	char str[256];
 1340: #ifdef OPENSSL
 1341: 	struct cert_info *cp;
 1342: 	char cbuf[256];
 1343: #endif /* OPENSSL */
 1344: 
 1345: 	switch (varid) {
 1346: 
 1347: 	    case CS_LEAP:
 1348: 		ctl_putuint(sys_var[CS_LEAP].text, sys_leap);
 1349: 		break;
 1350: 
 1351: 	    case CS_STRATUM:
 1352: 		ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum);
 1353: 		break;
 1354: 
 1355: 	    case CS_PRECISION:
 1356: 		ctl_putint(sys_var[CS_PRECISION].text, sys_precision);
 1357: 		break;
 1358: 
 1359: 	    case CS_ROOTDELAY:
 1360: 		ctl_putdbl(sys_var[CS_ROOTDELAY].text, sys_rootdelay *
 1361: 			   1e3);
 1362: 		break;
 1363: 
 1364: 	    case CS_ROOTDISPERSION:
 1365: 		ctl_putdbl(sys_var[CS_ROOTDISPERSION].text,
 1366: 			   sys_rootdisp * 1e3);
 1367: 		break;
 1368: 
 1369: 	    case CS_REFID:
 1370: 		if (sys_stratum > 1 && sys_stratum < STRATUM_UNSPEC)
 1371: 			ctl_putadr(sys_var[varid].text, sys_refid, NULL);
 1372: 		else
 1373: 			ctl_putrefid(sys_var[varid].text, sys_refid);
 1374: 		break;
 1375: 
 1376: 	    case CS_REFTIME:
 1377: 		ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime);
 1378: 		break;
 1379: 
 1380: 	    case CS_POLL:
 1381: 		ctl_putuint(sys_var[CS_POLL].text, sys_poll);
 1382: 		break;
 1383: 
 1384: 	    case CS_PEERID:
 1385: 		if (sys_peer == NULL)
 1386: 			ctl_putuint(sys_var[CS_PEERID].text, 0);
 1387: 		else
 1388: 			ctl_putuint(sys_var[CS_PEERID].text,
 1389: 				    sys_peer->associd);
 1390: 		break;
 1391: 
 1392: 	    case CS_OFFSET:
 1393: 		ctl_putdbl(sys_var[CS_OFFSET].text, last_offset * 1e3);
 1394: 		break;
 1395: 
 1396: 	    case CS_DRIFT:
 1397: 		ctl_putdbl(sys_var[CS_DRIFT].text, drift_comp * 1e6);
 1398: 		break;
 1399: 
 1400: 	    case CS_JITTER:
 1401: 		ctl_putdbl(sys_var[CS_JITTER].text, sys_jitter * 1e3);
 1402: 		break;
 1403: 
 1404: 	    case CS_ERROR:
 1405: 		ctl_putdbl(sys_var[CS_ERROR].text, clock_jitter * 1e3);
 1406: 		break;
 1407: 
 1408: 	    case CS_CLOCK:
 1409: 		get_systime(&tmp);
 1410: 		ctl_putts(sys_var[CS_CLOCK].text, &tmp);
 1411: 		break;
 1412: 
 1413: 	    case CS_PROCESSOR:
 1414: #ifndef HAVE_UNAME
 1415: 		ctl_putstr(sys_var[CS_PROCESSOR].text, str_processor,
 1416: 			   sizeof(str_processor) - 1);
 1417: #else
 1418: 		ctl_putstr(sys_var[CS_PROCESSOR].text,
 1419: 			   utsnamebuf.machine, strlen(utsnamebuf.machine));
 1420: #endif /* HAVE_UNAME */
 1421: 		break;
 1422: 
 1423: 	    case CS_SYSTEM:
 1424: #ifndef HAVE_UNAME
 1425: 		ctl_putstr(sys_var[CS_SYSTEM].text, str_system,
 1426: 			   sizeof(str_system) - 1);
 1427: #else
 1428: 		snprintf(str, sizeof(str), "%s/%s", utsnamebuf.sysname,
 1429: 			 utsnamebuf.release);
 1430: 		ctl_putstr(sys_var[CS_SYSTEM].text, str, strlen(str));
 1431: #endif /* HAVE_UNAME */
 1432: 		break;
 1433: 
 1434: 	    case CS_VERSION:
 1435: 		ctl_putstr(sys_var[CS_VERSION].text, Version,
 1436: 			   strlen(Version));
 1437: 		break;
 1438: 
 1439: 	    case CS_STABIL:
 1440: 		ctl_putdbl(sys_var[CS_STABIL].text, clock_stability *
 1441: 			   1e6);
 1442: 		break;
 1443: 
 1444: 	    case CS_VARLIST:
 1445: 	    {
 1446: 		    char buf[CTL_MAX_DATA_LEN];
 1447: 		    register char *s, *t, *be;
 1448: 		    register const char *ss;
 1449: 		    register int i;
 1450: 		    register struct ctl_var *k;
 1451: 
 1452: 		    s = buf;
 1453: 		    be = buf + sizeof(buf);
 1454: 		    if (s + strlen(sys_var[CS_VARLIST].text) + 4 > be)
 1455: 			    break;	/* really long var name */
 1456: 
 1457: 		    snprintf(s, sizeof(buf), "%s=\"",
 1458: 			sys_var[CS_VARLIST].text);
 1459: 		    s += strlen(s);
 1460: 		    t = s;
 1461: 		    for (k = sys_var; !(k->flags & EOV); k++) {
 1462: 			    if (k->flags & PADDING)
 1463: 				    continue;
 1464: 			    i = strlen(k->text);
 1465: 			    if (s+i+1 >= be)
 1466: 				    break;
 1467: 
 1468: 			    if (s != t)
 1469: 				    *s++ = ',';
 1470: 			    memcpy(s, k->text, i);
 1471: 			    s += i;
 1472: 		    }
 1473: 
 1474: 		    for (k = ext_sys_var; k && !(k->flags & EOV);
 1475: 			 k++) {
 1476: 			    if (k->flags & PADDING)
 1477: 				    continue;
 1478: 
 1479: 			    ss = k->text;
 1480: 			    if (!ss)
 1481: 				    continue;
 1482: 
 1483: 			    while (*ss && *ss != '=')
 1484: 				    ss++;
 1485: 			    i = ss - k->text;
 1486: 			    if (s + i + 1 >= be)
 1487: 				    break;
 1488: 
 1489: 			    if (s != t)
 1490: 				    *s++ = ',';
 1491: 			    memcpy(s, k->text,
 1492: 				    (unsigned)i);
 1493: 			    s += i;
 1494: 		    }
 1495: 		    if (s+2 >= be)
 1496: 			    break;
 1497: 
 1498: 		    *s++ = '"';
 1499: 		    *s = '\0';
 1500: 
 1501: 		    ctl_putdata(buf, (unsigned)( s - buf ),
 1502: 			0);
 1503: 	    }
 1504: 	    break;
 1505: 
 1506: 	    case CS_TAI:
 1507: 		if (sys_tai > 0)
 1508: 			ctl_putuint(sys_var[CS_TAI].text, sys_tai);
 1509: 		break;
 1510: 
 1511: 	    case CS_LEAPTAB:
 1512: 		if (leap_sec > 0)
 1513: 			ctl_putfs(sys_var[CS_LEAPTAB].text,
 1514: 			    leap_sec);
 1515: 		break;
 1516: 
 1517: 	    case CS_LEAPEND:
 1518: 		if (leap_expire > 0)
 1519: 			ctl_putfs(sys_var[CS_LEAPEND].text,
 1520: 			    leap_expire);
 1521: 		break;
 1522: 
 1523: 	    case CS_RATE:
 1524: 		ctl_putuint(sys_var[CS_RATE].text, ntp_minpoll);
 1525: 		break;
 1526: 
 1527: #ifdef OPENSSL
 1528: 	    case CS_FLAGS:
 1529: 		if (crypto_flags)
 1530: 			ctl_puthex(sys_var[CS_FLAGS].text,
 1531: 			    crypto_flags);
 1532: 		break;
 1533: 
 1534: 	    case CS_DIGEST:
 1535: 		if (crypto_flags) {
 1536: 			strcpy(str, OBJ_nid2ln(crypto_nid));
 1537: 			ctl_putstr(sys_var[CS_DIGEST].text, str,
 1538: 			    strlen(str));
 1539: 		}
 1540: 		break;
 1541: 
 1542: 	    case CS_SIGNATURE:
 1543: 		if (crypto_flags) {
 1544: 			const EVP_MD *dp;
 1545: 
 1546: 			dp = EVP_get_digestbynid(crypto_flags >> 16);
 1547: 			strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp)));
 1548: 			ctl_putstr(sys_var[CS_SIGNATURE].text, str,
 1549: 			    strlen(str));
 1550: 		}
 1551: 		break;
 1552: 
 1553: 	    case CS_HOST:
 1554: 		if (sys_hostname != NULL)
 1555: 			ctl_putstr(sys_var[CS_HOST].text, sys_hostname,
 1556: 			    strlen(sys_hostname));
 1557: 		break;
 1558: 
 1559: 	    case CS_GROUP:
 1560: 		if (sys_groupname != NULL)
 1561: 			ctl_putstr(sys_var[CS_GROUP].text, sys_groupname,
 1562: 			    strlen(sys_groupname));
 1563: 		break;
 1564: 
 1565: 	    case CS_CERTIF:
 1566: 		for (cp = cinfo; cp != NULL; cp = cp->link) {
 1567: 			snprintf(cbuf, sizeof(cbuf), "%s %s 0x%x",
 1568: 			    cp->subject, cp->issuer, cp->flags);
 1569: 			ctl_putstr(sys_var[CS_CERTIF].text, cbuf,
 1570: 			    strlen(cbuf));
 1571: 			ctl_putfs(sys_var[CS_REVTIME].text, cp->last);
 1572: 		}
 1573: 		break;
 1574: 
 1575: 	    case CS_PUBLIC:
 1576: 		if (hostval.tstamp != 0)
 1577: 			ctl_putfs(sys_var[CS_PUBLIC].text,
 1578: 			    ntohl(hostval.tstamp));
 1579: 		break;
 1580: #endif /* OPENSSL */
 1581: 	}
 1582: }
 1583: 
 1584: 
 1585: /*
 1586:  * ctl_putpeer - output a peer variable
 1587:  */
 1588: static void
 1589: ctl_putpeer(
 1590: 	int varid,
 1591: 	struct peer *peer
 1592: 	)
 1593: {
 1594: 	int temp;
 1595: #ifdef OPENSSL
 1596: 	char str[256];
 1597: 	struct autokey *ap;
 1598: #endif /* OPENSSL */
 1599: 
 1600: 	switch (varid) {
 1601: 
 1602: 	    case CP_CONFIG:
 1603: 		ctl_putuint(peer_var[CP_CONFIG].text,
 1604: 		    (unsigned)((peer->flags & FLAG_PREEMPT) == 0));
 1605: 		break;
 1606: 
 1607: 	    case CP_AUTHENABLE:
 1608: 		ctl_putuint(peer_var[CP_AUTHENABLE].text,
 1609: 		    (unsigned)(peer->keyid != 0));
 1610: 		break;
 1611: 
 1612: 	    case CP_AUTHENTIC:
 1613: 		ctl_putuint(peer_var[CP_AUTHENTIC].text,
 1614: 		    (unsigned)((peer->flags & FLAG_AUTHENTIC) != 0));
 1615: 		break;
 1616: 
 1617: 	    case CP_SRCADR:
 1618: 		ctl_putadr(peer_var[CP_SRCADR].text, 0,
 1619: 		    &peer->srcadr);
 1620: 		break;
 1621: 
 1622: 	    case CP_SRCPORT:
 1623: 		ctl_putuint(peer_var[CP_SRCPORT].text,
 1624: 		    ntohs(((struct sockaddr_in*)&peer->srcadr)->sin_port));
 1625: 		break;
 1626: 
 1627: 	    case CP_DSTADR:
 1628: 		if (peer->dstadr) {
 1629: 			ctl_putadr(peer_var[CP_DSTADR].text, 0,
 1630: 				   &(peer->dstadr->sin));
 1631: 		} else {
 1632: 			ctl_putadr(peer_var[CP_DSTADR].text, 0,
 1633: 				   NULL);
 1634: 		}
 1635: 		break;
 1636: 
 1637: 	    case CP_DSTPORT:
 1638: 		ctl_putuint(peer_var[CP_DSTPORT].text,
 1639: 		    (u_long)(peer->dstadr ?
 1640: 		    ntohs(((struct sockaddr_in*)&peer->dstadr->sin)->sin_port) : 0));
 1641: 		break;
 1642: 
 1643: 	    case CP_IN:
 1644: 		if (peer->r21 > 0)
 1645: 			ctl_putdbl(peer_var[CP_IN].text,
 1646: 				   peer->r21 / 1e3);
 1647: 		break;
 1648: 
 1649: 	    case CP_OUT:
 1650: 		if (peer->r34 >0)
 1651: 			ctl_putdbl(peer_var[CP_OUT].text,
 1652: 				   peer->r34 / 1e3);
 1653: 		break;
 1654: 
 1655: 	    case CP_RATE:
 1656: 		ctl_putuint(peer_var[CP_RATE].text, peer->throttle);
 1657: 		break;
 1658: 
 1659: 	    case CP_LEAP:
 1660: 		ctl_putuint(peer_var[CP_LEAP].text, peer->leap);
 1661: 		break;
 1662: 
 1663: 	    case CP_HMODE:
 1664: 		ctl_putuint(peer_var[CP_HMODE].text, peer->hmode);
 1665: 		break;
 1666: 
 1667: 	    case CP_STRATUM:
 1668: 		ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum);
 1669: 		break;
 1670: 
 1671: 	    case CP_PPOLL:
 1672: 		ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll);
 1673: 		break;
 1674: 
 1675: 	    case CP_HPOLL:
 1676: 		ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll);
 1677: 		break;
 1678: 
 1679: 	    case CP_PRECISION:
 1680: 		ctl_putint(peer_var[CP_PRECISION].text,
 1681: 			peer->precision);
 1682: 		break;
 1683: 
 1684: 	    case CP_ROOTDELAY:
 1685: 		ctl_putdbl(peer_var[CP_ROOTDELAY].text,
 1686: 			   peer->rootdelay * 1e3);
 1687: 		break;
 1688: 
 1689: 	    case CP_ROOTDISPERSION:
 1690: 		ctl_putdbl(peer_var[CP_ROOTDISPERSION].text,
 1691: 			   peer->rootdisp * 1e3);
 1692: 		break;
 1693: 
 1694: 	    case CP_REFID:
 1695: #ifdef REFCLOCK
 1696: 		if (peer->flags & FLAG_REFCLOCK) {
 1697: 			ctl_putrefid(peer_var[varid].text, peer->refid);
 1698: 			break;
 1699: 		}
 1700: #endif
 1701: 		if (peer->stratum > 1 && peer->stratum < STRATUM_UNSPEC)
 1702: 			ctl_putadr(peer_var[varid].text, peer->refid,
 1703: 				   NULL);
 1704: 		else
 1705: 			ctl_putrefid(peer_var[varid].text, peer->refid);
 1706: 		break;
 1707: 
 1708: 	    case CP_REFTIME:
 1709: 		ctl_putts(peer_var[CP_REFTIME].text, &peer->reftime);
 1710: 		break;
 1711: 
 1712: 	    case CP_ORG:
 1713: 		ctl_putts(peer_var[CP_ORG].text, &peer->aorg);
 1714: 		break;
 1715: 
 1716: 	    case CP_REC:
 1717: 		ctl_putts(peer_var[CP_REC].text, &peer->dst);
 1718: 		break;
 1719: 
 1720: 	    case CP_XMT:
 1721: 		if (peer->xleave != 0)
 1722: 			ctl_putdbl(peer_var[CP_XMT].text, peer->xleave *
 1723: 			    1e3);
 1724: 		break;
 1725: 
 1726: 	    case CP_BIAS:
 1727: 		if (peer->bias != 0)
 1728: 			ctl_putdbl(peer_var[CP_BIAS].text, peer->bias *
 1729: 			    1e3);
 1730: 		break;
 1731: 
 1732: 	    case CP_REACH:
 1733: 		ctl_puthex(peer_var[CP_REACH].text, peer->reach);
 1734: 		break;
 1735: 
 1736: 	    case CP_FLASH:
 1737: 		temp = peer->flash;
 1738: 		ctl_puthex(peer_var[CP_FLASH].text, temp);
 1739: 		break;
 1740: 
 1741: 	    case CP_TTL:
 1742: 		if (peer->ttl > 0)
 1743: 			ctl_putint(peer_var[CP_TTL].text,
 1744: 			    sys_ttl[peer->ttl]);
 1745: 		break;
 1746: 
 1747: 	    case CP_UNREACH:
 1748: 		ctl_putuint(peer_var[CP_UNREACH].text, peer->unreach);
 1749: 		break;
 1750: 
 1751: 	    case CP_TIMER:
 1752: 		ctl_putuint(peer_var[CP_TIMER].text,
 1753: 		    peer->nextdate - current_time);
 1754: 		break;
 1755: 
 1756: 	    case CP_DELAY:
 1757: 		ctl_putdbl(peer_var[CP_DELAY].text, peer->delay * 1e3);
 1758: 		break;
 1759: 
 1760: 	    case CP_OFFSET:
 1761: 		ctl_putdbl(peer_var[CP_OFFSET].text, peer->offset *
 1762: 		   1e3);
 1763: 		break;
 1764: 
 1765: 	    case CP_JITTER:
 1766: 		ctl_putdbl(peer_var[CP_JITTER].text, peer->jitter *
 1767: 		    1e3);
 1768: 		break;
 1769: 
 1770: 	    case CP_DISPERSION:
 1771: 		ctl_putdbl(peer_var[CP_DISPERSION].text, peer->disp *
 1772: 		   1e3);
 1773: 		break;
 1774: 
 1775: 	    case CP_KEYID:
 1776: 		if (peer->keyid > NTP_MAXKEY)
 1777: 			ctl_puthex(peer_var[CP_KEYID].text,
 1778: 			    peer->keyid);
 1779: 		else
 1780: 			ctl_putuint(peer_var[CP_KEYID].text,
 1781: 			    peer->keyid);
 1782: 		break;
 1783: 
 1784: 	    case CP_FILTDELAY:
 1785: 		ctl_putarray(peer_var[CP_FILTDELAY].text,
 1786: 		    peer->filter_delay, (int)peer->filter_nextpt);
 1787: 		break;
 1788: 
 1789: 	    case CP_FILTOFFSET:
 1790: 		ctl_putarray(peer_var[CP_FILTOFFSET].text,
 1791: 		    peer->filter_offset, (int)peer->filter_nextpt);
 1792: 		break;
 1793: 
 1794: 	    case CP_FILTERROR:
 1795: 		ctl_putarray(peer_var[CP_FILTERROR].text,
 1796: 		    peer->filter_disp, (int)peer->filter_nextpt);
 1797: 		break;
 1798: 
 1799: 	    case CP_PMODE:
 1800: 		ctl_putuint(peer_var[CP_PMODE].text, peer->pmode);
 1801: 		break;
 1802: 
 1803: 	    case CP_RECEIVED:
 1804: 		ctl_putuint(peer_var[CP_RECEIVED].text, peer->received);
 1805: 		break;
 1806: 
 1807: 	    case CP_SENT:
 1808: 		ctl_putuint(peer_var[CP_SENT].text, peer->sent);
 1809: 		break;
 1810: 
 1811: 	    case CP_VARLIST:
 1812: 	    {
 1813: 		    char buf[CTL_MAX_DATA_LEN];
 1814: 		    register char *s, *t, *be;
 1815: 		    register int i;
 1816: 		    register struct ctl_var *k;
 1817: 
 1818: 		    s = buf;
 1819: 		    be = buf + sizeof(buf);
 1820: 		    if (s + strlen(peer_var[CP_VARLIST].text) + 4 > be)
 1821: 			    break;	/* really long var name */
 1822: 
 1823: 		    snprintf(s, sizeof(buf), "%s=\"",
 1824: 			peer_var[CP_VARLIST].text);
 1825: 		    s += strlen(s);
 1826: 		    t = s;
 1827: 		    for (k = peer_var; !(k->flags & EOV); k++) {
 1828: 			    if (k->flags & PADDING)
 1829: 				    continue;
 1830: 
 1831: 			    i = strlen(k->text);
 1832: 			    if (s + i + 1 >= be)
 1833: 				    break;
 1834: 
 1835: 			    if (s != t)
 1836: 				    *s++ = ',';
 1837: 			    memcpy(s, k->text, i);
 1838: 			    s += i;
 1839: 		    }
 1840: 		    if (s+2 >= be)
 1841: 			    break;
 1842: 
 1843: 		    *s++ = '"';
 1844: 		    *s = '\0';
 1845: 		    ctl_putdata(buf, (unsigned)(s - buf), 0);
 1846: 	    }
 1847: 	    break;
 1848: #ifdef OPENSSL
 1849: 	    case CP_FLAGS:
 1850: 		if (peer->crypto)
 1851: 			ctl_puthex(peer_var[CP_FLAGS].text, peer->crypto);
 1852: 		break;
 1853: 
 1854: 	    case CP_SIGNATURE:
 1855: 		if (peer->crypto) {
 1856: 			const EVP_MD *dp;
 1857: 
 1858: 			dp = EVP_get_digestbynid(peer->crypto >> 16);
 1859: 			strcpy(str, OBJ_nid2ln(EVP_MD_pkey_type(dp)));
 1860: 			ctl_putstr(peer_var[CP_SIGNATURE].text, str,
 1861: 			    strlen(str));
 1862: 		}
 1863: 		break;
 1864: 
 1865: 	    case CP_HOST:
 1866: 		if (peer->subject != NULL)
 1867: 			ctl_putstr(peer_var[CP_HOST].text,
 1868: 			    peer->subject, strlen(peer->subject));
 1869: 		break;
 1870: 
 1871: 	    case CP_VALID:		/* not used */
 1872: 		break;
 1873: 
 1874: 	    case CP_INITSEQ:
 1875: 		if ((ap = (struct autokey *)peer->recval.ptr) == NULL)
 1876: 			break;
 1877: 
 1878: 		ctl_putint(peer_var[CP_INITSEQ].text, ap->seq);
 1879: 		ctl_puthex(peer_var[CP_INITKEY].text, ap->key);
 1880: 		ctl_putfs(peer_var[CP_INITTSP].text,
 1881: 			  ntohl(peer->recval.tstamp));
 1882: 		break;
 1883: #endif /* OPENSSL */
 1884: 	}
 1885: }
 1886: 
 1887: 
 1888: #ifdef REFCLOCK
 1889: /*
 1890:  * ctl_putclock - output clock variables
 1891:  */
 1892: static void
 1893: ctl_putclock(
 1894: 	int varid,
 1895: 	struct refclockstat *clock_stat,
 1896: 	int mustput
 1897: 	)
 1898: {
 1899: 	switch(varid) {
 1900: 
 1901: 	    case CC_TYPE:
 1902: 		if (mustput || clock_stat->clockdesc == NULL
 1903: 		    || *(clock_stat->clockdesc) == '\0') {
 1904: 			ctl_putuint(clock_var[CC_TYPE].text, clock_stat->type);
 1905: 		}
 1906: 		break;
 1907: 	    case CC_TIMECODE:
 1908: 		ctl_putstr(clock_var[CC_TIMECODE].text,
 1909: 			   clock_stat->p_lastcode,
 1910: 			   (unsigned)clock_stat->lencode);
 1911: 		break;
 1912: 
 1913: 	    case CC_POLL:
 1914: 		ctl_putuint(clock_var[CC_POLL].text, clock_stat->polls);
 1915: 		break;
 1916: 
 1917: 	    case CC_NOREPLY:
 1918: 		ctl_putuint(clock_var[CC_NOREPLY].text,
 1919: 			    clock_stat->noresponse);
 1920: 		break;
 1921: 
 1922: 	    case CC_BADFORMAT:
 1923: 		ctl_putuint(clock_var[CC_BADFORMAT].text,
 1924: 			    clock_stat->badformat);
 1925: 		break;
 1926: 
 1927: 	    case CC_BADDATA:
 1928: 		ctl_putuint(clock_var[CC_BADDATA].text,
 1929: 			    clock_stat->baddata);
 1930: 		break;
 1931: 
 1932: 	    case CC_FUDGETIME1:
 1933: 		if (mustput || (clock_stat->haveflags & CLK_HAVETIME1))
 1934: 			ctl_putdbl(clock_var[CC_FUDGETIME1].text,
 1935: 				   clock_stat->fudgetime1 * 1e3);
 1936: 		break;
 1937: 
 1938: 	    case CC_FUDGETIME2:
 1939: 		if (mustput || (clock_stat->haveflags & CLK_HAVETIME2))
 1940: 			ctl_putdbl(clock_var[CC_FUDGETIME2].text,
 1941: 				   clock_stat->fudgetime2 * 1e3);
 1942: 		break;
 1943: 
 1944: 	    case CC_FUDGEVAL1:
 1945: 		if (mustput || (clock_stat->haveflags & CLK_HAVEVAL1))
 1946: 			ctl_putint(clock_var[CC_FUDGEVAL1].text,
 1947: 				   clock_stat->fudgeval1);
 1948: 		break;
 1949: 
 1950: 	    case CC_FUDGEVAL2:
 1951: 		if (mustput || (clock_stat->haveflags & CLK_HAVEVAL2)) {
 1952: 			if (clock_stat->fudgeval1 > 1)
 1953: 				ctl_putadr(clock_var[CC_FUDGEVAL2].text,
 1954: 					   clock_stat->fudgeval2, NULL);
 1955: 			else
 1956: 				ctl_putrefid(clock_var[CC_FUDGEVAL2].text,
 1957: 					     clock_stat->fudgeval2);
 1958: 		}
 1959: 		break;
 1960: 
 1961: 	    case CC_FLAGS:
 1962: 		if (mustput || (clock_stat->haveflags &	(CLK_HAVEFLAG1 |
 1963: 							 CLK_HAVEFLAG2 | CLK_HAVEFLAG3 | CLK_HAVEFLAG4)))
 1964: 			ctl_putuint(clock_var[CC_FLAGS].text,
 1965: 				    clock_stat->flags);
 1966: 		break;
 1967: 
 1968: 	    case CC_DEVICE:
 1969: 		if (clock_stat->clockdesc == NULL ||
 1970: 		    *(clock_stat->clockdesc) == '\0') {
 1971: 			if (mustput)
 1972: 				ctl_putstr(clock_var[CC_DEVICE].text,
 1973: 					   "", 0);
 1974: 		} else {
 1975: 			ctl_putstr(clock_var[CC_DEVICE].text,
 1976: 				   clock_stat->clockdesc,
 1977: 				   strlen(clock_stat->clockdesc));
 1978: 		}
 1979: 		break;
 1980: 
 1981: 	    case CC_VARLIST:
 1982: 	    {
 1983: 		    char buf[CTL_MAX_DATA_LEN];
 1984: 		    register char *s, *t, *be;
 1985: 		    register const char *ss;
 1986: 		    register int i;
 1987: 		    register struct ctl_var *k;
 1988: 
 1989: 		    s = buf;
 1990: 		    be = buf + sizeof(buf);
 1991: 		    if (s + strlen(clock_var[CC_VARLIST].text) + 4 >
 1992: 			be)
 1993: 			    break;	/* really long var name */
 1994: 
 1995: 		    snprintf(s, sizeof(buf), "%s=\"", 
 1996: 		        clock_var[CC_VARLIST].text);
 1997: 		    s += strlen(s);
 1998: 		    t = s;
 1999: 
 2000: 		    for (k = clock_var; !(k->flags & EOV); k++) {
 2001: 			    if (k->flags & PADDING)
 2002: 				    continue;
 2003: 
 2004: 			    i = strlen(k->text);
 2005: 			    if (s + i + 1 >= be)
 2006: 				    break;
 2007: 
 2008: 			    if (s != t)
 2009: 				    *s++ = ',';
 2010: 			    memcpy(s, k->text, i);
 2011: 			    s += i;
 2012: 		    }
 2013: 
 2014: 		    for (k = clock_stat->kv_list; k && !(k->flags &
 2015: 							 EOV); k++) {
 2016: 			    if (k->flags & PADDING)
 2017: 				    continue;
 2018: 
 2019: 			    ss = k->text;
 2020: 			    if (!ss)
 2021: 				    continue;
 2022: 
 2023: 			    while (*ss && *ss != '=')
 2024: 				    ss++;
 2025: 			    i = ss - k->text;
 2026: 			    if (s+i+1 >= be)
 2027: 				    break;
 2028: 
 2029: 			    if (s != t)
 2030: 				    *s++ = ',';
 2031: 			    memcpy(s, k->text, (unsigned)i);
 2032: 			    s += i;
 2033: 			    *s = '\0';
 2034: 		    }
 2035: 		    if (s+2 >= be)
 2036: 			    break;
 2037: 
 2038: 		    *s++ = '"';
 2039: 		    *s = '\0';
 2040: 		    ctl_putdata(buf, (unsigned)( s - buf ), 0);
 2041: 	    }
 2042: 	    break;
 2043: 	}
 2044: }
 2045: #endif
 2046: 
 2047: 
 2048: 
 2049: /*
 2050:  * ctl_getitem - get the next data item from the incoming packet
 2051:  */
 2052: static struct ctl_var *
 2053: ctl_getitem(
 2054: 	struct ctl_var *var_list,
 2055: 	char **data
 2056: 	)
 2057: {
 2058: 	register struct ctl_var *v;
 2059: 	register char *cp;
 2060: 	register char *tp;
 2061: 	static struct ctl_var eol = { 0, EOV, };
 2062: 	static char buf[128];
 2063: 
 2064: 	/*
 2065: 	 * Delete leading commas and white space
 2066: 	 */
 2067: 	while (reqpt < reqend && (*reqpt == ',' ||
 2068: 				  isspace((unsigned char)*reqpt)))
 2069: 		reqpt++;
 2070: 	if (reqpt >= reqend)
 2071: 		return (0);
 2072: 
 2073: 	if (var_list == (struct ctl_var *)0)
 2074: 		return (&eol);
 2075: 
 2076: 	/*
 2077: 	 * Look for a first character match on the tag.  If we find
 2078: 	 * one, see if it is a full match.
 2079: 	 */
 2080: 	v = var_list;
 2081: 	cp = reqpt;
 2082: 	while (!(v->flags & EOV)) {
 2083: 		if (!(v->flags & PADDING) && *cp == *(v->text)) {
 2084: 			tp = v->text;
 2085: 			while (*tp != '\0' && *tp != '=' && cp <
 2086: 			       reqend && *cp == *tp) {
 2087: 				cp++;
 2088: 				tp++;
 2089: 			}
 2090: 			if ((*tp == '\0') || (*tp == '=')) {
 2091: 				while (cp < reqend && isspace((unsigned char)*cp))
 2092: 					cp++;
 2093: 				if (cp == reqend || *cp == ',') {
 2094: 					buf[0] = '\0';
 2095: 					*data = buf;
 2096: 					if (cp < reqend)
 2097: 						cp++;
 2098: 					reqpt = cp;
 2099: 					return v;
 2100: 				}
 2101: 				if (*cp == '=') {
 2102: 					cp++;
 2103: 					tp = buf;
 2104: 					while (cp < reqend && isspace((unsigned char)*cp))
 2105: 						cp++;
 2106: 					while (cp < reqend && *cp != ',') {
 2107: 						*tp++ = *cp++;
 2108: 						if (tp >= buf + sizeof(buf)) {
 2109: 							ctl_error(CERR_BADFMT);
 2110: 							numctlbadpkts++;
 2111: #if 0	/* Avoid possible DOS attack */
 2112: /* If we get a smarter msyslog we can re-enable this */
 2113: 							msyslog(LOG_WARNING,
 2114: 								"Possible 'ntpdx' exploit from %s:%d (possibly spoofed)\n",
 2115: 								stoa(rmt_addr), SRCPORT(rmt_addr)
 2116: 								);
 2117: #endif
 2118: 							return (0);
 2119: 						}
 2120: 					}
 2121: 					if (cp < reqend)
 2122: 						cp++;
 2123: 					*tp-- = '\0';
 2124: 					while (tp >= buf) {
 2125: 						if (!isspace((unsigned int)(*tp)))
 2126: 							break;
 2127: 						*tp-- = '\0';
 2128: 					}
 2129: 					reqpt = cp;
 2130: 					*data = buf;
 2131: 					return (v);
 2132: 				}
 2133: 			}
 2134: 			cp = reqpt;
 2135: 		}
 2136: 		v++;
 2137: 	}
 2138: 	return v;
 2139: }
 2140: 
 2141: 
 2142: /*
 2143:  * control_unspec - response to an unspecified op-code
 2144:  */
 2145: /*ARGSUSED*/
 2146: static void
 2147: control_unspec(
 2148: 	struct recvbuf *rbufp,
 2149: 	int restrict_mask
 2150: 	)
 2151: {
 2152: 	struct peer *peer;
 2153: 
 2154: 	/*
 2155: 	 * What is an appropriate response to an unspecified op-code?
 2156: 	 * I return no errors and no data, unless a specified assocation
 2157: 	 * doesn't exist.
 2158: 	 */
 2159: 	if (res_associd != 0) {
 2160: 		if ((peer = findpeerbyassoc(res_associd)) == 0) {
 2161: 			ctl_error(CERR_BADASSOC);
 2162: 			return;
 2163: 		}
 2164: 		rpkt.status = htons(ctlpeerstatus(peer));
 2165: 	} else {
 2166: 		rpkt.status = htons(ctlsysstatus());
 2167: 	}
 2168: 	ctl_flushpkt(0);
 2169: }
 2170: 
 2171: 
 2172: /*
 2173:  * read_status - return either a list of associd's, or a particular
 2174:  * peer's status.
 2175:  */
 2176: /*ARGSUSED*/
 2177: static void
 2178: read_status(
 2179: 	struct recvbuf *rbufp,
 2180: 	int restrict_mask
 2181: 	)
 2182: {
 2183: 	register int i;
 2184: 	register struct peer *peer;
 2185: 	u_short ass_stat[CTL_MAX_DATA_LEN / sizeof(u_short)];
 2186: 
 2187: #ifdef DEBUG
 2188: 	if (debug > 2)
 2189: 		printf("read_status: ID %d\n", res_associd);
 2190: #endif
 2191: 	/*
 2192: 	 * Two choices here. If the specified association ID is
 2193: 	 * zero we return all known assocation ID's.  Otherwise
 2194: 	 * we return a bunch of stuff about the particular peer.
 2195: 	 */
 2196: 	if (res_associd == 0) {
 2197: 		register int n;
 2198: 
 2199: 		n = 0;
 2200: 		rpkt.status = htons(ctlsysstatus());
 2201: 		for (i = 0; i < NTP_HASH_SIZE; i++) {
 2202: 			for (peer = assoc_hash[i]; peer != 0;
 2203: 			     peer = peer->ass_next) {
 2204: 				ass_stat[n++] = htons(peer->associd);
 2205: 				ass_stat[n++] =
 2206: 				    htons(ctlpeerstatus(peer));
 2207: 				if (n ==
 2208: 				    CTL_MAX_DATA_LEN/sizeof(u_short)) {
 2209: 					ctl_putdata((char *)ass_stat,
 2210: 						    n * sizeof(u_short), 1);
 2211: 					n = 0;
 2212: 				}
 2213: 			}
 2214: 		}
 2215: 
 2216: 		if (n != 0)
 2217: 			ctl_putdata((char *)ass_stat, n *
 2218: 				    sizeof(u_short), 1);
 2219: 		ctl_flushpkt(0);
 2220: 	} else {
 2221: 		peer = findpeerbyassoc(res_associd);
 2222: 		if (peer == 0) {
 2223: 			ctl_error(CERR_BADASSOC);
 2224: 		} else {
 2225: 			register u_char *cp;
 2226: 
 2227: 			rpkt.status = htons(ctlpeerstatus(peer));
 2228: 			if (res_authokay)
 2229: 				peer->num_events = 0;
 2230: 			/*
 2231: 			 * For now, output everything we know about the
 2232: 			 * peer. May be more selective later.
 2233: 			 */
 2234: 			for (cp = def_peer_var; *cp != 0; cp++)
 2235: 				ctl_putpeer((int)*cp, peer);
 2236: 			ctl_flushpkt(0);
 2237: 		}
 2238: 	}
 2239: }
 2240: 
 2241: 
 2242: /*
 2243:  * read_variables - return the variables the caller asks for
 2244:  */
 2245: /*ARGSUSED*/
 2246: static void
 2247: read_variables(
 2248: 	struct recvbuf *rbufp,
 2249: 	int restrict_mask
 2250: 	)
 2251: {
 2252: 	register struct ctl_var *v;
 2253: 	register int i;
 2254: 	char *valuep;
 2255: 	u_char *wants;
 2256: 	unsigned int gotvar = (CS_MAXCODE > CP_MAXCODE) ? (CS_MAXCODE +
 2257: 							   1) : (CP_MAXCODE + 1);
 2258: 	if (res_associd == 0) {
 2259: 		/*
 2260: 		 * Wants system variables. Figure out which he wants
 2261: 		 * and give them to him.
 2262: 		 */
 2263: 		rpkt.status = htons(ctlsysstatus());
 2264: 		if (res_authokay)
 2265: 			ctl_sys_num_events = 0;
 2266: 		gotvar += count_var(ext_sys_var);
 2267: 		wants = (u_char *)emalloc(gotvar);
 2268: 		memset((char *)wants, 0, gotvar);
 2269: 		gotvar = 0;
 2270: 		while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
 2271: 			if (v->flags & EOV) {
 2272: 				if ((v = ctl_getitem(ext_sys_var,
 2273: 						     &valuep)) != 0) {
 2274: 					if (v->flags & EOV) {
 2275: 						ctl_error(CERR_UNKNOWNVAR);
 2276: 						free((char *)wants);
 2277: 						return;
 2278: 					}
 2279: 					wants[CS_MAXCODE + 1 +
 2280: 					      v->code] = 1;
 2281: 					gotvar = 1;
 2282: 					continue;
 2283: 				} else {
 2284: 					break; /* shouldn't happen ! */
 2285: 				}
 2286: 			}
 2287: 			wants[v->code] = 1;
 2288: 			gotvar = 1;
 2289: 		}
 2290: 		if (gotvar) {
 2291: 			for (i = 1; i <= CS_MAXCODE; i++)
 2292: 				if (wants[i])
 2293: 					ctl_putsys(i);
 2294: 			for (i = 0; ext_sys_var &&
 2295: 				 !(ext_sys_var[i].flags & EOV); i++)
 2296: 				if (wants[i + CS_MAXCODE + 1])
 2297: 					ctl_putdata(ext_sys_var[i].text,
 2298: 						    strlen(ext_sys_var[i].text),
 2299: 						    0);
 2300: 		} else {
 2301: 			register u_char *cs;
 2302: 			register struct ctl_var *kv;
 2303: 
 2304: 			for (cs = def_sys_var; *cs != 0; cs++)
 2305: 				ctl_putsys((int)*cs);
 2306: 			for (kv = ext_sys_var; kv && !(kv->flags & EOV);
 2307: 			     kv++)
 2308: 				if (kv->flags & DEF)
 2309: 					ctl_putdata(kv->text,
 2310: 						    strlen(kv->text), 0);
 2311: 		}
 2312: 		free((char *)wants);
 2313: 	} else {
 2314: 		register struct peer *peer;
 2315: 
 2316: 		/*
 2317: 		 * Wants info for a particular peer. See if we know
 2318: 		 * the guy.
 2319: 		 */
 2320: 		peer = findpeerbyassoc(res_associd);
 2321: 		if (peer == 0) {
 2322: 			ctl_error(CERR_BADASSOC);
 2323: 			return;
 2324: 		}
 2325: 		rpkt.status = htons(ctlpeerstatus(peer));
 2326: 		if (res_authokay)
 2327: 			peer->num_events = 0;
 2328: 		wants = (u_char *)emalloc(gotvar);
 2329: 		memset((char*)wants, 0, gotvar);
 2330: 		gotvar = 0;
 2331: 		while ((v = ctl_getitem(peer_var, &valuep)) != 0) {
 2332: 			if (v->flags & EOV) {
 2333: 				ctl_error(CERR_UNKNOWNVAR);
 2334: 				free((char *)wants);
 2335: 				return;
 2336: 			}
 2337: 			wants[v->code] = 1;
 2338: 			gotvar = 1;
 2339: 		}
 2340: 		if (gotvar) {
 2341: 			for (i = 1; i <= CP_MAXCODE; i++)
 2342: 				if (wants[i])
 2343: 					ctl_putpeer(i, peer);
 2344: 		} else {
 2345: 			register u_char *cp;
 2346: 
 2347: 			for (cp = def_peer_var; *cp != 0; cp++)
 2348: 				ctl_putpeer((int)*cp, peer);
 2349: 		}
 2350: 		free((char *)wants);
 2351: 	}
 2352: 	ctl_flushpkt(0);
 2353: }
 2354: 
 2355: 
 2356: /*
 2357:  * write_variables - write into variables. We only allow leap bit
 2358:  * writing this way.
 2359:  */
 2360: /*ARGSUSED*/
 2361: static void
 2362: write_variables(
 2363: 	struct recvbuf *rbufp,
 2364: 	int restrict_mask
 2365: 	)
 2366: {
 2367: 	register struct ctl_var *v;
 2368: 	register int ext_var;
 2369: 	char *valuep;
 2370: 	long val = 0;
 2371: 
 2372: 	/*
 2373: 	 * If he's trying to write into a peer tell him no way
 2374: 	 */
 2375: 	if (res_associd != 0) {
 2376: 		ctl_error(CERR_PERMISSION);
 2377: 		return;
 2378: 	}
 2379: 
 2380: 	/*
 2381: 	 * Set status
 2382: 	 */
 2383: 	rpkt.status = htons(ctlsysstatus());
 2384: 
 2385: 	/*
 2386: 	 * Look through the variables. Dump out at the first sign of
 2387: 	 * trouble.
 2388: 	 */
 2389: 	while ((v = ctl_getitem(sys_var, &valuep)) != 0) {
 2390: 		ext_var = 0;
 2391: 		if (v->flags & EOV) {
 2392: 			if ((v = ctl_getitem(ext_sys_var, &valuep)) !=
 2393: 			    0) {
 2394: 				if (v->flags & EOV) {
 2395: 					ctl_error(CERR_UNKNOWNVAR);
 2396: 					return;
 2397: 				}
 2398: 				ext_var = 1;
 2399: 			} else {
 2400: 				break;
 2401: 			}
 2402: 		}
 2403: 		if (!(v->flags & CAN_WRITE)) {
 2404: 			ctl_error(CERR_PERMISSION);
 2405: 			return;
 2406: 		}
 2407: 		if (!ext_var && (*valuep == '\0' || !atoint(valuep,
 2408: 							    &val))) {
 2409: 			ctl_error(CERR_BADFMT);
 2410: 			return;
 2411: 		}
 2412: 		if (!ext_var && (val & ~LEAP_NOTINSYNC) != 0) {
 2413: 			ctl_error(CERR_BADVALUE);
 2414: 			return;
 2415: 		}
 2416: 
 2417: 		if (ext_var) {
 2418: 			char *s = (char *)emalloc(strlen(v->text) +
 2419: 						  strlen(valuep) + 2);
 2420: 			const char *t;
 2421: 			char *tt = s;
 2422: 
 2423: 			t = v->text;
 2424: 			while (*t && *t != '=')
 2425: 				*tt++ = *t++;
 2426: 
 2427: 			*tt++ = '=';
 2428: 			strcat(tt, valuep);
 2429: 			set_sys_var(s, strlen(s)+1, v->flags);
 2430: 			free(s);
 2431: 		} else {
 2432: 			/*
 2433: 			 * This one seems sane. Save it.
 2434: 			 */
 2435: 			switch(v->code) {
 2436: 
 2437: 			    case CS_LEAP:
 2438: 			    default:
 2439: 				ctl_error(CERR_UNSPEC); /* really */
 2440: 				return;
 2441: 			}
 2442: 		}
 2443: 	}
 2444: 
 2445: 	/*
 2446: 	 * If we got anything, do it. xxx nothing to do ***
 2447: 	 */
 2448: 	/*
 2449: 	  if (leapind != ~0 || leapwarn != ~0) {
 2450: 	  if (!leap_setleap((int)leapind, (int)leapwarn)) {
 2451: 	  ctl_error(CERR_PERMISSION);
 2452: 	  return;
 2453: 	  }
 2454: 	  }
 2455: 	*/
 2456: 	ctl_flushpkt(0);
 2457: }
 2458: 
 2459: /*
 2460:  * configure() processes ntpq :config/config-from-file, allowing
 2461:  *		generic runtime reconfiguration.
 2462:  */
 2463: static void configure(
 2464: 	struct recvbuf *rbufp,
 2465: 	int restrict_mask
 2466: 	)
 2467: {
 2468: 	size_t data_count;
 2469: 	int retval;
 2470: 	int replace_nl;
 2471: 
 2472: 	/* I haven't yet implemented changes to an existing association.
 2473: 	 * Hence check if the association id is 0
 2474: 	 */
 2475: 	if (res_associd != 0) {
 2476: 		ctl_error(CERR_BADVALUE);
 2477: 		return;
 2478: 	}
 2479: 
 2480: 	if (restrict_mask & RES_NOMODIFY) {
 2481: 		snprintf(remote_config.err_msg,
 2482: 			 sizeof(remote_config.err_msg),
 2483: 			 "runtime configuration prohibited by restrict ... nomodify");
 2484: 		ctl_putdata(remote_config.err_msg, 
 2485: 			    strlen(remote_config.err_msg), 0);
 2486: 		ctl_flushpkt(0);
 2487: 		msyslog(LOG_NOTICE,
 2488: 			"runtime config from %s rejected due to nomodify restriction",
 2489: 			stoa(&rbufp->recv_srcadr));
 2490: 		return;
 2491: 	}
 2492: 
 2493: 	/* Initialize the remote config buffer */
 2494: 	data_count = reqend - reqpt;
 2495: 	memcpy(remote_config.buffer, reqpt, data_count);
 2496: 	if (data_count > 0
 2497: 	    && '\n' != remote_config.buffer[data_count - 1])
 2498: 		remote_config.buffer[data_count++] = '\n';
 2499: 	remote_config.buffer[data_count] = '\0';
 2500: 	remote_config.pos = 0;
 2501: 	remote_config.err_pos = 0;
 2502: 	remote_config.no_errors = 0;
 2503: 
 2504: 	/* do not include terminating newline in log */
 2505: 	if (data_count > 0
 2506: 	    && '\n' == remote_config.buffer[data_count - 1]) {
 2507: 		remote_config.buffer[data_count - 1] = '\0';
 2508: 		replace_nl = 1;
 2509: 	} else
 2510: 		replace_nl = 0;
 2511: 
 2512: 	DPRINTF(1, ("Got Remote Configuration Command: %s\n",
 2513: 		remote_config.buffer));
 2514: 	msyslog(LOG_NOTICE, "%s config: %s",
 2515: 		stoa(&rbufp->recv_srcadr),
 2516: 		remote_config.buffer);
 2517: 
 2518: 	if (replace_nl)
 2519: 		remote_config.buffer[data_count - 1] = '\n';
 2520: 
 2521: 	config_remotely(&rbufp->recv_srcadr);
 2522: 
 2523: 	/* 
 2524: 	 * Check if errors were reported. If not, output 'Config
 2525: 	 * Succeeded'.  Else output the error count.  It would be nice
 2526: 	 * to output any parser error messages.
 2527: 	 */
 2528: 	if (0 == remote_config.no_errors) {
 2529: 		retval = snprintf(remote_config.err_msg,
 2530: 				  sizeof(remote_config.err_msg),
 2531: 				  "Config Succeeded");
 2532: 		if (retval > 0) 
 2533: 			remote_config.err_pos += retval;
 2534: 	}
 2535: 	
 2536: 	ctl_putdata(remote_config.err_msg, remote_config.err_pos, 0);
 2537: 	ctl_flushpkt(0);
 2538: 
 2539: 	DPRINTF(1, ("Reply: %s\n", remote_config.err_msg));
 2540: 
 2541: 	if (remote_config.no_errors > 0)
 2542: 		msyslog(LOG_NOTICE, "%d error in %s config",
 2543: 			remote_config.no_errors,
 2544: 			stoa(&rbufp->recv_srcadr));
 2545: }
 2546: 
 2547: 
 2548: /*
 2549:  * read_clock_status - return clock radio status
 2550:  */
 2551: /*ARGSUSED*/
 2552: static void
 2553: read_clock_status(
 2554: 	struct recvbuf *rbufp,
 2555: 	int restrict_mask
 2556: 	)
 2557: {
 2558: #ifndef REFCLOCK
 2559: 	/*
 2560: 	 * If no refclock support, no data to return
 2561: 	 */
 2562: 	ctl_error(CERR_BADASSOC);
 2563: #else
 2564: 	register struct ctl_var *v;
 2565: 	register int i;
 2566: 	register struct peer *peer;
 2567: 	char *valuep;
 2568: 	u_char *wants;
 2569: 	unsigned int gotvar;
 2570: 	struct refclockstat clock_stat;
 2571: 
 2572: 	if (res_associd == 0) {
 2573: 
 2574: 		/*
 2575: 		 * Find a clock for this jerk.	If the system peer
 2576: 		 * is a clock use it, else search the hash tables
 2577: 		 * for one.
 2578: 		 */
 2579: 		if (sys_peer != 0 && (sys_peer->flags & FLAG_REFCLOCK))
 2580: 		{
 2581: 			peer = sys_peer;
 2582: 		} else {
 2583: 			peer = 0;
 2584: 			for (i = 0; peer == 0 && i < NTP_HASH_SIZE; i++) {
 2585: 				for (peer = assoc_hash[i]; peer != 0;
 2586: 				     peer = peer->ass_next) {
 2587: 					if (peer->flags & FLAG_REFCLOCK)
 2588: 						break;
 2589: 				}
 2590: 			}
 2591: 			if (peer == 0) {
 2592: 				ctl_error(CERR_BADASSOC);
 2593: 				return;
 2594: 			}
 2595: 		}
 2596: 	} else {
 2597: 		peer = findpeerbyassoc(res_associd);
 2598: 		if (peer == 0 || !(peer->flags & FLAG_REFCLOCK)) {
 2599: 			ctl_error(CERR_BADASSOC);
 2600: 			return;
 2601: 		}
 2602: 	}
 2603: 
 2604: 	/*
 2605: 	 * If we got here we have a peer which is a clock. Get his
 2606: 	 * status.
 2607: 	 */
 2608: 	clock_stat.kv_list = (struct ctl_var *)0;
 2609: 	refclock_control(&peer->srcadr, (struct refclockstat *)0,
 2610: 			 &clock_stat);
 2611: 
 2612: 	/*
 2613: 	 * Look for variables in the packet.
 2614: 	 */
 2615: 	rpkt.status = htons(ctlclkstatus(&clock_stat));
 2616: 	gotvar = CC_MAXCODE + 1 + count_var(clock_stat.kv_list);
 2617: 	wants = (u_char *)emalloc(gotvar);
 2618: 	memset((char*)wants, 0, gotvar);
 2619: 	gotvar = 0;
 2620: 	while ((v = ctl_getitem(clock_var, &valuep)) != 0) {
 2621: 		if (v->flags & EOV) {
 2622: 			if ((v = ctl_getitem(clock_stat.kv_list,
 2623: 					     &valuep)) != 0) {
 2624: 				if (v->flags & EOV) {
 2625: 					ctl_error(CERR_UNKNOWNVAR);
 2626: 					free((char*)wants);
 2627: 					free_varlist(clock_stat.kv_list);
 2628: 					return;
 2629: 				}
 2630: 				wants[CC_MAXCODE + 1 + v->code] = 1;
 2631: 				gotvar = 1;
 2632: 				continue;
 2633: 			} else {
 2634: 				break; /* shouldn't happen ! */
 2635: 			}
 2636: 		}
 2637: 		wants[v->code] = 1;
 2638: 		gotvar = 1;
 2639: 	}
 2640: 
 2641: 	if (gotvar) {
 2642: 		for (i = 1; i <= CC_MAXCODE; i++)
 2643: 			if (wants[i])
 2644: 				ctl_putclock(i, &clock_stat, 1);
 2645: 		for (i = 0; clock_stat.kv_list &&
 2646: 			 !(clock_stat.kv_list[i].flags & EOV); i++)
 2647: 			if (wants[i + CC_MAXCODE + 1])
 2648: 				ctl_putdata(clock_stat.kv_list[i].text,
 2649: 					    strlen(clock_stat.kv_list[i].text),
 2650: 					    0);
 2651: 	} else {
 2652: 		register u_char *cc;
 2653: 		register struct ctl_var *kv;
 2654: 
 2655: 		for (cc = def_clock_var; *cc != 0; cc++)
 2656: 			ctl_putclock((int)*cc, &clock_stat, 0);
 2657: 		for (kv = clock_stat.kv_list; kv && !(kv->flags & EOV);
 2658: 		     kv++)
 2659: 			if (kv->flags & DEF)
 2660: 				ctl_putdata(kv->text, strlen(kv->text),
 2661: 					    0);
 2662: 	}
 2663: 
 2664: 	free((char*)wants);
 2665: 	free_varlist(clock_stat.kv_list);
 2666: 
 2667: 	ctl_flushpkt(0);
 2668: #endif
 2669: }
 2670: 
 2671: 
 2672: /*
 2673:  * write_clock_status - we don't do this
 2674:  */
 2675: /*ARGSUSED*/
 2676: static void
 2677: write_clock_status(
 2678: 	struct recvbuf *rbufp,
 2679: 	int restrict_mask
 2680: 	)
 2681: {
 2682: 	ctl_error(CERR_PERMISSION);
 2683: }
 2684: 
 2685: /*
 2686:  * Trap support from here on down. We send async trap messages when the
 2687:  * upper levels report trouble. Traps can by set either by control
 2688:  * messages or by configuration.
 2689:  */
 2690: /*
 2691:  * set_trap - set a trap in response to a control message
 2692:  */
 2693: static void
 2694: set_trap(
 2695: 	struct recvbuf *rbufp,
 2696: 	int restrict_mask
 2697: 	)
 2698: {
 2699: 	int traptype;
 2700: 
 2701: 	/*
 2702: 	 * See if this guy is allowed
 2703: 	 */
 2704: 	if (restrict_mask & RES_NOTRAP) {
 2705: 		ctl_error(CERR_PERMISSION);
 2706: 		return;
 2707: 	}
 2708: 
 2709: 	/*
 2710: 	 * Determine his allowed trap type.
 2711: 	 */
 2712: 	traptype = TRAP_TYPE_PRIO;
 2713: 	if (restrict_mask & RES_LPTRAP)
 2714: 		traptype = TRAP_TYPE_NONPRIO;
 2715: 
 2716: 	/*
 2717: 	 * Call ctlsettrap() to do the work.  Return
 2718: 	 * an error if it can't assign the trap.
 2719: 	 */
 2720: 	if (!ctlsettrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype,
 2721: 			(int)res_version))
 2722: 		ctl_error(CERR_NORESOURCE);
 2723: 	ctl_flushpkt(0);
 2724: }
 2725: 
 2726: 
 2727: /*
 2728:  * unset_trap - unset a trap in response to a control message
 2729:  */
 2730: static void
 2731: unset_trap(
 2732: 	struct recvbuf *rbufp,
 2733: 	int restrict_mask
 2734: 	)
 2735: {
 2736: 	int traptype;
 2737: 
 2738: 	/*
 2739: 	 * We don't prevent anyone from removing his own trap unless the
 2740: 	 * trap is configured. Note we also must be aware of the
 2741: 	 * possibility that restriction flags were changed since this
 2742: 	 * guy last set his trap. Set the trap type based on this.
 2743: 	 */
 2744: 	traptype = TRAP_TYPE_PRIO;
 2745: 	if (restrict_mask & RES_LPTRAP)
 2746: 		traptype = TRAP_TYPE_NONPRIO;
 2747: 
 2748: 	/*
 2749: 	 * Call ctlclrtrap() to clear this out.
 2750: 	 */
 2751: 	if (!ctlclrtrap(&rbufp->recv_srcadr, rbufp->dstadr, traptype))
 2752: 		ctl_error(CERR_BADASSOC);
 2753: 	ctl_flushpkt(0);
 2754: }
 2755: 
 2756: 
 2757: /*
 2758:  * ctlsettrap - called to set a trap
 2759:  */
 2760: int
 2761: ctlsettrap(
 2762: 	sockaddr_u *raddr,
 2763: 	struct interface *linter,
 2764: 	int traptype,
 2765: 	int version
 2766: 	)
 2767: {
 2768: 	register struct ctl_trap *tp;
 2769: 	register struct ctl_trap *tptouse;
 2770: 
 2771: 	/*
 2772: 	 * See if we can find this trap.  If so, we only need update
 2773: 	 * the flags and the time.
 2774: 	 */
 2775: 	if ((tp = ctlfindtrap(raddr, linter)) != NULL) {
 2776: 		switch (traptype) {
 2777: 
 2778: 		    case TRAP_TYPE_CONFIG:
 2779: 			tp->tr_flags = TRAP_INUSE|TRAP_CONFIGURED;
 2780: 			break;
 2781: 
 2782: 		    case TRAP_TYPE_PRIO:
 2783: 			if (tp->tr_flags & TRAP_CONFIGURED)
 2784: 				return (1); /* don't change anything */
 2785: 			tp->tr_flags = TRAP_INUSE;
 2786: 			break;
 2787: 
 2788: 		    case TRAP_TYPE_NONPRIO:
 2789: 			if (tp->tr_flags & TRAP_CONFIGURED)
 2790: 				return (1); /* don't change anything */
 2791: 			tp->tr_flags = TRAP_INUSE|TRAP_NONPRIO;
 2792: 			break;
 2793: 		}
 2794: 		tp->tr_settime = current_time;
 2795: 		tp->tr_resets++;
 2796: 		return (1);
 2797: 	}
 2798: 
 2799: 	/*
 2800: 	 * First we heard of this guy.	Try to find a trap structure
 2801: 	 * for him to use, clearing out lesser priority guys if we
 2802: 	 * have to. Clear out anyone who's expired while we're at it.
 2803: 	 */
 2804: 	tptouse = NULL;
 2805: 	for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
 2806: 		if ((tp->tr_flags & TRAP_INUSE) &&
 2807: 		    !(tp->tr_flags & TRAP_CONFIGURED) &&
 2808: 		    ((tp->tr_settime + CTL_TRAPTIME) > current_time)) {
 2809: 			tp->tr_flags = 0;
 2810: 			num_ctl_traps--;
 2811: 		}
 2812: 		if (!(tp->tr_flags & TRAP_INUSE)) {
 2813: 			tptouse = tp;
 2814: 		} else if (!(tp->tr_flags & TRAP_CONFIGURED)) {
 2815: 			switch (traptype) {
 2816: 
 2817: 			    case TRAP_TYPE_CONFIG:
 2818: 				if (tptouse == NULL) {
 2819: 					tptouse = tp;
 2820: 					break;
 2821: 				}
 2822: 				if (tptouse->tr_flags & TRAP_NONPRIO &&
 2823: 				    !(tp->tr_flags & TRAP_NONPRIO))
 2824: 					break;
 2825: 
 2826: 				if (!(tptouse->tr_flags & TRAP_NONPRIO)
 2827: 				    && tp->tr_flags & TRAP_NONPRIO) {
 2828: 					tptouse = tp;
 2829: 					break;
 2830: 				}
 2831: 				if (tptouse->tr_origtime <
 2832: 				    tp->tr_origtime)
 2833: 					tptouse = tp;
 2834: 				break;
 2835: 
 2836: 			    case TRAP_TYPE_PRIO:
 2837: 				if (tp->tr_flags & TRAP_NONPRIO) {
 2838: 					if (tptouse == NULL ||
 2839: 					    (tptouse->tr_flags &
 2840: 					     TRAP_INUSE &&
 2841: 					     tptouse->tr_origtime <
 2842: 					     tp->tr_origtime))
 2843: 						tptouse = tp;
 2844: 				}
 2845: 				break;
 2846: 
 2847: 			    case TRAP_TYPE_NONPRIO:
 2848: 				break;
 2849: 			}
 2850: 		}
 2851: 	}
 2852: 
 2853: 	/*
 2854: 	 * If we don't have room for him return an error.
 2855: 	 */
 2856: 	if (tptouse == NULL)
 2857: 		return (0);
 2858: 
 2859: 	/*
 2860: 	 * Set up this structure for him.
 2861: 	 */
 2862: 	tptouse->tr_settime = tptouse->tr_origtime = current_time;
 2863: 	tptouse->tr_count = tptouse->tr_resets = 0;
 2864: 	tptouse->tr_sequence = 1;
 2865: 	tptouse->tr_addr = *raddr;
 2866: 	tptouse->tr_localaddr = linter;
 2867: 	tptouse->tr_version = (u_char) version;
 2868: 	tptouse->tr_flags = TRAP_INUSE;
 2869: 	if (traptype == TRAP_TYPE_CONFIG)
 2870: 		tptouse->tr_flags |= TRAP_CONFIGURED;
 2871: 	else if (traptype == TRAP_TYPE_NONPRIO)
 2872: 		tptouse->tr_flags |= TRAP_NONPRIO;
 2873: 	num_ctl_traps++;
 2874: 	return (1);
 2875: }
 2876: 
 2877: 
 2878: /*
 2879:  * ctlclrtrap - called to clear a trap
 2880:  */
 2881: int
 2882: ctlclrtrap(
 2883: 	sockaddr_u *raddr,
 2884: 	struct interface *linter,
 2885: 	int traptype
 2886: 	)
 2887: {
 2888: 	register struct ctl_trap *tp;
 2889: 
 2890: 	if ((tp = ctlfindtrap(raddr, linter)) == NULL)
 2891: 		return (0);
 2892: 
 2893: 	if (tp->tr_flags & TRAP_CONFIGURED
 2894: 	    && traptype != TRAP_TYPE_CONFIG)
 2895: 		return (0);
 2896: 
 2897: 	tp->tr_flags = 0;
 2898: 	num_ctl_traps--;
 2899: 	return (1);
 2900: }
 2901: 
 2902: 
 2903: /*
 2904:  * ctlfindtrap - find a trap given the remote and local addresses
 2905:  */
 2906: static struct ctl_trap *
 2907: ctlfindtrap(
 2908: 	sockaddr_u *raddr,
 2909: 	struct interface *linter
 2910: 	)
 2911: {
 2912: 	register struct ctl_trap *tp;
 2913: 
 2914: 	for (tp = ctl_trap; tp < &ctl_trap[CTL_MAXTRAPS]; tp++) {
 2915: 		if ((tp->tr_flags & TRAP_INUSE)
 2916: 		    && (NSRCPORT(raddr) == NSRCPORT(&tp->tr_addr))
 2917: 		    && SOCK_EQ(raddr, &tp->tr_addr)
 2918: 	 	    && (linter == tp->tr_localaddr) )
 2919: 			return (tp);
 2920: 	}
 2921: 	return (struct ctl_trap *)NULL;
 2922: }
 2923: 
 2924: 
 2925: /*
 2926:  * report_event - report an event to the trappers
 2927:  */
 2928: void
 2929: report_event(
 2930: 	int	err,		/* error code */
 2931: 	struct peer *peer,	/* peer structure pointer */
 2932: 	const char *str		/* protostats string */
 2933: 	)
 2934: {
 2935: 	char	statstr[NTP_MAXSTRLEN];
 2936: 	int	i;
 2937: 	size_t	len;
 2938: 
 2939: 	/*
 2940: 	 * Report the error to the protostats file, system log and
 2941: 	 * trappers.
 2942: 	 */
 2943: 	if (peer == NULL) {
 2944: 
 2945: 		/*
 2946: 		 * Discard a system report if the number of reports of
 2947: 		 * the same type exceeds the maximum.
 2948: 		 */
 2949: 		if (ctl_sys_last_event != (u_char)err)
 2950: 			ctl_sys_num_events= 0;
 2951: 		if (ctl_sys_num_events >= CTL_SYS_MAXEVENTS)
 2952: 			return;
 2953: 
 2954: 		ctl_sys_last_event = (u_char)err;
 2955: 		ctl_sys_num_events++;
 2956: 		snprintf(statstr, NTP_MAXSTRLEN,
 2957: 		    "0.0.0.0 %04x %02x %s",
 2958: 		    ctlsysstatus(), err, eventstr(err));
 2959: 		if (str != NULL) {
 2960: 			len = strlen(statstr);
 2961: 			snprintf(statstr + len, sizeof(statstr) - len,
 2962: 			    " %s", str);
 2963: 		}
 2964: 		NLOG(NLOG_SYSEVENT)
 2965: 		    msyslog(LOG_INFO, statstr);
 2966: 	} else {
 2967: 
 2968: 		/*
 2969: 		 * Discard a peer report if the number of reports of
 2970: 		 * the same type exceeds the maximum for that peer.
 2971: 		 */
 2972: 		char	*src;
 2973: 		u_char	errlast;
 2974: 
 2975: 		errlast = (u_char)err & ~PEER_EVENT; 
 2976: 		if (peer->last_event == errlast)
 2977: 			peer->num_events = 0;
 2978: 		if (peer->num_events >= CTL_PEER_MAXEVENTS)
 2979: 			return;
 2980: 
 2981: 		peer->last_event = errlast;
 2982: 		peer->num_events++;
 2983: 		if (ISREFCLOCKADR(&peer->srcadr))
 2984: 			src = refnumtoa(&peer->srcadr);
 2985: 		else
 2986: 			src = stoa(&peer->srcadr);
 2987: 
 2988: 		snprintf(statstr, NTP_MAXSTRLEN,
 2989: 		    "%s %04x %02x %s", src,
 2990: 		    ctlpeerstatus(peer), err, eventstr(err));
 2991: 		if (str != NULL) {
 2992: 			len = strlen(statstr);
 2993: 			snprintf(statstr + len, sizeof(statstr) - len,
 2994: 			    " %s", str);
 2995: 		}
 2996: 		NLOG(NLOG_PEEREVENT)
 2997: 		    msyslog(LOG_INFO, statstr);
 2998: 	}
 2999: 	record_proto_stats(statstr);
 3000: #if DEBUG
 3001: 	if (debug)
 3002: 		printf("event at %lu %s\n", current_time, statstr);
 3003: #endif
 3004: 
 3005: 	/*
 3006: 	 * If no trappers, return.
 3007: 	 */
 3008: 	if (num_ctl_traps <= 0)
 3009: 		return;
 3010: 
 3011: 	/*
 3012: 	 * Set up the outgoing packet variables
 3013: 	 */
 3014: 	res_opcode = CTL_OP_ASYNCMSG;
 3015: 	res_offset = 0;
 3016: 	res_async = 1;
 3017: 	res_authenticate = 0;
 3018: 	datapt = rpkt.data;
 3019: 	dataend = &(rpkt.data[CTL_MAX_DATA_LEN]);
 3020: 	if (!(err & PEER_EVENT)) {
 3021: 		rpkt.associd = 0;
 3022: 		rpkt.status = htons(ctlsysstatus());
 3023: 
 3024: 		/*
 3025: 		 * For now, put everything we know about system
 3026: 		 * variables. Don't send crypto strings.
 3027: 		 */
 3028: 		for (i = 1; i <= CS_MAXCODE; i++) {
 3029: #ifdef OPENSSL
 3030: 			if (i > CS_VARLIST)
 3031: 				continue;
 3032: #endif /* OPENSSL */
 3033: 			ctl_putsys(i);
 3034: 		}
 3035: 	} else {
 3036: 		NTP_INSIST(peer != NULL);
 3037: 		rpkt.associd = htons(peer->associd);
 3038: 		rpkt.status = htons(ctlpeerstatus(peer));
 3039: 
 3040: 		/*
 3041: 		 * Dump it all. Later, maybe less.
 3042: 		 */
 3043: 		for (i = 1; i <= CP_MAXCODE; i++) {
 3044: #ifdef OPENSSL
 3045: 			if (i > CP_VARLIST)
 3046: 				continue;
 3047: #endif /* OPENSSL */
 3048: 			ctl_putpeer(i, peer);
 3049: 		}
 3050: #ifdef REFCLOCK
 3051: 		/*
 3052: 		 * for clock exception events: add clock variables to
 3053: 		 * reflect info on exception
 3054: 		 */
 3055: 		if (err == PEVNT_CLOCK) {
 3056: 			struct refclockstat clock_stat;
 3057: 			struct ctl_var *kv;
 3058: 
 3059: 			clock_stat.kv_list = (struct ctl_var *)0;
 3060: 			refclock_control(&peer->srcadr,
 3061: 					 (struct refclockstat *)0, &clock_stat);
 3062: 
 3063: 			ctl_puthex("refclockstatus",
 3064: 				   ctlclkstatus(&clock_stat));
 3065: 
 3066: 			for (i = 1; i <= CC_MAXCODE; i++)
 3067: 				ctl_putclock(i, &clock_stat, 0);
 3068: 			for (kv = clock_stat.kv_list; kv &&
 3069: 				 !(kv->flags & EOV); kv++)
 3070: 				if (kv->flags & DEF)
 3071: 					ctl_putdata(kv->text,
 3072: 						    strlen(kv->text), 0);
 3073: 			free_varlist(clock_stat.kv_list);
 3074: 		}
 3075: #endif /* REFCLOCK */
 3076: 	}
 3077: 
 3078: 	/*
 3079: 	 * We're done, return.
 3080: 	 */
 3081: 	ctl_flushpkt(0);
 3082: }
 3083: 
 3084: 
 3085: /*
 3086:  * ctl_clr_stats - clear stat counters
 3087:  */
 3088: void
 3089: ctl_clr_stats(void)
 3090: {
 3091: 	ctltimereset = current_time;
 3092: 	numctlreq = 0;
 3093: 	numctlbadpkts = 0;
 3094: 	numctlresponses = 0;
 3095: 	numctlfrags = 0;
 3096: 	numctlerrors = 0;
 3097: 	numctlfrags = 0;
 3098: 	numctltooshort = 0;
 3099: 	numctlinputresp = 0;
 3100: 	numctlinputfrag = 0;
 3101: 	numctlinputerr = 0;
 3102: 	numctlbadoffset = 0;
 3103: 	numctlbadversion = 0;
 3104: 	numctldatatooshort = 0;
 3105: 	numctlbadop = 0;
 3106: 	numasyncmsgs = 0;
 3107: }
 3108: 
 3109: static u_long
 3110: count_var(
 3111: 	struct ctl_var *k
 3112: 	)
 3113: {
 3114: 	register u_long c;
 3115: 
 3116: 	if (!k)
 3117: 		return (0);
 3118: 
 3119: 	c = 0;
 3120: 	while (!(k++->flags & EOV))
 3121: 		c++;
 3122: 	return (c);
 3123: }
 3124: 
 3125: char *
 3126: add_var(
 3127: 	struct ctl_var **kv,
 3128: 	u_long size,
 3129: 	u_short def
 3130: 	)
 3131: {
 3132: 	register u_long c;
 3133: 	register struct ctl_var *k;
 3134: 
 3135: 	c = count_var(*kv);
 3136: 
 3137: 	k = *kv;
 3138: 	*kv  = (struct ctl_var *)emalloc((c+2)*sizeof(struct ctl_var));
 3139: 	if (k) {
 3140: 		memmove((char *)*kv, (char *)k,
 3141: 			sizeof(struct ctl_var)*c);
 3142: 		free((char *)k);
 3143: 	}
 3144: 	(*kv)[c].code  = (u_short) c;
 3145: 	(*kv)[c].text  = (char *)emalloc(size);
 3146: 	(*kv)[c].flags = def;
 3147: 	(*kv)[c+1].code  = 0;
 3148: 	(*kv)[c+1].text  = (char *)0;
 3149: 	(*kv)[c+1].flags = EOV;
 3150: 	return (char *)(*kv)[c].text;
 3151: }
 3152: 
 3153: void
 3154: set_var(
 3155: 	struct ctl_var **kv,
 3156: 	const char *data,
 3157: 	u_long size,
 3158: 	u_short def
 3159: 	)
 3160: {
 3161: 	register struct ctl_var *k;
 3162: 	register const char *s;
 3163: 	register const char *t;
 3164: 	char *td;
 3165: 
 3166: 	if (!data || !size)
 3167: 		return;
 3168: 
 3169: 	k = *kv;
 3170: 	if (k != NULL) {
 3171: 		while (!(k->flags & EOV)) {
 3172: 			s = data;
 3173: 			t = k->text;
 3174: 			if (t)	{
 3175: 				while (*t != '=' && *s - *t == 0) {
 3176: 					s++;
 3177: 					t++;
 3178: 				}
 3179: 				if (*s == *t && ((*t == '=') || !*t)) {
 3180: 					free((void *)k->text);
 3181: 					td = (char *)emalloc(size);
 3182: 					memmove(td, data, size);
 3183: 					k->text =td;
 3184: 					k->flags = def;
 3185: 					return;
 3186: 				}
 3187: 			} else {
 3188: 				td = (char *)emalloc(size);
 3189: 				memmove(td, data, size);
 3190: 				k->text = td;
 3191: 				k->flags = def;
 3192: 				return;
 3193: 			}
 3194: 			k++;
 3195: 		}
 3196: 	}
 3197: 	td = add_var(kv, size, def);
 3198: 	memmove(td, data, size);
 3199: }
 3200: 
 3201: void
 3202: set_sys_var(
 3203: 	const char *data,
 3204: 	u_long size,
 3205: 	u_short def
 3206: 	)
 3207: {
 3208: 	set_var(&ext_sys_var, data, size, def);
 3209: }
 3210: 
 3211: void
 3212: free_varlist(
 3213: 	struct ctl_var *kv
 3214: 	)
 3215: {
 3216: 	struct ctl_var *k;
 3217: 	if (kv) {
 3218: 		for (k = kv; !(k->flags & EOV); k++)
 3219: 			free((void *)k->text);
 3220: 		free((void *)kv);
 3221: 	}
 3222: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>