trap.c revision 311596
12061Sjkh/* 236622Scharnier * Copyright (c) 2001-2003 32061Sjkh * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 433611Sjb * All rights reserved. 532427Sjb * 632427Sjb * Author: Harti Brandt <harti@freebsd.org> 736111Sjb * 833611Sjb * Copyright (c) 2010 The FreeBSD Foundation 932427Sjb * All rights reserved. 1032427Sjb * 112061Sjkh * Portions of this software were developed by Shteryana Sotirova Shopova 1215603Smarkm * under sponsorship from the FreeBSD Foundation. 1330169Sjkh * 1420710Sasami * Redistribution and use in source and binary forms, with or without 1520710Sasami * modification, are permitted provided that the following conditions 163197Scsgr * are met: 172061Sjkh * 1. Redistributions of source code must retain the above copyright 1812483Speter * notice, this list of conditions and the following disclaimer. 1934509Sbde * 2. Redistributions in binary form must reproduce the above copyright 202160Scsgr * notice, this list of conditions and the following disclaimer in the 212834Swollman * documentation and/or other materials provided with the distribution. 222061Sjkh * 232061Sjkh * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 242160Scsgr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2517308Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2619320Sadam * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 2727788Sasami * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2830169Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2925980Sasami * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 301594Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3117308Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3217308Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3327910Sasami * SUCH DAMAGE. 3427910Sasami * 3527910Sasami * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $ 3617308Speter * 3717308Speter * TrapSinkTable 3817308Speter */ 3919175Sbde#include <sys/types.h> 4019175Sbde#include <sys/queue.h> 4119175Sbde#include <sys/sysctl.h> 4219175Sbde#include <sys/un.h> 4317308Speter#include <stdint.h> 4427910Sasami#include <stdio.h> 4534509Sbde#include <stdlib.h> 4627910Sasami#include <stdarg.h> 4717308Speter#include <stdarg.h> 482061Sjkh#include <string.h> 492061Sjkh#include <ctype.h> 501594Srgrimes#include <syslog.h> 5130169Sjkh#include <unistd.h> 5230169Sjkh#include <netinet/in.h> 5330169Sjkh#include <arpa/inet.h> 5430169Sjkh 5530169Sjkh#include "snmpmod.h" 5630169Sjkh#include "snmpd.h" 5730169Sjkh#include "tree.h" 5830169Sjkh#include "oid.h" 597407Srgrimes 607108Sphkstruct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); 617108Sphk 627108Sphk/* List of target addresses */ 637407Srgrimesstatic struct target_addresslist target_addresslist = 647407Srgrimes SLIST_HEAD_INITIALIZER(target_addresslist); 657407Srgrimes 667108Sphk/* List of target parameters */ 672061Sjkhstatic struct target_paramlist target_paramlist = 682061Sjkh SLIST_HEAD_INITIALIZER(target_paramlist); 692061Sjkh 7017308Speter/* List of notification targets */ 712061Sjkhstatic struct target_notifylist target_notifylist = 722061Sjkh SLIST_HEAD_INITIALIZER(target_notifylist); 732061Sjkh 742061Sjkhstatic const struct asn_oid oid_begemotTrapSinkTable = 752061Sjkh OIDX_begemotTrapSinkTable; 7635427Sbdestatic const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; 7735427Sbdestatic const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID; 7830169Sjkh 792626Scsgrstruct trapsink_dep { 802061Sjkh struct snmp_dependency dep; 812061Sjkh u_int set; 822061Sjkh u_int status; 832061Sjkh u_char comm[SNMP_COMMUNITY_MAXLEN + 1]; 842061Sjkh u_int version; 852061Sjkh u_int rb; 8619320Sadam u_int rb_status; 872061Sjkh u_int rb_version; 882061Sjkh u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1]; 892061Sjkh}; 902061Sjkhenum { 912061Sjkh TDEP_STATUS = 0x0001, 922061Sjkh TDEP_COMM = 0x0002, 932061Sjkh TDEP_VERSION = 0x0004, 942061Sjkh 952061Sjkh TDEP_CREATE = 0x0001, 962061Sjkh TDEP_MODIFY = 0x0002, 972061Sjkh TDEP_DESTROY = 0x0004, 982834Swollman}; 992834Swollman 1002834Swollmanstatic int 1012834Swollmantrapsink_create(struct trapsink_dep *tdep) 1022834Swollman{ 1032834Swollman struct trapsink *t; 1041594Srgrimes struct sockaddr_in sa; 1054486Sphk 1064486Sphk if ((t = malloc(sizeof(*t))) == NULL) 1074486Sphk return (SNMP_ERR_RES_UNAVAIL); 1084486Sphk 1094486Sphk t->index = tdep->dep.idx; 1102061Sjkh t->status = TRAPSINK_NOT_READY; 1112061Sjkh t->comm[0] = '\0'; 11225979Sjkh t->version = TRAPSINK_V2; 11325979Sjkh 11425979Sjkh if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 11525979Sjkh syslog(LOG_ERR, "socket(UDP): %m"); 1162061Sjkh free(t); 11725979Sjkh return (SNMP_ERR_RES_UNAVAIL); 1182061Sjkh } 1192061Sjkh (void)shutdown(t->socket, SHUT_RD); 12017308Speter memset(&sa, 0, sizeof(sa)); 1212061Sjkh sa.sin_len = sizeof(sa); 1222061Sjkh sa.sin_family = AF_INET; 1232061Sjkh sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) | 1242061Sjkh (t->index.subs[1] << 16) | (t->index.subs[2] << 8) | 1252061Sjkh (t->index.subs[3] << 0)); 12612483Speter sa.sin_port = htons(t->index.subs[4]); 12712483Speter 12812483Speter if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 12912483Speter syslog(LOG_ERR, "connect(%s,%u): %m", 1302061Sjkh inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 13135479Sbde (void)close(t->socket); 1328854Srgrimes free(t); 1332061Sjkh return (SNMP_ERR_GENERR); 1342061Sjkh } 13512483Speter 1362061Sjkh if (tdep->set & TDEP_VERSION) 13735479Sbde t->version = tdep->version; 13835479Sbde if (tdep->set & TDEP_COMM) 13935479Sbde strcpy(t->comm, tdep->comm); 14035479Sbde 14135479Sbde if (t->comm[0] != '\0') 14235479Sbde t->status = TRAPSINK_NOT_IN_SERVICE; 14335479Sbde 14435479Sbde /* look whether we should activate */ 14535479Sbde if (tdep->status == 4) { 14635462Sjkh if (t->status == TRAPSINK_NOT_READY) { 14735462Sjkh if (t->socket != -1) 14818714Sache (void)close(t->socket); 14917308Speter free(t); 15034541Sbde return (SNMP_ERR_INCONS_VALUE); 15134575Sbde } 15234575Sbde t->status = TRAPSINK_ACTIVE; 15334575Sbde } 15434592Sbde 15517308Speter INSERT_OBJECT_OID(t, &trapsink_list); 15634575Sbde 15735427Sbde tdep->rb |= TDEP_CREATE; 15834575Sbde 15935427Sbde return (SNMP_ERR_NOERROR); 16034575Sbde} 16115603Smarkm 16217308Speterstatic void 16317308Spetertrapsink_free(struct trapsink *t) 16417308Speter{ 16517308Speter TAILQ_REMOVE(&trapsink_list, t, link); 16617308Speter if (t->socket != -1) 16717308Speter (void)close(t->socket); 16817308Speter free(t); 16917308Speter} 17017308Speter 17118362Sjkhstatic int 17219966Sachetrapsink_modify(struct trapsink *t, struct trapsink_dep *tdep) 17318362Sjkh{ 17417308Speter tdep->rb_status = t->status; 17527910Sasami tdep->rb_version = t->version; 17617308Speter strcpy(tdep->rb_comm, t->comm); 17717308Speter 17817308Speter if (tdep->set & TDEP_STATUS) { 17936074Sbde /* if we are active and should move to not_in_service do 18027910Sasami * this first */ 18136074Sbde if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) { 18236074Sbde t->status = TRAPSINK_NOT_IN_SERVICE; 18327910Sasami tdep->rb |= TDEP_MODIFY; 18417308Speter } 1852061Sjkh } 18627910Sasami 1872061Sjkh if (tdep->set & TDEP_VERSION) 18836074Sbde t->version = tdep->version; 18927910Sasami if (tdep->set & TDEP_COMM) 1902061Sjkh strcpy(t->comm, tdep->comm); 19117308Speter 19227910Sasami if (tdep->set & TDEP_STATUS) { 19317308Speter /* if we were inactive and should go active - do this now */ 19427910Sasami if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) { 19527910Sasami if (t->comm[0] == '\0') { 19627910Sasami t->status = tdep->rb_status; 19717308Speter t->version = tdep->rb_version; 19827910Sasami strcpy(t->comm, tdep->rb_comm); 19917308Speter return (SNMP_ERR_INCONS_VALUE); 20027910Sasami } 20127910Sasami t->status = TRAPSINK_ACTIVE; 20227910Sasami tdep->rb |= TDEP_MODIFY; 20327910Sasami } 20436622Scharnier } 20536622Scharnier return (SNMP_ERR_NOERROR); 20627910Sasami} 20727910Sasami 20827910Sasamistatic int 20927910Sasamitrapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep) 21027910Sasami{ 21127910Sasami if (tdep->set & TDEP_STATUS) 21234509Sbde t->status = tdep->rb_status; 21327910Sasami if (tdep->set & TDEP_VERSION) 21427910Sasami t->version = tdep->rb_version; 21527910Sasami if (tdep->set & TDEP_COMM) 21636423Speter strcpy(t->comm, tdep->rb_comm); 21736423Speter 21827910Sasami return (SNMP_ERR_NOERROR); 21936423Speter} 22035479Sbde 22127910Sasamistatic int 22227910Sasamitrapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t, 22334688Sbde struct trapsink_dep *tdep) 22434688Sbde{ 22527910Sasami t->status = TRAPSINK_DESTROY; 22635427Sbde tdep->rb_status = t->status; 22727910Sasami tdep->rb |= TDEP_DESTROY; 22835427Sbde return (SNMP_ERR_NOERROR); 22927910Sasami} 23035427Sbde 23127910Sasamistatic int 23227910Sasamitrapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep) 23327910Sasami{ 23427910Sasami t->status = tdep->rb_status; 23527910Sasami return (SNMP_ERR_NOERROR); 23627910Sasami} 23727910Sasami 23827910Sasamistatic int 23927910Sasamitrapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep, 24017308Speter enum snmp_depop op) 24117308Speter{ 24227910Sasami struct trapsink_dep *tdep = (struct trapsink_dep *)dep; 24317308Speter struct trapsink *t; 24427910Sasami 24527910Sasami t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0); 24627910Sasami 24727910Sasami switch (op) { 24833133Sadam 24917466Speter case SNMP_DEPOP_COMMIT: 25017308Speter if (tdep->set & TDEP_STATUS) { 25127910Sasami switch (tdep->status) { 25217308Speter 25334688Sbde case 1: 25434688Sbde case 2: 25536074Sbde if (t == NULL) 25636074Sbde return (SNMP_ERR_INCONS_VALUE); 25736074Sbde return (trapsink_modify(t, tdep)); 25836074Sbde 25934688Sbde case 4: 26034688Sbde case 5: 26133133Sadam if (t != NULL) 26217308Speter return (SNMP_ERR_INCONS_VALUE); 26317308Speter return (trapsink_create(tdep)); 26427910Sasami 26517308Speter case 6: 26636074Sbde if (t == NULL) 26727910Sasami return (SNMP_ERR_NOERROR); 26817308Speter return (trapsink_destroy(ctx, t, tdep)); 26917308Speter } 27027910Sasami } else if (tdep->set != 0) 27117308Speter return (trapsink_modify(t, tdep)); 27236074Sbde 27327910Sasami return (SNMP_ERR_NOERROR); 27427910Sasami 27517308Speter case SNMP_DEPOP_ROLLBACK: 27617308Speter if (tdep->rb & TDEP_CREATE) { 27727910Sasami trapsink_free(t); 27817308Speter return (SNMP_ERR_NOERROR); 27936074Sbde } 28027910Sasami if (tdep->rb & TDEP_MODIFY) 28133133Sadam return (trapsink_unmodify(t, tdep)); 28217308Speter if(tdep->rb & TDEP_DESTROY) 28317308Speter return (trapsink_undestroy(t, tdep)); 28427910Sasami return (SNMP_ERR_NOERROR); 28517308Speter 28636074Sbde case SNMP_DEPOP_FINISH: 28717308Speter if ((tdep->rb & TDEP_DESTROY) && t != NULL && 28817308Speter ctx->code == SNMP_RET_OK) 28927910Sasami trapsink_free(t); 29017308Speter return (SNMP_ERR_NOERROR); 29136074Sbde } 29233133Sadam abort(); 29317308Speter} 29417308Speter 29534509Sbdeint 29617308Speterop_trapsink(struct snmp_context *ctx, struct snmp_value *value, 29736429Speter u_int sub, u_int iidx, enum snmp_op op) 29835851Sjb{ 29935851Sjb struct trapsink *t; 30035851Sjb u_char ipa[4]; 30135851Sjb int32_t port; 30236074Sbde struct asn_oid idx; 30333133Sadam struct trapsink_dep *tdep; 30417962Speter u_char *p; 30517962Speter 30635851Sjb t = NULL; /* gcc */ 30717962Speter 30836074Sbde switch (op) { 30933133Sadam 31033133Sadam case SNMP_OP_GETNEXT: 31117962Speter if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) 31217962Speter return (SNMP_ERR_NOSUCHNAME); 31327910Sasami index_append(&value->var, sub, &t->index); 31417962Speter break; 31536074Sbde 31633133Sadam case SNMP_OP_GET: 31735479Sbde if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) 31817308Speter return (SNMP_ERR_NOSUCHNAME); 31917308Speter break; 32027910Sasami 32117308Speter case SNMP_OP_SET: 32236074Sbde if (index_decode(&value->var, sub, iidx, ipa, &port) || 32335479Sbde port == 0 || port > 65535) 32417308Speter return (SNMP_ERR_NO_CREATION); 32517308Speter t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub); 32635427Sbde 32735427Sbde asn_slice_oid(&idx, &value->var, sub, value->var.len); 32836074Sbde 32935427Sbde tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx, 33035427Sbde &oid_begemotTrapSinkTable, &idx, 33127910Sasami sizeof(*tdep), trapsink_dep); 33217962Speter if (tdep == NULL) 33336074Sbde return (SNMP_ERR_RES_UNAVAIL); 3342061Sjkh 33517308Speter switch (value->var.subs[sub - 1]) { 33627910Sasami 33727910Sasami case LEAF_begemotTrapSinkStatus: 33827910Sasami if (tdep->set & TDEP_STATUS) 33927910Sasami return (SNMP_ERR_INCONS_VALUE); 34027910Sasami switch (value->v.integer) { 34136074Sbde 34227910Sasami case 1: 34327910Sasami case 2: 34417308Speter if (t == NULL) 34517308Speter return (SNMP_ERR_INCONS_VALUE); 34617308Speter break; 34717308Speter 34817308Speter case 4: 34917308Speter case 5: 35017308Speter if (t != NULL) 35112483Speter return (SNMP_ERR_INCONS_VALUE); 35217308Speter break; 35312483Speter 35436074Sbde case 6: 35512483Speter break; 3562061Sjkh 35717962Speter default: 35817962Speter return (SNMP_ERR_WRONG_VALUE); 35936074Sbde } 36017962Speter tdep->status = value->v.integer; 36117962Speter tdep->set |= TDEP_STATUS; 36233595Snate return (SNMP_ERR_NOERROR); 36333595Snate 36436074Sbde case LEAF_begemotTrapSinkComm: 36533595Snate if (tdep->set & TDEP_COMM) 36633595Snate return (SNMP_ERR_INCONS_VALUE); 36717962Speter if (value->v.octetstring.len == 0 || 36817962Speter value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN) 36936074Sbde return (SNMP_ERR_WRONG_VALUE); 3702061Sjkh for (p = value->v.octetstring.octets; 37117308Speter p < value->v.octetstring.octets + value->v.octetstring.len; 37217308Speter p++) { 37317308Speter if (!isascii(*p) || !isprint(*p)) 37417308Speter return (SNMP_ERR_WRONG_VALUE); 37517308Speter } 37617308Speter tdep->set |= TDEP_COMM; 3772302Spaul strncpy(tdep->comm, value->v.octetstring.octets, 3782302Spaul value->v.octetstring.len); 3792302Spaul tdep->comm[value->v.octetstring.len] = '\0'; 38035462Sjkh return (SNMP_ERR_NOERROR); 3812302Spaul 38218714Sache case LEAF_begemotTrapSinkVersion: 38310760Sache if (tdep->set & TDEP_VERSION) 38418714Sache return (SNMP_ERR_INCONS_VALUE); 3852302Spaul if (value->v.integer != TRAPSINK_V1 && 38610760Sache value->v.integer != TRAPSINK_V2) 38718714Sache return (SNMP_ERR_WRONG_VALUE); 38810760Sache tdep->version = value->v.integer; 38910760Sache tdep->set |= TDEP_VERSION; 3902302Spaul return (SNMP_ERR_NOERROR); 3912302Spaul } 3922302Spaul if (t == NULL) 3932302Spaul return (SNMP_ERR_INCONS_NAME); 39436074Sbde else 3952302Spaul return (SNMP_ERR_NOT_WRITEABLE); 3962302Spaul 39717308Speter 39817308Speter case SNMP_OP_ROLLBACK: 39917308Speter case SNMP_OP_COMMIT: 40017308Speter return (SNMP_ERR_NOERROR); 40117308Speter } 40217308Speter 4032061Sjkh switch (value->var.subs[sub - 1]) { 40417308Speter 4052061Sjkh case LEAF_begemotTrapSinkStatus: 40636074Sbde value->v.integer = t->status; 40736074Sbde break; 40836074Sbde 40936074Sbde case LEAF_begemotTrapSinkComm: 41036074Sbde return (string_get(value, t->comm, -1)); 41136074Sbde 41236074Sbde case LEAF_begemotTrapSinkVersion: 41336074Sbde value->v.integer = t->version; 41430169Sjkh break; 41536074Sbde 41617308Speter } 41717308Speter return (SNMP_ERR_NOERROR); 41836074Sbde} 41917308Speter 4202061Sjkhstatic void 42117308Spetersnmp_create_v1_trap(struct snmp_pdu *pdu, char *com, 42217308Speter const struct asn_oid *trap_oid) 42317308Speter{ 42417308Speter memset(pdu, 0, sizeof(*pdu)); 42517308Speter strlcpy(pdu->community, com, sizeof(pdu->community)); 42617308Speter 4273626Swollman pdu->version = SNMP_V1; 4283626Swollman pdu->type = SNMP_PDU_TRAP; 4293626Swollman pdu->enterprise = systemg.object_id; 4303626Swollman memcpy(pdu->agent_addr, snmpd.trap1addr, 4); 43136074Sbde pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; 43236074Sbde pdu->specific_trap = 0; 43336074Sbde pdu->time_stamp = get_ticks() - start_tick; 43436074Sbde pdu->nbindings = 0; 43536074Sbde} 43636074Sbde 43736074Sbdestatic void 43836074Sbdesnmp_create_v2_trap(struct snmp_pdu *pdu, char *com, 43930169Sjkh const struct asn_oid *trap_oid) 44036074Sbde{ 4413626Swollman memset(pdu, 0, sizeof(*pdu)); 4423626Swollman strlcpy(pdu->community, com, sizeof(pdu->community)); 44336074Sbde 4443626Swollman pdu->version = SNMP_V2c; 4453626Swollman pdu->type = SNMP_PDU_TRAP2; 44617308Speter pdu->request_id = reqid_next(trap_reqid); 44717308Speter pdu->error_index = 0; 44817308Speter pdu->error_status = SNMP_ERR_NOERROR; 44917308Speter 45017308Speter pdu->bindings[0].var = oid_sysUpTime; 45117308Speter pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 45217308Speter pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 45317308Speter pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 45417308Speter 45517308Speter pdu->bindings[1].var = oid_snmpTrapOID; 4563626Swollman pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 45717308Speter pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 45817308Speter pdu->bindings[1].v.oid = *trap_oid; 45917308Speter 46017308Speter pdu->nbindings = 2; 46136074Sbde} 46217308Speter 46317308Speterstatic void 46417308Spetersnmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target, 46517308Speter const struct asn_oid *trap_oid) 46617308Speter{ 46717308Speter struct usm_user *usmuser; 46817308Speter 46927910Sasami memset(pdu, 0, sizeof(*pdu)); 47027910Sasami 47127910Sasami pdu->version = SNMP_V3; 47236074Sbde pdu->type = SNMP_PDU_TRAP2; 47336442Speter pdu->request_id = reqid_next(trap_reqid); 47436442Speter pdu->error_index = 0; 47536442Speter pdu->error_status = SNMP_ERR_NOERROR; 47636442Speter 47736442Speter pdu->bindings[0].var = oid_sysUpTime; 47836429Speter pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 47936429Speter pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 48036429Speter pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 48136429Speter 48236429Speter pdu->bindings[1].var = oid_snmpTrapOID; 48336429Speter pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 48427910Sasami pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 48536074Sbde pdu->bindings[1].v.oid = *trap_oid; 48636074Sbde 48730113Sjkh pdu->nbindings = 2; 48836074Sbde 48936074Sbde update_snmpd_engine_time(); 49030113Sjkh 49136074Sbde memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 49236074Sbde snmpd_engine.engine_len); 49336074Sbde pdu->engine.engine_len = snmpd_engine.engine_len; 49430113Sjkh pdu->engine.engine_boots = snmpd_engine.engine_boots; 49536429Speter pdu->engine.engine_time = snmpd_engine.engine_time; 49636429Speter pdu->engine.max_msg_size = snmpd_engine.max_msg_size; 49736429Speter strlcpy(pdu->user.sec_name, target->secname, 49829938Smckay sizeof(pdu->user.sec_name)); 49936074Sbde pdu->security_model = target->sec_model; 50029938Smckay 50117308Speter pdu->context_engine_len = snmpd_engine.engine_len; 50217308Speter memcpy(pdu->context_engine, snmpd_engine.engine_id, 50317308Speter snmpd_engine.engine_len); 50417308Speter 50517308Speter if (target->sec_model == SNMP_SECMODEL_USM && 50627910Sasami target->sec_level != SNMP_noAuthNoPriv) { 50727910Sasami usmuser = usm_find_user(pdu->engine.engine_id, 50827910Sasami pdu->engine.engine_len, pdu->user.sec_name); 50917308Speter if (usmuser != NULL) { 51017308Speter pdu->user.auth_proto = usmuser->suser.auth_proto; 51134520Sbde pdu->user.priv_proto = usmuser->suser.priv_proto; 51236074Sbde memcpy(pdu->user.auth_key, usmuser->suser.auth_key, 51336074Sbde sizeof(pdu->user.auth_key)); 51436074Sbde memcpy(pdu->user.priv_key, usmuser->suser.priv_key, 51530113Sjkh sizeof(pdu->user.priv_key)); 51634520Sbde } 51717308Speter snmp_pdu_init_secparams(pdu); 51817308Speter } 51917308Speter} 52017308Speter 52114119Spetervoid 5222061Sjkhsnmp_send_trap(const struct asn_oid *trap_oid, ...) 5237130Srgrimes{ 5247130Srgrimes struct snmp_pdu pdu; 5257130Srgrimes struct trapsink *t; 5262061Sjkh const struct snmp_value *v; 52736074Sbde struct target_notify *n; 52836074Sbde struct target_address *ta; 52936074Sbde struct target_param *tp; 53036074Sbde 53136074Sbde va_list ap; 53236074Sbde u_char *sndbuf; 53336074Sbde char *tag; 53436074Sbde size_t sndlen; 53536074Sbde ssize_t len; 53636074Sbde int32_t ip; 53730169Sjkh 53836074Sbde TAILQ_FOREACH(t, &trapsink_list, link) { 5393197Scsgr if (t->status != TRAPSINK_ACTIVE) 54030169Sjkh continue; 54136074Sbde 54236074Sbde if (t->version == TRAPSINK_V1) 54336074Sbde snmp_create_v1_trap(&pdu, t->comm, trap_oid); 54436074Sbde else 54536074Sbde snmp_create_v2_trap(&pdu, t->comm, trap_oid); 54636074Sbde 54730169Sjkh va_start(ap, trap_oid); 54836074Sbde while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 54930169Sjkh pdu.bindings[pdu.nbindings++] = *v; 55032427Sjb va_end(ap); 55136074Sbde 55232427Sjb if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 55336074Sbde syslog(LOG_DEBUG, "send trap to %s failed: no access", 55436074Sbde t->comm); 55536074Sbde continue; 55636074Sbde } 55736074Sbde 55836074Sbde if ((sndbuf = buf_alloc(1)) == NULL) { 55936074Sbde syslog(LOG_ERR, "trap send buffer: %m"); 56036074Sbde return; 56136074Sbde } 56236074Sbde 5637281Srgrimes snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 56436074Sbde 5653242Spaul if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) 56636074Sbde syslog(LOG_ERR, "send: %m"); 56736074Sbde else if ((size_t)len != sndlen) 56836074Sbde syslog(LOG_ERR, "send: short write %zu/%zu", 56936074Sbde sndlen, (size_t)len); 57030169Sjkh 57130169Sjkh free(sndbuf); 57236074Sbde } 57330169Sjkh 57436074Sbde SLIST_FOREACH(n, &target_notifylist, tn) { 57536074Sbde if (n->status != RowStatus_active || n->taglist[0] == '\0') 57636074Sbde continue; 57736074Sbde 57836074Sbde SLIST_FOREACH(ta, &target_addresslist, ta) 57936074Sbde if ((tag = strstr(ta->taglist, n->taglist)) != NULL && 58036074Sbde (tag[strlen(n->taglist)] == ' ' || 58136074Sbde tag[strlen(n->taglist)] == '\0' || 58236074Sbde tag[strlen(n->taglist)] == '\t' || 5832061Sjkh tag[strlen(n->taglist)] == '\r' || 58417308Speter tag[strlen(n->taglist)] == '\n') && 58517308Speter ta->status == RowStatus_active) 58617308Speter break; 58727910Sasami if (ta == NULL) 58827910Sasami continue; 58936573Speter 5905366Snate SLIST_FOREACH(tp, &target_paramlist, tp) 59127910Sasami if (strcmp(tp->name, ta->paramname) == 0 && 59227910Sasami tp->status == 1) 59327910Sasami break; 59427910Sasami if (tp == NULL) 59527910Sasami continue; 59627910Sasami 59727910Sasami switch (tp->mpmodel) { 59827910Sasami case SNMP_MPM_SNMP_V1: 59927910Sasami snmp_create_v1_trap(&pdu, tp->secname, trap_oid); 60027910Sasami break; 60127910Sasami 60227910Sasami case SNMP_MPM_SNMP_V2c: 60336374Ssos snmp_create_v2_trap(&pdu, tp->secname, trap_oid); 60436374Ssos break; 60536374Ssos 60636419Speter case SNMP_MPM_SNMP_V3: 60736585Speter snmp_create_v3_trap(&pdu, tp, trap_oid); 60836419Speter break; 60936074Sbde 61036074Sbde default: 61136074Sbde continue; 61234575Sbde } 61327910Sasami 6145366Snate va_start(ap, trap_oid); 61517308Speter while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 61635427Sbde pdu.bindings[pdu.nbindings++] = *v; 61717308Speter va_end(ap); 61835427Sbde 61935427Sbde if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 62035427Sbde syslog(LOG_DEBUG, "send trap to %s failed: no access", 62135427Sbde t->comm); 62235427Sbde continue; 62335427Sbde } 62435427Sbde 62535427Sbde if ((sndbuf = buf_alloc(1)) == NULL) { 62635427Sbde syslog(LOG_ERR, "trap send buffer: %m"); 62735427Sbde return; 62835427Sbde } 62935427Sbde 63035427Sbde snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 63135427Sbde 63235427Sbde if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) 63334541Sbde syslog(LOG_ERR, "send: %m"); 63435427Sbde else if ((size_t)len != sndlen) 63524754Sjdp syslog(LOG_ERR, "send: short write %zu/%zu", 63634541Sbde sndlen, (size_t)len); 63736444Speter 63836444Speter free(sndbuf); 63936470Sjhay } 64036444Speter} 64136444Speter 64235427Sbde/* 64335427Sbde * RFC 3413 SNMP Management Target MIB 64435427Sbde */ 64534541Sbdestruct snmpd_target_stats * 64635427Sbdebsnmpd_get_target_stats(void) 64734541Sbde{ 64835427Sbde return (&snmpd_target_stats); 6498295Srgrimes} 65034541Sbde 65134541Sbdestruct target_address * 65235427Sbdetarget_first_address(void) 65335427Sbde{ 65434541Sbde return (SLIST_FIRST(&target_addresslist)); 65535427Sbde} 65635427Sbde 65735427Sbdestruct target_address * 65835427Sbdetarget_next_address(struct target_address *addrs) 65935427Sbde{ 66034541Sbde if (addrs == NULL) 66135427Sbde return (NULL); 66235427Sbde 66335427Sbde return (SLIST_NEXT(addrs, ta)); 66435427Sbde} 66534541Sbde 66635427Sbdestruct target_address * 66735427Sbdetarget_new_address(char *aname) 66836397Ssos{ 66936444Speter int cmp; 67035427Sbde struct target_address *addrs, *temp, *prev; 67134541Sbde 67236074Sbde SLIST_FOREACH(addrs, &target_addresslist, ta) 67336074Sbde if (strcmp(aname, addrs->name) == 0) 67436074Sbde return (NULL); 67530113Sjkh 6768489Srgrimes if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) 67734541Sbde return (NULL); 67835427Sbde 67935427Sbde memset(addrs, 0, sizeof(*addrs)); 68035427Sbde strlcpy(addrs->name, aname, sizeof(addrs->name)); 68135427Sbde addrs->timeout = 150; 68235427Sbde addrs->retry = 3; /* XXX */ 68335427Sbde 68435427Sbde if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || 68535427Sbde strcmp(aname, prev->name) < 0) { 68635427Sbde SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); 68735427Sbde return (addrs); 68835427Sbde } 68935427Sbde 69035427Sbde SLIST_FOREACH(temp, &target_addresslist, ta) { 69136074Sbde if ((cmp = strcmp(aname, temp->name)) <= 0) 69235427Sbde break; 69335427Sbde prev = temp; 69434541Sbde } 69536074Sbde 6962160Scsgr if (temp == NULL || cmp < 0) 69734541Sbde SLIST_INSERT_AFTER(prev, addrs, ta); 69834541Sbde else if (cmp > 0) 69936074Sbde SLIST_INSERT_AFTER(temp, addrs, ta); 7002626Scsgr else { 7012061Sjkh syslog(LOG_ERR, "Target address %s exists", addrs->name); 70236589Sjhay free(addrs); 70336589Sjhay return (NULL); 70436589Sjhay } 70536589Sjhay 70636589Sjhay return (addrs); 70736589Sjhay} 70836589Sjhay 70917308Speterint 71017308Spetertarget_activate_address(struct target_address *addrs) 71117308Speter{ 71227910Sasami struct sockaddr_in sa; 71327910Sasami 71427910Sasami if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 71527910Sasami syslog(LOG_ERR, "socket(UDP): %m"); 71627910Sasami return (SNMP_ERR_RES_UNAVAIL); 71727910Sasami } 71817308Speter 71911806Sphk (void)shutdown(addrs->socket, SHUT_RD); 72019175Sbde memset(&sa, 0, sizeof(sa)); 72127910Sasami sa.sin_len = sizeof(sa); 72227910Sasami sa.sin_family = AF_INET; 72327910Sasami 72427910Sasami sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | 72527910Sasami (addrs->address[1] << 16) | (addrs->address[2] << 8) | 72627910Sasami (addrs->address[3] << 0)); 72727910Sasami sa.sin_port = htons(addrs->address[4]) << 8 | 72827910Sasami htons(addrs->address[5]) << 0; 72927910Sasami 73027910Sasami if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 73127910Sasami syslog(LOG_ERR, "connect(%s,%u): %m", 73227910Sasami inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 73327910Sasami (void)close(addrs->socket); 73427910Sasami return (SNMP_ERR_GENERR); 73527910Sasami } 73627910Sasami 73727910Sasami addrs->status = RowStatus_active; 73827910Sasami 73927910Sasami return (SNMP_ERR_NOERROR); 74027910Sasami} 74135621Sbde 74236589Sjhayint 74327910Sasamitarget_delete_address(struct target_address *addrs) 74434509Sbde{ 74527910Sasami SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); 74627910Sasami if (addrs->status == RowStatus_active) 74727910Sasami close(addrs->socket); 74827910Sasami free(addrs); 74927910Sasami 75027910Sasami return (0); 75127910Sasami} 75227910Sasami 75327910Sasamistruct target_param * 75427910Sasamitarget_first_param(void) 75536454Sjkh{ 75627910Sasami return (SLIST_FIRST(&target_paramlist)); 75727910Sasami} 75827910Sasami 75927910Sasamistruct target_param * 76027910Sasamitarget_next_param(struct target_param *param) 76127910Sasami{ 76227910Sasami if (param == NULL) 76327910Sasami return (NULL); 76419175Sbde 76527910Sasami return (SLIST_NEXT(param, tp)); 76627910Sasami} 76727910Sasami 76827910Sasamistruct target_param * 76927910Sasamitarget_new_param(char *pname) 77027910Sasami{ 77127910Sasami int cmp; 77227910Sasami struct target_param *param, *temp, *prev; 77334688Sbde 77427910Sasami SLIST_FOREACH(param, &target_paramlist, tp) 77527910Sasami if (strcmp(pname, param->name) == 0) 77627910Sasami return (NULL); 77736455Sjkh 77836455Sjkh if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) 77936074Sbde return (NULL); 78036074Sbde 78130113Sjkh memset(param, 0, sizeof(*param)); 78219175Sbde strlcpy(param->name, pname, sizeof(param->name)); 7832061Sjkh 78435479Sbde if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || 78530113Sjkh strcmp(pname, prev->name) < 0) { 78630113Sjkh SLIST_INSERT_HEAD(&target_paramlist, param, tp); 78735294Sdt return (param); 78830113Sjkh } 78930113Sjkh 79030113Sjkh SLIST_FOREACH(temp, &target_paramlist, tp) { 79130113Sjkh if ((cmp = strcmp(pname, temp->name)) <= 0) 79230113Sjkh break; 79330113Sjkh prev = temp; 79430113Sjkh } 79530113Sjkh 79630113Sjkh if (temp == NULL || cmp < 0) 79730113Sjkh SLIST_INSERT_AFTER(prev, param, tp); 79830113Sjkh else if (cmp > 0) 79930113Sjkh SLIST_INSERT_AFTER(temp, param, tp); 80030113Sjkh else { 80132427Sjb syslog(LOG_ERR, "Target parameter %s exists", param->name); 80232427Sjb free(param); 8031594Srgrimes return (NULL); 804 } 805 806 return (param); 807} 808 809int 810target_delete_param(struct target_param *param) 811{ 812 SLIST_REMOVE(&target_paramlist, param, target_param, tp); 813 free(param); 814 815 return (0); 816} 817 818struct target_notify * 819target_first_notify(void) 820{ 821 return (SLIST_FIRST(&target_notifylist)); 822} 823 824struct target_notify * 825target_next_notify(struct target_notify *notify) 826{ 827 if (notify == NULL) 828 return (NULL); 829 830 return (SLIST_NEXT(notify, tn)); 831} 832 833struct target_notify * 834target_new_notify(char *nname) 835{ 836 int cmp; 837 struct target_notify *notify, *temp, *prev; 838 839 SLIST_FOREACH(notify, &target_notifylist, tn) 840 if (strcmp(nname, notify->name) == 0) 841 return (NULL); 842 843 if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) 844 return (NULL); 845 846 memset(notify, 0, sizeof(*notify)); 847 strlcpy(notify->name, nname, sizeof(notify->name)); 848 849 if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || 850 strcmp(nname, prev->name) < 0) { 851 SLIST_INSERT_HEAD(&target_notifylist, notify, tn); 852 return (notify); 853 } 854 855 SLIST_FOREACH(temp, &target_notifylist, tn) { 856 if ((cmp = strcmp(nname, temp->name)) <= 0) 857 break; 858 prev = temp; 859 } 860 861 if (temp == NULL || cmp < 0) 862 SLIST_INSERT_AFTER(prev, notify, tn); 863 else if (cmp > 0) 864 SLIST_INSERT_AFTER(temp, notify, tn); 865 else { 866 syslog(LOG_ERR, "Notification target %s exists", notify->name); 867 free(notify); 868 return (NULL); 869 } 870 871 return (notify); 872} 873 874int 875target_delete_notify(struct target_notify *notify) 876{ 877 SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); 878 free(notify); 879 880 return (0); 881} 882 883void 884target_flush_all(void) 885{ 886 struct target_address *addrs; 887 struct target_param *param; 888 struct target_notify *notify; 889 890 while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { 891 SLIST_REMOVE_HEAD(&target_addresslist, ta); 892 if (addrs->status == RowStatus_active) 893 close(addrs->socket); 894 free(addrs); 895 } 896 SLIST_INIT(&target_addresslist); 897 898 while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { 899 SLIST_REMOVE_HEAD(&target_paramlist, tp); 900 free(param); 901 } 902 SLIST_INIT(&target_paramlist); 903 904 while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { 905 SLIST_REMOVE_HEAD(&target_notifylist, tn); 906 free(notify); 907 } 908 SLIST_INIT(&target_notifylist); 909} 910