1 /* $OpenBSD: snmpe.c,v 1.23 2008/12/08 11:34:55 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/queue.h> 20 #include <sys/param.h> 21 #include <sys/types.h> 22 #include <sys/stat.h> 23 #include <sys/socket.h> 24 #include <sys/un.h> 25 #include <sys/tree.h> 26 27 #include <net/if.h> 28 #include <netinet/in.h> 29 #include <arpa/inet.h> 30 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <errno.h> 34 #include <event.h> 35 #include <fcntl.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <pwd.h> 39 40 #include "snmpd.h" 41 42 int snmpe_parse(struct sockaddr_storage *, 43 struct ber_element *, struct snmp_message *); 44 unsigned long 45 snmpe_application(struct ber_element *); 46 void snmpe_sig_handler(int sig, short, void *); 47 void snmpe_shutdown(void); 48 void snmpe_dispatch_parent(int, short, void *); 49 int snmpe_bind(struct address *); 50 void snmpe_recvmsg(int fd, short, void *); 51 52 struct snmpd *env = NULL; 53 54 struct imsgbuf *ibuf_parent; 55 56 void 57 snmpe_sig_handler(int sig, short event, void *arg) 58 { 59 switch (sig) { 60 case SIGINT: 61 case SIGTERM: 62 snmpe_shutdown(); 63 break; 64 default: 65 fatalx("snmpe_sig_handler: unexpected signal"); 66 } 67 } 68 69 pid_t 70 snmpe(struct snmpd *x_env, int pipe_parent2snmpe[2]) 71 { 72 pid_t pid; 73 struct passwd *pw; 74 struct event ev_sigint; 75 struct event ev_sigterm; 76 #ifdef DEBUG 77 struct oid *oid; 78 #endif 79 80 switch (pid = fork()) { 81 case -1: 82 fatal("snmpe: cannot fork"); 83 case 0: 84 break; 85 default: 86 return (pid); 87 } 88 89 env = x_env; 90 91 if (control_init(&env->sc_csock) == -1) 92 fatalx("snmpe: control socket setup failed"); 93 if (control_init(&env->sc_rcsock) == -1) 94 fatalx("snmpe: restricted control socket setup failed"); 95 96 if ((env->sc_sock = snmpe_bind(&env->sc_address)) == -1) 97 fatalx("snmpe: failed to bind SNMP UDP socket"); 98 99 if ((pw = getpwnam(SNMPD_USER)) == NULL) 100 fatal("snmpe: getpwnam"); 101 102 #ifndef DEBUG 103 if (chroot(pw->pw_dir) == -1) 104 fatal("snmpe: chroot"); 105 if (chdir("/") == -1) 106 fatal("snmpe: chdir(\"/\")"); 107 #else 108 #warning disabling privilege revocation and chroot in DEBUG mode 109 #endif 110 111 setproctitle("snmp engine"); 112 snmpd_process = PROC_SNMPE; 113 114 #ifndef DEBUG 115 if (setgroups(1, &pw->pw_gid) || 116 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 117 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 118 fatal("snmpe: cannot drop privileges"); 119 #endif 120 121 #ifdef DEBUG 122 for (oid = NULL; (oid = smi_foreach(oid, 0)) != NULL;) { 123 char buf[BUFSIZ]; 124 smi_oidstring(&oid->o_id, buf, sizeof(buf)); 125 log_debug("oid %s", buf); 126 } 127 #endif 128 129 event_init(); 130 131 signal_set(&ev_sigint, SIGINT, snmpe_sig_handler, NULL); 132 signal_set(&ev_sigterm, SIGTERM, snmpe_sig_handler, NULL); 133 signal_add(&ev_sigint, NULL); 134 signal_add(&ev_sigterm, NULL); 135 signal(SIGPIPE, SIG_IGN); 136 signal(SIGHUP, SIG_IGN); 137 138 close(pipe_parent2snmpe[0]); 139 140 if ((ibuf_parent = calloc(1, sizeof(struct imsgbuf))) == NULL) 141 fatal("snmpe"); 142 143 imsg_init(ibuf_parent, pipe_parent2snmpe[1], snmpe_dispatch_parent); 144 145 ibuf_parent->events = EV_READ; 146 event_set(&ibuf_parent->ev, ibuf_parent->fd, ibuf_parent->events, 147 ibuf_parent->handler, ibuf_parent); 148 event_add(&ibuf_parent->ev, NULL); 149 150 TAILQ_INIT(&ctl_conns); 151 152 if (control_listen(&env->sc_csock) == -1) 153 fatalx("snmpe: control socket listen failed"); 154 if (control_listen(&env->sc_rcsock) == -1) 155 fatalx("snmpe: restricted control socket listen failed"); 156 157 event_set(&env->sc_ev, env->sc_sock, EV_READ|EV_PERSIST, 158 snmpe_recvmsg, env); 159 event_add(&env->sc_ev, NULL); 160 161 kr_init(); 162 trap_init(); 163 timer_init(); 164 165 event_dispatch(); 166 167 snmpe_shutdown(); 168 kr_shutdown(); 169 170 return (0); 171 } 172 173 void 174 snmpe_shutdown(void) 175 { 176 log_info("snmp engine exiting"); 177 _exit(0); 178 } 179 180 void 181 snmpe_dispatch_parent(int fd, short event, void * ptr) 182 { 183 struct imsgbuf *ibuf; 184 struct imsg imsg; 185 ssize_t n; 186 187 ibuf = ptr; 188 switch (event) { 189 case EV_READ: 190 if ((n = imsg_read(ibuf)) == -1) 191 fatal("imsg_read error"); 192 if (n == 0) { 193 /* this pipe is dead, so remove the event handler */ 194 event_del(&ibuf->ev); 195 event_loopexit(NULL); 196 return; 197 } 198 break; 199 case EV_WRITE: 200 if (msgbuf_write(&ibuf->w) == -1) 201 fatal("msgbuf_write"); 202 imsg_event_add(ibuf); 203 return; 204 default: 205 fatalx("snmpe_dispatch_parent: unknown event"); 206 } 207 208 for (;;) { 209 if ((n = imsg_get(ibuf, &imsg)) == -1) 210 fatal("snmpe_dispatch_parent: imsg_read error"); 211 if (n == 0) 212 break; 213 214 switch (imsg.hdr.type) { 215 default: 216 log_debug("snmpe_dispatch_parent: unexpected imsg %d", 217 imsg.hdr.type); 218 break; 219 } 220 imsg_free(&imsg); 221 } 222 imsg_event_add(ibuf); 223 } 224 225 int 226 snmpe_bind(struct address *addr) 227 { 228 char buf[512]; 229 int s; 230 231 if ((s = snmpd_socket_af(&addr->ss, htons(addr->port))) == -1) 232 return (-1); 233 234 /* 235 * Socket options 236 */ 237 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) 238 goto bad; 239 240 if (bind(s, (struct sockaddr *)&addr->ss, addr->ss.ss_len) == -1) 241 goto bad; 242 243 if (print_host(&addr->ss, buf, sizeof(buf)) == NULL) 244 goto bad; 245 246 log_info("snmpe_bind: binding to address %s:%d", buf, addr->port); 247 248 return (s); 249 250 bad: 251 close(s); 252 return (-1); 253 } 254 255 #ifdef DEBUG 256 void 257 snmpe_debug_elements(struct ber_element *root) 258 { 259 static int indent = 0; 260 long long v; 261 int d; 262 char *buf; 263 size_t len; 264 u_int i; 265 int constructed; 266 struct ber_oid o; 267 char str[BUFSIZ]; 268 269 /* calculate lengths */ 270 ber_calc_len(root); 271 272 switch (root->be_encoding) { 273 case BER_TYPE_SEQUENCE: 274 case BER_TYPE_SET: 275 constructed = root->be_encoding; 276 break; 277 default: 278 constructed = 0; 279 break; 280 } 281 282 fprintf(stderr, "%*slen %lu ", indent, "", root->be_len); 283 switch (root->be_class) { 284 case BER_CLASS_UNIVERSAL: 285 fprintf(stderr, "class: universal(%u) type: ", root->be_class); 286 switch (root->be_type) { 287 case BER_TYPE_EOC: 288 fprintf(stderr, "end-of-content"); 289 break; 290 case BER_TYPE_BOOLEAN: 291 fprintf(stderr, "boolean"); 292 break; 293 case BER_TYPE_INTEGER: 294 fprintf(stderr, "integer"); 295 break; 296 case BER_TYPE_BITSTRING: 297 fprintf(stderr, "bit-string"); 298 break; 299 case BER_TYPE_OCTETSTRING: 300 fprintf(stderr, "octet-string"); 301 break; 302 case BER_TYPE_NULL: 303 fprintf(stderr, "null"); 304 break; 305 case BER_TYPE_OBJECT: 306 fprintf(stderr, "object"); 307 break; 308 case BER_TYPE_ENUMERATED: 309 fprintf(stderr, "enumerated"); 310 break; 311 case BER_TYPE_SEQUENCE: 312 fprintf(stderr, "sequence"); 313 break; 314 case BER_TYPE_SET: 315 fprintf(stderr, "set"); 316 break; 317 } 318 break; 319 case BER_CLASS_APPLICATION: 320 fprintf(stderr, "class: application(%u) type: ", 321 root->be_class); 322 switch (root->be_type) { 323 case SNMP_T_IPADDR: 324 fprintf(stderr, "ipaddr"); 325 break; 326 case SNMP_T_COUNTER32: 327 fprintf(stderr, "counter32"); 328 break; 329 case SNMP_T_GAUGE32: 330 fprintf(stderr, "gauge32"); 331 break; 332 case SNMP_T_TIMETICKS: 333 fprintf(stderr, "timeticks"); 334 break; 335 case SNMP_T_OPAQUE: 336 fprintf(stderr, "opaque"); 337 break; 338 case SNMP_T_COUNTER64: 339 fprintf(stderr, "counter64"); 340 break; 341 } 342 break; 343 case BER_CLASS_CONTEXT: 344 fprintf(stderr, "class: context(%u) type: ", 345 root->be_class); 346 switch (root->be_type) { 347 case SNMP_C_GETREQ: 348 fprintf(stderr, "getreq"); 349 break; 350 case SNMP_C_GETNEXTREQ: 351 fprintf(stderr, "nextreq"); 352 break; 353 case SNMP_C_GETRESP: 354 fprintf(stderr, "getresp"); 355 break; 356 case SNMP_C_SETREQ: 357 fprintf(stderr, "setreq"); 358 break; 359 case SNMP_C_TRAP: 360 fprintf(stderr, "trap"); 361 break; 362 case SNMP_C_GETBULKREQ: 363 fprintf(stderr, "getbulkreq"); 364 break; 365 case SNMP_C_INFORMREQ: 366 fprintf(stderr, "informreq"); 367 break; 368 case SNMP_C_TRAPV2: 369 fprintf(stderr, "trapv2"); 370 break; 371 case SNMP_C_REPORT: 372 fprintf(stderr, "report"); 373 break; 374 } 375 break; 376 case BER_CLASS_PRIVATE: 377 fprintf(stderr, "class: private(%u) type: ", root->be_class); 378 break; 379 default: 380 fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class); 381 break; 382 } 383 fprintf(stderr, "(%lu) encoding %lu ", 384 root->be_type, root->be_encoding); 385 386 if (constructed) 387 root->be_encoding = constructed; 388 389 switch (root->be_encoding) { 390 case BER_TYPE_BOOLEAN: 391 if (ber_get_boolean(root, &d) == -1) { 392 fprintf(stderr, "<INVALID>\n"); 393 break; 394 } 395 fprintf(stderr, "%s(%d)\n", d ? "true" : "false", d); 396 break; 397 case BER_TYPE_INTEGER: 398 case BER_TYPE_ENUMERATED: 399 if (ber_get_integer(root, &v) == -1) { 400 fprintf(stderr, "<INVALID>\n"); 401 break; 402 } 403 fprintf(stderr, "value %lld\n", v); 404 break; 405 case BER_TYPE_BITSTRING: 406 if (ber_get_bitstring(root, (void *)&buf, &len) == -1) { 407 fprintf(stderr, "<INVALID>\n"); 408 break; 409 } 410 fprintf(stderr, "hexdump "); 411 for (i = 0; i < len; i++) 412 fprintf(stderr, "%02x", buf[i]); 413 fprintf(stderr, "\n"); 414 break; 415 case BER_TYPE_OBJECT: 416 if (ber_get_oid(root, &o) == -1) { 417 fprintf(stderr, "<INVALID>\n"); 418 break; 419 } 420 fprintf(stderr, "oid %s", 421 smi_oidstring(&o, str, sizeof(str))); 422 fprintf(stderr, "\n"); 423 break; 424 case BER_TYPE_OCTETSTRING: 425 if (ber_get_string(root, &buf) == -1) { 426 fprintf(stderr, "<INVALID>\n"); 427 break; 428 } 429 if (root->be_class == BER_CLASS_APPLICATION && 430 root->be_type == SNMP_T_IPADDR) { 431 fprintf(stderr, "addr %s\n", 432 inet_ntoa(*(struct in_addr *)buf)); 433 } else 434 fprintf(stderr, "string \"%s\"\n", 435 root->be_len ? buf : ""); 436 break; 437 case BER_TYPE_NULL: /* no payload */ 438 case BER_TYPE_EOC: 439 case BER_TYPE_SEQUENCE: 440 case BER_TYPE_SET: 441 default: 442 fprintf(stderr, "\n"); 443 break; 444 } 445 446 if (constructed && root->be_sub) { 447 indent += 2; 448 snmpe_debug_elements(root->be_sub); 449 indent -= 2; 450 } 451 if (root->be_next) 452 snmpe_debug_elements(root->be_next); 453 } 454 #endif 455 456 unsigned long 457 snmpe_application(struct ber_element *elm) 458 { 459 if (elm->be_class != BER_CLASS_APPLICATION) 460 return (BER_TYPE_OCTETSTRING); 461 462 switch (elm->be_type) { 463 case SNMP_T_IPADDR: 464 return (BER_TYPE_OCTETSTRING); 465 case SNMP_T_COUNTER32: 466 case SNMP_T_GAUGE32: 467 case SNMP_T_TIMETICKS: 468 case SNMP_T_OPAQUE: 469 case SNMP_T_COUNTER64: 470 return (BER_TYPE_INTEGER); 471 default: 472 break; 473 } 474 return (BER_TYPE_OCTETSTRING); 475 } 476 477 int 478 snmpe_parse(struct sockaddr_storage *ss, 479 struct ber_element *root, struct snmp_message *msg) 480 { 481 struct snmp_stats *stats = &env->sc_stats; 482 struct ber_element *a, *b, *c, *d, *e, *f, *next, *last; 483 const char *errstr = "invalid message"; 484 long long ver, req; 485 unsigned long type, errval, erridx; 486 u_int class, state, i = 0, j = 0; 487 char *comn, buf[BUFSIZ], host[MAXHOSTNAMELEN]; 488 struct ber_oid o; 489 size_t len; 490 491 bzero(msg, sizeof(*msg)); 492 493 if (ber_scanf_elements(root, "e{ieset{e", 494 &msg->sm_header, &ver, &msg->sm_headerend, &comn, 495 &msg->sm_pdu, &class, &type, &a) != 0) 496 goto parsefail; 497 498 /* SNMP version and community */ 499 switch (ver) { 500 case SNMP_V1: 501 case SNMP_V2: 502 msg->sm_version = ver; 503 break; 504 case SNMP_V3: 505 default: 506 stats->snmp_inbadversions++; 507 errstr = "bad snmp version"; 508 goto fail; 509 } 510 511 /* SNMP PDU context */ 512 if (class != BER_CLASS_CONTEXT) 513 goto parsefail; 514 switch (type) { 515 case SNMP_C_GETBULKREQ: 516 if (msg->sm_version == SNMP_V1) { 517 stats->snmp_inbadversions++; 518 errstr = "invalid request for protocol version 1"; 519 goto fail; 520 } 521 /* FALLTHROUGH */ 522 case SNMP_C_GETREQ: 523 stats->snmp_ingetrequests++; 524 /* FALLTHROUGH */ 525 case SNMP_C_GETNEXTREQ: 526 if (type == SNMP_C_GETNEXTREQ) 527 stats->snmp_ingetnexts++; 528 if (strcmp(env->sc_rdcommunity, comn) != 0 && 529 strcmp(env->sc_rwcommunity, comn) != 0) { 530 stats->snmp_inbadcommunitynames++; 531 errstr = "wrong read community"; 532 goto fail; 533 } 534 msg->sm_context = type; 535 break; 536 case SNMP_C_SETREQ: 537 stats->snmp_insetrequests++; 538 if (strcmp(env->sc_rwcommunity, comn) != 0) { 539 if (strcmp(env->sc_rdcommunity, comn) != 0) 540 stats->snmp_inbadcommunitynames++; 541 else 542 stats->snmp_inbadcommunityuses++; 543 errstr = "wrong write community"; 544 goto fail; 545 } 546 msg->sm_context = type; 547 break; 548 case SNMP_C_GETRESP: 549 stats->snmp_ingetresponses++; 550 errstr = "response without request"; 551 goto parsefail; 552 case SNMP_C_TRAP: 553 case SNMP_C_TRAPV2: 554 if (strcmp(env->sc_trcommunity, comn) != 0) { 555 stats->snmp_inbadcommunitynames++; 556 errstr = "wrong trap community"; 557 goto fail; 558 } 559 stats->snmp_intraps++; 560 errstr = "received trap"; 561 goto fail; 562 default: 563 errstr = "invalid context"; 564 goto parsefail; 565 } 566 567 if (strlcpy(msg->sm_community, comn, sizeof(msg->sm_community)) >= 568 sizeof(msg->sm_community)) { 569 stats->snmp_inbadcommunitynames++; 570 errstr = "community name too long"; 571 goto fail; 572 } 573 574 /* SNMP PDU */ 575 if (ber_scanf_elements(a, "iiie{et", 576 &req, &errval, &erridx, &msg->sm_pduend, 577 &msg->sm_varbind, &class, &type) != 0) { 578 stats->snmp_silentdrops++; 579 errstr = "invalid PDU"; 580 goto fail; 581 } 582 if (class != BER_CLASS_UNIVERSAL || type != BER_TYPE_SEQUENCE) { 583 stats->snmp_silentdrops++; 584 errstr = "invalid varbind"; 585 goto fail; 586 } 587 588 msg->sm_request = req; 589 msg->sm_error = errval; 590 msg->sm_errorindex = erridx; 591 592 print_host(ss, host, sizeof(host)); 593 log_debug("snmpe_parse: %s: SNMPv%d '%s' context %d request %lld", 594 host, msg->sm_version + 1, msg->sm_community, msg->sm_context, 595 msg->sm_request); 596 597 errstr = "invalid varbind element"; 598 for (i = 1, a = msg->sm_varbind, last = NULL; 599 a != NULL && i < SNMPD_MAXVARBIND; a = next, i++) { 600 next = a->be_next; 601 602 if (a->be_class != BER_CLASS_UNIVERSAL || 603 a->be_type != BER_TYPE_SEQUENCE) 604 continue; 605 if ((b = a->be_sub) == NULL) 606 continue; 607 for (state = 0; state < 2 && b != NULL; b = b->be_next) { 608 switch (state++) { 609 case 0: 610 if (ber_get_oid(b, &o) != 0) 611 goto varfail; 612 if (o.bo_n < BER_MIN_OID_LEN || 613 o.bo_n > BER_MAX_OID_LEN) 614 goto varfail; 615 if (msg->sm_context == SNMP_C_SETREQ) 616 stats->snmp_intotalsetvars++; 617 else 618 stats->snmp_intotalreqvars++; 619 log_debug("snmpe_parse: %s: oid %s", host, 620 smi_oidstring(&o, buf, sizeof(buf))); 621 break; 622 case 1: 623 c = d = NULL; 624 switch (msg->sm_context) { 625 case SNMP_C_GETNEXTREQ: 626 c = ber_add_sequence(NULL); 627 if ((d = mps_getnextreq(c, &o)) != NULL) 628 break; 629 ber_free_elements(c); 630 c = NULL; 631 msg->sm_error = SNMP_ERROR_NOSUCHNAME; 632 msg->sm_errorindex = i; 633 break; /* ignore error */ 634 case SNMP_C_GETREQ: 635 c = ber_add_sequence(NULL); 636 if ((d = mps_getreq(c, &o)) != NULL) 637 break; 638 msg->sm_error = SNMP_ERROR_NOSUCHNAME; 639 ber_free_elements(c); 640 goto varfail; 641 case SNMP_C_SETREQ: 642 if (mps_setreq(b, &o) == 0) 643 break; 644 msg->sm_error = SNMP_ERROR_READONLY; 645 goto varfail; 646 case SNMP_C_GETBULKREQ: 647 j = msg->sm_maxrepetitions; 648 msg->sm_errorindex = 0; 649 msg->sm_error = SNMP_ERROR_NOSUCHNAME; 650 for (d = NULL, len = 0; j > 0; j--) { 651 e = ber_add_sequence(NULL); 652 if (c == NULL) 653 c = e; 654 f = mps_getnextreq(e, &o); 655 if (f == NULL) { 656 ber_free_elements(e); 657 if (d == NULL) 658 goto varfail; 659 break; 660 } 661 len += ber_calc_len(e); 662 if (len > SNMPD_MAXVARBINDLEN) { 663 ber_free_elements(e); 664 break; 665 } 666 if (d != NULL) 667 ber_link_elements(d, e); 668 d = e; 669 } 670 msg->sm_error = 0; 671 break; 672 default: 673 goto varfail; 674 } 675 if (c == NULL) 676 break; 677 if (last == NULL) 678 msg->sm_varbindresp = c; 679 else 680 ber_link_elements(last, c); 681 last = c; 682 break; 683 } 684 } 685 if (state < 2) { 686 log_debug("snmpe_parse: state %d", state); 687 goto varfail; 688 } 689 } 690 691 return (0); 692 varfail: 693 log_debug("snmpe_parse: %s: %s, error index %d", host, errstr, i); 694 if (msg->sm_error == 0) 695 msg->sm_error = SNMP_ERROR_GENERR; 696 msg->sm_errorindex = i; 697 return (0); 698 parsefail: 699 stats->snmp_inasnparseerrs++; 700 fail: 701 print_host(ss, host, sizeof(host)); 702 log_debug("snmpe_parse: %s: %s", host, errstr); 703 return (-1); 704 } 705 706 void 707 snmpe_recvmsg(int fd, short sig, void *arg) 708 { 709 struct snmp_stats *stats = &env->sc_stats; 710 struct sockaddr_storage ss; 711 u_int8_t buf[READ_BUF_SIZE], *ptr = NULL; 712 socklen_t slen; 713 ssize_t len; 714 struct ber ber; 715 struct ber_element *req = NULL, *resp = NULL; 716 struct snmp_message msg; 717 718 slen = sizeof(ss); 719 if ((len = recvfrom(fd, buf, sizeof(buf), 0, 720 (struct sockaddr *)&ss, &slen)) < 1) 721 return; 722 723 stats->snmp_inpkts++; 724 725 bzero(&ber, sizeof(ber)); 726 ber.fd = -1; 727 ber_set_application(&ber, snmpe_application); 728 ber_set_readbuf(&ber, buf, len); 729 730 req = ber_read_elements(&ber, NULL); 731 732 if (req == NULL) { 733 stats->snmp_inasnparseerrs++; 734 goto done; 735 } 736 737 #ifdef DEBUG 738 snmpe_debug_elements(req); 739 #endif 740 741 if (snmpe_parse(&ss, req, &msg) == -1) 742 goto done; 743 744 if (msg.sm_varbindresp == NULL) 745 msg.sm_varbindresp = ber_unlink_elements(msg.sm_pduend); 746 747 switch (msg.sm_error) { 748 case SNMP_ERROR_TOOBIG: 749 stats->snmp_intoobigs++; 750 break; 751 case SNMP_ERROR_NOSUCHNAME: 752 stats->snmp_innosuchnames++; 753 break; 754 case SNMP_ERROR_BADVALUE: 755 stats->snmp_inbadvalues++; 756 break; 757 case SNMP_ERROR_READONLY: 758 stats->snmp_inreadonlys++; 759 break; 760 case SNMP_ERROR_GENERR: 761 default: 762 stats->snmp_ingenerrs++; 763 break; 764 } 765 766 /* Create new SNMP packet */ 767 resp = ber_add_sequence(NULL); 768 ber_printf_elements(resp, "ds{tiii{e}}.", 769 msg.sm_version, msg.sm_community, 770 BER_CLASS_CONTEXT, SNMP_C_GETRESP, 771 msg.sm_request, msg.sm_error, msg.sm_errorindex, 772 msg.sm_varbindresp); 773 774 #ifdef DEBUG 775 snmpe_debug_elements(resp); 776 #endif 777 778 len = ber_write_elements(&ber, resp); 779 if (ber_get_writebuf(&ber, (void *)&ptr) == -1) 780 goto done; 781 782 len = sendto(fd, ptr, len, 0, (struct sockaddr *)&ss, slen); 783 if (len != -1) 784 stats->snmp_outpkts++; 785 786 done: 787 ber_free(&ber); 788 if (req != NULL) 789 ber_free_elements(req); 790 if (resp != NULL) 791 ber_free_elements(resp); 792 } 793