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