1/* $OpenBSD: trap.c,v 1.43 2024/02/06 15:36:11 martijn Exp $ */ 2 3/* 4 * Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org> 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/socket.h> 21 22#include <ber.h> 23#include <stdint.h> 24#include <stdlib.h> 25#include <string.h> 26 27#include "log.h" 28#include "mib.h" 29#include "smi.h" 30#include "snmp.h" 31#include "snmpd.h" 32 33void 34trap_init(void) 35{ 36 /* 37 * Send a coldStart to notify that the daemon has been 38 * started and re-initialized. 39 */ 40 trap_send(&OID(MIB_coldStart), NULL); 41} 42 43int 44trap_send(struct ber_oid *oid, struct ber_element *elm) 45{ 46 struct trap_address *tr; 47 struct ber_element *vblist, *trap; 48 struct ber_oid uptime = OID(MIB_sysUpTime, 0); 49 struct ber_oid trapoid = OID(MIB_snmpTrapOID, 0); 50 char ostr[SNMP_MAX_OID_STRLEN]; 51 struct snmp_message *msg; 52 int r; 53 54 if (TAILQ_EMPTY(&snmpd_env->sc_trapreceivers)) 55 return (0); 56 57 mib_oid2string(oid, ostr, sizeof(ostr), snmpd_env->sc_oidfmt); 58 log_debug("trap_send: oid %s", ostr); 59 60 /* Add mandatory varbind elements */ 61 trap = ober_add_sequence(NULL); 62 vblist = ober_printf_elements(trap, "{Odt}{OO}", 63 &uptime, smi_getticks(), 64 BER_CLASS_APPLICATION, SNMP_T_TIMETICKS, 65 &trapoid, oid); 66 if (elm != NULL) 67 ober_link_elements(vblist, elm); 68 69 TAILQ_FOREACH(tr, &snmpd_env->sc_trapreceivers, entry) { 70 if (tr->ta_oid.bo_n) { 71 /* The trap receiver may want only a specified MIB */ 72 r = ober_oid_cmp(oid, &tr->ta_oid); 73 if (r != 0 && r != 2) 74 continue; 75 } 76 77 if ((msg = calloc(1, sizeof(*msg))) == NULL) 78 fatal("malloc"); 79 msg->sm_sock = snmpd_socket_af(&tr->ta_ss, SOCK_DGRAM); 80 if (msg->sm_sock == -1) { 81 log_warn("socket"); 82 free(msg); 83 continue; 84 } 85 memcpy(&(msg->sm_ss), &(tr->ta_ss), sizeof(msg->sm_ss)); 86 msg->sm_slen = tr->ta_ss.ss_len; 87 if (tr->ta_sslocal.ss_family != 0) { 88 memcpy(&(msg->sm_local_ss), &(tr->ta_sslocal), 89 sizeof(msg->sm_local_ss)); 90 msg->sm_local_slen = tr->ta_sslocal.ss_len; 91 } 92 msg->sm_version = tr->ta_version; 93 msg->sm_pdutype = SNMP_C_TRAPV2; 94 ober_set_application(&msg->sm_ber, smi_application); 95 msg->sm_request = arc4random(); 96 if ((msg->sm_varbindresp = ober_dup(trap->be_sub)) == NULL) 97 fatal("malloc"); 98 99 switch (msg->sm_version) { 100 case SNMP_V2: 101 (void)strlcpy(msg->sm_community, tr->ta_community, 102 sizeof(msg->sm_community)); 103 break; 104 case SNMP_V3: 105 msg->sm_msgid = msg->sm_request & INT32_MAX; 106 msg->sm_max_msg_size = READ_BUF_SIZE; 107 msg->sm_flags = tr->ta_seclevel != -1 ? 108 tr->ta_seclevel : snmpd_env->sc_min_seclevel; 109 msg->sm_secmodel = SNMP_SEC_USM; 110 msg->sm_engine_time = snmpd_engine_time(); 111 msg->sm_engine_boots = snmpd_env->sc_engine_boots; 112 memcpy(msg->sm_ctxengineid, snmpd_env->sc_engineid, 113 snmpd_env->sc_engineid_len); 114 msg->sm_ctxengineid_len = 115 snmpd_env->sc_engineid_len; 116 (void)strlcpy(msg->sm_username, tr->ta_usmusername, 117 sizeof(msg->sm_username)); 118 msg->sm_user = tr->ta_usmuser; 119 arc4random_buf(msg->sm_salt, sizeof(msg->sm_salt)); 120 break; 121 } 122 123 snmpe_response(msg); 124 } 125 ober_free_elements(trap); 126 127 return 0; 128} 129