summaryrefslogtreecommitdiffstats
path: root/src/include/conffile.h
blob: 237469c880603666a5975d8c4699af35ca81a7d8 (plain)
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
#ifndef _CONFFILE_H
#define _CONFFILE_H

/*
 * conffile.h	Defines for the conffile parsing routines.
 *
 * Version:	$Id$
 *
 */

RCSIDH(conffile_h, "$Id$")

#include <stddef.h>
#include <freeradius-devel/token.h>
#include <sys/time.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Export the minimum amount of information about these structs
 */
typedef struct conf_item CONF_ITEM;	//!< Generic configuration element, extended to become
					///< a #CONF_PAIR, a #CONF_SECTION or #CONF_DATA.
typedef struct conf_pair CONF_PAIR;	//!< #CONF_ITEM with an attribute, an operator and a value.
typedef struct conf_part CONF_SECTION;	//!< #CONF_ITEM used to group multiple #CONF_PAIR and #CONF_SECTION, together.
typedef struct conf_data CONF_DATA;	//!< #CONF_ITEM used to associate arbitrary data
					///< with a #CONF_PAIR or #CONF_SECTION.


typedef void conf_type_mismatch;	//!< Dummy type used to indicate PW_TYPE_*/C type mismatch.
typedef void conf_type_invalid;		//!< Dummy type used to indicate invalid PW_TYPE_*.

#if defined(HAVE_BUILTIN_CHOOSE_EXPR) && defined(HAVE_BUILTIN_TYPES_COMPATIBLE_P)
/*
 * Dumb hack for GCC which explodes with lots of errors masking the real
 * error cause, if we don't use typdefs for these structures.
 */
typedef struct timeval _timeval_t;

/** Check the type #_t matches the destination data type
 *
 * Validation macro to check the type of the pointer or offset #_p passed in
 * matches the type #_t of the configuration item.
 *
 * Uses various magic builtin precompilation functions, so will likely only
 * work with recent versions of clang and gcc.
 *
 * @note The warnings/errors emitted are usually awful.
 *
 * @param _t a #PW_TYPE value with optional PW_TYPE_* flags.
 * @param _ct data type of global or struct field, obtained with ``__typeof__``.
 * @param _p Pointer or offset.
 */
#  define FR_CONF_TYPE_CHECK(_t, _ct, _p) \
	__builtin_choose_expr((_t & PW_TYPE_TMPL),\
		__builtin_choose_expr(__builtin_types_compatible_p(vp_tmpl_t **, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_STRING),\
		__builtin_choose_expr(__builtin_types_compatible_p(char const **, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_BOOLEAN),\
		__builtin_choose_expr(__builtin_types_compatible_p(bool *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_SUBSECTION),\
		_p,\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_INTEGER),\
		__builtin_choose_expr(__builtin_types_compatible_p(uint32_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_IPV4_ADDR),\
		__builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_DATE),\
		__builtin_choose_expr(__builtin_types_compatible_p(uint32_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_ABINARY),\
		__builtin_choose_expr(__builtin_types_compatible_p(size_t[32/sizeof(size_t)], _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_OCTETS),\
		__builtin_choose_expr(__builtin_types_compatible_p(uint8_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_IFID),\
		__builtin_choose_expr(__builtin_types_compatible_p(uint8_t[8], _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_IPV6_ADDR),\
		__builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_IPV6_PREFIX),\
		__builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_BYTE),\
		__builtin_choose_expr(__builtin_types_compatible_p(uint8_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_SHORT),\
		__builtin_choose_expr(__builtin_types_compatible_p(uint16_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_ETHERNET),\
		__builtin_choose_expr(__builtin_types_compatible_p(uint8_t[6], _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_SIGNED),\
		__builtin_choose_expr(__builtin_types_compatible_p(int32_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_COMBO_IP_ADDR),\
		__builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_INTEGER64),\
		__builtin_choose_expr(__builtin_types_compatible_p(uint64_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_IPV4_PREFIX),\
		__builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_TIMEVAL),\
		__builtin_choose_expr(__builtin_types_compatible_p(_timeval_t *, _ct), _p, (conf_type_mismatch) 0),\
	__builtin_choose_expr((((_t) & 0xff) == PW_TYPE_COMBO_IP_PREFIX),\
		__builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
		(conf_type_invalid) 0\
	)))))))))))))))))))))

