summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBret Lambert <blambert@cvs.openbsd.org>2014-04-14 12:55:11 +0000
committerBret Lambert <blambert@cvs.openbsd.org>2014-04-14 12:55:11 +0000
commitde35535fa13c0a84b78e2258d19537ad5738e370 (patch)
tree689dd21ff1ec7a413fa566978e20022b4aac8439
parentc40ec85949aabf6db151b0978881bfbc7e2d4d03 (diff)
Make snmpd use the AgentX protcol for accepting trap requests.
AgentX notifications are the only portion implemented right now; get in the tree to flesh out the remainder. ok reyk@ benno@
-rw-r--r--usr.sbin/snmpd/Makefile4
-rw-r--r--usr.sbin/snmpd/agentx.c969
-rw-r--r--usr.sbin/snmpd/ber.c3
-rw-r--r--usr.sbin/snmpd/control.c261
-rw-r--r--usr.sbin/snmpd/parse.y22
-rw-r--r--usr.sbin/snmpd/snmp.h280
-rw-r--r--usr.sbin/snmpd/snmpd.conf.515
-rw-r--r--usr.sbin/snmpd/snmpd.h20
-rw-r--r--usr.sbin/snmpd/trap.c265
9 files changed, 1650 insertions, 189 deletions
diff --git a/usr.sbin/snmpd/Makefile b/usr.sbin/snmpd/Makefile
index 0dd6ed369af..753ab01ae1e 100644
--- a/usr.sbin/snmpd/Makefile
+++ b/usr.sbin/snmpd/Makefile
@@ -1,10 +1,10 @@
-# $OpenBSD: Makefile,v 1.11 2014/01/18 05:54:52 martynas Exp $
+# $OpenBSD: Makefile,v 1.12 2014/04/14 12:55:10 blambert Exp $
PROG= snmpd
MAN= snmpd.8 snmpd.conf.5
SRCS= parse.y ber.c log.c control.c snmpe.c \
mps.c trap.c mib.c smi.c kroute.c snmpd.c timer.c \
- pf.c proc.c usm.c
+ pf.c proc.c usm.c agentx.c
LDADD= -levent -lutil -lkvm -lcrypto
DPADD= ${LIBEVENT} ${LIBUTIL}
diff --git a/usr.sbin/snmpd/agentx.c b/usr.sbin/snmpd/agentx.c
new file mode 100644
index 00000000000..55a5c18f075
--- /dev/null
+++ b/usr.sbin/snmpd/agentx.c
@@ -0,0 +1,969 @@
+/* $OpenBSD: agentx.c,v 1.1 2014/04/14 12:55:10 blambert Exp $ */
+/*
+ * Copyright (c) 2013,2014 Bret Stephen Lambert <blambert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "snmp.h"
+#include "ber.h"
+
+int snmp_agentx_octetstring(struct agentx_pdu *, char *, int);
+int snmp_agentx_buffercheck(struct agentx_pdu *, size_t);
+int snmp_agentx_oid(struct agentx_pdu *, struct snmp_oid *);
+int snmp_agentx_buffer_consume(struct agentx_pdu *, u_int);
+int snmp_agentx_int(struct agentx_pdu *, uint32_t *);
+int snmp_agentx_int64(struct agentx_pdu *, uint64_t *);
+int snmp_agentx_do_read_raw(struct agentx_pdu *, void *, int, int);
+void snmp_agentx_update_ids(struct agentx_handle *, struct agentx_pdu *);
+struct agentx_pdu *
+ agentx_find_inflight(struct agentx_handle *, uint32_t, uint32_t);
+
+#ifdef DEBUG
+static void snmp_agentx_dump_hdr(struct agentx_hdr *);
+#endif
+
+#define PDU_BUFLEN 256
+
+/* snmpTrapOid.0 */
+struct snmp_oid trapoid_0 = {
+ .o_id = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 },
+ .o_n = 11
+};
+
+/*
+ * AgentX handle allocation and management routines.
+ */
+
+struct agentx_handle *
+snmp_agentx_alloc(int s)
+{
+ struct agentx_handle *h;
+
+ if ((h = calloc(1, sizeof(*h))) == NULL)
+ return (NULL);
+
+ h->fd = s;
+ h->timeout = AGENTX_DEFAULT_TIMEOUT;
+
+ TAILQ_INIT(&h->w);
+ TAILQ_INIT(&h->inflight);
+
+ return (h);
+}
+
+/*
+ * Synchronous open of unix socket path.
+ */
+struct agentx_handle *
+snmp_agentx_open(const char *path, char *descr, struct snmp_oid *oid)
+{
+ struct sockaddr_un sun;
+ struct agentx_handle *h;
+ int s;
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ return (NULL);
+
+ bzero(&sun, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
+
+ if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) == -1)
+ goto fail;
+
+ if ((h = snmp_agentx_fdopen(s, descr, oid)) == NULL)
+ goto fail;
+
+ return (h);
+ fail:
+ close(s);
+ return (NULL);
+}
+
+/*
+ * Synchronous AgentX open operation over previously-opened socket.
+ */
+struct agentx_handle *
+snmp_agentx_fdopen(int s, char *descr, struct snmp_oid *oid)
+{
+ struct agentx_handle *h;
+ struct agentx_pdu *pdu = NULL;
+
+ if ((h = snmp_agentx_alloc(s)) == NULL)
+ return (NULL);
+
+ if ((pdu = snmp_agentx_open_pdu(h, descr, oid)) == NULL ||
+ (pdu = snmp_agentx_request(h, pdu)) == NULL ||
+ snmp_agentx_open_response(h, pdu) == -1) {
+ if (pdu)
+ snmp_agentx_pdu_free(pdu);
+ snmp_agentx_free(h);
+ return (NULL);
+ }
+
+ return (h);
+}
+
+/*
+ * Synchronous close of agentx handle.
+ */
+int
+snmp_agentx_close(struct agentx_handle *h, uint8_t reason)
+{
+ struct agentx_pdu *pdu;
+ int error = 0;
+
+ if ((pdu = snmp_agentx_close_pdu(h, reason)) == NULL)
+ return (-1);
+ if ((pdu = snmp_agentx_request(h, pdu)) == NULL)
+ return (-1);
+ if (snmp_agentx_response(h, pdu) == -1)
+ error = -1;
+
+ snmp_agentx_pdu_free(pdu);
+
+ return (error);
+}
+
+void
+snmp_agentx_free(struct agentx_handle *h)
+{
+ struct agentx_pdu *pdu;
+
+ if (h->fd != -1)
+ close(h->fd);
+
+ while ((pdu = TAILQ_FIRST(&h->w))) {
+ TAILQ_REMOVE(&h->w, pdu, entry);
+ snmp_agentx_pdu_free(pdu);
+ }
+ while ((pdu = TAILQ_FIRST(&h->inflight))) {
+ TAILQ_REMOVE(&h->w, pdu, entry);
+ snmp_agentx_pdu_free(pdu);
+ }
+ if (h->r)
+ snmp_agentx_pdu_free(h->r);
+
+ free(h);
+}
+
+/*
+ * AgentX pdu allocation routines.
+ */
+
+/*
+ * Allocate an AgentX PDU.
+ */
+struct agentx_pdu *
+snmp_agentx_pdu_alloc(void)
+{
+ struct agentx_pdu *pdu;
+
+ if ((pdu = calloc(1, sizeof(*pdu))) == NULL)
+ return (NULL);
+ if ((pdu->buffer = calloc(PDU_BUFLEN, sizeof(uint8_t))) == NULL) {
+ free(pdu);
+ return (NULL);
+ }
+
+ pdu->buflen = PDU_BUFLEN;
+
+ bzero(pdu->buffer, pdu->buflen);
+ pdu->ptr = pdu->buffer + sizeof(struct agentx_hdr);
+ pdu->ioptr = pdu->buffer;
+ pdu->hdr = (struct agentx_hdr *)pdu->buffer;
+ pdu->hdr->version = AGENTX_VERSION;
+ pdu->hdr->flags = AGENTX_LOCAL_BYTE_ORDER_FLAG;
+ pdu->hdr->reserved = 0;
+ pdu->hdr->length = 0;
+ pdu->datalen = sizeof(struct agentx_hdr);
+
+ return (pdu);
+}
+
+/*
+ * Read the response PDU for a generic operation.
+ */
+int
+snmp_agentx_response(struct agentx_handle *h, struct agentx_pdu *pdu)
+{
+ struct agentx_response_data resp;
+
+ if (snmp_agentx_read_raw(pdu, &resp, sizeof(resp)) == -1)
+ return (-1);
+
+ if (!snmp_agentx_byteorder_native(pdu->hdr)) {
+ resp.error = snmp_agentx_int16_byteswap(resp.error);
+ resp.index = snmp_agentx_int16_byteswap(resp.index);
+ }
+
+ h->error = resp.error;
+ if (resp.error != AGENTX_ERR_NONE)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Read the response PDU for an open operation.
+ */
+int
+snmp_agentx_open_response(struct agentx_handle *h, struct agentx_pdu *pdu)
+{
+
+ if (snmp_agentx_response(h, pdu) == -1)
+ return (-1);
+
+ h->sessionid = pdu->hdr->sessionid;
+ return (0);
+}
+
+void
+snmp_agentx_pdu_free(struct agentx_pdu *pdu)
+{
+ free(pdu->buffer);
+ if (pdu->request)
+ free(pdu->request);
+ free(pdu);
+}
+
+/*
+ * Set the callback function to be called when a complete PDU is received.
+ */
+void
+snmp_agentx_set_callback(struct agentx_handle *h,
+ void (*cb)(struct agentx_handle *, struct agentx_pdu *, void *), void *arg)
+{
+ h->cb = cb;
+ h->cb_arg = arg;
+}
+
+int
+snmp_agentx_buffer_consume(struct agentx_pdu *b, u_int len)
+{
+ int padding;
+
+ padding = ((len + 3) & ~0x03) - len;
+
+ if (b->datalen < (len + padding))
+ return (-1);
+
+ b->datalen -= len + padding;
+ b->ptr += len + padding;
+
+ return (0);
+}
+
+/*
+ * Send an AgentX PDU. Flushes any already-enqueued PDUs.
+ */
+int
+snmp_agentx_send(struct agentx_handle *h, struct agentx_pdu *pdu)
+{
+ ssize_t n;
+
+ /* set the appropriate IDs in the protocol header */
+ if (pdu != NULL &&
+ (pdu->datalen == pdu->hdr->length + sizeof(struct agentx_hdr))) {
+ pdu->hdr->sessionid = h->sessionid;
+
+ if (pdu->hdr->type != AGENTX_RESPONSE) {
+ ++h->transactid;
+ ++h->packetid;
+ }
+
+ pdu->hdr->transactid = h->transactid;
+ pdu->hdr->packetid = h->packetid;
+ TAILQ_INSERT_TAIL(&h->w, pdu, entry);
+ }
+
+ again:
+ if ((pdu = TAILQ_FIRST(&h->w)) == NULL)
+ return (0);
+
+ if ((n = send(h->fd, pdu->ioptr, pdu->datalen, 0)) == -1)
+ return (-1);
+
+ pdu->ioptr += n;
+ pdu->datalen -= n;
+
+ if (pdu->datalen > 0) {
+ errno = EAGAIN;
+ return (-1);
+ }
+
+#ifdef DEBUG
+ snmp_agentx_dump_hdr(pdu->hdr);
+#endif
+
+ TAILQ_REMOVE(&h->w, pdu, entry);
+ TAILQ_INSERT_TAIL(&h->inflight, pdu, entry);
+
+ goto again;
+}
+
+/*
+ * Attempt to read a single AgentX PDU.
+ */
+struct agentx_pdu *
+snmp_agentx_recv(struct agentx_handle *h)
+{
+ struct agentx_pdu *pdu, *match;
+ ssize_t n;
+
+ h->error = AGENTX_ERR_NONE;
+
+ if (h->r == NULL) {
+ if ((h->r = snmp_agentx_pdu_alloc()) == NULL)
+ return (NULL);
+ h->r->datalen = 0; /* XXX -- force this for receive buffers */
+ }
+ pdu = h->r;
+
+ if (snmp_agentx_buffercheck(pdu, sizeof(struct agentx_hdr)) == -1)
+ return (NULL);
+
+ /* read header */
+ if (pdu->datalen < sizeof(struct agentx_hdr)) {
+ n = recv(h->fd, pdu->ioptr, sizeof(struct agentx_hdr), 0);
+
+ if (n == 0 || n == -1)
+ return (NULL);
+
+ pdu->datalen += n;
+ pdu->ioptr += n;
+
+ if (pdu->datalen < sizeof(struct agentx_hdr)) {
+ errno = EAGAIN;
+ return (NULL);
+ }
+
+ if (snmp_agentx_buffercheck(pdu, pdu->hdr->length) == -1)
+ return (NULL);
+ }
+
+ /* read body */
+ n = recv(h->fd, pdu->ioptr, pdu->hdr->length, 0);
+
+ if (n == 0 || n == -1)
+ return (NULL);
+
+ pdu->datalen += n;
+ pdu->ioptr += n;
+
+ if (pdu->datalen < pdu->hdr->length + sizeof(struct agentx_hdr)) {
+ errno = EAGAIN;
+ return (NULL);
+ }
+#ifdef DEBUG
+ snmp_agentx_dump_hdr(pdu->hdr);
+#endif
+ /* If this is an open on a new connection, fix it up */
+ if (pdu->hdr->type == AGENTX_OPEN && h->sessionid == 0) {
+ pdu->hdr->sessionid = 0; /* ignored, per RFC */
+ h->transactid = pdu->hdr->transactid;
+ h->packetid = pdu->hdr->packetid;
+ }
+
+ if (pdu->hdr->version != AGENTX_VERSION) {
+ h->error = AGENTX_ERR_PARSE_ERROR;
+ goto fail;
+ }
+
+ if (pdu->hdr->type == AGENTX_RESPONSE) {
+
+ match = agentx_find_inflight(h, pdu->hdr->transactid,
+ pdu->hdr->packetid);
+ if (match == NULL) {
+ errno = ESRCH; /* XXX */
+ goto fail;
+ }
+
+ TAILQ_REMOVE(&h->inflight, match, entry);
+ pdu->request = match;
+ h->r = NULL;
+
+ if (h->cb)
+ h->cb(h, pdu, h->cb_arg);
+
+ } else {
+ if (pdu->hdr->sessionid != h->sessionid) {
+ h->error = AGENTX_ERR_NOT_OPEN;
+ goto fail;
+ }
+
+ if (pdu->hdr->flags & AGENTX_NON_DEFAULT_CONTEXT) {
+ h->error = AGENTX_ERR_UNSUPPORTED_CONTEXT;
+ goto fail;
+ }
+
+ snmp_agentx_update_ids(h, pdu); /* XXX */
+
+ if (pdu->datalen != pdu->hdr->length + sizeof(*pdu->hdr)) {
+ h->error = AGENTX_ERR_PARSE_ERROR;
+ goto fail;
+ }
+ }
+
+ h->r = NULL;
+ return (pdu);
+ fail:
+ snmp_agentx_pdu_free(pdu);
+ h->r = NULL;
+ return (NULL);
+}
+
+/*
+ * Synchonous request and receipt of response.
+ */
+struct agentx_pdu *
+snmp_agentx_request(struct agentx_handle *h, struct agentx_pdu *pdu)
+{
+
+ if (snmp_agentx_send(h, pdu) == -1) {
+ if (errno != EAGAIN)
+ return (NULL);
+ }
+ while (snmp_agentx_send(h, NULL) == -1) {
+ if (errno != EAGAIN)
+ return (NULL);
+ }
+ while ((pdu = snmp_agentx_recv(h)) == NULL) {
+ if (errno != EAGAIN)
+ return (NULL);
+ }
+ h->error = AGENTX_ERR_NONE;
+
+ return (pdu);
+}
+
+struct agentx_pdu *
+agentx_find_inflight(struct agentx_handle *h, uint32_t tid, uint32_t pid)
+{
+ struct agentx_pdu *pdu;
+
+ TAILQ_FOREACH(pdu, &h->inflight, entry)
+ if (pdu->hdr->transactid == tid && pdu->hdr->packetid == pid)
+ break;
+ return (pdu);
+}
+
+int
+snmp_agentx_buffercheck(struct agentx_pdu *pdu, size_t len)
+{
+ uint8_t *newptr;
+ int newlen;
+
+ if (pdu->buflen - pdu->datalen >= len)
+ return (0);
+
+ newlen = pdu->buflen;
+ while (newlen - pdu->datalen < len)
+ newlen *= 2;
+
+ if ((newptr = realloc(pdu->buffer, newlen)) == NULL)
+ return (-1);
+
+ pdu->buflen = newlen;
+ pdu->ioptr = &newptr[pdu->ioptr - pdu->buffer];
+ pdu->buffer = newptr;
+ pdu->hdr = (struct agentx_hdr *)pdu->buffer;
+ pdu->ptr = &pdu->buffer[pdu->datalen];
+
+ return (0);
+}
+
+/*
+ * Utility routines for initializing common AgentX PDUs.
+ */
+
+struct agentx_pdu *
+snmp_agentx_open_pdu(struct agentx_handle *h, char *descr,
+ struct snmp_oid *oid)
+{
+ struct agentx_open_timeout to;
+ struct snmp_oid nulloid;
+ struct agentx_pdu *pdu;
+
+ if ((pdu = snmp_agentx_pdu_alloc()) == NULL)
+ return (NULL);
+
+ pdu->hdr->type = AGENTX_OPEN;
+
+ if (oid == NULL) {
+ bzero(&nulloid, sizeof(nulloid));
+ oid = &nulloid;
+ }
+
+ bzero(&to, sizeof(to));
+ to.timeout = AGENTX_DEFAULT_TIMEOUT;
+
+ if (snmp_agentx_raw(pdu, &to, sizeof(to)) == -1 ||
+ snmp_agentx_oid(pdu, oid) == -1 ||
+ snmp_agentx_octetstring(pdu, descr, strlen(descr)) == -1)
+ goto fail;
+
+ return (pdu);
+ fail:
+ snmp_agentx_pdu_free(pdu);
+ return (NULL);
+}
+
+struct agentx_pdu *
+snmp_agentx_close_pdu(struct agentx_handle *h, uint8_t reason)
+{
+ struct agentx_close_request_data req;
+ struct agentx_pdu *pdu;
+
+ if ((pdu = snmp_agentx_pdu_alloc()) == NULL)
+ return (NULL);
+ pdu->hdr->type = AGENTX_CLOSE;
+
+ bzero(&req, sizeof(req));
+ req.reason = reason;
+
+ if (snmp_agentx_raw(pdu, &req, sizeof(req)) == -1) {
+ snmp_agentx_pdu_free(pdu);
+ return (NULL);
+ }
+
+ return (pdu);
+}
+
+struct agentx_pdu *
+snmp_agentx_notify_pdu(struct snmp_oid *oid)
+{
+ struct agentx_pdu *pdu;
+
+ if ((pdu = snmp_agentx_pdu_alloc()) == NULL)
+ return (NULL);
+ pdu->hdr->type = AGENTX_NOTIFY;
+
+ if (snmp_agentx_varbind(pdu, &trapoid_0,
+ AGENTX_OBJECT_IDENTIFIER, oid, sizeof(*oid)) == -1) {
+ snmp_agentx_pdu_free(pdu);
+ return (NULL);
+ }
+
+ return (pdu);
+}
+
+struct agentx_pdu *
+snmp_agentx_response_pdu(int uptime, int error, int idx)
+{
+ struct agentx_response_data resp;
+ struct agentx_pdu *pdu;
+
+ if ((pdu = snmp_agentx_pdu_alloc()) == NULL)
+ return (NULL);
+ pdu->hdr->type = AGENTX_RESPONSE;
+
+ resp.sysuptime = uptime;
+ resp.error = error;
+ resp.index = idx;
+
+ if (snmp_agentx_raw(pdu, &resp, sizeof(resp)) == -1) {
+ snmp_agentx_pdu_free(pdu);
+ return (NULL);
+ }
+
+ return (pdu);
+}
+
+struct agentx_pdu *
+snmp_agentx_ping_pdu(void)
+{
+ struct agentx_pdu *pdu;
+
+ if ((pdu = snmp_agentx_pdu_alloc()) == NULL)
+ return (NULL);
+ pdu->hdr->version = AGENTX_VERSION;
+ pdu->hdr->type = AGENTX_PING;
+
+ return (pdu);
+}
+
+struct agentx_pdu *
+snmp_agentx_register_pdu(struct snmp_oid *oid, int timeout, int range_index,
+ int range_bound)
+{
+ struct agentx_register_hdr rhdr;
+ struct agentx_pdu *pdu;
+
+ if ((pdu = snmp_agentx_pdu_alloc()) == NULL)
+ return (NULL);
+
+ pdu->hdr->version = AGENTX_VERSION;
+ pdu->hdr->type = AGENTX_REGISTER;
+
+ rhdr.timeout = timeout;
+ rhdr.priority = AGENTX_REGISTER_PRIO_DEFAULT;
+ rhdr.subrange = range_index;
+ rhdr.reserved = 0;
+
+ if (snmp_agentx_raw(pdu, &rhdr, sizeof(rhdr)) == -1 ||
+ snmp_agentx_oid(pdu, oid) == -1 ||
+ (range_index && snmp_agentx_int(pdu, &range_bound) == -1)) {
+ snmp_agentx_pdu_free(pdu);
+ return (NULL);
+ }
+
+ return (pdu);
+}
+
+/*
+ * AgentX PDU write routines.
+ */
+
+int
+snmp_agentx_raw(struct agentx_pdu *pdu, void *data, int len)
+{
+
+ if (snmp_agentx_buffercheck(pdu, len) == -1)
+ return (-1);
+
+ memcpy(pdu->ptr, data, len);
+
+ pdu->hdr->length += len;
+ pdu->ptr += len;
+ pdu->datalen += len;
+
+ return (0);
+}
+
+int
+snmp_agentx_int(struct agentx_pdu *pdu, uint32_t *i)
+{
+ return (snmp_agentx_raw(pdu, i, sizeof(*i)));
+}
+
+int
+snmp_agentx_int64(struct agentx_pdu *pdu, uint64_t *i)
+{
+ return (snmp_agentx_raw(pdu, i, sizeof(*i)));
+}
+
+int
+snmp_agentx_octetstring(struct agentx_pdu *pdu, char *str, int len)
+{
+ static uint8_t pad[4] = { 0, 0, 0, 0 };
+ int padding;
+ uint32_t l;
+
+ padding = ((len + 3) & ~0x03) - len;
+
+ l = len;
+ if (snmp_agentx_int(pdu, &len) == -1 ||
+ snmp_agentx_raw(pdu, str, len) == -1 ||
+ snmp_agentx_raw(pdu, pad, padding) == -1)
+ return (-1);
+
+ return (0);
+}
+
+int
+snmp_agentx_oid(struct agentx_pdu *pdu, struct snmp_oid *oid)
+{
+ struct agentx_oid_hdr ohdr;
+ u_int i, prefix;
+
+ i = prefix = 0;
+
+ if (oid->o_id[0] == 1 && oid->o_id[1] == 3 &&
+ oid->o_id[2] == 6 && oid->o_id[3] == 1 &&
+ oid->o_id[4] < 256) {
+ prefix = oid->o_id[4];
+ i = 5;
+ }
+
+ if (prefix)
+ ohdr.n_subid = oid->o_n - 5;
+ else
+ ohdr.n_subid = oid->o_n;
+ ohdr.prefix = prefix;
+ ohdr.include = 0;
+ ohdr.reserved = 0;
+
+ if (snmp_agentx_raw(pdu, &ohdr, sizeof(ohdr)) == -1)
+ return (-1);
+
+ for (; i < oid->o_n; i++)
+ if (snmp_agentx_int(pdu, &oid->o_id[i]) == -1)
+ return (-1);
+
+ return (0);
+}
+
+int
+snmp_agentx_varbind(struct agentx_pdu *pdu, struct snmp_oid *oid, int type,
+ void *data, int len)
+{
+ struct agentx_varbind_hdr vbhdr;
+
+ vbhdr.type = type;
+ vbhdr.reserved = 0;
+ if (snmp_agentx_raw(pdu, &vbhdr, sizeof(vbhdr)) == -1)
+ return (-1);
+
+ if (snmp_agentx_oid(pdu, oid) == -1)
+ return (-1);
+
+ switch (type) {
+
+ case AGENTX_NO_SUCH_OBJECT:
+ case AGENTX_NO_SUCH_INSTANCE:
+ case AGENTX_END_OF_MIB_VIEW:
+ case AGENTX_NULL:
+ /* no data follows the OID */
+ return (0);
+
+ case AGENTX_IP_ADDRESS:
+ case AGENTX_OPAQUE:
+ case AGENTX_OCTET_STRING:
+ return (snmp_agentx_octetstring(pdu, data, len));
+
+ case AGENTX_OBJECT_IDENTIFIER:
+ return (snmp_agentx_oid(pdu, (struct snmp_oid *)data));
+
+ case AGENTX_INTEGER:
+ case AGENTX_COUNTER32:
+ case AGENTX_GAUGE32:
+ case AGENTX_TIME_TICKS:
+ return (snmp_agentx_int(pdu, (uint32_t *)data));
+
+ case AGENTX_COUNTER64:
+ return (snmp_agentx_int64(pdu, (uint64_t *)data));
+
+ default:
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * AgentX PDU read routines.
+ */
+
+int
+snmp_agentx_read_vbhdr(struct agentx_pdu *pdu,
+ struct agentx_varbind_hdr *vbhdr)
+{
+ if (snmp_agentx_read_raw(pdu, vbhdr, sizeof(*vbhdr)) == -1)
+ return (-1);
+ if (!snmp_agentx_byteorder_native(pdu->hdr))
+ vbhdr->type = snmp_agentx_int16_byteswap(vbhdr->type);
+ return (0);
+}
+
+int
+snmp_agentx_copy_raw(struct agentx_pdu *pdu, void *v, int len)
+{
+ return (snmp_agentx_do_read_raw(pdu, v, len, 0));
+}
+
+int
+snmp_agentx_read_raw(struct agentx_pdu *pdu, void *v, int len)
+{
+ return (snmp_agentx_do_read_raw(pdu, v, len, 1));
+}
+
+int
+snmp_agentx_do_read_raw(struct agentx_pdu *pdu, void *v, int len, int consume)
+{
+ void *ptr = pdu->ptr;
+
+ if (consume)
+ if (snmp_agentx_buffer_consume(pdu, len) == -1)
+ return (-1);
+
+ memcpy(v, ptr, len);
+
+ return (0);
+}
+
+int
+snmp_agentx_read_int(struct agentx_pdu *pdu, uint32_t *i)
+{
+ if (snmp_agentx_read_raw(pdu, i, sizeof(*i)) == -1)
+ return (-1);
+ if (!snmp_agentx_byteorder_native(pdu->hdr))
+ *i = snmp_agentx_int_byteswap(*i);
+ return (0);
+}
+
+int
+snmp_agentx_read_int64(struct agentx_pdu *pdu, uint64_t *i)
+{
+ if (snmp_agentx_read_raw(pdu, i, sizeof(*i)) == -1)
+ return (-1);
+ if (!snmp_agentx_byteorder_native(pdu->hdr))
+ *i = snmp_agentx_int64_byteswap(*i);
+ return (0);
+}
+
+int
+snmp_agentx_read_oid(struct agentx_pdu *pdu, struct snmp_oid *oid)
+{
+ struct agentx_oid_hdr ohdr;
+ int i = 0;
+
+ if (snmp_agentx_read_raw(pdu, &ohdr, sizeof(ohdr)) == -1)
+ return (-1);
+
+ bzero(oid, sizeof(*oid));
+
+ if (ohdr.prefix != 0) {
+ oid->o_id[0] = 1;
+ oid->o_id[1] = 3;
+ oid->o_id[2] = 6;
+ oid->o_id[3] = 1;
+ oid->o_id[4] = ohdr.prefix;
+ i = 5;
+ }
+
+ while (ohdr.n_subid--)
+ if (snmp_agentx_read_int(pdu, &oid->o_id[i++]) == -1)
+ return (-1);
+
+ oid->o_n = i;
+
+ return (0);
+}
+
+char *
+snmp_agentx_read_octetstr(struct agentx_pdu *pdu, int *len)
+{
+ char *str;
+ uint32_t l;
+
+ if (snmp_agentx_read_int(pdu, &l) == -1)
+ return (NULL);
+
+ if ((str = malloc(l)) == NULL)
+ return (NULL);
+
+ if (snmp_agentx_read_raw(pdu, str, l) == -1) {
+ free(str);
+ return (NULL);
+ }
+ *len = l;
+
+ return (str);
+}
+
+/*
+ * Synchronous AgentX calls.
+ */
+
+int
+snmp_agentx_ping(struct agentx_handle *h)
+{
+ struct agentx_pdu *pdu;
+ int error = 0;
+
+ if ((pdu = snmp_agentx_ping_pdu()) == NULL ||
+ (pdu = snmp_agentx_request(h, pdu)) == NULL)
+ return (-1);
+
+ if (snmp_agentx_response(h, pdu) == -1)
+ error = -1;
+ snmp_agentx_pdu_free(pdu);
+
+ return (error);
+}
+
+/*
+ * Internal utility functions.
+ */
+
+void
+snmp_agentx_update_ids(struct agentx_handle *h, struct agentx_pdu *pdu)
+{
+ /* XXX -- update to reflect the new queueing semantics */
+ h->transactid = pdu->hdr->transactid;
+ h->packetid = pdu->hdr->packetid;
+}
+
+char *
+snmp_agentx_type2name(int type)
+{
+ static char *names[] = {
+ "AGENTX_OPEN",
+ "AGENTX_CLOSE",
+ "AGENTX_REGISTER",
+ "AGENTX_UNREGISTER",
+ "AGENTX_GET",
+ "AGENTX_GET_NEXT",
+ "AGENTX_GET_BULK",
+ "AGENTX_TEST_SET",
+ "AGENTX_COMMIT_SET",
+ "AGENTX_UNDO_SET",
+ "AGENTX_CLEANUP_SET",
+ "AGENTX_NOTIFY",
+ "AGENTX_PING",
+ "AGENTX_INDEX_ALLOCATE",
+ "AGENTX_INDEX_DEALLOCATE",
+ "AGENTX_ADD_AGENT_CAPS",
+ "AGENTX_REMOVE_AGENT_CAPS",
+ "AGENTX_RESPONSE"
+ };
+
+ if (type > 18)
+ return ("unknown");
+
+ return (names[type - 1]);
+}
+
+#ifdef DEBUG
+static void
+snmp_agentx_dump_hdr(struct agentx_hdr *hdr)
+{
+ if (hdr == NULL) {
+ printf("NULL\n");
+ return;
+ }
+
+ printf("Version: %i\n", hdr->version);
+ printf("Type: %s\n", snmp_agentx_type2name(hdr->type));
+ printf("Flags: %i\n", hdr->flags);
+ printf("Reserved: %i\n", hdr->reserved);
+ printf("Session ID: %i\n", hdr->sessionid);
+ printf("Transaction ID: %i\n", hdr->transactid);
+ printf("Packet ID: %i\n", hdr->packetid);
+ printf("Data Length: %i\n", hdr->length);
+
+ if (hdr->type == AGENTX_RESPONSE) {
+ struct agentx_response *r = (struct agentx_response *)hdr;
+
+ printf("SysUptime: %i\n", r->data.sysuptime);
+ printf("Error: %i\n", r->data.error);
+ printf("Index: %i\n", r->data.index);
+ }
+}
+#endif
diff --git a/usr.sbin/snmpd/ber.c b/usr.sbin/snmpd/ber.c
index 82831393922..9ae498292ef 100644
--- a/usr.sbin/snmpd/ber.c
+++ b/usr.sbin/snmpd/ber.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ber.c,v 1.25 2013/10/01 12:41:47 reyk Exp $ */
+/* $OpenBSD: ber.c,v 1.26 2014/04/14 12:55:10 blambert Exp $ */
/*
* Copyright (c) 2007, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -651,6 +651,7 @@ ber_scanf_elements(struct ber_element *ber, char *fmt, ...)
goto fail;
ret++;
break;
+ case 'd':
case 'i':
i = va_arg(ap, long long *);
if (ber_get_integer(ber, i) == -1)
diff --git a/usr.sbin/snmpd/control.c b/usr.sbin/snmpd/control.c
index 1b0d736cede..d5bfada60cc 100644
--- a/usr.sbin/snmpd/control.c
+++ b/usr.sbin/snmpd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.21 2013/11/26 12:02:22 henning Exp $ */
+/* $OpenBSD: control.c,v 1.22 2014/04/14 12:55:10 blambert Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -40,12 +40,14 @@
struct ctl_connlist ctl_conns;
+static int agentx_sessionid = 1;
+
void control_accept(int, short, void *);
-struct ctl_conn
- *control_connbyfd(int);
-void control_close(int, struct control_sock *);
+void control_close(struct ctl_conn *);
void control_dispatch_imsg(int, short, void *);
+void control_dispatch_agentx(int, short, void *);
void control_imsg_forward(struct imsg *);
+void control_event_add(struct ctl_conn *, int, int, struct timeval *);
int
control_init(struct privsep *ps, struct control_sock *cs)
@@ -78,7 +80,7 @@ control_init(struct privsep *ps, struct control_sock *cs)
return (-1);
}
- if (cs->cs_restricted) {
+ if (cs->cs_restricted || cs->cs_agentx) {
old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
} else {
@@ -178,9 +180,20 @@ control_accept(int listenfd, short event, void *arg)
}
imsg_init(&c->iev.ibuf, connfd);
- c->iev.handler = control_dispatch_imsg;
+ if (cs->cs_agentx) {
+ c->data = snmp_agentx_alloc(c->iev.ibuf.fd);
+ if (c->data == NULL) {
+ free(c);
+ log_warn("%s: agentx", __func__);
+ return;
+ }
+ c->flags |= CTL_CONN_LOCKED;
+ c->iev.handler = control_dispatch_agentx;
+ } else
+ c->iev.handler = control_dispatch_imsg;
c->iev.events = EV_READ;
- c->iev.data = cs;
+ c->iev.data = c;
+ c->cs = cs;
event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
c->iev.handler, c->iev.data);
event_add(&c->iev.ev, NULL);
@@ -188,27 +201,10 @@ control_accept(int listenfd, short event, void *arg)
TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
}
-struct ctl_conn *
-control_connbyfd(int fd)
-{
- struct ctl_conn *c;
-
- for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd;
- c = TAILQ_NEXT(c, entry))
- ; /* nothing */
-
- return (c);
-}
-
void
-control_close(int fd, struct control_sock *cs)
+control_close(struct ctl_conn *c)
{
- struct ctl_conn *c;
-
- if ((c = control_connbyfd(fd)) == NULL) {
- log_warn("%s: fd %d: not found", __func__, fd);
- return;
- }
+ struct control_sock *cs = c->cs;
msgbuf_clear(&c->iev.ibuf.w);
TAILQ_REMOVE(&ctl_conns, c, entry);
@@ -229,27 +225,22 @@ control_close(int fd, struct control_sock *cs)
void
control_dispatch_imsg(int fd, short event, void *arg)
{
- struct control_sock *cs = arg;
+ struct ctl_conn *c = arg;
+ struct control_sock *cs = c->cs;
struct snmpd *env = cs->cs_env;
- struct ctl_conn *c;
struct imsg imsg;
int n, v, i;
- if ((c = control_connbyfd(fd)) == NULL) {
- log_warn("%s: fd %d: not found", __func__, fd);
- return;
- }
-
switch (event) {
case EV_READ:
if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) {
- control_close(fd, cs);
+ control_close(c);
return;
}
break;
case EV_WRITE:
if (msgbuf_write(&c->iev.ibuf.w) < 0 && errno != EAGAIN) {
- control_close(fd, cs);
+ control_close(c);
return;
}
break;
@@ -259,7 +250,7 @@ control_dispatch_imsg(int fd, short event, void *arg)
for (;;) {
if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
- control_close(fd, cs);
+ control_close(c);
return;
}
@@ -268,7 +259,7 @@ control_dispatch_imsg(int fd, short event, void *arg)
if (cs->cs_restricted || (c->flags & CTL_CONN_LOCKED)) {
switch (imsg.hdr.type) {
- case IMSG_SNMP_TRAP:
+ case IMSG_SNMP_AGENTX:
case IMSG_SNMP_ELEMENT:
case IMSG_SNMP_END:
case IMSG_SNMP_LOCK:
@@ -277,7 +268,7 @@ control_dispatch_imsg(int fd, short event, void *arg)
log_debug("control_dispatch_imsg: "
"client requested restricted command");
imsg_free(&imsg);
- control_close(fd, cs);
+ control_close(c);
return;
}
}
@@ -296,20 +287,39 @@ control_dispatch_imsg(int fd, short event, void *arg)
}
c->flags |= CTL_CONN_NOTIFY;
break;
+
case IMSG_SNMP_LOCK:
/* enable restricted control mode */
c->flags |= CTL_CONN_LOCKED;
break;
- case IMSG_SNMP_TRAP:
- if (trap_imsg(&c->iev, imsg.hdr.pid) == -1) {
+
+ case IMSG_SNMP_AGENTX:
+
+ /* rendezvous with the client */
+ imsg_compose_event(&c->iev, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
+ if (imsg_flush(&c->iev.ibuf) == -1) {
log_debug("control_dispatch_imsg: "
- "received invalid trap (pid %d)",
- imsg.hdr.pid);
+ "could not rendezvous with client");
imsg_free(&imsg);
- control_close(fd, cs);
+ control_close(c);
return;
}
+
+ /* enable AgentX socket */
+ c->data = snmp_agentx_alloc(c->iev.ibuf.fd);
+ if (c->data == NULL) {
+ log_debug("control_dispatch_imsg: "
+ "could not allocate restricted socket");
+ imsg_free(&imsg);
+ control_close(c);
+ return;
+ }
+ /* disable IMSG notifications */
+ c->flags &= ~CTL_CONN_NOTIFY;
+ c->flags |= CTL_CONN_LOCKED;
+ c->iev.handler = control_dispatch_agentx;
break;
+
case IMSG_CTL_VERBOSE:
IMSG_SIZE_CHECK(&imsg, &v);
@@ -336,6 +346,163 @@ control_dispatch_imsg(int fd, short event, void *arg)
imsg_event_add(&c->iev);
}
+/* ARGSUSED */
+void
+control_dispatch_agentx(int fd, short event, void *arg)
+{
+ struct ctl_conn *c = arg;
+ struct agentx_handle *h = c->data;
+ struct agentx_pdu *pdu;
+ struct timeval tv;
+ struct agentx_open_timeout to;
+ struct ber_oid oid;
+ struct agentx_close_request_data clhdr;
+ int closing = 0;
+ int evflags = 0;
+ int timer = 0;
+ int error = AGENTX_ERR_NONE;
+ int idx = 0, vcpylen, dlen, uptime;
+ char *descr, *varcpy;
+
+ varcpy = descr = NULL;
+ if (h->timeout != 0)
+ tv.tv_sec = h->timeout;
+ else
+ tv.tv_sec = AGENTX_DEFAULT_TIMEOUT;
+ tv.tv_usec = 0;
+
+ if (event & EV_TIMEOUT) {
+ log_info("subagent session '%i' timed out after %i seconds",
+ h->sessionid, h->timeout);
+ goto teardown;
+ }
+
+ if (event & EV_WRITE) {
+ if (snmp_agentx_send(h, NULL) == -1) {
+ if (errno != EAGAIN)
+ goto teardown;
+
+ /* short write */
+ evflags |= EV_WRITE;
+ timer = 1;
+ }
+ }
+
+ if (event & EV_READ) {
+ if ((pdu = snmp_agentx_recv(h)) == NULL) {
+ if (h->error) {
+ error = h->error;
+ goto respond;
+ }
+ if (errno != EAGAIN)
+ goto teardown;
+
+ /* short read */
+ timer = 1;
+ goto done;
+ }
+
+ switch (pdu->hdr->type) {
+ case AGENTX_OPEN:
+ if (snmp_agentx_read_raw(pdu, &to, sizeof(to)) == -1 ||
+ snmp_agentx_read_oid(pdu,
+ (struct snmp_oid *)&oid) == -1 ||
+ (descr =
+ snmp_agentx_read_octetstr(pdu, &dlen)) == NULL) {
+ error = AGENTX_ERR_PARSE_ERROR;
+ break;
+ }
+
+ log_info("opening AgentX socket for '%.*s'",
+ dlen, descr);
+
+ h->sessionid = pdu->hdr->sessionid =
+ agentx_sessionid++;
+ if (to.timeout != 0)
+ h->timeout = to.timeout;
+ else
+ h->timeout = AGENTX_DEFAULT_TIMEOUT;
+ break;
+
+ case AGENTX_CLOSE:
+ if (snmp_agentx_read_raw(pdu,
+ &clhdr, sizeof(clhdr)) == -1) {
+ error = AGENTX_ERR_PARSE_ERROR;
+ break;
+ }
+ closing = 1;
+ break;
+
+ case AGENTX_NOTIFY:
+ error = trap_agentx(h, pdu, &idx, &varcpy, &vcpylen);
+ break;
+
+ case AGENTX_PING:
+ /* no processing, just an empty response */
+ break;
+
+ /* unimplemented */
+ case AGENTX_ADD_AGENT_CAPS:
+ case AGENTX_REMOVE_AGENT_CAPS:
+ case AGENTX_RESPONSE:
+ case AGENTX_REGISTER:
+ case AGENTX_UNREGISTER:
+ case AGENTX_GET:
+ case AGENTX_GET_NEXT:
+ case AGENTX_GET_BULK:
+ case AGENTX_TEST_SET:
+ case AGENTX_COMMIT_SET:
+ case AGENTX_UNDO_SET:
+ case AGENTX_CLEANUP_SET:
+ case AGENTX_INDEX_ALLOCATE:
+ case AGENTX_INDEX_DEALLOCATE:
+ error = AGENTX_ERR_REQUEST_DENIED;
+ break;
+
+ /* NB: by RFC, this should precede all other checks. */
+ default:
+ log_info("unknown AgentX type '%i'", pdu->hdr->type);
+ error = AGENTX_ERR_PARSE_ERROR;
+ break;
+ }
+ respond:
+ if (pdu)
+ snmp_agentx_pdu_free(pdu);
+
+ uptime = smi_getticks();
+ if ((pdu = snmp_agentx_response_pdu(uptime, error, idx)) == NULL) {
+ log_debug("bad response generation: %s",
+ snmp_agentx_type2name(pdu->hdr->type));
+ if (varcpy)
+ free(varcpy);
+ control_event_add(c, fd, EV_WRITE, NULL); /* XXX -- EV_WRITE? */
+ return;
+ }
+
+ if (varcpy) {
+ snmp_agentx_raw(pdu, varcpy, vcpylen); /* XXX */
+ free(varcpy);
+ }
+ snmp_agentx_send(h, pdu);
+
+ /* Request processed, now write out response */
+ evflags |= EV_WRITE;
+ }
+
+ if (closing)
+ goto teardown;
+ done:
+ control_event_add(c, fd, evflags, timer ? &tv : NULL);
+ return;
+
+ teardown:
+ log_debug("subagent session '%i' destroyed", h->sessionid);
+ snmp_agentx_free(h);
+ if (varcpy)
+ free(varcpy);
+ control_close(c);
+}
+
void
control_imsg_forward(struct imsg *imsg)
{
@@ -347,3 +514,11 @@ control_imsg_forward(struct imsg *imsg)
0, imsg->hdr.pid, -1, imsg->data,
imsg->hdr.len - IMSG_HEADER_SIZE);
}
+
+void
+control_event_add(struct ctl_conn *c, int fd, int wflag, struct timeval *tv)
+{
+ event_del(&c->iev.ev);
+ event_set(&c->iev.ev, fd, EV_READ|wflag, control_dispatch_agentx, c);
+ event_add(&c->iev.ev, tv);
+}
diff --git a/usr.sbin/snmpd/parse.y b/usr.sbin/snmpd/parse.y
index 69b45cd0bf6..db25bb8c037 100644
--- a/usr.sbin/snmpd/parse.y
+++ b/usr.sbin/snmpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.29 2014/01/22 00:21:17 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.30 2014/04/14 12:55:10 blambert Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -51,6 +51,11 @@
#include "snmpd.h"
#include "mib.h"
+enum socktype {
+ SOCK_TYPE_RESTRICTED = 1,
+ SOCK_TYPE_AGENTX = 2
+};
+
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
static struct file {
TAILQ_ENTRY(file) entry;
@@ -120,11 +125,11 @@ typedef struct {
%token SYSTEM CONTACT DESCR LOCATION NAME OBJECTID SERVICES RTFILTER
%token READONLY READWRITE OCTETSTRING INTEGER COMMUNITY TRAP RECEIVER
%token SECLEVEL NONE AUTH ENC USER AUTHKEY ENCKEY ERROR DISABLED
-%token SOCKET RESTRICTED
+%token SOCKET RESTRICTED AGENTX
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.string> hostcmn
-%type <v.number> optwrite yesno seclevel restricted
+%type <v.number> optwrite yesno seclevel socktype
%type <v.data> objtype
%type <v.oid> oid hostoid
%type <v.auth> auth
@@ -266,7 +271,7 @@ main : LISTEN ON STRING {
}
user = NULL;
}
- | SOCKET STRING restricted {
+ | SOCKET STRING socktype {
if ($3) {
struct control_sock *rcsock;
@@ -276,7 +281,10 @@ main : LISTEN ON STRING {
YYERROR;
}
rcsock->cs_name = $2;
- rcsock->cs_restricted = 1;
+ if ($3 == SOCK_TYPE_RESTRICTED)
+ rcsock->cs_restricted = 1;
+ else if ($3 == SOCK_TYPE_AGENTX)
+ rcsock->cs_agentx = 1;
TAILQ_INSERT_TAIL(&conf->sc_ps.ps_rcsocks,
rcsock, cs_entry);
} else {
@@ -475,7 +483,8 @@ enc : STRING {
}
;
-restricted : RESTRICTED { $$ = 1; }
+socktype : RESTRICTED { $$ = SOCK_TYPE_RESTRICTED; }
+ | AGENTX { $$ = SOCK_TYPE_AGENTX; }
| /* nothing */ { $$ = 0; }
;
@@ -513,6 +522,7 @@ lookup(char *s)
{
/* this has to be sorted always */
static const struct keywords keywords[] = {
+ { "agentx", AGENTX },
{ "auth", AUTH },
{ "authkey", AUTHKEY },
{ "community", COMMUNITY },
diff --git a/usr.sbin/snmpd/snmp.h b/usr.sbin/snmpd/snmp.h
index eaf5f01a585..4d03441f5a0 100644
--- a/usr.sbin/snmpd/snmp.h
+++ b/usr.sbin/snmpd/snmp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmp.h,v 1.10 2012/09/17 16:43:59 reyk Exp $ */
+/* $OpenBSD: snmp.h,v 1.11 2014/04/14 12:55:10 blambert Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -19,12 +19,17 @@
#ifndef SNMP_HEADER
#define SNMP_HEADER
+#include <sys/types.h>
+#include <machine/endian.h>
+
/*
* SNMP IMSG interface
*/
-#define SNMP_MAX_OID_LEN 128 /* max size of the OID _string_ */
+#define SNMP_MAX_OID_STRLEN 128 /* max size of the OID _string_ */
#define SNMP_SOCKET "/var/run/snmpd.sock"
+#define AGENTX_SOCKET "/var/run/agentx.sock"
+#define SNMP_RESTRICTED_SOCKET "/var/run/snmpd.rsock"
enum snmp_type {
SNMP_IPADDR = 0,
@@ -45,10 +50,11 @@ enum snmp_type {
};
enum snmp_imsg_ctl {
- IMSG_SNMP_TRAP = 1000, /* something that works everywhere */
+ IMSG_SNMP_DUMMY = 1000, /* something that works everywhere */
IMSG_SNMP_ELEMENT,
IMSG_SNMP_END,
- IMSG_SNMP_LOCK /* enable restricted mode */
+ IMSG_SNMP_LOCK, /* enable restricted mode */
+ IMSG_SNMP_AGENTX
};
struct snmp_imsg_hdr {
@@ -60,7 +66,7 @@ struct snmp_imsg_hdr {
};
struct snmp_imsg {
- char snmp_oid[SNMP_MAX_OID_LEN];
+ char snmp_oid[SNMP_MAX_OID_STRLEN];
u_int8_t snmp_type;
u_int16_t snmp_len;
};
@@ -150,4 +156,268 @@ enum snmp_security_model {
#define SNMP_MAX_TIMEWINDOW 150 /* RFC3414 */
+#define SNMP_MIN_OID_LEN 2 /* OBJECT */
+#define SNMP_MAX_OID_LEN 32 /* OBJECT */
+
+struct snmp_oid {
+ u_int32_t o_id[SNMP_MAX_OID_LEN + 1];
+ size_t o_n;
+};
+
+/* AgentX protocol, as outlined in RFC 2741 */
+
+/* version */
+#define AGENTX_VERSION 1
+
+/* type */
+#define AGENTX_OPEN 1
+#define AGENTX_CLOSE 2
+#define AGENTX_REGISTER 3
+#define AGENTX_UNREGISTER 4
+#define AGENTX_GET 5
+#define AGENTX_GET_NEXT 6
+#define AGENTX_GET_BULK 7
+#define AGENTX_TEST_SET 8
+#define AGENTX_COMMIT_SET 9
+#define AGENTX_UNDO_SET 10
+#define AGENTX_CLEANUP_SET 11
+#define AGENTX_NOTIFY 12
+#define AGENTX_PING 13
+#define AGENTX_INDEX_ALLOCATE 14
+#define AGENTX_INDEX_DEALLOCATE 15
+#define AGENTX_ADD_AGENT_CAPS 16
+#define AGENTX_REMOVE_AGENT_CAPS 17
+#define AGENTX_RESPONSE 18
+
+/* error return codes */
+#define AGENTX_ERR_NONE 0
+#define AGENTX_ERR_OPEN_FAILED 256
+#define AGENTX_ERR_NOT_OPEN 257
+#define AGENTX_ERR_INDEX_WRONG_TYPE 258
+#define AGENTX_ERR_INDEX_ALREADY_ALLOCATED 259
+#define AGENTX_ERR_INDEX_NONE_AVAILABLE 260
+#define AGENTX_ERR_INDEX_NOT_ALLOCATED 261
+#define AGENTX_ERR_UNSUPPORTED_CONTEXT 262
+#define AGENTX_ERR_DUPLICATE_REGISTRATION 263
+#define AGENTX_ERR_UNKNOWN_REGISTRATION 264
+#define AGENTX_ERR_UNKNOWN_AGENT_CAPS 265
+#define AGENTX_ERR_PARSE_ERROR 266
+#define AGENTX_ERR_REQUEST_DENIED 267
+#define AGENTX_ERR_PROCESSING_ERROR 268
+
+/* flags */
+#define AGENTX_INSTANCE_REGISTRATION 0x01
+#define AGENTX_NEW_INDEX 0x02
+#define AGENTX_ANY_INDEX 0x04
+#define AGENTX_NON_DEFAULT_CONTEXT 0x08
+#define AGENTX_NETWORK_BYTE_ORDER 0x10
+#define AGENTX_FLAGS_MASK 0x1f
+
+/* encoded data types */
+#define AGENTX_INTEGER 2
+#define AGENTX_OCTET_STRING 4
+#define AGENTX_NULL 5
+#define AGENTX_OBJECT_IDENTIFIER 6
+#define AGENTX_IP_ADDRESS 64
+#define AGENTX_COUNTER32 65
+#define AGENTX_GAUGE32 66
+#define AGENTX_TIME_TICKS 67
+#define AGENTX_OPAQUE 68
+#define AGENTX_COUNTER64 70
+#define AGENTX_NO_SUCH_OBJECT 128
+#define AGENTX_NO_SUCH_INSTANCE 129
+#define AGENTX_END_OF_MIB_VIEW 130
+
+/* for registered MIB overlap */
+#define AGENTX_REGISTER_PRIO_DEFAULT 127
+
+/* reasons for request of close */
+#define AGENTX_CLOSE_OTHER 1
+#define AGENTX_CLOSE_PARSE_ERROR 2
+#define AGENTX_CLOSE_PROTOCOL_ERROR 3
+#define AGENTX_CLOSE_TIMEOUTS 4
+#define AGENTX_CLOSE_SHUTDOWN 5
+#define AGENTX_CLOSE_BY_MANAGER 6
+
+#define AGENTX_DEFAULT_TIMEOUT 3
+
+#define MIN_OID_LEN 2 /* OBJECT */
+#define MAX_OID_LEN 32 /* OBJECT */
+
+/*
+ * Protocol header prefixed to all messages
+ */
+struct agentx_hdr {
+ uint8_t version;
+ uint8_t type;
+ uint8_t flags;
+ uint8_t reserved;
+ uint32_t sessionid; /* chosen by agent */
+ uint32_t transactid; /* chosen by subagent */
+ uint32_t packetid; /* per-request id */
+ uint32_t length;
+} __packed;
+
+/*
+ * Prefixed to a series of 4-byte values indicating the OID
+ */
+struct agentx_oid_hdr {
+ uint8_t n_subid; /* # of oid elements (named in RFC) */
+ uint8_t prefix; /* if not 0, OID is 1.3.6.1.<prefix> */
+ uint8_t include; /* ??? */
+ uint8_t reserved; /* always 0 */
+} __packed;
+
+struct agentx_response_data {
+ uint32_t sysuptime; /* uptime of SNMP context */
+ uint16_t error; /* status of request */
+ uint16_t index; /* index of failed variable binding */
+} __packed;
+
+struct agentx_open_timeout {
+ uint8_t timeout;
+ uint8_t reserved[3];
+} __packed;
+
+struct agentx_register_hdr {
+ uint8_t timeout;
+ uint8_t priority;
+ uint8_t subrange;
+ uint8_t reserved;
+} __packed;
+
+struct agentx_null_oid {
+ uint8_t padding[4];
+} __packed;
+
+#define AGENTX_NULL_OID { 0, 0, 0, 0 }
+
+struct agentx_varbind_hdr {
+ uint16_t type;
+ uint16_t reserved;
+} __packed;
+
+struct agentx_response {
+ struct agentx_hdr hdr;
+ struct agentx_response_data data;
+} __packed;
+
+struct agentx_close_request_data {
+ uint8_t reason;
+ uint8_t padding[3];
+} __packed;
+
+struct agentx_close_request {
+ struct agentx_hdr hdr;
+ struct agentx_close_request_data data;
+} __packed;
+
+struct agentx_pdu {
+ uint8_t *buffer;
+ uint8_t *ptr;
+ uint8_t *ioptr;
+ size_t buflen;
+ size_t datalen;
+ struct agentx_hdr *hdr;
+
+ struct agentx_pdu *request; /* request this is a response to */
+ TAILQ_ENTRY(agentx_pdu) entry;
+};
+TAILQ_HEAD(agentx_pdulist, agentx_pdu);
+
+struct agentx_handle {
+ int fd;
+ uint32_t sessionid;
+ uint32_t transactid;
+ uint32_t packetid;
+ int timeout; /* in seconds */
+ int error;
+ int erridx;
+
+ struct agentx_pdulist w;
+ struct agentx_pdulist inflight;
+
+ struct agentx_pdu *r;
+
+ void (*cb)(struct agentx_handle *, struct agentx_pdu *, void *);
+ void *cb_arg;
+};
+
+struct agentx_handle *
+ snmp_agentx_alloc(int);
+struct agentx_handle *
+ snmp_agentx_open(const char *, char *, struct snmp_oid *);
+struct agentx_handle *
+ snmp_agentx_fdopen(int, char *, struct snmp_oid *);
+int snmp_agentx_response(struct agentx_handle *, struct agentx_pdu *);
+int snmp_agentx_open_response(struct agentx_handle *, struct agentx_pdu *);
+struct agentx_pdu *
+ snmp_agentx_open_pdu(struct agentx_handle *, char *descr,
+ struct snmp_oid *);
+void snmp_agentx_set_callback(struct agentx_handle *,
+ void (*)(struct agentx_handle *, struct agentx_pdu *, void *),
+ void *);
+struct agentx_pdu *
+ snmp_agentx_close_pdu(struct agentx_handle *, uint8_t);
+int snmp_agentx_close(struct agentx_handle *, uint8_t);
+void snmp_agentx_free(struct agentx_handle *);
+int snmp_agentx_ping(struct agentx_handle *);
+struct agentx_pdu *
+ snmp_agentx_ping_pdu(void);
+struct agentx_pdu *
+ snmp_agentx_notify_pdu(struct snmp_oid *);
+struct agentx_pdu *
+ snmp_agentx_request(struct agentx_handle *, struct agentx_pdu *);
+int snmp_agentx_varbind(struct agentx_pdu *, struct snmp_oid *, int,
+ void *, int);
+int snmp_agentx_send(struct agentx_handle *, struct agentx_pdu *);
+struct agentx_pdu *
+ snmp_agentx_recv(struct agentx_handle *);
+struct agentx_pdu *
+ snmp_agentx_response_pdu(int, int, int);
+struct agentx_pdu *
+ snmp_agentx_register_pdu(struct snmp_oid *, int, int, int);
+char *snmp_agentx_read_octetstr(struct agentx_pdu *, int *);
+int snmp_agentx_read_oid(struct agentx_pdu *, struct snmp_oid *);
+int snmp_agentx_read_raw(struct agentx_pdu *, void *, int);
+int snmp_agentx_copy_raw(struct agentx_pdu *, void *, int);
+char *snmp_agentx_type2name(int);
+int snmp_agentx_read_int(struct agentx_pdu *, uint32_t *);
+int snmp_agentx_read_int64(struct agentx_pdu *, uint64_t *);
+int snmp_agentx_raw(struct agentx_pdu *, void *, int);
+int snmp_agentx_read_vbhdr(struct agentx_pdu *, struct
+ agentx_varbind_hdr *);
+struct agentx_pdu *snmp_agentx_pdu_alloc(void);
+void snmp_agentx_pdu_free(struct agentx_pdu *);
+
+#if BYTE_ORDER == BIG_ENDIAN
+
+static __inline int
+snmp_agentx_byteorder_native(struct agentx_hdr *h)
+{
+ return ((h->flags & AGENTX_NETWORK_BYTE_ORDER) != 0);
+}
+
+#define AGENTX_LOCAL_BYTE_ORDER_FLAG AGENTX_NETWORK_BYTE_ORDER
+#define snmp_agentx_int_byteswap(_i) htole32(_i)
+#define snmp_agentx_int16_byteswap(_i) htole16(_i)
+#define snmp_agentx_int64_byteswap(_i) htole64(_i)
+
+#elif BYTE_ORDER == LITTLE_ENDIAN
+
+static __inline int
+snmp_agentx_byteorder_native(struct agentx_hdr *h)
+{
+ return ((h->flags & AGENTX_NETWORK_BYTE_ORDER) == 0);
+}
+
+#define AGENTX_LOCAL_BYTE_ORDER_FLAG 0
+#define snmp_agentx_int_byteswap(_i) htobe32(_i)
+#define snmp_agentx_int16_byteswap(_i) htobe16(_i)
+#define snmp_agentx_int64_byteswap(_i) htobe64(_i)
+
+#else
+#error "Unknown host byte order"
+#endif
+
#endif /* SNMP_HEADER */
diff --git a/usr.sbin/snmpd/snmpd.conf.5 b/usr.sbin/snmpd/snmpd.conf.5
index d84d9caf4b2..c1cec135a4d 100644
--- a/usr.sbin/snmpd/snmpd.conf.5
+++ b/usr.sbin/snmpd/snmpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: snmpd.conf.5,v 1.28 2013/10/17 09:14:01 blambert Exp $
+.\" $OpenBSD: snmpd.conf.5,v 1.29 2014/04/14 12:55:10 blambert Exp $
.\"
.\" Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: October 17 2013 $
+.Dd $Mdocdate: April 14 2014 $
.Dt SNMPD.CONF 5
.Os
.Sh NAME
@@ -136,18 +136,23 @@ If the chosen value is different from
will accept only SNMPv3 requests since older versions neither support
authentication nor encryption.
.Pp
-.It Ic socket Qo Ar path Qc Op Ic restricted
+.It Ic socket Qo Ar path Qc Op Ic restricted | Ic agentx
Create a control socket at
.Ar path .
If
.Ic restricted
-is specified a restricted control socket will be created.
+is specified, a restricted control socket will be created.
+If
+.Ic agentx
+is specified, a socket which speaks the AgentX protocol will be created.
Multiple
.Ic restricted
+and
+.Ic agentx
sockets may be created.
By default
.Pa /var/run/snmpd.sock
-is used and no restricted socket is created.
+is created and no other sockets are created.
.Pp
.It Ic system contact Ar string
Specify the name or description of the system contact, typically a
diff --git a/usr.sbin/snmpd/snmpd.h b/usr.sbin/snmpd/snmpd.h
index 95244c48e09..a07f28e3a66 100644
--- a/usr.sbin/snmpd/snmpd.h
+++ b/usr.sbin/snmpd/snmpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmpd.h,v 1.49 2014/02/14 10:38:09 florian Exp $ */
+/* $OpenBSD: snmpd.h,v 1.50 2014/04/14 12:55:10 blambert Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -100,6 +100,7 @@ struct control_sock {
struct event cs_evt;
int cs_fd;
int cs_restricted;
+ int cs_agentx;
void *cs_env;
TAILQ_ENTRY(control_sock) cs_entry;
@@ -162,7 +163,8 @@ struct ctl_conn {
#define CTL_CONN_NOTIFY 0x01
#define CTL_CONN_LOCKED 0x02 /* restricted mode */
struct imsgev iev;
-
+ void *data;
+ struct control_sock *cs;
};
TAILQ_HEAD(ctl_connlist, ctl_conn);
extern struct ctl_connlist ctl_conns;
@@ -336,7 +338,14 @@ struct pfr_buffer {
#define MSG_REPORT(m) (((m)->sm_flags & SNMP_MSGFLAG_REPORT) != 0)
struct snmp_message {
+ struct sockaddr_storage sm_ss;
+ socklen_t sm_slen;
+ char sm_host[MAXHOSTNAMELEN];
+
+ struct ber sm_ber;
+ struct ber_element *sm_req;
struct ber_element *sm_resp;
+
u_int8_t sm_data[READ_BUF_SIZE];
size_t sm_datalen;
@@ -366,6 +375,7 @@ struct snmp_message {
long long sm_request;
+ const char *sm_errstr;
long long sm_error;
#define sm_nonrepeaters sm_error
long long sm_errorindex;
@@ -547,6 +557,8 @@ void snmpe_shutdown(struct privsep *, struct privsep_proc *);
/* trap.c */
void trap_init(void);
int trap_imsg(struct imsgev *, pid_t);
+int trap_agentx(struct agentx_handle *, struct agentx_pdu *,
+ int *, char **, int *);
int trap_send(struct ber_oid *, struct ber_element *);
/* mps.c */
@@ -554,6 +566,8 @@ struct ber_element *
mps_getreq(struct ber_element *, struct ber_oid *, u_int);
struct ber_element *
mps_getnextreq(struct ber_element *, struct ber_oid *);
+struct ber_element *
+ mps_getbulkreq(struct ber_element *, struct ber_oid *, int);
int mps_setreq(struct ber_element *, struct ber_oid *);
int mps_set(struct ber_oid *, void *, long long);
int mps_getstr(struct oid *, struct ber_oid *,
@@ -650,4 +664,6 @@ int proc_composev_imsg(struct privsep *, enum privsep_procid,
u_int16_t, int, const struct iovec *, int);
int proc_forward_imsg(struct privsep *, struct imsg *,
enum privsep_procid);
+void proc_flush_imsg(struct privsep *, enum privsep_procid);
+
#endif /* _SNMPD_H */
diff --git a/usr.sbin/snmpd/trap.c b/usr.sbin/snmpd/trap.c
index 5c3ca65eecd..5375418a415 100644
--- a/usr.sbin/snmpd/trap.c
+++ b/usr.sbin/snmpd/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.21 2013/10/19 14:18:39 blambert Exp $ */
+/* $OpenBSD: trap.c,v 1.22 2014/04/14 12:55:10 blambert Exp $ */
/*
* Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
@@ -55,146 +55,162 @@ trap_init(void)
}
int
-trap_imsg(struct imsgev *iev, pid_t pid)
+trap_agentx(struct agentx_handle *h, struct agentx_pdu *pdu, int *idx,
+ char **varcpy, int *vcpylen)
{
- struct imsgbuf *ibuf;
- struct imsg imsg;
- int ret = -1, n, x = 0, state = 0;
- int done = 0;
- struct snmp_imsg *sm;
- u_int32_t d;
- u_int64_t l;
- u_int8_t *c;
- char ostr[SNMP_MAX_OID_LEN];
- struct ber_element *ber = NULL, *varbind = NULL, *a;
- size_t len = 0;
- struct ber_oid o;
-
- ibuf = &iev->ibuf;
- while (!done) {
- while (!done) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- goto done;
- if (n == 0)
- break;
-
- switch (imsg.hdr.type) {
- case IMSG_SNMP_ELEMENT:
- if (imsg.hdr.len < (IMSG_HEADER_SIZE +
- sizeof(struct snmp_imsg)))
- goto imsgdone;
-
- sm = (struct snmp_imsg *)imsg.data;
-
- if (!state++) {
- /* First element must be the trap OID */
- if (sm->snmp_type != SNMP_NULL)
- goto imsgdone;
- ber_string2oid(sm->snmp_oid, &o);
- break;
- }
+ struct agentx_varbind_hdr vbhdr;
+ struct ber_oid o, oid;
+ struct ber_oid uptime = OID(MIB_sysUpTime);
+ struct ber_oid trapoid = OID(MIB_snmpTrapOID);
+ u_int32_t d;
+ u_int64_t l;
+ char *str;
+ int slen;
+ struct ber_element *a, *ber, *varbind;
+ int x = 0, state = 0;
+ int ret = AGENTX_ERR_NONE;
+ int seensysuptime, seentrapoid;
+ size_t len = 0;
+ pid_t pid = -1;
+ char *v = NULL;
+
+ *varcpy = NULL;
+ ber = varbind = NULL;
+ seensysuptime = seentrapoid = 0;
+
+ if (pdu->hdr->flags & AGENTX_NON_DEFAULT_CONTEXT) {
+ ret = AGENTX_ERR_UNSUPPORTED_CONTEXT;
+ goto done;
+ }
+
+ if ((v = malloc(pdu->hdr->length)) == NULL ||
+ snmp_agentx_copy_raw(pdu, v, pdu->hdr->length) == -1) {
+ ret = AGENTX_ERR_PROCESSING_ERROR;
+ goto done;
+ }
- ber = ber_add_sequence(ber);
- if (varbind == NULL)
- varbind = ber;
- a = ber_add_oidstring(ber, sm->snmp_oid);
-
- switch (sm->snmp_type) {
- case SNMP_OBJECT:
- if (sm->snmp_len > sizeof(ostr) - 1)
- goto imsgdone;
- bzero(&ostr, sizeof(ostr));
- bcopy(sm + 1, &ostr, sm->snmp_len);
- a = ber_add_oidstring(a, ostr);
- break;
- case SNMP_BITSTRING:
- if (sm->snmp_len < 1)
- goto imsgdone;
- /* FALLTHROUGH */
- case SNMP_OCTETSTRING:
- case SNMP_IPADDR:
- if (sm->snmp_len >= SNMPD_MAXSTRLEN)
- goto imsgdone;
- c = (u_int8_t *)(sm + 1);
- if (sm->snmp_type == SNMP_BITSTRING)
- a = ber_add_bitstring(a, c,
- sm->snmp_len);
- else
- a = ber_add_nstring(a, c,
- sm->snmp_len);
- break;
- case SNMP_NULL:
- a = ber_add_null(a);
- break;
- case SNMP_INTEGER32:
- case SNMP_COUNTER32:
- case SNMP_GAUGE32:
- case SNMP_TIMETICKS:
- case SNMP_OPAQUE:
- case SNMP_UINTEGER32:
- if (sm->snmp_len != sizeof(d))
- goto imsgdone;
- bcopy(sm + 1, &d, sm->snmp_len);
- a = ber_add_integer(a, d);
- break;
- case SNMP_COUNTER64:
- if (sm->snmp_len != sizeof(l))
- goto imsgdone;
- bcopy(sm + 1, &l, sm->snmp_len);
- a = ber_add_integer(a, l);
- break;
- default:
- log_debug("trap_imsg: illegal type %d",
- sm->snmp_type);
- imsg_free(&imsg);
- goto imsgdone;
+ while (pdu->datalen > sizeof(struct agentx_hdr)) {
+ x++;
+
+ if (snmp_agentx_read_vbhdr(pdu, &vbhdr) == -1 ||
+ snmp_agentx_read_oid(pdu, (struct snmp_oid *)&oid) == -1) {
+ ret = AGENTX_ERR_PARSE_ERROR;
+ goto done;
+ }
+ if (state < 2) {
+ if (state == 0 && ber_oid_cmp(&oid, &uptime) == 0) {
+ if (snmp_agentx_read_int(pdu, &d) == -1) {
+ ret = AGENTX_ERR_PARSE_ERROR;
+ goto done;
}
- switch (sm->snmp_type) {
- case SNMP_INTEGER32:
- case SNMP_BITSTRING:
- case SNMP_OCTETSTRING:
- case SNMP_NULL:
- case SNMP_OBJECT:
- /* universal types */
- break;
- default:
- /* application-specific types */
- ber_set_header(a, BER_CLASS_APPLICATION,
- sm->snmp_type);
- break;
+ state = 1;
+ continue;
+ } else if (ber_oid_cmp(&oid, &trapoid) == 0) {
+ if (snmp_agentx_read_oid(pdu,
+ (struct snmp_oid *)&o) == -1) {
+ ret = AGENTX_ERR_PARSE_ERROR;
+ goto done;
}
- x++;
- break;
- case IMSG_SNMP_END:
- done = 1;
- break;
- default:
- log_debug("trap_imsg: illegal imsg %d",
- imsg.hdr.type);
- goto imsgdone;
+ state = 2;
+ continue;
+ } else {
+ ret = AGENTX_ERR_PROCESSING_ERROR;
+ goto done;
}
- imsg_free(&imsg);
}
- if (done)
+
+ ber = ber_add_sequence(ber);
+ if (varbind == NULL)
+ varbind = ber;
+
+ a = ber_add_oid(ber, &oid);
+
+ switch (vbhdr.type) {
+ case AGENTX_NO_SUCH_OBJECT:
+ case AGENTX_NO_SUCH_INSTANCE:
+ case AGENTX_END_OF_MIB_VIEW:
+ case AGENTX_NULL:
+ a = ber_add_null(a);
break;
- if ((n = imsg_read(ibuf)) == -1)
- goto done;
- if (n == 0)
+
+ case AGENTX_IP_ADDRESS:
+ case AGENTX_OPAQUE:
+ case AGENTX_OCTET_STRING:
+ str = snmp_agentx_read_octetstr(pdu, &slen);
+ if (str == NULL) {
+ ret = AGENTX_ERR_PARSE_ERROR;
+ goto done;
+ }
+ a = ber_add_nstring(a, str, slen);
+ break;
+
+ case AGENTX_OBJECT_IDENTIFIER:
+ if (snmp_agentx_read_oid(pdu,
+ (struct snmp_oid *)&oid) == -1) {
+ ret = AGENTX_ERR_PARSE_ERROR;
+ goto done;
+ }
+ a = ber_add_oid(a, &oid);
+ break;
+
+ case AGENTX_INTEGER:
+ case AGENTX_COUNTER32:
+ case AGENTX_GAUGE32:
+ case AGENTX_TIME_TICKS:
+ if (snmp_agentx_read_int(pdu, &d) == -1) {
+ ret = AGENTX_ERR_PARSE_ERROR;
+ goto done;
+ }
+ a = ber_add_integer(a, d);
+ break;
+
+ case AGENTX_COUNTER64:
+ if (snmp_agentx_read_int64(pdu, &l) == -1) {
+ ret = AGENTX_ERR_PARSE_ERROR;
+ goto done;
+ }
+ a = ber_add_integer(a, l);
+ break;
+
+ default:
+ log_debug("unknown data type '%i'", vbhdr.type);
+ ret = AGENTX_ERR_PARSE_ERROR;
goto done;
+ }
+
+ /* AgentX types correspond to BER types */
+ switch (vbhdr.type) {
+ case BER_TYPE_INTEGER:
+ case BER_TYPE_BITSTRING:
+ case BER_TYPE_OCTETSTRING:
+ case BER_TYPE_NULL:
+ case BER_TYPE_OBJECT:
+ /* universal types */
+ break;
+ default:
+ /* application-specific types */
+ ber_set_header(a, BER_CLASS_APPLICATION, vbhdr.type);
+ break;
+ }
}
if (varbind != NULL)
len = ber_calc_len(varbind);
- log_debug("trap_imsg: from pid %u len %d elements %d",
+ log_debug("trap_agentx: from pid %u len %d elements %d",
pid, len, x);
+
trap_send(&o, varbind);
- return (0);
- imsgdone:
- imsg_free(&imsg);
+ *varcpy = v;
+ *vcpylen = pdu->hdr->length;
+
+ return (AGENTX_ERR_NONE);
done:
if (varbind != NULL)
ber_free_elements(varbind);
+ if (v)
+ free(v);
+ *idx = x;
return (ret);
}
@@ -210,7 +226,7 @@ trap_send(struct ber_oid *oid, struct ber_element *elm)
u_int8_t *ptr;
struct ber_oid uptime = OID(MIB_sysUpTime);
struct ber_oid trapoid = OID(MIB_snmpTrapOID);
- char ostr[SNMP_MAX_OID_LEN];
+ char ostr[SNMP_MAX_OID_STRLEN];
struct oid oa, ob;
if (TAILQ_EMPTY(&env->sc_trapreceivers))
@@ -270,7 +286,6 @@ trap_send(struct ber_oid *oid, struct ber_element *elm)
#ifdef DEBUG
smi_debug_elements(root);
#endif
-
len = ber_write_elements(&ber, root);
if (ber_get_writebuf(&ber, (void *)&ptr) > 0 &&
sendto(s, ptr, len, 0, (struct sockaddr *)&tr->ss,