40#include <string.h> 41#include <ctype.h> 42#include <netdb.h> 43#include <errno.h> 44 45#include "asn1.h" 46#include "snmp.h" 47#include "snmppriv.h" 48 49static void snmp_error_func(const char *, ...); 50static void snmp_printf_func(const char *, ...); 51 52void (*snmp_error)(const char *, ...) = snmp_error_func; 53void (*snmp_printf)(const char *, ...) = snmp_printf_func; 54 55/* 56 * Get the next variable binding from the list. 57 * ASN errors on the sequence or the OID are always fatal. 58 */ 59static enum asn_err 60get_var_binding(struct asn_buf *b, struct snmp_value *binding) 61{ 62 u_char type; 63 asn_len_t len, trailer; 64 enum asn_err err; 65 66 if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 67 snmp_error("cannot parse varbind header"); 68 return (ASN_ERR_FAILED); 69 } 70 71 /* temporary truncate the length so that the parser does not 72 * eat up bytes behind the sequence in the case the encoding is 73 * wrong of inner elements. */ 74 trailer = b->asn_len - len; 75 b->asn_len = len; 76 77 if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) { 78 snmp_error("cannot parse binding objid"); 79 return (ASN_ERR_FAILED); 80 } 81 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) { 82 snmp_error("cannot parse binding value header"); 83 return (ASN_ERR_FAILED); 84 } 85 86 switch (type) { 87 88 case ASN_TYPE_NULL: 89 binding->syntax = SNMP_SYNTAX_NULL; 90 err = asn_get_null_raw(b, len); 91 break; 92 93 case ASN_TYPE_INTEGER: 94 binding->syntax = SNMP_SYNTAX_INTEGER; 95 err = asn_get_integer_raw(b, len, &binding->v.integer); 96 break; 97 98 case ASN_TYPE_OCTETSTRING: 99 binding->syntax = SNMP_SYNTAX_OCTETSTRING; 100 binding->v.octetstring.octets = malloc(len); 101 if (binding->v.octetstring.octets == NULL) { 102 snmp_error("%s", strerror(errno)); 103 return (ASN_ERR_FAILED); 104 } 105 binding->v.octetstring.len = len; 106 err = asn_get_octetstring_raw(b, len, 107 binding->v.octetstring.octets, 108 &binding->v.octetstring.len); 109 if (ASN_ERR_STOPPED(err)) { 110 free(binding->v.octetstring.octets); 111 binding->v.octetstring.octets = NULL; 112 } 113 break; 114 115 case ASN_TYPE_OBJID: 116 binding->syntax = SNMP_SYNTAX_OID; 117 err = asn_get_objid_raw(b, len, &binding->v.oid); 118 break; 119 120 case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS: 121 binding->syntax = SNMP_SYNTAX_IPADDRESS; 122 err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress); 123 break; 124 125 case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS: 126 binding->syntax = SNMP_SYNTAX_TIMETICKS; 127 err = asn_get_uint32_raw(b, len, &binding->v.uint32); 128 break; 129 130 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER: 131 binding->syntax = SNMP_SYNTAX_COUNTER; 132 err = asn_get_uint32_raw(b, len, &binding->v.uint32); 133 break; 134 135 case ASN_CLASS_APPLICATION|ASN_APP_GAUGE: 136 binding->syntax = SNMP_SYNTAX_GAUGE; 137 err = asn_get_uint32_raw(b, len, &binding->v.uint32); 138 break; 139 140 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64: 141 binding->syntax = SNMP_SYNTAX_COUNTER64; 142 err = asn_get_counter64_raw(b, len, &binding->v.counter64); 143 break; 144 145 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT: 146 binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT; 147 err = asn_get_null_raw(b, len); 148 break; 149 150 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE: 151 binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE; 152 err = asn_get_null_raw(b, len); 153 break; 154 155 case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW: 156 binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW; 157 err = asn_get_null_raw(b, len); 158 break; 159 160 default: 161 if ((err = asn_skip(b, len)) == ASN_ERR_OK) 162 err = ASN_ERR_TAG; 163 snmp_error("bad binding value type 0x%x", type); 164 break; 165 } 166 167 if (ASN_ERR_STOPPED(err)) { 168 snmp_error("cannot parse binding value"); 169 return (err); 170 } 171 172 if (b->asn_len != 0) 173 snmp_error("ignoring junk at end of binding"); 174 175 b->asn_len = trailer; 176 177 return (err); 178} 179 180/* 181 * Parse the different PDUs contents. Any ASN error in the outer components 182 * are fatal. Only errors in variable values may be tolerated. If all 183 * components can be parsed it returns either ASN_ERR_OK or the first 184 * error that was found. 185 */ 186enum asn_err 187snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) 188{ 189 if (pdu->type == SNMP_PDU_TRAP) { 190 if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) { 191 snmp_error("cannot parse trap enterprise"); 192 return (ASN_ERR_FAILED); 193 } 194 if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) { 195 snmp_error("cannot parse trap agent address"); 196 return (ASN_ERR_FAILED); 197 } 198 if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) { 199 snmp_error("cannot parse 'generic-trap'"); 200 return (ASN_ERR_FAILED); 201 } 202 if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) { 203 snmp_error("cannot parse 'specific-trap'"); 204 return (ASN_ERR_FAILED); 205 } 206 if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) { 207 snmp_error("cannot parse trap 'time-stamp'"); 208 return (ASN_ERR_FAILED); 209 } 210 } else { 211 if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) { 212 snmp_error("cannot parse 'request-id'"); 213 return (ASN_ERR_FAILED); 214 } 215 if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) { 216 snmp_error("cannot parse 'error_status'"); 217 return (ASN_ERR_FAILED); 218 } 219 if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) { 220 snmp_error("cannot parse 'error_index'"); 221 return (ASN_ERR_FAILED); 222 } 223 } 224 225 if (asn_get_sequence(b, lenp) != ASN_ERR_OK) { 226 snmp_error("cannot get varlist header"); 227 return (ASN_ERR_FAILED); 228 } 229 230 return (ASN_ERR_OK); 231} 232 233static enum asn_err 234parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 235{ 236 asn_len_t len, trailer; 237 struct snmp_value *v; 238 enum asn_err err, err1; 239 240 err = snmp_parse_pdus_hdr(b, pdu, &len); 241 if (ASN_ERR_STOPPED(err)) 242 return (err); 243 244 trailer = b->asn_len - len; 245 246 v = pdu->bindings; 247 err = ASN_ERR_OK; 248 while (b->asn_len != 0) { 249 if (pdu->nbindings == SNMP_MAX_BINDINGS) { 250 snmp_error("too many bindings (> %u) in PDU", 251 SNMP_MAX_BINDINGS); 252 return (ASN_ERR_FAILED); 253 } 254 err1 = get_var_binding(b, v); 255 if (ASN_ERR_STOPPED(err1)) 256 return (ASN_ERR_FAILED); 257 if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) { 258 err = err1; 259 *ip = pdu->nbindings + 1; 260 } 261 pdu->nbindings++; 262 v++; 263 } 264 265 b->asn_len = trailer; 266 267 return (err); 268} 269 270/* 271 * Parse the outer SEQUENCE value. ASN_ERR_TAG means 'bad version'. 272 */ 273enum asn_err 274snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) 275{ 276 int32_t version; 277 u_char type; 278 u_int comm_len; 279 280 if (asn_get_integer(b, &version) != ASN_ERR_OK) { 281 snmp_error("cannot decode version"); 282 return (ASN_ERR_FAILED); 283 } 284 285 if (version == 0) { 286 pdu->version = SNMP_V1; 287 } else if (version == 1) { 288 pdu->version = SNMP_V2c; 289 } else { 290 pdu->version = SNMP_Verr; 291 snmp_error("unsupported SNMP version"); 292 return (ASN_ERR_TAG); 293 } 294 295 comm_len = SNMP_COMMUNITY_MAXLEN; 296 if (asn_get_octetstring(b, (u_char *)pdu->community, 297 &comm_len) != ASN_ERR_OK) { 298 snmp_error("cannot decode community"); 299 return (ASN_ERR_FAILED); 300 } 301 pdu->community[comm_len] = '\0'; 302 303 if (asn_get_header(b, &type, lenp) != ASN_ERR_OK) { 304 snmp_error("cannot get pdu header"); 305 return (ASN_ERR_FAILED); 306 } 307 if ((type & ~ASN_TYPE_MASK) != 308 (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) { 309 snmp_error("bad pdu header tag"); 310 return (ASN_ERR_FAILED); 311 } 312 pdu->type = type & ASN_TYPE_MASK; 313 314 switch (pdu->type) { 315 316 case SNMP_PDU_GET: 317 case SNMP_PDU_GETNEXT: 318 case SNMP_PDU_RESPONSE: 319 case SNMP_PDU_SET: 320 break; 321 322 case SNMP_PDU_TRAP: 323 if (pdu->version != SNMP_V1) { 324 snmp_error("bad pdu type %u", pdu->type); 325 return (ASN_ERR_FAILED); 326 } 327 break; 328 329 case SNMP_PDU_GETBULK: 330 case SNMP_PDU_INFORM: 331 case SNMP_PDU_TRAP2: 332 case SNMP_PDU_REPORT: 333 if (pdu->version == SNMP_V1) { 334 snmp_error("bad pdu type %u", pdu->type); 335 return (ASN_ERR_FAILED); 336 } 337 break; 338 339 default: 340 snmp_error("bad pdu type %u", pdu->type); 341 return (ASN_ERR_FAILED); 342 } 343 344 345 if (*lenp > b->asn_len) { 346 snmp_error("pdu length too long"); 347 return (ASN_ERR_FAILED); 348 } 349 350 return (ASN_ERR_OK); 351} 352 353static enum asn_err 354parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 355{ 356 enum asn_err err; 357 asn_len_t len, trailer; 358 359 err = snmp_parse_message_hdr(b, pdu, &len); 360 if (ASN_ERR_STOPPED(err)) 361 return (err); 362 363 trailer = b->asn_len - len; 364 b->asn_len = len; 365 366 err = parse_pdus(b, pdu, ip); 367 if (ASN_ERR_STOPPED(err)) 368 return (ASN_ERR_FAILED); 369 370 if (b->asn_len != 0) 371 snmp_error("ignoring trailing junk after pdu"); 372 373 b->asn_len = trailer; 374 375 return (err); 376} 377 378/* 379 * Decode the PDU except for the variable bindings itself. 380 * If decoding fails because of a bad binding, but the rest can be 381 * decoded, ip points to the index of the failed variable (errors 382 * OORANGE, BADLEN or BADVERS). 383 */ 384enum snmp_code 385snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 386{ 387 asn_len_t len; 388 389 memset(pdu, 0, sizeof(*pdu)); 390 391 if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 392 snmp_error("cannot decode pdu header"); 393 return (SNMP_CODE_FAILED); 394 } 395 if (b->asn_len < len) { 396 snmp_error("outer sequence value too short"); 397 return (SNMP_CODE_FAILED); 398 } 399 if (b->asn_len != len) { 400 snmp_error("ignoring trailing junk in message"); 401 b->asn_len = len; 402 } 403 404 switch (parse_message(b, pdu, ip)) { 405 406 case ASN_ERR_OK: 407 return (SNMP_CODE_OK); 408 409 case ASN_ERR_FAILED: 410 case ASN_ERR_EOBUF: 411 snmp_pdu_free(pdu); 412 return (SNMP_CODE_FAILED); 413 414 case ASN_ERR_BADLEN: 415 return (SNMP_CODE_BADLEN); 416 417 case ASN_ERR_RANGE: 418 return (SNMP_CODE_OORANGE); 419 420 case ASN_ERR_TAG: 421 if (pdu->version == SNMP_Verr) 422 return (SNMP_CODE_BADVERS); 423 else 424 return (SNMP_CODE_BADENC); 425 } 426 427 return (SNMP_CODE_OK); 428} 429 430/* 431 * Check whether what we have is the complete PDU by snooping at the 432 * enclosing structure header. This returns: 433 * -1 if there are ASN.1 errors 434 * 0 if we need more data 435 * > 0 the length of this PDU 436 */ 437int 438snmp_pdu_snoop(const struct asn_buf *b0) 439{ 440 u_int length; 441 asn_len_t len; 442 struct asn_buf b = *b0; 443 444 /* <0x10|0x20> <len> <data...> */ 445 446 if (b.asn_len == 0) 447 return (0); 448 if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) { 449 asn_error(&b, "bad sequence type %u", b.asn_cptr[0]); 450 return (-1); 451 } 452 b.asn_len--; 453 b.asn_cptr++; 454 455 if (b.asn_len == 0) 456 return (0); 457 458 if (*b.asn_cptr & 0x80) { 459 /* long length */ 460 length = *b.asn_cptr++ & 0x7f; 461 b.asn_len--; 462 if (length == 0) { 463 asn_error(&b, "indefinite length not supported"); 464 return (-1); 465 } 466 if (length > ASN_MAXLENLEN) { 467 asn_error(&b, "long length too long (%u)", length); 468 return (-1); 469 } 470 if (length > b.asn_len) 471 return (0); 472 len = 0; 473 while (length--) { 474 len = (len << 8) | *b.asn_cptr++; 475 b.asn_len--; 476 } 477 } else { 478 len = *b.asn_cptr++; 479 b.asn_len--; 480 } 481 482 if (len > b.asn_len) 483 return (0); 484 485 return (len + b.asn_cptr - b0->asn_cptr); 486} 487 488/* 489 * Encode the SNMP PDU without the variable bindings field. 490 * We do this the rather uneffective way by 491 * moving things around and assuming that the length field will never 492 * use more than 2 bytes. 493 * We need a number of pointers to apply the fixes afterwards. 494 */ 495enum snmp_code 496snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu) 497{ 498 enum asn_err err; 499 500 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 501 &pdu->outer_ptr) != ASN_ERR_OK) 502 return (SNMP_CODE_FAILED); 503 504 if (pdu->version == SNMP_V1) 505 err = asn_put_integer(b, 0); 506 else if (pdu->version == SNMP_V2c) 507 err = asn_put_integer(b, 1); 508 else 509 return (SNMP_CODE_BADVERS); 510 if (err != ASN_ERR_OK) 511 return (SNMP_CODE_FAILED); 512 513 if (asn_put_octetstring(b, (u_char *)pdu->community, 514 strlen(pdu->community)) != ASN_ERR_OK) 515 return (SNMP_CODE_FAILED); 516 517 if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT | 518 pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK) 519 return (SNMP_CODE_FAILED); 520 521 if (pdu->type == SNMP_PDU_TRAP) { 522 if (pdu->version != SNMP_V1 || 523 asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK || 524 asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK || 525 asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK || 526 asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK || 527 asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK) 528 return (SNMP_CODE_FAILED); 529 } else { 530 if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK || 531 pdu->type == SNMP_PDU_INFORM || 532 pdu->type == SNMP_PDU_TRAP2 || 533 pdu->type == SNMP_PDU_REPORT)) 534 return (SNMP_CODE_FAILED); 535 536 if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK || 537 asn_put_integer(b, pdu->error_status) != ASN_ERR_OK || 538 asn_put_integer(b, pdu->error_index) != ASN_ERR_OK) 539 return (SNMP_CODE_FAILED); 540 } 541 542 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 543 &pdu->vars_ptr) != ASN_ERR_OK) 544 return (SNMP_CODE_FAILED); 545 546 return (SNMP_CODE_OK); 547} 548 549enum snmp_code 550snmp_fix_encoding(struct asn_buf *b, const struct snmp_pdu *pdu) 551{ 552 if (asn_commit_header(b, pdu->vars_ptr) != ASN_ERR_OK || 553 asn_commit_header(b, pdu->pdu_ptr) != ASN_ERR_OK || 554 asn_commit_header(b, pdu->outer_ptr) != ASN_ERR_OK) 555 return (SNMP_CODE_FAILED); 556 return (SNMP_CODE_OK); 557} 558 559/* 560 * Encode a binding. Caller must ensure, that the syntax is ok for that version. 561 * Be sure not to cobber b, when something fails. 562 */ 563enum asn_err 564snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding) 565{ 566 u_char *ptr; 567 enum asn_err err; 568 struct asn_buf save = *b; 569 570 if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | 571 ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) { 572 *b = save; 573 return (err); 574 } 575 576 if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) { 577 *b = save; 578 return (err); 579 } 580 581 switch (binding->syntax) { 582 583 case SNMP_SYNTAX_NULL: 584 err = asn_put_null(b); 585 break; 586 587 case SNMP_SYNTAX_INTEGER: 588 err = asn_put_integer(b, binding->v.integer); 589 break; 590 591 case SNMP_SYNTAX_OCTETSTRING: 592 err = asn_put_octetstring(b, binding->v.octetstring.octets, 593 binding->v.octetstring.len); 594 break; 595 596 case SNMP_SYNTAX_OID: 597 err = asn_put_objid(b, &binding->v.oid); 598 break; 599 600 case SNMP_SYNTAX_IPADDRESS: 601 err = asn_put_ipaddress(b, binding->v.ipaddress); 602 break; 603 604 case SNMP_SYNTAX_TIMETICKS: 605 err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32); 606 break; 607 608 case SNMP_SYNTAX_COUNTER: 609 err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32); 610 break; 611 612 case SNMP_SYNTAX_GAUGE: 613 err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32); 614 break; 615 616 case SNMP_SYNTAX_COUNTER64: 617 err = asn_put_counter64(b, binding->v.counter64); 618 break; 619 620 case SNMP_SYNTAX_NOSUCHOBJECT: 621 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT); 622 break; 623 624 case SNMP_SYNTAX_NOSUCHINSTANCE: 625 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE); 626 break; 627 628 case SNMP_SYNTAX_ENDOFMIBVIEW: 629 err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW); 630 break; 631 } 632 633 if (err != ASN_ERR_OK) { 634 *b = save; 635 return (err); 636 } 637 638 err = asn_commit_header(b, ptr); 639 if (err != ASN_ERR_OK) { 640 *b = save; 641 return (err); 642 } 643 644 return (ASN_ERR_OK); 645} 646 647/* 648 * Encode an PDU. 649 */ 650enum snmp_code 651snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b) 652{ 653 u_int idx; 654 enum snmp_code err; 655 656 if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK) 657 return (err); 658 for (idx = 0; idx < pdu->nbindings; idx++) 659 if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx])) 660 != ASN_ERR_OK) 661 return (SNMP_CODE_FAILED); 662 663 return (snmp_fix_encoding(resp_b, pdu)); 664} 665 666static void 667dump_binding(const struct snmp_value *b) 668{ 669 u_int i; 670 char buf[ASN_OIDSTRLEN]; 671 672 snmp_printf("%s=", asn_oid2str_r(&b->var, buf)); 673 switch (b->syntax) { 674 675 case SNMP_SYNTAX_NULL: 676 snmp_printf("NULL"); 677 break; 678 679 case SNMP_SYNTAX_INTEGER: 680 snmp_printf("INTEGER %d", b->v.integer); 681 break; 682 683 case SNMP_SYNTAX_OCTETSTRING: 684 snmp_printf("OCTET STRING %lu:", b->v.octetstring.len); 685 for (i = 0; i < b->v.octetstring.len; i++) 686 snmp_printf(" %02x", b->v.octetstring.octets[i]); 687 break; 688 689 case SNMP_SYNTAX_OID: 690 snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf)); 691 break; 692 693 case SNMP_SYNTAX_IPADDRESS: 694 snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0], 695 b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]); 696 break; 697 698 case SNMP_SYNTAX_COUNTER: 699 snmp_printf("COUNTER %u", b->v.uint32); 700 break; 701 702 case SNMP_SYNTAX_GAUGE: 703 snmp_printf("GAUGE %u", b->v.uint32); 704 break; 705 706 case SNMP_SYNTAX_TIMETICKS: 707 snmp_printf("TIMETICKS %u", b->v.uint32); 708 break; 709 710 case SNMP_SYNTAX_COUNTER64: 711 snmp_printf("COUNTER64 %lld", b->v.counter64); 712 break; 713 714 case SNMP_SYNTAX_NOSUCHOBJECT: 715 snmp_printf("NoSuchObject"); 716 break; 717 718 case SNMP_SYNTAX_NOSUCHINSTANCE: 719 snmp_printf("NoSuchInstance"); 720 break; 721 722 case SNMP_SYNTAX_ENDOFMIBVIEW: 723 snmp_printf("EndOfMibView"); 724 break; 725 726 default: 727 snmp_printf("UNKNOWN SYNTAX %u", b->syntax); 728 break; 729 } 730} 731 732static __inline void 733dump_bindings(const struct snmp_pdu *pdu) 734{ 735 u_int i; 736 737 for (i = 0; i < pdu->nbindings; i++) { 738 snmp_printf(" [%u]: ", i); 739 dump_binding(&pdu->bindings[i]); 740 snmp_printf("\n"); 741 } 742} 743 744static __inline void 745dump_notrap(const struct snmp_pdu *pdu) 746{ 747 snmp_printf(" request_id=%d", pdu->request_id); 748 snmp_printf(" error_status=%d", pdu->error_status); 749 snmp_printf(" error_index=%d\n", pdu->error_index); 750 dump_bindings(pdu); 751} 752 753void 754snmp_pdu_dump(const struct snmp_pdu *pdu) 755{ 756 char buf[ASN_OIDSTRLEN]; 757 const char *vers; 758 static const char *types[] = { 759 [SNMP_PDU_GET] = "GET", 760 [SNMP_PDU_GETNEXT] = "GETNEXT", 761 [SNMP_PDU_RESPONSE] = "RESPONSE", 762 [SNMP_PDU_SET] = "SET", 763 [SNMP_PDU_TRAP] = "TRAPv1", 764 [SNMP_PDU_GETBULK] = "GETBULK", 765 [SNMP_PDU_INFORM] = "INFORM", 766 [SNMP_PDU_TRAP2] = "TRAPv2", 767 [SNMP_PDU_REPORT] = "REPORT", 768 }; 769 770 if (pdu->version == SNMP_V1) 771 vers = "SNMPv1"; 772 else if (pdu->version == SNMP_V2c) 773 vers = "SNMPv2c"; 774 else 775 vers = "v?"; 776 777 switch (pdu->type) { 778 case SNMP_PDU_TRAP: 779 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); 780 snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf)); 781 snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0], 782 pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]); 783 snmp_printf(" generic_trap=%d", pdu->generic_trap); 784 snmp_printf(" specific_trap=%d", pdu->specific_trap); 785 snmp_printf(" time-stamp=%u\n", pdu->time_stamp); 786 dump_bindings(pdu); 787 break; 788 789 case SNMP_PDU_GET: 790 case SNMP_PDU_GETNEXT: 791 case SNMP_PDU_RESPONSE: 792 case SNMP_PDU_SET: 793 case SNMP_PDU_GETBULK: 794 case SNMP_PDU_INFORM: 795 case SNMP_PDU_TRAP2: 796 case SNMP_PDU_REPORT: 797 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); 798 dump_notrap(pdu); 799 break; 800 801 default: 802 snmp_printf("bad pdu type %u\n", pdu->type); 803 break; 804 } 805} 806 807void 808snmp_value_free(struct snmp_value *value) 809{ 810 if (value->syntax == SNMP_SYNTAX_OCTETSTRING) 811 free(value->v.octetstring.octets); 812 value->syntax = SNMP_SYNTAX_NULL; 813} 814 815int 816snmp_value_copy(struct snmp_value *to, const struct snmp_value *from) 817{ 818 to->var = from->var; 819 to->syntax = from->syntax; 820 821 if (from->syntax == SNMP_SYNTAX_OCTETSTRING) { 822 if ((to->v.octetstring.len = from->v.octetstring.len) == 0) 823 to->v.octetstring.octets = NULL; 824 else { 825 to->v.octetstring.octets = malloc(to->v.octetstring.len); 826 if (to->v.octetstring.octets == NULL) 827 return (-1); 828 (void)memcpy(to->v.octetstring.octets, 829 from->v.octetstring.octets, to->v.octetstring.len); 830 } 831 } else 832 to->v = from->v; 833 return (0); 834} 835 836void 837snmp_pdu_free(struct snmp_pdu *pdu) 838{ 839 u_int i; 840 841 for (i = 0; i < pdu->nbindings; i++) 842 snmp_value_free(&pdu->bindings[i]); 843} 844 845/* 846 * Parse an ASCII SNMP value into the binary form 847 */ 848int 849snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v) 850{ 851 char *end; 852 853 switch (syntax) { 854 855 case SNMP_SYNTAX_NULL: 856 case SNMP_SYNTAX_NOSUCHOBJECT: 857 case SNMP_SYNTAX_NOSUCHINSTANCE: 858 case SNMP_SYNTAX_ENDOFMIBVIEW: 859 if (*str != '\0') 860 return (-1); 861 return (0); 862 863 case SNMP_SYNTAX_INTEGER: 864 v->integer = strtoll(str, &end, 0); 865 if (*end != '\0') 866 return (-1); 867 return (0); 868 869 case SNMP_SYNTAX_OCTETSTRING: 870 { 871 u_long len; /* actual length of string */ 872 u_long alloc; /* allocate length of string */ 873 u_char *octs; /* actual octets */ 874 u_long oct; /* actual octet */ 875 u_char *nocts; /* to avoid memory leak */ 876 u_char c; /* actual character */ 877 878# define STUFFC(C) \ 879 if (alloc == len) { \ 880 alloc += 100; \ 881 if ((nocts = realloc(octs, alloc)) == NULL) { \ 882 free(octs); \ 883 return (-1); \ 884 } \ 885 octs = nocts; \ 886 } \ 887 octs[len++] = (C); 888 889 len = alloc = 0; 890 octs = NULL; 891 892 if (*str == '"') { 893 str++; 894 while((c = *str++) != '\0') { 895 if (c == '"') { 896 if (*str != '\0') { 897 free(octs); 898 return (-1); 899 } 900 break; 901 } 902 if (c == '\\') { 903 switch (c = *str++) { 904 905 case '\\': 906 break; 907 case 'a': 908 c = '\a'; 909 break; 910 case 'b': 911 c = '\b'; 912 break; 913 case 'f': 914 c = '\f'; 915 break; 916 case 'n': 917 c = '\n'; 918 break; 919 case 'r': 920 c = '\r'; 921 break; 922 case 't': 923 c = '\t'; 924 break; 925 case 'v': 926 c = '\v'; 927 break; 928 case 'x': 929 c = 0; 930 if (!isxdigit(*str)) 931 break; 932 if (isdigit(*str)) 933 c = *str++ - '0'; 934 else if (isupper(*str)) 935 c = *str++ - 'A' + 10; 936 else 937 c = *str++ - 'a' + 10; 938 if (!isxdigit(*str)) 939 break; 940 if (isdigit(*str)) 941 c += *str++ - '0'; 942 else if (isupper(*str)) 943 c += *str++ - 'A' + 10; 944 else 945 c += *str++ - 'a' + 10; 946 break; 947 case '0': case '1': case '2': 948 case '3': case '4': case '5': 949 case '6': case '7': 950 c = *str++ - '0'; 951 if (*str < '0' || *str > '7') 952 break; 953 c = *str++ - '0'; 954 if (*str < '0' || *str > '7') 955 break; 956 c = *str++ - '0'; 957 break; 958 default: 959 break; 960 } 961 } 962 STUFFC(c); 963 } 964 } else { 965 while (*str != '\0') { 966 oct = strtoul(str, &end, 16); 967 str = end; 968 if (oct > 0xff) { 969 free(octs); 970 return (-1); 971 } 972 STUFFC(oct); 973 if (*str == ':') 974 str++; 975 else if(*str != '\0') { 976 free(octs); 977 return (-1); 978 } 979 } 980 } 981 v->octetstring.octets = octs; 982 v->octetstring.len = len; 983 return (0); 984# undef STUFFC 985 } 986 987 case SNMP_SYNTAX_OID: 988 { 989 u_long subid; 990 991 v->oid.len = 0; 992 993 for (;;) { 994 if (v->oid.len == ASN_MAXOIDLEN) 995 return (-1); 996 subid = strtoul(str, &end, 10); 997 str = end; 998 if (subid > ASN_MAXID) 999 return (-1); 1000 v->oid.subs[v->oid.len++] = (asn_subid_t)subid; 1001 if (*str == '\0') 1002 break; 1003 if (*str != '.') 1004 return (-1); 1005 str++; 1006 } 1007 return (0); 1008 } 1009 1010 case SNMP_SYNTAX_IPADDRESS: 1011 { 1012 struct hostent *he; 1013 u_long ip[4]; 1014 int n; 1015 1016 if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2], 1017 &ip[3], &n) == 4 && (size_t)n == strlen(str) && 1018 ip[0] <= 0xff && ip[1] <= 0xff && 1019 ip[2] <= 0xff && ip[3] <= 0xff) { 1020 v->ipaddress[0] = (u_char)ip[0]; 1021 v->ipaddress[1] = (u_char)ip[1]; 1022 v->ipaddress[2] = (u_char)ip[2]; 1023 v->ipaddress[3] = (u_char)ip[3]; 1024 return (0); 1025 } 1026 1027 if ((he = gethostbyname(str)) == NULL) 1028 return (-1); 1029 if (he->h_addrtype != AF_INET) 1030 return (-1); 1031 1032 v->ipaddress[0] = he->h_addr[0]; 1033 v->ipaddress[1] = he->h_addr[1]; 1034 v->ipaddress[2] = he->h_addr[2]; 1035 v->ipaddress[3] = he->h_addr[3]; 1036 return (0); 1037 } 1038 1039 case SNMP_SYNTAX_COUNTER: 1040 case SNMP_SYNTAX_GAUGE: 1041 case SNMP_SYNTAX_TIMETICKS: 1042 { 1043 uint64_t sub; 1044 1045 sub = strtoull(str, &end, 0); 1046 if (*end != '\0' || sub > 0xffffffff) 1047 return (-1); 1048 v->uint32 = (uint32_t)sub; 1049 return (0); 1050 } 1051 1052 case SNMP_SYNTAX_COUNTER64: 1053 v->counter64 = strtoull(str, &end, 0); 1054 if (*end != '\0') 1055 return (-1); 1056 return (0); 1057 } 1058 abort(); 1059} 1060 1061static void 1062snmp_error_func(const char *fmt, ...) 1063{ 1064 va_list ap; 1065 1066 va_start(ap, fmt); 1067 fprintf(stderr, "SNMP: "); 1068 vfprintf(stderr, fmt, ap); 1069 fprintf(stderr, "\n"); 1070 va_end(ap); 1071} 1072 1073static void 1074snmp_printf_func(const char *fmt, ...) 1075{ 1076 va_list ap; 1077 1078 va_start(ap, fmt); 1079 vfprintf(stderr, fmt, ap); 1080 va_end(ap); 1081}
| 44#include <string.h> 45#include <ctype.h> 46#include <netdb.h> 47#include <errno.h> 48 49#include "asn1.h" 50#include "snmp.h" 51#include "snmppriv.h" 52 53static void snmp_error_func(const char *, ...); 54static void snmp_printf_func(const char *, ...); 55 56void (*snmp_error)(const char *, ...) = snmp_error_func; 57void (*snmp_printf)(const char *, ...) = snmp_printf_func; 58 59/* 60 * Get the next variable binding from the list. 61 * ASN errors on the sequence or the OID are always fatal. 62 */ 63static enum asn_err 64get_var_binding(struct asn_buf *b, struct snmp_value *binding) 65{ 66 u_char type; 67 asn_len_t len, trailer; 68 enum asn_err err; 69 70 if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 71 snmp_error("cannot parse varbind header"); 72 return (ASN_ERR_FAILED); 73 } 74 75 /* temporary truncate the length so that the parser does not 76 * eat up bytes behind the sequence in the case the encoding is 77 * wrong of inner elements. */ 78 trailer = b->asn_len - len; 79 b->asn_len = len; 80 81 if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) { 82 snmp_error("cannot parse binding objid"); 83 return (ASN_ERR_FAILED); 84 } 85 if (asn_get_header(b, &type, &len) != ASN_ERR_OK) { 86 snmp_error("cannot parse binding value header"); 87 return (ASN_ERR_FAILED); 88 } 89 90 switch (type) { 91 92 case ASN_TYPE_NULL: 93 binding->syntax = SNMP_SYNTAX_NULL; 94 err = asn_get_null_raw(b, len); 95 break; 96 97 case ASN_TYPE_INTEGER: 98 binding->syntax = SNMP_SYNTAX_INTEGER; 99 err = asn_get_integer_raw(b, len, &binding->v.integer); 100 break; 101 102 case ASN_TYPE_OCTETSTRING: 103 binding->syntax = SNMP_SYNTAX_OCTETSTRING; 104 binding->v.octetstring.octets = malloc(len); 105 if (binding->v.octetstring.octets == NULL) { 106 snmp_error("%s", strerror(errno)); 107 return (ASN_ERR_FAILED); 108 } 109 binding->v.octetstring.len = len; 110 err = asn_get_octetstring_raw(b, len, 111 binding->v.octetstring.octets, 112 &binding->v.octetstring.len); 113 if (ASN_ERR_STOPPED(err)) { 114 free(binding->v.octetstring.octets); 115 binding->v.octetstring.octets = NULL; 116 } 117 break; 118 119 case ASN_TYPE_OBJID: 120 binding->syntax = SNMP_SYNTAX_OID; 121 err = asn_get_objid_raw(b, len, &binding->v.oid); 122 break; 123 124 case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS: 125 binding->syntax = SNMP_SYNTAX_IPADDRESS; 126 err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress); 127 break; 128 129 case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS: 130 binding->syntax = SNMP_SYNTAX_TIMETICKS; 131 err = asn_get_uint32_raw(b, len, &binding->v.uint32); 132 break; 133 134 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER: 135 binding->syntax = SNMP_SYNTAX_COUNTER; 136 err = asn_get_uint32_raw(b, len, &binding->v.uint32); 137 break; 138 139 case ASN_CLASS_APPLICATION|ASN_APP_GAUGE: 140 binding->syntax = SNMP_SYNTAX_GAUGE; 141 err = asn_get_uint32_raw(b, len, &binding->v.uint32); 142 break; 143 144 case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64: 145 binding->syntax = SNMP_SYNTAX_COUNTER64; 146 err = asn_get_counter64_raw(b, len, &binding->v.counter64); 147 break; 148 149 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT: 150 binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT; 151 err = asn_get_null_raw(b, len); 152 break; 153 154 case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE: 155 binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE; 156 err = asn_get_null_raw(b, len); 157 break; 158 159 case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW: 160 binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW; 161 err = asn_get_null_raw(b, len); 162 break; 163 164 default: 165 if ((err = asn_skip(b, len)) == ASN_ERR_OK) 166 err = ASN_ERR_TAG; 167 snmp_error("bad binding value type 0x%x", type); 168 break; 169 } 170 171 if (ASN_ERR_STOPPED(err)) { 172 snmp_error("cannot parse binding value"); 173 return (err); 174 } 175 176 if (b->asn_len != 0) 177 snmp_error("ignoring junk at end of binding"); 178 179 b->asn_len = trailer; 180 181 return (err); 182} 183 184/* 185 * Parse the different PDUs contents. Any ASN error in the outer components 186 * are fatal. Only errors in variable values may be tolerated. If all 187 * components can be parsed it returns either ASN_ERR_OK or the first 188 * error that was found. 189 */ 190enum asn_err 191snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) 192{ 193 if (pdu->type == SNMP_PDU_TRAP) { 194 if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) { 195 snmp_error("cannot parse trap enterprise"); 196 return (ASN_ERR_FAILED); 197 } 198 if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) { 199 snmp_error("cannot parse trap agent address"); 200 return (ASN_ERR_FAILED); 201 } 202 if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) { 203 snmp_error("cannot parse 'generic-trap'"); 204 return (ASN_ERR_FAILED); 205 } 206 if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) { 207 snmp_error("cannot parse 'specific-trap'"); 208 return (ASN_ERR_FAILED); 209 } 210 if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) { 211 snmp_error("cannot parse trap 'time-stamp'"); 212 return (ASN_ERR_FAILED); 213 } 214 } else { 215 if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) { 216 snmp_error("cannot parse 'request-id'"); 217 return (ASN_ERR_FAILED); 218 } 219 if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) { 220 snmp_error("cannot parse 'error_status'"); 221 return (ASN_ERR_FAILED); 222 } 223 if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) { 224 snmp_error("cannot parse 'error_index'"); 225 return (ASN_ERR_FAILED); 226 } 227 } 228 229 if (asn_get_sequence(b, lenp) != ASN_ERR_OK) { 230 snmp_error("cannot get varlist header"); 231 return (ASN_ERR_FAILED); 232 } 233 234 return (ASN_ERR_OK); 235} 236 237static enum asn_err 238parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 239{ 240 asn_len_t len, trailer; 241 struct snmp_value *v; 242 enum asn_err err, err1; 243 244 err = snmp_parse_pdus_hdr(b, pdu, &len); 245 if (ASN_ERR_STOPPED(err)) 246 return (err); 247 248 trailer = b->asn_len - len; 249 250 v = pdu->bindings; 251 err = ASN_ERR_OK; 252 while (b->asn_len != 0) { 253 if (pdu->nbindings == SNMP_MAX_BINDINGS) { 254 snmp_error("too many bindings (> %u) in PDU", 255 SNMP_MAX_BINDINGS); 256 return (ASN_ERR_FAILED); 257 } 258 err1 = get_var_binding(b, v); 259 if (ASN_ERR_STOPPED(err1)) 260 return (ASN_ERR_FAILED); 261 if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) { 262 err = err1; 263 *ip = pdu->nbindings + 1; 264 } 265 pdu->nbindings++; 266 v++; 267 } 268 269 b->asn_len = trailer; 270 271 return (err); 272} 273 274/* 275 * Parse the outer SEQUENCE value. ASN_ERR_TAG means 'bad version'. 276 */ 277enum asn_err 278snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) 279{ 280 int32_t version; 281 u_char type; 282 u_int comm_len; 283 284 if (asn_get_integer(b, &version) != ASN_ERR_OK) { 285 snmp_error("cannot decode version"); 286 return (ASN_ERR_FAILED); 287 } 288 289 if (version == 0) { 290 pdu->version = SNMP_V1; 291 } else if (version == 1) { 292 pdu->version = SNMP_V2c; 293 } else { 294 pdu->version = SNMP_Verr; 295 snmp_error("unsupported SNMP version"); 296 return (ASN_ERR_TAG); 297 } 298 299 comm_len = SNMP_COMMUNITY_MAXLEN; 300 if (asn_get_octetstring(b, (u_char *)pdu->community, 301 &comm_len) != ASN_ERR_OK) { 302 snmp_error("cannot decode community"); 303 return (ASN_ERR_FAILED); 304 } 305 pdu->community[comm_len] = '\0'; 306 307 if (asn_get_header(b, &type, lenp) != ASN_ERR_OK) { 308 snmp_error("cannot get pdu header"); 309 return (ASN_ERR_FAILED); 310 } 311 if ((type & ~ASN_TYPE_MASK) != 312 (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) { 313 snmp_error("bad pdu header tag"); 314 return (ASN_ERR_FAILED); 315 } 316 pdu->type = type & ASN_TYPE_MASK; 317 318 switch (pdu->type) { 319 320 case SNMP_PDU_GET: 321 case SNMP_PDU_GETNEXT: 322 case SNMP_PDU_RESPONSE: 323 case SNMP_PDU_SET: 324 break; 325 326 case SNMP_PDU_TRAP: 327 if (pdu->version != SNMP_V1) { 328 snmp_error("bad pdu type %u", pdu->type); 329 return (ASN_ERR_FAILED); 330 } 331 break; 332 333 case SNMP_PDU_GETBULK: 334 case SNMP_PDU_INFORM: 335 case SNMP_PDU_TRAP2: 336 case SNMP_PDU_REPORT: 337 if (pdu->version == SNMP_V1) { 338 snmp_error("bad pdu type %u", pdu->type); 339 return (ASN_ERR_FAILED); 340 } 341 break; 342 343 default: 344 snmp_error("bad pdu type %u", pdu->type); 345 return (ASN_ERR_FAILED); 346 } 347 348 349 if (*lenp > b->asn_len) { 350 snmp_error("pdu length too long"); 351 return (ASN_ERR_FAILED); 352 } 353 354 return (ASN_ERR_OK); 355} 356 357static enum asn_err 358parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 359{ 360 enum asn_err err; 361 asn_len_t len, trailer; 362 363 err = snmp_parse_message_hdr(b, pdu, &len); 364 if (ASN_ERR_STOPPED(err)) 365 return (err); 366 367 trailer = b->asn_len - len; 368 b->asn_len = len; 369 370 err = parse_pdus(b, pdu, ip); 371 if (ASN_ERR_STOPPED(err)) 372 return (ASN_ERR_FAILED); 373 374 if (b->asn_len != 0) 375 snmp_error("ignoring trailing junk after pdu"); 376 377 b->asn_len = trailer; 378 379 return (err); 380} 381 382/* 383 * Decode the PDU except for the variable bindings itself. 384 * If decoding fails because of a bad binding, but the rest can be 385 * decoded, ip points to the index of the failed variable (errors 386 * OORANGE, BADLEN or BADVERS). 387 */ 388enum snmp_code 389snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 390{ 391 asn_len_t len; 392 393 memset(pdu, 0, sizeof(*pdu)); 394 395 if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 396 snmp_error("cannot decode pdu header"); 397 return (SNMP_CODE_FAILED); 398 } 399 if (b->asn_len < len) { 400 snmp_error("outer sequence value too short"); 401 return (SNMP_CODE_FAILED); 402 } 403 if (b->asn_len != len) { 404 snmp_error("ignoring trailing junk in message"); 405 b->asn_len = len; 406 } 407 408 switch (parse_message(b, pdu, ip)) { 409 410 case ASN_ERR_OK: 411 return (SNMP_CODE_OK); 412 413 case ASN_ERR_FAILED: 414 case ASN_ERR_EOBUF: 415 snmp_pdu_free(pdu); 416 return (SNMP_CODE_FAILED); 417 418 case ASN_ERR_BADLEN: 419 return (SNMP_CODE_BADLEN); 420 421 case ASN_ERR_RANGE: 422 return (SNMP_CODE_OORANGE); 423 424 case ASN_ERR_TAG: 425 if (pdu->version == SNMP_Verr) 426 return (SNMP_CODE_BADVERS); 427 else 428 return (SNMP_CODE_BADENC); 429 } 430 431 return (SNMP_CODE_OK); 432} 433 434/* 435 * Check whether what we have is the complete PDU by snooping at the 436 * enclosing structure header. This returns: 437 * -1 if there are ASN.1 errors 438 * 0 if we need more data 439 * > 0 the length of this PDU 440 */ 441int 442snmp_pdu_snoop(const struct asn_buf *b0) 443{ 444 u_int length; 445 asn_len_t len; 446 struct asn_buf b = *b0; 447 448 /* <0x10|0x20> <len> <data...> */ 449 450 if (b.asn_len == 0) 451 return (0); 452 if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) { 453 asn_error(&b, "bad sequence type %u", b.asn_cptr[0]); 454 return (-1); 455 } 456 b.asn_len--; 457 b.asn_cptr++; 458 459 if (b.asn_len == 0) 460 return (0); 461 462 if (*b.asn_cptr & 0x80) { 463 /* long length */ 464 length = *b.asn_cptr++ & 0x7f; 465 b.asn_len--; 466 if (length == 0) { 467 asn_error(&b, "indefinite length not supported"); 468 return (-1); 469 } 470 if (length > ASN_MAXLENLEN) { 471 asn_error(&b, "long length too long (%u)", length); 472 return (-1); 473 } 474 if (length > b.asn_len) 475 return (0); 476 len = 0; 477 while (length--) { 478 len = (len << 8) | *b.asn_cptr++; 479 b.asn_len--; 480 } 481 } else { 482 len = *b.asn_cptr++; 483 b.asn_len--; 484 } 485 486 if (len > b.asn_len) 487 return (0); 488 489 return (len + b.asn_cptr - b0->asn_cptr); 490} 491 492/* 493 * Encode the SNMP PDU without the variable bindings field. 494 * We do this the rather uneffective way by 495 * moving things around and assuming that the length field will never 496 * use more than 2 bytes. 497 * We need a number of pointers to apply the fixes afterwards. 498 */ 499enum snmp_code 500snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu) 501{ 502 enum asn_err err; 503 504 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 505 &pdu->outer_ptr) != ASN_ERR_OK) 506 return (SNMP_CODE_FAILED); 507 508 if (pdu->version == SNMP_V1) 509 err = asn_put_integer(b, 0); 510 else if (pdu->version == SNMP_V2c) 511 err = asn_put_integer(b, 1); 512 else 513 return (SNMP_CODE_BADVERS); 514 if (err != ASN_ERR_OK) 515 return (SNMP_CODE_FAILED); 516 517 if (asn_put_octetstring(b, (u_char *)pdu->community, 518 strlen(pdu->community)) != ASN_ERR_OK) 519 return (SNMP_CODE_FAILED); 520 521 if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT | 522 pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK) 523 return (SNMP_CODE_FAILED); 524 525 if (pdu->type == SNMP_PDU_TRAP) { 526 if (pdu->version != SNMP_V1 || 527 asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK || 528 asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK || 529 asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK || 530 asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK || 531 asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK) 532 return (SNMP_CODE_FAILED); 533 } else { 534 if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK || 535 pdu->type == SNMP_PDU_INFORM || 536 pdu->type == SNMP_PDU_TRAP2 || 537 pdu->type == SNMP_PDU_REPORT)) 538 return (SNMP_CODE_FAILED); 539 540 if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK || 541 asn_put_integer(b, pdu->error_status) != ASN_ERR_OK || 542 asn_put_integer(b, pdu->error_index) != ASN_ERR_OK) 543 return (SNMP_CODE_FAILED); 544 } 545 546 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 547 &pdu->vars_ptr) != ASN_ERR_OK) 548 return (SNMP_CODE_FAILED); 549 550 return (SNMP_CODE_OK); 551} 552 553enum snmp_code 554snmp_fix_encoding(struct asn_buf *b, const struct snmp_pdu *pdu) 555{ 556 if (asn_commit_header(b, pdu->vars_ptr) != ASN_ERR_OK || 557 asn_commit_header(b, pdu->pdu_ptr) != ASN_ERR_OK || 558 asn_commit_header(b, pdu->outer_ptr) != ASN_ERR_OK) 559 return (SNMP_CODE_FAILED); 560 return (SNMP_CODE_OK); 561} 562 563/* 564 * Encode a binding. Caller must ensure, that the syntax is ok for that version. 565 * Be sure not to cobber b, when something fails. 566 */ 567enum asn_err 568snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding) 569{ 570 u_char *ptr; 571 enum asn_err err; 572 struct asn_buf save = *b; 573 574 if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | 575 ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) { 576 *b = save; 577 return (err); 578 } 579 580 if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) { 581 *b = save; 582 return (err); 583 } 584 585 switch (binding->syntax) { 586 587 case SNMP_SYNTAX_NULL: 588 err = asn_put_null(b); 589 break; 590 591 case SNMP_SYNTAX_INTEGER: 592 err = asn_put_integer(b, binding->v.integer); 593 break; 594 595 case SNMP_SYNTAX_OCTETSTRING: 596 err = asn_put_octetstring(b, binding->v.octetstring.octets, 597 binding->v.octetstring.len); 598 break; 599 600 case SNMP_SYNTAX_OID: 601 err = asn_put_objid(b, &binding->v.oid); 602 break; 603 604 case SNMP_SYNTAX_IPADDRESS: 605 err = asn_put_ipaddress(b, binding->v.ipaddress); 606 break; 607 608 case SNMP_SYNTAX_TIMETICKS: 609 err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32); 610 break; 611 612 case SNMP_SYNTAX_COUNTER: 613 err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32); 614 break; 615 616 case SNMP_SYNTAX_GAUGE: 617 err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32); 618 break; 619 620 case SNMP_SYNTAX_COUNTER64: 621 err = asn_put_counter64(b, binding->v.counter64); 622 break; 623 624 case SNMP_SYNTAX_NOSUCHOBJECT: 625 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT); 626 break; 627 628 case SNMP_SYNTAX_NOSUCHINSTANCE: 629 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE); 630 break; 631 632 case SNMP_SYNTAX_ENDOFMIBVIEW: 633 err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW); 634 break; 635 } 636 637 if (err != ASN_ERR_OK) { 638 *b = save; 639 return (err); 640 } 641 642 err = asn_commit_header(b, ptr); 643 if (err != ASN_ERR_OK) { 644 *b = save; 645 return (err); 646 } 647 648 return (ASN_ERR_OK); 649} 650 651/* 652 * Encode an PDU. 653 */ 654enum snmp_code 655snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b) 656{ 657 u_int idx; 658 enum snmp_code err; 659 660 if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK) 661 return (err); 662 for (idx = 0; idx < pdu->nbindings; idx++) 663 if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx])) 664 != ASN_ERR_OK) 665 return (SNMP_CODE_FAILED); 666 667 return (snmp_fix_encoding(resp_b, pdu)); 668} 669 670static void 671dump_binding(const struct snmp_value *b) 672{ 673 u_int i; 674 char buf[ASN_OIDSTRLEN]; 675 676 snmp_printf("%s=", asn_oid2str_r(&b->var, buf)); 677 switch (b->syntax) { 678 679 case SNMP_SYNTAX_NULL: 680 snmp_printf("NULL"); 681 break; 682 683 case SNMP_SYNTAX_INTEGER: 684 snmp_printf("INTEGER %d", b->v.integer); 685 break; 686 687 case SNMP_SYNTAX_OCTETSTRING: 688 snmp_printf("OCTET STRING %lu:", b->v.octetstring.len); 689 for (i = 0; i < b->v.octetstring.len; i++) 690 snmp_printf(" %02x", b->v.octetstring.octets[i]); 691 break; 692 693 case SNMP_SYNTAX_OID: 694 snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf)); 695 break; 696 697 case SNMP_SYNTAX_IPADDRESS: 698 snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0], 699 b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]); 700 break; 701 702 case SNMP_SYNTAX_COUNTER: 703 snmp_printf("COUNTER %u", b->v.uint32); 704 break; 705 706 case SNMP_SYNTAX_GAUGE: 707 snmp_printf("GAUGE %u", b->v.uint32); 708 break; 709 710 case SNMP_SYNTAX_TIMETICKS: 711 snmp_printf("TIMETICKS %u", b->v.uint32); 712 break; 713 714 case SNMP_SYNTAX_COUNTER64: 715 snmp_printf("COUNTER64 %lld", b->v.counter64); 716 break; 717 718 case SNMP_SYNTAX_NOSUCHOBJECT: 719 snmp_printf("NoSuchObject"); 720 break; 721 722 case SNMP_SYNTAX_NOSUCHINSTANCE: 723 snmp_printf("NoSuchInstance"); 724 break; 725 726 case SNMP_SYNTAX_ENDOFMIBVIEW: 727 snmp_printf("EndOfMibView"); 728 break; 729 730 default: 731 snmp_printf("UNKNOWN SYNTAX %u", b->syntax); 732 break; 733 } 734} 735 736static __inline void 737dump_bindings(const struct snmp_pdu *pdu) 738{ 739 u_int i; 740 741 for (i = 0; i < pdu->nbindings; i++) { 742 snmp_printf(" [%u]: ", i); 743 dump_binding(&pdu->bindings[i]); 744 snmp_printf("\n"); 745 } 746} 747 748static __inline void 749dump_notrap(const struct snmp_pdu *pdu) 750{ 751 snmp_printf(" request_id=%d", pdu->request_id); 752 snmp_printf(" error_status=%d", pdu->error_status); 753 snmp_printf(" error_index=%d\n", pdu->error_index); 754 dump_bindings(pdu); 755} 756 757void 758snmp_pdu_dump(const struct snmp_pdu *pdu) 759{ 760 char buf[ASN_OIDSTRLEN]; 761 const char *vers; 762 static const char *types[] = { 763 [SNMP_PDU_GET] = "GET", 764 [SNMP_PDU_GETNEXT] = "GETNEXT", 765 [SNMP_PDU_RESPONSE] = "RESPONSE", 766 [SNMP_PDU_SET] = "SET", 767 [SNMP_PDU_TRAP] = "TRAPv1", 768 [SNMP_PDU_GETBULK] = "GETBULK", 769 [SNMP_PDU_INFORM] = "INFORM", 770 [SNMP_PDU_TRAP2] = "TRAPv2", 771 [SNMP_PDU_REPORT] = "REPORT", 772 }; 773 774 if (pdu->version == SNMP_V1) 775 vers = "SNMPv1"; 776 else if (pdu->version == SNMP_V2c) 777 vers = "SNMPv2c"; 778 else 779 vers = "v?"; 780 781 switch (pdu->type) { 782 case SNMP_PDU_TRAP: 783 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); 784 snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf)); 785 snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0], 786 pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]); 787 snmp_printf(" generic_trap=%d", pdu->generic_trap); 788 snmp_printf(" specific_trap=%d", pdu->specific_trap); 789 snmp_printf(" time-stamp=%u\n", pdu->time_stamp); 790 dump_bindings(pdu); 791 break; 792 793 case SNMP_PDU_GET: 794 case SNMP_PDU_GETNEXT: 795 case SNMP_PDU_RESPONSE: 796 case SNMP_PDU_SET: 797 case SNMP_PDU_GETBULK: 798 case SNMP_PDU_INFORM: 799 case SNMP_PDU_TRAP2: 800 case SNMP_PDU_REPORT: 801 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); 802 dump_notrap(pdu); 803 break; 804 805 default: 806 snmp_printf("bad pdu type %u\n", pdu->type); 807 break; 808 } 809} 810 811void 812snmp_value_free(struct snmp_value *value) 813{ 814 if (value->syntax == SNMP_SYNTAX_OCTETSTRING) 815 free(value->v.octetstring.octets); 816 value->syntax = SNMP_SYNTAX_NULL; 817} 818 819int 820snmp_value_copy(struct snmp_value *to, const struct snmp_value *from) 821{ 822 to->var = from->var; 823 to->syntax = from->syntax; 824 825 if (from->syntax == SNMP_SYNTAX_OCTETSTRING) { 826 if ((to->v.octetstring.len = from->v.octetstring.len) == 0) 827 to->v.octetstring.octets = NULL; 828 else { 829 to->v.octetstring.octets = malloc(to->v.octetstring.len); 830 if (to->v.octetstring.octets == NULL) 831 return (-1); 832 (void)memcpy(to->v.octetstring.octets, 833 from->v.octetstring.octets, to->v.octetstring.len); 834 } 835 } else 836 to->v = from->v; 837 return (0); 838} 839 840void 841snmp_pdu_free(struct snmp_pdu *pdu) 842{ 843 u_int i; 844 845 for (i = 0; i < pdu->nbindings; i++) 846 snmp_value_free(&pdu->bindings[i]); 847} 848 849/* 850 * Parse an ASCII SNMP value into the binary form 851 */ 852int 853snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v) 854{ 855 char *end; 856 857 switch (syntax) { 858 859 case SNMP_SYNTAX_NULL: 860 case SNMP_SYNTAX_NOSUCHOBJECT: 861 case SNMP_SYNTAX_NOSUCHINSTANCE: 862 case SNMP_SYNTAX_ENDOFMIBVIEW: 863 if (*str != '\0') 864 return (-1); 865 return (0); 866 867 case SNMP_SYNTAX_INTEGER: 868 v->integer = strtoll(str, &end, 0); 869 if (*end != '\0') 870 return (-1); 871 return (0); 872 873 case SNMP_SYNTAX_OCTETSTRING: 874 { 875 u_long len; /* actual length of string */ 876 u_long alloc; /* allocate length of string */ 877 u_char *octs; /* actual octets */ 878 u_long oct; /* actual octet */ 879 u_char *nocts; /* to avoid memory leak */ 880 u_char c; /* actual character */ 881 882# define STUFFC(C) \ 883 if (alloc == len) { \ 884 alloc += 100; \ 885 if ((nocts = realloc(octs, alloc)) == NULL) { \ 886 free(octs); \ 887 return (-1); \ 888 } \ 889 octs = nocts; \ 890 } \ 891 octs[len++] = (C); 892 893 len = alloc = 0; 894 octs = NULL; 895 896 if (*str == '"') { 897 str++; 898 while((c = *str++) != '\0') { 899 if (c == '"') { 900 if (*str != '\0') { 901 free(octs); 902 return (-1); 903 } 904 break; 905 } 906 if (c == '\\') { 907 switch (c = *str++) { 908 909 case '\\': 910 break; 911 case 'a': 912 c = '\a'; 913 break; 914 case 'b': 915 c = '\b'; 916 break; 917 case 'f': 918 c = '\f'; 919 break; 920 case 'n': 921 c = '\n'; 922 break; 923 case 'r': 924 c = '\r'; 925 break; 926 case 't': 927 c = '\t'; 928 break; 929 case 'v': 930 c = '\v'; 931 break; 932 case 'x': 933 c = 0; 934 if (!isxdigit(*str)) 935 break; 936 if (isdigit(*str)) 937 c = *str++ - '0'; 938 else if (isupper(*str)) 939 c = *str++ - 'A' + 10; 940 else 941 c = *str++ - 'a' + 10; 942 if (!isxdigit(*str)) 943 break; 944 if (isdigit(*str)) 945 c += *str++ - '0'; 946 else if (isupper(*str)) 947 c += *str++ - 'A' + 10; 948 else 949 c += *str++ - 'a' + 10; 950 break; 951 case '0': case '1': case '2': 952 case '3': case '4': case '5': 953 case '6': case '7': 954 c = *str++ - '0'; 955 if (*str < '0' || *str > '7') 956 break; 957 c = *str++ - '0'; 958 if (*str < '0' || *str > '7') 959 break; 960 c = *str++ - '0'; 961 break; 962 default: 963 break; 964 } 965 } 966 STUFFC(c); 967 } 968 } else { 969 while (*str != '\0') { 970 oct = strtoul(str, &end, 16); 971 str = end; 972 if (oct > 0xff) { 973 free(octs); 974 return (-1); 975 } 976 STUFFC(oct); 977 if (*str == ':') 978 str++; 979 else if(*str != '\0') { 980 free(octs); 981 return (-1); 982 } 983 } 984 } 985 v->octetstring.octets = octs; 986 v->octetstring.len = len; 987 return (0); 988# undef STUFFC 989 } 990 991 case SNMP_SYNTAX_OID: 992 { 993 u_long subid; 994 995 v->oid.len = 0; 996 997 for (;;) { 998 if (v->oid.len == ASN_MAXOIDLEN) 999 return (-1); 1000 subid = strtoul(str, &end, 10); 1001 str = end; 1002 if (subid > ASN_MAXID) 1003 return (-1); 1004 v->oid.subs[v->oid.len++] = (asn_subid_t)subid; 1005 if (*str == '\0') 1006 break; 1007 if (*str != '.') 1008 return (-1); 1009 str++; 1010 } 1011 return (0); 1012 } 1013 1014 case SNMP_SYNTAX_IPADDRESS: 1015 { 1016 struct hostent *he; 1017 u_long ip[4]; 1018 int n; 1019 1020 if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2], 1021 &ip[3], &n) == 4 && (size_t)n == strlen(str) && 1022 ip[0] <= 0xff && ip[1] <= 0xff && 1023 ip[2] <= 0xff && ip[3] <= 0xff) { 1024 v->ipaddress[0] = (u_char)ip[0]; 1025 v->ipaddress[1] = (u_char)ip[1]; 1026 v->ipaddress[2] = (u_char)ip[2]; 1027 v->ipaddress[3] = (u_char)ip[3]; 1028 return (0); 1029 } 1030 1031 if ((he = gethostbyname(str)) == NULL) 1032 return (-1); 1033 if (he->h_addrtype != AF_INET) 1034 return (-1); 1035 1036 v->ipaddress[0] = he->h_addr[0]; 1037 v->ipaddress[1] = he->h_addr[1]; 1038 v->ipaddress[2] = he->h_addr[2]; 1039 v->ipaddress[3] = he->h_addr[3]; 1040 return (0); 1041 } 1042 1043 case SNMP_SYNTAX_COUNTER: 1044 case SNMP_SYNTAX_GAUGE: 1045 case SNMP_SYNTAX_TIMETICKS: 1046 { 1047 uint64_t sub; 1048 1049 sub = strtoull(str, &end, 0); 1050 if (*end != '\0' || sub > 0xffffffff) 1051 return (-1); 1052 v->uint32 = (uint32_t)sub; 1053 return (0); 1054 } 1055 1056 case SNMP_SYNTAX_COUNTER64: 1057 v->counter64 = strtoull(str, &end, 0); 1058 if (*end != '\0') 1059 return (-1); 1060 return (0); 1061 } 1062 abort(); 1063} 1064 1065static void 1066snmp_error_func(const char *fmt, ...) 1067{ 1068 va_list ap; 1069 1070 va_start(ap, fmt); 1071 fprintf(stderr, "SNMP: "); 1072 vfprintf(stderr, fmt, ap); 1073 fprintf(stderr, "\n"); 1074 va_end(ap); 1075} 1076 1077static void 1078snmp_printf_func(const char *fmt, ...) 1079{ 1080 va_list ap; 1081 1082 va_start(ap, fmt); 1083 vfprintf(stderr, fmt, ap); 1084 va_end(ap); 1085}
|