1 /* $OpenBSD: snmpe.c,v 1.24 2009/06/06 05:52:01 pyr 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 imsgev *iev_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 ((iev_parent = calloc(1, sizeof(struct imsgev))) == NULL) 141 fatal("snmpe"); 142 143 imsg_init(&iev_parent->ibuf, pipe_parent2snmpe[1]); 144 iev_parent->handler = snmpe_dispatch_parent; 145 146 iev_parent->events = EV_READ; 147 event_set(&iev_parent->ev, iev_parent->ibuf.fd, iev_parent->events, 148 iev_parent->handler, iev_parent); 149 event_add(&iev_parent->ev, NULL); 150 151 TAILQ_INIT(&ctl_conns); 152 153 if (control_listen(&env->sc_csock) == -1) 154 fatalx("snmpe: control socket listen failed"); 155 if (control_listen(&env->sc_rcsock) == -1) 156 fatalx("snmpe: restricted control socket listen failed"); 157 158 event_set(&env->sc_ev, env->sc_sock, EV_READ|EV_PERSIST, 159 snmpe_recvmsg, env); 160 event_add(&env->sc_ev, NULL); 161 162 kr_init(); 163 trap_init(); 164 timer_init(); 165 166 event_dispatch(); 167 168 snmpe_shutdown(); 169 kr_shutdown(); 170 171 return (0); 172 } 173 174 void 175 snmpe_shutdown(void) 176 { 177 log_info("snmp engine exiting"); 178 _exit(0); 179 } 180 181 void 182 snmpe_dispatch_parent(int fd, short event, void * ptr) 183 { 184 struct imsgev *iev; 185 struct imsgbuf *ibuf; 186 struct imsg imsg; 187 ssize_t n; 188 189 iev = ptr; 190 ibuf = &iev->ibuf; 191 switch (event) { 192 case EV_READ: 193 if ((n = imsg_read(ibuf)) == -1) 194 fatal("imsg_read error"); 195 if (n == 0) { 196 /* this pipe is dead, so remove the event handler */ 197 event_del(&iev->ev); 198 event_loopexit(NULL); 199 return; 200 } 201 break; 202 case EV_WRITE: 203 if (msgbuf_write(&ibuf->w) == -1) 204 fatal("msgbuf_write"); 205 imsg_event_add(iev); 206 return; 207 default: 208 fatalx("snmpe_dispatch_parent: unknown event"); 209 } 210 211 for (;;) { 212 if ((n = imsg_get(ibuf, &imsg)) == -1) 213 fatal("snmpe_dispatch_parent: imsg_read error"); 214 if (n == 0) 215 break; 216 217 switch (imsg.hdr.type) { 218 default: 219 log_debug("snmpe_dispatch_parent: unexpected imsg %d", 220 imsg.hdr.type); 221 break; 222 } 223 imsg_free(&imsg); 224 } 225 imsg_event_add(iev); 226 } 227 228 int 229 snmpe_bind(struct address *addr) 230 { 231 char buf[512]; 232 int s; 233 234 if ((s = snmpd_socket_af(&addr->ss, htons(addr->port))) == -1) 235 return (-1); 236 237 /* 238 * Socket options 239 */ 240 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) 241 goto bad; 242 243 if (bind(s, (struct sockaddr *)&addr->ss, addr->ss.ss_len) == -1) 244 goto bad; 245 246 if (print_host(&addr->ss, buf, sizeof(buf)) == NULL) 247 goto bad; 248 249 log_info("snmpe_bind: binding to address %s:%d", buf, addr->port); 250 251 return (s); 252 253 bad: 254 close(s); 255 return (-1); 256 } 257 258 #ifdef DEBUG 259 void 260 snmpe_debug_elements(struct ber_element *root) 261 { 262 static int indent = 0; 263 long long v; 264 int d; 265 char *buf; 266 size_t len; 267 u_int i; 268 int constructed; 269 struct ber_oid o; 270 char str[BUFSIZ]; 271 272 /* calculate lengths */ 273 ber_calc_len(root); 274 275 switch (root->be_encoding) { 276 case BER_TYPE_SEQUENCE: 277 case BER_TYPE_SET: 278 constructed = root->be_encoding; 279 break; 280 default: 281 constructed = 0; 282 break; 283 } 284 285 fprintf(stderr, "%*slen %lu ", indent, "", root->be_len); 286 switch (root->be_class) { 287 case BER_CLASS_UNIVERSAL: 288 fprintf(stderr, "class: universal(%u) type: ", root->be_class); 289 switch (root->be_type) { 290 case BER_TYPE_EOC: 291 fprintf(stderr, "end-of-content"); 292 break; 293 case BER_TYPE_BOOLEAN: 294 fprintf(stderr, "boolean"); 295 break; 296 case BER_TYPE_INTEGER: 297 fprintf(stderr, "integer"); 298 break; 299 case BER_TYPE_BITSTRING: 300 fprintf(stderr, "bit-string"); 301 break; 302 case BER_TYPE_OCTETSTRING: 303 fprintf(stderr, "octet-string"); 304 break; 305 case BER_TYPE_NULL: 306 fprintf(stderr, "null"); 307 break; 308 case BER_TYPE_OBJECT: 309 fprintf(stderr, "object"); 310 break; 311 case BER_TYPE_ENUMERATED: 312 fprintf(stderr, "enumerated"); 313 break; 314 case BER_TYPE_SEQUENCE: 315 fprintf(stderr, "sequence"); 316 break; 317 case BER_TYPE_SET: 318 fprintf(stderr, "set"); 319 break; 320 } 321 break; 322 case BER_CLASS_APPLICATION: 323 fprintf(stderr, "class: application(%u) type: ", 324 root->be_class); 325 switch (root->be_type) { 326 case SNMP_T_IPADDR: 327 fprintf(stderr, "ipaddr"); 328 break; 329 case SNMP_T_COUNTER32: 330 fprintf(stderr, "counter32"); 331 break; 332 case SNMP_T_GAUGE32: 333 fprintf(stderr, "gauge32"); 334 break; 335 case SNMP_T_TIMETICKS: 336 fprintf(stderr, "timeticks"); 337 break; 338 case SNMP_T_OPAQUE: 339 fprintf(stderr, "opaque"); 340 break; 341 case SNMP_T_COUNTER64: 342 fprintf(stderr, "counter64"); 343 break; 344 } 345 break; 346 case BER_CLASS_CONTEXT: 347 fprintf(stderr, "class: context(%u) type: ", 348 root->be_class); 349 switch (root->be_type) { 350 case SNMP_C_GETREQ: 351 fprintf(stderr, "getreq"); 352 break; 353 case SNMP_C_GETNEXTREQ: 354 fprintf(stderr, "nextreq"); 355 break; 356 case SNMP_C_GETRESP: 357 fprintf(stderr, "getresp"); 358 break; 359 case SNMP_C_SETREQ: 360 fprintf(stderr, "setreq"); 361 break; 362 case SNMP_C_TRAP: 363 fprintf(stderr, "trap"); 364 break; 365 case SNMP_C_GETBULKREQ: 366 fprintf(stderr, "getbulkreq"); 367 break; 368 case SNMP_C_INFORMREQ: 369 fprintf(stderr, "informreq"); 370 break; 371 case SNMP_C_TRAPV2: 372 fprintf(stderr, "trapv2"); 373 break; 374 case SNMP_C_REPORT: 375 fprintf(stderr, "report"); 376 break; 377 } 378 break; 379 case BER_CLASS_PRIVATE: 380 fprintf(stderr, "class: private(%u) type: ", root->be_class); 381 break; 382 default: 383 fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class); 384 break; 385 } 386 fprintf(stderr, "(%lu) encoding %lu ", 387 root->be_type, root->be_encoding); 388 389 if (constructed) 390 root->be_encoding = constructed; 391 392 switch (root->be_encoding) { 393 case BER_TYPE_BOOLEAN: 394 if (ber_get_boolean(root, &d) == -1) { 395 fprintf(stderr, "<INVALID>\n"); 396 break; 397 } 398 fprintf(stderr, "%s(%d)\n", d ? "true" : "false", d); 399 break; 400 case BER_TYPE_INTEGER: 401 case BER_TYPE_ENUMERATED: 402 if (ber_get_integer(root, &v) == -1) { 403 fprintf(stderr, "<INVALID>\n"); 404 break; 405 } 406 fprintf(stderr, "value %lld\n", v); 407 break; 408 case BER_TYPE_BITSTRING: 409 if (ber_get_bitstring(root, (void *)&buf, &len) == -1) { 410 fprintf(stderr, "<INVALID>\n"); 411 break; 412 } 413 fprintf(stderr, "hexdump "); 414 for (i = 0; i < len; i++) 415 fprintf(stderr, "%02x", buf[i]); 416 fprintf(stderr, "\n"); 417 break; 418 case BER_TYPE_OBJECT: 419 if (ber_get_oid(root, &o) == -1) { 420 fprintf(stderr, "<INVALID>\n"); 421 break; 422 } 423 fprintf(stderr, "oid %s", 424 smi_oidstring(&o, str, sizeof(str))); 425 fprintf(stderr, "\n"); 426 break; 427 case BER_TYPE_OCTETSTRING: 428 if (ber_get_string(root, &buf) == -1) { 429 fprintf(stderr, "<INVALID>\n"); 430 break; 431 } 432 if (root->be_class == BER_CLASS_APPLICATION && 433 root->be_type == SNMP_T_IPADDR) { 434 fprintf(stderr, "addr %s\n", 435 inet_ntoa(*(struct in_addr *)buf)); 436 } else 437 fprintf(stderr, "string \"%s\"\n", 438 root->be_len ? buf : ""); 439 break; 440 case BER_TYPE_NULL: /* no payload */ 441 case BER_TYPE_EOC: 442 case BER_TYPE_SEQUENCE: 443 case BER_TYPE_SET: 444 default: 445 fprintf(stderr, "\n"); 446 break; 447 } 448 449 if (constructed && root->be_sub) { 450 indent += 2; 451 snmpe_debug_elements(root->be_sub); 452 indent -= 2; 453 } 454 if (root->be_next) 455 snmpe_debug_elements(root->be_next); 456 } 457 #endif 458 459 unsigned long 460 snmpe_application(struct ber_element *elm) 461 { 462 if (elm->be_class != BER_CLASS_APPLICATION) 463 return (BER_TYPE_OCTETSTRING); 464 465 switch (elm->be_type) { 466 case SNMP_T_IPADDR: 467 return (BER_TYPE_OCTETSTRING); 468 case SNMP_T_COUNTER32: 469 case SNMP_T_GAUGE32: 470 case SNMP_T_TIMETICKS: 471 case SNMP_T_OPAQUE: 472 case SNMP_T_COUNTER64: 473 return (BER_TYPE_INTEGER); 474 default: 475 break; 476 } 477 return (BER_TYPE_OCTETSTRING); 478 } 479 480 int 481 snmpe_parse(struct sockaddr_storage *ss, 482 struct ber_element *root, struct snmp_message *msg) 483 { 484 struct snmp_stats *stats = &env->sc_stats; 485 struct ber_element *a, *b, *c, *d, *e, *f, *next, *last; 486 const char *errstr = "invalid message"; 487 long long ver, req; 488 unsigned long type, errval, erridx; 489 u_int class, state, i = 0, j = 0; 490 char *comn, buf[BUFSIZ], host[MAXHOSTNAMELEN]; 491 struct ber_oid o; 492 size_t len; 493 494 bzero(msg, sizeof(*msg)); 495 496 if (ber_scanf_elements(root, "e{ieset{e", 497 &msg->sm_header, &ver, &msg->sm_headerend, &comn, 498 &msg->sm_pdu, &class, &type, &a) != 0) 499 goto parsefail; 500 501 /* SNMP version and community */ 502 switch (ver) { 503 case SNMP_V1: 504 case SNMP_V2: 505 msg->sm_version = ver; 506 break; 507 case SNMP_V3: 508 default: 509 stats->snmp_inbadversions++; 510 errstr = "bad snmp version"; 511 goto fail; 512 } 513 514 /* SNMP PDU context */ 515 if (class != BER_CLASS_CONTEXT) 516 goto parsefail; 517 switch (type) { 518 case SNMP_C_GETBULKREQ: 519 if (msg->sm_version == SNMP_V1) { 520 stats->snmp_inbadversions++; 521 errstr = "invalid request for protocol version 1"; 522 goto fail; 523 } 524 /* FALLTHROUGH */ 525 case SNMP_C_GETREQ: 526 stats->snmp_ingetrequests++; 527 /* FALLTHROUGH */ 528 case SNMP_C_GETNEXTREQ: 529 if (type == SNMP_C_GETNEXTREQ) 530 stats->snmp_ingetnexts++; 531 if (strcmp(env->sc_rdcommunity, comn) != 0 && 532 strcmp(env->sc_rwcommunity, comn) != 0) { 533 stats->snmp_inbadcommunitynames++; 534 errstr = "wrong read community"; 535 goto fail; 536 } 537 msg->sm_context = type; 538 break; 539 case SNMP_C_SETREQ: 540 stats->snmp_insetrequests++; 541 if (strcmp(env->sc_rwcommunity, comn) != 0) { 542 if (strcmp(env->sc_rdcommunity, comn) != 0) 543 stats->snmp_inbadcommunitynames++; 544 else 545 stats->snmp_inbadcommunityuses++; 546 errstr = "wrong write community"; 547 goto fail; 548 } 549 msg->sm_context = type; 550 break; 551 case SNMP_C_GETRESP: 552 stats->snmp_ingetresponses++; 553 errstr = "response without request"; 554 goto parsefail; 555 case SNMP_C_TRAP: 556 case SNMP_C_TRAPV2: 557 if (strcmp(env->sc_trcommunity, comn) != 0) { 558 stats->snmp_inbadcommunitynames++; 559 errstr = "wrong trap community"; 560 goto fail; 561 } 562 stats->snmp_intraps++; 563 errstr = "received trap"; 564 goto fail; 565 default: 566 errstr = "invalid context"; 567 goto parsefail; 568 } 569 570 if (strlcpy(msg->sm_community, comn, sizeof(msg->sm_community)) >= 571 sizeof(msg->sm_community)) { 572 stats->snmp_inbadcommunitynames++; 573 errstr = "community name too long"; 574 goto fail; 575 } 576 577 /* SNMP PDU */ 578 if (ber_scanf_elements(a, "iiie{et", 579 &req, &errval, &erridx, &msg->sm_pduend, 580 &msg->sm_varbind, &class, &type) != 0) { 581 stats->snmp_silentdrops++; 582 errstr = "invalid PDU"; 583 goto fail; 584 } 585 if (class != BER_CLASS_UNIVERSAL || type != BER_TYPE_SEQUENCE) { 586 stats->snmp_silentdrops++; 587 errstr = "invalid varbind"; 588 goto fail; 589 } 590 591 msg->sm_request = req; 592 msg->sm_error = errval; 593 msg->sm_errorindex = erridx; 594 595 print_host(ss, host, sizeof(host)); 596 log_debug("snmpe_parse: %s: SNMPv%d '%s' context %d request %lld", 597 host, msg->sm_version + 1, msg->sm_community, msg->sm_context, 598 msg->sm_request); 599 600 errstr = "invalid varbind element"; 601 for (i = 1, a = msg->sm_varbind, last = NULL; 602 a != NULL && i < SNMPD_MAXVARBIND; a = next, i++) { 603 next = a->be_next; 604 605 if (a->be_class != BER_CLASS_UNIVERSAL || 606 a->be_type != BER_TYPE_SEQUENCE) 607 continue; 608 if ((b = a->be_sub) == NULL) 609 continue; 610 for (state = 0; state < 2 && b != NULL; b = b->be_next) { 611 switch (state++) { 612 case 0: 613 if (ber_get_oid(b, &o) != 0) 614 goto varfail; 615 if (o.bo_n < BER_MIN_OID_LEN || 616 o.bo_n > BER_MAX_OID_LEN) 617 goto varfail; 618 if (msg->sm_context == SNMP_C_SETREQ) 619 stats->snmp_intotalsetvars++; 620 else 621 stats->snmp_intotalreqvars++; 622 log_debug("snmpe_parse: %s: oid %s", host, 623 smi_oidstring(&o, buf, sizeof(buf))); 624 break; 625 case 1: 626 c = d = NULL; 627 switch (msg->sm_context) { 628 case SNMP_C_GETNEXTREQ: 629 c = ber_add_sequence(NULL); 630 if ((d = mps_getnextreq(c, &o)) != NULL) 631 break; 632 ber_free_elements(c); 633 c = NULL; 634 msg->sm_error = SNMP_ERROR_NOSUCHNAME; 635 msg->sm_errorindex = i; 636 break; /* ignore error */ 637 case SNMP_C_GETREQ: 638 c = ber_add_sequence(NULL); 639 if ((d = mps_getreq(c, &o)) != NULL) 640 break; 641 msg->sm_error = SNMP_ERROR_NOSUCHNAME; 642 ber_free_elements(c); 643 goto varfail; 644 case SNMP_C_SETREQ: 645 if (mps_setreq(b, &o) == 0) 646 break; 647 msg->sm_error = SNMP_ERROR_READONLY; 648 goto varfail; 649 case SNMP_C_GETBULKREQ: 650 j = msg->sm_maxrepetitions; 651 msg->sm_errorindex = 0; 652 msg->sm_error = SNMP_ERROR_NOSUCHNAME; 653 for (d = NULL, len = 0; j > 0; j--) { 654 e = ber_add_sequence(NULL); 655 if (c == NULL) 656 c = e; 657 f = mps_getnextreq(e, &o); 658 if (f == NULL) { 659 ber_free_elements(e); 660 if (d == NULL) 661 goto varfail; 662 break; 663 } 664 len += ber_calc_len(e); 665 if (len > SNMPD_MAXVARBINDLEN) { 666 ber_free_elements(e); 667 break; 668 } 669 if (d != NULL) 670 ber_link_elements(d, e); 671 d = e; 672 } 673 msg->sm_error = 0; 674 break; 675 default: 676 goto varfail; 677 } 678 if (c == NULL) 679 break; 680 if (last == NULL) 681 msg->sm_varbindresp = c; 682 else 683 ber_link_elements(last, c); 684 last = c; 685 break; 686 } 687 } 688 if (state < 2) { 689 log_debug("snmpe_parse: state %d", state); 690 goto varfail; 691 } 692 } 693 694 return (0); 695 varfail: 696 log_debug("snmpe_parse: %s: %s, error index %d", host, errstr, i); 697 if (msg->sm_error == 0) 698 msg->sm_error = SNMP_ERROR_GENERR; 699 msg->sm_errorindex = i; 700 return (0); 701 parsefail: 702 stats->snmp_inasnparseerrs++; 703 fail: 704 print_host(ss, host, sizeof(host)); 705 log_debug("snmpe_parse: %s: %s", host, errstr); 706 return (-1); 707 } 708 709 void 710 snmpe_recvmsg(int fd, short sig, void *arg) 711 { 712 struct snmp_stats *stats = &env->sc_stats; 713 struct sockaddr_storage ss; 714 u_int8_t buf[READ_BUF_SIZE], *ptr = NULL; 715 socklen_t slen; 716 ssize_t len; 717 struct ber ber; 718 struct ber_element *req = NULL, *resp = NULL; 719 struct snmp_message msg; 720 721 slen = sizeof(ss); 722 if ((len = recvfrom(fd, buf, sizeof(buf), 0, 723 (struct sockaddr *)&ss, &slen)) < 1) 724 return; 725 726 stats->snmp_inpkts++; 727 728 bzero(&ber, sizeof(ber)); 729 ber.fd = -1; 730 ber_set_application(&ber, snmpe_application); 731 ber_set_readbuf(&ber, buf, len); 732 733 req = ber_read_elements(&ber, NULL); 734 735 if (req == NULL) { 736 stats->snmp_inasnparseerrs++; 737 goto done; 738 } 739 740 #ifdef DEBUG 741 snmpe_debug_elements(req); 742 #endif 743 744 if (snmpe_parse(&ss, req, &msg) == -1) 745 goto done; 746 747 if (msg.sm_varbindresp == NULL) 748 msg.sm_varbindresp = ber_unlink_elements(msg.sm_pduend); 749 750 switch (msg.sm_error) { 751 case SNMP_ERROR_TOOBIG: 752 stats->snmp_intoobigs++; 753 break; 754 case SNMP_ERROR_NOSUCHNAME: 755 stats->snmp_innosuchnames++; 756 break; 757 case SNMP_ERROR_BADVALUE: 758 stats->snmp_inbadvalues++; 759 break; 760 case SNMP_ERROR_READONLY: 761 stats->snmp_inreadonlys++; 762 break; 763 case SNMP_ERROR_GENERR: 764 default: 765 stats->snmp_ingenerrs++; 766 break; 767 } 768 769 /* Create new SNMP packet */ 770 resp = ber_add_sequence(NULL); 771 ber_printf_elements(resp, "ds{tiii{e}}.", 772 msg.sm_version, msg.sm_community, 773 BER_CLASS_CONTEXT, SNMP_C_GETRESP, 774 msg.sm_request, msg.sm_error, msg.sm_errorindex, 775 msg.sm_varbindresp); 776 777 #ifdef DEBUG 778 snmpe_debug_elements(resp); 779 #endif 780 781 len = ber_write_elements(&ber, resp); 782 if (ber_get_writebuf(&ber, (void *)&ptr) == -1) 783 goto done; 784 785 len = sendto(fd, ptr, len, 0, (struct sockaddr *)&ss, slen); 786 if (len != -1) 787 stats->snmp_outpkts++; 788 789 done: 790 ber_free(&ber); 791 if (req != NULL) 792 ber_free_elements(req); 793 if (resp != NULL) 794 ber_free_elements(resp); 795 } 796