Coverage Report

Created: 2026-05-11 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/lib/unlang/xlat_priv.h
Line
Count
Source
1
#pragma once
2
/*
3
 *   This program is free software; you can redistribute it and/or modify
4
 *   it under the terms of the GNU General Public License as published by
5
 *   the Free Software Foundation; either version 2 of the License, or
6
 *   (at your option) any later version.
7
 *
8
 *   This program is distributed in the hope that it will be useful,
9
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 *   GNU General Public License for more details.
12
 *
13
 *   You should have received a copy of the GNU General Public License
14
 *   along with this program; if not, write to the Free Software
15
 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16
 */
17
18
/**
19
 * $Id: 78ae83297f879229ffdaf1a777d8b0e7f4bd5eef $
20
 *
21
 * @file src/lib/unlang/xlat_priv.h
22
 * @brief String expansion ("translation"). Implements %Attribute -> value
23
 *
24
 * Private structures for the xlat tokenizer and xlat eval code.
25
 *
26
 * @copyright 2000,2006 The FreeRADIUS server project
27
 * @copyright 2000 Alan DeKok (aland@freeradius.org)
28
 */
29
#ifdef __cplusplus
30
extern "C" {
31
#endif
32
33
#include <freeradius-devel/unlang/xlat_ctx.h>
34
#include <freeradius-devel/unlang/xlat.h>
35
#include <freeradius-devel/unlang/xlat_func.h>
36
#include <freeradius-devel/server/module_ctx.h>
37
#include <freeradius-devel/io/pair.h>
38
#include <freeradius-devel/util/talloc.h>
39
#include <freeradius-devel/build.h>
40
41
#ifdef DEBUG_XLAT
42
#  define XLAT_DEBUG RDEBUG3
43
#else
44
#  define XLAT_DEBUG(...)
45
#endif
46
47
/*
48
 *  Allow public and private versions of the same structures
49
 */
50
#ifdef _CONST
51
#  error _CONST can only be defined in the local header
52
#endif
53
#ifndef _XLAT_PRIVATE
54
#  define _CONST const
55
#else
56
#  define _CONST
57
#endif
58
59
typedef struct xlat_s {
60
  fr_rb_node_t    func_node;    //!< Entry in the xlat function tree.
61
  fr_dlist_t    mi_entry;   //!< Entry in the list of functions
62
              ///< registered to a module instance.
63
64
  char const    *name;      //!< Name of xlat function.
65
  xlat_func_t   func;     //!< async xlat function (async unsafe).
66
67
  bool      internal;   //!< If true, cannot be redefined.
68
  bool      deprecated;   //!< this function was deprecated
69
  char const    *replaced_with;   //!< this function was replaced with something else
70
  fr_token_t    token;      //!< for expressions
71
72
  module_inst_ctx_t *mctx;      //!< Original module instantiation ctx if this
73
              ///< xlat was registered by a module.
74
75
  xlat_instantiate_t  instantiate;    //!< Instantiation function.
76
  xlat_detach_t   detach;     //!< Destructor for when xlat instances are freed.
77
  char const    *inst_type;   //!< C type of instance structure.
78
  size_t      inst_size;    //!< Size of instance data to pre-allocate.
79
  void      *uctx;      //!< uctx to pass to instantiation functions.
80
81
  xlat_thread_instantiate_t thread_instantiate; //!< Thread instantiation function.
82
  xlat_thread_detach_t  thread_detach;    //!< Destructor for when xlat thread instance data
83
              ///< is freed.
84
  char const    *thread_inst_type;  //!< C type of thread instance structure.
85
  size_t      thread_inst_size; //!< Size of the thread instance data to pre-allocate.
86
  void      *thread_uctx;   //!< uctx to pass to instantiation functions.
87
88
  xlat_print_t    print;      //!< function to call when printing
89
  xlat_resolve_t    resolve;          //!< function to call when resolving
90
  xlat_purify_t   purify;     //!< function to call when purifying the node.
91
92
  xlat_flags_t    flags;      //!< various flags
93
94
  xlat_arg_parser_t const *args;      //!< Definition of args consumed.
95
96
  call_env_method_t const *call_env_method; //!< Optional tmpl expansions performed before calling the
97
              ///< xlat.  Typically used for xlats which refer to tmpls
98
              ///< in their module config.
99
100
  fr_value_box_safe_for_t return_safe_for;  //!< Escaped value to set in output boxes.
101
  fr_type_t   return_type;    //!< Function is guaranteed to return one or more boxes
102
              ///< of this type.  If the return type is FR_TYPE_VOID
103
              ///< then the xlat function can return any type of output.
104
} xlat_t;
105
106
typedef enum {
107
  XLAT_INVALID    = 0x0000,   //!< Bad expansion
108
  XLAT_BOX    = 0x0001,   //!< #fr_value_box_t
109
  XLAT_ONE_LETTER   = 0x0002,   //!< Special "one-letter" expansion
110
  XLAT_FUNC   = 0x0004,   //!< xlat module
111
  XLAT_FUNC_UNRESOLVED  = 0x0008,   //!< func needs resolution during pass2.
112
  XLAT_TMPL   = 0x0010,   //!< xlat attribute
113
#ifdef HAVE_REGEX
114
  XLAT_REGEX    = 0x0020,   //!< regex reference %{1}, etc.
115
#endif
116
  XLAT_GROUP    = 0x0100    //!< encapsulated string of xlats
117
} xlat_type_t;
118
119
/** An xlat function call
120
 *
121
 */
122
typedef struct {
123
  uint64_t    id;     //!< Identifier unique to each permanent xlat node.
124
              ///< This is used by the instantiation code to order
125
              ///< nodes by the time they were created.
126
127
  xlat_t const    *func;      //!< The xlat expansion to expand format with.
128
  xlat_exp_head_t   *args;      //!< arguments to the function call
129
130
  fr_dict_t const   *dict;      //!< Records the namespace this xlat call was created in.
131
              ///< Used by the purify code to run fake requests in
132
              ///< the correct namespace, and accessible to instantiation
133
              ///< functions in case the xlat needs to perform runtime
134
              ///< resolution of attributes (as with %eval()).
135
136
  xlat_inst_t   *inst;      //!< Instance data for the #xlat_t.
137
  xlat_thread_inst_t  *thread_inst;   //!< Thread specific instance.
138
              ///< ONLY USED FOR EPHEMERAL XLATS.
139
140
  bool      ephemeral;    //!< Instance data is ephemeral (not inserted)
141
              ///< into the instance tree.
142
} xlat_call_t;
143
144
/** An xlat expansion node
145
 *
146
 * These nodes form a tree which represents one or more nested expansions.
147
 */
148
struct xlat_exp_s {
149
  fr_dlist_t    entry;
150
151
  char const *  _CONST  fmt;    //!< The original format string (a talloced buffer).
152
  fr_token_t    quote;    //!< Type of quoting around XLAT_GROUP types.
153
154
  xlat_flags_t    flags;    //!< Flags that control resolution and evaluation.
155
  xlat_type_t _CONST  type;   //!< type of this expansion.
156
157
#ifndef NDEBUG
158
  char const * _CONST file;   //!< File where the xlat was allocated.
159
  int     line;   //!< Line where the xlat was allocated.
160
#endif
161
162
  union {
163
    struct {
164
      xlat_exp_head_t *group;   //!< children of a group
165
      unsigned int    hoist : 1;  //!< it's a group, but we need to hoist the results
166
    };
167
168
    /** An tmpl_t reference
169
     *
170
     * May be an attribute to expand, or an exec reference, or a value-box, ...
171
     */
172
    tmpl_t    *vpt;
173
174
    /** A capture group, i.e. for %{1} and friends
175
     */
176
    int   regex_index;
177
178
    /** An xlat function call
179
     */
180
    xlat_call_t call;
181
182
    /** A value box
183
     */
184
    fr_value_box_t  data;
185
  };
186
};
187
188
struct xlat_exp_head_s {
189
  fr_dlist_head_t   dlist;
190
  xlat_flags_t    flags;    //!< Flags that control resolution and evaluation.
191
  unsigned int    instantiated : 1;  //!< temporary flag until we fix more things
192
  unsigned int    is_argv : 1;  //!< this thing holds function arguments
193
  unsigned int    cursor : 1; //!< otherwise it's too hard to pass xlat_arg_parser_t to the evaluation function.
194
  unsigned int    is_attr : 1;  //!< the argument is an attribute reference
195
196
#ifndef NDEBUG
197
  char const * _CONST file;   //!< File where the xlat was allocated.
198
  int     line;   //!< Line where the xlat was allocated.
199
#endif
200
};
201
202
typedef struct {
203
  char const    *out;   //!< Output data.
204
  size_t      len;    //!< Length of the output string.
205
} xlat_out_t;
206
/*
207
 *  Helper functions
208
 */
209
210
static inline xlat_exp_t *xlat_exp_head(xlat_exp_head_t const *head)
211
0
{
212
0
  if (!head) return NULL;
213
0
214
0
  return fr_dlist_head(&head->dlist);
215
0
}
Unexecuted instantiation: foreach.c:xlat_exp_head
Unexecuted instantiation: switch.c:xlat_exp_head
216
217
/** Iterate over the contents of a list, only one level
218
 *
219
 * @param[in] _list_head  to iterate over.
220
 * @param[in] _iter   Name of iteration variable.
221
 *        Will be declared in the scope of the loop.
222
 */
223
#define xlat_exp_foreach(_list_head, _iter) fr_dlist_foreach(&((_list_head)->dlist), xlat_exp_t, _iter)
224
225
/** Merge flags from child to parent
226
 *
227
 * For pass2, if either the parent or child is marked up for pass2, then the parent
228
 * is marked up for pass2.
229
 */
230
static inline CC_HINT(nonnull) void xlat_flags_merge(xlat_flags_t *parent, xlat_flags_t const *child)
231
0
{
232
0
  parent->needs_resolving |= child->needs_resolving;
233
0
  parent->pure &= child->pure; /* purity can only be removed, never added */
234
0
  parent->can_purify |= child->can_purify; /* there is SOME node under us which can be purified */
235
0
  parent->constant &= child->constant;
236
0
  parent->impure_func |= child->impure_func;
237
0
}
Unexecuted instantiation: foreach.c:xlat_flags_merge
Unexecuted instantiation: switch.c:xlat_flags_merge
238
239
static inline CC_HINT(nonnull) int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
240
0
{
241
0
  XLAT_VERIFY(node);
242
0
243
0
  xlat_flags_merge(&head->flags, &node->flags);
244
0
  return fr_dlist_insert_tail(&head->dlist, node);
245
0
}
Unexecuted instantiation: foreach.c:xlat_exp_insert_tail
Unexecuted instantiation: switch.c:xlat_exp_insert_tail
246
247
static inline xlat_exp_t *xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t const *node)
248
0
{
249
0
  if (!head) return NULL;
250
0
251
0
  return fr_dlist_next(&head->dlist, node);
252
0
}
Unexecuted instantiation: foreach.c:xlat_exp_next
Unexecuted instantiation: switch.c:xlat_exp_next
253
254
/*
255
 *  xlat_purify.c
256
 */
