-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
tmpl.h
518 lines (446 loc) · 17.6 KB
/
tmpl.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
#pragma once
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* $Id$
*
* @file lib/server/tmpl.h
* @brief Structures and prototypes for templates
*
* These functions are used to work with #vp_tmpl_t structs.
*
* #vp_tmpl_t (VPTs) specify either a data source, or a data sink.
*
* Examples of sources are #TMPL_TYPE_XLAT, #TMPL_TYPE_EXEC and #TMPL_TYPE_ATTR.
* Examples of sinks are #TMPL_TYPE_ATTR, #TMPL_TYPE_LIST.
*
* VPTs are used to gather values or attributes for evaluation, or copying, and to specify
* where values or #VALUE_PAIR should be copied to.
*
* To create new #vp_tmpl_t use one of the tmpl_*from_* functions. These parse
* strings into VPTs. The main parsing function is #tmpl_afrom_str, which can produce
* most types of VPTs. It uses the type of quoting (passed as an #FR_TOKEN) to determine
* what type of VPT to parse the string as. For example a #T_DOUBLE_QUOTED_STRING will
* produce either a #TMPL_TYPE_XLAT or a #TMPL_TYPE_UNPARSED (depending if the string
* contained a non-literal expansion).
*
* @see tmpl_afrom_str
* @see tmpl_afrom_attr_str
*
* In the case of #TMPL_TYPE_ATTR and #TMPL_TYPE_LIST, there are special cursor overlay
* functions which can be used to iterate over only the #VALUE_PAIR that match a
* vp_tmpl_t in a given list.
*
* @see tmpl_cursor_init
* @see tmpl_cursor_next
*
* Or for simplicity, there are functions which wrap the cursor functions, to copy or
* return the #VALUE_PAIR that match the VPT.
*
* @see tmpl_copy_vps
* @see tmpl_find_vp
*
* If you just need the string value of whatever the VPT refers to, the tmpl_*expand
* functions may be used. These functions evaluate the VPT, execing, and xlat expanding
* as necessary. In the case of #TMPL_TYPE_ATTR, and #FR_TYPE_STRING or #FR_TYPE_OCTETS
* #tmpl_expand will return a pointer to the raw #VALUE_PAIR buffer. This can be very
* useful when using the #FR_TYPE_TMPL type in #CONF_PARSER structs, as it allows the
* user to determine whether they want the module to sanitise the value using presentation
* format specific #xlat_escape_t function, or to operate on the raw value.
*
* @see tmpl_expand
* @see tmpl_aexpand
*
* @copyright 2014-2015 The FreeRADIUS server project
*/
RCSIDH(tmpl_h, "$Id$")
#ifdef __cplusplus
extern "C" {
#endif
/*
* Forward declarations
*/
typedef enum pair_list_e {
PAIR_LIST_REQUEST = 0, //!< Attributes in incoming or internally proxied
///< request (default).
PAIR_LIST_REPLY, //!< Attributes to send in the response.
PAIR_LIST_CONTROL, //!< Attributes that change the behaviour of
///< modules.
PAIR_LIST_STATE, //!< Attributes to store multiple rounds of
///< challenges/responses.
#ifdef WITH_PROXY
PAIR_LIST_PROXY_REQUEST, //!< A copy of attributes in the request list
///< that may be modified in pre-proxy before
//!< proxying the request.
PAIR_LIST_PROXY_REPLY, //!< Attributes sent in response to the proxied
///< request.
#endif
PAIR_LIST_UNKNOWN //!< Unknown list.
} pair_list_t;
extern fr_table_num_ordered_t const pair_list_table[];
extern size_t pair_list_table_len;
typedef enum requests_ref_e {
REQUEST_CURRENT = 0, //!< The current request (default).
REQUEST_OUTER, //!< #REQUEST containing the outer layer of the EAP
//!< conversation. Usually the RADIUS request sent
//!< by the NAS.
REQUEST_PARENT, //!< Parent (whatever it is).
REQUEST_PROXY, //!< Proxied request.
REQUEST_UNKNOWN //!< Unknown request.
} request_ref_t;
extern fr_table_num_sorted_t const request_ref_table[];
extern size_t request_ref_table_len;
/** Types of #vp_tmpl_t
*/
typedef enum tmpl_type_e {
TMPL_TYPE_UNKNOWN = 0, //!< Uninitialised.
TMPL_TYPE_UNPARSED, //!< Unparsed literal string.
TMPL_TYPE_XLAT, //!< XLAT expansion.
TMPL_TYPE_ATTR, //!< Dictionary attribute.
TMPL_TYPE_ATTR_UNDEFINED, //!< Attribute not found in the global dictionary.
TMPL_TYPE_LIST, //!< Attribute list.
TMPL_TYPE_REGEX, //!< Regular expression.
TMPL_TYPE_EXEC, //!< Callout to an external script or program.
TMPL_TYPE_DATA, //!< Value in native format.
TMPL_TYPE_XLAT_STRUCT, //!< Pre-parsed XLAT expansion.
TMPL_TYPE_REGEX_STRUCT, //!< Pre-parsed regular expression.
TMPL_TYPE_NULL //!< Has no value.
} tmpl_type_t;
/** Helpers to verify the type of #vp_tmpl_t
*/
#define tmpl_is_unknown(vpt) (vpt->type == TMPL_TYPE_UNKNOWN)
#define tmpl_is_unparsed(vpt) (vpt->type == TMPL_TYPE_UNPARSED)
#define tmpl_is_xlat(vpt) (vpt->type == TMPL_TYPE_XLAT)
#define tmpl_is_attr(vpt) (vpt->type == TMPL_TYPE_ATTR)
#define tmpl_is_attr_undefined(vpt) (vpt->type == TMPL_TYPE_ATTR_UNDEFINED)
#define tmpl_is_list(vpt) (vpt->type == TMPL_TYPE_LIST)
#define tmpl_is_regex(vpt) (vpt->type == TMPL_TYPE_REGEX)
#define tmpl_is_exec(vpt) (vpt->type == TMPL_TYPE_EXEC)
#define tmpl_is_data(vpt) (vpt->type == TMPL_TYPE_DATA)
#define tmpl_is_xlat_struct(vpt) (vpt->type == TMPL_TYPE_XLAT_STRUCT)
#define tmpl_is_regex_struct(vpt) (vpt->type == TMPL_TYPE_REGEX_STRUCT)
#define tmpl_is_null(vpt) (vpt->type == TMPL_TYPE_NULL)
extern fr_table_num_sorted_t const tmpl_type_table[];
extern size_t tmpl_type_table_len;
typedef struct vp_tmpl_s vp_tmpl_t;
typedef struct vp_tmpl_rules_s vp_tmpl_rules_t;
#include <freeradius-devel/server/xlat.h>
#include <freeradius-devel/util/packet.h>
#include <freeradius-devel/util/regex.h>
/** A source or sink of value data.
*
* Is used as both the RHS and LHS of a map (both update, and conditional types)
*
* @section update_maps Use in update vp_map_t
* When used on the LHS it describes an attribute to create and should be one of these types:
* - #TMPL_TYPE_ATTR
* - #TMPL_TYPE_LIST
*
* When used on the RHS it describes the value to assign to the attribute being created and
* should be one of these types:
* - #TMPL_TYPE_UNPARSED
* - #TMPL_TYPE_XLAT
* - #TMPL_TYPE_ATTR
* - #TMPL_TYPE_LIST
* - #TMPL_TYPE_EXEC
* - #TMPL_TYPE_DATA
* - #TMPL_TYPE_XLAT_STRUCT (pre-parsed xlat)
*
* @section conditional_maps Use in conditional vp_map_t
* When used as part of a condition it may be any of the RHS side types, as well as:
* - #TMPL_TYPE_REGEX_STRUCT (pre-parsed regex)
*
* @see vp_map_t
*/
struct vp_tmpl_s {
tmpl_type_t type; //!< What type of value tmpl refers to.
char const *name; //!< Raw string used to create the template.
size_t len; //!< Length of the raw string used to create the template.
FR_TOKEN quote; //!< What type of quoting was around the raw string.
union {
struct {
request_ref_t request; //!< Request to search or insert in.
pair_list_t list; //!< List to search or insert in.
fr_dict_attr_t const *da; //!< Resolved dictionary attribute.
union {
fr_dict_attr_t *da; //!< Unknown dictionary
//!< attribute buffer.
char *name;
} unknown;
int num; //!< For array references.
int8_t tag; //!< For tag references.
} attribute;
/*
* Attribute value. Typically used as the RHS of an update map.
*/
fr_value_box_t literal; //!< Value data.
xlat_exp_t *xlat; //!< pre-parsed xlat_exp_t
#ifdef HAVE_REGEX
struct {
regex_t *preg; //!< pre-parsed regex_t
fr_regex_flags_t regex_flags; //!< Flags for regular expressions.
};
#endif
} data;
};
/** @name Field accessors for #TMPL_TYPE_ATTR, #TMPL_TYPE_ATTR_UNDEFINED, #TMPL_TYPE_LIST
*
* @{
*/
#define tmpl_request data.attribute.request
#define tmpl_list data.attribute.list
#define tmpl_da data.attribute.da
#define tmpl_unknown data.attribute.unknown.da
#define tmpl_unknown_name data.attribute.unknown.name
#define tmpl_num data.attribute.num
#define tmpl_tag data.attribute.tag
/* @} **/
/** @name Field accessors for #TMPL_TYPE_XLAT_STRUCT
*
* @{
*/
#define tmpl_xlat data.xlat
/* @} **/
/** @name Field accessors for #TMPL_TYPE_DATA
*
* @{
*/
#define tmpl_value data.literal
#define tmpl_value_length data.literal.datum.length
#define tmpl_value_type data.literal.type
/* @} **/
/** @name Field accessors for #TMPL_TYPE_REGEX_STRUCT and #TMPL_TYPE_REGEX
*
* @{
*/
#ifdef HAVE_REGEX
# define tmpl_preg data.preg //!< #TMPL_TYPE_REGEX_STRUCT only.
# define tmpl_regex_flags data.regex_flags
#endif
/* @} **/
#ifndef WITH_VERIFY_PTR
# define TMPL_VERIFY(_x)
#else
# define TMPL_VERIFY(_x) tmpl_verify(__FILE__, __LINE__, _x)
void tmpl_verify(char const *file, int line, vp_tmpl_t const *vpt);
#endif
/** Produces an initialiser for static #TMPL_TYPE_LIST type #vp_tmpl_t
*
* Example:
@code{.c}
static vp_tmpl_t list = tmpl_initialiser_list(CURRENT_REQUEST, PAIR_LIST_REQUEST);
fr_cursor_t cursor;
VALUE_PAIR *vp;
// Iterate over all pairs in the request list
for (vp = tmpl_cursor_init(NULL, &cursor, request, &list);
vp;
vp = tmpl_cursor_next(&cursor, &list)) {
// Do something
}
@endcode
*
* @param _request to locate the list in.
* @param _list to set as the target for the template.
* @see tmpl_cursor_init
* @see tmpl_cursor_next
*/
#define tmpl_initialiser_list(_request, _list)\
{ \
.name = "static", \
.len = sizeof("static"), \
.type = TMPL_TYPE_LIST, \
.quote = T_SINGLE_QUOTED_STRING, \
.data = { \
.attribute = { \
.request = _request, \
.list = _list \
} \
} \
}
/** Determine the correct context and list head
*
* Used in conjunction with the fr_cursor functions to determine the correct list
* and TALLOC_CTX for inserting VALUE_PAIRs.
*
* Example:
@code{.c}
TALLOC_CTX *ctx;
VALUE_PAIR **head;
fr_value_box_t value;
RADIUS_LIST_AND_CTX(ctx, head, request, CURRENT_REQUEST, PAIR_LIST_REQUEST);
if (!list) return -1; // error
value.strvalue = talloc_typed_strdup(NULL, "my new username");
value.length = talloc_array_length(value.strvalue) - 1;
@endcode
*
* @param _ctx new #VALUE_PAIR s should be allocated in for the specified list.
* @param _head of the #VALUE_PAIR list.
* @param _request The current request.
* @param _ref to resolve.
* @param _list to resolve.
*/
#define RADIUS_LIST_AND_CTX(_ctx, _head, _request, _ref, _list) \
do {\
REQUEST *_rctx = _request; \
if ((radius_request(&_rctx, _ref) < 0) || \
!(_head = radius_list(_rctx, _list)) || \
!(_ctx = radius_list_ctx(_rctx, _list))) {\
_ctx = NULL; \
_head = NULL; \
}\
} while (0)
/** Specify whether attribute references require a prefix
*
*/
typedef enum {
VP_ATTR_REF_PREFIX_YES = 0, //!< Attribute refs must have '&' prefix.
VP_ATTR_REF_PREFIX_NO, //!< Attribute refs have no '&' prefix.
VP_ATTR_REF_PREFIX_AUTO //!< Attribute refs may have a '&' prefix.
} vp_attr_ref_prefix_t;
/** Optional arguments passed to vp_tmpl functions
*
*/
struct vp_tmpl_rules_s {
fr_dict_t const *dict_def; //!< Default dictionary to use
///< with unqualified attribute references.
request_ref_t request_def; //!< Default request to use with
///< unqualified attribute references.
pair_list_t list_def; //!< Default list to use with unqualified
///< attribute reference.
bool allow_unknown; //!< Allow unknown attributes i.e. attributes
///< defined by OID string.
bool allow_undefined; //!< Allow attributes that look valid but were
///< not found in the dictionaries.
///< This should be used as part of a multi-pass
///< approach to parsing.
bool allow_foreign; //!< Allow arguments not found in dict_def.
bool disallow_internal; //!< Allow/fallback to internal attributes.
bool disallow_qualifiers; //!< disallow request / list qualifiers
vp_attr_ref_prefix_t prefix; //!< Whether the attribute reference requires
///< a prefix.
};
typedef enum {
ATTR_REF_ERROR_NONE = 0, //!< No error.
ATTR_REF_ERROR_EMPTY, //!< Attribute ref contains no data.
ATTR_REF_ERROR_BAD_PREFIX, //!< Missing '&' or has '&' when it shouldn't.
ATTR_REF_ERROR_INVALID_LIST_QUALIFIER, //!< List qualifier is invalid.
ATTR_REF_ERROR_UNKNOWN_ATTRIBUTE_NOT_ALLOWED, //!< Attribute specified as OID, could not be
///< found in the dictionaries, and is disallowed
///< because 'disallow_internal' in vp_tmpl_rules_t
///< is trie.
ATTR_REF_ERROR_UNDEFINED_ATTRIBUTE_NOT_ALLOWED, //!< Attribute couldn't be found in the dictionaries.
ATTR_REF_ERROR_INVALID_ATTRIBUTE_NAME, //!< Attribute ref length is zero, or longer than
///< the maximum.
ATTR_REF_ERROR_INTERNAL_ATTRIBUTE_NOT_ALLOWED, //!< Attribute resolved to an internal attribute
///< which is disallowed.
ATTR_REF_ERROR_FOREIGN_ATTRIBUTES_NOT_ALLOWED, //!< Attribute resolved in a dictionary different
///< to the one specified.
ATTR_REF_ERROR_TAGGED_ATTRIBUTE_NOT_ALLOWED, //!< Tagged attributes not allowed here.
ATTR_REF_ERROR_INVALID_TAG, //!< Invalid tag value.
ATTR_REF_ERROR_INVALID_ARRAY_INDEX //!< Invalid array index.
} attr_ref_error_t;
/** Map ptr type to a boxed type
*
*/
#define FR_TYPE_FROM_PTR(_ptr) \
_Generic((_ptr), \
char **: FR_TYPE_STRING, \
char const **: FR_TYPE_STRING, \
uint8_t **: FR_TYPE_OCTETS, \
uint8_t const **: FR_TYPE_OCTETS, \
uint8_t *: FR_TYPE_UINT8, \
uint16_t *: FR_TYPE_UINT16, \
uint32_t *: FR_TYPE_UINT32, \
uint64_t *: FR_TYPE_UINT64, \
fr_value_box_t **: FR_TYPE_VALUE_BOX, \
fr_value_box_t const **: FR_TYPE_VALUE_BOX)
/** Expand a tmpl to a C type, using existing storage to hold variably sized types
*
* Expands a template using the _out ptr to determinate the cast type.
*
* @see _tmpl_to_type
*/
#define tmpl_expand(_out, _buff, _buff_len, _request, _vpt, _escape, _escape_ctx) \
_tmpl_to_type((void *)(_out), (uint8_t *)_buff, _buff_len, \
_request, _vpt, _escape, _escape_ctx, FR_TYPE_FROM_PTR(_out))
/** Expand a tmpl to a C type, allocing a new buffer to hold the string
*
* Expands a template using the _out ptr to determinate the cast type.
*
* @see _tmpl_to_atype
*/
#define tmpl_aexpand(_ctx, _out, _request, _vpt, _escape, _escape_ctx) \
_tmpl_to_atype(_ctx, (void *)(_out), _request, _vpt, _escape, _escape_ctx, FR_TYPE_FROM_PTR(_out))
/** Expand a tmpl to a C type, allocing a new buffer to hold the string
*
* Takes an explicit type which must match the ctype pointed to by out.
*
* @see _tmpl_to_atype
*/
#define tmpl_aexpand_type(_ctx, _out, _type, _request, _vpt, _escape, _escape_ctx) \
_tmpl_to_atype(_ctx, (void *)(_out), _request, _vpt, _escape, _escape_ctx, _type)
VALUE_PAIR **radius_list(REQUEST *request, pair_list_t list);
RADIUS_PACKET *radius_packet(REQUEST *request, pair_list_t list_name);
TALLOC_CTX *radius_list_ctx(REQUEST *request, pair_list_t list_name);
size_t radius_list_name(pair_list_t *out, char const *name, pair_list_t default_list);
int radius_request(REQUEST **request, request_ref_t name);
size_t radius_request_name(request_ref_t *out, char const *name, request_ref_t unknown);
vp_tmpl_t *tmpl_init(vp_tmpl_t *vpt, tmpl_type_t type,
char const *name, ssize_t len, FR_TOKEN quote);
vp_tmpl_t *tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, char const *name,
ssize_t len, FR_TOKEN quote);
void tmpl_from_da(vp_tmpl_t *vpt, fr_dict_attr_t const *da, int8_t tag, int num,
request_ref_t request, pair_list_t list);
int tmpl_afrom_value_box(TALLOC_CTX *ctx, vp_tmpl_t **out, fr_value_box_t *data, bool steal);
ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, attr_ref_error_t *err,
vp_tmpl_t **out, char const *name,
vp_tmpl_rules_t const *rules);
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, attr_ref_error_t *err,
vp_tmpl_t **out, char const *name,
vp_tmpl_rules_t const *rules) CC_HINT(nonnull (3, 4));
ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name, size_t inlen,
FR_TOKEN type, vp_tmpl_rules_t const *rules, bool do_escape);
int tmpl_cast_in_place(vp_tmpl_t *vpt, fr_type_t type, fr_dict_attr_t const *enumv);
void tmpl_cast_in_place_str(vp_tmpl_t *vpt);
int tmpl_cast_to_vp(VALUE_PAIR **out, REQUEST *request,
vp_tmpl_t const *vpt, fr_dict_attr_t const *cast);
size_t tmpl_snprint_attr_str(char *out, size_t outlen, vp_tmpl_t const *vpt);
size_t tmpl_snprint(char *out, size_t outlen, vp_tmpl_t const *vpt);
ssize_t _tmpl_to_type(void *out,
uint8_t *buff, size_t outlen,
REQUEST *request,
vp_tmpl_t const *vpt,
xlat_escape_t escape, void const *escape_ctx,
fr_type_t dst_type)
CC_HINT(nonnull (1, 4, 5));
ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out,
REQUEST *request,
vp_tmpl_t const *vpt,
xlat_escape_t escape, void const *escape_ctx,
fr_type_t dst_type)
CC_HINT(nonnull (2, 3, 4));
VALUE_PAIR *tmpl_cursor_init(int *err, fr_cursor_t *cursor, REQUEST *request,
vp_tmpl_t const *vpt);
int tmpl_copy_vps(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request,
vp_tmpl_t const *vpt);
int tmpl_find_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt);
int tmpl_find_or_add_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt);
int tmpl_define_unknown_attr(vp_tmpl_t *vpt);
int tmpl_define_undefined_attr(fr_dict_t *dict, vp_tmpl_t *vpt,
fr_type_t type, fr_dict_attr_flags_t const *flags);
#ifdef __cplusplus
}
#endif