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

1.1       misho       1: /*
                      2:  * ntpdc - control and monitor your ntpd daemon
                      3:  */
                      4: 
                      5: #include <stdio.h>
                      6: #include <stddef.h>
                      7: #include <ctype.h>
                      8: #include <signal.h>
                      9: #include <setjmp.h>
                     10: 
                     11: #include "ntpdc.h"
                     12: #include "ntp_select.h"
                     13: #include "ntp_io.h"
                     14: #include "ntp_stdlib.h"
                     15: #include "ntp_assert.h"
                     16: #include "ntp_lineedit.h"
                     17: #include "isc/net.h"
                     18: #include "isc/result.h"
                     19: #include <ssl_applink.c>
                     20: 
                     21: #include "ntp_libopts.h"
                     22: #include "ntpdc-opts.h"
                     23: 
                     24: #ifdef SYS_WINNT
                     25: # include <Mswsock.h>
                     26: # include <io.h>
                     27: #endif /* SYS_WINNT */
                     28: 
                     29: #ifdef SYS_VXWORKS
                     30:                                /* vxWorks needs mode flag -casey*/
                     31: # define open(name, flags)   open(name, flags, 0777)
                     32: # define SERVER_PORT_NUM     123
                     33: #endif
                     34: 
                     35: /* We use COMMAND as an autogen keyword */
                     36: #ifdef COMMAND
                     37: # undef COMMAND
                     38: #endif
                     39: 
                     40: /*
                     41:  * Because we now potentially understand a lot of commands (and
                     42:  * it requires a lot of commands to talk to ntpd) we will run
                     43:  * interactive if connected to a terminal.
                     44:  */
                     45: static int     interactive = 0;        /* set to 1 when we should prompt */
                     46: static const char *    prompt = "ntpdc> ";     /* prompt to ask him about */
                     47: 
                     48: /*
                     49:  * Keyid used for authenticated requests.  Obtained on the fly.
                     50:  */
                     51: static u_long  info_auth_keyid;
                     52: static int keyid_entered = 0;
                     53: 
                     54: static int     info_auth_keytype = NID_md5;    /* MD5 */
                     55: static size_t  info_auth_hashlen = 16;         /* MD5 */
                     56: u_long current_time;           /* needed by authkeys; not used */
                     57: 
                     58: /*
                     59:  * for get_systime()
                     60:  */
                     61: s_char sys_precision;          /* local clock precision (log2 s) */
                     62: 
                     63: int            ntpdcmain       (int,   char **);
                     64: /*
                     65:  * Built in command handler declarations
                     66:  */
                     67: static int     openhost        (const char *);
                     68: static int     sendpkt         (void *, size_t);
                     69: static void    growpktdata     (void);
                     70: static int     getresponse     (int, int, int *, int *, char **, int);
                     71: static int     sendrequest     (int, int, int, u_int, size_t, char *);
                     72: static void    getcmds         (void);
                     73: static RETSIGTYPE abortcmd     (int);
                     74: static void    docmd           (const char *);
                     75: static void    tokenize        (const char *, char **, int *);
                     76: static int     findcmd         (char *, struct xcmd *, struct xcmd *, struct xcmd **);
                     77: static int     getarg          (char *, int, arg_v *);
                     78: static int     getnetnum       (const char *, sockaddr_u *, char *, int);
                     79: static void    help            (struct parse *, FILE *);
                     80: static int     helpsort        (const void *, const void *);
                     81: static void    printusage      (struct xcmd *, FILE *);
                     82: static void    timeout         (struct parse *, FILE *);
                     83: static void    my_delay        (struct parse *, FILE *);
                     84: static void    host            (struct parse *, FILE *);
                     85: static void    keyid           (struct parse *, FILE *);
                     86: static void    keytype         (struct parse *, FILE *);
                     87: static void    passwd          (struct parse *, FILE *);
                     88: static void    hostnames       (struct parse *, FILE *);
                     89: static void    setdebug        (struct parse *, FILE *);
                     90: static void    quit            (struct parse *, FILE *);
                     91: static void    version         (struct parse *, FILE *);
                     92: static void    warning         (const char *, const char *, const char *);
                     93: static void    error           (const char *, const char *, const char *);
                     94: static u_long  getkeyid        (const char *);
                     95: 
                     96: 
                     97: 
                     98: /*
                     99:  * Built-in commands we understand
                    100:  */
                    101: static struct xcmd builtins[] = {
                    102:        { "?",          help,           {  OPT|NTP_STR, NO, NO, NO },
                    103:          { "command", "", "", "" },
                    104:          "tell the use and syntax of commands" },
                    105:        { "help",       help,           {  OPT|NTP_STR, NO, NO, NO },
                    106:          { "command", "", "", "" },
                    107:          "tell the use and syntax of commands" },
                    108:        { "timeout",    timeout,        { OPT|NTP_UINT, NO, NO, NO },
                    109:          { "msec", "", "", "" },
                    110:          "set the primary receive time out" },
                    111:        { "delay",      my_delay,       { OPT|NTP_INT, NO, NO, NO },
                    112:          { "msec", "", "", "" },
                    113:          "set the delay added to encryption time stamps" },
                    114:        { "host",       host,           { OPT|NTP_STR, OPT|NTP_STR, NO, NO },
                    115:          { "-4|-6", "hostname", "", "" },
                    116:          "specify the host whose NTP server we talk to" },
                    117:        { "passwd",     passwd,         { OPT|NTP_STR, NO, NO, NO },
                    118:          { "", "", "", "" },
                    119:          "specify a password to use for authenticated requests"},
                    120:        { "hostnames",  hostnames,      { OPT|NTP_STR, NO, NO, NO },
                    121:          { "yes|no", "", "", "" },
                    122:          "specify whether hostnames or net numbers are printed"},
                    123:        { "debug",      setdebug,       { OPT|NTP_STR, NO, NO, NO },
                    124:          { "no|more|less", "", "", "" },
                    125:          "set/change debugging level" },
                    126:        { "quit",       quit,           { NO, NO, NO, NO },
                    127:          { "", "", "", "" },
                    128:          "exit ntpdc" },
                    129:        { "exit",       quit,           { NO, NO, NO, NO },
                    130:          { "", "", "", "" },
                    131:          "exit ntpdc" },
                    132:        { "keyid",      keyid,          { OPT|NTP_UINT, NO, NO, NO },
                    133:          { "key#", "", "", "" },
                    134:          "set/show keyid to use for authenticated requests" },
                    135:        { "keytype",    keytype,        { OPT|NTP_STR, NO, NO, NO },
                    136:          { "(md5|des)", "", "", "" },
                    137:          "set/show key authentication type for authenticated requests (des|md5)" },
                    138:        { "version",    version,        { NO, NO, NO, NO },
                    139:          { "", "", "", "" },
                    140:          "print version number" },
                    141:        { 0,            0,              { NO, NO, NO, NO },
                    142:          { "", "", "", "" }, "" }
                    143: };
                    144: 
                    145: 
                    146: /*
                    147:  * Default values we use.
                    148:  */
                    149: #define        DEFHOST         "localhost"     /* default host name */
                    150: #define        DEFTIMEOUT      (5)             /* 5 second time out */
                    151: #define        DEFSTIMEOUT     (2)             /* 2 second time out after first */
                    152: #define        DEFDELAY        0x51EB852       /* 20 milliseconds, l_fp fraction */
                    153: #define        LENHOSTNAME     256             /* host name is 256 characters long */
                    154: #define        MAXCMDS         100             /* maximum commands on cmd line */
                    155: #define        MAXHOSTS        200             /* maximum hosts on cmd line */
                    156: #define        MAXLINE         512             /* maximum line length */
                    157: #define        MAXTOKENS       (1+1+MAXARGS+MOREARGS+2)        /* maximum number of usable tokens */
                    158: #define        SCREENWIDTH     78              /* nominal screen width in columns */
                    159: 
                    160: /*
                    161:  * Some variables used and manipulated locally
                    162:  */
                    163: static struct sock_timeval tvout = { DEFTIMEOUT, 0 };  /* time out for reads */
                    164: static struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
                    165: static l_fp delay_time;                                /* delay time */
                    166: static char currenthost[LENHOSTNAME];                  /* current host name */
                    167: int showhostnames = 1;                                 /* show host names by default */
                    168: 
                    169: static int ai_fam_templ;                               /* address family */
                    170: static int ai_fam_default;                             /* default address family */
                    171: static SOCKET sockfd;                                  /* fd socket is opened on */
                    172: static int havehost = 0;                               /* set to 1 when host open */
                    173: int s_port = 0;
                    174: 
                    175: /*
                    176:  * Holds data returned from queries.  We allocate INITDATASIZE
                    177:  * octets to begin with, increasing this as we need to.
                    178:  */
                    179: #define        INITDATASIZE    (sizeof(struct resp_pkt) * 16)
                    180: #define        INCDATASIZE     (sizeof(struct resp_pkt) * 8)
                    181: 
                    182: static char *pktdata;
                    183: static int pktdatasize;
                    184: 
                    185: /*
                    186:  * These are used to help the magic with old and new versions of ntpd.
                    187:  */
                    188: int impl_ver = IMPL_XNTPD;
                    189: static int req_pkt_size = REQ_LEN_NOMAC;
                    190: 
                    191: /*
                    192:  * For commands typed on the command line (with the -c option)
                    193:  */
                    194: static int numcmds = 0;
                    195: static const char *ccmds[MAXCMDS];
                    196: #define        ADDCMD(cp)      if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
                    197: 
                    198: /*
                    199:  * When multiple hosts are specified.
                    200:  */
                    201: static int numhosts = 0;
                    202: static const char *chosts[MAXHOSTS];
                    203: #define        ADDHOST(cp)     if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
                    204: 
                    205: /*
                    206:  * Error codes for internal use
                    207:  */
                    208: #define        ERR_INCOMPLETE          16
                    209: #define        ERR_TIMEOUT             17
                    210: 
                    211: /*
                    212:  * Macro definitions we use
                    213:  */
                    214: #define        ISSPACE(c)      ((c) == ' ' || (c) == '\t')
                    215: #define        ISEOL(c)        ((c) == '\n' || (c) == '\r' || (c) == '\0')
                    216: #define        STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
                    217: 
                    218: /*
                    219:  * For converting time stamps to dates
                    220:  */
                    221: #define        JAN_1970        2208988800      /* 1970 - 1900 in seconds */
                    222: 
                    223: /*
                    224:  * Jump buffer for longjumping back to the command level
                    225:  */
                    226: static jmp_buf interrupt_buf;
                    227: static  volatile int jump = 0;
                    228: 
                    229: /*
                    230:  * Pointer to current output unit
                    231:  */
                    232: static FILE *current_output;
                    233: 
                    234: /*
                    235:  * Command table imported from ntpdc_ops.c
                    236:  */
                    237: extern struct xcmd opcmds[];
                    238: 
                    239: char *progname;
                    240: volatile int debug;
                    241: 
                    242: #ifdef NO_MAIN_ALLOWED
                    243: CALL(ntpdc,"ntpdc",ntpdcmain);
                    244: #else
                    245: int
                    246: main(
                    247:        int argc,
                    248:        char *argv[]
                    249:        )
                    250: {
                    251:        return ntpdcmain(argc, argv);
                    252: }
                    253: #endif
                    254: 
                    255: #ifdef SYS_VXWORKS
                    256: void clear_globals(void)
                    257: {
                    258:     showhostnames = 0;              /* show host names by default */
                    259:     havehost = 0;                   /* set to 1 when host open */
                    260:     numcmds = 0;
                    261:     numhosts = 0;
                    262: }
                    263: #endif
                    264: 
                    265: /*
                    266:  * main - parse arguments and handle options
                    267:  */
                    268: int
                    269: ntpdcmain(
                    270:        int argc,
                    271:        char *argv[]
                    272:        )
                    273: {
                    274:        extern int ntp_optind;
                    275: 
                    276:        delay_time.l_ui = 0;
                    277:        delay_time.l_uf = DEFDELAY;
                    278: 
                    279: #ifdef SYS_VXWORKS
                    280:        clear_globals();
                    281:        taskPrioritySet(taskIdSelf(), 100 );
                    282: #endif
                    283: 
                    284:        init_lib();     /* sets up ipv4_works, ipv6_works */
                    285:        ssl_applink();
                    286: 
                    287:        /* Check to see if we have IPv6. Otherwise default to IPv4 */
                    288:        if (!ipv6_works)
                    289:                ai_fam_default = AF_INET;
                    290: 
                    291:        progname = argv[0];
                    292: 
                    293:        {
                    294:                int optct = ntpOptionProcess(&ntpdcOptions, argc, argv);
                    295:                argc -= optct;
                    296:                argv += optct;
                    297:        }
                    298: 
                    299:        if (HAVE_OPT(IPV4))
                    300:                ai_fam_templ = AF_INET;
                    301:        else if (HAVE_OPT(IPV6))
                    302:                ai_fam_templ = AF_INET6;
                    303:        else
                    304:                ai_fam_templ = ai_fam_default;
                    305: 
                    306:        if (HAVE_OPT(COMMAND)) {
                    307:                int             cmdct = STACKCT_OPT( COMMAND );
                    308:                const char**    cmds  = STACKLST_OPT( COMMAND );
                    309: 
                    310:                while (cmdct-- > 0) {
                    311:                        ADDCMD(*cmds++);
                    312:                }
                    313:        }
                    314: 
                    315:        debug = DESC(DEBUG_LEVEL).optOccCt;
                    316: 
                    317:        if (HAVE_OPT(INTERACTIVE)) {
                    318:                interactive = 1;
                    319:        }
                    320: 
                    321:        if (HAVE_OPT(NUMERIC)) {
                    322:                showhostnames = 0;
                    323:        }
                    324: 
                    325:        if (HAVE_OPT(LISTPEERS)) {
                    326:                ADDCMD("listpeers");
                    327:        }
                    328: 
                    329:        if (HAVE_OPT(PEERS)) {
                    330:                ADDCMD("peers");
                    331:        }
                    332: 
                    333:        if (HAVE_OPT(SHOWPEERS)) {
                    334:                ADDCMD("dmpeers");
                    335:        }
                    336: 
                    337:        if (ntp_optind == argc) {
                    338:                ADDHOST(DEFHOST);
                    339:        } else {
                    340:                for (; ntp_optind < argc; ntp_optind++)
                    341:                    ADDHOST(argv[ntp_optind]);
                    342:        }
                    343: 
                    344:        if (numcmds == 0 && interactive == 0
                    345:            && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
                    346:                interactive = 1;
                    347:        }
                    348: 
                    349: #if 0
                    350:        ai_fam_templ = ai_fam_default;
                    351:        while ((c = ntp_getopt(argc, argv, "46c:dilnps")) != EOF)
                    352:            switch (c) {
                    353:                case '4':
                    354:                    ai_fam_templ = AF_INET;
                    355:                    break;
                    356:                case '6':
                    357:                    ai_fam_templ = AF_INET6;
                    358:                    break;
                    359:                case 'c':
                    360:                    ADDCMD(ntp_optarg);
                    361:                    break;
                    362:                case 'd':
                    363:                    ++debug;
                    364:                    break;
                    365:                case 'i':
                    366:                    interactive = 1;
                    367:                    break;
                    368:                case 'l':
                    369:                    ADDCMD("listpeers");
                    370:                    break;
                    371:                case 'n':
                    372:                    showhostnames = 0;
                    373:                    break;
                    374:                case 'p':
                    375:                    ADDCMD("peers");
                    376:                    break;
                    377:                case 's':
                    378:                    ADDCMD("dmpeers");
                    379:                    break;
                    380:                default:
                    381:                    errflg++;
                    382:                    break;
                    383:            }
                    384: 
                    385:        if (errflg) {
                    386:                (void) fprintf(stderr,
                    387:                               "usage: %s [-46dilnps] [-c cmd] host ...\n",
                    388:                               progname);
                    389:                exit(2);
                    390:        }
                    391: 
                    392:        if (ntp_optind == argc) {
                    393:                ADDHOST(DEFHOST);
                    394:        } else {
                    395:                for (; ntp_optind < argc; ntp_optind++)
                    396:                    ADDHOST(argv[ntp_optind]);
                    397:        }
                    398: 
                    399:        if (numcmds == 0 && interactive == 0
                    400:            && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
                    401:                interactive = 1;
                    402:        }
                    403: #endif
                    404: 
                    405: #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
                    406:        if (interactive)
                    407:            (void) signal_no_reset(SIGINT, abortcmd);
                    408: #endif /* SYS_WINNT */
                    409: 
                    410:        /*
                    411:         * Initialize the packet data buffer
                    412:         */
                    413:        pktdatasize = INITDATASIZE;
                    414:        pktdata = emalloc(INITDATASIZE);
                    415: 
                    416:        if (numcmds == 0) {
                    417:                (void) openhost(chosts[0]);
                    418:                getcmds();
                    419:        } else {
                    420:                int ihost;
                    421:                int icmd;
                    422: 
                    423:                for (ihost = 0; ihost < numhosts; ihost++) {
                    424:                        if (openhost(chosts[ihost]))
                    425:                            for (icmd = 0; icmd < numcmds; icmd++) {
                    426:                                    if (numhosts > 1) 
                    427:                                        printf ("--- %s ---\n",chosts[ihost]);
                    428:                                    docmd(ccmds[icmd]);
                    429:                            }
                    430:                }
                    431:        }
                    432: #ifdef SYS_WINNT
                    433:        WSACleanup();
                    434: #endif
                    435:        return(0);
                    436: } /* main end */
                    437: 
                    438: 
                    439: /*
                    440:  * openhost - open a socket to a host
                    441:  */
                    442: static int
                    443: openhost(
                    444:        const char *hname
                    445:        )
                    446: {
                    447:        char temphost[LENHOSTNAME];
                    448:        int a_info, i;
                    449:        struct addrinfo hints, *ai = NULL;
                    450:        register const char *cp;
                    451:        char name[LENHOSTNAME];
                    452:        char service[5];
                    453: 
                    454:        /*
                    455:         * We need to get by the [] if they were entered 
                    456:         */
                    457:        
                    458:        cp = hname;
                    459:        
                    460:        if (*cp == '[') {
                    461:                cp++;   
                    462:                for (i = 0; *cp && *cp != ']'; cp++, i++)
                    463:                        name[i] = *cp;
                    464:                if (*cp == ']') {
                    465:                        name[i] = '\0';
                    466:                        hname = name;
                    467:                } else {
                    468:                        return 0;
                    469:                }
                    470:        }       
                    471: 
                    472:        /*
                    473:         * First try to resolve it as an ip address and if that fails,
                    474:         * do a fullblown (dns) lookup. That way we only use the dns
                    475:         * when it is needed and work around some implementations that
                    476:         * will return an "IPv4-mapped IPv6 address" address if you
                    477:         * give it an IPv4 address to lookup.
                    478:         */
                    479:        strcpy(service, "ntp");
                    480:        memset((char *)&hints, 0, sizeof(struct addrinfo));
                    481:        hints.ai_family = ai_fam_templ;
                    482:        hints.ai_protocol = IPPROTO_UDP;
                    483:        hints.ai_socktype = SOCK_DGRAM;
                    484:        hints.ai_flags = Z_AI_NUMERICHOST;
                    485: 
                    486:        a_info = getaddrinfo(hname, service, &hints, &ai);
                    487:        if (a_info == EAI_NONAME
                    488: #ifdef EAI_NODATA
                    489:            || a_info == EAI_NODATA
                    490: #endif
                    491:           ) {
                    492:                hints.ai_flags = AI_CANONNAME;
                    493: #ifdef AI_ADDRCONFIG
                    494:                hints.ai_flags |= AI_ADDRCONFIG;
                    495: #endif
                    496:                a_info = getaddrinfo(hname, service, &hints, &ai);      
                    497:        }
                    498:        /* Some older implementations don't like AI_ADDRCONFIG. */
                    499:        if (a_info == EAI_BADFLAGS) {
                    500:                hints.ai_flags = AI_CANONNAME;
                    501:                a_info = getaddrinfo(hname, service, &hints, &ai);      
                    502:        }
                    503:        if (a_info != 0) {
                    504:                (void) fprintf(stderr, "%s\n", gai_strerror(a_info));
                    505:                if (ai != NULL)
                    506:                        freeaddrinfo(ai);
                    507:                return 0;
                    508:        }
                    509: 
                    510:        /* 
                    511:         * getaddrinfo() has returned without error so ai should not 
                    512:         * be NULL.
                    513:         */
                    514:        NTP_INSIST(ai != NULL);
                    515: 
                    516:        if (ai->ai_canonname == NULL) {
                    517:                strncpy(temphost, stoa((sockaddr_u *)ai->ai_addr),
                    518:                    LENHOSTNAME);
                    519:                temphost[LENHOSTNAME-1] = '\0';
                    520:        } else {
                    521:                strncpy(temphost, ai->ai_canonname, LENHOSTNAME);
                    522:                temphost[LENHOSTNAME-1] = '\0';
                    523:        }
                    524: 
                    525:        if (debug > 2)
                    526:            printf("Opening host %s\n", temphost);
                    527: 
                    528:        if (havehost == 1) {
                    529:                if (debug > 2)
                    530:                    printf("Closing old host %s\n", currenthost);
                    531:                (void) closesocket(sockfd);
                    532:                havehost = 0;
                    533:        }
                    534:        (void) strcpy(currenthost, temphost);
                    535:        
                    536:        /* port maps to the same in both families */
                    537:        s_port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port; 
                    538: #ifdef SYS_VXWORKS
                    539:        ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
                    540:        if (ai->ai_family == AF_INET)
                    541:                *(struct sockaddr_in *)&hostaddr= 
                    542:                        *((struct sockaddr_in *)ai->ai_addr);
                    543:        else 
                    544:                *(struct sockaddr_in6 *)&hostaddr= 
                    545:                        *((struct sockaddr_in6 *)ai->ai_addr);
                    546: #endif /* SYS_VXWORKS */
                    547: 
                    548: #ifdef SYS_WINNT
                    549:        {
                    550:                int optionValue = SO_SYNCHRONOUS_NONALERT;
                    551:                int err;
                    552: 
                    553:                err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue));
                    554:                if (err != NO_ERROR) {
                    555:                        (void) fprintf(stderr, "cannot open nonoverlapped sockets\n");
                    556:                        exit(1);
                    557:                }
                    558:        }
                    559: 
                    560:        sockfd = socket(ai->ai_family, SOCK_DGRAM, 0);
                    561:        if (sockfd == INVALID_SOCKET) {
                    562:                error("socket", "", "");
                    563:                exit(-1);
                    564:        }
                    565: #else
                    566:        sockfd = socket(ai->ai_family, SOCK_DGRAM, 0);
                    567:        if (sockfd == -1)
                    568:            error("socket", "", "");
                    569: #endif /* SYS_WINNT */
                    570: 
                    571:        
                    572: #ifdef NEED_RCVBUF_SLOP
                    573: # ifdef SO_RCVBUF
                    574:        {
                    575:                int rbufsize = INITDATASIZE + 2048; /* 2K for slop */
                    576: 
                    577:                if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
                    578:                               &rbufsize, sizeof(int)) == -1)
                    579:                    error("setsockopt", "", "");
                    580:        }
                    581: # endif
                    582: #endif
                    583: 
                    584: #ifdef SYS_VXWORKS
                    585:        if (connect(sockfd, (struct sockaddr *)&hostaddr, 
                    586:                    sizeof(hostaddr)) == -1)
                    587: #else
                    588:        if (connect(sockfd, (struct sockaddr *)ai->ai_addr,
                    589:                    ai->ai_addrlen) == -1)
                    590: #endif /* SYS_VXWORKS */
                    591:            error("connect", "", "");
                    592: 
                    593:        freeaddrinfo(ai);
                    594:        havehost = 1;
                    595:        req_pkt_size = REQ_LEN_NOMAC;
                    596:        impl_ver = IMPL_XNTPD;
                    597:        return 1;
                    598: }
                    599: 
                    600: 
                    601: /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
                    602: /*
                    603:  * sendpkt - send a packet to the remote host
                    604:  */
                    605: static int
                    606: sendpkt(
                    607:        void *  xdata,
                    608:        size_t  xdatalen
                    609:        )
                    610: {
                    611:        if (send(sockfd, xdata, xdatalen, 0) == -1) {
                    612:                warning("write to %s failed", currenthost, "");
                    613:                return -1;
                    614:        }
                    615: 
                    616:        return 0;
                    617: }
                    618: 
                    619: 
                    620: /*
                    621:  * growpktdata - grow the packet data area
                    622:  */
                    623: static void
                    624: growpktdata(void)
                    625: {
                    626:        pktdatasize += INCDATASIZE;
                    627:        pktdata = erealloc(pktdata, (size_t)pktdatasize);
                    628: }
                    629: 
                    630: 
                    631: /*
                    632:  * getresponse - get a (series of) response packet(s) and return the data
                    633:  */
                    634: static int
                    635: getresponse(
                    636:        int implcode,
                    637:        int reqcode,
                    638:        int *ritems,
                    639:        int *rsize,
                    640:        char **rdata,
                    641:        int esize
                    642:        )
                    643: {
                    644:        struct resp_pkt rpkt;
                    645:        struct sock_timeval tvo;
                    646:        int items;
                    647:        int i;
                    648:        int size;
                    649:        int datasize;
                    650:        char *datap;
                    651:        char *tmp_data;
                    652:        char haveseq[MAXSEQ+1];
                    653:        int firstpkt;
                    654:        int lastseq;
                    655:        int numrecv;
                    656:        int seq;
                    657:        fd_set fds;
                    658:        int n;
                    659:        int pad;
                    660: 
                    661:        /*
                    662:         * This is pretty tricky.  We may get between 1 and many packets
                    663:         * back in response to the request.  We peel the data out of
                    664:         * each packet and collect it in one long block.  When the last
                    665:         * packet in the sequence is received we'll know how many we
                    666:         * should have had.  Note we use one long time out, should reconsider.
                    667:         */
                    668:        *ritems = 0;
                    669:        *rsize = 0;
                    670:        firstpkt = 1;
                    671:        numrecv = 0;
                    672:        *rdata = datap = pktdata;
                    673:        lastseq = 999;  /* too big to be a sequence number */
                    674:        memset(haveseq, 0, sizeof(haveseq));
                    675:        FD_ZERO(&fds);
                    676: 
                    677:     again:
                    678:        if (firstpkt)
                    679:                tvo = tvout;
                    680:        else
                    681:                tvo = tvsout;
                    682:        
                    683:        FD_SET(sockfd, &fds);
                    684:        n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo);
                    685: 
                    686:        if (n == -1) {
                    687:                warning("select fails", "", "");
                    688:                return -1;
                    689:        }
                    690:        if (n == 0) {
                    691:                /*
                    692:                 * Timed out.  Return what we have
                    693:                 */
                    694:                if (firstpkt) {
                    695:                        (void) fprintf(stderr,
                    696:                                       "%s: timed out, nothing received\n", currenthost);
                    697:                        return ERR_TIMEOUT;
                    698:                } else {
                    699:                        (void) fprintf(stderr,
                    700:                                       "%s: timed out with incomplete data\n",
                    701:                                       currenthost);
                    702:                        if (debug) {
                    703:                                printf("Received sequence numbers");
                    704:                                for (n = 0; n <= MAXSEQ; n++)
                    705:                                    if (haveseq[n])
                    706:                                        printf(" %d,", n);
                    707:                                if (lastseq != 999)
                    708:                                    printf(" last frame received\n");
                    709:                                else
                    710:                                    printf(" last frame not received\n");
                    711:                        }
                    712:                        return ERR_INCOMPLETE;
                    713:                }
                    714:        }
                    715: 
                    716:        n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
                    717:        if (n == -1) {
                    718:                warning("read", "", "");
                    719:                return -1;
                    720:        }
                    721: 
                    722: 
                    723:        /*
                    724:         * Check for format errors.  Bug proofing.
                    725:         */
                    726:        if (n < RESP_HEADER_SIZE) {
                    727:                if (debug)
                    728:                    printf("Short (%d byte) packet received\n", n);
                    729:                goto again;
                    730:        }
                    731:        if (INFO_VERSION(rpkt.rm_vn_mode) > NTP_VERSION ||
                    732:            INFO_VERSION(rpkt.rm_vn_mode) < NTP_OLDVERSION) {
                    733:                if (debug)
                    734:                    printf("Packet received with version %d\n",
                    735:                           INFO_VERSION(rpkt.rm_vn_mode));
                    736:                goto again;
                    737:        }
                    738:        if (INFO_MODE(rpkt.rm_vn_mode) != MODE_PRIVATE) {
                    739:                if (debug)
                    740:                    printf("Packet received with mode %d\n",
                    741:                           INFO_MODE(rpkt.rm_vn_mode));
                    742:                goto again;
                    743:        }
                    744:        if (INFO_IS_AUTH(rpkt.auth_seq)) {
                    745:                if (debug)
                    746:                    printf("Encrypted packet received\n");
                    747:                goto again;
                    748:        }
                    749:        if (!ISRESPONSE(rpkt.rm_vn_mode)) {
                    750:                if (debug)
                    751:                    printf("Received request packet, wanted response\n");
                    752:                goto again;
                    753:        }
                    754:        if (INFO_MBZ(rpkt.mbz_itemsize) != 0) {
                    755:                if (debug)
                    756:                    printf("Received packet with nonzero MBZ field!\n");
                    757:                goto again;
                    758:        }
                    759: 
                    760:        /*
                    761:         * Check implementation/request.  Could be old data getting to us.
                    762:         */
                    763:        if (rpkt.implementation != implcode || rpkt.request != reqcode) {
                    764:                if (debug)
                    765:                    printf(
                    766:                            "Received implementation/request of %d/%d, wanted %d/%d",
                    767:                            rpkt.implementation, rpkt.request,
                    768:                            implcode, reqcode);
                    769:                goto again;
                    770:        }
                    771: 
                    772:        /*
                    773:         * Check the error code.  If non-zero, return it.
                    774:         */
                    775:        if (INFO_ERR(rpkt.err_nitems) != INFO_OKAY) {
                    776:                if (debug && ISMORE(rpkt.rm_vn_mode)) {
                    777:                        printf("Error code %d received on not-final packet\n",
                    778:                               INFO_ERR(rpkt.err_nitems));
                    779:                }
                    780:                return (int)INFO_ERR(rpkt.err_nitems);
                    781:        }
                    782: 
                    783:        /*
                    784:         * Collect items and size.  Make sure they make sense.
                    785:         */
                    786:        items = INFO_NITEMS(rpkt.err_nitems);
                    787:        size = INFO_ITEMSIZE(rpkt.mbz_itemsize);
                    788:        if (esize > size)
                    789:                pad = esize - size;
                    790:        else 
                    791:                pad = 0;
                    792:        datasize = items * size;
                    793:        if ((size_t)datasize > (n-RESP_HEADER_SIZE)) {
                    794:                if (debug)
                    795:                    printf(
                    796:                            "Received items %d, size %d (total %d), data in packet is %lu\n",
                    797:                            items, size, datasize, (u_long)(n-RESP_HEADER_SIZE));
                    798:                goto again;
                    799:        }
                    800: 
                    801:        /*
                    802:         * If this isn't our first packet, make sure the size matches
                    803:         * the other ones.
                    804:         */
                    805:        if (!firstpkt && esize != *rsize) {
                    806:                if (debug)
                    807:                    printf("Received itemsize %d, previous %d\n",
                    808:                           size, *rsize);
                    809:                goto again;
                    810:        }
                    811:        /*
                    812:         * If we've received this before, +toss it
                    813:         */
                    814:        seq = INFO_SEQ(rpkt.auth_seq);
                    815:        if (haveseq[seq]) {
                    816:                if (debug)
                    817:                    printf("Received duplicate sequence number %d\n", seq);
                    818:                goto again;
                    819:        }
                    820:        haveseq[seq] = 1;
                    821: 
                    822:        /*
                    823:         * If this is the last in the sequence, record that.
                    824:         */
                    825:        if (!ISMORE(rpkt.rm_vn_mode)) {
                    826:                if (lastseq != 999) {
                    827:                        printf("Received second end sequence packet\n");
                    828:                        goto again;
                    829:                }
                    830:                lastseq = seq;
                    831:        }
                    832: 
                    833:        /*
                    834:         * So far, so good.  Copy this data into the output array.
                    835:         */
                    836:        if ((datap + datasize + (pad * items)) > (pktdata + pktdatasize)) {
                    837:                int offset = datap - pktdata;
                    838:                growpktdata();
                    839:                *rdata = pktdata; /* might have been realloced ! */
                    840:                datap = pktdata + offset;
                    841:        }
                    842:        /* 
                    843:         * We now move the pointer along according to size and number of
                    844:         * items.  This is so we can play nice with older implementations
                    845:         */
                    846: 
                    847:        tmp_data = rpkt.data;
                    848:        for (i = 0; i < items; i++) {
                    849:                memcpy(datap, tmp_data, (unsigned)size);
                    850:                tmp_data += size;
                    851:                memset(datap + size, 0, pad);
                    852:                datap += size + pad;
                    853:        }
                    854: 
                    855:        if (firstpkt) {
                    856:                firstpkt = 0;
                    857:                *rsize = size + pad;
                    858:        }
                    859:        *ritems += items;
                    860: 
                    861:        /*
                    862:         * Finally, check the count of received packets.  If we've got them
                    863:         * all, return
                    864:         */
                    865:        ++numrecv;
                    866:        if (numrecv <= lastseq)
                    867:                goto again;
                    868:        return INFO_OKAY;
                    869: }
                    870: 
                    871: 
                    872: /*
                    873:  * sendrequest - format and send a request packet
                    874:  *
                    875:  * Historically, ntpdc has used a fixed-size request packet regardless
                    876:  * of the actual payload size.  When authenticating, the timestamp, key
                    877:  * ID, and digest have been placed just before the end of the packet.
                    878:  * With the introduction in late 2009 of support for authenticated
                    879:  * ntpdc requests using larger 20-octet digests (vs. 16 for MD5), we
                    880:  * come up four bytes short.
                    881:  *
                    882:  * To maintain interop while allowing for larger digests, the behavior
                    883:  * is unchanged when using 16-octet digests.  For larger digests, the
                    884:  * timestamp, key ID, and digest are placed immediately following the
                    885:  * request payload, with the overall packet size variable.  ntpd can
                    886:  * distinguish 16-octet digests by the overall request size being
                    887:  * REQ_LEN_NOMAC + 4 + 16 with the auth bit enabled.  When using a
                    888:  * longer digest, that request size should be avoided.
                    889:  *
                    890:  * With the form used with 20-octet and larger digests, the timestamp,
                    891:  * key ID, and digest are located by ntpd relative to the start of the
                    892:  * packet, and the size of the digest is then implied by the packet
                    893:  * size.
                    894:  */
                    895: static int
                    896: sendrequest(
                    897:        int implcode,
                    898:        int reqcode,
                    899:        int auth,
                    900:        u_int qitems,
                    901:        size_t qsize,
                    902:        char *qdata
                    903:        )
                    904: {
                    905:        struct req_pkt qpkt;
                    906:        size_t  datasize;
                    907:        size_t  reqsize;
                    908:        u_long  key_id;
                    909:        l_fp    ts;
                    910:        l_fp *  ptstamp;
                    911:        int     maclen;
                    912:        char *  pass;
                    913: 
                    914:        memset(&qpkt, 0, sizeof(qpkt));
                    915: 
                    916:        qpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0);
                    917:        qpkt.implementation = (u_char)implcode;
                    918:        qpkt.request = (u_char)reqcode;
                    919: 
                    920:        datasize = qitems * qsize;
                    921:        if (datasize && qdata != NULL) {
                    922:                memcpy(qpkt.data, qdata, datasize);
                    923:                qpkt.err_nitems = ERR_NITEMS(0, qitems);
                    924:                qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);
                    925:        } else {
                    926:                qpkt.err_nitems = ERR_NITEMS(0, 0);
                    927:                qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize);  /* allow for optional first item */
                    928:        }
                    929: 
                    930:        if (!auth || (keyid_entered && info_auth_keyid == 0)) {
                    931:                qpkt.auth_seq = AUTH_SEQ(0, 0);
                    932:                return sendpkt(&qpkt, req_pkt_size);
                    933:        }
                    934: 
                    935:        if (info_auth_keyid == 0) {
                    936:                key_id = getkeyid("Keyid: ");
                    937:                if (!key_id) {
                    938:                        fprintf(stderr, "Invalid key identifier\n");
                    939:                        return 1;
                    940:                }
                    941:                info_auth_keyid = key_id;
                    942:        }
                    943:        if (!authistrusted(info_auth_keyid)) {
                    944:                pass = getpass_keytype(info_auth_keytype);
                    945:                if ('\0' == pass[0]) {
                    946:                        fprintf(stderr, "Invalid password\n");
                    947:                        return 1;
                    948:                }
                    949:                authusekey(info_auth_keyid, info_auth_keytype,
                    950:                           (u_char *)pass);
                    951:                authtrust(info_auth_keyid, 1);
                    952:        }
                    953:        qpkt.auth_seq = AUTH_SEQ(1, 0);
                    954:        if (info_auth_hashlen > 16) {
                    955:                /*
                    956:                 * Only ntpd which expects REQ_LEN_NOMAC plus maclen
                    957:                 * octets in an authenticated request using a 16 octet
                    958:                 * digest (that is, a newer ntpd) will handle digests
                    959:                 * larger than 16 octets, so for longer digests, do
                    960:                 * not attempt to shorten the requests for downlevel
                    961:                 * ntpd compatibility.
                    962:                 */
                    963:                if (REQ_LEN_NOMAC != req_pkt_size)
                    964:                        return 1;
                    965:                reqsize = REQ_LEN_HDR + datasize + sizeof(*ptstamp);
                    966:                /* align to 32 bits */
                    967:                reqsize = (reqsize + 3) & ~3;
                    968:        } else
                    969:                reqsize = req_pkt_size;
                    970:        ptstamp = (void *)((char *)&qpkt + reqsize);
                    971:        ptstamp--;
                    972:        get_systime(&ts);
                    973:        L_ADD(&ts, &delay_time);
                    974:        HTONL_FP(&ts, ptstamp);
                    975:        maclen = authencrypt(info_auth_keyid, (void *)&qpkt, reqsize);
                    976:        if (!maclen) {  
                    977:                fprintf(stderr, "Key not found\n");
                    978:                return 1;
                    979:        } else if (maclen != (info_auth_hashlen + sizeof(keyid_t))) {
                    980:                fprintf(stderr,
                    981:                        "%d octet MAC, %lu expected with %lu octet digest\n",
                    982:                        maclen, (u_long)(info_auth_hashlen + sizeof(keyid_t)),
                    983:                        (u_long)info_auth_hashlen);
                    984:                return 1;
                    985:        }
                    986:        return sendpkt(&qpkt, reqsize + maclen);
                    987: }
                    988: 
                    989: 
                    990: /*
                    991:  * doquery - send a request and process the response
                    992:  */
                    993: int
                    994: doquery(
                    995:        int implcode,
                    996:        int reqcode,
                    997:        int auth,
                    998:        int qitems,
                    999:        int qsize,
                   1000:        char *qdata,
                   1001:        int *ritems,
                   1002:        int *rsize,
                   1003:        char **rdata,
                   1004:        int quiet_mask,
                   1005:        int esize
                   1006:        )
                   1007: {
                   1008:        int res;
                   1009:        char junk[512];
                   1010:        fd_set fds;
                   1011:        struct sock_timeval tvzero;
                   1012: 
                   1013:        /*
                   1014:         * Check to make sure host is open
                   1015:         */
                   1016:        if (!havehost) {
                   1017:                (void) fprintf(stderr, "***No host open, use `host' command\n");
                   1018:                return -1;
                   1019:        }
                   1020: 
                   1021:        /*
                   1022:         * Poll the socket and clear out any pending data
                   1023:         */
                   1024: again:
                   1025:        do {
                   1026:                tvzero.tv_sec = tvzero.tv_usec = 0;
                   1027:                FD_ZERO(&fds);
                   1028:                FD_SET(sockfd, &fds);
                   1029:                res = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero);
                   1030: 
                   1031:                if (res == -1) {
                   1032:                        warning("polling select", "", "");
                   1033:                        return -1;
                   1034:                } else if (res > 0)
                   1035: 
                   1036:                    (void) recv(sockfd, junk, sizeof junk, 0);
                   1037:        } while (res > 0);
                   1038: 
                   1039: 
                   1040:        /*
                   1041:         * send a request
                   1042:         */
                   1043:        res = sendrequest(implcode, reqcode, auth, qitems, qsize, qdata);
                   1044:        if (res != 0)
                   1045:                return res;
                   1046:        
                   1047:        /*
                   1048:         * Get the response.  If we got a standard error, print a message
                   1049:         */
                   1050:        res = getresponse(implcode, reqcode, ritems, rsize, rdata, esize);
                   1051: 
                   1052:        /*
                   1053:         * Try to be compatible with older implementations of ntpd.
                   1054:         */
                   1055:        if (res == INFO_ERR_FMT && req_pkt_size != 48) {
                   1056:                int oldsize;
                   1057: 
                   1058:                oldsize = req_pkt_size;
                   1059: 
                   1060:                switch(req_pkt_size) {
                   1061:                case REQ_LEN_NOMAC:
                   1062:                        req_pkt_size = 160;
                   1063:                        break;
                   1064:                case 160:
                   1065:                        req_pkt_size = 48;
                   1066:                        break;
                   1067:                }
                   1068:                if (impl_ver == IMPL_XNTPD) {
                   1069:                        fprintf(stderr,
                   1070:                            "***Warning changing to older implementation\n");
                   1071:                        return INFO_ERR_IMPL;
                   1072:                }
                   1073: 
                   1074:                fprintf(stderr,
                   1075:                    "***Warning changing the request packet size from %d to %d\n",
                   1076:                    oldsize, req_pkt_size);
                   1077:                goto again;
                   1078:        }
                   1079: 
                   1080:        /* log error message if not told to be quiet */
                   1081:        if ((res > 0) && (((1 << res) & quiet_mask) == 0)) {
                   1082:                switch(res) {
                   1083:                case INFO_ERR_IMPL:
                   1084:                        /* Give us a chance to try the older implementation. */
                   1085:                        if (implcode == IMPL_XNTPD)
                   1086:                                break;
                   1087:                        (void) fprintf(stderr,
                   1088:                                       "***Server implementation incompatable with our own\n");
                   1089:                        break;
                   1090:                case INFO_ERR_REQ:
                   1091:                        (void) fprintf(stderr,
                   1092:                                       "***Server doesn't implement this request\n");
                   1093:                        break;
                   1094:                case INFO_ERR_FMT:
                   1095:                        (void) fprintf(stderr,
                   1096:                                       "***Server reports a format error in the received packet (shouldn't happen)\n");
                   1097:                        break;
                   1098:                case INFO_ERR_NODATA:
                   1099:                        (void) fprintf(stderr,
                   1100:                                       "***Server reports data not found\n");
                   1101:                        break;
                   1102:                case INFO_ERR_AUTH:
                   1103:                        (void) fprintf(stderr, "***Permission denied\n");
                   1104:                        break;
                   1105:                case ERR_TIMEOUT:
                   1106:                        (void) fprintf(stderr, "***Request timed out\n");
                   1107:                        break;
                   1108:                case ERR_INCOMPLETE:
                   1109:                        (void) fprintf(stderr,
                   1110:                                       "***Response from server was incomplete\n");
                   1111:                        break;
                   1112:                default:
                   1113:                        (void) fprintf(stderr,
                   1114:                                       "***Server returns unknown error code %d\n", res);
                   1115:                        break;
                   1116:                }
                   1117:        }
                   1118:        return res;
                   1119: }
                   1120: 
                   1121: 
                   1122: /*
                   1123:  * getcmds - read commands from the standard input and execute them
                   1124:  */
                   1125: static void
                   1126: getcmds(void)
                   1127: {
                   1128:        char *  line;
                   1129:        int     count;
                   1130: 
                   1131:        ntp_readline_init(interactive ? prompt : NULL);
                   1132: 
                   1133:        for (;;) {
                   1134:                line = ntp_readline(&count);
                   1135:                if (NULL == line)
                   1136:                        break;
                   1137:                docmd(line);
                   1138:                free(line);
                   1139:        }
                   1140: 
                   1141:        ntp_readline_uninit();
                   1142: }
                   1143: 
                   1144: 
                   1145: #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
                   1146: /*
                   1147:  * abortcmd - catch interrupts and abort the current command
                   1148:  */
                   1149: static RETSIGTYPE
                   1150: abortcmd(
                   1151:        int sig
                   1152:        )
                   1153: {
                   1154: 
                   1155:        if (current_output == stdout)
                   1156:            (void) fflush(stdout);
                   1157:        putc('\n', stderr);
                   1158:        (void) fflush(stderr);
                   1159:        if (jump) longjmp(interrupt_buf, 1);
                   1160: }
                   1161: #endif /* SYS_WINNT */
                   1162: 
                   1163: /*
                   1164:  * docmd - decode the command line and execute a command
                   1165:  */
                   1166: static void
                   1167: docmd(
                   1168:        const char *cmdline
                   1169:        )
                   1170: {
                   1171:        char *tokens[1+MAXARGS+MOREARGS+2];
                   1172:        struct parse pcmd;
                   1173:        int ntok;
                   1174:        int i, ti;
                   1175:        int rval;
                   1176:        struct xcmd *xcmd;
                   1177: 
                   1178:        ai_fam_templ = ai_fam_default;
                   1179:        /*
                   1180:         * Tokenize the command line.  If nothing on it, return.
                   1181:         */
                   1182:        tokenize(cmdline, tokens, &ntok);
                   1183:        if (ntok == 0)
                   1184:            return;
                   1185:        
                   1186:        /*
                   1187:         * Find the appropriate command description.
                   1188:         */
                   1189:        i = findcmd(tokens[0], builtins, opcmds, &xcmd);
                   1190:        if (i == 0) {
                   1191:                (void) fprintf(stderr, "***Command `%s' unknown\n",
                   1192:                               tokens[0]);
                   1193:                return;
                   1194:        } else if (i >= 2) {
                   1195:                (void) fprintf(stderr, "***Command `%s' ambiguous\n",
                   1196:                               tokens[0]);
                   1197:                return;
                   1198:        }
                   1199:        
                   1200:        /*
                   1201:         * Save the keyword, then walk through the arguments, interpreting
                   1202:         * as we go.
                   1203:         */
                   1204:        pcmd.keyword = tokens[0];
                   1205:        pcmd.nargs = 0;
                   1206:        ti = 1;
                   1207:        for (i = 0; i < MAXARGS && xcmd->arg[i] != NO;) {
                   1208:                if ((i+ti) >= ntok) {
                   1209:                        if (!(xcmd->arg[i] & OPT)) {
                   1210:                                printusage(xcmd, stderr);
                   1211:                                return;
                   1212:                        }
                   1213:                        break;
                   1214:                }
                   1215:                if ((xcmd->arg[i] & OPT) && (*tokens[i+ti] == '>'))
                   1216:                        break;
                   1217:                rval = getarg(tokens[i+ti], (int)xcmd->arg[i], &pcmd.argval[i]);
                   1218:                if (rval == -1) {
                   1219:                        ti++;
                   1220:                        continue;
                   1221:                }
                   1222:                if (rval == 0)
                   1223:                        return;
                   1224:                pcmd.nargs++;
                   1225:                i++;
                   1226:        }
                   1227: 
                   1228:        /* Any extra args are assumed to be "OPT|NTP_STR". */
                   1229:        for ( ; i < MAXARGS + MOREARGS;) {
                   1230:             if ((i+ti) >= ntok)
                   1231:                  break;
                   1232:                rval = getarg(tokens[i+ti], (int)(OPT|NTP_STR), &pcmd.argval[i]);
                   1233:                if (rval == -1) {
                   1234:                        ti++;
                   1235:                        continue;
                   1236:                }
                   1237:                if (rval == 0)
                   1238:                        return;
                   1239:                pcmd.nargs++;
                   1240:                i++;
                   1241:        }
                   1242: 
                   1243:        i += ti;
                   1244:        if (i < ntok && *tokens[i] == '>') {
                   1245:                char *fname;
                   1246: 
                   1247:                if (*(tokens[i]+1) != '\0')
                   1248:                    fname = tokens[i]+1;
                   1249:                else if ((i+1) < ntok)
                   1250:                    fname = tokens[i+1];
                   1251:                else {
                   1252:                        (void) fprintf(stderr, "***No file for redirect\n");
                   1253:                        return;
                   1254:                }
                   1255: 
                   1256:                current_output = fopen(fname, "w");
                   1257:                if (current_output == NULL) {
                   1258:                        (void) fprintf(stderr, "***Error opening %s: ", fname);
                   1259:                        perror("");
                   1260:                        return;
                   1261:                }
                   1262:        } else {
                   1263:                current_output = stdout;
                   1264:        }
                   1265: 
                   1266:        if (interactive && setjmp(interrupt_buf)) {
                   1267:                return;
                   1268:        } else {
                   1269:                jump = 1;
                   1270:                (xcmd->handler)(&pcmd, current_output);
                   1271:                jump = 0;
                   1272:                if (current_output != stdout)
                   1273:                        (void) fclose(current_output);
                   1274:                current_output = NULL;
                   1275:        }
                   1276: }
                   1277: 
                   1278: 
                   1279: /*
                   1280:  * tokenize - turn a command line into tokens
                   1281:  */
                   1282: static void
                   1283: tokenize(
                   1284:        const char *line,
                   1285:        char **tokens,
                   1286:        int *ntok
                   1287:        )
                   1288: {
                   1289:        register const char *cp;
                   1290:        register char *sp;
                   1291:        static char tspace[MAXLINE];
                   1292: 
                   1293:        sp = tspace;
                   1294:        cp = line;
                   1295:        for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
                   1296:                tokens[*ntok] = sp;
                   1297:                while (ISSPACE(*cp))
                   1298:                    cp++;
                   1299:                if (ISEOL(*cp))
                   1300:                    break;
                   1301:                do {
                   1302:                        *sp++ = *cp++;
                   1303:                } while (!ISSPACE(*cp) && !ISEOL(*cp));
                   1304: 
                   1305:                *sp++ = '\0';
                   1306:        }
                   1307: }
                   1308: 
                   1309: 
                   1310: 
                   1311: /*
                   1312:  * findcmd - find a command in a command description table
                   1313:  */
                   1314: static int
                   1315: findcmd(
                   1316:        register char *str,
                   1317:        struct xcmd *clist1,
                   1318:        struct xcmd *clist2,
                   1319:        struct xcmd **cmd
                   1320:        )
                   1321: {
                   1322:        register struct xcmd *cl;
                   1323:        register int clen;
                   1324:        int nmatch;
                   1325:        struct xcmd *nearmatch = NULL;
                   1326:        struct xcmd *clist;
                   1327: 
                   1328:        clen = strlen(str);
                   1329:        nmatch = 0;
                   1330:        if (clist1 != 0)
                   1331:            clist = clist1;
                   1332:        else if (clist2 != 0)
                   1333:            clist = clist2;
                   1334:        else
                   1335:            return 0;
                   1336: 
                   1337:     again:
                   1338:        for (cl = clist; cl->keyword != 0; cl++) {
                   1339:                /* do a first character check, for efficiency */
                   1340:                if (*str != *(cl->keyword))
                   1341:                    continue;
                   1342:                if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
                   1343:                        /*
                   1344:                         * Could be extact match, could be approximate.
                   1345:                         * Is exact if the length of the keyword is the
                   1346:                         * same as the str.
                   1347:                         */
                   1348:                        if (*((cl->keyword) + clen) == '\0') {
                   1349:                                *cmd = cl;
                   1350:                                return 1;
                   1351:                        }
                   1352:                        nmatch++;
                   1353:                        nearmatch = cl;
                   1354:                }
                   1355:        }
                   1356: 
                   1357:                                /*
                   1358:                                 * See if there is more to do.  If so, go again.  Sorry about the
                   1359:                                 * goto, too much looking at BSD sources...
                   1360:                                 */
                   1361:        if (clist == clist1 && clist2 != 0) {
                   1362:                clist = clist2;
                   1363:                goto again;
                   1364:        }
                   1365: 
                   1366:                                /*
                   1367:                                 * If we got extactly 1 near match, use it, else return number
                   1368:                                 * of matches.
                   1369:                                 */
                   1370:        if (nmatch == 1) {
                   1371:                *cmd = nearmatch;
                   1372:                return 1;
                   1373:        }
                   1374:        return nmatch;
                   1375: }
                   1376: 
                   1377: 
                   1378: /*
                   1379:  * getarg - interpret an argument token
                   1380:  *
                   1381:  * string is always set.
                   1382:  * type is set to the decoded type.
                   1383:  *
                   1384:  * return:      0 - failure
                   1385:  *              1 - success
                   1386:  *             -1 - skip to next token
                   1387:  */
                   1388: static int
                   1389: getarg(
                   1390:        char *str,
                   1391:        int code,
                   1392:        arg_v *argp
                   1393:        )
                   1394: {
                   1395:        int isneg;
                   1396:        char *cp, *np;
                   1397:        static const char *digits = "0123456789";
                   1398: 
                   1399:        memset(argp, 0, sizeof(*argp));
                   1400: 
                   1401:        argp->string = str;
                   1402:        argp->type   = code & ~OPT;
                   1403: 
                   1404:        switch (argp->type) {
                   1405:            case NTP_STR:
                   1406:                break;
                   1407:            case NTP_ADD:
                   1408:                if (!strcmp("-6", str)) {
                   1409:                        ai_fam_templ = AF_INET6;
                   1410:                        return -1;
                   1411:                } else if (!strcmp("-4", str)) {
                   1412:                        ai_fam_templ = AF_INET;
                   1413:                        return -1;
                   1414:                }
                   1415:                if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) {
                   1416:                        return 0;
                   1417:                }
                   1418:                break;
                   1419:            case NTP_INT:
                   1420:            case NTP_UINT:
                   1421:                isneg = 0;
                   1422:                np = str;
                   1423:                if (*np == '-') {
                   1424:                        np++;
                   1425:                        isneg = 1;
                   1426:                }
                   1427: 
                   1428:                argp->uval = 0;
                   1429:                do {
                   1430:                        cp = strchr(digits, *np);
                   1431:                        if (cp == NULL) {
                   1432:                                (void) fprintf(stderr,
                   1433:                                               "***Illegal integer value %s\n", str);
                   1434:                                return 0;
                   1435:                        }
                   1436:                        argp->uval *= 10;
                   1437:                        argp->uval += (cp - digits);
                   1438:                } while (*(++np) != '\0');
                   1439: 
                   1440:                if (isneg) {
                   1441:                        if ((code & ~OPT) == NTP_UINT) {
                   1442:                                (void) fprintf(stderr,
                   1443:                                               "***Value %s should be unsigned\n", str);
                   1444:                                return 0;
                   1445:                        }
                   1446:                        argp->ival = -argp->ival;
                   1447:                }
                   1448:                break;
                   1449:            case IP_VERSION:
                   1450:                if (!strcmp("-6", str))
                   1451:                        argp->ival = 6 ;
                   1452:                else if (!strcmp("-4", str))
                   1453:                        argp->ival = 4 ;
                   1454:                else {
                   1455:                        (void) fprintf(stderr,
                   1456:                            "***Version must be either 4 or 6\n");
                   1457:                        return 0;
                   1458:                }
                   1459:                break;
                   1460:        }
                   1461: 
                   1462:        return 1;
                   1463: }
                   1464: 
                   1465: 
                   1466: /*
                   1467:  * getnetnum - given a host name, return its net number
                   1468:  *            and (optional) full name
                   1469:  */
                   1470: static int
                   1471: getnetnum(
                   1472:        const char *hname,
                   1473:        sockaddr_u *num,
                   1474:        char *fullhost,
                   1475:        int af
                   1476:        )
                   1477: {
                   1478:        struct addrinfo hints, *ai = NULL;
                   1479: 
                   1480:        ZERO(hints);
                   1481:        hints.ai_flags = AI_CANONNAME;
                   1482: #ifdef AI_ADDRCONFIG
                   1483:        hints.ai_flags |= AI_ADDRCONFIG;
                   1484: #endif
                   1485:        
                   1486:        /*
                   1487:         * decodenetnum only works with addresses, but handles syntax
                   1488:         * that getaddrinfo doesn't:  [2001::1]:1234
                   1489:         */
                   1490:        if (decodenetnum(hname, num)) {
                   1491:                if (fullhost != NULL)
                   1492:                        getnameinfo(&num->sa, SOCKLEN(num), fullhost,
                   1493:                                    LENHOSTNAME, NULL, 0, 0);
                   1494:                return 1;
                   1495:        } else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
                   1496:                NTP_INSIST(sizeof(*num) >= ai->ai_addrlen);
                   1497:                memcpy(num, ai->ai_addr, ai->ai_addrlen);
                   1498:                if (fullhost != NULL) {
                   1499:                        if (ai->ai_canonname != NULL) {
                   1500:                                strncpy(fullhost, ai->ai_canonname,
                   1501:                                        LENHOSTNAME);
                   1502:                                fullhost[LENHOSTNAME - 1] = '\0';
                   1503:                        } else {
                   1504:                                getnameinfo(&num->sa, SOCKLEN(num),
                   1505:                                            fullhost, LENHOSTNAME, NULL,
                   1506:                                            0, 0);
                   1507:                        }
                   1508:                }
                   1509:                return 1;
                   1510:        }
                   1511:        fprintf(stderr, "***Can't find host %s\n", hname);
                   1512: 
                   1513:        return 0;
                   1514: }
                   1515: 
                   1516: /*
                   1517:  * nntohost - convert network number to host name.  This routine enforces
                   1518:  *            the showhostnames setting.
                   1519:  */
                   1520: char *
                   1521: nntohost(
                   1522:        sockaddr_u *netnum
                   1523:        )
                   1524: {
                   1525:        if (!showhostnames)
                   1526:                return stoa(netnum);
                   1527: 
                   1528:        if (ISREFCLOCKADR(netnum))
                   1529:                return refnumtoa(netnum);
                   1530:        return socktohost(netnum);
                   1531: }
                   1532: 
                   1533: 
                   1534: /*
                   1535:  * Finally, the built in command handlers
                   1536:  */
                   1537: 
                   1538: /*
                   1539:  * help - tell about commands, or details of a particular command
                   1540:  */
                   1541: static void
                   1542: help(
                   1543:        struct parse *pcmd,
                   1544:        FILE *fp
                   1545:        )
                   1546: {
                   1547:        struct xcmd *xcp;
                   1548:        char *cmd;
                   1549:        const char *list[100];
                   1550:        size_t word, words;
                   1551:        size_t row, rows;
                   1552:        size_t col, cols;
                   1553:        size_t length;
                   1554: 
                   1555:        if (pcmd->nargs == 0) {
                   1556:                words = 0;
                   1557:                for (xcp = builtins; xcp->keyword != 0; xcp++) {
                   1558:                        if (*(xcp->keyword) != '?')
                   1559:                                list[words++] = xcp->keyword;
                   1560:                }
                   1561:                for (xcp = opcmds; xcp->keyword != 0; xcp++)
                   1562:                        list[words++] = xcp->keyword;
                   1563: 
                   1564:                qsort((void *)list, (size_t)words, sizeof(list[0]),
                   1565:                      helpsort);
                   1566:                col = 0;
                   1567:                for (word = 0; word < words; word++) {
                   1568:                        length = strlen(list[word]);
                   1569:                        col = max(col, length);
                   1570:                }
                   1571: 
                   1572:                cols = SCREENWIDTH / ++col;
                   1573:                rows = (words + cols - 1) / cols;
                   1574: 
                   1575:                fprintf(fp, "ntpdc commands:\n");
                   1576: 
                   1577:                for (row = 0; row < rows; row++) {
                   1578:                        for (word = row; word < words; word += rows)
                   1579:                                fprintf(fp, "%-*.*s", col, col-1, list[word]);
                   1580:                        fprintf(fp, "\n");
                   1581:                }
                   1582:        } else {
                   1583:                cmd = pcmd->argval[0].string;
                   1584:                words = findcmd(cmd, builtins, opcmds, &xcp);
                   1585:                if (words == 0) {
                   1586:                        fprintf(stderr,
                   1587:                                "Command `%s' is unknown\n", cmd);
                   1588:                        return;
                   1589:                } else if (words >= 2) {
                   1590:                        fprintf(stderr,
                   1591:                                "Command `%s' is ambiguous\n", cmd);
                   1592:                        return;
                   1593:                }
                   1594:                fprintf(fp, "function: %s\n", xcp->comment);
                   1595:                printusage(xcp, fp);
                   1596:        }
                   1597: }
                   1598: 
                   1599: 
                   1600: /*
                   1601:  * helpsort - do hostname qsort comparisons
                   1602:  */
                   1603: static int
                   1604: helpsort(
                   1605:        const void *t1,
                   1606:        const void *t2
                   1607:        )
                   1608: {
                   1609:        const char * const *    name1 = t1;
                   1610:        const char * const *    name2 = t2;
                   1611: 
                   1612:        return strcmp(*name1, *name2);
                   1613: }
                   1614: 
                   1615: 
                   1616: /*
                   1617:  * printusage - print usage information for a command
                   1618:  */
                   1619: static void
                   1620: printusage(
                   1621:        struct xcmd *xcp,
                   1622:        FILE *fp
                   1623:        )
                   1624: {
                   1625:        int i, opt46;
                   1626: 
                   1627:        opt46 = 0;
                   1628:        (void) fprintf(fp, "usage: %s", xcp->keyword);
                   1629:        for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
                   1630:                if (opt46 == 0 && (xcp->arg[i] & ~OPT) == NTP_ADD) {
                   1631:                        (void) fprintf(fp, " [ -4|-6 ]");
                   1632:                        opt46 = 1;
                   1633:                }
                   1634:                if (xcp->arg[i] & OPT)
                   1635:                    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
                   1636:                else
                   1637:                    (void) fprintf(fp, " %s", xcp->desc[i]);
                   1638:        }
                   1639:        (void) fprintf(fp, "\n");
                   1640: }
                   1641: 
                   1642: 
                   1643: /*
                   1644:  * timeout - set time out time
                   1645:  */
                   1646: static void
                   1647: timeout(
                   1648:        struct parse *pcmd,
                   1649:        FILE *fp
                   1650:        )
                   1651: {
                   1652:        int val;
                   1653: 
                   1654:        if (pcmd->nargs == 0) {
                   1655:                val = tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
                   1656:                (void) fprintf(fp, "primary timeout %d ms\n", val);
                   1657:        } else {
                   1658:                tvout.tv_sec = pcmd->argval[0].uval / 1000;
                   1659:                tvout.tv_usec = (pcmd->argval[0].uval - (tvout.tv_sec * 1000))
                   1660:                        * 1000;
                   1661:        }
                   1662: }
                   1663: 
                   1664: 
                   1665: /*
                   1666:  * my_delay - set delay for auth requests
                   1667:  */
                   1668: static void
                   1669: my_delay(
                   1670:        struct parse *pcmd,
                   1671:        FILE *fp
                   1672:        )
                   1673: {
                   1674:        int isneg;
                   1675:        u_long val;
                   1676: 
                   1677:        if (pcmd->nargs == 0) {
                   1678:                val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
                   1679:                (void) fprintf(fp, "delay %lu ms\n", val);
                   1680:        } else {
                   1681:                if (pcmd->argval[0].ival < 0) {
                   1682:                        isneg = 1;
                   1683:                        val = (u_long)(-pcmd->argval[0].ival);
                   1684:                } else {
                   1685:                        isneg = 0;
                   1686:                        val = (u_long)pcmd->argval[0].ival;
                   1687:                }
                   1688: 
                   1689:                delay_time.l_ui = val / 1000;
                   1690:                val %= 1000;
                   1691:                delay_time.l_uf = val * 4294967;        /* 2**32/1000 */
                   1692: 
                   1693:                if (isneg)
                   1694:                    L_NEG(&delay_time);
                   1695:        }
                   1696: }
                   1697: 
                   1698: 
                   1699: /*
                   1700:  * host - set the host we are dealing with.
                   1701:  */
                   1702: static void
                   1703: host(
                   1704:        struct parse *pcmd,
                   1705:        FILE *fp
                   1706:        )
                   1707: {
                   1708:        int i;
                   1709: 
                   1710:        if (pcmd->nargs == 0) {
                   1711:                if (havehost)
                   1712:                    (void) fprintf(fp, "current host is %s\n", currenthost);
                   1713:                else
                   1714:                    (void) fprintf(fp, "no current host\n");
                   1715:                return;
                   1716:        }
                   1717: 
                   1718:        i = 0;
                   1719:        if (pcmd->nargs == 2) {
                   1720:                if (!strcmp("-4", pcmd->argval[i].string))
                   1721:                        ai_fam_templ = AF_INET;
                   1722:                else if (!strcmp("-6", pcmd->argval[i].string))
                   1723:                        ai_fam_templ = AF_INET6;
                   1724:                else {
                   1725:                        if (havehost)
                   1726:                                (void) fprintf(fp,
                   1727:                                    "current host remains %s\n", currenthost);
                   1728:                        else
                   1729:                                (void) fprintf(fp, "still no current host\n");
                   1730:                        return;
                   1731:                }
                   1732:                i = 1;
                   1733:        }
                   1734:        if (openhost(pcmd->argval[i].string)) {
                   1735:                (void) fprintf(fp, "current host set to %s\n", currenthost);
                   1736:        } else {
                   1737:                if (havehost)
                   1738:                    (void) fprintf(fp,
                   1739:                                   "current host remains %s\n", currenthost);
                   1740:                else
                   1741:                    (void) fprintf(fp, "still no current host\n");
                   1742:        }
                   1743: }
                   1744: 
                   1745: 
                   1746: /*
                   1747:  * keyid - get a keyid to use for authenticating requests
                   1748:  */
                   1749: static void
                   1750: keyid(
                   1751:        struct parse *pcmd,
                   1752:        FILE *fp
                   1753:        )
                   1754: {
                   1755:        if (pcmd->nargs == 0) {
                   1756:                if (info_auth_keyid == 0 && !keyid_entered)
                   1757:                    (void) fprintf(fp, "no keyid defined\n");
                   1758:                else if (info_auth_keyid == 0 && keyid_entered)
                   1759:                    (void) fprintf(fp, "no keyid will be sent\n");
                   1760:                else
                   1761:                    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
                   1762:        } else {
                   1763:                info_auth_keyid = pcmd->argval[0].uval;
                   1764:                keyid_entered = 1;
                   1765:        }
                   1766: }
                   1767: 
                   1768: 
                   1769: /*
                   1770:  * keytype - get type of key to use for authenticating requests
                   1771:  */
                   1772: static void
                   1773: keytype(
                   1774:        struct parse *pcmd,
                   1775:        FILE *fp
                   1776:        )
                   1777: {
                   1778:        const char *    digest_name;
                   1779:        size_t          digest_len;
                   1780:        int             key_type;
                   1781: 
                   1782:        if (!pcmd->nargs) {
                   1783:                fprintf(fp, "keytype is %s with %lu octet digests\n",
                   1784:                        keytype_name(info_auth_keytype),
                   1785:                        (u_long)info_auth_hashlen);
                   1786:                return;
                   1787:        }
                   1788: 
                   1789:        digest_name = pcmd->argval[0].string;
                   1790:        digest_len = 0;
                   1791:        key_type = keytype_from_text(digest_name, &digest_len);
                   1792: 
                   1793:        if (!key_type) {
                   1794:                fprintf(fp, "keytype must be 'md5'%s\n",
                   1795: #ifdef OPENSSL
                   1796:                        " or a digest type provided by OpenSSL");
                   1797: #else
                   1798:                        "");
                   1799: #endif
                   1800:                return;
                   1801:        }
                   1802: 
                   1803:        info_auth_keytype = key_type;
                   1804:        info_auth_hashlen = digest_len;
                   1805: }
                   1806: 
                   1807: 
                   1808: /*
                   1809:  * passwd - get an authentication key
                   1810:  */
                   1811: /*ARGSUSED*/
                   1812: static void
                   1813: passwd(
                   1814:        struct parse *pcmd,
                   1815:        FILE *fp
                   1816:        )
                   1817: {
                   1818:        char *pass;
                   1819: 
                   1820:        if (info_auth_keyid == 0) {
                   1821:                info_auth_keyid = getkeyid("Keyid: ");
                   1822:                if (info_auth_keyid == 0) {
                   1823:                        (void)fprintf(fp, "Keyid must be defined\n");
                   1824:                        return;
                   1825:                }
                   1826:        }
                   1827:        if (!interactive) {
                   1828:                authusekey(info_auth_keyid, info_auth_keytype,
                   1829:                           (u_char *)pcmd->argval[0].string);
                   1830:                authtrust(info_auth_keyid, 1);
                   1831:        } else {
                   1832:                pass = getpass_keytype(info_auth_keytype);
                   1833:                if (*pass == '\0')
                   1834:                    (void) fprintf(fp, "Password unchanged\n");
                   1835:                else {
                   1836:                    authusekey(info_auth_keyid, info_auth_keytype,
                   1837:                               (u_char *)pass);
                   1838:                    authtrust(info_auth_keyid, 1);
                   1839:                }
                   1840:        }
                   1841: }
                   1842: 
                   1843: 
                   1844: /*
                   1845:  * hostnames - set the showhostnames flag
                   1846:  */
                   1847: static void
                   1848: hostnames(
                   1849:        struct parse *pcmd,
                   1850:        FILE *fp
                   1851:        )
                   1852: {
                   1853:        if (pcmd->nargs == 0) {
                   1854:                if (showhostnames)
                   1855:                    (void) fprintf(fp, "hostnames being shown\n");
                   1856:                else
                   1857:                    (void) fprintf(fp, "hostnames not being shown\n");
                   1858:        } else {
                   1859:                if (STREQ(pcmd->argval[0].string, "yes"))
                   1860:                    showhostnames = 1;
                   1861:                else if (STREQ(pcmd->argval[0].string, "no"))
                   1862:                    showhostnames = 0;
                   1863:                else
                   1864:                    (void)fprintf(stderr, "What?\n");
                   1865:        }
                   1866: }
                   1867: 
                   1868: 
                   1869: /*
                   1870:  * setdebug - set/change debugging level
                   1871:  */
                   1872: static void
                   1873: setdebug(
                   1874:        struct parse *pcmd,
                   1875:        FILE *fp
                   1876:        )
                   1877: {
                   1878:        if (pcmd->nargs == 0) {
                   1879:                (void) fprintf(fp, "debug level is %d\n", debug);
                   1880:                return;
                   1881:        } else if (STREQ(pcmd->argval[0].string, "no")) {
                   1882:                debug = 0;
                   1883:        } else if (STREQ(pcmd->argval[0].string, "more")) {
                   1884:                debug++;
                   1885:        } else if (STREQ(pcmd->argval[0].string, "less")) {
                   1886:                debug--;
                   1887:        } else {
                   1888:                (void) fprintf(fp, "What?\n");
                   1889:                return;
                   1890:        }
                   1891:        (void) fprintf(fp, "debug level set to %d\n", debug);
                   1892: }
                   1893: 
                   1894: 
                   1895: /*
                   1896:  * quit - stop this nonsense
                   1897:  */
                   1898: /*ARGSUSED*/
                   1899: static void
                   1900: quit(
                   1901:        struct parse *pcmd,
                   1902:        FILE *fp
                   1903:        )
                   1904: {
                   1905:        if (havehost)
                   1906:            closesocket(sockfd);
                   1907:        exit(0);
                   1908: }
                   1909: 
                   1910: 
                   1911: /*
                   1912:  * version - print the current version number
                   1913:  */
                   1914: /*ARGSUSED*/
                   1915: static void
                   1916: version(
                   1917:        struct parse *pcmd,
                   1918:        FILE *fp
                   1919:        )
                   1920: {
                   1921: 
                   1922:        (void) fprintf(fp, "%s\n", Version);
                   1923:        return;
                   1924: }
                   1925: 
                   1926: 
                   1927: /*
                   1928:  * warning - print a warning message
                   1929:  */
                   1930: static void
                   1931: warning(
                   1932:        const char *fmt,
                   1933:        const char *st1,
                   1934:        const char *st2
                   1935:        )
                   1936: {
                   1937:        (void) fprintf(stderr, "%s: ", progname);
                   1938:        (void) fprintf(stderr, fmt, st1, st2);
                   1939:        (void) fprintf(stderr, ": ");
                   1940:        perror("");
                   1941: }
                   1942: 
                   1943: 
                   1944: /*
                   1945:  * error - print a message and exit
                   1946:  */
                   1947: static void
                   1948: error(
                   1949:        const char *fmt,
                   1950:        const char *st1,
                   1951:        const char *st2
                   1952:        )
                   1953: {
                   1954:        warning(fmt, st1, st2);
                   1955:        exit(1);
                   1956: }
                   1957: 
                   1958: /*
                   1959:  * getkeyid - prompt the user for a keyid to use
                   1960:  */
                   1961: static u_long
                   1962: getkeyid(
                   1963:        const char *keyprompt
                   1964:        )
                   1965: {
                   1966:        int c;
                   1967:        FILE *fi;
                   1968:        char pbuf[20];
                   1969:        size_t i;
                   1970:        size_t ilim;
                   1971: 
                   1972: #ifndef SYS_WINNT
                   1973:        if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
                   1974: #else
                   1975:        if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
                   1976: #endif /* SYS_WINNT */
                   1977:                fi = stdin;
                   1978:        else
                   1979:                setbuf(fi, (char *)NULL);
                   1980:        fprintf(stderr, "%s", keyprompt); fflush(stderr);
                   1981:        for (i = 0, ilim = COUNTOF(pbuf) - 1;
                   1982:             i < ilim && (c = getc(fi)) != '\n' && c != EOF;
                   1983:             )
                   1984:                pbuf[i++] = (char)c;
                   1985:        pbuf[i] = '\0';
                   1986:        if (fi != stdin)
                   1987:                fclose(fi);
                   1988: 
                   1989:        return (u_long) atoi(pbuf);
                   1990: }

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