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
trapsink_create(struct trapsink_dep * tdep)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 memset(&sa, 0, sizeof(sa));
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
trapsink_free(struct trapsink * t)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
trapsink_modify(struct trapsink * t,struct trapsink_dep * tdep)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
trapsink_unmodify(struct trapsink * t,struct trapsink_dep * tdep)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
trapsink_destroy(struct snmp_context * ctx __unused,struct trapsink * t,struct trapsink_dep * tdep)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
trapsink_undestroy(struct trapsink * t,struct trapsink_dep * tdep)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
trapsink_dep(struct snmp_context * ctx,struct snmp_dependency * dep,enum snmp_depop op)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
op_trapsink(struct snmp_context * ctx,struct snmp_value * value,u_int sub,u_int iidx,enum snmp_op op)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
snmp_create_v1_trap(struct snmp_pdu * pdu,char * com,const struct asn_oid * trap_oid)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
snmp_create_v2_trap(struct snmp_pdu * pdu,char * com,const struct asn_oid * trap_oid)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
snmp_create_v3_trap(struct snmp_pdu * pdu,struct target_param * target,const struct asn_oid * trap_oid)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
snmp_send_trap(const struct asn_oid * trap_oid,...)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 *
bsnmpd_get_target_stats(void)654 bsnmpd_get_target_stats(void)
655 {
656 return (&snmpd_target_stats);
657 }
658
659 struct target_address *
target_first_address(void)660 target_first_address(void)
661 {
662 return (SLIST_FIRST(&target_addresslist));
663 }
664
665 struct target_address *
target_next_address(struct target_address * addrs)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 *
target_new_address(char * aname)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
target_activate_address(struct target_address * addrs)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 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
750 int
target_delete_address(struct target_address * addrs)751 target_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
761 struct target_param *
target_first_param(void)762 target_first_param(void)
763 {
764 return (SLIST_FIRST(&target_paramlist));
765 }
766
767 struct target_param *
target_next_param(struct target_param * param)768 target_next_param(struct target_param *param)
769 {
770 if (param == NULL)
771 return (NULL);
772
773 return (SLIST_NEXT(param, tp));
774 }
775
776 struct target_param *
target_new_param(char * pname)777 target_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
817 int
target_delete_param(struct target_param * param)818 target_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
826 struct target_notify *
target_first_notify(void)827 target_first_notify(void)
828 {
829 return (SLIST_FIRST(&target_notifylist));
830 }
831
832 struct target_notify *
target_next_notify(struct target_notify * notify)833 target_next_notify(struct target_notify *notify)
834 {
835 if (notify == NULL)
836 return (NULL);
837
838 return (SLIST_NEXT(notify, tn));
839 }
840
841 struct target_notify *
target_new_notify(char * nname)842 target_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
882 int
target_delete_notify(struct target_notify * notify)883 target_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
891 void
target_flush_all(void)892 target_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