]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bsnmp/snmpd/trap.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bsnmp / snmpd / trap.c
1 /*
2  * Copyright (c) 2001-2003
3  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *      All rights reserved.
5  *
6  * Author: Harti Brandt <harti@freebsd.org>
7  *
8  * Copyright (c) 2010 The FreeBSD Foundation
9  * All rights reserved.
10  *
11  * Portions of this software were developed by Shteryana Sotirova Shopova
12  * under sponsorship from the FreeBSD Foundation.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 
23  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $
36  *
37  * TrapSinkTable
38  */
39 #include <sys/types.h>
40 #include <sys/queue.h>
41 #include <sys/sysctl.h>
42 #include <sys/un.h>
43 #include <stdint.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #include <ctype.h>
50 #include <syslog.h>
51 #include <unistd.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54
55 #include "snmpmod.h"
56 #include "snmpd.h"
57 #include "tree.h"
58 #include "oid.h"
59
60 struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list);
61
62 /* List of target addresses */
63 struct target_addresslist target_addresslist =
64     SLIST_HEAD_INITIALIZER(target_addresslist);
65
66 /* List of target parameters */
67 struct target_paramlist target_paramlist =
68     SLIST_HEAD_INITIALIZER(target_paramlist);
69
70 /* List of notification targets */
71 struct target_notifylist target_notifylist =
72     SLIST_HEAD_INITIALIZER(target_notifylist);
73
74 static const struct asn_oid oid_begemotTrapSinkTable =
75     OIDX_begemotTrapSinkTable;
76 static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime;
77 static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID;
78
79 struct trapsink_dep {
80         struct snmp_dependency dep;
81         u_int   set;
82         u_int   status;
83         u_char  comm[SNMP_COMMUNITY_MAXLEN + 1];
84         u_int   version;
85         u_int   rb;
86         u_int   rb_status;
87         u_int   rb_version;
88         u_char  rb_comm[SNMP_COMMUNITY_MAXLEN + 1];
89 };
90 enum {
91         TDEP_STATUS     = 0x0001,
92         TDEP_COMM       = 0x0002,
93         TDEP_VERSION    = 0x0004,
94
95         TDEP_CREATE     = 0x0001,
96         TDEP_MODIFY     = 0x0002,
97         TDEP_DESTROY    = 0x0004,
98 };
99
100 static int
101 trapsink_create(struct trapsink_dep *tdep)
102 {
103         struct trapsink *t;
104         struct sockaddr_in sa;
105
106         if ((t = malloc(sizeof(*t))) == NULL)
107                 return (SNMP_ERR_RES_UNAVAIL);
108
109         t->index = tdep->dep.idx;
110         t->status = TRAPSINK_NOT_READY;
111         t->comm[0] = '\0';
112         t->version = TRAPSINK_V2;
113
114         if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
115                 syslog(LOG_ERR, "socket(UDP): %m");
116                 free(t);
117                 return (SNMP_ERR_RES_UNAVAIL);
118         }
119         (void)shutdown(t->socket, SHUT_RD);
120
121         sa.sin_len = sizeof(sa);
122         sa.sin_family = AF_INET;
123         sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) |
124             (t->index.subs[1] << 16) | (t->index.subs[2] << 8) |
125             (t->index.subs[3] << 0));
126         sa.sin_port = htons(t->index.subs[4]);
127
128         if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
129                 syslog(LOG_ERR, "connect(%s,%u): %m",
130                     inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
131                 (void)close(t->socket);
132                 free(t);
133                 return (SNMP_ERR_GENERR);
134         }
135
136         if (tdep->set & TDEP_VERSION)
137                 t->version = tdep->version;
138         if (tdep->set & TDEP_COMM)
139                 strcpy(t->comm, tdep->comm);
140
141         if (t->comm[0] != '\0')
142                 t->status = TRAPSINK_NOT_IN_SERVICE;
143
144         /* look whether we should activate */
145         if (tdep->status == 4) {
146                 if (t->status == TRAPSINK_NOT_READY) {
147                         if (t->socket != -1)
148                                 (void)close(t->socket);
149                         free(t);
150                         return (SNMP_ERR_INCONS_VALUE);
151                 }
152                 t->status = TRAPSINK_ACTIVE;
153         }
154
155         INSERT_OBJECT_OID(t, &trapsink_list);
156
157         tdep->rb |= TDEP_CREATE;
158
159         return (SNMP_ERR_NOERROR);
160 }
161
162 static void
163 trapsink_free(struct trapsink *t)
164 {
165         TAILQ_REMOVE(&trapsink_list, t, link);
166         if (t->socket != -1)
167                 (void)close(t->socket);
168         free(t);
169 }
170
171 static int
172 trapsink_modify(struct trapsink *t, struct trapsink_dep *tdep)
173 {
174         tdep->rb_status = t->status;
175         tdep->rb_version = t->version;
176         strcpy(tdep->rb_comm, t->comm);
177
178         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
208 static int
209 trapsink_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
221 static int
222 trapsink_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
231 static int
232 trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep)
233 {
234         t->status = tdep->rb_status;
235         return (SNMP_ERR_NOERROR);
236 }
237
238 static int
239 trapsink_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
295 int
296 op_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
420 static void
421 snmp_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
437 static void
438 snmp_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
463 static void
464 snmp_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
529 void
530 snmp_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  */
653 struct snmpd_target_stats *
654 bsnmpd_get_target_stats(void)
655 {
656         return (&snmpd_target_stats);
657 }
658
659 struct target_address *
660 target_first_address(void)
661 {
662         return (SLIST_FIRST(&target_addresslist));
663 }
664
665 struct target_address *
666 target_next_address(struct target_address *addrs)
667 {
668         if (addrs == NULL)
669                 return (NULL);
670
671         return (SLIST_NEXT(addrs, ta));
672 }
673
674 struct target_address *
675 target_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
717 int
718 target_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         sa.sin_len = sizeof(sa);
729         sa.sin_family = AF_INET;
730
731         sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) |
732             (addrs->address[1] << 16) | (addrs->address[2] << 8) |
733             (addrs->address[3] << 0));
734         sa.sin_port = htons(addrs->address[4]) << 8 |
735              htons(addrs->address[5]) << 0;
736
737         if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
738                 syslog(LOG_ERR, "connect(%s,%u): %m",
739                     inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
740                 (void)close(addrs->socket);
741                 return (SNMP_ERR_GENERR);
742         }
743
744         addrs->status = RowStatus_active;
745
746         return (SNMP_ERR_NOERROR);
747 }
748
749 int
750 target_delete_address(struct target_address *addrs)
751 {
752         SLIST_REMOVE(&target_addresslist, addrs, target_address, ta);
753         if (addrs->status == RowStatus_active)
754                 close(addrs->socket);
755         free(addrs);
756
757         return (0);
758 }
759
760 struct target_param *
761 target_first_param(void)
762 {
763         return (SLIST_FIRST(&target_paramlist));
764 }
765
766 struct target_param *
767 target_next_param(struct target_param *param)
768 {
769         if (param == NULL)
770                 return (NULL);
771
772         return (SLIST_NEXT(param, tp));
773 }
774
775 struct target_param *
776 target_new_param(char *pname)
777 {
778         int cmp;
779         struct target_param *param, *temp, *prev;
780
781         SLIST_FOREACH(param, &target_paramlist, tp)
782                 if (strcmp(pname, param->name) == 0)
783                         return (NULL);
784
785         if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL)
786                 return (NULL);
787
788         memset(param, 0, sizeof(*param));
789         strlcpy(param->name, pname, sizeof(param->name));
790
791         if ((prev = SLIST_FIRST(&target_paramlist)) == NULL ||
792             strcmp(pname, prev->name) < 0) {
793                 SLIST_INSERT_HEAD(&target_paramlist, param, tp);
794                 return (param);
795         }
796
797         SLIST_FOREACH(temp, &target_paramlist, tp) {
798                 if ((cmp = strcmp(pname, temp->name)) <= 0)
799                         break;
800                 prev = temp;
801         }
802
803         if (temp == NULL || cmp < 0)
804                 SLIST_INSERT_AFTER(prev, param, tp);
805         else if (cmp > 0)
806                 SLIST_INSERT_AFTER(temp, param, tp);
807         else {
808                 syslog(LOG_ERR, "Target parameter %s exists", param->name);
809                 free(param);
810                 return (NULL);
811         }
812
813         return (param);
814 }
815
816 int
817 target_delete_param(struct target_param *param)
818 {
819         SLIST_REMOVE(&target_paramlist, param, target_param, tp);
820         free(param);
821
822         return (0);
823 }
824
825 struct target_notify *
826 target_first_notify(void)
827 {
828         return (SLIST_FIRST(&target_notifylist));
829 }
830
831 struct target_notify *
832 target_next_notify(struct target_notify *notify)
833 {
834         if (notify == NULL)
835                 return (NULL);
836
837         return (SLIST_NEXT(notify, tn));
838 }
839
840 struct target_notify *
841 target_new_notify(char *nname)
842 {
843         int cmp;
844         struct target_notify *notify, *temp, *prev;
845
846         SLIST_FOREACH(notify, &target_notifylist, tn)
847                 if (strcmp(nname, notify->name) == 0)
848                         return (NULL);
849
850         if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL)
851                 return (NULL);
852
853         memset(notify, 0, sizeof(*notify));
854         strlcpy(notify->name, nname, sizeof(notify->name));
855
856         if ((prev = SLIST_FIRST(&target_notifylist)) == NULL ||
857             strcmp(nname, prev->name) < 0) {
858                 SLIST_INSERT_HEAD(&target_notifylist, notify, tn);
859                 return (notify);
860         }
861
862         SLIST_FOREACH(temp, &target_notifylist, tn) {
863                 if ((cmp = strcmp(nname, temp->name)) <= 0)
864                         break;
865                 prev = temp;
866         }
867
868         if (temp == NULL || cmp < 0)
869                 SLIST_INSERT_AFTER(prev, notify, tn);
870         else if (cmp > 0)
871                 SLIST_INSERT_AFTER(temp, notify, tn);
872         else {
873                 syslog(LOG_ERR, "Notification target %s exists", notify->name);
874                 free(notify);
875                 return (NULL);
876         }
877
878         return (notify);
879 }
880
881 int
882 target_delete_notify(struct target_notify *notify)
883 {
884         SLIST_REMOVE(&target_notifylist, notify, target_notify, tn);
885         free(notify);
886
887         return (0);
888 }
889
890 void
891 target_flush_all(void)
892 {
893         struct target_address *addrs;
894         struct target_param *param;
895         struct target_notify *notify;
896
897         while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) {
898                 SLIST_REMOVE_HEAD(&target_addresslist, ta);
899                 if (addrs->status == RowStatus_active)
900                         close(addrs->socket);
901                 free(addrs);
902         }
903         SLIST_INIT(&target_addresslist);
904
905         while ((param = SLIST_FIRST(&target_paramlist)) != NULL) {
906                 SLIST_REMOVE_HEAD(&target_paramlist, tp);
907                 free(param);
908         }
909         SLIST_INIT(&target_paramlist);
910
911         while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) {
912                 SLIST_REMOVE_HEAD(&target_notifylist, tn);
913                 free(notify);
914         }
915         SLIST_INIT(&target_notifylist);
916 }