#  define FR_CONF_OFFSET(_t, _s, _f)	_t, FR_CONF_TYPE_CHECK((_t), __typeof__(&(((_s *)NULL)->_f)), offsetof(_s, _f)), NULL
#  define FR_CONF_POINTER(_t, _p)	_t, 0, FR_CONF_TYPE_CHECK((_t), __typeof__(_p), _p)
#  define FR_ITEM_POINTER(_t, _p)	_t, FR_CONF_TYPE_CHECK((_t), __typeof__(_p), _p)
#else
#  define FR_CONF_OFFSET(_t, _s, _f)	_t, offsetof(_s, _f), NULL
#  define FR_CONF_POINTER(_t, _p)	_t, 0, _p
#  define FR_ITEM_POINTER(_t, _p)	_t, _p
#endif

#define FR_CONF_DEPRECATED(_t, _p, _f) (_t) | PW_TYPE_DEPRECATED, 0, NULL

/*
 *  Instead of putting the information into a configuration structure,
 *  the configuration file routines MAY just parse it directly into
 *  user-supplied variables.
 */
#define PW_TYPE_SUBSECTION	102

/** @name #CONF_PARSER type flags
 *
 * These flags should be or'd with another PW_TYPE_* value to create validation
 * rules for the #cf_item_parse function.
 *
 * @note File PW_TYPE_FILE_* types have a base type of string, so they're validated
 *	 correctly by the config parser.
 * @{
 */
#define PW_TYPE_DEPRECATED	(1 << 10) //!< If a matching #CONF_PAIR is found, error out with a deprecated message.
#define PW_TYPE_REQUIRED	(1 << 11) //!< Error out if no matching #CONF_PAIR is found, and no dflt value is set.
#define PW_TYPE_ATTRIBUTE	(1 << 12) //!< Value must resolve to attribute in dict (deprecated, use #PW_TYPE_TMPL).
#define PW_TYPE_SECRET		(1 << 13) //!< Only print value if debug level >= 3.

#define PW_TYPE_FILE_INPUT	((1 << 14) | PW_TYPE_STRING) //!< File matching value must exist, and must be readable.
#define PW_TYPE_FILE_OUTPUT	((1 << 15) | PW_TYPE_STRING) //!< File matching value must exist, and must be writeable.

#define PW_TYPE_XLAT		(1 << 16) //!< string will be dynamically expanded.
#define PW_TYPE_TMPL		(1 << 17) //!< CONF_PAIR should be parsed as a template.

#define PW_TYPE_MULTI		(1 << 18) //!< CONF_PAIR can have multiple copies.
#define PW_TYPE_NOT_EMPTY	(1 << 19) //!< CONF_PAIR is required to have a non zero length value.
#define PW_TYPE_FILE_EXISTS	((1 << 20) | PW_TYPE_STRING) //!< File matching value must exist
#define PW_TYPE_IGNORE_DEFAULT	(1 << 21) //!< don't set from .dflt if the CONF_PAIR is missing
/* @} **/

#define FR_INTEGER_COND_CHECK(_name, _var, _cond, _new)\
do {\
	if (!(_cond)) {\
		WARN("Ignoring \"" _name " = %i\", forcing to \"" _name " = %i\"", _var, _new);\
		_var = _new;\
	}\
} while (0)

#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound) FR_INTEGER_COND_CHECK(_name, _var, (_var _op _bound), _bound)

