Annotation of embedaddon/ntp/ntpq/ntpq.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * ntpq - query an NTP server using mode 6 commands
                      3:  */
                      4: 
                      5: #include <stdio.h>
                      6: 
                      7: #include <ctype.h>
                      8: #include <signal.h>
                      9: #include <setjmp.h>
                     10: #include <sys/types.h>
                     11: #include <sys/time.h>
                     12: 
                     13: #include "ntpq.h"
                     14: #include "ntp_unixtime.h"
                     15: #include "ntp_calendar.h"
                     16: #include "ntp_io.h"
                     17: #include "ntp_select.h"
                     18: #include "ntp_stdlib.h"
                     19: #include "ntp_assert.h"
                     20: #include "ntp_lineedit.h"
                     21: #include "ntp_debug.h"
                     22: #include "isc/net.h"
                     23: #include "isc/result.h"
                     24: #include <ssl_applink.c>
                     25: 
                     26: #include "ntp_libopts.h"
                     27: #include "ntpq-opts.h"
                     28: 
                     29: #ifdef SYS_WINNT
                     30: # include <Mswsock.h>
                     31: # include <io.h>
                     32: #endif /* SYS_WINNT */
                     33: 
                     34: #ifdef SYS_VXWORKS
                     35:                                /* vxWorks needs mode flag -casey*/
                     36: # define open(name, flags)   open(name, flags, 0777)
                     37: # define SERVER_PORT_NUM     123
                     38: #endif
                     39: 
                     40: /* we use COMMAND as an autogen keyword */
                     41: #ifdef COMMAND
                     42: # undef COMMAND
                     43: #endif
                     44: 
                     45: /*
                     46:  * Because we potentially understand a lot of commands we will run
                     47:  * interactive if connected to a terminal.
                     48:  */
                     49: int interactive = 0;           /* set to 1 when we should prompt */
                     50: const char *prompt = "ntpq> "; /* prompt to ask him about */
                     51: 
                     52: /*
                     53:  * use old readvars behavior?  --old-rv processing in ntpq resets
                     54:  * this value based on the presence or absence of --old-rv.  It is
                     55:  * initialized to 1 here to maintain backward compatibility with
                     56:  * libntpq clients such as ntpsnmpd, which are free to reset it as
                     57:  * desired.
                     58:  */
                     59: int    old_rv = 1;
                     60: 
                     61: 
                     62: /*
                     63:  * for get_systime()
                     64:  */
                     65: s_char sys_precision;          /* local clock precision (log2 s) */
                     66: 
                     67: /*
                     68:  * Keyid used for authenticated requests.  Obtained on the fly.
                     69:  */
                     70: u_long info_auth_keyid = 0;
                     71: 
                     72: static int     info_auth_keytype = NID_md5;    /* MD5 */
                     73: static size_t  info_auth_hashlen = 16;         /* MD5 */
                     74: u_long current_time;           /* needed by authkeys; not used */
                     75: 
                     76: /*
                     77:  * Flag which indicates we should always send authenticated requests
                     78:  */
                     79: int always_auth = 0;
                     80: 
                     81: /*
                     82:  * Flag which indicates raw mode output.
                     83:  */
                     84: int rawmode = 0;
                     85: 
                     86: /*
                     87:  * Packet version number we use
                     88:  */
                     89: u_char pktversion = NTP_OLDVERSION + 1;
                     90: 
                     91: /*
                     92:  * Don't jump if no set jmp.
                     93:  */
                     94: volatile int jump = 0;
                     95: 
                     96: /*
                     97:  * Format values
                     98:  */
                     99: #define        PADDING 0
                    100: #define        TS      1       /* time stamp */
                    101: #define        FL      2       /* l_fp type value */
                    102: #define        FU      3       /* u_fp type value */
                    103: #define        FS      4       /* s_fp type value */
                    104: #define        UI      5       /* unsigned integer value */
                    105: #define        SI      6       /* signed integer value */
                    106: #define        HA      7       /* host address */
                    107: #define        NA      8       /* network address */
                    108: #define        ST      9       /* string value */
                    109: #define        RF      10      /* refid (sometimes string, sometimes not) */
                    110: #define        LP      11      /* leap (print in binary) */
                    111: #define        OC      12      /* integer, print in octal */
                    112: #define        MD      13      /* mode */
                    113: #define        AR      14      /* array of times */
                    114: #define FX     15      /* test flags */
                    115: #define        EOV     255     /* end of table */
                    116: 
                    117: 
                    118: /*
                    119:  * System variable values.  The array can be indexed by
                    120:  * the variable index to find the textual name.
                    121:  */
                    122: struct ctl_var sys_var[] = {
                    123:        { 0,            PADDING, "" },          /* 0 */
                    124:        { CS_LEAP,      LP,     "leap" },       /* 1 */
                    125:        { CS_STRATUM,   UI,     "stratum" },    /* 2 */
                    126:        { CS_PRECISION, SI,     "precision" },  /* 3 */
                    127:        { CS_ROOTDELAY, FS,     "rootdelay" },  /* 4 */
                    128:        { CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */
                    129:        { CS_REFID,     RF,     "refid" },      /* 6 */
                    130:        { CS_REFTIME,   TS,     "reftime" },    /* 7 */
                    131:        { CS_POLL,      UI,     "poll" },       /* 8 */
                    132:        { CS_PEERID,    UI,     "peer" },       /* 9 */
                    133:        { CS_OFFSET,    FL,     "offset" },     /* 10 */
                    134:        { CS_DRIFT,     FS,     "frequency" },  /* 11 */
                    135:        { CS_JITTER,    FU,     "jitter" },     /* 12 */
                    136:        { CS_CLOCK,     TS,     "clock" },      /* 13 */
                    137:        { CS_PROCESSOR, ST,     "processor" },  /* 14 */
                    138:        { CS_SYSTEM,    ST,     "system" },     /* 15 */
                    139:        { CS_VERSION,   ST,     "version" },    /* 16 */
                    140:        { CS_STABIL,    FS,     "stability" },  /* 17 */
                    141:        { CS_VARLIST,   ST,     "sys_var_list" }, /* 18 */
                    142:        { 0,            EOV,    ""      }
                    143: };
                    144: 
                    145: 
                    146: /*
                    147:  * Peer variable list
                    148:  */
                    149: struct ctl_var peer_var[] = {
                    150:        { 0,            PADDING, "" },          /* 0 */
                    151:        { CP_CONFIG,    UI,     "config" },     /* 1 */
                    152:        { CP_AUTHENABLE, UI,    "authenable" }, /* 2 */
                    153:        { CP_AUTHENTIC, UI,     "authentic" },  /* 3 */
                    154:        { CP_SRCADR,    HA,     "srcadr" },     /* 4 */
                    155:        { CP_SRCPORT,   UI,     "srcport" },    /* 5 */
                    156:        { CP_DSTADR,    NA,     "dstadr" },     /* 6 */
                    157:        { CP_DSTPORT,   UI,     "dstport" },    /* 7 */
                    158:        { CP_LEAP,      LP,     "leap" },       /* 8 */
                    159:        { CP_HMODE,     MD,     "hmode" },      /* 9 */
                    160:        { CP_STRATUM,   UI,     "stratum" },    /* 10 */
                    161:        { CP_PPOLL,     UI,     "ppoll" },      /* 11 */
                    162:        { CP_HPOLL,     UI,     "hpoll" },      /* 12 */
                    163:        { CP_PRECISION, SI,     "precision" },  /* 13 */
                    164:        { CP_ROOTDELAY, FS,     "rootdelay" },  /* 14 */
                    165:        { CP_ROOTDISPERSION, FU, "rootdisp" },  /* 15 */
                    166:        { CP_REFID,     RF,     "refid" },      /* 16 */
                    167:        { CP_REFTIME,   TS,     "reftime" },    /* 17 */
                    168:        { CP_ORG,       TS,     "org" },        /* 18 */
                    169:        { CP_REC,       TS,     "rec" },        /* 19 */
                    170:        { CP_XMT,       TS,     "xmt" },        /* 20 */
                    171:        { CP_REACH,     OC,     "reach" },      /* 21 */
                    172:        { CP_UNREACH,   UI,     "unreach" },    /* 22 */
                    173:        { CP_TIMER,     UI,     "timer" },      /* 23 */
                    174:        { CP_DELAY,     FS,     "delay" },      /* 24 */
                    175:        { CP_OFFSET,    FL,     "offset" },     /* 25 */
                    176:        { CP_JITTER,    FU,     "jitter" },     /* 26 */
                    177:        { CP_DISPERSION, FU,    "dispersion" }, /* 27 */
                    178:        { CP_KEYID,     UI,     "keyid" },      /* 28 */
                    179:        { CP_FILTDELAY, AR,     "filtdelay" },  /* 29 */
                    180:        { CP_FILTOFFSET, AR,    "filtoffset" }, /* 30 */
                    181:        { CP_PMODE,     ST,     "pmode" },      /* 31 */
                    182:        { CP_RECEIVED,  UI,     "received" },   /* 32 */
                    183:        { CP_SENT,      UI,     "sent" },       /* 33 */
                    184:        { CP_FILTERROR, AR,     "filtdisp" },   /* 34 */
                    185:        { CP_FLASH,     FX,     "flash" },      /* 35 */ 
                    186:        { CP_TTL,       UI,     "ttl" },        /* 36 */
                    187:        /*
                    188:         * These are duplicate entries so that we can
                    189:         * process deviant version of the ntp protocol.
                    190:         */
                    191:        { CP_SRCADR,    HA,     "peeraddr" },   /* 4 */
                    192:        { CP_SRCPORT,   UI,     "peerport" },   /* 5 */
                    193:        { CP_PPOLL,     UI,     "peerpoll" },   /* 11 */
                    194:        { CP_HPOLL,     UI,     "hostpoll" },   /* 12 */
                    195:        { CP_FILTERROR, AR,     "filterror" },  /* 34 */
                    196:        { 0,            EOV,    ""      }
                    197: };
                    198: 
                    199: 
                    200: /*
                    201:  * Clock variable list
                    202:  */
                    203: struct ctl_var clock_var[] = {
                    204:        { 0,            PADDING, "" },          /* 0 */
                    205:        { CC_TYPE,      UI,     "type" },       /* 1 */
                    206:        { CC_TIMECODE,  ST,     "timecode" },   /* 2 */
                    207:        { CC_POLL,      UI,     "poll" },       /* 3 */
                    208:        { CC_NOREPLY,   UI,     "noreply" },    /* 4 */
                    209:        { CC_BADFORMAT, UI,     "badformat" },  /* 5 */
                    210:        { CC_BADDATA,   UI,     "baddata" },    /* 6 */
                    211:        { CC_FUDGETIME1, FL,    "fudgetime1" }, /* 7 */
                    212:        { CC_FUDGETIME2, FL,    "fudgetime2" }, /* 8 */
                    213:        { CC_FUDGEVAL1, UI,     "stratum" },    /* 9 */
                    214:        { CC_FUDGEVAL2, RF,     "refid" },      /* 10 */
                    215:        { CC_FLAGS,     UI,     "flags" },      /* 11 */
                    216:        { CC_DEVICE,    ST,     "device" },     /* 12 */
                    217:        { 0,            EOV,    ""      }
                    218: };
                    219: 
                    220: 
                    221: /*
                    222:  * flasher bits
                    223:  */
                    224: static const char *tstflagnames[] = {
                    225:        "pkt_dup",              /* TEST1 */
                    226:        "pkt_bogus",            /* TEST2 */
                    227:        "pkt_unsync",           /* TEST3 */
                    228:        "pkt_denied",           /* TEST4 */
                    229:        "pkt_auth",             /* TEST5 */
                    230:        "pkt_stratum",          /* TEST6 */
                    231:        "pkt_header",           /* TEST7 */
                    232:        "pkt_autokey",          /* TEST8 */
                    233:        "pkt_crypto",           /* TEST9 */
                    234:        "peer_stratum",         /* TEST10 */
                    235:        "peer_dist",            /* TEST11 */
                    236:        "peer_loop",            /* TEST12 */
                    237:        "peer_unreach"          /* TEST13 */
                    238: };
                    239: 
                    240: 
                    241: int            ntpqmain        (int,   char **);
                    242: /*
                    243:  * Built in command handler declarations
                    244:  */
                    245: static int     openhost        (const char *);
                    246: 
                    247: static int     sendpkt         (void *, size_t);
                    248: static int     getresponse     (int, int, u_short *, int *, const char **, int);
                    249: static int     sendrequest     (int, int, int, int, char *);
                    250: static char *  tstflags        (u_long);
                    251: #ifndef BUILD_AS_LIB
                    252: static void    getcmds         (void);
                    253: #ifndef SYS_WINNT
                    254: static RETSIGTYPE abortcmd     (int);
                    255: #endif /* SYS_WINNT */
                    256: static void    docmd           (const char *);
                    257: static void    tokenize        (const char *, char **, int *);
                    258: static int     getarg          (char *, int, arg_v *);
                    259: #endif /* BUILD_AS_LIB */
                    260: static int     findcmd         (char *, struct xcmd *, struct xcmd *, struct xcmd **);
                    261: static int     rtdatetolfp     (char *, l_fp *);
                    262: static int     decodearr       (char *, int *, l_fp *);
                    263: static void    help            (struct parse *, FILE *);
                    264: static int     helpsort        (const void *, const void *);
                    265: static void    printusage      (struct xcmd *, FILE *);
                    266: static void    timeout         (struct parse *, FILE *);
                    267: static void    auth_delay      (struct parse *, FILE *);
                    268: static void    host            (struct parse *, FILE *);
                    269: static void    ntp_poll        (struct parse *, FILE *);
                    270: static void    keyid           (struct parse *, FILE *);
                    271: static void    keytype         (struct parse *, FILE *);
                    272: static void    passwd          (struct parse *, FILE *);
                    273: static void    hostnames       (struct parse *, FILE *);
                    274: static void    setdebug        (struct parse *, FILE *);
                    275: static void    quit            (struct parse *, FILE *);
                    276: static void    version         (struct parse *, FILE *);
                    277: static void    raw             (struct parse *, FILE *);
                    278: static void    cooked          (struct parse *, FILE *);
                    279: static void    authenticate    (struct parse *, FILE *);
                    280: static void    ntpversion      (struct parse *, FILE *);
                    281: static void    warning         (const char *, const char *, const char *);
                    282: static void    error           (const char *, const char *, const char *);
                    283: static u_long  getkeyid        (const char *);
                    284: static void    atoascii        (const char *, size_t, char *, size_t);
                    285: static void    cookedprint     (int, int, const char *, int, int, FILE *);
                    286: static void    rawprint        (int, int, const char *, int, int, FILE *);
                    287: static void    startoutput     (void);
                    288: static void    output          (FILE *, char *, char *);
                    289: static void    endoutput       (FILE *);
                    290: static void    outputarr       (FILE *, char *, int, l_fp *);
                    291: static int     assoccmp        (const void *, const void *);
                    292: void   ntpq_custom_opt_handler (tOptions *, tOptDesc *);
                    293: 
                    294: 
                    295: /*
                    296:  * Built-in commands we understand
                    297:  */
                    298: struct xcmd builtins[] = {
                    299:        { "?",          help,           {  OPT|NTP_STR, NO, NO, NO },
                    300:          { "command", "", "", "" },
                    301:          "tell the use and syntax of commands" },
                    302:        { "help",       help,           {  OPT|NTP_STR, NO, NO, NO },
                    303:          { "command", "", "", "" },
                    304:          "tell the use and syntax of commands" },
                    305:        { "timeout",    timeout,        { OPT|NTP_UINT, NO, NO, NO },
                    306:          { "msec", "", "", "" },
                    307:          "set the primary receive time out" },
                    308:        { "delay",      auth_delay,     { OPT|NTP_INT, NO, NO, NO },
                    309:          { "msec", "", "", "" },
                    310:          "set the delay added to encryption time stamps" },
                    311:        { "host",       host,           { OPT|NTP_STR, OPT|NTP_STR, NO, NO },
                    312:          { "-4|-6", "hostname", "", "" },
                    313:          "specify the host whose NTP server we talk to" },
                    314:        { "poll",       ntp_poll,       { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
                    315:          { "n", "verbose", "", "" },
                    316:          "poll an NTP server in client mode `n' times" },
                    317:        { "passwd",     passwd,         { NO, NO, NO, NO },
                    318:          { "", "", "", "" },
                    319:          "specify a password to use for authenticated requests"},
                    320:        { "hostnames",  hostnames,      { OPT|NTP_STR, NO, NO, NO },
                    321:          { "yes|no", "", "", "" },
                    322:          "specify whether hostnames or net numbers are printed"},
                    323:        { "debug",      setdebug,       { OPT|NTP_STR, NO, NO, NO },
                    324:          { "no|more|less", "", "", "" },
                    325:          "set/change debugging level" },
                    326:        { "quit",       quit,           { NO, NO, NO, NO },
                    327:          { "", "", "", "" },
                    328:          "exit ntpq" },
                    329:        { "exit",       quit,           { NO, NO, NO, NO },
                    330:          { "", "", "", "" },
                    331:          "exit ntpq" },
                    332:        { "keyid",      keyid,          { OPT|NTP_UINT, NO, NO, NO },
                    333:          { "key#", "", "", "" },
                    334:          "set keyid to use for authenticated requests" },
                    335:        { "version",    version,        { NO, NO, NO, NO },
                    336:          { "", "", "", "" },
                    337:          "print version number" },
                    338:        { "raw",        raw,            { NO, NO, NO, NO },
                    339:          { "", "", "", "" },
                    340:          "do raw mode variable output" },
                    341:        { "cooked",     cooked,         { NO, NO, NO, NO },
                    342:          { "", "", "", "" },
                    343:          "do cooked mode variable output" },
                    344:        { "authenticate", authenticate, { OPT|NTP_STR, NO, NO, NO },
                    345:          { "yes|no", "", "", "" },
                    346:          "always authenticate requests to this server" },
                    347:        { "ntpversion", ntpversion,     { OPT|NTP_UINT, NO, NO, NO },
                    348:          { "version number", "", "", "" },
                    349:          "set the NTP version number to use for requests" },
                    350:        { "keytype",    keytype,        { OPT|NTP_STR, NO, NO, NO },
                    351:          { "key type (md5|des)", "", "", "" },
                    352:          "set key type to use for authenticated requests (des|md5)" },
                    353:        { 0,            0,              { NO, NO, NO, NO },
                    354:          { "", "", "", "" }, "" }
                    355: };
                    356: 
                    357: 
                    358: /*
                    359:  * Default values we use.
                    360:  */
                    361: #define        DEFHOST         "localhost"     /* default host name */
                    362: #define        DEFTIMEOUT      (5)             /* 5 second time out */
                    363: #define        DEFSTIMEOUT     (2)             /* 2 second time out after first */
                    364: #define        DEFDELAY        0x51EB852       /* 20 milliseconds, l_fp fraction */
                    365: #define        LENHOSTNAME     256             /* host name is 256 characters long */
                    366: #define        MAXCMDS         100             /* maximum commands on cmd line */
                    367: #define        MAXHOSTS        200             /* maximum hosts on cmd line */
                    368: #define        MAXLINE         512             /* maximum line length */
                    369: #define        MAXTOKENS       (1+MAXARGS+2)   /* maximum number of usable tokens */
                    370: #define        MAXVARLEN       256             /* maximum length of a variable name */
                    371: #define        MAXVALLEN       400             /* maximum length of a variable value */
                    372: #define        MAXOUTLINE      72              /* maximum length of an output line */
                    373: #define SCREENWIDTH    76              /* nominal screen width in columns */
                    374: 
                    375: /*
                    376:  * Some variables used and manipulated locally
                    377:  */
                    378: struct sock_timeval tvout = { DEFTIMEOUT, 0 }; /* time out for reads */
                    379: struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
                    380: l_fp delay_time;                               /* delay time */
                    381: char currenthost[LENHOSTNAME];                 /* current host name */
                    382: int currenthostisnum;                          /* is prior text from IP? */
                    383: struct sockaddr_in hostaddr = { 0 };           /* host address */
                    384: int showhostnames = 1;                         /* show host names by default */
                    385: 
                    386: int ai_fam_templ;                              /* address family */
                    387: int ai_fam_default;                            /* default address family */
                    388: SOCKET sockfd;                                 /* fd socket is opened on */
                    389: int havehost = 0;                              /* set to 1 when host open */
                    390: int s_port = 0;
                    391: struct servent *server_entry = NULL;           /* server entry for ntp */
                    392: 
                    393: 
                    394: /*
                    395:  * Sequence number used for requests.  It is incremented before
                    396:  * it is used.
                    397:  */
                    398: u_short sequence;
                    399: 
                    400: /*
                    401:  * Holds data returned from queries.  Declare buffer long to be sure of
                    402:  * alignment.
                    403:  */
                    404: #define        MAXFRAGS        24              /* maximum number of fragments */
                    405: #define        DATASIZE        (MAXFRAGS*480)  /* maximum amount of data */
                    406: long pktdata[DATASIZE/sizeof(long)];
                    407: 
                    408: /*
                    409:  * Holds association data for use with the &n operator.
                    410:  */
                    411: struct association assoc_cache[MAXASSOC];
                    412: int numassoc = 0;              /* number of cached associations */
                    413: 
                    414: /*
                    415:  * For commands typed on the command line (with the -c option)
                    416:  */
                    417: int numcmds = 0;
                    418: const char *ccmds[MAXCMDS];
                    419: #define        ADDCMD(cp)      if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
                    420: 
                    421: /*
                    422:  * When multiple hosts are specified.
                    423:  */
                    424: int numhosts = 0;
                    425: const char *chosts[MAXHOSTS];
                    426: #define        ADDHOST(cp)     if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
                    427: 
                    428: /*
                    429:  * Error codes for internal use
                    430:  */
                    431: #define        ERR_UNSPEC              256
                    432: #define        ERR_INCOMPLETE  257
                    433: #define        ERR_TIMEOUT             258
                    434: #define        ERR_TOOMUCH             259
                    435: 
                    436: /*
                    437:  * Macro definitions we use
                    438:  */
                    439: #define        ISSPACE(c)      ((c) == ' ' || (c) == '\t')
                    440: #define        ISEOL(c)        ((c) == '\n' || (c) == '\r' || (c) == '\0')
                    441: #define        STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
                    442: 
                    443: /*
                    444:  * Jump buffer for longjumping back to the command level
                    445:  */
                    446: jmp_buf interrupt_buf;
                    447: 
                    448: /*
                    449:  * Points at file being currently printed into
                    450:  */
                    451: FILE *current_output;
                    452: 
                    453: /*
                    454:  * Command table imported from ntpdc_ops.c
                    455:  */
                    456: extern struct xcmd opcmds[];
                    457: 
                    458: char *progname;
                    459: volatile int debug;
                    460: 
                    461: #ifdef NO_MAIN_ALLOWED
                    462: #ifndef BUILD_AS_LIB
                    463: CALL(ntpq,"ntpq",ntpqmain);
                    464: 
                    465: void clear_globals(void)
                    466: {
                    467:        extern int ntp_optind;
                    468:        showhostnames = 0;      /* don'tshow host names by default */
                    469:        ntp_optind = 0;
                    470:        server_entry = NULL;    /* server entry for ntp */
                    471:        havehost = 0;           /* set to 1 when host open */
                    472:        numassoc = 0;           /* number of cached associations */
                    473:        numcmds = 0;
                    474:        numhosts = 0;
                    475: }
                    476: #endif /* !BUILD_AS_LIB */
                    477: #endif /* NO_MAIN_ALLOWED */
                    478: 
                    479: /*
                    480:  * main - parse arguments and handle options
                    481:  */
                    482: #ifndef NO_MAIN_ALLOWED
                    483: int
                    484: main(
                    485:        int argc,
                    486:        char *argv[]
                    487:        )
                    488: {
                    489:        return ntpqmain(argc, argv);
                    490: }
                    491: #endif
                    492: 
                    493: #ifndef BUILD_AS_LIB
                    494: int
                    495: ntpqmain(
                    496:        int argc,
                    497:        char *argv[]
                    498:        )
                    499: {
                    500:        extern int ntp_optind;
                    501: 
                    502: #ifdef SYS_VXWORKS
                    503:        clear_globals();
                    504:        taskPrioritySet(taskIdSelf(), 100 );
                    505: #endif
                    506: 
                    507:        delay_time.l_ui = 0;
                    508:        delay_time.l_uf = DEFDELAY;
                    509: 
                    510:        init_lib();     /* sets up ipv4_works, ipv6_works */
                    511:        ssl_applink();
                    512: 
                    513:        /* Check to see if we have IPv6. Otherwise default to IPv4 */
                    514:        if (!ipv6_works)
                    515:                ai_fam_default = AF_INET;
                    516: 
                    517:        progname = argv[0];
                    518: 
                    519:        {
                    520:                int optct = ntpOptionProcess(&ntpqOptions, argc, argv);
                    521:                argc -= optct;
                    522:                argv += optct;
                    523:        }
                    524: 
                    525:        /*
                    526:         * Process options other than -c and -p, which are specially
                    527:         * handled by ntpq_custom_opt_handler().
                    528:         */
                    529: 
                    530:        debug = DESC(DEBUG_LEVEL).optOccCt;
                    531: 
                    532:        if (HAVE_OPT(IPV4))
                    533:                ai_fam_templ = AF_INET;
                    534:        else if (HAVE_OPT(IPV6))
                    535:                ai_fam_templ = AF_INET6;
                    536:        else
                    537:                ai_fam_templ = ai_fam_default;
                    538: 
                    539:        if (HAVE_OPT(INTERACTIVE))
                    540:                interactive = 1;
                    541: 
                    542:        if (HAVE_OPT(NUMERIC))
                    543:                showhostnames = 0;
                    544: 
                    545:        old_rv = HAVE_OPT(OLD_RV);
                    546: 
                    547: #if 0
                    548:        while ((c = ntp_getopt(argc, argv, "46c:dinp")) != EOF)
                    549:            switch (c) {
                    550:                case '4':
                    551:                    ai_fam_templ = AF_INET;
                    552:                    break;
                    553:                case '6':
                    554:                    ai_fam_templ = AF_INET6;
                    555:                    break;
                    556:                case 'c':
                    557:                    ADDCMD(ntp_optarg);
                    558:                    break;
                    559:                case 'd':
                    560:                    ++debug;
                    561:                    break;
                    562:                case 'i':
                    563:                    interactive = 1;
                    564:                    break;
                    565:                case 'n':
                    566:                    showhostnames = 0;
                    567:                    break;
                    568:                case 'p':
                    569:                    ADDCMD("peers");
                    570:                    break;
                    571:                default:
                    572:                    errflg++;
                    573:                    break;
                    574:            }
                    575:        if (errflg) {
                    576:                (void) fprintf(stderr,
                    577:                               "usage: %s [-46dinp] [-c cmd] host ...\n",
                    578:                               progname);
                    579:                exit(2);
                    580:        }
                    581: #endif
                    582:        NTP_INSIST(ntp_optind <= argc);
                    583:        if (ntp_optind == argc) {
                    584:                ADDHOST(DEFHOST);
                    585:        } else {
                    586:                for (; ntp_optind < argc; ntp_optind++)
                    587:                        ADDHOST(argv[ntp_optind]);
                    588:        }
                    589: 
                    590:        if (numcmds == 0 && interactive == 0
                    591:            && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
                    592:                interactive = 1;
                    593:        }
                    594: 
                    595: #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
                    596:        if (interactive)
                    597:            (void) signal_no_reset(SIGINT, abortcmd);
                    598: #endif /* SYS_WINNT */
                    599: 
                    600:        if (numcmds == 0) {
                    601:                (void) openhost(chosts[0]);
                    602:                getcmds();
                    603:        } else {
                    604:                int ihost;
                    605:                int icmd;
                    606: 
                    607:                for (ihost = 0; ihost < numhosts; ihost++) {
                    608:                        if (openhost(chosts[ihost]))
                    609:                                for (icmd = 0; icmd < numcmds; icmd++)
                    610:                                        docmd(ccmds[icmd]);
                    611:                }
                    612:        }
                    613: #ifdef SYS_WINNT
                    614:        WSACleanup();
                    615: #endif /* SYS_WINNT */
                    616:        return 0;
                    617: }
                    618: #endif /* !BUILD_AS_LIB */
                    619: 
                    620: /*
                    621:  * openhost - open a socket to a host
                    622:  */
                    623: static int
                    624: openhost(
                    625:        const char *hname
                    626:        )
                    627: {
                    628:        char temphost[LENHOSTNAME];
                    629:        int a_info, i;
                    630:        struct addrinfo hints, *ai = NULL;
                    631:        register const char *cp;
                    632:        char name[LENHOSTNAME];
                    633:        char service[5];
                    634: 
                    635:        /*
                    636:         * We need to get by the [] if they were entered
                    637:         */
                    638:        
                    639:        cp = hname;
                    640:        
                    641:        if (*cp == '[') {
                    642:                cp++;
                    643:                for (i = 0; *cp && *cp != ']'; cp++, i++)
                    644:                        name[i] = *cp;
                    645:                if (*cp == ']') {
                    646:                        name[i] = '\0';
                    647:                        hname = name;
                    648:                } else {
                    649:                        return 0;
                    650:                }
                    651:        }
                    652: 
                    653:        /*
                    654:         * First try to resolve it as an ip address and if that fails,
                    655:         * do a fullblown (dns) lookup. That way we only use the dns
                    656:         * when it is needed and work around some implementations that
                    657:         * will return an "IPv4-mapped IPv6 address" address if you
                    658:         * give it an IPv4 address to lookup.
                    659:         */
                    660:        strcpy(service, "ntp");
                    661:        ZERO(hints);
                    662:        hints.ai_family = ai_fam_templ;
                    663:        hints.ai_protocol = IPPROTO_UDP;
                    664:        hints.ai_socktype = SOCK_DGRAM;
                    665:        hints.ai_flags = Z_AI_NUMERICHOST;
                    666: 
                    667:        a_info = getaddrinfo(hname, service, &hints, &ai);
                    668:        if (a_info == EAI_NONAME
                    669: #ifdef EAI_NODATA
                    670:            || a_info == EAI_NODATA
                    671: #endif
                    672:           ) {
                    673:                hints.ai_flags = AI_CANONNAME;
                    674: #ifdef AI_ADDRCONFIG
                    675:                hints.ai_flags |= AI_ADDRCONFIG;
                    676: #endif
                    677:                a_info = getaddrinfo(hname, service, &hints, &ai);      
                    678:        }
                    679: #ifdef AI_ADDRCONFIG
                    680:        /* Some older implementations don't like AI_ADDRCONFIG. */
                    681:        if (a_info == EAI_BADFLAGS) {
                    682:                hints.ai_flags = AI_CANONNAME;
                    683:                a_info = getaddrinfo(hname, service, &hints, &ai);      
                    684:        }
                    685: #endif
                    686:        if (a_info != 0) {
                    687:                (void) fprintf(stderr, "%s\n", gai_strerror(a_info));
                    688:                return 0;
                    689:        }
                    690: 
                    691:        if (!showhostnames || ai->ai_canonname == NULL) {
                    692:                strncpy(temphost, 
                    693:                        stoa((sockaddr_u *)ai->ai_addr),
                    694:                        LENHOSTNAME);
                    695:                currenthostisnum = TRUE;
                    696:        } else {
                    697:                strncpy(temphost, ai->ai_canonname, LENHOSTNAME);
                    698:                currenthostisnum = FALSE;
                    699:        }
                    700:        temphost[LENHOSTNAME-1] = '\0';
                    701: 
                    702:        if (debug > 2)
                    703:                printf("Opening host %s\n", temphost);
                    704: 
                    705:        if (havehost == 1) {
                    706:                if (debug > 2)
                    707:                        printf("Closing old host %s\n", currenthost);
                    708:                (void) closesocket(sockfd);
                    709:                havehost = 0;
                    710:        }
                    711:        (void) strcpy(currenthost, temphost);
                    712: 
                    713:        /* port maps to the same location in both families */
                    714:        s_port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port;
                    715: #ifdef SYS_VXWORKS
                    716:        ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
                    717:        if (ai->ai_family == AF_INET)
                    718:                *(struct sockaddr_in *)&hostaddr=
                    719:                        *((struct sockaddr_in *)ai->ai_addr);
                    720:        else
                    721:                *(struct sockaddr_in6 *)&hostaddr=
                    722:                        *((struct sockaddr_in6 *)ai->ai_addr);
                    723: #endif /* SYS_VXWORKS */
                    724: 
                    725: #ifdef SYS_WINNT
                    726:        {
                    727:                int optionValue = SO_SYNCHRONOUS_NONALERT;
                    728:                int err;
                    729: 
                    730:                err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
                    731:                                 (char *)&optionValue, sizeof(optionValue));
                    732:                if (err) {
                    733:                        err = WSAGetLastError();
                    734:                        fprintf(stderr,
                    735:                                "setsockopt(SO_SYNCHRONOUS_NONALERT) "
                    736:                                "error: %s\n", strerror(err));
                    737:                        exit(1);
                    738:                }
                    739:        }
                    740: #endif /* SYS_WINNT */
                    741: 
                    742:        sockfd = socket(ai->ai_family, SOCK_DGRAM, 0);
                    743:        if (sockfd == INVALID_SOCKET) {
                    744:                error("socket", "", "");
                    745:        }
                    746: 
                    747:        
                    748: #ifdef NEED_RCVBUF_SLOP
                    749: # ifdef SO_RCVBUF
                    750:        { int rbufsize = DATASIZE + 2048;       /* 2K for slop */
                    751:        if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
                    752:                       &rbufsize, sizeof(int)) == -1)
                    753:            error("setsockopt", "", "");
                    754:        }
                    755: # endif
                    756: #endif
                    757: 
                    758: #ifdef SYS_VXWORKS
                    759:        if (connect(sockfd, (struct sockaddr *)&hostaddr,
                    760:                    sizeof(hostaddr)) == -1)
                    761: #else
                    762:        if (connect(sockfd, (struct sockaddr *)ai->ai_addr,
                    763:                    ai->ai_addrlen) == -1)
                    764: #endif /* SYS_VXWORKS */
                    765:            error("connect", "", "");
                    766:        if (a_info == 0)
                    767:                freeaddrinfo(ai);
                    768:        havehost = 1;
                    769:        return 1;
                    770: }
                    771: 
                    772: 
                    773: /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
                    774: /*
                    775:  * sendpkt - send a packet to the remote host
                    776:  */
                    777: static int
                    778: sendpkt(
                    779:        void *  xdata,
                    780:        size_t  xdatalen
                    781:        )
                    782: {
                    783:        if (debug >= 3)
                    784:                printf("Sending %lu octets\n", (u_long)xdatalen);
                    785: 
                    786:        if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
                    787:                warning("write to %s failed", currenthost, "");
                    788:                return -1;
                    789:        }
                    790: 
                    791:        if (debug >= 4) {
                    792:                int first = 8;
                    793:                char *cdata = xdata;
                    794: 
                    795:                printf("Packet data:\n");
                    796:                while (xdatalen-- > 0) {
                    797:                        if (first-- == 0) {
                    798:                                printf("\n");
                    799:                                first = 7;
                    800:                        }
                    801:                        printf(" %02x", *cdata++ & 0xff);
                    802:                }
                    803:                printf("\n");
                    804:        }
                    805:        return 0;
                    806: }
                    807: 
                    808: 
                    809: 
                    810: /*
                    811:  * getresponse - get a (series of) response packet(s) and return the data
                    812:  */
                    813: static int
                    814: getresponse(
                    815:        int opcode,
                    816:        int associd,
                    817:        u_short *rstatus,
                    818:        int *rsize,
                    819:        const char **rdata,
                    820:        int timeo
                    821:        )
                    822: {
                    823:        struct ntp_control rpkt;
                    824:        struct sock_timeval tvo;
                    825:        u_short offsets[MAXFRAGS+1];
                    826:        u_short counts[MAXFRAGS+1];
                    827:        u_short offset;
                    828:        u_short count;
                    829:        size_t numfrags;
                    830:        size_t f;
                    831:        size_t ff;
                    832:        int seenlastfrag;
                    833:        int shouldbesize;
                    834:        fd_set fds;
                    835:        int n;
                    836:        int len;
                    837:        int first;
                    838:        char *data;
                    839: 
                    840:        /*
                    841:         * This is pretty tricky.  We may get between 1 and MAXFRAG packets
                    842:         * back in response to the request.  We peel the data out of
                    843:         * each packet and collect it in one long block.  When the last
                    844:         * packet in the sequence is received we'll know how much data we
                    845:         * should have had.  Note we use one long time out, should reconsider.
                    846:         */
                    847:        *rsize = 0;
                    848:        if (rstatus)
                    849:                *rstatus = 0;
                    850:        *rdata = (char *)pktdata;
                    851: 
                    852:        numfrags = 0;
                    853:        seenlastfrag = 0;
                    854: 
                    855:        FD_ZERO(&fds);
                    856: 
                    857:        /*
                    858:         * Loop until we have an error or a complete response.  Nearly all
                    859:         * code paths to loop again use continue.
                    860:         */
                    861:        for (;;) {
                    862: 
                    863:                if (numfrags == 0)
                    864:                        tvo = tvout;
                    865:                else
                    866:                        tvo = tvsout;
                    867:                
                    868:                FD_SET(sockfd, &fds);
                    869:                n = select(sockfd + 1, &fds, NULL, NULL, &tvo);
                    870: 
                    871:                if (n == -1) {
                    872:                        warning("select fails", "", "");
                    873:                        return -1;
                    874:                }
                    875:                if (n == 0) {
                    876:                        /*
                    877:                         * Timed out.  Return what we have
                    878:                         */
                    879:                        if (numfrags == 0) {
                    880:                                if (timeo)
                    881:                                        fprintf(stderr,
                    882:                                                "%s: timed out, nothing received\n",
                    883:                                                currenthost);
                    884:                                return ERR_TIMEOUT;
                    885:                        }
                    886:                        if (timeo)
                    887:                                fprintf(stderr,
                    888:                                        "%s: timed out with incomplete data\n",
                    889:                                        currenthost);
                    890:                        if (debug) {
                    891:                                fprintf(stderr,
                    892:                                        "ERR_INCOMPLETE: Received fragments:\n");
                    893:                                for (f = 0; f < numfrags; f++)
                    894:                                        fprintf(stderr,
                    895:                                                "%2u: %5d %5d\t%3d octets\n",
                    896:                                                f, offsets[f],
                    897:                                                offsets[f] +
                    898:                                                counts[f],
                    899:                                                counts[f]);
                    900:                                fprintf(stderr,
                    901:                                        "last fragment %sreceived\n",
                    902:                                        (seenlastfrag)
                    903:                                            ? ""
                    904:                                            : "not ");
                    905:                        }
                    906:                        return ERR_INCOMPLETE;
                    907:                }
                    908: 
                    909:                n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
                    910:                if (n == -1) {
                    911:                        warning("read", "", "");
                    912:                        return -1;
                    913:                }
                    914: 
                    915:                if (debug >= 4) {
                    916:                        len = n;
                    917:                        first = 8;
                    918:                        data = (char *)&rpkt;
                    919: 
                    920:                        printf("Packet data:\n");
                    921:                        while (len-- > 0) {
                    922:                                if (first-- == 0) {
                    923:                                        printf("\n");
                    924:                                        first = 7;
                    925:                                }
                    926:                                printf(" %02x", *data++ & 0xff);
                    927:                        }
                    928:                        printf("\n");
                    929:                }
                    930: 
                    931:                /*
                    932:                 * Check for format errors.  Bug proofing.
                    933:                 */
                    934:                if (n < CTL_HEADER_LEN) {
                    935:                        if (debug)
                    936:                                printf("Short (%d byte) packet received\n", n);
                    937:                        continue;
                    938:                }
                    939:                if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
                    940:                    || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
                    941:                        if (debug)
                    942:                                printf("Packet received with version %d\n",
                    943:                                       PKT_VERSION(rpkt.li_vn_mode));
                    944:                        continue;
                    945:                }
                    946:                if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
                    947:                        if (debug)
                    948:                                printf("Packet received with mode %d\n",
                    949:                                       PKT_MODE(rpkt.li_vn_mode));
                    950:                        continue;
                    951:                }
                    952:                if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
                    953:                        if (debug)
                    954:                                printf("Received request packet, wanted response\n");
                    955:                        continue;
                    956:                }
                    957: 
                    958:                /*
                    959:                 * Check opcode and sequence number for a match.
                    960:                 * Could be old data getting to us.
                    961:                 */
                    962:                if (ntohs(rpkt.sequence) != sequence) {
                    963:                        if (debug)
                    964:                                printf("Received sequnce number %d, wanted %d\n",
                    965:                                       ntohs(rpkt.sequence), sequence);
                    966:                        continue;
                    967:                }
                    968:                if (CTL_OP(rpkt.r_m_e_op) != opcode) {
                    969:                        if (debug)
                    970:                            printf(
                    971:                                    "Received opcode %d, wanted %d (sequence number okay)\n",
                    972:                                    CTL_OP(rpkt.r_m_e_op), opcode);
                    973:                        continue;
                    974:                }
                    975: 
                    976:                /*
                    977:                 * Check the error code.  If non-zero, return it.
                    978:                 */
                    979:                if (CTL_ISERROR(rpkt.r_m_e_op)) {
                    980:                        int errcode;
                    981: 
                    982:                        errcode = (ntohs(rpkt.status) >> 8) & 0xff;
                    983:                        if (debug && CTL_ISMORE(rpkt.r_m_e_op)) {
                    984:                                printf("Error code %d received on not-final packet\n",
                    985:                                       errcode);
                    986:                        }
                    987:                        if (errcode == CERR_UNSPEC)
                    988:                            return ERR_UNSPEC;
                    989:                        return errcode;
                    990:                }
                    991: 
                    992:                /*
                    993:                 * Check the association ID to make sure it matches what
                    994:                 * we sent.
                    995:                 */
                    996:                if (ntohs(rpkt.associd) != associd) {
                    997:                        if (debug)
                    998:                            printf("Association ID %d doesn't match expected %d\n",
                    999:                                   ntohs(rpkt.associd), associd);
                   1000:                        /*
                   1001:                         * Hack for silly fuzzballs which, at the time of writing,
                   1002:                         * return an assID of sys.peer when queried for system variables.
                   1003:                         */
                   1004: #ifdef notdef
                   1005:                        continue;
                   1006: #endif
                   1007:                }
                   1008: 
                   1009:                /*
                   1010:                 * Collect offset and count.  Make sure they make sense.
                   1011:                 */
                   1012:                offset = ntohs(rpkt.offset);
                   1013:                count = ntohs(rpkt.count);
                   1014: 
                   1015:                /*
                   1016:                 * validate received payload size is padded to next 32-bit
                   1017:                 * boundary and no smaller than claimed by rpkt.count
                   1018:                 */
                   1019:                if (n & 0x3) {
                   1020:                        if (debug)
                   1021:                                printf("Response packet not padded, "
                   1022:                                        "size = %d\n", n);
                   1023:                        continue;
                   1024:                }
                   1025: 
                   1026:                shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3;
                   1027: 
                   1028:                if (n < shouldbesize) {
                   1029:                        printf("Response packet claims %u octets "
                   1030:                                "payload, above %d received\n",
                   1031:                                count,
                   1032:                                n - CTL_HEADER_LEN
                   1033:                                );
                   1034:                        return ERR_INCOMPLETE;
                   1035:                }
                   1036: 
                   1037:                if (debug >= 3 && shouldbesize > n) {
                   1038:                        u_int32 key;
                   1039:                        u_int32 *lpkt;
                   1040:                        int maclen;
                   1041: 
                   1042:                        /*
                   1043:                         * Usually we ignore authentication, but for debugging purposes
                   1044:                         * we watch it here.
                   1045:                         */
                   1046:                        /* round to 8 octet boundary */
                   1047:                        shouldbesize = (shouldbesize + 7) & ~7;
                   1048: 
                   1049:                        maclen = n - shouldbesize;
                   1050:                        if (maclen >= MIN_MAC_LEN) {
                   1051:                                printf(
                   1052:                                        "Packet shows signs of authentication (total %d, data %d, mac %d)\n",
                   1053:                                        n, shouldbesize, maclen);
                   1054:                                lpkt = (u_int32 *)&rpkt;
                   1055:                                printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
                   1056:                                       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]),
                   1057:                                       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]),
                   1058:                                       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]),
                   1059:                                       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]),
                   1060:                                       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]),
                   1061:                                       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2]));
                   1062:                                key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]);
                   1063:                                printf("Authenticated with keyid %lu\n", (u_long)key);
                   1064:                                if (key != 0 && key != info_auth_keyid) {
                   1065:                                        printf("We don't know that key\n");
                   1066:                                } else {
                   1067:                                        if (authdecrypt(key, (u_int32 *)&rpkt,
                   1068:                                            n - maclen, maclen)) {
                   1069:                                                printf("Auth okay!\n");
                   1070:                                        } else {
                   1071:                                                printf("Auth failed!\n");
                   1072:                                        }
                   1073:                                }
                   1074:                        }
                   1075:                }
                   1076: 
                   1077:                if (debug >= 2)
                   1078:                        printf("Got packet, size = %d\n", n);
                   1079:                if ((int)count > (n - CTL_HEADER_LEN)) {
                   1080:                        if (debug)
                   1081:                                printf("Received count of %d octets, "
                   1082:                                        "data in packet is %d\n",
                   1083:                                        count, n-CTL_HEADER_LEN);
                   1084:                        continue;
                   1085:                }
                   1086:                if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
                   1087:                        if (debug)
                   1088:                                printf("Received count of 0 in non-final fragment\n");
                   1089:                        continue;
                   1090:                }
                   1091:                if (offset + count > sizeof(pktdata)) {
                   1092:                        if (debug)
                   1093:                                printf("Offset %d, count %d, too big for buffer\n",
                   1094:                                       offset, count);
                   1095:                        return ERR_TOOMUCH;
                   1096:                }
                   1097:                if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
                   1098:                        if (debug)
                   1099:                                printf("Received second last fragment packet\n");
                   1100:                        continue;
                   1101:                }
                   1102: 
                   1103:                /*
                   1104:                 * So far, so good.  Record this fragment, making sure it doesn't
                   1105:                 * overlap anything.
                   1106:                 */
                   1107:                if (debug >= 2)
                   1108:                        printf("Packet okay\n");;
                   1109: 
                   1110:                if (numfrags > (MAXFRAGS - 1)) {
                   1111:                        if (debug)
                   1112:                                printf("Number of fragments exceeds maximum %d\n",
                   1113:                                       MAXFRAGS - 1);
                   1114:                        return ERR_TOOMUCH;
                   1115:                }
                   1116: 
                   1117:                /*
                   1118:                 * Find the position for the fragment relative to any
                   1119:                 * previously received.
                   1120:                 */
                   1121:                for (f = 0; 
                   1122:                     f < numfrags && offsets[f] < offset; 
                   1123:                     f++) {
                   1124:                        /* empty body */ ;
                   1125:                }
                   1126: 
                   1127:                if (f < numfrags && offset == offsets[f]) {
                   1128:                        if (debug)
                   1129:                                printf("duplicate %u octets at %u ignored, prior %u at %u\n",
                   1130:                                       count, offset, counts[f],
                   1131:                                       offsets[f]);
                   1132:                        continue;
                   1133:                }
                   1134: 
                   1135:                if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) {
                   1136:                        if (debug)
                   1137:                                printf("received frag at %u overlaps with %u octet frag at %u\n",
                   1138:                                       offset, counts[f-1],
                   1139:                                       offsets[f-1]);
                   1140:                        continue;
                   1141:                }
                   1142: 
                   1143:                if (f < numfrags && (offset + count) > offsets[f]) {
                   1144:                        if (debug)
                   1145:                                printf("received %u octet frag at %u overlaps with frag at %u\n",
                   1146:                                       count, offset, offsets[f]);
                   1147:                        continue;
                   1148:                }
                   1149: 
                   1150:                for (ff = numfrags; ff > f; ff--) {
                   1151:                        offsets[ff] = offsets[ff-1];
                   1152:                        counts[ff] = counts[ff-1];
                   1153:                }
                   1154:                offsets[f] = offset;
                   1155:                counts[f] = count;
                   1156:                numfrags++;
                   1157: 
                   1158:                /*
                   1159:                 * Got that stuffed in right.  Figure out if this was the last.
                   1160:                 * Record status info out of the last packet.
                   1161:                 */
                   1162:                if (!CTL_ISMORE(rpkt.r_m_e_op)) {
                   1163:                        seenlastfrag = 1;
                   1164:                        if (rstatus != 0)
                   1165:                                *rstatus = ntohs(rpkt.status);
                   1166:                }
                   1167: 
                   1168:                /*
                   1169:                 * Copy the data into the data buffer.
                   1170:                 */
                   1171:                memcpy((char *)pktdata + offset, rpkt.data, count);
                   1172: 
                   1173:                /*
                   1174:                 * If we've seen the last fragment, look for holes in the sequence.
                   1175:                 * If there aren't any, we're done.
                   1176:                 */
                   1177:                if (seenlastfrag && offsets[0] == 0) {
                   1178:                        for (f = 1; f < numfrags; f++)
                   1179:                                if (offsets[f-1] + counts[f-1] !=
                   1180:                                    offsets[f])
                   1181:                                        break;
                   1182:                        if (f == numfrags) {
                   1183:                                *rsize = offsets[f-1] + counts[f-1];
                   1184:                                if (debug)
                   1185:                                        fprintf(stderr,
                   1186:                                                "%u packets reassembled into response\n",
                   1187:                                                numfrags);
                   1188:                                return 0;
                   1189:                        }
                   1190:                }
                   1191:        }  /* giant for (;;) collecting response packets */
                   1192: }  /* getresponse() */
                   1193: 
                   1194: 
                   1195: /*
                   1196:  * sendrequest - format and send a request packet
                   1197:  */
                   1198: static int
                   1199: sendrequest(
                   1200:        int opcode,
                   1201:        int associd,
                   1202:        int auth,
                   1203:        int qsize,
                   1204:        char *qdata
                   1205:        )
                   1206: {
                   1207:        struct ntp_control qpkt;
                   1208:        int     pktsize;
                   1209:        u_long  key_id;
                   1210:        char *  pass;
                   1211:        int     maclen;
                   1212: 
                   1213:        /*
                   1214:         * Check to make sure the data will fit in one packet
                   1215:         */
                   1216:        if (qsize > CTL_MAX_DATA_LEN) {
                   1217:                fprintf(stderr,
                   1218:                        "***Internal error!  qsize (%d) too large\n",
                   1219:                        qsize);
                   1220:                return 1;
                   1221:        }
                   1222: 
                   1223:        /*
                   1224:         * Fill in the packet
                   1225:         */
                   1226:        qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
                   1227:        qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK);
                   1228:        qpkt.sequence = htons(sequence);
                   1229:        qpkt.status = 0;
                   1230:        qpkt.associd = htons((u_short)associd);
                   1231:        qpkt.offset = 0;
                   1232:        qpkt.count = htons((u_short)qsize);
                   1233: 
                   1234:        pktsize = CTL_HEADER_LEN;
                   1235: 
                   1236:        /*
                   1237:         * If we have data, copy and pad it out to a 32-bit boundary.
                   1238:         */
                   1239:        if (qsize > 0) {
                   1240:                memcpy(qpkt.data, qdata, (size_t)qsize);
                   1241:                pktsize += qsize;
                   1242:                while (pktsize & (sizeof(u_int32) - 1)) {
                   1243:                        qpkt.data[qsize++] = 0;
                   1244:                        pktsize++;
                   1245:                }
                   1246:        }
                   1247: 
                   1248:        /*
                   1249:         * If it isn't authenticated we can just send it.  Otherwise
                   1250:         * we're going to have to think about it a little.
                   1251:         */
                   1252:        if (!auth && !always_auth) {
                   1253:                return sendpkt(&qpkt, pktsize);
                   1254:        } 
                   1255: 
                   1256:        /*
                   1257:         * Pad out packet to a multiple of 8 octets to be sure
                   1258:         * receiver can handle it.
                   1259:         */
                   1260:        while (pktsize & 7) {
                   1261:                qpkt.data[qsize++] = 0;
                   1262:                pktsize++;
                   1263:        }
                   1264: 
                   1265:        /*
                   1266:         * Get the keyid and the password if we don't have one.
                   1267:         */
                   1268:        if (info_auth_keyid == 0) {
                   1269:                key_id = getkeyid("Keyid: ");
                   1270:                if (key_id == 0 || key_id > NTP_MAXKEY) {
                   1271:                        fprintf(stderr, 
                   1272:                                "Invalid key identifier\n");
                   1273:                        return 1;
                   1274:                }
                   1275:                info_auth_keyid = key_id;
                   1276:        }
                   1277:        if (!authistrusted(info_auth_keyid)) {
                   1278:                pass = getpass_keytype(info_auth_keytype);
                   1279:                if ('\0' == pass[0]) {
                   1280:                        fprintf(stderr, "Invalid password\n");
                   1281:                        return 1;
                   1282:                }
                   1283:                authusekey(info_auth_keyid, info_auth_keytype,
                   1284:                           (u_char *)pass);
                   1285:                authtrust(info_auth_keyid, 1);
                   1286:        }
                   1287: 
                   1288:        /*
                   1289:         * Do the encryption.
                   1290:         */
                   1291:        maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
                   1292:        if (!maclen) {  
                   1293:                fprintf(stderr, "Key not found\n");
                   1294:                return 1;
                   1295:        } else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
                   1296:                fprintf(stderr,
                   1297:                        "%d octet MAC, %lu expected with %lu octet digest\n",
                   1298:                        maclen, (u_long)(info_auth_hashlen + sizeof(keyid_t)),
                   1299:                        (u_long)info_auth_hashlen);
                   1300:                return 1;
                   1301:        }
                   1302:        
                   1303:        return sendpkt((char *)&qpkt, pktsize + maclen);
                   1304: }
                   1305: 
                   1306: 
                   1307: /*
                   1308:  * show_error_msg - display the error text for a mode 6 error response.
                   1309:  */
                   1310: void
                   1311: show_error_msg(
                   1312:        int             m6resp,
                   1313:        associd_t       associd
                   1314:        )
                   1315: {
                   1316:        if (numhosts > 1)
                   1317:                fprintf(stderr, "server=%s ", currenthost);
                   1318: 
                   1319:        switch(m6resp) {
                   1320: 
                   1321:        case CERR_BADFMT:
                   1322:                fprintf(stderr,
                   1323:                    "***Server reports a bad format request packet\n");
                   1324:                break;
                   1325: 
                   1326:        case CERR_PERMISSION:
                   1327:                fprintf(stderr,
                   1328:                    "***Server disallowed request (authentication?)\n");
                   1329:                break;
                   1330: 
                   1331:        case CERR_BADOP:
                   1332:                fprintf(stderr,
                   1333:                    "***Server reports a bad opcode in request\n");
                   1334:                break;
                   1335: 
                   1336:        case CERR_BADASSOC:
                   1337:                fprintf(stderr,
                   1338:                    "***Association ID %d unknown to server\n",
                   1339:                    associd);
                   1340:                break;
                   1341: 
                   1342:        case CERR_UNKNOWNVAR:
                   1343:                fprintf(stderr,
                   1344:                    "***A request variable unknown to the server\n");
                   1345:                break;
                   1346: 
                   1347:        case CERR_BADVALUE:
                   1348:                fprintf(stderr,
                   1349:                    "***Server indicates a request variable was bad\n");
                   1350:                break;
                   1351: 
                   1352:        case ERR_UNSPEC:
                   1353:                fprintf(stderr,
                   1354:                    "***Server returned an unspecified error\n");
                   1355:                break;
                   1356: 
                   1357:        case ERR_TIMEOUT:
                   1358:                fprintf(stderr, "***Request timed out\n");
                   1359:                break;
                   1360: 
                   1361:        case ERR_INCOMPLETE:
                   1362:                fprintf(stderr,
                   1363:                    "***Response from server was incomplete\n");
                   1364:                break;
                   1365: 
                   1366:        case ERR_TOOMUCH:
                   1367:                fprintf(stderr,
                   1368:                    "***Buffer size exceeded for returned data\n");
                   1369:                break;
                   1370: 
                   1371:        default:
                   1372:                fprintf(stderr,
                   1373:                    "***Server returns unknown error code %d\n",
                   1374:                    m6resp);
                   1375:        }
                   1376: }
                   1377: 
                   1378: /*
                   1379:  * doquery - send a request and process the response, displaying
                   1380:  *          error messages for any error responses.
                   1381:  */
                   1382: int
                   1383: doquery(
                   1384:        int opcode,
                   1385:        associd_t associd,
                   1386:        int auth,
                   1387:        int qsize,
                   1388:        char *qdata,
                   1389:        u_short *rstatus,
                   1390:        int *rsize,
                   1391:        const char **rdata
                   1392:        )
                   1393: {
                   1394:        return doqueryex(opcode, associd, auth, qsize, qdata, rstatus,
                   1395:                         rsize, rdata, FALSE);
                   1396: }
                   1397: 
                   1398: 
                   1399: /*
                   1400:  * doqueryex - send a request and process the response, optionally
                   1401:  *            displaying error messages for any error responses.
                   1402:  */
                   1403: int
                   1404: doqueryex(
                   1405:        int opcode,
                   1406:        associd_t associd,
                   1407:        int auth,
                   1408:        int qsize,
                   1409:        char *qdata,
                   1410:        u_short *rstatus,
                   1411:        int *rsize,
                   1412:        const char **rdata,
                   1413:        int quiet
                   1414:        )
                   1415: {
                   1416:        int res;
                   1417:        int done;
                   1418: 
                   1419:        /*
                   1420:         * Check to make sure host is open
                   1421:         */
                   1422:        if (!havehost) {
                   1423:                fprintf(stderr, "***No host open, use `host' command\n");
                   1424:                return -1;
                   1425:        }
                   1426: 
                   1427:        done = 0;
                   1428:        sequence++;
                   1429: 
                   1430:     again:
                   1431:        /*
                   1432:         * send a request
                   1433:         */
                   1434:        res = sendrequest(opcode, associd, auth, qsize, qdata);
                   1435:        if (res != 0)
                   1436:                return res;
                   1437:        
                   1438:        /*
                   1439:         * Get the response.  If we got a standard error, print a message
                   1440:         */
                   1441:        res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
                   1442: 
                   1443:        if (res > 0) {
                   1444:                if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
                   1445:                        if (res == ERR_INCOMPLETE) {
                   1446:                                /*
                   1447:                                 * better bump the sequence so we don't
                   1448:                                 * get confused about differing fragments.
                   1449:                                 */
                   1450:                                sequence++;
                   1451:                        }
                   1452:                        done = 1;
                   1453:                        goto again;
                   1454:                }
                   1455:                if (!quiet)
                   1456:                        show_error_msg(res, associd);
                   1457: 
                   1458:        }
                   1459:        return res;
                   1460: }
                   1461: 
                   1462: 
                   1463: #ifndef BUILD_AS_LIB
                   1464: /*
                   1465:  * getcmds - read commands from the standard input and execute them
                   1466:  */
                   1467: static void
                   1468: getcmds(void)
                   1469: {
                   1470:        char *  line;
                   1471:        int     count;
                   1472: 
                   1473:        ntp_readline_init(interactive ? prompt : NULL);
                   1474: 
                   1475:        for (;;) {
                   1476:                line = ntp_readline(&count);
                   1477:                if (NULL == line)
                   1478:                        break;
                   1479:                docmd(line);
                   1480:                free(line);
                   1481:        }
                   1482: 
                   1483:        ntp_readline_uninit();
                   1484: }
                   1485: #endif /* !BUILD_AS_LIB */
                   1486: 
                   1487: 
                   1488: #if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
                   1489: /*
                   1490:  * abortcmd - catch interrupts and abort the current command
                   1491:  */
                   1492: static RETSIGTYPE
                   1493: abortcmd(
                   1494:        int sig
                   1495:        )
                   1496: {
                   1497:        if (current_output == stdout)
                   1498:            (void) fflush(stdout);
                   1499:        putc('\n', stderr);
                   1500:        (void) fflush(stderr);
                   1501:        if (jump) longjmp(interrupt_buf, 1);
                   1502: }
                   1503: #endif /* !SYS_WINNT && !BUILD_AS_LIB */
                   1504: 
                   1505: 
                   1506: #ifndef        BUILD_AS_LIB
                   1507: /*
                   1508:  * docmd - decode the command line and execute a command
                   1509:  */
                   1510: static void
                   1511: docmd(
                   1512:        const char *cmdline
                   1513:        )
                   1514: {
                   1515:        char *tokens[1+MAXARGS+2];
                   1516:        struct parse pcmd;
                   1517:        int ntok;
                   1518:        static int i;
                   1519:        struct xcmd *xcmd;
                   1520: 
                   1521:        /*
                   1522:         * Tokenize the command line.  If nothing on it, return.
                   1523:         */
                   1524:        tokenize(cmdline, tokens, &ntok);
                   1525:        if (ntok == 0)
                   1526:            return;
                   1527:        
                   1528:        /*
                   1529:         * Find the appropriate command description.
                   1530:         */
                   1531:        i = findcmd(tokens[0], builtins, opcmds, &xcmd);
                   1532:        if (i == 0) {
                   1533:                (void) fprintf(stderr, "***Command `%s' unknown\n",
                   1534:                               tokens[0]);
                   1535:                return;
                   1536:        } else if (i >= 2) {
                   1537:                (void) fprintf(stderr, "***Command `%s' ambiguous\n",
                   1538:                               tokens[0]);
                   1539:                return;
                   1540:        }
                   1541:        
                   1542:        /*
                   1543:         * Save the keyword, then walk through the arguments, interpreting
                   1544:         * as we go.
                   1545:         */
                   1546:        pcmd.keyword = tokens[0];
                   1547:        pcmd.nargs = 0;
                   1548:        for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
                   1549:                if ((i+1) >= ntok) {
                   1550:                        if (!(xcmd->arg[i] & OPT)) {
                   1551:                                printusage(xcmd, stderr);
                   1552:                                return;
                   1553:                        }
                   1554:                        break;
                   1555:                }
                   1556:                if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
                   1557:                        break;
                   1558:                if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
                   1559:                        return;
                   1560:                pcmd.nargs++;
                   1561:        }
                   1562: 
                   1563:        i++;
                   1564:        if (i < ntok && *tokens[i] == '>') {
                   1565:                char *fname;
                   1566: 
                   1567:                if (*(tokens[i]+1) != '\0')
                   1568:                        fname = tokens[i]+1;
                   1569:                else if ((i+1) < ntok)
                   1570:                        fname = tokens[i+1];
                   1571:                else {
                   1572:                        (void) fprintf(stderr, "***No file for redirect\n");
                   1573:                        return;
                   1574:                }
                   1575: 
                   1576:                current_output = fopen(fname, "w");
                   1577:                if (current_output == NULL) {
                   1578:                        (void) fprintf(stderr, "***Error opening %s: ", fname);
                   1579:                        perror("");
                   1580:                        return;
                   1581:                }
                   1582:                i = 1;          /* flag we need a close */
                   1583:        } else {
                   1584:                current_output = stdout;
                   1585:                i = 0;          /* flag no close */
                   1586:        }
                   1587: 
                   1588:        if (interactive && setjmp(interrupt_buf)) {
                   1589:                jump = 0;
                   1590:                return;
                   1591:        } else {
                   1592:                jump++;
                   1593:                (xcmd->handler)(&pcmd, current_output);
                   1594:                jump = 0;       /* HMS: 961106: was after fclose() */
                   1595:                if (i) (void) fclose(current_output);
                   1596:        }
                   1597: }
                   1598: 
                   1599: 
                   1600: /*
                   1601:  * tokenize - turn a command line into tokens
                   1602:  *
                   1603:  * SK: Modified to allow a quoted string 
                   1604:  *
                   1605:  * HMS: If the first character of the first token is a ':' then (after
                   1606:  * eating inter-token whitespace) the 2nd token is the rest of the line.
                   1607:  */
                   1608: 
                   1609: static void
                   1610: tokenize(
                   1611:        const char *line,
                   1612:        char **tokens,
                   1613:        int *ntok
                   1614:        )
                   1615: {
                   1616:        register const char *cp;
                   1617:        register char *sp;
                   1618:        static char tspace[MAXLINE];
                   1619: 
                   1620:        sp = tspace;
                   1621:        cp = line;
                   1622:        for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
                   1623:                tokens[*ntok] = sp;
                   1624: 
                   1625:                /* Skip inter-token whitespace */
                   1626:                while (ISSPACE(*cp))
                   1627:                    cp++;
                   1628: 
                   1629:                /* If we're at EOL we're done */
                   1630:                if (ISEOL(*cp))
                   1631:                    break;
                   1632: 
                   1633:                /* If this is the 2nd token and the first token begins
                   1634:                 * with a ':', then just grab to EOL.
                   1635:                 */
                   1636: 
                   1637:                if (*ntok == 1 && tokens[0][0] == ':') {
                   1638:                        do {
                   1639:                                *sp++ = *cp++;
                   1640:                        } while (!ISEOL(*cp));
                   1641:                }
                   1642: 
                   1643:                /* Check if this token begins with a double quote.
                   1644:                 * If yes, continue reading till the next double quote
                   1645:                 */
                   1646:                else if (*cp == '\"') {
                   1647:                        ++cp;
                   1648:                        do {
                   1649:                                *sp++ = *cp++;
                   1650:                        } while ((*cp != '\"') && !ISEOL(*cp));
                   1651:                        /* HMS: a missing closing " should be an error */
                   1652:                }
                   1653:                else {
                   1654:                        do {
                   1655:                                *sp++ = *cp++;
                   1656:                        } while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
                   1657:                        /* HMS: Why check for a " in the previous line? */
                   1658:                }
                   1659: 
                   1660:                *sp++ = '\0';
                   1661:        }
                   1662: }
                   1663: 
                   1664: 
                   1665: /*
                   1666:  * getarg - interpret an argument token
                   1667:  */
                   1668: static int
                   1669: getarg(
                   1670:        char *str,
                   1671:        int code,
                   1672:        arg_v *argp
                   1673:        )
                   1674: {
                   1675:        int isneg;
                   1676:        char *cp, *np;
                   1677:        static const char *digits = "0123456789";
                   1678: 
                   1679:        switch (code & ~OPT) {
                   1680:            case NTP_STR:
                   1681:                argp->string = str;
                   1682:                break;
                   1683:            case NTP_ADD:
                   1684:                if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) {
                   1685:                        return 0;
                   1686:                }
                   1687:                break;
                   1688:            case NTP_INT:
                   1689:            case NTP_UINT:
                   1690:                isneg = 0;
                   1691:                np = str;
                   1692:                if (*np == '&') {
                   1693:                        np++;
                   1694:                        isneg = atoi(np);
                   1695:                        if (isneg <= 0) {
                   1696:                                (void) fprintf(stderr,
                   1697:                                               "***Association value `%s' invalid/undecodable\n", str);
                   1698:                                return 0;
                   1699:                        }
                   1700:                        if (isneg > numassoc) {
                   1701:                                if (numassoc == 0) {
                   1702:                                        (void) fprintf(stderr,
                   1703:                                                       "***Association for `%s' unknown (max &%d)\n",
                   1704:                                                       str, numassoc);
                   1705:                                        return 0;
                   1706:                                } else {
                   1707:                                        isneg = numassoc;
                   1708:                                }
                   1709:                        }
                   1710:                        argp->uval = assoc_cache[isneg-1].assid;
                   1711:                        break;
                   1712:                }
                   1713: 
                   1714:                if (*np == '-') {
                   1715:                        np++;
                   1716:                        isneg = 1;
                   1717:                }
                   1718: 
                   1719:                argp->uval = 0;
                   1720:                do {
                   1721:                        cp = strchr(digits, *np);
                   1722:                        if (cp == NULL) {
                   1723:                                (void) fprintf(stderr,
                   1724:                                               "***Illegal integer value %s\n", str);
                   1725:                                return 0;
                   1726:                        }
                   1727:                        argp->uval *= 10;
                   1728:                        argp->uval += (cp - digits);
                   1729:                } while (*(++np) != '\0');
                   1730: 
                   1731:                if (isneg) {
                   1732:                        if ((code & ~OPT) == NTP_UINT) {
                   1733:                                (void) fprintf(stderr,
                   1734:                                               "***Value %s should be unsigned\n", str);
                   1735:                                return 0;
                   1736:                        }
                   1737:                        argp->ival = -argp->ival;
                   1738:                }
                   1739:                break;
                   1740:             case IP_VERSION:
                   1741:                if (!strcmp("-6", str))
                   1742:                        argp->ival = 6 ;
                   1743:                else if (!strcmp("-4", str))
                   1744:                        argp->ival = 4 ;
                   1745:                else {
                   1746:                        (void) fprintf(stderr,
                   1747:                            "***Version must be either 4 or 6\n");
                   1748:                        return 0;
                   1749:                }
                   1750:                break;
                   1751:        }
                   1752: 
                   1753:        return 1;
                   1754: }
                   1755: #endif /* !BUILD_AS_LIB */
                   1756: 
                   1757: 
                   1758: /*
                   1759:  * findcmd - find a command in a command description table
                   1760:  */
                   1761: static int
                   1762: findcmd(
                   1763:        register char *str,
                   1764:        struct xcmd *clist1,
                   1765:        struct xcmd *clist2,
                   1766:        struct xcmd **cmd
                   1767:        )
                   1768: {
                   1769:        register struct xcmd *cl;
                   1770:        register int clen;
                   1771:        int nmatch;
                   1772:        struct xcmd *nearmatch = NULL;
                   1773:        struct xcmd *clist;
                   1774: 
                   1775:        clen = strlen(str);
                   1776:        nmatch = 0;
                   1777:        if (clist1 != 0)
                   1778:            clist = clist1;
                   1779:        else if (clist2 != 0)
                   1780:            clist = clist2;
                   1781:        else
                   1782:            return 0;
                   1783: 
                   1784:     again:
                   1785:        for (cl = clist; cl->keyword != 0; cl++) {
                   1786:                /* do a first character check, for efficiency */
                   1787:                if (*str != *(cl->keyword))
                   1788:                    continue;
                   1789:                if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
                   1790:                        /*
                   1791:                         * Could be extact match, could be approximate.
                   1792:                         * Is exact if the length of the keyword is the
                   1793:                         * same as the str.
                   1794:                         */
                   1795:                        if (*((cl->keyword) + clen) == '\0') {
                   1796:                                *cmd = cl;
                   1797:                                return 1;
                   1798:                        }
                   1799:                        nmatch++;
                   1800:                        nearmatch = cl;
                   1801:                }
                   1802:        }
                   1803: 
                   1804:        /*
                   1805:         * See if there is more to do.  If so, go again.  Sorry about the
                   1806:         * goto, too much looking at BSD sources...
                   1807:         */
                   1808:        if (clist == clist1 && clist2 != 0) {
                   1809:                clist = clist2;
                   1810:                goto again;
                   1811:        }
                   1812: 
                   1813:        /*
                   1814:         * If we got extactly 1 near match, use it, else return number
                   1815:         * of matches.
                   1816:         */
                   1817:        if (nmatch == 1) {
                   1818:                *cmd = nearmatch;
                   1819:                return 1;
                   1820:        }
                   1821:        return nmatch;
                   1822: }
                   1823: 
                   1824: 
                   1825: /*
                   1826:  * getnetnum - given a host name, return its net number
                   1827:  *            and (optional) full name
                   1828:  */
                   1829: int
                   1830: getnetnum(
                   1831:        const char *hname,
                   1832:        sockaddr_u *num,
                   1833:        char *fullhost,
                   1834:        int af
                   1835:        )
                   1836: {
                   1837:        struct addrinfo hints, *ai = NULL;
                   1838: 
                   1839:        ZERO(hints);
                   1840:        hints.ai_flags = AI_CANONNAME;
                   1841: #ifdef AI_ADDRCONFIG
                   1842:        hints.ai_flags |= AI_ADDRCONFIG;
                   1843: #endif
                   1844:        
                   1845:        /*
                   1846:         * decodenetnum only works with addresses, but handles syntax
                   1847:         * that getaddrinfo doesn't:  [2001::1]:1234
                   1848:         */
                   1849:        if (decodenetnum(hname, num)) {
                   1850:                if (fullhost != NULL)
                   1851:                        getnameinfo(&num->sa, SOCKLEN(num), fullhost,
                   1852:                                    LENHOSTNAME, NULL, 0, 0);
                   1853:                return 1;
                   1854:        } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
                   1855:                NTP_INSIST(sizeof(*num) >= ai->ai_addrlen);
                   1856:                memcpy(num, ai->ai_addr, ai->ai_addrlen);
                   1857:                if (fullhost != NULL) {
                   1858:                        if (ai->ai_canonname != NULL) {
                   1859:                                strncpy(fullhost, ai->ai_canonname,
                   1860:                                        LENHOSTNAME);
                   1861:                                fullhost[LENHOSTNAME - 1] = '\0';
                   1862:                        } else {
                   1863:                                getnameinfo(&num->sa, SOCKLEN(num),
                   1864:                                            fullhost, LENHOSTNAME, NULL,
                   1865:                                            0, 0);
                   1866:                        }
                   1867:                }
                   1868:                return 1;
                   1869:        }
                   1870:        fprintf(stderr, "***Can't find host %s\n", hname);
                   1871: 
                   1872:        return 0;
                   1873: }
                   1874: 
                   1875: /*
                   1876:  * nntohost - convert network number to host name.  This routine enforces
                   1877:  *            the showhostnames setting.
                   1878:  */
                   1879: char *
                   1880: nntohost(
                   1881:        sockaddr_u *netnum
                   1882:        )
                   1883: {
                   1884:        return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE);
                   1885: }
                   1886: 
                   1887: 
                   1888: /*
                   1889:  * nntohost_col - convert network number to host name in fixed width.
                   1890:  *               This routine enforces the showhostnames setting.
                   1891:  *               When displaying hostnames longer than the width,
                   1892:  *               the first part of the hostname is displayed.  When
                   1893:  *               displaying numeric addresses longer than the width,
                   1894:  *               Such as IPv6 addresses, the caller decides whether
                   1895:  *               the first or last of the numeric address is used.
                   1896:  */
                   1897: char *
                   1898: nntohost_col(
                   1899:        sockaddr_u *    addr,
                   1900:        size_t          width,
                   1901:        int             preserve_lowaddrbits
                   1902:        )
                   1903: {
                   1904:        const char *    out;
                   1905: 
                   1906:        if (!showhostnames) {
                   1907:                if (preserve_lowaddrbits)
                   1908:                        out = trunc_left(stoa(addr), width);
                   1909:                else
                   1910:                        out = trunc_right(stoa(addr), width);
                   1911:        } else if (ISREFCLOCKADR(addr)) {
                   1912:                out = refnumtoa(addr);
                   1913:        } else {
                   1914:                out = trunc_right(socktohost(addr), width);
                   1915:        }
                   1916:        return out;
                   1917: }
                   1918: 
                   1919: 
                   1920: /*
                   1921:  * rtdatetolfp - decode an RT-11 date into an l_fp
                   1922:  */
                   1923: static int
                   1924: rtdatetolfp(
                   1925:        char *str,
                   1926:        l_fp *lfp
                   1927:        )
                   1928: {
                   1929:        register char *cp;
                   1930:        register int i;
                   1931:        struct calendar cal;
                   1932:        char buf[4];
                   1933:        static const char *months[12] = {
                   1934:                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                   1935:                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
                   1936:        };
                   1937: 
                   1938:        cal.yearday = 0;
                   1939: 
                   1940:        /*
                   1941:         * An RT-11 date looks like:
                   1942:         *
                   1943:         * d[d]-Mth-y[y] hh:mm:ss
                   1944:         *
                   1945:         * (No docs, but assume 4-digit years are also legal...)
                   1946:         *
                   1947:         * d[d]-Mth-y[y[y[y]]] hh:mm:ss
                   1948:         */
                   1949:        cp = str;
                   1950:        if (!isdigit((int)*cp)) {
                   1951:                if (*cp == '-') {
                   1952:                        /*
                   1953:                         * Catch special case
                   1954:                         */
                   1955:                        L_CLR(lfp);
                   1956:                        return 1;
                   1957:                }
                   1958:                return 0;
                   1959:        }
                   1960: 
                   1961:        cal.monthday = (u_char) (*cp++ - '0');  /* ascii dependent */
                   1962:        if (isdigit((int)*cp)) {
                   1963:                cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1));
                   1964:                cal.monthday = (u_char)(cal.monthday + *cp++ - '0');
                   1965:        }
                   1966: 
                   1967:        if (*cp++ != '-')
                   1968:            return 0;
                   1969:        
                   1970:        for (i = 0; i < 3; i++)
                   1971:            buf[i] = *cp++;
                   1972:        buf[3] = '\0';
                   1973: 
                   1974:        for (i = 0; i < 12; i++)
                   1975:            if (STREQ(buf, months[i]))
                   1976:                break;
                   1977:        if (i == 12)
                   1978:            return 0;
                   1979:        cal.month = (u_char)(i + 1);
                   1980: 
                   1981:        if (*cp++ != '-')
                   1982:            return 0;
                   1983:        
                   1984:        if (!isdigit((int)*cp))
                   1985:            return 0;
                   1986:        cal.year = (u_short)(*cp++ - '0');
                   1987:        if (isdigit((int)*cp)) {
                   1988:                cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
                   1989:                cal.year = (u_short)(*cp++ - '0');
                   1990:        }
                   1991:        if (isdigit((int)*cp)) {
                   1992:                cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
                   1993:                cal.year = (u_short)(cal.year + *cp++ - '0');
                   1994:        }
                   1995:        if (isdigit((int)*cp)) {
                   1996:                cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
                   1997:                cal.year = (u_short)(cal.year + *cp++ - '0');
                   1998:        }
                   1999: 
                   2000:        /*
                   2001:         * Catch special case.  If cal.year == 0 this is a zero timestamp.
                   2002:         */
                   2003:        if (cal.year == 0) {
                   2004:                L_CLR(lfp);
                   2005:                return 1;
                   2006:        }
                   2007: 
                   2008:        if (*cp++ != ' ' || !isdigit((int)*cp))
                   2009:            return 0;
                   2010:        cal.hour = (u_char)(*cp++ - '0');
                   2011:        if (isdigit((int)*cp)) {
                   2012:                cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1));
                   2013:                cal.hour = (u_char)(cal.hour + *cp++ - '0');
                   2014:        }
                   2015: 
                   2016:        if (*cp++ != ':' || !isdigit((int)*cp))
                   2017:            return 0;
                   2018:        cal.minute = (u_char)(*cp++ - '0');
                   2019:        if (isdigit((int)*cp)) {
                   2020:                cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1));
                   2021:                cal.minute = (u_char)(cal.minute + *cp++ - '0');
                   2022:        }
                   2023: 
                   2024:        if (*cp++ != ':' || !isdigit((int)*cp))
                   2025:            return 0;
                   2026:        cal.second = (u_char)(*cp++ - '0');
                   2027:        if (isdigit((int)*cp)) {
                   2028:                cal.second = (u_char)((cal.second << 3) + (cal.second << 1));
                   2029:                cal.second = (u_char)(cal.second + *cp++ - '0');
                   2030:        }
                   2031: 
                   2032:        /*
                   2033:         * For RT-11, 1972 seems to be the pivot year
                   2034:         */
                   2035:        if (cal.year < 72)
                   2036:                cal.year += 2000;
                   2037:        if (cal.year < 100)
                   2038:                cal.year += 1900;
                   2039: 
                   2040:        lfp->l_ui = caltontp(&cal);
                   2041:        lfp->l_uf = 0;
                   2042:        return 1;
                   2043: }
                   2044: 
                   2045: 
                   2046: /*
                   2047:  * decodets - decode a timestamp into an l_fp format number, with
                   2048:  *           consideration of fuzzball formats.
                   2049:  */
                   2050: int
                   2051: decodets(
                   2052:        char *str,
                   2053:        l_fp *lfp
                   2054:        )
                   2055: {
                   2056:        char *cp;
                   2057:        char buf[30];
                   2058:        size_t b;
                   2059: 
                   2060:        /*
                   2061:         * If it starts with a 0x, decode as hex.
                   2062:         */
                   2063:        if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
                   2064:                return hextolfp(str+2, lfp);
                   2065: 
                   2066:        /*
                   2067:         * If it starts with a '"', try it as an RT-11 date.
                   2068:         */
                   2069:        if (*str == '"') {
                   2070:                cp = str + 1;
                   2071:                b = 0;
                   2072:                while ('"' != *cp && '\0' != *cp &&
                   2073:                       b < COUNTOF(buf) - 1)
                   2074:                        buf[b++] = *cp++;
                   2075:                buf[b] = '\0';
                   2076:                return rtdatetolfp(buf, lfp);
                   2077:        }
                   2078: 
                   2079:        /*
                   2080:         * Might still be hex.  Check out the first character.  Talk
                   2081:         * about heuristics!
                   2082:         */
                   2083:        if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
                   2084:                return hextolfp(str, lfp);
                   2085: 
                   2086:        /*
                   2087:         * Try it as a decimal.  If this fails, try as an unquoted
                   2088:         * RT-11 date.  This code should go away eventually.
                   2089:         */
                   2090:        if (atolfp(str, lfp))
                   2091:                return 1;
                   2092: 
                   2093:        return rtdatetolfp(str, lfp);
                   2094: }
                   2095: 
                   2096: 
                   2097: /*
                   2098:  * decodetime - decode a time value.  It should be in milliseconds
                   2099:  */
                   2100: int
                   2101: decodetime(
                   2102:        char *str,
                   2103:        l_fp *lfp
                   2104:        )
                   2105: {
                   2106:        return mstolfp(str, lfp);
                   2107: }
                   2108: 
                   2109: 
                   2110: /*
                   2111:  * decodeint - decode an integer
                   2112:  */
                   2113: int
                   2114: decodeint(
                   2115:        char *str,
                   2116:        long *val
                   2117:        )
                   2118: {
                   2119:        if (*str == '0') {
                   2120:                if (*(str+1) == 'x' || *(str+1) == 'X')
                   2121:                    return hextoint(str+2, (u_long *)val);
                   2122:                return octtoint(str, (u_long *)val);
                   2123:        }
                   2124:        return atoint(str, val);
                   2125: }
                   2126: 
                   2127: 
                   2128: /*
                   2129:  * decodeuint - decode an unsigned integer
                   2130:  */
                   2131: int
                   2132: decodeuint(
                   2133:        char *str,
                   2134:        u_long *val
                   2135:        )
                   2136: {
                   2137:        if (*str == '0') {
                   2138:                if (*(str + 1) == 'x' || *(str + 1) == 'X')
                   2139:                        return (hextoint(str + 2, val));
                   2140:                return (octtoint(str, val));
                   2141:        }
                   2142:        return (atouint(str, val));
                   2143: }
                   2144: 
                   2145: 
                   2146: /*
                   2147:  * decodearr - decode an array of time values
                   2148:  */
                   2149: static int
                   2150: decodearr(
                   2151:        char *str,
                   2152:        int *narr,
                   2153:        l_fp *lfparr
                   2154:        )
                   2155: {
                   2156:        register char *cp, *bp;
                   2157:        register l_fp *lfp;
                   2158:        char buf[60];
                   2159: 
                   2160:        lfp = lfparr;
                   2161:        cp = str;
                   2162:        *narr = 0;
                   2163: 
                   2164:        while (*narr < 8) {
                   2165:                while (isspace((int)*cp))
                   2166:                    cp++;
                   2167:                if (*cp == '\0')
                   2168:                    break;
                   2169: 
                   2170:                bp = buf;
                   2171:                while (!isspace((int)*cp) && *cp != '\0')
                   2172:                    *bp++ = *cp++;
                   2173:                *bp++ = '\0';
                   2174: 
                   2175:                if (!decodetime(buf, lfp))
                   2176:                    return 0;
                   2177:                (*narr)++;
                   2178:                lfp++;
                   2179:        }
                   2180:        return 1;
                   2181: }
                   2182: 
                   2183: 
                   2184: /*
                   2185:  * Finally, the built in command handlers
                   2186:  */
                   2187: 
                   2188: /*
                   2189:  * help - tell about commands, or details of a particular command
                   2190:  */
                   2191: static void
                   2192: help(
                   2193:        struct parse *pcmd,
                   2194:        FILE *fp
                   2195:        )
                   2196: {
                   2197:        struct xcmd *xcp = NULL;        /* quiet warning */
                   2198:        char *cmd;
                   2199:        const char *list[100];
                   2200:        size_t word, words;
                   2201:        size_t row, rows;
                   2202:        size_t col, cols;
                   2203:        size_t length;
                   2204: 
                   2205:        if (pcmd->nargs == 0) {
                   2206:                words = 0;
                   2207:                for (xcp = builtins; xcp->keyword != NULL; xcp++) {
                   2208:                        if (*(xcp->keyword) != '?')
                   2209:                                list[words++] = xcp->keyword;
                   2210:                }
                   2211:                for (xcp = opcmds; xcp->keyword != NULL; xcp++)
                   2212:                        list[words++] = xcp->keyword;
                   2213: 
                   2214:                qsort((void *)list, (size_t)words, sizeof(list[0]),
                   2215:                      helpsort);
                   2216:                col = 0;
                   2217:                for (word = 0; word < words; word++) {
                   2218:                        length = strlen(list[word]);
                   2219:                        col = max(col, length);
                   2220:                }
                   2221: 
                   2222:                cols = SCREENWIDTH / ++col;
                   2223:                rows = (words + cols - 1) / cols;
                   2224: 
                   2225:                fprintf(fp, "ntpq commands:\n");
                   2226: 
                   2227:                for (row = 0; row < rows; row++) {
                   2228:                        for (word = row; word < words; word += rows)
                   2229:                                fprintf(fp, "%-*.*s", col,  col-1,
                   2230:                                        list[word]);
                   2231:                        fprintf(fp, "\n");
                   2232:                }
                   2233:        } else {
                   2234:                cmd = pcmd->argval[0].string;
                   2235:                words = findcmd(cmd, builtins, opcmds, &xcp);
                   2236:                if (words == 0) {
                   2237:                        fprintf(stderr,
                   2238:                                "Command `%s' is unknown\n", cmd);
                   2239:                        return;
                   2240:                } else if (words >= 2) {
                   2241:                        fprintf(stderr,
                   2242:                                "Command `%s' is ambiguous\n", cmd);
                   2243:                        return;
                   2244:                }
                   2245:                fprintf(fp, "function: %s\n", xcp->comment);
                   2246:                printusage(xcp, fp);
                   2247:        }
                   2248: }
                   2249: 
                   2250: 
                   2251: /*
                   2252:  * helpsort - do hostname qsort comparisons
                   2253:  */
                   2254: static int
                   2255: helpsort(
                   2256:        const void *t1,
                   2257:        const void *t2
                   2258:        )
                   2259: {
                   2260:        const char * const *    name1 = t1;
                   2261:        const char * const *    name2 = t2;
                   2262: 
                   2263:        return strcmp(*name1, *name2);
                   2264: }
                   2265: 
                   2266: 
                   2267: /*
                   2268:  * printusage - print usage information for a command
                   2269:  */
                   2270: static void
                   2271: printusage(
                   2272:        struct xcmd *xcp,
                   2273:        FILE *fp
                   2274:        )
                   2275: {
                   2276:        register int i;
                   2277: 
                   2278:        (void) fprintf(fp, "usage: %s", xcp->keyword);
                   2279:        for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
                   2280:                if (xcp->arg[i] & OPT)
                   2281:                    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
                   2282:                else
                   2283:                    (void) fprintf(fp, " %s", xcp->desc[i]);
                   2284:        }
                   2285:        (void) fprintf(fp, "\n");
                   2286: }
                   2287: 
                   2288: 
                   2289: /*
                   2290:  * timeout - set time out time
                   2291:  */
                   2292: static void
                   2293: timeout(
                   2294:        struct parse *pcmd,
                   2295:        FILE *fp
                   2296:        )
                   2297: {
                   2298:        int val;
                   2299: 
                   2300:        if (pcmd->nargs == 0) {
                   2301:                val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
                   2302:                (void) fprintf(fp, "primary timeout %d ms\n", val);
                   2303:        } else {
                   2304:                tvout.tv_sec = pcmd->argval[0].uval / 1000;
                   2305:                tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
                   2306:                        * 1000;
                   2307:        }
                   2308: }
                   2309: 
                   2310: 
                   2311: /*
                   2312:  * auth_delay - set delay for auth requests
                   2313:  */
                   2314: static void
                   2315: auth_delay(
                   2316:        struct parse *pcmd,
                   2317:        FILE *fp
                   2318:        )
                   2319: {
                   2320:        int isneg;
                   2321:        u_long val;
                   2322: 
                   2323:        if (pcmd->nargs == 0) {
                   2324:                val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
                   2325:                (void) fprintf(fp, "delay %lu ms\n", val);
                   2326:        } else {
                   2327:                if (pcmd->argval[0].ival < 0) {
                   2328:                        isneg = 1;
                   2329:                        val = (u_long)(-pcmd->argval[0].ival);
                   2330:                } else {
                   2331:                        isneg = 0;
                   2332:                        val = (u_long)pcmd->argval[0].ival;
                   2333:                }
                   2334: 
                   2335:                delay_time.l_ui = val / 1000;
                   2336:                val %= 1000;
                   2337:                delay_time.l_uf = val * 4294967;        /* 2**32/1000 */
                   2338: 
                   2339:                if (isneg)
                   2340:                    L_NEG(&delay_time);
                   2341:        }
                   2342: }
                   2343: 
                   2344: 
                   2345: /*
                   2346:  * host - set the host we are dealing with.
                   2347:  */
                   2348: static void
                   2349: host(
                   2350:        struct parse *pcmd,
                   2351:        FILE *fp
                   2352:        )
                   2353: {
                   2354:        int i;
                   2355: 
                   2356:        if (pcmd->nargs == 0) {
                   2357:                if (havehost)
                   2358:                        (void) fprintf(fp, "current host is %s\n",
                   2359:                                           currenthost);
                   2360:                else
                   2361:                        (void) fprintf(fp, "no current host\n");
                   2362:                return;
                   2363:        }
                   2364: 
                   2365:        i = 0;
                   2366:        ai_fam_templ = ai_fam_default;
                   2367:        if (pcmd->nargs == 2) {
                   2368:                if (!strcmp("-4", pcmd->argval[i].string))
                   2369:                        ai_fam_templ = AF_INET;
                   2370:                else if (!strcmp("-6", pcmd->argval[i].string))
                   2371:                        ai_fam_templ = AF_INET6;
                   2372:                else {
                   2373:                        if (havehost)
                   2374:                                (void) fprintf(fp,
                   2375:                                               "current host remains %s\n",
                   2376:                                               currenthost);
                   2377:                        else
                   2378:                                (void) fprintf(fp, "still no current host\n");
                   2379:                        return;
                   2380:                }
                   2381:                i = 1;
                   2382:        }
                   2383:        if (openhost(pcmd->argval[i].string)) {
                   2384:                (void) fprintf(fp, "current host set to %s\n", currenthost);
                   2385:                numassoc = 0;
                   2386:        } else {
                   2387:                if (havehost)
                   2388:                        (void) fprintf(fp,
                   2389:                                       "current host remains %s\n", 
                   2390:                                       currenthost);
                   2391:                else
                   2392:                        (void) fprintf(fp, "still no current host\n");
                   2393:        }
                   2394: }
                   2395: 
                   2396: 
                   2397: /*
                   2398:  * poll - do one (or more) polls of the host via NTP
                   2399:  */
                   2400: /*ARGSUSED*/
                   2401: static void
                   2402: ntp_poll(
                   2403:        struct parse *pcmd,
                   2404:        FILE *fp
                   2405:        )
                   2406: {
                   2407:        (void) fprintf(fp, "poll not implemented yet\n");
                   2408: }
                   2409: 
                   2410: 
                   2411: /*
                   2412:  * keyid - get a keyid to use for authenticating requests
                   2413:  */
                   2414: static void
                   2415: keyid(
                   2416:        struct parse *pcmd,
                   2417:        FILE *fp
                   2418:        )
                   2419: {
                   2420:        if (pcmd->nargs == 0) {
                   2421:                if (info_auth_keyid == 0)
                   2422:                    (void) fprintf(fp, "no keyid defined\n");
                   2423:                else
                   2424:                    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
                   2425:        } else {
                   2426:                /* allow zero so that keyid can be cleared. */
                   2427:                if(pcmd->argval[0].uval > NTP_MAXKEY)
                   2428:                    (void) fprintf(fp, "Invalid key identifier\n");
                   2429:                info_auth_keyid = pcmd->argval[0].uval;
                   2430:        }
                   2431: }
                   2432: 
                   2433: /*
                   2434:  * keytype - get type of key to use for authenticating requests
                   2435:  */
                   2436: static void
                   2437: keytype(
                   2438:        struct parse *pcmd,
                   2439:        FILE *fp
                   2440:        )
                   2441: {
                   2442:        const char *    digest_name;
                   2443:        size_t          digest_len;
                   2444:        int             key_type;
                   2445: 
                   2446:        if (!pcmd->nargs) {
                   2447:                fprintf(fp, "keytype is %s with %lu octet digests\n",
                   2448:                        keytype_name(info_auth_keytype),
                   2449:                        (u_long)info_auth_hashlen);
                   2450:                return;
                   2451:        }
                   2452: 
                   2453:        digest_name = pcmd->argval[0].string;
                   2454:        digest_len = 0;
                   2455:        key_type = keytype_from_text(digest_name, &digest_len);
                   2456: 
                   2457:        if (!key_type) {
                   2458:                fprintf(fp, "keytype must be 'md5'%s\n",
                   2459: #ifdef OPENSSL
                   2460:                        " or a digest type provided by OpenSSL");
                   2461: #else
                   2462:                        "");
                   2463: #endif
                   2464:                return;
                   2465:        }
                   2466: 
                   2467:        info_auth_keytype = key_type;
                   2468:        info_auth_hashlen = digest_len;
                   2469: }
                   2470: 
                   2471: 
                   2472: /*
                   2473:  * passwd - get an authentication key
                   2474:  */
                   2475: /*ARGSUSED*/
                   2476: static void
                   2477: passwd(
                   2478:        struct parse *pcmd,
                   2479:        FILE *fp
                   2480:        )
                   2481: {
                   2482:        char *pass;
                   2483: 
                   2484:        if (info_auth_keyid == 0) {
                   2485:                int u_keyid = getkeyid("Keyid: ");
                   2486:                if (u_keyid == 0 || u_keyid > NTP_MAXKEY) {
                   2487:                        (void)fprintf(fp, "Invalid key identifier\n");
                   2488:                        return;
                   2489:                }
                   2490:                info_auth_keyid = u_keyid;
                   2491:        }
                   2492:        if (pcmd->nargs >= 1)
                   2493:                pass = pcmd->argval[0].string;
                   2494:        else {
                   2495:                pass = getpass_keytype(info_auth_keytype);
                   2496:                if ('\0' == pass[0]) {
                   2497:                        fprintf(fp, "Password unchanged\n");
                   2498:                        return;
                   2499:                }
                   2500:        }
                   2501:        authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
                   2502:        authtrust(info_auth_keyid, 1);
                   2503: }
                   2504: 
                   2505: 
                   2506: /*
                   2507:  * hostnames - set the showhostnames flag
                   2508:  */
                   2509: static void
                   2510: hostnames(
                   2511:        struct parse *pcmd,
                   2512:        FILE *fp
                   2513:        )
                   2514: {
                   2515:        if (pcmd->nargs == 0) {
                   2516:                if (showhostnames)
                   2517:                    (void) fprintf(fp, "hostnames being shown\n");
                   2518:                else
                   2519:                    (void) fprintf(fp, "hostnames not being shown\n");
                   2520:        } else {
                   2521:                if (STREQ(pcmd->argval[0].string, "yes"))
                   2522:                    showhostnames = 1;
                   2523:                else if (STREQ(pcmd->argval[0].string, "no"))
                   2524:                    showhostnames = 0;
                   2525:                else
                   2526:                    (void)fprintf(stderr, "What?\n");
                   2527:        }
                   2528: }
                   2529: 
                   2530: 
                   2531: 
                   2532: /*
                   2533:  * setdebug - set/change debugging level
                   2534:  */
                   2535: static void
                   2536: setdebug(
                   2537:        struct parse *pcmd,
                   2538:        FILE *fp
                   2539:        )
                   2540: {
                   2541:        if (pcmd->nargs == 0) {
                   2542:                (void) fprintf(fp, "debug level is %d\n", debug);
                   2543:                return;
                   2544:        } else if (STREQ(pcmd->argval[0].string, "no")) {
                   2545:                debug = 0;
                   2546:        } else if (STREQ(pcmd->argval[0].string, "more")) {
                   2547:                debug++;
                   2548:        } else if (STREQ(pcmd->argval[0].string, "less")) {
                   2549:                debug--;
                   2550:        } else {
                   2551:                (void) fprintf(fp, "What?\n");
                   2552:                return;
                   2553:        }
                   2554:        (void) fprintf(fp, "debug level set to %d\n", debug);
                   2555: }
                   2556: 
                   2557: 
                   2558: /*
                   2559:  * quit - stop this nonsense
                   2560:  */
                   2561: /*ARGSUSED*/
                   2562: static void
                   2563: quit(
                   2564:        struct parse *pcmd,
                   2565:        FILE *fp
                   2566:        )
                   2567: {
                   2568:        if (havehost)
                   2569:            closesocket(sockfd);        /* cleanliness next to godliness */
                   2570:        exit(0);
                   2571: }
                   2572: 
                   2573: 
                   2574: /*
                   2575:  * version - print the current version number
                   2576:  */
                   2577: /*ARGSUSED*/
                   2578: static void
                   2579: version(
                   2580:        struct parse *pcmd,
                   2581:        FILE *fp
                   2582:        )
                   2583: {
                   2584: 
                   2585:        (void) fprintf(fp, "%s\n", Version);
                   2586:        return;
                   2587: }
                   2588: 
                   2589: 
                   2590: /*
                   2591:  * raw - set raw mode output
                   2592:  */
                   2593: /*ARGSUSED*/
                   2594: static void
                   2595: raw(
                   2596:        struct parse *pcmd,
                   2597:        FILE *fp
                   2598:        )
                   2599: {
                   2600:        rawmode = 1;
                   2601:        (void) fprintf(fp, "Output set to raw\n");
                   2602: }
                   2603: 
                   2604: 
                   2605: /*
                   2606:  * cooked - set cooked mode output
                   2607:  */
                   2608: /*ARGSUSED*/
                   2609: static void
                   2610: cooked(
                   2611:        struct parse *pcmd,
                   2612:        FILE *fp
                   2613:        )
                   2614: {
                   2615:        rawmode = 0;
                   2616:        (void) fprintf(fp, "Output set to cooked\n");
                   2617:        return;
                   2618: }
                   2619: 
                   2620: 
                   2621: /*
                   2622:  * authenticate - always authenticate requests to this host
                   2623:  */
                   2624: static void
                   2625: authenticate(
                   2626:        struct parse *pcmd,
                   2627:        FILE *fp
                   2628:        )
                   2629: {
                   2630:        if (pcmd->nargs == 0) {
                   2631:                if (always_auth) {
                   2632:                        (void) fprintf(fp,
                   2633:                                       "authenticated requests being sent\n");
                   2634:                } else
                   2635:                    (void) fprintf(fp,
                   2636:                                   "unauthenticated requests being sent\n");
                   2637:        } else {
                   2638:                if (STREQ(pcmd->argval[0].string, "yes")) {
                   2639:                        always_auth = 1;
                   2640:                } else if (STREQ(pcmd->argval[0].string, "no")) {
                   2641:                        always_auth = 0;
                   2642:                } else
                   2643:                    (void)fprintf(stderr, "What?\n");
                   2644:        }
                   2645: }
                   2646: 
                   2647: 
                   2648: /*
                   2649:  * ntpversion - choose the NTP version to use
                   2650:  */
                   2651: static void
                   2652: ntpversion(
                   2653:        struct parse *pcmd,
                   2654:        FILE *fp
                   2655:        )
                   2656: {
                   2657:        if (pcmd->nargs == 0) {
                   2658:                (void) fprintf(fp,
                   2659:                               "NTP version being claimed is %d\n", pktversion);
                   2660:        } else {
                   2661:                if (pcmd->argval[0].uval < NTP_OLDVERSION
                   2662:                    || pcmd->argval[0].uval > NTP_VERSION) {
                   2663:                        (void) fprintf(stderr, "versions %d to %d, please\n",
                   2664:                                       NTP_OLDVERSION, NTP_VERSION);
                   2665:                } else {
                   2666:                        pktversion = (u_char) pcmd->argval[0].uval;
                   2667:                }
                   2668:        }
                   2669: }
                   2670: 
                   2671: 
                   2672: /*
                   2673:  * warning - print a warning message
                   2674:  */
                   2675: static void
                   2676: warning(
                   2677:        const char *fmt,
                   2678:        const char *st1,
                   2679:        const char *st2
                   2680:        )
                   2681: {
                   2682:        (void) fprintf(stderr, "%s: ", progname);
                   2683:        (void) fprintf(stderr, fmt, st1, st2);
                   2684:        (void) fprintf(stderr, ": ");
                   2685:        perror("");
                   2686: }
                   2687: 
                   2688: 
                   2689: /*
                   2690:  * error - print a message and exit
                   2691:  */
                   2692: static void
                   2693: error(
                   2694:        const char *fmt,
                   2695:        const char *st1,
                   2696:        const char *st2
                   2697:        )
                   2698: {
                   2699:        warning(fmt, st1, st2);
                   2700:        exit(1);
                   2701: }
                   2702: 
                   2703: /*
                   2704:  * getkeyid - prompt the user for a keyid to use
                   2705:  */
                   2706: static u_long
                   2707: getkeyid(
                   2708:        const char *keyprompt
                   2709:        )
                   2710: {
                   2711:        int c;
                   2712:        FILE *fi;
                   2713:        char pbuf[20];
                   2714:        size_t i;
                   2715:        size_t ilim;
                   2716: 
                   2717: #ifndef SYS_WINNT
                   2718:        if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
                   2719: #else
                   2720:        if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
                   2721: #endif /* SYS_WINNT */
                   2722:                fi = stdin;
                   2723:        else
                   2724:                setbuf(fi, (char *)NULL);
                   2725:        fprintf(stderr, "%s", keyprompt); fflush(stderr);
                   2726:        for (i = 0, ilim = COUNTOF(pbuf) - 1;
                   2727:             i < ilim && (c = getc(fi)) != '\n' && c != EOF;
                   2728:             )
                   2729:                pbuf[i++] = (char)c;
                   2730:        pbuf[i] = '\0';
                   2731:        if (fi != stdin)
                   2732:                fclose(fi);
                   2733: 
                   2734:        return (u_long) atoi(pbuf);
                   2735: }
                   2736: 
                   2737: 
                   2738: /*
                   2739:  * atoascii - printable-ize possibly ascii data using the character
                   2740:  *           transformations cat -v uses.
                   2741:  */
                   2742: static void
                   2743: atoascii(
                   2744:        const char *in,
                   2745:        size_t in_octets,
                   2746:        char *out,
                   2747:        size_t out_octets
                   2748:        )
                   2749: {
                   2750:        register const u_char * pchIn;
                   2751:                 const u_char * pchInLimit;
                   2752:        register u_char *       pchOut;
                   2753:        register u_char         c;
                   2754: 
                   2755:        pchIn = (const u_char *)in;
                   2756:        pchInLimit = pchIn + in_octets;
                   2757:        pchOut = (u_char *)out;
                   2758: 
                   2759:        if (NULL == pchIn) {
                   2760:                if (0 < out_octets)
                   2761:                        *pchOut = '\0';
                   2762:                return;
                   2763:        }
                   2764: 
                   2765: #define        ONEOUT(c)                                       \
                   2766: do {                                                   \
                   2767:        if (0 == --out_octets) {                        \
                   2768:                *pchOut = '\0';                         \
                   2769:                return;                                 \
                   2770:        }                                               \
                   2771:        *pchOut++ = (c);                                \
                   2772: } while (0)
                   2773: 
                   2774:        for (   ; pchIn < pchInLimit; pchIn++) {
                   2775:                c = *pchIn;
                   2776:                if ('\0' == c)
                   2777:                        break;
                   2778:                if (c & 0x80) {
                   2779:                        ONEOUT('M');
                   2780:                        ONEOUT('-');
                   2781:                        c &= 0x7f;
                   2782:                }
                   2783:                if (c < ' ') {
                   2784:                        ONEOUT('^');
                   2785:                        ONEOUT((u_char)(c + '@'));
                   2786:                } else if (0x7f == c) {
                   2787:                        ONEOUT('^');
                   2788:                        ONEOUT('?');
                   2789:                } else
                   2790:                        ONEOUT(c);
                   2791:        }
                   2792:        ONEOUT('\0');
                   2793: 
                   2794: #undef ONEOUT
                   2795: }
                   2796: 
                   2797: 
                   2798: /*
                   2799:  * makeascii - print possibly ascii data using the character
                   2800:  *            transformations that cat -v uses.
                   2801:  */
                   2802: void
                   2803: makeascii(
                   2804:        int length,
                   2805:        const char *data,
                   2806:        FILE *fp
                   2807:        )
                   2808: {
                   2809:        const u_char *data_u_char;
                   2810:        const u_char *cp;
                   2811:        int c;
                   2812: 
                   2813:        data_u_char = (const u_char *)data;
                   2814: 
                   2815:        for (cp = data_u_char; cp < data_u_char + length; cp++) {
                   2816:                c = (int)*cp;
                   2817:                if (c & 0x80) {
                   2818:                        putc('M', fp);
                   2819:                        putc('-', fp);
                   2820:                        c &= 0x7f;
                   2821:                }
                   2822: 
                   2823:                if (c < ' ') {
                   2824:                        putc('^', fp);
                   2825:                        putc(c + '@', fp);
                   2826:                } else if (0x7f == c) {
                   2827:                        putc('^', fp);
                   2828:                        putc('?', fp);
                   2829:                } else
                   2830:                        putc(c, fp);
                   2831:        }
                   2832: }
                   2833: 
                   2834: 
                   2835: /*
                   2836:  * asciize - same thing as makeascii except add a newline
                   2837:  */
                   2838: void
                   2839: asciize(
                   2840:        int length,
                   2841:        char *data,
                   2842:        FILE *fp
                   2843:        )
                   2844: {
                   2845:        makeascii(length, data, fp);
                   2846:        putc('\n', fp);
                   2847: }
                   2848: 
                   2849: 
                   2850: /*
                   2851:  * truncate string to fit clipping excess at end.
                   2852:  *     "too long"      ->      "too l"
                   2853:  * Used for hostnames.
                   2854:  */
                   2855: char *
                   2856: trunc_right(
                   2857:        const char *    src,
                   2858:        size_t          width
                   2859:        )
                   2860: {
                   2861:        size_t  sl;
                   2862:        char *  out;
                   2863: 
                   2864:        
                   2865:        sl = strlen(src);
                   2866:        if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) {
                   2867:                LIB_GETBUF(out);
                   2868:                memcpy(out, src, width);
                   2869:                out[width] = '\0';
                   2870: 
                   2871:                return out;
                   2872:        }
                   2873: 
                   2874:        return src;
                   2875: }
                   2876: 
                   2877: 
                   2878: /*
                   2879:  * truncate string to fit by preserving right side and using '_' to hint
                   2880:  *     "too long"      ->      "_long"
                   2881:  * Used for local IPv6 addresses, where low bits differentiate.
                   2882:  */
                   2883: char *
                   2884: trunc_left(
                   2885:        const char *    src,
                   2886:        size_t          width
                   2887:        )
                   2888: {
                   2889:        size_t  sl;
                   2890:        char *  out;
                   2891: 
                   2892: 
                   2893:        sl = strlen(src);
                   2894:        if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) {
                   2895:                LIB_GETBUF(out);
                   2896:                out[0] = '_';
                   2897:                memcpy(&out[1], &src[sl + 1 - width], width);
                   2898: 
                   2899:                return out;
                   2900:        }
                   2901: 
                   2902:        return src;
                   2903: }
                   2904: 
                   2905: 
                   2906: /*
                   2907:  * Some circular buffer space
                   2908:  */
                   2909: #define        CBLEN   80
                   2910: #define        NUMCB   6
                   2911: 
                   2912: char circ_buf[NUMCB][CBLEN];
                   2913: int nextcb = 0;
                   2914: 
                   2915: /*
                   2916:  * nextvar - find the next variable in the buffer
                   2917:  */
                   2918: int
                   2919: nextvar(
                   2920:        int *datalen,
                   2921:        const char **datap,
                   2922:        char **vname,
                   2923:        char **vvalue
                   2924:        )
                   2925: {
                   2926:        const char *cp;
                   2927:        char *np;
                   2928:        const char *cpend;
                   2929:        char *npend;    /* character after last */
                   2930:        int quoted = 0;
                   2931:        static char name[MAXVARLEN];
                   2932:        static char value[MAXVALLEN];
                   2933: 
                   2934:        cp = *datap;
                   2935:        cpend = cp + *datalen;
                   2936: 
                   2937:        /*
                   2938:         * Space past commas and white space
                   2939:         */
                   2940:        while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
                   2941:                cp++;
                   2942:        if (cp == cpend)
                   2943:                return 0;
                   2944:        
                   2945:        /*
                   2946:         * Copy name until we hit a ',', an '=', a '\r' or a '\n'.  Backspace
                   2947:         * over any white space and terminate it.
                   2948:         */
                   2949:        np = name;
                   2950:        npend = &name[MAXVARLEN];
                   2951:        while (cp < cpend && np < npend && *cp != ',' && *cp != '='
                   2952:               && *cp != '\r' && *cp != '\n')
                   2953:            *np++ = *cp++;
                   2954:        /*
                   2955:         * Check if we ran out of name space, without reaching the end or a
                   2956:         * terminating character
                   2957:         */
                   2958:        if (np == npend && !(cp == cpend || *cp == ',' || *cp == '=' ||
                   2959:                             *cp == '\r' || *cp == '\n'))
                   2960:            return 0;
                   2961:        while (isspace((int)(*(np-1))))
                   2962:            np--;
                   2963:        *np = '\0';
                   2964:        *vname = name;
                   2965: 
                   2966:        /*
                   2967:         * Check if we hit the end of the buffer or a ','.  If so we are done.
                   2968:         */
                   2969:        if (cp == cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
                   2970:                if (cp != cpend)
                   2971:                    cp++;
                   2972:                *datap = cp;
                   2973:                *datalen = cpend - cp;
                   2974:                *vvalue = (char *)0;
                   2975:                return 1;
                   2976:        }
                   2977: 
                   2978:        /*
                   2979:         * So far, so good.  Copy out the value
                   2980:         */
                   2981:        cp++;   /* past '=' */
                   2982:        while (cp < cpend && (isspace((int)*cp) && *cp != '\r' && *cp != '\n'))
                   2983:            cp++;
                   2984:        np = value;
                   2985:        npend = &value[MAXVALLEN];
                   2986:        while (cp < cpend && np < npend && ((*cp != ',') || quoted))
                   2987:        {
                   2988:                quoted ^= ((*np++ = *cp++) == '"');
                   2989:        }
                   2990: 
                   2991:        /*
                   2992:         * Check if we overran the value buffer while still in a quoted string
                   2993:         * or without finding a comma
                   2994:         */
                   2995:        if (np == npend && (quoted || *cp != ','))
                   2996:            return 0;
                   2997:        /*
                   2998:         * Trim off any trailing whitespace
                   2999:         */
                   3000:        while (np > value && isspace((int)(*(np-1))))
                   3001:            np--;
                   3002:        *np = '\0';
                   3003: 
                   3004:        /*
                   3005:         * Return this.  All done.
                   3006:         */
                   3007:        if (cp != cpend)
                   3008:            cp++;
                   3009:        *datap = cp;
                   3010:        *datalen = cpend - cp;
                   3011:        *vvalue = value;
                   3012:        return 1;
                   3013: }
                   3014: 
                   3015: 
                   3016: /*
                   3017:  * findvar - see if this variable is known to us.
                   3018:  * If "code" is 1, return ctl_var->code.
                   3019:  * Otherwise return the ordinal position of the found variable.
                   3020:  */
                   3021: int
                   3022: findvar(
                   3023:        char *varname,
                   3024:        struct ctl_var *varlist,
                   3025:        int code
                   3026:        )
                   3027: {
                   3028:        register char *np;
                   3029:        register struct ctl_var *vl;
                   3030: 
                   3031:        vl = varlist;
                   3032:        np = varname;
                   3033:        while (vl->fmt != EOV) {
                   3034:                if (vl->fmt != PADDING && STREQ(np, vl->text))
                   3035:                    return (code)
                   3036:                                ? vl->code
                   3037:                                : (vl - varlist)
                   3038:                            ;
                   3039:                vl++;
                   3040:        }
                   3041:        return 0;
                   3042: }
                   3043: 
                   3044: 
                   3045: 
                   3046: /*
                   3047:  * printvars - print variables returned in response packet
                   3048:  */
                   3049: void
                   3050: printvars(
                   3051:        int length,
                   3052:        const char *data,
                   3053:        int status,
                   3054:        int sttype,
                   3055:        int quiet,
                   3056:        FILE *fp
                   3057:        )
                   3058: {
                   3059:        if (rawmode)
                   3060:            rawprint(sttype, length, data, status, quiet, fp);
                   3061:        else
                   3062:            cookedprint(sttype, length, data, status, quiet, fp);
                   3063: }
                   3064: 
                   3065: 
                   3066: /*
                   3067:  * rawprint - do a printout of the data in raw mode
                   3068:  */
                   3069: static void
                   3070: rawprint(
                   3071:        int datatype,
                   3072:        int length,
                   3073:        const char *data,
                   3074:        int status,
                   3075:        int quiet,
                   3076:        FILE *fp
                   3077:        )
                   3078: {
                   3079:        const char *cp;
                   3080:        const char *cpend;
                   3081: 
                   3082:        /*
                   3083:         * Essentially print the data as is.  We reformat unprintables, though.
                   3084:         */
                   3085:        cp = data;
                   3086:        cpend = data + length;
                   3087: 
                   3088:        if (!quiet)
                   3089:                (void) fprintf(fp, "status=0x%04x,\n", status);
                   3090: 
                   3091:        while (cp < cpend) {
                   3092:                if (*cp == '\r') {
                   3093:                        /*
                   3094:                         * If this is a \r and the next character is a
                   3095:                         * \n, supress this, else pretty print it.  Otherwise
                   3096:                         * just output the character.
                   3097:                         */
                   3098:                        if (cp == (cpend - 1) || *(cp + 1) != '\n')
                   3099:                            makeascii(1, cp, fp);
                   3100:                } else if (isspace(*cp) || isprint(*cp))
                   3101:                        putc(*cp, fp);
                   3102:                else
                   3103:                        makeascii(1, cp, fp);
                   3104:                cp++;
                   3105:        }
                   3106: }
                   3107: 
                   3108: 
                   3109: /*
                   3110:  * Global data used by the cooked output routines
                   3111:  */
                   3112: int out_chars;         /* number of characters output */
                   3113: int out_linecount;     /* number of characters output on this line */
                   3114: 
                   3115: 
                   3116: /*
                   3117:  * startoutput - get ready to do cooked output
                   3118:  */
                   3119: static void
                   3120: startoutput(void)
                   3121: {
                   3122:        out_chars = 0;
                   3123:        out_linecount = 0;
                   3124: }
                   3125: 
                   3126: 
                   3127: /*
                   3128:  * output - output a variable=value combination
                   3129:  */
                   3130: static void
                   3131: output(
                   3132:        FILE *fp,
                   3133:        char *name,
                   3134:        char *value
                   3135:        )
                   3136: {
                   3137:        size_t len;
                   3138: 
                   3139:        /* strlen of "name=value" */
                   3140:        len = strlen(name) + 1 + strlen(value);
                   3141: 
                   3142:        if (out_chars != 0) {
                   3143:                out_chars += 2;
                   3144:                if ((out_linecount + len + 2) > MAXOUTLINE) {
                   3145:                        fputs(",\n", fp);
                   3146:                        out_linecount = 0;
                   3147:                } else {
                   3148:                        fputs(", ", fp);
                   3149:                        out_linecount += 2;
                   3150:                }
                   3151:        }
                   3152: 
                   3153:        fputs(name, fp);
                   3154:        putc('=', fp);
                   3155:        fputs(value, fp);
                   3156:        out_chars += len;
                   3157:        out_linecount += len;
                   3158: }
                   3159: 
                   3160: 
                   3161: /*
                   3162:  * endoutput - terminate a block of cooked output
                   3163:  */
                   3164: static void
                   3165: endoutput(
                   3166:        FILE *fp
                   3167:        )
                   3168: {
                   3169:        if (out_chars != 0)
                   3170:                putc('\n', fp);
                   3171: }
                   3172: 
                   3173: 
                   3174: /*
                   3175:  * outputarr - output an array of values
                   3176:  */
                   3177: static void
                   3178: outputarr(
                   3179:        FILE *fp,
                   3180:        char *name,
                   3181:        int narr,
                   3182:        l_fp *lfp
                   3183:        )
                   3184: {
                   3185:        register char *bp;
                   3186:        register char *cp;
                   3187:        register int i;
                   3188:        register int len;
                   3189:        char buf[256];
                   3190: 
                   3191:        bp = buf;
                   3192:        /*
                   3193:         * Hack to align delay and offset values
                   3194:         */
                   3195:        for (i = (int)strlen(name); i < 11; i++)
                   3196:            *bp++ = ' ';
                   3197:        
                   3198:        for (i = narr; i > 0; i--) {
                   3199:                if (i != narr)
                   3200:                    *bp++ = ' ';
                   3201:                cp = lfptoms(lfp, 2);
                   3202:                len = strlen(cp);
                   3203:                if (len > 7) {
                   3204:                        cp[7] = '\0';
                   3205:                        len = 7;
                   3206:                }
                   3207:                while (len < 7) {
                   3208:                        *bp++ = ' ';
                   3209:                        len++;
                   3210:                }
                   3211:                while (*cp != '\0')
                   3212:                    *bp++ = *cp++;
                   3213:                lfp++;
                   3214:        }
                   3215:        *bp = '\0';
                   3216:        output(fp, name, buf);
                   3217: }
                   3218: 
                   3219: static char *
                   3220: tstflags(
                   3221:        u_long val
                   3222:        )
                   3223: {
                   3224:        register char *cp, *s;
                   3225:        size_t cb;
                   3226:        register int i;
                   3227:        register const char *sep;
                   3228: 
                   3229:        sep = "";
                   3230:        i = 0;
                   3231:        s = cp = circ_buf[nextcb];
                   3232:        if (++nextcb >= NUMCB)
                   3233:                nextcb = 0;
                   3234:        cb = sizeof(circ_buf[0]);
                   3235: 
                   3236:        snprintf(cp, cb, "%02lx", val);
                   3237:        cp += strlen(cp);
                   3238:        cb -= strlen(cp);
                   3239:        if (!val) {
                   3240:                strncat(cp, " ok", cb);
                   3241:                cp += strlen(cp);
                   3242:                cb -= strlen(cp);
                   3243:        } else {
                   3244:                if (cb) {
                   3245:                        *cp++ = ' ';
                   3246:                        cb--;
                   3247:                }
                   3248:                for (i = 0; i < COUNTOF(tstflagnames); i++) {
                   3249:                        if (val & 0x1) {
                   3250:                                snprintf(cp, cb, "%s%s", sep,
                   3251:                                         tstflagnames[i]);
                   3252:                                sep = ", ";
                   3253:                                cp += strlen(cp);
                   3254:                                cb -= strlen(cp);
                   3255:                        }
                   3256:                        val >>= 1;
                   3257:                }
                   3258:        }
                   3259:        if (cb)
                   3260:                *cp = '\0';
                   3261: 
                   3262:        return s;
                   3263: }
                   3264: 
                   3265: /*
                   3266:  * cookedprint - output variables in cooked mode
                   3267:  */
                   3268: static void
                   3269: cookedprint(
                   3270:        int datatype,
                   3271:        int length,
                   3272:        const char *data,
                   3273:        int status,
                   3274:        int quiet,
                   3275:        FILE *fp
                   3276:        )
                   3277: {
                   3278:        register int varid;
                   3279:        char *name;
                   3280:        char *value;
                   3281:        char output_raw;
                   3282:        int fmt;
                   3283:        struct ctl_var *varlist;
                   3284:        l_fp lfp;
                   3285:        long ival;
                   3286:        sockaddr_u hval;
                   3287:        u_long uval;
                   3288:        l_fp lfparr[8];
                   3289:        int narr;
                   3290: 
                   3291:        switch (datatype) {
                   3292:        case TYPE_PEER:
                   3293:                varlist = peer_var;
                   3294:                break;
                   3295:        case TYPE_SYS:
                   3296:                varlist = sys_var;
                   3297:                break;
                   3298:        case TYPE_CLOCK:
                   3299:                varlist = clock_var;
                   3300:                break;
                   3301:        default:
                   3302:                fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n",
                   3303:                        datatype);
                   3304:                return;
                   3305:        }
                   3306: 
                   3307:        if (!quiet)
                   3308:                fprintf(fp, "status=%04x %s,\n", status,
                   3309:                        statustoa(datatype, status));
                   3310: 
                   3311:        startoutput();
                   3312:        while (nextvar(&length, &data, &name, &value)) {
                   3313:                varid = findvar(name, varlist, 0);
                   3314:                if (varid == 0) {
                   3315:                        output_raw = '*';
                   3316:                } else {
                   3317:                        output_raw = 0;
                   3318:                        fmt = varlist[varid].fmt;
                   3319:                        switch(fmt) {
                   3320:                            case TS:
                   3321:                                if (!decodets(value, &lfp))
                   3322:                                    output_raw = '?';
                   3323:                                else
                   3324:                                    output(fp, name, prettydate(&lfp));
                   3325:                                break;
                   3326:                            case FL:
                   3327:                            case FU:
                   3328:                            case FS:
                   3329:                                if (!decodetime(value, &lfp))
                   3330:                                    output_raw = '?';
                   3331:                                else {
                   3332:                                        switch (fmt) {
                   3333:                                            case FL:
                   3334:                                                output(fp, name,
                   3335:                                                       lfptoms(&lfp, 3));
                   3336:                                                break;
                   3337:                                            case FU:
                   3338:                                                output(fp, name,
                   3339:                                                       ulfptoms(&lfp, 3));
                   3340:                                                break;
                   3341:                                            case FS:
                   3342:                                                output(fp, name,
                   3343:                                                       lfptoms(&lfp, 3));
                   3344:                                                break;
                   3345:                                        }
                   3346:                                }
                   3347:                                break;
                   3348:                        
                   3349:                            case UI:
                   3350:                                if (!decodeuint(value, &uval))
                   3351:                                    output_raw = '?';
                   3352:                                else
                   3353:                                    output(fp, name, uinttoa(uval));
                   3354:                                break;
                   3355:                        
                   3356:                            case SI:
                   3357:                                if (!decodeint(value, &ival))
                   3358:                                    output_raw = '?';
                   3359:                                else
                   3360:                                    output(fp, name, inttoa(ival));
                   3361:                                break;
                   3362: 
                   3363:                            case HA:
                   3364:                            case NA:
                   3365:                                if (!decodenetnum(value, &hval))
                   3366:                                    output_raw = '?';
                   3367:                                else if (fmt == HA){
                   3368:                                    output(fp, name, nntohost(&hval));
                   3369:                                } else {
                   3370:                                    output(fp, name, stoa(&hval));
                   3371:                                }
                   3372:                                break;
                   3373:                        
                   3374:                            case ST:
                   3375:                                output_raw = '*';
                   3376:                                break;
                   3377:                        
                   3378:                            case RF:
                   3379:                                if (decodenetnum(value, &hval)) {
                   3380:                                        if (ISREFCLOCKADR(&hval))
                   3381:                                                output(fp, name,
                   3382:                                                    refnumtoa(&hval));
                   3383:                                        else
                   3384:                                                output(fp, name, stoa(&hval));
                   3385:                                } else if ((int)strlen(value) <= 4)
                   3386:                                    output(fp, name, value);
                   3387:                                else
                   3388:                                    output_raw = '?';
                   3389:                                break;
                   3390: 
                   3391:                            case LP:
                   3392:                                if (!decodeuint(value, &uval) || uval > 3)
                   3393:                                    output_raw = '?';
                   3394:                                else {
                   3395:                                        char b[3];
                   3396:                                        b[0] = b[1] = '0';
                   3397:                                        if (uval & 0x2)
                   3398:                                            b[0] = '1';
                   3399:                                        if (uval & 0x1)
                   3400:                                            b[1] = '1';
                   3401:                                        b[2] = '\0';
                   3402:                                        output(fp, name, b);
                   3403:                                }
                   3404:                                break;
                   3405: 
                   3406:                            case OC:
                   3407:                                if (!decodeuint(value, &uval))
                   3408:                                    output_raw = '?';
                   3409:                                else {
                   3410:                                        char b[12];
                   3411: 
                   3412:                                        (void) snprintf(b, sizeof b, "%03lo", uval);
                   3413:                                        output(fp, name, b);
                   3414:                                }
                   3415:                                break;
                   3416:                        
                   3417:                            case MD:
                   3418:                                if (!decodeuint(value, &uval))
                   3419:                                    output_raw = '?';
                   3420:                                else
                   3421:                                    output(fp, name, uinttoa(uval));
                   3422:                                break;
                   3423:                        
                   3424:                            case AR:
                   3425:                                if (!decodearr(value, &narr, lfparr))
                   3426:                                    output_raw = '?';
                   3427:                                else
                   3428:                                    outputarr(fp, name, narr, lfparr);
                   3429:                                break;
                   3430: 
                   3431:                            case FX:
                   3432:                                if (!decodeuint(value, &uval))
                   3433:                                    output_raw = '?';
                   3434:                                else
                   3435:                                    output(fp, name, tstflags(uval));
                   3436:                                break;
                   3437:                        
                   3438:                            default:
                   3439:                                (void) fprintf(stderr,
                   3440:                                    "Internal error in cookedprint, %s=%s, fmt %d\n",
                   3441:                                    name, value, fmt);
                   3442:                                break;
                   3443:                        }
                   3444: 
                   3445:                }
                   3446:                if (output_raw != 0) {
                   3447:                        char bn[401];
                   3448:                        char bv[401];
                   3449:                        int len;
                   3450: 
                   3451:                        atoascii(name, MAXVARLEN, bn, sizeof(bn));
                   3452:                        atoascii(value, MAXVARLEN, bv, sizeof(bv));
                   3453:                        if (output_raw != '*') {
                   3454:                                len = strlen(bv);
                   3455:                                bv[len] = output_raw;
                   3456:                                bv[len+1] = '\0';
                   3457:                        }
                   3458:                        output(fp, bn, bv);
                   3459:                }
                   3460:        }
                   3461:        endoutput(fp);
                   3462: }
                   3463: 
                   3464: 
                   3465: /*
                   3466:  * sortassoc - sort associations in the cache into ascending order
                   3467:  */
                   3468: void
                   3469: sortassoc(void)
                   3470: {
                   3471:        if (numassoc > 1)
                   3472:                qsort((void *)assoc_cache, (size_t)numassoc,
                   3473:                    sizeof(assoc_cache[0]), assoccmp);
                   3474: }
                   3475: 
                   3476: 
                   3477: /*
                   3478:  * assoccmp - compare two associations
                   3479:  */
                   3480: static int
                   3481: assoccmp(
                   3482:        const void *t1,
                   3483:        const void *t2
                   3484:        )
                   3485: {
                   3486:        const struct association *ass1 = t1;
                   3487:        const struct association *ass2 = t2;
                   3488: 
                   3489:        if (ass1->assid < ass2->assid)
                   3490:                return -1;
                   3491:        if (ass1->assid > ass2->assid)
                   3492:                return 1;
                   3493:        return 0;
                   3494: }
                   3495: 
                   3496: 
                   3497: /*
                   3498:  * ntpq_custom_opt_handler - autoopts handler for -c and -p
                   3499:  *
                   3500:  * By default, autoopts loses the relative order of -c and -p options
                   3501:  * on the command line.  This routine replaces the default handler for
                   3502:  * those routines and builds a list of commands to execute preserving
                   3503:  * the order.
                   3504:  */
                   3505: void
                   3506: ntpq_custom_opt_handler(
                   3507:        tOptions *pOptions,
                   3508:        tOptDesc *pOptDesc
                   3509:        )
                   3510: {
                   3511:        switch (pOptDesc->optValue) {
                   3512:        
                   3513:        default:
                   3514:                fprintf(stderr, 
                   3515:                        "ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
                   3516:                        pOptDesc->optValue, pOptDesc->optValue);
                   3517:                exit(-1);
                   3518: 
                   3519:        case 'c':
                   3520:                ADDCMD(pOptDesc->pzLastArg);
                   3521:                break;
                   3522: 
                   3523:        case 'p':
                   3524:                ADDCMD("peers");
                   3525:                break;
                   3526:        }
                   3527: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>