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