1145522Sdarrenr/* $OpenBSD: application.c,v 1.43 2024/02/08 17:34:09 martijn Exp $ */ 2145522Sdarrenr 357126Sguido/* 457126Sguido * Copyright (c) 2021 Martijn van Duren <martijn@openbsd.org> 5145522Sdarrenr * 6145522Sdarrenr * Permission to use, copy, modify, and distribute this software for any 7145522Sdarrenr * purpose with or without fee is hereby granted, provided that the above 8145522Sdarrenr * copyright notice and this permission notice appear in all copies. 9170268Sdarrenr * 1057126Sguido * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1153642Sguido * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1253642Sguido * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1353642Sguido * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1453642Sguido * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1553642Sguido * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16145522Sdarrenr * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17145522Sdarrenr */ 18145522Sdarrenr 19145522Sdarrenr#include <sys/queue.h> 2053642Sguido#include <sys/time.h> 2153642Sguido#include <sys/tree.h> 2253642Sguido#include <sys/types.h> 23145522Sdarrenr 2453642Sguido#include <assert.h> 25145522Sdarrenr#include <errno.h> 2653642Sguido#include <event.h> 2753642Sguido#include <inttypes.h> 2853642Sguido#include <stdlib.h> 2953642Sguido#include <stdio.h> 3053642Sguido#include <string.h> 3153642Sguido 3253642Sguido#include "application.h" 3353642Sguido#include "log.h" 34145522Sdarrenr#include "mib.h" 35145522Sdarrenr#include "smi.h" 36145522Sdarrenr#include "snmp.h" 3753642Sguido#include "snmpd.h" 3853642Sguido#include "snmpe.h" 3953642Sguido 4053642Sguido#define OID(...) (struct ber_oid){ { __VA_ARGS__ }, \ 41145522Sdarrenr (sizeof((uint32_t []) { __VA_ARGS__ }) / sizeof(uint32_t)) } 42145522Sdarrenr 43145522SdarrenrTAILQ_HEAD(, appl_context) contexts = TAILQ_HEAD_INITIALIZER(contexts); 44145522Sdarrenr 45145522Sdarrenrstruct appl_agentcap { 46145522Sdarrenr struct appl_backend *aa_backend; 47145522Sdarrenr struct appl_context *aa_context; 48145522Sdarrenr uint32_t aa_index; 49145522Sdarrenr struct ber_oid aa_oid; 5053642Sguido char aa_descr[256]; 5153642Sguido int aa_uptime; 5253642Sguido 53145522Sdarrenr TAILQ_ENTRY(appl_agentcap) aa_entry; 5453642Sguido}; 5553642Sguido 5653642Sguidostruct appl_context { 5753642Sguido char ac_name[APPL_CONTEXTNAME_MAX + 1]; 5853642Sguido 5953642Sguido RB_HEAD(appl_regions, appl_region) ac_regions; 6053642Sguido TAILQ_HEAD(, appl_agentcap) ac_agentcaps; 6160857Sdarrenr int ac_agentcap_lastid; 6260857Sdarrenr int ac_agentcap_lastchange; 6360857Sdarrenr 64145522Sdarrenr TAILQ_ENTRY(appl_context) ac_entries; 65145522Sdarrenr}; 66145522Sdarrenr 6760857Sdarrenrstruct appl_region { 6860857Sdarrenr struct ber_oid ar_oid; 6960857Sdarrenr uint8_t ar_priority; 7060857Sdarrenr int32_t ar_timeout; 7153642Sguido int ar_instance; 7253642Sguido int ar_subtree; /* Claim entire subtree */ 7353642Sguido struct appl_backend *ar_backend; 7453642Sguido struct appl_region *ar_next; /* Sorted by priority */ 7553642Sguido 76145522Sdarrenr RB_ENTRY(appl_region) ar_entry; 7753642Sguido}; 7853642Sguido 7953642Sguidostruct appl_request_upstream { 8053642Sguido struct appl_context *aru_ctx; 8153642Sguido struct snmp_message *aru_statereference; 8255929Sguido enum snmp_pdutype aru_requesttype; 8355929Sguido enum snmp_pdutype aru_responsetype; 84145522Sdarrenr int32_t aru_requestid; /* upstream requestid */ 8580482Sdarrenr int32_t aru_transactionid; /* RFC 2741 section 6.1 */ 8653642Sguido uint16_t aru_nonrepeaters; 8753642Sguido uint16_t aru_maxrepetitions; 8853642Sguido struct appl_varbind_internal *aru_vblist; 89145522Sdarrenr size_t aru_varbindlen; 90145522Sdarrenr enum appl_error aru_error; 9153642Sguido int16_t aru_index; 9253642Sguido int aru_locked; /* Prevent recursion through appl_request_send */ 9353642Sguido 9453642Sguido enum snmp_version aru_pduversion; 9553642Sguido}; 9653642Sguido 9753642Sguidostruct appl_request_downstream { 98145522Sdarrenr struct appl_request_upstream *ard_request; 9953642Sguido struct appl_backend *ard_backend; 100145522Sdarrenr enum snmp_pdutype ard_requesttype; 101145522Sdarrenr uint16_t ard_nonrepeaters; 10253642Sguido uint16_t ard_maxrepetitions; 103145522Sdarrenr int32_t ard_requestid; 104145522Sdarrenr uint8_t ard_retries; 105145522Sdarrenr 106145522Sdarrenr struct appl_varbind_internal *ard_vblist; 107145522Sdarrenr struct event ard_timer; 10853642Sguido 10953642Sguido RB_ENTRY(appl_request_downstream) ard_entry; 11053642Sguido}; 111145522Sdarrenr 112145522Sdarrenrenum appl_varbind_state { 113145522Sdarrenr APPL_VBSTATE_MUSTFILL, 114145522Sdarrenr APPL_VBSTATE_NEW, 115145522Sdarrenr APPL_VBSTATE_PENDING, 11653642Sguido APPL_VBSTATE_DONE 11753642Sguido}; 11853642Sguido 11953642Sguidostruct appl_varbind_internal { 12053642Sguido enum appl_varbind_state avi_state; 12153642Sguido struct appl_varbind avi_varbind; 12253642Sguido struct appl_region *avi_region; 12353642Sguido struct ber_oid avi_origid; 12455929Sguido int16_t avi_index; 12553642Sguido struct appl_request_upstream *avi_request_upstream; 12653642Sguido struct appl_request_downstream *avi_request_downstream; 12753642Sguido struct appl_varbind_internal *avi_next; 12853642Sguido struct appl_varbind_internal *avi_sub; 12953642Sguido}; 13053642Sguido 13153642Sguido/* SNMP-TARGET-MIB (RFC 3413) */ 13253642Sguidostruct snmp_target_mib { 13353642Sguido uint32_t snmp_unavailablecontexts; 13453642Sguido uint32_t snmp_unknowncontexts; 13553642Sguido} snmp_target_mib; 13653642Sguido 13753642Sguidovoid appl_agentcap_free(struct appl_agentcap *); 13853642Sguidoenum appl_error appl_region(struct appl_context *, uint32_t, uint8_t, 13953642Sguido struct ber_oid *, uint8_t, int, int, struct appl_backend *); 14053642Sguidovoid appl_region_free(struct appl_context *, struct appl_region *); 14153642Sguidoenum appl_error appl_region_unregister_match(struct appl_context *, uint8_t, 14253642Sguido struct ber_oid *, char *, struct appl_backend *, int); 14353642Sguidostruct appl_region *appl_region_find(struct appl_context *, 14453642Sguido const struct ber_oid *); 14553642Sguidostruct appl_region *appl_region_next(struct appl_context *, 14653642Sguido struct ber_oid *, struct appl_region *); 14753642Sguidovoid appl_request_upstream_free(struct appl_request_upstream *); 14853642Sguidovoid appl_request_downstream_free(struct appl_request_downstream *); 14953642Sguidovoid appl_request_upstream_resolve(struct appl_request_upstream *); 15053642Sguidovoid appl_request_downstream_send(struct appl_request_downstream *); 15153642Sguidovoid appl_request_downstream_timeout(int, short, void *); 15253642Sguidovoid appl_request_upstream_reply(struct appl_request_upstream *); 15353642Sguidoint appl_varbind_valid(struct appl_varbind *, struct appl_varbind_internal *, 15453642Sguido int, int, int, const char **); 15553642Sguidoint appl_error_valid(enum appl_error, enum snmp_pdutype); 15653642Sguidounsigned int appl_ber_any(struct ber_element *); 15753642Sguidoint appl_varbind_backend(struct appl_varbind_internal *); 15853642Sguidovoid appl_varbind_error(struct appl_varbind_internal *, enum appl_error); 15953642Sguidovoid appl_pdu_log(struct appl_backend *, enum snmp_pdutype, int32_t, uint16_t, 16053642Sguido uint16_t, struct appl_varbind *); 16153642Sguidovoid ober_oid_nextsibling(struct ber_oid *); 16253642Sguido 16353642Sguidoint appl_region_cmp(struct appl_region *, struct appl_region *); 16453642Sguidoint appl_request_cmp(struct appl_request_downstream *, 16553642Sguido struct appl_request_downstream *); 16653642Sguido 16753642SguidoRB_PROTOTYPE_STATIC(appl_regions, appl_region, ar_entry, appl_region_cmp); 16853642SguidoRB_PROTOTYPE_STATIC(appl_requests, appl_request_downstream, ard_entry, 16953642Sguido appl_request_cmp); 17053642Sguido 17153642Sguido#define APPL_CONTEXT_NAME(ctx) (ctx->ac_name[0] == '\0' ? NULL : ctx->ac_name) 17253642Sguido 17353642Sguidovoid 17453642Sguidoappl(void) 17553642Sguido{ 17653642Sguido appl_agentx(); 17753642Sguido} 17855929Sguido 17953642Sguidovoid 18053642Sguidoappl_init(void) 18153642Sguido{ 182145522Sdarrenr appl_blocklist_init(); 18353642Sguido appl_internal_init(); 18453642Sguido appl_agentx_init(); 18553642Sguido} 18653642Sguido 18755929Sguidovoid 18855929Sguidoappl_shutdown(void) 18953642Sguido{ 19055929Sguido struct appl_context *ctx, *tctx; 191145522Sdarrenr 19267614Sdarrenr appl_blocklist_shutdown(); 19355929Sguido appl_internal_shutdown(); 19455929Sguido appl_agentx_shutdown(); 19553642Sguido 196145522Sdarrenr TAILQ_FOREACH_SAFE(ctx, &contexts, ac_entries, tctx) { 19755929Sguido assert(RB_EMPTY(&(ctx->ac_regions))); 198145522Sdarrenr assert(TAILQ_EMPTY(&(ctx->ac_agentcaps))); 19953642Sguido TAILQ_REMOVE(&contexts, ctx, ac_entries); 20053642Sguido free(ctx); 20155929Sguido } 20255929Sguido} 20355929Sguido 20455929Sguidostruct appl_context * 20555929Sguidoappl_context(const char *name, int create) 20655929Sguido{ 20753642Sguido struct appl_context *ctx; 20853642Sguido 209145522Sdarrenr if (name == NULL) 21053642Sguido name = ""; 211145522Sdarrenr 212145522Sdarrenr if (strlen(name) > APPL_CONTEXTNAME_MAX) { 21353642Sguido errno = EINVAL; 214145522Sdarrenr return NULL; 215145522Sdarrenr } 21653642Sguido 217145522Sdarrenr TAILQ_FOREACH(ctx, &contexts, ac_entries) { 218145522Sdarrenr if (strcmp(name, ctx->ac_name) == 0) 21953642Sguido return ctx; 22053642Sguido } 22153642Sguido 222145522Sdarrenr /* Always allow the default namespace */ 223145522Sdarrenr if (!create && name[0] != '\0') { 224145522Sdarrenr errno = ENOENT; 225145522Sdarrenr return NULL; 226145522Sdarrenr } 227145522Sdarrenr 22853642Sguido if ((ctx = malloc(sizeof(*ctx))) == NULL) 22953642Sguido return NULL; 23053642Sguido 23153642Sguido strlcpy(ctx->ac_name, name, sizeof(ctx->ac_name)); 23253642Sguido RB_INIT(&(ctx->ac_regions)); 23353642Sguido TAILQ_INIT(&(ctx->ac_agentcaps)); 234145522Sdarrenr ctx->ac_agentcap_lastid = 0; 23553642Sguido ctx->ac_agentcap_lastchange = 0; 23653642Sguido 23753642Sguido TAILQ_INSERT_TAIL(&contexts, ctx, ac_entries); 23853642Sguido return ctx; 23953642Sguido} 24053642Sguido 24153642Sguido/* Name from RFC 2741 section 6.2.14 */ 24253642Sguidoenum appl_error 24353642Sguidoappl_addagentcaps(const char *ctxname, struct ber_oid *oid, const char *descr, 24453642Sguido struct appl_backend *backend) 24553642Sguido{ 24653642Sguido struct appl_context *ctx; 24753642Sguido struct appl_agentcap *cap; 24853642Sguido char oidbuf[1024]; 24953642Sguido 25053642Sguido if (ctxname == NULL) 25153642Sguido ctxname = ""; 25253642Sguido 25353642Sguido mib_oid2string(oid, oidbuf, sizeof(oidbuf), snmpd_env->sc_oidfmt); 25455929Sguido log_info("%s: Adding agent capabilities %s context(%s)", 25553642Sguido backend->ab_name, oidbuf, ctxname); 25653642Sguido 25753642Sguido if ((ctx = appl_context(ctxname, 0)) == NULL) { 25855929Sguido log_info("%s: Can't add agent capabilities %s: " 25955929Sguido "Unsupported context \"%s\"", backend->ab_name, oidbuf, 26055929Sguido ctxname); 26155929Sguido return APPL_ERROR_UNSUPPORTEDCONTEXT; 26255929Sguido } 26355929Sguido 26455929Sguido if ((cap = malloc(sizeof(*cap))) == NULL) { 26555929Sguido log_warn("%s: Can't add agent capabilities %s", 26653642Sguido backend->ab_name, oidbuf); 26753642Sguido return APPL_ERROR_PROCESSINGERROR; 26855929Sguido } 269145522Sdarrenr 27055929Sguido cap->aa_backend = backend; 27155929Sguido cap->aa_context = ctx; 27255929Sguido cap->aa_index = ++ctx->ac_agentcap_lastid; 27355929Sguido cap->aa_oid = *oid; 27455929Sguido cap->aa_uptime = smi_getticks(); 27555929Sguido if (strlcpy(cap->aa_descr, descr, 27655929Sguido sizeof(cap->aa_descr)) >= sizeof(cap->aa_descr)) { 27755929Sguido log_info("%s: Can't add agent capabilities %s: " 27855929Sguido "Invalid description", backend->ab_name, oidbuf); 27955929Sguido free(cap); 280145522Sdarrenr return APPL_ERROR_PARSEERROR; 281145522Sdarrenr } 282145522Sdarrenr 283145522Sdarrenr TAILQ_INSERT_TAIL(&(ctx->ac_agentcaps), cap, aa_entry); 28455929Sguido ctx->ac_agentcap_lastchange = cap->aa_uptime; 28555929Sguido 28667853Sdarrenr return APPL_ERROR_NOERROR; 287145522Sdarrenr} 28855929Sguido 28960857Sdarrenr/* Name from RFC2741 section 6.2.15 */ 29060857Sdarrenrenum appl_error 29155929Sguidoappl_removeagentcaps(const char *ctxname, struct ber_oid *oid, 29255929Sguido struct appl_backend *backend) 29355929Sguido{ 29455929Sguido struct appl_context *ctx; 29555929Sguido struct appl_agentcap *cap, *tmp; 29655929Sguido char oidbuf[1024]; 29755929Sguido int found = 0; 29855929Sguido 29955929Sguido if (ctxname == NULL) 30080482Sdarrenr ctxname = ""; 301145522Sdarrenr 302145522Sdarrenr mib_oid2string(oid, oidbuf, sizeof(oidbuf), snmpd_env->sc_oidfmt); 303145522Sdarrenr log_info("%s: Removing agent capabilities %s context(%s)", 304145522Sdarrenr backend->ab_name, oidbuf, ctxname); 305145522Sdarrenr 306145522Sdarrenr if ((ctx = appl_context(ctxname, 0)) == NULL) { 307145522Sdarrenr log_info("%s: Can't remove agent capabilities %s: " 308145522Sdarrenr "Unsupported context \"%s\"", backend->ab_name, oidbuf, 309145522Sdarrenr ctxname); 310170268Sdarrenr return APPL_ERROR_UNSUPPORTEDCONTEXT; 31155929Sguido } 31255929Sguido 31355929Sguido TAILQ_FOREACH_SAFE(cap, &(ctx->ac_agentcaps), aa_entry, tmp) { 31455929Sguido /* No duplicate oid check, just continue */ 31555929Sguido if (cap->aa_backend != backend || 31655929Sguido ober_oid_cmp(oid, &(cap->aa_oid)) != 0) 31755929Sguido continue; 31855929Sguido found = 1; 31955929Sguido appl_agentcap_free(cap); 32080482Sdarrenr } 321145522Sdarrenr 322145522Sdarrenr if (found) 323145522Sdarrenr return APPL_ERROR_NOERROR; 324145522Sdarrenr 325145522Sdarrenr log_info("%s: Can't remove agent capabilities %s: not found", 326145522Sdarrenr backend->ab_name, oidbuf); 327145522Sdarrenr return APPL_ERROR_UNKNOWNAGENTCAPS; 328145522Sdarrenr} 329145522Sdarrenr 330170268Sdarrenrvoid 33155929Sguidoappl_agentcap_free(struct appl_agentcap *cap) 33255929Sguido{ 33360857Sdarrenr TAILQ_REMOVE(&(cap->aa_context->ac_agentcaps), cap, aa_entry); 33455929Sguido cap->aa_context->ac_agentcap_lastchange = smi_getticks(); 33560857Sdarrenr free(cap); 33655929Sguido} 33755929Sguido 33853642Sguidostruct ber_element * 33953642Sguidoappl_sysorlastchange(struct ber_oid *oid) 340{ 341 struct appl_context *ctx; 342 struct ber_element *value; 343 344 ctx = appl_context(NULL, 0); 345 value = ober_add_integer(NULL, ctx->ac_agentcap_lastchange); 346 if (value != NULL) 347 ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS); 348 else 349 log_warn("ober_add_integer"); 350 351 return value; 352} 353 354#define SYSORIDX_POS 10 355struct ber_element * 356appl_sysortable(struct ber_oid *oid) 357{ 358 struct appl_context *ctx; 359 struct appl_agentcap *cap; 360 struct ber_element *value = NULL; 361 362 if (oid->bo_n != SYSORIDX_POS + 1) 363 goto notfound; 364 365 ctx = appl_context(NULL, 0); 366 TAILQ_FOREACH(cap, &(ctx->ac_agentcaps), aa_entry) { 367 if (cap->aa_index == oid->bo_id[SYSORIDX_POS]) 368 break; 369 } 370 if (cap == NULL) 371 goto notfound; 372 373 if (ober_oid_cmp(&OID(MIB_sysORID), oid) == -2) 374 value = ober_add_oid(NULL, &(cap->aa_oid)); 375 else if (ober_oid_cmp(&OID(MIB_sysORDescr), oid) == -2) 376 value = ober_add_string(NULL, cap->aa_descr); 377 else if (ober_oid_cmp(&OID(MIB_sysORUpTime), oid) == -2) { 378 if ((value = ober_add_integer(NULL, cap->aa_uptime)) != NULL) 379 ober_set_header(value, 380 BER_CLASS_APPLICATION, SNMP_T_TIMETICKS); 381 } 382 if (value == NULL) 383 log_warn("ober_add_*"); 384 return value; 385 386 notfound: 387 if ((value = appl_exception(APPL_EXC_NOSUCHINSTANCE)) == NULL) 388 log_warn("appl_exception"); 389 return value; 390} 391 392struct ber_element * 393appl_sysortable_getnext(int8_t include, struct ber_oid *oid) 394{ 395 struct appl_context *ctx; 396 struct appl_agentcap *cap; 397 struct ber_element *value = NULL; 398 399 if (oid->bo_n < SYSORIDX_POS + 1) { 400 include = 1; 401 oid->bo_id[SYSORIDX_POS] = 0; 402 } else if (oid->bo_n < SYSORIDX_POS + 1) 403 include = 0; 404 405 ctx = appl_context(NULL, 0); 406 TAILQ_FOREACH(cap, &(ctx->ac_agentcaps), aa_entry) { 407 if (cap->aa_index > oid->bo_id[SYSORIDX_POS]) 408 break; 409 if (cap->aa_index == oid->bo_id[SYSORIDX_POS] && include) 410 break; 411 } 412 if (cap == NULL) { 413 value = appl_exception(APPL_EXC_NOSUCHINSTANCE); 414 goto done; 415 } 416 417 oid->bo_id[SYSORIDX_POS] = cap->aa_index; 418 oid->bo_n = SYSORIDX_POS + 1; 419 420 if (ober_oid_cmp(&OID(MIB_sysORID), oid) == -2) 421 value = ober_add_oid(NULL, &(cap->aa_oid)); 422 else if (ober_oid_cmp(&OID(MIB_sysORDescr), oid) == -2) 423 value = ober_add_string(NULL, cap->aa_descr); 424 else if (ober_oid_cmp(&OID(MIB_sysORUpTime), oid) == -2) { 425 if ((value = ober_add_integer(NULL, cap->aa_uptime)) != NULL) 426 ober_set_header(value, 427 BER_CLASS_APPLICATION, SNMP_T_TIMETICKS); 428 } 429 done: 430 if (value == NULL) 431 log_warn("ober_add_*"); 432 return value; 433} 434 435struct ber_element * 436appl_targetmib(struct ber_oid *oid) 437{ 438 struct ber_element *value = NULL; 439 440 if (ober_oid_cmp(oid, &OID(MIB_snmpUnavailableContexts, 0)) == 0) 441 value = ober_add_integer(NULL, 442 snmp_target_mib.snmp_unavailablecontexts); 443 else if (ober_oid_cmp(oid, &OID(MIB_snmpUnknownContexts, 0)) == 0) 444 value = ober_add_integer(NULL, 445 snmp_target_mib.snmp_unknowncontexts); 446 447 if (value != NULL) 448 ober_set_header(value, BER_CLASS_APPLICATION, SNMP_T_COUNTER32); 449 return value; 450} 451 452enum appl_error 453appl_region(struct appl_context *ctx, uint32_t timeout, uint8_t priority, 454 struct ber_oid *oid, uint8_t range_subid, int instance, int subtree, 455 struct appl_backend *backend) 456{ 457 struct appl_region *region = NULL, *nregion; 458 char oidbuf[1024], regionbuf[1024], subidbuf[11]; 459 size_t i, bo_n; 460 461 bo_n = oid->bo_n; 462 if (range_subid != 0) 463 oid->bo_n = range_subid; 464 mib_oid2string(oid, oidbuf, sizeof(oidbuf), snmpd_env->sc_oidfmt); 465 if (range_subid != 0) { 466 oid->bo_n = bo_n; 467 i = range_subid + 1; 468 } else 469 i = oid->bo_n; 470 for (; i < oid->bo_n; i++) { 471 strlcat(oidbuf, ".", sizeof(oidbuf)); 472 snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32, 473 oid->bo_id[i]); 474 strlcat(oidbuf, subidbuf, sizeof(oidbuf)); 475 } 476 477 /* 478 * Don't allow overlap when subtree flag is set. 479 * This allows us to keep control of certain regions like system. 480 */ 481 region = appl_region_find(ctx, oid); 482 if (region != NULL && region->ar_subtree && 483 region->ar_backend != backend) 484 goto overlap; 485 486 if ((nregion = malloc(sizeof(*nregion))) == NULL) { 487 log_warn("%s: Can't register %s: Processing error", 488 backend->ab_name, oidbuf); 489 return APPL_ERROR_PROCESSINGERROR; 490 } 491 nregion->ar_oid = *oid; 492 nregion->ar_priority = priority; 493 nregion->ar_timeout = timeout; 494 nregion->ar_instance = instance; 495 nregion->ar_subtree = subtree; 496 nregion->ar_backend = backend; 497 nregion->ar_next = NULL; 498 499 region = RB_INSERT(appl_regions, &(ctx->ac_regions), nregion); 500 if (region == NULL) 501 return APPL_ERROR_NOERROR; 502 503 if (region->ar_priority == priority) 504 goto duplicate; 505 if (region->ar_priority > priority) { 506 RB_REMOVE(appl_regions, &(ctx->ac_regions), region); 507 RB_INSERT(appl_regions, &(ctx->ac_regions), nregion); 508 nregion->ar_next = region; 509 return APPL_ERROR_NOERROR; 510 } 511 512 while (region->ar_next != NULL && 513 region->ar_next->ar_priority < priority) 514 region = region->ar_next; 515 if (region->ar_next != NULL && region->ar_next->ar_priority == priority) 516 goto duplicate; 517 nregion->ar_next = region->ar_next; 518 region->ar_next = nregion; 519 520 return APPL_ERROR_NOERROR; 521 duplicate: 522 free(nregion); 523 log_info("%s: %s priority %"PRId8": Duplicate registration", 524 backend->ab_name, oidbuf, priority); 525 return APPL_ERROR_DUPLICATEREGISTRATION; 526 overlap: 527 regionbuf[0] = '\0'; 528 for (i = 0; i < region->ar_oid.bo_n; i++) { 529 if (i != 0) 530 strlcat(regionbuf, ".", sizeof(regionbuf)); 531 snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32, 532 region->ar_oid.bo_id[i]); 533 strlcat(regionbuf, subidbuf, sizeof(regionbuf)); 534 } 535 log_info("%s: %s overlaps with %s: Request denied", 536 backend->ab_name, oidbuf, regionbuf); 537 return APPL_ERROR_REQUESTDENIED; 538} 539 540/* Name from RFC 2741 section 6.2.3 */ 541enum appl_error 542appl_register(const char *ctxname, uint32_t timeout, uint8_t priority, 543 struct ber_oid *oid, int instance, int subtree, uint8_t range_subid, 544 uint32_t upper_bound, struct appl_backend *backend) 545{ 546 struct appl_context *ctx; 547 struct appl_region *region, search; 548 char oidbuf[1024], subidbuf[11]; 549 enum appl_error error; 550 size_t i, bo_n; 551 uint32_t lower_bound; 552 553 bo_n = oid->bo_n; 554 if (range_subid != 0) 555 oid->bo_n = range_subid; 556 mib_oid2string(oid, oidbuf, sizeof(oidbuf), snmpd_env->sc_oidfmt); 557 if (range_subid != 0) { 558 oid->bo_n = bo_n; 559 i = range_subid + 1; 560 } else 561 i = oid->bo_n; 562 for (; i < oid->bo_n; i++) { 563 strlcat(oidbuf, ".", sizeof(oidbuf)); 564 snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32, oid->bo_id[i]); 565 if (range_subid == i + 1) { 566 strlcat(oidbuf, "[", sizeof(oidbuf)); 567 strlcat(oidbuf, subidbuf, sizeof(oidbuf)); 568 strlcat(oidbuf, "-", sizeof(oidbuf)); 569 snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32, 570 upper_bound); 571 strlcat(oidbuf, subidbuf, sizeof(oidbuf)); 572 strlcat(oidbuf, "]", sizeof(oidbuf)); 573 } else 574 strlcat(oidbuf, subidbuf, sizeof(oidbuf)); 575 } 576 577 if (ctxname == NULL) 578 ctxname = ""; 579 log_info("%s: Registering %s%s context(%s) priority(%"PRIu8") " 580 "timeout(%"PRIu32".%02us)", backend->ab_name, oidbuf, 581 instance ? "(instance)" : "", ctxname, priority, 582 timeout/100, timeout % 100); 583 584 if ((ctx = appl_context(ctxname, 0)) == NULL) { 585 if (errno == ENOMEM) { 586 log_warn("%s: Can't register %s: Processing error", 587 backend->ab_name, oidbuf); 588 return APPL_ERROR_PROCESSINGERROR; 589 } 590 log_info("%s: Can't register %s: Unsupported context \"%s\"", 591 backend->ab_name, oidbuf, ctxname); 592 return APPL_ERROR_UNSUPPORTEDCONTEXT; 593 } 594 /* Default timeouts should be handled by backend */ 595 if (timeout == 0) 596 fatalx("%s: Timeout can't be 0", __func__); 597 if (priority == 0) { 598 log_warnx("%s: Can't register %s: priority can't be 0", 599 backend->ab_name, oidbuf); 600 return APPL_ERROR_PARSEERROR; 601 } 602 603 if (range_subid == 0) 604 return appl_region(ctx, timeout, priority, oid, range_subid, 605 instance, subtree, backend); 606 607 range_subid--; 608 if (range_subid >= oid->bo_n) { 609 log_warnx("%s: Can't register %s: range_subid too large", 610 backend->ab_name, oidbuf); 611 return APPL_ERROR_PARSEERROR; 612 } 613 if (oid->bo_id[range_subid] > upper_bound) { 614 log_warnx("%s: Can't register %s: upper bound smaller than " 615 "range_subid", backend->ab_name, oidbuf); 616 return APPL_ERROR_PARSEERROR; 617 } 618 619 lower_bound = oid->bo_id[range_subid]; 620 do { 621 if ((error = appl_region(ctx, timeout, priority, oid, 622 range_subid, instance, subtree, 623 backend)) != APPL_ERROR_NOERROR) 624 goto fail; 625 } while (oid->bo_id[range_subid]++ != upper_bound); 626 if ((error = appl_region(ctx, timeout, priority, oid, range_subid, 627 instance, subtree, backend)) != APPL_ERROR_NOERROR) 628 goto fail; 629 630 return APPL_ERROR_NOERROR; 631 fail: 632 search.ar_oid = *oid; 633 if (search.ar_oid.bo_id[range_subid] == lower_bound) 634 return error; 635 636 for (search.ar_oid.bo_id[range_subid]--; 637 search.ar_oid.bo_id[range_subid] != lower_bound; 638 search.ar_oid.bo_id[range_subid]--) { 639 region = RB_FIND(appl_regions, &(ctx->ac_regions), &search); 640 while (region->ar_priority != priority) 641 region = region->ar_next; 642 appl_region_free(ctx, region); 643 } 644 region = RB_FIND(appl_regions, &(ctx->ac_regions), &search); 645 while (region->ar_priority != priority) 646 region = region->ar_next; 647 appl_region_free(ctx, region); 648 return error; 649} 650 651/* Name from RFC 2741 section 6.2.4 */ 652enum appl_error 653appl_unregister(const char *ctxname, uint8_t priority, struct ber_oid *oid, 654 uint8_t range_subid, uint32_t upper_bound, struct appl_backend *backend) 655{ 656 struct appl_context *ctx; 657 char oidbuf[1024], subidbuf[11]; 658 enum appl_error error; 659 uint32_t lower_bound; 660 size_t i; 661 662 oidbuf[0] = '\0'; 663 for (i = 0; i < oid->bo_n; i++) { 664 snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32, oid->bo_id[i]); 665 if (i != 0) 666 strlcat(oidbuf, ".", sizeof(oidbuf)); 667 if (range_subid == i + 1) { 668 strlcat(oidbuf, "[", sizeof(oidbuf)); 669 strlcat(oidbuf, subidbuf, sizeof(oidbuf)); 670 strlcat(oidbuf, "-", sizeof(oidbuf)); 671 snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32, 672 upper_bound); 673 strlcat(oidbuf, subidbuf, sizeof(oidbuf)); 674 strlcat(oidbuf, "]", sizeof(oidbuf)); 675 } else 676 strlcat(oidbuf, subidbuf, sizeof(oidbuf)); 677 } 678 679 if (ctxname == NULL) 680 ctxname = ""; 681 log_info("%s: Unregistering %s context(%s) priority(%"PRIu8")", 682 backend->ab_name, oidbuf,ctxname, priority); 683 684 if ((ctx = appl_context(ctxname, 0)) == NULL) { 685 if (errno == ENOMEM) { 686 log_warn("%s: Can't unregister %s: Processing error", 687 backend->ab_name, oidbuf); 688 return APPL_ERROR_PROCESSINGERROR; 689 } 690 log_info("%s: Can't unregister %s: Unsupported context \"%s\"", 691 backend->ab_name, oidbuf, ctxname); 692 return APPL_ERROR_UNSUPPORTEDCONTEXT; 693 } 694 695 if (priority == 0) { 696 log_warnx("%s: Can't unregister %s: priority can't be 0", 697 backend->ab_name, oidbuf); 698 return APPL_ERROR_PARSEERROR; 699 } 700 701 if (range_subid == 0) 702 return appl_region_unregister_match(ctx, priority, oid, oidbuf, 703 backend, 1); 704 705 range_subid--; 706 if (range_subid >= oid->bo_n) { 707 log_warnx("%s: Can't unregiser %s: range_subid too large", 708 backend->ab_name, oidbuf); 709 return APPL_ERROR_PARSEERROR; 710 } 711 if (oid->bo_id[range_subid] > upper_bound) { 712 log_warnx("%s: Can't unregister %s: upper bound smaller than " 713 "range_subid", backend->ab_name, oidbuf); 714 return APPL_ERROR_PARSEERROR; 715 } 716 717 lower_bound = oid->bo_id[range_subid]; 718 do { 719 if ((error = appl_region_unregister_match(ctx, priority, oid, 720 oidbuf, backend, 0)) != APPL_ERROR_NOERROR) 721 return error; 722 } while (oid->bo_id[range_subid]++ != upper_bound); 723 724 oid->bo_id[range_subid] = lower_bound; 725 do { 726 (void)appl_region_unregister_match(ctx, priority, oid, oidbuf, 727 backend, 1); 728 } while (oid->bo_id[range_subid]++ != upper_bound); 729 730 return APPL_ERROR_NOERROR; 731} 732 733enum appl_error 734appl_region_unregister_match(struct appl_context *ctx, uint8_t priority, 735 struct ber_oid *oid, char *oidbuf, struct appl_backend *backend, int dofree) 736{ 737 struct appl_region *region, search; 738 739 search.ar_oid = *oid; 740 region = RB_FIND(appl_regions, &(ctx->ac_regions), &search); 741 while (region != NULL && region->ar_priority < priority) 742 region = region->ar_next; 743 if (region == NULL || region->ar_priority != priority) { 744 log_warnx("%s: Can't unregister %s: region not found", 745 backend->ab_name, oidbuf); 746 return APPL_ERROR_UNKNOWNREGISTRATION; 747 } 748 if (region->ar_backend != backend) { 749 log_warnx("%s: Can't unregister %s: region not owned " 750 "by backend", backend->ab_name, oidbuf); 751 return APPL_ERROR_UNKNOWNREGISTRATION; 752 } 753 if (dofree) 754 appl_region_free(ctx, region); 755 return APPL_ERROR_NOERROR; 756} 757 758void 759appl_region_free(struct appl_context *ctx, struct appl_region *region) 760{ 761 struct appl_region *pregion; 762 763 pregion = RB_FIND(appl_regions, &(ctx->ac_regions), region); 764 765 if (pregion == region) { 766 RB_REMOVE(appl_regions, &(ctx->ac_regions), region); 767 if (region->ar_next != NULL) 768 RB_INSERT(appl_regions, &(ctx->ac_regions), 769 region->ar_next); 770 } else { 771 while (pregion->ar_next != region) 772 pregion = pregion->ar_next; 773 pregion->ar_next = region->ar_next; 774 } 775 776 free(region); 777} 778 779/* backend is owned by the sub-application, just release application.c stuff */ 780void 781appl_close(struct appl_backend *backend) 782{ 783 struct appl_context *ctx; 784 struct appl_agentcap *cap, *tcap; 785 struct appl_region *region, *tregion, *nregion; 786 struct appl_request_downstream *request, *trequest; 787 788 TAILQ_FOREACH(ctx, &contexts, ac_entries) { 789 TAILQ_FOREACH_SAFE(cap, &(ctx->ac_agentcaps), aa_entry, tcap) { 790 if (cap->aa_backend == backend) 791 appl_agentcap_free(cap); 792 } 793 RB_FOREACH_SAFE(region, appl_regions, 794 &(ctx->ac_regions), tregion) { 795 while (region != NULL) { 796 nregion = region->ar_next; 797 if (region->ar_backend == backend) 798 appl_region_free(ctx, region); 799 region = nregion; 800 } 801 } 802 } 803 804 RB_FOREACH_SAFE(request, appl_requests, 805 &(backend->ab_requests), trequest) 806 appl_request_downstream_free(request); 807} 808 809struct appl_region * 810appl_region_find(struct appl_context *ctx, 811 const struct ber_oid *oid) 812{ 813 struct appl_region *region, search; 814 815 search.ar_oid = *oid; 816 while (search.ar_oid.bo_n > 0) { 817 region = RB_FIND(appl_regions, &(ctx->ac_regions), &search); 818 if (region != NULL) 819 return region; 820 search.ar_oid.bo_n--; 821 } 822 return NULL; 823} 824 825struct appl_region * 826appl_region_next(struct appl_context *ctx, struct ber_oid *oid, 827 struct appl_region *cregion) 828{ 829 struct appl_region search, *nregion, *pregion; 830 int cmp; 831 832 search.ar_oid = *oid; 833 nregion = RB_NFIND(appl_regions, &(ctx->ac_regions), &search); 834 835 if (cregion == nregion) 836 nregion = RB_NEXT(appl_regions, &(ctx->ac_regions), nregion); 837 /* Past last element in tree, we might still have a parent */ 838 if (nregion == NULL) { 839 search.ar_oid = cregion->ar_oid; 840 search.ar_oid.bo_n--; 841 return appl_region_find(ctx, &(search.ar_oid)); 842 } 843 cmp = appl_region_cmp(cregion, nregion); 844 if (cmp >= 0) 845 fatalx("%s: wrong OID order", __func__); 846 /* Direct descendant */ 847 if (cmp == -2) 848 return nregion; 849 850 /* cmp == -1 */ 851 search.ar_oid = cregion->ar_oid; 852 /* Find direct next sibling */ 853 ober_oid_nextsibling(&(search.ar_oid)); 854 if (ober_oid_cmp(&(nregion->ar_oid), &(search.ar_oid)) == 0) 855 return nregion; 856 /* Sibling gaps go to parent, or end end at border */ 857 search.ar_oid = cregion->ar_oid; 858 search.ar_oid.bo_n--; 859 pregion = appl_region_find(ctx, &(search.ar_oid)); 860 861 return pregion != NULL ? pregion : nregion; 862} 863 864/* Name from RFC 3413 section 3.2 */ 865void 866appl_processpdu(struct snmp_message *statereference, const char *ctxname, 867 enum snmp_version pduversion, struct ber_element *pdu) 868{ 869 struct appl_context *ctx; 870 struct appl_request_upstream *ureq; 871 struct ber_element *varbind, *varbindlist; 872 long long nonrepeaters, maxrepetitions; 873 static uint32_t transactionid; 874 int32_t requestid; 875 size_t i, varbindlen = 0, repeaterlen; 876 877 /* pdu must be ASN.1 validated in snmpe.c */ 878 (void) ober_scanf_elements(pdu, "{diie", &requestid, &nonrepeaters, 879 &maxrepetitions, &varbindlist); 880 881 /* RFC 3413, section 3.2, processPDU, item 5, final bullet */ 882 if ((ctx = appl_context(ctxname, 0)) == NULL) { 883 snmp_target_mib.snmp_unknowncontexts++; 884 appl_report(statereference, requestid, 885 &OID(MIB_snmpUnknownContexts, 0)); 886 return; 887 } 888 889 if ((ureq = malloc(sizeof(*ureq))) == NULL) 890 fatal("malloc"); 891 892 ureq->aru_ctx = ctx; 893 ureq->aru_statereference = statereference; 894 ureq->aru_transactionid = transactionid++; 895 ureq->aru_requesttype = pdu->be_type; 896 ureq->aru_responsetype = SNMP_C_RESPONSE; 897 ureq->aru_requestid = requestid; 898 ureq->aru_error = APPL_ERROR_NOERROR; 899 ureq->aru_index = 0; 900 ureq->aru_nonrepeaters = nonrepeaters; 901 ureq->aru_maxrepetitions = maxrepetitions; 902 ureq->aru_varbindlen = 0; 903 ureq->aru_locked = 0; 904 ureq->aru_pduversion = pduversion; 905 906 varbind = varbindlist->be_sub; 907 for (; varbind != NULL; varbind = varbind->be_next) 908 varbindlen++; 909 910 repeaterlen = varbindlen - nonrepeaters; 911 if (pdu->be_type == SNMP_C_GETBULKREQ) 912 ureq->aru_varbindlen = nonrepeaters + 913 (repeaterlen * maxrepetitions); 914 else 915 ureq->aru_varbindlen = varbindlen; 916 if ((ureq->aru_vblist = calloc(ureq->aru_varbindlen, 917 sizeof(*ureq->aru_vblist))) == NULL) 918 fatal("malloc"); 919 920 varbind = varbindlist->be_sub; 921 /* Use aru_varbindlen in case maxrepetitions == 0 */ 922 for (i = 0; i < ureq->aru_varbindlen; i++) { 923 ureq->aru_vblist[i].avi_request_upstream = ureq; 924 ureq->aru_vblist[i].avi_index = i + 1; 925 ureq->aru_vblist[i].avi_state = APPL_VBSTATE_NEW; 926 /* This can only happen with bulkreq */ 927 if (varbind == NULL) { 928 ureq->aru_vblist[i - repeaterlen].avi_sub = 929 &(ureq->aru_vblist[i]); 930 ureq->aru_vblist[i].avi_state = APPL_VBSTATE_MUSTFILL; 931 ureq->aru_vblist[i].avi_index = 932 ureq->aru_vblist[i - repeaterlen].avi_index; 933 continue; 934 } 935 ober_get_oid(varbind->be_sub, 936 &(ureq->aru_vblist[i].avi_varbind.av_oid)); 937 ureq->aru_vblist[i].avi_origid = 938 ureq->aru_vblist[i].avi_varbind.av_oid; 939 if (i + 1 < varbindlen) 940 ureq->aru_vblist[i].avi_varbind.av_next = 941 &(ureq->aru_vblist[i + 1].avi_varbind); 942 else 943 ureq->aru_vblist[i].avi_varbind.av_next = NULL; 944 varbind = varbind->be_next; 945 } 946 947 appl_pdu_log(NULL, pdu->be_type, requestid, nonrepeaters, 948 maxrepetitions, &(ureq->aru_vblist[0].avi_varbind)); 949 950 appl_request_upstream_resolve(ureq); 951} 952 953void 954appl_request_upstream_free(struct appl_request_upstream *ureq) 955{ 956 size_t i; 957 struct appl_varbind_internal *vb; 958 959 if (ureq == NULL) 960 return; 961 962 ureq->aru_locked = 1; 963 for (i = 0; i < ureq->aru_varbindlen && ureq->aru_vblist != NULL; i++) { 964 vb = &(ureq->aru_vblist[i]); 965 ober_free_elements(vb->avi_varbind.av_value); 966 appl_request_downstream_free(vb->avi_request_downstream); 967 } 968 free(ureq->aru_vblist); 969 970 assert(ureq->aru_statereference == NULL); 971 972 free(ureq); 973} 974 975void 976appl_request_downstream_free(struct appl_request_downstream *dreq) 977{ 978 struct appl_varbind_internal *vb; 979 980 if (dreq == NULL) 981 return; 982 983 RB_REMOVE(appl_requests, &(dreq->ard_backend->ab_requests), dreq); 984 evtimer_del(&(dreq->ard_timer)); 985 986 for (vb = dreq->ard_vblist; vb != NULL; vb = vb->avi_next) { 987 vb->avi_request_downstream = NULL; 988 if (vb->avi_state == APPL_VBSTATE_PENDING) 989 vb->avi_state = APPL_VBSTATE_NEW; 990 } 991 992 appl_request_upstream_resolve(dreq->ard_request); 993 free(dreq); 994} 995 996void 997appl_request_upstream_resolve(struct appl_request_upstream *ureq) 998{ 999 struct appl_varbind_internal *vb, *lvb, *tvb; 1000 struct appl_request_downstream *dreq; 1001 struct appl_region *region, *lregion; 1002 struct timeval tv; 1003 int done; 1004 size_t i; 1005 int32_t maxrepetitions; 1006 int32_t timeout; 1007 1008 if (ureq->aru_locked) 1009 return; 1010 ureq->aru_locked = 1; 1011 1012 if (ureq->aru_requesttype == SNMP_C_SETREQ) { 1013 ureq->aru_error = APPL_ERROR_NOTWRITABLE; 1014 ureq->aru_index = 1; 1015 appl_request_upstream_reply(ureq); 1016 return; 1017 } 1018 1019 next: 1020 dreq = NULL; 1021 lvb = NULL; 1022 done = 1; 1023 timeout = 0; 1024 1025 if (ureq->aru_error != APPL_ERROR_NOERROR) { 1026 appl_request_upstream_reply(ureq); 1027 return; 1028 } 1029 for (i = 0; i < ureq->aru_varbindlen; i++) { 1030 vb = &(ureq->aru_vblist[i]); 1031 1032 switch (vb->avi_state) { 1033 case APPL_VBSTATE_MUSTFILL: 1034 case APPL_VBSTATE_PENDING: 1035 done = 0; 1036 continue; 1037 case APPL_VBSTATE_DONE: 1038 continue; 1039 case APPL_VBSTATE_NEW: 1040 break; 1041 } 1042 if (appl_varbind_backend(vb) == -1) 1043 fatal("appl_varbind_backend"); 1044 if (vb->avi_state != APPL_VBSTATE_DONE) 1045 done = 0; 1046 } 1047 1048 for (i = 0; i < ureq->aru_varbindlen; i++) { 1049 vb = &(ureq->aru_vblist[i]); 1050 1051 if (vb->avi_state != APPL_VBSTATE_NEW) 1052 continue; 1053 1054 vb = &(ureq->aru_vblist[i]); 1055 region = vb->avi_region; 1056 lregion = lvb != NULL ? lvb->avi_region : NULL; 1057 if (lvb != NULL && region->ar_backend != lregion->ar_backend) 1058 continue; 1059 1060 vb->avi_varbind.av_next = NULL; 1061 vb->avi_next = NULL; 1062 tvb = vb; 1063 for (maxrepetitions = 0; tvb != NULL; tvb = tvb->avi_sub) 1064 maxrepetitions++; 1065 if (dreq == NULL) { 1066 if ((dreq = malloc(sizeof(*dreq))) == NULL) 1067 fatal("malloc"); 1068 1069 dreq->ard_request = ureq; 1070 dreq->ard_vblist = vb; 1071 dreq->ard_backend = vb->avi_region->ar_backend; 1072 dreq->ard_retries = dreq->ard_backend->ab_retries; 1073 dreq->ard_requesttype = ureq->aru_requesttype; 1074 /* 1075 * We don't yet fully handle bulkrequest responses. 1076 * It's completely valid to map onto getrequest. 1077 * maxrepetitions calculated in preparation of support. 1078 */ 1079 if (dreq->ard_requesttype == SNMP_C_GETBULKREQ && 1080 dreq->ard_backend->ab_fn->ab_getbulk == NULL) 1081 dreq->ard_requesttype = SNMP_C_GETNEXTREQ; 1082 /* 1083 * If first varbind is nonrepeater, set maxrepetitions 1084 * to 0, so that the next varbind with 1085 * maxrepetitions > 1 determines length. 1086 */ 1087 if (maxrepetitions == 1) { 1088 dreq->ard_maxrepetitions = 0; 1089 dreq->ard_nonrepeaters = 1; 1090 } else { 1091 dreq->ard_maxrepetitions = maxrepetitions; 1092 dreq->ard_nonrepeaters = 0; 1093 } 1094 do { 1095 dreq->ard_requestid = arc4random(); 1096 } while (RB_INSERT(appl_requests, 1097 &(dreq->ard_backend->ab_requests), dreq) != NULL); 1098 lvb = vb; 1099 /* avi_sub isn't set on !bulkrequest, so we always enter here */ 1100 } else if (maxrepetitions == 1) { 1101 dreq->ard_nonrepeaters++; 1102 vb->avi_varbind.av_next = 1103 &(dreq->ard_vblist->avi_varbind); 1104 vb->avi_next = dreq->ard_vblist; 1105 dreq->ard_vblist = vb; 1106 } else { 1107 lvb->avi_varbind.av_next = &(vb->avi_varbind); 1108 lvb->avi_next = vb; 1109 /* RFC 2741 section 7.2.1.3: 1110 * The value of g.max_repetitions in the GetBulk-PDU may 1111 * be less than (but not greater than) the value in the 1112 * original request PDU. 1113 */ 1114 if (dreq->ard_maxrepetitions > maxrepetitions || 1115 dreq->ard_maxrepetitions == 0) 1116 dreq->ard_maxrepetitions = maxrepetitions; 1117 lvb = vb; 1118 } 1119 vb->avi_request_downstream = dreq; 1120 vb->avi_state = APPL_VBSTATE_PENDING; 1121 if (region->ar_timeout > timeout) 1122 timeout = region->ar_timeout; 1123 } 1124 1125 if (dreq == NULL) { 1126 ureq->aru_locked = 0; 1127 if (done) 1128 appl_request_upstream_reply(ureq); 1129 return; 1130 } 1131 1132 tv.tv_sec = timeout / 100; 1133 tv.tv_usec = (timeout % 100) * 10000; 1134 evtimer_set(&(dreq->ard_timer), appl_request_downstream_timeout, dreq); 1135 evtimer_add(&(dreq->ard_timer), &tv); 1136 1137 appl_request_downstream_send(dreq); 1138 goto next; 1139} 1140 1141void 1142appl_request_downstream_send(struct appl_request_downstream *dreq) 1143{ 1144 1145 appl_pdu_log(dreq->ard_backend, dreq->ard_requesttype, 1146 dreq->ard_requestid, 0, 0, &(dreq->ard_vblist->avi_varbind)); 1147 1148 if (dreq->ard_requesttype == SNMP_C_GETREQ) { 1149 dreq->ard_backend->ab_fn->ab_get(dreq->ard_backend, 1150 dreq->ard_request->aru_transactionid, 1151 dreq->ard_requestid, 1152 APPL_CONTEXT_NAME(dreq->ard_request->aru_ctx), 1153 &(dreq->ard_vblist->avi_varbind)); 1154 } else if (dreq->ard_requesttype == SNMP_C_GETNEXTREQ) { 1155 dreq->ard_backend->ab_fn->ab_getnext(dreq->ard_backend, 1156 dreq->ard_request->aru_transactionid, 1157 dreq->ard_requestid, 1158 APPL_CONTEXT_NAME(dreq->ard_request->aru_ctx), 1159 &(dreq->ard_vblist->avi_varbind)); 1160 } 1161} 1162 1163void 1164appl_request_downstream_timeout(__unused int fd, __unused short event, 1165 void *cookie) 1166{ 1167 struct appl_request_downstream *dreq = cookie; 1168 1169 log_info("%s: %"PRIu32" timed out%s", 1170 dreq->ard_backend->ab_name, dreq->ard_requestid, 1171 dreq->ard_retries > 0 ? ": retrying" : ""); 1172 if (dreq->ard_retries > 0) { 1173 dreq->ard_retries--; 1174 appl_request_downstream_send(dreq); 1175 } else 1176 appl_response(dreq->ard_backend, dreq->ard_requestid, 1177 APPL_ERROR_GENERR, 1, &(dreq->ard_vblist->avi_varbind)); 1178} 1179 1180void 1181appl_request_upstream_reply(struct appl_request_upstream *ureq) 1182{ 1183 struct ber_element *varbindlist = NULL, *varbind = NULL, *value; 1184 struct appl_varbind_internal *vb; 1185 size_t i, repvarbinds, varbindlen; 1186 ssize_t match = -1; 1187 1188 varbindlen = ureq->aru_varbindlen; 1189 1190 if (ureq->aru_pduversion == SNMP_V1) { 1191 /* RFC 3584 section 4.2.2.2 Map exceptions */ 1192 for (i = 0; i < varbindlen; i++) { 1193 vb = &(ureq->aru_vblist[i]); 1194 value = vb->avi_varbind.av_value; 1195 if (value != NULL && 1196 value->be_class == BER_CLASS_CONTEXT) 1197 appl_varbind_error(vb, APPL_ERROR_NOSUCHNAME); 1198 } 1199 /* RFC 3584 section 4.4 Map errors */ 1200 switch (ureq->aru_error) { 1201 case APPL_ERROR_WRONGVALUE: 1202 case APPL_ERROR_WRONGENCODING: 1203 case APPL_ERROR_WRONGTYPE: 1204 case APPL_ERROR_WRONGLENGTH: 1205 case APPL_ERROR_INCONSISTENTVALUE: 1206 ureq->aru_error = APPL_ERROR_BADVALUE; 1207 break; 1208 case APPL_ERROR_NOACCESS: 1209 case APPL_ERROR_NOTWRITABLE: 1210 case APPL_ERROR_NOCREATION: 1211 case APPL_ERROR_INCONSISTENTNAME: 1212 case APPL_ERROR_AUTHORIZATIONERROR: 1213 ureq->aru_error = APPL_ERROR_NOSUCHNAME; 1214 break; 1215 case APPL_ERROR_RESOURCEUNAVAILABLE: 1216 case APPL_ERROR_COMMITFAILED: 1217 case APPL_ERROR_UNDOFAILED: 1218 ureq->aru_error = APPL_ERROR_GENERR; 1219 break; 1220 default: 1221 break; 1222 } 1223 } 1224 /* RFC 3416 section 4.2.{1,2,3} reset original varbinds */ 1225 if (ureq->aru_error != APPL_ERROR_NOERROR) { 1226 if (ureq->aru_requesttype == SNMP_C_GETBULKREQ) 1227 varbindlen = 1228 (ureq->aru_varbindlen - ureq->aru_nonrepeaters) / 1229 ureq->aru_maxrepetitions; 1230 for (i = 0; i < varbindlen; i++) { 1231 vb = &(ureq->aru_vblist[i]); 1232 vb->avi_varbind.av_oid = vb->avi_origid; 1233 ober_free_elements(vb->avi_varbind.av_value); 1234 vb->avi_varbind.av_value = ober_add_null(NULL); 1235 } 1236 /* RFC 3416 section 4.2.3: Strip excessive EOMV */ 1237 } else if (ureq->aru_requesttype == SNMP_C_GETBULKREQ) { 1238 repvarbinds = (ureq->aru_varbindlen - ureq->aru_nonrepeaters) / 1239 ureq->aru_maxrepetitions; 1240 for (i = ureq->aru_nonrepeaters; 1241 i < ureq->aru_varbindlen - repvarbinds; i++) { 1242 value = ureq->aru_vblist[i].avi_varbind.av_value; 1243 if ((i - ureq->aru_nonrepeaters) % repvarbinds == 0 && 1244 value->be_class == BER_CLASS_CONTEXT && 1245 value->be_type == APPL_EXC_ENDOFMIBVIEW) { 1246 if (match != -1) 1247 break; 1248 match = i; 1249 } 1250 if (value->be_class != BER_CLASS_CONTEXT || 1251 value->be_type != APPL_EXC_ENDOFMIBVIEW) 1252 match = -1; 1253 } 1254 if (match != -1) 1255 varbindlen = match + repvarbinds; 1256 } 1257 1258 for (i = 0; i < varbindlen; i++) { 1259 vb = &(ureq->aru_vblist[i]); 1260 vb->avi_varbind.av_next = 1261 &(ureq->aru_vblist[i + 1].avi_varbind); 1262 value = vb->avi_varbind.av_value; 1263 if (value->be_class == BER_CLASS_CONTEXT && 1264 value->be_type == APPL_EXC_ENDOFMIBVIEW) 1265 vb->avi_varbind.av_oid = vb->avi_origid; 1266 } 1267 1268 ureq->aru_vblist[i - 1].avi_varbind.av_next = NULL; 1269 appl_pdu_log(NULL, ureq->aru_responsetype, ureq->aru_requestid, 1270 ureq->aru_error, ureq->aru_index, 1271 &(ureq->aru_vblist[0].avi_varbind)); 1272 1273 for (i = 0; i < varbindlen; i++) { 1274 varbind = ober_printf_elements(varbind, "{Oe}", 1275 &(ureq->aru_vblist[i].avi_varbind.av_oid), 1276 ureq->aru_vblist[i].avi_varbind.av_value); 1277 ureq->aru_vblist[i].avi_varbind.av_value = NULL; 1278 if (varbind == NULL) 1279 fatal("ober_printf_elements"); 1280 if (varbindlist == NULL) 1281 varbindlist = varbind; 1282 } 1283 1284 snmpe_send(ureq->aru_statereference, ureq->aru_responsetype, 1285 ureq->aru_requestid, ureq->aru_error, ureq->aru_index, varbindlist); 1286 ureq->aru_statereference = NULL; 1287 appl_request_upstream_free(ureq); 1288} 1289 1290/* Name from RFC 2741 section 6.2.16 */ 1291void 1292appl_response(struct appl_backend *backend, int32_t requestid, 1293 enum appl_error error, int16_t index, struct appl_varbind *vblist) 1294{ 1295 struct appl_request_downstream *dreq, search; 1296 struct appl_request_upstream *ureq = NULL; 1297 const char *errstr; 1298 char oidbuf[1024]; 1299 struct appl_varbind *vb; 1300 struct appl_varbind_internal *origvb = NULL; 1301 int invalid = 0; 1302 int next = 0, eomv; 1303 int32_t i; 1304 1305 appl_pdu_log(backend, SNMP_C_RESPONSE, requestid, error, index, vblist); 1306 1307 search.ard_requestid = requestid; 1308 dreq = RB_FIND(appl_requests, &(backend->ab_requests), &search); 1309 if (dreq == NULL) { 1310 log_debug("%s: %"PRIu32" not outstanding", 1311 backend->ab_name, requestid); 1312 /* Continue to verify validity */ 1313 } else { 1314 ureq = dreq->ard_request; 1315 next = ureq->aru_requesttype == SNMP_C_GETNEXTREQ || 1316 ureq->aru_requesttype == SNMP_C_GETBULKREQ; 1317 origvb = dreq->ard_vblist; 1318 if (!appl_error_valid(error, dreq->ard_requesttype)) { 1319 log_warnx("%s: %"PRIu32" Invalid error", 1320 backend->ab_name, requestid); 1321 invalid = 1; 1322 } 1323 } 1324 1325 vb = vblist; 1326 for (i = 1; vb != NULL; vb = vb->av_next, i++) { 1327 if (!appl_varbind_valid(vb, origvb, next, 1328 error != APPL_ERROR_NOERROR, backend->ab_range, &errstr)) { 1329 mib_oid2string(&(vb->av_oid), oidbuf, sizeof(oidbuf), 1330 snmpd_env->sc_oidfmt); 1331 log_warnx("%s: %"PRIu32" %s: %s", 1332 backend->ab_name, requestid, oidbuf, errstr); 1333 invalid = 1; 1334 } 1335 /* Transfer av_value */ 1336 if (origvb != NULL) { 1337 if (error != APPL_ERROR_NOERROR && i == index) 1338 appl_varbind_error(origvb, error); 1339 origvb->avi_state = APPL_VBSTATE_DONE; 1340 origvb->avi_varbind.av_oid = vb->av_oid; 1341 1342 eomv = vb->av_value != NULL && 1343 vb->av_value->be_class == BER_CLASS_CONTEXT && 1344 vb->av_value->be_type == APPL_EXC_ENDOFMIBVIEW; 1345 /* 1346 * Treat results past av_oid_end for backends that 1347 * don't support searchranges as EOMV 1348 */ 1349 eomv |= !backend->ab_range && next && 1350 ober_oid_cmp(&(vb->av_oid), 1351 &(origvb->avi_varbind.av_oid_end)) >= 0; 1352 /* RFC 3584 section 4.2.2.1 */ 1353 if (ureq->aru_pduversion == SNMP_V1 && 1354 vb->av_value != NULL && 1355 vb->av_value->be_class == BER_CLASS_APPLICATION && 1356 vb->av_value->be_type == SNMP_COUNTER64) { 1357 if (next) 1358 eomv = 1; 1359 else 1360 appl_varbind_error(origvb, 1361 APPL_ERROR_NOSUCHNAME); 1362 } 1363 1364 if (eomv) { 1365 ober_free_elements(vb->av_value); 1366 origvb->avi_varbind.av_oid = 1367 origvb->avi_varbind.av_oid_end; 1368 origvb->avi_varbind.av_include = 1; 1369 vb->av_value = NULL; 1370 origvb->avi_state = APPL_VBSTATE_NEW; 1371 } 1372 origvb->avi_varbind.av_value = vb->av_value; 1373 if (origvb->avi_varbind.av_next == NULL && 1374 vb->av_next != NULL) { 1375 log_warnx("%s: Request %"PRIu32" returned more " 1376 "varbinds then requested", 1377 backend->ab_name, requestid); 1378 invalid = 1; 1379 } 1380 if (origvb->avi_sub != NULL && 1381 origvb->avi_state == APPL_VBSTATE_DONE) { 1382 origvb->avi_sub->avi_varbind.av_oid = 1383 origvb->avi_varbind.av_oid; 1384 origvb->avi_sub->avi_origid = 1385 origvb->avi_varbind.av_oid; 1386 origvb->avi_sub->avi_state = APPL_VBSTATE_NEW; 1387 } 1388 origvb = origvb->avi_next; 1389 } else { 1390 ober_free_elements(vb->av_value); 1391 vb->av_value = NULL; 1392 } 1393 } 1394 if (error != APPL_ERROR_NOERROR && (index <= 0 || index >= i)) { 1395 log_warnx("Invalid error index"); 1396 invalid = 1; 1397 } 1398/* amavisd-snmp-subagent sets index to 1, no reason to crash over it. */ 1399#if PEDANTIC 1400 if (error == APPL_ERROR_NOERROR && index != 0) { 1401 log_warnx("error index with no error"); 1402 invalid = 1; 1403 } 1404#endif 1405 if (vb == NULL && origvb != NULL) { 1406 log_warnx("%s: Request %"PRIu32" returned less varbinds then " 1407 "requested", backend->ab_name, requestid); 1408 invalid = 1; 1409 } 1410 1411 if (dreq != NULL) { 1412 if (invalid) 1413 appl_varbind_error(dreq->ard_vblist, APPL_ERROR_GENERR); 1414 appl_request_downstream_free(dreq); 1415 } 1416 1417 if (invalid && backend->ab_fn->ab_close != NULL) { 1418 log_warnx("%s: Closing: Too many parse errors", 1419 backend->ab_name); 1420 backend->ab_fn->ab_close(backend, APPL_CLOSE_REASONPARSEERROR); 1421 } 1422} 1423 1424int 1425appl_varbind_valid(struct appl_varbind *varbind, 1426 struct appl_varbind_internal *request, int next, int null, int range, 1427 const char **errstr) 1428{ 1429 int cmp; 1430 int eomv = 0; 1431 long long intval; 1432 void *buf; 1433 size_t len; 1434 struct ber ber; 1435 struct ber_element *elm; 1436 1437 if (null) 1438 next = 0; 1439 1440 if (varbind->av_value == NULL) { 1441 if (!null) { 1442 *errstr = "missing value"; 1443 return 0; 1444 } 1445 return 1; 1446 } 1447 1448 if (null) { 1449 if (varbind->av_value->be_class != BER_CLASS_UNIVERSAL || 1450 varbind->av_value->be_type != BER_TYPE_NULL) { 1451 *errstr = "expecting null value"; 1452 return 0; 1453 } 1454 } else { 1455 if (varbind->av_value->be_class == BER_CLASS_UNIVERSAL && 1456 varbind->av_value->be_type == BER_TYPE_NULL) { 1457 *errstr = "unexpected null value"; 1458 return 0; 1459 } 1460 } 1461 1462 if (varbind->av_value->be_class == BER_CLASS_UNIVERSAL) { 1463 switch (varbind->av_value->be_type) { 1464 case BER_TYPE_NULL: 1465 /* Checked above */ 1466 break; 1467 case BER_TYPE_INTEGER: 1468 (void)ober_get_integer(varbind->av_value, &intval); 1469 if (intval < SMI_INTEGER_MIN) { 1470 *errstr = "INTEGER value too small"; 1471 return 0; 1472 } 1473 if (intval > SMI_INTEGER_MAX) { 1474 *errstr = "INTEGER value too large"; 1475 return 0; 1476 } 1477 break; 1478 case BER_TYPE_OCTETSTRING: 1479 (void)ober_get_nstring(varbind->av_value, NULL, &len); 1480 if (len > SMI_OCTETSTRING_MAX) { 1481 *errstr = "OCTET STRING too long"; 1482 return 0; 1483 } 1484 break; 1485 case BER_TYPE_OBJECT: 1486 /* validated by ber.c */ 1487 break; 1488 default: 1489 *errstr = "invalid value encoding"; 1490 return 0; 1491 } 1492 } else if (varbind->av_value->be_class == BER_CLASS_APPLICATION) { 1493 switch (varbind->av_value->be_type) { 1494 case SNMP_T_IPADDR: 1495 (void)ober_get_nstring(varbind->av_value, NULL, &len); 1496 if (len != SMI_IPADDRESS_MAX) { 1497 *errstr = "invalid IpAddress size"; 1498 return 0; 1499 } 1500 break; 1501 case SNMP_T_COUNTER32: 1502 (void)ober_get_integer(varbind->av_value, &intval); 1503 if (intval < SMI_COUNTER32_MIN) { 1504 *errstr = "Counter32 value too small"; 1505 return 0; 1506 } 1507 if (intval > SMI_COUNTER32_MAX) { 1508 *errstr = "Counter32 value too large"; 1509 return 0; 1510 } 1511 break; 1512 case SNMP_T_GAUGE32: 1513 (void)ober_get_integer(varbind->av_value, &intval); 1514 if (intval < SMI_GAUGE32_MIN) { 1515 *errstr = "Gauge32 value too small"; 1516 return 0; 1517 } 1518 if (intval > SMI_GAUGE32_MAX) { 1519 *errstr = "Gauge32 value too large"; 1520 return 0; 1521 } 1522 break; 1523 case SNMP_T_TIMETICKS: 1524 (void)ober_get_integer(varbind->av_value, &intval); 1525 if (intval < SMI_TIMETICKS_MIN) { 1526 *errstr = "TimeTicks value too small"; 1527 return 0; 1528 } 1529 if (intval > SMI_TIMETICKS_MAX) { 1530 *errstr = "TimeTicks value too large"; 1531 return 0; 1532 } 1533 break; 1534 case SNMP_T_OPAQUE: 1535 (void)ober_get_nstring(varbind->av_value, &buf, &len); 1536 memset(&ber, 0, sizeof(ber)); 1537 ober_set_application(&ber, appl_ber_any); 1538 ober_set_readbuf(&ber, buf, len); 1539 elm = ober_read_elements(&ber, NULL); 1540 if (elm == NULL || ober_calc_len(elm) != len) { 1541 ober_free_elements(elm); 1542 *errstr = "Opaque not valid ber encoded value"; 1543 return 0; 1544 } 1545 ober_free_elements(elm); 1546 break; 1547 case SNMP_T_COUNTER64: 1548 /* Maximum value supported by ber.c */ 1549 break; 1550 default: 1551 *errstr = "invalid value encoding"; 1552 return 0; 1553 } 1554 } else if (varbind->av_value->be_class == BER_CLASS_CONTEXT) { 1555 switch (varbind->av_value->be_type) { 1556 case APPL_EXC_NOSUCHOBJECT: 1557 if (next && request != NULL) { 1558 *errstr = "Unexpected noSuchObject"; 1559 return 0; 1560 } 1561 break; 1562 case APPL_EXC_NOSUCHINSTANCE: 1563 if (next && request != NULL) { 1564 *errstr = "Unexpected noSuchInstance"; 1565 return 0; 1566 } 1567 break; 1568 case APPL_EXC_ENDOFMIBVIEW: 1569 if (!next && request != NULL) { 1570 *errstr = "Unexpected endOfMibView"; 1571 return 0; 1572 } 1573 eomv = 1; 1574 break; 1575 default: 1576 *errstr = "invalid value encoding"; 1577 return 0; 1578 } 1579 } else { 1580 *errstr = "invalid value encoding"; 1581 return 0; 1582 } 1583 1584 if (request == NULL) 1585 return 1; 1586 1587 cmp = ober_oid_cmp(&(request->avi_varbind.av_oid), &(varbind->av_oid)); 1588 if (next) { 1589 if (request->avi_region->ar_instance && 1590 ober_oid_cmp(&(request->avi_region->ar_oid), 1591 &(varbind->av_oid)) != 0) { 1592 *errstr = "oid below instance"; 1593 return 0; 1594 } 1595 if (!eomv) { 1596 if (request->avi_varbind.av_include) { 1597 if (cmp > 0) { 1598 *errstr = "oid not incrementing"; 1599 return 0; 1600 } 1601 } else { 1602 if (cmp >= 0) { 1603 *errstr = "oid not incrementing"; 1604 return 0; 1605 } 1606 } 1607 if (range && ober_oid_cmp(&(varbind->av_oid), 1608 &(request->avi_varbind.av_oid_end)) >= 0) { 1609 *errstr = "end oid not honoured"; 1610 return 0; 1611 } 1612 } 1613 } else { 1614 if (cmp != 0) { 1615 *errstr = "oids not equal"; 1616 return 0; 1617 } 1618 } 1619 return 1; 1620} 1621 1622unsigned int 1623appl_ber_any(struct ber_element *elm) 1624{ 1625 return BER_TYPE_OCTETSTRING; 1626} 1627 1628int 1629appl_error_valid(enum appl_error error, enum snmp_pdutype type) 1630{ 1631 switch (error) { 1632 case APPL_ERROR_NOERROR: 1633 case APPL_ERROR_TOOBIG: 1634 case APPL_ERROR_NOSUCHNAME: 1635 case APPL_ERROR_GENERR: 1636 return 1; 1637 case APPL_ERROR_BADVALUE: 1638 case APPL_ERROR_READONLY: 1639 case APPL_ERROR_NOACCESS: 1640 case APPL_ERROR_WRONGTYPE: 1641 case APPL_ERROR_WRONGLENGTH: 1642 case APPL_ERROR_WRONGENCODING: 1643 case APPL_ERROR_WRONGVALUE: 1644 case APPL_ERROR_NOCREATION: 1645 case APPL_ERROR_INCONSISTENTVALUE: 1646 case APPL_ERROR_RESOURCEUNAVAILABLE: 1647 case APPL_ERROR_COMMITFAILED: 1648 case APPL_ERROR_UNDOFAILED: 1649 case APPL_ERROR_NOTWRITABLE: 1650 case APPL_ERROR_INCONSISTENTNAME: 1651 return type == SNMP_C_SETREQ; 1652 case APPL_ERROR_AUTHORIZATIONERROR: 1653 return type == SNMP_C_GETREQ || type == SNMP_C_SETREQ; 1654 default: 1655 return 0; 1656 } 1657} 1658 1659int 1660appl_varbind_backend(struct appl_varbind_internal *ivb) 1661{ 1662 struct appl_request_upstream *ureq = ivb->avi_request_upstream; 1663 struct appl_region search, *region, *pregion; 1664 struct appl_varbind *vb = &(ivb->avi_varbind); 1665 struct ber_oid oid, nextsibling; 1666 int next, cmp; 1667 1668 next = ureq->aru_requesttype == SNMP_C_GETNEXTREQ || 1669 ureq->aru_requesttype == SNMP_C_GETBULKREQ; 1670 1671 region = appl_region_find(ureq->aru_ctx, &(vb->av_oid)); 1672 if (region == NULL) { 1673 if (!next) { 1674 vb->av_value = appl_exception(APPL_EXC_NOSUCHOBJECT); 1675 ivb->avi_state = APPL_VBSTATE_DONE; 1676 if (vb->av_value == NULL) 1677 return -1; 1678 return 0; 1679 } 1680 search.ar_oid = vb->av_oid; 1681 region = RB_NFIND(appl_regions, 1682 &(ureq->aru_ctx->ac_regions), &search); 1683 if (region == NULL) 1684 goto eomv; 1685 vb->av_oid = region->ar_oid; 1686 vb->av_include = 1; 1687 } 1688 cmp = ober_oid_cmp(&(region->ar_oid), &(vb->av_oid)); 1689 if (cmp == -2) { 1690 if (region->ar_instance) { 1691 if (!next) { 1692 vb->av_value = 1693 appl_exception(APPL_EXC_NOSUCHINSTANCE); 1694 ivb->avi_state = APPL_VBSTATE_DONE; 1695 if (vb->av_value == NULL) 1696 return -1; 1697 return 0; 1698 } 1699 vb->av_oid = region->ar_oid; 1700 ober_oid_nextsibling(&(vb->av_oid)); 1701 vb->av_include = 1; 1702 return appl_varbind_backend(ivb); 1703 } 1704 } else if (cmp == 0) { 1705 if (region->ar_instance && next && !vb->av_include) { 1706 vb->av_oid = region->ar_oid; 1707 ober_oid_nextsibling(&(vb->av_oid)); 1708 vb->av_include = 1; 1709 return appl_varbind_backend(ivb); 1710 } 1711 } 1712 ivb->avi_region = region; 1713 if (next) { 1714 oid = vb->av_oid; 1715 /* 1716 * For the searchrange end we only want contiguous regions. 1717 * This means directly connecting, or overlapping with the same 1718 * backend. 1719 */ 1720 do { 1721 pregion = region; 1722 region = appl_region_next(ureq->aru_ctx, &oid, pregion); 1723 if (region == NULL) { 1724 oid = pregion->ar_oid; 1725 ober_oid_nextsibling(&oid); 1726 break; 1727 } 1728 cmp = ober_oid_cmp(&(region->ar_oid), &oid); 1729 if (cmp == 2) 1730 oid = region->ar_oid; 1731 else if (cmp == 1) { 1732 /* Break out if we find a gap */ 1733 nextsibling = pregion->ar_oid; 1734 ober_oid_nextsibling(&nextsibling); 1735 if (ober_oid_cmp(&(region->ar_oid), 1736 &nextsibling) != 0) { 1737 oid = pregion->ar_oid; 1738 ober_oid_nextsibling(&oid); 1739 break; 1740 } 1741 oid = region->ar_oid; 1742 } else if (cmp == -2) { 1743 oid = pregion->ar_oid; 1744 ober_oid_nextsibling(&oid); 1745 } else 1746 fatalx("We can't stop/move back on getnext"); 1747 } while (region->ar_backend == pregion->ar_backend); 1748 vb->av_oid_end = oid; 1749 } 1750 return 0; 1751 1752 eomv: 1753 do { 1754 ivb->avi_varbind.av_value = 1755 appl_exception(APPL_EXC_ENDOFMIBVIEW); 1756 ivb->avi_state = APPL_VBSTATE_DONE; 1757 if (ivb->avi_varbind.av_value == NULL) 1758 return -1; 1759 if (ivb->avi_sub != NULL) { 1760 ivb->avi_sub->avi_varbind.av_oid = 1761 ivb->avi_varbind.av_oid; 1762 ivb->avi_sub->avi_origid = ivb->avi_origid; 1763 } 1764 ivb = ivb->avi_sub; 1765 } while (ivb != NULL); 1766 1767 return 0; 1768} 1769 1770void 1771appl_varbind_error(struct appl_varbind_internal *avi, enum appl_error error) 1772{ 1773 struct appl_request_upstream *ureq = avi->avi_request_upstream; 1774 1775 if (ureq->aru_error == APPL_ERROR_GENERR) 1776 return; 1777 if (ureq->aru_error != APPL_ERROR_NOERROR && error != APPL_ERROR_GENERR) 1778 return; 1779 ureq->aru_error = error; 1780 ureq->aru_index = avi->avi_index; 1781} 1782 1783void 1784appl_report(struct snmp_message *statereference, int32_t requestid, 1785 struct ber_oid *oid) 1786{ 1787 struct appl_request_upstream *ureq; 1788 1789 if ((ureq = calloc(1, sizeof(*ureq))) == NULL) 1790 fatal("malloc"); 1791 ureq->aru_ctx = appl_context(NULL, 0); 1792 ureq->aru_statereference = statereference; 1793 ureq->aru_requesttype = SNMP_C_GETREQ; 1794 ureq->aru_responsetype = SNMP_C_REPORT; 1795 ureq->aru_requestid = requestid; 1796 ureq->aru_transactionid = 0; 1797 ureq->aru_nonrepeaters = 0; 1798 ureq->aru_maxrepetitions = 0; 1799 if ((ureq->aru_vblist = calloc(1, sizeof(*ureq->aru_vblist))) == NULL) 1800 fatal("malloc"); 1801 ureq->aru_varbindlen = 1; 1802 ureq->aru_error = APPL_ERROR_NOERROR; 1803 ureq->aru_index = 0; 1804 ureq->aru_locked = 0; 1805 ureq->aru_pduversion = SNMP_V3; 1806 1807 ureq->aru_vblist[0].avi_state = APPL_VBSTATE_NEW; 1808 ureq->aru_vblist[0].avi_varbind.av_oid = *oid; 1809 ureq->aru_vblist[0].avi_varbind.av_value = NULL; 1810 ureq->aru_vblist[0].avi_varbind.av_next = NULL; 1811 ureq->aru_vblist[0].avi_origid = *oid; 1812 ureq->aru_vblist[0].avi_index = 1; 1813 ureq->aru_vblist[0].avi_request_upstream = ureq; 1814 ureq->aru_vblist[0].avi_request_downstream = NULL; 1815 ureq->aru_vblist[0].avi_next = NULL; 1816 ureq->aru_vblist[0].avi_sub = NULL; 1817 1818 appl_request_upstream_resolve(ureq); 1819} 1820 1821struct ber_element * 1822appl_exception(enum appl_exception type) 1823{ 1824 struct ber_element *value; 1825 1826 if ((value = ober_add_null(NULL)) == NULL) { 1827 log_warn("malloc"); 1828 return NULL; 1829 } 1830 ober_set_header(value, BER_CLASS_CONTEXT, type); 1831 1832 return value; 1833} 1834 1835void 1836appl_pdu_log(struct appl_backend *backend, enum snmp_pdutype pdutype, 1837 int32_t requestid, uint16_t error, uint16_t index, 1838 struct appl_varbind *vblist) 1839{ 1840 struct appl_varbind *vb; 1841 char buf[1024], oidbuf[1024], *str; 1842 int next; 1843 1844 if (log_getverbose() < 2) 1845 return; 1846 1847 next = (pdutype == SNMP_C_GETNEXTREQ || pdutype == SNMP_C_GETBULKREQ); 1848 1849 buf[0] = '\0'; 1850 for (vb = vblist; vb != NULL; vb = vb->av_next) { 1851 strlcat(buf, "{", sizeof(buf)); 1852 strlcat(buf, mib_oid2string(&(vb->av_oid), oidbuf, 1853 sizeof(oidbuf), snmpd_env->sc_oidfmt), sizeof(buf)); 1854 if (next) { 1855 if (vb->av_include) 1856 strlcat(buf, "(incl)", sizeof(buf)); 1857 if (vb->av_oid_end.bo_n > 0) { 1858 strlcat(buf, "-", sizeof(buf)); 1859 strlcat(buf, mib_oid2string(&(vb->av_oid_end), 1860 oidbuf, sizeof(oidbuf), 1861 snmpd_env->sc_oidfmt), sizeof(buf)); 1862 } 1863 } 1864 strlcat(buf, ":", sizeof(buf)); 1865 if (vb->av_value != NULL) { 1866 str = smi_print_element(vb->av_value); 1867 strlcat(buf, str == NULL ? "???" : str, sizeof(buf)); 1868 free(str); 1869 } else 1870 strlcat(buf, "null", sizeof(buf)); 1871 strlcat(buf, "}", sizeof(buf)); 1872 } 1873 log_debug("%s%s%s{%"PRId32", %"PRIu16", %"PRIu16", {%s}}", 1874 backend != NULL ? backend->ab_name : "", 1875 backend != NULL ? ": " : "", 1876 snmpe_pdutype2string(pdutype), requestid, error, index, buf); 1877} 1878 1879void 1880ober_oid_nextsibling(struct ber_oid *oid) 1881{ 1882 while (oid->bo_n > 0) { 1883 oid->bo_id[oid->bo_n - 1]++; 1884 /* Overflow check */ 1885 if (oid->bo_id[oid->bo_n - 1] != 0) 1886 return; 1887 oid->bo_n--; 1888 } 1889} 1890 1891int 1892appl_region_cmp(struct appl_region *r1, struct appl_region *r2) 1893{ 1894 return ober_oid_cmp(&(r1->ar_oid), &(r2->ar_oid)); 1895} 1896 1897int 1898appl_request_cmp(struct appl_request_downstream *r1, 1899 struct appl_request_downstream *r2) 1900{ 1901 return r1->ard_requestid < r2->ard_requestid ? -1 : 1902 r1->ard_requestid > r2->ard_requestid; 1903} 1904 1905RB_GENERATE_STATIC(appl_regions, appl_region, ar_entry, appl_region_cmp); 1906RB_GENERATE_STATIC(appl_requests, appl_request_downstream, ard_entry, 1907 appl_request_cmp); 1908