257
int xlat_purify_list(xlat_exp_head_t *head, request_t *request);
258
259
/** Walker callback for xlat_walk()
260
 *
261
 * @param[in] exp being evaluated.
262
 * @param[in] uctx  passed to xlat_walk.
263
 * @return
264
 *  - 1 for "prune walk here".
265
 *  - 0 on success.
266
 *  - <0 if node evaluation failed.  Causes xlat_walk to return the negative integer.
267
 */
268
typedef int (*xlat_walker_t)(xlat_exp_t *exp, void *uctx);
269
270
/*
271
 *  xlat_alloc.c
272
 */
273
xlat_exp_head_t *_xlat_exp_head_alloc(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx);
274
#define   xlat_exp_head_alloc(_ctx) _xlat_exp_head_alloc(NDEBUG_LOCATION_EXP _ctx)
275
276
void    _xlat_exp_set_type(NDEBUG_LOCATION_ARGS xlat_exp_t *node, xlat_type_t type);
277
#define   xlat_exp_set_type(_node, _type) _xlat_exp_set_type(NDEBUG_LOCATION_EXP _node, _type)
278
279
xlat_exp_t  *_xlat_exp_alloc_null(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx);
280
#define   xlat_exp_alloc_null(_ctx) _xlat_exp_alloc_null(NDEBUG_LOCATION_EXP _ctx)
281
282
xlat_exp_t  *_xlat_exp_alloc(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, xlat_type_t type, char const *in, size_t inlen);
283
#define   xlat_exp_alloc(_ctx, _type, _in, _inlen) _xlat_exp_alloc(NDEBUG_LOCATION_EXP _ctx, _type, _in, _inlen)
284
285
void    xlat_exp_set_name(xlat_exp_t *node, char const *fmt, size_t len) CC_HINT(nonnull);
286
void    xlat_exp_set_name_shallow(xlat_exp_t *node, char const *fmt) CC_HINT(nonnull);
287
void    xlat_exp_set_name_buffer(xlat_exp_t *node, char const *fmt) CC_HINT(nonnull);
288
289
void    xlat_exp_set_vpt(xlat_exp_t *node, tmpl_t *vpt) CC_HINT(nonnull);
290
void    xlat_exp_set_func(xlat_exp_t *node, xlat_t const *func, fr_dict_t const *dict) CC_HINT(nonnull(1,2));
291
void    xlat_exp_finalize_func(xlat_exp_t *node) CC_HINT(nonnull);
292
293
/*
294
 *  xlat_func.c
295
 */
