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