#define FR_TIMEVAL_BOUND_CHECK(_name, _var, _op, _bound_sec, _bound_usec)\
do {\
	struct timeval _bound = {_bound_sec, _bound_usec};\
	if (!timercmp(_var, &_bound, _op)) {\
		WARN("Ignoring \"" _name " = %d.%.06d\", forcing to \"" _name " = %d.%06d\"",\
			(int)(_var)->tv_sec, (int)(_var)->tv_usec,\
			(int)_bound.tv_sec, (int)_bound.tv_usec);\
		*_var = _bound;\
	}\
} while (0)

#define FR_TIMEVAL_TO_MS(_x) (((_x)->tv_usec * 1000) + ((_x)->tv_sec / 1000))
extern bool 			check_config;

/** Defines a #CONF_PAIR to C data type mapping
 *
 * Is typically used to define mappings between module sections, and module instance structs.
 * May also be used to set global configuration options.
 *
 * Offset/data values should be set using #FR_CONF_OFFSET or #FR_CONF_POINTER.
 *
 * Example with #FR_CONF_OFFSET :
 @code{.c}
   static CONF_PARSER module_config[] = {
   	{ "example", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, example_instance_t, example), "default_value" },
   	CONF_PARSER_TERMINATOR
   }
 @endcode
 *
 * Example with #FR_CONF_POINTER :
 @code{.c}
   static CONF_PARSER global_config[] = {
   	{ "example", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, &my_global), "default_value" },
   	CONF_PARSER_TERMINATOR
   }
 @endcode
 *
 * @see FR_CONF_OFFSET
 * @see FR_CONF_POINTER
 * @see cf_section_parse
 * @see cf_item_parse
 */
typedef struct CONF_PARSER {
	char const	*name;			//!< Name of the #CONF_ITEM to parse.
	int		type;			//!< A #PW_TYPE value, may be or'd with one or more PW_TYPE_* flags.
						//!< @see cf_item_parse.

	size_t		offset;			//!< Relative offset of field or structure to write the parsed value to.
						//!< When #type is set to #PW_TYPE_SUBSECTION, may be used to specify
						//!< a base offset to add to all offsets contained within the
						//!< subsection.
						//!< @note Must be used exclusively to #data.

	void		*data;			//!< Pointer to a static variable to write the parsed value to.
						//!< @note Must be used exclusively to #offset.

	const void	*dflt;			//!< Default as it would appear in radiusd.conf.
						//!< When #type is set to #PW_TYPE_SUBSECTION, should be a pointer
						//!< to the start of another array of #CONF_PARSER structs, forming
						//!< the subsection.
} CONF_PARSER;

#define CONF_PARSER_TERMINATOR	{ NULL, -1, 0, NULL, NULL }

CONF_PAIR	*cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value,
			       FR_TOKEN op, FR_TOKEN lhs_type, FR_TOKEN rhs_type);
CONF_PAIR	*cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp);
void		cf_pair_add(CONF_SECTION *parent, CONF_PAIR *cp);

CONF_SECTION	*cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2);
CONF_SECTION	*cf_section_dup(CONF_SECTION *parent, CONF_SECTION const *cs,
				char const *name1, char const *name2, bool copy_meta);
void		cf_section_add(CONF_SECTION *parent, CONF_SECTION *cs);
int		cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value);
int		cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *data, char const *dflt);
int		cf_section_parse(CONF_SECTION *, void *base, CONF_PARSER const *variables);
int		cf_section_parse_pass2(CONF_SECTION *, void *base, CONF_PARSER const *variables);
const CONF_PARSER *cf_section_parse_table(CONF_SECTION *cs);
int		cf_file_read(CONF_SECTION *cs, char const *file);
void		cf_file_free(CONF_SECTION *cs);

CONF_PAIR	*cf_pair_find(CONF_SECTION const *, char const *name);
CONF_PAIR	*cf_pair_find_next(CONF_SECTION const *, CONF_PAIR const *, char const *name);
CONF_SECTION	*cf_section_find(char const *name);
CONF_SECTION	*cf_section_find_name2(CONF_SECTION const *section,
				       char const *name1, char const *name2);