296
xlat_t    *xlat_func_find(char const *name, ssize_t namelen);
297
298
/*
299
 *  xlat_eval.c
300
 */
301
extern fr_dict_attr_t const *attr_expr_bool_enum;
302
extern fr_dict_attr_t const *attr_module_return_code;
303
extern fr_dict_attr_t const *attr_cast_base;
304
305
fr_dict_attr_t const *xlat_time_res_attr(char const *res);
306
307
/*
308
 *  xlat_tokenize.c
309
 */
310
extern bool const xlat_func_chars[SBUFF_CHAR_CLASS];
311
312
int   xlat_tokenize_regex(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in, fr_sbuff_marker_t *m_s) CC_HINT(nonnull);
313
314
void    xlat_signal(xlat_func_signal_t signal, xlat_exp_t const *exp,
315
          request_t *request, void *rctx, fr_signal_t action);
316
317
xlat_action_t xlat_frame_eval_resume(TALLOC_CTX *ctx, fr_dcursor_t *out,
318
               xlat_exp_head_t const **child,
319
               request_t *request,  xlat_exp_head_t const *head, xlat_exp_t const **in,
320
               fr_value_box_list_t *result, xlat_func_t resume, void *rctx);
321
322
xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_dcursor_t *out,
323
               xlat_exp_head_t const **child,
