The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
pair_print.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library 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 GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /** Pair serialisation API
18  *
19  * @file src/lib/util/pair_print.c
20  *
21  * @copyright 2020 The FreeRADIUS server project
22  */
23 #include <freeradius-devel/util/pair.h>
24 #include <freeradius-devel/util/talloc.h>
25 #include <freeradius-devel/util/proto.h>
26 #include <freeradius-devel/util/pair_legacy.h>
27 
28 /** Print the value of an attribute to a string
29  *
30  * @param[in] out Where to write the string.
31  * @param[in] vp to print.
32  * @param[in] quote Char to add before and after printed value,
33  * if 0 no char will be added, if < 0 raw string
34  * will be added.
35  * @return
36  * - >= 0 length of data written to out.
37  * - <0 the number of bytes we would have needed to write
38  * the complete string to out.
39  */
41 {
42  fr_sbuff_t our_out;
43 
44  PAIR_VERIFY(vp);
45 
46  switch (vp->vp_type) {
47  /*
48  * For structural types descend down
49  */
50  case FR_TYPE_STRUCTURAL:
51  our_out = FR_SBUFF(out);
52  if (fr_pair_list_empty(&vp->vp_group)) {
53  FR_SBUFF_IN_CHAR_RETURN(&our_out, '{', ' ', '}');
54 
55  } else {
56  FR_SBUFF_IN_CHAR_RETURN(&our_out, '{', ' ');
57 
58  FR_SBUFF_RETURN(fr_pair_list_print, &our_out, vp->da, &vp->vp_group);
59 
60  FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ', '}');
61  }
62 
63  FR_SBUFF_SET_RETURN(out, &our_out);
64 
65  /*
66  * For simple types just print the box
67  */
68  default:
69  return fr_value_box_print_quoted(out, &vp->data, quote);
70  }
71 }
72 
73 /** Print one attribute and value to a string
74  *
75  * Print a fr_pair_t in the format:
76 @verbatim
77  <attribute_name> <op> <value>
78 @endverbatim
79  * to a string.
80  *
81  * @param[in] out Where to write the string.
82  * @param[in] parent If not NULL, only print OID components from
83  * this parent to the VP.
84  * @param[in] vp to print.
85  * @return
86  * - Length of data written to out.
87  * - value >= outlen on truncation.
88  */
90 {
91  char const *token = NULL;
92  fr_sbuff_t our_out = FR_SBUFF(out);
93 
94  PAIR_VERIFY(vp);
95 
96  if ((vp->op > T_INVALID) && (vp->op < T_TOKEN_LAST)) {
97  token = fr_tokens[vp->op];
98  } else {
99  token = "<INVALID-TOKEN>";
100  }
101 
102  /*
103  * Groups are printed from the root.
104  */
105  if (parent && (parent->type == FR_TYPE_GROUP)) parent = NULL;
106 
107  if (vp->vp_raw) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "raw.");
108  FR_DICT_ATTR_OID_PRINT_RETURN(&our_out, parent, vp->da, false);
109  FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ');
110  FR_SBUFF_IN_STRCPY_RETURN(&our_out, token);
111  FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ');
113 
114  FR_SBUFF_SET_RETURN(out, &our_out);
115 }
116 
117 /** Print one attribute and value to a string with escape rules
118  *
119  * Similar to fr_pair_print(), but secrets are omitted. This function duplicates parts of the functionality
120  * of fr_pair_print(). fr_pair_print_value_quoted(), and fr_value_box_print_quoted(), but for the special
121  * case of secure strings.
122  *
123  * Note that only secrets of type "string" and "octets" are omitted. Other "secret" data types are still
124  * printed as-is.
125  *
126  * "octets" are still printed as "<<< secret >>>". Which won't parse correctly, but that's fine. Because
127  * omitted data is not meant to be parsed into real data.
128  *
129  * @param[in] out Where to write the string.
130  * @param[in] parent If not NULL, only print OID components from
131  * this parent to the VP.
132  * @param[in] vp to print.
133 
134  * @return
135  * - < 0 on error
136  * - Length of data written to out.
137  * - value >= outlen on truncation.
138  */
140 {
141  char const *token = NULL;
142  fr_sbuff_t our_out = FR_SBUFF(out);
143 
144  PAIR_VERIFY(vp);
145 
146  if ((vp->op > T_INVALID) && (vp->op < T_TOKEN_LAST)) {
147  token = fr_tokens[vp->op];
148  } else {
149  token = "<INVALID-TOKEN>";
150  }
151 
152  /*
153  * Groups are printed from the root.
154  */
155  if (parent && (parent->type == FR_TYPE_GROUP)) parent = NULL;
156 
157  if (vp->vp_raw) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "raw.");
158  FR_DICT_ATTR_OID_PRINT_RETURN(&our_out, parent, vp->da, false);
159  FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ');
160  FR_SBUFF_IN_STRCPY_RETURN(&our_out, token);
161  FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ');
162 
163  if (fr_type_is_leaf(vp->vp_type)) {
164  switch (vp->vp_type) {
165  case FR_TYPE_STRING:
166  if (vp->data.secret) goto secret;
167  FALL_THROUGH;
168 
169  case FR_TYPE_DATE:
171  break;
172 
173  case FR_TYPE_OCTETS:
174  if (vp->data.secret) {
175  secret:
176  FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "<<< secret >>>");
177  break;
178  }
179  FALL_THROUGH;
180 
181  default:
182  if (fr_value_box_print(&our_out, &vp->data, NULL) < 0) return -1;
183  break;
184  }
185  } else {
186  fr_pair_t *child;
187  fr_dcursor_t cursor;
188 
189  FR_SBUFF_IN_CHAR_RETURN(&our_out, '{', ' ');
190  for (child = fr_pair_dcursor_init(&cursor, &vp->vp_group);
191  child != NULL;
192  child = fr_dcursor_next(&cursor)) {
193  FR_SBUFF_RETURN(fr_pair_print_secure, &our_out, vp->da, child);
194  if (fr_dcursor_next_peek(&cursor)) FR_SBUFF_IN_CHAR_RETURN(&our_out, ',', ' ');
195  }
196  FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ', '}');
197  }
198 
199  FR_SBUFF_SET_RETURN(out, &our_out);
200 }
201 
202 /** Print a pair list
203  *
204  * @param[in] out Where to write the string.
205  * @param[in] parent parent da to start from
206  * @param[in] list pair list
207  * @return
208  * - Length of data written to out.
209  * - value >= outlen on truncation.
210  */
212 {
213  fr_pair_t *vp;
214  fr_sbuff_t our_out = FR_SBUFF(out);
215 
216  vp = fr_pair_list_head(list);
217  if (!vp) {
219  return fr_sbuff_used(out);
220  }
221 
222  /*
223  * Groups are printed from the root.
224  */
225  if (parent && (parent->type == FR_TYPE_GROUP)) parent = NULL;
226 
227  while (true) {
228  FR_SBUFF_RETURN(fr_pair_print, &our_out, parent, vp);
229  vp = fr_pair_list_next(list, vp);
230  if (!vp) break;
231 
232  FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, ", ");
233  }
234 
235  FR_SBUFF_SET_RETURN(out, &our_out);
236 }
237 
238 static void fr_pair_list_log_sbuff(fr_log_t const *log, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, char const *file, int line, fr_sbuff_t *sbuff)
239 {
240  fr_dict_attr_t const *parent_da = NULL;
241 
242  fr_pair_list_foreach(list, vp) {
243  PAIR_VERIFY_WITH_LIST(list, vp);
244 
245  fr_sbuff_set_to_start(sbuff);
246 
247  if (vp->vp_raw) (void) fr_sbuff_in_strcpy(sbuff, "raw.");
248 
249  if (parent && (parent->vp_type != FR_TYPE_GROUP)) parent_da = parent->da;
250  if (fr_dict_attr_oid_print(sbuff, parent_da, vp->da, false) <= 0) return;
251 
252  /*
253  * Recursively print grouped attributes.
254  */
255  switch (vp->vp_type) {
256  case FR_TYPE_STRUCTURAL:
257  fr_log(log, L_DBG, file, line, "%*s%*s {", lvl * 2, "",
258  (int) fr_sbuff_used(sbuff), fr_sbuff_start(sbuff));
259  _fr_pair_list_log(log, lvl + 1, vp, &vp->vp_group, file, line);
260  fr_log(log, L_DBG, file, line, "%*s}", lvl * 2, "");
261  break;
262 
263  default:
264  (void) fr_sbuff_in_strcpy(sbuff, " = ");
266 
267  fr_log(log, L_DBG, file, line, "%*s%*s", lvl * 2, "",
268  (int) fr_sbuff_used(sbuff), fr_sbuff_start(sbuff));
269  }
270  }
271 }
272 
273 
274 /** Print a list of attributes and enumv
275  *
276  * @param[in] log to output to.
277  * @param[in] lvl depth in structural attribute.
278  * @param[in] parent parent attribute
279  * @param[in] list to print.
280  * @param[in] file where the message originated
281  * @param[in] line where the message originated
282  */
283 void _fr_pair_list_log(fr_log_t const *log, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, char const *file, int line)
284 {
285  fr_sbuff_t sbuff;
286  char buffer[1024];
287 
288  fr_sbuff_init_out(&sbuff, buffer, sizeof(buffer));
289 
290  fr_pair_list_log_sbuff(log, lvl, parent, list, file, line, &sbuff);
291 }
292 
293 /** Dumps a list to the default logging destination - Useful for calling from debuggers
294  *
295  */
297 {
298  _fr_pair_list_log(&default_log, 0, NULL, list, "<internal>", 0);
299 }
300 
301 
302 /** Dumps a pair to the default logging destination - Useful for calling from debuggers
303  *
304  */
305 void fr_pair_debug(fr_pair_t const *pair)
306 {
307  fr_sbuff_t sbuff;
308  char buffer[1024];
309 
310  fr_sbuff_init_out(&sbuff, buffer, sizeof(buffer));
311 
312  (void) fr_pair_print(&sbuff, NULL, pair);
313 
314  fr_log(&default_log, L_DBG, __FILE__, __LINE__, "%pV",
316 }
static int const char char buffer[256]
Definition: acutest.h:574
int const char * file
Definition: acutest.h:702
int const char int line
Definition: acutest.h:702
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
static void * fr_dcursor_next_peek(fr_dcursor_t *cursor)
Return the next iterator item without advancing the cursor.
Definition: dcursor.h:302
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
#define FR_DICT_ATTR_OID_PRINT_RETURN(...)
Definition: dict.h:521
fr_log_t default_log
Definition: log.c:290
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition: log.c:599
@ L_DBG
Only displayed when debugging is enabled.
Definition: log.h:59
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
Definition: merged_model.c:111
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
long int ssize_t
Definition: merged_model.c:24
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)
Definition: merged_model.c:188
void fr_pair_list_debug(fr_pair_list_t const *list)
Dumps a list to the default logging destination - Useful for calling from debuggers.
Definition: pair_print.c:296
static void fr_pair_list_log_sbuff(fr_log_t const *log, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, char const *file, int line, fr_sbuff_t *sbuff)
Definition: pair_print.c:238
void _fr_pair_list_log(fr_log_t const *log, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, char const *file, int line)
Print a list of attributes and enumv.
Definition: pair_print.c:283
ssize_t fr_pair_print(fr_sbuff_t *out, fr_dict_attr_t const *parent, fr_pair_t const *vp)
Print one attribute and value to a string.
Definition: pair_print.c:89
ssize_t fr_pair_print_secure(fr_sbuff_t *out, fr_dict_attr_t const *parent, fr_pair_t const *vp)
Print one attribute and value to a string with escape rules.
Definition: pair_print.c:139
void fr_pair_debug(fr_pair_t const *pair)
Dumps a pair to the default logging destination - Useful for calling from debuggers.
Definition: pair_print.c:305
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
Definition: pair_print.c:40
ssize_t fr_pair_list_print(fr_sbuff_t *out, fr_dict_attr_t const *parent, fr_pair_list_t const *list)
Print a pair list.
Definition: pair_print.c:211
static char * secret
Definition: radclient-ng.c:69
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition: sbuff.c:1419
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str)
#define fr_sbuff_init_out(_out, _start, _len_or_end)
#define FR_SBUFF_RETURN(_func, _sbuff,...)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_IN_STRCPY_RETURN(...)
if(!subtype_vp) goto fail
fr_pair_t * vp
Definition: log.h:96
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
char const * fr_tokens[T_TOKEN_LAST]
Definition: token.c:78
enum fr_token fr_token_t
@ T_INVALID
Definition: token.h:39
@ T_DOUBLE_QUOTED_STRING
Definition: token.h:121
#define T_TOKEN_LAST
Definition: token.h:129
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition: pair_inline.c:43
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
Definition: pair_inline.c:125
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition: pair_inline.c:70
#define PAIR_VERIFY(_x)
Definition: pair.h:190
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition: pair.h:260
#define PAIR_VERIFY_WITH_LIST(_l, _x)
Definition: pair.h:191
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:590
static fr_slen_t parent
Definition: pair.h:844
#define FR_TYPE_STRUCTURAL
Definition: types.h:296
#define fr_type_is_leaf(_x)
Definition: types.h:372
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition: value.c:5301
ssize_t fr_value_box_print_quoted(fr_sbuff_t *out, fr_value_box_t const *data, fr_token_t quote)
Print one boxed value to a string with quotes (where needed)
Definition: value.c:5489
FR_SBUFF_SET_RETURN(sbuff, &our_sbuff)
#define fr_box_strvalue_len(_val, _len)
Definition: value.h:279
static size_t char ** out
Definition: value.h:984