The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
23 RCSID("$Id: 127c079724f256f49a7bb580b903c657ecded59e $")
24 
25 #include <freeradius-devel/util/dict_priv.h>
26 #include <freeradius-devel/util/print.h>
27 #include <freeradius-devel/util/proto.h>
28 #include <ctype.h>
29 
31 {
32  fr_sbuff_t our_out = FR_SBUFF(out);
33 
34 #define FLAG_SET(_flag) if (flags->_flag) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, STRINGIFY(_flag)",")
35 
36  FLAG_SET(is_root);
37  FLAG_SET(is_unknown);
38  FLAG_SET(is_raw);
39  FLAG_SET(internal);
40  FLAG_SET(array);
41  FLAG_SET(has_value);
42  FLAG_SET(counter);
43  FLAG_SET(name_only);
44 
45  if (dict && !flags->extra && flags->subtype) {
46  FR_SBUFF_IN_STRCPY_RETURN(&our_out, fr_table_str_by_value(dict->subtype_table, flags->subtype, "?"));
47  FR_SBUFF_IN_CHAR_RETURN(&our_out, ',');
48  }
49 
50  if (flags->length) {
51  switch (type) {
52  case FR_TYPE_FIXED_SIZE:
53  /*
54  * Bit fields are in the dicts as various
55  * `uint*` types. But with special flags
56  * saying they're bit fields.
57  */
58  if (flags->extra && (flags->subtype == FLAG_BIT_FIELD)) {
59  FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "bit[%u],", flags->length);
60  }
61  break;
62 
63  default:
64  FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "length=%i,", flags->length);
65  break;
66  }
67  }
68  if (flags->extra) {
69  switch (flags->subtype) {
70  case FLAG_KEY_FIELD:
71  FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "key,");
72  break;
73 
74  case FLAG_BIT_FIELD:
75  break;
76 
77  case FLAG_LENGTH_UINT8:
78  FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "length=uint8,");
79  break;
80 
81  case FLAG_LENGTH_UINT16:
82  FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "length=uint16,");
83  break;
84 
85  default:
86  break;
87  }
88  }
89 
90  /*
91  * Print out the date precision.
92  */
93  if ((type == FR_TYPE_DATE) || (type == FR_TYPE_TIME_DELTA)) {
95  fr_table_str_by_value(fr_time_precision_table, flags->flag_time_res, "?"));
96  FR_SBUFF_IN_CHAR_RETURN(&our_out, ',');
97  if (flags->is_unsigned) FR_SBUFF_IN_CHAR_RETURN(&our_out, 'u');
98  FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "int%d", flags->length << 3);
99  }
100 
101  /*
102  * Remove trailing commas.
103  */
104  fr_sbuff_trim(&our_out, (bool[UINT8_MAX + 1]){ [','] = true });
105 
106  /*
107  * Ensure that the buffer is initialized.
108  */
109  if (fr_sbuff_used(&our_out) == 0) FR_SBUFF_IN_CHAR_RETURN(&our_out, '\0');
110 
111  FR_SBUFF_SET_RETURN(out, &our_out);
112 }
113 
114 /** Build the da_stack for the specified DA and encode the path by name in OID form
115  *
116  * @param[out] out Where to write the OID.
117  * @param[in] ancestor If not NULL, only print OID portion between ancestor and da.
118  * @param[in] da to print OID string for.
119  * @param[in] numeric print the OID components as numbers, not attribute names.
120  * @return
121  * - >0 The number of bytes written to the buffer.
122  * - <= 0 The number of bytes we would have needed to write the
123  * next OID component.
124  */
126  fr_dict_attr_t const *ancestor, fr_dict_attr_t const *da, bool numeric)
127 {
128  int i;
129  int depth = 0;
130  fr_da_stack_t da_stack;
131  fr_sbuff_t our_out = FR_SBUFF(out);
132 
133  /*
134  * If the ancestor and the DA match, there's
135  * no OID string to print.
136  */
137  if ((ancestor == da) || (da->depth == 0)) return 0;
138 
139  fr_proto_da_stack_build(&da_stack, da);
140 
141  /*
142  * We may have swapped from a known to an unknown
143  * attribute. We still print out the unknown one.
144  */
145  if (ancestor && da->flags.is_unknown) {
146  fr_assert(da->depth > ancestor->depth);
147 
148  ancestor = da_stack.da[ancestor->depth - 1];
149  }
150 
151  if (ancestor) {
152  if (da_stack.da[ancestor->depth - 1] != ancestor) {
153  fr_strerror_printf("Attribute '%s' is not a descendent of \"%s\"", da->name, ancestor->name);
154  return 0;
155  }
156  depth = ancestor->depth;
157  }
158 
159  /*
160  * We don't print the ancestor, we print the OID
161  * between it and the da.
162  */
163  if (numeric) {
164  FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", da_stack.da[depth]->attr);
165  for (i = depth + 1; i < (int)da->depth; i++) {
166  FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
167  FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", da_stack.da[i]->attr);
168  }
169  } else {
170  FR_SBUFF_IN_STRCPY_RETURN(&our_out, da_stack.da[depth]->name);
171  for (i = depth + 1; i < (int)da->depth; i++) {
172  FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
173  FR_SBUFF_IN_STRCPY_RETURN(&our_out, da_stack.da[i]->name);
174  }
175  }
176  FR_SBUFF_SET_RETURN(out, &our_out);
177 }
178 
179 typedef struct {
180  fr_dict_t const *dict;
181  char prefix[256];
182  char flags[256];
183  char oid[256];
184  unsigned int start_depth;
186 
187 static int dict_attr_debug(fr_dict_attr_t const *da, void *uctx)
188 {
189  fr_dict_attr_debug_t *our_uctx = uctx;
190  fr_hash_iter_t iter;
191  fr_dict_enum_value_t const *enumv;
193 
194  fr_dict_attr_flags_print(&FR_SBUFF_OUT(our_uctx->flags, sizeof(our_uctx->flags)),
195  our_uctx->dict, da->type, &da->flags);
196 
197  snprintf(our_uctx->prefix, sizeof(our_uctx->prefix),
198  "[%02i] 0x%016" PRIxPTR "%*s",
199  da->depth,
200  (unsigned long)da,
201  (da->depth - our_uctx->start_depth) * 4, "");
202 
203  FR_FAULT_LOG("%s%s(%u) %s %s",
204  our_uctx->prefix,
205  da->name,
206  da->attr,
207  fr_type_to_str(da->type),
208  our_uctx->flags);
209 
210  dict_attr_ext_debug(our_uctx->prefix, da); /* Print all the extension debug info */
211 
213  if (!ext || !ext->name_by_value) return 0;
214 
215  for (enumv = fr_hash_table_iter_init(ext->name_by_value, &iter);
216  enumv;
217  enumv = fr_hash_table_iter_next(ext->name_by_value, &iter)) {
218  char *value = fr_asprintf(NULL, "%pV", enumv->value);
219 
220  FR_FAULT_LOG("%s %s -> %s",
221  our_uctx->prefix,
222  enumv->name,
223  value);
225  }
226 
227  return 0;
228 }
229 
231 {
232  fr_dict_attr_debug_t uctx = { .dict = fr_dict_by_da(da), .start_depth = da->depth };
233  fr_hash_table_t *namespace;
234  fr_hash_iter_t iter;
235  fr_dict_attr_t *our_da;
236 
237  namespace = dict_attr_namespace(da);
238  if (!namespace) {
239  FR_FAULT_LOG("%s does not have namespace", da->name);
240  return;
241  }
242 
243  for (our_da = fr_hash_table_iter_init(namespace, &iter);
244  our_da;
245  our_da = fr_hash_table_iter_next(namespace, &iter)) {
246  dict_attr_debug(our_da, &uctx);
247  }
248 }
249 
251 {
252  fr_dict_attr_debug_t uctx = { .dict = fr_dict_by_da(da), .start_depth = da->depth };
253 
254  dict_attr_debug(da, &uctx);
255  (void)fr_dict_walk(da, dict_attr_debug, &uctx);
256 }
257 
259 {
261 }
262 
263 static int dict_attr_export(fr_dict_attr_t const *da, void *uctx)
264 {
265  fr_dict_attr_debug_t *our_uctx = uctx;
266 
267  (void) fr_dict_attr_oid_print(&FR_SBUFF_OUT(our_uctx->prefix, sizeof(our_uctx->prefix)),
268  NULL, da, false);
269  (void) fr_dict_attr_oid_print(&FR_SBUFF_OUT(our_uctx->oid, sizeof(our_uctx->oid)),
270  NULL, da, true);
271  *our_uctx->flags = 0; /* some attributes don't have flags */
272  fr_dict_attr_flags_print(&FR_SBUFF_OUT(our_uctx->flags, sizeof(our_uctx->flags)),
273  our_uctx->dict, da->type, &da->flags);
274 
275  FR_FAULT_LOG("ATTRIBUTE\t%-40s\t%-20s\t%s\t%s",
276  our_uctx->prefix,
277  our_uctx->oid,
278  fr_type_to_str(da->type),
279  our_uctx->flags);
280 
281  return 0;
282 }
283 
284 static void fr_dict_attr_export(fr_dict_attr_t const *da)
285 {
286  fr_dict_attr_debug_t uctx = { .dict = fr_dict_by_da(da), .start_depth = da->depth };
287 
288  dict_attr_export(da, &uctx);
289  (void)fr_dict_walk(da, dict_attr_export, &uctx);
290 }
291 
292 /** Export in the standard form: ATTRIBUTE name oid flags
293  *
294  */
296 {
298 }
static fr_dict_t * dict
Definition: fuzzer.c:46
#define RCSID(id)
Definition: build.h:444
#define FR_FAULT_LOG(_fmt,...)
Definition: debug.h:49
int fr_dict_walk(fr_dict_attr_t const *da, fr_dict_walk_t callback, void *uctx)
Definition: dict_util.c:4371
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
Definition: dict.h:145
@ FLAG_LENGTH_UINT16
string / octets type is prefixed by uint16 of length
Definition: dict.h:146
@ FLAG_KEY_FIELD
this is a key field for a subsequent struct
Definition: dict.h:143
@ FLAG_BIT_FIELD
bit field inside of a struct
Definition: dict.h:144
unsigned int extra
really "subtype is used by dict, not by protocol"
Definition: dict.h:109
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
fr_value_box_t const * value
Enum value (what name maps to).
Definition: dict.h:213
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:2203
@ FR_DICT_ATTR_EXT_ENUMV
Enumeration values.
Definition: dict.h:166
unsigned int is_unsigned
hackity hack for dates and time deltas
Definition: dict.h:94
char const * name
Enum name.
Definition: dict.h:210
uint8_t subtype
protocol-specific values, OR key fields
Definition: dict.h:118
uint8_t length
length of the attribute
Definition: dict.h:124
Values of the encryption flags.
Definition: merged_model.c:139
Value of an enumerated attribute.
Definition: dict.h:209
static void * fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
Definition: dict_ext.h:120
fr_hash_table_t * name_by_value
Lookup a name by value.
Definition: dict_ext.h:90
Attribute extension - Holds enumeration values.
Definition: dict_ext.h:87
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:180
static int dict_attr_export(fr_dict_attr_t const *da, void *uctx)
Definition: dict_print.c:263
void fr_dict_namespace_debug(fr_dict_attr_t const *da)
Definition: dict_print.c:230
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:30
void fr_dict_debug(fr_dict_t const *dict)
Definition: dict_print.c:258
static void fr_dict_attr_export(fr_dict_attr_t const *da)
Definition: dict_print.c:284
unsigned int start_depth
Definition: dict_print.c:184
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:125
#define FLAG_SET(_flag)
static int dict_attr_debug(fr_dict_attr_t const *da, void *uctx)
Definition: dict_print.c:187
void fr_dict_export(fr_dict_t const *dict)
Export in the standard form: ATTRIBUTE name oid flags.
Definition: dict_print.c:295
void fr_dict_attr_debug(fr_dict_attr_t const *da)
Definition: dict_print.c:250
Test enumeration values.
Definition: dict_test.h:92
void * fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
Initialise an iterator.
Definition: hash.c:672
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:620
Stores the state of the current iteration operation.
Definition: hash.h:41
talloc_free(reap)
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
Definition: merged_model.c:113
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
Definition: merged_model.c:111
long int ssize_t
Definition: merged_model.c:24
#define UINT8_MAX
Definition: merged_model.c:32
static size_t array[MY_ARRAY_SIZE]
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:876
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
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:2087
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str)
#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_assert(0)
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:253
fr_table_num_ordered_t const fr_time_precision_table[]
Definition: time.c:46
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition: proto.h:56
Structure for holding the stack of dictionary attributes being encoded.
Definition: proto.h:54
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
#define FR_TYPE_FIXED_SIZE
Definition: types.h:290
FR_SBUFF_SET_RETURN(sbuff, &our_sbuff)
static size_t char ** out
Definition: value.h:984