The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
dict_print.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/** Print dictionary attributes, flags, etc...
18 *
19 * @file src/lib/util/dict_print.c
20 *
21 * @copyright 2019 The FreeRADIUS server project
22 */
23RCSID("$Id: a277c266c4c7495f22c7db62c2f4001a8b0fff39 $")
24
25#include <freeradius-devel/util/dict_priv.h>
26#include <freeradius-devel/util/print.h>
27#include <freeradius-devel/util/proto.h>
28
30{
31 fr_sbuff_t our_out = FR_SBUFF(out);
32
33#define FLAG_SET(_flag) if (flags->_flag) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, STRINGIFY(_flag)",")
34
35 FLAG_SET(is_root);
36 FLAG_SET(is_unknown);
37 FLAG_SET(is_raw);
38 FLAG_SET(is_alias);
39 FLAG_SET(has_alias);
40 FLAG_SET(internal);
41 FLAG_SET(array);
42 FLAG_SET(has_value);
43 FLAG_SET(counter);
44 FLAG_SET(name_only);
45
46 if (dict && !flags->extra && flags->subtype) {
47 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", flags->subtype);
48 FR_SBUFF_IN_CHAR_RETURN(&our_out, ',');
49 }
50
51 if (flags->length) {
52 switch (type) {
54 /*
55 * Bit fields are in the dicts as various
56 * `uint*` types. But with special flags
57 * saying they're bit fields.
58 */
59 if (flags->extra && (flags->subtype == FLAG_BIT_FIELD)) {
60 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "bit[%u],", flags->length);
61 }
62 break;
63
64 default:
65 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "length=%i,", flags->length);
66 break;
67 }
68 }
69 if (flags->extra) {
70 switch (flags->subtype) {
71 case FLAG_KEY_FIELD:
72 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "key,");
73 break;
74
75 case FLAG_BIT_FIELD:
76 break;
77
79 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "length=uint8,");
80 break;
81
83 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "length=uint16,");
84 break;
85
86 default:
87 break;
88 }
89 }
90
91 /*
92 * Print out the date precision.
93 */
94 if ((type == FR_TYPE_DATE) || (type == FR_TYPE_TIME_DELTA)) {
96 fr_table_str_by_value(fr_time_precision_table, flags->flag_time_res, "?"));
97 FR_SBUFF_IN_CHAR_RETURN(&our_out, ',');
98 if (flags->is_unsigned) FR_SBUFF_IN_CHAR_RETURN(&our_out, 'u');
99 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "int%d", flags->length << 3);
100 }
101
102 /*
103 * Remove trailing commas.
104 */
105 fr_sbuff_trim(&our_out, (bool[UINT8_MAX + 1]){ [','] = true });
106
107 /*
108 * Ensure that the buffer is initialized.
109 */
110 if (fr_sbuff_used(&our_out) == 0) FR_SBUFF_IN_CHAR_RETURN(&our_out, '\0');
111
112 FR_SBUFF_SET_RETURN(out, &our_out);
113}
114
115/** Build the da_stack for the specified DA and encode the path by name in OID form
116 *
117 * @param[out] out Where to write the OID.
118 * @param[in] ancestor If not NULL, only print OID portion between ancestor and da.
119 * @param[in] da to print OID string for.
120 * @param[in] numeric print the OID components as numbers, not attribute names.
121 * @return
122 * - >0 The number of bytes written to the buffer.
123 * - <= 0 The number of bytes we would have needed to write the
124 * next OID component.
125 */
127 fr_dict_attr_t const *ancestor, fr_dict_attr_t const *da, bool numeric)
128{
129 int i;
130 int depth = 0;
131 fr_da_stack_t da_stack;
132 fr_sbuff_t our_out = FR_SBUFF(out);
133
134 /*
135 * If the ancestor and the DA match, there's
136 * no OID string to print.
137 */
138 if ((ancestor == da) || (da->depth == 0)) return 0;
139
140 if (ancestor && (ancestor->flags.is_root)) ancestor = NULL;
141
142 fr_proto_da_stack_build(&da_stack, da);
143
144 /*
145 * We may have swapped from a known to an unknown
146 * attribute. We still print out the unknown one.
147 */
148 if (ancestor && da->flags.is_unknown) {
149 fr_assert(da->depth > ancestor->depth);
150
151 ancestor = da_stack.da[ancestor->depth - 1];
152 }
153
154 if (ancestor) {
155 if (da_stack.da[ancestor->depth - 1] != ancestor) {
156 fr_strerror_printf("Attribute '%s' is not a descendent of \"%s\"", da->name, ancestor->name);
157 return 0;
158 }
159 depth = ancestor->depth;
160 }
161
162 /*
163 * We don't print the ancestor, we print the OID
164 * between it and the da.
165 */
166 if (numeric) {
167 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", da_stack.da[depth]->attr);
168 for (i = depth + 1; i < (int)da->depth; i++) {
169 FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
170 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", da_stack.da[i]->attr);
171 }
172 } else {
173 FR_SBUFF_IN_STRCPY_RETURN(&our_out, da_stack.da[depth]->name);
174 for (i = depth + 1; i < (int)da->depth; i++) {
175 FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
176 FR_SBUFF_IN_STRCPY_RETURN(&our_out, da_stack.da[i]->name);
177 }
178 }
179 FR_SBUFF_SET_RETURN(out, &our_out);
180}
181
182typedef struct {
183 FILE *fp;
185 fr_dict_attr_t const *da; //!< where we started
186 char prefix[256];
187 char flags[256];
188 char oid[256];
189 unsigned int start_depth;
191
192static int dict_attr_debug(fr_dict_attr_t const *da, void *uctx)
193{
194 fr_dict_attr_debug_t *ctx = uctx;
195 fr_hash_iter_t iter;
196 fr_dict_enum_value_t const *enumv;
198
199 /*
200 * Don't print it twice.
201 */
202 if (da == ctx->da) return 0;
203
205 ctx->dict, da->type, &da->flags);
206
207 snprintf(ctx->prefix, sizeof(ctx->prefix),
208 "[%02u] 0x%016" PRIxPTR "%*s - ",
209 da->depth,
210 (unsigned long)da,
211 (da->depth - ctx->start_depth) * 4, "");
212
213 fprintf(ctx->fp, "%s%s(%u) %s %s\n",
214 ctx->prefix,
215 da->name,
216 da->attr,
217 fr_type_to_str(da->type),
218 ctx->flags);
219
220 dict_attr_ext_debug(ctx->prefix, da); /* Print all the extension debug info */
221
223 if (!ext || !ext->name_by_value) return 0;
224
225 for (enumv = fr_hash_table_iter_init(ext->name_by_value, &iter);
226 enumv;
227 enumv = fr_hash_table_iter_next(ext->name_by_value, &iter)) {
228 char *value = fr_asprintf(NULL, "%pV", enumv->value);
229
230 fprintf(ctx->fp, "%s %s -> %s\n",
231 ctx->prefix,
232 enumv->name,
233 value);
235 }
236
237 return 0;
238}
239
241{
242 fr_dict_attr_debug_t uctx = {
243 .fp = fp,
244 .dict = fr_dict_by_da(da),
245 .start_depth = da->depth,
246 };
247 fr_hash_table_t *namespace;
248 fr_hash_iter_t iter;
249 fr_dict_attr_t *our_da;
250
251 namespace = dict_attr_namespace(da);
252 if (!namespace) {
253 fprintf(fp, "%s does not have namespace\n", da->name);
254 return;
255 }
256
257 for (our_da = fr_hash_table_iter_init(namespace, &iter);
258 our_da;
259 our_da = fr_hash_table_iter_next(namespace, &iter)) {
260 dict_attr_debug(our_da, &uctx);
261 }
262}
263
264void fr_dict_attr_debug(FILE *fp, fr_dict_attr_t const *da)
265{
266 fr_dict_attr_debug_t uctx = {
267 .fp = fp,
268 .dict = fr_dict_by_da(da),
269 .start_depth = da->depth,
270 };
271
272 dict_attr_debug(da, &uctx);
273 uctx.da = da,
274
275 (void)fr_dict_walk(da, dict_attr_debug, &uctx);
276}
277
278void fr_dict_debug(FILE *fp, fr_dict_t const *dict)
279{
281}
282
283static int dict_attr_export(fr_dict_attr_t const *da, void *uctx)
284{
285 fr_dict_attr_debug_t *ctx = uctx;
286
287 (void) fr_dict_attr_oid_print(&FR_SBUFF_OUT(ctx->prefix, sizeof(ctx->prefix)),
288 NULL, da, false);
289 (void) fr_dict_attr_oid_print(&FR_SBUFF_OUT(ctx->oid, sizeof(ctx->oid)),
290 NULL, da, true);
291
292 *ctx->flags = 0; /* some attributes don't have flags */
294 ctx->dict, da->type, &da->flags);
295 fprintf(ctx->fp, "ATTRIBUTE\t%-40s\t%-20s\t%s\t%s\n",
296 ctx->prefix,
297 ctx->oid,
298 fr_type_to_str(da->type),
299 ctx->flags);
300
301 return 0;
302}
303
304static void fr_dict_attr_export(FILE *fp, fr_dict_attr_t const *da)
305{
306 fr_dict_attr_debug_t uctx = {
307 .fp = fp,
308 .dict = fr_dict_by_da(da),
309 .start_depth = da->depth
310 };
311
312 dict_attr_export(da, &uctx);
313 (void)fr_dict_walk(da, dict_attr_export, &uctx);
314}
315
316/** Export in the standard form: ATTRIBUTE name oid flags
317 *
318 */
319void fr_dict_export(FILE *fp, fr_dict_t const *dict)
320{
322}
323
325{
326 fr_hash_table_t *namespace;
327 fr_hash_iter_t iter;
328 fr_dict_attr_t *da;
329 char buffer [256];
330
331 namespace = dict_attr_namespace(parent);
332 if (!namespace) {
333 fprintf(fp, "%s does not have namespace\n", parent->name);
334 return;
335 }
336
337 for (da = fr_hash_table_iter_init(namespace, &iter);
338 da;
339 da = fr_hash_table_iter_next(namespace, &iter)) {
340 fr_dict_attr_t const *ref;
341
342 if (!da->flags.is_alias) continue;
343
344 if (!fr_type_is_leaf(da->type)) continue;
345
346 ref = fr_dict_attr_ref(da);
347 if (!ref) continue;
348
349 if (da->depth == ref->depth) continue;
350
351#ifdef STATIC_ANALYZER
352 buffer[0] = '\0';
353#endif
354
356 NULL, ref, false);
357
358 fprintf(fp, "%-40s\t%s\n", da->name, buffer);
359 }
360}
static int const char char buffer[256]
Definition acutest.h:578
#define RCSID(id)
Definition build.h:485
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
Definition dict.h:166
@ FLAG_LENGTH_UINT16
string / octets type is prefixed by uint16 of length
Definition dict.h:167
@ FLAG_KEY_FIELD
this is a key field for a subsequent struct
Definition dict.h:164
@ FLAG_BIT_FIELD
bit field inside of a struct
Definition dict.h:165
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:2879
int fr_dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
Definition dict_util.c:5093
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2673
unsigned int extra
really "subtype is used by dict, not by protocol"
Definition dict.h:120
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:258
uint16_t length
length of the attribute
Definition dict.h:153
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition dict.h:189
unsigned int is_unsigned
hackity hack for dates and time deltas
Definition dict.h:98
char const * name
Enum name.
Definition dict.h:255
uint8_t subtype
needs a fixup during dictionary parsing
Definition dict.h:131
Values of the encryption flags.
Value of an enumerated attribute.
Definition dict.h:254
fr_hash_table_t * name_by_value
Lookup a name by value.
Definition dict_ext.h:111
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition dict_ext.h:134
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition dict_ext.h:178
Attribute extension - Holds enumeration values.
Definition dict_ext.h:108
static void dict_attr_ext_debug(char const *name, fr_dict_attr_t const *da)
Print extension debug information for attributes.
fr_dict_t const * dict
Definition dict_print.c:184
void fr_dict_namespace_debug(FILE *fp, fr_dict_attr_t const *da)
Definition dict_print.c:240
static int dict_attr_export(fr_dict_attr_t const *da, void *uctx)
Definition dict_print.c:283
void fr_dict_alias_export(FILE *fp, fr_dict_attr_t const *parent)
Definition dict_print.c:324
void fr_dict_debug(FILE *fp, fr_dict_t const *dict)
Definition dict_print.c:278
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)
Definition dict_print.c:29
static void fr_dict_attr_export(FILE *fp, fr_dict_attr_t const *da)
Definition dict_print.c:304
void fr_dict_attr_debug(FILE *fp, fr_dict_attr_t const *da)
Definition dict_print.c:264
unsigned int start_depth
Definition dict_print.c:189
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)
Build the da_stack for the specified DA and encode the path by name in OID form.
Definition dict_print.c:126
#define FLAG_SET(_flag)
fr_dict_attr_t const * da
where we started
Definition dict_print.c:185
static int dict_attr_debug(fr_dict_attr_t const *da, void *uctx)
Definition dict_print.c:192
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
Test enumeration values.
Definition dict_test.h:92
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:625
void * fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Initialise an iterator.
Definition hash.c:677
Stores the state of the current iteration operation.
Definition hash.h:41
talloc_free(reap)
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
long int ssize_t
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)
#define UINT8_MAX
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
Definition print.c:884
void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
Build a complete DA stack from the da back to the root.
Definition proto.c:118
#define fr_assert(_expr)
Definition rad_assert.h:38
size_t fr_sbuff_trim(fr_sbuff_t *sbuff, bool const to_trim[static UINT8_MAX+1])
Trim trailing characters from a string we're composing.
Definition sbuff.c:2156
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define FR_SBUFF_IN_SPRINTF_RETURN(...)
#define FR_SBUFF(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_IN_STRCPY_RETURN(...)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
fr_aka_sim_id_type_t type
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
fr_table_num_ordered_t const fr_time_precision_table[]
Definition time.c:46
static fr_slen_t parent
Definition pair.h:854
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition proto.h:57
Structure for holding the stack of dictionary attributes being encoded.
Definition proto.h:55
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_type_is_leaf(_x)
Definition types.h:394
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
#define FR_TYPE_FIXED_SIZE
Definition types.h:311
static size_t char ** out
Definition value.h:1023