The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
radict.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: ef0101baff59fbc442f9a2ee148ddc8e8df5212e $
19 *
20 * @file radict.c
21 * @brief Utility to print attribute data in tab delimited format
22 *
23 * @copyright 2017 The FreeRADIUS server project
24 * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 */
26RCSID("$Id: ef0101baff59fbc442f9a2ee148ddc8e8df5212e $")
27
28#include <freeradius-devel/util/conf.h>
29#include <freeradius-devel/util/syserror.h>
30#include <freeradius-devel/util/atexit.h>
31#include <freeradius-devel/util/dict_priv.h>
32#include <dirent.h>
33#include <sys/stat.h>
34
35#ifdef HAVE_GETOPT_H
36# include <getopt.h>
37#endif
38
50
51static fr_dict_t *dicts[255];
52static bool print_values = false;
53static bool print_headers = false;
54static bool print_recursive = false;
55static char const *mib = NULL;
56static char const *parent_oid = NULL;
59
60DIAG_OFF(unused-macros)
61#define DEBUG2(fmt, ...) if (fr_log_fp && (fr_debug_lvl > 2)) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
62#define DEBUG(fmt, ...) if (fr_log_fp && (fr_debug_lvl > 1)) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
63#define INFO(fmt, ...) if (fr_log_fp && (fr_debug_lvl > 0)) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
64DIAG_ON(unused-macros)
65
66static void usage(void)
67{
68 fprintf(stderr, "usage: radict [OPTS] [attribute...]\n");
69 fprintf(stderr, " -A Export aliases.\n");
70 fprintf(stderr, " -c Print out in CSV format.\n");
71 fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
72 fprintf(stderr, " -f Export dictionary definitions in the normal dictionary format\n");
73 fprintf(stderr, " -F <format> Set output format. Use 'csv', 'full', or 'dictionary'\n");
74 fprintf(stderr, " -E Export dictionary definitions.\n");
75 fprintf(stderr, " -h Print help text.\n");
76 fprintf(stderr, " -H Show the headers of each field.\n");
77 fprintf(stderr, " -M <name> Mangle names for MIB, and set MIB root.\n");
78 fprintf(stderr, " -p <protocol> Set protocol by name\n");
79 fprintf(stderr, " -r Write out attributes recursively.\n");
80 fprintf(stderr, " -V Write out all attribute values.\n");
81 fprintf(stderr, " -x Debugging mode.\n");
82 fprintf(stderr, "\n");
83 fprintf(stderr, "Very simple interface to extract attribute definitions from FreeRADIUS dictionaries\n");
84}
85
86static int load_dicts(char const *dict_dir, char const *protocol)
87{
88 int loaded = 0;
89 DIR *dir;
90 struct dirent *dp;
91
92 DEBUG("Reading directory %s", dict_dir);
93
94 dir = opendir(dict_dir);
95 if (!dir) {
96 fr_strerror_printf("Failed opening \"%s\": %s", dict_dir, fr_syserror(errno));
97 return -1;
98 }
99
100 while ((dp = readdir(dir)) != NULL) {
101 struct stat stat_buff;
102 char *file_str;
103
104 if (dp->d_name[0] == '.') continue;
105
106 /*
107 * We only want to load one...
108 */
109 if (protocol && (strcmp(dp->d_name, protocol) != 0)) continue;
110
111 /*
112 * Skip the internal FreeRADIUS dictionary.
113 */
114 if (strcmp(dp->d_name, "freeradius") == 0) continue;
115
116 file_str = talloc_asprintf(NULL, "%s/%s", dict_dir, dp->d_name);
117
118 if (stat(file_str, &stat_buff) == -1) {
119 fr_strerror_printf("Failed stating file \"%s\": %s", file_str, fr_syserror(errno));
120 error:
121 closedir(dir);
122 talloc_free(file_str);
123 return -1;
124 }
125
126 /*
127 * Only process directories
128 */
129 if ((stat_buff.st_mode & S_IFMT) == S_IFDIR) {
130 char *dict_file;
131 struct stat dict_stat_buff;
132 int ret;
133
134 dict_file = talloc_asprintf(NULL, "%s/dictionary", file_str);
135 ret = stat(dict_file, &dict_stat_buff);
136 talloc_free(dict_file);
137
138 /*
139 * If the directory contains a dictionary file,
140 * load it as a dictionary.
141 */
142 if (ret == 0) {
143 if (dict_end >= (dicts + (NUM_ELEMENTS(dicts)))) {
144 fr_strerror_const("Reached maximum number of dictionaries");
145 goto error;
146 }
147
148 DEBUG("Loading dictionary: %s/dictionary", file_str);
149 if (fr_dict_protocol_afrom_file(dict_end, dp->d_name, NULL, __FILE__) < 0) {
150 goto error;
151 }
152 dict_end++;
153 loaded++;
154 }
155
156 /*
157 * For now, don't do sub-protocols.
158 */
159 }
160 talloc_free(file_str);
161 }
162 closedir(dir);
163
164 if (!loaded) {
165 if (!protocol) {
166 fr_strerror_printf("Failed to load any dictionaries");
167 } else {
168 fr_strerror_printf("Failed to load dictionary for protocol %s", protocol);
169 }
170
171 return -1;
172 }
173
174 return 0;
175}
176
177static const char *spaces = " ";
178
179static void da_print_info(fr_dict_t const *dict, fr_dict_attr_t const *da, int depth)
180{
181 char oid_str[512];
182 char flags[256];
183 fr_hash_iter_t iter;
185 fr_sbuff_t old_str_sbuff = FR_SBUFF_OUT(oid_str, sizeof(oid_str));
186 fr_sbuff_t flags_sbuff = FR_SBUFF_OUT(flags, sizeof(flags));
187
188 char const *type;
189 fr_dict_attr_t const *child;
190 fr_hash_table_t *namespace;
191
192 if (fr_dict_attr_oid_print(&old_str_sbuff, NULL, da, false) <= 0) {
193 fr_strerror_printf("OID string too long");
194 fr_exit(EXIT_FAILURE);
195 }
196
197 fr_dict_attr_flags_print(&flags_sbuff, dict, da->type, &da->flags);
198
199 if (!da->flags.is_alias) {
200 type = fr_type_to_str(da->type);
201 } else {
202 fr_assert(da->type == FR_TYPE_VOID);
203 type = "ALIAS";
204 }
205
206 printf("%.*s", depth, spaces);
207
208 /* Protocol Name Type */
209
210 switch(output_format) {
211 case RADICT_OUT_CSV:
212 printf("%s,%s,%s,%d,%s,%s\n",
213 depth == 0 ? fr_dict_root(dict)->name : "",
214 fr_sbuff_start(&old_str_sbuff),
215 da->name,
216 da->attr,
217 type,
218 fr_sbuff_start(&flags_sbuff));
219 break;
220
221 case RADICT_OUT_FANCY:
222 default:
223 printf("%s\t%s\t%s\t%d\t%s\t%s\n",
224 depth == 0 ? fr_dict_root(dict)->name : "",
225 fr_sbuff_start(&old_str_sbuff),
226 da->name,
227 da->attr,
228 type,
229 fr_sbuff_start(&flags_sbuff));
230 }
231
232 if (print_values) {
234
236 if (!ext || !ext->value_by_name) return;
237
238 for (enumv = fr_hash_table_iter_init(ext->value_by_name, &iter);
239 enumv;
240 enumv = fr_hash_table_iter_next(ext->value_by_name, &iter)) {
241 char *str;
242
243 switch(output_format) {
244 case RADICT_OUT_CSV:
245 str = fr_asprintf(NULL, "%s,%s,%s,%d,%s,%s,%s,%pV",
246 depth == 0 ? fr_dict_root(dict)->name : "",
247 fr_sbuff_start(&old_str_sbuff),
248 da->name,
249 da->attr,
250 type,
251 fr_sbuff_start(&flags_sbuff),
252 enumv->name,
253 enumv->value);
254 break;
255
256 case RADICT_OUT_FANCY:
257 default:
258 str = fr_asprintf(NULL, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%pV",
259 depth == 0 ? fr_dict_root(dict)->name : "",
260 fr_sbuff_start(&old_str_sbuff),
261 da->name,
262 da->attr,
263 type,
264 fr_sbuff_start(&flags_sbuff),
265 enumv->name,
266 enumv->value);
267 }
268
269 printf("%.*s%s\n", depth, spaces, str);
270 talloc_free(str);
271 }
272 }
273
274 /*
275 * Print definitions recursively.
276 */
277 if (!print_recursive || !fr_type_is_structural(da->type)) return;
278
279 namespace = dict_attr_namespace(da);
280 fr_assert(namespace != NULL);
281
282 for (child = fr_hash_table_iter_init(namespace, &iter);
283 child != NULL;
284 child = fr_hash_table_iter_next(namespace, &iter)) {
285 da_print_info(dict, child, depth + 1);
286 }
287}
288
289static char const *type_to_c_type[] = {
290 [FR_TYPE_STRING] = "char",
291 [FR_TYPE_OCTETS] = "uint8_t",
292
293 [FR_TYPE_IPV4_ADDR] = "struct in_addr",
294 [FR_TYPE_IPV6_ADDR] = "struct in6_addr",
295
296// [FR_TYPE_IFID] = "fr_ifid_t",
297// [FR_TYPE_ETHERNET] = "fr_ethernet_t",
298
299 [FR_TYPE_UINT8] = "uint8_t",
300 [FR_TYPE_UINT16] = "uint16_t",
301 [FR_TYPE_UINT32] = "uint32_t",
302 [FR_TYPE_UINT64] = "uint64_t",
303
304 [FR_TYPE_INT8] = "int8_t",
305 [FR_TYPE_INT16] = "int16_t",
306 [FR_TYPE_INT32] = "int32_t",
307 [FR_TYPE_INT64] = "int64_t",
308
309 [FR_TYPE_DATE] = "fr_time_t",
310 [FR_TYPE_TIME_DELTA] = "fr_time_delta_t",
311
312 [FR_TYPE_MAX] = 0 //!< Ensure array covers all types.
313};
314
315static char const *length_to_c_type[] = {
316 [2] = "uint16_t",
317 [4] = "uint32_t",
318 [8] = "uint64_t",
319};
320
321static void da_normalize_name(fr_dict_attr_t const *da, char buffer[static FR_DICT_ATTR_MAX_NAME_LEN*2 + 1])
322{
323 char const *start = da->name;
324 char const *p;
325 char *q;
326 bool mangle = false;
327
328 /*
329 * The RADIUS MIBs have lots of repetition. So we do some simple mangling of the names to make
330 * them easier to understand.
331 */
332 if (mib && da->parent) {
333 size_t len;
334
335 len = strlen(da->parent->name);
336
337 /*
338 * "radiusAuthServer" and "radiusAuthServTotalAccessRejects"
339 * to "total_access_rejects"
340 *
341 * Otherwise "radiusAuthServer" in the "RADIUS" dictionary, to "auth_server"
342 */
343 mangle = (strncmp(da->parent->name, da->name, len) == 0);
344 if (!mangle) {
345 fr_dict_attr_t const *root = fr_dict_root(da->dict);
346
347 len = strlen(root->name);
348 mangle = (strncasecmp(root->name, da->name, len) == 0);
349 }
350
351 if (mangle) start += len;
352 }
353
354 q = buffer;
355
356 for (p = start; *p != '\0'; p++) {
357 if ((*p >= '0') && (*p <= '9')) {
358 *q++ = *p;
359 continue;
360 }
361
362 if (islower((unsigned int) *p)) {
363 *q++ = *p;
364 continue;
365 }
366
367 if (isupper((unsigned int) *p)) {
368 if (mangle && (p > start)) {
369 *(q++) = '_';
370 }
371
372 *q++ = tolower((unsigned int)*p);
373 continue;
374 }
375
376 *q++ = '_';
377 }
378
379 *q = '\0';
380}
381
382static void da_print_name(FILE *fp, fr_dict_attr_t const *da)
383{
385
387 fprintf(fp, "%s", buffer);
388}
389
390static const bool type_allowed[FR_TYPE_MAX] = {
391 [FR_TYPE_STRING] = true,
392 [FR_TYPE_OCTETS] = true,
393
394 [FR_TYPE_UINT16] = true,
395 [FR_TYPE_UINT32] = true,
396 [FR_TYPE_UINT64] = true,
397
398 [FR_TYPE_IPV4_ADDR] = true,
399 [FR_TYPE_IPV6_ADDR] = true,
400
401 [FR_TYPE_DATE] = true,
402 [FR_TYPE_TIME_DELTA] = true,
403
404};
405
407{
408 int i;
409 fr_dict_attr_t const *da;
410
411 for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
412 if (!type_allowed[da->type]) return false;
413 }
414
415 return true;
416}
417
418#define CHECK_TYPE(_parent) \
419do { \
420 if ((parent->type != FR_TYPE_STRUCT) && (parent->type != FR_TYPE_TLV)) { \
421 fprintf(stderr, "%s is not a struct or tlv\n", parent->name); \
422 return; \
423 } \
424 if (!children_ok(parent)) fr_exit(EXIT_FAILURE); \
425} while (0)
426
427/** Print structures and mappings, mainly for statistics.
428 */
429static void da_print_struct(FILE *fp, fr_dict_attr_t const *parent)
430{
431 int i;
432 fr_dict_attr_t const *da;
433
435
436 /*
437 * @todo - print full OID path and filename?
438 */
439 fprintf(fp, "/*\n *\t%s\n */\n", parent->name);
440 fprintf(fp, "typedef struct {\n");
441
442 for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
443 unsigned int length = 0;
444
445 /*
446 * @todo - if the last field is a union, print out the union definitions first.
447 */
448 fr_assert(!da->flags.array);
449
450 if (da_is_bit_field(da)) {
451 /*
452 * @todo - this is all big endian. for little endian, we print out the bytes in
453 * order, but the bits in each byte are reversed. Likely the easiest way to do
454 * this is via a separate function that we call. But this shouldn't be necessary
455 * for statistics structures, as they shouldn't contain bitfields.
456 */
457 fprintf(fp, "\tunsigned int : %u\t", da->flags.length);
458
459 } else switch (da->type) {
460 case FR_TYPE_STRING:
461 if ((parent->type == FR_TYPE_TLV) && !da->flags.length) {
462 fprintf(fp, "\t%s\t*", type_to_c_type[da->type]);
463 break;
464 }
466
467 case FR_TYPE_OCTETS:
468 fr_assert(da->flags.length > 0);
469 length = da->flags.length;
470 fprintf(fp, "\t%s\t", type_to_c_type[da->type]);
471 break;
472
473 case FR_TYPE_DATE:
474 fr_assert(da->flags.length <= 8);
475 fr_assert(length_to_c_type[da->flags.length] != NULL);
476 fprintf(fp, "\t%s\t", length_to_c_type[da->flags.length]);
477 break;
478
479 default:
480 fr_assert(type_to_c_type[da->type] != NULL);
481 fprintf(fp, "\t%s\t", type_to_c_type[da->type]);
482 break;
483 }
484
485 da_print_name(fp, da);
486
487 if (length) {
488 fprintf(fp, "[%u]", length);
489 }
490
491 fprintf(fp, ";\n");
492 }
493
494 fprintf(fp, "} ");
495
496 fprintf(fp, "fr_stats_");
498 fprintf(fp, "_");
500 fprintf(fp, "_t;\n");
501}
502
503static void da_print_base_c_da_def(FILE *fp, fr_dict_attr_t const *parent)
504{
505 int i;
506 fr_dict_attr_t const *da;
508
510
512
513 fprintf(fp, "static fr_dict_attr_t const *attr_%s;\n", parent_name);
514
515 for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
516 fprintf(fp, "static fr_dict_attr_t const *attr_%s_", parent_name);
517 da_print_name(fp, da);
518 fprintf(fp, ";\n");
519 }
520
521 fprintf(fp, "\n\n");
522}
523
524
525/** Map data types to enum names representing those types
526 */
527#define ENUM_NAME(_x) [_x] = STRINGIFY(_x)
528
573
574static void da_print_stats_link(FILE *fp, fr_dict_attr_t const *parent)
575{
576 int i, num_elements = 0;
577 fr_dict_attr_t const *da;
578 char dict_name[FR_DICT_ATTR_MAX_NAME_LEN*2 + 1];
580
582
583 da_normalize_name(fr_dict_root(parent->dict), dict_name);
585
586 fprintf(fp, "fr_stats_link_t const fr_stats_link_%s_%s = {\n", dict_name, parent_name);
587
588 fprintf(fp, "\t.name = \"fr_stats_%s_%s_t\",\n", dict_name, parent_name);
589 fprintf(fp, "\t.root_p = &attr_%s,\n", parent_name);
590 if (mib) fprintf(fp, "\t.mib = \"%s\",\n", mib);
591 fprintf(fp, "\t.size = sizeof(fr_stats_%s_%s_t),\n", dict_name, parent_name);
592
593 for (i = 1; fr_dict_attr_child_by_num(parent, i) != NULL; i++) {
594 num_elements = i;
595 }
596 fprintf(fp, "\t.num_elements = %d,\n", num_elements);
597
598 fprintf(fp, "\t.entry = {\n");
599
600 /*
601 * For locality, also print out data type and size. That way we _can_ dereference the da, but we
602 * don't _need_ to.
603 */
604 for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
605 fprintf(fp, "\t\t{\n");
606 fprintf(fp, "\t\t\t.da_p = &attr_%s_", parent_name);
607 da_print_name(fp, da);
608 fprintf(fp, ",\n");
609
610 fprintf(fp, "\t\t\t.type = %s,\n", fr_type_to_enum_name[da->type]);
611
612 fprintf(fp, "\t\t\t.offset = offsetof(fr_stats_%s_%s_t, ", dict_name, parent_name);
613 da_print_name(fp, da);
614 fprintf(fp, "),\n");
615
616 fprintf(fp, "\t\t\t.size = %u,\n", da->flags.length);
617
618 fprintf(fp, "\t\t},\n");
619 }
620
621 fprintf(fp, "\t},\n");
622 fprintf(fp, "};\n\n");
623}
624
625static void da_print_attr_autoload(FILE *fp, fr_dict_attr_t const *parent)
626{
627 int i;
628 fr_dict_attr_t const *da;
629 char dict_name[FR_DICT_ATTR_MAX_NAME_LEN*2 + 1];
631
633
634 da_normalize_name(fr_dict_root(parent->dict), dict_name);
636
637 /*
638 * Define the parent.
639 */
640 fprintf(fp, "{ .out = &attr_%s, .name = \"%s\", .type = %s, .dict = &dict_%s },\n",
642
643 /*
644 * And each child
645 */
646 for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
647 fprintf(fp, "{ .out = &attr_%s_", parent_name);
648 da_print_name(fp, da);
649 fprintf(fp, ", .name = \".%s\", .type = %s, .dict = &dict_%s },\n",
650 da->name, fr_type_to_enum_name[da->type], dict_name);
651 }
652
653 fprintf(fp, "\n\n");
654}
655
656static void da_print_stats_h(FILE *fp, fr_dict_attr_t const *parent)
657{
658 char dict_name[FR_DICT_ATTR_MAX_NAME_LEN*2 + 1];
660
662
663 da_normalize_name(fr_dict_root(parent->dict), dict_name);
665
667
668 fprintf(fp, "\n");
669
670 fprintf(fp, "/*\n * fr_stats_%s_%s_instance_t\n */\n", dict_name, parent_name);
671 fprintf(fp, "FR_STATS_TYPEDEF(%s_%s);\n\n", dict_name, parent_name);
672
673 fprintf(fp, "extern fr_stats_link_t const fr_stats_link_%s_%s;\n\n", dict_name, parent_name);
674}
675
676
677static void _raddict_export(fr_dict_t const *dict, uint64_t *count, uintptr_t *low, uintptr_t *high, fr_dict_attr_t const *da, unsigned int lvl)
678{
679 unsigned int i;
680 size_t len;
681 fr_dict_attr_t const *p;
682 char flags[256];
683 fr_dict_attr_t const **children;
684
685 fr_dict_attr_flags_print(&FR_SBUFF_OUT(flags, sizeof(flags)), dict, da->type, &da->flags);
686
687 /*
688 * Root attributes are allocated outside of the pool
689 * so it's not helpful to include them in the calculation.
690 */
691 if (!da->flags.is_root) {
692 if (low && ((uintptr_t)da < *low)) {
693 *low = (uintptr_t)da;
694 }
695 if (high && ((uintptr_t)da > *high)) {
696 *high = (uintptr_t)da;
697 }
698
699 da_print_info(fr_dict_by_da(da), da, 0);
700 }
701
702 if (count) (*count)++;
703
704 /*
705 * Todo - Should be fixed to use attribute walking API
706 */
707 children = dict_attr_children(da);
708 if (children) {
709 len = talloc_array_length(children);
710 for (i = 0; i < len; i++) {
711 for (p = children[i]; p; p = p->next) {
712 _raddict_export(dict, count, low, high, p, lvl + 1);
713 }
714 }
715 }
716}
717
718static void raddict_export(uint64_t *count, uintptr_t *low, uintptr_t *high, fr_dict_t *dict)
719{
720 if (count) *count = 0;
721 if (low) *low = UINTPTR_MAX;
722 if (high) *high = 0;
723
724 _raddict_export(dict, count, low, high, fr_dict_root(dict), 0);
725}
726
728 { L("fancy"), RADICT_OUT_FANCY },
729 { L("csv"), RADICT_OUT_CSV },
730 { L("dict"), RADICT_OUT_DICT },
731 { L("struct"), RADICT_OUT_STRUCT },
732 { L("stats_link"), RADICT_OUT_STATS_LINK },
733 { L("da_def"), RADICT_OUT_BASE_C_DA_DEF },
734 { L("attr_autoload"), RADICT_OUT_ATTR_AUTOLOAD },
735 { L("stats.h"), RADICT_OUT_STATS_H },
736};
738
740 { L("fancy"), NULL },
741 { L("csv"), NULL },
742 { L("dict"), NULL },
743 { L("struct"), (void *) da_print_struct },
744 { L("stats_link"), (void *) da_print_stats_link },
745 { L("da_def"), (void *) da_print_base_c_da_def },
746 { L("attr_autoload"), (void *) da_print_attr_autoload },
747 { L("stats.h"), (void *) da_print_stats_h },
748};
750
751typedef void (*da_print_func_t)(FILE *fp, fr_dict_attr_t const *da);
752
753
754/**
755 *
756 * @hidecallgraph
757 */
758int main(int argc, char *argv[])
759{
760 char const *dict_dir = DICTDIR;
761 int c;
762 int ret = 0;
763 bool found = false;
764 bool export = false;
765 bool file_export = false;
766 bool alias = false;
767 char const *protocol = NULL;
768 da_print_func_t func = NULL;
769
770 TALLOC_CTX *autofree;
771
772 /*
773 * Must be called first, so the handler is called last
774 */
776
778
779#ifndef NDEBUG
780 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
781 fr_perror("radict - Fault setup");
782 fr_exit(EXIT_FAILURE);
783 }
784#endif
785
786 talloc_set_log_stderr();
787
788 fr_debug_lvl = 1;
789 fr_log_fp = stdout;
790
791 while ((c = getopt(argc, argv, "AcfF:ED:M:p:rVxhH")) != -1) switch (c) {
792 case 'A':
793 alias = true;
794 break;
795
796 case 'c':
798 break;
799
800 case 'H':
801 print_headers = true;
802 break;
803
804 case 'f':
805 file_export = true;
806 break;
807
808 case 'F':
811 fprintf(stderr, "Invalid output format '%s'\n", optarg);
812 fr_exit(EXIT_FAILURE);
813 }
814
816 break;
817
818 case 'E':
819 export = true;
820 break;
821
822 case 'D':
823 dict_dir = optarg;
824 break;
825
826 case 'M':
827 mib = optarg;
828 break;
829
830 case 'p':
831 protocol = optarg;
832 break;
833
834 case 'r':
835 print_recursive = true;
836 break;
837
838 case 'V':
839 print_values = true;
840 break;
841
842 case 'x':
843 fr_debug_lvl++;
844 break;
845
846 case 'h':
847 default:
848 usage();
849 goto finish;
850 }
851 argc -= optind;
852 argv += optind;
853
854 /*
855 * Mismatch between the binary and the libraries it depends on
856 */
858 fr_perror("radict - library mismatch");
859 ret = 1;
860 goto finish;
861 }
862
863 if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
864 fr_perror("radict - Global context init failed");
865 ret = 1;
866 goto finish;
867 }
868
869 DEBUG("Loading dictionary: %s/%s", dict_dir, FR_DICTIONARY_FILE);
870
872 fr_perror("radict - Loading internal dictionary failed");
873 ret = 1;
874 goto finish;
875 }
876
877 /*
878 * Don't emit spurious errors...
879 */
881 if (load_dicts(dict_dir, protocol) < 0) {
882 fr_perror("radict - Loading dictionaries failed");
883 ret = 1;
884 goto finish;
885 }
886
887 if (dict_end == dicts) {
888 fr_perror("radict - No dictionaries loaded");
889 ret = 1;
890 goto finish;
891 }
892
893 if (print_headers) switch(output_format) {
894 case RADICT_OUT_CSV:
895 printf("Dictionary,OID,Attribute,ID,Type,Flags\n");
896 break;
897
898 case RADICT_OUT_FANCY:
899 default:
900 printf("Dictionary\tOID\tAttribute\tID\tType\tFlags\n");
901 }
902
903 if (file_export) {
904 fr_dict_t **dict_p = dicts;
905
906 do {
907 if (protocol && (strcasecmp(fr_dict_root(*dict_p)->name, protocol) == 0)) {
908 fr_dict_export(fr_log_fp, *dict_p);
909 }
910 } while (++dict_p < dict_end);
911 }
912
913 if (export) {
914 fr_dict_t **dict_p = dicts;
915
916 do {
917 uint64_t count;
918 uintptr_t high;
919 uintptr_t low;
920
921 raddict_export(&count, &low, &high, *dict_p);
922 DEBUG2("Attribute count %" PRIu64, count);
923 DEBUG2("Memory allocd %zu (bytes)", talloc_total_size(*dict_p));
924 DEBUG2("Memory spread %zu (bytes)", (size_t) (high - low));
925 } while (++dict_p < dict_end);
926
927 goto finish;
928 }
929
930 if (alias) {
931 fr_dict_t **dict_p = dicts;
932
933 do {
934 if (protocol && (strcasecmp(fr_dict_root(*dict_p)->name, protocol) == 0)) {
936 }
937 } while (++dict_p < dict_end);
938
939 goto finish;
940 }
941
942 if (argc == 0) goto finish;
943
944 while (argc-- > 0) {
945 char *attr;
946 fr_dict_attr_t const *da;
947 fr_dict_t **dict_p = dicts;
948
949 attr = *argv++;
950
951 /*
952 * Loop through all the dicts. An attribute may
953 * exist in multiple dictionaries.
954 */
955 do {
956 DEBUG2("Looking for \"%s\" in dict \"%s\"", attr, fr_dict_root(*dict_p)->name);
957
958 da = fr_dict_attr_by_oid(NULL, fr_dict_root(*dict_p), attr);
959 if (!da) {
960 DEBUG2("Dictionary %s does not contain attribute %s\n",
961 fr_dict_root(*dict_p)->name, attr);
962 continue;
963 }
964
965 if (!func) {
966 da_print_info(*dict_p, da, 0);
967 } else {
968 parent_oid = attr;
969 func(stdout, da);
970 }
971 found = true;
972 } while (++dict_p < dict_end);
973 }
974
975 if (!found) ret = 64;
976
977finish:
978 /*
979 * Release our references on all the dicts
980 * we loaded.
981 */
982 {
983 fr_dict_t **dict_p = dicts;
984
985 do {
986 fr_dict_free(dict_p, __FILE__);
987 } while (++dict_p < dict_end);
988 }
989 if (talloc_free(autofree) < 0) fr_perror("radict - Error freeing dictionaries");
990
991 /*
992 * Ensure our atexit handlers run before any other
993 * atexit handlers registered by third party libraries.
994 */
996
997 return ret;
998}
static int const char char buffer[256]
Definition acutest.h:576
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition atexit.c:159
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:285
static TALLOC_CTX * autofree
Definition fuzzer.c:44
#define RCSID(id)
Definition build.h:506
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:343
#define DIAG_ON(_x)
Definition build.h:481
#define NUM_ELEMENTS(_t)
Definition build.h:358
#define DIAG_OFF(_x)
Definition build.h:480
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1056
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition debug.h:230
fr_dict_t const * fr_dict_by_da(fr_dict_attr_t const *da)
Attempt to locate the protocol dictionary containing an attribute.
Definition dict_util.c:2871
void fr_dict_alias_export(FILE *fp, fr_dict_attr_t const *parent)
Definition dict_print.c:324
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent))
(Re-)Initialize the special internal dictionary
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2665
#define da_is_bit_field(_da)
Definition dict.h:171
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:257
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4329
int fr_dict_protocol_afrom_file(fr_dict_t **out, char const *proto_name, char const *proto_dir, char const *dependent))
(Re)-initialize a protocol dictionary
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition dict.h:188
fr_dict_attr_t const * fr_dict_attr_by_oid(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *oid))
Resolve an attribute using an OID string.
Definition dict_util.c:2638
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:3593
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir))
Initialise the global protocol hashes.
Definition dict_util.c:4713
char const * name
Enum name.
Definition dict.h:254
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
Definition dict.h:501
void fr_dict_export(FILE *fp, fr_dict_t const *dict)
Export in the standard form: ATTRIBUTE name oid flags.
Definition dict_print.c:319
Value of an enumerated attribute.
Definition dict.h:253
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:121
fr_hash_table_t * value_by_name
Lookup an enumeration value by name.
Definition dict_ext.h:97
Attribute extension - Holds enumeration values.
Definition dict_ext.h:95
static fr_dict_attr_t const ** dict_attr_children(fr_dict_attr_t const *da)
void * fr_hash_table_iter_next(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Iterate over entries in a hash table.
Definition hash.c:649
void * fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Initialise an iterator.
Definition hash.c:704
Stores the state of the current iteration operation.
Definition hash.h:41
talloc_free(hp)
int fr_debug_lvl
Definition log.c:40
FILE * fr_log_fp
Definition log.c:39
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_MAX
Number of defined data types.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_VOID
User data.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
ssize_t fr_dict_attr_flags_print(fr_sbuff_t *out, fr_dict_t const *dict, fr_type_t type, fr_dict_attr_flags_t const *flags)
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)
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
int strncasecmp(char *s1, char *s2, int n)
Definition missing.c:35
int strcasecmp(char *s1, char *s2)
Definition missing.c:65
#define parent_name(_x)
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
Definition print.c:883
#define fr_assert(_expr)
Definition rad_assert.h:37
static char const * fr_type_to_enum_name[]
Definition radict.c:529
int main(int argc, char *argv[])
Definition radict.c:758
static fr_dict_t ** dict_end
Definition radict.c:58
static void da_print_struct(FILE *fp, fr_dict_attr_t const *parent)
Print structures and mappings, mainly for statistics.
Definition radict.c:429
static void da_normalize_name(fr_dict_attr_t const *da, char buffer[static FR_DICT_ATTR_MAX_NAME_LEN *2+1])
Definition radict.c:321
static void da_print_name(FILE *fp, fr_dict_attr_t const *da)
Definition radict.c:382
static fr_table_num_ordered_t const format_table[]
Definition radict.c:727
static int load_dicts(char const *dict_dir, char const *protocol)
Definition radict.c:86
static void da_print_stats_link(FILE *fp, fr_dict_attr_t const *parent)
Definition radict.c:574
static void raddict_export(uint64_t *count, uintptr_t *low, uintptr_t *high, fr_dict_t *dict)
Definition radict.c:718
static void da_print_stats_h(FILE *fp, fr_dict_attr_t const *parent)
Definition radict.c:656
static bool print_values
Definition radict.c:52
static bool print_recursive
Definition radict.c:54
static fr_dict_t * dicts[255]
Definition radict.c:51
static bool print_headers
Definition radict.c:53
static char const * length_to_c_type[]
Definition radict.c:315
static const bool type_allowed[FR_TYPE_MAX]
Definition radict.c:390
static size_t format_table_len
Definition radict.c:737
static fr_table_ptr_ordered_t const function_table[]
Definition radict.c:739
static size_t function_table_len
Definition radict.c:749
static void da_print_info(fr_dict_t const *dict, fr_dict_attr_t const *da, int depth)
Definition radict.c:179
static void da_print_attr_autoload(FILE *fp, fr_dict_attr_t const *parent)
Definition radict.c:625
static void da_print_base_c_da_def(FILE *fp, fr_dict_attr_t const *parent)
Definition radict.c:503
#define CHECK_TYPE(_parent)
Definition radict.c:418
static void _raddict_export(fr_dict_t const *dict, uint64_t *count, uintptr_t *low, uintptr_t *high, fr_dict_attr_t const *da, unsigned int lvl)
Definition radict.c:677
#define DEBUG2(fmt,...)
Definition radict.c:61
static char const * type_to_c_type[]
Definition radict.c:289
radict_out_t
Definition radict.c:39
@ RADICT_OUT_STRUCT
Definition radict.c:44
@ RADICT_OUT_DICT
Definition radict.c:43
@ RADICT_OUT_STATS_H
Definition radict.c:48
@ RADICT_OUT_ATTR_AUTOLOAD
Definition radict.c:47
@ RADICT_OUT_BASE_C_DA_DEF
Definition radict.c:46
@ RADICT_OUT_INVALID
Definition radict.c:40
@ RADICT_OUT_STATS_LINK
Definition radict.c:45
@ RADICT_OUT_FANCY
Definition radict.c:41
@ RADICT_OUT_CSV
Definition radict.c:42
static char const * parent_oid
Definition radict.c:56
#define DEBUG(fmt,...)
Definition radict.c:62
static void usage(void)
Definition radict.c:66
void(* da_print_func_t)(FILE *fp, fr_dict_attr_t const *da)
Definition radict.c:751
static const char * spaces
Definition radict.c:177
static radict_out_t output_format
Definition radict.c:57
static bool children_ok(fr_dict_attr_t const *parent)
Definition radict.c:406
static char const * mib
Definition radict.c:55
#define ENUM_NAME(_x)
Map data types to enum names representing those types.
Definition radict.c:527
static char const * name
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
return count
Definition module.c:155
fr_aka_sim_id_type_t type
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
An element in an arbitrarily ordered array of name to num mappings.
Definition table.h:57
An element in an arbitrarily ordered array of name to ptr mappings.
Definition table.h:73
#define talloc_asprintf
Definition talloc.h:144
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:48
#define FR_DICTIONARY_FILE
Definition conf.h:7
#define FR_DICTIONARY_INTERNAL_DIR
Definition conf.h:8
static fr_slen_t parent
Definition pair.h:858
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:732
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:576
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_structural(_x)
Definition types.h:392
@ FR_TYPE_UNION
A union of limited children.
Definition types.h:81
@ FR_TYPE_ATTR
A contains an attribute reference.
Definition types.h:83
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:454
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition version.c:40
#define RADIUSD_MAGIC_NUMBER
Definition version.h:81