324
               request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in,
325
               void *env_data, fr_value_box_list_t *result) CC_HINT(nonnull(1,2,3,4));
326
327
xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_exp_head_t const **child,
328
        request_t *request, xlat_exp_head_t const *head, xlat_exp_t const **in);
329
330
int   xlat_eval_walk(xlat_exp_head_t *head, xlat_walker_t walker, xlat_type_t type, void *uctx);
331
332
int   xlat_eval_init(void);
333
334
void    xlat_eval_free(void);
335
336
void    unlang_xlat_init(void);
337
338
int   unlang_xlat_push_node(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out,
339
              request_t *request, xlat_exp_t *node);
340
341
int     xlat_decode_value_box_list(TALLOC_CTX *ctx, fr_pair_list_t *out,
342
             request_t *request, void *decode_ctx, fr_pair_decode_t decode,
343
             fr_value_box_list_t *in);
344
/*
345
 *  xlat_expr.c
346
 */
347
int   xlat_register_expressions(void);
348
349
/*
350
 *  xlat_tokenize.c
351
 */
352
ssize_t   xlat_print_node(fr_sbuff_t *out, xlat_exp_head_t const *head, xlat_exp_t const *node,
353
        fr_sbuff_escape_rules_t const *e_rules, char c);
354
355
fr_slen_t xlat_tokenize_word(TALLOC_CTX *ctx, xlat_exp_t **out, fr_sbuff_t *in, fr_token_t quote,
356
           fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules) CC_HINT(nonnull);
357
358
#ifdef __cplusplus
359
}
360
#endif