1 /*
2 * Copyright (c) 2005,2018
3 * Hartmut Brandt.
4 * All rights reserved.
5 *
6 * Author: Harti Brandt <harti@freebsd.org>
7 *
8 * Redistribution of this software and documentation and use in source and
9 * binary forms, with or without modification, are permitted provided that
10 * the following conditions are met:
11 *
12 * 1. Redistributions of source code or documentation must retain the above
13 * copyright notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
19 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $Begemot: bsnmp/snmp_ntp/snmp_ntp.c,v 1.9 2005/10/06 07:15:01 brandt_h Exp $
31 *
32 * NTP interface for SNMPd.
33 */
34
35 #include <sys/queue.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <sys/select.h>
39 #include <sys/socket.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <netdb.h>
43 #ifdef HAVE_STDINT_H
44 #include <stdint.h>
45 #elif defined(HAVE_INTTYPES_H)
46 #include <inttypes.h>
47 #endif
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <syslog.h>
52 #include <unistd.h>
53
54 #include "support.h"
55 #include "snmpmod.h"
56
57 #define SNMPTREE_TYPES
58 #include "ntp_tree.h"
59 #include "ntp_oid.h"
60
61 #define NTPC_MAX 576
62 #define NTPC_VERSION 3
63 #define NTPC_MODE 6
64 #define NTPC_DMAX 468
65
66 #define NTPC_BIT_RESP 0x80
67 #define NTPC_BIT_ERROR 0x40
68 #define NTPC_BIT_MORE 0x20
69
70 #define NTPC_OPMASK 0x1f
71 #define NTPC_OP_READSTAT 1
72 #define NTPC_OP_READVAR 2
73
74 /* our module handle */
75 static struct lmodule *module;
76
77 /* debug flag */
78 static uint32_t ntp_debug;
79 #define DBG_DUMP_PKTS 0x01
80 #define DBG_DUMP_VARS 0x02
81
82 /* OIDs */
83 static const struct asn_oid oid_ntpMIB = OIDX_ntpMIB;
84
85 /* the Object Resource registration index */
86 static u_int reg_index;
87
88 /* last time we've fetch the system variables */
89 static uint64_t sysinfo_tick;
90
91 /* cached system variables */
92 static int32_t sys_leap;
93 static int sysb_leap;
94 static int32_t sys_stratum;
95 static int sysb_stratum;
96 static int32_t sys_precision;
97 static int sysb_precision;
98 static char *sys_rootdelay;
99 static char *sys_rootdispersion;
100 static char *sys_refid;
101 static char sys_reftime[8];
102 static int sysb_reftime;
103 static int32_t sys_poll;
104 static int sysb_poll;
105 static uint32_t sys_peer;
106 static int sysb_peer;
107 static u_char sys_clock[8];
108 static int sysb_clock;
109 static char *sys_system;
110 static char *sys_processor;
111 static int sysb_jitter;
112 static double sys_jitter;
113 static int sysb_stability;
114 static double sys_stability;
115
116 /* last time we've fetch the peer list */
117 static uint64_t peers_tick;
118
119 /* request sequence number generator */
120 static uint16_t seqno;
121
122 /* NTPD socket */
123 static int ntpd_sock;
124 static void *ntpd_fd;
125
126 struct peer {
127 /* required entries for macros */
128 uint32_t index;
129 TAILQ_ENTRY(peer) link;
130
131 int32_t config; /* config bit */
132 u_char srcadr[4]; /* PeerAddress */
133 uint32_t srcport; /* PeerPort */
134 u_char dstadr[4]; /* HostAddress */
135 uint32_t dstport; /* HostPort */
136 int32_t leap; /* Leap */
137 int32_t hmode; /* Mode */
138 int32_t stratum; /* Stratum */
139 int32_t ppoll; /* PeerPoll */
140 int32_t hpoll; /* HostPoll */
141 int32_t precision; /* Precision */
142 char *rootdelay; /* RootDelay */
143 char *rootdispersion;/* RootDispersion */
144 char *refid; /* RefId */
145 u_char reftime[8]; /* RefTime */
146 u_char orgtime[8]; /* OrgTime */
147 u_char rcvtime[8]; /* ReceiveTime */
148 u_char xmttime[8]; /* TransmitTime */
149 u_int32_t reach; /* Reach */
150 int32_t timer; /* Timer */
151 char *offset; /* Offset */
152 char *delay; /* Delay */
153 char *dispersion; /* Dispersion */
154 int32_t filt_entries;
155 };
156 TAILQ_HEAD(peer_list, peer);
157
158 /* list of peers */
159 static struct peer_list peers = TAILQ_HEAD_INITIALIZER(peers);
160
161 struct filt {
162 /* required fields */
163 struct asn_oid index;
164 TAILQ_ENTRY(filt) link;
165
166 char *offset;
167 char *delay;
168 char *dispersion;
169 };
170 TAILQ_HEAD(filt_list, filt);
171
172 /* list of filters */
173 static struct filt_list filts = TAILQ_HEAD_INITIALIZER(filts);
174
175 /* configuration */
176 static u_char *ntp_host;
177 static u_char *ntp_port;
178 static uint32_t ntp_timeout;
179
180 static void ntpd_input(int, void *);
181 static int open_socket(void);
182
183 /* the initialization function */
184 static int
ntp_init(struct lmodule * mod,int argc,char * argv[]__unused)185 ntp_init(struct lmodule *mod, int argc, char *argv[] __unused)
186 {
187
188 module = mod;
189
190 if (argc != 0) {
191 syslog(LOG_ERR, "bad number of arguments for %s", __func__);
192 return (EINVAL);
193 }
194
195 ntp_host = strdup("localhost");
196 ntp_port = strdup("ntp");
197 ntp_timeout = 50; /* 0.5sec */
198
199 return (0);
200 }
201
202 /*
203 * Module is started
204 */
205 static void
ntp_start(void)206 ntp_start(void)
207 {
208
209 if (open_socket() != -1) {
210 ntpd_fd = fd_select(ntpd_sock, ntpd_input, NULL, module);
211 if (ntpd_fd == NULL) {
212 syslog(LOG_ERR, "fd_select failed on ntpd socket: %m");
213 return;
214 }
215 }
216 reg_index = or_register(&oid_ntpMIB, "The MIB for NTP.", module);
217 }
218
219 /*
220 * Called, when the module is to be unloaded after it was successfully loaded
221 */
222 static int
ntp_fini(void)223 ntp_fini(void)
224 {
225
226 or_unregister(reg_index);
227 fd_deselect(ntpd_fd);
228
229 return (0);
230 }
231
232 const struct snmp_module config = {
233 .comment = "This module implements the NTP MIB",
234 .init = ntp_init,
235 .start = ntp_start,
236 .fini = ntp_fini,
237 .tree = ntp_ctree,
238 .tree_size = ntp_CTREE_SIZE,
239 };
240
241 /*
242 * Open the NTPD socket
243 */
244 static int
open_socket(void)245 open_socket(void)
246 {
247 struct addrinfo hints, *res, *res0;
248 int error;
249 const char *cause;
250
251 memset(&hints, 0, sizeof(hints));
252 hints.ai_family = AF_INET;
253 hints.ai_socktype = SOCK_DGRAM;
254
255 error = getaddrinfo(ntp_host, ntp_port, &hints, &res0);
256 if (error) {
257 syslog(LOG_ERR, "%s(%s): %s", ntp_host, ntp_port,
258 gai_strerror(error));
259 return (-1);
260 }
261
262 ntpd_sock = -1;
263 cause = "no address";
264 errno = EADDRNOTAVAIL;
265 for (res = res0; res != NULL; res = res->ai_next) {
266 ntpd_sock = socket(res->ai_family, res->ai_socktype,
267 res->ai_protocol);
268 if (ntpd_sock == -1) {
269 cause = "socket";
270 continue;
271 }
272 if (connect(ntpd_sock, res->ai_addr, res->ai_addrlen) == -1) {
273 cause = "connect";
274 (void)close(ntpd_sock);
275 ntpd_sock = -1;
276 continue;
277 }
278 break;
279 }
280 if (ntpd_sock == -1) {
281 syslog(LOG_ERR, "%s: %m", cause);
282 return (-1);
283 }
284 freeaddrinfo(res0);
285 return (0);
286 }
287
288 /*
289 * Dump a packet
290 */
291 static void
dump_packet(const u_char * pkt,size_t ret)292 dump_packet(const u_char *pkt, size_t ret)
293 {
294 char buf[8 * 3 + 1];
295 size_t i, j;
296
297 for (i = 0; i < ret; i += 8) {
298 buf[0] = '\0';
299 for (j = 0; i + j < (size_t)ret && j < 8; j++)
300 sprintf(buf + strlen(buf), " %02x", pkt[i + j]);
301 syslog(LOG_INFO, "%04zu:%s", i, buf);
302 }
303 }
304
305 /*
306 * Execute an NTP request.
307 */
308 static int
ntpd_request(u_int op,u_int associd,const char * vars)309 ntpd_request(u_int op, u_int associd, const char *vars)
310 {
311 u_char *rpkt;
312 u_char *ptr;
313 size_t vlen;
314 ssize_t ret;
315
316 if ((rpkt = malloc(NTPC_MAX)) == NULL) {
317 syslog(LOG_ERR, "%m");
318 return (-1);
319 }
320 memset(rpkt, 0, NTPC_MAX);
321
322 ptr = rpkt;
323 *ptr++ = (NTPC_VERSION << 3) | NTPC_MODE;
324 *ptr++ = op;
325
326 if (++seqno == 0)
327 seqno++;
328 *ptr++ = seqno >> 8;
329 *ptr++ = seqno;
330
331 /* skip status */
332 ptr += 2;
333
334 *ptr++ = associd >> 8;
335 *ptr++ = associd;
336
337 /* skip offset */
338 ptr += 2;
339
340 if (vars != NULL) {
341 vlen = strlen(vars);
342 if (vlen > NTPC_DMAX) {
343 syslog(LOG_ERR, "NTP request too long (%zu)", vlen);
344 free(rpkt);
345 return (-1);
346 }
347 *ptr++ = vlen >> 8;
348 *ptr++ = vlen;
349
350 memcpy(ptr, vars, vlen);
351 ptr += vlen;
352 } else
353 /* skip data length (is already zero) */
354 ptr += 2;
355
356 while ((ptr - rpkt) % 4 != 0)
357 *ptr++ = 0;
358
359 if (ntp_debug & DBG_DUMP_PKTS) {
360 syslog(LOG_INFO, "sending %zd bytes", ptr - rpkt);
361 dump_packet(rpkt, ptr - rpkt);
362 }
363
364 ret = send(ntpd_sock, rpkt, ptr - rpkt, 0);
365 if (ret == -1) {
366 syslog(LOG_ERR, "cannot send to ntpd: %m");
367 free(rpkt);
368 return (-1);
369 }
370 return (0);
371 }
372
373 /*
374 * Callback if packet arrived from NTPD
375 */
376 static int
ntpd_read(uint16_t * op,uint16_t * associd,u_char ** data,size_t * datalen)377 ntpd_read(uint16_t *op, uint16_t *associd, u_char **data, size_t *datalen)
378 {
379 u_char pkt[NTPC_MAX + 1];
380 u_char *ptr, *nptr;
381 u_int n;
382 ssize_t ret;
383 size_t z;
384 u_int offset; /* current offset */
385 int more; /* more flag */
386 int sel;
387 struct timeval inc, end, rem;
388 fd_set iset;
389
390 *datalen = 0;
391 *data = NULL;
392 offset = 0;
393
394 inc.tv_sec = ntp_timeout / 100;
395 inc.tv_usec = (ntp_timeout % 100) * 1000;
396
397 (void)gettimeofday(&end, NULL);
398 timeradd(&end, &inc, &end);
399
400 next:
401 /* compute remaining time */
402 (void)gettimeofday(&rem, NULL);
403 if (timercmp(&rem, &end, >=)) {
404 /* do a poll */
405 rem.tv_sec = 0;
406 rem.tv_usec = 0;
407 } else {
408 timersub(&end, &rem, &rem);
409 }
410
411 /* select */
412 FD_ZERO(&iset);
413 FD_SET(ntpd_sock, &iset);
414 sel = select(ntpd_sock + 1, &iset, NULL, NULL, &rem);
415 if (sel == -1) {
416 if (errno == EINTR)
417 goto next;
418 syslog(LOG_ERR, "select ntpd_sock: %m");
419 free(*data);
420 return (-1);
421 }
422 if (sel == 0) {
423 syslog(LOG_ERR, "timeout on NTP connection");
424 free(*data);
425 return (-1);
426 }
427
428 /* now read it */
429 ret = recv(ntpd_sock, pkt, sizeof(pkt), 0);
430 if (ret == -1) {
431 syslog(LOG_ERR, "error reading from ntpd: %m");
432 free(*data);
433 return (-1);
434 }
435
436 if (ntp_debug & DBG_DUMP_PKTS) {
437 syslog(LOG_INFO, "got %zd bytes", ret);
438 dump_packet(pkt, (size_t)ret);
439 }
440
441 ptr = pkt;
442 if ((*ptr & 0x3f) != ((NTPC_VERSION << 3) | NTPC_MODE)) {
443 syslog(LOG_ERR, "unexpected packet version 0x%x", *ptr);
444 free(*data);
445 return (-1);
446 }
447 ptr++;
448
449 if (!(*ptr & NTPC_BIT_RESP)) {
450 syslog(LOG_ERR, "not a response packet");
451 return (-1);
452 }
453 if (*ptr & NTPC_BIT_ERROR) {
454 z = *datalen - 12;
455 if (z > NTPC_DMAX)
456 z = NTPC_DMAX;
457 syslog(LOG_ERR, "error response: %.*s", (int)z, pkt + 12);
458 free(*data);
459 return (-1);
460 }
461 more = (*ptr & NTPC_BIT_MORE);
462
463 *op = *ptr++ & NTPC_OPMASK;
464
465 /* seqno */
466 n = *ptr++ << 8;
467 n |= *ptr++;
468
469 if (n != seqno) {
470 syslog(LOG_ERR, "expecting seqno %u, got %u", seqno, n);
471 free(*data);
472 return (-1);
473 }
474
475 /* status */
476 n = *ptr++ << 8;
477 n |= *ptr++;
478
479 /* associd */
480 *associd = *ptr++ << 8;
481 *associd |= *ptr++;
482
483 /* offset */
484 n = *ptr++ << 8;
485 n |= *ptr++;
486
487 if (n != offset) {
488 syslog(LOG_ERR, "offset: expecting %u, got %u", offset, n);
489 free(*data);
490 return (-1);
491 }
492
493 /* count */
494 n = *ptr++ << 8;
495 n |= *ptr++;
496
497 if ((size_t)ret < 12 + n) {
498 syslog(LOG_ERR, "packet too short");
499 return (-1);
500 }
501
502 nptr = realloc(*data, *datalen + n);
503 if (nptr == NULL) {
504 syslog(LOG_ERR, "cannot allocate memory: %m");
505 free(*data);
506 return (-1);
507 }
508 *data = nptr;
509
510 memcpy(*data + offset, ptr, n);
511 *datalen += n;
512
513 if (!more)
514 return (0);
515
516 offset += n;
517 goto next;
518 }
519
520 /*
521 * Send a request and wait for the response
522 */
523 static int
ntpd_dialog(u_int op,u_int associd,const char * vars,u_char ** data,size_t * datalen)524 ntpd_dialog(u_int op, u_int associd, const char *vars, u_char **data,
525 size_t *datalen)
526 {
527 uint16_t rassocid;
528 uint16_t rop;
529
530 if (ntpd_request(op, associd, vars) == -1)
531 return (-1);
532 if (ntpd_read(&rop, &rassocid, data, datalen) == -1)
533 return (-1);
534
535 if (rop != op) {
536 syslog(LOG_ERR, "bad response op 0x%x", rop);
537 free(data);
538 return (-1);
539 }
540
541 if (associd != rassocid) {
542 syslog(LOG_ERR, "response for wrong associd");
543 free(data);
544 return (-1);
545 }
546 return (0);
547 }
548
549 /*
550 * Callback if packet arrived from NTPD
551 */
552 static void
ntpd_input(int fd __unused,void * arg __unused)553 ntpd_input(int fd __unused, void *arg __unused)
554 {
555 uint16_t associd;
556 uint16_t op;
557 u_char *data;
558 size_t datalen;
559
560 if (ntpd_read(&op, &associd, &data, &datalen) == -1)
561 return;
562
563 free(data);
564 }
565
566 /*
567 * Find the value of a variable
568 */
569 static int
ntpd_parse(u_char ** data,size_t * datalen,char ** namep,char ** valp)570 ntpd_parse(u_char **data, size_t *datalen, char **namep, char **valp)
571 {
572 u_char *ptr = *data;
573 u_char *end = ptr + *datalen;
574 char *ptr1;
575 char endc;
576
577 /* skip leading spaces */
578 while (ptr < end && isspace((int)*ptr))
579 ptr++;
580
581 if (ptr == end)
582 return (0);
583
584 *namep = ptr;
585
586 /* skip to space or '=' or ','*/
587 while (ptr < end && !isspace((int)*ptr) && *ptr != '=' && *ptr != ',')
588 ptr++;
589 endc = *ptr;
590 *ptr++ = '\0';
591
592 /* skip space */
593 while (ptr < end && isspace((int)*ptr))
594 ptr++;
595
596 if (ptr == end || endc == ',') {
597 /* no value */
598 *valp = NULL;
599 *datalen -= ptr - *data;
600 *data = ptr;
601 return (1);
602 }
603
604 if (*ptr == '"') {
605 /* quoted */
606 ptr++;
607 *valp = ptr;
608 while (ptr < end && *ptr != '"')
609 ptr++;
610 if (ptr == end)
611 return (0);
612
613 *ptr++ = '\0';
614
615 /* find comma */
616 while (ptr < end && isspace((int)*ptr) && *ptr == ',')
617 ptr++;
618 } else {
619 *valp = ptr;
620
621 /* skip to end of value */
622 while (ptr < end && *ptr != ',')
623 ptr++;
624
625 /* remove trailing blanks */
626 for (ptr1 = ptr; ptr1 > *valp; ptr1--)
627 if (!isspace((int)ptr1[-1]))
628 break;
629 *ptr1 = '\0';
630
631 if (ptr < end)
632 ptr++;
633 }
634
635 *datalen -= ptr - *data;
636 *data = ptr;
637
638 return (1);
639 }
640
641 /*
642 * Parse an int32 value
643 */
644 static int
val_parse_int32(const char * val,int32_t * p,int32_t min,int32_t max,int base)645 val_parse_int32(const char *val, int32_t *p, int32_t min, int32_t max, int base)
646 {
647 long n;
648 char *end;
649
650 errno = 0;
651 n = strtol(val, &end, base);
652 if (errno != 0 || *end != '\0')
653 return (0);
654 if (n < min || n > max)
655 return (0);
656 *p = (int32_t)n;
657 return (1);
658 }
659
660 /*
661 * Parse an uint32 value
662 */
663 static int
val_parse_uint32(const char * val,uint32_t * p,uint32_t min,uint32_t max,int base)664 val_parse_uint32(const char *val, uint32_t *p, uint32_t min, uint32_t max,
665 int base)
666 {
667 u_long n;
668 char *end;
669
670 errno = 0;
671 n = strtoul(val, &end, base);
672 if (errno != 0 || *end != '\0')
673 return (0);
674 if (n < min || n > max)
675 return (0);
676 *p = (uint32_t)n;
677 return (1);
678 }
679
680 /*
681 * Parse a double
682 */
683 static int
val_parse_double(const char * val,double * p)684 val_parse_double(const char *val, double *p)
685 {
686 char *end;
687
688 errno = 0;
689 *p = strtod(val, &end);
690 if (errno != 0 || *end != '\0')
691 return (0);
692 return (1);
693 }
694
695 static int
val_parse_ts(const char * val,char * buf)696 val_parse_ts(const char *val, char *buf)
697 {
698 int r, n;
699 u_int i, f;
700
701 if (strlen(val) > 2 && val[0] == '0' && val[1] == 'x') {
702 /* hex format */
703 r = sscanf(val + 2, "%x.%x%n", &i, &f, &n);
704 if (r != 2 || (size_t)n != strlen(val + 2))
705 return (0);
706 } else {
707 /* probably decimal */
708 r = sscanf(val, "%d.%d%n", &i, &f, &n);
709 if (r != 2 || (size_t)n != strlen(val))
710 return (0);
711 }
712 buf[0] = i >> 24;
713 buf[1] = i >> 16;
714 buf[2] = i >> 8;
715 buf[3] = i >> 0;
716 buf[4] = f >> 24;
717 buf[5] = f >> 16;
718 buf[6] = f >> 8;
719 buf[7] = f >> 0;
720 return (1);
721 }
722
723 /*
724 * Parse an IP address. This resolves non-numeric names.
725 */
726 static int
val_parse_ip(const char * val,u_char ip[4])727 val_parse_ip(const char *val, u_char ip[4])
728 {
729 int r, n, error;
730 struct addrinfo hints, *res0;
731 struct sockaddr_in *sin_local;
732
733 r = sscanf(val, "%hhd.%hhd.%hhd.%hhd%n",
734 &ip[0], &ip[1], &ip[2], &ip[3], &n);
735 if (n == 4 && (size_t)n == strlen(val))
736 return (0);
737
738 memset(ip, 0, 4);
739
740 memset(&hints, 0, sizeof(hints));
741 hints.ai_family = AF_INET;
742 hints.ai_socktype = SOCK_DGRAM;
743
744 error = getaddrinfo(val, NULL, &hints, &res0);
745 if (error) {
746 syslog(LOG_ERR, "%s: %s", val, gai_strerror(error));
747 return (-1);
748 }
749 if (res0 == NULL) {
750 syslog(LOG_ERR, "%s: no address", val);
751 return (-1);
752 }
753
754 sin_local = (struct sockaddr_in *)(void *)res0->ai_addr;
755 ip[3] = sin_local->sin_addr.s_addr >> 24;
756 ip[2] = sin_local->sin_addr.s_addr >> 16;
757 ip[1] = sin_local->sin_addr.s_addr >> 8;
758 ip[0] = sin_local->sin_addr.s_addr >> 0;
759
760 freeaddrinfo(res0);
761 return (0);
762 }
763
764 /*
765 * Fetch system info
766 */
767 static int
fetch_sysinfo(void)768 fetch_sysinfo(void)
769 {
770 u_char *data;
771 u_char *ptr;
772 size_t datalen;
773 char *name;
774 char *val;
775
776 if (ntpd_dialog(NTPC_OP_READVAR, 0,
777 "leap,stratum,precision,rootdelay,rootdispersion,refid,reftime,"
778 "poll,peer,clock,system,processor,jitter,stability",
779 &data, &datalen))
780 return (-1);
781
782 /* clear info */
783 sysb_leap = 0;
784 sysb_stratum = 0;
785 sysb_precision = 0;
786 free(sys_rootdelay);
787 sys_rootdelay = NULL;
788 free(sys_rootdispersion);
789 sys_rootdispersion = NULL;
790 free(sys_refid);
791 sys_refid = NULL;
792 sysb_reftime = 0;
793 sysb_poll = 0;
794 sysb_peer = 0;
795 sysb_clock = 0;
796 free(sys_system);
797 sys_system = NULL;
798 free(sys_processor);
799 sys_processor = NULL;
800 sysb_jitter = 0;
801 sysb_stability = 0;
802
803 ptr = data;
804 while (ntpd_parse(&ptr, &datalen, &name, &val)) {
805 if (ntp_debug & DBG_DUMP_VARS)
806 syslog(LOG_DEBUG, "%s: '%s'='%s'", __func__, name, val);
807 if (strcmp(name, "leap") == 0 ||
808 strcmp(name, "sys.leap") == 0) {
809 sysb_leap = val_parse_int32(val, &sys_leap,
810 0, 3, 2);
811
812 } else if (strcmp(name, "stratum") == 0 ||
813 strcmp(name, "sys.stratum") == 0) {
814 sysb_stratum = val_parse_int32(val, &sys_stratum,
815 0, 255, 0);
816
817 } else if (strcmp(name, "precision") == 0 ||
818 strcmp(name, "sys.precision") == 0) {
819 sysb_precision = val_parse_int32(val, &sys_precision,
820 INT32_MIN, INT32_MAX, 0);
821
822 } else if (strcmp(name, "rootdelay") == 0 ||
823 strcmp(name, "sys.rootdelay") == 0) {
824 sys_rootdelay = strdup(val);
825
826 } else if (strcmp(name, "rootdispersion") == 0 ||
827 strcmp(name, "sys.rootdispersion") == 0) {
828 sys_rootdispersion = strdup(val);
829
830 } else if (strcmp(name, "refid") == 0 ||
831 strcmp(name, "sys.refid") == 0) {
832 sys_refid = strdup(val);
833
834 } else if (strcmp(name, "reftime") == 0 ||
835 strcmp(name, "sys.reftime") == 0) {
836 sysb_reftime = val_parse_ts(val, sys_reftime);
837
838 } else if (strcmp(name, "poll") == 0 ||
839 strcmp(name, "sys.poll") == 0) {
840 sysb_poll = val_parse_int32(val, &sys_poll,
841 INT32_MIN, INT32_MAX, 0);
842
843 } else if (strcmp(name, "peer") == 0 ||
844 strcmp(name, "sys.peer") == 0) {
845 sysb_peer = val_parse_uint32(val, &sys_peer,
846 0, UINT32_MAX, 0);
847
848 } else if (strcmp(name, "clock") == 0 ||
849 strcmp(name, "sys.clock") == 0) {
850 sysb_clock = val_parse_ts(val, sys_clock);
851
852 } else if (strcmp(name, "system") == 0 ||
853 strcmp(name, "sys.system") == 0) {
854 sys_system = strdup(val);
855
856 } else if (strcmp(name, "processor") == 0 ||
857 strcmp(name, "sys.processor") == 0) {
858 sys_processor = strdup(val);
859
860 } else if (strcmp(name, "jitter") == 0 ||
861 strcmp(name, "sys.jitter") == 0) {
862 sysb_jitter = val_parse_double(val, &sys_jitter);
863
864 } else if (strcmp(name, "stability") == 0 ||
865 strcmp(name, "sys.stability") == 0) {
866 sysb_stability = val_parse_double(val, &sys_stability);
867 }
868 }
869
870 free(data);
871 return (0);
872 }
873
874 static int
parse_filt(char * val,uint16_t associd,int which)875 parse_filt(char *val, uint16_t associd, int which)
876 {
877 char *w;
878 int cnt;
879 struct filt *f;
880
881 cnt = 0;
882 for (w = strtok(val, " \t"); w != NULL; w = strtok(NULL, " \t")) {
883 TAILQ_FOREACH(f, &filts, link)
884 if (f->index.subs[0] == associd &&
885 f->index.subs[1] == (asn_subid_t)(cnt + 1))
886 break;
887 if (f == NULL) {
888 f = malloc(sizeof(*f));
889 memset(f, 0, sizeof(*f));
890 f->index.len = 2;
891 f->index.subs[0] = associd;
892 f->index.subs[1] = cnt + 1;
893
894 INSERT_OBJECT_OID(f, &filts);
895 }
896
897 switch (which) {
898
899 case 0:
900 f->offset = strdup(w);
901 break;
902
903 case 1:
904 f->delay = strdup(w);
905 break;
906
907 case 2:
908 f->dispersion = strdup(w);
909 break;
910
911 default:
912 abort();
913 }
914 cnt++;
915 }
916 return (cnt);
917 }
918
919 /*
920 * Fetch the complete peer list
921 */
922 static int
fetch_peers(void)923 fetch_peers(void)
924 {
925 u_char *data, *pdata, *ptr;
926 size_t datalen, pdatalen;
927 int i;
928 struct peer *p;
929 struct filt *f;
930 uint16_t associd;
931 char *name, *val;
932
933 /* free the old list */
934 while ((p = TAILQ_FIRST(&peers)) != NULL) {
935 TAILQ_REMOVE(&peers, p, link);
936 free(p->rootdelay);
937 free(p->rootdispersion);
938 free(p->refid);
939 free(p->offset);
940 free(p->delay);
941 free(p->dispersion);
942 free(p);
943 }
944 while ((f = TAILQ_FIRST(&filts)) != NULL) {
945 TAILQ_REMOVE(&filts, f, link);
946 free(f->offset);
947 free(f->delay);
948 free(f->dispersion);
949 free(f);
950 }
951
952 /* fetch the list of associations */
953 if (ntpd_dialog(NTPC_OP_READSTAT, 0, NULL, &data, &datalen))
954 return (-1);
955
956 for (i = 0; i < (int)(datalen / 4); i++) {
957 associd = data[4 * i + 0] << 8;
958 associd |= data[4 * i + 1] << 0;
959
960 /* ask for the association variables */
961 if (ntpd_dialog(NTPC_OP_READVAR, associd,
962 "config,srcadr,srcport,dstadr,dstport,leap,hmode,stratum,"
963 "hpoll,ppoll,precision,rootdelay,rootdispersion,refid,"
964 "reftime,org,rec,xmt,reach,timer,offset,delay,dispersion,"
965 "filtdelay,filtoffset,filtdisp",
966 &pdata, &pdatalen)) {
967 free(data);
968 return (-1);
969 }
970
971 /* now save and parse the data */
972 p = malloc(sizeof(*p));
973 if (p == NULL) {
974 free(data);
975 syslog(LOG_ERR, "%m");
976 return (-1);
977 }
978 memset(p, 0, sizeof(*p));
979 p->index = associd;
980 INSERT_OBJECT_INT(p, &peers);
981
982 ptr = pdata;
983 while (ntpd_parse(&ptr, &pdatalen, &name, &val)) {
984 if (ntp_debug & DBG_DUMP_VARS)
985 syslog(LOG_DEBUG, "%s: '%s'='%s'",
986 __func__, name, val);
987 if (strcmp(name, "config") == 0 ||
988 strcmp(name, "peer.config") == 0) {
989 val_parse_int32(val, &p->config, 0, 1, 0);
990
991 } else if (strcmp(name, "srcadr") == 0 ||
992 strcmp(name, "peer.srcadr") == 0) {
993 val_parse_ip(val, p->srcadr);
994
995 } else if (strcmp(name, "srcport") == 0 ||
996 strcmp(name, "peer.srcport") == 0) {
997 val_parse_uint32(val, &p->srcport,
998 1, 65535, 0);
999
1000 } else if (strcmp(name, "dstadr") == 0 ||
1001 strcmp(name, "peer.dstadr") == 0) {
1002 val_parse_ip(val, p->dstadr);
1003
1004 } else if (strcmp(name, "dstport") == 0 ||
1005 strcmp(name, "peer.dstport") == 0) {
1006 val_parse_uint32(val, &p->dstport,
1007 1, 65535, 0);
1008
1009 } else if (strcmp(name, "leap") == 0 ||
1010 strcmp(name, "peer.leap") == 0) {
1011 val_parse_int32(val, &p->leap, 0, 3, 2);
1012
1013 } else if (strcmp(name, "hmode") == 0 ||
1014 strcmp(name, "peer.hmode") == 0) {
1015 val_parse_int32(val, &p->hmode, 0, 7, 0);
1016
1017 } else if (strcmp(name, "stratum") == 0 ||
1018 strcmp(name, "peer.stratum") == 0) {
1019 val_parse_int32(val, &p->stratum, 0, 255, 0);
1020
1021 } else if (strcmp(name, "ppoll") == 0 ||
1022 strcmp(name, "peer.ppoll") == 0) {
1023 val_parse_int32(val, &p->ppoll,
1024 INT32_MIN, INT32_MAX, 0);
1025
1026 } else if (strcmp(name, "hpoll") == 0 ||
1027 strcmp(name, "peer.hpoll") == 0) {
1028 val_parse_int32(val, &p->hpoll,
1029 INT32_MIN, INT32_MAX, 0);
1030
1031 } else if (strcmp(name, "precision") == 0 ||
1032 strcmp(name, "peer.precision") == 0) {
1033 val_parse_int32(val, &p->hpoll,
1034 INT32_MIN, INT32_MAX, 0);
1035
1036 } else if (strcmp(name, "rootdelay") == 0 ||
1037 strcmp(name, "peer.rootdelay") == 0) {
1038 p->rootdelay = strdup(val);
1039
1040 } else if (strcmp(name, "rootdispersion") == 0 ||
1041 strcmp(name, "peer.rootdispersion") == 0) {
1042 p->rootdispersion = strdup(val);
1043
1044 } else if (strcmp(name, "refid") == 0 ||
1045 strcmp(name, "peer.refid") == 0) {
1046 p->refid = strdup(val);
1047
1048 } else if (strcmp(name, "reftime") == 0 ||
1049 strcmp(name, "sys.reftime") == 0) {
1050 val_parse_ts(val, p->reftime);
1051
1052 } else if (strcmp(name, "org") == 0 ||
1053 strcmp(name, "sys.org") == 0) {
1054 val_parse_ts(val, p->orgtime);
1055
1056 } else if (strcmp(name, "rec") == 0 ||
1057 strcmp(name, "sys.rec") == 0) {
1058 val_parse_ts(val, p->rcvtime);
1059
1060 } else if (strcmp(name, "xmt") == 0 ||
1061 strcmp(name, "sys.xmt") == 0) {
1062 val_parse_ts(val, p->xmttime);
1063
1064 } else if (strcmp(name, "reach") == 0 ||
1065 strcmp(name, "peer.reach") == 0) {
1066 val_parse_uint32(val, &p->reach,
1067 0, 65535, 0);
1068
1069 } else if (strcmp(name, "timer") == 0 ||
1070 strcmp(name, "peer.timer") == 0) {
1071 val_parse_int32(val, &p->timer,
1072 INT32_MIN, INT32_MAX, 0);
1073
1074 } else if (strcmp(name, "offset") == 0 ||
1075 strcmp(name, "peer.offset") == 0) {
1076 p->offset = strdup(val);
1077
1078 } else if (strcmp(name, "delay") == 0 ||
1079 strcmp(name, "peer.delay") == 0) {
1080 p->delay = strdup(val);
1081
1082 } else if (strcmp(name, "dispersion") == 0 ||
1083 strcmp(name, "peer.dispersion") == 0) {
1084 p->dispersion = strdup(val);
1085
1086 } else if (strcmp(name, "filtdelay") == 0 ||
1087 strcmp(name, "peer.filtdelay") == 0) {
1088 p->filt_entries = parse_filt(val, associd, 0);
1089
1090 } else if (strcmp(name, "filtoffset") == 0 ||
1091 strcmp(name, "peer.filtoffset") == 0) {
1092 p->filt_entries = parse_filt(val, associd, 1);
1093
1094 } else if (strcmp(name, "filtdisp") == 0 ||
1095 strcmp(name, "peer.filtdisp") == 0) {
1096 p->filt_entries = parse_filt(val, associd, 2);
1097 }
1098 }
1099 free(pdata);
1100 }
1101
1102 free(data);
1103 return (0);
1104 }
1105
1106 /*
1107 * System variables - read-only scalars only.
1108 */
1109 int
op_ntpSystem(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op op)1110 op_ntpSystem(struct snmp_context *ctx __unused, struct snmp_value *value,
1111 u_int sub, u_int iidx __unused, enum snmp_op op)
1112 {
1113 asn_subid_t which = value->var.subs[sub - 1];
1114
1115 switch (op) {
1116
1117 case SNMP_OP_GETNEXT:
1118 abort();
1119
1120 case SNMP_OP_GET:
1121 if (this_tick > sysinfo_tick) {
1122 if (fetch_sysinfo() == -1)
1123 return (SNMP_ERR_GENERR);
1124 sysinfo_tick = this_tick;
1125 }
1126
1127 switch (which) {
1128
1129 case LEAF_ntpSysLeap:
1130 if (!sysb_leap)
1131 return (SNMP_ERR_NOSUCHNAME);
1132 value->v.integer = sys_leap;
1133 break;
1134
1135 case LEAF_ntpSysStratum:
1136 if (!sysb_stratum)
1137 return (SNMP_ERR_NOSUCHNAME);
1138 value->v.integer = sys_stratum;
1139 break;
1140
1141 case LEAF_ntpSysPrecision:
1142 if (!sysb_precision)
1143 return (SNMP_ERR_NOSUCHNAME);
1144 value->v.integer = sys_precision;
1145 break;
1146
1147 case LEAF_ntpSysRootDelay:
1148 if (sys_rootdelay == NULL)
1149 return (SNMP_ERR_NOSUCHNAME);
1150 return (string_get(value, sys_rootdelay, -1));
1151
1152 case LEAF_ntpSysRootDispersion:
1153 if (sys_rootdispersion == NULL)
1154 return (SNMP_ERR_NOSUCHNAME);
1155 return (string_get(value, sys_rootdispersion, -1));
1156
1157 case LEAF_ntpSysRefId:
1158 if (sys_refid == NULL)
1159 return (SNMP_ERR_NOSUCHNAME);
1160 return (string_get(value, sys_refid, -1));
1161
1162 case LEAF_ntpSysRefTime:
1163 if (sysb_reftime == 0)
1164 return (SNMP_ERR_NOSUCHNAME);
1165 return (string_get(value, sys_reftime, 8));
1166
1167 case LEAF_ntpSysPoll:
1168 if (sysb_poll == 0)
1169 return (SNMP_ERR_NOSUCHNAME);
1170 value->v.integer = sys_poll;
1171 break;
1172
1173 case LEAF_ntpSysPeer:
1174 if (sysb_peer == 0)
1175 return (SNMP_ERR_NOSUCHNAME);
1176 value->v.uint32 = sys_peer;
1177 break;
1178
1179 case LEAF_ntpSysClock:
1180 if (sysb_clock == 0)
1181 return (SNMP_ERR_NOSUCHNAME);
1182 return (string_get(value, sys_clock, 8));
1183
1184 case LEAF_ntpSysSystem:
1185 if (sys_system == NULL)
1186 return (SNMP_ERR_NOSUCHNAME);
1187 return (string_get(value, sys_system, -1));
1188
1189 case LEAF_ntpSysProcessor:
1190 if (sys_processor == NULL)
1191 return (SNMP_ERR_NOSUCHNAME);
1192 return (string_get(value, sys_processor, -1));
1193
1194 default:
1195 abort();
1196 }
1197 return (SNMP_ERR_NOERROR);
1198
1199 case SNMP_OP_SET:
1200 return (SNMP_ERR_NOT_WRITEABLE);
1201
1202 case SNMP_OP_COMMIT:
1203 case SNMP_OP_ROLLBACK:
1204 abort();
1205 }
1206 abort();
1207 }
1208
1209 int
op_ntpPeersVarTable(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx,enum snmp_op op)1210 op_ntpPeersVarTable(struct snmp_context *ctx __unused, struct snmp_value *value,
1211 u_int sub, u_int iidx, enum snmp_op op)
1212 {
1213 asn_subid_t which = value->var.subs[sub - 1];
1214 uint32_t peer;
1215 struct peer *t;
1216
1217 if (this_tick > peers_tick) {
1218 if (fetch_peers() == -1)
1219 return (SNMP_ERR_GENERR);
1220 peers_tick = this_tick;
1221 }
1222
1223 switch (op) {
1224
1225 case SNMP_OP_GETNEXT:
1226 t = NEXT_OBJECT_INT(&peers, &value->var, sub);
1227 if (t == NULL)
1228 return (SNMP_ERR_NOSUCHNAME);
1229 value->var.len = sub + 1;
1230 value->var.subs[sub] = t->index;
1231 break;
1232
1233 case SNMP_OP_GET:
1234 t = FIND_OBJECT_INT(&peers, &value->var, sub);
1235 if (t == NULL)
1236 return (SNMP_ERR_NOSUCHNAME);
1237 break;
1238
1239 case SNMP_OP_SET:
1240 if (index_decode(&value->var, sub, iidx, &peer))
1241 return (SNMP_ERR_NO_CREATION);
1242 t = FIND_OBJECT_INT(&peers, &value->var, sub);
1243 if (t != NULL)
1244 return (SNMP_ERR_NOT_WRITEABLE);
1245 return (SNMP_ERR_NO_CREATION);
1246
1247 case SNMP_OP_COMMIT:
1248 case SNMP_OP_ROLLBACK:
1249 default:
1250 abort();
1251 }
1252
1253 /*
1254 * Come here for GET and COMMIT
1255 */
1256 switch (which) {
1257
1258 case LEAF_ntpPeersConfigured:
1259 value->v.integer = t->config;
1260 break;
1261
1262 case LEAF_ntpPeersPeerAddress:
1263 return (ip_get(value, t->srcadr));
1264
1265 case LEAF_ntpPeersPeerPort:
1266 value->v.uint32 = t->srcport;
1267 break;
1268
1269 case LEAF_ntpPeersHostAddress:
1270 return (ip_get(value, t->dstadr));
1271
1272 case LEAF_ntpPeersHostPort:
1273 value->v.uint32 = t->dstport;
1274 break;
1275
1276 case LEAF_ntpPeersLeap:
1277 value->v.integer = t->leap;
1278 break;
1279
1280 case LEAF_ntpPeersMode:
1281 value->v.integer = t->hmode;
1282 break;
1283
1284 case LEAF_ntpPeersStratum:
1285 value->v.integer = t->stratum;
1286 break;
1287
1288 case LEAF_ntpPeersPeerPoll:
1289 value->v.integer = t->ppoll;
1290 break;
1291
1292 case LEAF_ntpPeersHostPoll:
1293 value->v.integer = t->hpoll;
1294 break;
1295
1296 case LEAF_ntpPeersPrecision:
1297 value->v.integer = t->precision;
1298 break;
1299
1300 case LEAF_ntpPeersRootDelay:
1301 return (string_get(value, t->rootdelay, -1));
1302
1303 case LEAF_ntpPeersRootDispersion:
1304 return (string_get(value, t->rootdispersion, -1));
1305
1306 case LEAF_ntpPeersRefId:
1307 return (string_get(value, t->refid, -1));
1308
1309 case LEAF_ntpPeersRefTime:
1310 return (string_get(value, t->reftime, 8));
1311
1312 case LEAF_ntpPeersOrgTime:
1313 return (string_get(value, t->orgtime, 8));
1314
1315 case LEAF_ntpPeersReceiveTime:
1316 return (string_get(value, t->rcvtime, 8));
1317
1318 case LEAF_ntpPeersTransmitTime:
1319 return (string_get(value, t->xmttime, 8));
1320
1321 case LEAF_ntpPeersReach:
1322 value->v.uint32 = t->reach;
1323 break;
1324
1325 case LEAF_ntpPeersTimer:
1326 value->v.uint32 = t->timer;
1327 break;
1328
1329 case LEAF_ntpPeersOffset:
1330 return (string_get(value, t->offset, -1));
1331
1332 case LEAF_ntpPeersDelay:
1333 return (string_get(value, t->delay, -1));
1334
1335 case LEAF_ntpPeersDispersion:
1336 return (string_get(value, t->dispersion, -1));
1337
1338 default:
1339 abort();
1340 }
1341 return (SNMP_ERR_NOERROR);
1342 }
1343
1344
1345 int
op_ntpFilterPeersVarTable(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx,enum snmp_op op)1346 op_ntpFilterPeersVarTable(struct snmp_context *ctx __unused,
1347 struct snmp_value *value, u_int sub, u_int iidx, enum snmp_op op)
1348 {
1349 asn_subid_t which = value->var.subs[sub - 1];
1350 uint32_t peer;
1351 struct peer *t;
1352
1353 if (this_tick > peers_tick) {
1354 if (fetch_peers() == -1)
1355 return (SNMP_ERR_GENERR);
1356 peers_tick = this_tick;
1357 }
1358
1359 switch (op) {
1360
1361 case SNMP_OP_GETNEXT:
1362 t = NEXT_OBJECT_INT(&peers, &value->var, sub);
1363 if (t == NULL)
1364 return (SNMP_ERR_NOSUCHNAME);
1365 value->var.len = sub + 1;
1366 value->var.subs[sub] = t->index;
1367 break;
1368
1369 case SNMP_OP_GET:
1370 t = FIND_OBJECT_INT(&peers, &value->var, sub);
1371 if (t == NULL)
1372 return (SNMP_ERR_NOSUCHNAME);
1373 break;
1374
1375 case SNMP_OP_SET:
1376 if (index_decode(&value->var, sub, iidx, &peer))
1377 return (SNMP_ERR_NO_CREATION);
1378 t = FIND_OBJECT_INT(&peers, &value->var, sub);
1379 if (t != NULL)
1380 return (SNMP_ERR_NOT_WRITEABLE);
1381 return (SNMP_ERR_NO_CREATION);
1382
1383 case SNMP_OP_COMMIT:
1384 case SNMP_OP_ROLLBACK:
1385 default:
1386 abort();
1387 }
1388
1389 /*
1390 * Come here for GET and COMMIT
1391 */
1392 switch (which) {
1393
1394 case LEAF_ntpFilterValidEntries:
1395 value->v.integer = t->filt_entries;
1396 break;
1397
1398 default:
1399 abort();
1400 }
1401 return (SNMP_ERR_NOERROR);
1402 }
1403
1404 int
op_ntpFilterRegisterTable(struct snmp_context * ctx __unused,struct snmp_value * value __unused,u_int sub __unused,u_int iidx __unused,enum snmp_op op __unused)1405 op_ntpFilterRegisterTable(struct snmp_context *ctx __unused, struct snmp_value *value __unused,
1406 u_int sub __unused, u_int iidx __unused, enum snmp_op op __unused)
1407 {
1408 asn_subid_t which = value->var.subs[sub - 1];
1409 uint32_t peer;
1410 uint32_t filt;
1411 struct filt *t;
1412
1413 if (this_tick > peers_tick) {
1414 if (fetch_peers() == -1)
1415 return (SNMP_ERR_GENERR);
1416 peers_tick = this_tick;
1417 }
1418
1419 switch (op) {
1420
1421 case SNMP_OP_GETNEXT:
1422 t = NEXT_OBJECT_OID(&filts, &value->var, sub);
1423 if (t == NULL)
1424 return (SNMP_ERR_NOSUCHNAME);
1425 index_append(&value->var, sub, &t->index);
1426 break;
1427
1428 case SNMP_OP_GET:
1429 t = FIND_OBJECT_OID(&filts, &value->var, sub);
1430 if (t == NULL)
1431 return (SNMP_ERR_NOSUCHNAME);
1432 break;
1433
1434 case SNMP_OP_SET:
1435 if (index_decode(&value->var, sub, iidx, &peer, &filt))
1436 return (SNMP_ERR_NO_CREATION);
1437 t = FIND_OBJECT_OID(&filts, &value->var, sub);
1438 if (t != NULL)
1439 return (SNMP_ERR_NOT_WRITEABLE);
1440 return (SNMP_ERR_NO_CREATION);
1441
1442 case SNMP_OP_COMMIT:
1443 case SNMP_OP_ROLLBACK:
1444 default:
1445 abort();
1446 }
1447
1448 /*
1449 * Come here for GET and COMMIT
1450 */
1451 switch (which) {
1452
1453 case LEAF_ntpFilterPeersOffset:
1454 return (string_get(value, t->offset, -1));
1455
1456 case LEAF_ntpFilterPeersDelay:
1457 return (string_get(value, t->delay, -1));
1458
1459 case LEAF_ntpFilterPeersDispersion:
1460 return (string_get(value, t->dispersion, -1));
1461
1462 default:
1463 abort();
1464 }
1465 return (SNMP_ERR_NOERROR);
1466 }
1467
1468 /*
1469 * System variables - read-only scalars only.
1470 */
1471 int
op_begemot_ntp(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op op)1472 op_begemot_ntp(struct snmp_context *ctx __unused, struct snmp_value *value,
1473 u_int sub, u_int iidx __unused, enum snmp_op op)
1474 {
1475 asn_subid_t which = value->var.subs[sub - 1];
1476 int ret;
1477
1478 switch (op) {
1479
1480 case SNMP_OP_GETNEXT:
1481 abort();
1482
1483 case SNMP_OP_GET:
1484 switch (which) {
1485
1486 case LEAF_begemotNtpHost:
1487 return (string_get(value, ntp_host, -1));
1488
1489 case LEAF_begemotNtpPort:
1490 return (string_get(value, ntp_port, -1));
1491
1492 case LEAF_begemotNtpTimeout:
1493 value->v.uint32 = ntp_timeout;
1494 return (SNMP_ERR_NOERROR);
1495
1496 case LEAF_begemotNtpDebug:
1497 value->v.uint32 = ntp_debug;
1498 return (SNMP_ERR_NOERROR);
1499
1500 case LEAF_begemotNtpJitter:
1501 if (this_tick > sysinfo_tick) {
1502 if (fetch_sysinfo() == -1)
1503 return (SNMP_ERR_GENERR);
1504 sysinfo_tick = this_tick;
1505 }
1506 if (!sysb_jitter)
1507 return (SNMP_ERR_NOSUCHNAME);
1508 value->v.counter64 = sys_jitter / 1000 * (1ULL << 32);
1509 return (SNMP_ERR_NOERROR);
1510
1511 case LEAF_begemotNtpStability:
1512 if (this_tick > sysinfo_tick) {
1513 if (fetch_sysinfo() == -1)
1514 return (SNMP_ERR_GENERR);
1515 sysinfo_tick = this_tick;
1516 }
1517 if (!sysb_stability)
1518 return (SNMP_ERR_NOSUCHNAME);
1519 value->v.counter64 = sys_stability * (1ULL << 32);
1520 return (SNMP_ERR_NOERROR);
1521 }
1522 abort();
1523
1524 case SNMP_OP_SET:
1525 switch (which) {
1526
1527 case LEAF_begemotNtpHost:
1528 /* only at initialization */
1529 if (community != COMM_INITIALIZE)
1530 return (SNMP_ERR_NOT_WRITEABLE);
1531
1532 if ((ret = string_save(value, ctx, -1, &ntp_host))
1533 != SNMP_ERR_NOERROR)
1534 return (ret);
1535 return (SNMP_ERR_NOERROR);
1536
1537 case LEAF_begemotNtpPort:
1538 /* only at initialization */
1539 if (community != COMM_INITIALIZE)
1540 return (SNMP_ERR_NOT_WRITEABLE);
1541
1542 if ((ret = string_save(value, ctx, -1, &ntp_port))
1543 != SNMP_ERR_NOERROR)
1544 return (ret);
1545 return (SNMP_ERR_NOERROR);
1546
1547 case LEAF_begemotNtpTimeout:
1548 ctx->scratch->int1 = ntp_timeout;
1549 if (value->v.uint32 < 1)
1550 return (SNMP_ERR_WRONG_VALUE);
1551 ntp_timeout = value->v.integer;
1552 return (SNMP_ERR_NOERROR);
1553
1554 case LEAF_begemotNtpDebug:
1555 ctx->scratch->int1 = ntp_debug;
1556 ntp_debug = value->v.integer;
1557 return (SNMP_ERR_NOERROR);
1558 }
1559 abort();
1560
1561 case SNMP_OP_ROLLBACK:
1562 switch (which) {
1563
1564 case LEAF_begemotNtpHost:
1565 string_rollback(ctx, &ntp_host);
1566 return (SNMP_ERR_NOERROR);
1567
1568 case LEAF_begemotNtpPort:
1569 string_rollback(ctx, &ntp_port);
1570 return (SNMP_ERR_NOERROR);
1571
1572 case LEAF_begemotNtpTimeout:
1573 ntp_timeout = ctx->scratch->int1;
1574 return (SNMP_ERR_NOERROR);
1575
1576 case LEAF_begemotNtpDebug:
1577 ntp_debug = ctx->scratch->int1;
1578 return (SNMP_ERR_NOERROR);
1579 }
1580 abort();
1581
1582 case SNMP_OP_COMMIT:
1583 switch (which) {
1584
1585 case LEAF_begemotNtpHost:
1586 string_commit(ctx);
1587 return (SNMP_ERR_NOERROR);
1588
1589 case LEAF_begemotNtpPort:
1590 string_commit(ctx);
1591 return (SNMP_ERR_NOERROR);
1592
1593 case LEAF_begemotNtpTimeout:
1594 case LEAF_begemotNtpDebug:
1595 return (SNMP_ERR_NOERROR);
1596 }
1597 abort();
1598 }
1599 abort();
1600 }
1601