1122394Sharti/* 2122394Sharti * Copyright (c) 2001-2003 3122394Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122394Sharti * All rights reserved. 5122394Sharti * 6122394Sharti * Author: Harti Brandt <harti@freebsd.org> 7216594Ssyrinx * 8216594Ssyrinx * Copyright (c) 2010 The FreeBSD Foundation 9216594Ssyrinx * All rights reserved. 10216594Ssyrinx * 11216594Ssyrinx * Portions of this software were developed by Shteryana Sotirova Shopova 12216594Ssyrinx * under sponsorship from the FreeBSD Foundation. 13216594Ssyrinx * 14133211Sharti * Redistribution and use in source and binary forms, with or without 15133211Sharti * modification, are permitted provided that the following conditions 16133211Sharti * are met: 17133211Sharti * 1. Redistributions of source code must retain the above copyright 18133211Sharti * notice, this list of conditions and the following disclaimer. 19122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 20122394Sharti * notice, this list of conditions and the following disclaimer in the 21122394Sharti * documentation and/or other materials provided with the distribution. 22133211Sharti * 23133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33133211Sharti * SUCH DAMAGE. 34122394Sharti * 35150920Sharti * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $ 36122394Sharti * 37122394Sharti * TrapSinkTable 38122394Sharti */ 39122394Sharti#include <sys/types.h> 40216294Ssyrinx#include <sys/queue.h> 41122394Sharti#include <sys/sysctl.h> 42122394Sharti#include <sys/un.h> 43216594Ssyrinx#include <stdint.h> 44122394Sharti#include <stdio.h> 45122394Sharti#include <stdlib.h> 46122394Sharti#include <stdarg.h> 47122394Sharti#include <stdarg.h> 48122394Sharti#include <string.h> 49122394Sharti#include <ctype.h> 50122394Sharti#include <syslog.h> 51122394Sharti#include <unistd.h> 52122394Sharti#include <netinet/in.h> 53122394Sharti#include <arpa/inet.h> 54122394Sharti 55122394Sharti#include "snmpmod.h" 56122394Sharti#include "snmpd.h" 57122394Sharti#include "tree.h" 58122394Sharti#include "oid.h" 59122394Sharti 60122394Shartistruct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); 61122394Sharti 62216594Ssyrinx/* List of target addresses */ 63216594Ssyrinxstruct target_addresslist target_addresslist = 64216594Ssyrinx SLIST_HEAD_INITIALIZER(target_addresslist); 65216594Ssyrinx 66216594Ssyrinx/* List of target parameters */ 67216594Ssyrinxstruct target_paramlist target_paramlist = 68216594Ssyrinx SLIST_HEAD_INITIALIZER(target_paramlist); 69216594Ssyrinx 70216594Ssyrinx/* List of notification targets */ 71216594Ssyrinxstruct target_notifylist target_notifylist = 72216594Ssyrinx SLIST_HEAD_INITIALIZER(target_notifylist); 73216594Ssyrinx 74122394Shartistatic const struct asn_oid oid_begemotTrapSinkTable = 75122394Sharti OIDX_begemotTrapSinkTable; 76122394Shartistatic const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; 77122394Shartistatic const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID; 78122394Sharti 79122394Shartistruct trapsink_dep { 80122394Sharti struct snmp_dependency dep; 81122394Sharti u_int set; 82122394Sharti u_int status; 83122394Sharti u_char comm[SNMP_COMMUNITY_MAXLEN + 1]; 84122394Sharti u_int version; 85122394Sharti u_int rb; 86122394Sharti u_int rb_status; 87122394Sharti u_int rb_version; 88122394Sharti u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1]; 89122394Sharti}; 90122394Shartienum { 91122394Sharti TDEP_STATUS = 0x0001, 92122394Sharti TDEP_COMM = 0x0002, 93122394Sharti TDEP_VERSION = 0x0004, 94122394Sharti 95122394Sharti TDEP_CREATE = 0x0001, 96122394Sharti TDEP_MODIFY = 0x0002, 97122394Sharti TDEP_DESTROY = 0x0004, 98122394Sharti}; 99122394Sharti 100122394Shartistatic int 101122394Shartitrapsink_create(struct trapsink_dep *tdep) 102122394Sharti{ 103122394Sharti struct trapsink *t; 104122394Sharti struct sockaddr_in sa; 105122394Sharti 106122394Sharti if ((t = malloc(sizeof(*t))) == NULL) 107122394Sharti return (SNMP_ERR_RES_UNAVAIL); 108122394Sharti 109122394Sharti t->index = tdep->dep.idx; 110122394Sharti t->status = TRAPSINK_NOT_READY; 111122394Sharti t->comm[0] = '\0'; 112122394Sharti t->version = TRAPSINK_V2; 113122394Sharti 114122394Sharti if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 115122394Sharti syslog(LOG_ERR, "socket(UDP): %m"); 116122394Sharti free(t); 117122394Sharti return (SNMP_ERR_RES_UNAVAIL); 118122394Sharti } 119122394Sharti (void)shutdown(t->socket, SHUT_RD); 120122394Sharti 121122394Sharti sa.sin_len = sizeof(sa); 122122394Sharti sa.sin_family = AF_INET; 123122394Sharti sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) | 124122394Sharti (t->index.subs[1] << 16) | (t->index.subs[2] << 8) | 125122394Sharti (t->index.subs[3] << 0)); 126122394Sharti sa.sin_port = htons(t->index.subs[4]); 127122394Sharti 128122394Sharti if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 129122394Sharti syslog(LOG_ERR, "connect(%s,%u): %m", 130150920Sharti inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 131122394Sharti (void)close(t->socket); 132122394Sharti free(t); 133122394Sharti return (SNMP_ERR_GENERR); 134122394Sharti } 135122394Sharti 136122394Sharti if (tdep->set & TDEP_VERSION) 137122394Sharti t->version = tdep->version; 138122394Sharti if (tdep->set & TDEP_COMM) 139122394Sharti strcpy(t->comm, tdep->comm); 140122394Sharti 141122394Sharti if (t->comm[0] != '\0') 142122394Sharti t->status = TRAPSINK_NOT_IN_SERVICE; 143122394Sharti 144122394Sharti /* look whether we should activate */ 145122394Sharti if (tdep->status == 4) { 146122394Sharti if (t->status == TRAPSINK_NOT_READY) { 147122394Sharti if (t->socket != -1) 148122394Sharti (void)close(t->socket); 149122394Sharti free(t); 150122394Sharti return (SNMP_ERR_INCONS_VALUE); 151122394Sharti } 152122394Sharti t->status = TRAPSINK_ACTIVE; 153122394Sharti } 154122394Sharti 155122394Sharti INSERT_OBJECT_OID(t, &trapsink_list); 156122394Sharti 157122394Sharti tdep->rb |= TDEP_CREATE; 158122394Sharti 159122394Sharti return (SNMP_ERR_NOERROR); 160122394Sharti} 161122394Sharti 162122394Shartistatic void 163122394Shartitrapsink_free(struct trapsink *t) 164122394Sharti{ 165122394Sharti TAILQ_REMOVE(&trapsink_list, t, link); 166122394Sharti if (t->socket != -1) 167122394Sharti (void)close(t->socket); 168122394Sharti free(t); 169122394Sharti} 170122394Sharti 171122394Shartistatic int 172122394Shartitrapsink_modify(struct trapsink *t, struct trapsink_dep *tdep) 173122394Sharti{ 174122394Sharti tdep->rb_status = t->status; 175122394Sharti tdep->rb_version = t->version; 176122394Sharti strcpy(tdep->rb_comm, t->comm); 177122394Sharti 178122394Sharti if (tdep->set & TDEP_STATUS) { 179122394Sharti /* if we are active and should move to not_in_service do 180122394Sharti * this first */ 181122394Sharti if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) { 182122394Sharti t->status = TRAPSINK_NOT_IN_SERVICE; 183122394Sharti tdep->rb |= TDEP_MODIFY; 184122394Sharti } 185122394Sharti } 186122394Sharti 187122394Sharti if (tdep->set & TDEP_VERSION) 188122394Sharti t->version = tdep->version; 189122394Sharti if (tdep->set & TDEP_COMM) 190122394Sharti strcpy(t->comm, tdep->comm); 191122394Sharti 192122394Sharti if (tdep->set & TDEP_STATUS) { 193122394Sharti /* if we were inactive and should go active - do this now */ 194122394Sharti if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) { 195122394Sharti if (t->comm[0] == '\0') { 196122394Sharti t->status = tdep->rb_status; 197122394Sharti t->version = tdep->rb_version; 198122394Sharti strcpy(t->comm, tdep->rb_comm); 199122394Sharti return (SNMP_ERR_INCONS_VALUE); 200122394Sharti } 201122394Sharti t->status = TRAPSINK_ACTIVE; 202122394Sharti tdep->rb |= TDEP_MODIFY; 203122394Sharti } 204122394Sharti } 205122394Sharti return (SNMP_ERR_NOERROR); 206122394Sharti} 207122394Sharti 208122394Shartistatic int 209122394Shartitrapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep) 210122394Sharti{ 211122394Sharti if (tdep->set & TDEP_STATUS) 212122394Sharti t->status = tdep->rb_status; 213122394Sharti if (tdep->set & TDEP_VERSION) 214122394Sharti t->version = tdep->rb_version; 215122394Sharti if (tdep->set & TDEP_COMM) 216122394Sharti strcpy(t->comm, tdep->rb_comm); 217122394Sharti 218122394Sharti return (SNMP_ERR_NOERROR); 219122394Sharti} 220122394Sharti 221122394Shartistatic int 222128237Shartitrapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t, 223122394Sharti struct trapsink_dep *tdep) 224122394Sharti{ 225122394Sharti t->status = TRAPSINK_DESTROY; 226122394Sharti tdep->rb_status = t->status; 227122394Sharti tdep->rb |= TDEP_DESTROY; 228122394Sharti return (SNMP_ERR_NOERROR); 229122394Sharti} 230122394Sharti 231122394Shartistatic int 232122394Shartitrapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep) 233122394Sharti{ 234122394Sharti t->status = tdep->rb_status; 235122394Sharti return (SNMP_ERR_NOERROR); 236122394Sharti} 237122394Sharti 238122394Shartistatic int 239122394Shartitrapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep, 240122394Sharti enum snmp_depop op) 241122394Sharti{ 242122394Sharti struct trapsink_dep *tdep = (struct trapsink_dep *)dep; 243122394Sharti struct trapsink *t; 244122394Sharti 245122394Sharti t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0); 246122394Sharti 247122394Sharti switch (op) { 248122394Sharti 249122394Sharti case SNMP_DEPOP_COMMIT: 250122394Sharti if (tdep->set & TDEP_STATUS) { 251122394Sharti switch (tdep->status) { 252122394Sharti 253122394Sharti case 1: 254122394Sharti case 2: 255122394Sharti if (t == NULL) 256122394Sharti return (SNMP_ERR_INCONS_VALUE); 257122394Sharti return (trapsink_modify(t, tdep)); 258122394Sharti 259122394Sharti case 4: 260122394Sharti case 5: 261122394Sharti if (t != NULL) 262122394Sharti return (SNMP_ERR_INCONS_VALUE); 263122394Sharti return (trapsink_create(tdep)); 264122394Sharti 265122394Sharti case 6: 266122394Sharti if (t == NULL) 267122394Sharti return (SNMP_ERR_NOERROR); 268122394Sharti return (trapsink_destroy(ctx, t, tdep)); 269122394Sharti } 270122394Sharti } else if (tdep->set != 0) 271122394Sharti return (trapsink_modify(t, tdep)); 272122394Sharti 273122394Sharti return (SNMP_ERR_NOERROR); 274122394Sharti 275122394Sharti case SNMP_DEPOP_ROLLBACK: 276122394Sharti if (tdep->rb & TDEP_CREATE) { 277122394Sharti trapsink_free(t); 278122394Sharti return (SNMP_ERR_NOERROR); 279122394Sharti } 280122394Sharti if (tdep->rb & TDEP_MODIFY) 281122394Sharti return (trapsink_unmodify(t, tdep)); 282122394Sharti if(tdep->rb & TDEP_DESTROY) 283122394Sharti return (trapsink_undestroy(t, tdep)); 284122394Sharti return (SNMP_ERR_NOERROR); 285128237Sharti 286128237Sharti case SNMP_DEPOP_FINISH: 287128237Sharti if ((tdep->rb & TDEP_DESTROY) && t != NULL && 288128237Sharti ctx->code == SNMP_RET_OK) 289128237Sharti trapsink_free(t); 290128237Sharti return (SNMP_ERR_NOERROR); 291122394Sharti } 292122394Sharti abort(); 293122394Sharti} 294122394Sharti 295122394Shartiint 296122394Shartiop_trapsink(struct snmp_context *ctx, struct snmp_value *value, 297122394Sharti u_int sub, u_int iidx, enum snmp_op op) 298122394Sharti{ 299122394Sharti struct trapsink *t; 300122394Sharti u_char ipa[4]; 301122394Sharti int32_t port; 302122394Sharti struct asn_oid idx; 303122394Sharti struct trapsink_dep *tdep; 304122394Sharti u_char *p; 305122394Sharti 306122394Sharti t = NULL; /* gcc */ 307122394Sharti 308122394Sharti switch (op) { 309122394Sharti 310122394Sharti case SNMP_OP_GETNEXT: 311122394Sharti if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) 312122394Sharti return (SNMP_ERR_NOSUCHNAME); 313122394Sharti index_append(&value->var, sub, &t->index); 314122394Sharti break; 315122394Sharti 316122394Sharti case SNMP_OP_GET: 317122394Sharti if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) 318122394Sharti return (SNMP_ERR_NOSUCHNAME); 319122394Sharti break; 320122394Sharti 321122394Sharti case SNMP_OP_SET: 322122394Sharti if (index_decode(&value->var, sub, iidx, ipa, &port) || 323122394Sharti port == 0 || port > 65535) 324122394Sharti return (SNMP_ERR_NO_CREATION); 325122394Sharti t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub); 326122394Sharti 327122394Sharti asn_slice_oid(&idx, &value->var, sub, value->var.len); 328122394Sharti 329122394Sharti tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx, 330122394Sharti &oid_begemotTrapSinkTable, &idx, 331122394Sharti sizeof(*tdep), trapsink_dep); 332122394Sharti if (tdep == NULL) 333122394Sharti return (SNMP_ERR_RES_UNAVAIL); 334122394Sharti 335122394Sharti switch (value->var.subs[sub - 1]) { 336122394Sharti 337122394Sharti case LEAF_begemotTrapSinkStatus: 338122394Sharti if (tdep->set & TDEP_STATUS) 339122394Sharti return (SNMP_ERR_INCONS_VALUE); 340122394Sharti switch (value->v.integer) { 341122394Sharti 342122394Sharti case 1: 343122394Sharti case 2: 344122394Sharti if (t == NULL) 345122394Sharti return (SNMP_ERR_INCONS_VALUE); 346122394Sharti break; 347122394Sharti 348122394Sharti case 4: 349122394Sharti case 5: 350122394Sharti if (t != NULL) 351122394Sharti return (SNMP_ERR_INCONS_VALUE); 352122394Sharti break; 353122394Sharti 354122394Sharti case 6: 355122394Sharti break; 356122394Sharti 357122394Sharti default: 358122394Sharti return (SNMP_ERR_WRONG_VALUE); 359122394Sharti } 360122394Sharti tdep->status = value->v.integer; 361122394Sharti tdep->set |= TDEP_STATUS; 362122394Sharti return (SNMP_ERR_NOERROR); 363122394Sharti 364122394Sharti case LEAF_begemotTrapSinkComm: 365122394Sharti if (tdep->set & TDEP_COMM) 366122394Sharti return (SNMP_ERR_INCONS_VALUE); 367122394Sharti if (value->v.octetstring.len == 0 || 368122394Sharti value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN) 369122394Sharti return (SNMP_ERR_WRONG_VALUE); 370122394Sharti for (p = value->v.octetstring.octets; 371122394Sharti p < value->v.octetstring.octets + value->v.octetstring.len; 372122394Sharti p++) { 373122394Sharti if (!isascii(*p) || !isprint(*p)) 374122394Sharti return (SNMP_ERR_WRONG_VALUE); 375122394Sharti } 376122394Sharti tdep->set |= TDEP_COMM; 377122394Sharti strncpy(tdep->comm, value->v.octetstring.octets, 378122394Sharti value->v.octetstring.len); 379122394Sharti tdep->comm[value->v.octetstring.len] = '\0'; 380122394Sharti return (SNMP_ERR_NOERROR); 381122394Sharti 382122394Sharti case LEAF_begemotTrapSinkVersion: 383122394Sharti if (tdep->set & TDEP_VERSION) 384122394Sharti return (SNMP_ERR_INCONS_VALUE); 385122394Sharti if (value->v.integer != TRAPSINK_V1 && 386122394Sharti value->v.integer != TRAPSINK_V2) 387122394Sharti return (SNMP_ERR_WRONG_VALUE); 388122394Sharti tdep->version = value->v.integer; 389122394Sharti tdep->set |= TDEP_VERSION; 390122394Sharti return (SNMP_ERR_NOERROR); 391122394Sharti } 392122394Sharti if (t == NULL) 393122394Sharti return (SNMP_ERR_INCONS_NAME); 394122394Sharti else 395122394Sharti return (SNMP_ERR_NOT_WRITEABLE); 396122394Sharti 397122394Sharti 398122394Sharti case SNMP_OP_ROLLBACK: 399122394Sharti case SNMP_OP_COMMIT: 400122394Sharti return (SNMP_ERR_NOERROR); 401122394Sharti } 402122394Sharti 403122394Sharti switch (value->var.subs[sub - 1]) { 404122394Sharti 405122394Sharti case LEAF_begemotTrapSinkStatus: 406122394Sharti value->v.integer = t->status; 407122394Sharti break; 408122394Sharti 409122394Sharti case LEAF_begemotTrapSinkComm: 410122394Sharti return (string_get(value, t->comm, -1)); 411122394Sharti 412122394Sharti case LEAF_begemotTrapSinkVersion: 413122394Sharti value->v.integer = t->version; 414122394Sharti break; 415122394Sharti 416122394Sharti } 417122394Sharti return (SNMP_ERR_NOERROR); 418122394Sharti} 419122394Sharti 420216594Ssyrinxstatic void 421216594Ssyrinxsnmp_create_v1_trap(struct snmp_pdu *pdu, char *com, 422216594Ssyrinx const struct asn_oid *trap_oid) 423216594Ssyrinx{ 424216594Ssyrinx memset(pdu, 0, sizeof(*pdu)); 425216594Ssyrinx strcpy(pdu->community, com); 426216594Ssyrinx 427216594Ssyrinx pdu->version = SNMP_V1; 428216594Ssyrinx pdu->type = SNMP_PDU_TRAP; 429216594Ssyrinx pdu->enterprise = systemg.object_id; 430216594Ssyrinx memcpy(pdu->agent_addr, snmpd.trap1addr, 4); 431216594Ssyrinx pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; 432216594Ssyrinx pdu->specific_trap = 0; 433216594Ssyrinx pdu->time_stamp = get_ticks() - start_tick; 434216594Ssyrinx pdu->nbindings = 0; 435216594Ssyrinx} 436216594Ssyrinx 437216594Ssyrinxstatic void 438216594Ssyrinxsnmp_create_v2_trap(struct snmp_pdu *pdu, char *com, 439216594Ssyrinx const struct asn_oid *trap_oid) 440216594Ssyrinx{ 441216594Ssyrinx memset(pdu, 0, sizeof(*pdu)); 442216594Ssyrinx strcpy(pdu->community, com); 443216594Ssyrinx 444216594Ssyrinx pdu->version = SNMP_V2c; 445216594Ssyrinx pdu->type = SNMP_PDU_TRAP2; 446216594Ssyrinx pdu->request_id = reqid_next(trap_reqid); 447216594Ssyrinx pdu->error_index = 0; 448216594Ssyrinx pdu->error_status = SNMP_ERR_NOERROR; 449216594Ssyrinx 450216594Ssyrinx pdu->bindings[0].var = oid_sysUpTime; 451216594Ssyrinx pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 452216594Ssyrinx pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 453216594Ssyrinx pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 454216594Ssyrinx 455216594Ssyrinx pdu->bindings[1].var = oid_snmpTrapOID; 456216594Ssyrinx pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 457216594Ssyrinx pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 458216594Ssyrinx pdu->bindings[1].v.oid = *trap_oid; 459216594Ssyrinx 460216594Ssyrinx pdu->nbindings = 2; 461216594Ssyrinx} 462216594Ssyrinx 463216594Ssyrinxstatic void 464216594Ssyrinxsnmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target, 465216594Ssyrinx const struct asn_oid *trap_oid) 466216594Ssyrinx{ 467216594Ssyrinx uint64_t etime; 468216594Ssyrinx struct usm_user *usmuser; 469216594Ssyrinx 470216594Ssyrinx memset(pdu, 0, sizeof(*pdu)); 471216594Ssyrinx 472216594Ssyrinx pdu->version = SNMP_V3; 473216594Ssyrinx pdu->type = SNMP_PDU_TRAP2; 474216594Ssyrinx pdu->request_id = reqid_next(trap_reqid); 475216594Ssyrinx pdu->error_index = 0; 476216594Ssyrinx pdu->error_status = SNMP_ERR_NOERROR; 477216594Ssyrinx 478216594Ssyrinx pdu->bindings[0].var = oid_sysUpTime; 479216594Ssyrinx pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 480216594Ssyrinx pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 481216594Ssyrinx pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 482216594Ssyrinx 483216594Ssyrinx pdu->bindings[1].var = oid_snmpTrapOID; 484216594Ssyrinx pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 485216594Ssyrinx pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 486216594Ssyrinx pdu->bindings[1].v.oid = *trap_oid; 487216594Ssyrinx 488216594Ssyrinx pdu->nbindings = 2; 489216594Ssyrinx 490216594Ssyrinx etime = (get_ticks() - start_tick) / 100ULL; 491216594Ssyrinx if (etime < INT32_MAX) 492216594Ssyrinx snmpd_engine.engine_time = etime; 493216594Ssyrinx else { 494216594Ssyrinx start_tick = get_ticks(); 495216594Ssyrinx set_snmpd_engine(); 496216594Ssyrinx snmpd_engine.engine_time = start_tick; 497216594Ssyrinx } 498216594Ssyrinx 499216594Ssyrinx memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 500216594Ssyrinx snmpd_engine.engine_len); 501216594Ssyrinx pdu->engine.engine_len = snmpd_engine.engine_len; 502216594Ssyrinx pdu->engine.engine_boots = snmpd_engine.engine_boots; 503216594Ssyrinx pdu->engine.engine_time = snmpd_engine.engine_time; 504216594Ssyrinx pdu->engine.max_msg_size = snmpd_engine.max_msg_size; 505216594Ssyrinx strlcpy(pdu->user.sec_name, target->secname, 506216594Ssyrinx sizeof(pdu->user.sec_name)); 507216594Ssyrinx pdu->security_model = target->sec_model; 508216594Ssyrinx 509216594Ssyrinx pdu->context_engine_len = snmpd_engine.engine_len; 510216594Ssyrinx memcpy(pdu->context_engine, snmpd_engine.engine_id, 511216594Ssyrinx snmpd_engine.engine_len); 512216594Ssyrinx 513216594Ssyrinx if (target->sec_model == SNMP_SECMODEL_USM && 514216594Ssyrinx target->sec_level != SNMP_noAuthNoPriv) { 515216594Ssyrinx usmuser = usm_find_user(pdu->engine.engine_id, 516216594Ssyrinx pdu->engine.engine_len, pdu->user.sec_name); 517216594Ssyrinx if (usmuser != NULL) { 518216594Ssyrinx pdu->user.auth_proto = usmuser->suser.auth_proto; 519216594Ssyrinx pdu->user.priv_proto = usmuser->suser.priv_proto; 520216594Ssyrinx memcpy(pdu->user.auth_key, usmuser->suser.auth_key, 521216594Ssyrinx sizeof(pdu->user.auth_key)); 522216594Ssyrinx memcpy(pdu->user.priv_key, usmuser->suser.priv_key, 523216594Ssyrinx sizeof(pdu->user.priv_key)); 524216594Ssyrinx } 525216594Ssyrinx snmp_pdu_init_secparams(pdu); 526216594Ssyrinx } 527216594Ssyrinx} 528216594Ssyrinx 529122394Shartivoid 530122394Shartisnmp_send_trap(const struct asn_oid *trap_oid, ...) 531122394Sharti{ 532122394Sharti struct snmp_pdu pdu; 533122394Sharti struct trapsink *t; 534122394Sharti const struct snmp_value *v; 535216594Ssyrinx struct target_notify *n; 536216594Ssyrinx struct target_address *ta; 537216594Ssyrinx struct target_param *tp; 538216594Ssyrinx 539122394Sharti va_list ap; 540122394Sharti u_char *sndbuf; 541216594Ssyrinx char *tag; 542122394Sharti size_t sndlen; 543122394Sharti ssize_t len; 544216594Ssyrinx int32_t ip; 545122394Sharti 546122394Sharti TAILQ_FOREACH(t, &trapsink_list, link) { 547122394Sharti if (t->status != TRAPSINK_ACTIVE) 548122394Sharti continue; 549216594Ssyrinx 550216594Ssyrinx if (t->version == TRAPSINK_V1) 551216594Ssyrinx snmp_create_v1_trap(&pdu, t->comm, trap_oid); 552216594Ssyrinx else 553216594Ssyrinx snmp_create_v2_trap(&pdu, t->comm, trap_oid); 554122394Sharti 555216594Ssyrinx va_start(ap, trap_oid); 556216594Ssyrinx while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 557216594Ssyrinx pdu.bindings[pdu.nbindings++] = *v; 558216594Ssyrinx va_end(ap); 559122394Sharti 560216594Ssyrinx if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 561216594Ssyrinx syslog(LOG_DEBUG, "send trap to %s failed: no access", 562216594Ssyrinx t->comm); 563216594Ssyrinx continue; 564216594Ssyrinx } 565122394Sharti 566216594Ssyrinx if ((sndbuf = buf_alloc(1)) == NULL) { 567216594Ssyrinx syslog(LOG_ERR, "trap send buffer: %m"); 568216594Ssyrinx return; 569216594Ssyrinx } 570122394Sharti 571216594Ssyrinx snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 572216594Ssyrinx 573216594Ssyrinx if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) 574216594Ssyrinx syslog(LOG_ERR, "send: %m"); 575216594Ssyrinx else if ((size_t)len != sndlen) 576216594Ssyrinx syslog(LOG_ERR, "send: short write %zu/%zu", 577216594Ssyrinx sndlen, (size_t)len); 578216594Ssyrinx 579216594Ssyrinx free(sndbuf); 580216594Ssyrinx } 581216594Ssyrinx 582216594Ssyrinx SLIST_FOREACH(n, &target_notifylist, tn) { 583216594Ssyrinx if (n->status != RowStatus_active || n->taglist[0] == '\0') 584216594Ssyrinx continue; 585216594Ssyrinx 586216594Ssyrinx SLIST_FOREACH(ta, &target_addresslist, ta) 587216594Ssyrinx if ((tag = strstr(ta->taglist, n->taglist)) != NULL && 588216594Ssyrinx (tag[strlen(n->taglist)] == ' ' || 589216594Ssyrinx tag[strlen(n->taglist)] == '\0' || 590216594Ssyrinx tag[strlen(n->taglist)] == '\t' || 591216594Ssyrinx tag[strlen(n->taglist)] == '\r' || 592216594Ssyrinx tag[strlen(n->taglist)] == '\n') && 593216594Ssyrinx ta->status == RowStatus_active) 594216594Ssyrinx break; 595216594Ssyrinx if (ta == NULL) 596216594Ssyrinx continue; 597216594Ssyrinx 598216594Ssyrinx SLIST_FOREACH(tp, &target_paramlist, tp) 599216594Ssyrinx if (strcmp(tp->name, ta->paramname) == 0 && 600216594Ssyrinx tp->status == 1) 601216594Ssyrinx break; 602216594Ssyrinx if (tp == NULL) 603216594Ssyrinx continue; 604216594Ssyrinx 605216594Ssyrinx switch (tp->mpmodel) { 606216594Ssyrinx case SNMP_MPM_SNMP_V1: 607216594Ssyrinx snmp_create_v1_trap(&pdu, tp->secname, trap_oid); 608216594Ssyrinx break; 609216594Ssyrinx 610216594Ssyrinx case SNMP_MPM_SNMP_V2c: 611216594Ssyrinx snmp_create_v2_trap(&pdu, tp->secname, trap_oid); 612216594Ssyrinx break; 613216594Ssyrinx 614216594Ssyrinx case SNMP_MPM_SNMP_V3: 615216594Ssyrinx snmp_create_v3_trap(&pdu, tp, trap_oid); 616216594Ssyrinx break; 617216594Ssyrinx 618216594Ssyrinx default: 619216594Ssyrinx continue; 620122394Sharti } 621122394Sharti 622122394Sharti va_start(ap, trap_oid); 623122394Sharti while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 624122394Sharti pdu.bindings[pdu.nbindings++] = *v; 625122394Sharti va_end(ap); 626122394Sharti 627216594Ssyrinx if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 628216594Ssyrinx syslog(LOG_DEBUG, "send trap to %s failed: no access", 629216594Ssyrinx t->comm); 630216594Ssyrinx continue; 631216594Ssyrinx } 632216594Ssyrinx 633122394Sharti if ((sndbuf = buf_alloc(1)) == NULL) { 634122394Sharti syslog(LOG_ERR, "trap send buffer: %m"); 635122394Sharti return; 636122394Sharti } 637122394Sharti 638122394Sharti snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 639122394Sharti 640216594Ssyrinx if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) 641122394Sharti syslog(LOG_ERR, "send: %m"); 642122394Sharti else if ((size_t)len != sndlen) 643122394Sharti syslog(LOG_ERR, "send: short write %zu/%zu", 644122394Sharti sndlen, (size_t)len); 645122394Sharti 646122394Sharti free(sndbuf); 647122394Sharti } 648122394Sharti} 649216594Ssyrinx 650216594Ssyrinx/* 651216594Ssyrinx * RFC 3413 SNMP Management Target MIB 652216594Ssyrinx */ 653216594Ssyrinxstruct snmpd_target_stats * 654216594Ssyrinxbsnmpd_get_target_stats(void) 655216594Ssyrinx{ 656216594Ssyrinx return (&snmpd_target_stats); 657216594Ssyrinx} 658216594Ssyrinx 659216594Ssyrinxstruct target_address * 660216594Ssyrinxtarget_first_address(void) 661216594Ssyrinx{ 662216594Ssyrinx return (SLIST_FIRST(&target_addresslist)); 663216594Ssyrinx} 664216594Ssyrinx 665216594Ssyrinxstruct target_address * 666216594Ssyrinxtarget_next_address(struct target_address *addrs) 667216594Ssyrinx{ 668216594Ssyrinx if (addrs == NULL) 669216594Ssyrinx return (NULL); 670216594Ssyrinx 671216594Ssyrinx return (SLIST_NEXT(addrs, ta)); 672216594Ssyrinx} 673216594Ssyrinx 674216594Ssyrinxstruct target_address * 675216594Ssyrinxtarget_new_address(char *aname) 676216594Ssyrinx{ 677216594Ssyrinx int cmp; 678216594Ssyrinx struct target_address *addrs, *temp, *prev; 679216594Ssyrinx 680216594Ssyrinx SLIST_FOREACH(addrs, &target_addresslist, ta) 681216594Ssyrinx if (strcmp(aname, addrs->name) == 0) 682216594Ssyrinx return (NULL); 683216594Ssyrinx 684216594Ssyrinx if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) 685216594Ssyrinx return (NULL); 686216594Ssyrinx 687216594Ssyrinx memset(addrs, 0, sizeof(*addrs)); 688216594Ssyrinx strlcpy(addrs->name, aname, sizeof(addrs->name)); 689216594Ssyrinx addrs->timeout = 150; 690216594Ssyrinx addrs->retry = 3; /* XXX */ 691216594Ssyrinx 692216594Ssyrinx if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || 693216594Ssyrinx strcmp(aname, prev->name) < 0) { 694216594Ssyrinx SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); 695216594Ssyrinx return (addrs); 696216594Ssyrinx } 697216594Ssyrinx 698216594Ssyrinx SLIST_FOREACH(temp, &target_addresslist, ta) { 699216594Ssyrinx if ((cmp = strcmp(aname, temp->name)) <= 0) 700216594Ssyrinx break; 701216594Ssyrinx prev = temp; 702216594Ssyrinx } 703216594Ssyrinx 704216594Ssyrinx if (temp == NULL || cmp < 0) 705216594Ssyrinx SLIST_INSERT_AFTER(prev, addrs, ta); 706216594Ssyrinx else if (cmp > 0) 707216594Ssyrinx SLIST_INSERT_AFTER(temp, addrs, ta); 708216594Ssyrinx else { 709216594Ssyrinx syslog(LOG_ERR, "Target address %s exists", addrs->name); 710216594Ssyrinx free(addrs); 711216594Ssyrinx return (NULL); 712216594Ssyrinx } 713216594Ssyrinx 714216594Ssyrinx return (addrs); 715216594Ssyrinx} 716216594Ssyrinx 717216594Ssyrinxint 718216594Ssyrinxtarget_activate_address(struct target_address *addrs) 719216594Ssyrinx{ 720216594Ssyrinx struct sockaddr_in sa; 721216594Ssyrinx 722216594Ssyrinx if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 723216594Ssyrinx syslog(LOG_ERR, "socket(UDP): %m"); 724216594Ssyrinx return (SNMP_ERR_RES_UNAVAIL); 725216594Ssyrinx } 726216594Ssyrinx 727216594Ssyrinx (void)shutdown(addrs->socket, SHUT_RD); 728216594Ssyrinx sa.sin_len = sizeof(sa); 729216594Ssyrinx sa.sin_family = AF_INET; 730216594Ssyrinx 731216594Ssyrinx sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | 732216594Ssyrinx (addrs->address[1] << 16) | (addrs->address[2] << 8) | 733216594Ssyrinx (addrs->address[3] << 0)); 734216594Ssyrinx sa.sin_port = htons(addrs->address[4]) << 8 | 735216594Ssyrinx htons(addrs->address[5]) << 0; 736216594Ssyrinx 737216594Ssyrinx if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 738216594Ssyrinx syslog(LOG_ERR, "connect(%s,%u): %m", 739216594Ssyrinx inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 740216594Ssyrinx (void)close(addrs->socket); 741216594Ssyrinx return (SNMP_ERR_GENERR); 742216594Ssyrinx } 743216594Ssyrinx 744216594Ssyrinx addrs->status = RowStatus_active; 745216594Ssyrinx 746216594Ssyrinx return (SNMP_ERR_NOERROR); 747216594Ssyrinx} 748216594Ssyrinx 749216594Ssyrinxint 750216594Ssyrinxtarget_delete_address(struct target_address *addrs) 751216594Ssyrinx{ 752216594Ssyrinx SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); 753216594Ssyrinx if (addrs->status == RowStatus_active) 754216594Ssyrinx close(addrs->socket); 755216594Ssyrinx free(addrs); 756216594Ssyrinx 757216594Ssyrinx return (0); 758216594Ssyrinx} 759216594Ssyrinx 760216594Ssyrinxstruct target_param * 761216594Ssyrinxtarget_first_param(void) 762216594Ssyrinx{ 763216594Ssyrinx return (SLIST_FIRST(&target_paramlist)); 764216594Ssyrinx} 765216594Ssyrinx 766216594Ssyrinxstruct target_param * 767216594Ssyrinxtarget_next_param(struct target_param *param) 768216594Ssyrinx{ 769216594Ssyrinx if (param == NULL) 770216594Ssyrinx return (NULL); 771216594Ssyrinx 772216594Ssyrinx return (SLIST_NEXT(param, tp)); 773216594Ssyrinx} 774216594Ssyrinx 775216594Ssyrinxstruct target_param * 776216594Ssyrinxtarget_new_param(char *pname) 777216594Ssyrinx{ 778216594Ssyrinx int cmp; 779216594Ssyrinx struct target_param *param, *temp, *prev; 780216594Ssyrinx 781216594Ssyrinx SLIST_FOREACH(param, &target_paramlist, tp) 782216594Ssyrinx if (strcmp(pname, param->name) == 0) 783216594Ssyrinx return (NULL); 784216594Ssyrinx 785216594Ssyrinx if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) 786216594Ssyrinx return (NULL); 787216594Ssyrinx 788216594Ssyrinx memset(param, 0, sizeof(*param)); 789216594Ssyrinx strlcpy(param->name, pname, sizeof(param->name)); 790216594Ssyrinx 791216594Ssyrinx if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || 792216594Ssyrinx strcmp(pname, prev->name) < 0) { 793216594Ssyrinx SLIST_INSERT_HEAD(&target_paramlist, param, tp); 794216594Ssyrinx return (param); 795216594Ssyrinx } 796216594Ssyrinx 797216594Ssyrinx SLIST_FOREACH(temp, &target_paramlist, tp) { 798216594Ssyrinx if ((cmp = strcmp(pname, temp->name)) <= 0) 799216594Ssyrinx break; 800216594Ssyrinx prev = temp; 801216594Ssyrinx } 802216594Ssyrinx 803216594Ssyrinx if (temp == NULL || cmp < 0) 804216594Ssyrinx SLIST_INSERT_AFTER(prev, param, tp); 805216594Ssyrinx else if (cmp > 0) 806216594Ssyrinx SLIST_INSERT_AFTER(temp, param, tp); 807216594Ssyrinx else { 808216594Ssyrinx syslog(LOG_ERR, "Target parameter %s exists", param->name); 809216594Ssyrinx free(param); 810216594Ssyrinx return (NULL); 811216594Ssyrinx } 812216594Ssyrinx 813216594Ssyrinx return (param); 814216594Ssyrinx} 815216594Ssyrinx 816216594Ssyrinxint 817216594Ssyrinxtarget_delete_param(struct target_param *param) 818216594Ssyrinx{ 819216594Ssyrinx SLIST_REMOVE(&target_paramlist, param, target_param, tp); 820216594Ssyrinx free(param); 821216594Ssyrinx 822216594Ssyrinx return (0); 823216594Ssyrinx} 824216594Ssyrinx 825216594Ssyrinxstruct target_notify * 826216594Ssyrinxtarget_first_notify(void) 827216594Ssyrinx{ 828216594Ssyrinx return (SLIST_FIRST(&target_notifylist)); 829216594Ssyrinx} 830216594Ssyrinx 831216594Ssyrinxstruct target_notify * 832216594Ssyrinxtarget_next_notify(struct target_notify *notify) 833216594Ssyrinx{ 834216594Ssyrinx if (notify == NULL) 835216594Ssyrinx return (NULL); 836216594Ssyrinx 837216594Ssyrinx return (SLIST_NEXT(notify, tn)); 838216594Ssyrinx} 839216594Ssyrinx 840216594Ssyrinxstruct target_notify * 841216594Ssyrinxtarget_new_notify(char *nname) 842216594Ssyrinx{ 843216594Ssyrinx int cmp; 844216594Ssyrinx struct target_notify *notify, *temp, *prev; 845216594Ssyrinx 846216594Ssyrinx SLIST_FOREACH(notify, &target_notifylist, tn) 847216594Ssyrinx if (strcmp(nname, notify->name) == 0) 848216594Ssyrinx return (NULL); 849216594Ssyrinx 850216594Ssyrinx if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) 851216594Ssyrinx return (NULL); 852216594Ssyrinx 853216594Ssyrinx memset(notify, 0, sizeof(*notify)); 854216594Ssyrinx strlcpy(notify->name, nname, sizeof(notify->name)); 855216594Ssyrinx 856216594Ssyrinx if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || 857216594Ssyrinx strcmp(nname, prev->name) < 0) { 858216594Ssyrinx SLIST_INSERT_HEAD(&target_notifylist, notify, tn); 859216594Ssyrinx return (notify); 860216594Ssyrinx } 861216594Ssyrinx 862216594Ssyrinx SLIST_FOREACH(temp, &target_notifylist, tn) { 863216594Ssyrinx if ((cmp = strcmp(nname, temp->name)) <= 0) 864216594Ssyrinx break; 865216594Ssyrinx prev = temp; 866216594Ssyrinx } 867216594Ssyrinx 868216594Ssyrinx if (temp == NULL || cmp < 0) 869216594Ssyrinx SLIST_INSERT_AFTER(prev, notify, tn); 870216594Ssyrinx else if (cmp > 0) 871216594Ssyrinx SLIST_INSERT_AFTER(temp, notify, tn); 872216594Ssyrinx else { 873216594Ssyrinx syslog(LOG_ERR, "Notification target %s exists", notify->name); 874216594Ssyrinx free(notify); 875216594Ssyrinx return (NULL); 876216594Ssyrinx } 877216594Ssyrinx 878216594Ssyrinx return (notify); 879216594Ssyrinx} 880216594Ssyrinx 881216594Ssyrinxint 882216594Ssyrinxtarget_delete_notify(struct target_notify *notify) 883216594Ssyrinx{ 884216594Ssyrinx SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); 885216594Ssyrinx free(notify); 886216594Ssyrinx 887216594Ssyrinx return (0); 888216594Ssyrinx} 889216594Ssyrinx 890216594Ssyrinxvoid 891216594Ssyrinxtarget_flush_all(void) 892216594Ssyrinx{ 893216594Ssyrinx struct target_address *addrs; 894216594Ssyrinx struct target_param *param; 895216594Ssyrinx struct target_notify *notify; 896216594Ssyrinx 897216594Ssyrinx while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { 898216594Ssyrinx SLIST_REMOVE_HEAD(&target_addresslist, ta); 899216594Ssyrinx if (addrs->status == RowStatus_active) 900216594Ssyrinx close(addrs->socket); 901216594Ssyrinx free(addrs); 902216594Ssyrinx } 903216594Ssyrinx SLIST_INIT(&target_addresslist); 904216594Ssyrinx 905216594Ssyrinx while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { 906216594Ssyrinx SLIST_REMOVE_HEAD(&target_paramlist, tp); 907216594Ssyrinx free(param); 908216594Ssyrinx } 909216594Ssyrinx SLIST_INIT(&target_paramlist); 910216594Ssyrinx 911216594Ssyrinx while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { 912216594Ssyrinx SLIST_REMOVE_HEAD(&target_notifylist, tn); 913216594Ssyrinx free(notify); 914216594Ssyrinx } 915216594Ssyrinx SLIST_INIT(&target_notifylist); 916216594Ssyrinx} 917