The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: dbc611090ff5244577366b5fdcf3a412dbe6113a $
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: dbc611090ff5244577366b5fdcf3a412dbe6113a $")
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 if (!namespace) {
281 fr_assert(0); /* the namespace should always exist */
282 return;
283 }
284
285 for (child = fr_hash_table_iter_init(namespace, &iter);
286 child != NULL;
287 child = fr_hash_table_iter_next(namespace, &iter)) {
288 da_print_info(dict, child, depth + 1);
289 }
290}
291
292static char const *type_to_c_type[] = {
293 [FR_TYPE_STRING] = "char",
294 [FR_TYPE_OCTETS] = "uint8_t",
295
296 [FR_TYPE_IPV4_ADDR] = "struct in_addr",
297 [FR_TYPE_IPV6_ADDR] = "struct in6_addr",
298
299// [FR_TYPE_IFID] = "fr_ifid_t",
300// [FR_TYPE_ETHERNET] = "fr_ethernet_t",
301
302 [FR_TYPE_UINT8] = "uint8_t",
303 [FR_TYPE_UINT16] = "uint16_t",
304 [FR_TYPE_UINT32] = "uint32_t",
305 [FR_TYPE_UINT64] = "uint64_t",
306
307 [FR_TYPE_INT8] = "int8_t",
308 [FR_TYPE_INT16] = "int16_t",
309 [FR_TYPE_INT32] = "int32_t",
310 [FR_TYPE_INT64] = "int64_t",
311
312 [FR_TYPE_DATE] = "fr_time_t",
313 [FR_TYPE_TIME_DELTA] = "fr_time_delta_t",
314
315 [FR_TYPE_MAX] = 0 //!< Ensure array covers all types.
316};
317
318static char const *length_to_c_type[] = {
319 [2] = "uint16_t",
320 [4] = "uint32_t",
321 [8] = "uint64_t",
322};
323
324static void da_normalize_name(fr_dict_attr_t const *da, char buffer[static FR_DICT_ATTR_MAX_NAME_LEN*2 + 1])
325{
326 char const *start = da->name;
327 char const *p;
328 char *q;
329 bool mangle = false;
330
331 /*
332 * The RADIUS MIBs have lots of repetition. So we do some simple mangling of the names to make
333 * them easier to understand.
334 */
335 if (mib && da->parent) {
336 size_t len;
337
338 len = strlen(da->parent->name);
339
340 /*
341 * "radiusAuthServer" and "radiusAuthServTotalAccessRejects"
342 * to "total_access_rejects"
343 *
344 * Otherwise "radiusAuthServer" in the "RADIUS" dictionary, to "auth_server"
345 */
346 mangle = (strncmp(da->parent->name, da->name, len) == 0);
347 if (!mangle) {
348 fr_dict_attr_t const *root = fr_dict_root(da->dict);
349
350 len = strlen(root->name);
351 mangle = (strncasecmp(root->name, da->name, len) == 0);
352 }
353
354 if (mangle) start += len;
355 }
356
357 q = buffer;
358
359 for (p = start; *p != '\0'; p++) {
360 if ((*p >= '0') && (*p <= '9')) {
361 *q++ = *p;
362 continue;
363 }
364
365 if (islower((unsigned int) *p)) {
366 *q++ = *p;
367 continue;
368 }
369
370 if (isupper((unsigned int) *p)) {
371 if (mangle && (p > start)) {
372 *(q++) = '_';
373 }
374
375 *q++ = tolower((unsigned int)*p);
376 continue;
377 }
378
379 *q++ = '_';
380 }
381
382 *q = '\0';
383}
384
385static void da_print_name(FILE *fp, fr_dict_attr_t const *da)
386{
388
390 fprintf(fp, "%s", buffer);
391}
392
393static const bool type_allowed[FR_TYPE_MAX] = {
394 [FR_TYPE_STRING] = true,
395 [FR_TYPE_OCTETS] = true,
396
397 [FR_TYPE_UINT16] = true,
398 [FR_TYPE_UINT32] = true,
399 [FR_TYPE_UINT64] = true,
400
401 [FR_TYPE_IPV4_ADDR] = true,
402 [FR_TYPE_IPV6_ADDR] = true,
403
404 [FR_TYPE_DATE] = true,
405 [FR_TYPE_TIME_DELTA] = true,
406
407};
408
410{
411 int i;
412 fr_dict_attr_t const *da;
413
414 for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
415 if (!type_allowed[da->type]) return false;
416 }
417
418 return true;
419}
420
421#define CHECK_TYPE(_parent) \
422do { \
423 if ((parent->type != FR_TYPE_STRUCT) && (parent->type != FR_TYPE_TLV)) { \
424 fprintf(stderr, "%s is not a struct or tlv\n", parent->name); \
425 return; \
426 } \
427 if (!children_ok(parent)) fr_exit(EXIT_FAILURE); \
428} while (0)
429
430/** Print structures and mappings, mainly for statistics.
431 */
432static void da_print_struct(FILE *fp, fr_dict_attr_t const *parent)
433{
434 int i;
435 fr_dict_attr_t const *da;
436
438
439 /*
440 * @todo - print full OID path and filename?
441 */
442 fprintf(fp, "/*\n *\t%s\n */\n", parent->name);
443 fprintf(fp, "typedef struct {\n");
444
445 for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
446 unsigned int length = 0;
447
448 /*
449 * @todo - if the last field is a union, print out the union definitions first.
450 */
451 fr_assert(!da->flags.array);
452
453 if (da_is_bit_field(da)) {
454 /*
455 * @todo - this is all big endian. for little endian, we print out the bytes in
456 * order, but the bits in each byte are reversed. Likely the easiest way to do
457 * this is via a separate function that we call. But this shouldn't be necessary
458 * for statistics structures, as they shouldn't contain bitfields.
459 */
460 fprintf(fp, "\tunsigned int : %u\t", da->flags.length);
461
462 } else switch (da->type) {
463 case FR_TYPE_STRING:
464 if ((parent->type == FR_TYPE_TLV) && !da->flags.length) {
465 fprintf(fp, "\t%s\t*", type_to_c_type[da->type]);
466 break;
467 }
469
470 case FR_TYPE_OCTETS:
471 fr_assert(da->flags.length > 0);
472 length = da->flags.length;
473 fprintf(fp, "\t%s\t", type_to_c_type[da->type]);
474 break;
475
476 case FR_TYPE_DATE:
477 fr_assert(da->flags.length <= 8);
478 fr_assert(length_to_c_type[da->flags.length] != NULL);
479 fprintf(fp, "\t%s\t", length_to_c_type[da->flags.length]);
480 break;
481
482 default:
483 fr_assert(type_to_c_type[da->type] != NULL);
484 fprintf(fp, "\t%s\t", type_to_c_type[da->type]);
485 break;
486 }
487
488 da_print_name(fp, da);
489
490 if (length) {
491 fprintf(fp, "[%u]", length);
492 }
493
494 fprintf(fp, ";\n");
495 }
496
497 fprintf(fp, "} ");
498
499 fprintf(fp, "fr_stats_");
501 fprintf(fp, "_");
503 fprintf(fp, "_t;\n");
504}
505
506static void da_print_base_c_da_def(FILE *fp, fr_dict_attr_t const *parent)
507{
508 int i;
509 fr_dict_attr_t const *da;
511
513
515
516 fprintf(fp, "static fr_dict_attr_t const *attr_%s;\n", parent_name);
517
518 for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
519 fprintf(fp, "static fr_dict_attr_t const *attr_%s_", parent_name);
520 da_print_name(fp, da);
521 fprintf(fp, ";\n");
522 }
523
524 fprintf(fp, "\n\n");
525}
526
527
528/** Map data types to enum names representing those types
529 */
530#define ENUM_NAME(_x) [_x] = STRINGIFY(_x)
531
576
577static void da_print_stats_link(FILE *fp, fr_dict_attr_t const *parent)
578{
579 int i, num_elements = 0;
580 fr_dict_attr_t const *da;
581 char dict_name[FR_DICT_ATTR_MAX_NAME_LEN*2 + 1];
583
585
586 da_normalize_name(fr_dict_root(parent->dict), dict_name);
588
589 fprintf(fp, "fr_stats_link_t const fr_stats_link_%s_%s = {\n", dict_name, parent_name);
590
591 fprintf(fp, "\t.name = \"fr_stats_%s_%s_t\",\n", dict_name, parent_name);
592 fprintf(fp, "\t.root_p = &attr_%s,\n", parent_name);
593 if (mib) fprintf(fp, "\t.mib = \"%s\",\n", mib);
594 fprintf(fp, "\t.size = sizeof(fr_stats_%s_%s_t),\n", dict_name, parent_name);
595
596 for (i = 1; fr_dict_attr_child_by_num(parent, i) != NULL; i++) {
597 num_elements = i;
598 }
599 fprintf(fp, "\t.num_elements = %d,\n", num_elements);
600
601 fprintf(fp, "\t.entry = {\n");
602
603 /*
604 * For locality, also print out data type and size. That way we _can_ dereference the da, but we
605 * don't _need_ to.
606 */
607 for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
608 fprintf(fp, "\t\t{\n");
609 fprintf(fp, "\t\t\t.da_p = &attr_%s_", parent_name);
610 da_print_name(fp, da);
611 fprintf(fp, ",\n");
612
613 fprintf(fp, "\t\t\t.type = %s,\n", fr_type_to_enum_name[da->type]);
614
615 fprintf(fp, "\t\t\t.offset = offsetof(fr_stats_%s_%s_t, ", dict_name, parent_name);
616 da_print_name(fp, da);
617 fprintf(fp, "),\n");
618
619 fprintf(fp, "\t\t\t.size = %u,\n", da->flags.length);
620
621 fprintf(fp, "\t\t},\n");
622 }
623
624 fprintf(fp, "\t},\n");
625 fprintf(fp, "};\n\n");
626}
627
628static void da_print_attr_autoload(FILE *fp, fr_dict_attr_t const *parent)
629{
630 int i;
631 fr_dict_attr_t const *da;
632 char dict_name[FR_DICT_ATTR_MAX_NAME_LEN*2 + 1];
634
636
637 da_normalize_name(fr_dict_root(parent->dict), dict_name);
639
640 /*
641 * Define the parent.
642 */
643 fprintf(fp, "{ .out = &attr_%s, .name = \"%s\", .type = %s, .dict = &dict_%s },\n",
645
646 /*
647 * And each child
648 */
649 for (i = 1; (da = fr_dict_attr_child_by_num(parent, i)) != NULL; i++) {
650 fprintf(fp, "{ .out = &attr_%s_", parent_name);
651 da_print_name(fp, da);
652 fprintf(fp, ", .name = \".%s\", .type = %s, .dict = &dict_%s },\n",
653 da->name, fr_type_to_enum_name[da->type], dict_name);
654 }
655
656 fprintf(fp, "\n\n");
657}
658
659static void da_print_stats_h(FILE *fp, fr_dict_attr_t const *parent)
660{
661 char dict_name[FR_DICT_ATTR_MAX_NAME_LEN*2 + 1];
663
665
666 da_normalize_name(fr_dict_root(parent->dict), dict_name);
668
670
671 fprintf(fp, "\n");
672
673 fprintf(fp, "/*\n * fr_stats_%s_%s_instance_t\n */\n", dict_name, parent_name);
674 fprintf(fp, "FR_STATS_TYPEDEF(%s_%s);\n\n", dict_name, parent_name);
675
676 fprintf(fp, "extern fr_stats_link_t const fr_stats_link_%s_%s;\n\n", dict_name, parent_name);
677}
678
679
680static 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)
681{
682 unsigned int i;
683 size_t len;
684 fr_dict_attr_t const *p;
685 char flags[256];
686 fr_dict_attr_t const **children;
687
688 fr_dict_attr_flags_print(&FR_SBUFF_OUT(flags, sizeof(flags)), dict, da->type, &da->flags);
689
690 /*
691 * Root attributes are allocated outside of the pool
692 * so it's not helpful to include them in the calculation.
693 */
694 if (!da->flags.is_root) {
695 if (low && ((uintptr_t)da < *low)) {
696 *low = (uintptr_t)da;
697 }
698 if (high && ((uintptr_t)da > *high)) {
699 *high = (uintptr_t)da;
700 }
701
702 da_print_info(fr_dict_by_da(da), da, 0);
703 }
704
705 if (count) (*count)++;
706
707 /*
708 * Todo - Should be fixed to use attribute walking API
709 */
710 children = dict_attr_children(da);
711 if (children) {
712 len = talloc_array_length(children);
713 for (i = 0; i < len; i++) {
714 for (p = children[i]; p; p = p->next) {
715 _raddict_export(dict, count, low, high, p, lvl + 1);
716 }
717 }
718 }
719}
720
721static void raddict_export(uint64_t *count, uintptr_t *low, uintptr_t *high, fr_dict_t *dict)
722{
723 if (count) *count = 0;
724 if (low) *low = UINTPTR_MAX;
725 if (high) *high = 0;
726
727 _raddict_export(dict, count, low, high, fr_dict_root(dict), 0);
728}
729
731 { L("fancy"), RADICT_OUT_FANCY },
732 { L("csv"), RADICT_OUT_CSV },
733 { L("dict"), RADICT_OUT_DICT },
734 { L("struct"), RADICT_OUT_STRUCT },
735 { L("stats_link"), RADICT_OUT_STATS_LINK },
736 { L("da_def"), RADICT_OUT_BASE_C_DA_DEF },
737 { L("attr_autoload"), RADICT_OUT_ATTR_AUTOLOAD },
738 { L("stats.h"), RADICT_OUT_STATS_H },
739};
741
743 { L("fancy"), NULL },
744 { L("csv"), NULL },
745 { L("dict"), NULL },
746 { L("struct"), (void *) da_print_struct },
747 { L("stats_link"), (void *) da_print_stats_link },
748 { L("da_def"), (void *) da_print_base_c_da_def },
749 { L("attr_autoload"), (void *) da_print_attr_autoload },
750 { L("stats.h"), (void *) da_print_stats_h },
751};
753
754typedef void (*da_print_func_t)(FILE *fp, fr_dict_attr_t const *da);
755
756
757/**
758 *
759 * @hidecallgraph
760 */
761int main(int argc, char *argv[])
762{
763 char const *dict_dir = DICTDIR;
764 int c;
765 int ret = 0;
766 bool found = false;
767 bool export = false;
768 bool file_export = false;
769 bool alias = false;
770 char const *protocol = NULL;
771 da_print_func_t func = NULL;
772
773 TALLOC_CTX *autofree;
774
775 /*
776 * Must be called first, so the handler is called last
777 */
779
781
782#ifndef NDEBUG
783 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
784 fr_perror("radict - Fault setup");
785 fr_exit(EXIT_FAILURE);
786 }
787#endif
788
789 talloc_set_log_stderr();
790
791 fr_debug_lvl = 1;
792 fr_log_fp = stdout;
793
794 while ((c = getopt(argc, argv, "AcfF:ED:M:p:rVxhH")) != -1) switch (c) {
795 case 'A':
796 alias = true;
797 break;
798
799 case 'c':
801 break;
802
803 case 'H':
804 print_headers = true;
805 break;
806
807 case 'f':
808 file_export = true;
809 break;
810
811 case 'F':
814 fprintf(stderr, "Invalid output format '%s'\n", optarg);
815 fr_exit(EXIT_FAILURE);
816 }
817
819 break;
820
821 case 'E':
822 export = true;
823 break;
824
825 case 'D':
826 dict_dir = optarg;
827 break;
828
829 case 'M':
830 mib = optarg;
831 break;
832
833 case 'p':
834 protocol = optarg;
835 break;
836
837 case 'r':
838 print_recursive = true;
839 break;
840
841 case 'V':
842 print_values = true;
843 break;
844
845 case 'x':
846 fr_debug_lvl++;
847 break;
848
849 case 'h':
850 default:
851 usage();
852 goto finish;
853 }
854 argc -= optind;
855 argv += optind;
856
857 /*
858 * Mismatch between the binary and the libraries it depends on
859 */
861 fr_perror("radict - library mismatch");
862 ret = 1;
863 goto finish;
864 }
865
866 if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
867 fr_perror("radict - Global context init failed");
868 ret = 1;
869 goto finish;
870 }
871
872 DEBUG("Loading dictionary: %s/%s", dict_dir, FR_DICTIONARY_FILE);
873
875 fr_perror("radict - Loading internal dictionary failed");
876 ret = 1;
877 goto finish;
878 }
879
880 /*
881 * Don't emit spurious errors...
882 */
884 if (load_dicts(dict_dir, protocol) < 0) {
885 fr_perror("radict - Loading dictionaries failed");
886 ret = 1;
887 goto finish;
888 }
889
890 if (dict_end == dicts) {
891 fr_perror("radict - No dictionaries loaded");
892 ret = 1;
893 goto finish;
894 }
895
896 if (print_headers) switch(output_format) {
897 case RADICT_OUT_CSV:
898 printf("Dictionary,OID,Attribute,ID,Type,Flags\n");
899 break;
900
901 case RADICT_OUT_FANCY:
902 default:
903 printf("Dictionary\tOID\tAttribute\tID\tType\tFlags\n");
904 }
905
906 if (file_export) {
907 fr_dict_t **dict_p = dicts;
908
909 do {
910 if (protocol && (strcasecmp(fr_dict_root(*dict_p)->name, protocol) == 0)) {
911 fr_dict_export(fr_log_fp, *dict_p);
912 }
913 } while (++dict_p < dict_end);
914 }
915
916 if (export) {
917 fr_dict_t **dict_p = dicts;
918
919 do {
920 uint64_t count;
921 uintptr_t high;
922 uintptr_t low;
923
924 raddict_export(&count, &low, &high, *dict_p);
925 DEBUG2("Attribute count %" PRIu64, count);
926 DEBUG2("Memory allocd %zu (bytes)", talloc_total_size(*dict_p));
927 DEBUG2("Memory spread %zu (bytes)", (size_t) (high - low));
928 } while (++dict_p < dict_end);
929
930 goto finish;
931 }
932
933 if (alias) {
934 fr_dict_t **dict_p = dicts;
935
936 do {
937 if (protocol && (strcasecmp(fr_dict_root(*dict_p)->name, protocol) == 0)) {
939 }
940 } while (++dict_p < dict_end);
941
942 goto finish;
943 }
944
945 if (argc == 0) goto finish;
946
947 while (argc-- > 0) {
948 char *attr;
949 fr_dict_attr_t const *da;
950 fr_dict_t **dict_p = dicts;
951
952 attr = *argv++;
953
954 /*
955 * Loop through all the dicts. An attribute may
956 * exist in multiple dictionaries.
957 */
958 do {
959 DEBUG2("Looking for \"%s\" in dict \"%s\"", attr, fr_dict_root(*dict_p)->name);
960
961 da = fr_dict_attr_by_oid(NULL, fr_dict_root(*dict_p), attr);
962 if (!da) {
963 DEBUG2("Dictionary %s does not contain attribute %s\n",
964 fr_dict_root(*dict_p)->name, attr);
965 continue;
966 }
967
968 if (!func) {
969 da_print_info(*dict_p, da, 0);
970 } else {
971 parent_oid = attr;
972 func(stdout, da);
973 }
974 found = true;
975 } while (++dict_p < dict_end);
976 }
977
978 if (!found) ret = 64;
979
980finish:
981 /*
982 * Release our references on all the dicts
983 * we loaded.
984 */
985 {
986 fr_dict_t **dict_p = dicts;
987
988 do {
989 fr_dict_free(dict_p, __FILE__);
990 } while (++dict_p < dict_end);
991 }
992 if (talloc_free(autofree) < 0) fr_perror("radict - Error freeing dictionaries");
993
994 /*
995 * Ensure our atexit handlers run before any other
996 * atexit handlers registered by third party libraries.
997 */
999
1000 return ret;
1001}
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:179
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:308
#define RCSID(id)
Definition build.h:512
#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:487
#define NUM_ELEMENTS(_t)
Definition build.h:358
#define DIAG_OFF(_x)
Definition build.h:486
TALLOC_CTX * autofree
Definition common.c:29
fr_dict_t * dict
Definition common.c:31
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:1071
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition debug.h:220
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:2848
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:2639
#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:4306
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:2612
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:3570
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:4690
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:41
FILE * fr_log_fp
Definition log.c:40
@ 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:532
int main(int argc, char *argv[])
Definition radict.c:761
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:432
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:324
static void da_print_name(FILE *fp, fr_dict_attr_t const *da)
Definition radict.c:385
static fr_table_num_ordered_t const format_table[]
Definition radict.c:730
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:577
static void raddict_export(uint64_t *count, uintptr_t *low, uintptr_t *high, fr_dict_t *dict)
Definition radict.c:721
static void da_print_stats_h(FILE *fp, fr_dict_attr_t const *parent)
Definition radict.c:659
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:318
static const bool type_allowed[FR_TYPE_MAX]
Definition radict.c:393
static size_t format_table_len
Definition radict.c:740
static fr_table_ptr_ordered_t const function_table[]
Definition radict.c:742
static size_t function_table_len
Definition radict.c:752
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:628
static void da_print_base_c_da_def(FILE *fp, fr_dict_attr_t const *parent)
Definition radict.c:506
#define CHECK_TYPE(_parent)
Definition radict.c:421
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:680
#define DEBUG2(fmt,...)
Definition radict.c:61
static char const * type_to_c_type[]
Definition radict.c:292
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:754
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:409
static char const * mib
Definition radict.c:55
#define ENUM_NAME(_x)
Map data types to enum names representing those types.
Definition radict.c:530
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:685
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:151
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:55
#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:737
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:581
#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