CONF_SECTION	*cf_section_sub_find(CONF_SECTION const *, char const *name);
CONF_SECTION	*cf_section_sub_find_name2(CONF_SECTION const *, char const *name1, char const *name2);
char const 	*cf_section_value_find(CONF_SECTION const *, char const *attr);
CONF_SECTION	*cf_top_section(CONF_SECTION *cs);

void *cf_data_find(CONF_SECTION const *, char const *);
int cf_data_add(CONF_SECTION *, char const *, void *, void (*)(void *));
void *cf_data_remove(CONF_SECTION *cs, char const *name);

char const *cf_pair_attr(CONF_PAIR const *pair);
char const *cf_pair_value(CONF_PAIR const *pair);
FR_TOKEN cf_pair_operator(CONF_PAIR const *pair);
FR_TOKEN cf_pair_attr_type(CONF_PAIR const *pair);
FR_TOKEN cf_pair_value_type(CONF_PAIR const *pair);
VALUE_PAIR *cf_pairtovp(CONF_PAIR *pair);
char const *cf_section_name1(CONF_SECTION const *cs);
char const *cf_section_name2(CONF_SECTION const *cs);
char const *cf_section_name(CONF_SECTION const *cs);
FR_TOKEN cf_section_name2_type(CONF_SECTION const *cs);
int dump_config(CONF_SECTION const *cs);
CONF_SECTION *cf_subsection_find_next(CONF_SECTION const *section,
				      CONF_SECTION const *subsection,
				      char const *name1);
CONF_SECTION *cf_section_find_next(CONF_SECTION const *section,
				   CONF_SECTION const *subsection,
				   char const *name1);
int cf_section_lineno(CONF_SECTION const *section);
int cf_pair_lineno(CONF_PAIR const *pair);
char const *cf_pair_filename(CONF_PAIR const *pair);
char const *cf_section_filename(CONF_SECTION const *section);
CONF_ITEM *cf_item_find_next(CONF_SECTION const *section, CONF_ITEM const *item);
int cf_pair_count(CONF_SECTION const *cs);
CONF_SECTION *cf_item_parent(CONF_ITEM const *ci);
bool cf_item_is_section(CONF_ITEM const *item);
bool cf_item_is_pair(CONF_ITEM const *item);
bool cf_item_is_data(CONF_ITEM const *item);
CONF_PAIR *cf_item_to_pair(CONF_ITEM const *item);
CONF_SECTION *cf_item_to_section(CONF_ITEM const *item);
CONF_ITEM *cf_pair_to_item(CONF_PAIR const *cp);
CONF_ITEM *cf_section_to_item(CONF_SECTION const *cs);

void cf_log_err(CONF_ITEM const *ci, char const *fmt, ...)		CC_HINT(format (printf, 2, 3));
void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt, ...)	CC_HINT(format (printf, 2, 3));
void cf_log_err_cp(CONF_PAIR const *cp, char const *fmt, ...)		CC_HINT(format (printf, 2, 3));
void cf_log_info(CONF_SECTION const *cs, char const *fmt, ...)		CC_HINT(format (printf, 2, 3));
void cf_log_module(CONF_SECTION const *cs, char const *fmt, ...)	CC_HINT(format (printf, 2, 3));

void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci);
CONF_ITEM *cf_reference_item(CONF_SECTION const *parentcs,
			     CONF_SECTION *outercs,
			     char const *ptr);

#define CF_FILE_NONE   (0)
#define CF_FILE_ERROR  (1)
#define CF_FILE_CONFIG (1 << 2)
#define CF_FILE_MODULE (1 << 3)
int cf_file_changed(CONF_SECTION *cs, rb_walker_t callback);

extern CONF_SECTION *root_config;
extern bool cf_new_escape;

#ifdef __cplusplus
}
#endif

#endif /* _CONFFILE_H */