1122394Sharti/* 2122394Sharti * Copyright (c) 2001-2003 3122394Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122394Sharti * All rights reserved. 5122394Sharti * 6122394Sharti * Author: Harti Brandt <harti@freebsd.org> 7310903Sngie * 8133211Sharti * Redistribution and use in source and binary forms, with or without 9133211Sharti * modification, are permitted provided that the following conditions 10133211Sharti * are met: 11133211Sharti * 1. Redistributions of source code must retain the above copyright 12133211Sharti * notice, this list of conditions and the following disclaimer. 13122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 14122394Sharti * notice, this list of conditions and the following disclaimer in the 15122394Sharti * documentation and/or other materials provided with the distribution. 16310903Sngie * 17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133211Sharti * SUCH DAMAGE. 28122394Sharti * 29150920Sharti * $Begemot: bsnmp/lib/snmpagent.c,v 1.20 2005/10/04 11:21:33 brandt_h Exp $ 30122394Sharti * 31122394Sharti * SNMP Agent functions 32122394Sharti */ 33122394Sharti#include <sys/types.h> 34122394Sharti#include <sys/queue.h> 35122394Sharti#include <stdio.h> 36122394Sharti#include <stdlib.h> 37122394Sharti#include <stddef.h> 38122394Sharti#include <stdarg.h> 39150920Sharti#ifdef HAVE_STDINT_H 40133211Sharti#include <stdint.h> 41150920Sharti#elif defined(HAVE_INTTYPES_H) 42150920Sharti#include <inttypes.h> 43150920Sharti#endif 44122394Sharti#include <string.h> 45122394Sharti 46122394Sharti#include "asn1.h" 47122394Sharti#include "snmp.h" 48122394Sharti#include "snmppriv.h" 49122394Sharti#include "snmpagent.h" 50122394Sharti 51122394Shartistatic void snmp_debug_func(const char *fmt, ...); 52122394Sharti 53122394Shartivoid (*snmp_debug)(const char *fmt, ...) = snmp_debug_func; 54122394Sharti 55122394Shartistruct snmp_node *tree; 56122394Shartiu_int tree_size; 57122394Sharti 58122394Sharti/* 59122394Sharti * Structure to hold dependencies during SET processing 60122394Sharti * The last two members of this structure must be the 61122394Sharti * dependency visible by the user and the user data. 62122394Sharti */ 63122394Shartistruct depend { 64122394Sharti TAILQ_ENTRY(depend) link; 65122394Sharti size_t len; /* size of data part */ 66122394Sharti snmp_depop_t func; 67122394Sharti struct snmp_dependency dep; 68133211Sharti#if defined(__GNUC__) && __GNUC__ < 3 69133211Sharti u_char data[0]; 70133211Sharti#else 71122394Sharti u_char data[]; 72133211Sharti#endif 73122394Sharti}; 74122394ShartiTAILQ_HEAD(depend_list, depend); 75122394Sharti 76122394Sharti/* 77122394Sharti * Set context 78122394Sharti */ 79122394Shartistruct context { 80122394Sharti struct snmp_context ctx; 81122394Sharti struct depend_list dlist; 82122394Sharti const struct snmp_node *node[SNMP_MAX_BINDINGS]; 83122394Sharti struct snmp_scratch scratch[SNMP_MAX_BINDINGS]; 84122394Sharti struct depend *depend; 85122394Sharti}; 86122394Sharti 87122394Sharti#define TR(W) (snmp_trace & SNMP_TRACE_##W) 88122394Shartiu_int snmp_trace = 0; 89122394Sharti 90122394Shartistatic char oidbuf[ASN_OIDSTRLEN]; 91122394Sharti 92122394Sharti/* 93122394Sharti * Allocate a context 94122394Sharti */ 95122394Shartistruct snmp_context * 96122394Shartisnmp_init_context(void) 97122394Sharti{ 98122394Sharti struct context *context; 99122394Sharti 100122394Sharti if ((context = malloc(sizeof(*context))) == NULL) 101122394Sharti return (NULL); 102122394Sharti 103122394Sharti memset(context, 0, sizeof(*context)); 104122394Sharti TAILQ_INIT(&context->dlist); 105122394Sharti 106122394Sharti return (&context->ctx); 107122394Sharti} 108122394Sharti 109122394Sharti/* 110122394Sharti * Find a variable for SET/GET and the first GETBULK pass. 111122394Sharti * Return the node pointer. If the search fails, set the errp to 112122394Sharti * the correct SNMPv2 GET exception code. 113122394Sharti */ 114122394Shartistatic struct snmp_node * 115122394Shartifind_node(const struct snmp_value *value, enum snmp_syntax *errp) 116122394Sharti{ 117122394Sharti struct snmp_node *tp; 118122394Sharti 119122394Sharti if (TR(FIND)) 120122394Sharti snmp_debug("find: searching %s", 121122394Sharti asn_oid2str_r(&value->var, oidbuf)); 122122394Sharti 123122394Sharti /* 124122394Sharti * If we have an exact match (the entry in the table is a 125122394Sharti * sub-oid from the variable) we have found what we are for. 126122394Sharti * If the table oid is higher than the variable, there is no match. 127122394Sharti */ 128122394Sharti for (tp = tree; tp < tree + tree_size; tp++) { 129122394Sharti if (asn_is_suboid(&tp->oid, &value->var)) 130122394Sharti goto found; 131122394Sharti if (asn_compare_oid(&tp->oid, &value->var) >= 0) 132122394Sharti break; 133122394Sharti } 134122394Sharti 135122394Sharti if (TR(FIND)) 136122394Sharti snmp_debug("find: no match"); 137122394Sharti *errp = SNMP_SYNTAX_NOSUCHOBJECT; 138122394Sharti return (NULL); 139122394Sharti 140122394Sharti found: 141122394Sharti /* leafs must have a 0 instance identifier */ 142122394Sharti if (tp->type == SNMP_NODE_LEAF && 143122394Sharti (value->var.len != tp->oid.len + 1 || 144122394Sharti value->var.subs[tp->oid.len] != 0)) { 145122394Sharti if (TR(FIND)) 146122394Sharti snmp_debug("find: bad leaf index"); 147122394Sharti *errp = SNMP_SYNTAX_NOSUCHINSTANCE; 148122394Sharti return (NULL); 149122394Sharti } 150122394Sharti if (TR(FIND)) 151122394Sharti snmp_debug("find: found %s", 152122394Sharti asn_oid2str_r(&value->var, oidbuf)); 153122394Sharti return (tp); 154122394Sharti} 155122394Sharti 156122394Shartistatic struct snmp_node * 157122394Shartifind_subnode(const struct snmp_value *value) 158122394Sharti{ 159122394Sharti struct snmp_node *tp; 160122394Sharti 161122394Sharti for (tp = tree; tp < tree + tree_size; tp++) { 162122394Sharti if (asn_is_suboid(&value->var, &tp->oid)) 163122394Sharti return (tp); 164122394Sharti } 165122394Sharti return (NULL); 166122394Sharti} 167122394Sharti 168216294Ssyrinxstatic void 169301661Sngiesnmp_pdu_create_response(const struct snmp_pdu *pdu, struct snmp_pdu *resp) 170216294Ssyrinx{ 171216294Ssyrinx memset(resp, 0, sizeof(*resp)); 172216294Ssyrinx strcpy(resp->community, pdu->community); 173216294Ssyrinx resp->version = pdu->version; 174216294Ssyrinx resp->type = SNMP_PDU_RESPONSE; 175216294Ssyrinx resp->request_id = pdu->request_id; 176216294Ssyrinx resp->version = pdu->version; 177216294Ssyrinx 178216294Ssyrinx if (resp->version != SNMP_V3) 179216294Ssyrinx return; 180216294Ssyrinx 181216594Ssyrinx memcpy(&resp->engine, &pdu->engine, sizeof(pdu->engine)); 182216594Ssyrinx memcpy(&resp->user, &pdu->user, sizeof(pdu->user)); 183216594Ssyrinx snmp_pdu_init_secparams(resp); 184216294Ssyrinx resp->identifier = pdu->identifier; 185216294Ssyrinx resp->security_model = pdu->security_model; 186216294Ssyrinx resp->context_engine_len = pdu->context_engine_len; 187216294Ssyrinx memcpy(resp->context_engine, pdu->context_engine, 188216294Ssyrinx resp->context_engine_len); 189216294Ssyrinx strlcpy(resp->context_name, pdu->context_name, 190216294Ssyrinx sizeof(resp->context_name)); 191216294Ssyrinx} 192216294Ssyrinx 193122394Sharti/* 194122394Sharti * Execute a GET operation. The tree is rooted at the global 'root'. 195122394Sharti * Build the response PDU on the fly. If the return code is SNMP_RET_ERR 196122394Sharti * the pdu error status and index will be set. 197122394Sharti */ 198122394Shartienum snmp_ret 199122394Shartisnmp_get(struct snmp_pdu *pdu, struct asn_buf *resp_b, 200122394Sharti struct snmp_pdu *resp, void *data) 201122394Sharti{ 202122394Sharti int ret; 203122394Sharti u_int i; 204122394Sharti struct snmp_node *tp; 205122394Sharti enum snmp_syntax except; 206122394Sharti struct context context; 207122394Sharti enum asn_err err; 208122394Sharti 209122394Sharti memset(&context, 0, sizeof(context)); 210122394Sharti context.ctx.data = data; 211122394Sharti 212216294Ssyrinx snmp_pdu_create_response(pdu, resp); 213122394Sharti 214122394Sharti if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK) 215122394Sharti /* cannot even encode header - very bad */ 216122394Sharti return (SNMP_RET_IGN); 217122394Sharti 218122394Sharti for (i = 0; i < pdu->nbindings; i++) { 219122394Sharti resp->bindings[i].var = pdu->bindings[i].var; 220122394Sharti if ((tp = find_node(&pdu->bindings[i], &except)) == NULL) { 221122394Sharti if (pdu->version == SNMP_V1) { 222122394Sharti if (TR(GET)) 223122394Sharti snmp_debug("get: nosuchname"); 224122394Sharti pdu->error_status = SNMP_ERR_NOSUCHNAME; 225122394Sharti pdu->error_index = i + 1; 226122394Sharti snmp_pdu_free(resp); 227122394Sharti return (SNMP_RET_ERR); 228122394Sharti } 229122394Sharti if (TR(GET)) 230122394Sharti snmp_debug("get: exception %u", except); 231122394Sharti resp->bindings[i].syntax = except; 232122394Sharti 233122394Sharti } else { 234122394Sharti /* call the action to fetch the value. */ 235122394Sharti resp->bindings[i].syntax = tp->syntax; 236122394Sharti ret = (*tp->op)(&context.ctx, &resp->bindings[i], 237122394Sharti tp->oid.len, tp->index, SNMP_OP_GET); 238122394Sharti if (TR(GET)) 239122394Sharti snmp_debug("get: action returns %d", ret); 240122394Sharti 241122394Sharti if (ret == SNMP_ERR_NOSUCHNAME) { 242122394Sharti if (pdu->version == SNMP_V1) { 243122394Sharti pdu->error_status = SNMP_ERR_NOSUCHNAME; 244122394Sharti pdu->error_index = i + 1; 245122394Sharti snmp_pdu_free(resp); 246122394Sharti return (SNMP_RET_ERR); 247122394Sharti } 248122394Sharti if (TR(GET)) 249122394Sharti snmp_debug("get: exception noSuchInstance"); 250122394Sharti resp->bindings[i].syntax = SNMP_SYNTAX_NOSUCHINSTANCE; 251122394Sharti 252122394Sharti } else if (ret != SNMP_ERR_NOERROR) { 253122394Sharti pdu->error_status = SNMP_ERR_GENERR; 254122394Sharti pdu->error_index = i + 1; 255122394Sharti snmp_pdu_free(resp); 256122394Sharti return (SNMP_RET_ERR); 257122394Sharti } 258122394Sharti } 259122394Sharti resp->nbindings++; 260122394Sharti 261122394Sharti err = snmp_binding_encode(resp_b, &resp->bindings[i]); 262122394Sharti 263122394Sharti if (err == ASN_ERR_EOBUF) { 264122394Sharti pdu->error_status = SNMP_ERR_TOOBIG; 265122394Sharti pdu->error_index = 0; 266122394Sharti snmp_pdu_free(resp); 267122394Sharti return (SNMP_RET_ERR); 268122394Sharti } 269122394Sharti if (err != ASN_ERR_OK) { 270122394Sharti if (TR(GET)) 271122394Sharti snmp_debug("get: binding encoding: %u", err); 272122394Sharti pdu->error_status = SNMP_ERR_GENERR; 273122394Sharti pdu->error_index = i + 1; 274122394Sharti snmp_pdu_free(resp); 275122394Sharti return (SNMP_RET_ERR); 276122394Sharti } 277122394Sharti } 278122394Sharti 279301661Sngie if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) { 280301661Sngie snmp_debug("get: failed to encode PDU"); 281301661Sngie return (SNMP_RET_ERR); 282301661Sngie } 283301661Sngie 284301661Sngie return (SNMP_RET_OK); 285122394Sharti} 286122394Sharti 287122394Shartistatic struct snmp_node * 288122394Shartinext_node(const struct snmp_value *value, int *pnext) 289122394Sharti{ 290122394Sharti struct snmp_node *tp; 291122394Sharti 292122394Sharti if (TR(FIND)) 293122394Sharti snmp_debug("next: searching %s", 294122394Sharti asn_oid2str_r(&value->var, oidbuf)); 295122394Sharti 296122394Sharti *pnext = 0; 297122394Sharti for (tp = tree; tp < tree + tree_size; tp++) { 298122394Sharti if (asn_is_suboid(&tp->oid, &value->var)) { 299122394Sharti /* the tree OID is a sub-oid of the requested OID. */ 300122394Sharti if (tp->type == SNMP_NODE_LEAF) { 301122394Sharti if (tp->oid.len == value->var.len) { 302122394Sharti /* request for scalar type */ 303122394Sharti if (TR(FIND)) 304122394Sharti snmp_debug("next: found scalar %s", 305122394Sharti asn_oid2str_r(&tp->oid, oidbuf)); 306122394Sharti return (tp); 307122394Sharti } 308122394Sharti /* try next */ 309122394Sharti } else { 310122394Sharti if (TR(FIND)) 311122394Sharti snmp_debug("next: found column %s", 312122394Sharti asn_oid2str_r(&tp->oid, oidbuf)); 313122394Sharti return (tp); 314122394Sharti } 315122394Sharti } else if (asn_is_suboid(&value->var, &tp->oid) || 316122394Sharti asn_compare_oid(&tp->oid, &value->var) >= 0) { 317122394Sharti if (TR(FIND)) 318122394Sharti snmp_debug("next: found %s", 319122394Sharti asn_oid2str_r(&tp->oid, oidbuf)); 320122394Sharti *pnext = 1; 321122394Sharti return (tp); 322122394Sharti } 323122394Sharti } 324122394Sharti 325122394Sharti if (TR(FIND)) 326122394Sharti snmp_debug("next: failed"); 327122394Sharti 328122394Sharti return (NULL); 329122394Sharti} 330122394Sharti 331122394Shartistatic enum snmp_ret 332122394Shartido_getnext(struct context *context, const struct snmp_value *inb, 333122394Sharti struct snmp_value *outb, struct snmp_pdu *pdu) 334122394Sharti{ 335122394Sharti const struct snmp_node *tp; 336122394Sharti int ret, next; 337122394Sharti 338122394Sharti if ((tp = next_node(inb, &next)) == NULL) 339122394Sharti goto eofMib; 340122394Sharti 341122394Sharti /* retain old variable if we are doing a GETNEXT on an exact 342122394Sharti * matched leaf only */ 343122394Sharti if (tp->type == SNMP_NODE_LEAF || next) 344122394Sharti outb->var = tp->oid; 345122394Sharti else 346122394Sharti outb->var = inb->var; 347122394Sharti 348122394Sharti for (;;) { 349122394Sharti outb->syntax = tp->syntax; 350122394Sharti if (tp->type == SNMP_NODE_LEAF) { 351122394Sharti /* make a GET operation */ 352122394Sharti outb->var.subs[outb->var.len++] = 0; 353122394Sharti ret = (*tp->op)(&context->ctx, outb, tp->oid.len, 354122394Sharti tp->index, SNMP_OP_GET); 355122394Sharti } else { 356122394Sharti /* make a GETNEXT */ 357122394Sharti ret = (*tp->op)(&context->ctx, outb, tp->oid.len, 358122394Sharti tp->index, SNMP_OP_GETNEXT); 359122394Sharti } 360122394Sharti if (ret != SNMP_ERR_NOSUCHNAME) { 361122394Sharti /* got something */ 362122394Sharti if (ret != SNMP_ERR_NOERROR && TR(GETNEXT)) 363122394Sharti snmp_debug("getnext: %s returns %u", 364122394Sharti asn_oid2str(&outb->var), ret); 365122394Sharti break; 366122394Sharti } 367122394Sharti 368122394Sharti /* object has no data - try next */ 369122394Sharti if (++tp == tree + tree_size) 370122394Sharti break; 371142810Sharti 372142810Sharti if (TR(GETNEXT)) 373142810Sharti snmp_debug("getnext: no data - avancing to %s", 374142810Sharti asn_oid2str(&tp->oid)); 375142810Sharti 376122394Sharti outb->var = tp->oid; 377122394Sharti } 378122394Sharti 379122394Sharti if (ret == SNMP_ERR_NOSUCHNAME) { 380122394Sharti eofMib: 381122394Sharti outb->var = inb->var; 382122394Sharti if (pdu->version == SNMP_V1) { 383122394Sharti pdu->error_status = SNMP_ERR_NOSUCHNAME; 384122394Sharti return (SNMP_RET_ERR); 385122394Sharti } 386122394Sharti outb->syntax = SNMP_SYNTAX_ENDOFMIBVIEW; 387122394Sharti 388122394Sharti } else if (ret != SNMP_ERR_NOERROR) { 389122394Sharti pdu->error_status = SNMP_ERR_GENERR; 390122394Sharti return (SNMP_RET_ERR); 391122394Sharti } 392122394Sharti return (SNMP_RET_OK); 393122394Sharti} 394122394Sharti 395122394Sharti 396122394Sharti/* 397122394Sharti * Execute a GETNEXT operation. The tree is rooted at the global 'root'. 398122394Sharti * Build the response PDU on the fly. The return is: 399122394Sharti */ 400122394Shartienum snmp_ret 401122394Shartisnmp_getnext(struct snmp_pdu *pdu, struct asn_buf *resp_b, 402122394Sharti struct snmp_pdu *resp, void *data) 403122394Sharti{ 404122394Sharti struct context context; 405122394Sharti u_int i; 406122394Sharti enum asn_err err; 407122394Sharti enum snmp_ret result; 408122394Sharti 409122394Sharti memset(&context, 0, sizeof(context)); 410122394Sharti context.ctx.data = data; 411122394Sharti 412216294Ssyrinx snmp_pdu_create_response(pdu, resp); 413122394Sharti 414122394Sharti if (snmp_pdu_encode_header(resp_b, resp)) 415122394Sharti return (SNMP_RET_IGN); 416122394Sharti 417122394Sharti for (i = 0; i < pdu->nbindings; i++) { 418122394Sharti result = do_getnext(&context, &pdu->bindings[i], 419122394Sharti &resp->bindings[i], pdu); 420122394Sharti 421122394Sharti if (result != SNMP_RET_OK) { 422122394Sharti pdu->error_index = i + 1; 423122394Sharti snmp_pdu_free(resp); 424122394Sharti return (result); 425122394Sharti } 426122394Sharti 427122394Sharti resp->nbindings++; 428122394Sharti 429122394Sharti err = snmp_binding_encode(resp_b, &resp->bindings[i]); 430122394Sharti 431122394Sharti if (err == ASN_ERR_EOBUF) { 432122394Sharti pdu->error_status = SNMP_ERR_TOOBIG; 433122394Sharti pdu->error_index = 0; 434122394Sharti snmp_pdu_free(resp); 435122394Sharti return (SNMP_RET_ERR); 436122394Sharti } 437122394Sharti if (err != ASN_ERR_OK) { 438122394Sharti if (TR(GET)) 439122394Sharti snmp_debug("getnext: binding encoding: %u", err); 440122394Sharti pdu->error_status = SNMP_ERR_GENERR; 441122394Sharti pdu->error_index = i + 1; 442122394Sharti snmp_pdu_free(resp); 443122394Sharti return (SNMP_RET_ERR); 444122394Sharti } 445122394Sharti } 446301661Sngie 447301661Sngie if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) { 448301661Sngie snmp_debug("getnext: failed to encode PDU"); 449301661Sngie return (SNMP_RET_ERR); 450301661Sngie } 451301661Sngie 452301661Sngie return (SNMP_RET_OK); 453122394Sharti} 454122394Sharti 455122394Shartienum snmp_ret 456122394Shartisnmp_getbulk(struct snmp_pdu *pdu, struct asn_buf *resp_b, 457122394Sharti struct snmp_pdu *resp, void *data) 458122394Sharti{ 459122394Sharti struct context context; 460122394Sharti u_int i; 461122394Sharti int cnt; 462122394Sharti u_int non_rep; 463122394Sharti int eomib; 464122394Sharti enum snmp_ret result; 465122394Sharti enum asn_err err; 466122394Sharti 467122394Sharti memset(&context, 0, sizeof(context)); 468122394Sharti context.ctx.data = data; 469122394Sharti 470216294Ssyrinx snmp_pdu_create_response(pdu, resp); 471122394Sharti 472122394Sharti if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK) 473122394Sharti /* cannot even encode header - very bad */ 474122394Sharti return (SNMP_RET_IGN); 475122394Sharti 476122394Sharti if ((non_rep = pdu->error_status) > pdu->nbindings) 477122394Sharti non_rep = pdu->nbindings; 478122394Sharti 479122394Sharti /* non-repeaters */ 480122394Sharti for (i = 0; i < non_rep; i++) { 481122394Sharti result = do_getnext(&context, &pdu->bindings[i], 482122394Sharti &resp->bindings[resp->nbindings], pdu); 483122394Sharti 484122394Sharti if (result != SNMP_RET_OK) { 485122394Sharti pdu->error_index = i + 1; 486122394Sharti snmp_pdu_free(resp); 487122394Sharti return (result); 488122394Sharti } 489122394Sharti 490122394Sharti err = snmp_binding_encode(resp_b, 491122394Sharti &resp->bindings[resp->nbindings++]); 492122394Sharti 493122394Sharti if (err == ASN_ERR_EOBUF) 494122394Sharti goto done; 495122394Sharti 496122394Sharti if (err != ASN_ERR_OK) { 497122394Sharti if (TR(GET)) 498122394Sharti snmp_debug("getnext: binding encoding: %u", err); 499122394Sharti pdu->error_status = SNMP_ERR_GENERR; 500122394Sharti pdu->error_index = i + 1; 501122394Sharti snmp_pdu_free(resp); 502122394Sharti return (SNMP_RET_ERR); 503122394Sharti } 504122394Sharti } 505122394Sharti 506122394Sharti if (non_rep == pdu->nbindings) 507122394Sharti goto done; 508122394Sharti 509122394Sharti /* repeates */ 510122394Sharti for (cnt = 0; cnt < pdu->error_index; cnt++) { 511122394Sharti eomib = 1; 512122394Sharti for (i = non_rep; i < pdu->nbindings; i++) { 513260638Sdelphij 514260638Sdelphij if (resp->nbindings == SNMP_MAX_BINDINGS) 515260638Sdelphij /* PDU is full */ 516260638Sdelphij goto done; 517260638Sdelphij 518310903Sngie if (cnt == 0) 519122394Sharti result = do_getnext(&context, &pdu->bindings[i], 520122394Sharti &resp->bindings[resp->nbindings], pdu); 521122394Sharti else 522122394Sharti result = do_getnext(&context, 523122394Sharti &resp->bindings[resp->nbindings - 524122394Sharti (pdu->nbindings - non_rep)], 525122394Sharti &resp->bindings[resp->nbindings], pdu); 526122394Sharti 527122394Sharti if (result != SNMP_RET_OK) { 528122394Sharti pdu->error_index = i + 1; 529122394Sharti snmp_pdu_free(resp); 530122394Sharti return (result); 531122394Sharti } 532122394Sharti if (resp->bindings[resp->nbindings].syntax != 533122394Sharti SNMP_SYNTAX_ENDOFMIBVIEW) 534122394Sharti eomib = 0; 535122394Sharti 536122394Sharti err = snmp_binding_encode(resp_b, 537122394Sharti &resp->bindings[resp->nbindings++]); 538122394Sharti 539122394Sharti if (err == ASN_ERR_EOBUF) 540122394Sharti goto done; 541122394Sharti 542122394Sharti if (err != ASN_ERR_OK) { 543122394Sharti if (TR(GET)) 544122394Sharti snmp_debug("getnext: binding encoding: %u", err); 545122394Sharti pdu->error_status = SNMP_ERR_GENERR; 546122394Sharti pdu->error_index = i + 1; 547122394Sharti snmp_pdu_free(resp); 548122394Sharti return (SNMP_RET_ERR); 549122394Sharti } 550122394Sharti } 551122394Sharti if (eomib) 552122394Sharti break; 553122394Sharti } 554122394Sharti 555122394Sharti done: 556301661Sngie if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) { 557301661Sngie snmp_debug("getnext: failed to encode PDU"); 558301661Sngie return (SNMP_RET_ERR); 559301661Sngie } 560301661Sngie 561301661Sngie return (SNMP_RET_OK); 562122394Sharti} 563122394Sharti 564122394Sharti/* 565122394Sharti * Rollback a SET operation. Failed index is 'i'. 566122394Sharti */ 567122394Shartistatic void 568122394Shartirollback(struct context *context, struct snmp_pdu *pdu, u_int i) 569122394Sharti{ 570122394Sharti struct snmp_value *b; 571122394Sharti const struct snmp_node *np; 572122394Sharti int ret; 573122394Sharti 574122394Sharti while (i-- > 0) { 575122394Sharti b = &pdu->bindings[i]; 576122394Sharti np = context->node[i]; 577122394Sharti 578122394Sharti context->ctx.scratch = &context->scratch[i]; 579122394Sharti 580122394Sharti ret = (*np->op)(&context->ctx, b, np->oid.len, np->index, 581122394Sharti SNMP_OP_ROLLBACK); 582122394Sharti 583122394Sharti if (ret != SNMP_ERR_NOERROR) { 584122394Sharti snmp_error("set: rollback failed (%d) on variable %s " 585122394Sharti "index %u", ret, asn_oid2str(&b->var), i); 586122394Sharti if (pdu->version != SNMP_V1) { 587122394Sharti pdu->error_status = SNMP_ERR_UNDO_FAILED; 588122394Sharti pdu->error_index = 0; 589122394Sharti } 590122394Sharti } 591122394Sharti } 592122394Sharti} 593122394Sharti 594122394Sharti/* 595122394Sharti * Commit dependencies. 596122394Sharti */ 597122394Shartiint 598122394Shartisnmp_dep_commit(struct snmp_context *ctx) 599122394Sharti{ 600122394Sharti struct context *context = (struct context *)ctx; 601122394Sharti int ret; 602122394Sharti 603122394Sharti TAILQ_FOREACH(context->depend, &context->dlist, link) { 604122394Sharti ctx->dep = &context->depend->dep; 605122394Sharti 606122394Sharti if (TR(SET)) 607122394Sharti snmp_debug("set: dependency commit %s", 608122394Sharti asn_oid2str(&ctx->dep->obj)); 609122394Sharti 610122394Sharti ret = context->depend->func(ctx, ctx->dep, SNMP_DEPOP_COMMIT); 611122394Sharti 612122394Sharti if (ret != SNMP_ERR_NOERROR) { 613122394Sharti if (TR(SET)) 614122394Sharti snmp_debug("set: dependency failed %d", ret); 615122394Sharti return (ret); 616122394Sharti } 617122394Sharti } 618122394Sharti return (SNMP_ERR_NOERROR); 619122394Sharti} 620122394Sharti 621122394Sharti/* 622122394Sharti * Rollback dependencies 623122394Sharti */ 624122394Shartiint 625122394Shartisnmp_dep_rollback(struct snmp_context *ctx) 626122394Sharti{ 627122394Sharti struct context *context = (struct context *)ctx; 628122394Sharti int ret, ret1; 629122394Sharti char objbuf[ASN_OIDSTRLEN]; 630122394Sharti char idxbuf[ASN_OIDSTRLEN]; 631122394Sharti 632122394Sharti ret1 = SNMP_ERR_NOERROR; 633122394Sharti while ((context->depend = 634122394Sharti TAILQ_PREV(context->depend, depend_list, link)) != NULL) { 635122394Sharti ctx->dep = &context->depend->dep; 636122394Sharti 637122394Sharti if (TR(SET)) 638122394Sharti snmp_debug("set: dependency rollback %s", 639122394Sharti asn_oid2str(&ctx->dep->obj)); 640122394Sharti 641122394Sharti ret = context->depend->func(ctx, ctx->dep, SNMP_DEPOP_ROLLBACK); 642122394Sharti 643122394Sharti if (ret != SNMP_ERR_NOERROR) { 644122394Sharti snmp_debug("set: dep rollback returns %u: %s %s", ret, 645122394Sharti asn_oid2str_r(&ctx->dep->obj, objbuf), 646122394Sharti asn_oid2str_r(&ctx->dep->idx, idxbuf)); 647122394Sharti if (ret1 == SNMP_ERR_NOERROR) 648122394Sharti ret1 = ret; 649122394Sharti } 650122394Sharti } 651122394Sharti return (ret1); 652122394Sharti} 653122394Sharti 654128237Shartivoid 655128237Shartisnmp_dep_finish(struct snmp_context *ctx) 656128237Sharti{ 657128237Sharti struct context *context = (struct context *)ctx; 658128237Sharti struct depend *d; 659128237Sharti 660128237Sharti while ((d = TAILQ_FIRST(&context->dlist)) != NULL) { 661128237Sharti ctx->dep = &d->dep; 662128237Sharti (void)d->func(ctx, ctx->dep, SNMP_DEPOP_FINISH); 663128237Sharti TAILQ_REMOVE(&context->dlist, d, link); 664128237Sharti free(d); 665128237Sharti } 666128237Sharti} 667128237Sharti 668122394Sharti/* 669122394Sharti * Do a SET operation. 670122394Sharti */ 671122394Shartienum snmp_ret 672122394Shartisnmp_set(struct snmp_pdu *pdu, struct asn_buf *resp_b, 673122394Sharti struct snmp_pdu *resp, void *data) 674122394Sharti{ 675122394Sharti int ret; 676122394Sharti u_int i; 677122394Sharti enum asn_err asnerr; 678122394Sharti struct context context; 679122394Sharti const struct snmp_node *np; 680122394Sharti struct snmp_value *b; 681122394Sharti enum snmp_syntax except; 682122394Sharti 683122394Sharti memset(&context, 0, sizeof(context)); 684122394Sharti TAILQ_INIT(&context.dlist); 685122394Sharti context.ctx.data = data; 686122394Sharti 687216294Ssyrinx snmp_pdu_create_response(pdu, resp); 688122394Sharti 689122394Sharti if (snmp_pdu_encode_header(resp_b, resp)) 690122394Sharti return (SNMP_RET_IGN); 691122394Sharti 692310903Sngie /* 693122394Sharti * 1. Find all nodes, check that they are writeable and 694122394Sharti * that the syntax is ok, copy over the binding to the response. 695122394Sharti */ 696122394Sharti for (i = 0; i < pdu->nbindings; i++) { 697122394Sharti b = &pdu->bindings[i]; 698122394Sharti 699122394Sharti if ((np = context.node[i] = find_node(b, &except)) == NULL) { 700122394Sharti /* not found altogether or LEAF with wrong index */ 701122394Sharti if (TR(SET)) 702122394Sharti snmp_debug("set: node not found %s", 703122394Sharti asn_oid2str_r(&b->var, oidbuf)); 704122394Sharti if (pdu->version == SNMP_V1) { 705122394Sharti pdu->error_index = i + 1; 706122394Sharti pdu->error_status = SNMP_ERR_NOSUCHNAME; 707122394Sharti } else if ((np = find_subnode(b)) != NULL) { 708122394Sharti /* 2. intermediate object */ 709122394Sharti pdu->error_index = i + 1; 710122394Sharti pdu->error_status = SNMP_ERR_NOT_WRITEABLE; 711122394Sharti } else if (except == SNMP_SYNTAX_NOSUCHOBJECT) { 712122394Sharti pdu->error_index = i + 1; 713122394Sharti pdu->error_status = SNMP_ERR_NO_ACCESS; 714122394Sharti } else { 715122394Sharti pdu->error_index = i + 1; 716122394Sharti pdu->error_status = SNMP_ERR_NO_CREATION; 717122394Sharti } 718122394Sharti snmp_pdu_free(resp); 719122394Sharti return (SNMP_RET_ERR); 720122394Sharti } 721122394Sharti /* 722122394Sharti * 2. write/createable? 723122394Sharti * Can check this for leafs only, because in v2 we have 724122394Sharti * to differentiate between NOT_WRITEABLE and NO_CREATION 725122394Sharti * and only the action routine for COLUMNS knows, whether 726122394Sharti * a column exists. 727122394Sharti */ 728122394Sharti if (np->type == SNMP_NODE_LEAF && 729122394Sharti !(np->flags & SNMP_NODE_CANSET)) { 730122394Sharti if (pdu->version == SNMP_V1) { 731122394Sharti pdu->error_index = i + 1; 732122394Sharti pdu->error_status = SNMP_ERR_NOSUCHNAME; 733122394Sharti } else { 734122394Sharti pdu->error_index = i + 1; 735122394Sharti pdu->error_status = SNMP_ERR_NOT_WRITEABLE; 736122394Sharti } 737122394Sharti snmp_pdu_free(resp); 738122394Sharti return (SNMP_RET_ERR); 739122394Sharti } 740122394Sharti /* 741122394Sharti * 3. Ensure the right syntax 742122394Sharti */ 743122394Sharti if (np->syntax != b->syntax) { 744122394Sharti if (pdu->version == SNMP_V1) { 745122394Sharti pdu->error_index = i + 1; 746122394Sharti pdu->error_status = SNMP_ERR_BADVALUE; /* v2: wrongType */ 747122394Sharti } else { 748122394Sharti pdu->error_index = i + 1; 749122394Sharti pdu->error_status = SNMP_ERR_WRONG_TYPE; 750122394Sharti } 751122394Sharti snmp_pdu_free(resp); 752122394Sharti return (SNMP_RET_ERR); 753122394Sharti } 754122394Sharti /* 755122394Sharti * 4. Copy binding 756122394Sharti */ 757122394Sharti if (snmp_value_copy(&resp->bindings[i], b)) { 758122394Sharti pdu->error_index = i + 1; 759122394Sharti pdu->error_status = SNMP_ERR_GENERR; 760122394Sharti snmp_pdu_free(resp); 761122394Sharti return (SNMP_RET_ERR); 762122394Sharti } 763122394Sharti asnerr = snmp_binding_encode(resp_b, &resp->bindings[i]); 764122394Sharti if (asnerr == ASN_ERR_EOBUF) { 765122394Sharti pdu->error_index = i + 1; 766122394Sharti pdu->error_status = SNMP_ERR_TOOBIG; 767122394Sharti snmp_pdu_free(resp); 768122394Sharti return (SNMP_RET_ERR); 769122394Sharti } else if (asnerr != ASN_ERR_OK) { 770122394Sharti pdu->error_index = i + 1; 771122394Sharti pdu->error_status = SNMP_ERR_GENERR; 772122394Sharti snmp_pdu_free(resp); 773122394Sharti return (SNMP_RET_ERR); 774122394Sharti } 775122394Sharti resp->nbindings++; 776122394Sharti } 777122394Sharti 778128237Sharti context.ctx.code = SNMP_RET_OK; 779122394Sharti 780122394Sharti /* 781122394Sharti * 2. Call the SET method for each node. If a SET fails, rollback 782122394Sharti * everything. Map error codes depending on the version. 783122394Sharti */ 784122394Sharti for (i = 0; i < pdu->nbindings; i++) { 785122394Sharti b = &pdu->bindings[i]; 786122394Sharti np = context.node[i]; 787122394Sharti 788122394Sharti context.ctx.var_index = i + 1; 789122394Sharti context.ctx.scratch = &context.scratch[i]; 790122394Sharti 791122394Sharti ret = (*np->op)(&context.ctx, b, np->oid.len, np->index, 792122394Sharti SNMP_OP_SET); 793122394Sharti 794122394Sharti if (TR(SET)) 795122394Sharti snmp_debug("set: action %s returns %d", np->name, ret); 796122394Sharti 797122394Sharti if (pdu->version == SNMP_V1) { 798122394Sharti switch (ret) { 799122394Sharti case SNMP_ERR_NO_ACCESS: 800122394Sharti ret = SNMP_ERR_NOSUCHNAME; 801122394Sharti break; 802122394Sharti case SNMP_ERR_WRONG_TYPE: 803122394Sharti /* should no happen */ 804122394Sharti ret = SNMP_ERR_BADVALUE; 805122394Sharti break; 806122394Sharti case SNMP_ERR_WRONG_LENGTH: 807122394Sharti ret = SNMP_ERR_BADVALUE; 808122394Sharti break; 809122394Sharti case SNMP_ERR_WRONG_ENCODING: 810122394Sharti /* should not happen */ 811122394Sharti ret = SNMP_ERR_BADVALUE; 812122394Sharti break; 813122394Sharti case SNMP_ERR_WRONG_VALUE: 814122394Sharti ret = SNMP_ERR_BADVALUE; 815122394Sharti break; 816122394Sharti case SNMP_ERR_NO_CREATION: 817122394Sharti ret = SNMP_ERR_NOSUCHNAME; 818122394Sharti break; 819122394Sharti case SNMP_ERR_INCONS_VALUE: 820122394Sharti ret = SNMP_ERR_BADVALUE; 821122394Sharti break; 822122394Sharti case SNMP_ERR_RES_UNAVAIL: 823122394Sharti ret = SNMP_ERR_GENERR; 824122394Sharti break; 825122394Sharti case SNMP_ERR_COMMIT_FAILED: 826122394Sharti ret = SNMP_ERR_GENERR; 827122394Sharti break; 828122394Sharti case SNMP_ERR_UNDO_FAILED: 829122394Sharti ret = SNMP_ERR_GENERR; 830122394Sharti break; 831122394Sharti case SNMP_ERR_AUTH_ERR: 832122394Sharti /* should not happen */ 833122394Sharti ret = SNMP_ERR_GENERR; 834122394Sharti break; 835122394Sharti case SNMP_ERR_NOT_WRITEABLE: 836122394Sharti ret = SNMP_ERR_NOSUCHNAME; 837122394Sharti break; 838122394Sharti case SNMP_ERR_INCONS_NAME: 839122394Sharti ret = SNMP_ERR_BADVALUE; 840122394Sharti break; 841122394Sharti } 842122394Sharti } 843122394Sharti if (ret != SNMP_ERR_NOERROR) { 844122394Sharti pdu->error_index = i + 1; 845122394Sharti pdu->error_status = ret; 846122394Sharti 847122394Sharti rollback(&context, pdu, i); 848122394Sharti snmp_pdu_free(resp); 849122394Sharti 850128237Sharti context.ctx.code = SNMP_RET_ERR; 851122394Sharti 852122394Sharti goto errout; 853122394Sharti } 854122394Sharti } 855122394Sharti 856122394Sharti /* 857122394Sharti * 3. Call dependencies 858122394Sharti */ 859122394Sharti if (TR(SET)) 860122394Sharti snmp_debug("set: set operations ok"); 861122394Sharti 862122394Sharti if ((ret = snmp_dep_commit(&context.ctx)) != SNMP_ERR_NOERROR) { 863122394Sharti pdu->error_status = ret; 864122394Sharti pdu->error_index = context.ctx.var_index; 865122394Sharti 866122394Sharti if ((ret = snmp_dep_rollback(&context.ctx)) != SNMP_ERR_NOERROR) { 867122394Sharti if (pdu->version != SNMP_V1) { 868122394Sharti pdu->error_status = SNMP_ERR_UNDO_FAILED; 869122394Sharti pdu->error_index = 0; 870122394Sharti } 871122394Sharti } 872122394Sharti rollback(&context, pdu, i); 873122394Sharti snmp_pdu_free(resp); 874122394Sharti 875128237Sharti context.ctx.code = SNMP_RET_ERR; 876122394Sharti 877122394Sharti goto errout; 878122394Sharti } 879122394Sharti 880122394Sharti /* 881122394Sharti * 4. Commit and copy values from the original packet to the response. 882122394Sharti * This is not the commit operation from RFC 1905 but rather an 883122394Sharti * 'FREE RESOURCES' operation. It shouldn't fail. 884122394Sharti */ 885122394Sharti if (TR(SET)) 886122394Sharti snmp_debug("set: commiting"); 887122394Sharti 888122394Sharti for (i = 0; i < pdu->nbindings; i++) { 889122394Sharti b = &resp->bindings[i]; 890122394Sharti np = context.node[i]; 891122394Sharti 892122394Sharti context.ctx.var_index = i + 1; 893122394Sharti context.ctx.scratch = &context.scratch[i]; 894122394Sharti 895122394Sharti ret = (*np->op)(&context.ctx, b, np->oid.len, np->index, 896122394Sharti SNMP_OP_COMMIT); 897122394Sharti 898122394Sharti if (ret != SNMP_ERR_NOERROR) 899122394Sharti snmp_error("set: commit failed (%d) on" 900122394Sharti " variable %s index %u", ret, 901122394Sharti asn_oid2str_r(&b->var, oidbuf), i); 902122394Sharti } 903122394Sharti 904122394Sharti if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) { 905122394Sharti snmp_error("set: fix_encoding failed"); 906122394Sharti snmp_pdu_free(resp); 907128237Sharti context.ctx.code = SNMP_RET_IGN; 908122394Sharti } 909122394Sharti 910122394Sharti /* 911122394Sharti * Done 912122394Sharti */ 913122394Sharti errout: 914128237Sharti snmp_dep_finish(&context.ctx); 915122394Sharti 916122394Sharti if (TR(SET)) 917128237Sharti snmp_debug("set: returning %d", context.ctx.code); 918122394Sharti 919128237Sharti return (context.ctx.code); 920122394Sharti} 921122394Sharti/* 922122394Sharti * Lookup a dependency. If it doesn't exist, create one 923122394Sharti */ 924122394Shartistruct snmp_dependency * 925122394Shartisnmp_dep_lookup(struct snmp_context *ctx, const struct asn_oid *obj, 926122394Sharti const struct asn_oid *idx, size_t len, snmp_depop_t func) 927122394Sharti{ 928122394Sharti struct context *context; 929122394Sharti struct depend *d; 930122394Sharti 931122394Sharti context = (struct context *)(void *) 932122394Sharti ((char *)ctx - offsetof(struct context, ctx)); 933122394Sharti if (TR(DEPEND)) { 934122394Sharti snmp_debug("depend: looking for %s", asn_oid2str(obj)); 935122394Sharti if (idx) 936122394Sharti snmp_debug("depend: index is %s", asn_oid2str(idx)); 937122394Sharti } 938122394Sharti TAILQ_FOREACH(d, &context->dlist, link) 939122394Sharti if (asn_compare_oid(obj, &d->dep.obj) == 0 && 940122394Sharti ((idx == NULL && d->dep.idx.len == 0) || 941122394Sharti (idx != NULL && asn_compare_oid(idx, &d->dep.idx) == 0))) { 942122394Sharti if(TR(DEPEND)) 943122394Sharti snmp_debug("depend: found"); 944122394Sharti return (&d->dep); 945122394Sharti } 946122394Sharti 947122394Sharti if(TR(DEPEND)) 948122394Sharti snmp_debug("depend: creating"); 949122394Sharti 950122394Sharti if ((d = malloc(offsetof(struct depend, dep) + len)) == NULL) 951122394Sharti return (NULL); 952122394Sharti memset(&d->dep, 0, len); 953122394Sharti 954122394Sharti d->dep.obj = *obj; 955122394Sharti if (idx == NULL) 956122394Sharti d->dep.idx.len = 0; 957122394Sharti else 958122394Sharti d->dep.idx = *idx; 959122394Sharti d->len = len; 960122394Sharti d->func = func; 961122394Sharti 962122394Sharti TAILQ_INSERT_TAIL(&context->dlist, d, link); 963122394Sharti 964122394Sharti return (&d->dep); 965122394Sharti} 966122394Sharti 967122394Sharti/* 968122394Sharti * Make an error response from a PDU. We do this without decoding the 969122394Sharti * variable bindings. This means we can sent the junk back to a caller 970310903Sngie * that has sent us junk in the first place. 971122394Sharti */ 972122394Shartienum snmp_ret 973122394Shartisnmp_make_errresp(const struct snmp_pdu *pdu, struct asn_buf *pdu_b, 974122394Sharti struct asn_buf *resp_b) 975122394Sharti{ 976301661Sngie u_char type; 977122394Sharti asn_len_t len; 978122394Sharti struct snmp_pdu resp; 979122394Sharti enum asn_err err; 980122394Sharti enum snmp_code code; 981122394Sharti 982301661Sngie snmp_pdu_create_response(pdu, &resp); 983301661Sngie 984216294Ssyrinx if ((code = snmp_pdu_decode_header(pdu_b, &resp)) != SNMP_CODE_OK) 985122394Sharti return (SNMP_RET_IGN); 986122394Sharti 987301661Sngie if (pdu->version == SNMP_V3) { 988301661Sngie if (resp.user.priv_proto != SNMP_PRIV_NOPRIV && 989301661Sngie (asn_get_header(pdu_b, &type, &resp.scoped_len) != ASN_ERR_OK 990301661Sngie || type != ASN_TYPE_OCTETSTRING)) { 991301661Sngie snmp_error("cannot decode encrypted pdu"); 992301661Sngie return (SNMP_RET_IGN); 993301661Sngie } 994301661Sngie 995301661Sngie if (asn_get_sequence(pdu_b, &len) != ASN_ERR_OK) { 996301661Sngie snmp_error("cannot decode scoped pdu header"); 997301661Sngie return (SNMP_RET_IGN); 998301661Sngie } 999301661Sngie 1000301661Sngie len = SNMP_ENGINE_ID_SIZ; 1001301661Sngie if (asn_get_octetstring(pdu_b, (u_char *)resp.context_engine, 1002301661Sngie &len) != ASN_ERR_OK) { 1003301661Sngie snmp_error("cannot decode msg context engine"); 1004301661Sngie return (SNMP_RET_IGN); 1005301661Sngie } 1006301661Sngie resp.context_engine_len = len; 1007301661Sngie len = SNMP_CONTEXT_NAME_SIZ; 1008301661Sngie if (asn_get_octetstring(pdu_b, (u_char *)resp.context_name, 1009301661Sngie &len) != ASN_ERR_OK) { 1010301661Sngie snmp_error("cannot decode msg context name"); 1011301661Sngie return (SNMP_RET_IGN); 1012301661Sngie } 1013301661Sngie resp.context_name[len] = '\0'; 1014301661Sngie } 1015301661Sngie 1016301661Sngie 1017301661Sngie if (asn_get_header(pdu_b, &type, &len) != ASN_ERR_OK) { 1018301661Sngie snmp_error("cannot get pdu header"); 1019122394Sharti return (SNMP_RET_IGN); 1020301661Sngie } 1021122394Sharti 1022301661Sngie if ((type & ~ASN_TYPE_MASK) != 1023301661Sngie (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) { 1024301661Sngie snmp_error("bad pdu header tag"); 1025301661Sngie return (SNMP_RET_IGN); 1026301661Sngie } 1027301661Sngie 1028122394Sharti err = snmp_parse_pdus_hdr(pdu_b, &resp, &len); 1029122394Sharti if (ASN_ERR_STOPPED(err)) 1030122394Sharti return (SNMP_RET_IGN); 1031122394Sharti if (pdu_b->asn_len < len) 1032122394Sharti return (SNMP_RET_IGN); 1033122394Sharti pdu_b->asn_len = len; 1034122394Sharti 1035122394Sharti /* now we have the bindings left - construct new message */ 1036122394Sharti resp.error_status = pdu->error_status; 1037122394Sharti resp.error_index = pdu->error_index; 1038122394Sharti resp.type = SNMP_PDU_RESPONSE; 1039122394Sharti 1040122394Sharti code = snmp_pdu_encode_header(resp_b, &resp); 1041122394Sharti if (code != SNMP_CODE_OK) 1042122394Sharti return (SNMP_RET_IGN); 1043122394Sharti 1044122394Sharti if (pdu_b->asn_len > resp_b->asn_len) 1045122394Sharti /* too short */ 1046122394Sharti return (SNMP_RET_IGN); 1047122394Sharti (void)memcpy(resp_b->asn_ptr, pdu_b->asn_cptr, pdu_b->asn_len); 1048122394Sharti resp_b->asn_len -= pdu_b->asn_len; 1049122394Sharti resp_b->asn_ptr += pdu_b->asn_len; 1050122394Sharti 1051122394Sharti code = snmp_fix_encoding(resp_b, &resp); 1052122394Sharti if (code != SNMP_CODE_OK) 1053122394Sharti return (SNMP_RET_IGN); 1054122394Sharti 1055122394Sharti return (SNMP_RET_OK); 1056122394Sharti} 1057122394Sharti 1058122394Shartistatic void 1059122394Shartisnmp_debug_func(const char *fmt, ...) 1060122394Sharti{ 1061122394Sharti va_list ap; 1062122394Sharti 1063122394Sharti va_start(ap, fmt); 1064122394Sharti vfprintf(stderr, fmt, ap); 1065122394Sharti va_end(ap); 1066122394Sharti fprintf(stderr, "\n"); 1067122394Sharti} 1068