]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bsnmp/snmpd/trap.c
Merge openmp trunk r366426, resolve conflicts, and add FREEBSD-Xlist.
[FreeBSD/FreeBSD.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
58 #define SNMPTREE_TYPES
59 #include "tree.h"
60 #include "oid.h"
61
62 struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list);
63
64 /* List of target addresses */
65 static struct target_addresslist target_addresslist =
66     SLIST_HEAD_INITIALIZER(target_addresslist);
67
68 /* List of target parameters */
69 static struct target_paramlist target_paramlist =
70     SLIST_HEAD_INITIALIZER(target_paramlist);
71
72 /* List of notification targets */
73 static struct target_notifylist target_notifylist =
74     SLIST_HEAD_INITIALIZER(target_notifylist);
75
76 static const struct asn_oid oid_begemotTrapSinkTable =
77     OIDX_begemotTrapSinkTable;
78 static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime;
79 static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID;
80
81 struct trapsink_dep {
82         struct snmp_dependency dep;
83         u_int   set;
84         u_int   status;
85         u_char  comm[SNMP_COMMUNITY_MAXLEN + 1];
86         u_int   version;
87         u_int   rb;
88         u_int   rb_status;
89         u_int   rb_version;
90         u_char  rb_comm[SNMP_COMMUNITY_MAXLEN + 1];
91 };
92 enum {
93         TDEP_STATUS     = 0x0001,
94         TDEP_COMM       = 0x0002,
95         TDEP_VERSION    = 0x0004,
96
97         TDEP_CREATE     = 0x0001,
98         TDEP_MODIFY     = 0x0002,
99         TDEP_DESTROY    = 0x0004,
100 };
101
102 static int
103 trapsink_create(struct trapsink_dep *tdep)
104 {
105         struct trapsink *t;
106         struct sockaddr_in sa;
107
108         if ((t = malloc(sizeof(*t))) == NULL)
109                 return (SNMP_ERR_RES_UNAVAIL);
110
111         t->index = tdep->dep.idx;
112         t->status = TRAPSINK_NOT_READY;
113         t->comm[0] = '\0';
114         t->version = TRAPSINK_V2;
115
116         if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
117                 syslog(LOG_ERR, "socket(UDP): %m");
118                 free(t);
119                 return (SNMP_ERR_RES_UNAVAIL);
120         }
121         (void)shutdown(t->socket, SHUT_RD);
122         memset(&sa, 0, sizeof(sa));
123         sa.sin_len = sizeof(sa);
124         sa.sin_family = AF_INET;
125         sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) |
126             (t->index.subs[1] << 16) | (t->index.subs[2] << 8) |
127             (t->index.subs[3] << 0));
128         sa.sin_port = htons(t->index.subs[4]);
129
130         if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
131                 syslog(LOG_ERR, "connect(%s,%u): %m",
132                     inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
133                 (void)close(t->socket);
134                 free(t);
135                 return (SNMP_ERR_GENERR);
136         }
137
138         if (tdep->set & TDEP_VERSION)
139                 t->version = tdep->version;
140         if (tdep->set & TDEP_COMM)
141                 strcpy(t->comm, tdep->comm);
142
143         if (t->comm[0] != '\0')
144                 t->status = TRAPSINK_NOT_IN_SERVICE;
145
146         /* look whether we should activate */
147         if (tdep->status == 4) {
148                 if (t->status == TRAPSINK_NOT_READY) {
149                         if (t->socket != -1)
150                                 (void)close(t->socket);
151                         free(t);
152                         return (SNMP_ERR_INCONS_VALUE);
153                 }
154                 t->status = TRAPSINK_ACTIVE;
155         }
156
157         INSERT_OBJECT_OID(t, &trapsink_list);
158
159         tdep->rb |= TDEP_CREATE;
160
161         return (SNMP_ERR_NOERROR);
162 }
163
164 static void
165 trapsink_free(struct trapsink *t)
166 {
167         TAILQ_REMOVE(&trapsink_list, t, link);
168         if (t->socket != -1)
169                 (void)close(t->socket);
170         free(t);
171 }
172
173 static int
174 trapsink_modify(struct trapsink *t, struct trapsink_dep *tdep)
175 {
176         tdep->rb_status = t->status;
177         tdep->rb_version = t->version;
178         strcpy(tdep->rb_comm, t->comm);
179
180         if (tdep->set & TDEP_STATUS) {
181                 /* if we are active and should move to not_in_service do
182                  * this first */
183                 if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) {
184                         t->status = TRAPSINK_NOT_IN_SERVICE;
185                         tdep->rb |= TDEP_MODIFY;
186                 }
187         }
188
189         if (tdep->set & TDEP_VERSION)
190                 t->version = tdep->version;
191         if (tdep->set & TDEP_COMM)
192                 strcpy(t->comm, tdep->comm);
193
194         if (tdep->set & TDEP_STATUS) {
195                 /* if we were inactive and should go active - do this now */
196                 if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) {
197                         if (t->comm[0] == '\0') {
198                                 t->status = tdep->rb_status;
199                                 t->version = tdep->rb_version;
200                                 strcpy(t->comm, tdep->rb_comm);
201                                 return (SNMP_ERR_INCONS_VALUE);
202                         }
203                         t->status = TRAPSINK_ACTIVE;
204                         tdep->rb |= TDEP_MODIFY;
205                 }
206         }
207         return (SNMP_ERR_NOERROR);
208 }
209
210 static int
211 trapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep)
212 {
213         if (tdep->set & TDEP_STATUS)
214                 t->status = tdep->rb_status;
215         if (tdep->set & TDEP_VERSION)
216                 t->version = tdep->rb_version;
217         if (tdep->set & TDEP_COMM)
218                 strcpy(t->comm, tdep->rb_comm);
219
220         return (SNMP_ERR_NOERROR);
221 }
222
223 static int
224 trapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t,
225     struct trapsink_dep *tdep)
226 {
227         t->status = TRAPSINK_DESTROY;
228         tdep->rb_status = t->status;
229         tdep->rb |= TDEP_DESTROY;
230         return (SNMP_ERR_NOERROR);
231 }
232
233 static int
234 trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep)
235 {
236         t->status = tdep->rb_status;
237         return (SNMP_ERR_NOERROR);
238 }
239
240 static int
241 trapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep,
242     enum snmp_depop op)
243 {
244         struct trapsink_dep *tdep = (struct trapsink_dep *)dep;
245         struct trapsink *t;
246
247         t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0);
248
249         switch (op) {
250
251           case SNMP_DEPOP_COMMIT:
252                 if (tdep->set & TDEP_STATUS) {
253                         switch (tdep->status) {
254
255                           case 1:
256                           case 2:
257                                 if (t == NULL)
258                                         return (SNMP_ERR_INCONS_VALUE);
259                                 return (trapsink_modify(t, tdep));
260
261                           case 4:
262                           case 5:
263                                 if (t != NULL)
264                                         return (SNMP_ERR_INCONS_VALUE);
265                                 return (trapsink_create(tdep));
266
267                           case 6:
268                                 if (t == NULL)
269                                         return (SNMP_ERR_NOERROR);
270                                 return (trapsink_destroy(ctx, t, tdep));
271                         }
272                 } else if (tdep->set != 0)
273                         return (trapsink_modify(t, tdep));
274
275                 return (SNMP_ERR_NOERROR);
276
277           case SNMP_DEPOP_ROLLBACK:
278                 if (tdep->rb & TDEP_CREATE) {
279                         trapsink_free(t);
280                         return (SNMP_ERR_NOERROR);
281                 }
282                 if (tdep->rb & TDEP_MODIFY)
283                         return (trapsink_unmodify(t, tdep));
284                 if(tdep->rb & TDEP_DESTROY)
285                         return (trapsink_undestroy(t, tdep));
286                 return (SNMP_ERR_NOERROR);
287
288           case SNMP_DEPOP_FINISH:
289                 if ((tdep->rb & TDEP_DESTROY) && t != NULL &&
290                     ctx->code == SNMP_RET_OK)
291                         trapsink_free(t);
292                 return (SNMP_ERR_NOERROR);
293         }
294         abort();
295 }
296
297 int
298 op_trapsink(struct snmp_context *ctx, struct snmp_value *value,
299     u_int sub, u_int iidx, enum snmp_op op)
300 {
301         struct trapsink *t;
302         u_char ipa[4];
303         int32_t port;
304         struct asn_oid idx;
305         struct trapsink_dep *tdep;
306         u_char *p;
307
308         t = NULL;               /* gcc */
309
310         switch (op) {
311
312           case SNMP_OP_GETNEXT:
313                 if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
314                         return (SNMP_ERR_NOSUCHNAME);
315                 index_append(&value->var, sub, &t->index);
316                 break;
317
318           case SNMP_OP_GET:
319                 if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
320                         return (SNMP_ERR_NOSUCHNAME);
321                 break;
322
323           case SNMP_OP_SET:
324                 if (index_decode(&value->var, sub, iidx, ipa, &port) ||
325                     port == 0 || port > 65535)
326                         return (SNMP_ERR_NO_CREATION);
327                 t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub);
328
329                 asn_slice_oid(&idx, &value->var, sub, value->var.len);
330
331                 tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx,
332                     &oid_begemotTrapSinkTable, &idx,
333                     sizeof(*tdep), trapsink_dep);
334                 if (tdep == NULL)
335                         return (SNMP_ERR_RES_UNAVAIL);
336
337                 switch (value->var.subs[sub - 1]) {
338
339                   case LEAF_begemotTrapSinkStatus:
340                         if (tdep->set & TDEP_STATUS)
341                                 return (SNMP_ERR_INCONS_VALUE);
342                         switch (value->v.integer) {
343
344                           case 1:
345                           case 2:
346                                 if (t == NULL)
347                                         return (SNMP_ERR_INCONS_VALUE);
348                                 break;
349
350                           case 4:
351                           case 5:
352                                 if (t != NULL)
353                                         return (SNMP_ERR_INCONS_VALUE);
354                                 break;
355
356                           case 6:
357                                 break;
358
359                           default:
360                                 return (SNMP_ERR_WRONG_VALUE);
361                         }
362                         tdep->status = value->v.integer;
363                         tdep->set |= TDEP_STATUS;
364                         return (SNMP_ERR_NOERROR);
365
366                   case LEAF_begemotTrapSinkComm:
367                         if (tdep->set & TDEP_COMM)
368                                 return (SNMP_ERR_INCONS_VALUE);
369                         if (value->v.octetstring.len == 0 ||
370                             value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN)
371                                 return (SNMP_ERR_WRONG_VALUE);
372                         for (p = value->v.octetstring.octets;
373                              p < value->v.octetstring.octets + value->v.octetstring.len;
374                              p++) {
375                                 if (!isascii(*p) || !isprint(*p))
376                                         return (SNMP_ERR_WRONG_VALUE);
377                         }
378                         tdep->set |= TDEP_COMM;
379                         strncpy(tdep->comm, value->v.octetstring.octets,
380                             value->v.octetstring.len);
381                         tdep->comm[value->v.octetstring.len] = '\0';
382                         return (SNMP_ERR_NOERROR);
383
384                   case LEAF_begemotTrapSinkVersion:
385                         if (tdep->set & TDEP_VERSION)
386                                 return (SNMP_ERR_INCONS_VALUE);
387                         if (value->v.integer != TRAPSINK_V1 &&
388                             value->v.integer != TRAPSINK_V2)
389                                 return (SNMP_ERR_WRONG_VALUE);
390                         tdep->version = value->v.integer;
391                         tdep->set |= TDEP_VERSION;
392                         return (SNMP_ERR_NOERROR);
393                 }
394                 if (t == NULL)
395                         return (SNMP_ERR_INCONS_NAME);
396                 else
397                         return (SNMP_ERR_NOT_WRITEABLE);
398
399
400           case SNMP_OP_ROLLBACK:
401           case SNMP_OP_COMMIT:
402                 return (SNMP_ERR_NOERROR);
403         }
404
405         switch (value->var.subs[sub - 1]) {
406
407           case LEAF_begemotTrapSinkStatus:
408                 value->v.integer = t->status;
409                 break;
410
411           case LEAF_begemotTrapSinkComm:
412                 return (string_get(value, t->comm, -1));
413
414           case LEAF_begemotTrapSinkVersion:
415                 value->v.integer = t->version;
416                 break;
417
418         }
419         return (SNMP_ERR_NOERROR);
420 }
421
422 static void
423 snmp_create_v1_trap(struct snmp_pdu *pdu, char *com,
424     const struct asn_oid *trap_oid)
425 {
426         memset(pdu, 0, sizeof(*pdu));
427         strlcpy(pdu->community, com, sizeof(pdu->community));
428
429         pdu->version = SNMP_V1;
430         pdu->type = SNMP_PDU_TRAP;
431         pdu->enterprise = systemg.object_id;
432         memcpy(pdu->agent_addr, snmpd.trap1addr, 4);
433         pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1;
434         pdu->specific_trap = 0;
435         pdu->time_stamp = get_ticks() - start_tick;
436         pdu->nbindings = 0;
437 }
438
439 static void
440 snmp_create_v2_trap(struct snmp_pdu *pdu, char *com,
441     const struct asn_oid *trap_oid)
442 {
443         memset(pdu, 0, sizeof(*pdu));
444         strlcpy(pdu->community, com, sizeof(pdu->community));
445
446         pdu->version = SNMP_V2c;
447         pdu->type = SNMP_PDU_TRAP2;
448         pdu->request_id = reqid_next(trap_reqid);
449         pdu->error_index = 0;
450         pdu->error_status = SNMP_ERR_NOERROR;
451
452         pdu->bindings[0].var = oid_sysUpTime;
453         pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0;
454         pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS;
455         pdu->bindings[0].v.uint32 = get_ticks() - start_tick;
456
457         pdu->bindings[1].var = oid_snmpTrapOID;
458         pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0;
459         pdu->bindings[1].syntax = SNMP_SYNTAX_OID;
460         pdu->bindings[1].v.oid = *trap_oid;
461
462         pdu->nbindings = 2;
463 }
464
465 static void
466 snmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target,
467     const struct asn_oid *trap_oid)
468 {
469         struct usm_user *usmuser;
470
471         memset(pdu, 0, sizeof(*pdu));
472
473         pdu->version = SNMP_V3;
474         pdu->type = SNMP_PDU_TRAP2;
475         pdu->request_id = reqid_next(trap_reqid);
476         pdu->error_index = 0;
477         pdu->error_status = SNMP_ERR_NOERROR;
478
479         pdu->bindings[0].var = oid_sysUpTime;
480         pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0;
481         pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS;
482         pdu->bindings[0].v.uint32 = get_ticks() - start_tick;
483
484         pdu->bindings[1].var = oid_snmpTrapOID;
485         pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0;
486         pdu->bindings[1].syntax = SNMP_SYNTAX_OID;
487         pdu->bindings[1].v.oid = *trap_oid;
488
489         pdu->nbindings = 2;
490
491         update_snmpd_engine_time();
492
493         memcpy(pdu->engine.engine_id, snmpd_engine.engine_id,
494             snmpd_engine.engine_len);
495         pdu->engine.engine_len = snmpd_engine.engine_len;
496         pdu->engine.engine_boots = snmpd_engine.engine_boots;
497         pdu->engine.engine_time = snmpd_engine.engine_time;
498         pdu->engine.max_msg_size = snmpd_engine.max_msg_size;
499         strlcpy(pdu->user.sec_name, target->secname,
500             sizeof(pdu->user.sec_name));
501         pdu->security_model = target->sec_model;
502
503         pdu->context_engine_len = snmpd_engine.engine_len;
504         memcpy(pdu->context_engine, snmpd_engine.engine_id,
505             snmpd_engine.engine_len);
506
507         if (target->sec_model == SNMP_SECMODEL_USM &&
508             target->sec_level != SNMP_noAuthNoPriv) {
509                 usmuser = usm_find_user(pdu->engine.engine_id,
510                    pdu->engine.engine_len, pdu->user.sec_name);
511                 if (usmuser != NULL) {
512                         pdu->user.auth_proto = usmuser->suser.auth_proto;
513                         pdu->user.priv_proto = usmuser->suser.priv_proto;
514                         memcpy(pdu->user.auth_key, usmuser->suser.auth_key,
515                             sizeof(pdu->user.auth_key));
516                         memcpy(pdu->user.priv_key, usmuser->suser.priv_key,
517                             sizeof(pdu->user.priv_key));
518                 }
519                 snmp_pdu_init_secparams(pdu);
520         }
521 }
522
523 void
524 snmp_send_trap(const struct asn_oid *trap_oid, ...)
525 {
526         struct snmp_pdu pdu;
527         struct trapsink *t;
528         const struct snmp_value *v;
529         struct target_notify *n;
530         struct target_address *ta;
531         struct target_param *tp;
532
533         va_list ap;
534         u_char *sndbuf;
535         char *tag;
536         size_t sndlen;
537         ssize_t len;
538         int32_t ip;
539
540         TAILQ_FOREACH(t, &trapsink_list, link) {
541                 if (t->status != TRAPSINK_ACTIVE)
542                         continue;
543
544                 if (t->version == TRAPSINK_V1)
545                         snmp_create_v1_trap(&pdu, t->comm, trap_oid);
546                 else
547                         snmp_create_v2_trap(&pdu, t->comm, trap_oid);
548
549                 va_start(ap, trap_oid);
550                 while ((v = va_arg(ap, const struct snmp_value *)) != NULL)
551                         pdu.bindings[pdu.nbindings++] = *v;
552                 va_end(ap);
553
554                 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) {
555                         syslog(LOG_DEBUG, "send trap to %s failed: no access",
556                             t->comm);
557                         continue;
558                 }
559
560                 if ((sndbuf = buf_alloc(1)) == NULL) {
561                         syslog(LOG_ERR, "trap send buffer: %m");
562                         return;
563                 }
564
565                 snmp_output(&pdu, sndbuf, &sndlen, "TRAP");
566
567                 if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1)
568                         syslog(LOG_ERR, "send: %m");
569                 else if ((size_t)len != sndlen)
570                         syslog(LOG_ERR, "send: short write %zu/%zu",
571                             sndlen, (size_t)len);
572
573                 free(sndbuf);
574         }
575
576         SLIST_FOREACH(n, &target_notifylist, tn) {
577                 if (n->status != RowStatus_active || n->taglist[0] == '\0')
578                         continue;
579
580                 SLIST_FOREACH(ta, &target_addresslist, ta)
581                         if ((tag = strstr(ta->taglist, n->taglist)) != NULL  &&
582                             (tag[strlen(n->taglist)] == ' ' ||
583                              tag[strlen(n->taglist)] == '\0' ||
584                              tag[strlen(n->taglist)] == '\t' ||
585                              tag[strlen(n->taglist)] == '\r' ||
586                              tag[strlen(n->taglist)] == '\n') &&
587                              ta->status == RowStatus_active)
588                                 break;
589                 if (ta == NULL)
590                         continue;
591
592                 SLIST_FOREACH(tp, &target_paramlist, tp)
593                         if (strcmp(tp->name, ta->paramname) == 0 &&
594                             tp->status == 1)
595                                 break;
596                 if (tp == NULL)
597                         continue;
598
599                 switch (tp->mpmodel) {
600                 case SNMP_MPM_SNMP_V1:
601                         snmp_create_v1_trap(&pdu, tp->secname, trap_oid);
602                         break;
603
604                 case SNMP_MPM_SNMP_V2c:
605                         snmp_create_v2_trap(&pdu, tp->secname, trap_oid);
606                         break;
607
608                 case SNMP_MPM_SNMP_V3:
609                         snmp_create_v3_trap(&pdu, tp, trap_oid);
610                         break;
611
612                 default:
613                         continue;
614                 }
615
616                 va_start(ap, trap_oid);
617                 while ((v = va_arg(ap, const struct snmp_value *)) != NULL)
618                         pdu.bindings[pdu.nbindings++] = *v;
619                 va_end(ap);
620
621                 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) {
622                         syslog(LOG_DEBUG, "send trap to %s failed: no access",
623                             t->comm);
624                         continue;
625                 }
626
627                 if ((sndbuf = buf_alloc(1)) == NULL) {
628                         syslog(LOG_ERR, "trap send buffer: %m");
629                         return;
630                 }
631
632                 snmp_output(&pdu, sndbuf, &sndlen, "TRAP");
633
634                 if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1)
635                         syslog(LOG_ERR, "send: %m");
636                 else if ((size_t)len != sndlen)
637                         syslog(LOG_ERR, "send: short write %zu/%zu",
638                             sndlen, (size_t)len);
639
640                 free(sndbuf);
641         }
642 }
643
644 /*
645  * RFC 3413 SNMP Management Target MIB
646  */
647 struct snmpd_target_stats *
648 bsnmpd_get_target_stats(void)
649 {
650         return (&snmpd_target_stats);
651 }
652
653 struct target_address *
654 target_first_address(void)
655 {
656         return (SLIST_FIRST(&target_addresslist));
657 }
658
659 struct target_address *
660 target_next_address(struct target_address *addrs)
661 {
662         if (addrs == NULL)
663                 return (NULL);
664
665         return (SLIST_NEXT(addrs, ta));
666 }
667
668 struct target_address *
669 target_new_address(char *aname)
670 {
671         int cmp;
672         struct target_address *addrs, *temp, *prev;
673
674         SLIST_FOREACH(addrs, &target_addresslist, ta)
675                 if (strcmp(aname, addrs->name) == 0)
676                         return (NULL);
677
678         if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL)
679                 return (NULL);
680
681         memset(addrs, 0, sizeof(*addrs));
682         strlcpy(addrs->name, aname, sizeof(addrs->name));
683         addrs->timeout = 150;
684         addrs->retry = 3; /* XXX */
685
686         if ((prev = SLIST_FIRST(&target_addresslist)) == NULL ||
687             strcmp(aname, prev->name) < 0) {
688                 SLIST_INSERT_HEAD(&target_addresslist, addrs, ta);
689                 return (addrs);
690         }
691
692         SLIST_FOREACH(temp, &target_addresslist, ta) {
693                 if ((cmp = strcmp(aname, temp->name)) <= 0)
694                         break;
695                 prev = temp;
696         }
697
698         if (temp == NULL || cmp < 0)
699                 SLIST_INSERT_AFTER(prev, addrs, ta);
700         else if (cmp > 0)
701                 SLIST_INSERT_AFTER(temp, addrs, ta);
702         else {
703                 syslog(LOG_ERR, "Target address %s exists", addrs->name);
704                 free(addrs);
705                 return (NULL);
706         }
707
708         return (addrs);
709 }
710
711 int
712 target_activate_address(struct target_address *addrs)
713 {
714         struct sockaddr_in sa;
715
716         if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
717                 syslog(LOG_ERR, "socket(UDP): %m");
718                 return (SNMP_ERR_RES_UNAVAIL);
719         }
720
721         (void)shutdown(addrs->socket, SHUT_RD);
722         memset(&sa, 0, sizeof(sa));
723         sa.sin_len = sizeof(sa);
724         sa.sin_family = AF_INET;
725
726         sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) |
727             (addrs->address[1] << 16) | (addrs->address[2] << 8) |
728             (addrs->address[3] << 0));
729         sa.sin_port = htons(addrs->address[4] << 8 | addrs->address[5]);
730
731         if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
732                 syslog(LOG_ERR, "connect(%s,%u): %m",
733                     inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
734                 (void)close(addrs->socket);
735                 return (SNMP_ERR_GENERR);
736         }
737
738         addrs->status = RowStatus_active;
739
740         return (SNMP_ERR_NOERROR);
741 }
742
743 int
744 target_delete_address(struct target_address *addrs)
745 {
746         SLIST_REMOVE(&target_addresslist, addrs, target_address, ta);
747         if (addrs->status == RowStatus_active)
748                 close(addrs->socket);
749         free(addrs);
750
751         return (0);
752 }
753
754 struct target_param *
755 target_first_param(void)
756 {
757         return (SLIST_FIRST(&target_paramlist));
758 }
759
760 struct target_param *
761 target_next_param(struct target_param *param)
762 {
763         if (param == NULL)
764                 return (NULL);
765
766         return (SLIST_NEXT(param, tp));
767 }
768
769 struct target_param *
770 target_new_param(char *pname)
771 {
772         int cmp;
773         struct target_param *param, *temp, *prev;
774
775         SLIST_FOREACH(param, &target_paramlist, tp)
776                 if (strcmp(pname, param->name) == 0)
777                         return (NULL);
778
779         if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL)
780                 return (NULL);
781
782         memset(param, 0, sizeof(*param));
783         strlcpy(param->name, pname, sizeof(param->name));
784
785         if ((prev = SLIST_FIRST(&target_paramlist)) == NULL ||
786             strcmp(pname, prev->name) < 0) {
787                 SLIST_INSERT_HEAD(&target_paramlist, param, tp);
788                 return (param);
789         }
790
791         SLIST_FOREACH(temp, &target_paramlist, tp) {
792                 if ((cmp = strcmp(pname, temp->name)) <= 0)
793                         break;
794                 prev = temp;
795         }
796
797         if (temp == NULL || cmp < 0)
798                 SLIST_INSERT_AFTER(prev, param, tp);
799         else if (cmp > 0)
800                 SLIST_INSERT_AFTER(temp, param, tp);
801         else {
802                 syslog(LOG_ERR, "Target parameter %s exists", param->name);
803                 free(param);
804                 return (NULL);
805         }
806
807         return (param);
808 }
809
810 int
811 target_delete_param(struct target_param *param)
812 {
813         SLIST_REMOVE(&target_paramlist, param, target_param, tp);
814         free(param);
815
816         return (0);
817 }
818
819 struct target_notify *
820 target_first_notify(void)
821 {
822         return (SLIST_FIRST(&target_notifylist));
823 }
824
825 struct target_notify *
826 target_next_notify(struct target_notify *notify)
827 {
828         if (notify == NULL)
829                 return (NULL);
830
831         return (SLIST_NEXT(notify, tn));
832 }
833
834 struct target_notify *
835 target_new_notify(char *nname)
836 {
837         int cmp;
838         struct target_notify *notify, *temp, *prev;
839
840         SLIST_FOREACH(notify, &target_notifylist, tn)
841                 if (strcmp(nname, notify->name) == 0)
842                         return (NULL);
843
844         if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL)
845                 return (NULL);
846
847         memset(notify, 0, sizeof(*notify));
848         strlcpy(notify->name, nname, sizeof(notify->name));
849
850         if ((prev = SLIST_FIRST(&target_notifylist)) == NULL ||
851             strcmp(nname, prev->name) < 0) {
852                 SLIST_INSERT_HEAD(&target_notifylist, notify, tn);
853                 return (notify);
854         }
855
856         SLIST_FOREACH(temp, &target_notifylist, tn) {
857                 if ((cmp = strcmp(nname, temp->name)) <= 0)
858                         break;
859                 prev = temp;
860         }
861
862         if (temp == NULL || cmp < 0)
863                 SLIST_INSERT_AFTER(prev, notify, tn);
864         else if (cmp > 0)
865                 SLIST_INSERT_AFTER(temp, notify, tn);
866         else {
867                 syslog(LOG_ERR, "Notification target %s exists", notify->name);
868                 free(notify);
869                 return (NULL);
870         }
871
872         return (notify);
873 }
874
875 int
876 target_delete_notify(struct target_notify *notify)
877 {
878         SLIST_REMOVE(&target_notifylist, notify, target_notify, tn);
879         free(notify);
880
881         return (0);
882 }
883
884 void
885 target_flush_all(void)
886 {
887         struct target_address *addrs;
888         struct target_param *param;
889         struct target_notify *notify;
890
891         while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) {
892                 SLIST_REMOVE_HEAD(&target_addresslist, ta);
893                 if (addrs->status == RowStatus_active)
894                         close(addrs->socket);
895                 free(addrs);
896         }
897         SLIST_INIT(&target_addresslist);
898
899         while ((param = SLIST_FIRST(&target_paramlist)) != NULL) {
900                 SLIST_REMOVE_HEAD(&target_paramlist, tp);
901                 free(param);
902         }
903         SLIST_INIT(&target_paramlist);
904
905         while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) {
906                 SLIST_REMOVE_HEAD(&target_notifylist, tn);
907                 free(notify);
908         }
909         SLIST_INIT(&target_notifylist);
910 }