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