184417368Smartijn #include <sys/socket.h>
284417368Smartijn #include <sys/types.h>
384417368Smartijn
484417368Smartijn #include <arpa/inet.h>
584417368Smartijn
684417368Smartijn #include <ber.h>
784417368Smartijn #include <err.h>
8*1434a006Smartijn #include <errno.h>
984417368Smartijn #include <inttypes.h>
1084417368Smartijn #include <netdb.h>
1184417368Smartijn #include <poll.h>
1284417368Smartijn #include <stdlib.h>
1384417368Smartijn #include <string.h>
1484417368Smartijn #include <unistd.h>
1584417368Smartijn #include <vis.h>
1684417368Smartijn
1784417368Smartijn #include "regress.h"
1884417368Smartijn
1984417368Smartijn #include <stdio.h>
2084417368Smartijn
2184417368Smartijn #define SNMP_HOSTNAME "127.0.0.1"
2284417368Smartijn #define SNMP_PORT "161"
2384417368Smartijn
2484417368Smartijn #define SNMP_R_COMMUNITY "public"
2584417368Smartijn
26da328aa4Smartijn #define MIB_SNMP_V3 MIB_SNMP, 1
27da328aa4Smartijn #define MIB_SNMP_USM MIB_SNMP_V3, 1
28da328aa4Smartijn
29da328aa4Smartijn #define MIB_SUBAGENT_V3 MIB_SUBAGENT_SNMP, 1
30da328aa4Smartijn #define MIB_SUBAGENT_USM MIB_SUBAGENT_V3, 1
31da328aa4Smartijn
32da328aa4Smartijn #define SNMPMODULES 1, 3, 6, 1, 6, 3
33da328aa4Smartijn #define SNMPUSMMIB SNMPMODULES, 15
34da328aa4Smartijn #define USMMIBOBJECTS SNMPUSMMIB, 1
35da328aa4Smartijn #define USMSTATS USMMIBOBJECTS, 1
36da328aa4Smartijn #define USMSTATSUNKNOWNENGINEIDS USMSTATS, 4
37da328aa4Smartijn
38da328aa4Smartijn #define BER_OID(...) (struct ber_oid){ {__VA_ARGS__}, \
39da328aa4Smartijn (sizeof((uint32_t []){__VA_ARGS__}) / sizeof(uint32_t)) }
40da328aa4Smartijn
4184417368Smartijn enum snmp_application {
4284417368Smartijn APPLICATION_IPADDR = 0,
4384417368Smartijn APPLICATION_COUNTER32 = 1,
4484417368Smartijn APPLICATION_GAUGE32 = 2,
4584417368Smartijn APPLICATION_UNSIGNED32 = 2,
4684417368Smartijn APPLICATION_TIMETICKS = 3,
4784417368Smartijn APPLICATION_OPAQUE = 4,
4884417368Smartijn APPLICATION_NSAPADDR = 5,
4984417368Smartijn APPLICATION_COUNTER64 = 6,
5084417368Smartijn };
5184417368Smartijn
5284417368Smartijn enum snmp_exception {
5384417368Smartijn EXCEPTION_NOSUCHOBJECT = 0,
5484417368Smartijn EXCEPTION_NOSUCHINSTANCE = 1,
5584417368Smartijn EXCEPTION_ENDOFMIBVIEW = 2
5684417368Smartijn };
5784417368Smartijn
58da328aa4Smartijn enum security_model {
59da328aa4Smartijn SM_USM = 3,
60da328aa4Smartijn SM_TSM = 4
61da328aa4Smartijn };
62da328aa4Smartijn
63da328aa4Smartijn struct usm {
64da328aa4Smartijn char engineid[32];
65da328aa4Smartijn size_t engineidlen;
66da328aa4Smartijn int engineboots;
67da328aa4Smartijn int enginetime;
68da328aa4Smartijn char username[33];
69da328aa4Smartijn };
70da328aa4Smartijn
71da328aa4Smartijn union securityparams {
72da328aa4Smartijn struct usm usm;
73da328aa4Smartijn };
74da328aa4Smartijn
75da328aa4Smartijn #define MSGFLAG_AUTH (1 << 0)
76da328aa4Smartijn #define MSGFLAG_PRIV (1 << 1)
77da328aa4Smartijn #define MSG_NOAUTHNOPRIV 0
78da328aa4Smartijn #define MSG_AUTHNOPRIV MSGFLAG_AUTH
79da328aa4Smartijn #define MSG_AUTHPRIV (MSGFLAG_AUTH | MSGFLAG_PRIV)
80da328aa4Smartijn #define MSGFLAG_REPORTABLE (1 << 2)
81da328aa4Smartijn #define MSGFLAG_ALL (MSGFLAG_AUTH | MSGFLAG_PRIV | MSGFLAG_REPORTABLE)
82da328aa4Smartijn struct headerdata {
83da328aa4Smartijn int32_t msgid;
84da328aa4Smartijn int32_t msgmaxsize;
85da328aa4Smartijn int8_t msgflags;
86da328aa4Smartijn enum security_model msgsm;
87da328aa4Smartijn char engineid[32];
88da328aa4Smartijn size_t engineidlen;
89da328aa4Smartijn char contextname[256];
90da328aa4Smartijn };
91da328aa4Smartijn
9284417368Smartijn int32_t snmpv2_send(int, const char *, enum snmp_request, int32_t, int32_t,
9384417368Smartijn int32_t, struct varbind *, size_t);
94da328aa4Smartijn int32_t snmpv3_get(int, int, struct headerdata *, union securityparams *,
95da328aa4Smartijn int32_t, struct varbind *, size_t);
96da328aa4Smartijn int32_t snmpv3_send(int, int, struct headerdata *, union securityparams *,
97da328aa4Smartijn enum snmp_request, int32_t, int32_t, int32_t, struct varbind *, size_t);
98da328aa4Smartijn int32_t snmpv3_usm_send(int, int, struct headerdata *, struct usm *, int32_t,
99da328aa4Smartijn struct varbind *, size_t);
100da328aa4Smartijn void snmpv3_usm_discovery(int, int, struct headerdata *, struct usm *);
101da328aa4Smartijn void snmpv3_encode(int, struct ber *, struct headerdata *,
102da328aa4Smartijn union securityparams *, struct ber_element *);
103da328aa4Smartijn void snmpv3_usm_encode(int, struct ber *, struct usm *);
104da328aa4Smartijn struct ber_element *snmpv3_decode(int, void *, size_t, struct ber_element *,
105da328aa4Smartijn struct headerdata *, union securityparams *);
106da328aa4Smartijn void snmpv3_response_validate(int, int, struct headerdata *,
107da328aa4Smartijn union securityparams *, int32_t, int32_t, int32_t, struct varbind *,
108da328aa4Smartijn size_t);
109da328aa4Smartijn void snmpv3_usm_decode(int, void *, size_t, void *, size_t, struct usm *);
110da328aa4Smartijn struct ber_element *snmp_recv(int, int, void *buf, size_t *);
11184417368Smartijn struct ber_element *snmp_pdu(enum snmp_request, int32_t, int32_t, int32_t,
11284417368Smartijn struct varbind *, size_t);
11384417368Smartijn struct ber_element *snmp_varbindlist(struct varbind *, size_t);
11484417368Smartijn struct ber_oid *snmp_oid2ber_oid(struct oid *, struct ber_oid *);
11584417368Smartijn struct ber_element *snmp_data2ber_element(enum type, union data *);
11684417368Smartijn unsigned int smi_application(struct ber_element *);
11784417368Smartijn char *smi_oid2string(struct ber_oid *, char *, size_t);
11884417368Smartijn char *smi_print_element(struct ber_element *);
11984417368Smartijn struct ber_element *v2cmps(struct ber_element *, const char *);
12084417368Smartijn void snmp_pdu_validate(struct ber_element *, enum snmp_request, int32_t,
12184417368Smartijn int32_t, int32_t, struct varbind *, size_t);
12284417368Smartijn
123da328aa4Smartijn void
snmp_v3_usm_noauthpriv(void)124da328aa4Smartijn snmp_v3_usm_noauthpriv(void)
125da328aa4Smartijn {
126da328aa4Smartijn struct sockaddr_storage ss;
127da328aa4Smartijn struct sockaddr *sa = (struct sockaddr *)&ss;
128da328aa4Smartijn socklen_t salen;
129da328aa4Smartijn int snmp_s, ax_s;
130da328aa4Smartijn uint32_t sessionid;
131da328aa4Smartijn struct varbind varbind = {
132da328aa4Smartijn .type = TYPE_NULL,
133da328aa4Smartijn .name = OID_STRUCT(MIB_SNMP_USM, 1, 0),
134da328aa4Smartijn .data.int32 = 1
135da328aa4Smartijn };
136da328aa4Smartijn struct headerdata hd = {
137da328aa4Smartijn .msgid = 0,
138da328aa4Smartijn .msgmaxsize = 0,
139da328aa4Smartijn .msgflags = MSG_NOAUTHNOPRIV | MSGFLAG_REPORTABLE,
140da328aa4Smartijn .msgsm = SM_USM
141da328aa4Smartijn };
142da328aa4Smartijn union securityparams params = {
143da328aa4Smartijn .usm.engineidlen = 0,
144da328aa4Smartijn .usm.engineboots = 0,
145da328aa4Smartijn .usm.enginetime = 0,
146da328aa4Smartijn .usm.username = "noauthpriv"
147da328aa4Smartijn };
148da328aa4Smartijn int32_t requestid;
149da328aa4Smartijn char buf[1024];
150da328aa4Smartijn size_t n;
151da328aa4Smartijn
152da328aa4Smartijn ax_s = agentx_connect(axsocket);
153da328aa4Smartijn sessionid = agentx_open(ax_s, 0, 0,
154da328aa4Smartijn OID_ARG(MIB_SUBAGENT_USM, 1), __func__);
155da328aa4Smartijn agentx_register(ax_s, sessionid, 0, 0, 127, 0,
156da328aa4Smartijn OID_ARG(MIB_SNMP_USM, 1), 0);
157da328aa4Smartijn
158da328aa4Smartijn salen = snmp_resolve(SOCK_DGRAM, hostname, servname, sa);
159da328aa4Smartijn snmp_s = snmp_connect(SOCK_DGRAM, sa, salen);
160da328aa4Smartijn requestid = snmpv3_get(snmp_s, 1000, &hd, ¶ms, 0, &varbind, 1);
161da328aa4Smartijn
162da328aa4Smartijn n = agentx_read(ax_s, buf, sizeof(buf), 1000);
163da328aa4Smartijn varbind.type = TYPE_INTEGER;
164da328aa4Smartijn agentx_get_handle(__func__, buf, n, 0, sessionid, &varbind, 1);
165da328aa4Smartijn agentx_response(ax_s, buf, 0, NOERROR, &varbind, 1);
166da328aa4Smartijn
167da328aa4Smartijn snmpv3_response_validate(snmp_s, 1000, &hd, ¶ms, requestid, 0, 0,
168da328aa4Smartijn &varbind, 1);
169da328aa4Smartijn }
170da328aa4Smartijn
17184417368Smartijn socklen_t
snmp_resolve(int type,const char * hostname,const char * servname,struct sockaddr * sa)17284417368Smartijn snmp_resolve(int type, const char *hostname, const char *servname, struct sockaddr *sa)
17384417368Smartijn {
17484417368Smartijn struct addrinfo hints, *res;
17584417368Smartijn socklen_t salen;
17684417368Smartijn int error;
17784417368Smartijn
17884417368Smartijn if (hostname == NULL)
17984417368Smartijn hostname = SNMP_HOSTNAME;
18084417368Smartijn if (servname == NULL)
18184417368Smartijn servname = SNMP_PORT;
18284417368Smartijn
18384417368Smartijn memset(&hints, 0, sizeof(hints));
18484417368Smartijn hints.ai_family = AF_UNSPEC;
18584417368Smartijn hints.ai_socktype = type;
18684417368Smartijn
18784417368Smartijn if ((error = getaddrinfo(hostname, servname, &hints, &res)) != 0)
18884417368Smartijn errx(1, "getaddrinfo(%s, %s): %s", hostname, servname,
18984417368Smartijn gai_strerror(error));
19084417368Smartijn
19184417368Smartijn memcpy(sa, res->ai_addr, res->ai_addrlen);
19284417368Smartijn salen = res->ai_addrlen;
19384417368Smartijn
19484417368Smartijn freeaddrinfo(res);
19584417368Smartijn return salen;
19684417368Smartijn }
19784417368Smartijn
19884417368Smartijn int
snmp_connect(int type,struct sockaddr * sa,socklen_t salen)19984417368Smartijn snmp_connect(int type, struct sockaddr *sa, socklen_t salen)
20084417368Smartijn {
20184417368Smartijn int s;
20284417368Smartijn
20384417368Smartijn if ((s = socket(sa->sa_family, type, 0)) == -1)
20484417368Smartijn err(1, "socket");
20584417368Smartijn if (connect(s, sa, salen) == -1)
20684417368Smartijn err(1, "connect");
20784417368Smartijn return s;
20884417368Smartijn }
20984417368Smartijn
21084417368Smartijn int32_t
snmpv2_get(int s,const char * community,int32_t requestid,struct varbind * varbindlist,size_t nvarbind)21184417368Smartijn snmpv2_get(int s, const char *community, int32_t requestid,
21284417368Smartijn struct varbind *varbindlist, size_t nvarbind)
21384417368Smartijn {
21484417368Smartijn return snmpv2_send(s, community, REQUEST_GET, requestid, 0, 0,
21584417368Smartijn varbindlist, nvarbind);
21684417368Smartijn }
21784417368Smartijn
21884417368Smartijn int32_t
snmpv2_getnext(int s,const char * community,int32_t requestid,struct varbind * varbindlist,size_t nvarbind)21984417368Smartijn snmpv2_getnext(int s, const char *community, int32_t requestid,
22084417368Smartijn struct varbind *varbindlist, size_t nvarbind)
22184417368Smartijn {
22284417368Smartijn return snmpv2_send(s, community, REQUEST_GETNEXT, requestid, 0, 0,
22384417368Smartijn varbindlist, nvarbind);
22484417368Smartijn }
22584417368Smartijn
22684417368Smartijn int32_t
snmpv2_getbulk(int s,const char * community,int32_t requestid,int32_t nonrep,int32_t maxrep,struct varbind * varbindlist,size_t nvarbind)22784417368Smartijn snmpv2_getbulk(int s, const char *community, int32_t requestid, int32_t nonrep,
22884417368Smartijn int32_t maxrep, struct varbind *varbindlist, size_t nvarbind)
22984417368Smartijn {
23084417368Smartijn return snmpv2_send(s, community, REQUEST_GETBULK, requestid, nonrep,
23184417368Smartijn maxrep, varbindlist, nvarbind);
23284417368Smartijn }
23384417368Smartijn
2344e63e8f9Smartijn 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)2354e63e8f9Smartijn snmpv2_build(const char *community, enum snmp_request request,
2364e63e8f9Smartijn int32_t requestid, int32_t error, int32_t index,
2374e63e8f9Smartijn struct varbind *varbindlist, size_t nvarbind)
2384e63e8f9Smartijn {
2394e63e8f9Smartijn struct ber_element *message;
2404e63e8f9Smartijn
2414e63e8f9Smartijn if (community == NULL)
2424e63e8f9Smartijn community = SNMP_R_COMMUNITY;
2434e63e8f9Smartijn message = ober_printf_elements(NULL, "{dse}", 1, community,
2444e63e8f9Smartijn snmp_pdu(request, requestid, error, index, varbindlist, nvarbind));
2454e63e8f9Smartijn if (message == NULL)
2464e63e8f9Smartijn err(1, NULL);
2474e63e8f9Smartijn
2484e63e8f9Smartijn return message;
2494e63e8f9Smartijn }
2504e63e8f9Smartijn
25184417368Smartijn 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)25284417368Smartijn snmpv2_send(int s, const char *community, enum snmp_request request,
25384417368Smartijn int32_t requestid, int32_t error, int32_t index,
25484417368Smartijn struct varbind *varbindlist, size_t nvarbind)
25584417368Smartijn {
25684417368Smartijn struct ber_element *message;
25784417368Smartijn struct ber ber = {};
25884417368Smartijn void *buf;
25984417368Smartijn ssize_t buflen, writelen;
26084417368Smartijn
26184417368Smartijn while (requestid == 0)
26284417368Smartijn requestid = arc4random();
2634e63e8f9Smartijn
2644e63e8f9Smartijn message = snmpv2_build(community, request, requestid, error, index,
2654e63e8f9Smartijn varbindlist,nvarbind);
26684417368Smartijn
26784417368Smartijn if (ober_write_elements(&ber, message) == -1)
26884417368Smartijn err(1, "ober_write_elements");
26984417368Smartijn
27084417368Smartijn buflen = ober_get_writebuf(&ber, &buf);
27184417368Smartijn if ((writelen = write(s, buf, buflen)) == -1)
27284417368Smartijn err(1, "write");
27384417368Smartijn if (writelen != buflen)
27484417368Smartijn errx(1, "write: short write");
27584417368Smartijn
27684417368Smartijn if (verbose) {
27784417368Smartijn printf("SNMP send(%d):\n", s);
27884417368Smartijn smi_debug_elements(message);
27984417368Smartijn }
28084417368Smartijn ober_free_elements(message);
28184417368Smartijn ober_free(&ber);
28284417368Smartijn
28384417368Smartijn return requestid;
28484417368Smartijn }
28584417368Smartijn
28684417368Smartijn 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)28784417368Smartijn snmpv2_response_validate(int s, int timeout, const char *community,
28884417368Smartijn int32_t requestid, int32_t error, int32_t index,
28984417368Smartijn struct varbind *varbindlist, size_t nvarbind)
29084417368Smartijn {
29184417368Smartijn struct ber_element *message, *pdu;
292*1434a006Smartijn char buf[100000];
293da328aa4Smartijn size_t buflen = sizeof(buf);
29484417368Smartijn
295da328aa4Smartijn message = snmp_recv(s, timeout, buf, &buflen);
29684417368Smartijn
29784417368Smartijn if (community == NULL)
29884417368Smartijn community = SNMP_R_COMMUNITY;
29984417368Smartijn snmp_pdu_validate(v2cmps(message, community), REQUEST_RESPONSE,
30084417368Smartijn requestid, error, index, varbindlist, nvarbind);
30184417368Smartijn
30284417368Smartijn ober_free_elements(message);
30384417368Smartijn }
30484417368Smartijn
30584417368Smartijn struct ber_element *
snmp_recv(int s,int timeout,void * buf,size_t * buflen)306da328aa4Smartijn snmp_recv(int s, int timeout, void *buf, size_t *buflen)
30784417368Smartijn {
30884417368Smartijn struct pollfd pfd = {
30984417368Smartijn .fd = s,
31084417368Smartijn .events = POLLIN
31184417368Smartijn };
31284417368Smartijn struct ber ber = {};
31384417368Smartijn struct ber_element *message;
31484417368Smartijn ssize_t n;
315*1434a006Smartijn size_t ntot = 0;
31684417368Smartijn int ret;
31784417368Smartijn
318*1434a006Smartijn again:
31984417368Smartijn if ((ret = poll(&pfd, 1, timeout)) == -1)
32084417368Smartijn err(1, "poll");
321*1434a006Smartijn if (ret == 0) {
322*1434a006Smartijn if (ntot == 0)
32384417368Smartijn errx(1, "%s: timeout", __func__);
324*1434a006Smartijn errc(1, ECANCELED, "%s: unable to decode message", __func__);
325*1434a006Smartijn }
326*1434a006Smartijn if ((n = read(s, buf + ntot, *buflen - ntot)) == -1)
327*1434a006Smartijn err(1, "snmp read");
328*1434a006Smartijn ntot += n;
329da328aa4Smartijn
33084417368Smartijn ober_set_application(&ber, smi_application);
331*1434a006Smartijn ober_set_readbuf(&ber, buf, ntot);
33284417368Smartijn
333*1434a006Smartijn if ((message = ober_read_elements(&ber, NULL)) == NULL) {
334*1434a006Smartijn if (errno == ECANCELED)
335*1434a006Smartijn goto again;
336da328aa4Smartijn errx(1, "%s: unable to decode message", __func__);
337*1434a006Smartijn }
338*1434a006Smartijn *buflen = n;
33984417368Smartijn if (verbose) {
34084417368Smartijn printf("SNMP received(%d):\n", s);
34184417368Smartijn smi_debug_elements(message);
34284417368Smartijn }
34384417368Smartijn
34484417368Smartijn ober_free(&ber);
34584417368Smartijn
34684417368Smartijn return message;
34784417368Smartijn }
34884417368Smartijn
349da328aa4Smartijn int32_t
snmpv3_get(int s,int timeout,struct headerdata * hd,union securityparams * params,int32_t requestid,struct varbind * varbindlist,size_t nvarbind)350da328aa4Smartijn snmpv3_get(int s, int timeout, struct headerdata *hd,
351da328aa4Smartijn union securityparams *params, int32_t requestid,
352da328aa4Smartijn struct varbind *varbindlist, size_t nvarbind)
353da328aa4Smartijn {
354da328aa4Smartijn return snmpv3_send(s, timeout, hd, params, REQUEST_GET, requestid,
355da328aa4Smartijn 0, 0, varbindlist, nvarbind);
356da328aa4Smartijn }
357da328aa4Smartijn
358da328aa4Smartijn 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)359da328aa4Smartijn snmpv3_send(int s, int timeout, struct headerdata *hd,
360da328aa4Smartijn union securityparams *params, enum snmp_request request, int32_t requestid,
361da328aa4Smartijn int32_t error, int32_t index, struct varbind *varbindlist, size_t nvarbind)
362da328aa4Smartijn {
363da328aa4Smartijn struct ber ber;
364da328aa4Smartijn void *buf;
365da328aa4Smartijn ssize_t buflen, writelen;
366da328aa4Smartijn
367da328aa4Smartijn if (hd->msgid == 0)
368da328aa4Smartijn hd->msgid = arc4random();
369da328aa4Smartijn if (hd->msgmaxsize == 0)
370da328aa4Smartijn hd->msgmaxsize = 484;
371da328aa4Smartijn if (requestid == 0)
372da328aa4Smartijn requestid = arc4random();
373da328aa4Smartijn
374da328aa4Smartijn if (hd->msgsm == SM_USM)
375da328aa4Smartijn snmpv3_usm_discovery(s, timeout, hd, ¶ms->usm);
376da328aa4Smartijn
377da328aa4Smartijn snmpv3_encode(s, &ber, hd, params, snmp_pdu(request, requestid, error,
378da328aa4Smartijn index, varbindlist, nvarbind));
379da328aa4Smartijn
380da328aa4Smartijn buflen = ober_get_writebuf(&ber, &buf);
381da328aa4Smartijn if ((writelen = write(s, buf, buflen)) == -1)
382da328aa4Smartijn err(1, "write");
383da328aa4Smartijn if (writelen != buflen)
384da328aa4Smartijn errx(1, "write: short write");
385da328aa4Smartijn
386da328aa4Smartijn ober_free(&ber);
387da328aa4Smartijn
388da328aa4Smartijn return requestid;
389da328aa4Smartijn }
390da328aa4Smartijn
391da328aa4Smartijn void
snmpv3_usm_discovery(int s,int timeout,struct headerdata * hd,struct usm * params)392da328aa4Smartijn snmpv3_usm_discovery(int s, int timeout, struct headerdata *hd,
393da328aa4Smartijn struct usm *params)
394da328aa4Smartijn {
395da328aa4Smartijn struct ber_element *message, *pdu;
396da328aa4Smartijn struct ber_oid oid;
397da328aa4Smartijn struct ber ber;
398da328aa4Smartijn struct headerdata hdd;
399da328aa4Smartijn union securityparams sp = {
400da328aa4Smartijn .usm = *params
401da328aa4Smartijn };
402da328aa4Smartijn void *buf;
403da328aa4Smartijn char rbuf[1024];
404da328aa4Smartijn size_t rbuflen = sizeof(rbuf);
405da328aa4Smartijn int8_t msgflags;
406da328aa4Smartijn size_t buflen, writelen;
407da328aa4Smartijn char oidbuf[1024];
408da328aa4Smartijn struct varbind vb = {
409da328aa4Smartijn .type = TYPE_COUNTER32,
410da328aa4Smartijn .dataunknown = 1
411da328aa4Smartijn };
412da328aa4Smartijn
413da328aa4Smartijn hdd = *hd;
414da328aa4Smartijn hdd.msgid = arc4random();
415da328aa4Smartijn if (params->engineidlen == 0) {
416da328aa4Smartijn hdd.msgflags = MSGFLAG_REPORTABLE;
417da328aa4Smartijn sp.usm.username[0] = '\0';
418da328aa4Smartijn } else if (hd->msgflags & MSGFLAG_AUTH && params->engineboots == 0 &&
419da328aa4Smartijn params->enginetime == 0)
420da328aa4Smartijn hdd.msgflags = MSGFLAG_AUTH | MSGFLAG_REPORTABLE;
421da328aa4Smartijn else
422da328aa4Smartijn return;
423da328aa4Smartijn
424da328aa4Smartijn pdu = snmp_pdu(REQUEST_GET, 0, 0, 0, NULL, 0);
425da328aa4Smartijn snmpv3_encode(s, &ber, &hdd, &sp, pdu);
426da328aa4Smartijn buflen = ober_get_writebuf(&ber, &buf);
427da328aa4Smartijn if ((writelen = write(s, buf, buflen)) == -1)
428da328aa4Smartijn err(1, "write");
429da328aa4Smartijn if (writelen != buflen)
430da328aa4Smartijn errx(1, "write: short write");
431da328aa4Smartijn
432da328aa4Smartijn retry:
433da328aa4Smartijn message = snmp_recv(s, timeout, rbuf, &rbuflen);
434da328aa4Smartijn
435da328aa4Smartijn hdd.msgflags &= ~MSGFLAG_REPORTABLE;
436da328aa4Smartijn pdu = snmpv3_decode(s, rbuf, rbuflen, message, &hdd, &sp);
437da328aa4Smartijn
438da328aa4Smartijn if (params->engineidlen == 0) {
439da328aa4Smartijn vb.name = OID_STRUCT(USMSTATSUNKNOWNENGINEIDS, 0);
440da328aa4Smartijn snmp_pdu_validate(pdu, REQUEST_REPORT, 0, 0, 0, &vb, 1);
441da328aa4Smartijn memcpy(params->engineid, sp.usm.engineid, sp.usm.engineidlen);
442da328aa4Smartijn params->engineidlen = sp.usm.engineidlen;
443da328aa4Smartijn if (hd->msgflags & MSGFLAG_AUTH)
444da328aa4Smartijn snmpv3_usm_discovery(s, timeout, hd, params);
445da328aa4Smartijn }
446da328aa4Smartijn
447da328aa4Smartijn ober_free(&ber);
448da328aa4Smartijn ober_free_elements(message);
449da328aa4Smartijn
450da328aa4Smartijn return;
451da328aa4Smartijn }
452da328aa4Smartijn
453da328aa4Smartijn void
snmpv3_encode(int s,struct ber * ber,struct headerdata * hd,union securityparams * params,struct ber_element * pdu)454da328aa4Smartijn snmpv3_encode(int s, struct ber *ber, struct headerdata *hd,
455da328aa4Smartijn union securityparams *params, struct ber_element *pdu)
456da328aa4Smartijn {
457da328aa4Smartijn struct ber_element *message;
458da328aa4Smartijn void *sp;
459da328aa4Smartijn size_t splen;
460da328aa4Smartijn
461da328aa4Smartijn switch (hd->msgsm) {
462da328aa4Smartijn case SM_USM:
463da328aa4Smartijn snmpv3_usm_encode(s, ber, ¶ms->usm);
464da328aa4Smartijn break;
465da328aa4Smartijn default:
466da328aa4Smartijn errx(1, "%s: unsupported securityModel %d",
467da328aa4Smartijn __func__, hd->msgsm);
468da328aa4Smartijn }
469da328aa4Smartijn
470da328aa4Smartijn splen = ober_get_writebuf(ber, &sp);
471da328aa4Smartijn if ((message = ober_printf_elements(NULL, "{d{ddxd}x{xse}}", 3,
472da328aa4Smartijn hd->msgid, hd->msgmaxsize, &hd->msgflags, sizeof(hd->msgflags),
473da328aa4Smartijn hd->msgsm, sp, splen, hd->engineid, hd->engineidlen,
474da328aa4Smartijn hd->contextname, pdu)) == NULL)
475da328aa4Smartijn err(1, NULL);
476da328aa4Smartijn ober_free(ber);
477da328aa4Smartijn *ber = (struct ber){};
478da328aa4Smartijn ober_set_application(ber, smi_application);
479da328aa4Smartijn if (ober_write_elements(ber, message) == -1)
480da328aa4Smartijn err(1, NULL);
481da328aa4Smartijn if (verbose) {
482da328aa4Smartijn printf("SNMP send(%d):\n", s);
483da328aa4Smartijn smi_debug_elements(message);
484da328aa4Smartijn }
485da328aa4Smartijn ober_free_elements(message);
486da328aa4Smartijn }
487da328aa4Smartijn
488da328aa4Smartijn void
snmpv3_usm_encode(int s,struct ber * ber,struct usm * params)489da328aa4Smartijn snmpv3_usm_encode(int s, struct ber *ber, struct usm *params)
490da328aa4Smartijn {
491da328aa4Smartijn struct ber_element *sp;
492da328aa4Smartijn
493da328aa4Smartijn *ber = (struct ber){};
494da328aa4Smartijn ober_set_application(ber, smi_application);
495da328aa4Smartijn if ((sp = ober_printf_elements(NULL, "{xddxss}", params->engineid,
496da328aa4Smartijn params->engineidlen, params->engineboots, params->enginetime,
497da328aa4Smartijn params->username, strlen(params->username), "", "")) == NULL)
498da328aa4Smartijn err(1, NULL);
499da328aa4Smartijn if (ober_write_elements(ber, sp) == -1)
500da328aa4Smartijn err(1, NULL);
501da328aa4Smartijn if (verbose) {
502da328aa4Smartijn printf("USM params send(%d):\n", s);
503da328aa4Smartijn smi_debug_elements(sp);
504da328aa4Smartijn }
505da328aa4Smartijn ober_free_elements(sp);
506da328aa4Smartijn }
507da328aa4Smartijn
508da328aa4Smartijn struct ber_element *
snmpv3_decode(int s,void * buf,size_t buflen,struct ber_element * message,struct headerdata * hd,union securityparams * sp)509da328aa4Smartijn snmpv3_decode(int s, void *buf, size_t buflen, struct ber_element *message,
510da328aa4Smartijn struct headerdata *hd, union securityparams *sp)
511da328aa4Smartijn {
512da328aa4Smartijn struct ber_element *pdu;
513da328aa4Smartijn int32_t version, msgid, msgmaxsize, sm;
514da328aa4Smartijn char *msgflags, *spstr, *engineid, *name;
515da328aa4Smartijn size_t msgflagslen, spstrlen, engineidlen, namelen;
516da328aa4Smartijn int class;
517da328aa4Smartijn unsigned int type;
518da328aa4Smartijn
519da328aa4Smartijn if (ober_scanf_elements(message, "{d{ddxd$}x{xxe}",
520da328aa4Smartijn &version, &msgid, &msgmaxsize, &msgflags, &msgflagslen,
521da328aa4Smartijn &sm, &spstr, &spstrlen, &engineid, &engineidlen, &name, &namelen,
522da328aa4Smartijn &pdu) == -1)
523da328aa4Smartijn errx(1, "%s: ober_scanf_elements", __func__);
524da328aa4Smartijn if (version != 3)
525da328aa4Smartijn errx(1, "%s: invalid version", __func__);
526da328aa4Smartijn if (msgid != hd->msgid)
527da328aa4Smartijn errx(1, "%s: unexpected msgid", __func__);
528da328aa4Smartijn if (msgmaxsize < 484 || msgmaxsize > 2147483647)
529da328aa4Smartijn errx(1, "%s: invalid msgmaxsize", __func__);
530da328aa4Smartijn if (msgflagslen != 1 || msgflags[0] != hd->msgflags)
531da328aa4Smartijn errx(1, "%s: invalid msgflags", __func__);
532da328aa4Smartijn if (sm != hd->msgsm)
533da328aa4Smartijn errx(1, "%s: unexpected security model", __func__);
534da328aa4Smartijn if (engineidlen < 5 || engineidlen > 32)
535da328aa4Smartijn errx(1, "%s: invalid contextEngineID", __func__);
536da328aa4Smartijn if (hd->engineidlen != 0) {
537da328aa4Smartijn if (hd->engineidlen != engineidlen ||
538da328aa4Smartijn memcmp(hd->engineid, engineid, engineidlen) != 0)
539da328aa4Smartijn errx(1, "%s: unexpected engineid", __func__);
540da328aa4Smartijn } else {
541da328aa4Smartijn hd->engineidlen = engineidlen;
542da328aa4Smartijn memcpy(hd->engineid, engineid, engineidlen);
543da328aa4Smartijn }
544da328aa4Smartijn if (namelen > 255)
545da328aa4Smartijn errx(1, "%s: invalid ctxnamelen", __func__);
546da328aa4Smartijn if (strcmp(hd->contextname, name) != 0)
547da328aa4Smartijn errx(1, "%s: unexpected context", __func__);
548da328aa4Smartijn
549da328aa4Smartijn switch (sm) {
550da328aa4Smartijn case SM_USM:
551da328aa4Smartijn snmpv3_usm_decode(s, buf, buflen, spstr, spstrlen, &sp->usm);
552da328aa4Smartijn }
553da328aa4Smartijn return pdu;
554da328aa4Smartijn }
555da328aa4Smartijn
556da328aa4Smartijn void
snmpv3_usm_decode(int s,void * buf,size_t buflen,void * spstr,size_t spstrlen,struct usm * usm)557da328aa4Smartijn snmpv3_usm_decode(int s, void *buf, size_t buflen, void *spstr, size_t spstrlen,
558da328aa4Smartijn struct usm *usm)
559da328aa4Smartijn {
560da328aa4Smartijn struct ber ber = {};
561da328aa4Smartijn struct ber_element *sp;
562da328aa4Smartijn char *engineid, *username, *authparams, *privparams;
563da328aa4Smartijn size_t engineidlen, usernamelen, authparamslen, privparamslen;
564da328aa4Smartijn int32_t engineboots, enginetime;
565da328aa4Smartijn
566da328aa4Smartijn ober_set_application(&ber, smi_application);
567da328aa4Smartijn ober_set_readbuf(&ber, spstr, spstrlen);
568da328aa4Smartijn if ((sp = ober_read_elements(&ber, NULL)) == NULL)
569da328aa4Smartijn errx(1, "%s: ober_read_elements", __func__);
570da328aa4Smartijn if (verbose) {
571da328aa4Smartijn printf("USM params received(%d):\n", s);
572da328aa4Smartijn smi_debug_elements(sp);
573da328aa4Smartijn }
574da328aa4Smartijn
575da328aa4Smartijn if (ober_scanf_elements(sp, "{xddxxx}", &engineid, &engineidlen,
576da328aa4Smartijn &engineboots, &enginetime, &username, &usernamelen, &authparams,
577da328aa4Smartijn &authparamslen, &privparams, &privparamslen) == -1)
578da328aa4Smartijn errx(1, "%s: ober_scanf_elements", __func__);
579da328aa4Smartijn
580da328aa4Smartijn if (engineidlen < 5 || engineidlen > 32)
581da328aa4Smartijn errx(1, "%s: invalid msgAuthoritativeEngineID", __func__);
582da328aa4Smartijn if (engineboots < 0 || engineboots > 2147483647)
583da328aa4Smartijn errx(1, "%s: invalid msgAuthoritativeEngineBoots", __func__);
584da328aa4Smartijn if (enginetime < 0 || enginetime > 2147483647)
585da328aa4Smartijn errx(1, "%s: invalid msgAuthoritativeEngineTime", __func__);
586da328aa4Smartijn if (usernamelen < 0 || usernamelen > 32)
587da328aa4Smartijn errx(1, "%s: invalid msgUserName", __func__);
588da328aa4Smartijn
589da328aa4Smartijn if (usm->engineidlen == 0) {
590da328aa4Smartijn memcpy(usm->engineid, engineid, engineidlen);
591da328aa4Smartijn usm->engineidlen = engineidlen;
592da328aa4Smartijn } else {
593da328aa4Smartijn if (usm->engineidlen != engineidlen ||
594da328aa4Smartijn memcmp(usm->engineid, engineid, engineidlen) != 0)
595da328aa4Smartijn errx(1, "%s: unexpected engineid", __func__);
596da328aa4Smartijn }
597da328aa4Smartijn if (usm->engineboots == 0 && usm->enginetime == 0) {
598da328aa4Smartijn usm->engineboots = engineboots;
599da328aa4Smartijn usm->enginetime = enginetime;
600da328aa4Smartijn } else {
601da328aa4Smartijn if (usm->engineboots < engineboots)
602da328aa4Smartijn errx(1, "%s: engineboots decremented", __func__);
603da328aa4Smartijn else if (usm->engineboots == engineboots) {
604da328aa4Smartijn if (enginetime < usm->enginetime - 150 ||
605da328aa4Smartijn enginetime > usm->enginetime + 150)
606da328aa4Smartijn errx(1, "%s: enginetime out of window",
607da328aa4Smartijn __func__);
608da328aa4Smartijn } else {
609da328aa4Smartijn if (enginetime > 150)
610da328aa4Smartijn errx(1, "%s: enginetime out of window",
611da328aa4Smartijn __func__);
612da328aa4Smartijn }
613da328aa4Smartijn }
614da328aa4Smartijn if (strcmp(username, usm->username) != 0)
615da328aa4Smartijn errx(1, "unexpected username");
616da328aa4Smartijn }
617da328aa4Smartijn
618da328aa4Smartijn 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)619da328aa4Smartijn snmpv3_response_validate(int s, int timeout, struct headerdata *hd,
620da328aa4Smartijn union securityparams *sp, int32_t requestid, int32_t error, int32_t index,
621da328aa4Smartijn struct varbind *varbindlist, size_t nvarbind)
622da328aa4Smartijn {
623da328aa4Smartijn struct ber_element *message, *pdu;
624da328aa4Smartijn char buf[1024];
625da328aa4Smartijn size_t buflen = sizeof(buf);
626da328aa4Smartijn hd->msgflags &= ~MSGFLAG_REPORTABLE;
627da328aa4Smartijn
628da328aa4Smartijn message = snmp_recv(s, timeout, buf, &buflen);
629da328aa4Smartijn pdu = snmpv3_decode(1, buf, sizeof(buf), message, hd, sp);
630da328aa4Smartijn snmp_pdu_validate(pdu, REQUEST_RESPONSE, requestid, error, index,
631da328aa4Smartijn varbindlist, nvarbind);
632da328aa4Smartijn
633da328aa4Smartijn ober_free_elements(message);
634da328aa4Smartijn }
635da328aa4Smartijn
63684417368Smartijn void
snmp_timeout(int s,int timeout)63784417368Smartijn snmp_timeout(int s, int timeout)
63884417368Smartijn {
63984417368Smartijn int ret;
64084417368Smartijn struct pollfd pfd = {
64184417368Smartijn .fd = s,
64284417368Smartijn .events = POLLIN
64384417368Smartijn };
64484417368Smartijn
64584417368Smartijn if ((ret = poll(&pfd, 1, timeout)) == -1)
64684417368Smartijn err(1, "poll");
64784417368Smartijn if (ret != 0)
64884417368Smartijn errx(1, "%s: unexpected snmp data", __func__);
64984417368Smartijn }
65084417368Smartijn
65184417368Smartijn struct ber_element *
snmp_pdu(enum snmp_request request,int32_t requestid,int32_t error,int32_t index,struct varbind * varbindlist,size_t nvarbind)65284417368Smartijn snmp_pdu(enum snmp_request request, int32_t requestid, int32_t error,
65384417368Smartijn int32_t index, struct varbind *varbindlist, size_t nvarbind)
65484417368Smartijn {
65584417368Smartijn struct ber_element *pdu;
65684417368Smartijn
65784417368Smartijn if ((pdu = ober_printf_elements(NULL, "{tddde}", BER_CLASS_CONTEXT,
65884417368Smartijn request, requestid, error, index,
65984417368Smartijn snmp_varbindlist(varbindlist, nvarbind))) == NULL)
66084417368Smartijn err(1, NULL);
66184417368Smartijn return pdu;
66284417368Smartijn }
66384417368Smartijn
66484417368Smartijn struct ber_element *
snmp_varbindlist(struct varbind * varbindlist,size_t nvarbind)66584417368Smartijn snmp_varbindlist(struct varbind *varbindlist, size_t nvarbind)
66684417368Smartijn {
66784417368Smartijn struct ber_element *vblist, *prev = NULL;
66884417368Smartijn struct ber_oid oid;
66984417368Smartijn size_t i;
67084417368Smartijn
67184417368Smartijn if ((vblist = prev = ober_add_sequence(NULL)) == NULL)
67284417368Smartijn err(1, NULL);
67384417368Smartijn for (i = 0; i < nvarbind; i++) {
67484417368Smartijn if ((prev = ober_printf_elements(prev, "{Oe}",
67584417368Smartijn snmp_oid2ber_oid(&varbindlist[i].name, &oid),
67684417368Smartijn snmp_data2ber_element(varbindlist[i].type,
67784417368Smartijn &varbindlist[i].data))) == NULL)
67884417368Smartijn err(1, NULL);
67984417368Smartijn }
68084417368Smartijn
68184417368Smartijn return vblist;
68284417368Smartijn }
68384417368Smartijn
68484417368Smartijn struct ber_oid *
snmp_oid2ber_oid(struct oid * oid,struct ber_oid * boid)68584417368Smartijn snmp_oid2ber_oid(struct oid *oid, struct ber_oid *boid)
68684417368Smartijn {
68784417368Smartijn size_t i;
68884417368Smartijn
68984417368Smartijn for (i = 0; i < oid->n_subid; i++)
69084417368Smartijn boid->bo_id[i] = oid->subid[i];
69184417368Smartijn boid->bo_n = oid->n_subid;
69284417368Smartijn
69384417368Smartijn return boid;
69484417368Smartijn }
69584417368Smartijn
69684417368Smartijn struct ber_element *
snmp_data2ber_element(enum type type,union data * data)69784417368Smartijn snmp_data2ber_element(enum type type, union data *data)
69884417368Smartijn {
69984417368Smartijn struct ber_element *elm;
70084417368Smartijn struct ber_oid oid;
70184417368Smartijn
70284417368Smartijn switch (type) {
70384417368Smartijn case TYPE_INTEGER:
70484417368Smartijn elm = ober_add_integer(NULL, data->int32);
70584417368Smartijn break;
70684417368Smartijn case TYPE_OCTETSTRING:
70784417368Smartijn elm = ober_add_nstring(NULL, data->octetstring.string,
70884417368Smartijn data->octetstring.len);
70984417368Smartijn break;
71084417368Smartijn case TYPE_NULL:
71184417368Smartijn elm = ober_add_null(NULL);
71284417368Smartijn break;
71384417368Smartijn case TYPE_OBJECTIDENTIFIER:
71484417368Smartijn elm = ober_add_oid(NULL, snmp_oid2ber_oid(&data->oid, &oid));
71584417368Smartijn break;
71684417368Smartijn case TYPE_IPADDRESS:
71784417368Smartijn if ((elm = ober_add_nstring(NULL, data->octetstring.string,
71884417368Smartijn data->octetstring.len)) == NULL)
71984417368Smartijn err(1, NULL);
72084417368Smartijn ober_set_header(elm, BER_CLASS_APPLICATION, APPLICATION_IPADDR);
72184417368Smartijn break;
72284417368Smartijn case TYPE_COUNTER32:
72384417368Smartijn if ((elm = ober_add_integer(NULL, data->uint32)) == NULL)
72484417368Smartijn err(1, NULL);
72584417368Smartijn ober_set_header(elm, BER_CLASS_APPLICATION,
72684417368Smartijn APPLICATION_COUNTER32);
72784417368Smartijn break;
72884417368Smartijn case TYPE_GAUGE32:
72984417368Smartijn if ((elm = ober_add_integer(NULL, data->uint32)) == NULL)
73084417368Smartijn err(1, NULL);
73184417368Smartijn ober_set_header(elm, BER_CLASS_APPLICATION,
73284417368Smartijn APPLICATION_GAUGE32);
73384417368Smartijn break;
73484417368Smartijn case TYPE_TIMETICKS:
73584417368Smartijn if ((elm = ober_add_integer(NULL, data->uint32)) == NULL)
73684417368Smartijn err(1, NULL);
73784417368Smartijn ober_set_header(elm, BER_CLASS_APPLICATION,
73884417368Smartijn APPLICATION_TIMETICKS);
73984417368Smartijn break;
74084417368Smartijn case TYPE_OPAQUE:
74184417368Smartijn if ((elm = ober_add_nstring(NULL, data->octetstring.string,
74284417368Smartijn data->octetstring.len)) == NULL)
74384417368Smartijn err(1, NULL);
74484417368Smartijn ober_set_header(elm, BER_CLASS_APPLICATION, APPLICATION_OPAQUE);
74584417368Smartijn break;
74684417368Smartijn case TYPE_COUNTER64:
74784417368Smartijn if ((elm = ober_add_integer(NULL, data->uint64)) == NULL)
74884417368Smartijn err(1, NULL);
74984417368Smartijn ober_set_header(elm, BER_CLASS_APPLICATION,
75084417368Smartijn APPLICATION_COUNTER64);
75184417368Smartijn break;
75284417368Smartijn case TYPE_NOSUCHOBJECT:
75384417368Smartijn if ((elm = ober_add_null(NULL)) == NULL)
75484417368Smartijn err(1, NULL);
75584417368Smartijn ober_set_header(elm, BER_CLASS_CONTEXT, EXCEPTION_NOSUCHOBJECT);
75684417368Smartijn break;
75784417368Smartijn case TYPE_NOSUCHINSTANCE:
75884417368Smartijn if ((elm = ober_add_null(NULL)) == NULL)
75984417368Smartijn err(1, NULL);
76084417368Smartijn ober_set_header(elm, BER_CLASS_CONTEXT,
76184417368Smartijn EXCEPTION_NOSUCHINSTANCE);
76284417368Smartijn break;
76384417368Smartijn case TYPE_ENDOFMIBVIEW:
76484417368Smartijn if ((elm = ober_add_null(NULL)) == NULL)
76584417368Smartijn err(1, NULL);
76684417368Smartijn ober_set_header(elm, BER_CLASS_CONTEXT, EXCEPTION_ENDOFMIBVIEW);
76784417368Smartijn break;
76884417368Smartijn default:
76984417368Smartijn errx(1, "%s: unsupported type: %d", __func__, type);
77084417368Smartijn }
77184417368Smartijn if (elm == NULL)
77284417368Smartijn err(1, NULL);
77384417368Smartijn return elm;
77484417368Smartijn }
77584417368Smartijn
77684417368Smartijn unsigned int
smi_application(struct ber_element * elm)77784417368Smartijn smi_application(struct ber_element *elm)
77884417368Smartijn {
77984417368Smartijn if (elm->be_class != BER_CLASS_APPLICATION)
78084417368Smartijn return -1;
78184417368Smartijn
78284417368Smartijn switch (elm->be_type) {
78384417368Smartijn case APPLICATION_IPADDR:
78484417368Smartijn case APPLICATION_OPAQUE:
78584417368Smartijn return BER_TYPE_OCTETSTRING;
78684417368Smartijn case APPLICATION_COUNTER32:
78784417368Smartijn case APPLICATION_GAUGE32:
78884417368Smartijn case APPLICATION_TIMETICKS:
78984417368Smartijn case APPLICATION_COUNTER64:
79084417368Smartijn return BER_TYPE_INTEGER;
79184417368Smartijn default:
79284417368Smartijn return -1;
79384417368Smartijn }
79484417368Smartijn }
79584417368Smartijn
79684417368Smartijn char *
smi_oid2string(struct ber_oid * oid,char * buf,size_t len)79784417368Smartijn smi_oid2string(struct ber_oid *oid, char *buf, size_t len)
79884417368Smartijn {
79984417368Smartijn char digit[11];
80084417368Smartijn size_t i;
80184417368Smartijn
80284417368Smartijn buf[0] = '\0';
80384417368Smartijn for (i = 0; i < oid->bo_n; i++) {
80484417368Smartijn snprintf(digit, sizeof(digit), "%"PRIu32, oid->bo_id[i]);
80584417368Smartijn if (i > 0)
80684417368Smartijn strlcat(buf, ".", len);
80784417368Smartijn strlcat(buf, digit, len);
80884417368Smartijn }
80984417368Smartijn return buf;
81084417368Smartijn }
81184417368Smartijn
81284417368Smartijn char *
smi_print_element(struct ber_element * root)81384417368Smartijn smi_print_element(struct ber_element *root)
81484417368Smartijn {
81584417368Smartijn char *str = NULL, *buf, *p;
81684417368Smartijn long long v;
81784417368Smartijn struct ber_oid o;
81884417368Smartijn char strbuf[BUFSIZ];
81984417368Smartijn
82084417368Smartijn switch (root->be_class) {
82184417368Smartijn case BER_CLASS_UNIVERSAL:
82284417368Smartijn switch (root->be_type) {
82384417368Smartijn case BER_TYPE_INTEGER:
82484417368Smartijn if (ober_get_integer(root, &v) == -1)
82584417368Smartijn goto fail;
82684417368Smartijn if (asprintf(&str, "%lld", v) == -1)
82784417368Smartijn goto fail;
82884417368Smartijn break;
82984417368Smartijn case BER_TYPE_OBJECT:
83084417368Smartijn if (ober_get_oid(root, &o) == -1)
83184417368Smartijn goto fail;
83284417368Smartijn if (asprintf(&str, "%s", smi_oid2string(&o, strbuf,
83384417368Smartijn sizeof(strbuf))) == -1)
83484417368Smartijn goto fail;
83584417368Smartijn break;
83684417368Smartijn case BER_TYPE_OCTETSTRING:
83784417368Smartijn if (ober_get_string(root, &buf) == -1)
83884417368Smartijn goto fail;
83984417368Smartijn p = reallocarray(NULL, 4, root->be_len + 1);
84084417368Smartijn if (p == NULL)
84184417368Smartijn goto fail;
84284417368Smartijn strvisx(p, buf, root->be_len, VIS_NL);
84384417368Smartijn if (asprintf(&str, "\"%s\"", p) == -1) {
84484417368Smartijn free(p);
84584417368Smartijn goto fail;
84684417368Smartijn }
84784417368Smartijn free(p);
84884417368Smartijn break;
84984417368Smartijn case BER_TYPE_NULL:
85084417368Smartijn if (asprintf(&str, "null") == -1)
85184417368Smartijn goto fail;
85284417368Smartijn break;
85384417368Smartijn default:
85484417368Smartijn /* Should not happen in a valid SNMP packet */
85584417368Smartijn if (asprintf(&str, "[U/%u]", root->be_type) == -1)
85684417368Smartijn goto fail;
85784417368Smartijn break;
85884417368Smartijn }
85984417368Smartijn break;
86084417368Smartijn case BER_CLASS_APPLICATION:
86184417368Smartijn switch (root->be_type) {
86284417368Smartijn case APPLICATION_IPADDR:
86384417368Smartijn if (ober_get_string(root, &buf) == -1)
86484417368Smartijn goto fail;
86584417368Smartijn if (asprintf(&str, "%s",
86684417368Smartijn inet_ntoa(*(struct in_addr *)buf)) == -1)
86784417368Smartijn goto fail;
86884417368Smartijn break;
86984417368Smartijn case APPLICATION_COUNTER32:
87084417368Smartijn if (ober_get_integer(root, &v) == -1)
87184417368Smartijn goto fail;
87284417368Smartijn if (asprintf(&str, "%lld(c32)", v) == -1)
87384417368Smartijn goto fail;
87484417368Smartijn break;
87584417368Smartijn case APPLICATION_GAUGE32:
87684417368Smartijn if (ober_get_integer(root, &v) == -1)
87784417368Smartijn goto fail;
87884417368Smartijn if (asprintf(&str, "%lld(g32)", v) == -1)
87984417368Smartijn goto fail;
88084417368Smartijn break;
88184417368Smartijn case APPLICATION_TIMETICKS:
88284417368Smartijn if (ober_get_integer(root, &v) == -1)
88384417368Smartijn goto fail;
88484417368Smartijn if (asprintf(&str, "%lld.%llds", v/100, v%100) == -1)
88584417368Smartijn goto fail;
88684417368Smartijn break;
88784417368Smartijn case APPLICATION_OPAQUE:
88884417368Smartijn if (ober_get_string(root, &buf) == -1)
88984417368Smartijn goto fail;
89084417368Smartijn p = reallocarray(NULL, 4, root->be_len + 1);
89184417368Smartijn if (p == NULL)
89284417368Smartijn goto fail;
89384417368Smartijn strvisx(p, buf, root->be_len, VIS_NL);
89484417368Smartijn if (asprintf(&str, "\"%s\"(opaque)", p) == -1) {
89584417368Smartijn free(p);
89684417368Smartijn goto fail;
89784417368Smartijn }
89884417368Smartijn free(p);
89984417368Smartijn break;
90084417368Smartijn case APPLICATION_COUNTER64:
90184417368Smartijn if (ober_get_integer(root, &v) == -1)
90284417368Smartijn goto fail;
90384417368Smartijn if (asprintf(&str, "%lld(c64)", v) == -1)
90484417368Smartijn goto fail;
90584417368Smartijn break;
90684417368Smartijn default:
90784417368Smartijn /* Should not happen in a valid SNMP packet */
90884417368Smartijn if (asprintf(&str, "[A/%u]", root->be_type) == -1)
90984417368Smartijn goto fail;
91084417368Smartijn break;
91184417368Smartijn }
91284417368Smartijn break;
91384417368Smartijn case BER_CLASS_CONTEXT:
91484417368Smartijn switch (root->be_type) {
91584417368Smartijn case EXCEPTION_NOSUCHOBJECT:
91684417368Smartijn str = strdup("noSuchObject");
91784417368Smartijn break;
91884417368Smartijn case EXCEPTION_NOSUCHINSTANCE:
91984417368Smartijn str = strdup("noSuchInstance");
92084417368Smartijn break;
92184417368Smartijn case EXCEPTION_ENDOFMIBVIEW:
92284417368Smartijn str = strdup("endOfMibView");
92384417368Smartijn break;
92484417368Smartijn default:
92584417368Smartijn /* Should not happen in a valid SNMP packet */
92684417368Smartijn if (asprintf(&str, "[C/%u]", root->be_type) == -1)
92784417368Smartijn goto fail;
92884417368Smartijn break;
92984417368Smartijn }
93084417368Smartijn break;
93184417368Smartijn default:
93284417368Smartijn /* Should not happen in a valid SNMP packet */
93384417368Smartijn if (asprintf(&str, "[%hhu/%u]", root->be_class,
93484417368Smartijn root->be_type) == -1)
93584417368Smartijn goto fail;
93684417368Smartijn break;
93784417368Smartijn }
93884417368Smartijn
93984417368Smartijn return (str);
94084417368Smartijn
94184417368Smartijn fail:
94284417368Smartijn free(str);
94384417368Smartijn return (NULL);
94484417368Smartijn }
94584417368Smartijn
94684417368Smartijn void
smi_debug_elements(struct ber_element * root)94784417368Smartijn smi_debug_elements(struct ber_element *root)
94884417368Smartijn {
94984417368Smartijn static int indent = 0;
95084417368Smartijn char *value;
95184417368Smartijn int constructed;
95284417368Smartijn
95384417368Smartijn /* calculate lengths */
95484417368Smartijn ober_calc_len(root);
95584417368Smartijn
95684417368Smartijn switch (root->be_encoding) {
95784417368Smartijn case BER_TYPE_SEQUENCE:
95884417368Smartijn case BER_TYPE_SET:
95984417368Smartijn constructed = root->be_encoding;
96084417368Smartijn break;
96184417368Smartijn default:
96284417368Smartijn constructed = 0;
96384417368Smartijn break;
96484417368Smartijn }
96584417368Smartijn
96684417368Smartijn fprintf(stderr, "%*slen %lu ", indent, "", root->be_len);
96784417368Smartijn switch (root->be_class) {
96884417368Smartijn case BER_CLASS_UNIVERSAL:
96984417368Smartijn fprintf(stderr, "class: universal(%u) type: ", root->be_class);
97084417368Smartijn switch (root->be_type) {
97184417368Smartijn case BER_TYPE_EOC:
97284417368Smartijn fprintf(stderr, "end-of-content");
97384417368Smartijn break;
97484417368Smartijn case BER_TYPE_INTEGER:
97584417368Smartijn fprintf(stderr, "integer");
97684417368Smartijn break;
97784417368Smartijn case BER_TYPE_BITSTRING:
97884417368Smartijn fprintf(stderr, "bit-string");
97984417368Smartijn break;
98084417368Smartijn case BER_TYPE_OCTETSTRING:
98184417368Smartijn fprintf(stderr, "octet-string");
98284417368Smartijn break;
98384417368Smartijn case BER_TYPE_NULL:
98484417368Smartijn fprintf(stderr, "null");
98584417368Smartijn break;
98684417368Smartijn case BER_TYPE_OBJECT:
98784417368Smartijn fprintf(stderr, "object");
98884417368Smartijn break;
98984417368Smartijn case BER_TYPE_ENUMERATED:
99084417368Smartijn fprintf(stderr, "enumerated");
99184417368Smartijn break;
99284417368Smartijn case BER_TYPE_SEQUENCE:
99384417368Smartijn fprintf(stderr, "sequence");
99484417368Smartijn break;
99584417368Smartijn case BER_TYPE_SET:
99684417368Smartijn fprintf(stderr, "set");
99784417368Smartijn break;
99884417368Smartijn }
99984417368Smartijn break;
100084417368Smartijn case BER_CLASS_APPLICATION:
100184417368Smartijn fprintf(stderr, "class: application(%u) type: ",
100284417368Smartijn root->be_class);
100384417368Smartijn switch (root->be_type) {
100484417368Smartijn case APPLICATION_IPADDR:
100584417368Smartijn fprintf(stderr, "ipaddr");
100684417368Smartijn break;
100784417368Smartijn case APPLICATION_COUNTER32:
100884417368Smartijn fprintf(stderr, "counter32");
100984417368Smartijn break;
101084417368Smartijn case APPLICATION_GAUGE32:
101184417368Smartijn fprintf(stderr, "gauge32");
101284417368Smartijn break;
101384417368Smartijn case APPLICATION_TIMETICKS:
101484417368Smartijn fprintf(stderr, "timeticks");
101584417368Smartijn break;
101684417368Smartijn case APPLICATION_OPAQUE:
101784417368Smartijn fprintf(stderr, "opaque");
101884417368Smartijn break;
101984417368Smartijn case APPLICATION_COUNTER64:
102084417368Smartijn fprintf(stderr, "counter64");
102184417368Smartijn break;
102284417368Smartijn }
102384417368Smartijn break;
102484417368Smartijn case BER_CLASS_CONTEXT:
102584417368Smartijn fprintf(stderr, "class: context(%u) type: ",
102684417368Smartijn root->be_class);
102784417368Smartijn switch (root->be_type) {
102884417368Smartijn case REQUEST_GET:
102984417368Smartijn fprintf(stderr, "getreq");
103084417368Smartijn break;
103184417368Smartijn case REQUEST_GETNEXT:
103284417368Smartijn fprintf(stderr, "getnextreq");
103384417368Smartijn break;
103484417368Smartijn case REQUEST_RESPONSE:
103584417368Smartijn fprintf(stderr, "response");
103684417368Smartijn break;
103784417368Smartijn case REQUEST_SET:
103884417368Smartijn fprintf(stderr, "setreq");
103984417368Smartijn break;
104084417368Smartijn case REQUEST_TRAP:
104184417368Smartijn fprintf(stderr, "trap");
104284417368Smartijn break;
104384417368Smartijn case REQUEST_GETBULK:
104484417368Smartijn fprintf(stderr, "getbulkreq");
104584417368Smartijn break;
104684417368Smartijn case REQUEST_INFORM:
104784417368Smartijn fprintf(stderr, "informreq");
104884417368Smartijn break;
104984417368Smartijn case REQUEST_TRAPV2:
105084417368Smartijn fprintf(stderr, "trapv2");
105184417368Smartijn break;
105284417368Smartijn case REQUEST_REPORT:
105384417368Smartijn fprintf(stderr, "report");
105484417368Smartijn break;
105584417368Smartijn }
105684417368Smartijn break;
105784417368Smartijn case BER_CLASS_PRIVATE:
105884417368Smartijn fprintf(stderr, "class: private(%u) type: ", root->be_class);
105984417368Smartijn break;
106084417368Smartijn default:
106184417368Smartijn fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class);
106284417368Smartijn break;
106384417368Smartijn }
106484417368Smartijn fprintf(stderr, "(%u) encoding %u ",
106584417368Smartijn root->be_type, root->be_encoding);
106684417368Smartijn
106784417368Smartijn if ((value = smi_print_element(root)) == NULL)
106884417368Smartijn goto invalid;
106984417368Smartijn
107084417368Smartijn switch (root->be_encoding) {
107184417368Smartijn case BER_TYPE_INTEGER:
107284417368Smartijn case BER_TYPE_ENUMERATED:
107384417368Smartijn fprintf(stderr, "value %s", value);
107484417368Smartijn break;
107584417368Smartijn case BER_TYPE_BITSTRING:
107684417368Smartijn fprintf(stderr, "hexdump %s", value);
107784417368Smartijn break;
107884417368Smartijn case BER_TYPE_OBJECT:
107984417368Smartijn fprintf(stderr, "oid %s", value);
108084417368Smartijn break;
108184417368Smartijn case BER_TYPE_OCTETSTRING:
108284417368Smartijn if (root->be_class == BER_CLASS_APPLICATION &&
108384417368Smartijn root->be_type == APPLICATION_IPADDR) {
108484417368Smartijn fprintf(stderr, "addr %s", value);
108584417368Smartijn } else {
108684417368Smartijn fprintf(stderr, "string %s", value);
108784417368Smartijn }
108884417368Smartijn break;
108984417368Smartijn case BER_TYPE_NULL: /* no payload */
109084417368Smartijn case BER_TYPE_EOC:
109184417368Smartijn case BER_TYPE_SEQUENCE:
109284417368Smartijn case BER_TYPE_SET:
109384417368Smartijn default:
109484417368Smartijn fprintf(stderr, "%s", value);
109584417368Smartijn break;
109684417368Smartijn }
109784417368Smartijn
109884417368Smartijn invalid:
109984417368Smartijn if (value == NULL)
110084417368Smartijn fprintf(stderr, "<INVALID>");
110184417368Smartijn else
110284417368Smartijn free(value);
110384417368Smartijn fprintf(stderr, "\n");
110484417368Smartijn
110584417368Smartijn if (constructed)
110684417368Smartijn root->be_encoding = constructed;
110784417368Smartijn
110884417368Smartijn if (constructed && root->be_sub) {
110984417368Smartijn indent += 2;
111084417368Smartijn smi_debug_elements(root->be_sub);
111184417368Smartijn indent -= 2;
111284417368Smartijn }
111384417368Smartijn if (root->be_next)
111484417368Smartijn smi_debug_elements(root->be_next);
111584417368Smartijn }
111684417368Smartijn
111784417368Smartijn struct ber_element *
v2cmps(struct ber_element * message,const char * community)111884417368Smartijn v2cmps(struct ber_element *message, const char *community)
111984417368Smartijn {
112084417368Smartijn int version;
112184417368Smartijn const char *mcommunity;
112284417368Smartijn struct ber_element *pdu;
112384417368Smartijn
112484417368Smartijn if (ober_scanf_elements(message, "{dse}$", &version, &mcommunity, &pdu) == -1)
112584417368Smartijn err(1, "%s: ober_scanf_elements", __func__);
112684417368Smartijn
112784417368Smartijn if (strcmp(mcommunity, community) != 0)
112884417368Smartijn errx(1, "%s: invalid community (%s/%s)", __func__, mcommunity,
112984417368Smartijn community);
113084417368Smartijn
113184417368Smartijn return pdu;
113284417368Smartijn }
113384417368Smartijn
113484417368Smartijn 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)113584417368Smartijn snmp_pdu_validate(struct ber_element *pdu, enum snmp_request request,
113684417368Smartijn int32_t requestid, int32_t error, int32_t index, struct varbind *varbindlist,
113784417368Smartijn size_t nvarbind)
113884417368Smartijn {
113984417368Smartijn int32_t mrequestid, merror, mindex;
114084417368Smartijn int class;
114184417368Smartijn unsigned int type;
114284417368Smartijn struct ber_element *mvarbindlist, *varbind;
114384417368Smartijn struct ber_oid moid, oid;
114484417368Smartijn struct ber_element *value;
114584417368Smartijn char oidbuf1[512], oidbuf2[512];
114684417368Smartijn size_t i;
114784417368Smartijn
114884417368Smartijn if (ober_scanf_elements(pdu, "t{ddd{e}$}$", &class, &type, &mrequestid,
114984417368Smartijn &merror, &mindex, &varbind) == -1)
115084417368Smartijn err(1, "%s: ober_scanf_elementsi", __func__);
115184417368Smartijn
115284417368Smartijn if (class != BER_CLASS_CONTEXT || type != request)
115384417368Smartijn errx(1, "%s: unexpected pdu type", __func__);
115484417368Smartijn if (mrequestid != requestid)
115584417368Smartijn errx(1, "%s: unexpected pdu requestid (%d/%d)",
115684417368Smartijn __func__, mrequestid, requestid);
115784417368Smartijn if (error != merror)
115884417368Smartijn errx(1, "%s: unexpected pdu error (%d/%d)",
115984417368Smartijn __func__, merror, error);
116084417368Smartijn if (index != mindex)
116184417368Smartijn errx(1, "%s: unepxected pdu index (%d/%d)",
116284417368Smartijn __func__, mindex, index);
116384417368Smartijn
116484417368Smartijn for (i = 0; varbind != NULL; varbind = varbind->be_next, i++) {
116584417368Smartijn if (ober_scanf_elements(varbind, "{oeS$}", &moid, &value) == -1)
116684417368Smartijn err(1, "%s: ober_scanf_elements", __func__);
116784417368Smartijn if (i >= nvarbind)
116884417368Smartijn continue;
116984417368Smartijn snmp_oid2ber_oid(&varbindlist[i].name, &oid);
1170da328aa4Smartijn if (!varbindlist[i].nameunknown && ober_oid_cmp(&moid, &oid) != 0)
117184417368Smartijn errx(1, "%s: unexpected oid (%s/%s)", __func__,
117284417368Smartijn smi_oid2string(&moid, oidbuf1, sizeof(oidbuf1)),
117384417368Smartijn smi_oid2string(&oid, oidbuf2, sizeof(oidbuf2)));
1174da328aa4Smartijn if (value->be_class == BER_CLASS_UNIVERSAL &&
1175da328aa4Smartijn value->be_type == BER_TYPE_INTEGER) {
1176da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1177da328aa4Smartijn varbindlist[i].type != TYPE_INTEGER)
117884417368Smartijn errx(1, "%s: unexpected value", __func__);
1179da328aa4Smartijn if (!varbindlist[i].dataunknown &&
1180da328aa4Smartijn varbindlist[i].data.int32 != value->be_numeric)
1181da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1182da328aa4Smartijn } else if (value->be_class == BER_CLASS_UNIVERSAL &&
1183da328aa4Smartijn value->be_type == BER_TYPE_OCTETSTRING) {
1184da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1185da328aa4Smartijn varbindlist[i].type != TYPE_OCTETSTRING)
1186da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1187da328aa4Smartijn if (!varbindlist[i].dataunknown && (
1188da328aa4Smartijn varbindlist[i].data.octetstring.len !=
1189da328aa4Smartijn value->be_len ||
119084417368Smartijn memcmp(varbindlist[i].data.octetstring.string,
1191da328aa4Smartijn value->be_val, value->be_len) != 0))
119284417368Smartijn errx(1, "%s: unexpected value", __func__);
1193da328aa4Smartijn } else if (value->be_class == BER_CLASS_UNIVERSAL &&
1194da328aa4Smartijn value->be_type == BER_TYPE_NULL) {
1195da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1196da328aa4Smartijn varbindlist[i].type != TYPE_NULL)
119784417368Smartijn errx(1, "%s: unexpected value", __func__);
1198da328aa4Smartijn } else if (value->be_class == BER_CLASS_UNIVERSAL &&
1199da328aa4Smartijn value->be_type == BER_TYPE_OBJECT) {
1200da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1201da328aa4Smartijn varbindlist[i].type != TYPE_OBJECTIDENTIFIER)
120284417368Smartijn errx(1, "%s: unexpected value", __func__);
1203da328aa4Smartijn if (!varbindlist[i].dataunknown) {
120484417368Smartijn if (ober_get_oid(value, &moid) == -1)
1205da328aa4Smartijn errx(1, "%s: unexpected value",
1206da328aa4Smartijn __func__);
1207da328aa4Smartijn snmp_oid2ber_oid(&varbindlist[i].data.oid,
1208da328aa4Smartijn &oid);
120984417368Smartijn if (ober_oid_cmp(&oid, &moid) != 0)
1210da328aa4Smartijn errx(1, "%s: unexpected value",
1211da328aa4Smartijn __func__);
121284417368Smartijn }
1213da328aa4Smartijn } else if (value->be_class == BER_CLASS_APPLICATION &&
1214da328aa4Smartijn value->be_type == APPLICATION_IPADDR) {
1215da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1216da328aa4Smartijn varbindlist[i].type != TYPE_IPADDRESS)
1217da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1218da328aa4Smartijn if (value->be_len != 4)
1219da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1220da328aa4Smartijn if (!varbindlist[i].dataunknown) {
1221da328aa4Smartijn if (memcmp(value->be_val,
1222da328aa4Smartijn varbindlist[i].data.octetstring.string,
1223da328aa4Smartijn value->be_len) != 0)
1224da328aa4Smartijn errx(1, "%s: unexpected value",
1225da328aa4Smartijn __func__);
1226da328aa4Smartijn }
1227da328aa4Smartijn } else if (value->be_class == BER_CLASS_APPLICATION &&
1228da328aa4Smartijn value->be_type == APPLICATION_COUNTER32) {
1229da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1230da328aa4Smartijn varbindlist[i].type != TYPE_COUNTER32)
1231da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1232da328aa4Smartijn if (!varbindlist[i].dataunknown &&
1233da328aa4Smartijn varbindlist[i].data.uint32 != value->be_numeric)
1234da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1235da328aa4Smartijn } else if (value->be_class == BER_CLASS_APPLICATION &&
1236da328aa4Smartijn value->be_type == APPLICATION_GAUGE32) {
1237da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1238da328aa4Smartijn varbindlist[i].type != TYPE_GAUGE32)
1239da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1240da328aa4Smartijn if (!varbindlist[i].dataunknown &&
1241da328aa4Smartijn varbindlist[i].data.uint32 != value->be_numeric)
1242da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1243da328aa4Smartijn } else if (value->be_class == BER_CLASS_APPLICATION &&
1244da328aa4Smartijn value->be_type == APPLICATION_TIMETICKS) {
1245da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1246da328aa4Smartijn varbindlist[i].type != TYPE_TIMETICKS)
1247da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1248da328aa4Smartijn if (!varbindlist[i].dataunknown &&
1249da328aa4Smartijn varbindlist[i].data.uint32 != value->be_numeric)
1250da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1251da328aa4Smartijn } else if (value->be_class == BER_CLASS_APPLICATION &&
1252da328aa4Smartijn value->be_type == APPLICATION_OPAQUE) {
1253da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1254da328aa4Smartijn varbindlist[i].type != TYPE_OPAQUE)
1255da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1256da328aa4Smartijn if (!varbindlist[i].dataunknown && (
1257da328aa4Smartijn varbindlist[i].data.octetstring.len !=
1258da328aa4Smartijn value->be_len ||
1259da328aa4Smartijn memcmp(varbindlist[i].data.octetstring.string,
1260da328aa4Smartijn value->be_val, value->be_len) != 0))
1261da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1262da328aa4Smartijn } else if (value->be_class == BER_CLASS_APPLICATION &&
1263da328aa4Smartijn value->be_type == APPLICATION_COUNTER64) {
1264da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1265da328aa4Smartijn varbindlist[i].type != TYPE_COUNTER64)
1266da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1267da328aa4Smartijn if (!varbindlist[i].dataunknown &&
1268da328aa4Smartijn varbindlist[i].data.uint64 != value->be_numeric)
1269da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1270da328aa4Smartijn } else if (value->be_class == BER_CLASS_CONTEXT &&
1271da328aa4Smartijn value->be_type == EXCEPTION_NOSUCHOBJECT) {
1272da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1273da328aa4Smartijn varbindlist[i].type != TYPE_NOSUCHOBJECT)
1274da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1275da328aa4Smartijn } else if (value->be_class == BER_CLASS_CONTEXT &&
1276da328aa4Smartijn value->be_type == EXCEPTION_NOSUCHINSTANCE) {
1277da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1278da328aa4Smartijn varbindlist[i].type != TYPE_NOSUCHINSTANCE)
1279da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1280da328aa4Smartijn } else if (value->be_class == BER_CLASS_CONTEXT &&
1281da328aa4Smartijn value->be_type == EXCEPTION_ENDOFMIBVIEW) {
1282da328aa4Smartijn if (!varbindlist[i].typeunknown &&
1283da328aa4Smartijn varbindlist[i].type != TYPE_ENDOFMIBVIEW)
1284da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
1285da328aa4Smartijn } else
1286da328aa4Smartijn errx(1, "%s: unexpected value", __func__);
128784417368Smartijn }
128884417368Smartijn if (i != nvarbind)
128984417368Smartijn errx(1, "%s: unexpected amount of varbind (%zu/%zu)", __func__,
129084417368Smartijn i, nvarbind);
129184417368Smartijn }
1292