From 16365c5352f777d8ea56614d7100d0edd48c6d72 Mon Sep 17 00:00:00 2001 From: martijn Date: Sat, 4 Nov 2023 09:22:52 +0000 Subject: [PATCH] Introduce application_internal.c. This backend is meant to replace application_legacy.c, mps.c, and mib.c. This commit just introduces the backend. The existing MIBs inside mib.c will be copied over in subsequent commits. OK tb@ --- usr.sbin/snmpd/Makefile | 4 +- usr.sbin/snmpd/application.c | 4 +- usr.sbin/snmpd/application.h | 6 +- usr.sbin/snmpd/application_internal.c | 271 ++++++++++++++++++++++++++ usr.sbin/snmpd/snmpd.h | 5 +- 5 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 usr.sbin/snmpd/application_internal.c diff --git a/usr.sbin/snmpd/Makefile b/usr.sbin/snmpd/Makefile index 261e89b62c2..26f2ff8aeb6 100644 --- a/usr.sbin/snmpd/Makefile +++ b/usr.sbin/snmpd/Makefile @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile,v 1.22 2022/10/25 10:46:59 martijn Exp $ +# $OpenBSD: Makefile,v 1.23 2023/11/04 09:22:52 martijn Exp $ PROG= snmpd MAN= snmpd.8 snmpd.conf.5 SRCS= parse.y log.c snmpe.c application.c application_legacy.c \ - application_blocklist.c \ + application_blocklist.c application_internal.c \ application_agentx.c ax.c \ mps.c trap.c mib.c smi.c snmpd.c \ proc.c usm.c traphandler.c util.c diff --git a/usr.sbin/snmpd/application.c b/usr.sbin/snmpd/application.c index c36f059345f..2663c9ed55e 100644 --- a/usr.sbin/snmpd/application.c +++ b/usr.sbin/snmpd/application.c @@ -1,4 +1,4 @@ -/* $OpenBSD: application.c,v 1.27 2023/10/29 11:20:06 martijn Exp $ */ +/* $OpenBSD: application.c,v 1.28 2023/11/04 09:22:52 martijn Exp $ */ /* * Copyright (c) 2021 Martijn van Duren @@ -159,6 +159,7 @@ void appl_init(void) { appl_blocklist_init(); + appl_internal_init(); appl_legacy_init(); appl_agentx_init(); } @@ -169,6 +170,7 @@ appl_shutdown(void) struct appl_context *ctx, *tctx; appl_blocklist_shutdown(); + appl_internal_shutdown(); appl_legacy_shutdown(); appl_agentx_shutdown(); diff --git a/usr.sbin/snmpd/application.h b/usr.sbin/snmpd/application.h index 39e7b5fc410..6e638e2c988 100644 --- a/usr.sbin/snmpd/application.h +++ b/usr.sbin/snmpd/application.h @@ -1,4 +1,4 @@ -/* $OpenBSD: application.h,v 1.6 2023/10/24 13:28:11 martijn Exp $ */ +/* $OpenBSD: application.h,v 1.7 2023/11/04 09:22:52 martijn Exp $ */ /* * Copyright (c) 2021 Martijn van Duren @@ -147,3 +147,7 @@ void appl_agentx_backend(int); /* application_blocklist.c */ void appl_blocklist_init(void); void appl_blocklist_shutdown(void); + +/* application_internal.c */ +void appl_internal_init(void); +void appl_internal_shutdown(void); diff --git a/usr.sbin/snmpd/application_internal.c b/usr.sbin/snmpd/application_internal.c new file mode 100644 index 00000000000..5d2cdb1edb1 --- /dev/null +++ b/usr.sbin/snmpd/application_internal.c @@ -0,0 +1,271 @@ +/* $OpenBSD: application_internal.c,v 1.1 2023/11/04 09:22:52 martijn Exp $ */ + +/* + * Copyright (c) 2023 Martijn van Duren + * + * 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 + +#include +#include + +#include "application.h" +#include "log.h" +#include "mib.h" +#include "smi.h" +#include "snmpd.h" + +struct appl_internal_object { + struct ber_oid oid; + struct ber_element * (*get)(struct ber_oid *); + /* No getnext means the object is scalar */ + struct ber_element * (*getnext)(int8_t, struct ber_oid *); + + RB_ENTRY(appl_internal_object) entry; +}; + +void appl_internal_region(struct ber_oid *); +void appl_internal_object(struct ber_oid *, + struct ber_element *(*)(struct ber_oid *), + struct ber_element *(*)(int8_t, struct ber_oid *)); +void appl_internal_get(struct appl_backend *, int32_t, int32_t, const char *, + struct appl_varbind *); +void appl_internal_getnext(struct appl_backend *, int32_t, int32_t, + const char *, struct appl_varbind *); +struct appl_internal_object *appl_internal_object_parent(struct ber_oid *); +int appl_internal_object_cmp(struct appl_internal_object *, + struct appl_internal_object *); + +struct appl_backend_functions appl_internal_functions = { + .ab_get = appl_internal_get, + .ab_getnext = appl_internal_getnext, + .ab_getbulk = NULL, /* getbulk is too complex */ +}; + +struct appl_backend appl_internal = { + .ab_name = "internal", + .ab_cookie = NULL, + .ab_retries = 0, + .ab_range = 1, + .ab_fn = &appl_internal_functions +}; + +static RB_HEAD(appl_internal_objects, appl_internal_object) + appl_internal_objects = RB_INITIALIZER(&appl_internal_objects); +RB_PROTOTYPE_STATIC(appl_internal_objects, appl_internal_object, entry, + appl_internal_object_cmp); + +void +appl_internal_init(void) +{ +} + +void +appl_internal_shutdown(void) +{ + struct appl_internal_object *object; + + while ((object = RB_ROOT(&appl_internal_objects)) != NULL) { + RB_REMOVE(appl_internal_objects, &appl_internal_objects, + object); + free(object); + } + + appl_close(&appl_internal); +} + +void +appl_internal_region(struct ber_oid *oid) +{ + enum appl_error error; + char oidbuf[1024]; + + error = appl_register(NULL, 150, 1, oid, 0, 1, 0, 0, &appl_internal); + /* + * Ignore requestDenied, duplicateRegistration, and unsupportedContext + */ + if (error == APPL_ERROR_PROCESSINGERROR || + error == APPL_ERROR_PARSEERROR) { + smi_oid2string(oid, oidbuf, sizeof(oidbuf), 0); + fatalx("internal: Failed to register %s", oidbuf); + } +} + +void +appl_internal_object(struct ber_oid *oid, + struct ber_element *(*get)(struct ber_oid *), + struct ber_element *(*getnext)(int8_t, struct ber_oid *)) +{ + struct appl_internal_object *obj; + + if ((obj = calloc(1, sizeof(*obj))) == NULL) + fatal(NULL); + obj->oid = *oid; + obj->get = get; + obj->getnext = getnext; + + RB_INSERT(appl_internal_objects, &appl_internal_objects, obj); +} + +void +appl_internal_get(struct appl_backend *backend, __unused int32_t transactionid, + int32_t requestid, __unused const char *ctx, struct appl_varbind *vblist) +{ + struct ber_oid oid; + struct appl_internal_object *object; + struct appl_varbind *vb, *resp; + size_t i; + int r; + + for (i = 0, vb = vblist; vb != NULL; vb = vb->av_next, i++) + continue; + + if ((resp = calloc(i, sizeof(*resp))) == NULL) { + log_warn("%s", backend->ab_name); + appl_response(backend, requestid, APPL_ERROR_GENERR, 1, vblist); + return; + } + + for (i = 0, vb = vblist; vb != NULL; vb = vb->av_next, i++) { + resp[i].av_oid = vb->av_oid; + if ((object = appl_internal_object_parent(&vb->av_oid)) == NULL) + resp[i].av_value = + appl_exception(APPL_EXC_NOSUCHOBJECT); + else { + oid = object->oid; + /* Add 0 element for scalar */ + if (object->getnext == NULL) + oid.bo_id[oid.bo_n++] = 0; + r = ober_oid_cmp(&vb->av_oid, &oid); + if ((r == 0 && object->getnext == NULL) || + (r == 2 && object->getnext != NULL)) + resp[i].av_value = object->get(&resp[i].av_oid); + else + resp[i].av_value = + appl_exception(APPL_EXC_NOSUCHINSTANCE); + } + if (resp[i].av_value == NULL) { + log_warnx("%s: Failed to get value", backend->ab_name); + goto fail; + } + resp[i].av_next = &resp[i + 1]; + } + resp[i - 1].av_next = NULL; + + appl_response(backend, requestid, APPL_ERROR_NOERROR, 0, resp); + return; + + fail: + for (vb = resp; vb != NULL; vb = vb->av_next) + ober_free_elements(vb->av_value); + free(resp); + appl_response(backend, requestid, APPL_ERROR_GENERR, i + 1, vblist); +} + +void +appl_internal_getnext(struct appl_backend *backend, + __unused int32_t transactionid, int32_t requestid, __unused const char *ctx, + struct appl_varbind *vblist) +{ + struct ber_oid oid; + struct appl_internal_object *object, search; + struct appl_varbind *vb, *resp; + size_t i; + int r; + int8_t include; + + for (i = 0, vb = vblist; vb != NULL; vb = vb->av_next, i++) + continue; + + if ((resp = calloc(i, sizeof(*resp))) == NULL) { + log_warn("%s", backend->ab_name); + appl_response(backend, requestid, APPL_ERROR_GENERR, 1, vblist); + return; + } + + for (i = 0, vb = vblist; vb != NULL; vb = vb->av_next, i++) { + resp[i].av_oid = vb->av_oid; + object = appl_internal_object_parent(&vb->av_oid); + if (object == NULL) { + search.oid = vb->av_oid; + object = RB_NFIND(appl_internal_objects, + &appl_internal_objects, &search); + } + + include = vb->av_include; + for (; object != NULL; object = RB_NEXT(appl_internal_objects, + &appl_internal_objects, object), include = 1) { + if (object->getnext == NULL) { + oid = object->oid; + oid.bo_id[oid.bo_n++] = 0; + r = ober_oid_cmp(&resp[i].av_oid, &oid); + if (r > 0 || (r == 0 && !include)) + continue; + resp[i].av_oid = oid; + resp[i].av_value = object->get(&oid); + break; + } + /* non-scalar */ + fatalx("%s: not implemented", backend->ab_name); + } + if (ober_oid_cmp(&resp[i].av_oid, &vb->av_oid_end) >= 0 || + object == NULL) { + resp[i].av_oid = vb->av_oid; + ober_free_elements(resp[i].av_value); + resp[i].av_value = + appl_exception(APPL_EXC_ENDOFMIBVIEW); + } + if (resp[i].av_value == NULL) { + log_warnx("%s: Failed to get value", backend->ab_name); + goto fail; + } + resp[i].av_next = &resp[i + 1]; + } + resp[i - 1].av_next = NULL; + + appl_response(backend, requestid, APPL_ERROR_NOERROR, 0, resp); + return; + + fail: + for (vb = resp; vb != NULL; vb = vb->av_next) + ober_free_elements(vb->av_value); + free(resp); + appl_response(backend, requestid, APPL_ERROR_GENERR, i + 1, vblist); +} + +struct appl_internal_object * +appl_internal_object_parent(struct ber_oid *oid) +{ + struct appl_internal_object *object, search; + + search.oid = *oid; + do { + if ((object = RB_FIND(appl_internal_objects, + &appl_internal_objects, &search)) != NULL) + return object; + } while (--search.oid.bo_n > 0); + + return NULL; +} + +int +appl_internal_object_cmp(struct appl_internal_object *o1, + struct appl_internal_object *o2) +{ + return ober_oid_cmp(&o1->oid, &o2->oid); +} + +RB_GENERATE_STATIC(appl_internal_objects, appl_internal_object, entry, + appl_internal_object_cmp); diff --git a/usr.sbin/snmpd/snmpd.h b/usr.sbin/snmpd/snmpd.h index 7abeeea0adf..3c46a451b1e 100644 --- a/usr.sbin/snmpd/snmpd.h +++ b/usr.sbin/snmpd/snmpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: snmpd.h,v 1.106 2022/10/06 14:41:08 martijn Exp $ */ +/* $OpenBSD: snmpd.h,v 1.107 2023/11/04 09:22:52 martijn Exp $ */ /* * Copyright (c) 2007, 2008, 2012 Reyk Floeter @@ -215,7 +215,8 @@ struct oid { (((_oid)->o_flags & OID_IFSET) && \ ((_oid)->o_data == NULL) && ((_oid)->o_val == 0)) -#define OID(...) { { __VA_ARGS__ } } +#define OID(...) (struct ber_oid){ { __VA_ARGS__ }, \ + (sizeof((uint32_t []) { __VA_ARGS__ }) / sizeof(uint32_t)) } #define MIBDECL(...) { { MIB_##__VA_ARGS__ } }, #__VA_ARGS__ #define MIB(...) { { MIB_##__VA_ARGS__ } }, NULL #define MIBEND { { 0 } }, NULL -- 2.20.1