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