Deleted Added
full compact
trap.c (150921) trap.c (216294)
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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $
30 *
31 * TrapSinkTable
32 */
33#include <sys/types.h>
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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $
30 *
31 * TrapSinkTable
32 */
33#include <sys/types.h>
34#include <sys/queue.h>
34#include <sys/sysctl.h>
35#include <sys/un.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <stdarg.h>
39#include <stdarg.h>
40#include <string.h>
41#include <ctype.h>
42#include <syslog.h>
43#include <unistd.h>
44#include <netinet/in.h>
45#include <arpa/inet.h>
46
47#include "snmpmod.h"
48#include "snmpd.h"
49#include "tree.h"
50#include "oid.h"
51
52struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list);
53
54static const struct asn_oid oid_begemotTrapSinkTable =
55 OIDX_begemotTrapSinkTable;
56static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime;
57static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID;
58
59struct trapsink_dep {
60 struct snmp_dependency dep;
61 u_int set;
62 u_int status;
63 u_char comm[SNMP_COMMUNITY_MAXLEN + 1];
64 u_int version;
65 u_int rb;
66 u_int rb_status;
67 u_int rb_version;
68 u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1];
69};
70enum {
71 TDEP_STATUS = 0x0001,
72 TDEP_COMM = 0x0002,
73 TDEP_VERSION = 0x0004,
74
75 TDEP_CREATE = 0x0001,
76 TDEP_MODIFY = 0x0002,
77 TDEP_DESTROY = 0x0004,
78};
79
80static int
81trapsink_create(struct trapsink_dep *tdep)
82{
83 struct trapsink *t;
84 struct sockaddr_in sa;
85
86 if ((t = malloc(sizeof(*t))) == NULL)
87 return (SNMP_ERR_RES_UNAVAIL);
88
89 t->index = tdep->dep.idx;
90 t->status = TRAPSINK_NOT_READY;
91 t->comm[0] = '\0';
92 t->version = TRAPSINK_V2;
93
94 if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
95 syslog(LOG_ERR, "socket(UDP): %m");
96 free(t);
97 return (SNMP_ERR_RES_UNAVAIL);
98 }
99 (void)shutdown(t->socket, SHUT_RD);
100
101 sa.sin_len = sizeof(sa);
102 sa.sin_family = AF_INET;
103 sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) |
104 (t->index.subs[1] << 16) | (t->index.subs[2] << 8) |
105 (t->index.subs[3] << 0));
106 sa.sin_port = htons(t->index.subs[4]);
107
108 if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
109 syslog(LOG_ERR, "connect(%s,%u): %m",
110 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
111 (void)close(t->socket);
112 free(t);
113 return (SNMP_ERR_GENERR);
114 }
115
116 if (tdep->set & TDEP_VERSION)
117 t->version = tdep->version;
118 if (tdep->set & TDEP_COMM)
119 strcpy(t->comm, tdep->comm);
120
121 if (t->comm[0] != '\0')
122 t->status = TRAPSINK_NOT_IN_SERVICE;
123
124 /* look whether we should activate */
125 if (tdep->status == 4) {
126 if (t->status == TRAPSINK_NOT_READY) {
127 if (t->socket != -1)
128 (void)close(t->socket);
129 free(t);
130 return (SNMP_ERR_INCONS_VALUE);
131 }
132 t->status = TRAPSINK_ACTIVE;
133 }
134
135 INSERT_OBJECT_OID(t, &trapsink_list);
136
137 tdep->rb |= TDEP_CREATE;
138
139 return (SNMP_ERR_NOERROR);
140}
141
142static void
143trapsink_free(struct trapsink *t)
144{
145 TAILQ_REMOVE(&trapsink_list, t, link);
146 if (t->socket != -1)
147 (void)close(t->socket);
148 free(t);
149}
150
151static int
152trapsink_modify(struct trapsink *t, struct trapsink_dep *tdep)
153{
154 tdep->rb_status = t->status;
155 tdep->rb_version = t->version;
156 strcpy(tdep->rb_comm, t->comm);
157
158 if (tdep->set & TDEP_STATUS) {
159 /* if we are active and should move to not_in_service do
160 * this first */
161 if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) {
162 t->status = TRAPSINK_NOT_IN_SERVICE;
163 tdep->rb |= TDEP_MODIFY;
164 }
165 }
166
167 if (tdep->set & TDEP_VERSION)
168 t->version = tdep->version;
169 if (tdep->set & TDEP_COMM)
170 strcpy(t->comm, tdep->comm);
171
172 if (tdep->set & TDEP_STATUS) {
173 /* if we were inactive and should go active - do this now */
174 if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) {
175 if (t->comm[0] == '\0') {
176 t->status = tdep->rb_status;
177 t->version = tdep->rb_version;
178 strcpy(t->comm, tdep->rb_comm);
179 return (SNMP_ERR_INCONS_VALUE);
180 }
181 t->status = TRAPSINK_ACTIVE;
182 tdep->rb |= TDEP_MODIFY;
183 }
184 }
185 return (SNMP_ERR_NOERROR);
186}
187
188static int
189trapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep)
190{
191 if (tdep->set & TDEP_STATUS)
192 t->status = tdep->rb_status;
193 if (tdep->set & TDEP_VERSION)
194 t->version = tdep->rb_version;
195 if (tdep->set & TDEP_COMM)
196 strcpy(t->comm, tdep->rb_comm);
197
198 return (SNMP_ERR_NOERROR);
199}
200
201static int
202trapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t,
203 struct trapsink_dep *tdep)
204{
205 t->status = TRAPSINK_DESTROY;
206 tdep->rb_status = t->status;
207 tdep->rb |= TDEP_DESTROY;
208 return (SNMP_ERR_NOERROR);
209}
210
211static int
212trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep)
213{
214 t->status = tdep->rb_status;
215 return (SNMP_ERR_NOERROR);
216}
217
218static int
219trapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep,
220 enum snmp_depop op)
221{
222 struct trapsink_dep *tdep = (struct trapsink_dep *)dep;
223 struct trapsink *t;
224
225 t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0);
226
227 switch (op) {
228
229 case SNMP_DEPOP_COMMIT:
230 if (tdep->set & TDEP_STATUS) {
231 switch (tdep->status) {
232
233 case 1:
234 case 2:
235 if (t == NULL)
236 return (SNMP_ERR_INCONS_VALUE);
237 return (trapsink_modify(t, tdep));
238
239 case 4:
240 case 5:
241 if (t != NULL)
242 return (SNMP_ERR_INCONS_VALUE);
243 return (trapsink_create(tdep));
244
245 case 6:
246 if (t == NULL)
247 return (SNMP_ERR_NOERROR);
248 return (trapsink_destroy(ctx, t, tdep));
249 }
250 } else if (tdep->set != 0)
251 return (trapsink_modify(t, tdep));
252
253 return (SNMP_ERR_NOERROR);
254
255 case SNMP_DEPOP_ROLLBACK:
256 if (tdep->rb & TDEP_CREATE) {
257 trapsink_free(t);
258 return (SNMP_ERR_NOERROR);
259 }
260 if (tdep->rb & TDEP_MODIFY)
261 return (trapsink_unmodify(t, tdep));
262 if(tdep->rb & TDEP_DESTROY)
263 return (trapsink_undestroy(t, tdep));
264 return (SNMP_ERR_NOERROR);
265
266 case SNMP_DEPOP_FINISH:
267 if ((tdep->rb & TDEP_DESTROY) && t != NULL &&
268 ctx->code == SNMP_RET_OK)
269 trapsink_free(t);
270 return (SNMP_ERR_NOERROR);
271 }
272 abort();
273}
274
275int
276op_trapsink(struct snmp_context *ctx, struct snmp_value *value,
277 u_int sub, u_int iidx, enum snmp_op op)
278{
279 struct trapsink *t;
280 u_char ipa[4];
281 int32_t port;
282 struct asn_oid idx;
283 struct trapsink_dep *tdep;
284 u_char *p;
285
286 t = NULL; /* gcc */
287
288 switch (op) {
289
290 case SNMP_OP_GETNEXT:
291 if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
292 return (SNMP_ERR_NOSUCHNAME);
293 index_append(&value->var, sub, &t->index);
294 break;
295
296 case SNMP_OP_GET:
297 if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
298 return (SNMP_ERR_NOSUCHNAME);
299 break;
300
301 case SNMP_OP_SET:
302 if (index_decode(&value->var, sub, iidx, ipa, &port) ||
303 port == 0 || port > 65535)
304 return (SNMP_ERR_NO_CREATION);
305 t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub);
306
307 asn_slice_oid(&idx, &value->var, sub, value->var.len);
308
309 tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx,
310 &oid_begemotTrapSinkTable, &idx,
311 sizeof(*tdep), trapsink_dep);
312 if (tdep == NULL)
313 return (SNMP_ERR_RES_UNAVAIL);
314
315 switch (value->var.subs[sub - 1]) {
316
317 case LEAF_begemotTrapSinkStatus:
318 if (tdep->set & TDEP_STATUS)
319 return (SNMP_ERR_INCONS_VALUE);
320 switch (value->v.integer) {
321
322 case 1:
323 case 2:
324 if (t == NULL)
325 return (SNMP_ERR_INCONS_VALUE);
326 break;
327
328 case 4:
329 case 5:
330 if (t != NULL)
331 return (SNMP_ERR_INCONS_VALUE);
332 break;
333
334 case 6:
335 break;
336
337 default:
338 return (SNMP_ERR_WRONG_VALUE);
339 }
340 tdep->status = value->v.integer;
341 tdep->set |= TDEP_STATUS;
342 return (SNMP_ERR_NOERROR);
343
344 case LEAF_begemotTrapSinkComm:
345 if (tdep->set & TDEP_COMM)
346 return (SNMP_ERR_INCONS_VALUE);
347 if (value->v.octetstring.len == 0 ||
348 value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN)
349 return (SNMP_ERR_WRONG_VALUE);
350 for (p = value->v.octetstring.octets;
351 p < value->v.octetstring.octets + value->v.octetstring.len;
352 p++) {
353 if (!isascii(*p) || !isprint(*p))
354 return (SNMP_ERR_WRONG_VALUE);
355 }
356 tdep->set |= TDEP_COMM;
357 strncpy(tdep->comm, value->v.octetstring.octets,
358 value->v.octetstring.len);
359 tdep->comm[value->v.octetstring.len] = '\0';
360 return (SNMP_ERR_NOERROR);
361
362 case LEAF_begemotTrapSinkVersion:
363 if (tdep->set & TDEP_VERSION)
364 return (SNMP_ERR_INCONS_VALUE);
365 if (value->v.integer != TRAPSINK_V1 &&
366 value->v.integer != TRAPSINK_V2)
367 return (SNMP_ERR_WRONG_VALUE);
368 tdep->version = value->v.integer;
369 tdep->set |= TDEP_VERSION;
370 return (SNMP_ERR_NOERROR);
371 }
372 if (t == NULL)
373 return (SNMP_ERR_INCONS_NAME);
374 else
375 return (SNMP_ERR_NOT_WRITEABLE);
376
377
378 case SNMP_OP_ROLLBACK:
379 case SNMP_OP_COMMIT:
380 return (SNMP_ERR_NOERROR);
381 }
382
383 switch (value->var.subs[sub - 1]) {
384
385 case LEAF_begemotTrapSinkStatus:
386 value->v.integer = t->status;
387 break;
388
389 case LEAF_begemotTrapSinkComm:
390 return (string_get(value, t->comm, -1));
391
392 case LEAF_begemotTrapSinkVersion:
393 value->v.integer = t->version;
394 break;
395
396 }
397 return (SNMP_ERR_NOERROR);
398}
399
400void
401snmp_send_trap(const struct asn_oid *trap_oid, ...)
402{
403 struct snmp_pdu pdu;
404 struct trapsink *t;
405 const struct snmp_value *v;
406 va_list ap;
407 u_char *sndbuf;
408 size_t sndlen;
409 ssize_t len;
410
411 TAILQ_FOREACH(t, &trapsink_list, link) {
412 if (t->status != TRAPSINK_ACTIVE)
413 continue;
414 memset(&pdu, 0, sizeof(pdu));
415 strcpy(pdu.community, t->comm);
416 if (t->version == TRAPSINK_V1) {
417 pdu.version = SNMP_V1;
418 pdu.type = SNMP_PDU_TRAP;
419 pdu.enterprise = systemg.object_id;
420 memcpy(pdu.agent_addr, snmpd.trap1addr, 4);
421 pdu.generic_trap = trap_oid->subs[trap_oid->len - 1] - 1;
422 pdu.specific_trap = 0;
423 pdu.time_stamp = get_ticks() - start_tick;
424
425 pdu.nbindings = 0;
426 } else {
427 pdu.version = SNMP_V2c;
428 pdu.type = SNMP_PDU_TRAP2;
429 pdu.request_id = reqid_next(trap_reqid);
430 pdu.error_index = 0;
431 pdu.error_status = SNMP_ERR_NOERROR;
432
433 pdu.bindings[0].var = oid_sysUpTime;
434 pdu.bindings[0].var.subs[pdu.bindings[0].var.len++] = 0;
435 pdu.bindings[0].syntax = SNMP_SYNTAX_TIMETICKS;
436 pdu.bindings[0].v.uint32 = get_ticks() - start_tick;
437
438 pdu.bindings[1].var = oid_snmpTrapOID;
439 pdu.bindings[1].var.subs[pdu.bindings[1].var.len++] = 0;
440 pdu.bindings[1].syntax = SNMP_SYNTAX_OID;
441 pdu.bindings[1].v.oid = *trap_oid;
442
443 pdu.nbindings = 2;
444 }
445
446 va_start(ap, trap_oid);
447 while ((v = va_arg(ap, const struct snmp_value *)) != NULL)
448 pdu.bindings[pdu.nbindings++] = *v;
449 va_end(ap);
450
451 if ((sndbuf = buf_alloc(1)) == NULL) {
452 syslog(LOG_ERR, "trap send buffer: %m");
453 return;
454 }
455
456 snmp_output(&pdu, sndbuf, &sndlen, "TRAP");
457
458 if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1)
459 syslog(LOG_ERR, "send: %m");
460 else if ((size_t)len != sndlen)
461 syslog(LOG_ERR, "send: short write %zu/%zu",
462 sndlen, (size_t)len);
463
464 free(sndbuf);
465 }
466}
35#include <sys/sysctl.h>
36#include <sys/un.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <stdarg.h>
40#include <stdarg.h>
41#include <string.h>
42#include <ctype.h>
43#include <syslog.h>
44#include <unistd.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47
48#include "snmpmod.h"
49#include "snmpd.h"
50#include "tree.h"
51#include "oid.h"
52
53struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list);
54
55static const struct asn_oid oid_begemotTrapSinkTable =
56 OIDX_begemotTrapSinkTable;
57static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime;
58static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID;
59
60struct trapsink_dep {
61 struct snmp_dependency dep;
62 u_int set;
63 u_int status;
64 u_char comm[SNMP_COMMUNITY_MAXLEN + 1];
65 u_int version;
66 u_int rb;
67 u_int rb_status;
68 u_int rb_version;
69 u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1];
70};
71enum {
72 TDEP_STATUS = 0x0001,
73 TDEP_COMM = 0x0002,
74 TDEP_VERSION = 0x0004,
75
76 TDEP_CREATE = 0x0001,
77 TDEP_MODIFY = 0x0002,
78 TDEP_DESTROY = 0x0004,
79};
80
81static int
82trapsink_create(struct trapsink_dep *tdep)
83{
84 struct trapsink *t;
85 struct sockaddr_in sa;
86
87 if ((t = malloc(sizeof(*t))) == NULL)
88 return (SNMP_ERR_RES_UNAVAIL);
89
90 t->index = tdep->dep.idx;
91 t->status = TRAPSINK_NOT_READY;
92 t->comm[0] = '\0';
93 t->version = TRAPSINK_V2;
94
95 if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
96 syslog(LOG_ERR, "socket(UDP): %m");
97 free(t);
98 return (SNMP_ERR_RES_UNAVAIL);
99 }
100 (void)shutdown(t->socket, SHUT_RD);
101
102 sa.sin_len = sizeof(sa);
103 sa.sin_family = AF_INET;
104 sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) |
105 (t->index.subs[1] << 16) | (t->index.subs[2] << 8) |
106 (t->index.subs[3] << 0));
107 sa.sin_port = htons(t->index.subs[4]);
108
109 if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
110 syslog(LOG_ERR, "connect(%s,%u): %m",
111 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
112 (void)close(t->socket);
113 free(t);
114 return (SNMP_ERR_GENERR);
115 }
116
117 if (tdep->set & TDEP_VERSION)
118 t->version = tdep->version;
119 if (tdep->set & TDEP_COMM)
120 strcpy(t->comm, tdep->comm);
121
122 if (t->comm[0] != '\0')
123 t->status = TRAPSINK_NOT_IN_SERVICE;
124
125 /* look whether we should activate */
126 if (tdep->status == 4) {
127 if (t->status == TRAPSINK_NOT_READY) {
128 if (t->socket != -1)
129 (void)close(t->socket);
130 free(t);
131 return (SNMP_ERR_INCONS_VALUE);
132 }
133 t->status = TRAPSINK_ACTIVE;
134 }
135
136 INSERT_OBJECT_OID(t, &trapsink_list);
137
138 tdep->rb |= TDEP_CREATE;
139
140 return (SNMP_ERR_NOERROR);
141}
142
143static void
144trapsink_free(struct trapsink *t)
145{
146 TAILQ_REMOVE(&trapsink_list, t, link);
147 if (t->socket != -1)
148 (void)close(t->socket);
149 free(t);
150}
151
152static int
153trapsink_modify(struct trapsink *t, struct trapsink_dep *tdep)
154{
155 tdep->rb_status = t->status;
156 tdep->rb_version = t->version;
157 strcpy(tdep->rb_comm, t->comm);
158
159 if (tdep->set & TDEP_STATUS) {
160 /* if we are active and should move to not_in_service do
161 * this first */
162 if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) {
163 t->status = TRAPSINK_NOT_IN_SERVICE;
164 tdep->rb |= TDEP_MODIFY;
165 }
166 }
167
168 if (tdep->set & TDEP_VERSION)
169 t->version = tdep->version;
170 if (tdep->set & TDEP_COMM)
171 strcpy(t->comm, tdep->comm);
172
173 if (tdep->set & TDEP_STATUS) {
174 /* if we were inactive and should go active - do this now */
175 if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) {
176 if (t->comm[0] == '\0') {
177 t->status = tdep->rb_status;
178 t->version = tdep->rb_version;
179 strcpy(t->comm, tdep->rb_comm);
180 return (SNMP_ERR_INCONS_VALUE);
181 }
182 t->status = TRAPSINK_ACTIVE;
183 tdep->rb |= TDEP_MODIFY;
184 }
185 }
186 return (SNMP_ERR_NOERROR);
187}
188
189static int
190trapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep)
191{
192 if (tdep->set & TDEP_STATUS)
193 t->status = tdep->rb_status;
194 if (tdep->set & TDEP_VERSION)
195 t->version = tdep->rb_version;
196 if (tdep->set & TDEP_COMM)
197 strcpy(t->comm, tdep->rb_comm);
198
199 return (SNMP_ERR_NOERROR);
200}
201
202static int
203trapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t,
204 struct trapsink_dep *tdep)
205{
206 t->status = TRAPSINK_DESTROY;
207 tdep->rb_status = t->status;
208 tdep->rb |= TDEP_DESTROY;
209 return (SNMP_ERR_NOERROR);
210}
211
212static int
213trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep)
214{
215 t->status = tdep->rb_status;
216 return (SNMP_ERR_NOERROR);
217}
218
219static int
220trapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep,
221 enum snmp_depop op)
222{
223 struct trapsink_dep *tdep = (struct trapsink_dep *)dep;
224 struct trapsink *t;
225
226 t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0);
227
228 switch (op) {
229
230 case SNMP_DEPOP_COMMIT:
231 if (tdep->set & TDEP_STATUS) {
232 switch (tdep->status) {
233
234 case 1:
235 case 2:
236 if (t == NULL)
237 return (SNMP_ERR_INCONS_VALUE);
238 return (trapsink_modify(t, tdep));
239
240 case 4:
241 case 5:
242 if (t != NULL)
243 return (SNMP_ERR_INCONS_VALUE);
244 return (trapsink_create(tdep));
245
246 case 6:
247 if (t == NULL)
248 return (SNMP_ERR_NOERROR);
249 return (trapsink_destroy(ctx, t, tdep));
250 }
251 } else if (tdep->set != 0)
252 return (trapsink_modify(t, tdep));
253
254 return (SNMP_ERR_NOERROR);
255
256 case SNMP_DEPOP_ROLLBACK:
257 if (tdep->rb & TDEP_CREATE) {
258 trapsink_free(t);
259 return (SNMP_ERR_NOERROR);
260 }
261 if (tdep->rb & TDEP_MODIFY)
262 return (trapsink_unmodify(t, tdep));
263 if(tdep->rb & TDEP_DESTROY)
264 return (trapsink_undestroy(t, tdep));
265 return (SNMP_ERR_NOERROR);
266
267 case SNMP_DEPOP_FINISH:
268 if ((tdep->rb & TDEP_DESTROY) && t != NULL &&
269 ctx->code == SNMP_RET_OK)
270 trapsink_free(t);
271 return (SNMP_ERR_NOERROR);
272 }
273 abort();
274}
275
276int
277op_trapsink(struct snmp_context *ctx, struct snmp_value *value,
278 u_int sub, u_int iidx, enum snmp_op op)
279{
280 struct trapsink *t;
281 u_char ipa[4];
282 int32_t port;
283 struct asn_oid idx;
284 struct trapsink_dep *tdep;
285 u_char *p;
286
287 t = NULL; /* gcc */
288
289 switch (op) {
290
291 case SNMP_OP_GETNEXT:
292 if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
293 return (SNMP_ERR_NOSUCHNAME);
294 index_append(&value->var, sub, &t->index);
295 break;
296
297 case SNMP_OP_GET:
298 if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
299 return (SNMP_ERR_NOSUCHNAME);
300 break;
301
302 case SNMP_OP_SET:
303 if (index_decode(&value->var, sub, iidx, ipa, &port) ||
304 port == 0 || port > 65535)
305 return (SNMP_ERR_NO_CREATION);
306 t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub);
307
308 asn_slice_oid(&idx, &value->var, sub, value->var.len);
309
310 tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx,
311 &oid_begemotTrapSinkTable, &idx,
312 sizeof(*tdep), trapsink_dep);
313 if (tdep == NULL)
314 return (SNMP_ERR_RES_UNAVAIL);
315
316 switch (value->var.subs[sub - 1]) {
317
318 case LEAF_begemotTrapSinkStatus:
319 if (tdep->set & TDEP_STATUS)
320 return (SNMP_ERR_INCONS_VALUE);
321 switch (value->v.integer) {
322
323 case 1:
324 case 2:
325 if (t == NULL)
326 return (SNMP_ERR_INCONS_VALUE);
327 break;
328
329 case 4:
330 case 5:
331 if (t != NULL)
332 return (SNMP_ERR_INCONS_VALUE);
333 break;
334
335 case 6:
336 break;
337
338 default:
339 return (SNMP_ERR_WRONG_VALUE);
340 }
341 tdep->status = value->v.integer;
342 tdep->set |= TDEP_STATUS;
343 return (SNMP_ERR_NOERROR);
344
345 case LEAF_begemotTrapSinkComm:
346 if (tdep->set & TDEP_COMM)
347 return (SNMP_ERR_INCONS_VALUE);
348 if (value->v.octetstring.len == 0 ||
349 value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN)
350 return (SNMP_ERR_WRONG_VALUE);
351 for (p = value->v.octetstring.octets;
352 p < value->v.octetstring.octets + value->v.octetstring.len;
353 p++) {
354 if (!isascii(*p) || !isprint(*p))
355 return (SNMP_ERR_WRONG_VALUE);
356 }
357 tdep->set |= TDEP_COMM;
358 strncpy(tdep->comm, value->v.octetstring.octets,
359 value->v.octetstring.len);
360 tdep->comm[value->v.octetstring.len] = '\0';
361 return (SNMP_ERR_NOERROR);
362
363 case LEAF_begemotTrapSinkVersion:
364 if (tdep->set & TDEP_VERSION)
365 return (SNMP_ERR_INCONS_VALUE);
366 if (value->v.integer != TRAPSINK_V1 &&
367 value->v.integer != TRAPSINK_V2)
368 return (SNMP_ERR_WRONG_VALUE);
369 tdep->version = value->v.integer;
370 tdep->set |= TDEP_VERSION;
371 return (SNMP_ERR_NOERROR);
372 }
373 if (t == NULL)
374 return (SNMP_ERR_INCONS_NAME);
375 else
376 return (SNMP_ERR_NOT_WRITEABLE);
377
378
379 case SNMP_OP_ROLLBACK:
380 case SNMP_OP_COMMIT:
381 return (SNMP_ERR_NOERROR);
382 }
383
384 switch (value->var.subs[sub - 1]) {
385
386 case LEAF_begemotTrapSinkStatus:
387 value->v.integer = t->status;
388 break;
389
390 case LEAF_begemotTrapSinkComm:
391 return (string_get(value, t->comm, -1));
392
393 case LEAF_begemotTrapSinkVersion:
394 value->v.integer = t->version;
395 break;
396
397 }
398 return (SNMP_ERR_NOERROR);
399}
400
401void
402snmp_send_trap(const struct asn_oid *trap_oid, ...)
403{
404 struct snmp_pdu pdu;
405 struct trapsink *t;
406 const struct snmp_value *v;
407 va_list ap;
408 u_char *sndbuf;
409 size_t sndlen;
410 ssize_t len;
411
412 TAILQ_FOREACH(t, &trapsink_list, link) {
413 if (t->status != TRAPSINK_ACTIVE)
414 continue;
415 memset(&pdu, 0, sizeof(pdu));
416 strcpy(pdu.community, t->comm);
417 if (t->version == TRAPSINK_V1) {
418 pdu.version = SNMP_V1;
419 pdu.type = SNMP_PDU_TRAP;
420 pdu.enterprise = systemg.object_id;
421 memcpy(pdu.agent_addr, snmpd.trap1addr, 4);
422 pdu.generic_trap = trap_oid->subs[trap_oid->len - 1] - 1;
423 pdu.specific_trap = 0;
424 pdu.time_stamp = get_ticks() - start_tick;
425
426 pdu.nbindings = 0;
427 } else {
428 pdu.version = SNMP_V2c;
429 pdu.type = SNMP_PDU_TRAP2;
430 pdu.request_id = reqid_next(trap_reqid);
431 pdu.error_index = 0;
432 pdu.error_status = SNMP_ERR_NOERROR;
433
434 pdu.bindings[0].var = oid_sysUpTime;
435 pdu.bindings[0].var.subs[pdu.bindings[0].var.len++] = 0;
436 pdu.bindings[0].syntax = SNMP_SYNTAX_TIMETICKS;
437 pdu.bindings[0].v.uint32 = get_ticks() - start_tick;
438
439 pdu.bindings[1].var = oid_snmpTrapOID;
440 pdu.bindings[1].var.subs[pdu.bindings[1].var.len++] = 0;
441 pdu.bindings[1].syntax = SNMP_SYNTAX_OID;
442 pdu.bindings[1].v.oid = *trap_oid;
443
444 pdu.nbindings = 2;
445 }
446
447 va_start(ap, trap_oid);
448 while ((v = va_arg(ap, const struct snmp_value *)) != NULL)
449 pdu.bindings[pdu.nbindings++] = *v;
450 va_end(ap);
451
452 if ((sndbuf = buf_alloc(1)) == NULL) {
453 syslog(LOG_ERR, "trap send buffer: %m");
454 return;
455 }
456
457 snmp_output(&pdu, sndbuf, &sndlen, "TRAP");
458
459 if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1)
460 syslog(LOG_ERR, "send: %m");
461 else if ((size_t)len != sndlen)
462 syslog(LOG_ERR, "send: short write %zu/%zu",
463 sndlen, (size_t)len);
464
465 free(sndbuf);
466 }
467}