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