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>