1 /* $OpenBSD: trap.c,v 1.21 2013/10/19 14:18:39 blambert 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/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) - 1) 105 goto imsgdone; 106 bzero(&ostr, sizeof(ostr)); 107 bcopy(sm + 1, &ostr, sm->snmp_len); 108 a = ber_add_oidstring(a, ostr); 109 break; 110 case SNMP_BITSTRING: 111 if (sm->snmp_len < 1) 112 goto imsgdone; 113 /* FALLTHROUGH */ 114 case SNMP_OCTETSTRING: 115 case SNMP_IPADDR: 116 if (sm->snmp_len >= SNMPD_MAXSTRLEN) 117 goto imsgdone; 118 c = (u_int8_t *)(sm + 1); 119 if (sm->snmp_type == SNMP_BITSTRING) 120 a = ber_add_bitstring(a, c, 121 sm->snmp_len); 122 else 123 a = ber_add_nstring(a, c, 124 sm->snmp_len); 125 break; 126 case SNMP_NULL: 127 a = ber_add_null(a); 128 break; 129 case SNMP_INTEGER32: 130 case SNMP_COUNTER32: 131 case SNMP_GAUGE32: 132 case SNMP_TIMETICKS: 133 case SNMP_OPAQUE: 134 case SNMP_UINTEGER32: 135 if (sm->snmp_len != sizeof(d)) 136 goto imsgdone; 137 bcopy(sm + 1, &d, sm->snmp_len); 138 a = ber_add_integer(a, d); 139 break; 140 case SNMP_COUNTER64: 141 if (sm->snmp_len != sizeof(l)) 142 goto imsgdone; 143 bcopy(sm + 1, &l, sm->snmp_len); 144 a = ber_add_integer(a, l); 145 break; 146 default: 147 log_debug("trap_imsg: illegal type %d", 148 sm->snmp_type); 149 imsg_free(&imsg); 150 goto imsgdone; 151 } 152 switch (sm->snmp_type) { 153 case SNMP_INTEGER32: 154 case SNMP_BITSTRING: 155 case SNMP_OCTETSTRING: 156 case SNMP_NULL: 157 case SNMP_OBJECT: 158 /* universal types */ 159 break; 160 default: 161 /* application-specific types */ 162 ber_set_header(a, BER_CLASS_APPLICATION, 163 sm->snmp_type); 164 break; 165 } 166 x++; 167 break; 168 case IMSG_SNMP_END: 169 done = 1; 170 break; 171 default: 172 log_debug("trap_imsg: illegal imsg %d", 173 imsg.hdr.type); 174 goto imsgdone; 175 } 176 imsg_free(&imsg); 177 } 178 if (done) 179 break; 180 if ((n = imsg_read(ibuf)) == -1) 181 goto done; 182 if (n == 0) 183 goto done; 184 } 185 186 if (varbind != NULL) 187 len = ber_calc_len(varbind); 188 log_debug("trap_imsg: from pid %u len %d elements %d", 189 pid, len, x); 190 trap_send(&o, varbind); 191 return (0); 192 193 imsgdone: 194 imsg_free(&imsg); 195 done: 196 if (varbind != NULL) 197 ber_free_elements(varbind); 198 return (ret); 199 } 200 201 int 202 trap_send(struct ber_oid *oid, struct ber_element *elm) 203 { 204 int ret = 0, s; 205 struct address *tr; 206 struct ber_element *root, *b, *c, *trap; 207 struct ber ber; 208 char *cmn; 209 ssize_t len; 210 u_int8_t *ptr; 211 struct ber_oid uptime = OID(MIB_sysUpTime); 212 struct ber_oid trapoid = OID(MIB_snmpTrapOID); 213 char ostr[SNMP_MAX_OID_LEN]; 214 struct oid oa, ob; 215 216 if (TAILQ_EMPTY(&env->sc_trapreceivers)) 217 return (0); 218 219 smi_scalar_oidlen(&uptime); 220 smi_scalar_oidlen(&trapoid); 221 smi_scalar_oidlen(oid); 222 223 smi_oid2string(oid, ostr, sizeof(ostr), 0); 224 log_debug("trap_send: oid %s", ostr); 225 226 /* Setup OIDs to compare against the trap receiver MIB */ 227 bzero(&oa, sizeof(oa)); 228 bcopy(oid->bo_id, &oa.o_oid, sizeof(oa.o_oid)); 229 oa.o_oidlen = oid->bo_n; 230 bzero(&ob, sizeof(ob)); 231 ob.o_flags = OID_TABLE; 232 233 /* Add mandatory varbind elements */ 234 trap = ber_add_sequence(NULL); 235 c = ber_printf_elements(trap, "{Odt}{OO}", 236 &uptime, smi_getticks(), 237 BER_CLASS_APPLICATION, SNMP_T_TIMETICKS, 238 &trapoid, oid); 239 if (elm != NULL) 240 ber_link_elements(c, elm); 241 242 bzero(&ber, sizeof(ber)); 243 ber.fd = -1; 244 245 TAILQ_FOREACH(tr, &env->sc_trapreceivers, entry) { 246 if (tr->sa_oid != NULL && tr->sa_oid->bo_n) { 247 /* The trap receiver may want only a specified MIB */ 248 bcopy(&tr->sa_oid->bo_id, &ob.o_oid, 249 sizeof(ob.o_oid)); 250 ob.o_oidlen = tr->sa_oid->bo_n; 251 if (smi_oid_cmp(&oa, &ob) != 0) 252 continue; 253 } 254 255 if ((s = snmpd_socket_af(&tr->ss, htons(tr->port))) == -1) { 256 ret = -1; 257 goto done; 258 } 259 260 cmn = tr->sa_community != NULL ? 261 tr->sa_community : env->sc_trcommunity; 262 263 /* SNMP header */ 264 root = ber_add_sequence(NULL); 265 b = ber_printf_elements(root, "ds{tddd", 266 SNMP_V2, cmn, BER_CLASS_CONTEXT, SNMP_C_TRAPV2, 267 arc4random(), 0, 0); 268 ber_link_elements(b, trap); 269 270 #ifdef DEBUG 271 smi_debug_elements(root); 272 #endif 273 274 len = ber_write_elements(&ber, root); 275 if (ber_get_writebuf(&ber, (void *)&ptr) > 0 && 276 sendto(s, ptr, len, 0, (struct sockaddr *)&tr->ss, 277 tr->ss.ss_len) != -1) { 278 env->sc_stats.snmp_outpkts++; 279 ret++; 280 } 281 282 close(s); 283 ber_unlink_elements(b); 284 ber_free_elements(root); 285 } 286 287 done: 288 ber_free_elements(trap); 289 ber_free(&ber); 290 291 return (ret); 292 } 293