1 /* $OpenBSD: trap.c,v 1.16 2012/02/01 18:44:06 camield 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 return (0); 189 190 imsgdone: 191 imsg_free(&imsg); 192 done: 193 if (varbind != NULL) 194 ber_free_elements(varbind); 195 return (ret); 196 } 197 198 int 199 trap_send(struct ber_oid *oid, struct ber_element *elm) 200 { 201 int ret = 0, s; 202 struct address *tr; 203 struct ber_element *root, *b, *c, *trap; 204 struct ber ber; 205 char *cmn; 206 ssize_t len; 207 u_int8_t *ptr; 208 struct ber_oid uptime = OID(MIB_sysUpTime); 209 struct ber_oid trapoid = OID(MIB_snmpTrapOID); 210 char ostr[SNMP_MAX_OID_LEN]; 211 struct oid oa, ob; 212 213 if (TAILQ_EMPTY(&env->sc_trapreceivers)) 214 return (0); 215 216 smi_scalar_oidlen(&uptime); 217 smi_scalar_oidlen(&trapoid); 218 smi_scalar_oidlen(oid); 219 220 smi_oidstring(oid, ostr, sizeof(ostr)); 221 log_debug("trap_send: oid %s", ostr); 222 223 /* Setup OIDs to compare against the trap receiver MIB */ 224 bzero(&oa, sizeof(oa)); 225 bcopy(oid->bo_id, &oa.o_oid, sizeof(oa.o_oid)); 226 oa.o_oidlen = oid->bo_n; 227 bzero(&ob, sizeof(ob)); 228 ob.o_flags = OID_TABLE; 229 230 /* Add mandatory varbind elements */ 231 trap = ber_add_sequence(NULL); 232 c = ber_printf_elements(trap, "{Odt}{OO}", 233 &uptime, smi_getticks(), 234 BER_CLASS_APPLICATION, SNMP_T_TIMETICKS, 235 &trapoid, oid); 236 if (elm != NULL) 237 ber_link_elements(c, elm); 238 239 bzero(&ber, sizeof(ber)); 240 ber.fd = -1; 241 242 TAILQ_FOREACH(tr, &env->sc_trapreceivers, entry) { 243 if (tr->sa_oid != NULL && tr->sa_oid->bo_n) { 244 /* The trap receiver may want only a specified MIB */ 245 bcopy(&tr->sa_oid->bo_id, &ob.o_oid, 246 sizeof(ob.o_oid)); 247 ob.o_oidlen = tr->sa_oid->bo_n; 248 if (smi_oid_cmp(&oa, &ob) != 0) 249 continue; 250 } 251 252 if ((s = snmpd_socket_af(&tr->ss, htons(tr->port))) == -1) { 253 ret = -1; 254 goto done; 255 } 256 257 cmn = tr->sa_community != NULL ? 258 tr->sa_community : env->sc_trcommunity; 259 260 /* SNMP header */ 261 root = ber_add_sequence(NULL); 262 b = ber_printf_elements(root, "ds{tddd", 263 SNMP_V2, cmn, BER_CLASS_CONTEXT, SNMP_C_TRAPV2, 264 arc4random(), 0, 0); 265 ber_link_elements(b, trap); 266 267 #ifdef DEBUG 268 snmpe_debug_elements(root); 269 #endif 270 271 len = ber_write_elements(&ber, root); 272 if (ber_get_writebuf(&ber, (void *)&ptr) > 0 && 273 sendto(s, ptr, len, 0, (struct sockaddr *)&tr->ss, 274 tr->ss.ss_len) != -1) { 275 env->sc_stats.snmp_outpkts++; 276 ret++; 277 } 278 279 close(s); 280 ber_unlink_elements(b); 281 ber_free_elements(root); 282 } 283 284 done: 285 ber_free_elements(trap); 286 ber_free(&ber); 287 288 return (ret); 289 } 290