1*c3e23a03Smartijn /* $OpenBSD: application.c,v 1.43 2024/02/08 17:34:09 martijn Exp $ */
27f594a49Smartijn
37f594a49Smartijn /*
47f594a49Smartijn * Copyright (c) 2021 Martijn van Duren <martijn@openbsd.org>
57f594a49Smartijn *
67f594a49Smartijn * Permission to use, copy, modify, and distribute this software for any
77f594a49Smartijn * purpose with or without fee is hereby granted, provided that the above
87f594a49Smartijn * copyright notice and this permission notice appear in all copies.
97f594a49Smartijn *
107f594a49Smartijn * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
117f594a49Smartijn * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
127f594a49Smartijn * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
137f594a49Smartijn * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
147f594a49Smartijn * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
157f594a49Smartijn * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
167f594a49Smartijn * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177f594a49Smartijn */
187f594a49Smartijn
197f594a49Smartijn #include <sys/queue.h>
20a9292d2aSmartijn #include <sys/time.h>
217f594a49Smartijn #include <sys/tree.h>
22a9292d2aSmartijn #include <sys/types.h>
237f594a49Smartijn
247f594a49Smartijn #include <assert.h>
257f594a49Smartijn #include <errno.h>
267f594a49Smartijn #include <event.h>
277f594a49Smartijn #include <inttypes.h>
287f594a49Smartijn #include <stdlib.h>
297f594a49Smartijn #include <stdio.h>
307f594a49Smartijn #include <string.h>
317f594a49Smartijn
327f594a49Smartijn #include "application.h"
337f594a49Smartijn #include "log.h"
34f0bcdb5cSmartijn #include "mib.h"
357f594a49Smartijn #include "smi.h"
367f594a49Smartijn #include "snmp.h"
37f0bcdb5cSmartijn #include "snmpd.h"
387f594a49Smartijn #include "snmpe.h"
397f594a49Smartijn
40215fd4bcSmartijn #define OID(...) (struct ber_oid){ { __VA_ARGS__ }, \
41215fd4bcSmartijn (sizeof((uint32_t []) { __VA_ARGS__ }) / sizeof(uint32_t)) }
42215fd4bcSmartijn
437f594a49Smartijn TAILQ_HEAD(, appl_context) contexts = TAILQ_HEAD_INITIALIZER(contexts);
447f594a49Smartijn
452993c1b4Smartijn struct appl_agentcap {
462993c1b4Smartijn struct appl_backend *aa_backend;
472993c1b4Smartijn struct appl_context *aa_context;
482993c1b4Smartijn uint32_t aa_index;
492993c1b4Smartijn struct ber_oid aa_oid;
502993c1b4Smartijn char aa_descr[256];
512993c1b4Smartijn int aa_uptime;
522993c1b4Smartijn
532993c1b4Smartijn TAILQ_ENTRY(appl_agentcap) aa_entry;
542993c1b4Smartijn };
552993c1b4Smartijn
567f594a49Smartijn struct appl_context {
577f594a49Smartijn char ac_name[APPL_CONTEXTNAME_MAX + 1];
587f594a49Smartijn
597f594a49Smartijn RB_HEAD(appl_regions, appl_region) ac_regions;
602993c1b4Smartijn TAILQ_HEAD(, appl_agentcap) ac_agentcaps;
612993c1b4Smartijn int ac_agentcap_lastid;
622993c1b4Smartijn int ac_agentcap_lastchange;
637f594a49Smartijn
647f594a49Smartijn TAILQ_ENTRY(appl_context) ac_entries;
657f594a49Smartijn };
667f594a49Smartijn
677f594a49Smartijn struct appl_region {
687f594a49Smartijn struct ber_oid ar_oid;
697f594a49Smartijn uint8_t ar_priority;
707f594a49Smartijn int32_t ar_timeout;
717f594a49Smartijn int ar_instance;
727f594a49Smartijn int ar_subtree; /* Claim entire subtree */
737f594a49Smartijn struct appl_backend *ar_backend;
747f594a49Smartijn struct appl_region *ar_next; /* Sorted by priority */
757f594a49Smartijn
767f594a49Smartijn RB_ENTRY(appl_region) ar_entry;
777f594a49Smartijn };
787f594a49Smartijn
797f594a49Smartijn struct appl_request_upstream {
807f594a49Smartijn struct appl_context *aru_ctx;
817f594a49Smartijn struct snmp_message *aru_statereference;
82e40a541eSmartijn enum snmp_pdutype aru_requesttype;
83b12d45ecSmartijn enum snmp_pdutype aru_responsetype;
847f594a49Smartijn int32_t aru_requestid; /* upstream requestid */
857f594a49Smartijn int32_t aru_transactionid; /* RFC 2741 section 6.1 */
86a0e7c950Smartijn uint16_t aru_nonrepeaters;
87a0e7c950Smartijn uint16_t aru_maxrepetitions;
887f594a49Smartijn struct appl_varbind_internal *aru_vblist;
897f594a49Smartijn size_t aru_varbindlen;
907f594a49Smartijn enum appl_error aru_error;
917f594a49Smartijn int16_t aru_index;
927f594a49Smartijn int aru_locked; /* Prevent recursion through appl_request_send */
937f594a49Smartijn
947f594a49Smartijn enum snmp_version aru_pduversion;
957f594a49Smartijn };
967f594a49Smartijn
977f594a49Smartijn struct appl_request_downstream {
987f594a49Smartijn struct appl_request_upstream *ard_request;
997f594a49Smartijn struct appl_backend *ard_backend;
1007f594a49Smartijn enum snmp_pdutype ard_requesttype;
101a0e7c950Smartijn uint16_t ard_nonrepeaters;
102a0e7c950Smartijn uint16_t ard_maxrepetitions;
1037f594a49Smartijn int32_t ard_requestid;
1047f594a49Smartijn uint8_t ard_retries;
1057f594a49Smartijn
1067f594a49Smartijn struct appl_varbind_internal *ard_vblist;
1077f594a49Smartijn struct event ard_timer;
1087f594a49Smartijn
1097f594a49Smartijn RB_ENTRY(appl_request_downstream) ard_entry;
1107f594a49Smartijn };
1117f594a49Smartijn
1127f594a49Smartijn enum appl_varbind_state {
1137f594a49Smartijn APPL_VBSTATE_MUSTFILL,
1147f594a49Smartijn APPL_VBSTATE_NEW,
1157f594a49Smartijn APPL_VBSTATE_PENDING,
1167f594a49Smartijn APPL_VBSTATE_DONE
1177f594a49Smartijn };
1187f594a49Smartijn
1197f594a49Smartijn struct appl_varbind_internal {
1207f594a49Smartijn enum appl_varbind_state avi_state;
1217f594a49Smartijn struct appl_varbind avi_varbind;
1227f594a49Smartijn struct appl_region *avi_region;
1232f3602daSmartijn struct ber_oid avi_origid;
1247f594a49Smartijn int16_t avi_index;
1257f594a49Smartijn struct appl_request_upstream *avi_request_upstream;
1267f594a49Smartijn struct appl_request_downstream *avi_request_downstream;
1277f594a49Smartijn struct appl_varbind_internal *avi_next;
1287f594a49Smartijn struct appl_varbind_internal *avi_sub;
1297f594a49Smartijn };
1307f594a49Smartijn
1317f594a49Smartijn /* SNMP-TARGET-MIB (RFC 3413) */
1327f594a49Smartijn struct snmp_target_mib {
1337f594a49Smartijn uint32_t snmp_unavailablecontexts;
1347f594a49Smartijn uint32_t snmp_unknowncontexts;
1357f594a49Smartijn } snmp_target_mib;
1367f594a49Smartijn
1372993c1b4Smartijn void appl_agentcap_free(struct appl_agentcap *);
1387f594a49Smartijn enum appl_error appl_region(struct appl_context *, uint32_t, uint8_t,
139f0bcdb5cSmartijn struct ber_oid *, uint8_t, int, int, struct appl_backend *);
1407f594a49Smartijn void appl_region_free(struct appl_context *, struct appl_region *);
1411e1ddca6Smartijn enum appl_error appl_region_unregister_match(struct appl_context *, uint8_t,
1421e1ddca6Smartijn struct ber_oid *, char *, struct appl_backend *, int);
1437f594a49Smartijn struct appl_region *appl_region_find(struct appl_context *,
1447f594a49Smartijn const struct ber_oid *);
1457f594a49Smartijn struct appl_region *appl_region_next(struct appl_context *,
1467f594a49Smartijn struct ber_oid *, struct appl_region *);
1477f594a49Smartijn void appl_request_upstream_free(struct appl_request_upstream *);
1487f594a49Smartijn void appl_request_downstream_free(struct appl_request_downstream *);
1497f594a49Smartijn void appl_request_upstream_resolve(struct appl_request_upstream *);
1507f594a49Smartijn void appl_request_downstream_send(struct appl_request_downstream *);
1517f594a49Smartijn void appl_request_downstream_timeout(int, short, void *);
1527f594a49Smartijn void appl_request_upstream_reply(struct appl_request_upstream *);
15316d26808Smartijn int appl_varbind_valid(struct appl_varbind *, struct appl_varbind_internal *,
15416d26808Smartijn int, int, int, const char **);
155c1fbd6d4Smartijn int appl_error_valid(enum appl_error, enum snmp_pdutype);
156*c3e23a03Smartijn unsigned int appl_ber_any(struct ber_element *);
1577f594a49Smartijn int appl_varbind_backend(struct appl_varbind_internal *);
1587f594a49Smartijn void appl_varbind_error(struct appl_varbind_internal *, enum appl_error);
1597f594a49Smartijn void appl_pdu_log(struct appl_backend *, enum snmp_pdutype, int32_t, uint16_t,
1607f594a49Smartijn uint16_t, struct appl_varbind *);
1617f594a49Smartijn void ober_oid_nextsibling(struct ber_oid *);
1627f594a49Smartijn
1637f594a49Smartijn int appl_region_cmp(struct appl_region *, struct appl_region *);
1647f594a49Smartijn int appl_request_cmp(struct appl_request_downstream *,
1657f594a49Smartijn struct appl_request_downstream *);
1667f594a49Smartijn
1677f594a49Smartijn RB_PROTOTYPE_STATIC(appl_regions, appl_region, ar_entry, appl_region_cmp);
1687f594a49Smartijn RB_PROTOTYPE_STATIC(appl_requests, appl_request_downstream, ard_entry,
1697f594a49Smartijn appl_request_cmp);
1707f594a49Smartijn
1717f594a49Smartijn #define APPL_CONTEXT_NAME(ctx) (ctx->ac_name[0] == '\0' ? NULL : ctx->ac_name)
1727f594a49Smartijn
1737f594a49Smartijn void
appl(void)1744100cc5fSmartijn appl(void)
1754100cc5fSmartijn {
1764100cc5fSmartijn appl_agentx();
1774100cc5fSmartijn }
1784100cc5fSmartijn
1794100cc5fSmartijn void
appl_init(void)1807f594a49Smartijn appl_init(void)
1817f594a49Smartijn {
182614c3698Smartijn appl_blocklist_init();
18316365c53Smartijn appl_internal_init();
1844100cc5fSmartijn appl_agentx_init();
1857f594a49Smartijn }
1867f594a49Smartijn
1877f594a49Smartijn void
appl_shutdown(void)1887f594a49Smartijn appl_shutdown(void)
1897f594a49Smartijn {
1907f594a49Smartijn struct appl_context *ctx, *tctx;
1917f594a49Smartijn
192614c3698Smartijn appl_blocklist_shutdown();
19316365c53Smartijn appl_internal_shutdown();
1944100cc5fSmartijn appl_agentx_shutdown();
1957f594a49Smartijn
1967f594a49Smartijn TAILQ_FOREACH_SAFE(ctx, &contexts, ac_entries, tctx) {
1977f594a49Smartijn assert(RB_EMPTY(&(ctx->ac_regions)));
1982993c1b4Smartijn assert(TAILQ_EMPTY(&(ctx->ac_agentcaps)));
1997f594a49Smartijn TAILQ_REMOVE(&contexts, ctx, ac_entries);
2007f594a49Smartijn free(ctx);
2017f594a49Smartijn }
2027f594a49Smartijn }
2037f594a49Smartijn
204253352b6Smartijn struct appl_context *
appl_context(const char * name,int create)2057f594a49Smartijn appl_context(const char *name, int create)
2067f594a49Smartijn {
2077f594a49Smartijn struct appl_context *ctx;
2087f594a49Smartijn
2097f594a49Smartijn if (name == NULL)
2107f594a49Smartijn name = "";
2117f594a49Smartijn
2127f594a49Smartijn if (strlen(name) > APPL_CONTEXTNAME_MAX) {
2137f594a49Smartijn errno = EINVAL;
2147f594a49Smartijn return NULL;
2157f594a49Smartijn }
2167f594a49Smartijn
2177f594a49Smartijn TAILQ_FOREACH(ctx, &contexts, ac_entries) {
2187f594a49Smartijn if (strcmp(name, ctx->ac_name) == 0)
2197f594a49Smartijn return ctx;
2207f594a49Smartijn }
2217f594a49Smartijn
2227f594a49Smartijn /* Always allow the default namespace */
2237f594a49Smartijn if (!create && name[0] != '\0') {
2247f594a49Smartijn errno = ENOENT;
2257f594a49Smartijn return NULL;
2267f594a49Smartijn }
2277f594a49Smartijn
2287f594a49Smartijn if ((ctx = malloc(sizeof(*ctx))) == NULL)
2297f594a49Smartijn return NULL;
2307f594a49Smartijn
2317f594a49Smartijn strlcpy(ctx->ac_name, name, sizeof(ctx->ac_name));
2327f594a49Smartijn RB_INIT(&(ctx->ac_regions));
2332993c1b4Smartijn TAILQ_INIT(&(ctx->ac_agentcaps));
2342993c1b4Smartijn ctx->ac_agentcap_lastid = 0;
2352993c1b4Smartijn ctx->ac_agentcap_lastchange = 0;
2367f594a49Smartijn
2377f594a49Smartijn TAILQ_INSERT_TAIL(&contexts, ctx, ac_entries);
2387f594a49Smartijn return ctx;
2397f594a49Smartijn }
2407f594a49Smartijn
2412993c1b4Smartijn /* Name from RFC 2741 section 6.2.14 */
2422993c1b4Smartijn enum appl_error
appl_addagentcaps(const char * ctxname,struct ber_oid * oid,const char * descr,struct appl_backend * backend)2432993c1b4Smartijn appl_addagentcaps(const char *ctxname, struct ber_oid *oid, const char *descr,
2442993c1b4Smartijn struct appl_backend *backend)
2452993c1b4Smartijn {
2462993c1b4Smartijn struct appl_context *ctx;
2472993c1b4Smartijn struct appl_agentcap *cap;
2482993c1b4Smartijn char oidbuf[1024];
2492993c1b4Smartijn
2502993c1b4Smartijn if (ctxname == NULL)
2512993c1b4Smartijn ctxname = "";
2522993c1b4Smartijn
253f0bcdb5cSmartijn mib_oid2string(oid, oidbuf, sizeof(oidbuf), snmpd_env->sc_oidfmt);
2542993c1b4Smartijn log_info("%s: Adding agent capabilities %s context(%s)",
2552993c1b4Smartijn backend->ab_name, oidbuf, ctxname);
2562993c1b4Smartijn
2572993c1b4Smartijn if ((ctx = appl_context(ctxname, 0)) == NULL) {
2582993c1b4Smartijn log_info("%s: Can't add agent capabilities %s: "
2592993c1b4Smartijn "Unsupported context \"%s\"", backend->ab_name, oidbuf,
2602993c1b4Smartijn ctxname);
2612993c1b4Smartijn return APPL_ERROR_UNSUPPORTEDCONTEXT;
2622993c1b4Smartijn }
2632993c1b4Smartijn
264dede7ac8Smartijn if ((cap = malloc(sizeof(*cap))) == NULL) {
2652993c1b4Smartijn log_warn("%s: Can't add agent capabilities %s",
2662993c1b4Smartijn backend->ab_name, oidbuf);
2672993c1b4Smartijn return APPL_ERROR_PROCESSINGERROR;
2682993c1b4Smartijn }
2692993c1b4Smartijn
2702993c1b4Smartijn cap->aa_backend = backend;
2712993c1b4Smartijn cap->aa_context = ctx;
2722993c1b4Smartijn cap->aa_index = ++ctx->ac_agentcap_lastid;
2732993c1b4Smartijn cap->aa_oid = *oid;
2742993c1b4Smartijn cap->aa_uptime = smi_getticks();
2752993c1b4Smartijn if (strlcpy(cap->aa_descr, descr,
2762993c1b4Smartijn sizeof(cap->aa_descr)) >= sizeof(cap->aa_descr)) {
2772993c1b4Smartijn log_info("%s: Can't add agent capabilities %s: "
2782993c1b4Smartijn "Invalid description", backend->ab_name, oidbuf);
2792993c1b4Smartijn free(cap);
2802993c1b4Smartijn return APPL_ERROR_PARSEERROR;
2812993c1b4Smartijn }
2822993c1b4Smartijn
2832993c1b4Smartijn TAILQ_INSERT_TAIL(&(ctx->ac_agentcaps), cap, aa_entry);
2842993c1b4Smartijn ctx->ac_agentcap_lastchange = cap->aa_uptime;
2852993c1b4Smartijn
2862993c1b4Smartijn return APPL_ERROR_NOERROR;
2872993c1b4Smartijn }
2882993c1b4Smartijn
2892993c1b4Smartijn /* Name from RFC2741 section 6.2.15 */
2902993c1b4Smartijn enum appl_error
appl_removeagentcaps(const char * ctxname,struct ber_oid * oid,struct appl_backend * backend)2912993c1b4Smartijn appl_removeagentcaps(const char *ctxname, struct ber_oid *oid,
2922993c1b4Smartijn struct appl_backend *backend)
2932993c1b4Smartijn {
2942993c1b4Smartijn struct appl_context *ctx;
2952993c1b4Smartijn struct appl_agentcap *cap, *tmp;
2962993c1b4Smartijn char oidbuf[1024];
2972993c1b4Smartijn int found = 0;
2982993c1b4Smartijn
2992993c1b4Smartijn if (ctxname == NULL)
3002993c1b4Smartijn ctxname = "";
3012993c1b4Smartijn
302f0bcdb5cSmartijn mib_oid2string(oid, oidbuf, sizeof(oidbuf), snmpd_env->sc_oidfmt);
3032993c1b4Smartijn log_info("%s: Removing agent capabilities %s context(%s)",
3042993c1b4Smartijn backend->ab_name, oidbuf, ctxname);
3052993c1b4Smartijn
3062993c1b4Smartijn if ((ctx = appl_context(ctxname, 0)) == NULL) {
3072993c1b4Smartijn log_info("%s: Can't remove agent capabilities %s: "
3082993c1b4Smartijn "Unsupported context \"%s\"", backend->ab_name, oidbuf,
3092993c1b4Smartijn ctxname);
3102993c1b4Smartijn return APPL_ERROR_UNSUPPORTEDCONTEXT;
3112993c1b4Smartijn }
3122993c1b4Smartijn
3132993c1b4Smartijn TAILQ_FOREACH_SAFE(cap, &(ctx->ac_agentcaps), aa_entry, tmp) {
3142993c1b4Smartijn /* No duplicate oid check, just continue */
3152993c1b4Smartijn if (cap->aa_backend != backend ||
3162993c1b4Smartijn ober_oid_cmp(oid, &(cap->aa_oid)) != 0)
3172993c1b4Smartijn continue;
3182993c1b4Smartijn found = 1;
3192993c1b4Smartijn appl_agentcap_free(cap);
3202993c1b4Smartijn }
3212993c1b4Smartijn
3222993c1b4Smartijn if (found)
3232993c1b4Smartijn return APPL_ERROR_NOERROR;
3242993c1b4Smartijn
3252993c1b4Smartijn log_info("%s: Can't remove agent capabilities %s: not found",
3262993c1b4Smartijn backend->ab_name, oidbuf);
3272993c1b4Smartijn return APPL_ERROR_UNKNOWNAGENTCAPS;
3282993c1b4Smartijn }
3292993c1b4Smartijn
3302993c1b4Smartijn void
appl_agentcap_free(struct appl_agentcap * cap)3312993c1b4Smartijn appl_agentcap_free(struct appl_agentcap *cap)
3322993c1b4Smartijn {
3332993c1b4Smartijn TAILQ_REMOVE(&(cap->aa_context->ac_agentcaps), cap, aa_entry);
3342993c1b4Smartijn cap->aa_context->ac_agentcap_lastchange = smi_getticks();
3352993c1b4Smartijn free(cap);
3362993c1b4Smartijn }
3372993c1b4Smartijn
338215fd4bcSmartijn struct ber_element *
appl_sysorlastchange(struct ber_oid * oid)339215fd4bcSmartijn appl_sysorlastchange(struct ber_oid *oid)
340215fd4bcSmartijn {
341215fd4bcSmartijn struct appl_context *ctx;
342215fd4bcSmartijn struct ber_element *value;
343215fd4bcSmartijn
344215fd4bcSmartijn ctx = appl_context(NULL, 0);
345215fd4bcSmartijn value = ober_add_integer(NULL, ctx->ac_agentcap_lastchange);
346215fd4bcSmartijn if (value != NULL)
347215fd4bcSmartijn ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
348215fd4bcSmartijn else
349215fd4bcSmartijn log_warn("ober_add_integer");
350215fd4bcSmartijn
351215fd4bcSmartijn return value;
352215fd4bcSmartijn }
353215fd4bcSmartijn
354215fd4bcSmartijn #define SYSORIDX_POS 10
355215fd4bcSmartijn struct ber_element *
appl_sysortable(struct ber_oid * oid)356215fd4bcSmartijn appl_sysortable(struct ber_oid *oid)
357215fd4bcSmartijn {
358215fd4bcSmartijn struct appl_context *ctx;
359215fd4bcSmartijn struct appl_agentcap *cap;
360215fd4bcSmartijn struct ber_element *value = NULL;
361215fd4bcSmartijn
362215fd4bcSmartijn if (oid->bo_n != SYSORIDX_POS + 1)
363215fd4bcSmartijn goto notfound;
364215fd4bcSmartijn
365215fd4bcSmartijn ctx = appl_context(NULL, 0);
366215fd4bcSmartijn TAILQ_FOREACH(cap, &(ctx->ac_agentcaps), aa_entry) {
367215fd4bcSmartijn if (cap->aa_index == oid->bo_id[SYSORIDX_POS])
368215fd4bcSmartijn break;
369215fd4bcSmartijn }
370215fd4bcSmartijn if (cap == NULL)
371215fd4bcSmartijn goto notfound;
372215fd4bcSmartijn
373215fd4bcSmartijn if (ober_oid_cmp(&OID(MIB_sysORID), oid) == -2)
374215fd4bcSmartijn value = ober_add_oid(NULL, &(cap->aa_oid));
375215fd4bcSmartijn else if (ober_oid_cmp(&OID(MIB_sysORDescr), oid) == -2)
376215fd4bcSmartijn value = ober_add_string(NULL, cap->aa_descr);
377215fd4bcSmartijn else if (ober_oid_cmp(&OID(MIB_sysORUpTime), oid) == -2) {
378215fd4bcSmartijn if ((value = ober_add_integer(NULL, cap->aa_uptime)) != NULL)
379215fd4bcSmartijn ober_set_header(value,
380215fd4bcSmartijn BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
381215fd4bcSmartijn }
382215fd4bcSmartijn if (value == NULL)
383215fd4bcSmartijn log_warn("ober_add_*");
384215fd4bcSmartijn return value;
385215fd4bcSmartijn
386215fd4bcSmartijn notfound:
387215fd4bcSmartijn if ((value = appl_exception(APPL_EXC_NOSUCHINSTANCE)) == NULL)
388215fd4bcSmartijn log_warn("appl_exception");
389215fd4bcSmartijn return value;
390215fd4bcSmartijn }
391215fd4bcSmartijn
392215fd4bcSmartijn struct ber_element *
appl_sysortable_getnext(int8_t include,struct ber_oid * oid)393215fd4bcSmartijn appl_sysortable_getnext(int8_t include, struct ber_oid *oid)
394215fd4bcSmartijn {
395215fd4bcSmartijn struct appl_context *ctx;
396215fd4bcSmartijn struct appl_agentcap *cap;
397215fd4bcSmartijn struct ber_element *value = NULL;
398215fd4bcSmartijn
399215fd4bcSmartijn if (oid->bo_n < SYSORIDX_POS + 1) {
400215fd4bcSmartijn include = 1;
401215fd4bcSmartijn oid->bo_id[SYSORIDX_POS] = 0;
402215fd4bcSmartijn } else if (oid->bo_n < SYSORIDX_POS + 1)
403215fd4bcSmartijn include = 0;
404215fd4bcSmartijn
405215fd4bcSmartijn ctx = appl_context(NULL, 0);
406215fd4bcSmartijn TAILQ_FOREACH(cap, &(ctx->ac_agentcaps), aa_entry) {
407215fd4bcSmartijn if (cap->aa_index > oid->bo_id[SYSORIDX_POS])
408215fd4bcSmartijn break;
409215fd4bcSmartijn if (cap->aa_index == oid->bo_id[SYSORIDX_POS] && include)
410215fd4bcSmartijn break;
411215fd4bcSmartijn }
412215fd4bcSmartijn if (cap == NULL) {
413215fd4bcSmartijn value = appl_exception(APPL_EXC_NOSUCHINSTANCE);
414215fd4bcSmartijn goto done;
415215fd4bcSmartijn }
416215fd4bcSmartijn
417215fd4bcSmartijn oid->bo_id[SYSORIDX_POS] = cap->aa_index;
418215fd4bcSmartijn oid->bo_n = SYSORIDX_POS + 1;
419215fd4bcSmartijn
420215fd4bcSmartijn if (ober_oid_cmp(&OID(MIB_sysORID), oid) == -2)
421215fd4bcSmartijn value = ober_add_oid(NULL, &(cap->aa_oid));
422215fd4bcSmartijn else if (ober_oid_cmp(&OID(MIB_sysORDescr), oid) == -2)
423215fd4bcSmartijn value = ober_add_string(NULL, cap->aa_descr);
424215fd4bcSmartijn else if (ober_oid_cmp(&OID(MIB_sysORUpTime), oid) == -2) {
425215fd4bcSmartijn if ((value = ober_add_integer(NULL, cap->aa_uptime)) != NULL)
426215fd4bcSmartijn ober_set_header(value,
427215fd4bcSmartijn BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
428215fd4bcSmartijn }
429215fd4bcSmartijn done:
430215fd4bcSmartijn if (value == NULL)
431215fd4bcSmartijn log_warn("ober_add_*");
432215fd4bcSmartijn return value;
433215fd4bcSmartijn }
434215fd4bcSmartijn
43592d4cb1dSmartijn struct ber_element *
appl_targetmib(struct ber_oid * oid)43692d4cb1dSmartijn appl_targetmib(struct ber_oid *oid)
43792d4cb1dSmartijn {
43892d4cb1dSmartijn struct ber_element *value = NULL;
43992d4cb1dSmartijn
44092d4cb1dSmartijn if (ober_oid_cmp(oid, &OID(MIB_snmpUnavailableContexts, 0)) == 0)
44192d4cb1dSmartijn value = ober_add_integer(NULL,
44292d4cb1dSmartijn snmp_target_mib.snmp_unavailablecontexts);
44392d4cb1dSmartijn else if (ober_oid_cmp(oid, &OID(MIB_snmpUnknownContexts, 0)) == 0)
44492d4cb1dSmartijn value = ober_add_integer(NULL,
44592d4cb1dSmartijn snmp_target_mib.snmp_unknowncontexts);
44692d4cb1dSmartijn
44792d4cb1dSmartijn if (value != NULL)
44892d4cb1dSmartijn ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_COUNTER32);
44992d4cb1dSmartijn return value;
45092d4cb1dSmartijn }
45192d4cb1dSmartijn
4527f594a49Smartijn enum appl_error
appl_region(struct appl_context * ctx,uint32_t timeout,uint8_t priority,struct ber_oid * oid,uint8_t range_subid,int instance,int subtree,struct appl_backend * backend)4537f594a49Smartijn appl_region(struct appl_context *ctx, uint32_t timeout, uint8_t priority,
454f0bcdb5cSmartijn struct ber_oid *oid, uint8_t range_subid, int instance, int subtree,
4557f594a49Smartijn struct appl_backend *backend)
4567f594a49Smartijn {
457268af927Smartijn struct appl_region *region = NULL, *nregion;
4587f594a49Smartijn char oidbuf[1024], regionbuf[1024], subidbuf[11];
459f0bcdb5cSmartijn size_t i, bo_n;
4607f594a49Smartijn
461f0bcdb5cSmartijn bo_n = oid->bo_n;
462f0bcdb5cSmartijn if (range_subid != 0)
463f0bcdb5cSmartijn oid->bo_n = range_subid;
464f0bcdb5cSmartijn mib_oid2string(oid, oidbuf, sizeof(oidbuf), snmpd_env->sc_oidfmt);
465f0bcdb5cSmartijn if (range_subid != 0) {
466f0bcdb5cSmartijn oid->bo_n = bo_n;
467f0bcdb5cSmartijn i = range_subid + 1;
468f0bcdb5cSmartijn } else
469f0bcdb5cSmartijn i = oid->bo_n;
470f0bcdb5cSmartijn for (; i < oid->bo_n; i++) {
4710e097521Smartijn strlcat(oidbuf, ".", sizeof(oidbuf));
4720e097521Smartijn snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32,
4730e097521Smartijn oid->bo_id[i]);
4740e097521Smartijn strlcat(oidbuf, subidbuf, sizeof(oidbuf));
4750e097521Smartijn }
4760e097521Smartijn
4777f594a49Smartijn /*
4787f594a49Smartijn * Don't allow overlap when subtree flag is set.
4797f594a49Smartijn * This allows us to keep control of certain regions like system.
4807f594a49Smartijn */
4817f594a49Smartijn region = appl_region_find(ctx, oid);
4827515106cSmartijn if (region != NULL && region->ar_subtree &&
4837515106cSmartijn region->ar_backend != backend)
4847f594a49Smartijn goto overlap;
4857f594a49Smartijn
4867f594a49Smartijn if ((nregion = malloc(sizeof(*nregion))) == NULL) {
4877f594a49Smartijn log_warn("%s: Can't register %s: Processing error",
4887f594a49Smartijn backend->ab_name, oidbuf);
4897f594a49Smartijn return APPL_ERROR_PROCESSINGERROR;
4907f594a49Smartijn }
4917f594a49Smartijn nregion->ar_oid = *oid;
4927f594a49Smartijn nregion->ar_priority = priority;
4937f594a49Smartijn nregion->ar_timeout = timeout;
4947f594a49Smartijn nregion->ar_instance = instance;
4957f594a49Smartijn nregion->ar_subtree = subtree;
4967f594a49Smartijn nregion->ar_backend = backend;
4977f594a49Smartijn nregion->ar_next = NULL;
4987f594a49Smartijn
4997f594a49Smartijn region = RB_INSERT(appl_regions, &(ctx->ac_regions), nregion);
5007f594a49Smartijn if (region == NULL)
5017f594a49Smartijn return APPL_ERROR_NOERROR;
5027f594a49Smartijn
5037f594a49Smartijn if (region->ar_priority == priority)
5047f594a49Smartijn goto duplicate;
5057f594a49Smartijn if (region->ar_priority > priority) {
5067f594a49Smartijn RB_REMOVE(appl_regions, &(ctx->ac_regions), region);
5077f594a49Smartijn RB_INSERT(appl_regions, &(ctx->ac_regions), nregion);
5087f594a49Smartijn nregion->ar_next = region;
5097f594a49Smartijn return APPL_ERROR_NOERROR;
5107f594a49Smartijn }
5117f594a49Smartijn
5127f594a49Smartijn while (region->ar_next != NULL &&
5137f594a49Smartijn region->ar_next->ar_priority < priority)
5147f594a49Smartijn region = region->ar_next;
5157f594a49Smartijn if (region->ar_next != NULL && region->ar_next->ar_priority == priority)
5167f594a49Smartijn goto duplicate;
5177f594a49Smartijn nregion->ar_next = region->ar_next;
5187f594a49Smartijn region->ar_next = nregion;
5197f594a49Smartijn
5207f594a49Smartijn return APPL_ERROR_NOERROR;
5217f594a49Smartijn duplicate:
5227f594a49Smartijn free(nregion);
5237f594a49Smartijn log_info("%s: %s priority %"PRId8": Duplicate registration",
5247f594a49Smartijn backend->ab_name, oidbuf, priority);
5257f594a49Smartijn return APPL_ERROR_DUPLICATEREGISTRATION;
5267f594a49Smartijn overlap:
527002d07d7Smartijn regionbuf[0] = '\0';
5287f594a49Smartijn for (i = 0; i < region->ar_oid.bo_n; i++) {
5297f594a49Smartijn if (i != 0)
5307f594a49Smartijn strlcat(regionbuf, ".", sizeof(regionbuf));
5317f594a49Smartijn snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32,
5327f594a49Smartijn region->ar_oid.bo_id[i]);
5337f594a49Smartijn strlcat(regionbuf, subidbuf, sizeof(regionbuf));
5347f594a49Smartijn }
5357f594a49Smartijn log_info("%s: %s overlaps with %s: Request denied",
5367f594a49Smartijn backend->ab_name, oidbuf, regionbuf);
5377f594a49Smartijn return APPL_ERROR_REQUESTDENIED;
5387f594a49Smartijn }
5397f594a49Smartijn
5407f594a49Smartijn /* Name from RFC 2741 section 6.2.3 */
5417f594a49Smartijn enum appl_error
appl_register(const char * ctxname,uint32_t timeout,uint8_t priority,struct ber_oid * oid,int instance,int subtree,uint8_t range_subid,uint32_t upper_bound,struct appl_backend * backend)5427f594a49Smartijn appl_register(const char *ctxname, uint32_t timeout, uint8_t priority,
5437f594a49Smartijn struct ber_oid *oid, int instance, int subtree, uint8_t range_subid,
5447f594a49Smartijn uint32_t upper_bound, struct appl_backend *backend)
5457f594a49Smartijn {
5467f594a49Smartijn struct appl_context *ctx;
5477f594a49Smartijn struct appl_region *region, search;
5487f594a49Smartijn char oidbuf[1024], subidbuf[11];
5497f594a49Smartijn enum appl_error error;
550f0bcdb5cSmartijn size_t i, bo_n;
5517f594a49Smartijn uint32_t lower_bound;
5527f594a49Smartijn
553f0bcdb5cSmartijn bo_n = oid->bo_n;
554f0bcdb5cSmartijn if (range_subid != 0)
555f0bcdb5cSmartijn oid->bo_n = range_subid;
556f0bcdb5cSmartijn mib_oid2string(oid, oidbuf, sizeof(oidbuf), snmpd_env->sc_oidfmt);
557f0bcdb5cSmartijn if (range_subid != 0) {
558f0bcdb5cSmartijn oid->bo_n = bo_n;
559f0bcdb5cSmartijn i = range_subid + 1;
560f0bcdb5cSmartijn } else
561f0bcdb5cSmartijn i = oid->bo_n;
562f0bcdb5cSmartijn for (; i < oid->bo_n; i++) {
5637f594a49Smartijn strlcat(oidbuf, ".", sizeof(oidbuf));
564f0bcdb5cSmartijn snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32, oid->bo_id[i]);
5657f594a49Smartijn if (range_subid == i + 1) {
5667f594a49Smartijn strlcat(oidbuf, "[", sizeof(oidbuf));
5677f594a49Smartijn strlcat(oidbuf, subidbuf, sizeof(oidbuf));
5687f594a49Smartijn strlcat(oidbuf, "-", sizeof(oidbuf));
5697f594a49Smartijn snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32,
5707f594a49Smartijn upper_bound);
5717f594a49Smartijn strlcat(oidbuf, subidbuf, sizeof(oidbuf));
5727f594a49Smartijn strlcat(oidbuf, "]", sizeof(oidbuf));
5737f594a49Smartijn } else
5747f594a49Smartijn strlcat(oidbuf, subidbuf, sizeof(oidbuf));
5757f594a49Smartijn }
5767f594a49Smartijn
5777f594a49Smartijn if (ctxname == NULL)
5787f594a49Smartijn ctxname = "";
5797f594a49Smartijn log_info("%s: Registering %s%s context(%s) priority(%"PRIu8") "
5807f594a49Smartijn "timeout(%"PRIu32".%02us)", backend->ab_name, oidbuf,
5817f594a49Smartijn instance ? "(instance)" : "", ctxname, priority,
5827f594a49Smartijn timeout/100, timeout % 100);
5837f594a49Smartijn
5847f594a49Smartijn if ((ctx = appl_context(ctxname, 0)) == NULL) {
5857f594a49Smartijn if (errno == ENOMEM) {
5867f594a49Smartijn log_warn("%s: Can't register %s: Processing error",
5877f594a49Smartijn backend->ab_name, oidbuf);
5887f594a49Smartijn return APPL_ERROR_PROCESSINGERROR;
5897f594a49Smartijn }
5907f594a49Smartijn log_info("%s: Can't register %s: Unsupported context \"%s\"",
5917f594a49Smartijn backend->ab_name, oidbuf, ctxname);
5927f594a49Smartijn return APPL_ERROR_UNSUPPORTEDCONTEXT;
5937f594a49Smartijn }
5947f594a49Smartijn /* Default timeouts should be handled by backend */
5957f594a49Smartijn if (timeout == 0)
5967f594a49Smartijn fatalx("%s: Timeout can't be 0", __func__);
5977f594a49Smartijn if (priority == 0) {
5987f594a49Smartijn log_warnx("%s: Can't register %s: priority can't be 0",
5997f594a49Smartijn backend->ab_name, oidbuf);
6007f594a49Smartijn return APPL_ERROR_PARSEERROR;
6017f594a49Smartijn }
6027f594a49Smartijn
6037f594a49Smartijn if (range_subid == 0)
604f0bcdb5cSmartijn return appl_region(ctx, timeout, priority, oid, range_subid,
605f0bcdb5cSmartijn instance, subtree, backend);
6067f594a49Smartijn
6071eb9016fSmartijn range_subid--;
6081eb9016fSmartijn if (range_subid >= oid->bo_n) {
6091eb9016fSmartijn log_warnx("%s: Can't register %s: range_subid too large",
6101eb9016fSmartijn backend->ab_name, oidbuf);
6111eb9016fSmartijn return APPL_ERROR_PARSEERROR;
6121eb9016fSmartijn }
6131eb9016fSmartijn if (oid->bo_id[range_subid] > upper_bound) {
6141eb9016fSmartijn log_warnx("%s: Can't register %s: upper bound smaller than "
6151eb9016fSmartijn "range_subid", backend->ab_name, oidbuf);
6161eb9016fSmartijn return APPL_ERROR_PARSEERROR;
6171eb9016fSmartijn }
6181eb9016fSmartijn
6191eb9016fSmartijn lower_bound = oid->bo_id[range_subid];
6207f594a49Smartijn do {
621f0bcdb5cSmartijn if ((error = appl_region(ctx, timeout, priority, oid,
622f0bcdb5cSmartijn range_subid, instance, subtree,
623f0bcdb5cSmartijn backend)) != APPL_ERROR_NOERROR)
6247f594a49Smartijn goto fail;
6251eb9016fSmartijn } while (oid->bo_id[range_subid]++ != upper_bound);
626f0bcdb5cSmartijn if ((error = appl_region(ctx, timeout, priority, oid, range_subid,
627f0bcdb5cSmartijn instance, subtree, backend)) != APPL_ERROR_NOERROR)
6287f594a49Smartijn goto fail;
6297f594a49Smartijn
6307f594a49Smartijn return APPL_ERROR_NOERROR;
6317f594a49Smartijn fail:
6327f594a49Smartijn search.ar_oid = *oid;
6337f594a49Smartijn if (search.ar_oid.bo_id[range_subid] == lower_bound)
6347f594a49Smartijn return error;
6357f594a49Smartijn
6367f594a49Smartijn for (search.ar_oid.bo_id[range_subid]--;
6377f594a49Smartijn search.ar_oid.bo_id[range_subid] != lower_bound;
6387f594a49Smartijn search.ar_oid.bo_id[range_subid]--) {
6397f594a49Smartijn region = RB_FIND(appl_regions, &(ctx->ac_regions), &search);
6407f594a49Smartijn while (region->ar_priority != priority)
6417f594a49Smartijn region = region->ar_next;
6427f594a49Smartijn appl_region_free(ctx, region);
6437f594a49Smartijn }
6447f594a49Smartijn region = RB_FIND(appl_regions, &(ctx->ac_regions), &search);
6457f594a49Smartijn while (region->ar_priority != priority)
6467f594a49Smartijn region = region->ar_next;
6477f594a49Smartijn appl_region_free(ctx, region);
6487f594a49Smartijn return error;
6497f594a49Smartijn }
6507f594a49Smartijn
6517f594a49Smartijn /* Name from RFC 2741 section 6.2.4 */
6527f594a49Smartijn enum appl_error
appl_unregister(const char * ctxname,uint8_t priority,struct ber_oid * oid,uint8_t range_subid,uint32_t upper_bound,struct appl_backend * backend)6537f594a49Smartijn appl_unregister(const char *ctxname, uint8_t priority, struct ber_oid *oid,
6547f594a49Smartijn uint8_t range_subid, uint32_t upper_bound, struct appl_backend *backend)
6557f594a49Smartijn {
6567f594a49Smartijn struct appl_context *ctx;
6577f594a49Smartijn char oidbuf[1024], subidbuf[11];
6581e1ddca6Smartijn enum appl_error error;
6591e1ddca6Smartijn uint32_t lower_bound;
6607f594a49Smartijn size_t i;
6617f594a49Smartijn
6627f594a49Smartijn oidbuf[0] = '\0';
6637f594a49Smartijn for (i = 0; i < oid->bo_n; i++) {
6647f594a49Smartijn snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32, oid->bo_id[i]);
6657f594a49Smartijn if (i != 0)
6667f594a49Smartijn strlcat(oidbuf, ".", sizeof(oidbuf));
6677f594a49Smartijn if (range_subid == i + 1) {
6687f594a49Smartijn strlcat(oidbuf, "[", sizeof(oidbuf));
6697f594a49Smartijn strlcat(oidbuf, subidbuf, sizeof(oidbuf));
6707f594a49Smartijn strlcat(oidbuf, "-", sizeof(oidbuf));
6717f594a49Smartijn snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32,
6727f594a49Smartijn upper_bound);
6737f594a49Smartijn strlcat(oidbuf, subidbuf, sizeof(oidbuf));
6747f594a49Smartijn strlcat(oidbuf, "]", sizeof(oidbuf));
6757f594a49Smartijn } else
6767f594a49Smartijn strlcat(oidbuf, subidbuf, sizeof(oidbuf));
6777f594a49Smartijn }
6787f594a49Smartijn
6797f594a49Smartijn if (ctxname == NULL)
6807f594a49Smartijn ctxname = "";
6817f594a49Smartijn log_info("%s: Unregistering %s context(%s) priority(%"PRIu8")",
6827f594a49Smartijn backend->ab_name, oidbuf,ctxname, priority);
6837f594a49Smartijn
6847f594a49Smartijn if ((ctx = appl_context(ctxname, 0)) == NULL) {
6857f594a49Smartijn if (errno == ENOMEM) {
6867f594a49Smartijn log_warn("%s: Can't unregister %s: Processing error",
6877f594a49Smartijn backend->ab_name, oidbuf);
6887f594a49Smartijn return APPL_ERROR_PROCESSINGERROR;
6897f594a49Smartijn }
6907f594a49Smartijn log_info("%s: Can't unregister %s: Unsupported context \"%s\"",
6917f594a49Smartijn backend->ab_name, oidbuf, ctxname);
6927f594a49Smartijn return APPL_ERROR_UNSUPPORTEDCONTEXT;
6937f594a49Smartijn }
6947f594a49Smartijn
6957f594a49Smartijn if (priority == 0) {
6967f594a49Smartijn log_warnx("%s: Can't unregister %s: priority can't be 0",
6977f594a49Smartijn backend->ab_name, oidbuf);
6987f594a49Smartijn return APPL_ERROR_PARSEERROR;
6997f594a49Smartijn }
7007f594a49Smartijn
7011e1ddca6Smartijn if (range_subid == 0)
7021e1ddca6Smartijn return appl_region_unregister_match(ctx, priority, oid, oidbuf,
7031e1ddca6Smartijn backend, 1);
7041e1ddca6Smartijn
7051e1ddca6Smartijn range_subid--;
7061e1ddca6Smartijn if (range_subid >= oid->bo_n) {
7077f594a49Smartijn log_warnx("%s: Can't unregiser %s: range_subid too large",
7087f594a49Smartijn backend->ab_name, oidbuf);
7097f594a49Smartijn return APPL_ERROR_PARSEERROR;
7107f594a49Smartijn }
7111e1ddca6Smartijn if (oid->bo_id[range_subid] > upper_bound) {
7121e1ddca6Smartijn log_warnx("%s: Can't unregister %s: upper bound smaller than "
7131e1ddca6Smartijn "range_subid", backend->ab_name, oidbuf);
7147f594a49Smartijn return APPL_ERROR_PARSEERROR;
7157f594a49Smartijn }
7167f594a49Smartijn
7171e1ddca6Smartijn lower_bound = oid->bo_id[range_subid];
7181e1ddca6Smartijn do {
7191e1ddca6Smartijn if ((error = appl_region_unregister_match(ctx, priority, oid,
7201e1ddca6Smartijn oidbuf, backend, 0)) != APPL_ERROR_NOERROR)
7211e1ddca6Smartijn return error;
7221e1ddca6Smartijn } while (oid->bo_id[range_subid]++ != upper_bound);
7231e1ddca6Smartijn
7241e1ddca6Smartijn oid->bo_id[range_subid] = lower_bound;
7251e1ddca6Smartijn do {
7261e1ddca6Smartijn (void)appl_region_unregister_match(ctx, priority, oid, oidbuf,
7271e1ddca6Smartijn backend, 1);
7281e1ddca6Smartijn } while (oid->bo_id[range_subid]++ != upper_bound);
7291e1ddca6Smartijn
7301e1ddca6Smartijn return APPL_ERROR_NOERROR;
7311e1ddca6Smartijn }
7321e1ddca6Smartijn
7331e1ddca6Smartijn enum appl_error
appl_region_unregister_match(struct appl_context * ctx,uint8_t priority,struct ber_oid * oid,char * oidbuf,struct appl_backend * backend,int dofree)7341e1ddca6Smartijn appl_region_unregister_match(struct appl_context *ctx, uint8_t priority,
7351e1ddca6Smartijn struct ber_oid *oid, char *oidbuf, struct appl_backend *backend, int dofree)
7361e1ddca6Smartijn {
7371e1ddca6Smartijn struct appl_region *region, search;
7381e1ddca6Smartijn
7397f594a49Smartijn search.ar_oid = *oid;
7407f594a49Smartijn region = RB_FIND(appl_regions, &(ctx->ac_regions), &search);
7417f594a49Smartijn while (region != NULL && region->ar_priority < priority)
7427f594a49Smartijn region = region->ar_next;
7437f594a49Smartijn if (region == NULL || region->ar_priority != priority) {
7447f594a49Smartijn log_warnx("%s: Can't unregister %s: region not found",
7457f594a49Smartijn backend->ab_name, oidbuf);
7467f594a49Smartijn return APPL_ERROR_UNKNOWNREGISTRATION;
7477f594a49Smartijn }
7487f594a49Smartijn if (region->ar_backend != backend) {
7497f594a49Smartijn log_warnx("%s: Can't unregister %s: region not owned "
7507f594a49Smartijn "by backend", backend->ab_name, oidbuf);
7517f594a49Smartijn return APPL_ERROR_UNKNOWNREGISTRATION;
7527f594a49Smartijn }
7531e1ddca6Smartijn if (dofree)
7547f594a49Smartijn appl_region_free(ctx, region);
7557f594a49Smartijn return APPL_ERROR_NOERROR;
7567f594a49Smartijn }
7577f594a49Smartijn
7587f594a49Smartijn void
appl_region_free(struct appl_context * ctx,struct appl_region * region)7597f594a49Smartijn appl_region_free(struct appl_context *ctx, struct appl_region *region)
7607f594a49Smartijn {
7617f594a49Smartijn struct appl_region *pregion;
7627f594a49Smartijn
7637f594a49Smartijn pregion = RB_FIND(appl_regions, &(ctx->ac_regions), region);
7647f594a49Smartijn
7657f594a49Smartijn if (pregion == region) {
7667f594a49Smartijn RB_REMOVE(appl_regions, &(ctx->ac_regions), region);
7677f594a49Smartijn if (region->ar_next != NULL)
7687f594a49Smartijn RB_INSERT(appl_regions, &(ctx->ac_regions),
7697f594a49Smartijn region->ar_next);
7707f594a49Smartijn } else {
7717f594a49Smartijn while (pregion->ar_next != region)
7727f594a49Smartijn pregion = pregion->ar_next;
7737f594a49Smartijn pregion->ar_next = region->ar_next;
7747f594a49Smartijn }
7757f594a49Smartijn
7767f594a49Smartijn free(region);
7777f594a49Smartijn }
7787f594a49Smartijn
7797f594a49Smartijn /* backend is owned by the sub-application, just release application.c stuff */
7807f594a49Smartijn void
appl_close(struct appl_backend * backend)7817f594a49Smartijn appl_close(struct appl_backend *backend)
7827f594a49Smartijn {
7837f594a49Smartijn struct appl_context *ctx;
7842993c1b4Smartijn struct appl_agentcap *cap, *tcap;
7857f594a49Smartijn struct appl_region *region, *tregion, *nregion;
7867f594a49Smartijn struct appl_request_downstream *request, *trequest;
7877f594a49Smartijn
7887f594a49Smartijn TAILQ_FOREACH(ctx, &contexts, ac_entries) {
7892993c1b4Smartijn TAILQ_FOREACH_SAFE(cap, &(ctx->ac_agentcaps), aa_entry, tcap) {
7902993c1b4Smartijn if (cap->aa_backend == backend)
7912993c1b4Smartijn appl_agentcap_free(cap);
7922993c1b4Smartijn }
7937f594a49Smartijn RB_FOREACH_SAFE(region, appl_regions,
7947f594a49Smartijn &(ctx->ac_regions), tregion) {
7957f594a49Smartijn while (region != NULL) {
7967f594a49Smartijn nregion = region->ar_next;
7977f594a49Smartijn if (region->ar_backend == backend)
7987f594a49Smartijn appl_region_free(ctx, region);
7997f594a49Smartijn region = nregion;
8007f594a49Smartijn }
8017f594a49Smartijn }
8027f594a49Smartijn }
8037f594a49Smartijn
8047f594a49Smartijn RB_FOREACH_SAFE(request, appl_requests,
8057f594a49Smartijn &(backend->ab_requests), trequest)
8067f594a49Smartijn appl_request_downstream_free(request);
8077f594a49Smartijn }
8087f594a49Smartijn
8097f594a49Smartijn struct appl_region *
appl_region_find(struct appl_context * ctx,const struct ber_oid * oid)8107f594a49Smartijn appl_region_find(struct appl_context *ctx,
8117f594a49Smartijn const struct ber_oid *oid)
8127f594a49Smartijn {
8137f594a49Smartijn struct appl_region *region, search;
8147f594a49Smartijn
8157f594a49Smartijn search.ar_oid = *oid;
8167f594a49Smartijn while (search.ar_oid.bo_n > 0) {
8177f594a49Smartijn region = RB_FIND(appl_regions, &(ctx->ac_regions), &search);
8187f594a49Smartijn if (region != NULL)
8197f594a49Smartijn return region;
8207f594a49Smartijn search.ar_oid.bo_n--;
8217f594a49Smartijn }
8227f594a49Smartijn return NULL;
8237f594a49Smartijn }
8247f594a49Smartijn
8257f594a49Smartijn struct appl_region *
appl_region_next(struct appl_context * ctx,struct ber_oid * oid,struct appl_region * cregion)8267f594a49Smartijn appl_region_next(struct appl_context *ctx, struct ber_oid *oid,
8277f594a49Smartijn struct appl_region *cregion)
8287f594a49Smartijn {
8297f594a49Smartijn struct appl_region search, *nregion, *pregion;
8307f594a49Smartijn int cmp;
8317f594a49Smartijn
8327f594a49Smartijn search.ar_oid = *oid;
8337f594a49Smartijn nregion = RB_NFIND(appl_regions, &(ctx->ac_regions), &search);
8347f594a49Smartijn
8357f594a49Smartijn if (cregion == nregion)
8367f594a49Smartijn nregion = RB_NEXT(appl_regions, &(ctx->ac_regions), nregion);
8377f594a49Smartijn /* Past last element in tree, we might still have a parent */
8387f594a49Smartijn if (nregion == NULL) {
8397f594a49Smartijn search.ar_oid = cregion->ar_oid;
8407f594a49Smartijn search.ar_oid.bo_n--;
8417f594a49Smartijn return appl_region_find(ctx, &(search.ar_oid));
8427f594a49Smartijn }
8437f594a49Smartijn cmp = appl_region_cmp(cregion, nregion);
8447f594a49Smartijn if (cmp >= 0)
8457f594a49Smartijn fatalx("%s: wrong OID order", __func__);
8467f594a49Smartijn /* Direct descendant */
8477f594a49Smartijn if (cmp == -2)
8487f594a49Smartijn return nregion;
8497f594a49Smartijn
8507f594a49Smartijn /* cmp == -1 */
8517f594a49Smartijn search.ar_oid = cregion->ar_oid;
8527f594a49Smartijn /* Find direct next sibling */
8537f594a49Smartijn ober_oid_nextsibling(&(search.ar_oid));
8547f594a49Smartijn if (ober_oid_cmp(&(nregion->ar_oid), &(search.ar_oid)) == 0)
8557f594a49Smartijn return nregion;
8567f594a49Smartijn /* Sibling gaps go to parent, or end end at border */
8577f594a49Smartijn search.ar_oid = cregion->ar_oid;
8587f594a49Smartijn search.ar_oid.bo_n--;
8597f594a49Smartijn pregion = appl_region_find(ctx, &(search.ar_oid));
8607f594a49Smartijn
8617f594a49Smartijn return pregion != NULL ? pregion : nregion;
8627f594a49Smartijn }
8637f594a49Smartijn
8647f594a49Smartijn /* Name from RFC 3413 section 3.2 */
8657f594a49Smartijn void
appl_processpdu(struct snmp_message * statereference,const char * ctxname,enum snmp_version pduversion,struct ber_element * pdu)8667f594a49Smartijn appl_processpdu(struct snmp_message *statereference, const char *ctxname,
8677f594a49Smartijn enum snmp_version pduversion, struct ber_element *pdu)
8687f594a49Smartijn {
8697f594a49Smartijn struct appl_context *ctx;
8707f594a49Smartijn struct appl_request_upstream *ureq;
871b12d45ecSmartijn struct ber_element *varbind, *varbindlist;
8727f594a49Smartijn long long nonrepeaters, maxrepetitions;
8737f594a49Smartijn static uint32_t transactionid;
8747f594a49Smartijn int32_t requestid;
8757f594a49Smartijn size_t i, varbindlen = 0, repeaterlen;
8767f594a49Smartijn
8777f594a49Smartijn /* pdu must be ASN.1 validated in snmpe.c */
878c055c533Smartijn (void) ober_scanf_elements(pdu, "{diie", &requestid, &nonrepeaters,
8797f594a49Smartijn &maxrepetitions, &varbindlist);
8807f594a49Smartijn
8817f594a49Smartijn /* RFC 3413, section 3.2, processPDU, item 5, final bullet */
8827f594a49Smartijn if ((ctx = appl_context(ctxname, 0)) == NULL) {
8837f594a49Smartijn snmp_target_mib.snmp_unknowncontexts++;
884b12d45ecSmartijn appl_report(statereference, requestid,
885b12d45ecSmartijn &OID(MIB_snmpUnknownContexts, 0));
8867f594a49Smartijn return;
8877f594a49Smartijn }
8887f594a49Smartijn
8897f594a49Smartijn if ((ureq = malloc(sizeof(*ureq))) == NULL)
8907f594a49Smartijn fatal("malloc");
8917f594a49Smartijn
8927f594a49Smartijn ureq->aru_ctx = ctx;
8937f594a49Smartijn ureq->aru_statereference = statereference;
8947f594a49Smartijn ureq->aru_transactionid = transactionid++;
895e40a541eSmartijn ureq->aru_requesttype = pdu->be_type;
896b12d45ecSmartijn ureq->aru_responsetype = SNMP_C_RESPONSE;
8977f594a49Smartijn ureq->aru_requestid = requestid;
8987f594a49Smartijn ureq->aru_error = APPL_ERROR_NOERROR;
8997f594a49Smartijn ureq->aru_index = 0;
9007f594a49Smartijn ureq->aru_nonrepeaters = nonrepeaters;
9017f594a49Smartijn ureq->aru_maxrepetitions = maxrepetitions;
9027f594a49Smartijn ureq->aru_varbindlen = 0;
9037f594a49Smartijn ureq->aru_locked = 0;
9047f594a49Smartijn ureq->aru_pduversion = pduversion;
9057f594a49Smartijn
9067f594a49Smartijn varbind = varbindlist->be_sub;
9077f594a49Smartijn for (; varbind != NULL; varbind = varbind->be_next)
9087f594a49Smartijn varbindlen++;
9097f594a49Smartijn
9107f594a49Smartijn repeaterlen = varbindlen - nonrepeaters;
9117f594a49Smartijn if (pdu->be_type == SNMP_C_GETBULKREQ)
9127f594a49Smartijn ureq->aru_varbindlen = nonrepeaters +
9137f594a49Smartijn (repeaterlen * maxrepetitions);
9147f594a49Smartijn else
9157f594a49Smartijn ureq->aru_varbindlen = varbindlen;
9167f594a49Smartijn if ((ureq->aru_vblist = calloc(ureq->aru_varbindlen,
9177f594a49Smartijn sizeof(*ureq->aru_vblist))) == NULL)
9187f594a49Smartijn fatal("malloc");
9197f594a49Smartijn
9207f594a49Smartijn varbind = varbindlist->be_sub;
9217f594a49Smartijn /* Use aru_varbindlen in case maxrepetitions == 0 */
9227f594a49Smartijn for (i = 0; i < ureq->aru_varbindlen; i++) {
9237f594a49Smartijn ureq->aru_vblist[i].avi_request_upstream = ureq;
9247f594a49Smartijn ureq->aru_vblist[i].avi_index = i + 1;
9257f594a49Smartijn ureq->aru_vblist[i].avi_state = APPL_VBSTATE_NEW;
9267f594a49Smartijn /* This can only happen with bulkreq */
9277f594a49Smartijn if (varbind == NULL) {
9287f594a49Smartijn ureq->aru_vblist[i - repeaterlen].avi_sub =
9297f594a49Smartijn &(ureq->aru_vblist[i]);
9307f594a49Smartijn ureq->aru_vblist[i].avi_state = APPL_VBSTATE_MUSTFILL;
9310246d57fSmartijn ureq->aru_vblist[i].avi_index =
9320246d57fSmartijn ureq->aru_vblist[i - repeaterlen].avi_index;
9337f594a49Smartijn continue;
9347f594a49Smartijn }
9357f594a49Smartijn ober_get_oid(varbind->be_sub,
9367f594a49Smartijn &(ureq->aru_vblist[i].avi_varbind.av_oid));
9372f3602daSmartijn ureq->aru_vblist[i].avi_origid =
9382f3602daSmartijn ureq->aru_vblist[i].avi_varbind.av_oid;
93980990c3aSmartijn if (i + 1 < varbindlen)
9407f594a49Smartijn ureq->aru_vblist[i].avi_varbind.av_next =
9417f594a49Smartijn &(ureq->aru_vblist[i + 1].avi_varbind);
94280990c3aSmartijn else
9437f594a49Smartijn ureq->aru_vblist[i].avi_varbind.av_next = NULL;
9447f594a49Smartijn varbind = varbind->be_next;
9457f594a49Smartijn }
9467f594a49Smartijn
9477f594a49Smartijn appl_pdu_log(NULL, pdu->be_type, requestid, nonrepeaters,
9487f594a49Smartijn maxrepetitions, &(ureq->aru_vblist[0].avi_varbind));
9497f594a49Smartijn
9507f594a49Smartijn appl_request_upstream_resolve(ureq);
9517f594a49Smartijn }
9527f594a49Smartijn
9537f594a49Smartijn void
appl_request_upstream_free(struct appl_request_upstream * ureq)9547f594a49Smartijn appl_request_upstream_free(struct appl_request_upstream *ureq)
9557f594a49Smartijn {
9567f594a49Smartijn size_t i;
9577f594a49Smartijn struct appl_varbind_internal *vb;
9587f594a49Smartijn
9597f594a49Smartijn if (ureq == NULL)
9607f594a49Smartijn return;
9617f594a49Smartijn
96206c02db8Smartijn ureq->aru_locked = 1;
9637f594a49Smartijn for (i = 0; i < ureq->aru_varbindlen && ureq->aru_vblist != NULL; i++) {
9647f594a49Smartijn vb = &(ureq->aru_vblist[i]);
9657f594a49Smartijn ober_free_elements(vb->avi_varbind.av_value);
9667f594a49Smartijn appl_request_downstream_free(vb->avi_request_downstream);
9677f594a49Smartijn }
9687f594a49Smartijn free(ureq->aru_vblist);
9697f594a49Smartijn
9707f594a49Smartijn assert(ureq->aru_statereference == NULL);
9717f594a49Smartijn
9727f594a49Smartijn free(ureq);
9737f594a49Smartijn }
9747f594a49Smartijn
9757f594a49Smartijn void
appl_request_downstream_free(struct appl_request_downstream * dreq)9767f594a49Smartijn appl_request_downstream_free(struct appl_request_downstream *dreq)
9777f594a49Smartijn {
9787f594a49Smartijn struct appl_varbind_internal *vb;
9797f594a49Smartijn
9807f594a49Smartijn if (dreq == NULL)
9817f594a49Smartijn return;
9827f594a49Smartijn
9837f594a49Smartijn RB_REMOVE(appl_requests, &(dreq->ard_backend->ab_requests), dreq);
9847f594a49Smartijn evtimer_del(&(dreq->ard_timer));
9857f594a49Smartijn
98656fb13c3Smartijn for (vb = dreq->ard_vblist; vb != NULL; vb = vb->avi_next) {
9877f594a49Smartijn vb->avi_request_downstream = NULL;
98806c02db8Smartijn if (vb->avi_state == APPL_VBSTATE_PENDING)
98956fb13c3Smartijn vb->avi_state = APPL_VBSTATE_NEW;
99056fb13c3Smartijn }
9917f594a49Smartijn
99256fb13c3Smartijn appl_request_upstream_resolve(dreq->ard_request);
9937f594a49Smartijn free(dreq);
9947f594a49Smartijn }
9957f594a49Smartijn
9967f594a49Smartijn void
appl_request_upstream_resolve(struct appl_request_upstream * ureq)9977f594a49Smartijn appl_request_upstream_resolve(struct appl_request_upstream *ureq)
9987f594a49Smartijn {
9997f594a49Smartijn struct appl_varbind_internal *vb, *lvb, *tvb;
10007f594a49Smartijn struct appl_request_downstream *dreq;
10017f594a49Smartijn struct appl_region *region, *lregion;
10027f594a49Smartijn struct timeval tv;
10037f594a49Smartijn int done;
10047f594a49Smartijn size_t i;
10057f594a49Smartijn int32_t maxrepetitions;
10067f594a49Smartijn int32_t timeout;
10077f594a49Smartijn
10087f594a49Smartijn if (ureq->aru_locked)
10097f594a49Smartijn return;
10107f594a49Smartijn ureq->aru_locked = 1;
10117f594a49Smartijn
1012e40a541eSmartijn if (ureq->aru_requesttype == SNMP_C_SETREQ) {
10137f594a49Smartijn ureq->aru_error = APPL_ERROR_NOTWRITABLE;
10147f594a49Smartijn ureq->aru_index = 1;
10157f594a49Smartijn appl_request_upstream_reply(ureq);
10167f594a49Smartijn return;
10177f594a49Smartijn }
10187f594a49Smartijn
10197f594a49Smartijn next:
10207f594a49Smartijn dreq = NULL;
10217f594a49Smartijn lvb = NULL;
10227f594a49Smartijn done = 1;
10237f594a49Smartijn timeout = 0;
10247f594a49Smartijn
10257f594a49Smartijn if (ureq->aru_error != APPL_ERROR_NOERROR) {
10267f594a49Smartijn appl_request_upstream_reply(ureq);
10277f594a49Smartijn return;
10287f594a49Smartijn }
10297f594a49Smartijn for (i = 0; i < ureq->aru_varbindlen; i++) {
10307f594a49Smartijn vb = &(ureq->aru_vblist[i]);
10317f594a49Smartijn
10327f594a49Smartijn switch (vb->avi_state) {
10337f594a49Smartijn case APPL_VBSTATE_MUSTFILL:
10347f594a49Smartijn case APPL_VBSTATE_PENDING:
10357f594a49Smartijn done = 0;
10367f594a49Smartijn continue;
10377f594a49Smartijn case APPL_VBSTATE_DONE:
10387f594a49Smartijn continue;
10397f594a49Smartijn case APPL_VBSTATE_NEW:
10407f594a49Smartijn break;
10417f594a49Smartijn }
10427f594a49Smartijn if (appl_varbind_backend(vb) == -1)
10437f594a49Smartijn fatal("appl_varbind_backend");
10447f594a49Smartijn if (vb->avi_state != APPL_VBSTATE_DONE)
10457f594a49Smartijn done = 0;
10467f594a49Smartijn }
10477f594a49Smartijn
10487f594a49Smartijn for (i = 0; i < ureq->aru_varbindlen; i++) {
10497f594a49Smartijn vb = &(ureq->aru_vblist[i]);
10507f594a49Smartijn
10517f594a49Smartijn if (vb->avi_state != APPL_VBSTATE_NEW)
10527f594a49Smartijn continue;
10537f594a49Smartijn
10547f594a49Smartijn vb = &(ureq->aru_vblist[i]);
10557f594a49Smartijn region = vb->avi_region;
10567f594a49Smartijn lregion = lvb != NULL ? lvb->avi_region : NULL;
10577f594a49Smartijn if (lvb != NULL && region->ar_backend != lregion->ar_backend)
10587f594a49Smartijn continue;
10597f594a49Smartijn
10607f594a49Smartijn vb->avi_varbind.av_next = NULL;
10617f594a49Smartijn vb->avi_next = NULL;
10627f594a49Smartijn tvb = vb;
10637f594a49Smartijn for (maxrepetitions = 0; tvb != NULL; tvb = tvb->avi_sub)
10647f594a49Smartijn maxrepetitions++;
10657f594a49Smartijn if (dreq == NULL) {
10667f594a49Smartijn if ((dreq = malloc(sizeof(*dreq))) == NULL)
10677f594a49Smartijn fatal("malloc");
10687f594a49Smartijn
10697f594a49Smartijn dreq->ard_request = ureq;
10707f594a49Smartijn dreq->ard_vblist = vb;
10717f594a49Smartijn dreq->ard_backend = vb->avi_region->ar_backend;
10727f594a49Smartijn dreq->ard_retries = dreq->ard_backend->ab_retries;
1073e40a541eSmartijn dreq->ard_requesttype = ureq->aru_requesttype;
10747f594a49Smartijn /*
10757f594a49Smartijn * We don't yet fully handle bulkrequest responses.
10767f594a49Smartijn * It's completely valid to map onto getrequest.
10777f594a49Smartijn * maxrepetitions calculated in preparation of support.
10787f594a49Smartijn */
10797f594a49Smartijn if (dreq->ard_requesttype == SNMP_C_GETBULKREQ &&
10807f594a49Smartijn dreq->ard_backend->ab_fn->ab_getbulk == NULL)
10817f594a49Smartijn dreq->ard_requesttype = SNMP_C_GETNEXTREQ;
10827f594a49Smartijn /*
10837f594a49Smartijn * If first varbind is nonrepeater, set maxrepetitions
10847f594a49Smartijn * to 0, so that the next varbind with
10857f594a49Smartijn * maxrepetitions > 1 determines length.
10867f594a49Smartijn */
10877f594a49Smartijn if (maxrepetitions == 1) {
10887f594a49Smartijn dreq->ard_maxrepetitions = 0;
10897f594a49Smartijn dreq->ard_nonrepeaters = 1;
10907f594a49Smartijn } else {
10917f594a49Smartijn dreq->ard_maxrepetitions = maxrepetitions;
10927f594a49Smartijn dreq->ard_nonrepeaters = 0;
10937f594a49Smartijn }
10947f594a49Smartijn do {
10957f594a49Smartijn dreq->ard_requestid = arc4random();
10967f594a49Smartijn } while (RB_INSERT(appl_requests,
10977f594a49Smartijn &(dreq->ard_backend->ab_requests), dreq) != NULL);
10987f594a49Smartijn lvb = vb;
10997f594a49Smartijn /* avi_sub isn't set on !bulkrequest, so we always enter here */
11007f594a49Smartijn } else if (maxrepetitions == 1) {
11017f594a49Smartijn dreq->ard_nonrepeaters++;
11027f594a49Smartijn vb->avi_varbind.av_next =
11037f594a49Smartijn &(dreq->ard_vblist->avi_varbind);
11047f594a49Smartijn vb->avi_next = dreq->ard_vblist;
11057f594a49Smartijn dreq->ard_vblist = vb;
11067f594a49Smartijn } else {
11077f594a49Smartijn lvb->avi_varbind.av_next = &(vb->avi_varbind);
11087f594a49Smartijn lvb->avi_next = vb;
11097f594a49Smartijn /* RFC 2741 section 7.2.1.3:
11107f594a49Smartijn * The value of g.max_repetitions in the GetBulk-PDU may
11117f594a49Smartijn * be less than (but not greater than) the value in the
11127f594a49Smartijn * original request PDU.
11137f594a49Smartijn */
11147f594a49Smartijn if (dreq->ard_maxrepetitions > maxrepetitions ||
11157f594a49Smartijn dreq->ard_maxrepetitions == 0)
11167f594a49Smartijn dreq->ard_maxrepetitions = maxrepetitions;
11177f594a49Smartijn lvb = vb;
11187f594a49Smartijn }
11197f594a49Smartijn vb->avi_request_downstream = dreq;
11207f594a49Smartijn vb->avi_state = APPL_VBSTATE_PENDING;
11217f594a49Smartijn if (region->ar_timeout > timeout)
11227f594a49Smartijn timeout = region->ar_timeout;
11237f594a49Smartijn }
11247f594a49Smartijn
11257f594a49Smartijn if (dreq == NULL) {
11267f594a49Smartijn ureq->aru_locked = 0;
11277f594a49Smartijn if (done)
11287f594a49Smartijn appl_request_upstream_reply(ureq);
11297f594a49Smartijn return;
11307f594a49Smartijn }
11317f594a49Smartijn
11327f594a49Smartijn tv.tv_sec = timeout / 100;
11337f594a49Smartijn tv.tv_usec = (timeout % 100) * 10000;
11347f594a49Smartijn evtimer_set(&(dreq->ard_timer), appl_request_downstream_timeout, dreq);
11357f594a49Smartijn evtimer_add(&(dreq->ard_timer), &tv);
11367f594a49Smartijn
11377f594a49Smartijn appl_request_downstream_send(dreq);
11387f594a49Smartijn goto next;
11397f594a49Smartijn }
11407f594a49Smartijn
11417f594a49Smartijn void
appl_request_downstream_send(struct appl_request_downstream * dreq)11427f594a49Smartijn appl_request_downstream_send(struct appl_request_downstream *dreq)
11437f594a49Smartijn {
11447f594a49Smartijn
11457f594a49Smartijn appl_pdu_log(dreq->ard_backend, dreq->ard_requesttype,
11467f594a49Smartijn dreq->ard_requestid, 0, 0, &(dreq->ard_vblist->avi_varbind));
11477f594a49Smartijn
11487f594a49Smartijn if (dreq->ard_requesttype == SNMP_C_GETREQ) {
11497f594a49Smartijn dreq->ard_backend->ab_fn->ab_get(dreq->ard_backend,
11507f594a49Smartijn dreq->ard_request->aru_transactionid,
11517f594a49Smartijn dreq->ard_requestid,
11527f594a49Smartijn APPL_CONTEXT_NAME(dreq->ard_request->aru_ctx),
11537f594a49Smartijn &(dreq->ard_vblist->avi_varbind));
11547f594a49Smartijn } else if (dreq->ard_requesttype == SNMP_C_GETNEXTREQ) {
11557f594a49Smartijn dreq->ard_backend->ab_fn->ab_getnext(dreq->ard_backend,
11567f594a49Smartijn dreq->ard_request->aru_transactionid,
11577f594a49Smartijn dreq->ard_requestid,
11587f594a49Smartijn APPL_CONTEXT_NAME(dreq->ard_request->aru_ctx),
11597f594a49Smartijn &(dreq->ard_vblist->avi_varbind));
11607f594a49Smartijn }
11617f594a49Smartijn }
11627f594a49Smartijn
11637f594a49Smartijn void
appl_request_downstream_timeout(__unused int fd,__unused short event,void * cookie)11647f594a49Smartijn appl_request_downstream_timeout(__unused int fd, __unused short event,
11657f594a49Smartijn void *cookie)
11667f594a49Smartijn {
11677f594a49Smartijn struct appl_request_downstream *dreq = cookie;
11687f594a49Smartijn
11697f594a49Smartijn log_info("%s: %"PRIu32" timed out%s",
11707f594a49Smartijn dreq->ard_backend->ab_name, dreq->ard_requestid,
11717f594a49Smartijn dreq->ard_retries > 0 ? ": retrying" : "");
11727f594a49Smartijn if (dreq->ard_retries > 0) {
11737f594a49Smartijn dreq->ard_retries--;
11747f594a49Smartijn appl_request_downstream_send(dreq);
11757f594a49Smartijn } else
11767f594a49Smartijn appl_response(dreq->ard_backend, dreq->ard_requestid,
11777f594a49Smartijn APPL_ERROR_GENERR, 1, &(dreq->ard_vblist->avi_varbind));
11787f594a49Smartijn }
11797f594a49Smartijn
11807f594a49Smartijn void
appl_request_upstream_reply(struct appl_request_upstream * ureq)11817f594a49Smartijn appl_request_upstream_reply(struct appl_request_upstream *ureq)
11827f594a49Smartijn {
11837f594a49Smartijn struct ber_element *varbindlist = NULL, *varbind = NULL, *value;
11847f594a49Smartijn struct appl_varbind_internal *vb;
11857f594a49Smartijn size_t i, repvarbinds, varbindlen;
11867f594a49Smartijn ssize_t match = -1;
11877f594a49Smartijn
11887f594a49Smartijn varbindlen = ureq->aru_varbindlen;
11897f594a49Smartijn
1190f1f9290eSmartijn if (ureq->aru_pduversion == SNMP_V1) {
1191f1f9290eSmartijn /* RFC 3584 section 4.2.2.2 Map exceptions */
1192f1f9290eSmartijn for (i = 0; i < varbindlen; i++) {
11937f594a49Smartijn vb = &(ureq->aru_vblist[i]);
1194f1f9290eSmartijn value = vb->avi_varbind.av_value;
1195f1f9290eSmartijn if (value != NULL &&
1196f1f9290eSmartijn value->be_class == BER_CLASS_CONTEXT)
11977f594a49Smartijn appl_varbind_error(vb, APPL_ERROR_NOSUCHNAME);
11987f594a49Smartijn }
1199f1f9290eSmartijn /* RFC 3584 section 4.4 Map errors */
12007f594a49Smartijn switch (ureq->aru_error) {
12017f594a49Smartijn case APPL_ERROR_WRONGVALUE:
12027f594a49Smartijn case APPL_ERROR_WRONGENCODING:
12037f594a49Smartijn case APPL_ERROR_WRONGTYPE:
12047f594a49Smartijn case APPL_ERROR_WRONGLENGTH:
12057f594a49Smartijn case APPL_ERROR_INCONSISTENTVALUE:
12067f594a49Smartijn ureq->aru_error = APPL_ERROR_BADVALUE;
12077f594a49Smartijn break;
12087f594a49Smartijn case APPL_ERROR_NOACCESS:
12097f594a49Smartijn case APPL_ERROR_NOTWRITABLE:
12107f594a49Smartijn case APPL_ERROR_NOCREATION:
12117f594a49Smartijn case APPL_ERROR_INCONSISTENTNAME:
12127f594a49Smartijn case APPL_ERROR_AUTHORIZATIONERROR:
12137f594a49Smartijn ureq->aru_error = APPL_ERROR_NOSUCHNAME;
12147f594a49Smartijn break;
12157f594a49Smartijn case APPL_ERROR_RESOURCEUNAVAILABLE:
12167f594a49Smartijn case APPL_ERROR_COMMITFAILED:
12177f594a49Smartijn case APPL_ERROR_UNDOFAILED:
12187f594a49Smartijn ureq->aru_error = APPL_ERROR_GENERR;
12197f594a49Smartijn break;
12207f594a49Smartijn default:
12217f594a49Smartijn break;
12227f594a49Smartijn }
12237f594a49Smartijn }
1224f1f9290eSmartijn /* RFC 3416 section 4.2.{1,2,3} reset original varbinds */
1225f1f9290eSmartijn if (ureq->aru_error != APPL_ERROR_NOERROR) {
12267a3effa3Smartijn if (ureq->aru_requesttype == SNMP_C_GETBULKREQ)
12277a3effa3Smartijn varbindlen =
12287a3effa3Smartijn (ureq->aru_varbindlen - ureq->aru_nonrepeaters) /
12297a3effa3Smartijn ureq->aru_maxrepetitions;
12307a3effa3Smartijn for (i = 0; i < varbindlen; i++) {
12317a3effa3Smartijn vb = &(ureq->aru_vblist[i]);
12327a3effa3Smartijn vb->avi_varbind.av_oid = vb->avi_origid;
1233f1f9290eSmartijn ober_free_elements(vb->avi_varbind.av_value);
12347a3effa3Smartijn vb->avi_varbind.av_value = ober_add_null(NULL);
1235f1f9290eSmartijn }
1236f1f9290eSmartijn /* RFC 3416 section 4.2.3: Strip excessive EOMV */
1237e40a541eSmartijn } else if (ureq->aru_requesttype == SNMP_C_GETBULKREQ) {
1238f1f9290eSmartijn repvarbinds = (ureq->aru_varbindlen - ureq->aru_nonrepeaters) /
1239f1f9290eSmartijn ureq->aru_maxrepetitions;
1240f1f9290eSmartijn for (i = ureq->aru_nonrepeaters;
1241f1f9290eSmartijn i < ureq->aru_varbindlen - repvarbinds; i++) {
1242f1f9290eSmartijn value = ureq->aru_vblist[i].avi_varbind.av_value;
1243f1f9290eSmartijn if ((i - ureq->aru_nonrepeaters) % repvarbinds == 0 &&
1244f1f9290eSmartijn value->be_class == BER_CLASS_CONTEXT &&
1245f1f9290eSmartijn value->be_type == APPL_EXC_ENDOFMIBVIEW) {
1246f1f9290eSmartijn if (match != -1)
1247f1f9290eSmartijn break;
1248f1f9290eSmartijn match = i;
1249f1f9290eSmartijn }
1250f1f9290eSmartijn if (value->be_class != BER_CLASS_CONTEXT ||
1251f1f9290eSmartijn value->be_type != APPL_EXC_ENDOFMIBVIEW)
1252f1f9290eSmartijn match = -1;
1253f1f9290eSmartijn }
1254f1f9290eSmartijn if (match != -1)
1255f1f9290eSmartijn varbindlen = match + repvarbinds;
1256f1f9290eSmartijn }
1257f1f9290eSmartijn
1258f1f9290eSmartijn for (i = 0; i < varbindlen; i++) {
1259f1f9290eSmartijn vb = &(ureq->aru_vblist[i]);
1260f1f9290eSmartijn vb->avi_varbind.av_next =
1261f1f9290eSmartijn &(ureq->aru_vblist[i + 1].avi_varbind);
12622f3602daSmartijn value = vb->avi_varbind.av_value;
12632f3602daSmartijn if (value->be_class == BER_CLASS_CONTEXT &&
12642f3602daSmartijn value->be_type == APPL_EXC_ENDOFMIBVIEW)
12652f3602daSmartijn vb->avi_varbind.av_oid = vb->avi_origid;
1266f1f9290eSmartijn }
12677f594a49Smartijn
12687f594a49Smartijn ureq->aru_vblist[i - 1].avi_varbind.av_next = NULL;
1269b12d45ecSmartijn appl_pdu_log(NULL, ureq->aru_responsetype, ureq->aru_requestid,
12707f594a49Smartijn ureq->aru_error, ureq->aru_index,
12717f594a49Smartijn &(ureq->aru_vblist[0].avi_varbind));
12727f594a49Smartijn
12737f594a49Smartijn for (i = 0; i < varbindlen; i++) {
12747f594a49Smartijn varbind = ober_printf_elements(varbind, "{Oe}",
12757f594a49Smartijn &(ureq->aru_vblist[i].avi_varbind.av_oid),
12767f594a49Smartijn ureq->aru_vblist[i].avi_varbind.av_value);
12777f594a49Smartijn ureq->aru_vblist[i].avi_varbind.av_value = NULL;
12787f594a49Smartijn if (varbind == NULL)
12797f594a49Smartijn fatal("ober_printf_elements");
12807f594a49Smartijn if (varbindlist == NULL)
12817f594a49Smartijn varbindlist = varbind;
12827f594a49Smartijn }
12837f594a49Smartijn
1284b12d45ecSmartijn snmpe_send(ureq->aru_statereference, ureq->aru_responsetype,
12857f594a49Smartijn ureq->aru_requestid, ureq->aru_error, ureq->aru_index, varbindlist);
12867f594a49Smartijn ureq->aru_statereference = NULL;
12877f594a49Smartijn appl_request_upstream_free(ureq);
12887f594a49Smartijn }
12897f594a49Smartijn
12907f594a49Smartijn /* Name from RFC 2741 section 6.2.16 */
12917f594a49Smartijn void
appl_response(struct appl_backend * backend,int32_t requestid,enum appl_error error,int16_t index,struct appl_varbind * vblist)12927f594a49Smartijn appl_response(struct appl_backend *backend, int32_t requestid,
12937f594a49Smartijn enum appl_error error, int16_t index, struct appl_varbind *vblist)
12947f594a49Smartijn {
12957f594a49Smartijn struct appl_request_downstream *dreq, search;
12967f594a49Smartijn struct appl_request_upstream *ureq = NULL;
12977f594a49Smartijn const char *errstr;
12987f594a49Smartijn char oidbuf[1024];
12997f594a49Smartijn struct appl_varbind *vb;
13007f594a49Smartijn struct appl_varbind_internal *origvb = NULL;
13017f594a49Smartijn int invalid = 0;
13021345d1c8Smartijn int next = 0, eomv;
13037f594a49Smartijn int32_t i;
13047f594a49Smartijn
13057f594a49Smartijn appl_pdu_log(backend, SNMP_C_RESPONSE, requestid, error, index, vblist);
13067f594a49Smartijn
13077f594a49Smartijn search.ard_requestid = requestid;
13087f594a49Smartijn dreq = RB_FIND(appl_requests, &(backend->ab_requests), &search);
13097f594a49Smartijn if (dreq == NULL) {
13107f594a49Smartijn log_debug("%s: %"PRIu32" not outstanding",
13117f594a49Smartijn backend->ab_name, requestid);
13127f594a49Smartijn /* Continue to verify validity */
13137f594a49Smartijn } else {
13147f594a49Smartijn ureq = dreq->ard_request;
1315e40a541eSmartijn next = ureq->aru_requesttype == SNMP_C_GETNEXTREQ ||
1316e40a541eSmartijn ureq->aru_requesttype == SNMP_C_GETBULKREQ;
13177f594a49Smartijn origvb = dreq->ard_vblist;
1318c1fbd6d4Smartijn if (!appl_error_valid(error, dreq->ard_requesttype)) {
1319c1fbd6d4Smartijn log_warnx("%s: %"PRIu32" Invalid error",
1320c1fbd6d4Smartijn backend->ab_name, requestid);
1321c1fbd6d4Smartijn invalid = 1;
1322c1fbd6d4Smartijn }
13237f594a49Smartijn }
13247f594a49Smartijn
13257f594a49Smartijn vb = vblist;
13267f594a49Smartijn for (i = 1; vb != NULL; vb = vb->av_next, i++) {
132716d26808Smartijn if (!appl_varbind_valid(vb, origvb, next,
13281345d1c8Smartijn error != APPL_ERROR_NOERROR, backend->ab_range, &errstr)) {
1329f0bcdb5cSmartijn mib_oid2string(&(vb->av_oid), oidbuf, sizeof(oidbuf),
1330f0bcdb5cSmartijn snmpd_env->sc_oidfmt);
13317f594a49Smartijn log_warnx("%s: %"PRIu32" %s: %s",
13327f594a49Smartijn backend->ab_name, requestid, oidbuf, errstr);
13337f594a49Smartijn invalid = 1;
13347f594a49Smartijn }
13357f594a49Smartijn /* Transfer av_value */
13367f594a49Smartijn if (origvb != NULL) {
13377f594a49Smartijn if (error != APPL_ERROR_NOERROR && i == index)
13387f594a49Smartijn appl_varbind_error(origvb, error);
13397f594a49Smartijn origvb->avi_state = APPL_VBSTATE_DONE;
13407f594a49Smartijn origvb->avi_varbind.av_oid = vb->av_oid;
13411345d1c8Smartijn
13421345d1c8Smartijn eomv = vb->av_value != NULL &&
1343025669f9Smartijn vb->av_value->be_class == BER_CLASS_CONTEXT &&
13441345d1c8Smartijn vb->av_value->be_type == APPL_EXC_ENDOFMIBVIEW;
13451345d1c8Smartijn /*
13461345d1c8Smartijn * Treat results past av_oid_end for backends that
13471345d1c8Smartijn * don't support searchranges as EOMV
13481345d1c8Smartijn */
13491345d1c8Smartijn eomv |= !backend->ab_range && next &&
13501345d1c8Smartijn ober_oid_cmp(&(vb->av_oid),
1351fdfe462fSmartijn &(origvb->avi_varbind.av_oid_end)) >= 0;
13527f594a49Smartijn /* RFC 3584 section 4.2.2.1 */
13537f594a49Smartijn if (ureq->aru_pduversion == SNMP_V1 &&
13547f594a49Smartijn vb->av_value != NULL &&
13557f594a49Smartijn vb->av_value->be_class == BER_CLASS_APPLICATION &&
13567f594a49Smartijn vb->av_value->be_type == SNMP_COUNTER64) {
13571345d1c8Smartijn if (next)
13581345d1c8Smartijn eomv = 1;
13591345d1c8Smartijn else
13607f594a49Smartijn appl_varbind_error(origvb,
13617f594a49Smartijn APPL_ERROR_NOSUCHNAME);
13627f594a49Smartijn }
13631345d1c8Smartijn
13641345d1c8Smartijn if (eomv) {
13651345d1c8Smartijn ober_free_elements(vb->av_value);
13661345d1c8Smartijn origvb->avi_varbind.av_oid =
13671345d1c8Smartijn origvb->avi_varbind.av_oid_end;
13681345d1c8Smartijn origvb->avi_varbind.av_include = 1;
13691345d1c8Smartijn vb->av_value = NULL;
13701345d1c8Smartijn origvb->avi_state = APPL_VBSTATE_NEW;
13717f594a49Smartijn }
13727f594a49Smartijn origvb->avi_varbind.av_value = vb->av_value;
13737f594a49Smartijn if (origvb->avi_varbind.av_next == NULL &&
13747f594a49Smartijn vb->av_next != NULL) {
13757f594a49Smartijn log_warnx("%s: Request %"PRIu32" returned more "
13767f594a49Smartijn "varbinds then requested",
13777f594a49Smartijn backend->ab_name, requestid);
13787f594a49Smartijn invalid = 1;
13797f594a49Smartijn }
13807f594a49Smartijn if (origvb->avi_sub != NULL &&
13817f594a49Smartijn origvb->avi_state == APPL_VBSTATE_DONE) {
13827f594a49Smartijn origvb->avi_sub->avi_varbind.av_oid =
13837f594a49Smartijn origvb->avi_varbind.av_oid;
13843cf38abbSmartijn origvb->avi_sub->avi_origid =
13853cf38abbSmartijn origvb->avi_varbind.av_oid;
13867f594a49Smartijn origvb->avi_sub->avi_state = APPL_VBSTATE_NEW;
13877f594a49Smartijn }
13887f594a49Smartijn origvb = origvb->avi_next;
13897f594a49Smartijn } else {
13907f594a49Smartijn ober_free_elements(vb->av_value);
13917f594a49Smartijn vb->av_value = NULL;
13927f594a49Smartijn }
13937f594a49Smartijn }
13947f594a49Smartijn if (error != APPL_ERROR_NOERROR && (index <= 0 || index >= i)) {
13957f594a49Smartijn log_warnx("Invalid error index");
13967f594a49Smartijn invalid = 1;
13977f594a49Smartijn }
13984100cc5fSmartijn /* amavisd-snmp-subagent sets index to 1, no reason to crash over it. */
13994100cc5fSmartijn #if PEDANTIC
14007f594a49Smartijn if (error == APPL_ERROR_NOERROR && index != 0) {
14017f594a49Smartijn log_warnx("error index with no error");
14027f594a49Smartijn invalid = 1;
14037f594a49Smartijn }
14044100cc5fSmartijn #endif
14057f594a49Smartijn if (vb == NULL && origvb != NULL) {
14067f594a49Smartijn log_warnx("%s: Request %"PRIu32" returned less varbinds then "
14077f594a49Smartijn "requested", backend->ab_name, requestid);
14087f594a49Smartijn invalid = 1;
14097f594a49Smartijn }
14107f594a49Smartijn
14117f594a49Smartijn if (dreq != NULL) {
14127f594a49Smartijn if (invalid)
14137f594a49Smartijn appl_varbind_error(dreq->ard_vblist, APPL_ERROR_GENERR);
14147f594a49Smartijn appl_request_downstream_free(dreq);
14157f594a49Smartijn }
14167f594a49Smartijn
14177f594a49Smartijn if (invalid && backend->ab_fn->ab_close != NULL) {
14187f594a49Smartijn log_warnx("%s: Closing: Too many parse errors",
14197f594a49Smartijn backend->ab_name);
14207f594a49Smartijn backend->ab_fn->ab_close(backend, APPL_CLOSE_REASONPARSEERROR);
14217f594a49Smartijn }
14227f594a49Smartijn }
14237f594a49Smartijn
14247f594a49Smartijn int
appl_varbind_valid(struct appl_varbind * varbind,struct appl_varbind_internal * request,int next,int null,int range,const char ** errstr)142516d26808Smartijn appl_varbind_valid(struct appl_varbind *varbind,
142616d26808Smartijn struct appl_varbind_internal *request, int next, int null, int range,
142716d26808Smartijn const char **errstr)
14287f594a49Smartijn {
14297f594a49Smartijn int cmp;
14307f594a49Smartijn int eomv = 0;
1431*c3e23a03Smartijn long long intval;
1432*c3e23a03Smartijn void *buf;
1433*c3e23a03Smartijn size_t len;
1434*c3e23a03Smartijn struct ber ber;
1435*c3e23a03Smartijn struct ber_element *elm;
14367f594a49Smartijn
1437fba71c50Smartijn if (null)
1438fba71c50Smartijn next = 0;
1439fba71c50Smartijn
14407f594a49Smartijn if (varbind->av_value == NULL) {
1441f0c6917bSmartijn if (!null) {
14427f594a49Smartijn *errstr = "missing value";
14437f594a49Smartijn return 0;
14447f594a49Smartijn }
1445f0c6917bSmartijn return 1;
1446f0c6917bSmartijn }
1447*c3e23a03Smartijn
1448*c3e23a03Smartijn if (null) {
1449*c3e23a03Smartijn if (varbind->av_value->be_class != BER_CLASS_UNIVERSAL ||
1450*c3e23a03Smartijn varbind->av_value->be_type != BER_TYPE_NULL) {
1451*c3e23a03Smartijn *errstr = "expecting null value";
1452*c3e23a03Smartijn return 0;
1453*c3e23a03Smartijn }
1454*c3e23a03Smartijn } else {
1455*c3e23a03Smartijn if (varbind->av_value->be_class == BER_CLASS_UNIVERSAL &&
1456*c3e23a03Smartijn varbind->av_value->be_type == BER_TYPE_NULL) {
1457*c3e23a03Smartijn *errstr = "unexpected null value";
1458*c3e23a03Smartijn return 0;
1459*c3e23a03Smartijn }
1460*c3e23a03Smartijn }
1461*c3e23a03Smartijn
14627f594a49Smartijn if (varbind->av_value->be_class == BER_CLASS_UNIVERSAL) {
14637f594a49Smartijn switch (varbind->av_value->be_type) {
14647f594a49Smartijn case BER_TYPE_NULL:
1465*c3e23a03Smartijn /* Checked above */
14667f594a49Smartijn break;
14677f594a49Smartijn case BER_TYPE_INTEGER:
1468*c3e23a03Smartijn (void)ober_get_integer(varbind->av_value, &intval);
1469*c3e23a03Smartijn if (intval < SMI_INTEGER_MIN) {
1470*c3e23a03Smartijn *errstr = "INTEGER value too small";
1471*c3e23a03Smartijn return 0;
1472*c3e23a03Smartijn }
1473*c3e23a03Smartijn if (intval > SMI_INTEGER_MAX) {
1474*c3e23a03Smartijn *errstr = "INTEGER value too large";
1475*c3e23a03Smartijn return 0;
1476*c3e23a03Smartijn }
14777f594a49Smartijn break;
1478*c3e23a03Smartijn case BER_TYPE_OCTETSTRING:
1479*c3e23a03Smartijn (void)ober_get_nstring(varbind->av_value, NULL, &len);
1480*c3e23a03Smartijn if (len > SMI_OCTETSTRING_MAX) {
1481*c3e23a03Smartijn *errstr = "OCTET STRING too long";
1482*c3e23a03Smartijn return 0;
1483*c3e23a03Smartijn }
1484*c3e23a03Smartijn break;
1485*c3e23a03Smartijn case BER_TYPE_OBJECT:
1486*c3e23a03Smartijn /* validated by ber.c */
1487*c3e23a03Smartijn break;
14887f594a49Smartijn default:
1489*c3e23a03Smartijn *errstr = "invalid value encoding";
14907f594a49Smartijn return 0;
14917f594a49Smartijn }
14927f594a49Smartijn } else if (varbind->av_value->be_class == BER_CLASS_APPLICATION) {
14937f594a49Smartijn switch (varbind->av_value->be_type) {
14947f594a49Smartijn case SNMP_T_IPADDR:
1495*c3e23a03Smartijn (void)ober_get_nstring(varbind->av_value, NULL, &len);
1496*c3e23a03Smartijn if (len != SMI_IPADDRESS_MAX) {
1497*c3e23a03Smartijn *errstr = "invalid IpAddress size";
1498*c3e23a03Smartijn return 0;
1499*c3e23a03Smartijn }
15007f594a49Smartijn break;
1501*c3e23a03Smartijn case SNMP_T_COUNTER32:
1502*c3e23a03Smartijn (void)ober_get_integer(varbind->av_value, &intval);
1503*c3e23a03Smartijn if (intval < SMI_COUNTER32_MIN) {
1504*c3e23a03Smartijn *errstr = "Counter32 value too small";
1505*c3e23a03Smartijn return 0;
1506*c3e23a03Smartijn }
1507*c3e23a03Smartijn if (intval > SMI_COUNTER32_MAX) {
1508*c3e23a03Smartijn *errstr = "Counter32 value too large";
1509*c3e23a03Smartijn return 0;
1510*c3e23a03Smartijn }
1511*c3e23a03Smartijn break;
1512*c3e23a03Smartijn case SNMP_T_GAUGE32:
1513*c3e23a03Smartijn (void)ober_get_integer(varbind->av_value, &intval);
1514*c3e23a03Smartijn if (intval < SMI_GAUGE32_MIN) {
1515*c3e23a03Smartijn *errstr = "Gauge32 value too small";
1516*c3e23a03Smartijn return 0;
1517*c3e23a03Smartijn }
1518*c3e23a03Smartijn if (intval > SMI_GAUGE32_MAX) {
1519*c3e23a03Smartijn *errstr = "Gauge32 value too large";
1520*c3e23a03Smartijn return 0;
1521*c3e23a03Smartijn }
1522*c3e23a03Smartijn break;
1523*c3e23a03Smartijn case SNMP_T_TIMETICKS:
1524*c3e23a03Smartijn (void)ober_get_integer(varbind->av_value, &intval);
1525*c3e23a03Smartijn if (intval < SMI_TIMETICKS_MIN) {
1526*c3e23a03Smartijn *errstr = "TimeTicks value too small";
1527*c3e23a03Smartijn return 0;
1528*c3e23a03Smartijn }
1529*c3e23a03Smartijn if (intval > SMI_TIMETICKS_MAX) {
1530*c3e23a03Smartijn *errstr = "TimeTicks value too large";
1531*c3e23a03Smartijn return 0;
1532*c3e23a03Smartijn }
1533*c3e23a03Smartijn break;
1534*c3e23a03Smartijn case SNMP_T_OPAQUE:
1535*c3e23a03Smartijn (void)ober_get_nstring(varbind->av_value, &buf, &len);
1536*c3e23a03Smartijn memset(&ber, 0, sizeof(ber));
1537*c3e23a03Smartijn ober_set_application(&ber, appl_ber_any);
1538*c3e23a03Smartijn ober_set_readbuf(&ber, buf, len);
1539*c3e23a03Smartijn elm = ober_read_elements(&ber, NULL);
1540*c3e23a03Smartijn if (elm == NULL || ober_calc_len(elm) != len) {
1541*c3e23a03Smartijn ober_free_elements(elm);
1542*c3e23a03Smartijn *errstr = "Opaque not valid ber encoded value";
1543*c3e23a03Smartijn return 0;
1544*c3e23a03Smartijn }
1545*c3e23a03Smartijn ober_free_elements(elm);
1546*c3e23a03Smartijn break;
1547*c3e23a03Smartijn case SNMP_T_COUNTER64:
1548*c3e23a03Smartijn /* Maximum value supported by ber.c */
1549*c3e23a03Smartijn break;
15507f594a49Smartijn default:
1551*c3e23a03Smartijn *errstr = "invalid value encoding";
15527f594a49Smartijn return 0;
15537f594a49Smartijn }
15547f594a49Smartijn } else if (varbind->av_value->be_class == BER_CLASS_CONTEXT) {
15557f594a49Smartijn switch (varbind->av_value->be_type) {
15567f594a49Smartijn case APPL_EXC_NOSUCHOBJECT:
15577f594a49Smartijn if (next && request != NULL) {
15587f594a49Smartijn *errstr = "Unexpected noSuchObject";
15597f594a49Smartijn return 0;
15607f594a49Smartijn }
1561*c3e23a03Smartijn break;
15627f594a49Smartijn case APPL_EXC_NOSUCHINSTANCE:
15637f594a49Smartijn if (next && request != NULL) {
15647f594a49Smartijn *errstr = "Unexpected noSuchInstance";
15657f594a49Smartijn return 0;
15667f594a49Smartijn }
15677f594a49Smartijn break;
15687f594a49Smartijn case APPL_EXC_ENDOFMIBVIEW:
15697f594a49Smartijn if (!next && request != NULL) {
15707f594a49Smartijn *errstr = "Unexpected endOfMibView";
15717f594a49Smartijn return 0;
15727f594a49Smartijn }
15737f594a49Smartijn eomv = 1;
15747f594a49Smartijn break;
15757f594a49Smartijn default:
1576*c3e23a03Smartijn *errstr = "invalid value encoding";
15777f594a49Smartijn return 0;
15787f594a49Smartijn }
15797f594a49Smartijn } else {
1580*c3e23a03Smartijn *errstr = "invalid value encoding";
15817f594a49Smartijn return 0;
15827f594a49Smartijn }
15837f594a49Smartijn
15847f594a49Smartijn if (request == NULL)
15857f594a49Smartijn return 1;
15867f594a49Smartijn
158716d26808Smartijn cmp = ober_oid_cmp(&(request->avi_varbind.av_oid), &(varbind->av_oid));
158816d26808Smartijn if (next) {
158916d26808Smartijn if (request->avi_region->ar_instance &&
159016d26808Smartijn ober_oid_cmp(&(request->avi_region->ar_oid),
159116d26808Smartijn &(varbind->av_oid)) != 0) {
159216d26808Smartijn *errstr = "oid below instance";
159316d26808Smartijn return 0;
159416d26808Smartijn }
159516d26808Smartijn if (!eomv) {
159616d26808Smartijn if (request->avi_varbind.av_include) {
15977f594a49Smartijn if (cmp > 0) {
15987f594a49Smartijn *errstr = "oid not incrementing";
15997f594a49Smartijn return 0;
16007f594a49Smartijn }
16017f594a49Smartijn } else {
16027f594a49Smartijn if (cmp >= 0) {
16037f594a49Smartijn *errstr = "oid not incrementing";
16047f594a49Smartijn return 0;
16057f594a49Smartijn }
16067f594a49Smartijn }
16071345d1c8Smartijn if (range && ober_oid_cmp(&(varbind->av_oid),
1608fdfe462fSmartijn &(request->avi_varbind.av_oid_end)) >= 0) {
16091345d1c8Smartijn *errstr = "end oid not honoured";
16101345d1c8Smartijn return 0;
16111345d1c8Smartijn }
161216d26808Smartijn }
16137f594a49Smartijn } else {
16147f594a49Smartijn if (cmp != 0) {
16157f594a49Smartijn *errstr = "oids not equal";
16167f594a49Smartijn return 0;
16177f594a49Smartijn }
16187f594a49Smartijn }
16197f594a49Smartijn return 1;
16207f594a49Smartijn }
16217f594a49Smartijn
1622*c3e23a03Smartijn unsigned int
appl_ber_any(struct ber_element * elm)1623*c3e23a03Smartijn appl_ber_any(struct ber_element *elm)
1624*c3e23a03Smartijn {
1625*c3e23a03Smartijn return BER_TYPE_OCTETSTRING;
1626*c3e23a03Smartijn }
1627*c3e23a03Smartijn
16287f594a49Smartijn int
appl_error_valid(enum appl_error error,enum snmp_pdutype type)1629c1fbd6d4Smartijn appl_error_valid(enum appl_error error, enum snmp_pdutype type)
1630c1fbd6d4Smartijn {
1631c1fbd6d4Smartijn switch (error) {
1632c1fbd6d4Smartijn case APPL_ERROR_NOERROR:
1633c1fbd6d4Smartijn case APPL_ERROR_TOOBIG:
1634c1fbd6d4Smartijn case APPL_ERROR_NOSUCHNAME:
1635c1fbd6d4Smartijn case APPL_ERROR_GENERR:
1636c1fbd6d4Smartijn return 1;
1637c1fbd6d4Smartijn case APPL_ERROR_BADVALUE:
1638c1fbd6d4Smartijn case APPL_ERROR_READONLY:
1639c1fbd6d4Smartijn case APPL_ERROR_NOACCESS:
1640c1fbd6d4Smartijn case APPL_ERROR_WRONGTYPE:
1641c1fbd6d4Smartijn case APPL_ERROR_WRONGLENGTH:
1642c1fbd6d4Smartijn case APPL_ERROR_WRONGENCODING:
1643c1fbd6d4Smartijn case APPL_ERROR_WRONGVALUE:
1644c1fbd6d4Smartijn case APPL_ERROR_NOCREATION:
1645c1fbd6d4Smartijn case APPL_ERROR_INCONSISTENTVALUE:
1646c1fbd6d4Smartijn case APPL_ERROR_RESOURCEUNAVAILABLE:
1647c1fbd6d4Smartijn case APPL_ERROR_COMMITFAILED:
1648c1fbd6d4Smartijn case APPL_ERROR_UNDOFAILED:
1649c1fbd6d4Smartijn case APPL_ERROR_NOTWRITABLE:
1650c1fbd6d4Smartijn case APPL_ERROR_INCONSISTENTNAME:
1651c1fbd6d4Smartijn return type == SNMP_C_SETREQ;
1652c1fbd6d4Smartijn case APPL_ERROR_AUTHORIZATIONERROR:
1653c1fbd6d4Smartijn return type == SNMP_C_GETREQ || type == SNMP_C_SETREQ;
1654c1fbd6d4Smartijn default:
1655c1fbd6d4Smartijn return 0;
1656c1fbd6d4Smartijn }
1657c1fbd6d4Smartijn }
1658c1fbd6d4Smartijn
1659c1fbd6d4Smartijn int
appl_varbind_backend(struct appl_varbind_internal * ivb)16607f594a49Smartijn appl_varbind_backend(struct appl_varbind_internal *ivb)
16617f594a49Smartijn {
16627f594a49Smartijn struct appl_request_upstream *ureq = ivb->avi_request_upstream;
16637f594a49Smartijn struct appl_region search, *region, *pregion;
16647f594a49Smartijn struct appl_varbind *vb = &(ivb->avi_varbind);
1665ee42e1e9Smartijn struct ber_oid oid, nextsibling;
16667f594a49Smartijn int next, cmp;
16677f594a49Smartijn
1668e40a541eSmartijn next = ureq->aru_requesttype == SNMP_C_GETNEXTREQ ||
1669e40a541eSmartijn ureq->aru_requesttype == SNMP_C_GETBULKREQ;
16707f594a49Smartijn
16717f594a49Smartijn region = appl_region_find(ureq->aru_ctx, &(vb->av_oid));
16727f594a49Smartijn if (region == NULL) {
16737f594a49Smartijn if (!next) {
16747f594a49Smartijn vb->av_value = appl_exception(APPL_EXC_NOSUCHOBJECT);
16757f594a49Smartijn ivb->avi_state = APPL_VBSTATE_DONE;
16767f594a49Smartijn if (vb->av_value == NULL)
16777f594a49Smartijn return -1;
16787f594a49Smartijn return 0;
16797f594a49Smartijn }
16807f594a49Smartijn search.ar_oid = vb->av_oid;
16817f594a49Smartijn region = RB_NFIND(appl_regions,
16827f594a49Smartijn &(ureq->aru_ctx->ac_regions), &search);
16837f594a49Smartijn if (region == NULL)
16847f594a49Smartijn goto eomv;
16857f594a49Smartijn vb->av_oid = region->ar_oid;
16867f594a49Smartijn vb->av_include = 1;
16877f594a49Smartijn }
16887f594a49Smartijn cmp = ober_oid_cmp(&(region->ar_oid), &(vb->av_oid));
16897f594a49Smartijn if (cmp == -2) {
16907f594a49Smartijn if (region->ar_instance) {
16917f594a49Smartijn if (!next) {
16927f594a49Smartijn vb->av_value =
16937f594a49Smartijn appl_exception(APPL_EXC_NOSUCHINSTANCE);
16947f594a49Smartijn ivb->avi_state = APPL_VBSTATE_DONE;
16957f594a49Smartijn if (vb->av_value == NULL)
16967f594a49Smartijn return -1;
16977f594a49Smartijn return 0;
16987f594a49Smartijn }
16997f594a49Smartijn vb->av_oid = region->ar_oid;
1700f2ee28c5Smartijn ober_oid_nextsibling(&(vb->av_oid));
17017f594a49Smartijn vb->av_include = 1;
1702f2ee28c5Smartijn return appl_varbind_backend(ivb);
17037f594a49Smartijn }
17047f594a49Smartijn } else if (cmp == 0) {
17057f594a49Smartijn if (region->ar_instance && next && !vb->av_include) {
17067f594a49Smartijn vb->av_oid = region->ar_oid;
1707f2ee28c5Smartijn ober_oid_nextsibling(&(vb->av_oid));
17087f594a49Smartijn vb->av_include = 1;
1709f2ee28c5Smartijn return appl_varbind_backend(ivb);
17107f594a49Smartijn }
17117f594a49Smartijn }
17127f594a49Smartijn ivb->avi_region = region;
17137f594a49Smartijn if (next) {
1714ee42e1e9Smartijn oid = vb->av_oid;
1715ee42e1e9Smartijn /*
1716ee42e1e9Smartijn * For the searchrange end we only want contiguous regions.
1717ee42e1e9Smartijn * This means directly connecting, or overlapping with the same
1718ee42e1e9Smartijn * backend.
1719ee42e1e9Smartijn */
17207f594a49Smartijn do {
17217f594a49Smartijn pregion = region;
1722e8bc0ca5Smartijn region = appl_region_next(ureq->aru_ctx, &oid, pregion);
17237f594a49Smartijn if (region == NULL) {
1724ee42e1e9Smartijn oid = pregion->ar_oid;
1725ee42e1e9Smartijn ober_oid_nextsibling(&oid);
1726ee42e1e9Smartijn break;
1727ee42e1e9Smartijn }
1728ee42e1e9Smartijn cmp = ober_oid_cmp(&(region->ar_oid), &oid);
1729ee42e1e9Smartijn if (cmp == 2)
1730ee42e1e9Smartijn oid = region->ar_oid;
1731ee42e1e9Smartijn else if (cmp == 1) {
1732ee42e1e9Smartijn /* Break out if we find a gap */
1733ee42e1e9Smartijn nextsibling = pregion->ar_oid;
1734ee42e1e9Smartijn ober_oid_nextsibling(&nextsibling);
17357f594a49Smartijn if (ober_oid_cmp(&(region->ar_oid),
1736ee42e1e9Smartijn &nextsibling) != 0) {
1737ee42e1e9Smartijn oid = pregion->ar_oid;
1738ee42e1e9Smartijn ober_oid_nextsibling(&oid);
1739ee42e1e9Smartijn break;
17407f594a49Smartijn }
1741ee42e1e9Smartijn oid = region->ar_oid;
1742ee42e1e9Smartijn } else if (cmp == -2) {
1743ee42e1e9Smartijn oid = pregion->ar_oid;
1744ee42e1e9Smartijn ober_oid_nextsibling(&oid);
1745ee42e1e9Smartijn } else
1746ee42e1e9Smartijn fatalx("We can't stop/move back on getnext");
1747ee42e1e9Smartijn } while (region->ar_backend == pregion->ar_backend);
1748ee42e1e9Smartijn vb->av_oid_end = oid;
17497f594a49Smartijn }
17507f594a49Smartijn return 0;
17517f594a49Smartijn
17527f594a49Smartijn eomv:
17537f594a49Smartijn do {
17547f594a49Smartijn ivb->avi_varbind.av_value =
17557f594a49Smartijn appl_exception(APPL_EXC_ENDOFMIBVIEW);
17567f594a49Smartijn ivb->avi_state = APPL_VBSTATE_DONE;
17577f594a49Smartijn if (ivb->avi_varbind.av_value == NULL)
17587f594a49Smartijn return -1;
17593cf38abbSmartijn if (ivb->avi_sub != NULL) {
17607f594a49Smartijn ivb->avi_sub->avi_varbind.av_oid =
17617f594a49Smartijn ivb->avi_varbind.av_oid;
17623cf38abbSmartijn ivb->avi_sub->avi_origid = ivb->avi_origid;
17633cf38abbSmartijn }
17647f594a49Smartijn ivb = ivb->avi_sub;
17657f594a49Smartijn } while (ivb != NULL);
17667f594a49Smartijn
17677f594a49Smartijn return 0;
17687f594a49Smartijn }
17697f594a49Smartijn
17707f594a49Smartijn void
appl_varbind_error(struct appl_varbind_internal * avi,enum appl_error error)17717f594a49Smartijn appl_varbind_error(struct appl_varbind_internal *avi, enum appl_error error)
17727f594a49Smartijn {
17737f594a49Smartijn struct appl_request_upstream *ureq = avi->avi_request_upstream;
17747f594a49Smartijn
17757f594a49Smartijn if (ureq->aru_error == APPL_ERROR_GENERR)
17767f594a49Smartijn return;
17777f594a49Smartijn if (ureq->aru_error != APPL_ERROR_NOERROR && error != APPL_ERROR_GENERR)
17787f594a49Smartijn return;
17797f594a49Smartijn ureq->aru_error = error;
17807f594a49Smartijn ureq->aru_index = avi->avi_index;
17817f594a49Smartijn }
17827f594a49Smartijn
17837f594a49Smartijn void
appl_report(struct snmp_message * statereference,int32_t requestid,struct ber_oid * oid)1784b12d45ecSmartijn appl_report(struct snmp_message *statereference, int32_t requestid,
1785b12d45ecSmartijn struct ber_oid *oid)
17867f594a49Smartijn {
1787b12d45ecSmartijn struct appl_request_upstream *ureq;
17887f594a49Smartijn
1789b12d45ecSmartijn if ((ureq = calloc(1, sizeof(*ureq))) == NULL)
1790b12d45ecSmartijn fatal("malloc");
1791b12d45ecSmartijn ureq->aru_ctx = appl_context(NULL, 0);
1792b12d45ecSmartijn ureq->aru_statereference = statereference;
1793b12d45ecSmartijn ureq->aru_requesttype = SNMP_C_GETREQ;
1794b12d45ecSmartijn ureq->aru_responsetype = SNMP_C_REPORT;
1795b12d45ecSmartijn ureq->aru_requestid = requestid;
1796b12d45ecSmartijn ureq->aru_transactionid = 0;
1797b12d45ecSmartijn ureq->aru_nonrepeaters = 0;
1798b12d45ecSmartijn ureq->aru_maxrepetitions = 0;
1799b12d45ecSmartijn if ((ureq->aru_vblist = calloc(1, sizeof(*ureq->aru_vblist))) == NULL)
1800b12d45ecSmartijn fatal("malloc");
1801b12d45ecSmartijn ureq->aru_varbindlen = 1;
1802b12d45ecSmartijn ureq->aru_error = APPL_ERROR_NOERROR;
1803b12d45ecSmartijn ureq->aru_index = 0;
1804b12d45ecSmartijn ureq->aru_locked = 0;
1805b12d45ecSmartijn ureq->aru_pduversion = SNMP_V3;
18067f594a49Smartijn
1807b12d45ecSmartijn ureq->aru_vblist[0].avi_state = APPL_VBSTATE_NEW;
1808b12d45ecSmartijn ureq->aru_vblist[0].avi_varbind.av_oid = *oid;
1809b12d45ecSmartijn ureq->aru_vblist[0].avi_varbind.av_value = NULL;
1810b12d45ecSmartijn ureq->aru_vblist[0].avi_varbind.av_next = NULL;
1811b12d45ecSmartijn ureq->aru_vblist[0].avi_origid = *oid;
1812b12d45ecSmartijn ureq->aru_vblist[0].avi_index = 1;
1813b12d45ecSmartijn ureq->aru_vblist[0].avi_request_upstream = ureq;
1814b12d45ecSmartijn ureq->aru_vblist[0].avi_request_downstream = NULL;
1815b12d45ecSmartijn ureq->aru_vblist[0].avi_next = NULL;
1816b12d45ecSmartijn ureq->aru_vblist[0].avi_sub = NULL;
1817b12d45ecSmartijn
1818b12d45ecSmartijn appl_request_upstream_resolve(ureq);
18197f594a49Smartijn }
18207f594a49Smartijn
18217f594a49Smartijn struct ber_element *
appl_exception(enum appl_exception type)18227f594a49Smartijn appl_exception(enum appl_exception type)
18237f594a49Smartijn {
18247f594a49Smartijn struct ber_element *value;
18257f594a49Smartijn
18267f594a49Smartijn if ((value = ober_add_null(NULL)) == NULL) {
18277f594a49Smartijn log_warn("malloc");
18287f594a49Smartijn return NULL;
18297f594a49Smartijn }
18307f594a49Smartijn ober_set_header(value, BER_CLASS_CONTEXT, type);
18317f594a49Smartijn
18327f594a49Smartijn return value;
18337f594a49Smartijn }
18347f594a49Smartijn
18357f594a49Smartijn void
appl_pdu_log(struct appl_backend * backend,enum snmp_pdutype pdutype,int32_t requestid,uint16_t error,uint16_t index,struct appl_varbind * vblist)18367f594a49Smartijn appl_pdu_log(struct appl_backend *backend, enum snmp_pdutype pdutype,
18377f594a49Smartijn int32_t requestid, uint16_t error, uint16_t index,
18387f594a49Smartijn struct appl_varbind *vblist)
18397f594a49Smartijn {
18407f594a49Smartijn struct appl_varbind *vb;
18417f594a49Smartijn char buf[1024], oidbuf[1024], *str;
18427f594a49Smartijn int next;
18437f594a49Smartijn
18447f594a49Smartijn if (log_getverbose() < 2)
18457f594a49Smartijn return;
18467f594a49Smartijn
18477f594a49Smartijn next = (pdutype == SNMP_C_GETNEXTREQ || pdutype == SNMP_C_GETBULKREQ);
18487f594a49Smartijn
18497f594a49Smartijn buf[0] = '\0';
18507f594a49Smartijn for (vb = vblist; vb != NULL; vb = vb->av_next) {
18517f594a49Smartijn strlcat(buf, "{", sizeof(buf));
1852f0bcdb5cSmartijn strlcat(buf, mib_oid2string(&(vb->av_oid), oidbuf,
1853f0bcdb5cSmartijn sizeof(oidbuf), snmpd_env->sc_oidfmt), sizeof(buf));
18547f594a49Smartijn if (next) {
18557f594a49Smartijn if (vb->av_include)
18567f594a49Smartijn strlcat(buf, "(incl)", sizeof(buf));
18577f594a49Smartijn if (vb->av_oid_end.bo_n > 0) {
18587f594a49Smartijn strlcat(buf, "-", sizeof(buf));
1859f0bcdb5cSmartijn strlcat(buf, mib_oid2string(&(vb->av_oid_end),
1860f0bcdb5cSmartijn oidbuf, sizeof(oidbuf),
1861f0bcdb5cSmartijn snmpd_env->sc_oidfmt), sizeof(buf));
18627f594a49Smartijn }
18637f594a49Smartijn }
18647f594a49Smartijn strlcat(buf, ":", sizeof(buf));
18657f594a49Smartijn if (vb->av_value != NULL) {
18667f594a49Smartijn str = smi_print_element(vb->av_value);
18677f594a49Smartijn strlcat(buf, str == NULL ? "???" : str, sizeof(buf));
18687f594a49Smartijn free(str);
18697f594a49Smartijn } else
18707f594a49Smartijn strlcat(buf, "null", sizeof(buf));
18717f594a49Smartijn strlcat(buf, "}", sizeof(buf));
18727f594a49Smartijn }
18737f594a49Smartijn log_debug("%s%s%s{%"PRId32", %"PRIu16", %"PRIu16", {%s}}",
18747f594a49Smartijn backend != NULL ? backend->ab_name : "",
18757f594a49Smartijn backend != NULL ? ": " : "",
18767f594a49Smartijn snmpe_pdutype2string(pdutype), requestid, error, index, buf);
18777f594a49Smartijn }
18787f594a49Smartijn
18797f594a49Smartijn void
ober_oid_nextsibling(struct ber_oid * oid)18807f594a49Smartijn ober_oid_nextsibling(struct ber_oid *oid)
18817f594a49Smartijn {
18827f594a49Smartijn while (oid->bo_n > 0) {
18837f594a49Smartijn oid->bo_id[oid->bo_n - 1]++;
18847f594a49Smartijn /* Overflow check */
18857f594a49Smartijn if (oid->bo_id[oid->bo_n - 1] != 0)
18867f594a49Smartijn return;
18877f594a49Smartijn oid->bo_n--;
18887f594a49Smartijn }
18897f594a49Smartijn }
18907f594a49Smartijn
18917f594a49Smartijn int
appl_region_cmp(struct appl_region * r1,struct appl_region * r2)18927f594a49Smartijn appl_region_cmp(struct appl_region *r1, struct appl_region *r2)
18937f594a49Smartijn {
18947f594a49Smartijn return ober_oid_cmp(&(r1->ar_oid), &(r2->ar_oid));
18957f594a49Smartijn }
18967f594a49Smartijn
18977f594a49Smartijn int
appl_request_cmp(struct appl_request_downstream * r1,struct appl_request_downstream * r2)18987f594a49Smartijn appl_request_cmp(struct appl_request_downstream *r1,
18997f594a49Smartijn struct appl_request_downstream *r2)
19007f594a49Smartijn {
19017f594a49Smartijn return r1->ard_requestid < r2->ard_requestid ? -1 :
19027f594a49Smartijn r1->ard_requestid > r2->ard_requestid;
19037f594a49Smartijn }
19047f594a49Smartijn
19057f594a49Smartijn RB_GENERATE_STATIC(appl_regions, appl_region, ar_entry, appl_region_cmp);
19067f594a49Smartijn RB_GENERATE_STATIC(appl_requests, appl_request_downstream, ard_entry,
19077f594a49Smartijn appl_request_cmp);
1908