1 /*-
2 * Copyright (c) 2010,2018 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Shteryana Sotirova Shopova under
6 * sponsorship from the FreeBSD Foundation.
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 THE 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 THE 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 * $FreeBSD$
30 */
31 #include <sys/queue.h>
32 #include <sys/types.h>
33
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <stdint.h>
39 #include <string.h>
40 #include <syslog.h>
41
42 #include "asn1.h"
43 #include "snmp.h"
44 #include "snmpmod.h"
45
46 #define SNMPTREE_TYPES
47 #include "target_tree.h"
48 #include "target_oid.h"
49
50 static struct lmodule *target_module;
51 /* For the registration. */
52 static const struct asn_oid oid_target = OIDX_snmpTargetMIB;
53 static const struct asn_oid oid_notification = OIDX_snmpNotificationMIB;
54
55 static uint reg_target;
56 static uint reg_notification;
57
58 static int32_t target_lock;
59
60 static const struct asn_oid oid_udp_domain = OIDX_snmpUDPDomain;
61
62 /*
63 * Internal datastructures and forward declarations.
64 */
65 static void target_append_index(struct asn_oid *, uint,
66 const char *);
67 static int target_decode_index(const struct asn_oid *, uint,
68 char *);
69 static struct target_address *target_get_address(const struct asn_oid *,
70 uint);
71 static struct target_address *target_get_next_address(const struct asn_oid *,
72 uint);
73 static struct target_param *target_get_param(const struct asn_oid *,
74 uint);
75 static struct target_param *target_get_next_param(const struct asn_oid *,
76 uint);
77 static struct target_notify *target_get_notify(const struct asn_oid *,
78 uint);
79 static struct target_notify *target_get_next_notify(const struct asn_oid *,
80 uint);
81
82 int
op_snmp_target(struct snmp_context * ctx __unused,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)83 op_snmp_target(struct snmp_context *ctx __unused, struct snmp_value *val,
84 uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
85 {
86 struct snmpd_target_stats *ctx_stats;
87
88 if (val->var.subs[sub - 1] == LEAF_snmpTargetSpinLock) {
89 switch (op) {
90 case SNMP_OP_GET:
91 if (++target_lock == INT32_MAX)
92 target_lock = 0;
93 val->v.integer = target_lock;
94 break;
95 case SNMP_OP_GETNEXT:
96 abort();
97 case SNMP_OP_SET:
98 if (val->v.integer != target_lock)
99 return (SNMP_ERR_INCONS_VALUE);
100 break;
101 case SNMP_OP_ROLLBACK:
102 /* FALLTHROUGH */
103 case SNMP_OP_COMMIT:
104 break;
105 }
106 return (SNMP_ERR_NOERROR);
107 } else if (op == SNMP_OP_SET)
108 return (SNMP_ERR_NOT_WRITEABLE);
109
110 if ((ctx_stats = bsnmpd_get_target_stats()) == NULL)
111 return (SNMP_ERR_GENERR);
112
113 if (op == SNMP_OP_GET) {
114 switch (val->var.subs[sub - 1]) {
115 case LEAF_snmpUnavailableContexts:
116 val->v.uint32 = ctx_stats->unavail_contexts;
117 break;
118 case LEAF_snmpUnknownContexts:
119 val->v.uint32 = ctx_stats->unknown_contexts;
120 break;
121 default:
122 return (SNMP_ERR_NOSUCHNAME);
123 }
124 return (SNMP_ERR_NOERROR);
125 }
126 abort();
127 }
128
129 int
op_snmp_target_addrs(struct snmp_context * ctx __unused,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)130 op_snmp_target_addrs(struct snmp_context *ctx __unused, struct snmp_value *val,
131 uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
132 {
133 char aname[SNMP_ADM_STR32_SIZ];
134 struct target_address *addrs;
135
136 switch (op) {
137 case SNMP_OP_GET:
138 if ((addrs = target_get_address(&val->var, sub)) == NULL)
139 return (SNMP_ERR_NOSUCHNAME);
140 break;
141
142 case SNMP_OP_GETNEXT:
143 if ((addrs = target_get_next_address(&val->var, sub)) == NULL)
144 return (SNMP_ERR_NOSUCHNAME);
145 target_append_index(&val->var, sub, addrs->name);
146 break;
147
148 case SNMP_OP_SET:
149 if ((addrs = target_get_address(&val->var, sub)) == NULL &&
150 (val->var.subs[sub - 1] != LEAF_snmpTargetAddrRowStatus ||
151 val->v.integer != RowStatus_createAndWait))
152 return (SNMP_ERR_NOSUCHNAME);
153
154 if (addrs != NULL) {
155 if (community != COMM_INITIALIZE &&
156 addrs->type == StorageType_readOnly)
157 return (SNMP_ERR_NOT_WRITEABLE);
158 if (addrs->status == RowStatus_active &&
159 val->v.integer != RowStatus_destroy)
160 return (SNMP_ERR_INCONS_VALUE);
161 }
162
163 switch (val->var.subs[sub - 1]) {
164 case LEAF_snmpTargetAddrTDomain:
165 return (SNMP_ERR_INCONS_VALUE);
166 case LEAF_snmpTargetAddrTAddress:
167 if (val->v.octetstring.len != SNMP_UDP_ADDR_SIZ)
168 return (SNMP_ERR_INCONS_VALUE);
169 ctx->scratch->ptr1 = malloc(SNMP_UDP_ADDR_SIZ);
170 if (ctx->scratch->ptr1 == NULL)
171 return (SNMP_ERR_GENERR);
172 memcpy(ctx->scratch->ptr1, addrs->address,
173 SNMP_UDP_ADDR_SIZ);
174 memcpy(addrs->address, val->v.octetstring.octets,
175 SNMP_UDP_ADDR_SIZ);
176 break;
177
178 case LEAF_snmpTargetAddrTagList:
179 if (val->v.octetstring.len >= SNMP_TAG_SIZ)
180 return (SNMP_ERR_INCONS_VALUE);
181 ctx->scratch->int1 = strlen(addrs->taglist) + 1;
182 ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
183 if (ctx->scratch->ptr1 == NULL)
184 return (SNMP_ERR_GENERR);
185 strlcpy(ctx->scratch->ptr1, addrs->taglist,
186 ctx->scratch->int1);
187 memcpy(addrs->taglist, val->v.octetstring.octets,
188 val->v.octetstring.len);
189 addrs->taglist[val->v.octetstring.len] = '\0';
190 break;
191
192 case LEAF_snmpTargetAddrParams:
193 if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ)
194 return (SNMP_ERR_INCONS_VALUE);
195 ctx->scratch->int1 = strlen(addrs->paramname) + 1;
196 ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
197 if (ctx->scratch->ptr1 == NULL)
198 return (SNMP_ERR_GENERR);
199 strlcpy(ctx->scratch->ptr1, addrs->paramname,
200 ctx->scratch->int1);
201 memcpy(addrs->paramname, val->v.octetstring.octets,
202 val->v.octetstring.len);
203 addrs->paramname[val->v.octetstring.len] = '\0';
204 break;
205
206 case LEAF_snmpTargetAddrRetryCount:
207 ctx->scratch->int1 = addrs->retry;
208 addrs->retry = val->v.integer;
209 break;
210
211 case LEAF_snmpTargetAddrTimeout:
212 ctx->scratch->int1 = addrs->timeout;
213 addrs->timeout = val->v.integer / 10;
214 break;
215
216 case LEAF_snmpTargetAddrStorageType:
217 return (SNMP_ERR_INCONS_VALUE);
218
219 case LEAF_snmpTargetAddrRowStatus:
220 if (addrs != NULL) {
221 if (val->v.integer != RowStatus_active &&
222 val->v.integer != RowStatus_destroy)
223 return (SNMP_ERR_INCONS_VALUE);
224 if (val->v.integer == RowStatus_active &&
225 (addrs->address[0] == 0 ||
226 strlen(addrs->taglist) == 0 ||
227 strlen(addrs->paramname) == 0))
228 return (SNMP_ERR_INCONS_VALUE);
229 ctx->scratch->int1 = addrs->status;
230 addrs->status = val->v.integer;
231 return (SNMP_ERR_NOERROR);
232 }
233 if (val->v.integer != RowStatus_createAndWait ||
234 target_decode_index(&val->var, sub, aname) < 0)
235 return (SNMP_ERR_INCONS_VALUE);
236 if ((addrs = target_new_address(aname)) == NULL)
237 return (SNMP_ERR_GENERR);
238 addrs->status = RowStatus_destroy;
239 if (community != COMM_INITIALIZE)
240 addrs->type = StorageType_volatile;
241 else
242 addrs->type = StorageType_readOnly;
243 break;
244 }
245 return (SNMP_ERR_NOERROR);
246
247 case SNMP_OP_COMMIT:
248 switch (val->var.subs[sub - 1]) {
249 case LEAF_snmpTargetAddrTAddress:
250 case LEAF_snmpTargetAddrTagList:
251 case LEAF_snmpTargetAddrParams:
252 free(ctx->scratch->ptr1);
253 break;
254 case LEAF_snmpTargetAddrRowStatus:
255 if ((addrs = target_get_address(&val->var, sub)) == NULL)
256 return (SNMP_ERR_GENERR);
257 if (val->v.integer == RowStatus_destroy)
258 return (target_delete_address(addrs));
259 else if (val->v.integer == RowStatus_active)
260 return (target_activate_address(addrs));
261 break;
262 default:
263 break;
264 }
265 return (SNMP_ERR_NOERROR);
266
267 case SNMP_OP_ROLLBACK:
268 if ((addrs = target_get_address(&val->var, sub)) == NULL)
269 return (SNMP_ERR_GENERR);
270
271 switch (val->var.subs[sub - 1]) {
272 case LEAF_snmpTargetAddrTAddress:
273 memcpy(addrs->address, ctx->scratch->ptr1,
274 SNMP_UDP_ADDR_SIZ);
275 free(ctx->scratch->ptr1);
276 break;
277
278 case LEAF_snmpTargetAddrTagList:
279 strlcpy(addrs->taglist, ctx->scratch->ptr1,
280 ctx->scratch->int1);
281 free(ctx->scratch->ptr1);
282 break;
283
284 case LEAF_snmpTargetAddrParams:
285 strlcpy(addrs->paramname, ctx->scratch->ptr1,
286 ctx->scratch->int1);
287 free(ctx->scratch->ptr1);
288 break;
289
290 case LEAF_snmpTargetAddrRetryCount:
291 addrs->retry = ctx->scratch->int1;
292 break;
293
294 case LEAF_snmpTargetAddrTimeout:
295 addrs->timeout = ctx->scratch->int1;
296 break;
297
298 case LEAF_snmpTargetAddrRowStatus:
299 if (ctx->scratch->int1 == RowStatus_destroy)
300 return (target_delete_address(addrs));
301 break;
302 default:
303 break;
304 }
305 return (SNMP_ERR_NOERROR);
306
307 default:
308 abort();
309 }
310
311 switch (val->var.subs[sub - 1]) {
312 case LEAF_snmpTargetAddrTDomain:
313 return (oid_get(val, &oid_udp_domain));
314 case LEAF_snmpTargetAddrTAddress:
315 return (string_get(val, addrs->address, SNMP_UDP_ADDR_SIZ));
316 case LEAF_snmpTargetAddrTimeout:
317 val->v.integer = addrs->timeout;
318 break;
319 case LEAF_snmpTargetAddrRetryCount:
320 val->v.integer = addrs->retry;
321 break;
322 case LEAF_snmpTargetAddrTagList:
323 return (string_get(val, addrs->taglist, -1));
324 case LEAF_snmpTargetAddrParams:
325 return (string_get(val, addrs->paramname, -1));
326 case LEAF_snmpTargetAddrStorageType:
327 val->v.integer = addrs->type;
328 break;
329 case LEAF_snmpTargetAddrRowStatus:
330 val->v.integer = addrs->status;
331 break;
332 default:
333 abort();
334 }
335
336 return (SNMP_ERR_NOERROR);
337 }
338
339 int
op_snmp_target_params(struct snmp_context * ctx __unused,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)340 op_snmp_target_params(struct snmp_context *ctx __unused, struct snmp_value *val,
341 uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
342 {
343 char pname[SNMP_ADM_STR32_SIZ];
344 struct target_param *param;
345
346 switch (op) {
347 case SNMP_OP_GET:
348 if ((param = target_get_param(&val->var, sub)) == NULL)
349 return (SNMP_ERR_NOSUCHNAME);
350 break;
351
352 case SNMP_OP_GETNEXT:
353 if ((param = target_get_next_param(&val->var, sub)) == NULL)
354 return (SNMP_ERR_NOSUCHNAME);
355 target_append_index(&val->var, sub, param->name);
356 break;
357
358 case SNMP_OP_SET:
359 if ((param = target_get_param(&val->var, sub)) == NULL &&
360 (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus ||
361 val->v.integer != RowStatus_createAndWait))
362 return (SNMP_ERR_NOSUCHNAME);
363
364 if (param != NULL) {
365 if (community != COMM_INITIALIZE &&
366 param->type == StorageType_readOnly)
367 return (SNMP_ERR_NOT_WRITEABLE);
368 if (param->status == RowStatus_active &&
369 val->v.integer != RowStatus_destroy)
370 return (SNMP_ERR_INCONS_VALUE);
371 }
372
373 switch (val->var.subs[sub - 1]) {
374 case LEAF_snmpTargetParamsMPModel:
375 if (val->v.integer != SNMP_MPM_SNMP_V1 &&
376 val->v.integer != SNMP_MPM_SNMP_V2c &&
377 val->v.integer != SNMP_MPM_SNMP_V3)
378 return (SNMP_ERR_INCONS_VALUE);
379 ctx->scratch->int1 = param->mpmodel;
380 param->mpmodel = val->v.integer;
381 break;
382
383 case LEAF_snmpTargetParamsSecurityModel:
384 if (val->v.integer != SNMP_SECMODEL_SNMPv1 &&
385 val->v.integer != SNMP_SECMODEL_SNMPv2c &&
386 val->v.integer != SNMP_SECMODEL_USM)
387 return (SNMP_ERR_INCONS_VALUE);
388 ctx->scratch->int1 = param->sec_model;
389 param->sec_model = val->v.integer;
390 break;
391
392 case LEAF_snmpTargetParamsSecurityName:
393 if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ)
394 return (SNMP_ERR_INCONS_VALUE);
395 ctx->scratch->int1 = strlen(param->secname) + 1;
396 ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
397 if (ctx->scratch->ptr1 == NULL)
398 return (SNMP_ERR_GENERR);
399 strlcpy(ctx->scratch->ptr1, param->secname,
400 ctx->scratch->int1);
401 memcpy(param->secname, val->v.octetstring.octets,
402 val->v.octetstring.len);
403 param->secname[val->v.octetstring.len] = '\0';
404 break;
405
406 case LEAF_snmpTargetParamsSecurityLevel:
407 if (val->v.integer != SNMP_noAuthNoPriv &&
408 val->v.integer != SNMP_authNoPriv &&
409 val->v.integer != SNMP_authPriv)
410 return (SNMP_ERR_INCONS_VALUE);
411 ctx->scratch->int1 = param->sec_level;
412 param->sec_level = val->v.integer;
413 break;
414
415 case LEAF_snmpTargetParamsStorageType:
416 return (SNMP_ERR_INCONS_VALUE);
417
418 case LEAF_snmpTargetParamsRowStatus:
419 if (param != NULL) {
420 if (val->v.integer != RowStatus_active &&
421 val->v.integer != RowStatus_destroy)
422 return (SNMP_ERR_INCONS_VALUE);
423 if (val->v.integer == RowStatus_active &&
424 (param->sec_model == 0 ||
425 param->sec_level == 0 ||
426 strlen(param->secname) == 0))
427 return (SNMP_ERR_INCONS_VALUE);
428 ctx->scratch->int1 = param->status;
429 param->status = val->v.integer;
430 return (SNMP_ERR_NOERROR);
431 }
432 if (val->v.integer != RowStatus_createAndWait ||
433 target_decode_index(&val->var, sub, pname) < 0)
434 return (SNMP_ERR_INCONS_VALUE);
435 if ((param = target_new_param(pname)) == NULL)
436 return (SNMP_ERR_GENERR);
437 param->status = RowStatus_destroy;
438 if (community != COMM_INITIALIZE)
439 param->type = StorageType_volatile;
440 else
441 param->type = StorageType_readOnly;
442 break;
443 }
444 return (SNMP_ERR_NOERROR);
445
446 case SNMP_OP_COMMIT:
447 switch (val->var.subs[sub - 1]) {
448 case LEAF_snmpTargetParamsSecurityName:
449 free(ctx->scratch->ptr1);
450 break;
451 case LEAF_snmpTargetParamsRowStatus:
452 if ((param = target_get_param(&val->var, sub)) == NULL)
453 return (SNMP_ERR_GENERR);
454 if (val->v.integer == RowStatus_destroy)
455 return (target_delete_param(param));
456 break;
457 default:
458 break;
459 }
460 return (SNMP_ERR_NOERROR);
461
462 case SNMP_OP_ROLLBACK:
463 if ((param = target_get_param(&val->var, sub)) == NULL &&
464 (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus ||
465 val->v.integer != RowStatus_createAndWait))
466 return (SNMP_ERR_GENERR);
467 switch (val->var.subs[sub - 1]) {
468 case LEAF_snmpTargetParamsMPModel:
469 param->mpmodel = ctx->scratch->int1;
470 break;
471 case LEAF_snmpTargetParamsSecurityModel:
472 param->sec_model = ctx->scratch->int1;
473 break;
474 case LEAF_snmpTargetParamsSecurityName:
475 strlcpy(param->secname, ctx->scratch->ptr1,
476 sizeof(param->secname));
477 free(ctx->scratch->ptr1);
478 break;
479 case LEAF_snmpTargetParamsSecurityLevel:
480 param->sec_level = ctx->scratch->int1;
481 break;
482 case LEAF_snmpTargetParamsRowStatus:
483 if (ctx->scratch->int1 == RowStatus_destroy)
484 return (target_delete_param(param));
485 break;
486 default:
487 break;
488 }
489
490 return (SNMP_ERR_NOERROR);
491
492 default:
493 abort();
494 }
495
496 switch (val->var.subs[sub - 1]) {
497 case LEAF_snmpTargetParamsMPModel:
498 val->v.integer = param->mpmodel;
499 break;
500 case LEAF_snmpTargetParamsSecurityModel:
501 val->v.integer = param->sec_model;
502 break;
503 case LEAF_snmpTargetParamsSecurityName:
504 return (string_get(val, param->secname, -1));
505 case LEAF_snmpTargetParamsSecurityLevel:
506 val->v.integer = param->sec_level;
507 break;
508 case LEAF_snmpTargetParamsStorageType:
509 val->v.integer = param->type;
510 break;
511 case LEAF_snmpTargetParamsRowStatus:
512 val->v.integer = param->status;
513 break;
514 default:
515 abort();
516 }
517
518 return (SNMP_ERR_NOERROR);
519 }
520
521 int
op_snmp_notify(struct snmp_context * ctx __unused,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)522 op_snmp_notify(struct snmp_context *ctx __unused, struct snmp_value *val,
523 uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
524 {
525 char nname[SNMP_ADM_STR32_SIZ];
526 struct target_notify *notify;
527
528 switch (op) {
529 case SNMP_OP_GET:
530 if ((notify = target_get_notify(&val->var, sub)) == NULL)
531 return (SNMP_ERR_NOSUCHNAME);
532 break;
533
534 case SNMP_OP_GETNEXT:
535 if ((notify = target_get_next_notify(&val->var, sub)) == NULL)
536 return (SNMP_ERR_NOSUCHNAME);
537 target_append_index(&val->var, sub, notify->name);
538 break;
539
540 case SNMP_OP_SET:
541 if ((notify = target_get_notify(&val->var, sub)) == NULL &&
542 (val->var.subs[sub - 1] != LEAF_snmpNotifyRowStatus ||
543 val->v.integer != RowStatus_createAndGo))
544 return (SNMP_ERR_NOSUCHNAME);
545
546 if (notify != NULL) {
547 if (community != COMM_INITIALIZE &&
548 notify->type == StorageType_readOnly)
549 return (SNMP_ERR_NOT_WRITEABLE);
550 }
551
552 switch (val->var.subs[sub - 1]) {
553 case LEAF_snmpNotifyTag:
554 if (val->v.octetstring.len >= SNMP_TAG_SIZ)
555 return (SNMP_ERR_INCONS_VALUE);
556 ctx->scratch->int1 = strlen(notify->taglist) + 1;
557 ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
558 if (ctx->scratch->ptr1 == NULL)
559 return (SNMP_ERR_GENERR);
560 strlcpy(ctx->scratch->ptr1, notify->taglist,
561 ctx->scratch->int1);
562 memcpy(notify->taglist, val->v.octetstring.octets,
563 val->v.octetstring.len);
564 notify->taglist[val->v.octetstring.len] = '\0';
565 break;
566
567 case LEAF_snmpNotifyType:
568 /* FALLTHROUGH */
569 case LEAF_snmpNotifyStorageType:
570 return (SNMP_ERR_INCONS_VALUE);
571 case LEAF_snmpNotifyRowStatus:
572 if (notify != NULL) {
573 if (val->v.integer != RowStatus_active &&
574 val->v.integer != RowStatus_destroy)
575 return (SNMP_ERR_INCONS_VALUE);
576 ctx->scratch->int1 = notify->status;
577 notify->status = val->v.integer;
578 return (SNMP_ERR_NOERROR);
579 }
580 if (val->v.integer != RowStatus_createAndGo ||
581 target_decode_index(&val->var, sub, nname) < 0)
582 return (SNMP_ERR_INCONS_VALUE);
583 if ((notify = target_new_notify(nname)) == NULL)
584 return (SNMP_ERR_GENERR);
585 notify->status = RowStatus_destroy;
586 if (community != COMM_INITIALIZE)
587 notify->type = StorageType_volatile;
588 else
589 notify->type = StorageType_readOnly;
590 break;
591 }
592 return (SNMP_ERR_NOERROR);
593
594 case SNMP_OP_COMMIT:
595 switch (val->var.subs[sub - 1]) {
596 case LEAF_snmpNotifyTag:
597 free(ctx->scratch->ptr1);
598 break;
599 case LEAF_snmpNotifyRowStatus:
600 notify = target_get_notify(&val->var, sub);
601 if (notify == NULL)
602 return (SNMP_ERR_GENERR);
603 if (val->v.integer == RowStatus_destroy)
604 return (target_delete_notify(notify));
605 else
606 notify->status = RowStatus_active;
607 break;
608 default:
609 break;
610 }
611 return (SNMP_ERR_NOERROR);
612
613 case SNMP_OP_ROLLBACK:
614 if ((notify = target_get_notify(&val->var, sub)) == NULL)
615 return (SNMP_ERR_GENERR);
616
617 switch (val->var.subs[sub - 1]) {
618 case LEAF_snmpNotifyTag:
619 strlcpy(notify->taglist, ctx->scratch->ptr1,
620 ctx->scratch->int1);
621 free(ctx->scratch->ptr1);
622 break;
623 case LEAF_snmpNotifyRowStatus:
624 if (ctx->scratch->int1 == RowStatus_destroy)
625 return (target_delete_notify(notify));
626 break;
627 default:
628 break;
629 }
630 return (SNMP_ERR_NOERROR);
631
632 default:
633 abort();
634 }
635
636
637 switch (val->var.subs[sub - 1]) {
638 case LEAF_snmpNotifyTag:
639 return (string_get(val, notify->taglist, -1));
640 case LEAF_snmpNotifyType:
641 val->v.integer = snmpNotifyType_trap;
642 break;
643 case LEAF_snmpNotifyStorageType:
644 val->v.integer = notify->type;
645 break;
646 case LEAF_snmpNotifyRowStatus:
647 val->v.integer = notify->status;
648 break;
649 default:
650 abort();
651 }
652
653 return (SNMP_ERR_NOERROR);
654 }
655
656 static void
target_append_index(struct asn_oid * oid,uint sub,const char * name)657 target_append_index(struct asn_oid *oid, uint sub, const char *name)
658 {
659 uint32_t i;
660
661 oid->len = sub + strlen(name);
662 for (i = 0; i < strlen(name); i++)
663 oid->subs[sub + i] = name[i];
664 }
665
666 static int
target_decode_index(const struct asn_oid * oid,uint sub,char * name)667 target_decode_index(const struct asn_oid *oid, uint sub, char *name)
668 {
669 uint32_t i;
670
671 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >=
672 SNMP_ADM_STR32_SIZ)
673 return (-1);
674
675 for (i = 0; i < oid->subs[sub]; i++)
676 name[i] = oid->subs[sub + i + 1];
677 name[i] = '\0';
678
679 return (0);
680 }
681
682 static struct target_address *
target_get_address(const struct asn_oid * oid,uint sub)683 target_get_address(const struct asn_oid *oid, uint sub)
684 {
685 char aname[SNMP_ADM_STR32_SIZ];
686 struct target_address *addrs;
687
688 if (target_decode_index(oid, sub, aname) < 0)
689 return (NULL);
690
691 for (addrs = target_first_address(); addrs != NULL;
692 addrs = target_next_address(addrs))
693 if (strcmp(aname, addrs->name) == 0)
694 return (addrs);
695
696 return (NULL);
697 }
698
699 static struct target_address *
target_get_next_address(const struct asn_oid * oid,uint sub)700 target_get_next_address(const struct asn_oid * oid, uint sub)
701 {
702 char aname[SNMP_ADM_STR32_SIZ];
703 struct target_address *addrs;
704
705 if (oid->len - sub == 0)
706 return (target_first_address());
707
708 if (target_decode_index(oid, sub, aname) < 0)
709 return (NULL);
710
711 for (addrs = target_first_address(); addrs != NULL;
712 addrs = target_next_address(addrs))
713 if (strcmp(aname, addrs->name) == 0)
714 return (target_next_address(addrs));
715
716 return (NULL);
717 }
718
719 static struct target_param *
target_get_param(const struct asn_oid * oid,uint sub)720 target_get_param(const struct asn_oid *oid, uint sub)
721 {
722 char pname[SNMP_ADM_STR32_SIZ];
723 struct target_param *param;
724
725 if (target_decode_index(oid, sub, pname) < 0)
726 return (NULL);
727
728 for (param = target_first_param(); param != NULL;
729 param = target_next_param(param))
730 if (strcmp(pname, param->name) == 0)
731 return (param);
732
733 return (NULL);
734 }
735
736 static struct target_param *
target_get_next_param(const struct asn_oid * oid,uint sub)737 target_get_next_param(const struct asn_oid *oid, uint sub)
738 {
739 char pname[SNMP_ADM_STR32_SIZ];
740 struct target_param *param;
741
742 if (oid->len - sub == 0)
743 return (target_first_param());
744
745 if (target_decode_index(oid, sub, pname) < 0)
746 return (NULL);
747
748 for (param = target_first_param(); param != NULL;
749 param = target_next_param(param))
750 if (strcmp(pname, param->name) == 0)
751 return (target_next_param(param));
752
753 return (NULL);
754 }
755
756 static struct target_notify *
target_get_notify(const struct asn_oid * oid,uint sub)757 target_get_notify(const struct asn_oid *oid, uint sub)
758 {
759 char nname[SNMP_ADM_STR32_SIZ];
760 struct target_notify *notify;
761
762 if (target_decode_index(oid, sub, nname) < 0)
763 return (NULL);
764
765 for (notify = target_first_notify(); notify != NULL;
766 notify = target_next_notify(notify))
767 if (strcmp(nname, notify->name) == 0)
768 return (notify);
769
770 return (NULL);
771 }
772
773 static struct target_notify *
target_get_next_notify(const struct asn_oid * oid,uint sub)774 target_get_next_notify(const struct asn_oid *oid, uint sub)
775 {
776 char nname[SNMP_ADM_STR32_SIZ];
777 struct target_notify *notify;
778
779 if (oid->len - sub == 0)
780 return (target_first_notify());
781
782 if (target_decode_index(oid, sub, nname) < 0)
783 return (NULL);
784
785 for (notify = target_first_notify(); notify != NULL;
786 notify = target_next_notify(notify))
787 if (strcmp(nname, notify->name) == 0)
788 return (target_next_notify(notify));
789
790 return (NULL);
791 }
792
793 static int
target_init(struct lmodule * mod,int argc __unused,char * argv[]__unused)794 target_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
795 {
796 target_module = mod;
797 target_lock = random();
798
799 return (0);
800 }
801
802
803 static int
target_fini(void)804 target_fini(void)
805 {
806 target_flush_all();
807 or_unregister(reg_target);
808 or_unregister(reg_notification);
809
810 return (0);
811 }
812
813 static void
target_start(void)814 target_start(void)
815 {
816 reg_target = or_register(&oid_target,
817 "The MIB module for managing SNMP Management Targets.",
818 target_module);
819 reg_notification = or_register(&oid_notification,
820 "The MIB module for configuring generation of SNMP notifications.",
821 target_module);
822 }
823
824 static void
target_dump(void)825 target_dump(void)
826 {
827 /* XXX: dump the module stats & list of mgmt targets */
828 }
829
830 static const char target_comment[] = \
831 "This module implements SNMP Management Target MIB Module defined in RFC 3413.";
832
833 extern const struct snmp_module config;
834 const struct snmp_module config = {
835 .comment = target_comment,
836 .init = target_init,
837 .fini = target_fini,
838 .start = target_start,
839 .tree = target_ctree,
840 .dump = target_dump,
841 .tree_size = target_CTREE_SIZE,
842 };
843