Annotation of embedaddon/ntp/ntpd/ntp_control.c, revision 1.1.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>