trap.c revision 310903
133965Sjdp/* 2104834Sobrien * Copyright (c) 2001-2003 3218822Sdim * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 433965Sjdp * All rights reserved. 533965Sjdp * 633965Sjdp * Author: Harti Brandt <harti@freebsd.org> 733965Sjdp * 860484Sobrien * Copyright (c) 2010 The FreeBSD Foundation 933965Sjdp * All rights reserved. 1033965Sjdp * 1133965Sjdp * Portions of this software were developed by Shteryana Sotirova Shopova 1233965Sjdp * under sponsorship from the FreeBSD Foundation. 1333965Sjdp * 1433965Sjdp * Redistribution and use in source and binary forms, with or without 1533965Sjdp * modification, are permitted provided that the following conditions 1633965Sjdp * are met: 1733965Sjdp * 1. Redistributions of source code must retain the above copyright 1833965Sjdp * notice, this list of conditions and the following disclaimer. 1933965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 2033965Sjdp * notice, this list of conditions and the following disclaimer in the 2133965Sjdp * documentation and/or other materials provided with the distribution. 2233965Sjdp * 2333965Sjdp * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24218822Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25218822Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2633965Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27218822Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28218822Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29218822Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3033965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31218822Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32218822Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33218822Sdim * SUCH DAMAGE. 34218822Sdim * 35218822Sdim * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $ 36218822Sdim * 37218822Sdim * TrapSinkTable 38218822Sdim */ 39218822Sdim#include <sys/types.h> 40218822Sdim#include <sys/queue.h> 41218822Sdim#include <sys/sysctl.h> 42218822Sdim#include <sys/un.h> 43218822Sdim#include <stdint.h> 44218822Sdim#include <stdio.h> 45218822Sdim#include <stdlib.h> 46218822Sdim#include <stdarg.h> 47218822Sdim#include <stdarg.h> 48218822Sdim#include <string.h> 49218822Sdim#include <ctype.h> 50218822Sdim#include <syslog.h> 5133965Sjdp#include <unistd.h> 5233965Sjdp#include <netinet/in.h> 5360484Sobrien#include <arpa/inet.h> 5460484Sobrien 5533965Sjdp#include "snmpmod.h" 5633965Sjdp#include "snmpd.h" 5733965Sjdp#include "tree.h" 5833965Sjdp#include "oid.h" 5933965Sjdp 6077298Sobrienstruct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); 6133965Sjdp 6233965Sjdp/* List of target addresses */ 63218822Sdimstatic struct target_addresslist target_addresslist = 6489857Sobrien SLIST_HEAD_INITIALIZER(target_addresslist); 6533965Sjdp 66130561Sobrien/* List of target parameters */ 6733965Sjdpstatic struct target_paramlist target_paramlist = 68218822Sdim SLIST_HEAD_INITIALIZER(target_paramlist); 69218822Sdim 70218822Sdim/* List of notification targets */ 71218822Sdimstatic struct target_notifylist target_notifylist = 7260484Sobrien SLIST_HEAD_INITIALIZER(target_notifylist); 73130561Sobrien 74130561Sobrienstatic const struct asn_oid oid_begemotTrapSinkTable = 7533965Sjdp OIDX_begemotTrapSinkTable; 7633965Sjdpstatic const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; 7733965Sjdpstatic const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID; 7833965Sjdp 79130561Sobrienstruct trapsink_dep { 80130561Sobrien struct snmp_dependency dep; 8133965Sjdp u_int set; 8233965Sjdp u_int status; 8333965Sjdp u_char comm[SNMP_COMMUNITY_MAXLEN + 1]; 8489857Sobrien u_int version; 8533965Sjdp u_int rb; 8633965Sjdp u_int rb_status; 87130561Sobrien u_int rb_version; 88130561Sobrien u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1]; 89130561Sobrien}; 90130561Sobrienenum { 91130561Sobrien TDEP_STATUS = 0x0001, 92130561Sobrien TDEP_COMM = 0x0002, 93130561Sobrien TDEP_VERSION = 0x0004, 94130561Sobrien 95130561Sobrien TDEP_CREATE = 0x0001, 96130561Sobrien TDEP_MODIFY = 0x0002, 9733965Sjdp TDEP_DESTROY = 0x0004, 98130561Sobrien}; 99130561Sobrien 10033965Sjdpstatic int 101218822Sdimtrapsink_create(struct trapsink_dep *tdep) 102218822Sdim{ 10333965Sjdp struct trapsink *t; 10433965Sjdp struct sockaddr_in sa; 10533965Sjdp 10677298Sobrien if ((t = malloc(sizeof(*t))) == NULL) 10733965Sjdp return (SNMP_ERR_RES_UNAVAIL); 108218822Sdim 109218822Sdim t->index = tdep->dep.idx; 11033965Sjdp t->status = TRAPSINK_NOT_READY; 111104834Sobrien t->comm[0] = '\0'; 112218822Sdim t->version = TRAPSINK_V2; 113218822Sdim 114218822Sdim if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 115218822Sdim syslog(LOG_ERR, "socket(UDP): %m"); 116218822Sdim free(t); 117218822Sdim return (SNMP_ERR_RES_UNAVAIL); 118218822Sdim } 119218822Sdim (void)shutdown(t->socket, SHUT_RD); 120218822Sdim memset(&sa, 0, sizeof(sa)); 121218822Sdim sa.sin_len = sizeof(sa); 122218822Sdim sa.sin_family = AF_INET; 123218822Sdim sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) | 124218822Sdim (t->index.subs[1] << 16) | (t->index.subs[2] << 8) | 125218822Sdim (t->index.subs[3] << 0)); 126218822Sdim sa.sin_port = htons(t->index.subs[4]); 127218822Sdim 128218822Sdim if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 129218822Sdim syslog(LOG_ERR, "connect(%s,%u): %m", 130218822Sdim inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 131218822Sdim (void)close(t->socket); 132218822Sdim free(t); 133218822Sdim return (SNMP_ERR_GENERR); 134218822Sdim } 13560484Sobrien 13689857Sobrien if (tdep->set & TDEP_VERSION) 13789857Sobrien t->version = tdep->version; 13889857Sobrien if (tdep->set & TDEP_COMM) 13989857Sobrien strcpy(t->comm, tdep->comm); 140104834Sobrien 141104834Sobrien if (t->comm[0] != '\0') 142218822Sdim t->status = TRAPSINK_NOT_IN_SERVICE; 14360484Sobrien 144104834Sobrien /* look whether we should activate */ 14589857Sobrien if (tdep->status == 4) { 146130561Sobrien if (t->status == TRAPSINK_NOT_READY) { 14733965Sjdp if (t->socket != -1) 14833965Sjdp (void)close(t->socket); 14933965Sjdp free(t); 15033965Sjdp return (SNMP_ERR_INCONS_VALUE); 15133965Sjdp } 152130561Sobrien t->status = TRAPSINK_ACTIVE; 15333965Sjdp } 15433965Sjdp 15533965Sjdp INSERT_OBJECT_OID(t, &trapsink_list); 15633965Sjdp 15733965Sjdp tdep->rb |= TDEP_CREATE; 15838889Sjdp 15938889Sjdp return (SNMP_ERR_NOERROR); 16033965Sjdp} 16138889Sjdp 16238889Sjdpstatic void 16377298Sobrientrapsink_free(struct trapsink *t) 16438889Sjdp{ 16577298Sobrien TAILQ_REMOVE(&trapsink_list, t, link); 16638889Sjdp if (t->socket != -1) 16777298Sobrien (void)close(t->socket); 16877298Sobrien free(t); 16977298Sobrien} 17077298Sobrien 17138889Sjdpstatic int 17233965Sjdptrapsink_modify(struct trapsink *t, struct trapsink_dep *tdep) 17333965Sjdp{ 17433965Sjdp tdep->rb_status = t->status; 17533965Sjdp tdep->rb_version = t->version; 17633965Sjdp strcpy(tdep->rb_comm, t->comm); 17733965Sjdp 17877298Sobrien if (tdep->set & TDEP_STATUS) { 17977298Sobrien /* if we are active and should move to not_in_service do 18033965Sjdp * this first */ 18177298Sobrien if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) { 18277298Sobrien t->status = TRAPSINK_NOT_IN_SERVICE; 18333965Sjdp tdep->rb |= TDEP_MODIFY; 18433965Sjdp } 18533965Sjdp } 186130561Sobrien 18733965Sjdp if (tdep->set & TDEP_VERSION) 18877298Sobrien t->version = tdep->version; 18933965Sjdp if (tdep->set & TDEP_COMM) 19033965Sjdp strcpy(t->comm, tdep->comm); 19177298Sobrien 19233965Sjdp if (tdep->set & TDEP_STATUS) { 19333965Sjdp /* if we were inactive and should go active - do this now */ 19477298Sobrien if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) { 19533965Sjdp if (t->comm[0] == '\0') { 19633965Sjdp t->status = tdep->rb_status; 19777298Sobrien t->version = tdep->rb_version; 19833965Sjdp strcpy(t->comm, tdep->rb_comm); 19977298Sobrien return (SNMP_ERR_INCONS_VALUE); 20077298Sobrien } 20133965Sjdp t->status = TRAPSINK_ACTIVE; 20233965Sjdp tdep->rb |= TDEP_MODIFY; 20333965Sjdp } 20477298Sobrien } 20533965Sjdp return (SNMP_ERR_NOERROR); 20633965Sjdp} 20733965Sjdp 20833965Sjdpstatic int 20933965Sjdptrapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep) 21033965Sjdp{ 21133965Sjdp if (tdep->set & TDEP_STATUS) 21233965Sjdp t->status = tdep->rb_status; 21333965Sjdp if (tdep->set & TDEP_VERSION) 21433965Sjdp t->version = tdep->rb_version; 21533965Sjdp if (tdep->set & TDEP_COMM) 21633965Sjdp strcpy(t->comm, tdep->rb_comm); 21733965Sjdp 21833965Sjdp return (SNMP_ERR_NOERROR); 21933965Sjdp} 22033965Sjdp 22133965Sjdpstatic int 22233965Sjdptrapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t, 22333965Sjdp struct trapsink_dep *tdep) 22433965Sjdp{ 22533965Sjdp t->status = TRAPSINK_DESTROY; 22633965Sjdp tdep->rb_status = t->status; 22733965Sjdp tdep->rb |= TDEP_DESTROY; 22833965Sjdp return (SNMP_ERR_NOERROR); 22933965Sjdp} 23033965Sjdp 23138889Sjdpstatic int 23233965Sjdptrapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep) 23338889Sjdp{ 23433965Sjdp t->status = tdep->rb_status; 23533965Sjdp return (SNMP_ERR_NOERROR); 236130561Sobrien} 237130561Sobrien 23833965Sjdpstatic int 239130561Sobrientrapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep, 24077298Sobrien enum snmp_depop op) 241130561Sobrien{ 24260484Sobrien struct trapsink_dep *tdep = (struct trapsink_dep *)dep; 24377298Sobrien struct trapsink *t; 24477298Sobrien 245130561Sobrien t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0); 246130561Sobrien 24760484Sobrien switch (op) { 248130561Sobrien 249130561Sobrien case SNMP_DEPOP_COMMIT: 25033965Sjdp if (tdep->set & TDEP_STATUS) { 25177298Sobrien switch (tdep->status) { 25233965Sjdp 25333965Sjdp case 1: 25433965Sjdp case 2: 25533965Sjdp if (t == NULL) 25633965Sjdp return (SNMP_ERR_INCONS_VALUE); 25733965Sjdp return (trapsink_modify(t, tdep)); 25833965Sjdp 25933965Sjdp case 4: 26033965Sjdp case 5: 26133965Sjdp if (t != NULL) 26233965Sjdp return (SNMP_ERR_INCONS_VALUE); 26333965Sjdp return (trapsink_create(tdep)); 26433965Sjdp 26533965Sjdp case 6: 26633965Sjdp if (t == NULL) 26733965Sjdp return (SNMP_ERR_NOERROR); 26833965Sjdp return (trapsink_destroy(ctx, t, tdep)); 26933965Sjdp } 27033965Sjdp } else if (tdep->set != 0) 27133965Sjdp return (trapsink_modify(t, tdep)); 27233965Sjdp 273130561Sobrien return (SNMP_ERR_NOERROR); 27433965Sjdp 27533965Sjdp case SNMP_DEPOP_ROLLBACK: 27633965Sjdp if (tdep->rb & TDEP_CREATE) { 277130561Sobrien trapsink_free(t); 27833965Sjdp return (SNMP_ERR_NOERROR); 27933965Sjdp } 280130561Sobrien if (tdep->rb & TDEP_MODIFY) 28133965Sjdp return (trapsink_unmodify(t, tdep)); 28233965Sjdp if(tdep->rb & TDEP_DESTROY) 28333965Sjdp return (trapsink_undestroy(t, tdep)); 284130561Sobrien return (SNMP_ERR_NOERROR); 28533965Sjdp 28633965Sjdp case SNMP_DEPOP_FINISH: 28733965Sjdp if ((tdep->rb & TDEP_DESTROY) && t != NULL && 28833965Sjdp ctx->code == SNMP_RET_OK) 28933965Sjdp trapsink_free(t); 29033965Sjdp return (SNMP_ERR_NOERROR); 291130561Sobrien } 29233965Sjdp abort(); 29333965Sjdp} 294130561Sobrien 29533965Sjdpint 29633965Sjdpop_trapsink(struct snmp_context *ctx, struct snmp_value *value, 297130561Sobrien u_int sub, u_int iidx, enum snmp_op op) 29833965Sjdp{ 29933965Sjdp struct trapsink *t; 30033965Sjdp u_char ipa[4]; 30133965Sjdp int32_t port; 30233965Sjdp struct asn_oid idx; 30333965Sjdp struct trapsink_dep *tdep; 30433965Sjdp u_char *p; 30533965Sjdp 30633965Sjdp t = NULL; /* gcc */ 30733965Sjdp 30877298Sobrien switch (op) { 30933965Sjdp 31033965Sjdp case SNMP_OP_GETNEXT: 31133965Sjdp if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) 31233965Sjdp return (SNMP_ERR_NOSUCHNAME); 31333965Sjdp index_append(&value->var, sub, &t->index); 31433965Sjdp break; 31533965Sjdp 31633965Sjdp case SNMP_OP_GET: 31733965Sjdp if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) 31833965Sjdp return (SNMP_ERR_NOSUCHNAME); 319130561Sobrien break; 32033965Sjdp 32133965Sjdp case SNMP_OP_SET: 32233965Sjdp if (index_decode(&value->var, sub, iidx, ipa, &port) || 32333965Sjdp port == 0 || port > 65535) 324130561Sobrien return (SNMP_ERR_NO_CREATION); 32533965Sjdp t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub); 32633965Sjdp 327130561Sobrien asn_slice_oid(&idx, &value->var, sub, value->var.len); 32833965Sjdp 32933965Sjdp tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx, 330130561Sobrien &oid_begemotTrapSinkTable, &idx, 33133965Sjdp sizeof(*tdep), trapsink_dep); 33233965Sjdp if (tdep == NULL) 333130561Sobrien return (SNMP_ERR_RES_UNAVAIL); 33433965Sjdp 33533965Sjdp switch (value->var.subs[sub - 1]) { 33633965Sjdp 33733965Sjdp case LEAF_begemotTrapSinkStatus: 33833965Sjdp if (tdep->set & TDEP_STATUS) 33933965Sjdp return (SNMP_ERR_INCONS_VALUE); 34033965Sjdp switch (value->v.integer) { 34133965Sjdp 34233965Sjdp case 1: 34333965Sjdp case 2: 34433965Sjdp if (t == NULL) 34533965Sjdp return (SNMP_ERR_INCONS_VALUE); 34633965Sjdp break; 34733965Sjdp 34833965Sjdp case 4: 34933965Sjdp case 5: 35033965Sjdp if (t != NULL) 35133965Sjdp return (SNMP_ERR_INCONS_VALUE); 35233965Sjdp break; 35333965Sjdp 35433965Sjdp case 6: 35533965Sjdp break; 35660484Sobrien 35760484Sobrien default: 35877298Sobrien return (SNMP_ERR_WRONG_VALUE); 35960484Sobrien } 36060484Sobrien tdep->status = value->v.integer; 36138889Sjdp tdep->set |= TDEP_STATUS; 36238889Sjdp return (SNMP_ERR_NOERROR); 36338889Sjdp 36438889Sjdp case LEAF_begemotTrapSinkComm: 36538889Sjdp if (tdep->set & TDEP_COMM) 36638889Sjdp return (SNMP_ERR_INCONS_VALUE); 36733965Sjdp if (value->v.octetstring.len == 0 || 36833965Sjdp value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN) 369218822Sdim return (SNMP_ERR_WRONG_VALUE); 370218822Sdim for (p = value->v.octetstring.octets; 371218822Sdim p < value->v.octetstring.octets + value->v.octetstring.len; 37233965Sjdp p++) { 373218822Sdim if (!isascii(*p) || !isprint(*p)) 374218822Sdim return (SNMP_ERR_WRONG_VALUE); 37533965Sjdp } 37633965Sjdp tdep->set |= TDEP_COMM; 37733965Sjdp strncpy(tdep->comm, value->v.octetstring.octets, 37833965Sjdp value->v.octetstring.len); 37933965Sjdp tdep->comm[value->v.octetstring.len] = '\0'; 38033965Sjdp return (SNMP_ERR_NOERROR); 38133965Sjdp 38233965Sjdp case LEAF_begemotTrapSinkVersion: 38333965Sjdp if (tdep->set & TDEP_VERSION) 38433965Sjdp return (SNMP_ERR_INCONS_VALUE); 38533965Sjdp if (value->v.integer != TRAPSINK_V1 && 38633965Sjdp value->v.integer != TRAPSINK_V2) 38733965Sjdp return (SNMP_ERR_WRONG_VALUE); 388130561Sobrien tdep->version = value->v.integer; 38933965Sjdp tdep->set |= TDEP_VERSION; 39033965Sjdp return (SNMP_ERR_NOERROR); 39133965Sjdp } 39260484Sobrien if (t == NULL) 39360484Sobrien return (SNMP_ERR_INCONS_NAME); 39460484Sobrien else 39560484Sobrien return (SNMP_ERR_NOT_WRITEABLE); 39660484Sobrien 39760484Sobrien 39889857Sobrien case SNMP_OP_ROLLBACK: 39960484Sobrien case SNMP_OP_COMMIT: 40089857Sobrien return (SNMP_ERR_NOERROR); 40160484Sobrien } 40289857Sobrien 40389857Sobrien switch (value->var.subs[sub - 1]) { 40460484Sobrien 405130561Sobrien case LEAF_begemotTrapSinkStatus: 406130561Sobrien value->v.integer = t->status; 407218822Sdim break; 408218822Sdim 409218822Sdim case LEAF_begemotTrapSinkComm: 410218822Sdim return (string_get(value, t->comm, -1)); 411218822Sdim 412218822Sdim case LEAF_begemotTrapSinkVersion: 413130561Sobrien value->v.integer = t->version; 414130561Sobrien break; 415130561Sobrien 416218822Sdim } 417218822Sdim return (SNMP_ERR_NOERROR); 418218822Sdim} 419218822Sdim 420218822Sdimstatic void 421218822Sdimsnmp_create_v1_trap(struct snmp_pdu *pdu, char *com, 422218822Sdim const struct asn_oid *trap_oid) 423218822Sdim{ 424218822Sdim memset(pdu, 0, sizeof(*pdu)); 425218822Sdim strcpy(pdu->community, com); 426218822Sdim 427218822Sdim pdu->version = SNMP_V1; 428218822Sdim pdu->type = SNMP_PDU_TRAP; 429218822Sdim pdu->enterprise = systemg.object_id; 430218822Sdim memcpy(pdu->agent_addr, snmpd.trap1addr, 4); 431218822Sdim pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; 432218822Sdim pdu->specific_trap = 0; 433218822Sdim pdu->time_stamp = get_ticks() - start_tick; 434218822Sdim pdu->nbindings = 0; 435218822Sdim} 436218822Sdim 437218822Sdimstatic void 438218822Sdimsnmp_create_v2_trap(struct snmp_pdu *pdu, char *com, 43989857Sobrien const struct asn_oid *trap_oid) 44060484Sobrien{ 44189857Sobrien memset(pdu, 0, sizeof(*pdu)); 44260484Sobrien strcpy(pdu->community, com); 44360484Sobrien 44477298Sobrien pdu->version = SNMP_V2c; 44589857Sobrien pdu->type = SNMP_PDU_TRAP2; 44660484Sobrien pdu->request_id = reqid_next(trap_reqid); 447218822Sdim pdu->error_index = 0; 44860484Sobrien pdu->error_status = SNMP_ERR_NOERROR; 44960484Sobrien 450130561Sobrien pdu->bindings[0].var = oid_sysUpTime; 45189857Sobrien pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 45260484Sobrien pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 453218822Sdim pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 454218822Sdim 455218822Sdim pdu->bindings[1].var = oid_snmpTrapOID; 456218822Sdim pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 457218822Sdim pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 458218822Sdim pdu->bindings[1].v.oid = *trap_oid; 459218822Sdim 460104834Sobrien pdu->nbindings = 2; 461104834Sobrien} 462104834Sobrien 463218822Sdimstatic void 464218822Sdimsnmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target, 46560484Sobrien const struct asn_oid *trap_oid) 46660484Sobrien{ 467218822Sdim uint64_t etime; 46860484Sobrien struct usm_user *usmuser; 46989857Sobrien 47089857Sobrien memset(pdu, 0, sizeof(*pdu)); 47189857Sobrien 47260484Sobrien pdu->version = SNMP_V3; 47338889Sjdp pdu->type = SNMP_PDU_TRAP2; 47438889Sjdp pdu->request_id = reqid_next(trap_reqid); 475130561Sobrien pdu->error_index = 0; 476130561Sobrien pdu->error_status = SNMP_ERR_NOERROR; 47738889Sjdp 47838889Sjdp pdu->bindings[0].var = oid_sysUpTime; 479130561Sobrien pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 480130561Sobrien pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 481130561Sobrien pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 48238889Sjdp 48377298Sobrien pdu->bindings[1].var = oid_snmpTrapOID; 48438889Sjdp pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 48538889Sjdp pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 48638889Sjdp pdu->bindings[1].v.oid = *trap_oid; 48738889Sjdp 48838889Sjdp pdu->nbindings = 2; 48938889Sjdp 49038889Sjdp etime = (get_ticks() - start_tick) / 100ULL; 49138889Sjdp if (etime < INT32_MAX) 49238889Sjdp snmpd_engine.engine_time = etime; 49338889Sjdp else { 49438889Sjdp start_tick = get_ticks(); 49560484Sobrien set_snmpd_engine(); 49660484Sobrien snmpd_engine.engine_time = start_tick; 497104834Sobrien } 498104834Sobrien 499104834Sobrien memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 500104834Sobrien snmpd_engine.engine_len); 50138889Sjdp pdu->engine.engine_len = snmpd_engine.engine_len; 50238889Sjdp pdu->engine.engine_boots = snmpd_engine.engine_boots; 50338889Sjdp pdu->engine.engine_time = snmpd_engine.engine_time; 50438889Sjdp pdu->engine.max_msg_size = snmpd_engine.max_msg_size; 50538889Sjdp strlcpy(pdu->user.sec_name, target->secname, 50638889Sjdp sizeof(pdu->user.sec_name)); 50738889Sjdp pdu->security_model = target->sec_model; 50860484Sobrien 509104834Sobrien pdu->context_engine_len = snmpd_engine.engine_len; 510104834Sobrien memcpy(pdu->context_engine, snmpd_engine.engine_id, 51138889Sjdp snmpd_engine.engine_len); 51238889Sjdp 51360484Sobrien if (target->sec_model == SNMP_SECMODEL_USM && 51438889Sjdp target->sec_level != SNMP_noAuthNoPriv) { 51538889Sjdp usmuser = usm_find_user(pdu->engine.engine_id, 516218822Sdim pdu->engine.engine_len, pdu->user.sec_name); 517218822Sdim if (usmuser != NULL) { 518218822Sdim pdu->user.auth_proto = usmuser->suser.auth_proto; 519218822Sdim pdu->user.priv_proto = usmuser->suser.priv_proto; 520218822Sdim memcpy(pdu->user.auth_key, usmuser->suser.auth_key, 521218822Sdim sizeof(pdu->user.auth_key)); 522218822Sdim memcpy(pdu->user.priv_key, usmuser->suser.priv_key, 523218822Sdim sizeof(pdu->user.priv_key)); 524218822Sdim } 525218822Sdim snmp_pdu_init_secparams(pdu); 52633965Sjdp } 527218822Sdim} 528218822Sdim 529218822Sdimvoid 53033965Sjdpsnmp_send_trap(const struct asn_oid *trap_oid, ...) 53189857Sobrien{ 532218822Sdim struct snmp_pdu pdu; 53389857Sobrien struct trapsink *t; 53489857Sobrien const struct snmp_value *v; 53589857Sobrien struct target_notify *n; 53660484Sobrien struct target_address *ta; 53789857Sobrien struct target_param *tp; 53889857Sobrien 53989857Sobrien va_list ap; 54089857Sobrien u_char *sndbuf; 54189857Sobrien char *tag; 54289857Sobrien size_t sndlen; 54389857Sobrien ssize_t len; 54489857Sobrien int32_t ip; 545218822Sdim 54689857Sobrien TAILQ_FOREACH(t, &trapsink_list, link) { 54789857Sobrien if (t->status != TRAPSINK_ACTIVE) 54889857Sobrien continue; 54989857Sobrien 550218822Sdim if (t->version == TRAPSINK_V1) 55189857Sobrien snmp_create_v1_trap(&pdu, t->comm, trap_oid); 55289857Sobrien else 55389857Sobrien snmp_create_v2_trap(&pdu, t->comm, trap_oid); 55489857Sobrien 55589857Sobrien va_start(ap, trap_oid); 55689857Sobrien while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 55789857Sobrien pdu.bindings[pdu.nbindings++] = *v; 55860484Sobrien va_end(ap); 559218822Sdim 560218822Sdim if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 561218822Sdim syslog(LOG_DEBUG, "send trap to %s failed: no access", 56260484Sobrien t->comm); 56360484Sobrien continue; 56460484Sobrien } 56560484Sobrien 56660484Sobrien if ((sndbuf = buf_alloc(1)) == NULL) { 56789857Sobrien syslog(LOG_ERR, "trap send buffer: %m"); 56860484Sobrien return; 56977298Sobrien } 57077298Sobrien 57177298Sobrien snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 57260484Sobrien 57360484Sobrien if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) 57460484Sobrien syslog(LOG_ERR, "send: %m"); 57560484Sobrien else if ((size_t)len != sndlen) 57660484Sobrien syslog(LOG_ERR, "send: short write %zu/%zu", 57760484Sobrien sndlen, (size_t)len); 57860484Sobrien 579130561Sobrien free(sndbuf); 58089857Sobrien } 58189857Sobrien 58260484Sobrien SLIST_FOREACH(n, &target_notifylist, tn) { 58360484Sobrien if (n->status != RowStatus_active || n->taglist[0] == '\0') 58460484Sobrien continue; 58577298Sobrien 58660484Sobrien SLIST_FOREACH(ta, &target_addresslist, ta) 58760484Sobrien if ((tag = strstr(ta->taglist, n->taglist)) != NULL && 58860484Sobrien (tag[strlen(n->taglist)] == ' ' || 58989857Sobrien tag[strlen(n->taglist)] == '\0' || 59089857Sobrien tag[strlen(n->taglist)] == '\t' || 59189857Sobrien tag[strlen(n->taglist)] == '\r' || 59289857Sobrien tag[strlen(n->taglist)] == '\n') && 59389857Sobrien ta->status == RowStatus_active) 594130561Sobrien break; 595104834Sobrien if (ta == NULL) 596104834Sobrien continue; 597104834Sobrien 598104834Sobrien SLIST_FOREACH(tp, &target_paramlist, tp) 599104834Sobrien if (strcmp(tp->name, ta->paramname) == 0 && 600104834Sobrien tp->status == 1) 601104834Sobrien break; 602104834Sobrien if (tp == NULL) 603104834Sobrien continue; 604104834Sobrien 605104834Sobrien switch (tp->mpmodel) { 606104834Sobrien case SNMP_MPM_SNMP_V1: 607104834Sobrien snmp_create_v1_trap(&pdu, tp->secname, trap_oid); 608104834Sobrien break; 609130561Sobrien 61060484Sobrien case SNMP_MPM_SNMP_V2c: 61160484Sobrien snmp_create_v2_trap(&pdu, tp->secname, trap_oid); 61289857Sobrien break; 61389857Sobrien 61460484Sobrien case SNMP_MPM_SNMP_V3: 61589857Sobrien snmp_create_v3_trap(&pdu, tp, trap_oid); 61660484Sobrien break; 61760484Sobrien 61889857Sobrien default: 619104834Sobrien continue; 620104834Sobrien } 621104834Sobrien 622104834Sobrien va_start(ap, trap_oid); 623104834Sobrien while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 624104834Sobrien pdu.bindings[pdu.nbindings++] = *v; 625104834Sobrien va_end(ap); 62689857Sobrien 62789857Sobrien if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 62889857Sobrien syslog(LOG_DEBUG, "send trap to %s failed: no access", 62989857Sobrien t->comm); 63060484Sobrien continue; 63160484Sobrien } 63260484Sobrien 633104834Sobrien if ((sndbuf = buf_alloc(1)) == NULL) { 634104834Sobrien syslog(LOG_ERR, "trap send buffer: %m"); 635104834Sobrien return; 636104834Sobrien } 63789857Sobrien 63889857Sobrien snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 63989857Sobrien 64089857Sobrien if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) 64189857Sobrien syslog(LOG_ERR, "send: %m"); 64289857Sobrien else if ((size_t)len != sndlen) 64389857Sobrien syslog(LOG_ERR, "send: short write %zu/%zu", 64489857Sobrien sndlen, (size_t)len); 64589857Sobrien 64689857Sobrien free(sndbuf); 64789857Sobrien } 64889857Sobrien} 64989857Sobrien 65089857Sobrien/* 65189857Sobrien * RFC 3413 SNMP Management Target MIB 65260484Sobrien */ 65389857Sobrienstruct snmpd_target_stats * 65489857Sobrienbsnmpd_get_target_stats(void) 65560484Sobrien{ 656104834Sobrien return (&snmpd_target_stats); 657104834Sobrien} 658104834Sobrien 659104834Sobrienstruct target_address * 660104834Sobrientarget_first_address(void) 661104834Sobrien{ 662104834Sobrien return (SLIST_FIRST(&target_addresslist)); 663104834Sobrien} 664104834Sobrien 665104834Sobrienstruct target_address * 666104834Sobrientarget_next_address(struct target_address *addrs) 667104834Sobrien{ 668104834Sobrien if (addrs == NULL) 669104834Sobrien return (NULL); 670104834Sobrien 671104834Sobrien return (SLIST_NEXT(addrs, ta)); 672104834Sobrien} 673104834Sobrien 674104834Sobrienstruct target_address * 675218822Sdimtarget_new_address(char *aname) 676104834Sobrien{ 67789857Sobrien int cmp; 678104834Sobrien struct target_address *addrs, *temp, *prev; 679104834Sobrien 68089857Sobrien SLIST_FOREACH(addrs, &target_addresslist, ta) 68160484Sobrien if (strcmp(aname, addrs->name) == 0) 68289857Sobrien return (NULL); 68389857Sobrien 68489857Sobrien if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) 68560484Sobrien return (NULL); 68689857Sobrien 68789857Sobrien memset(addrs, 0, sizeof(*addrs)); 68860484Sobrien strlcpy(addrs->name, aname, sizeof(addrs->name)); 68989857Sobrien addrs->timeout = 150; 69089857Sobrien addrs->retry = 3; /* XXX */ 69160484Sobrien 69289857Sobrien if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || 69389857Sobrien strcmp(aname, prev->name) < 0) { 69489857Sobrien SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); 69589857Sobrien return (addrs); 69689857Sobrien } 69789857Sobrien 69889857Sobrien SLIST_FOREACH(temp, &target_addresslist, ta) { 69989857Sobrien if ((cmp = strcmp(aname, temp->name)) <= 0) 70089857Sobrien break; 70189857Sobrien prev = temp; 70260484Sobrien } 70389857Sobrien 70489857Sobrien if (temp == NULL || cmp < 0) 70589857Sobrien SLIST_INSERT_AFTER(prev, addrs, ta); 70689857Sobrien else if (cmp > 0) 70760484Sobrien SLIST_INSERT_AFTER(temp, addrs, ta); 70860484Sobrien else { 70960484Sobrien syslog(LOG_ERR, "Target address %s exists", addrs->name); 710218822Sdim free(addrs); 711218822Sdim return (NULL); 712218822Sdim } 713218822Sdim 714218822Sdim return (addrs); 715218822Sdim} 716218822Sdim 717218822Sdimint 718218822Sdimtarget_activate_address(struct target_address *addrs) 719218822Sdim{ 720218822Sdim struct sockaddr_in sa; 72160484Sobrien 72260484Sobrien if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 72360484Sobrien syslog(LOG_ERR, "socket(UDP): %m"); 724218822Sdim return (SNMP_ERR_RES_UNAVAIL); 72560484Sobrien } 72660484Sobrien 72760484Sobrien (void)shutdown(addrs->socket, SHUT_RD); 72860484Sobrien memset(&sa, 0, sizeof(sa)); 72960484Sobrien sa.sin_len = sizeof(sa); 73060484Sobrien sa.sin_family = AF_INET; 73160484Sobrien 73260484Sobrien sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | 733130561Sobrien (addrs->address[1] << 16) | (addrs->address[2] << 8) | 73460484Sobrien (addrs->address[3] << 0)); 73560484Sobrien sa.sin_port = htons(addrs->address[4]) << 8 | 73660484Sobrien htons(addrs->address[5]) << 0; 73760484Sobrien 73860484Sobrien if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 73960484Sobrien syslog(LOG_ERR, "connect(%s,%u): %m", 74060484Sobrien inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 74160484Sobrien (void)close(addrs->socket); 74260484Sobrien return (SNMP_ERR_GENERR); 74360484Sobrien } 74460484Sobrien 74560484Sobrien addrs->status = RowStatus_active; 74660484Sobrien 74760484Sobrien return (SNMP_ERR_NOERROR); 74860484Sobrien} 74960484Sobrien 75060484Sobrienint 75160484Sobrientarget_delete_address(struct target_address *addrs) 75260484Sobrien{ 75360484Sobrien SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); 75460484Sobrien if (addrs->status == RowStatus_active) 75560484Sobrien close(addrs->socket); 75660484Sobrien free(addrs); 75760484Sobrien 75860484Sobrien return (0); 75960484Sobrien} 76060484Sobrien 76160484Sobrienstruct target_param * 76260484Sobrientarget_first_param(void) 76360484Sobrien{ 76460484Sobrien return (SLIST_FIRST(&target_paramlist)); 76560484Sobrien} 76660484Sobrien 76760484Sobrienstruct target_param * 76860484Sobrientarget_next_param(struct target_param *param) 76960484Sobrien{ 77091041Sobrien if (param == NULL) 77160484Sobrien return (NULL); 77260484Sobrien 77360484Sobrien return (SLIST_NEXT(param, tp)); 774104834Sobrien} 775104834Sobrien 776218822Sdimstruct target_param * 77760484Sobrientarget_new_param(char *pname) 77860484Sobrien{ 77960484Sobrien int cmp; 78089857Sobrien struct target_param *param, *temp, *prev; 78191041Sobrien 782104834Sobrien SLIST_FOREACH(param, &target_paramlist, tp) 783104834Sobrien if (strcmp(pname, param->name) == 0) 784104834Sobrien return (NULL); 785104834Sobrien 786104834Sobrien if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) 787104834Sobrien return (NULL); 788104834Sobrien 789104834Sobrien memset(param, 0, sizeof(*param)); 790104834Sobrien strlcpy(param->name, pname, sizeof(param->name)); 791104834Sobrien 79260484Sobrien if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || 79360484Sobrien strcmp(pname, prev->name) < 0) { 79460484Sobrien SLIST_INSERT_HEAD(&target_paramlist, param, tp); 79560484Sobrien return (param); 79660484Sobrien } 79777298Sobrien 79860484Sobrien SLIST_FOREACH(temp, &target_paramlist, tp) { 79960484Sobrien if ((cmp = strcmp(pname, temp->name)) <= 0) 80060484Sobrien break; 80160484Sobrien prev = temp; 80260484Sobrien } 80360484Sobrien 80433965Sjdp if (temp == NULL || cmp < 0) 80533965Sjdp SLIST_INSERT_AFTER(prev, param, tp); 80633965Sjdp else if (cmp > 0) 807218822Sdim SLIST_INSERT_AFTER(temp, param, tp); 808218822Sdim else { 809218822Sdim syslog(LOG_ERR, "Target parameter %s exists", param->name); 81033965Sjdp free(param); 81133965Sjdp return (NULL); 81233965Sjdp } 81333965Sjdp 81460484Sobrien return (param); 81560484Sobrien} 81660484Sobrien 817130561Sobrienint 81860484Sobrientarget_delete_param(struct target_param *param) 81960484Sobrien{ 82060484Sobrien SLIST_REMOVE(&target_paramlist, param, target_param, tp); 82160484Sobrien free(param); 82260484Sobrien 823130561Sobrien return (0); 82433965Sjdp} 82533965Sjdp 82633965Sjdpstruct target_notify * 827130561Sobrientarget_first_notify(void) 82833965Sjdp{ 82933965Sjdp return (SLIST_FIRST(&target_notifylist)); 83033965Sjdp} 83189857Sobrien 83289857Sobrienstruct target_notify * 83389857Sobrientarget_next_notify(struct target_notify *notify) 83489857Sobrien{ 83589857Sobrien if (notify == NULL) 83633965Sjdp return (NULL); 83733965Sjdp 83833965Sjdp return (SLIST_NEXT(notify, tn)); 83933965Sjdp} 84033965Sjdp 84133965Sjdpstruct target_notify * 84233965Sjdptarget_new_notify(char *nname) 84333965Sjdp{ 84460484Sobrien int cmp; 84560484Sobrien struct target_notify *notify, *temp, *prev; 84660484Sobrien 84760484Sobrien SLIST_FOREACH(notify, &target_notifylist, tn) 84860484Sobrien if (strcmp(nname, notify->name) == 0) 84960484Sobrien return (NULL); 850130561Sobrien 851130561Sobrien if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) 85260484Sobrien return (NULL); 85360484Sobrien 85460484Sobrien memset(notify, 0, sizeof(*notify)); 85560484Sobrien strlcpy(notify->name, nname, sizeof(notify->name)); 85660484Sobrien 85760484Sobrien if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || 85860484Sobrien strcmp(nname, prev->name) < 0) { 85989857Sobrien SLIST_INSERT_HEAD(&target_notifylist, notify, tn); 860104834Sobrien return (notify); 86189857Sobrien } 86289857Sobrien 86360484Sobrien SLIST_FOREACH(temp, &target_notifylist, tn) { 864130561Sobrien if ((cmp = strcmp(nname, temp->name)) <= 0) 86589857Sobrien break; 86660484Sobrien prev = temp; 86760484Sobrien } 86860484Sobrien 86960484Sobrien if (temp == NULL || cmp < 0) 87060484Sobrien SLIST_INSERT_AFTER(prev, notify, tn); 87160484Sobrien else if (cmp > 0) 87289857Sobrien SLIST_INSERT_AFTER(temp, notify, tn); 87389857Sobrien else { 87489857Sobrien syslog(LOG_ERR, "Notification target %s exists", notify->name); 87589857Sobrien free(notify); 87689857Sobrien return (NULL); 87760484Sobrien } 87889857Sobrien 87960484Sobrien return (notify); 88060484Sobrien} 88160484Sobrien 88289857Sobrienint 883104834Sobrientarget_delete_notify(struct target_notify *notify) 88489857Sobrien{ 88560484Sobrien SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); 88689857Sobrien free(notify); 88789857Sobrien 88889857Sobrien return (0); 88989857Sobrien} 89089857Sobrien 89189857Sobrienvoid 89289857Sobrientarget_flush_all(void) 89360484Sobrien{ 89489857Sobrien struct target_address *addrs; 89560484Sobrien struct target_param *param; 89689857Sobrien struct target_notify *notify; 89789857Sobrien 89889857Sobrien while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { 89989857Sobrien SLIST_REMOVE_HEAD(&target_addresslist, ta); 90089857Sobrien if (addrs->status == RowStatus_active) 90160484Sobrien close(addrs->socket); 90289857Sobrien free(addrs); 90360484Sobrien } 904130561Sobrien SLIST_INIT(&target_addresslist); 90589857Sobrien 90689857Sobrien while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { 90789857Sobrien SLIST_REMOVE_HEAD(&target_paramlist, tp); 90889857Sobrien free(param); 90989857Sobrien } 91089857Sobrien SLIST_INIT(&target_paramlist); 91189857Sobrien 91260484Sobrien while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { 91360484Sobrien SLIST_REMOVE_HEAD(&target_notifylist, tn); 91460484Sobrien free(notify); 91560484Sobrien } 91660484Sobrien SLIST_INIT(&target_notifylist); 91760484Sobrien} 91889857Sobrien