The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
xlat_alloc.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: c08ae80128a212f2f942f8e78b058aef654da43f $
19 *
20 * @file xlat_alloc.c
21 * @brief Functions to allocate different types of xlat nodes
22 */
23
24RCSID("$Id: c08ae80128a212f2f942f8e78b058aef654da43f $")
25
26#include <freeradius-devel/server/base.h>
27
28
29#define _XLAT_PRIVATE
30#include <freeradius-devel/unlang/xlat_priv.h>
31
33{
35
36 MEM(head = talloc_zero(ctx, xlat_exp_head_t));
37
38 fr_dlist_init(&head->dlist, xlat_exp_t, entry);
39 head->flags = XLAT_FLAGS_INIT;
40#ifndef NDEBUG
41 head->file = file;
42 head->line = line;
43#endif
44
45 return head;
46}
47
48/** Set the type of an xlat node
49 *
50 * Also initialises any xlat_exp_head necessary
51 *
52 * @param[in] node to set type for.
53 * @param[in] type to set.
54 */
56{
57 /*
58 * Do nothing if it's the same type
59 */
60 if (node->type == type) return;
61
62 /*
63 * Free existing lists if present
64 */
65 if (node->type != 0) switch (node->type) {
66 case XLAT_GROUP:
67 TALLOC_FREE(node->group);
68 break;
69
71 if (type == XLAT_FUNC) goto done; /* Just switching from unresolved to resolved */
73
74 case XLAT_FUNC:
75 TALLOC_FREE(node->call.args);
76 break;
77
78 case XLAT_TMPL:
79 if (node->vpt && (node->fmt == node->vpt->name)) (void) talloc_steal(node, node->fmt);
80
81 /*
82 * Converting a tmpl to a box. If the tmpl is data, we can then just steal the contents
83 * of the box.
84 */
85 if (type == XLAT_BOX) {
86 tmpl_t *vpt = node->vpt;
87
88 if (!vpt) break;
89
91
92 if (!tmpl_is_data(vpt)) {
94 break;
95 }
96
97 /*
98 * Initialize the box from the tmpl data. And then do NOT re-initialize the box
99 * later.
100 */
101 node->flags = XLAT_FLAGS_INIT;
102 fr_value_box_steal(node, &node->data, tmpl_value(vpt));
104 goto done;
105 }
106
107 TALLOC_FREE(node->vpt);
108 break;
109
110 default:
111 break;
112 }
113
114 /*
115 * Alloc new lists to match the type
116 */
117 switch (type) {
118 case XLAT_GROUP:
119 node->group = _xlat_exp_head_alloc(NDEBUG_LOCATION_VALS node);
120 node->flags = node->group->flags;
121 break;
122
123 case XLAT_FUNC:
124 node->flags = XLAT_FLAGS_INIT;
125 break;
126
128 node->flags = XLAT_FLAGS_INIT;
129 node->flags.needs_resolving = true;
130 break;
131
132 case XLAT_BOX:
133 node->flags = XLAT_FLAGS_INIT;
134 fr_value_box_init_null(&node->data);
135 break;
136
137#ifdef HAVE_REGEX
138 case XLAT_REGEX:
139 node->flags = (xlat_flags_t) {};
140 break;
141#endif
142
143 case XLAT_ONE_LETTER:
144 /*
145 * %% is pure. Everything else is not.
146 */
147 fr_assert(node->fmt);
148
149 if (node->fmt[0] != '%') {
150 node->flags = (xlat_flags_t) {};
151 } else {
152 node->flags = XLAT_FLAGS_INIT;
153 }
154 break;
155
156 default:
157 node->flags = XLAT_FLAGS_INIT;
158 break;
159 }
160
161done:
162 node->type = type;
163}
164
165static xlat_exp_t *xlat_exp_alloc_pool(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, unsigned int extra_hdrs, size_t extra)
166{
167 xlat_exp_t *node;
168
169 MEM(node = talloc_zero_pooled_object(ctx, xlat_exp_t, extra_hdrs, extra));
170 node->flags = XLAT_FLAGS_INIT;
171 node->quote = T_BARE_WORD;
172#ifndef NDEBUG
173 node->file = file;
174 node->line = line;
175#endif
176
177 return node;
178}
179
180/** Allocate an xlat node with no name, and no type set
181 *
182 * @param[in] ctx to allocate node in.
183 * @return A new xlat node.
184 */
189
190/** Allocate an xlat node
191 *
192 * @param[in] ctx to allocate node in.
193 * @param[in] type of the node.
194 * @param[in] in original input string.
195 * @param[in] inlen the length of the original input string.
196 * @return A new xlat node.
197 */
199{
200 xlat_exp_t *node;
201 unsigned int extra_hdrs;
202 size_t extra;
203
204 /*
205 * Figure out how much extra memory we
206 * need to allocate for this node type.
207 */
208 switch (type) {
209 case XLAT_GROUP:
210 extra_hdrs = 1;
211 extra = sizeof(xlat_exp_head_t);
212 break;
213
214 case XLAT_FUNC:
215 extra_hdrs = 1;
216 extra = sizeof(xlat_exp_head_t);
217 break;
218
219 default:
220 extra_hdrs = 0;
221 extra = 0;
222 }
223
225 ctx,
226 (in != NULL) + extra_hdrs,
227 inlen + extra);
229
230 node->quote = T_BARE_WORD; /* ensure that this is always initialized */
231
232 if (!in) return node;
233
234 node->fmt = talloc_bstrndup(node, in, inlen);
235 switch (type) {
236 case XLAT_BOX:
237 fr_value_box_strdup_shallow(&node->data, NULL, node->fmt, false);
238 break;
239
240 default:
241 break;
242 }
243
244 return node;
245}
246
247/** Set the tmpl for a node, along with flags and the name.
248 *
249 * @param[in] node to set fmt for.
250 * @param[in] vpt the tmpl to set
251 */
253{
254 if (tmpl_contains_xlat(vpt)) {
255 node->flags = tmpl_xlat(vpt)->flags;
256 }
257
259 node->flags = (xlat_flags_t) {};
260 }
261
263
264 node->vpt = vpt;
265 xlat_exp_set_name_shallow(node, vpt->name);
266}
267
268/** Set the function for a node
269 *
270 * @param[in] node to set fmt for.
271 * @param[in] func to set
272 * @param[in] dict the dictionary to set
273 */
274void xlat_exp_set_func(xlat_exp_t *node, xlat_t const *func, fr_dict_t const *dict)
275{
276 node->call.func = func;
277 node->call.dict = dict;
278 node->flags = func->flags;
279 node->flags.impure_func = !func->flags.pure;
280
281 if (!dict) node->flags.needs_resolving = true;
282}
283
285{
286 if (!node->call.args) return;
287
288 node->call.args->is_argv = true;
289
290 if (node->type == XLAT_FUNC_UNRESOLVED) return;
291
292 xlat_flags_merge(&node->flags, &node->call.args->flags);
293
294 /*
295 * We might not be able to purify the function call, but perhaps we can purify the arguments to it.
296 */
297 node->flags.can_purify = (node->call.func->flags.pure && node->call.args->flags.pure) | node->call.args->flags.can_purify;
298 node->flags.impure_func = !node->call.func->flags.pure;
299}
300
301
302/** Set the format string for an xlat node
303 *
304 * @param[in] node to set fmt for.
305 * @param[in] fmt talloced buffer to set as the fmt string.
306 * @param[in] len of fmt string.
307 */
308void xlat_exp_set_name(xlat_exp_t *node, char const *fmt, size_t len)
309{
310 fr_assert(node->fmt != fmt);
311
312 if (node->fmt) talloc_const_free(node->fmt);
313 MEM(node->fmt = talloc_bstrndup(node, fmt, len));
314}
315
316/** Set the format string for an xlat node, copying from a talloc'd buffer
317 *
318 * @param[in] node to set fmt for.
319 * @param[in] fmt talloced buffer to set as the fmt string.
320 */
322{
323 if (node->fmt) {
324 if (node->fmt == fmt) {
325 (void) talloc_steal(node, fmt);
326 } else {
327 talloc_const_free(node->fmt);
328 }
329 }
330 MEM(node->fmt = talloc_typed_strdup_buffer(node, fmt));
331}
332
333/** Set the format string for an xlat node from a pre-existing buffer
334 *
335 * @param[in] node to set fmt for.
336 * @param[in] fmt talloced buffer to set as the fmt string.
337 */
339{
340 fr_assert(node->fmt != fmt);
341
342 if (node->fmt) talloc_const_free(node->fmt);
343 node->fmt = talloc_get_type_abort_const(fmt, char);
344}
345
346/** Copy all nodes in the input list to the output list
347 *
348 * @param[in] ctx to allocate new nodes in.
349 * @param[out] out Where to write new nodes.
350 * @param[in] in Input nodes.
351 * @return
352 * - 0 on success.
353 * - -1 on failure.
354 */
356{
357 xlat_exp_head_t *head = NULL;
358
359 xlat_flags_merge(&out->flags, &in->flags);
360
361 /*
362 * Copy everything in the list of nodes
363 */
364 xlat_exp_foreach(in, p) {
365 xlat_exp_t *node;
366
367 (void)talloc_get_type_abort(p, xlat_exp_t);
368
369 /*
370 * Ensure the format string is valid... At this point
371 * they should all be talloc'd strings.
372 */
373 MEM(node = xlat_exp_alloc(ctx, p->type,
374 talloc_get_type_abort_const(p->fmt, char), talloc_array_length(p->fmt) - 1));
375
376 node->quote = p->quote;
377 node->flags = p->flags;
378
379 switch (p->type) {
380 case XLAT_INVALID:
381 fr_strerror_printf("Cannot copy xlat node of type \"invalid\"");
382 error:
384 return -1;
385
386 case XLAT_BOX:
387 if (unlikely(fr_value_box_copy(node, &node->data, &p->data) < 0)) goto error;
388 break;
389
390 case XLAT_ONE_LETTER: /* Done with format */
392 break;
393
394 case XLAT_FUNC:
395 /*
396 * Only copy the function pointer, and whether this
397 * is ephemeral.
398 *
399 * All instance data is specific to the xlat node and
400 * cannot be duplicated.
401 *
402 * The node xlat nodes will need to be registered in
403 * the xlat instantiation table later.
404 */
405 node->call.func = p->call.func;
406 node->call.dict = p->call.dict;
407 node->call.ephemeral = p->call.ephemeral;
409 node, node->call.args, p->call.args) < 0)) goto error;
410 break;
411
412 case XLAT_TMPL:
413 node->vpt = tmpl_copy(node, p->vpt);
414 break;
415
416#ifdef HAVE_REGEX
417 case XLAT_REGEX:
418 node->regex_index = p->regex_index;
419 break;
420#endif
421
422 case XLAT_GROUP:
424 node, node->group, p->group) < 0)) goto error;
425 break;
426 }
427
429 }
430
431 return 0;
432}
433
435{
436 int ret;
437
438 if (!in) return 0;
439
443
444 return ret;
445}
446
447#ifdef WITH_VERIFY_PTR
448void xlat_exp_verify(xlat_exp_t const *node)
449{
451
452 switch (node->type) {
453 case XLAT_GROUP:
454 xlat_exp_head_verify(node->group);
455 (void)talloc_get_type_abort_const(node->fmt, char);
456 return;
457
458 case XLAT_FUNC:
459 fr_assert(node->call.args->is_argv);
460
461 xlat_exp_foreach(node->call.args, arg) {
462 fr_assert(arg->type == XLAT_GROUP);
463
464 /*
465 * We can't do this yet, because the old function argument parser doesn't do the
466 * right thing.
467 */
468// fr_assert(arg->quote == T_BARE_WORD);
469 }
470
471 xlat_exp_head_verify(node->call.args);
472 (void)talloc_get_type_abort_const(node->fmt, char);
473 return;
474
475 case XLAT_TMPL: {
476 tmpl_t const *vpt = node->vpt;
477
478 if (node->quote != node->vpt->quote) {
479 if (node->vpt->quote == T_SOLIDUS_QUOTED_STRING) {
480 /*
481 * m'foo' versus /foo/
482 */
483 fr_assert(node->quote != T_BARE_WORD);
484 } else {
485 /*
486 * Mismatching quotes are bad.
487 */
488 fr_assert(node->quote == T_BARE_WORD);
489 }
490 }
491
492 if (tmpl_is_attr(vpt)) {
493 fr_dict_attr_t const *da;
494 da = tmpl_attr_tail_da(node->vpt);
495
496 if (tmpl_rules_cast(node->vpt) != FR_TYPE_NULL) {
497 /*
498 * Casts must be omitted, unless we're using a cast as a way to get rid
499 * of enum names.
500 */
501 if (tmpl_rules_cast(node->vpt) == da->type) {
502 fr_assert(da->flags.has_value);
503 }
504
505 } else if (node->quote != T_BARE_WORD) {
506 fr_assert(da->type != FR_TYPE_STRING);
507 }
508
509 return;
510 }
511
512 /*
513 * Casts should have been hoisted.
514 */
515 if (tmpl_is_data(node->vpt)) {
517 }
518
519#if 0
520 /*
521 * @todo - xlats SHOULD have been hoisted, unless they're quoted or cast.
522 */
523 if (tmpl_is_xlat(node->vpt)) {
524 fr_assert((node->vpt->quote != T_BARE_WORD) ||
525 (tmpl_rules_cast(node->vpt) != FR_TYPE_NULL));
526 return;
527 }
528#endif
529
530 if (tmpl_is_exec(node->vpt) || tmpl_is_exec_unresolved(node->vpt)) {
532 fr_assert(!node->flags.constant);
533 fr_assert(!node->flags.pure);
534 fr_assert(!node->flags.can_purify);
535 }
536
537 return;
538 }
539
540 case XLAT_BOX:
541 fr_assert(node->flags.constant);
542 fr_assert(node->flags.pure);
543// fr_assert(node->flags.can_purify);
544 break;
545
546 default:
547 break;
548 }
549}
550
551/** Performs recursive validation of node lists
552 */
553void xlat_exp_head_verify(xlat_exp_head_t const *head)
554{
556
557 xlat_exp_foreach(head, node) xlat_exp_verify(node);
558}
559#endif
int const char * file
Definition acutest.h:702
static int const char * fmt
Definition acutest.h:573
int const char int line
Definition acutest.h:702
#define RCSID(id)
Definition build.h:485
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define unlikely(_x)
Definition build.h:383
#define NDEBUG_LOCATION_VALS
Definition build.h:264
#define NDEBUG_LOCATION_ARGS
Pass caller information to the function.
Definition build.h:263
#define MEM(x)
Definition debug.h:36
static fr_slen_t in
Definition dict.h:833
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:260
talloc_free(reap)
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
#define tmpl_contains_xlat(vpt)
Definition tmpl.h:227
#define tmpl_is_xlat(vpt)
Definition tmpl.h:210
#define tmpl_value(_tmpl)
Definition tmpl.h:937
#define tmpl_is_attr(vpt)
Definition tmpl.h:208
#define tmpl_is_exec(vpt)
Definition tmpl.h:211
#define tmpl_is_exec_unresolved(vpt)
Definition tmpl.h:218
#define tmpl_xlat(_tmpl)
Definition tmpl.h:930
#define tmpl_rules_cast(_tmpl)
Definition tmpl.h:942
#define tmpl_contains_attr(vpt)
Definition tmpl.h:225
tmpl_t * tmpl_copy(TALLOC_CTX *ctx, tmpl_t const *in)
Copy a tmpl.
#define tmpl_is_data(vpt)
Definition tmpl.h:206
static fr_slen_t vpt
Definition tmpl.h:1269
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:801
#define tmpl_needs_resolving(vpt)
Definition tmpl.h:223
fr_aka_sim_id_type_t type
char * talloc_typed_strdup_buffer(TALLOC_CTX *ctx, char const *p)
Call talloc_strndup, setting the type on the new chunk correctly.
Definition talloc.c:465
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:560
#define talloc_get_type_abort_const
Definition talloc.h:282
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:177
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:224
@ T_BARE_WORD
Definition token.h:120
@ T_BACK_QUOTED_STRING
Definition token.h:123
@ T_SOLIDUS_QUOTED_STRING
Definition token.h:124
#define XLAT_HEAD_VERIFY(_head)
Definition xlat.h:463
#define XLAT_FLAGS_INIT
Definition xlat.h:117
static fr_slen_t head
Definition xlat.h:416
uint8_t needs_resolving
Needs pass2 resolution.
Definition xlat.h:108
uint8_t can_purify
if the xlat has a pure function with pure arguments.
Definition xlat.h:111
uint8_t pure
has no external side effects, true for BOX, LITERAL, and some functions
Definition xlat.h:109
uint8_t impure_func
xlat contains an impure function
Definition xlat.h:110
uint8_t constant
xlat is just tmpl_attr_tail_data, or XLAT_BOX
Definition xlat.h:113
Flags that control resolution and evaluation.
Definition xlat.h:107
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition value.c:3963
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
Definition value.c:4270
int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
Copy value data verbatim moving any buffers to the specified context.
Definition value.c:4092
#define fr_value_box_init_null(_vb)
Initialise an empty/null box that will be filled later.
Definition value.h:604
static size_t char fr_sbuff_t size_t inlen
Definition value.h:1012
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1012
xlat_exp_head_t * _xlat_exp_head_alloc(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx)
Definition xlat_alloc.c:32
void xlat_exp_finalize_func(xlat_exp_t *node)
Definition xlat_alloc.c:284
void xlat_exp_set_vpt(xlat_exp_t *node, tmpl_t *vpt)
Set the tmpl for a node, along with flags and the name.
Definition xlat_alloc.c:252
xlat_exp_t * _xlat_exp_alloc(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, xlat_type_t type, char const *in, size_t inlen)
Allocate an xlat node.
Definition xlat_alloc.c:198
void xlat_exp_set_name(xlat_exp_t *node, char const *fmt, size_t len)
Set the format string for an xlat node.
Definition xlat_alloc.c:308
void xlat_exp_set_name_buffer(xlat_exp_t *node, char const *fmt)
Set the format string for an xlat node, copying from a talloc'd buffer.
Definition xlat_alloc.c:321
xlat_exp_t * _xlat_exp_alloc_null(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx)
Allocate an xlat node with no name, and no type set.
Definition xlat_alloc.c:185
int _xlat_copy(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, xlat_exp_head_t *out, xlat_exp_head_t const *in)
Definition xlat_alloc.c:434
void xlat_exp_set_func(xlat_exp_t *node, xlat_t const *func, fr_dict_t const *dict)
Set the function for a node.
Definition xlat_alloc.c:274
static xlat_exp_t * xlat_exp_alloc_pool(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, unsigned int extra_hdrs, size_t extra)
Definition xlat_alloc.c:165
void xlat_exp_set_name_shallow(xlat_exp_t *node, char const *fmt)
Set the format string for an xlat node from a pre-existing buffer.
Definition xlat_alloc.c:338
static int _xlat_copy_internal(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, xlat_exp_head_t *out, xlat_exp_head_t const *in)
Copy all nodes in the input list to the output list.
Definition xlat_alloc.c:355
void _xlat_exp_set_type(NDEBUG_LOCATION_ARGS xlat_exp_t *node, xlat_type_t type)
Set the type of an xlat node.
Definition xlat_alloc.c:55
struct xlat_exp_head_s xlat_exp_head_t
Definition xlat_ctx.h:36
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition xlat_priv.h:154
int line
Line where the xlat was allocated.
Definition xlat_priv.h:159
fr_token_t quote
Type of quoting around XLAT_GROUP types.
Definition xlat_priv.h:152
xlat_type_t
Definition xlat_priv.h:106
@ XLAT_ONE_LETTER
Special "one-letter" expansion.
Definition xlat_priv.h:109
@ XLAT_BOX
fr_value_box_t
Definition xlat_priv.h:108
@ XLAT_TMPL
xlat attribute
Definition xlat_priv.h:112
@ XLAT_FUNC
xlat module
Definition xlat_priv.h:110
@ XLAT_GROUP
encapsulated string of xlats
Definition xlat_priv.h:116
@ XLAT_FUNC_UNRESOLVED
func needs resolution during pass2.
Definition xlat_priv.h:111
@ XLAT_INVALID
Bad expansion.
Definition xlat_priv.h:107
static void xlat_flags_merge(xlat_flags_t *parent, xlat_flags_t const *child)
Merge flags from child to parent.
Definition xlat_priv.h:228
char const *_CONST fmt
The original format string (a talloced buffer).
Definition xlat_priv.h:151
xlat_type_t _CONST type
type of this expansion.
Definition xlat_priv.h:155
char const *_CONST file
File where the xlat was allocated.
Definition xlat_priv.h:158
#define xlat_exp_alloc(_ctx, _type, _in, _inlen)
Definition xlat_priv.h:281
xlat_flags_t flags
various flags
Definition xlat_priv.h:92
#define xlat_exp_foreach(_list_head, _iter)
Iterate over the contents of a list, only one level.
Definition xlat_priv.h:221
static int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
Definition xlat_priv.h:237
An xlat expansion node.
Definition xlat_priv.h:148