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