1 /* $OpenBSD: trap.c,v 1.14 2009/06/06 05:52:01 pyr Exp $ */ 2 3 /* 4 * Copyright (c) 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 40 #include "snmpd.h" 41 #include "mib.h" 42 43 extern struct snmpd *env; 44 45 void 46 trap_init(void) 47 { 48 struct ber_oid trapoid = OID(MIB_coldStart); 49 50 /* 51 * Send a coldStart to notify that the daemon has been 52 * started and re-initialized. 53 */ 54 trap_send(&trapoid, NULL); 55 } 56 57 int 58 trap_imsg(struct imsgev *iev, pid_t pid) 59 { 60 struct imsgbuf *ibuf; 61 struct imsg imsg; 62 int ret = -1, n, x = 0, state = 0; 63 int done = 0; 64 struct snmp_imsg *sm; 65 u_int32_t d; 66 u_int64_t l; 67 u_int8_t *c; 68 char ostr[SNMP_MAX_OID_LEN]; 69 struct ber_element *ber = NULL, *varbind = NULL, *a; 70 size_t len = 0; 71 struct ber_oid o; 72 73 ibuf = &iev->ibuf; 74 while (!done) { 75 while (!done) { 76 if ((n = imsg_get(ibuf, &imsg)) == -1) 77 goto done; 78 if (n == 0) 79 break; 80 81 switch (imsg.hdr.type) { 82 case IMSG_SNMP_ELEMENT: 83 if (imsg.hdr.len < (IMSG_HEADER_SIZE + 84 sizeof(struct snmp_imsg))) 85 goto imsgdone; 86 87 sm = (struct snmp_imsg *)imsg.data; 88 89 if (!state++) { 90 /* First element must be the trap OID */ 91 if (sm->snmp_type != SNMP_NULL) 92 goto imsgdone; 93 ber_string2oid(sm->snmp_oid, &o); 94 break; 95 } 96 97 ber = ber_add_sequence(ber); 98 if (varbind == NULL) 99 varbind = ber; 100 a = ber_add_oidstring(ber, sm->snmp_oid); 101 102 switch (sm->snmp_type) { 103 case SNMP_OBJECT: 104 if (sm->snmp_len != sizeof(ostr)) 105 goto imsgdone; 106 bcopy(sm + 1, &ostr, sm->snmp_len); 107 a = ber_add_oidstring(a, ostr); 108 break; 109 case SNMP_BITSTRING: 110 case SNMP_OCTETSTRING: 111 case SNMP_IPADDR: 112 if ((sm->snmp_len < 1) || 113 (sm->snmp_len >= SNMPD_MAXSTRLEN)) 114 goto imsgdone; 115 c = (u_int8_t *)(sm + 1); 116 if (sm->snmp_type == SNMP_BITSTRING) 117 a = ber_add_bitstring(a, c, 118 sm->snmp_len); 119 else 120 a = ber_add_nstring(a, c, 121 sm->snmp_len); 122 break; 123 case SNMP_NULL: 124 a = ber_add_null(a); 125 break; 126 case SNMP_INTEGER32: 127 case SNMP_COUNTER32: 128 case SNMP_GAUGE32: 129 case SNMP_TIMETICKS: 130 case SNMP_OPAQUE: 131 case SNMP_UINTEGER32: 132 if (sm->snmp_len != sizeof(d)) 133 goto imsgdone; 134 bcopy(sm + 1, &d, sm->snmp_len); 135 a = ber_add_integer(a, d); 136 break; 137 case SNMP_COUNTER64: 138 if (sm->snmp_len != sizeof(l)) 139 goto imsgdone; 140 bcopy(sm + 1, &l, sm->snmp_len); 141 a = ber_add_integer(a, l); 142 break; 143 default: 144 log_debug("trap_imsg: illegal type %d", 145 sm->snmp_type); 146 imsg_free(&imsg); 147 goto imsgdone; 148 } 149 switch (sm->snmp_type) { 150 case SNMP_INTEGER32: 151 case SNMP_BITSTRING: 152 case SNMP_OCTETSTRING: 153 case SNMP_NULL: 154 case SNMP_OBJECT: 155 /* universal types */ 156 break; 157 default: 158 /* application-specific types */ 159 ber_set_header(a, BER_CLASS_APPLICATION, 160 sm->snmp_type); 161 break; 162 } 163 x++; 164 break; 165 case IMSG_SNMP_END: 166 done = 1; 167 break; 168 default: 169 log_debug("trap_imsg: illegal imsg %d", 170 imsg.hdr.type); 171 goto imsgdone; 172 } 173 imsg_free(&imsg); 174 } 175 if (done) 176 break; 177 if ((n = imsg_read(ibuf)) == -1) 178 goto done; 179 if (n == 0) 180 goto done; 181 } 182 183 if (varbind != NULL) 184 len = ber_calc_len(varbind); 185 log_debug("trap_imsg: from pid %u len %d elements %d", 186 pid, len, x); 187 trap_send(&o, varbind); 188 189 ret = 0; 190 imsgdone: 191 if (ret != 0) 192 imsg_free(&imsg); 193 done: 194 if (varbind != NULL) 195 ber_free_elements(varbind); 196 return (ret); 197 } 198 199 int 200 trap_send(struct ber_oid *oid, struct ber_element *elm) 201 { 202 int ret = 0, s; 203 struct address *tr; 204 struct ber_element *root, *b, *c, *trap; 205 struct ber ber; 206 char *cmn; 207 ssize_t len; 208 u_int8_t *ptr; 209 struct ber_oid uptime = OID(MIB_sysUpTime); 210 struct ber_oid trapoid = OID(MIB_snmpTrapOID); 211 char ostr[SNMP_MAX_OID_LEN]; 212 struct oid oa, ob; 213 214 if (TAILQ_EMPTY(&env->sc_trapreceivers)) 215 return (0); 216 217 smi_oidlen(&uptime); 218 smi_oidlen(&trapoid); 219 smi_oidlen(oid); 220 221 smi_oidstring(oid, ostr, sizeof(ostr)); 222 log_debug("trap_send: oid %s", ostr); 223 224 /* Setup OIDs to compare against the trap receiver MIB */ 225 bzero(&oa, sizeof(oa)); 226 bcopy(oid->bo_id, &oa.o_oid, sizeof(oa.o_oid)); 227 oa.o_oidlen = oid->bo_n; 228 bzero(&ob, sizeof(ob)); 229 ob.o_flags = OID_TABLE; 230 231 /* Add mandatory varbind elements */ 232 trap = ber_add_sequence(NULL); 233 c = ber_printf_elements(trap, "{Odt}{OO}", 234 &uptime, smi_getticks(), 235 BER_CLASS_APPLICATION, SNMP_T_TIMETICKS, 236 &trapoid, oid); 237 if (elm != NULL) 238 ber_link_elements(c, elm); 239 240 bzero(&ber, sizeof(ber)); 241 ber.fd = -1; 242 243 TAILQ_FOREACH(tr, &env->sc_trapreceivers, entry) { 244 if (tr->sa_oid != NULL && tr->sa_oid->bo_n) { 245 /* The trap receiver may want only a specified MIB */ 246 bcopy(&tr->sa_oid->bo_id, &ob.o_oid, 247 sizeof(ob.o_oid)); 248 ob.o_oidlen = tr->sa_oid->bo_n; 249 if (smi_oid_cmp(&oa, &ob) != 0) 250 continue; 251 } 252 253 if ((s = snmpd_socket_af(&tr->ss, htons(tr->port))) == -1) { 254 ret = -1; 255 goto done; 256 } 257 258 cmn = tr->sa_community != NULL ? 259 tr->sa_community : env->sc_trcommunity; 260 261 /* SNMP header */ 262 root = ber_add_sequence(NULL); 263 b = ber_printf_elements(root, "ds{tddd", 264 SNMP_V2, cmn, BER_CLASS_CONTEXT, SNMP_C_TRAPV2, 265 arc4random(), 0, 0); 266 ber_link_elements(b, trap); 267 268 #ifdef DEBUG 269 snmpe_debug_elements(root); 270 #endif 271 272 len = ber_write_elements(&ber, root); 273 if (ber_get_writebuf(&ber, (void *)&ptr) > 0 && 274 sendto(s, ptr, len, 0, (struct sockaddr *)&tr->ss, 275 tr->ss.ss_len) != -1) { 276 env->sc_stats.snmp_outpkts++; 277 ret++; 278 } 279 280 close(s); 281 ber_unlink_elements(b); 282 ber_free_elements(root); 283 } 284 285 done: 286 if (elm != NULL) 287 ber_unlink_elements(c); 288 ber_free_elements(trap); 289 ber_free(&ber); 290 291 return (ret); 292 } 293