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