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. 22310901Sngie * 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 */ 63292815Sngiestatic struct target_addresslist target_addresslist = 64216594Ssyrinx SLIST_HEAD_INITIALIZER(target_addresslist); 65216594Ssyrinx 66216594Ssyrinx/* List of target parameters */ 67292815Sngiestatic struct target_paramlist target_paramlist = 68216594Ssyrinx SLIST_HEAD_INITIALIZER(target_paramlist); 69216594Ssyrinx 70216594Ssyrinx/* List of notification targets */ 71292815Sngiestatic struct 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); 120240191Skevlo memset(&sa, 0, sizeof(sa)); 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); 217310730Sngie 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)); 425311596Sngie strlcpy(pdu->community, com, sizeof(pdu->community)); 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)); 442311596Sngie strlcpy(pdu->community, com, sizeof(pdu->community)); 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 struct usm_user *usmuser; 468216594Ssyrinx 469216594Ssyrinx memset(pdu, 0, sizeof(*pdu)); 470216594Ssyrinx 471216594Ssyrinx pdu->version = SNMP_V3; 472216594Ssyrinx pdu->type = SNMP_PDU_TRAP2; 473216594Ssyrinx pdu->request_id = reqid_next(trap_reqid); 474216594Ssyrinx pdu->error_index = 0; 475216594Ssyrinx pdu->error_status = SNMP_ERR_NOERROR; 476216594Ssyrinx 477216594Ssyrinx pdu->bindings[0].var = oid_sysUpTime; 478216594Ssyrinx pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 479216594Ssyrinx pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 480216594Ssyrinx pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 481216594Ssyrinx 482216594Ssyrinx pdu->bindings[1].var = oid_snmpTrapOID; 483216594Ssyrinx pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 484216594Ssyrinx pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 485216594Ssyrinx pdu->bindings[1].v.oid = *trap_oid; 486216594Ssyrinx 487216594Ssyrinx pdu->nbindings = 2; 488216594Ssyrinx 489310990Sngie update_snmpd_engine_time(); 490216594Ssyrinx 491216594Ssyrinx memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 492216594Ssyrinx snmpd_engine.engine_len); 493216594Ssyrinx pdu->engine.engine_len = snmpd_engine.engine_len; 494216594Ssyrinx pdu->engine.engine_boots = snmpd_engine.engine_boots; 495216594Ssyrinx pdu->engine.engine_time = snmpd_engine.engine_time; 496216594Ssyrinx pdu->engine.max_msg_size = snmpd_engine.max_msg_size; 497216594Ssyrinx strlcpy(pdu->user.sec_name, target->secname, 498216594Ssyrinx sizeof(pdu->user.sec_name)); 499216594Ssyrinx pdu->security_model = target->sec_model; 500216594Ssyrinx 501216594Ssyrinx pdu->context_engine_len = snmpd_engine.engine_len; 502216594Ssyrinx memcpy(pdu->context_engine, snmpd_engine.engine_id, 503216594Ssyrinx snmpd_engine.engine_len); 504216594Ssyrinx 505216594Ssyrinx if (target->sec_model == SNMP_SECMODEL_USM && 506216594Ssyrinx target->sec_level != SNMP_noAuthNoPriv) { 507216594Ssyrinx usmuser = usm_find_user(pdu->engine.engine_id, 508216594Ssyrinx pdu->engine.engine_len, pdu->user.sec_name); 509216594Ssyrinx if (usmuser != NULL) { 510216594Ssyrinx pdu->user.auth_proto = usmuser->suser.auth_proto; 511216594Ssyrinx pdu->user.priv_proto = usmuser->suser.priv_proto; 512216594Ssyrinx memcpy(pdu->user.auth_key, usmuser->suser.auth_key, 513216594Ssyrinx sizeof(pdu->user.auth_key)); 514216594Ssyrinx memcpy(pdu->user.priv_key, usmuser->suser.priv_key, 515216594Ssyrinx sizeof(pdu->user.priv_key)); 516216594Ssyrinx } 517216594Ssyrinx snmp_pdu_init_secparams(pdu); 518216594Ssyrinx } 519216594Ssyrinx} 520216594Ssyrinx 521122394Shartivoid 522122394Shartisnmp_send_trap(const struct asn_oid *trap_oid, ...) 523122394Sharti{ 524122394Sharti struct snmp_pdu pdu; 525122394Sharti struct trapsink *t; 526122394Sharti const struct snmp_value *v; 527216594Ssyrinx struct target_notify *n; 528216594Ssyrinx struct target_address *ta; 529216594Ssyrinx struct target_param *tp; 530216594Ssyrinx 531122394Sharti va_list ap; 532122394Sharti u_char *sndbuf; 533216594Ssyrinx char *tag; 534122394Sharti size_t sndlen; 535122394Sharti ssize_t len; 536216594Ssyrinx int32_t ip; 537122394Sharti 538122394Sharti TAILQ_FOREACH(t, &trapsink_list, link) { 539122394Sharti if (t->status != TRAPSINK_ACTIVE) 540122394Sharti continue; 541310730Sngie 542216594Ssyrinx if (t->version == TRAPSINK_V1) 543216594Ssyrinx snmp_create_v1_trap(&pdu, t->comm, trap_oid); 544216594Ssyrinx else 545216594Ssyrinx snmp_create_v2_trap(&pdu, t->comm, trap_oid); 546122394Sharti 547216594Ssyrinx va_start(ap, trap_oid); 548216594Ssyrinx while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 549216594Ssyrinx pdu.bindings[pdu.nbindings++] = *v; 550216594Ssyrinx va_end(ap); 551122394Sharti 552216594Ssyrinx if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 553216594Ssyrinx syslog(LOG_DEBUG, "send trap to %s failed: no access", 554216594Ssyrinx t->comm); 555216594Ssyrinx continue; 556216594Ssyrinx } 557122394Sharti 558216594Ssyrinx if ((sndbuf = buf_alloc(1)) == NULL) { 559216594Ssyrinx syslog(LOG_ERR, "trap send buffer: %m"); 560216594Ssyrinx return; 561216594Ssyrinx } 562122394Sharti 563216594Ssyrinx snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 564216594Ssyrinx 565216594Ssyrinx if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) 566216594Ssyrinx syslog(LOG_ERR, "send: %m"); 567216594Ssyrinx else if ((size_t)len != sndlen) 568216594Ssyrinx syslog(LOG_ERR, "send: short write %zu/%zu", 569216594Ssyrinx sndlen, (size_t)len); 570216594Ssyrinx 571216594Ssyrinx free(sndbuf); 572216594Ssyrinx } 573216594Ssyrinx 574216594Ssyrinx SLIST_FOREACH(n, &target_notifylist, tn) { 575216594Ssyrinx if (n->status != RowStatus_active || n->taglist[0] == '\0') 576216594Ssyrinx continue; 577216594Ssyrinx 578216594Ssyrinx SLIST_FOREACH(ta, &target_addresslist, ta) 579216594Ssyrinx if ((tag = strstr(ta->taglist, n->taglist)) != NULL && 580216594Ssyrinx (tag[strlen(n->taglist)] == ' ' || 581216594Ssyrinx tag[strlen(n->taglist)] == '\0' || 582216594Ssyrinx tag[strlen(n->taglist)] == '\t' || 583216594Ssyrinx tag[strlen(n->taglist)] == '\r' || 584216594Ssyrinx tag[strlen(n->taglist)] == '\n') && 585216594Ssyrinx ta->status == RowStatus_active) 586216594Ssyrinx break; 587216594Ssyrinx if (ta == NULL) 588216594Ssyrinx continue; 589216594Ssyrinx 590216594Ssyrinx SLIST_FOREACH(tp, &target_paramlist, tp) 591216594Ssyrinx if (strcmp(tp->name, ta->paramname) == 0 && 592216594Ssyrinx tp->status == 1) 593216594Ssyrinx break; 594216594Ssyrinx if (tp == NULL) 595216594Ssyrinx continue; 596216594Ssyrinx 597216594Ssyrinx switch (tp->mpmodel) { 598216594Ssyrinx case SNMP_MPM_SNMP_V1: 599216594Ssyrinx snmp_create_v1_trap(&pdu, tp->secname, trap_oid); 600216594Ssyrinx break; 601216594Ssyrinx 602216594Ssyrinx case SNMP_MPM_SNMP_V2c: 603216594Ssyrinx snmp_create_v2_trap(&pdu, tp->secname, trap_oid); 604216594Ssyrinx break; 605216594Ssyrinx 606216594Ssyrinx case SNMP_MPM_SNMP_V3: 607216594Ssyrinx snmp_create_v3_trap(&pdu, tp, trap_oid); 608216594Ssyrinx break; 609216594Ssyrinx 610216594Ssyrinx default: 611216594Ssyrinx continue; 612122394Sharti } 613122394Sharti 614122394Sharti va_start(ap, trap_oid); 615122394Sharti while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 616122394Sharti pdu.bindings[pdu.nbindings++] = *v; 617122394Sharti va_end(ap); 618122394Sharti 619216594Ssyrinx if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 620216594Ssyrinx syslog(LOG_DEBUG, "send trap to %s failed: no access", 621216594Ssyrinx t->comm); 622216594Ssyrinx continue; 623216594Ssyrinx } 624216594Ssyrinx 625122394Sharti if ((sndbuf = buf_alloc(1)) == NULL) { 626122394Sharti syslog(LOG_ERR, "trap send buffer: %m"); 627122394Sharti return; 628122394Sharti } 629122394Sharti 630122394Sharti snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 631122394Sharti 632216594Ssyrinx if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) 633122394Sharti syslog(LOG_ERR, "send: %m"); 634122394Sharti else if ((size_t)len != sndlen) 635122394Sharti syslog(LOG_ERR, "send: short write %zu/%zu", 636122394Sharti sndlen, (size_t)len); 637122394Sharti 638122394Sharti free(sndbuf); 639122394Sharti } 640122394Sharti} 641216594Ssyrinx 642216594Ssyrinx/* 643216594Ssyrinx * RFC 3413 SNMP Management Target MIB 644216594Ssyrinx */ 645216594Ssyrinxstruct snmpd_target_stats * 646216594Ssyrinxbsnmpd_get_target_stats(void) 647216594Ssyrinx{ 648216594Ssyrinx return (&snmpd_target_stats); 649216594Ssyrinx} 650216594Ssyrinx 651216594Ssyrinxstruct target_address * 652216594Ssyrinxtarget_first_address(void) 653216594Ssyrinx{ 654216594Ssyrinx return (SLIST_FIRST(&target_addresslist)); 655216594Ssyrinx} 656216594Ssyrinx 657216594Ssyrinxstruct target_address * 658216594Ssyrinxtarget_next_address(struct target_address *addrs) 659216594Ssyrinx{ 660216594Ssyrinx if (addrs == NULL) 661216594Ssyrinx return (NULL); 662216594Ssyrinx 663216594Ssyrinx return (SLIST_NEXT(addrs, ta)); 664216594Ssyrinx} 665216594Ssyrinx 666216594Ssyrinxstruct target_address * 667216594Ssyrinxtarget_new_address(char *aname) 668216594Ssyrinx{ 669216594Ssyrinx int cmp; 670216594Ssyrinx struct target_address *addrs, *temp, *prev; 671216594Ssyrinx 672216594Ssyrinx SLIST_FOREACH(addrs, &target_addresslist, ta) 673216594Ssyrinx if (strcmp(aname, addrs->name) == 0) 674216594Ssyrinx return (NULL); 675216594Ssyrinx 676216594Ssyrinx if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) 677216594Ssyrinx return (NULL); 678216594Ssyrinx 679216594Ssyrinx memset(addrs, 0, sizeof(*addrs)); 680216594Ssyrinx strlcpy(addrs->name, aname, sizeof(addrs->name)); 681216594Ssyrinx addrs->timeout = 150; 682216594Ssyrinx addrs->retry = 3; /* XXX */ 683216594Ssyrinx 684216594Ssyrinx if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || 685216594Ssyrinx strcmp(aname, prev->name) < 0) { 686216594Ssyrinx SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); 687216594Ssyrinx return (addrs); 688216594Ssyrinx } 689216594Ssyrinx 690216594Ssyrinx SLIST_FOREACH(temp, &target_addresslist, ta) { 691216594Ssyrinx if ((cmp = strcmp(aname, temp->name)) <= 0) 692216594Ssyrinx break; 693216594Ssyrinx prev = temp; 694216594Ssyrinx } 695216594Ssyrinx 696216594Ssyrinx if (temp == NULL || cmp < 0) 697216594Ssyrinx SLIST_INSERT_AFTER(prev, addrs, ta); 698216594Ssyrinx else if (cmp > 0) 699216594Ssyrinx SLIST_INSERT_AFTER(temp, addrs, ta); 700216594Ssyrinx else { 701216594Ssyrinx syslog(LOG_ERR, "Target address %s exists", addrs->name); 702216594Ssyrinx free(addrs); 703216594Ssyrinx return (NULL); 704216594Ssyrinx } 705216594Ssyrinx 706216594Ssyrinx return (addrs); 707216594Ssyrinx} 708216594Ssyrinx 709216594Ssyrinxint 710216594Ssyrinxtarget_activate_address(struct target_address *addrs) 711216594Ssyrinx{ 712216594Ssyrinx struct sockaddr_in sa; 713216594Ssyrinx 714216594Ssyrinx if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 715216594Ssyrinx syslog(LOG_ERR, "socket(UDP): %m"); 716216594Ssyrinx return (SNMP_ERR_RES_UNAVAIL); 717216594Ssyrinx } 718216594Ssyrinx 719216594Ssyrinx (void)shutdown(addrs->socket, SHUT_RD); 720240191Skevlo memset(&sa, 0, sizeof(sa)); 721216594Ssyrinx sa.sin_len = sizeof(sa); 722216594Ssyrinx sa.sin_family = AF_INET; 723216594Ssyrinx 724216594Ssyrinx sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | 725216594Ssyrinx (addrs->address[1] << 16) | (addrs->address[2] << 8) | 726216594Ssyrinx (addrs->address[3] << 0)); 727346027Sae sa.sin_port = htons(addrs->address[4] << 8 | addrs->address[5]); 728216594Ssyrinx 729216594Ssyrinx if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 730216594Ssyrinx syslog(LOG_ERR, "connect(%s,%u): %m", 731216594Ssyrinx inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 732216594Ssyrinx (void)close(addrs->socket); 733216594Ssyrinx return (SNMP_ERR_GENERR); 734216594Ssyrinx } 735216594Ssyrinx 736216594Ssyrinx addrs->status = RowStatus_active; 737216594Ssyrinx 738216594Ssyrinx return (SNMP_ERR_NOERROR); 739216594Ssyrinx} 740216594Ssyrinx 741216594Ssyrinxint 742216594Ssyrinxtarget_delete_address(struct target_address *addrs) 743216594Ssyrinx{ 744216594Ssyrinx SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); 745216594Ssyrinx if (addrs->status == RowStatus_active) 746216594Ssyrinx close(addrs->socket); 747216594Ssyrinx free(addrs); 748216594Ssyrinx 749216594Ssyrinx return (0); 750216594Ssyrinx} 751216594Ssyrinx 752216594Ssyrinxstruct target_param * 753216594Ssyrinxtarget_first_param(void) 754216594Ssyrinx{ 755216594Ssyrinx return (SLIST_FIRST(&target_paramlist)); 756216594Ssyrinx} 757216594Ssyrinx 758216594Ssyrinxstruct target_param * 759216594Ssyrinxtarget_next_param(struct target_param *param) 760216594Ssyrinx{ 761216594Ssyrinx if (param == NULL) 762216594Ssyrinx return (NULL); 763216594Ssyrinx 764216594Ssyrinx return (SLIST_NEXT(param, tp)); 765216594Ssyrinx} 766216594Ssyrinx 767216594Ssyrinxstruct target_param * 768216594Ssyrinxtarget_new_param(char *pname) 769216594Ssyrinx{ 770216594Ssyrinx int cmp; 771216594Ssyrinx struct target_param *param, *temp, *prev; 772216594Ssyrinx 773216594Ssyrinx SLIST_FOREACH(param, &target_paramlist, tp) 774216594Ssyrinx if (strcmp(pname, param->name) == 0) 775216594Ssyrinx return (NULL); 776216594Ssyrinx 777216594Ssyrinx if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) 778216594Ssyrinx return (NULL); 779216594Ssyrinx 780216594Ssyrinx memset(param, 0, sizeof(*param)); 781216594Ssyrinx strlcpy(param->name, pname, sizeof(param->name)); 782216594Ssyrinx 783216594Ssyrinx if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || 784216594Ssyrinx strcmp(pname, prev->name) < 0) { 785216594Ssyrinx SLIST_INSERT_HEAD(&target_paramlist, param, tp); 786216594Ssyrinx return (param); 787216594Ssyrinx } 788216594Ssyrinx 789216594Ssyrinx SLIST_FOREACH(temp, &target_paramlist, tp) { 790216594Ssyrinx if ((cmp = strcmp(pname, temp->name)) <= 0) 791216594Ssyrinx break; 792216594Ssyrinx prev = temp; 793216594Ssyrinx } 794216594Ssyrinx 795216594Ssyrinx if (temp == NULL || cmp < 0) 796216594Ssyrinx SLIST_INSERT_AFTER(prev, param, tp); 797216594Ssyrinx else if (cmp > 0) 798216594Ssyrinx SLIST_INSERT_AFTER(temp, param, tp); 799216594Ssyrinx else { 800216594Ssyrinx syslog(LOG_ERR, "Target parameter %s exists", param->name); 801216594Ssyrinx free(param); 802216594Ssyrinx return (NULL); 803216594Ssyrinx } 804216594Ssyrinx 805216594Ssyrinx return (param); 806216594Ssyrinx} 807216594Ssyrinx 808216594Ssyrinxint 809216594Ssyrinxtarget_delete_param(struct target_param *param) 810216594Ssyrinx{ 811216594Ssyrinx SLIST_REMOVE(&target_paramlist, param, target_param, tp); 812216594Ssyrinx free(param); 813216594Ssyrinx 814216594Ssyrinx return (0); 815216594Ssyrinx} 816216594Ssyrinx 817216594Ssyrinxstruct target_notify * 818216594Ssyrinxtarget_first_notify(void) 819216594Ssyrinx{ 820216594Ssyrinx return (SLIST_FIRST(&target_notifylist)); 821216594Ssyrinx} 822216594Ssyrinx 823216594Ssyrinxstruct target_notify * 824216594Ssyrinxtarget_next_notify(struct target_notify *notify) 825216594Ssyrinx{ 826216594Ssyrinx if (notify == NULL) 827216594Ssyrinx return (NULL); 828216594Ssyrinx 829216594Ssyrinx return (SLIST_NEXT(notify, tn)); 830216594Ssyrinx} 831216594Ssyrinx 832216594Ssyrinxstruct target_notify * 833216594Ssyrinxtarget_new_notify(char *nname) 834216594Ssyrinx{ 835216594Ssyrinx int cmp; 836216594Ssyrinx struct target_notify *notify, *temp, *prev; 837216594Ssyrinx 838216594Ssyrinx SLIST_FOREACH(notify, &target_notifylist, tn) 839216594Ssyrinx if (strcmp(nname, notify->name) == 0) 840216594Ssyrinx return (NULL); 841216594Ssyrinx 842216594Ssyrinx if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) 843216594Ssyrinx return (NULL); 844216594Ssyrinx 845216594Ssyrinx memset(notify, 0, sizeof(*notify)); 846216594Ssyrinx strlcpy(notify->name, nname, sizeof(notify->name)); 847216594Ssyrinx 848216594Ssyrinx if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || 849216594Ssyrinx strcmp(nname, prev->name) < 0) { 850216594Ssyrinx SLIST_INSERT_HEAD(&target_notifylist, notify, tn); 851216594Ssyrinx return (notify); 852216594Ssyrinx } 853216594Ssyrinx 854216594Ssyrinx SLIST_FOREACH(temp, &target_notifylist, tn) { 855216594Ssyrinx if ((cmp = strcmp(nname, temp->name)) <= 0) 856216594Ssyrinx break; 857216594Ssyrinx prev = temp; 858216594Ssyrinx } 859216594Ssyrinx 860216594Ssyrinx if (temp == NULL || cmp < 0) 861216594Ssyrinx SLIST_INSERT_AFTER(prev, notify, tn); 862216594Ssyrinx else if (cmp > 0) 863216594Ssyrinx SLIST_INSERT_AFTER(temp, notify, tn); 864216594Ssyrinx else { 865216594Ssyrinx syslog(LOG_ERR, "Notification target %s exists", notify->name); 866216594Ssyrinx free(notify); 867216594Ssyrinx return (NULL); 868216594Ssyrinx } 869216594Ssyrinx 870216594Ssyrinx return (notify); 871216594Ssyrinx} 872216594Ssyrinx 873216594Ssyrinxint 874216594Ssyrinxtarget_delete_notify(struct target_notify *notify) 875216594Ssyrinx{ 876216594Ssyrinx SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); 877216594Ssyrinx free(notify); 878216594Ssyrinx 879216594Ssyrinx return (0); 880216594Ssyrinx} 881216594Ssyrinx 882216594Ssyrinxvoid 883216594Ssyrinxtarget_flush_all(void) 884216594Ssyrinx{ 885216594Ssyrinx struct target_address *addrs; 886216594Ssyrinx struct target_param *param; 887216594Ssyrinx struct target_notify *notify; 888216594Ssyrinx 889216594Ssyrinx while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { 890216594Ssyrinx SLIST_REMOVE_HEAD(&target_addresslist, ta); 891216594Ssyrinx if (addrs->status == RowStatus_active) 892216594Ssyrinx close(addrs->socket); 893216594Ssyrinx free(addrs); 894216594Ssyrinx } 895216594Ssyrinx SLIST_INIT(&target_addresslist); 896216594Ssyrinx 897216594Ssyrinx while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { 898216594Ssyrinx SLIST_REMOVE_HEAD(&target_paramlist, tp); 899216594Ssyrinx free(param); 900216594Ssyrinx } 901216594Ssyrinx SLIST_INIT(&target_paramlist); 902216594Ssyrinx 903216594Ssyrinx while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { 904216594Ssyrinx SLIST_REMOVE_HEAD(&target_notifylist, tn); 905216594Ssyrinx free(notify); 906216594Ssyrinx } 907216594Ssyrinx SLIST_INIT(&target_notifylist); 908216594Ssyrinx} 909