The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
snmp.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/*
18 * $Id: a6db746ba7611bcb6c0159a8aaea715ff119a463 $
19 *
20 * @file src/lib/server/snmp.c
21 * @brief Implements an SNMP-like interface using FreeRADIUS attributes
22 *
23 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 *
25 * @copyright 2016 The FreeRADIUS server project
26 * @copyright 2016 Network RADIUS SAS
27 */
28RCSID("$Id: a6db746ba7611bcb6c0159a8aaea715ff119a463 $")
29
30#include <freeradius-devel/util/atexit.h>
31#include <freeradius-devel/util/debug.h>
32
33#include <freeradius-devel/util/misc.h>
34#include <freeradius-devel/util/proto.h>
35#include <freeradius-devel/util/value.h>
36
37#include <freeradius-devel/server/dependency.h>
38#include <freeradius-devel/server/main_loop.h>
39#include <freeradius-devel/server/snmp.h>
40
41#include <freeradius-devel/protocol/snmp/freeradius.h>
42
43static fr_dict_t const *dict_snmp;
44
47 { .out = &dict_snmp, .proto = "snmp" },
49};
50
55
58 { .out = &attr_snmp_operation, .name = "FreeRADIUS-SNMP-Operation", .type = FR_TYPE_UINT8, .dict = &dict_snmp },
59 { .out = &attr_snmp_type, .name = "FreeRADIUS-SNMP-Type", .type = FR_TYPE_UINT8, .dict = &dict_snmp },
60 { .out = &attr_snmp_failure, .name = "FreeRADIUS-SNMP-Failure", .type = FR_TYPE_UINT8, .dict = &dict_snmp },
61 { .out = &attr_snmp_root, .name = "FreeRADIUS-Iso", .type = FR_TYPE_TLV, .dict = &dict_snmp },
63};
64
65#define FR_FREERADIUS_SNMP_TYPE_OBJECT 0
66
67#define SNMP_MAP_TERMINATOR { .name = NULL, .da = NULL, .type = 0 }
68
70
71typedef int (*fr_snmp_get_func_t)(TALLOC_CTX *ctx, fr_value_box_t *out, fr_snmp_map_t const *map, void *snmp_ctx);
72typedef int (*fr_snmp_set_func_t)(fr_snmp_map_t const *map, void *snmp_ctx, fr_value_box_t *data);
73typedef int (*fr_snmp_index_func_t)(TALLOC_CTX *ctx, void **snmp_ctx_out,
74 fr_snmp_map_t const *map, void const *snmp_ctx_in, uint32_t index);
75
76/** Maps a fr_pair_t to the source of a value
77 *
78 * @note Arrays of maps must be in ascending attribute order.
79 * This is because the lookup is performed using a binary
80 * search, not by index.
81 *
82 * Mappings between attributes and snmp values are more complex in
83 * an SNMP based interface, because we need to traverse the tree,
84 * looking at indexes in multiple levels of mapping tables.
85 */
87 char const *name; //!< Attribute number. Table entries must be in
88 //!< attribute number order.
89 fr_dict_attr_t const *da; //!< Dictionary attribute (resolved from attribute number).
90 unsigned int type; //!< SNMP type - More specific than attribute type.
91
92 fr_snmp_get_func_t get; //!< Function to retrieve value.
93 fr_snmp_set_func_t set; //!< Function to write a new value.
94 fr_snmp_index_func_t index; //!< Function for traversing indexes.
95
96 union {
97 size_t offset; //!< Offset in snmp_ctx (passed to index function).
98 fr_snmp_map_t *last; //!< Last sibling at this level.
99 };
100
101 fr_snmp_map_t *child; //!< Child map.
102};
103
106static int reset_state = FR_RADIUS_AUTH_SERV_CONFIG_RESET_VALUE_RUNNING;
107
109 UNUSED void *snmp_ctx)
110{
111 fr_assert(map->da->type == FR_TYPE_STRING);
112
113 if (fr_value_box_asprintf(ctx, out, NULL, false, "FreeRADIUS %s", radiusd_version_short) < 0) return -1;
114
115 return 0;
116}
117
119 UNUSED void *snmp_ctx)
120{
121 fr_time_t now;
122 fr_time_delta_t delta;
123
124 fr_assert(map->da->type == FR_TYPE_UINT32);
125
126 now = fr_time();
127 delta = fr_time_sub(now, start_time);
128
129 /*
130 * ticks are in 1/100's of seconds.
131 */
132 out->vb_uint32 += fr_time_delta_to_csec(delta);
133
134 return 0;
135}
136
138 UNUSED void *snmp_ctx)
139{
140 fr_time_t now;
141 fr_time_delta_t delta;
142
143 fr_assert(map->da->type == FR_TYPE_UINT32);
144
145 now = fr_time();
146 delta = fr_time_sub(now, reset_time);
147
148 /*
149 * ticks are in 1/100's of seconds.
150 */
151 out->vb_uint32 += fr_time_delta_to_csec(delta);
152
153 return 0;
154}
155
157 UNUSED void *snmp_ctx)
158{
159 fr_assert(map->da->type == FR_TYPE_UINT32);
160
161 out->vb_uint32 = reset_state;
162
163 return 0;
164}
165
167{
168 fr_assert(map->da->type == FR_TYPE_UINT32);
169
170 switch (in->vb_uint32) {
171 case FR_RADIUS_AUTH_SERV_CONFIG_RESET_VALUE_RESET:
174 return 0;
175
176 default:
177 return -(FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_VALUE);
178 }
179
180}
181
183 fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
184{
185 fr_assert(map->da->type == FR_TYPE_UINT32);
186
187 out->vb_uint32 = *(uint32_t *)((uint8_t *)(&radius_auth_stats) + map->offset);
188
189 return 0;
190}
191
192static int snmp_client_index(UNUSED TALLOC_CTX *ctx, void **snmp_ctx_out,
193 UNUSED fr_snmp_map_t const *map,
194 NDEBUG_UNUSED void const *snmp_ctx_in, uint32_t index_num)
195{
196 fr_client_t *client;
197
198 fr_assert(!snmp_ctx_in);
199
200 if (index_num == 0) return 1; /* SNMP indices start from 1; 0 is invalid */
201 client = client_findbynumber(NULL, index_num - 1); /* Clients indexed from 0 */
202 if (!client) return 1; /* No more clients */
203
204 *snmp_ctx_out = client;
205
206 return 0;
207}
208
209static int snmp_client_index_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out,
210 UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
211{
212 fr_client_t *client = snmp_ctx;
213
214 fr_assert(client);
215
216 out->vb_uint32 = client->number + 1; /* Clients indexed from 0 */
217
218 return 0;
219}
220
222 NDEBUG_UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
223{
224 fr_client_t *client = snmp_ctx;
225
226 fr_assert(client);
227 fr_assert(map->da->type == FR_TYPE_IPV4_ADDR);
228
229 /*
230 * The old SNMP MIB only allowed access
231 * to the IPv4 address.
232 *
233 * The EXT mib allows access to either
234 * address.
235 */
236 if (client->ipaddr.af != AF_INET) return 0;
237 memcpy(&out->vb_ip, &client->ipaddr, sizeof(out->vb_ip));
238
239 return 0;
240}
241
242static int snmp_client_id_get(TALLOC_CTX *ctx, fr_value_box_t *out,
243 NDEBUG_UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
244{
245 fr_client_t *client = snmp_ctx;
246
247 fr_assert(client);
248 fr_assert(map->da->type == FR_TYPE_STRING);
249
250 if (fr_value_box_bstrdup_buffer(ctx, out, NULL, client->longname, false) < 0) return -1;
251
252 return 0;
253}
254
256 fr_snmp_map_t const *map, void *snmp_ctx)
257{
258 fr_client_t *client = snmp_ctx;
259
260 fr_assert(client);
261 fr_assert(map->da->type == FR_TYPE_UINT32);
262
263 out->vb_uint32 = *(uint32_t *)((uint8_t *)(&client->auth) + map->offset);
264
265 return 0;
266}
267
269 { .name = "Radius-Auth-Client-Index",
270 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_INTEGER,
271 .get = snmp_client_index_get },
272 { .name = "Radius-Auth-Client-Address",
273 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_IPADDRESS,
275 { .name = "Radius-Auth-Client-ID",
276 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_STRING,
277 .get = snmp_client_id_get },
278 { .name = "Radius-Auth-Serv-Access-Requests",
279 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
280 .offset = offsetof(fr_stats_t, total_requests),
282 { .name = "Radius-Auth-Serv-Dup-Access-Requests",
283 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
284 .offset = offsetof(fr_stats_t, total_dup_requests),
286 { .name = "Radius-Auth-Serv-Access-Accepts",
287 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
288 .offset = offsetof(fr_stats_t, total_access_accepts),
290 { .name = "Radius-Auth-Serv-Access-Rejects",
291 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
292 .offset = offsetof(fr_stats_t, total_access_rejects),
294 { .name = "Radius-Auth-Serv-Access-Challenges",
295 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
296 .offset = offsetof(fr_stats_t, total_access_challenges),
298 { .name = "Radius-Auth-Serv-Malformed-Access-Requests",
299 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
300 .offset = offsetof(fr_stats_t, total_malformed_requests),
302 { .name = "Radius-Auth-Serv-Bad-Authenticators",
303 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
304 .offset = offsetof(fr_stats_t, total_bad_authenticators),
306 { .name = "Radius-Auth-Serv-Packets-Dropped",
307 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
308 .offset = offsetof(fr_stats_t, total_packets_dropped),
310 { .name = "Radius-Auth-Serv-Unknown-Types",
311 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
312 .offset = offsetof(fr_stats_t, total_unknown_types),
315};
316
318 { .name = "Radius-Auth-Client-Entry",
320 .index = snmp_client_index,
323};
324
326 { .name = "Radius-Auth-Serv-Ident",
327 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_STRING,
329 { .name = "Radius-Auth-Serv-Up-Time",
330 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_TIMETICKS,
331 .get = snmp_value_uptime_get },
332 { .name = "Radius-Auth-Serv-Reset-Time",
333 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_TIMETICKS,
335 { .name = "Radius-Auth-Serv-Config-Reset",
336 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_INTEGER,
338 .set = snmp_config_reset_set },
339 { .name = "Radius-Auth-Serv-Total-Access-Requests",
340 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
341 .offset = offsetof(fr_stats_t, total_requests),
343 { .name = "Radius-Auth-Serv-Total-Invalid-Requests",
344 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
345 .offset = offsetof(fr_stats_t, total_invalid_requests),
347 { .name = "Radius-Auth-Serv-Total-Dup-Access-Requests",
348 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
349 .offset = offsetof(fr_stats_t, total_dup_requests),
351 { .name = "Radius-Auth-Serv-Total-Access-Accepts",
352 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
353 .offset = offsetof(fr_stats_t, total_access_accepts),
355 { .name = "Radius-Auth-Serv-Total-Access-Rejects",
356 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
357 .offset = offsetof(fr_stats_t, total_access_rejects),
359 { .name = "Radius-Auth-Serv-Total-Access-Challenges",
360 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
361 .offset = offsetof(fr_stats_t, total_access_challenges),
363 { .name = "Radius-Auth-Serv-Total-Malformed-Access-Requests",
364 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
365 .offset = offsetof(fr_stats_t, total_malformed_requests),
367 { .name = "Radius-Auth-Serv-Total-Bad-Authenticators",
368 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
369 .offset = offsetof(fr_stats_t, total_bad_authenticators),
371 { .name = "Radius-Auth-Serv-Total-Packets-Dropped",
372 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
373 .offset = offsetof(fr_stats_t, total_packets_dropped),
375 { .name = "Radius-Auth-Serv-Total-Unknown-Types",
376 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
377 .offset = offsetof(fr_stats_t, total_unknown_types),
379 { .name = "Radius-Auth-Client-table",
381 .child = snmp_auth_client_entry},
383};
384
386 { .name = "Radius-Auth-Serv",
388 .child = snmp_auth_serv_counters },
390};
391
393 { .name = "Radius-Auth-Serv-Mib-Objects",
395 .child = snmp_auth_serv },
397};
398
400 { .name = "Radius-Auth-Serv-Mib",
404};
405
407 { .name = "Radius-Authentication",
409 .child = snmp_auth_serv_mib },
411};
412
414 { .name = "Radius-Mib",
416 .child = snmp_authentication },
418};
419
421 { .name = "FreeRADIUS-Mib-2",
423 .child = snmp_radius_mib },
425};
426
428 { .name = "FreeRADIUS-Mgmt",
430 .child = snmp_mib_2 },
432};
433
435 { .name = "FreeRADIUS-Internet",
437 .child = snmp_mgmt },
439};
440
442 { .name = "FreeRADIUS-Dod",
444 .child = snmp_internet },
446};
447
449 { .name = "FreeRADIUS-Org",
451 .child = snmp_dod },
453};
454
456 { .name = "FreeRADIUS-Iso",
458 .child = snmp_org },
460};
461
463 fr_da_stack_t *da_stack, unsigned int depth,
464 fr_dcursor_t *cursor,
465 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op);
466
467/** Perform a binary search to find a map matching a da
468 *
469 * @param map to search in.
470 * @param da to search for.
471 * @return
472 * - Matching map if da was found.
473 * - NULL if da was not found.
474 */
475static fr_snmp_map_t const *snmp_map_search(fr_snmp_map_t const map[], fr_dict_attr_t const *da)
476{
477 fr_snmp_map_t const *p = &map[1], *q = map[0].last, *m;
478
479 fr_assert(p <= q);
480
481 /*
482 * Fast path...
483 */
484 if (p == q) {
485 fr_assert(p->da);
486
487 if (p->da->attr == da->attr) return p;
488 return NULL;
489 }
490
491 m = p + ((q - p) / 2);
492
493 while (p <= q) {
494 if (m->da->attr < da->attr) p = m + 1;
495 else if (m->da->attr == da->attr) break;
496 else q = m - 1;
497 m = p + ((q - p) / 2);
498 }
499 if (p > q) return NULL;
500
501 return m;
502}
503
504/** Perform depth first traversal of the tree until we hit a leaf node
505 *
506 * This is used for building a fake da_stack, for findNext, so that if
507 * we get a findNext operation on something that's not a leaf, we can
508 * find the first leaf under that branch of the tree.
509 *
510 * @param[out] da_stack to rewrite.
511 * @param[in] depth at which to start rewriting.
512 * @param[in] map at this level.
513 */
514static void snmp_next_leaf(fr_da_stack_t *da_stack, unsigned int depth, fr_snmp_map_t const *map)
515{
516 uint32_t i;
517 fr_snmp_map_t const *map_p = map;
518
519 for (i = depth; (i < FR_DICT_MAX_TLV_STACK) && map_p; i++) {
520 da_stack->da[i] = map_p->da;
521 map_p = map_p->child;
522 }
523 da_stack->depth = i;
524}
525
527 fr_da_stack_t *da_stack, unsigned int depth,
528 fr_dcursor_t cursor,
529 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op,
530 uint32_t index_num)
531{
532 ssize_t ret;
533 uint32_t i;
534
535 /*
536 * Can't modify snmp_ctx, as we may need to go back up
537 * the stack, and retry when performing a getNext.
538 */
539 void *this_snmp_ctx = NULL;
540 TALLOC_CTX *tmp_ctx;
541
542 for (i = index_num; i < UINT32_MAX; i++) {
543 fr_dict_attr_t const *da;
544 fr_pair_t *vp;
545
546 tmp_ctx = talloc_new(request);
547 if (!tmp_ctx) {
548 fr_strerror_const("Out Of Memory");
549 return -(depth);
550 }
551
552 ret = map->index(tmp_ctx, &this_snmp_ctx, map, snmp_ctx, i);
553 if (ret < 0) {
554 talloc_free(tmp_ctx);
555 return ret; /* error */
556 }
557 if (ret > 0) {
558 talloc_free(tmp_ctx);
559
560 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) {
561 invalid:
562 fr_strerror_const("Invalid OID: Match stopped here");
563 return -(depth);
564 }
565
566 return ret; /* no more entries at this level, findNext at lower level */
567 }
568
569 ret = snmp_process(out, request,
570 da_stack, depth + 1,
571 &cursor,
572 map->child, this_snmp_ctx, snmp_op);
573 TALLOC_FREE(tmp_ctx);
574
575 if (ret < 0) return ret; /* error */
576 if (ret > 0) { /* findNext */
577 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) goto invalid;
578
579 /*
580 * Rebuild the stack to point to the first
581 * leaf (usually .1) of the entry.
582 *
583 * If we've unwound to this level then we're
584 * going to try again with a new entry.
585 * We need to start at the start of that
586 * entry, not at the end (where we previously
587 * were).
588 */
589 fr_proto_da_stack_build(da_stack, map->da);
590 this_snmp_ctx = NULL;
591 continue;
592 }
593
594 /*
595 * Success! - Build and prepend an index
596 * attribute to let the client know which entry
597 * we processed.
598 */
599 da = fr_dict_attr_child_by_num(map->da->parent, 0);
600 if (!da) {
601 fr_strerror_printf("No index attribute defined for \"%s\"", map->name);
602 return -(depth);
603 }
604
605 MEM(vp = fr_pair_afrom_da(request->reply_ctx, da));
606 vp->vp_uint32 = i;
608
609 return 0; /* done */
610 }
611
612 fr_strerror_const("Invalid OID: Hit max index");
613
614 return -(depth);
615}
616
618 fr_da_stack_t *da_stack, unsigned int depth,
619 fr_dcursor_t *cursor,
620 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
621{
622 fr_pair_t *next;
623 uint32_t index_num;
624 fr_pair_t *vp;
625
626 FR_PROTO_STACK_PRINT(da_stack, depth);
627
628 if (map[0].last < &map[1]) {
629 fr_strerror_const("Invalid OID: Empty map");
630 error:
631 return -(ssize_t)depth;
632 }
633
634 if (map[1].type != FR_FREERADIUS_SNMP_TYPE_OBJECT) {
635 fr_strerror_const("Invalid OID: Cannot traverse leaf");
636 goto error;
637 }
638
639 if (!map[1].index) {
640 fr_strerror_printf("Invalid OID: Got index attribute, but SNMP object is not "
641 "a table entry");
642 goto error;
643 }
644
645 if (da_stack->da[depth]->type != FR_TYPE_UINT32) {
646 fr_strerror_printf("Bad index attribute: Index attribute \"%s\" should be a integer, "
647 "but is a %s", da_stack->da[depth]->name,
648 fr_type_to_str(da_stack->da[depth]->type));
649 goto error;
650 }
651
652 /*
653 * Get the index from the index attribute's value.
654 */
655 vp = fr_dcursor_current(cursor);
656 if (!vp) {
657 fr_strerror_const("Invalid OID: No index attribute in request");
658 goto error;
659 }
660 index_num = vp->vp_uint32;
661
662 /*
663 * Advance the cursor to the next index attribute
664 * if it is an index attribute...
665 */
666 next = fr_dcursor_next_peek(cursor);
667 if (next && fr_dict_attr_common_parent(vp->da, next->da, true)) {
668 fr_proto_da_stack_build(da_stack, next->da);
669
670 while ((next = fr_dcursor_next(cursor))) if (fr_dict_attr_common_parent(vp->da, next->da, true)) break;
671 }
672
673 return snmp_process_index(out, request,
674 da_stack, depth,
675 *cursor,
676 &map[1], snmp_ctx, snmp_op,
677 index_num);
678}
679
681 fr_da_stack_t *da_stack, unsigned int depth,
682 fr_dcursor_t *cursor,
683 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
684{
685 fr_snmp_map_t const *map_p;
686 ssize_t ret;
687
688 FR_PROTO_STACK_PRINT(da_stack, depth);
689
690 /*
691 * Return element in map that matches the da at this
692 * level in the da_stack.
693 */
694 map_p = snmp_map_search(map, da_stack->da[depth]);
695 if (!map_p) {
696 invalid:
697 fr_strerror_const("Invalid OID: Match stopped here");
698 error:
699 return -(ssize_t)depth;
700 }
701
702 if (!map_p->child) {
703 fr_strerror_const("Internal error: Dictionary and SNMP map structure mismatch");
704 goto error;
705 }
706
707 /*
708 * Allow for attributes that represent fixed indexes
709 * usually *-Entry attributes.
710 *
711 * This allows a complete SNMP OID to be represented
712 * as a single attribute (with index 1 being used for
713 * each traversal).
714 *
715 * The real purpose is to allow the fake da_stack
716 * code to work correctly without needing to add
717 * fake index attributes
718 */
719 if (map_p->index) {
720 return snmp_process_index(out, request,
721 da_stack, depth,
722 *cursor,
723 map_p, snmp_ctx, snmp_op,
724 da_stack->da[depth]->attr);
725 }
726
727 for (;;) {
728 ret = snmp_process(out, request,
729 da_stack, depth + 1,
730 cursor,
731 map_p->child, snmp_ctx, snmp_op);
732 if (ret < 0) return ret; /* error */
733 if (ret > 0) { /* findNext */
734 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) goto invalid;
735 if (++map_p <= map[0].last) continue;
736 return 1; /* findNext at lower level */
737 }
738 return 0; /* done */
739 }
740}
741
743 fr_da_stack_t *da_stack, unsigned int depth,
744 fr_dcursor_t *cursor,
745 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
746{
747 fr_pair_t *vp;
748 fr_snmp_map_t const *map_p;
749
750 FR_PROTO_STACK_PRINT(da_stack, depth);
751
752 vp = fr_dcursor_current(cursor);
753
754 /*
755 * Return element in map that matches the da at this
756 * level in the da_stack.
757 */
758 map_p = snmp_map_search(map, da_stack->da[depth]);
759 if (!map_p) {
760 fr_strerror_const("Invalid OID: Match stopped here");
761 error:
762 return -(ssize_t)depth;
763 }
764
765 /*
766 * It's a leaf attribute, call the correct get/set function
767 */
768 switch (snmp_op) {
769 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT:
770 if (map_p == map[0].last) {
771 return 1; /* findNext at lower level */
772 }
773 if (vp && (map_p->da == vp->da)) { /* Next unless we faked part of the stack */
774 map_p++;
775
776 /*
777 * We were called with a leaf map, but advanced
778 * to a non-leaf map.
779 */
780 if (map_p->type == FR_FREERADIUS_SNMP_TYPE_OBJECT) {
781 return snmp_process(out, request,
782 da_stack, depth + 1,
783 cursor,
784 map_p->child, snmp_ctx, snmp_op);
785 }
786 }
788
789 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GET:
790 {
792
793 /*
794 * Verify map is a leaf
795 */
796 if (map_p->type == FR_FREERADIUS_SNMP_TYPE_OBJECT) {
797 fr_strerror_const("Invalid OID: Is not a leaf node");
798 goto error;
799 }
800
801 if (!map_p->get) {
802 fr_strerror_const("Invalid operation: Node does not support GET operations");
803 goto error;
804 }
805
806 /*
807 * Get functions can only return a single
808 * attribute. To reduce boilerplate code
809 * in callbacks, we handled allocating and
810 * inserting fr_pair_ts, and pass in a
811 * fr_value_box_t struct for the callback
812 * to complete.
813 */
814 if (map_p->get(request->reply, &data, map_p, snmp_ctx) < 0) goto error;
815
816 MEM(vp = fr_pair_afrom_da(request->reply_ctx, map_p->da));
817 fr_value_box_steal(vp, &vp->data, &data);
819
820 MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_snmp_type));
821 vp->vp_uint32 = map_p->type;
823 }
824 return 0;
825
826 case FR_FREERADIUS_SNMP_OPERATION_VALUE_SET:
827 {
828 ssize_t ret;
829
830 if (!map_p->set || (map_p->type == FR_FREERADIUS_SNMP_TYPE_OBJECT)) {
831 MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_snmp_failure));
832 vp->vp_uint32 = FR_FREERADIUS_SNMP_FAILURE_VALUE_NOT_WRITABLE;
834 return 0;
835 }
836
837 vp = fr_dcursor_current(cursor);
838 ret = map_p->set(map_p, snmp_ctx, &vp->data);
839 if (ret < 0) switch (-(ret)) {
840 case FR_FREERADIUS_SNMP_FAILURE_VALUE_NOT_WRITABLE:
841 case FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_TYPE:
842 case FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_LENGTH:
843 case FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_VALUE:
844 case FR_FREERADIUS_SNMP_FAILURE_VALUE_INCONSISTENT_VALUE:
845 MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_snmp_failure));
846 vp->vp_uint32 = -(ret);
848 break;
849
850 default:
851 goto error;
852 }
853 }
854 return 0;
855
856 default:
857 fr_assert(0);
858 goto error;
859 }
860}
861
862/** Traverse a tree of SNMP maps
863 *
864 * @param[out] out Where to write response attributes.
865 * @param[in] request The current request.
866 * @param[in,out] da_stack we're traversing.
867 * @param[in] depth we're currently at in the da_stack.
868 * @param[in] cursor representing the current attribute we're processing.
869 * @param[in] map matching the current depth in the da_stack.
870 * @param[in] snmp_ctx allocated by the previous index traversal function.
871 * @param[in] snmp_op we're performing.
872 * @return
873 * - 0 on success.
874 * - 1 to signal caller that it should find the next OID at this level
875 * and recurse again.
876 * - <0 the depth at which an error occurred, as a negative integer.
877 */
879 fr_da_stack_t *da_stack, unsigned int depth,
880 fr_dcursor_t *cursor,
881 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
882{
883 fr_assert(map);
884
885 FR_PROTO_STACK_PRINT(da_stack, depth);
886
887 /*
888 * We've run out of stack... This is an error unless
889 * we're performing a getNext operation, in which
890 * case we fake the rest of the stack.
891 */
892 if (!da_stack->da[depth]) {
893 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) {
894 fr_strerror_const("Invalid OID: Not a leaf");
895 return -(ssize_t)depth;
896 }
897 snmp_next_leaf(da_stack, depth, &map[1]);
898
899 if (!fr_cond_assert(da_stack->da[depth])) return -1;
900 }
901
902 /*
903 * It's an index attribute, use the value of
904 * the index attribute to traverse the index.
905 */
906 if (da_stack->da[depth]->attr == 0) return snmp_process_index_attr(out, request,
907 da_stack, depth,
908 cursor,
909 map, snmp_ctx, snmp_op);
910
911 /*
912 * It's a TLV, recurse, and locate the map
913 * matching the next deepest DA in the
914 * da_stack.
915 */
916 if (da_stack->da[depth]->type == FR_TYPE_TLV) return snmp_process_tlv(out, request,
917 da_stack, depth,
918 cursor,
919 map, snmp_ctx, snmp_op);
920
921 /*
922 * Must be a leaf, call the appropriate get/set function
923 * and create attributes for the response.
924 */
925 return snmp_process_leaf(out, request,
926 da_stack, depth,
927 cursor,
928 map, snmp_ctx, snmp_op);
929}
930
932{
933 fr_dcursor_t request_cursor, op_cursor, out_cursor, reply_cursor;
935 fr_pair_t *vp;
936
937 char oid_str[FR_DICT_MAX_TLV_STACK * 4]; /* .<num>{1,3} */
938 size_t oid_len, len;
939
940 fr_da_stack_t da_stack;
941 unsigned int depth;
942 ssize_t ret;
943
944 fr_pair_t *op;
945
947 fr_pair_dcursor_init(&request_cursor, &request->request_pairs);
948 fr_pair_dcursor_by_da_init(&op_cursor, &request->request_pairs, attr_snmp_operation);
949 fr_pair_dcursor_init(&reply_cursor, &request->reply_pairs);
950 fr_pair_dcursor_init(&out_cursor, &head);
951
952 RDEBUG2("Processing SNMP stats request");
953
954 /*
955 * First take a pass over the request, converting
956 * any unknown types back to real attributes.
957 *
958 * This hack is required because empty TLVs are
959 * not allowed in the RADIUS protocol, so we
960 * encode the TLV as an octet type attribute
961 */
962 for (vp = fr_dcursor_head(&request_cursor);
963 vp;
964 vp = fr_dcursor_next(&request_cursor)) {
965 fr_dict_attr_t const *da;
966
967 if (!vp->da->flags.is_unknown) continue;
968
970 if (!da) {
971 WARN("Failed converting \"%s\" to a known attribute", vp->da->name);
972 continue;
973 }
974
975 RDEBUG2("Unknown attribute \"%s\" resolves to \"%s\"", vp->da->name, da->name);
976
977 /*
978 * Clear out any junk values
979 */
980 if (da->type == FR_TYPE_TLV) fr_value_box_clear(&vp->data);
981
982 if (fr_pair_reinit_from_da(&request->request_pairs, vp, da) < 0) {
983 RPWARN("Failed converting unknown attribute to known attribute");
984 continue;
985 }
986 }
987
988 for (vp = fr_pair_dcursor_by_ancestor_init(&request_cursor, &request->request_pairs, attr_snmp_root);
989 vp;
990 vp = fr_dcursor_next(&request_cursor)) {
991 fr_proto_da_stack_build(&da_stack, vp->da);
992
993 /*
994 * Wind to the frame in the TLV stack that matches our
995 * SNMP root.
996 */
997 for (depth = 0; da_stack.da[depth]; depth++) if (attr_snmp_root == da_stack.da[depth]) break;
998
999 /*
1000 * Any attribute returned by fr_dcursor_next_by_ancestor
1001 * should have the SNMP root attribute as an ancestor.
1002 */
1003 fr_assert(da_stack.da[depth]);
1004 fr_assert(da_stack.da[depth] == attr_snmp_root);
1005
1006 /*
1007 * Operator attribute acts as a request delimiter
1008 */
1009 op = fr_dcursor_current(&op_cursor);
1010 if (!op) {
1011 ERROR("Missing operation (%s)", attr_snmp_operation->name);
1012 return -1;
1013 }
1014 fr_dcursor_next(&op_cursor);
1015
1016 switch (op->vp_uint32) {
1017 case FR_FREERADIUS_SNMP_OPERATION_VALUE_PING:
1018 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GET:
1019 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT:
1020 case FR_FREERADIUS_SNMP_OPERATION_VALUE_SET:
1021 break;
1022
1023 default:
1024 ERROR("Invalid operation %u", op->vp_uint32);
1025 return -1;
1026 }
1027
1028 /*
1029 * Returns depth (as negative integer) at which the error occurred
1030 */
1031 ret = snmp_process(&out_cursor, request,
1032 &da_stack, depth,
1033 &request_cursor,
1034 snmp_iso, NULL, op->vp_uint32);
1035 if (ret < 0) {
1036 fr_sbuff_t oid_str_sbuff = FR_SBUFF_OUT(oid_str, sizeof(oid_str));
1038
1039 (void) fr_sbuff_in_char(&oid_str_sbuff, '.');
1040
1041 /* Get the length of the matching part */
1042 oid_len = fr_dict_attr_oid_print(&oid_str_sbuff, attr_snmp_root, da_stack.da[-(ret)], false);
1043
1044 /* Get the last frame in the current stack */
1045 len = fr_dict_attr_oid_print(&oid_str_sbuff, attr_snmp_root,
1046 da_stack.da[da_stack.depth - 1], false);
1047
1048 /* Use the difference in OID string length to place the marker */
1049 REMARKER(oid_str, oid_len - (len - oid_len), "%s", fr_strerror());
1050
1051 return -1;
1052 }
1053 }
1054
1055 fr_dcursor_head(&out_cursor);
1056 fr_dcursor_merge(&reply_cursor, &out_cursor);
1057
1058 return 0;
1059}
1060
1061/** Internal SNMP initialisation function (used for recursion)
1062 *
1063 */
1065{
1066 unsigned int i;
1067
1068 for (i = 0; map[i].name; i++) {
1069 if (map[i].type == FR_FREERADIUS_SNMP_TYPE_OBJECT) {
1070 int ret;
1071
1072 fr_assert(map[i].child);
1073
1074 map[i].da = fr_dict_attr_by_name(NULL, parent, map[i].name);
1075 if (!map[i].da) {
1076 ERROR("Incomplete dictionary: Missing definition for \"%s\"", map[i].name);
1077 return -1;
1078 }
1079
1080 ret = _fr_snmp_init_r(map[i].child, map[i].da);
1081 if (ret < 0) return -1;
1082
1083 continue;
1084 }
1085
1086 map[i].da = fr_dict_attr_by_name(NULL, parent, map[i].name);
1087 if (!map[i].da) {
1088 ERROR("Incomplete dictionary: Missing definition for \"%s\"", map[i].name);
1089 return -1;
1090 }
1091 }
1092
1093 /*
1094 * Shift the contents of the map, clearing the first entry.
1095 *
1096 * @note We could also do a quicksort here but we assume
1097 * that future developers will heed this warning to list
1098 * attributes in ascending order.
1099 */
1100 memmove(&map[1], map, sizeof(*map) * i);
1101 memset(&map[0], 0, sizeof(*map));
1102 map[0].name = "Not the map offset you were looking for";
1103 map[0].last = &map[i]; /* This allows us to perform a binary search in the array */
1104
1105 return 0;
1106}
1107static int _fr_snmp_init(UNUSED void *uctx)
1108{
1109 start_time = fr_time();
1111
1112 if (fr_dict_autoload(snmp_dict) < 0) {
1113 fr_perror("snmp_init");
1114 return -1;
1115 }
1116
1118 fr_perror("snmp_init");
1119 return -1;
1120 }
1121
1122 return _fr_snmp_init_r(snmp_iso, fr_dict_root(dict_snmp)); /* The SNMP root node */
1123}
1124
1125static int _fr_snmp_free(UNUSED void *uctx)
1126{
1128
1129 return 0;
1130}
1131
1132/** Initialise the tree of SNMP map structures used to attach callbacks to OIDs
1133 *
1134 */
1136{
1137 int ret;
1138
1139 fr_atexit_global_once_ret(&ret, _fr_snmp_init, _fr_snmp_free, NULL);
1140
1141 return ret;
1142}
#define RCSID(id)
Definition build.h:512
#define NDEBUG_UNUSED
Definition build.h:347
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:343
#define UNUSED
Definition build.h:336
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:288
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:406
static void fr_dcursor_merge(fr_dcursor_t *cursor, fr_dcursor_t *to_append)
Moves items from one cursor to another.
Definition dcursor.h:520
static void * fr_dcursor_next_peek(fr_dcursor_t *cursor)
Return the next iterator item without advancing the cursor.
Definition dcursor.h:303
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:337
static void * fr_dcursor_head(fr_dcursor_t *cursor)
Rewind cursor to the start of the list.
Definition dcursor.h:232
static int fr_dcursor_prepend(fr_dcursor_t *cursor, void *v)
Insert a single item at the start of the list.
Definition dcursor.h:376
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
#define MEM(x)
Definition debug.h:36
char const * radiusd_version_short
Definition dependency.c:39
#define ERROR(fmt,...)
Definition dhcpclient.c:40
fr_dict_attr_t const * fr_dict_attr_unknown_resolve(fr_dict_t const *dict, fr_dict_attr_t const *da)
Check to see if we can convert a nested TLV structure to known attributes.
#define fr_dict_autofree(_to_free)
Definition dict.h:915
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
Definition dict_util.c:2287
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3505
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2639
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4372
#define fr_dict_autoload(_to_load)
Definition dict.h:912
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition dict.h:517
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition dict_util.c:3570
static fr_slen_t in
Definition dict.h:882
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
talloc_free(hp)
int af
Address family.
Definition inet.h:63
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition client.h:83
fr_stats_t auth
Authentication stats.
Definition client.h:141
char const * longname
Client identifier.
Definition client.h:87
int number
Unique client number.
Definition client.h:136
Describes a host allowed to send packets to the server.
Definition client.h:80
#define RPWARN(fmt,...)
Definition log.h:313
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
Definition log.h:510
#define fr_time()
Definition event.c:60
void main_loop_signal_raise(int flag)
Definition main_loop.c:78
@ RADIUS_SIGNAL_SELF_HUP
Definition main_loop.h:36
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
unsigned int uint32_t
long int ssize_t
ssize_t fr_dict_attr_oid_print(fr_sbuff_t *out, fr_dict_attr_t const *ancestor, fr_dict_attr_t const *da, bool numeric)
unsigned char uint8_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:290
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
int fr_pair_reinit_from_da(fr_pair_list_t *list, fr_pair_t *vp, fr_dict_attr_t const *da)
Re-initialise an attribute with a different da.
Definition pair.c:327
void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
Build a complete DA stack from the da back to the root.
Definition proto.c:118
#define fr_assert(_expr)
Definition rad_assert.h:37
#define RDEBUG2(fmt,...)
#define WARN(fmt,...)
static char const * name
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_in_char(_sbuff,...)
fr_stats_t radius_auth_stats
Definition stats.c:38
fr_snmp_get_func_t get
Function to retrieve value.
Definition snmp.c:92
static fr_snmp_map_t snmp_auth_serv[]
Definition snmp.c:385
fr_snmp_index_func_t index
Function for traversing indexes.
Definition snmp.c:94
static fr_snmp_map_t snmp_radius_mib[]
Definition snmp.c:413
static ssize_t snmp_process_tlv(fr_dcursor_t *out, request_t *request, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
Definition snmp.c:680
static fr_snmp_map_t snmp_auth_client_entry[]
Definition snmp.c:317
static fr_snmp_map_t snmp_mgmt[]
Definition snmp.c:427
static fr_snmp_map_t const * snmp_map_search(fr_snmp_map_t const map[], fr_dict_attr_t const *da)
Perform a binary search to find a map matching a da.
Definition snmp.c:475
static int _fr_snmp_init(UNUSED void *uctx)
Definition snmp.c:1107
static fr_snmp_map_t snmp_auth_serv_mib[]
Definition snmp.c:399
static int snmp_value_uptime_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
Definition snmp.c:118
static fr_time_t start_time
Definition snmp.c:104
static int snmp_config_reset_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
Definition snmp.c:156
char const * name
Attribute number.
Definition snmp.c:87
static int snmp_auth_client_stats_offset_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, fr_snmp_map_t const *map, void *snmp_ctx)
Definition snmp.c:255
fr_snmp_set_func_t set
Function to write a new value.
Definition snmp.c:93
static fr_time_t reset_time
Definition snmp.c:105
static fr_dict_t const * dict_snmp
Definition snmp.c:43
static fr_dict_attr_t const * attr_snmp_root
Definition snmp.c:54
static fr_snmp_map_t snmp_auth_serv_counters[]
Definition snmp.c:325
static void snmp_next_leaf(fr_da_stack_t *da_stack, unsigned int depth, fr_snmp_map_t const *map)
Perform depth first traversal of the tree until we hit a leaf node.
Definition snmp.c:514
int(* fr_snmp_index_func_t)(TALLOC_CTX *ctx, void **snmp_ctx_out, fr_snmp_map_t const *map, void const *snmp_ctx_in, uint32_t index)
Definition snmp.c:73
int(* fr_snmp_set_func_t)(fr_snmp_map_t const *map, void *snmp_ctx, fr_value_box_t *data)
Definition snmp.c:72
#define FR_FREERADIUS_SNMP_TYPE_OBJECT
Definition snmp.c:65
static ssize_t snmp_process_index(fr_dcursor_t *out, request_t *request, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t cursor, fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op, uint32_t index_num)
Definition snmp.c:526
static int snmp_client_ipv4addr_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
Definition snmp.c:221
static fr_snmp_map_t snmp_iso[]
Definition snmp.c:455
static int _fr_snmp_init_r(fr_snmp_map_t map[], fr_dict_attr_t const *parent)
Internal SNMP initialisation function (used for recursion)
Definition snmp.c:1064
static fr_snmp_map_t snmp_mib_2[]
Definition snmp.c:420
fr_dict_attr_autoload_t snmp_dict_attr[]
Definition snmp.c:57
int fr_snmp_process(request_t *request)
Definition snmp.c:931
static int snmp_config_reset_set(NDEBUG_UNUSED fr_snmp_map_t const *map, UNUSED void *snmp_ctx, fr_value_box_t *in)
Definition snmp.c:166
static ssize_t snmp_process_leaf(fr_dcursor_t *out, request_t *request, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
Definition snmp.c:742
static fr_snmp_map_t snmp_authentication[]
Definition snmp.c:406
static int snmp_auth_stats_offset_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
Definition snmp.c:182
static int snmp_client_index_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
Definition snmp.c:209
int(* fr_snmp_get_func_t)(TALLOC_CTX *ctx, fr_value_box_t *out, fr_snmp_map_t const *map, void *snmp_ctx)
Definition snmp.c:71
static int _fr_snmp_free(UNUSED void *uctx)
Definition snmp.c:1125
static fr_snmp_map_t snmp_org[]
Definition snmp.c:448
static int snmp_client_index(UNUSED TALLOC_CTX *ctx, void **snmp_ctx_out, UNUSED fr_snmp_map_t const *map, NDEBUG_UNUSED void const *snmp_ctx_in, uint32_t index_num)
Definition snmp.c:192
static fr_snmp_map_t snmp_dod[]
Definition snmp.c:441
static int snmp_value_serv_ident_get(TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
Definition snmp.c:108
int fr_snmp_init(void)
Initialise the tree of SNMP map structures used to attach callbacks to OIDs.
Definition snmp.c:1135
static int reset_state
Definition snmp.c:106
static fr_dict_attr_t const * attr_snmp_failure
Definition snmp.c:53
unsigned int type
SNMP type - More specific than attribute type.
Definition snmp.c:90
static fr_dict_attr_t const * attr_snmp_type
Definition snmp.c:52
static ssize_t snmp_process(fr_dcursor_t *out, request_t *request, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
Traverse a tree of SNMP maps.
Definition snmp.c:878
fr_dict_autoload_t snmp_dict[]
Definition snmp.c:46
fr_snmp_map_t * child
Child map.
Definition snmp.c:101
static int snmp_config_reset_time_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, UNUSED void *snmp_ctx)
Definition snmp.c:137
static ssize_t snmp_process_index_attr(fr_dcursor_t *out, request_t *request, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
Definition snmp.c:617
fr_dict_attr_t const * da
Dictionary attribute (resolved from attribute number).
Definition snmp.c:89
static int snmp_client_id_get(TALLOC_CTX *ctx, fr_value_box_t *out, NDEBUG_UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
Definition snmp.c:242
static fr_dict_attr_t const * attr_snmp_operation
Definition snmp.c:51
static fr_snmp_map_t snmp_auth_serv_mib_objects[]
Definition snmp.c:392
static fr_snmp_map_t snmp_internet[]
Definition snmp.c:434
#define SNMP_MAP_TERMINATOR
Definition snmp.c:67
static fr_snmp_map_t snmp_auth_client_entry_counters[]
Definition snmp.c:268
Maps a fr_pair_t to the source of a value.
Definition snmp.c:86
fr_client_t * client_findbynumber(UNUSED const fr_client_list_t *clients, UNUSED int number)
Definition client.c:361
fr_aka_sim_id_type_t type
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
static int64_t fr_time_delta_to_csec(fr_time_delta_t delta)
Definition time.h:642
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
static fr_slen_t head
Definition xlat.h:420
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
Definition pair.h:639
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:604
#define fr_pair_dcursor_by_ancestor_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes descended from the specified fr_dict_attr_t.
Definition pair.h:657
static fr_slen_t parent
Definition pair.h:858
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Definition proto.h:44
uint8_t depth
Deepest attribute in the stack.
Definition proto.h:56
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition proto.h:57
Structure for holding the stack of dictionary attributes being encoded.
Definition proto.h:55
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:737
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:454
int fr_value_box_bstrdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated talloced buffer to a fr_value_box_t.
Definition value.c:4901
int fr_value_box_asprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted, char const *fmt,...)
Print a formatted string using our internal printf wrapper and assign it to a value box.
Definition value.c:4707
int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
Copy value data verbatim moving any buffers to the specified context.
Definition value.c:4552
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4377
static fr_slen_t data
Definition value.h:1340
static size_t char ** out
Definition value.h:1030