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: eda926ec56b4c1e04b26f859349bfccd2a71109c $
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: eda926ec56b4c1e04b26f859349bfccd2a71109c $")
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" },
48 { NULL }
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 },
62 { NULL }
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 fr_value_box_asprintf(ctx, out, NULL, false, "FreeRADIUS %s", radiusd_version_short);
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 client = client_findbynumber(NULL, index_num - 1); /* Clients indexed from 0 */
201 if (!client) return 1; /* No more clients */
202
203 *snmp_ctx_out = client;
204
205 return 0;
206}
207
208static int snmp_client_index_get(UNUSED TALLOC_CTX *ctx, fr_value_box_t *out,
209 UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
210{
211 fr_client_t *client = snmp_ctx;
212
213 fr_assert(client);
214
215 out->vb_uint32 = client->number + 1; /* Clients indexed from 0 */
216
217 return 0;
218}
219
221 NDEBUG_UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
222{
223 fr_client_t *client = snmp_ctx;
224
225 fr_assert(client);
226 fr_assert(map->da->type == FR_TYPE_IPV4_ADDR);
227
228 /*
229 * The old SNMP MIB only allowed access
230 * to the IPv4 address.
231 *
232 * The EXT mib allows access to either
233 * address.
234 */
235 if (client->ipaddr.af != AF_INET) return 0;
236 memcpy(&out->vb_ip, &client->ipaddr, sizeof(out->vb_ip));
237
238 return 0;
239}
240
241static int snmp_client_id_get(TALLOC_CTX *ctx, fr_value_box_t *out,
242 NDEBUG_UNUSED fr_snmp_map_t const *map, void *snmp_ctx)
243{
244 fr_client_t *client = snmp_ctx;
245
246 fr_assert(client);
247 fr_assert(map->da->type == FR_TYPE_STRING);
248
249 fr_value_box_bstrdup_buffer(ctx, out, NULL, client->longname, false);
250
251 return 0;
252}
253
255 fr_snmp_map_t const *map, void *snmp_ctx)
256{
257 fr_client_t *client = snmp_ctx;
258
259 fr_assert(client);
260 fr_assert(map->da->type == FR_TYPE_UINT32);
261
262 out->vb_uint32 = *(uint32_t *)((uint8_t *)(&client->auth) + map->offset);
263
264 return 0;
265}
266
268 { .name = "Radius-Auth-Client-Index",
269 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_INTEGER,
270 .get = snmp_client_index_get },
271 { .name = "Radius-Auth-Client-Address",
272 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_IPADDRESS,
274 { .name = "Radius-Auth-Client-ID",
275 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_STRING,
276 .get = snmp_client_id_get },
277 { .name = "Radius-Auth-Serv-Access-Requests",
278 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
279 .offset = offsetof(fr_stats_t, total_requests),
281 { .name = "Radius-Auth-Serv-Dup-Access-Requests",
282 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
283 .offset = offsetof(fr_stats_t, total_dup_requests),
285 { .name = "Radius-Auth-Serv-Access-Accepts",
286 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
287 .offset = offsetof(fr_stats_t, total_access_accepts),
289 { .name = "Radius-Auth-Serv-Access-Rejects",
290 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
291 .offset = offsetof(fr_stats_t, total_access_rejects),
293 { .name = "Radius-Auth-Serv-Access-Challenges",
294 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
295 .offset = offsetof(fr_stats_t, total_access_challenges),
297 { .name = "Radius-Auth-Serv-Malformed-Access-Requests",
298 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
299 .offset = offsetof(fr_stats_t, total_malformed_requests),
301 { .name = "Radius-Auth-Serv-Bad-Authenticators",
302 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
303 .offset = offsetof(fr_stats_t, total_bad_authenticators),
305 { .name = "Radius-Auth-Serv-Packets-Dropped",
306 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
307 .offset = offsetof(fr_stats_t, total_packets_dropped),
309 { .name = "Radius-Auth-Serv-Unknown-Types",
310 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
311 .offset = offsetof(fr_stats_t, total_unknown_types),
314};
315
317 { .name = "Radius-Auth-Client-Entry",
319 .index = snmp_client_index,
322};
323
325 { .name = "Radius-Auth-Serv-Ident",
326 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_STRING,
328 { .name = "Radius-Auth-Serv-Up-Time",
329 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_TIMETICKS,
330 .get = snmp_value_uptime_get },
331 { .name = "Radius-Auth-Serv-Reset-Time",
332 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_TIMETICKS,
334 { .name = "Radius-Auth-Serv-Config-Reset",
335 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_INTEGER,
337 .set = snmp_config_reset_set },
338 { .name = "Radius-Auth-Serv-Total-Access-Requests",
339 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
340 .offset = offsetof(fr_stats_t, total_requests),
342 { .name = "Radius-Auth-Serv-Total-Invalid-Requests",
343 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
344 .offset = offsetof(fr_stats_t, total_invalid_requests),
346 { .name = "Radius-Auth-Serv-Total-Dup-Access-Requests",
347 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
348 .offset = offsetof(fr_stats_t, total_dup_requests),
350 { .name = "Radius-Auth-Serv-Total-Access-Accepts",
351 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
352 .offset = offsetof(fr_stats_t, total_access_accepts),
354 { .name = "Radius-Auth-Serv-Total-Access-Rejects",
355 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
356 .offset = offsetof(fr_stats_t, total_access_rejects),
358 { .name = "Radius-Auth-Serv-Total-Access-Challenges",
359 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
360 .offset = offsetof(fr_stats_t, total_access_challenges),
362 { .name = "Radius-Auth-Serv-Total-Malformed-Access-Requests",
363 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
364 .offset = offsetof(fr_stats_t, total_malformed_requests),
366 { .name = "Radius-Auth-Serv-Total-Bad-Authenticators",
367 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
368 .offset = offsetof(fr_stats_t, total_bad_authenticators),
370 { .name = "Radius-Auth-Serv-Total-Packets-Dropped",
371 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
372 .offset = offsetof(fr_stats_t, total_packets_dropped),
374 { .name = "Radius-Auth-Serv-Total-Unknown-Types",
375 .type = FR_FREERADIUS_SNMP_TYPE_VALUE_COUNTER,
376 .offset = offsetof(fr_stats_t, total_unknown_types),
378 { .name = "Radius-Auth-Client-table",
380 .child = snmp_auth_client_entry},
382};
383
385 { .name = "Radius-Auth-Serv",
387 .child = snmp_auth_serv_counters },
389};
390
392 { .name = "Radius-Auth-Serv-Mib-Objects",
394 .child = snmp_auth_serv },
396};
397
399 { .name = "Radius-Auth-Serv-Mib",
403};
404
406 { .name = "Radius-Authentication",
408 .child = snmp_auth_serv_mib },
410};
411
413 { .name = "Radius-Mib",
415 .child = snmp_authentication },
417};
418
420 { .name = "FreeRADIUS-Mib-2",
422 .child = snmp_radius_mib },
424};
425
427 { .name = "FreeRADIUS-Mgmt",
429 .child = snmp_mib_2 },
431};
432
434 { .name = "FreeRADIUS-Internet",
436 .child = snmp_mgmt },
438};
439
441 { .name = "FreeRADIUS-Dod",
443 .child = snmp_internet },
445};
446
448 { .name = "FreeRADIUS-Org",
450 .child = snmp_dod },
452};
453
455 { .name = "FreeRADIUS-Iso",
457 .child = snmp_org },
459};
460
462 fr_da_stack_t *da_stack, unsigned int depth,
463 fr_dcursor_t *cursor,
464 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op);
465
466/** Perform a binary search to find a map matching a da
467 *
468 * @param map to search in.
469 * @param da to search for.
470 * @return
471 * - Matching map if da was found.
472 * - NULL if da was not found.
473 */
474static fr_snmp_map_t const *snmp_map_search(fr_snmp_map_t const map[], fr_dict_attr_t const *da)
475{
476 fr_snmp_map_t const *p = &map[1], *q = map[0].last, *m;
477
478 fr_assert(p <= q);
479
480 /*
481 * Fast path...
482 */
483 if (p == q) {
484 fr_assert(p->da);
485
486 if (p->da->attr == da->attr) return p;
487 return NULL;
488 }
489
490 m = p + ((q - p) / 2);
491
492 while (p <= q) {
493 if (m->da->attr < da->attr) p = m + 1;
494 else if (m->da->attr == da->attr) break;
495 else q = m - 1;
496 m = p + ((q - p) / 2);
497 }
498 if (p > q) return NULL;
499
500 return m;
501}
502
503/** Perform depth first traversal of the tree until we hit a leaf node
504 *
505 * This is used for building a fake da_stack, for findNext, so that if
506 * we get a findNext operation on something that's not a leaf, we can
507 * find the first leaf under that branch of the tree.
508 *
509 * @param[out] da_stack to rewrite.
510 * @param[in] depth at which to start rewriting.
511 * @param[in] map at this level.
512 */
513static void snmp_next_leaf(fr_da_stack_t *da_stack, unsigned int depth, fr_snmp_map_t const *map)
514{
515 uint32_t i;
516 fr_snmp_map_t const *map_p = map;
517
518 for (i = depth; (i < FR_DICT_MAX_TLV_STACK) && map_p; i++) {
519 da_stack->da[i] = map_p->da;
520 map_p = map_p->child;
521 }
522 da_stack->depth = i;
523}
524
526 fr_da_stack_t *da_stack, unsigned int depth,
527 fr_dcursor_t cursor,
528 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op,
529 uint32_t index_num)
530{
531 ssize_t ret;
532 uint32_t i;
533
534 /*
535 * Can't modify snmp_ctx, as we may need to go back up
536 * the stack, and retry when performing a getNext.
537 */
538 void *this_snmp_ctx = NULL;
539 TALLOC_CTX *tmp_ctx;
540
541 for (i = index_num; i < UINT32_MAX; i++) {
542 fr_dict_attr_t const *da;
543 fr_pair_t *vp;
544
545 tmp_ctx = talloc_new(request);
546 if (!tmp_ctx) {
547 fr_strerror_const("Out Of Memory");
548 return -(depth);
549 }
550
551 ret = map->index(tmp_ctx, &this_snmp_ctx, map, snmp_ctx, i);
552 if (ret < 0) {
553 talloc_free(tmp_ctx);
554 return ret; /* error */
555 }
556 if (ret > 0) {
557 talloc_free(tmp_ctx);
558
559 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) {
560 invalid:
561 fr_strerror_const("Invalid OID: Match stopped here");
562 return -(depth);
563 }
564
565 return ret; /* no more entries at this level, findNext at lower level */
566 }
567
568 ret = snmp_process(out, request,
569 da_stack, depth + 1,
570 &cursor,
571 map->child, this_snmp_ctx, snmp_op);
572 TALLOC_FREE(tmp_ctx);
573
574 if (ret < 0) return ret; /* error */
575 if (ret > 0) { /* findNext */
576 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) goto invalid;
577
578 /*
579 * Rebuild the stack to point to the first
580 * leaf (usually .1) of the entry.
581 *
582 * If we've unwound to this level then we're
583 * going to try again with a new entry.
584 * We need to start at the start of that
585 * entry, not at the end (where we previously
586 * were).
587 */
588 fr_proto_da_stack_build(da_stack, map->da);
589 this_snmp_ctx = NULL;
590 continue;
591 }
592
593 /*
594 * Success! - Build and prepend an index
595 * attribute to let the client know which entry
596 * we processed.
597 */
598 da = fr_dict_attr_child_by_num(map->da->parent, 0);
599 if (!da) {
600 fr_strerror_printf("No index attribute defined for \"%s\"", map->name);
601 return -(depth);
602 }
603
604 MEM(vp = fr_pair_afrom_da(request->reply_ctx, da));
605 vp->vp_uint32 = i;
607
608 return 0; /* done */
609 }
610
611 fr_strerror_const("Invalid OID: Hit max index");
612
613 return -(depth);
614}
615
617 fr_da_stack_t *da_stack, unsigned int depth,
618 fr_dcursor_t *cursor,
619 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
620{
621 fr_pair_t *next;
622 uint32_t index_num;
623 fr_pair_t *vp;
624
625 FR_PROTO_STACK_PRINT(da_stack, depth);
626
627 if (map[0].last < &map[1]) {
628 fr_strerror_const("Invalid OID: Empty map");
629 error:
630 return -(ssize_t)depth;
631 }
632
633 if (map[1].type != FR_FREERADIUS_SNMP_TYPE_OBJECT) {
634 fr_strerror_const("Invalid OID: Cannot traverse leaf");
635 goto error;
636 }
637
638 if (!map[1].index) {
639 fr_strerror_printf("Invalid OID: Got index attribute, but SNMP object is not "
640 "a table entry");
641 goto error;
642 }
643
644 if (da_stack->da[depth]->type != FR_TYPE_UINT32) {
645 fr_strerror_printf("Bad index attribute: Index attribute \"%s\" should be a integer, "
646 "but is a %s", da_stack->da[depth]->name,
647 fr_type_to_str(da_stack->da[depth]->type));
648 goto error;
649 }
650
651 /*
652 * Get the index from the index attribute's value.
653 */
654 vp = fr_dcursor_current(cursor);
655 index_num = vp->vp_uint32;
656
657 /*
658 * Advance the cursor to the next index attribute
659 * if it is an index attribute...
660 */
661 next = fr_dcursor_next_peek(cursor);
662 if (next && fr_dict_attr_common_parent(vp->da, next->da, true)) {
663 fr_proto_da_stack_build(da_stack, next->da);
664
665 while ((next = fr_dcursor_next(cursor))) if (fr_dict_attr_common_parent(vp->da, next->da, true)) break;
666 }
667
668 return snmp_process_index(out, request,
669 da_stack, depth,
670 *cursor,
671 &map[1], snmp_ctx, snmp_op,
672 index_num);
673}
674
676 fr_da_stack_t *da_stack, unsigned int depth,
677 fr_dcursor_t *cursor,
678 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
679{
680 fr_snmp_map_t const *map_p;
681 ssize_t ret;
682
683 FR_PROTO_STACK_PRINT(da_stack, depth);
684
685 /*
686 * Return element in map that matches the da at this
687 * level in the da_stack.
688 */
689 map_p = snmp_map_search(map, da_stack->da[depth]);
690 if (!map_p) {
691 invalid:
692 fr_strerror_const("Invalid OID: Match stopped here");
693 error:
694 return -(ssize_t)depth;
695 }
696
697 if (!map_p->child) {
698 fr_strerror_const("Internal error: Dictionary and SNMP map structure mismatch");
699 goto error;
700 }
701
702 /*
703 * Allow for attributes that represent fixed indexes
704 * usually *-Entry attributes.
705 *
706 * This allows a complete SNMP OID to be represented
707 * as a single attribute (with index 1 being used for
708 * each traversal).
709 *
710 * The real purpose is to allow the fake da_stack
711 * code to work correctly without needing to add
712 * fake index attributes
713 */
714 if (map_p->index) {
715 return snmp_process_index(out, request,
716 da_stack, depth,
717 *cursor,
718 map_p, snmp_ctx, snmp_op,
719 da_stack->da[depth]->attr);
720 }
721
722 for (;;) {
723 ret = snmp_process(out, request,
724 da_stack, depth + 1,
725 cursor,
726 map_p->child, snmp_ctx, snmp_op);
727 if (ret < 0) return ret; /* error */
728 if (ret > 0) { /* findNext */
729 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) goto invalid;
730 if (++map_p <= map[0].last) continue;
731 return 1; /* findNext at lower level */
732 }
733 return 0; /* done */
734 }
735}
736
738 fr_da_stack_t *da_stack, unsigned int depth,
739 fr_dcursor_t *cursor,
740 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
741{
742 fr_pair_t *vp;
743 fr_snmp_map_t const *map_p;
744
745 FR_PROTO_STACK_PRINT(da_stack, depth);
746
747 vp = fr_dcursor_current(cursor);
748
749 /*
750 * Return element in map that matches the da at this
751 * level in the da_stack.
752 */
753 map_p = snmp_map_search(map, da_stack->da[depth]);
754 if (!map_p) {
755 fr_strerror_const("Invalid OID: Match stopped here");
756 error:
757 return -(ssize_t)depth;
758 }
759
760 /*
761 * It's a leaf attribute, call the correct get/set function
762 */
763 switch (snmp_op) {
764 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT:
765 if (map_p == map[0].last) {
766 return 1; /* findNext at lower level */
767 }
768 if (map_p->da == vp->da) { /* Next unless we faked part of the stack */
769 map_p++;
770
771 /*
772 * We were called with a leaf map, but advanced
773 * to a non-leaf map.
774 */
775 if (map_p->type == FR_FREERADIUS_SNMP_TYPE_OBJECT) {
776 return snmp_process(out, request,
777 da_stack, depth + 1,
778 cursor,
779 map_p->child, snmp_ctx, snmp_op);
780 }
781 }
783
784 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GET:
785 {
787
788 /*
789 * Verify map is a leaf
790 */
791 if (map_p->type == FR_FREERADIUS_SNMP_TYPE_OBJECT) {
792 fr_strerror_const("Invalid OID: Is not a leaf node");
793 goto error;
794 }
795
796 if (!map_p->get) {
797 fr_strerror_const("Invalid operation: Node does not support GET operations");
798 goto error;
799 }
800
801 /*
802 * Get functions can only return a single
803 * attribute. To reduce boilerplate code
804 * in callbacks, we handled allocating and
805 * inserting fr_pair_ts, and pass in a
806 * fr_value_box_t struct for the callback
807 * to complete.
808 */
809 if (map_p->get(request->reply, &data, map_p, snmp_ctx) < 0) goto error;
810
811 MEM(vp = fr_pair_afrom_da(request->reply_ctx, map_p->da));
812 fr_value_box_steal(vp, &vp->data, &data);
814
815 MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_snmp_type));
816 vp->vp_uint32 = map_p->type;
818 }
819 return 0;
820
821 case FR_FREERADIUS_SNMP_OPERATION_VALUE_SET:
822 {
823 ssize_t ret;
824
825 if (!map_p->set || (map_p->type == FR_FREERADIUS_SNMP_TYPE_OBJECT)) {
826 MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_snmp_failure));
827 vp->vp_uint32 = FR_FREERADIUS_SNMP_FAILURE_VALUE_NOT_WRITABLE;
829 return 0;
830 }
831
832 vp = fr_dcursor_current(cursor);
833 ret = map_p->set(map_p, snmp_ctx, &vp->data);
834 if (ret < 0) switch (-(ret)) {
835 case FR_FREERADIUS_SNMP_FAILURE_VALUE_NOT_WRITABLE:
836 case FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_TYPE:
837 case FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_LENGTH:
838 case FR_FREERADIUS_SNMP_FAILURE_VALUE_WRONG_VALUE:
839 case FR_FREERADIUS_SNMP_FAILURE_VALUE_INCONSISTENT_VALUE:
840 MEM(vp = fr_pair_afrom_da(request->reply_ctx, attr_snmp_failure));
841 vp->vp_uint32 = -(ret);
843 break;
844
845 default:
846 goto error;
847 }
848 }
849 return 0;
850
851 default:
852 fr_assert(0);
853 goto error;
854 }
855}
856
857/** Traverse a tree of SNMP maps
858 *
859 * @param[out] out Where to write response attributes.
860 * @param[in] request The current request.
861 * @param[in,out] da_stack we're traversing.
862 * @param[in] depth we're currently at in the da_stack.
863 * @param[in] cursor representing the current attribute we're processing.
864 * @param[in] map matching the current depth in the da_stack.
865 * @param[in] snmp_ctx allocated by the previous index traversal function.
866 * @param[in] snmp_op we're performing.
867 * @return
868 * - 0 on success.
869 * - 1 to signal caller that it should find the next OID at this level
870 * and recurse again.
871 * - <0 the depth at which an error occurred, as a negative integer.
872 */
874 fr_da_stack_t *da_stack, unsigned int depth,
875 fr_dcursor_t *cursor,
876 fr_snmp_map_t const *map, void *snmp_ctx, unsigned int snmp_op)
877{
878 fr_assert(map);
879
880 FR_PROTO_STACK_PRINT(da_stack, depth);
881
882 /*
883 * We've run out of stack... This is an error unless
884 * we're performing a getNext operation, in which
885 * case we fake the rest of the stack.
886 */
887 if (!da_stack->da[depth]) {
888 if (snmp_op != FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT) {
889 fr_strerror_const("Invalid OID: Not a leaf");
890 return -(ssize_t)(depth - 1);
891 }
892 snmp_next_leaf(da_stack, depth, &map[1]);
893
894 if (!fr_cond_assert(da_stack->da[depth])) return -1;
895 }
896
897 /*
898 * It's an index attribute, use the value of
899 * the index attribute to traverse the index.
900 */
901 if (da_stack->da[depth]->attr == 0) return snmp_process_index_attr(out, request,
902 da_stack, depth,
903 cursor,
904 map, snmp_ctx, snmp_op);
905
906 /*
907 * It's a TLV, recurse, and locate the map
908 * matching the next deepest DA in the
909 * da_stack.
910 */
911 if (da_stack->da[depth]->type == FR_TYPE_TLV) return snmp_process_tlv(out, request,
912 da_stack, depth,
913 cursor,
914 map, snmp_ctx, snmp_op);
915
916 /*
917 * Must be a leaf, call the appropriate get/set function
918 * and create attributes for the response.
919 */
920 return snmp_process_leaf(out, request,
921 da_stack, depth,
922 cursor,
923 map, snmp_ctx, snmp_op);
924}
925
927{
928 fr_dcursor_t request_cursor, op_cursor, out_cursor, reply_cursor;
930 fr_pair_t *vp;
931
932 char oid_str[FR_DICT_MAX_TLV_STACK * 4]; /* .<num>{1,3} */
933 size_t oid_len, len;
934
935 fr_da_stack_t da_stack;
936 unsigned int depth;
937 ssize_t ret;
938
939 fr_pair_t *op;
940
942 fr_pair_dcursor_init(&request_cursor, &request->request_pairs);
943 fr_pair_dcursor_by_da_init(&op_cursor, &request->request_pairs, attr_snmp_operation);
944 fr_pair_dcursor_init(&reply_cursor, &request->reply_pairs);
945 fr_pair_dcursor_init(&out_cursor, &head);
946
947 RDEBUG2("Processing SNMP stats request");
948
949 /*
950 * First take a pass over the request, converting
951 * any unknown types back to real attributes.
952 *
953 * This hack is required because empty TLVs are
954 * not allowed in the RADIUS protocol, so we
955 * encode the TLV as an octet type attribute
956 */
957 for (vp = fr_dcursor_head(&request_cursor);
958 vp;
959 vp = fr_dcursor_next(&request_cursor)) {
960 fr_dict_attr_t const *da;
961
962 if (!vp->da->flags.is_unknown) continue;
963
965 if (!da) {
966 WARN("Failed converting \"%s\" to a known attribute", vp->da->name);
967 continue;
968 }
969
970 RDEBUG2("Unknown attribute \"%s\" resolves to \"%s\"", vp->da->name, da->name);
971
972 /*
973 * Clear out any junk values
974 */
975 if (da->type == FR_TYPE_TLV) fr_value_box_clear(&vp->data);
976
977 if (fr_pair_reinit_from_da(&request->request_pairs, vp, da) < 0) {
978 RPWARN("Failed converting unknown attribute to known attribute");
979 continue;
980 }
981 }
982
983 for (vp = fr_pair_dcursor_by_ancestor_init(&request_cursor, &request->request_pairs, attr_snmp_root);
984 vp;
985 vp = fr_dcursor_next(&request_cursor)) {
986 fr_proto_da_stack_build(&da_stack, vp->da);
987
988 /*
989 * Wind to the frame in the TLV stack that matches our
990 * SNMP root.
991 */
992 for (depth = 0; da_stack.da[depth]; depth++) if (attr_snmp_root == da_stack.da[depth]) break;
993
994 /*
995 * Any attribute returned by fr_dcursor_next_by_ancestor
996 * should have the SNMP root attribute as an ancestor.
997 */
998 fr_assert(da_stack.da[depth]);
999 fr_assert(da_stack.da[depth] == attr_snmp_root);
1000
1001 /*
1002 * Operator attribute acts as a request delimiter
1003 */
1004 op = fr_dcursor_current(&op_cursor);
1005 if (!op) {
1006 ERROR("Missing operation (%s)", attr_snmp_operation->name);
1007 return -1;
1008 }
1009 fr_dcursor_next(&op_cursor);
1010
1011 switch (op->vp_uint32) {
1012 case FR_FREERADIUS_SNMP_OPERATION_VALUE_PING:
1013 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GET:
1014 case FR_FREERADIUS_SNMP_OPERATION_VALUE_GETNEXT:
1015 case FR_FREERADIUS_SNMP_OPERATION_VALUE_SET:
1016 break;
1017
1018 default:
1019 ERROR("Invalid operation %u", vp->vp_uint32);
1020 return -1;
1021 }
1022
1023 /*
1024 * Returns depth (as negative integer) at which the error occurred
1025 */
1026 ret = snmp_process(&out_cursor, request,
1027 &da_stack, depth,
1028 &request_cursor,
1029 snmp_iso, NULL, op->vp_uint32);
1030 if (ret < 0) {
1031 fr_sbuff_t oid_str_sbuff = FR_SBUFF_OUT(oid_str, sizeof(oid_str));
1033
1034 (void) fr_sbuff_in_char(&oid_str_sbuff, '.');
1035
1036 /* Get the length of the matching part */
1037 oid_len = fr_dict_attr_oid_print(&oid_str_sbuff, attr_snmp_root, da_stack.da[-(ret)], false);
1038
1039 /* Get the last frame in the current stack */
1040 len = fr_dict_attr_oid_print(&oid_str_sbuff, attr_snmp_root,
1041 da_stack.da[da_stack.depth - 1], false);
1042
1043 /* Use the difference in OID string length to place the marker */
1044 REMARKER(oid_str, oid_len - (len - oid_len), "%s", fr_strerror());
1045
1046 return -1;
1047 }
1048 }
1049
1050 fr_dcursor_head(&out_cursor);
1051 fr_dcursor_merge(&reply_cursor, &out_cursor);
1052
1053 return 0;
1054}
1055
1056/** Internal SNMP initialisation function (used for recursion)
1057 *
1058 */
1060{
1061 unsigned int i;
1062
1063 for (i = 0; map[i].name; i++) {
1064 if (map[i].type == FR_FREERADIUS_SNMP_TYPE_OBJECT) {
1065 int ret;
1066
1067 fr_assert(map[i].child);
1068
1069 map[i].da = fr_dict_attr_by_name(NULL, parent, map[i].name);
1070 if (!map[i].da) {
1071 ERROR("Incomplete dictionary: Missing definition for \"%s\"", map[i].name);
1072 return -1;
1073 }
1074
1075 ret = _fr_snmp_init_r(map[i].child, map[i].da);
1076 if (ret < 0) return -1;
1077
1078 continue;
1079 }
1080
1081 map[i].da = fr_dict_attr_by_name(NULL, parent, map[i].name);
1082 if (!map[i].da) {
1083 ERROR("Incomplete dictionary: Missing definition for \"%s\"", map[i].name);
1084 return -1;
1085 }
1086 }
1087
1088 /*
1089 * Shift the contents of the map, clearing the first entry.
1090 *
1091 * @note We could also do a quicksort here but we assume
1092 * that future developers will heed this warning to list
1093 * attributes in ascending order.
1094 */
1095 memmove(&map[1], map, sizeof(*map) * i);
1096 memset(&map[0], 0, sizeof(*map));
1097 map[0].name = "Not the map offset you were looking for";
1098 map[0].last = &map[i]; /* This allows us to perform a binary search in the array */
1099
1100 return 0;
1101}
1102static int _fr_snmp_init(UNUSED void *uctx)
1103{
1104 start_time = fr_time();
1106
1107 if (fr_dict_autoload(snmp_dict) < 0) {
1108 fr_perror("snmp_init");
1109 return -1;
1110 }
1111
1113 fr_perror("snmp_init");
1114 return -1;
1115 }
1116
1117 return _fr_snmp_init_r(snmp_iso, fr_dict_root(dict_snmp)); /* The SNMP root node */
1118}
1119
1120static int _fr_snmp_free(UNUSED void *uctx)
1121{
1123
1124 return 0;
1125}
1126
1127/** Initialise the tree of SNMP map structures used to attach callbacks to OIDs
1128 *
1129 */
1131{
1132 int ret;
1133
1134 fr_atexit_global_once_ret(&ret, _fr_snmp_init, _fr_snmp_free, NULL);
1135
1136 return ret;
1137}
#define RCSID(id)
Definition build.h:483
#define NDEBUG_UNUSED
Definition build.h:326
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:322
#define UNUSED
Definition build.h:315
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:234
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:139
#define MEM(x)
Definition debug.h:36
char const * radiusd_version_short
Definition dependency.c:40
#define ERROR(fmt,...)
Definition dhcpclient.c:41
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:853
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:2037
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:3263
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:268
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
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:4090
#define fr_dict_autoload(_to_load)
Definition dict.h:850
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition dict.h:495
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:3328
static fr_slen_t in
Definition dict.h:824
Specifies an attribute which must be present for the module to function.
Definition dict.h:267
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
int af
Address family.
Definition inet.h:64
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition client.h:83
fr_stats_t auth
Authentication stats.
Definition client.h:137
char const * longname
Client identifier.
Definition client.h:87
int number
Unique client number.
Definition client.h:132
Describes a host allowed to send packets to the server.
Definition client.h:80
#define RPWARN(fmt,...)
Definition log.h:301
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
Definition log.h:498
talloc_free(reap)
void main_loop_signal_raise(int flag)
Definition main_loop.c:79
@ 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:283
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:314
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:38
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define WARN(fmt,...)
Definition radclient.h:47
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:42
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:384
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:412
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:675
static fr_snmp_map_t snmp_auth_client_entry[]
Definition snmp.c:316
static fr_snmp_map_t snmp_mgmt[]
Definition snmp.c:426
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:474
static int _fr_snmp_init(UNUSED void *uctx)
Definition snmp.c:1102
static fr_snmp_map_t snmp_auth_serv_mib[]
Definition snmp.c:398
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:254
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:324
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:513
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:525
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:220
static fr_snmp_map_t snmp_iso[]
Definition snmp.c:454
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:1059
static fr_snmp_map_t snmp_mib_2[]
Definition snmp.c:419
fr_dict_attr_autoload_t snmp_dict_attr[]
Definition snmp.c:57
int fr_snmp_process(request_t *request)
Definition snmp.c:926
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:737
static fr_snmp_map_t snmp_authentication[]
Definition snmp.c:405
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:208
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:1120
static fr_snmp_map_t snmp_org[]
Definition snmp.c:447
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:440
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:1130
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:873
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:616
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:241
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:391
static fr_snmp_map_t snmp_internet[]
Definition snmp.c:433
#define SNMP_MAP_TERMINATOR
Definition snmp.c:67
static fr_snmp_map_t snmp_auth_client_entry_counters[]
Definition snmp.c:267
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:369
fr_aka_sim_id_type_t type
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
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:422
#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:628
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:591
#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:646
static fr_slen_t parent
Definition pair.h:851
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Definition proto.h:43
uint8_t depth
Deepest attribute in the stack.
Definition proto.h:55
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition proto.h:56
Structure for holding the stack of dictionary attributes being encoded.
Definition proto.h:54
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:554
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:733
#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:433
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:4208
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:4014
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:3858
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:3723
static fr_slen_t data
Definition value.h:1265
static size_t char ** out
Definition value.h:997