trap.c revision 292815
1109001Sbenno/*
2109001Sbenno * Copyright (c) 2001-2003
3109001Sbenno *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4109001Sbenno *	All rights reserved.
5109001Sbenno *
6109001Sbenno * Author: Harti Brandt <harti@freebsd.org>
7109001Sbenno *
8109001Sbenno * Copyright (c) 2010 The FreeBSD Foundation
9109001Sbenno * All rights reserved.
10109001Sbenno *
11109001Sbenno * Portions of this software were developed by Shteryana Sotirova Shopova
12109001Sbenno * under sponsorship from the FreeBSD Foundation.
13109001Sbenno *
14109001Sbenno * Redistribution and use in source and binary forms, with or without
15109001Sbenno * modification, are permitted provided that the following conditions
16109001Sbenno * are met:
17109001Sbenno * 1. Redistributions of source code must retain the above copyright
18109001Sbenno *    notice, this list of conditions and the following disclaimer.
19109001Sbenno * 2. Redistributions in binary form must reproduce the above copyright
20109001Sbenno *    notice, this list of conditions and the following disclaimer in the
21109001Sbenno *    documentation and/or other materials provided with the distribution.
22109001Sbenno *
23109001Sbenno * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24109001Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25109001Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26109001Sbenno * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27109001Sbenno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28109001Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29109001Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30109001Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31131102Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32109001Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33109001Sbenno * SUCH DAMAGE.
34109001Sbenno *
35109001Sbenno * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $
36109001Sbenno *
37109001Sbenno * TrapSinkTable
38183882Snwhitehorn */
39186128Snwhitehorn#include <sys/types.h>
40109001Sbenno#include <sys/queue.h>
41119291Simp#include <sys/sysctl.h>
42119291Simp#include <sys/un.h>
43119291Simp#include <stdint.h>
44109001Sbenno#include <stdio.h>
45109001Sbenno#include <stdlib.h>
46109001Sbenno#include <stdarg.h>
47109001Sbenno#include <stdarg.h>
48109001Sbenno#include <string.h>
49183882Snwhitehorn#include <ctype.h>
50186128Snwhitehorn#include <syslog.h>
51186128Snwhitehorn#include <unistd.h>
52109001Sbenno#include <netinet/in.h>
53109001Sbenno#include <arpa/inet.h>
54109001Sbenno
55109001Sbenno#include "snmpmod.h"
56109001Sbenno#include "snmpd.h"
57109001Sbenno#include "tree.h"
58109001Sbenno#include "oid.h"
59109001Sbenno
60109001Sbennostruct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list);
61109001Sbenno
62109001Sbenno/* List of target addresses */
63109001Sbennostatic struct target_addresslist target_addresslist =
64109001Sbenno    SLIST_HEAD_INITIALIZER(target_addresslist);
65109001Sbenno
66109001Sbenno/* List of target parameters */
67109001Sbennostatic struct target_paramlist target_paramlist =
68109001Sbenno    SLIST_HEAD_INITIALIZER(target_paramlist);
69109001Sbenno
70109001Sbenno/* List of notification targets */
71109001Sbennostatic struct target_notifylist target_notifylist =
72109001Sbenno    SLIST_HEAD_INITIALIZER(target_notifylist);
73109001Sbenno
74109001Sbennostatic const struct asn_oid oid_begemotTrapSinkTable =
75109001Sbenno    OIDX_begemotTrapSinkTable;
76186128Snwhitehornstatic const struct asn_oid oid_sysUpTime = OIDX_sysUpTime;
77109001Sbennostatic const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID;
78183882Snwhitehorn
79183882Snwhitehornstruct trapsink_dep {
80183882Snwhitehorn	struct snmp_dependency dep;
81109001Sbenno	u_int	set;
82109001Sbenno	u_int	status;
83109001Sbenno	u_char	comm[SNMP_COMMUNITY_MAXLEN + 1];
84154079Sjhb	u_int	version;
85109001Sbenno	u_int	rb;
86186128Snwhitehorn	u_int	rb_status;
87186128Snwhitehorn	u_int	rb_version;
88186128Snwhitehorn	u_char	rb_comm[SNMP_COMMUNITY_MAXLEN + 1];
89186128Snwhitehorn};
90186128Snwhitehornenum {
91186128Snwhitehorn	TDEP_STATUS	= 0x0001,
92186128Snwhitehorn	TDEP_COMM	= 0x0002,
93186128Snwhitehorn	TDEP_VERSION	= 0x0004,
94186128Snwhitehorn
95186128Snwhitehorn	TDEP_CREATE	= 0x0001,
96186128Snwhitehorn	TDEP_MODIFY	= 0x0002,
97186128Snwhitehorn	TDEP_DESTROY	= 0x0004,
98154079Sjhb};
99186128Snwhitehorn
100109001Sbennostatic int
101109001Sbennotrapsink_create(struct trapsink_dep *tdep)
102109001Sbenno{
103109001Sbenno	struct trapsink *t;
104109001Sbenno	struct sockaddr_in sa;
105109001Sbenno
106109001Sbenno	if ((t = malloc(sizeof(*t))) == NULL)
107109001Sbenno		return (SNMP_ERR_RES_UNAVAIL);
108109001Sbenno
109109001Sbenno	t->index = tdep->dep.idx;
110183882Snwhitehorn	t->status = TRAPSINK_NOT_READY;
111183882Snwhitehorn	t->comm[0] = '\0';
112109001Sbenno	t->version = TRAPSINK_V2;
113109001Sbenno
114183882Snwhitehorn	if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
115183882Snwhitehorn		syslog(LOG_ERR, "socket(UDP): %m");
116109001Sbenno		free(t);
117109001Sbenno		return (SNMP_ERR_RES_UNAVAIL);
118109001Sbenno	}
119109001Sbenno	(void)shutdown(t->socket, SHUT_RD);
120109001Sbenno	memset(&sa, 0, sizeof(sa));
121186128Snwhitehorn	sa.sin_len = sizeof(sa);
122186128Snwhitehorn	sa.sin_family = AF_INET;
123186128Snwhitehorn	sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) |
124186128Snwhitehorn	    (t->index.subs[1] << 16) | (t->index.subs[2] << 8) |
125186128Snwhitehorn	    (t->index.subs[3] << 0));
126186128Snwhitehorn	sa.sin_port = htons(t->index.subs[4]);
127186128Snwhitehorn
128186128Snwhitehorn	if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
129186128Snwhitehorn		syslog(LOG_ERR, "connect(%s,%u): %m",
130109001Sbenno		    inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
131109001Sbenno		(void)close(t->socket);
132109001Sbenno		free(t);
133109001Sbenno		return (SNMP_ERR_GENERR);
134109001Sbenno	}
135109001Sbenno
136183882Snwhitehorn	if (tdep->set & TDEP_VERSION)
137186128Snwhitehorn		t->version = tdep->version;
138183882Snwhitehorn	if (tdep->set & TDEP_COMM)
139183882Snwhitehorn		strcpy(t->comm, tdep->comm);
140183882Snwhitehorn
141183882Snwhitehorn	if (t->comm[0] != '\0')
142183882Snwhitehorn		t->status = TRAPSINK_NOT_IN_SERVICE;
143183882Snwhitehorn
144183882Snwhitehorn	/* look whether we should activate */
145186128Snwhitehorn	if (tdep->status == 4) {
146186128Snwhitehorn		if (t->status == TRAPSINK_NOT_READY) {
147186128Snwhitehorn			if (t->socket != -1)
148186128Snwhitehorn				(void)close(t->socket);
149186128Snwhitehorn			free(t);
150186128Snwhitehorn			return (SNMP_ERR_INCONS_VALUE);
151186128Snwhitehorn		}
152186128Snwhitehorn		t->status = TRAPSINK_ACTIVE;
153186128Snwhitehorn	}
154186128Snwhitehorn
155186128Snwhitehorn	INSERT_OBJECT_OID(t, &trapsink_list);
156186128Snwhitehorn
157186128Snwhitehorn	tdep->rb |= TDEP_CREATE;
158186128Snwhitehorn
159186128Snwhitehorn	return (SNMP_ERR_NOERROR);
160186128Snwhitehorn}
161186128Snwhitehorn
162186128Snwhitehornstatic void
163186128Snwhitehorntrapsink_free(struct trapsink *t)
164186128Snwhitehorn{
165186128Snwhitehorn	TAILQ_REMOVE(&trapsink_list, t, link);
166186128Snwhitehorn	if (t->socket != -1)
167186128Snwhitehorn		(void)close(t->socket);
168186128Snwhitehorn	free(t);
169186128Snwhitehorn}
170186128Snwhitehorn
171186128Snwhitehornstatic int
172186128Snwhitehorntrapsink_modify(struct trapsink *t, struct trapsink_dep *tdep)
173186128Snwhitehorn{
174186128Snwhitehorn	tdep->rb_status = t->status;
175186128Snwhitehorn	tdep->rb_version = t->version;
176186128Snwhitehorn	strcpy(tdep->rb_comm, t->comm);
177186128Snwhitehorn
178186128Snwhitehorn	if (tdep->set & TDEP_STATUS) {
179		/* if we are active and should move to not_in_service do
180		 * this first */
181		if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) {
182			t->status = TRAPSINK_NOT_IN_SERVICE;
183			tdep->rb |= TDEP_MODIFY;
184		}
185	}
186
187	if (tdep->set & TDEP_VERSION)
188		t->version = tdep->version;
189	if (tdep->set & TDEP_COMM)
190		strcpy(t->comm, tdep->comm);
191
192	if (tdep->set & TDEP_STATUS) {
193		/* if we were inactive and should go active - do this now */
194		if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) {
195			if (t->comm[0] == '\0') {
196				t->status = tdep->rb_status;
197				t->version = tdep->rb_version;
198				strcpy(t->comm, tdep->rb_comm);
199				return (SNMP_ERR_INCONS_VALUE);
200			}
201			t->status = TRAPSINK_ACTIVE;
202			tdep->rb |= TDEP_MODIFY;
203		}
204	}
205	return (SNMP_ERR_NOERROR);
206}
207
208static int
209trapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep)
210{
211	if (tdep->set & TDEP_STATUS)
212		t->status = tdep->rb_status;
213	if (tdep->set & TDEP_VERSION)
214		t->version = tdep->rb_version;
215	if (tdep->set & TDEP_COMM)
216		strcpy(t->comm, tdep->rb_comm);
217
218	return (SNMP_ERR_NOERROR);
219}
220
221static int
222trapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t,
223    struct trapsink_dep *tdep)
224{
225	t->status = TRAPSINK_DESTROY;
226	tdep->rb_status = t->status;
227	tdep->rb |= TDEP_DESTROY;
228	return (SNMP_ERR_NOERROR);
229}
230
231static int
232trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep)
233{
234	t->status = tdep->rb_status;
235	return (SNMP_ERR_NOERROR);
236}
237
238static int
239trapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep,
240    enum snmp_depop op)
241{
242	struct trapsink_dep *tdep = (struct trapsink_dep *)dep;
243	struct trapsink *t;
244
245	t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0);
246
247	switch (op) {
248
249	  case SNMP_DEPOP_COMMIT:
250		if (tdep->set & TDEP_STATUS) {
251			switch (tdep->status) {
252
253			  case 1:
254			  case 2:
255				if (t == NULL)
256					return (SNMP_ERR_INCONS_VALUE);
257				return (trapsink_modify(t, tdep));
258
259			  case 4:
260			  case 5:
261				if (t != NULL)
262					return (SNMP_ERR_INCONS_VALUE);
263				return (trapsink_create(tdep));
264
265			  case 6:
266				if (t == NULL)
267					return (SNMP_ERR_NOERROR);
268				return (trapsink_destroy(ctx, t, tdep));
269			}
270		} else if (tdep->set != 0)
271			return (trapsink_modify(t, tdep));
272
273		return (SNMP_ERR_NOERROR);
274
275	  case SNMP_DEPOP_ROLLBACK:
276		if (tdep->rb & TDEP_CREATE) {
277			trapsink_free(t);
278			return (SNMP_ERR_NOERROR);
279		}
280		if (tdep->rb & TDEP_MODIFY)
281			return (trapsink_unmodify(t, tdep));
282		if(tdep->rb & TDEP_DESTROY)
283			return (trapsink_undestroy(t, tdep));
284		return (SNMP_ERR_NOERROR);
285
286	  case SNMP_DEPOP_FINISH:
287		if ((tdep->rb & TDEP_DESTROY) && t != NULL &&
288		    ctx->code == SNMP_RET_OK)
289			trapsink_free(t);
290		return (SNMP_ERR_NOERROR);
291	}
292	abort();
293}
294
295int
296op_trapsink(struct snmp_context *ctx, struct snmp_value *value,
297    u_int sub, u_int iidx, enum snmp_op op)
298{
299	struct trapsink *t;
300	u_char ipa[4];
301	int32_t port;
302	struct asn_oid idx;
303	struct trapsink_dep *tdep;
304	u_char *p;
305
306	t = NULL;		/* gcc */
307
308	switch (op) {
309
310	  case SNMP_OP_GETNEXT:
311		if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
312			return (SNMP_ERR_NOSUCHNAME);
313		index_append(&value->var, sub, &t->index);
314		break;
315
316	  case SNMP_OP_GET:
317		if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
318			return (SNMP_ERR_NOSUCHNAME);
319		break;
320
321	  case SNMP_OP_SET:
322		if (index_decode(&value->var, sub, iidx, ipa, &port) ||
323		    port == 0 || port > 65535)
324			return (SNMP_ERR_NO_CREATION);
325		t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub);
326
327		asn_slice_oid(&idx, &value->var, sub, value->var.len);
328
329		tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx,
330		    &oid_begemotTrapSinkTable, &idx,
331		    sizeof(*tdep), trapsink_dep);
332		if (tdep == NULL)
333			return (SNMP_ERR_RES_UNAVAIL);
334
335		switch (value->var.subs[sub - 1]) {
336
337		  case LEAF_begemotTrapSinkStatus:
338			if (tdep->set & TDEP_STATUS)
339				return (SNMP_ERR_INCONS_VALUE);
340			switch (value->v.integer) {
341
342			  case 1:
343			  case 2:
344				if (t == NULL)
345					return (SNMP_ERR_INCONS_VALUE);
346				break;
347
348			  case 4:
349			  case 5:
350				if (t != NULL)
351					return (SNMP_ERR_INCONS_VALUE);
352				break;
353
354			  case 6:
355				break;
356
357			  default:
358				return (SNMP_ERR_WRONG_VALUE);
359			}
360			tdep->status = value->v.integer;
361			tdep->set |= TDEP_STATUS;
362			return (SNMP_ERR_NOERROR);
363
364		  case LEAF_begemotTrapSinkComm:
365			if (tdep->set & TDEP_COMM)
366				return (SNMP_ERR_INCONS_VALUE);
367			if (value->v.octetstring.len == 0 ||
368			    value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN)
369				return (SNMP_ERR_WRONG_VALUE);
370			for (p = value->v.octetstring.octets;
371			     p < value->v.octetstring.octets + value->v.octetstring.len;
372			     p++) {
373				if (!isascii(*p) || !isprint(*p))
374					return (SNMP_ERR_WRONG_VALUE);
375			}
376			tdep->set |= TDEP_COMM;
377			strncpy(tdep->comm, value->v.octetstring.octets,
378			    value->v.octetstring.len);
379			tdep->comm[value->v.octetstring.len] = '\0';
380			return (SNMP_ERR_NOERROR);
381
382		  case LEAF_begemotTrapSinkVersion:
383			if (tdep->set & TDEP_VERSION)
384				return (SNMP_ERR_INCONS_VALUE);
385			if (value->v.integer != TRAPSINK_V1 &&
386			    value->v.integer != TRAPSINK_V2)
387				return (SNMP_ERR_WRONG_VALUE);
388			tdep->version = value->v.integer;
389			tdep->set |= TDEP_VERSION;
390			return (SNMP_ERR_NOERROR);
391		}
392		if (t == NULL)
393			return (SNMP_ERR_INCONS_NAME);
394		else
395			return (SNMP_ERR_NOT_WRITEABLE);
396
397
398	  case SNMP_OP_ROLLBACK:
399	  case SNMP_OP_COMMIT:
400		return (SNMP_ERR_NOERROR);
401	}
402
403	switch (value->var.subs[sub - 1]) {
404
405	  case LEAF_begemotTrapSinkStatus:
406		value->v.integer = t->status;
407		break;
408
409	  case LEAF_begemotTrapSinkComm:
410		return (string_get(value, t->comm, -1));
411
412	  case LEAF_begemotTrapSinkVersion:
413		value->v.integer = t->version;
414		break;
415
416	}
417	return (SNMP_ERR_NOERROR);
418}
419
420static void
421snmp_create_v1_trap(struct snmp_pdu *pdu, char *com,
422    const struct asn_oid *trap_oid)
423{
424	memset(pdu, 0, sizeof(*pdu));
425	strcpy(pdu->community, com);
426
427	pdu->version = SNMP_V1;
428	pdu->type = SNMP_PDU_TRAP;
429	pdu->enterprise = systemg.object_id;
430	memcpy(pdu->agent_addr, snmpd.trap1addr, 4);
431	pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1;
432	pdu->specific_trap = 0;
433	pdu->time_stamp = get_ticks() - start_tick;
434	pdu->nbindings = 0;
435}
436
437static void
438snmp_create_v2_trap(struct snmp_pdu *pdu, char *com,
439    const struct asn_oid *trap_oid)
440{
441	memset(pdu, 0, sizeof(*pdu));
442	strcpy(pdu->community, com);
443
444	pdu->version = SNMP_V2c;
445	pdu->type = SNMP_PDU_TRAP2;
446	pdu->request_id = reqid_next(trap_reqid);
447	pdu->error_index = 0;
448	pdu->error_status = SNMP_ERR_NOERROR;
449
450	pdu->bindings[0].var = oid_sysUpTime;
451	pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0;
452	pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS;
453	pdu->bindings[0].v.uint32 = get_ticks() - start_tick;
454
455	pdu->bindings[1].var = oid_snmpTrapOID;
456	pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0;
457	pdu->bindings[1].syntax = SNMP_SYNTAX_OID;
458	pdu->bindings[1].v.oid = *trap_oid;
459
460	pdu->nbindings = 2;
461}
462
463static void
464snmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target,
465    const struct asn_oid *trap_oid)
466{
467	uint64_t etime;
468	struct usm_user *usmuser;
469
470	memset(pdu, 0, sizeof(*pdu));
471
472	pdu->version = SNMP_V3;
473	pdu->type = SNMP_PDU_TRAP2;
474	pdu->request_id = reqid_next(trap_reqid);
475	pdu->error_index = 0;
476	pdu->error_status = SNMP_ERR_NOERROR;
477
478	pdu->bindings[0].var = oid_sysUpTime;
479	pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0;
480	pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS;
481	pdu->bindings[0].v.uint32 = get_ticks() - start_tick;
482
483	pdu->bindings[1].var = oid_snmpTrapOID;
484	pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0;
485	pdu->bindings[1].syntax = SNMP_SYNTAX_OID;
486	pdu->bindings[1].v.oid = *trap_oid;
487
488	pdu->nbindings = 2;
489
490	etime = (get_ticks() - start_tick)  / 100ULL;
491	if (etime < INT32_MAX)
492		snmpd_engine.engine_time = etime;
493	else {
494		start_tick = get_ticks();
495		set_snmpd_engine();
496		snmpd_engine.engine_time = start_tick;
497	}
498
499	memcpy(pdu->engine.engine_id, snmpd_engine.engine_id,
500	    snmpd_engine.engine_len);
501	pdu->engine.engine_len = snmpd_engine.engine_len;
502	pdu->engine.engine_boots = snmpd_engine.engine_boots;
503	pdu->engine.engine_time = snmpd_engine.engine_time;
504	pdu->engine.max_msg_size = snmpd_engine.max_msg_size;
505	strlcpy(pdu->user.sec_name, target->secname,
506	    sizeof(pdu->user.sec_name));
507	pdu->security_model = target->sec_model;
508
509	pdu->context_engine_len = snmpd_engine.engine_len;
510	memcpy(pdu->context_engine, snmpd_engine.engine_id,
511	    snmpd_engine.engine_len);
512
513	if (target->sec_model == SNMP_SECMODEL_USM &&
514	    target->sec_level != SNMP_noAuthNoPriv) {
515	    	usmuser = usm_find_user(pdu->engine.engine_id,
516	    	   pdu->engine.engine_len, pdu->user.sec_name);
517		if (usmuser != NULL) {
518			pdu->user.auth_proto = usmuser->suser.auth_proto;
519			pdu->user.priv_proto = usmuser->suser.priv_proto;
520			memcpy(pdu->user.auth_key, usmuser->suser.auth_key,
521			    sizeof(pdu->user.auth_key));
522			memcpy(pdu->user.priv_key, usmuser->suser.priv_key,
523			    sizeof(pdu->user.priv_key));
524		}
525		snmp_pdu_init_secparams(pdu);
526	}
527}
528
529void
530snmp_send_trap(const struct asn_oid *trap_oid, ...)
531{
532	struct snmp_pdu pdu;
533	struct trapsink *t;
534	const struct snmp_value *v;
535	struct target_notify *n;
536	struct target_address *ta;
537	struct target_param *tp;
538
539	va_list ap;
540	u_char *sndbuf;
541	char *tag;
542	size_t sndlen;
543	ssize_t len;
544	int32_t ip;
545
546	TAILQ_FOREACH(t, &trapsink_list, link) {
547		if (t->status != TRAPSINK_ACTIVE)
548			continue;
549
550		if (t->version == TRAPSINK_V1)
551			snmp_create_v1_trap(&pdu, t->comm, trap_oid);
552		else
553			snmp_create_v2_trap(&pdu, t->comm, trap_oid);
554
555		va_start(ap, trap_oid);
556		while ((v = va_arg(ap, const struct snmp_value *)) != NULL)
557			pdu.bindings[pdu.nbindings++] = *v;
558		va_end(ap);
559
560		if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) {
561			syslog(LOG_DEBUG, "send trap to %s failed: no access",
562			    t->comm);
563			continue;
564		}
565
566		if ((sndbuf = buf_alloc(1)) == NULL) {
567			syslog(LOG_ERR, "trap send buffer: %m");
568			return;
569		}
570
571		snmp_output(&pdu, sndbuf, &sndlen, "TRAP");
572
573		if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1)
574			syslog(LOG_ERR, "send: %m");
575		else if ((size_t)len != sndlen)
576			syslog(LOG_ERR, "send: short write %zu/%zu",
577			    sndlen, (size_t)len);
578
579		free(sndbuf);
580	}
581
582	SLIST_FOREACH(n, &target_notifylist, tn) {
583		if (n->status != RowStatus_active || n->taglist[0] == '\0')
584			continue;
585
586		SLIST_FOREACH(ta, &target_addresslist, ta)
587			if ((tag = strstr(ta->taglist, n->taglist)) != NULL  &&
588			    (tag[strlen(n->taglist)] == ' ' ||
589			     tag[strlen(n->taglist)] == '\0' ||
590			     tag[strlen(n->taglist)] == '\t' ||
591			     tag[strlen(n->taglist)] == '\r' ||
592			     tag[strlen(n->taglist)] == '\n') &&
593			     ta->status == RowStatus_active)
594				break;
595		if (ta == NULL)
596			continue;
597
598		SLIST_FOREACH(tp, &target_paramlist, tp)
599			if (strcmp(tp->name, ta->paramname) == 0 &&
600			    tp->status == 1)
601				break;
602		if (tp == NULL)
603			continue;
604
605		switch (tp->mpmodel) {
606		case SNMP_MPM_SNMP_V1:
607			snmp_create_v1_trap(&pdu, tp->secname, trap_oid);
608			break;
609
610		case SNMP_MPM_SNMP_V2c:
611			snmp_create_v2_trap(&pdu, tp->secname, trap_oid);
612			break;
613
614		case SNMP_MPM_SNMP_V3:
615			snmp_create_v3_trap(&pdu, tp, trap_oid);
616			break;
617
618		default:
619			continue;
620		}
621
622		va_start(ap, trap_oid);
623		while ((v = va_arg(ap, const struct snmp_value *)) != NULL)
624			pdu.bindings[pdu.nbindings++] = *v;
625		va_end(ap);
626
627		if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) {
628			syslog(LOG_DEBUG, "send trap to %s failed: no access",
629			    t->comm);
630			continue;
631		}
632
633		if ((sndbuf = buf_alloc(1)) == NULL) {
634			syslog(LOG_ERR, "trap send buffer: %m");
635			return;
636		}
637
638		snmp_output(&pdu, sndbuf, &sndlen, "TRAP");
639
640		if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1)
641			syslog(LOG_ERR, "send: %m");
642		else if ((size_t)len != sndlen)
643			syslog(LOG_ERR, "send: short write %zu/%zu",
644			    sndlen, (size_t)len);
645
646		free(sndbuf);
647	}
648}
649
650/*
651 * RFC 3413 SNMP Management Target MIB
652 */
653struct snmpd_target_stats *
654bsnmpd_get_target_stats(void)
655{
656	return (&snmpd_target_stats);
657}
658
659struct target_address *
660target_first_address(void)
661{
662	return (SLIST_FIRST(&target_addresslist));
663}
664
665struct target_address *
666target_next_address(struct target_address *addrs)
667{
668	if (addrs == NULL)
669		return (NULL);
670
671	return (SLIST_NEXT(addrs, ta));
672}
673
674struct target_address *
675target_new_address(char *aname)
676{
677	int cmp;
678	struct target_address *addrs, *temp, *prev;
679
680	SLIST_FOREACH(addrs, &target_addresslist, ta)
681		if (strcmp(aname, addrs->name) == 0)
682			return (NULL);
683
684	if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL)
685		return (NULL);
686
687	memset(addrs, 0, sizeof(*addrs));
688	strlcpy(addrs->name, aname, sizeof(addrs->name));
689	addrs->timeout = 150;
690	addrs->retry = 3; /* XXX */
691
692	if ((prev = SLIST_FIRST(&target_addresslist)) == NULL ||
693	    strcmp(aname, prev->name) < 0) {
694		SLIST_INSERT_HEAD(&target_addresslist, addrs, ta);
695		return (addrs);
696	}
697
698	SLIST_FOREACH(temp, &target_addresslist, ta) {
699		if ((cmp = strcmp(aname, temp->name)) <= 0)
700			break;
701		prev = temp;
702	}
703
704	if (temp == NULL || cmp < 0)
705		SLIST_INSERT_AFTER(prev, addrs, ta);
706	else if (cmp > 0)
707		SLIST_INSERT_AFTER(temp, addrs, ta);
708	else {
709		syslog(LOG_ERR, "Target address %s exists", addrs->name);
710		free(addrs);
711		return (NULL);
712	}
713
714	return (addrs);
715}
716
717int
718target_activate_address(struct target_address *addrs)
719{
720	struct sockaddr_in sa;
721
722	if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
723		syslog(LOG_ERR, "socket(UDP): %m");
724		return (SNMP_ERR_RES_UNAVAIL);
725	}
726
727	(void)shutdown(addrs->socket, SHUT_RD);
728	memset(&sa, 0, sizeof(sa));
729	sa.sin_len = sizeof(sa);
730	sa.sin_family = AF_INET;
731
732	sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) |
733	    (addrs->address[1] << 16) | (addrs->address[2] << 8) |
734	    (addrs->address[3] << 0));
735	sa.sin_port = htons(addrs->address[4]) << 8 |
736	     htons(addrs->address[5]) << 0;
737
738	if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
739		syslog(LOG_ERR, "connect(%s,%u): %m",
740		    inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
741		(void)close(addrs->socket);
742		return (SNMP_ERR_GENERR);
743	}
744
745	addrs->status = RowStatus_active;
746
747	return (SNMP_ERR_NOERROR);
748}
749
750int
751target_delete_address(struct target_address *addrs)
752{
753	SLIST_REMOVE(&target_addresslist, addrs, target_address, ta);
754	if (addrs->status == RowStatus_active)
755		close(addrs->socket);
756	free(addrs);
757
758	return (0);
759}
760
761struct target_param *
762target_first_param(void)
763{
764	return (SLIST_FIRST(&target_paramlist));
765}
766
767struct target_param *
768target_next_param(struct target_param *param)
769{
770	if (param == NULL)
771		return (NULL);
772
773	return (SLIST_NEXT(param, tp));
774}
775
776struct target_param *
777target_new_param(char *pname)
778{
779	int cmp;
780	struct target_param *param, *temp, *prev;
781
782	SLIST_FOREACH(param, &target_paramlist, tp)
783		if (strcmp(pname, param->name) == 0)
784			return (NULL);
785
786	if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL)
787		return (NULL);
788
789	memset(param, 0, sizeof(*param));
790	strlcpy(param->name, pname, sizeof(param->name));
791
792	if ((prev = SLIST_FIRST(&target_paramlist)) == NULL ||
793	    strcmp(pname, prev->name) < 0) {
794		SLIST_INSERT_HEAD(&target_paramlist, param, tp);
795		return (param);
796	}
797
798	SLIST_FOREACH(temp, &target_paramlist, tp) {
799		if ((cmp = strcmp(pname, temp->name)) <= 0)
800			break;
801		prev = temp;
802	}
803
804	if (temp == NULL || cmp < 0)
805		SLIST_INSERT_AFTER(prev, param, tp);
806	else if (cmp > 0)
807		SLIST_INSERT_AFTER(temp, param, tp);
808	else {
809		syslog(LOG_ERR, "Target parameter %s exists", param->name);
810		free(param);
811		return (NULL);
812	}
813
814	return (param);
815}
816
817int
818target_delete_param(struct target_param *param)
819{
820	SLIST_REMOVE(&target_paramlist, param, target_param, tp);
821	free(param);
822
823	return (0);
824}
825
826struct target_notify *
827target_first_notify(void)
828{
829	return (SLIST_FIRST(&target_notifylist));
830}
831
832struct target_notify *
833target_next_notify(struct target_notify *notify)
834{
835	if (notify == NULL)
836		return (NULL);
837
838	return (SLIST_NEXT(notify, tn));
839}
840
841struct target_notify *
842target_new_notify(char *nname)
843{
844	int cmp;
845	struct target_notify *notify, *temp, *prev;
846
847	SLIST_FOREACH(notify, &target_notifylist, tn)
848		if (strcmp(nname, notify->name) == 0)
849			return (NULL);
850
851	if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL)
852		return (NULL);
853
854	memset(notify, 0, sizeof(*notify));
855	strlcpy(notify->name, nname, sizeof(notify->name));
856
857	if ((prev = SLIST_FIRST(&target_notifylist)) == NULL ||
858	    strcmp(nname, prev->name) < 0) {
859		SLIST_INSERT_HEAD(&target_notifylist, notify, tn);
860		return (notify);
861	}
862
863	SLIST_FOREACH(temp, &target_notifylist, tn) {
864		if ((cmp = strcmp(nname, temp->name)) <= 0)
865			break;
866		prev = temp;
867	}
868
869	if (temp == NULL || cmp < 0)
870		SLIST_INSERT_AFTER(prev, notify, tn);
871	else if (cmp > 0)
872		SLIST_INSERT_AFTER(temp, notify, tn);
873	else {
874		syslog(LOG_ERR, "Notification target %s exists", notify->name);
875		free(notify);
876		return (NULL);
877	}
878
879	return (notify);
880}
881
882int
883target_delete_notify(struct target_notify *notify)
884{
885	SLIST_REMOVE(&target_notifylist, notify, target_notify, tn);
886	free(notify);
887
888	return (0);
889}
890
891void
892target_flush_all(void)
893{
894	struct target_address *addrs;
895	struct target_param *param;
896	struct target_notify *notify;
897
898	while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) {
899		SLIST_REMOVE_HEAD(&target_addresslist, ta);
900		if (addrs->status == RowStatus_active)
901			close(addrs->socket);
902		free(addrs);
903	}
904	SLIST_INIT(&target_addresslist);
905
906	while ((param = SLIST_FIRST(&target_paramlist)) != NULL) {
907		SLIST_REMOVE_HEAD(&target_paramlist, tp);
908		free(param);
909	}
910	SLIST_INIT(&target_paramlist);
911
912	while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) {
913		SLIST_REMOVE_HEAD(&target_notifylist, tn);
914		free(notify);
915	}
916	SLIST_INIT(&target_notifylist);
917}
918