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