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: 0934122f6e55427387b7637585df9e33b1c5fafe $
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: 0934122f6e55427387b7637585df9e33b1c5fafe $")
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
44
45static fr_dict_t *dicts[255];
46static bool print_values = false;
47static bool print_headers = false;
50
51DIAG_OFF(unused-macros)
52#define DEBUG2(fmt, ...) if (fr_log_fp && (fr_debug_lvl > 2)) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
53#define DEBUG(fmt, ...) if (fr_log_fp && (fr_debug_lvl > 1)) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
54#define INFO(fmt, ...) if (fr_log_fp && (fr_debug_lvl > 0)) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
55DIAG_ON(unused-macros)
56
57static void usage(void)
58{
59 fprintf(stderr, "usage: radict [OPTS] <attribute> [attribute...]\n");
60 fprintf(stderr, " -E Export dictionary definitions.\n");
61 fprintf(stderr, " -V Write out all attribute values.\n");
62 fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
63 fprintf(stderr, " -p <protocol> Set protocol by name\n");
64 fprintf(stderr, " -x Debugging mode.\n");
65 fprintf(stderr, " -c Print out in CSV format.\n");
66 fprintf(stderr, " -H Show the headers of each field.\n");
67 fprintf(stderr, "\n");
68 fprintf(stderr, "Very simple interface to extract attribute definitions from FreeRADIUS dictionaries\n");
69}
70
71static int load_dicts(char const *dict_dir, char const *protocol)
72{
73 DIR *dir;
74 struct dirent *dp;
75
76 INFO("Reading directory %s", dict_dir);
77
78 dir = opendir(dict_dir);
79 if (!dir) {
80 fr_strerror_printf("Failed opening \"%s\": %s", dict_dir, fr_syserror(errno));
81 return -1;
82 }
83
84 while ((dp = readdir(dir)) != NULL) {
85 struct stat stat_buff;
86 char *file_str;
87
88 if (dp->d_name[0] == '.') continue;
89
90 /*
91 * We only want to load one...
92 */
93 if (protocol && (strcmp(dp->d_name, protocol) != 0)) continue;
94
95 /*
96 * Skip the internal FreeRADIUS dictionary.
97 */
98 if (strcmp(dp->d_name, "freeradius") == 0) continue;
99
100 file_str = talloc_asprintf(NULL, "%s/%s", dict_dir, dp->d_name);
101
102 if (stat(file_str, &stat_buff) == -1) {
103 fr_strerror_printf("Failed stating file \"%s\": %s", file_str, fr_syserror(errno));
104 error:
105 closedir(dir);
106 talloc_free(file_str);
107 return -1;
108 }
109
110 /*
111 * Only process directories
112 */
113 if ((stat_buff.st_mode & S_IFMT) == S_IFDIR) {
114 char *dict_file;
115 struct stat dict_stat_buff;
116 int ret;
117
118 dict_file = talloc_asprintf(NULL, "%s/dictionary", file_str);
119 ret = stat(dict_file, &dict_stat_buff);
120 talloc_free(dict_file);
121
122 /*
123 * If the directory contains a dictionary file,
124 * load it as a dictionary.
125 */
126 if (ret == 0) {
127 if (dict_end >= (dicts + (NUM_ELEMENTS(dicts)))) {
128 fr_strerror_const("Reached maximum number of dictionaries");
129 goto error;
130 }
131
132 INFO("Loading dictionary: %s/dictionary", file_str);
133 if (fr_dict_protocol_afrom_file(dict_end, dp->d_name, NULL, __FILE__) < 0) {
134 goto error;
135 }
136 dict_end++;
137 }
138
139 /*
140 * For now, don't do sub-protocols.
141 */
142 }
143 talloc_free(file_str);
144 }
145 closedir(dir);
146
147 return 0;
148}
149
150static void da_print_info_td(fr_dict_t const *dict, fr_dict_attr_t const *da)
151{
152 char oid_str[512];
153 char flags[256];
154 fr_hash_iter_t iter;
156 fr_sbuff_t old_str_sbuff = FR_SBUFF_OUT(oid_str, sizeof(oid_str));
157 fr_sbuff_t flags_sbuff = FR_SBUFF_OUT(flags, sizeof(flags));
158
159 if (fr_dict_attr_oid_print(&old_str_sbuff, NULL, da, false) <= 0) {
160 fr_strerror_printf("OID string too long");
161 fr_exit(EXIT_FAILURE);
162 }
163
164 fr_dict_attr_flags_print(&flags_sbuff, dict, da->type, &da->flags);
165
166 /* Protocol Name Type */
167
168 switch(output_format) {
169 case RADICT_OUT_CSV:
170 printf("%s,%s,%s,%d,%s,%s\n",
171 fr_dict_root(dict)->name,
172 fr_sbuff_start(&old_str_sbuff),
173 da->name,
174 da->attr,
175 fr_type_to_str(da->type),
176 fr_sbuff_start(&flags_sbuff));
177 break;
178
179 case RADICT_OUT_FANCY:
180 default:
181 printf("%s\t%s\t%s\t%d\t%s\t%s\n",
182 fr_dict_root(dict)->name,
183 fr_sbuff_start(&old_str_sbuff),
184 da->name,
185 da->attr,
186 fr_type_to_str(da->type),
187 fr_sbuff_start(&flags_sbuff));
188 }
189
190 if (print_values) {
192
194 if (!ext || !ext->value_by_name) return;
195
196 for (enumv = fr_hash_table_iter_init(ext->value_by_name, &iter);
197 enumv;
198 enumv = fr_hash_table_iter_next(ext->value_by_name, &iter)) {
199 char *str;
200
201
202 switch(output_format) {
203 case RADICT_OUT_CSV:
204 str = fr_asprintf(NULL, "%s,%s,%s,%d,%s,%s,%s,%pV",
205 fr_dict_root(dict)->name,
206 fr_sbuff_start(&old_str_sbuff),
207 da->name,
208 da->attr,
209 fr_type_to_str(da->type),
210 fr_sbuff_start(&flags_sbuff),
211 enumv->name,
212 enumv->value);
213 break;
214
215 case RADICT_OUT_FANCY:
216 default:
217 str = fr_asprintf(NULL, "%s\t%s\t%s\t%d\t%s\t%s\t%s\t%pV",
218 fr_dict_root(dict)->name,
219 fr_sbuff_start(&old_str_sbuff),
220 da->name,
221 da->attr,
222 fr_type_to_str(da->type),
223 fr_sbuff_start(&flags_sbuff),
224 enumv->name,
225 enumv->value);
226 }
227
228 printf("%s\n", str);
229 talloc_free(str);
230 }
231 }
232}
233
234static 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)
235{
236 unsigned int i;
237 size_t len;
238 fr_dict_attr_t const *p;
239 char flags[256];
240 fr_dict_attr_t const **children;
241
242 fr_dict_attr_flags_print(&FR_SBUFF_OUT(flags, sizeof(flags)), dict, da->type, &da->flags);
243
244 /*
245 * Root attributes are allocated outside of the pool
246 * so it's not helpful to include them in the calculation.
247 */
248 if (!da->flags.is_root) {
249 if (low && ((uintptr_t)da < *low)) {
250 *low = (uintptr_t)da;
251 }
252 if (high && ((uintptr_t)da > *high)) {
253 *high = (uintptr_t)da;
254 }
255
257 }
258
259 if (count) (*count)++;
260
261 /*
262 * Todo - Should be fixed to use attribute walking API
263 */
264 children = dict_attr_children(da);
265 if (children) {
266 len = talloc_array_length(children);
267 for (i = 0; i < len; i++) {
268 for (p = children[i]; p; p = p->next) {
269 _raddict_export(dict, count, low, high, p, lvl + 1);
270 }
271 }
272 }
273}
274
275static void raddict_export(uint64_t *count, uintptr_t *low, uintptr_t *high, fr_dict_t *dict)
276{
277 if (count) *count = 0;
278 if (low) *low = UINTPTR_MAX;
279 if (high) *high = 0;
280
281 _raddict_export(dict, count, low, high, fr_dict_root(dict), 0);
282}
283
284/**
285 *
286 * @hidecallgraph
287 */
288int main(int argc, char *argv[])
289{
290 char const *dict_dir = DICTDIR;
291 char c;
292 int ret = 0;
293 bool found = false;
294 bool export = false;
295 bool file_export = false;
296 char const *protocol = NULL;
297
298 TALLOC_CTX *autofree;
299
300 /*
301 * Must be called first, so the handler is called last
302 */
304
306
307#ifndef NDEBUG
308 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
309 fr_perror("radict - Fault setup");
310 fr_exit(EXIT_FAILURE);
311 }
312#endif
313
314 talloc_set_log_stderr();
315
316 fr_debug_lvl = 1;
317
318 while ((c = getopt(argc, argv, "cfED:p:VxhH")) != -1) switch (c) {
319 case 'c':
321 break;
322
323 case 'H':
324 print_headers = true;
325 break;
326
327 case 'f':
328 file_export = true;
329 break;
330
331 case 'E':
332 export = true;
333 break;
334
335 case 'D':
336 dict_dir = optarg;
337 break;
338
339 case 'p':
340 protocol = optarg;
341 break;
342
343 case 'V':
344 print_values = true;
345 break;
346
347 case 'x':
348 fr_log_fp = stdout;
349 fr_debug_lvl++;
350 break;
351
352 case 'h':
353 default:
354 usage();
355 found = true;
356 goto finish;
357 }
358 argc -= optind;
359 argv += optind;
360
361 /*
362 * Mismatch between the binary and the libraries it depends on
363 */
365 fr_perror("radict - library mismatch");
366 ret = 1;
367 goto finish;
368 }
369
370 if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
371 fr_perror("radict - Global context init failed");
372 ret = 1;
373 goto finish;
374 }
375
376 INFO("Loading dictionary: %s/%s", dict_dir, FR_DICTIONARY_FILE);
377
379 fr_perror("radict - Loading internal dictionary failed");
380 ret = 1;
381 goto finish;
382 }
383 /*
384 * Don't emit spurious errors...
385 */
387 if (load_dicts(dict_dir, protocol) < 0) {
388 fr_perror("radict - Loading dictionaries failed");
389 ret = 1;
390 goto finish;
391 }
392
393 if (dict_end == dicts) {
394 fr_perror("radict - No dictionaries loaded");
395 ret = 1;
396 goto finish;
397 }
398
399 if (print_headers) switch(output_format) {
400 case RADICT_OUT_CSV:
401 printf("Dictionary,OID,Attribute,ID,Type,Flags\n");
402 break;
403
404 case RADICT_OUT_FANCY:
405 default:
406 printf("Dictionary\tOID\tAttribute\tID\tType\tFlags\n");
407 }
408
409 if (file_export) {
410 fr_dict_t **dict_p = dicts;
411
412 do {
413 if (protocol && (strcasecmp(fr_dict_root(*dict_p)->name, protocol) == 0)) {
414 fr_dict_export(*dict_p);
415 }
416 } while (++dict_p < dict_end);
417 }
418
419 if (export) {
420 fr_dict_t **dict_p = dicts;
421
422 do {
423 uint64_t count;
424 uintptr_t high;
425 uintptr_t low;
426
427 raddict_export(&count, &low, &high, *dict_p);
428 DEBUG2("Attribute count %" PRIu64, count);
429 DEBUG2("Memory allocd %zu (bytes)", talloc_total_size(*dict_p));
430 DEBUG2("Memory spread %zu (bytes)", (size_t) (high - low));
431 } while (++dict_p < dict_end);
432 }
433
434 while (argc-- > 0) {
435 char *attr;
436 fr_dict_attr_t const *da;
437 fr_dict_t **dict_p = dicts;
438
439 attr = *argv++;
440
441
442 /*
443 * Loop through all the dicts. An attribute may
444 * exist in multiple dictionaries.
445 */
446 do {
447 DEBUG2("Looking for \"%s\" in dict \"%s\"", attr, fr_dict_root(*dict_p)->name);
448
449 da = fr_dict_attr_by_oid(NULL, fr_dict_root(*dict_p), attr);
450 if (da) {
451 da_print_info_td(*dict_p, da);
452 found = true;
453 }
454 } while (++dict_p < dict_end);
455 }
456
457finish:
458 /*
459 * Release our references on all the dicts
460 * we loaded.
461 */
462 {
463 fr_dict_t **dict_p = dicts;
464
465 do {
466 fr_dict_free(dict_p, __FILE__);
467 } while (++dict_p < dict_end);
468 }
469 if (talloc_free(autofree) < 0) fr_perror("radict - Error freeing dictionaries");
470
471 /*
472 * Ensure our atexit handlers run before any other
473 * atexit handlers registered by third party libraries.
474 */
476
477 return found ? ret : 64;
478}
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
#define RCSID(id)
Definition build.h:483
#define DIAG_ON(_x)
Definition build.h:458
#define NUM_ELEMENTS(_t)
Definition build.h:337
#define DIAG_OFF(_x)
Definition build.h:457
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:1242
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition debug.h:228
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:4392
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:2606
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:2400
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:231
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4024
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition dict.h:169
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:2373
void fr_dict_export(fr_dict_t const *dict)
Export in the standard form: ATTRIBUTE name oid flags.
Definition dict_print.c:295
char const * name
Enum name.
Definition dict.h:228
Value of an enumerated attribute.
Definition dict.h:227
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:140
fr_hash_table_t * value_by_name
Lookup an enumeration value by name.
Definition dict_ext.h:109
Attribute extension - Holds enumeration values.
Definition dict_ext.h:107
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:626
void * fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Initialise an iterator.
Definition hash.c:678
Stores the state of the current iteration operation.
Definition hash.h:41
talloc_free(reap)
int fr_debug_lvl
Definition log.c:43
FILE * fr_log_fp
Definition log.c:42
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)
int strcasecmp(char *s1, char *s2)
Definition missing.c:66
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
Definition print.c:874
static TALLOC_CTX * autofree
int main(int argc, char *argv[])
Definition radict.c:288
static fr_dict_t ** dict_end
Definition radict.c:49
static int load_dicts(char const *dict_dir, char const *protocol)
Definition radict.c:71
static void raddict_export(uint64_t *count, uintptr_t *low, uintptr_t *high, fr_dict_t *dict)
Definition radict.c:275
static bool print_values
Definition radict.c:46
static fr_dict_t * dicts[255]
Definition radict.c:45
static bool print_headers
Definition radict.c:47
#define INFO(fmt,...)
Definition radict.c:54
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:234
#define DEBUG2(fmt,...)
Definition radict.c:52
radict_out_t
Definition radict.c:40
@ RADICT_OUT_FANCY
Definition radict.c:41
@ RADICT_OUT_CSV
Definition radict.c:42
static void usage(void)
Definition radict.c:57
static void da_print_info_td(fr_dict_t const *dict, fr_dict_attr_t const *da)
Definition radict.c:150
static radict_out_t output_format
Definition radict.c:48
static char const * name
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
return count
Definition module.c:163
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#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
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:733
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:577
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
int fr_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