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