1 /* $OpenBSD: snmpe.c,v 1.57 2019/04/29 16:04:05 rob Exp $ */ 2 3 /* 4 * Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org> 5 * Copyright (c) 2017 Marco Pfatschbacher <mpf@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/queue.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 #include "mib.h" 42 43 void snmpe_init(struct privsep *, struct privsep_proc *, void *); 44 int snmpe_parse(struct snmp_message *); 45 void snmpe_tryparse(int, struct snmp_message *); 46 int snmpe_parsevarbinds(struct snmp_message *); 47 void snmpe_response(struct snmp_message *); 48 void snmpe_sig_handler(int sig, short, void *); 49 int snmpe_dispatch_parent(int, struct privsep_proc *, struct imsg *); 50 int snmpe_bind(struct address *); 51 void snmpe_recvmsg(int fd, short, void *); 52 void snmpe_readcb(int fd, short, void *); 53 void snmpe_writecb(int fd, short, void *); 54 void snmpe_acceptcb(int fd, short, void *); 55 void snmpe_prepare_read(struct snmp_message *, int); 56 int snmpe_encode(struct snmp_message *); 57 void snmp_msgfree(struct snmp_message *); 58 59 struct imsgev *iev_parent; 60 static const struct timeval snmpe_tcp_timeout = { 10, 0 }; /* 10s */ 61 62 static struct privsep_proc procs[] = { 63 { "parent", PROC_PARENT, snmpe_dispatch_parent } 64 }; 65 66 void 67 snmpe(struct privsep *ps, struct privsep_proc *p) 68 { 69 struct snmpd *env = ps->ps_env; 70 struct address *h; 71 struct listen_sock *so; 72 #ifdef DEBUG 73 char buf[BUFSIZ]; 74 struct oid *oid; 75 #endif 76 77 #ifdef DEBUG 78 for (oid = NULL; (oid = smi_foreach(oid, 0)) != NULL;) { 79 smi_oid2string(&oid->o_id, buf, sizeof(buf), 0); 80 log_debug("oid %s", buf); 81 } 82 #endif 83 84 /* bind SNMP UDP/TCP sockets */ 85 TAILQ_FOREACH(h, &env->sc_addresses, entry) { 86 if ((so = calloc(1, sizeof(*so))) == NULL) 87 fatal("snmpe: %s", __func__); 88 if ((so->s_fd = snmpe_bind(h)) == -1) 89 fatal("snmpe: failed to bind SNMP socket"); 90 so->s_ipproto = h->ipproto; 91 TAILQ_INSERT_TAIL(&env->sc_sockets, so, entry); 92 } 93 94 proc_run(ps, p, procs, nitems(procs), snmpe_init, NULL); 95 } 96 97 /* ARGSUSED */ 98 void 99 snmpe_init(struct privsep *ps, struct privsep_proc *p, void *arg) 100 { 101 struct snmpd *env = ps->ps_env; 102 struct listen_sock *so; 103 104 kr_init(); 105 trap_init(); 106 timer_init(); 107 usm_generate_keys(); 108 109 /* listen for incoming SNMP UDP/TCP messages */ 110 TAILQ_FOREACH(so, &env->sc_sockets, entry) { 111 if (so->s_ipproto == IPPROTO_TCP) { 112 if (listen(so->s_fd, 5) < 0) 113 fatalx("snmpe: failed to listen on socket"); 114 event_set(&so->s_ev, so->s_fd, EV_READ, snmpe_acceptcb, so); 115 evtimer_set(&so->s_evt, snmpe_acceptcb, so); 116 } else { 117 event_set(&so->s_ev, so->s_fd, EV_READ|EV_PERSIST, 118 snmpe_recvmsg, env); 119 } 120 event_add(&so->s_ev, NULL); 121 } 122 123 if (unveil("/", "") == -1) 124 fatal("unveil"); 125 if (unveil(NULL, NULL) == -1) 126 fatal("unveil"); 127 } 128 129 void 130 snmpe_shutdown(void) 131 { 132 struct listen_sock *so; 133 134 TAILQ_FOREACH(so, &snmpd_env->sc_sockets, entry) { 135 event_del(&so->s_ev); 136 if (so->s_ipproto == IPPROTO_TCP) 137 event_del(&so->s_evt); 138 close(so->s_fd); 139 } 140 kr_shutdown(); 141 } 142 143 int 144 snmpe_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) 145 { 146 switch (imsg->hdr.type) { 147 default: 148 break; 149 } 150 151 return (-1); 152 } 153 154 int 155 snmpe_bind(struct address *addr) 156 { 157 char buf[512]; 158 int val, s; 159 160 if ((s = snmpd_socket_af(&addr->ss, htons(addr->port), 161 addr->ipproto)) == -1) 162 return (-1); 163 164 /* 165 * Socket options 166 */ 167 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) 168 goto bad; 169 170 if (addr->ipproto == IPPROTO_TCP) { 171 val = 1; 172 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 173 &val, sizeof(val)) == -1) 174 fatal("setsockopt SO_REUSEADDR"); 175 } else { /* UDP */ 176 switch (addr->ss.ss_family) { 177 case AF_INET: 178 val = 1; 179 if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, 180 &val, sizeof(int)) == -1) { 181 log_warn("%s: failed to set IPv4 packet info", 182 __func__); 183 goto bad; 184 } 185 break; 186 case AF_INET6: 187 val = 1; 188 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, 189 &val, sizeof(int)) == -1) { 190 log_warn("%s: failed to set IPv6 packet info", 191 __func__); 192 goto bad; 193 } 194 } 195 } 196 197 if (bind(s, (struct sockaddr *)&addr->ss, addr->ss.ss_len) == -1) 198 goto bad; 199 200 if (print_host(&addr->ss, buf, sizeof(buf)) == NULL) 201 goto bad; 202 203 log_info("snmpe: listening on %s %s:%d", 204 (addr->ipproto == IPPROTO_TCP) ? "tcp" : "udp", buf, addr->port); 205 206 return (s); 207 208 bad: 209 close(s); 210 return (-1); 211 } 212 213 int 214 snmpe_parse(struct snmp_message *msg) 215 { 216 struct snmpd *env = snmpd_env; 217 struct snmp_stats *stats = &env->sc_stats; 218 struct ber_element *a; 219 long long ver, req; 220 long long errval, erridx; 221 unsigned int type; 222 u_int class; 223 char *comn; 224 char *flagstr, *ctxname; 225 size_t len; 226 struct sockaddr_storage *ss = &msg->sm_ss; 227 struct ber_element *root = msg->sm_req; 228 229 msg->sm_errstr = "invalid message"; 230 231 if (ber_scanf_elements(root, "{ie", &ver, &a) != 0) 232 goto parsefail; 233 234 /* SNMP version and community */ 235 msg->sm_version = ver; 236 switch (msg->sm_version) { 237 case SNMP_V1: 238 case SNMP_V2: 239 if (env->sc_min_seclevel != 0) 240 goto badversion; 241 if (ber_scanf_elements(a, "se", &comn, &msg->sm_pdu) != 0) 242 goto parsefail; 243 if (strlcpy(msg->sm_community, comn, 244 sizeof(msg->sm_community)) >= sizeof(msg->sm_community)) { 245 stats->snmp_inbadcommunitynames++; 246 msg->sm_errstr = "community name too long"; 247 goto fail; 248 } 249 break; 250 case SNMP_V3: 251 if (ber_scanf_elements(a, "{iisi}e", 252 &msg->sm_msgid, &msg->sm_max_msg_size, &flagstr, 253 &msg->sm_secmodel, &a) != 0) 254 goto parsefail; 255 256 msg->sm_flags = *flagstr; 257 if (MSG_SECLEVEL(msg) < env->sc_min_seclevel || 258 msg->sm_secmodel != SNMP_SEC_USM) { 259 /* XXX currently only USM supported */ 260 msg->sm_errstr = "unsupported security model"; 261 stats->snmp_usmbadseclevel++; 262 msg->sm_usmerr = OIDVAL_usmErrSecLevel; 263 goto parsefail; 264 } 265 266 if ((a = usm_decode(msg, a, &msg->sm_errstr)) == NULL) 267 goto parsefail; 268 269 if (ber_scanf_elements(a, "{xxe", 270 &msg->sm_ctxengineid, &msg->sm_ctxengineid_len, 271 &ctxname, &len, &msg->sm_pdu) != 0) 272 goto parsefail; 273 if (len > SNMPD_MAXCONTEXNAMELEN) 274 goto parsefail; 275 memcpy(msg->sm_ctxname, ctxname, len); 276 msg->sm_ctxname[len] = '\0'; 277 break; 278 default: 279 badversion: 280 stats->snmp_inbadversions++; 281 msg->sm_errstr = "bad snmp version"; 282 goto fail; 283 } 284 285 if (ber_scanf_elements(msg->sm_pdu, "t{e", &class, &type, &a) != 0) 286 goto parsefail; 287 288 /* SNMP PDU context */ 289 if (class != BER_CLASS_CONTEXT) 290 goto parsefail; 291 292 switch (type) { 293 case SNMP_C_GETBULKREQ: 294 if (msg->sm_version == SNMP_V1) { 295 stats->snmp_inbadversions++; 296 msg->sm_errstr = 297 "invalid request for protocol version 1"; 298 goto fail; 299 } 300 /* FALLTHROUGH */ 301 302 case SNMP_C_GETREQ: 303 stats->snmp_ingetrequests++; 304 /* FALLTHROUGH */ 305 306 case SNMP_C_GETNEXTREQ: 307 if (type == SNMP_C_GETNEXTREQ) 308 stats->snmp_ingetnexts++; 309 if (msg->sm_version != SNMP_V3 && 310 strcmp(env->sc_rdcommunity, msg->sm_community) != 0 && 311 strcmp(env->sc_rwcommunity, msg->sm_community) != 0) { 312 stats->snmp_inbadcommunitynames++; 313 msg->sm_errstr = "wrong read community"; 314 goto fail; 315 } 316 msg->sm_context = type; 317 break; 318 319 case SNMP_C_SETREQ: 320 stats->snmp_insetrequests++; 321 if (msg->sm_version != SNMP_V3 && 322 strcmp(env->sc_rwcommunity, msg->sm_community) != 0) { 323 if (strcmp(env->sc_rdcommunity, msg->sm_community) != 0) 324 stats->snmp_inbadcommunitynames++; 325 else 326 stats->snmp_inbadcommunityuses++; 327 msg->sm_errstr = "wrong write community"; 328 goto fail; 329 } 330 msg->sm_context = type; 331 break; 332 333 case SNMP_C_GETRESP: 334 stats->snmp_ingetresponses++; 335 msg->sm_errstr = "response without request"; 336 goto parsefail; 337 338 case SNMP_C_TRAP: 339 case SNMP_C_TRAPV2: 340 if (msg->sm_version != SNMP_V3 && 341 strcmp(env->sc_trcommunity, msg->sm_community) != 0) { 342 stats->snmp_inbadcommunitynames++; 343 msg->sm_errstr = "wrong trap community"; 344 goto fail; 345 } 346 stats->snmp_intraps++; 347 msg->sm_errstr = "received trap"; 348 goto fail; 349 350 default: 351 msg->sm_errstr = "invalid context"; 352 goto parsefail; 353 } 354 355 /* SNMP PDU */ 356 if (ber_scanf_elements(a, "iiie{et", 357 &req, &errval, &erridx, &msg->sm_pduend, 358 &msg->sm_varbind, &class, &type) != 0) { 359 stats->snmp_silentdrops++; 360 msg->sm_errstr = "invalid PDU"; 361 goto fail; 362 } 363 if (class != BER_CLASS_UNIVERSAL || type != BER_TYPE_SEQUENCE) { 364 stats->snmp_silentdrops++; 365 msg->sm_errstr = "invalid varbind"; 366 goto fail; 367 } 368 369 msg->sm_request = req; 370 msg->sm_error = errval; 371 msg->sm_errorindex = erridx; 372 373 print_host(ss, msg->sm_host, sizeof(msg->sm_host)); 374 if (msg->sm_version == SNMP_V3) 375 log_debug("%s: %s: SNMPv3 context %d, flags %#x, " 376 "secmodel %lld, user '%s', ctx-engine %s, ctx-name '%s', " 377 "request %lld", __func__, msg->sm_host, msg->sm_context, 378 msg->sm_flags, msg->sm_secmodel, msg->sm_username, 379 tohexstr(msg->sm_ctxengineid, msg->sm_ctxengineid_len), 380 msg->sm_ctxname, msg->sm_request); 381 else 382 log_debug("%s: %s: SNMPv%d '%s' context %d request %lld", 383 __func__, msg->sm_host, msg->sm_version + 1, 384 msg->sm_community, msg->sm_context, msg->sm_request); 385 386 return (0); 387 388 parsefail: 389 stats->snmp_inasnparseerrs++; 390 fail: 391 print_host(ss, msg->sm_host, sizeof(msg->sm_host)); 392 log_debug("%s: %s: %s", __func__, msg->sm_host, msg->sm_errstr); 393 return (-1); 394 } 395 396 int 397 snmpe_parsevarbinds(struct snmp_message *msg) 398 { 399 struct snmp_stats *stats = &snmpd_env->sc_stats; 400 char buf[BUFSIZ]; 401 struct ber_oid o; 402 int ret = 0; 403 404 msg->sm_errstr = "invalid varbind element"; 405 406 if (msg->sm_i == 0) { 407 msg->sm_i = 1; 408 msg->sm_a = msg->sm_varbind; 409 msg->sm_last = NULL; 410 } 411 412 for (; msg->sm_a != NULL && msg->sm_i < SNMPD_MAXVARBIND; 413 msg->sm_a = msg->sm_next, msg->sm_i++) { 414 msg->sm_next = msg->sm_a->be_next; 415 416 if (msg->sm_a->be_class != BER_CLASS_UNIVERSAL || 417 msg->sm_a->be_type != BER_TYPE_SEQUENCE) 418 continue; 419 if ((msg->sm_b = msg->sm_a->be_sub) == NULL) 420 continue; 421 422 for (msg->sm_state = 0; msg->sm_state < 2 && msg->sm_b != NULL; 423 msg->sm_b = msg->sm_b->be_next) { 424 switch (msg->sm_state++) { 425 case 0: 426 if (ber_get_oid(msg->sm_b, &o) != 0) 427 goto varfail; 428 if (o.bo_n < BER_MIN_OID_LEN || 429 o.bo_n > BER_MAX_OID_LEN) 430 goto varfail; 431 if (msg->sm_context == SNMP_C_SETREQ) 432 stats->snmp_intotalsetvars++; 433 else 434 stats->snmp_intotalreqvars++; 435 log_debug("%s: %s: oid %s", 436 __func__, msg->sm_host, 437 smi_oid2string(&o, buf, sizeof(buf), 0)); 438 break; 439 case 1: 440 msg->sm_c = NULL; 441 msg->sm_end = NULL; 442 443 switch (msg->sm_context) { 444 445 case SNMP_C_GETNEXTREQ: 446 msg->sm_c = ber_add_sequence(NULL); 447 ret = mps_getnextreq(msg, msg->sm_c, 448 &o); 449 if (ret == 0 || ret == 1) 450 break; 451 ber_free_elements(msg->sm_c); 452 msg->sm_error = SNMP_ERROR_NOSUCHNAME; 453 goto varfail; 454 455 case SNMP_C_GETREQ: 456 msg->sm_c = ber_add_sequence(NULL); 457 ret = mps_getreq(msg, msg->sm_c, &o, 458 msg->sm_version); 459 if (ret == 0 || ret == 1) 460 break; 461 msg->sm_error = SNMP_ERROR_NOSUCHNAME; 462 ber_free_elements(msg->sm_c); 463 goto varfail; 464 465 case SNMP_C_SETREQ: 466 if (snmpd_env->sc_readonly == 0) { 467 ret = mps_setreq(msg, 468 msg->sm_b, &o); 469 if (ret == 0) 470 break; 471 } 472 msg->sm_error = SNMP_ERROR_READONLY; 473 goto varfail; 474 475 case SNMP_C_GETBULKREQ: 476 ret = mps_getbulkreq(msg, &msg->sm_c, 477 &msg->sm_end, &o, 478 (msg->sm_i <= msg->sm_nonrepeaters) 479 ? 1 : msg->sm_maxrepetitions); 480 if (ret == 0 || ret == 1) 481 break; 482 msg->sm_error = SNMP_ERROR_NOSUCHNAME; 483 goto varfail; 484 485 default: 486 goto varfail; 487 } 488 if (msg->sm_c == NULL) 489 break; 490 if (msg->sm_end == NULL) 491 msg->sm_end = msg->sm_c; 492 if (msg->sm_last == NULL) 493 msg->sm_varbindresp = msg->sm_c; 494 else 495 ber_link_elements(msg->sm_last, msg->sm_c); 496 msg->sm_last = msg->sm_end; 497 break; 498 } 499 } 500 if (msg->sm_state < 2) { 501 log_debug("%s: state %d", __func__, msg->sm_state); 502 goto varfail; 503 } 504 } 505 506 msg->sm_errstr = "none"; 507 msg->sm_error = 0; 508 msg->sm_errorindex = 0; 509 510 return (ret); 511 varfail: 512 log_debug("%s: %s: %s, error index %d", __func__, 513 msg->sm_host, msg->sm_errstr, msg->sm_i); 514 if (msg->sm_error == 0) 515 msg->sm_error = SNMP_ERROR_GENERR; 516 msg->sm_errorindex = msg->sm_i; 517 return (-1); 518 } 519 520 void 521 snmpe_acceptcb(int fd, short type, void *arg) 522 { 523 struct listen_sock *so = arg; 524 struct sockaddr_storage ss; 525 socklen_t len = sizeof(ss); 526 struct snmp_message *msg; 527 int afd; 528 529 event_add(&so->s_ev, NULL); 530 if ((type & EV_TIMEOUT)) 531 return; 532 533 if ((afd = accept4(fd, (struct sockaddr *)&ss, &len, 534 SOCK_NONBLOCK|SOCK_CLOEXEC)) < 0) { 535 /* Pause accept if we are out of file descriptors */ 536 if (errno == ENFILE || errno == EMFILE) { 537 struct timeval evtpause = { 1, 0 }; 538 539 event_del(&so->s_ev); 540 evtimer_add(&so->s_evt, &evtpause); 541 } else if (errno != EAGAIN && errno != EINTR) 542 log_debug("%s: accept4", __func__); 543 return; 544 } 545 if ((msg = calloc(1, sizeof(*msg))) == NULL) 546 goto fail; 547 548 snmpe_prepare_read(msg, afd); 549 return; 550 fail: 551 free(msg); 552 close(afd); 553 return; 554 } 555 556 void 557 snmpe_prepare_read(struct snmp_message *msg, int fd) 558 { 559 msg->sm_sock = fd; 560 msg->sm_sock_tcp = 1; 561 event_del(&msg->sm_sockev); 562 event_set(&msg->sm_sockev, fd, EV_READ, 563 snmpe_readcb, msg); 564 event_add(&msg->sm_sockev, &snmpe_tcp_timeout); 565 } 566 567 void 568 snmpe_tryparse(int fd, struct snmp_message *msg) 569 { 570 struct snmp_stats *stats = &snmpd_env->sc_stats; 571 572 ber_set_application(&msg->sm_ber, smi_application); 573 ber_set_readbuf(&msg->sm_ber, msg->sm_data, msg->sm_datalen); 574 msg->sm_req = ber_read_elements(&msg->sm_ber, NULL); 575 if (msg->sm_req == NULL) { 576 if (errno == ECANCELED) { 577 /* short read; try again */ 578 snmpe_prepare_read(msg, fd); 579 return; 580 } 581 goto fail; 582 } 583 584 if (snmpe_parse(msg) == -1) { 585 if (msg->sm_usmerr && MSG_REPORT(msg)) { 586 usm_make_report(msg); 587 snmpe_response(msg); 588 return; 589 } else 590 goto fail; 591 } 592 stats->snmp_inpkts++; 593 594 snmpe_dispatchmsg(msg); 595 return; 596 fail: 597 snmp_msgfree(msg); 598 close(fd); 599 } 600 601 void 602 snmpe_readcb(int fd, short type, void *arg) 603 { 604 struct snmp_message *msg = arg; 605 ssize_t len; 606 607 if (type == EV_TIMEOUT || msg->sm_datalen >= sizeof(msg->sm_data)) 608 goto fail; 609 610 len = read(fd, msg->sm_data + msg->sm_datalen, 611 sizeof(msg->sm_data) - msg->sm_datalen); 612 if (len <= 0) { 613 if (errno != EAGAIN && errno != EINTR) 614 goto fail; 615 snmpe_prepare_read(msg, fd); 616 return; 617 } 618 619 msg->sm_datalen += (size_t)len; 620 snmpe_tryparse(fd, msg); 621 return; 622 623 fail: 624 snmp_msgfree(msg); 625 close(fd); 626 } 627 628 void 629 snmpe_writecb(int fd, short type, void *arg) 630 { 631 struct snmp_stats *stats = &snmpd_env->sc_stats; 632 struct snmp_message *msg = arg; 633 struct snmp_message *nmsg; 634 ssize_t len; 635 size_t reqlen; 636 struct ber *ber = &msg->sm_ber; 637 638 if (type == EV_TIMEOUT) 639 goto fail; 640 641 len = ber->br_wend - ber->br_wbuf; 642 ber->br_wptr = ber->br_wbuf; 643 644 log_debug("%s: write fd %d len %zd", __func__, fd, len); 645 646 len = write(fd, ber->br_wptr, len); 647 if (len == -1) { 648 if (errno == EAGAIN || errno == EINTR) 649 return; 650 else 651 goto fail; 652 } 653 654 ber->br_wptr += len; 655 656 if (ber->br_wptr < ber->br_wend) { 657 event_del(&msg->sm_sockev); 658 event_set(&msg->sm_sockev, msg->sm_sock, EV_WRITE, 659 snmpe_writecb, msg); 660 event_add(&msg->sm_sockev, &snmpe_tcp_timeout); 661 return; 662 } 663 664 stats->snmp_outpkts++; 665 666 if ((nmsg = calloc(1, sizeof(*nmsg))) == NULL) 667 goto fail; 668 669 /* 670 * Reuse the connection. 671 * In case we already read data of the next message, copy it over. 672 */ 673 reqlen = ber_calc_len(msg->sm_req); 674 if (msg->sm_datalen > reqlen) { 675 memcpy(nmsg->sm_data, msg->sm_data + reqlen, 676 msg->sm_datalen - reqlen); 677 nmsg->sm_datalen = msg->sm_datalen - reqlen; 678 snmp_msgfree(msg); 679 snmpe_prepare_read(nmsg, fd); 680 snmpe_tryparse(fd, nmsg); 681 } else { 682 snmp_msgfree(msg); 683 snmpe_prepare_read(nmsg, fd); 684 } 685 return; 686 687 fail: 688 close(fd); 689 snmp_msgfree(msg); 690 } 691 692 void 693 snmpe_recvmsg(int fd, short sig, void *arg) 694 { 695 struct snmpd *env = arg; 696 struct snmp_stats *stats = &env->sc_stats; 697 ssize_t len; 698 struct snmp_message *msg; 699 700 if ((msg = calloc(1, sizeof(*msg))) == NULL) 701 return; 702 703 msg->sm_sock = fd; 704 msg->sm_slen = sizeof(msg->sm_ss); 705 if ((len = recvfromto(fd, msg->sm_data, sizeof(msg->sm_data), 0, 706 (struct sockaddr *)&msg->sm_ss, &msg->sm_slen, 707 (struct sockaddr *)&msg->sm_local_ss, &msg->sm_local_slen)) < 1) { 708 free(msg); 709 return; 710 } 711 712 stats->snmp_inpkts++; 713 msg->sm_datalen = (size_t)len; 714 715 bzero(&msg->sm_ber, sizeof(msg->sm_ber)); 716 ber_set_application(&msg->sm_ber, smi_application); 717 ber_set_readbuf(&msg->sm_ber, msg->sm_data, msg->sm_datalen); 718 719 msg->sm_req = ber_read_elements(&msg->sm_ber, NULL); 720 if (msg->sm_req == NULL) { 721 stats->snmp_inasnparseerrs++; 722 snmp_msgfree(msg); 723 return; 724 } 725 726 #ifdef DEBUG 727 fprintf(stderr, "recv msg:\n"); 728 smi_debug_elements(msg->sm_req); 729 #endif 730 731 if (snmpe_parse(msg) == -1) { 732 if (msg->sm_usmerr != 0 && MSG_REPORT(msg)) { 733 usm_make_report(msg); 734 snmpe_response(msg); 735 return; 736 } else { 737 snmp_msgfree(msg); 738 return; 739 } 740 } 741 742 snmpe_dispatchmsg(msg); 743 } 744 745 void 746 snmpe_dispatchmsg(struct snmp_message *msg) 747 { 748 /* dispatched to subagent */ 749 if (snmpe_parsevarbinds(msg) == 1) 750 return; 751 752 /* respond directly */ 753 msg->sm_context = SNMP_C_GETRESP; 754 snmpe_response(msg); 755 } 756 757 void 758 snmpe_response(struct snmp_message *msg) 759 { 760 struct snmp_stats *stats = &snmpd_env->sc_stats; 761 u_int8_t *ptr = NULL; 762 ssize_t len; 763 764 if (msg->sm_varbindresp == NULL && msg->sm_pduend != NULL) 765 msg->sm_varbindresp = ber_unlink_elements(msg->sm_pduend); 766 767 switch (msg->sm_error) { 768 case SNMP_ERROR_TOOBIG: 769 stats->snmp_intoobigs++; 770 break; 771 case SNMP_ERROR_NOSUCHNAME: 772 stats->snmp_innosuchnames++; 773 break; 774 case SNMP_ERROR_BADVALUE: 775 stats->snmp_inbadvalues++; 776 break; 777 case SNMP_ERROR_READONLY: 778 stats->snmp_inreadonlys++; 779 break; 780 case SNMP_ERROR_GENERR: 781 default: 782 stats->snmp_ingenerrs++; 783 break; 784 } 785 786 /* Create new SNMP packet */ 787 if (snmpe_encode(msg) < 0) 788 goto done; 789 790 len = ber_write_elements(&msg->sm_ber, msg->sm_resp); 791 if (ber_get_writebuf(&msg->sm_ber, (void *)&ptr) == -1) 792 goto done; 793 794 usm_finalize_digest(msg, ptr, len); 795 if (msg->sm_sock_tcp) { 796 event_del(&msg->sm_sockev); 797 event_set(&msg->sm_sockev, msg->sm_sock, EV_WRITE, 798 snmpe_writecb, msg); 799 event_add(&msg->sm_sockev, &snmpe_tcp_timeout); 800 return; 801 } else { 802 len = sendtofrom(msg->sm_sock, ptr, len, 0, 803 (struct sockaddr *)&msg->sm_ss, msg->sm_slen, 804 (struct sockaddr *)&msg->sm_local_ss, msg->sm_local_slen); 805 if (len != -1) 806 stats->snmp_outpkts++; 807 } 808 809 done: 810 snmp_msgfree(msg); 811 } 812 813 void 814 snmp_msgfree(struct snmp_message *msg) 815 { 816 event_del(&msg->sm_sockev); 817 ber_free(&msg->sm_ber); 818 if (msg->sm_req != NULL) 819 ber_free_elements(msg->sm_req); 820 if (msg->sm_resp != NULL) 821 ber_free_elements(msg->sm_resp); 822 free(msg); 823 } 824 825 int 826 snmpe_encode(struct snmp_message *msg) 827 { 828 struct ber_element *ehdr; 829 struct ber_element *pdu, *epdu; 830 831 msg->sm_resp = ber_add_sequence(NULL); 832 if ((ehdr = ber_add_integer(msg->sm_resp, msg->sm_version)) == NULL) 833 return -1; 834 if (msg->sm_version == SNMP_V3) { 835 char f = MSG_SECLEVEL(msg); 836 837 if ((ehdr = ber_printf_elements(ehdr, "{iixi}", msg->sm_msgid, 838 msg->sm_max_msg_size, &f, sizeof(f), 839 msg->sm_secmodel)) == NULL) 840 return -1; 841 842 /* XXX currently only USM supported */ 843 if ((ehdr = usm_encode(msg, ehdr)) == NULL) 844 return -1; 845 } else { 846 if ((ehdr = ber_add_string(ehdr, msg->sm_community)) == NULL) 847 return -1; 848 } 849 850 pdu = epdu = ber_add_sequence(NULL); 851 if (msg->sm_version == SNMP_V3) { 852 if ((epdu = ber_printf_elements(epdu, "xs{", 853 snmpd_env->sc_engineid, snmpd_env->sc_engineid_len, 854 msg->sm_ctxname)) == NULL) { 855 ber_free_elements(pdu); 856 return -1; 857 } 858 } 859 860 if (!ber_printf_elements(epdu, "tiii{e}", BER_CLASS_CONTEXT, 861 msg->sm_context, msg->sm_request, 862 msg->sm_error, msg->sm_errorindex, 863 msg->sm_varbindresp)) { 864 ber_free_elements(pdu); 865 return -1; 866 } 867 868 if (MSG_HAS_PRIV(msg)) 869 pdu = usm_encrypt(msg, pdu); 870 ber_link_elements(ehdr, pdu); 871 872 #ifdef DEBUG 873 fprintf(stderr, "resp msg:\n"); 874 smi_debug_elements(msg->sm_resp); 875 #endif 876 return 0; 877 } 878