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