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