1 #include <sys/socket.h>
2 #include <sys/types.h>
3
4 #include <arpa/inet.h>
5
6 #include <ber.h>
7 #include <err.h>
8 #include <errno.h>
9 #include <inttypes.h>
10 #include <netdb.h>
11 #include <poll.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <vis.h>
16
17 #include "regress.h"
18
19 #include <stdio.h>
20
21 #define SNMP_HOSTNAME "127.0.0.1"
22 #define SNMP_PORT "161"
23
24 #define SNMP_R_COMMUNITY "public"
25
26 #define MIB_SNMP_V3 MIB_SNMP, 1
27 #define MIB_SNMP_USM MIB_SNMP_V3, 1
28
29 #define MIB_SUBAGENT_V3 MIB_SUBAGENT_SNMP, 1
30 #define MIB_SUBAGENT_USM MIB_SUBAGENT_V3, 1
31
32 #define SNMPMODULES 1, 3, 6, 1, 6, 3
33 #define SNMPUSMMIB SNMPMODULES, 15
34 #define USMMIBOBJECTS SNMPUSMMIB, 1
35 #define USMSTATS USMMIBOBJECTS, 1
36 #define USMSTATSUNKNOWNENGINEIDS USMSTATS, 4
37
38 #define BER_OID(...) (struct ber_oid){ {__VA_ARGS__}, \
39 (sizeof((uint32_t []){__VA_ARGS__}) / sizeof(uint32_t)) }
40
41 enum snmp_application {
42 APPLICATION_IPADDR = 0,
43 APPLICATION_COUNTER32 = 1,
44 APPLICATION_GAUGE32 = 2,
45 APPLICATION_UNSIGNED32 = 2,
46 APPLICATION_TIMETICKS = 3,
47 APPLICATION_OPAQUE = 4,
48 APPLICATION_NSAPADDR = 5,
49 APPLICATION_COUNTER64 = 6,
50 };
51
52 enum snmp_exception {
53 EXCEPTION_NOSUCHOBJECT = 0,
54 EXCEPTION_NOSUCHINSTANCE = 1,
55 EXCEPTION_ENDOFMIBVIEW = 2
56 };
57
58 enum security_model {
59 SM_USM = 3,
60 SM_TSM = 4
61 };
62
63 struct usm {
64 char engineid[32];
65 size_t engineidlen;
66 int engineboots;
67 int enginetime;
68 char username[33];
69 };
70
71 union securityparams {
72 struct usm usm;
73 };
74
75 #define MSGFLAG_AUTH (1 << 0)
76 #define MSGFLAG_PRIV (1 << 1)
77 #define MSG_NOAUTHNOPRIV 0
78 #define MSG_AUTHNOPRIV MSGFLAG_AUTH
79 #define MSG_AUTHPRIV (MSGFLAG_AUTH | MSGFLAG_PRIV)
80 #define MSGFLAG_REPORTABLE (1 << 2)
81 #define MSGFLAG_ALL (MSGFLAG_AUTH | MSGFLAG_PRIV | MSGFLAG_REPORTABLE)
82 struct headerdata {
83 int32_t msgid;
84 int32_t msgmaxsize;
85 int8_t msgflags;
86 enum security_model msgsm;
87 char engineid[32];
88 size_t engineidlen;
89 char contextname[256];
90 };
91
92 int32_t snmpv2_send(int, const char *, enum snmp_request, int32_t, int32_t,
93 int32_t, struct varbind *, size_t);
94 int32_t snmpv3_get(int, int, struct headerdata *, union securityparams *,
95 int32_t, struct varbind *, size_t);
96 int32_t snmpv3_send(int, int, struct headerdata *, union securityparams *,
97 enum snmp_request, int32_t, int32_t, int32_t, struct varbind *, size_t);
98 int32_t snmpv3_usm_send(int, int, struct headerdata *, struct usm *, int32_t,
99 struct varbind *, size_t);
100 void snmpv3_usm_discovery(int, int, struct headerdata *, struct usm *);
101 void snmpv3_encode(int, struct ber *, struct headerdata *,
102 union securityparams *, struct ber_element *);
103 void snmpv3_usm_encode(int, struct ber *, struct usm *);
104 struct ber_element *snmpv3_decode(int, void *, size_t, struct ber_element *,
105 struct headerdata *, union securityparams *);
106 void snmpv3_response_validate(int, int, struct headerdata *,
107 union securityparams *, int32_t, int32_t, int32_t, struct varbind *,
108 size_t);
109 void snmpv3_usm_decode(int, void *, size_t, void *, size_t, struct usm *);
110 struct ber_element *snmp_recv(int, int, void *buf, size_t *);
111 struct ber_element *snmp_pdu(enum snmp_request, int32_t, int32_t, int32_t,
112 struct varbind *, size_t);
113 struct ber_element *snmp_varbindlist(struct varbind *, size_t);
114 struct ber_oid *snmp_oid2ber_oid(struct oid *, struct ber_oid *);
115 struct ber_element *snmp_data2ber_element(enum type, union data *);
116 unsigned int smi_application(struct ber_element *);
117 char *smi_oid2string(struct ber_oid *, char *, size_t);
118 char *smi_print_element(struct ber_element *);
119 struct ber_element *v2cmps(struct ber_element *, const char *);
120 void snmp_pdu_validate(struct ber_element *, enum snmp_request, int32_t,
121 int32_t, int32_t, struct varbind *, size_t);
122
123 void
snmp_v3_usm_noauthpriv(void)124 snmp_v3_usm_noauthpriv(void)
125 {
126 struct sockaddr_storage ss;
127 struct sockaddr *sa = (struct sockaddr *)&ss;
128 socklen_t salen;
129 int snmp_s, ax_s;
130 uint32_t sessionid;
131 struct varbind varbind = {
132 .type = TYPE_NULL,
133 .name = OID_STRUCT(MIB_SNMP_USM, 1, 0),
134 .data.int32 = 1
135 };
136 struct headerdata hd = {
137 .msgid = 0,
138 .msgmaxsize = 0,
139 .msgflags = MSG_NOAUTHNOPRIV | MSGFLAG_REPORTABLE,
140 .msgsm = SM_USM
141 };
142 union securityparams params = {
143 .usm.engineidlen = 0,
144 .usm.engineboots = 0,
145 .usm.enginetime = 0,
146 .usm.username = "noauthpriv"
147 };
148 int32_t requestid;
149 char buf[1024];
150 size_t n;
151
152 ax_s = agentx_connect(axsocket);
153 sessionid = agentx_open(ax_s, 0, 0,
154 OID_ARG(MIB_SUBAGENT_USM, 1), __func__);
155 agentx_register(ax_s, sessionid, 0, 0, 127, 0,
156 OID_ARG(MIB_SNMP_USM, 1), 0);
157
158 salen = snmp_resolve(SOCK_DGRAM, hostname, servname, sa);
159 snmp_s = snmp_connect(SOCK_DGRAM, sa, salen);
160 requestid = snmpv3_get(snmp_s, 1000, &hd, ¶ms, 0, &varbind, 1);
161
162 n = agentx_read(ax_s, buf, sizeof(buf), 1000);
163 varbind.type = TYPE_INTEGER;
164 agentx_get_handle(__func__, buf, n, 0, sessionid, &varbind, 1);
165 agentx_response(ax_s, buf, 0, NOERROR, &varbind, 1);
166
167 snmpv3_response_validate(snmp_s, 1000, &hd, ¶ms, requestid, 0, 0,
168 &varbind, 1);
169 }
170
171 socklen_t
snmp_resolve(int type,const char * hostname,const char * servname,struct sockaddr * sa)172 snmp_resolve(int type, const char *hostname, const char *servname, struct sockaddr *sa)
173 {
174 struct addrinfo hints, *res;
175 socklen_t salen;
176 int error;
177
178 if (hostname == NULL)
179 hostname = SNMP_HOSTNAME;
180 if (servname == NULL)
181 servname = SNMP_PORT;
182
183 memset(&hints, 0, sizeof(hints));
184 hints.ai_family = AF_UNSPEC;
185 hints.ai_socktype = type;
186
187 if ((error = getaddrinfo(hostname, servname, &hints, &res)) != 0)
188 errx(1, "getaddrinfo(%s, %s): %s", hostname, servname,
189 gai_strerror(error));
190
191 memcpy(sa, res->ai_addr, res->ai_addrlen);
192 salen = res->ai_addrlen;
193
194 freeaddrinfo(res);
195 return salen;
196 }
197
198 int
snmp_connect(int type,struct sockaddr * sa,socklen_t salen)199 snmp_connect(int type, struct sockaddr *sa, socklen_t salen)
200 {
201 int s;
202
203 if ((s = socket(sa->sa_family, type, 0)) == -1)
204 err(1, "socket");
205 if (connect(s, sa, salen) == -1)
206 err(1, "connect");
207 return s;
208 }
209
210 int32_t
snmpv2_get(int s,const char * community,int32_t requestid,struct varbind * varbindlist,size_t nvarbind)211 snmpv2_get(int s, const char *community, int32_t requestid,
212 struct varbind *varbindlist, size_t nvarbind)
213 {
214 return snmpv2_send(s, community, REQUEST_GET, requestid, 0, 0,
215 varbindlist, nvarbind);
216 }
217
218 int32_t
snmpv2_getnext(int s,const char * community,int32_t requestid,struct varbind * varbindlist,size_t nvarbind)219 snmpv2_getnext(int s, const char *community, int32_t requestid,
220 struct varbind *varbindlist, size_t nvarbind)
221 {
222 return snmpv2_send(s, community, REQUEST_GETNEXT, requestid, 0, 0,
223 varbindlist, nvarbind);
224 }
225
226 int32_t
snmpv2_getbulk(int s,const char * community,int32_t requestid,int32_t nonrep,int32_t maxrep,struct varbind * varbindlist,size_t nvarbind)227 snmpv2_getbulk(int s, const char *community, int32_t requestid, int32_t nonrep,
228 int32_t maxrep, struct varbind *varbindlist, size_t nvarbind)
229 {
230 return snmpv2_send(s, community, REQUEST_GETBULK, requestid, nonrep,
231 maxrep, varbindlist, nvarbind);
232 }
233
234 struct ber_element *
snmpv2_build(const char * community,enum snmp_request request,int32_t requestid,int32_t error,int32_t index,struct varbind * varbindlist,size_t nvarbind)235 snmpv2_build(const char *community, enum snmp_request request,
236 int32_t requestid, int32_t error, int32_t index,
237 struct varbind *varbindlist, size_t nvarbind)
238 {
239 struct ber_element *message;
240
241 if (community == NULL)
242 community = SNMP_R_COMMUNITY;
243 message = ober_printf_elements(NULL, "{dse}", 1, community,
244 snmp_pdu(request, requestid, error, index, varbindlist, nvarbind));
245 if (message == NULL)
246 err(1, NULL);
247
248 return message;
249 }
250
251 int32_t
snmpv2_send(int s,const char * community,enum snmp_request request,int32_t requestid,int32_t error,int32_t index,struct varbind * varbindlist,size_t nvarbind)252 snmpv2_send(int s, const char *community, enum snmp_request request,
253 int32_t requestid, int32_t error, int32_t index,
254 struct varbind *varbindlist, size_t nvarbind)
255 {
256 struct ber_element *message;
257 struct ber ber = {};
258 void *buf;
259 ssize_t buflen, writelen;
260
261 while (requestid == 0)
262 requestid = arc4random();
263
264 message = snmpv2_build(community, request, requestid, error, index,
265 varbindlist,nvarbind);
266
267 if (ober_write_elements(&ber, message) == -1)
268 err(1, "ober_write_elements");
269
270 buflen = ober_get_writebuf(&ber, &buf);
271 if ((writelen = write(s, buf, buflen)) == -1)
272 err(1, "write");
273 if (writelen != buflen)
274 errx(1, "write: short write");
275
276 if (verbose) {
277 printf("SNMP send(%d):\n", s);
278 smi_debug_elements(message);
279 }
280 ober_free_elements(message);
281 ober_free(&ber);
282
283 return requestid;
284 }
285
286 void
snmpv2_response_validate(int s,int timeout,const char * community,int32_t requestid,int32_t error,int32_t index,struct varbind * varbindlist,size_t nvarbind)287 snmpv2_response_validate(int s, int timeout, const char *community,
288 int32_t requestid, int32_t error, int32_t index,
289 struct varbind *varbindlist, size_t nvarbind)
290 {
291 struct ber_element *message, *pdu;
292 char buf[100000];
293 size_t buflen = sizeof(buf);
294
295 message = snmp_recv(s, timeout, buf, &buflen);
296
297 if (community == NULL)
298 community = SNMP_R_COMMUNITY;
299 snmp_pdu_validate(v2cmps(message, community), REQUEST_RESPONSE,
300 requestid, error, index, varbindlist, nvarbind);
301
302 ober_free_elements(message);
303 }
304
305 struct ber_element *
snmp_recv(int s,int timeout,void * buf,size_t * buflen)306 snmp_recv(int s, int timeout, void *buf, size_t *buflen)
307 {
308 struct pollfd pfd = {
309 .fd = s,
310 .events = POLLIN
311 };
312 struct ber ber = {};
313 struct ber_element *message;
314 ssize_t n;
315 size_t ntot = 0;
316 int ret;
317
318 again:
319 if ((ret = poll(&pfd, 1, timeout)) == -1)
320 err(1, "poll");
321 if (ret == 0) {
322 if (ntot == 0)
323 errx(1, "%s: timeout", __func__);
324 errc(1, ECANCELED, "%s: unable to decode message", __func__);
325 }
326 if ((n = read(s, buf + ntot, *buflen - ntot)) == -1)
327 err(1, "snmp read");
328 ntot += n;
329
330 ober_set_application(&ber, smi_application);
331 ober_set_readbuf(&ber, buf, ntot);
332
333 if ((message = ober_read_elements(&ber, NULL)) == NULL) {
334 if (errno == ECANCELED)
335 goto again;
336 errx(1, "%s: unable to decode message", __func__);
337 }
338 *buflen = n;
339 if (verbose) {
340 printf("SNMP received(%d):\n", s);
341 smi_debug_elements(message);
342 }
343
344 ober_free(&ber);
345
346 return message;
347 }
348
349 int32_t
snmpv3_get(int s,int timeout,struct headerdata * hd,union securityparams * params,int32_t requestid,struct varbind * varbindlist,size_t nvarbind)350 snmpv3_get(int s, int timeout, struct headerdata *hd,
351 union securityparams *params, int32_t requestid,
352 struct varbind *varbindlist, size_t nvarbind)
353 {
354 return snmpv3_send(s, timeout, hd, params, REQUEST_GET, requestid,
355 0, 0, varbindlist, nvarbind);
356 }
357
358 int32_t
snmpv3_send(int s,int timeout,struct headerdata * hd,union securityparams * params,enum snmp_request request,int32_t requestid,int32_t error,int32_t index,struct varbind * varbindlist,size_t nvarbind)359 snmpv3_send(int s, int timeout, struct headerdata *hd,
360 union securityparams *params, enum snmp_request request, int32_t requestid,
361 int32_t error, int32_t index, struct varbind *varbindlist, size_t nvarbind)
362 {
363 struct ber ber;
364 void *buf;
365 ssize_t buflen, writelen;
366
367 if (hd->msgid == 0)
368 hd->msgid = arc4random();
369 if (hd->msgmaxsize == 0)
370 hd->msgmaxsize = 484;
371 if (requestid == 0)
372 requestid = arc4random();
373
374 if (hd->msgsm == SM_USM)
375 snmpv3_usm_discovery(s, timeout, hd, ¶ms->usm);
376
377 snmpv3_encode(s, &ber, hd, params, snmp_pdu(request, requestid, error,
378 index, varbindlist, nvarbind));
379
380 buflen = ober_get_writebuf(&ber, &buf);
381 if ((writelen = write(s, buf, buflen)) == -1)
382 err(1, "write");
383 if (writelen != buflen)
384 errx(1, "write: short write");
385
386 ober_free(&ber);
387
388 return requestid;
389 }
390
391 void
snmpv3_usm_discovery(int s,int timeout,struct headerdata * hd,struct usm * params)392 snmpv3_usm_discovery(int s, int timeout, struct headerdata *hd,
393 struct usm *params)
394 {
395 struct ber_element *message, *pdu;
396 struct ber_oid oid;
397 struct ber ber;
398 struct headerdata hdd;
399 union securityparams sp = {
400 .usm = *params
401 };
402 void *buf;
403 char rbuf[1024];
404 size_t rbuflen = sizeof(rbuf);
405 int8_t msgflags;
406 size_t buflen, writelen;
407 char oidbuf[1024];
408 struct varbind vb = {
409 .type = TYPE_COUNTER32,
410 .dataunknown = 1
411 };
412
413 hdd = *hd;
414 hdd.msgid = arc4random();
415 if (params->engineidlen == 0) {
416 hdd.msgflags = MSGFLAG_REPORTABLE;
417 sp.usm.username[0] = '\0';
418 } else if (hd->msgflags & MSGFLAG_AUTH && params->engineboots == 0 &&
419 params->enginetime == 0)
420 hdd.msgflags = MSGFLAG_AUTH | MSGFLAG_REPORTABLE;
421 else
422 return;
423
424 pdu = snmp_pdu(REQUEST_GET, 0, 0, 0, NULL, 0);
425 snmpv3_encode(s, &ber, &hdd, &sp, pdu);
426 buflen = ober_get_writebuf(&ber, &buf);
427 if ((writelen = write(s, buf, buflen)) == -1)
428 err(1, "write");
429 if (writelen != buflen)
430 errx(1, "write: short write");
431
432 retry:
433 message = snmp_recv(s, timeout, rbuf, &rbuflen);
434
435 hdd.msgflags &= ~MSGFLAG_REPORTABLE;
436 pdu = snmpv3_decode(s, rbuf, rbuflen, message, &hdd, &sp);
437
438 if (params->engineidlen == 0) {
439 vb.name = OID_STRUCT(USMSTATSUNKNOWNENGINEIDS, 0);
440 snmp_pdu_validate(pdu, REQUEST_REPORT, 0, 0, 0, &vb, 1);
441 memcpy(params->engineid, sp.usm.engineid, sp.usm.engineidlen);
442 params->engineidlen = sp.usm.engineidlen;
443 if (hd->msgflags & MSGFLAG_AUTH)
444 snmpv3_usm_discovery(s, timeout, hd, params);
445 }
446
447 ober_free(&ber);
448 ober_free_elements(message);
449
450 return;
451 }
452
453 void
snmpv3_encode(int s,struct ber * ber,struct headerdata * hd,union securityparams * params,struct ber_element * pdu)454 snmpv3_encode(int s, struct ber *ber, struct headerdata *hd,
455 union securityparams *params, struct ber_element *pdu)
456 {
457 struct ber_element *message;
458 void *sp;
459 size_t splen;
460
461 switch (hd->msgsm) {
462 case SM_USM:
463 snmpv3_usm_encode(s, ber, ¶ms->usm);
464 break;
465 default:
466 errx(1, "%s: unsupported securityModel %d",
467 __func__, hd->msgsm);
468 }
469
470 splen = ober_get_writebuf(ber, &sp);
471 if ((message = ober_printf_elements(NULL, "{d{ddxd}x{xse}}", 3,
472 hd->msgid, hd->msgmaxsize, &hd->msgflags, sizeof(hd->msgflags),
473 hd->msgsm, sp, splen, hd->engineid, hd->engineidlen,
474 hd->contextname, pdu)) == NULL)
475 err(1, NULL);
476 ober_free(ber);
477 *ber = (struct ber){};
478 ober_set_application(ber, smi_application);
479 if (ober_write_elements(ber, message) == -1)
480 err(1, NULL);
481 if (verbose) {
482 printf("SNMP send(%d):\n", s);
483 smi_debug_elements(message);
484 }
485 ober_free_elements(message);
486 }
487
488 void
snmpv3_usm_encode(int s,struct ber * ber,struct usm * params)489 snmpv3_usm_encode(int s, struct ber *ber, struct usm *params)
490 {
491 struct ber_element *sp;
492
493 *ber = (struct ber){};
494 ober_set_application(ber, smi_application);
495 if ((sp = ober_printf_elements(NULL, "{xddxss}", params->engineid,
496 params->engineidlen, params->engineboots, params->enginetime,
497 params->username, strlen(params->username), "", "")) == NULL)
498 err(1, NULL);
499 if (ober_write_elements(ber, sp) == -1)
500 err(1, NULL);
501 if (verbose) {
502 printf("USM params send(%d):\n", s);
503 smi_debug_elements(sp);
504 }
505 ober_free_elements(sp);
506 }
507
508 struct ber_element *
snmpv3_decode(int s,void * buf,size_t buflen,struct ber_element * message,struct headerdata * hd,union securityparams * sp)509 snmpv3_decode(int s, void *buf, size_t buflen, struct ber_element *message,
510 struct headerdata *hd, union securityparams *sp)
511 {
512 struct ber_element *pdu;
513 int32_t version, msgid, msgmaxsize, sm;
514 char *msgflags, *spstr, *engineid, *name;
515 size_t msgflagslen, spstrlen, engineidlen, namelen;
516 int class;
517 unsigned int type;
518
519 if (ober_scanf_elements(message, "{d{ddxd$}x{xxe}",
520 &version, &msgid, &msgmaxsize, &msgflags, &msgflagslen,
521 &sm, &spstr, &spstrlen, &engineid, &engineidlen, &name, &namelen,
522 &pdu) == -1)
523 errx(1, "%s: ober_scanf_elements", __func__);
524 if (version != 3)
525 errx(1, "%s: invalid version", __func__);
526 if (msgid != hd->msgid)
527 errx(1, "%s: unexpected msgid", __func__);
528 if (msgmaxsize < 484 || msgmaxsize > 2147483647)
529 errx(1, "%s: invalid msgmaxsize", __func__);
530 if (msgflagslen != 1 || msgflags[0] != hd->msgflags)
531 errx(1, "%s: invalid msgflags", __func__);
532 if (sm != hd->msgsm)
533 errx(1, "%s: unexpected security model", __func__);
534 if (engineidlen < 5 || engineidlen > 32)
535 errx(1, "%s: invalid contextEngineID", __func__);
536 if (hd->engineidlen != 0) {
537 if (hd->engineidlen != engineidlen ||
538 memcmp(hd->engineid, engineid, engineidlen) != 0)
539 errx(1, "%s: unexpected engineid", __func__);
540 } else {
541 hd->engineidlen = engineidlen;
542 memcpy(hd->engineid, engineid, engineidlen);
543 }
544 if (namelen > 255)
545 errx(1, "%s: invalid ctxnamelen", __func__);
546 if (strcmp(hd->contextname, name) != 0)
547 errx(1, "%s: unexpected context", __func__);
548
549 switch (sm) {
550 case SM_USM:
551 snmpv3_usm_decode(s, buf, buflen, spstr, spstrlen, &sp->usm);
552 }
553 return pdu;
554 }
555
556 void
snmpv3_usm_decode(int s,void * buf,size_t buflen,void * spstr,size_t spstrlen,struct usm * usm)557 snmpv3_usm_decode(int s, void *buf, size_t buflen, void *spstr, size_t spstrlen,
558 struct usm *usm)
559 {
560 struct ber ber = {};
561 struct ber_element *sp;
562 char *engineid, *username, *authparams, *privparams;
563 size_t engineidlen, usernamelen, authparamslen, privparamslen;
564 int32_t engineboots, enginetime;
565
566 ober_set_application(&ber, smi_application);
567 ober_set_readbuf(&ber, spstr, spstrlen);
568 if ((sp = ober_read_elements(&ber, NULL)) == NULL)
569 errx(1, "%s: ober_read_elements", __func__);
570 if (verbose) {
571 printf("USM params received(%d):\n", s);
572 smi_debug_elements(sp);
573 }
574
575 if (ober_scanf_elements(sp, "{xddxxx}", &engineid, &engineidlen,
576 &engineboots, &enginetime, &username, &usernamelen, &authparams,
577 &authparamslen, &privparams, &privparamslen) == -1)
578 errx(1, "%s: ober_scanf_elements", __func__);
579
580 if (engineidlen < 5 || engineidlen > 32)
581 errx(1, "%s: invalid msgAuthoritativeEngineID", __func__);
582 if (engineboots < 0 || engineboots > 2147483647)
583 errx(1, "%s: invalid msgAuthoritativeEngineBoots", __func__);
584 if (enginetime < 0 || enginetime > 2147483647)
585 errx(1, "%s: invalid msgAuthoritativeEngineTime", __func__);
586 if (usernamelen < 0 || usernamelen > 32)
587 errx(1, "%s: invalid msgUserName", __func__);
588
589 if (usm->engineidlen == 0) {
590 memcpy(usm->engineid, engineid, engineidlen);
591 usm->engineidlen = engineidlen;
592 } else {
593 if (usm->engineidlen != engineidlen ||
594 memcmp(usm->engineid, engineid, engineidlen) != 0)
595 errx(1, "%s: unexpected engineid", __func__);
596 }
597 if (usm->engineboots == 0 && usm->enginetime == 0) {
598 usm->engineboots = engineboots;
599 usm->enginetime = enginetime;
600 } else {
601 if (usm->engineboots < engineboots)
602 errx(1, "%s: engineboots decremented", __func__);
603 else if (usm->engineboots == engineboots) {
604 if (enginetime < usm->enginetime - 150 ||
605 enginetime > usm->enginetime + 150)
606 errx(1, "%s: enginetime out of window",
607 __func__);
608 } else {
609 if (enginetime > 150)
610 errx(1, "%s: enginetime out of window",
611 __func__);
612 }
613 }
614 if (strcmp(username, usm->username) != 0)
615 errx(1, "unexpected username");
616 }
617
618 void
snmpv3_response_validate(int s,int timeout,struct headerdata * hd,union securityparams * sp,int32_t requestid,int32_t error,int32_t index,struct varbind * varbindlist,size_t nvarbind)619 snmpv3_response_validate(int s, int timeout, struct headerdata *hd,
620 union securityparams *sp, int32_t requestid, int32_t error, int32_t index,
621 struct varbind *varbindlist, size_t nvarbind)
622 {
623 struct ber_element *message, *pdu;
624 char buf[1024];
625 size_t buflen = sizeof(buf);
626 hd->msgflags &= ~MSGFLAG_REPORTABLE;
627
628 message = snmp_recv(s, timeout, buf, &buflen);
629 pdu = snmpv3_decode(1, buf, sizeof(buf), message, hd, sp);
630 snmp_pdu_validate(pdu, REQUEST_RESPONSE, requestid, error, index,
631 varbindlist, nvarbind);
632
633 ober_free_elements(message);
634 }
635
636 void
snmp_timeout(int s,int timeout)637 snmp_timeout(int s, int timeout)
638 {
639 int ret;
640 struct pollfd pfd = {
641 .fd = s,
642 .events = POLLIN
643 };
644
645 if ((ret = poll(&pfd, 1, timeout)) == -1)
646 err(1, "poll");
647 if (ret != 0)
648 errx(1, "%s: unexpected snmp data", __func__);
649 }
650
651 struct ber_element *
snmp_pdu(enum snmp_request request,int32_t requestid,int32_t error,int32_t index,struct varbind * varbindlist,size_t nvarbind)652 snmp_pdu(enum snmp_request request, int32_t requestid, int32_t error,
653 int32_t index, struct varbind *varbindlist, size_t nvarbind)
654 {
655 struct ber_element *pdu;
656
657 if ((pdu = ober_printf_elements(NULL, "{tddde}", BER_CLASS_CONTEXT,
658 request, requestid, error, index,
659 snmp_varbindlist(varbindlist, nvarbind))) == NULL)
660 err(1, NULL);
661 return pdu;
662 }
663
664 struct ber_element *
snmp_varbindlist(struct varbind * varbindlist,size_t nvarbind)665 snmp_varbindlist(struct varbind *varbindlist, size_t nvarbind)
666 {
667 struct ber_element *vblist, *prev = NULL;
668 struct ber_oid oid;
669 size_t i;
670
671 if ((vblist = prev = ober_add_sequence(NULL)) == NULL)
672 err(1, NULL);
673 for (i = 0; i < nvarbind; i++) {
674 if ((prev = ober_printf_elements(prev, "{Oe}",
675 snmp_oid2ber_oid(&varbindlist[i].name, &oid),
676 snmp_data2ber_element(varbindlist[i].type,
677 &varbindlist[i].data))) == NULL)
678 err(1, NULL);
679 }
680
681 return vblist;
682 }
683
684 struct ber_oid *
snmp_oid2ber_oid(struct oid * oid,struct ber_oid * boid)685 snmp_oid2ber_oid(struct oid *oid, struct ber_oid *boid)
686 {
687 size_t i;
688
689 for (i = 0; i < oid->n_subid; i++)
690 boid->bo_id[i] = oid->subid[i];
691 boid->bo_n = oid->n_subid;
692
693 return boid;
694 }
695
696 struct ber_element *
snmp_data2ber_element(enum type type,union data * data)697 snmp_data2ber_element(enum type type, union data *data)
698 {
699 struct ber_element *elm;
700 struct ber_oid oid;
701
702 switch (type) {
703 case TYPE_INTEGER:
704 elm = ober_add_integer(NULL, data->int32);
705 break;
706 case TYPE_OCTETSTRING:
707 elm = ober_add_nstring(NULL, data->octetstring.string,
708 data->octetstring.len);
709 break;
710 case TYPE_NULL:
711 elm = ober_add_null(NULL);
712 break;
713 case TYPE_OBJECTIDENTIFIER:
714 elm = ober_add_oid(NULL, snmp_oid2ber_oid(&data->oid, &oid));
715 break;
716 case TYPE_IPADDRESS:
717 if ((elm = ober_add_nstring(NULL, data->octetstring.string,
718 data->octetstring.len)) == NULL)
719 err(1, NULL);
720 ober_set_header(elm, BER_CLASS_APPLICATION, APPLICATION_IPADDR);
721 break;
722 case TYPE_COUNTER32:
723 if ((elm = ober_add_integer(NULL, data->uint32)) == NULL)
724 err(1, NULL);
725 ober_set_header(elm, BER_CLASS_APPLICATION,
726 APPLICATION_COUNTER32);
727 break;
728 case TYPE_GAUGE32:
729 if ((elm = ober_add_integer(NULL, data->uint32)) == NULL)
730 err(1, NULL);
731 ober_set_header(elm, BER_CLASS_APPLICATION,
732 APPLICATION_GAUGE32);
733 break;
734 case TYPE_TIMETICKS:
735 if ((elm = ober_add_integer(NULL, data->uint32)) == NULL)
736 err(1, NULL);
737 ober_set_header(elm, BER_CLASS_APPLICATION,
738 APPLICATION_TIMETICKS);
739 break;
740 case TYPE_OPAQUE:
741 if ((elm = ober_add_nstring(NULL, data->octetstring.string,
742 data->octetstring.len)) == NULL)
743 err(1, NULL);
744 ober_set_header(elm, BER_CLASS_APPLICATION, APPLICATION_OPAQUE);
745 break;
746 case TYPE_COUNTER64:
747 if ((elm = ober_add_integer(NULL, data->uint64)) == NULL)
748 err(1, NULL);
749 ober_set_header(elm, BER_CLASS_APPLICATION,
750 APPLICATION_COUNTER64);
751 break;
752 case TYPE_NOSUCHOBJECT:
753 if ((elm = ober_add_null(NULL)) == NULL)
754 err(1, NULL);
755 ober_set_header(elm, BER_CLASS_CONTEXT, EXCEPTION_NOSUCHOBJECT);
756 break;
757 case TYPE_NOSUCHINSTANCE:
758 if ((elm = ober_add_null(NULL)) == NULL)
759 err(1, NULL);
760 ober_set_header(elm, BER_CLASS_CONTEXT,
761 EXCEPTION_NOSUCHINSTANCE);
762 break;
763 case TYPE_ENDOFMIBVIEW:
764 if ((elm = ober_add_null(NULL)) == NULL)
765 err(1, NULL);
766 ober_set_header(elm, BER_CLASS_CONTEXT, EXCEPTION_ENDOFMIBVIEW);
767 break;
768 default:
769 errx(1, "%s: unsupported type: %d", __func__, type);
770 }
771 if (elm == NULL)
772 err(1, NULL);
773 return elm;
774 }
775
776 unsigned int
smi_application(struct ber_element * elm)777 smi_application(struct ber_element *elm)
778 {
779 if (elm->be_class != BER_CLASS_APPLICATION)
780 return -1;
781
782 switch (elm->be_type) {
783 case APPLICATION_IPADDR:
784 case APPLICATION_OPAQUE:
785 return BER_TYPE_OCTETSTRING;
786 case APPLICATION_COUNTER32:
787 case APPLICATION_GAUGE32:
788 case APPLICATION_TIMETICKS:
789 case APPLICATION_COUNTER64:
790 return BER_TYPE_INTEGER;
791 default:
792 return -1;
793 }
794 }
795
796 char *
smi_oid2string(struct ber_oid * oid,char * buf,size_t len)797 smi_oid2string(struct ber_oid *oid, char *buf, size_t len)
798 {
799 char digit[11];
800 size_t i;
801
802 buf[0] = '\0';
803 for (i = 0; i < oid->bo_n; i++) {
804 snprintf(digit, sizeof(digit), "%"PRIu32, oid->bo_id[i]);
805 if (i > 0)
806 strlcat(buf, ".", len);
807 strlcat(buf, digit, len);
808 }
809 return buf;
810 }
811
812 char *
smi_print_element(struct ber_element * root)813 smi_print_element(struct ber_element *root)
814 {
815 char *str = NULL, *buf, *p;
816 long long v;
817 struct ber_oid o;
818 char strbuf[BUFSIZ];
819
820 switch (root->be_class) {
821 case BER_CLASS_UNIVERSAL:
822 switch (root->be_type) {
823 case BER_TYPE_INTEGER:
824 if (ober_get_integer(root, &v) == -1)
825 goto fail;
826 if (asprintf(&str, "%lld", v) == -1)
827 goto fail;
828 break;
829 case BER_TYPE_OBJECT:
830 if (ober_get_oid(root, &o) == -1)
831 goto fail;
832 if (asprintf(&str, "%s", smi_oid2string(&o, strbuf,
833 sizeof(strbuf))) == -1)
834 goto fail;
835 break;
836 case BER_TYPE_OCTETSTRING:
837 if (ober_get_string(root, &buf) == -1)
838 goto fail;
839 p = reallocarray(NULL, 4, root->be_len + 1);
840 if (p == NULL)
841 goto fail;
842 strvisx(p, buf, root->be_len, VIS_NL);
843 if (asprintf(&str, "\"%s\"", p) == -1) {
844 free(p);
845 goto fail;
846 }
847 free(p);
848 break;
849 case BER_TYPE_NULL:
850 if (asprintf(&str, "null") == -1)
851 goto fail;
852 break;
853 default:
854 /* Should not happen in a valid SNMP packet */
855 if (asprintf(&str, "[U/%u]", root->be_type) == -1)
856 goto fail;
857 break;
858 }
859 break;
860 case BER_CLASS_APPLICATION:
861 switch (root->be_type) {
862 case APPLICATION_IPADDR:
863 if (ober_get_string(root, &buf) == -1)
864 goto fail;
865 if (asprintf(&str, "%s",
866 inet_ntoa(*(struct in_addr *)buf)) == -1)
867 goto fail;
868 break;
869 case APPLICATION_COUNTER32:
870 if (ober_get_integer(root, &v) == -1)
871 goto fail;
872 if (asprintf(&str, "%lld(c32)", v) == -1)
873 goto fail;
874 break;
875 case APPLICATION_GAUGE32:
876 if (ober_get_integer(root, &v) == -1)
877 goto fail;
878 if (asprintf(&str, "%lld(g32)", v) == -1)
879 goto fail;
880 break;
881 case APPLICATION_TIMETICKS:
882 if (ober_get_integer(root, &v) == -1)
883 goto fail;
884 if (asprintf(&str, "%lld.%llds", v/100, v%100) == -1)
885 goto fail;
886 break;
887 case APPLICATION_OPAQUE:
888 if (ober_get_string(root, &buf) == -1)
889 goto fail;
890 p = reallocarray(NULL, 4, root->be_len + 1);
891 if (p == NULL)
892 goto fail;
893 strvisx(p, buf, root->be_len, VIS_NL);
894 if (asprintf(&str, "\"%s\"(opaque)", p) == -1) {
895 free(p);
896 goto fail;
897 }
898 free(p);
899 break;
900 case APPLICATION_COUNTER64:
901 if (ober_get_integer(root, &v) == -1)
902 goto fail;
903 if (asprintf(&str, "%lld(c64)", v) == -1)
904 goto fail;
905 break;
906 default:
907 /* Should not happen in a valid SNMP packet */
908 if (asprintf(&str, "[A/%u]", root->be_type) == -1)
909 goto fail;
910 break;
911 }
912 break;
913 case BER_CLASS_CONTEXT:
914 switch (root->be_type) {
915 case EXCEPTION_NOSUCHOBJECT:
916 str = strdup("noSuchObject");
917 break;
918 case EXCEPTION_NOSUCHINSTANCE:
919 str = strdup("noSuchInstance");
920 break;
921 case EXCEPTION_ENDOFMIBVIEW:
922 str = strdup("endOfMibView");
923 break;
924 default:
925 /* Should not happen in a valid SNMP packet */
926 if (asprintf(&str, "[C/%u]", root->be_type) == -1)
927 goto fail;
928 break;
929 }
930 break;
931 default:
932 /* Should not happen in a valid SNMP packet */
933 if (asprintf(&str, "[%hhu/%u]", root->be_class,
934 root->be_type) == -1)
935 goto fail;
936 break;
937 }
938
939 return (str);
940
941 fail:
942 free(str);
943 return (NULL);
944 }
945
946 void
smi_debug_elements(struct ber_element * root)947 smi_debug_elements(struct ber_element *root)
948 {
949 static int indent = 0;
950 char *value;
951 int constructed;
952
953 /* calculate lengths */
954 ober_calc_len(root);
955
956 switch (root->be_encoding) {
957 case BER_TYPE_SEQUENCE:
958 case BER_TYPE_SET:
959 constructed = root->be_encoding;
960 break;
961 default:
962 constructed = 0;
963 break;
964 }
965
966 fprintf(stderr, "%*slen %lu ", indent, "", root->be_len);
967 switch (root->be_class) {
968 case BER_CLASS_UNIVERSAL:
969 fprintf(stderr, "class: universal(%u) type: ", root->be_class);
970 switch (root->be_type) {
971 case BER_TYPE_EOC:
972 fprintf(stderr, "end-of-content");
973 break;
974 case BER_TYPE_INTEGER:
975 fprintf(stderr, "integer");
976 break;
977 case BER_TYPE_BITSTRING:
978 fprintf(stderr, "bit-string");
979 break;
980 case BER_TYPE_OCTETSTRING:
981 fprintf(stderr, "octet-string");
982 break;
983 case BER_TYPE_NULL:
984 fprintf(stderr, "null");
985 break;
986 case BER_TYPE_OBJECT:
987 fprintf(stderr, "object");
988 break;
989 case BER_TYPE_ENUMERATED:
990 fprintf(stderr, "enumerated");
991 break;
992 case BER_TYPE_SEQUENCE:
993 fprintf(stderr, "sequence");
994 break;
995 case BER_TYPE_SET:
996 fprintf(stderr, "set");
997 break;
998 }
999 break;
1000 case BER_CLASS_APPLICATION:
1001 fprintf(stderr, "class: application(%u) type: ",
1002 root->be_class);
1003 switch (root->be_type) {
1004 case APPLICATION_IPADDR:
1005 fprintf(stderr, "ipaddr");
1006 break;
1007 case APPLICATION_COUNTER32:
1008 fprintf(stderr, "counter32");
1009 break;
1010 case APPLICATION_GAUGE32:
1011 fprintf(stderr, "gauge32");
1012 break;
1013 case APPLICATION_TIMETICKS:
1014 fprintf(stderr, "timeticks");
1015 break;
1016 case APPLICATION_OPAQUE:
1017 fprintf(stderr, "opaque");
1018 break;
1019 case APPLICATION_COUNTER64:
1020 fprintf(stderr, "counter64");
1021 break;
1022 }
1023 break;
1024 case BER_CLASS_CONTEXT:
1025 fprintf(stderr, "class: context(%u) type: ",
1026 root->be_class);
1027 switch (root->be_type) {
1028 case REQUEST_GET:
1029 fprintf(stderr, "getreq");
1030 break;
1031 case REQUEST_GETNEXT:
1032 fprintf(stderr, "getnextreq");
1033 break;
1034 case REQUEST_RESPONSE:
1035 fprintf(stderr, "response");
1036 break;
1037 case REQUEST_SET:
1038 fprintf(stderr, "setreq");
1039 break;
1040 case REQUEST_TRAP:
1041 fprintf(stderr, "trap");
1042 break;
1043 case REQUEST_GETBULK:
1044 fprintf(stderr, "getbulkreq");
1045 break;
1046 case REQUEST_INFORM:
1047 fprintf(stderr, "informreq");
1048 break;
1049 case REQUEST_TRAPV2:
1050 fprintf(stderr, "trapv2");
1051 break;
1052 case REQUEST_REPORT:
1053 fprintf(stderr, "report");
1054 break;
1055 }
1056 break;
1057 case BER_CLASS_PRIVATE:
1058 fprintf(stderr, "class: private(%u) type: ", root->be_class);
1059 break;
1060 default:
1061 fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class);
1062 break;
1063 }
1064 fprintf(stderr, "(%u) encoding %u ",
1065 root->be_type, root->be_encoding);
1066
1067 if ((value = smi_print_element(root)) == NULL)
1068 goto invalid;
1069
1070 switch (root->be_encoding) {
1071 case BER_TYPE_INTEGER:
1072 case BER_TYPE_ENUMERATED:
1073 fprintf(stderr, "value %s", value);
1074 break;
1075 case BER_TYPE_BITSTRING:
1076 fprintf(stderr, "hexdump %s", value);
1077 break;
1078 case BER_TYPE_OBJECT:
1079 fprintf(stderr, "oid %s", value);
1080 break;
1081 case BER_TYPE_OCTETSTRING:
1082 if (root->be_class == BER_CLASS_APPLICATION &&
1083 root->be_type == APPLICATION_IPADDR) {
1084 fprintf(stderr, "addr %s", value);
1085 } else {
1086 fprintf(stderr, "string %s", value);
1087 }
1088 break;
1089 case BER_TYPE_NULL: /* no payload */
1090 case BER_TYPE_EOC:
1091 case BER_TYPE_SEQUENCE:
1092 case BER_TYPE_SET:
1093 default:
1094 fprintf(stderr, "%s", value);
1095 break;
1096 }
1097
1098 invalid:
1099 if (value == NULL)
1100 fprintf(stderr, "<INVALID>");
1101 else
1102 free(value);
1103 fprintf(stderr, "\n");
1104
1105 if (constructed)
1106 root->be_encoding = constructed;
1107
1108 if (constructed && root->be_sub) {
1109 indent += 2;
1110 smi_debug_elements(root->be_sub);
1111 indent -= 2;
1112 }
1113 if (root->be_next)
1114 smi_debug_elements(root->be_next);
1115 }
1116
1117 struct ber_element *
v2cmps(struct ber_element * message,const char * community)1118 v2cmps(struct ber_element *message, const char *community)
1119 {
1120 int version;
1121 const char *mcommunity;
1122 struct ber_element *pdu;
1123
1124 if (ober_scanf_elements(message, "{dse}$", &version, &mcommunity, &pdu) == -1)
1125 err(1, "%s: ober_scanf_elements", __func__);
1126
1127 if (strcmp(mcommunity, community) != 0)
1128 errx(1, "%s: invalid community (%s/%s)", __func__, mcommunity,
1129 community);
1130
1131 return pdu;
1132 }
1133
1134 void
snmp_pdu_validate(struct ber_element * pdu,enum snmp_request request,int32_t requestid,int32_t error,int32_t index,struct varbind * varbindlist,size_t nvarbind)1135 snmp_pdu_validate(struct ber_element *pdu, enum snmp_request request,
1136 int32_t requestid, int32_t error, int32_t index, struct varbind *varbindlist,
1137 size_t nvarbind)
1138 {
1139 int32_t mrequestid, merror, mindex;
1140 int class;
1141 unsigned int type;
1142 struct ber_element *mvarbindlist, *varbind;
1143 struct ber_oid moid, oid;
1144 struct ber_element *value;
1145 char oidbuf1[512], oidbuf2[512];
1146 size_t i;
1147
1148 if (ober_scanf_elements(pdu, "t{ddd{e}$}$", &class, &type, &mrequestid,
1149 &merror, &mindex, &varbind) == -1)
1150 err(1, "%s: ober_scanf_elementsi", __func__);
1151
1152 if (class != BER_CLASS_CONTEXT || type != request)
1153 errx(1, "%s: unexpected pdu type", __func__);
1154 if (mrequestid != requestid)
1155 errx(1, "%s: unexpected pdu requestid (%d/%d)",
1156 __func__, mrequestid, requestid);
1157 if (error != merror)
1158 errx(1, "%s: unexpected pdu error (%d/%d)",
1159 __func__, merror, error);
1160 if (index != mindex)
1161 errx(1, "%s: unepxected pdu index (%d/%d)",
1162 __func__, mindex, index);
1163
1164 for (i = 0; varbind != NULL; varbind = varbind->be_next, i++) {
1165 if (ober_scanf_elements(varbind, "{oeS$}", &moid, &value) == -1)
1166 err(1, "%s: ober_scanf_elements", __func__);
1167 if (i >= nvarbind)
1168 continue;
1169 snmp_oid2ber_oid(&varbindlist[i].name, &oid);
1170 if (!varbindlist[i].nameunknown && ober_oid_cmp(&moid, &oid) != 0)
1171 errx(1, "%s: unexpected oid (%s/%s)", __func__,
1172 smi_oid2string(&moid, oidbuf1, sizeof(oidbuf1)),
1173 smi_oid2string(&oid, oidbuf2, sizeof(oidbuf2)));
1174 if (value->be_class == BER_CLASS_UNIVERSAL &&
1175 value->be_type == BER_TYPE_INTEGER) {
1176 if (!varbindlist[i].typeunknown &&
1177 varbindlist[i].type != TYPE_INTEGER)
1178 errx(1, "%s: unexpected value", __func__);
1179 if (!varbindlist[i].dataunknown &&
1180 varbindlist[i].data.int32 != value->be_numeric)
1181 errx(1, "%s: unexpected value", __func__);
1182 } else if (value->be_class == BER_CLASS_UNIVERSAL &&
1183 value->be_type == BER_TYPE_OCTETSTRING) {
1184 if (!varbindlist[i].typeunknown &&
1185 varbindlist[i].type != TYPE_OCTETSTRING)
1186 errx(1, "%s: unexpected value", __func__);
1187 if (!varbindlist[i].dataunknown && (
1188 varbindlist[i].data.octetstring.len !=
1189 value->be_len ||
1190 memcmp(varbindlist[i].data.octetstring.string,
1191 value->be_val, value->be_len) != 0))
1192 errx(1, "%s: unexpected value", __func__);
1193 } else if (value->be_class == BER_CLASS_UNIVERSAL &&
1194 value->be_type == BER_TYPE_NULL) {
1195 if (!varbindlist[i].typeunknown &&
1196 varbindlist[i].type != TYPE_NULL)
1197 errx(1, "%s: unexpected value", __func__);
1198 } else if (value->be_class == BER_CLASS_UNIVERSAL &&
1199 value->be_type == BER_TYPE_OBJECT) {
1200 if (!varbindlist[i].typeunknown &&
1201 varbindlist[i].type != TYPE_OBJECTIDENTIFIER)
1202 errx(1, "%s: unexpected value", __func__);
1203 if (!varbindlist[i].dataunknown) {
1204 if (ober_get_oid(value, &moid) == -1)
1205 errx(1, "%s: unexpected value",
1206 __func__);
1207 snmp_oid2ber_oid(&varbindlist[i].data.oid,
1208 &oid);
1209 if (ober_oid_cmp(&oid, &moid) != 0)
1210 errx(1, "%s: unexpected value",
1211 __func__);
1212 }
1213 } else if (value->be_class == BER_CLASS_APPLICATION &&
1214 value->be_type == APPLICATION_IPADDR) {
1215 if (!varbindlist[i].typeunknown &&
1216 varbindlist[i].type != TYPE_IPADDRESS)
1217 errx(1, "%s: unexpected value", __func__);
1218 if (value->be_len != 4)
1219 errx(1, "%s: unexpected value", __func__);
1220 if (!varbindlist[i].dataunknown) {
1221 if (memcmp(value->be_val,
1222 varbindlist[i].data.octetstring.string,
1223 value->be_len) != 0)
1224 errx(1, "%s: unexpected value",
1225 __func__);
1226 }
1227 } else if (value->be_class == BER_CLASS_APPLICATION &&
1228 value->be_type == APPLICATION_COUNTER32) {
1229 if (!varbindlist[i].typeunknown &&
1230 varbindlist[i].type != TYPE_COUNTER32)
1231 errx(1, "%s: unexpected value", __func__);
1232 if (!varbindlist[i].dataunknown &&
1233 varbindlist[i].data.uint32 != value->be_numeric)
1234 errx(1, "%s: unexpected value", __func__);
1235 } else if (value->be_class == BER_CLASS_APPLICATION &&
1236 value->be_type == APPLICATION_GAUGE32) {
1237 if (!varbindlist[i].typeunknown &&
1238 varbindlist[i].type != TYPE_GAUGE32)
1239 errx(1, "%s: unexpected value", __func__);
1240 if (!varbindlist[i].dataunknown &&
1241 varbindlist[i].data.uint32 != value->be_numeric)
1242 errx(1, "%s: unexpected value", __func__);
1243 } else if (value->be_class == BER_CLASS_APPLICATION &&
1244 value->be_type == APPLICATION_TIMETICKS) {
1245 if (!varbindlist[i].typeunknown &&
1246 varbindlist[i].type != TYPE_TIMETICKS)
1247 errx(1, "%s: unexpected value", __func__);
1248 if (!varbindlist[i].dataunknown &&
1249 varbindlist[i].data.uint32 != value->be_numeric)
1250 errx(1, "%s: unexpected value", __func__);
1251 } else if (value->be_class == BER_CLASS_APPLICATION &&
1252 value->be_type == APPLICATION_OPAQUE) {
1253 if (!varbindlist[i].typeunknown &&
1254 varbindlist[i].type != TYPE_OPAQUE)
1255 errx(1, "%s: unexpected value", __func__);
1256 if (!varbindlist[i].dataunknown && (
1257 varbindlist[i].data.octetstring.len !=
1258 value->be_len ||
1259 memcmp(varbindlist[i].data.octetstring.string,
1260 value->be_val, value->be_len) != 0))
1261 errx(1, "%s: unexpected value", __func__);
1262 } else if (value->be_class == BER_CLASS_APPLICATION &&
1263 value->be_type == APPLICATION_COUNTER64) {
1264 if (!varbindlist[i].typeunknown &&
1265 varbindlist[i].type != TYPE_COUNTER64)
1266 errx(1, "%s: unexpected value", __func__);
1267 if (!varbindlist[i].dataunknown &&
1268 varbindlist[i].data.uint64 != value->be_numeric)
1269 errx(1, "%s: unexpected value", __func__);
1270 } else if (value->be_class == BER_CLASS_CONTEXT &&
1271 value->be_type == EXCEPTION_NOSUCHOBJECT) {
1272 if (!varbindlist[i].typeunknown &&
1273 varbindlist[i].type != TYPE_NOSUCHOBJECT)
1274 errx(1, "%s: unexpected value", __func__);
1275 } else if (value->be_class == BER_CLASS_CONTEXT &&
1276 value->be_type == EXCEPTION_NOSUCHINSTANCE) {
1277 if (!varbindlist[i].typeunknown &&
1278 varbindlist[i].type != TYPE_NOSUCHINSTANCE)
1279 errx(1, "%s: unexpected value", __func__);
1280 } else if (value->be_class == BER_CLASS_CONTEXT &&
1281 value->be_type == EXCEPTION_ENDOFMIBVIEW) {
1282 if (!varbindlist[i].typeunknown &&
1283 varbindlist[i].type != TYPE_ENDOFMIBVIEW)
1284 errx(1, "%s: unexpected value", __func__);
1285 } else
1286 errx(1, "%s: unexpected value", __func__);
1287 }
1288 if (i != nvarbind)
1289 errx(1, "%s: unexpected amount of varbind (%zu/%zu)", __func__,
1290 i, nvarbind);
1291 }
1292