The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
base.c
Go to the documentation of this file.
1/*
2 * This program is 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 (at
5 * 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: b1147fc4b0c9a7cea52e7e073049e023743d3492 $
19 * @file lib/eap/base.c
20 * @brief Code common to clients and to servers.
21 *
22 * @copyright 2000-2003,2006 The FreeRADIUS server project
23 * @copyright 2001 hereUare Communications, Inc. (raghud@hereuare.com)
24 * @copyright 2003 Alan DeKok (aland@freeradius.org)
25 * @copyright 2003 Michael Richardson (mcr@sandelman.ottawa.on.ca)
26 */
27
28/*
29 * EAP PACKET FORMAT
30 * --- ------ ------
31 * 0 1 2 3
32 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
33 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 * | Code | Identifier | Length |
35 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * | Data ...
37 * +-+-+-+-+
38 *
39 *
40 * EAP Request and Response Packet Format
41 * --- ------- --- -------- ------ ------
42 * 0 1 2 3
43 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 * | Code | Identifier | Length |
46 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 * | Type | Type-Data ...
48 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
49 *
50 *
51 * EAP Success and Failure Packet Format
52 * --- ------- --- ------- ------ ------
53 * 0 1 2 3
54 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
55 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 * | Code | Identifier | Length |
57 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58 *
59 */
60
61RCSID("$Id: b1147fc4b0c9a7cea52e7e073049e023743d3492 $")
62
63#define LOG_PREFIX "eap"
64
65#include <freeradius-devel/eap/base.h>
66#include <freeradius-devel/radius/defs.h>
67#include <freeradius-devel/server/state.h>
68#include <freeradius-devel/server/pair.h>
69#include <freeradius-devel/server/auth.h>
70#include <freeradius-devel/unlang/call.h>
71#include <freeradius-devel/unlang/function.h>
72#include "types.h"
73#include "attrs.h"
74
77static fr_dict_t const *dict_tls;
78
81 { .out = &dict_freeradius, .proto = "freeradius" },
82 { .out = &dict_radius, .proto = "radius" },
83 { .out = &dict_tls, .proto = "tls" },
85};
86
105
108 { .out = &attr_chbind_response_code, .name = "Chbind-Response-Code", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
109 { .out = &attr_eap_identity, .name = "EAP-Identity", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
110 { .out = &attr_eap_session_id, .name = "EAP-Session-Id", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
111 { .out = &attr_eap_type, .name = "EAP-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
112 { .out = &attr_state, .name = "State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
113 { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
114 { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
115 { .out = &attr_eap_channel_binding_message, .name = "Vendor-Specific.UKERNA.EAP-Channel-Binding-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
116 { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
117 { .out = &attr_eap_msk, .name = "EAP-MSK", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
118 { .out = &attr_eap_emsk, .name = "EAP-EMSK", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
119 { .out = &attr_framed_mtu, .name = "Framed-MTU", .type = FR_TYPE_UINT32, .dict = &dict_radius },
120 { .out = &attr_freeradius_proxied_to, .name = "Vendor-Specific.FreeRADIUS.Proxied-To", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
121 { .out = &attr_ms_mppe_send_key, .name = "Vendor-Specific.Microsoft.MPPE-Send-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
122 { .out = &attr_ms_mppe_recv_key, .name = "Vendor-Specific.Microsoft.MPPE-Recv-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
123 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
124 { .out = &attr_tls_min_version, .name = "Min-Version", .type = FR_TYPE_FLOAT32, .dict = &dict_tls },
125 { .out = &attr_tls_max_version, .name = "Max-Version", .type = FR_TYPE_FLOAT32, .dict = &dict_tls },
126
128};
129
130void eap_packet_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *list, eap_packet_raw_t const *eap)
131{
132 int total, size;
133 uint8_t const *ptr;
134 fr_pair_t *vp;
135
136 total = eap->length[0] * 256 + eap->length[1];
137
138 if (total == 0) {
139 DEBUG("Asked to encode empty EAP-Message!");
140 return;
141 }
142
143 ptr = (uint8_t const *) eap;
144
145 do {
146 size = total;
147 if (size > 253) size = 253;
148
150 fr_pair_value_memdup(vp, ptr, size, false);
151
152 fr_pair_append(list, vp);
153
154 ptr += size;
155 total -= size;
156 } while (total > 0);
157}
158
159/** Basic EAP packet verifications & validations
160 *
161 * @param[in] ctx talloc ctx for the eap packet.
162 * @param[in] eap_packet_p to validate.
163 * @return
164 * - true the packet is valid.
165 * - false the packet is invalid.
166 */
167static bool eap_is_valid(TALLOC_CTX *ctx, eap_packet_raw_t **eap_packet_p)
168{
169 uint16_t len;
170 size_t packet_len;
171 eap_packet_raw_t *eap_packet = *eap_packet_p;
172
173 /*
174 * These length checks are also done by eap_packet_from_vp(),
175 * but that's OK. The static analysis tools aren't smart
176 * enough to figure that out.
177 */
178 packet_len = talloc_array_length((uint8_t *) eap_packet);
179 if (packet_len <= EAP_HEADER_LEN) {
180 fr_strerror_printf("Invalid EAP data length %zu <= 4", packet_len);
181 return false;
182 }
183
184 memcpy(&len, eap_packet->length, sizeof(uint16_t));
185 len = ntohs(len);
186
187 if ((len <= EAP_HEADER_LEN) || (len > packet_len)) {
188 fr_strerror_printf("Invalid EAP length field. Expected value in range %d-%zu, was %u bytes",
189 EAP_HEADER_LEN, packet_len, len);
190 return false;
191 }
192
193 /*
194 * The supplicant only sends us a response.
195 */
196 if (eap_packet->code != FR_EAP_CODE_RESPONSE) {
197 fr_strerror_printf("Invalid EAP code %d: Ignoring the packet", eap_packet->code);
198 return false;
199 }
200
201 /* we don't expect notification, but we send it */
202 if (eap_packet->data[0] == FR_EAP_METHOD_NOTIFICATION) {
203 fr_strerror_const("Got NOTIFICATION, Ignoring the packet");
204 return false;
205 }
206
207 /*
208 * Handle expanded types by smashing them to
209 * normal types.
210 */
211 if (eap_packet->data[0] == FR_EAP_EXPANDED_TYPE) {
212 uint8_t *p, *q;
213
214 if (len <= (EAP_HEADER_LEN + 1 + 3 + 4)) {
215 fr_strerror_const("Expanded EAP type is too short: ignoring the packet");
216 return false;
217 }
218
219 if ((eap_packet->data[1] != 0) ||
220 (eap_packet->data[2] != 0) ||
221 (eap_packet->data[3] != 0)) {
222 fr_strerror_const("Expanded EAP type has unknown Vendor-ID: ignoring the packet");
223 return false;
224 }
225
226 if ((eap_packet->data[4] != 0) ||
227 (eap_packet->data[5] != 0) ||
228 (eap_packet->data[6] != 0)) {
229 fr_strerror_const("Expanded EAP type has unknown Vendor-Type: ignoring the packet");
230 return false;
231 }
232
233 if ((eap_packet->data[7] <= FR_EAP_METHOD_NAK) ||
234 (eap_packet->data[7] >= FR_EAP_METHOD_MAX)) {
235 fr_strerror_printf("Unsupported Expanded EAP type %s (%u): ignoring the packet",
236 eap_type2name(eap_packet->data[7]), eap_packet->data[7]);
237 return false;
238 }
239
240 /*
241 * Re-write the EAP packet to NOT have the expanded type.
242 */
243 q = (uint8_t *) eap_packet;
244 memmove(q + EAP_HEADER_LEN, q + EAP_HEADER_LEN + 7, len - 7 - EAP_HEADER_LEN);
245
246 p = talloc_realloc(ctx, eap_packet, uint8_t, len - 7);
247 if (!p) {
248 fr_strerror_printf("Unsupported EAP type %s (%u): ignoring the packet",
249 eap_type2name(eap_packet->data[0]), eap_packet->data[0]);
250 return false;
251 }
252
253 len -= 7;
254 p[2] = (len >> 8) & 0xff;
255 p[3] = len & 0xff;
256
257 *eap_packet_p = (eap_packet_raw_t *)p;
258
259 return true;
260 }
261
262 if ((eap_packet->data[0] == 0) ||
263 (eap_packet->data[0] >= FR_EAP_METHOD_MAX)) {
264 fr_strerror_printf("Unsupported EAP type %s (%u): ignoring the packet",
265 eap_type2name(eap_packet->data[0]), eap_packet->data[0]);
266 return false;
267 }
268
269 return true;
270}
271
272/*
273 * Handles multiple EAP-Message attrs
274 * ie concatenates all to get the complete EAP packet.
275 *
276 * NOTE: Sometimes Framed-MTU might contain the length of EAP-Message,
277 * refer fragmentation in rfc2869.
278 */
280{
281 fr_pair_t *vp;
282 eap_packet_raw_t *eap_packet;
283 uint16_t len;
284
285 /*
286 * Get only EAP-Message attribute list
287 */
289 if (!vp) {
290 fr_strerror_const("EAP-Message not found");
291 return NULL;
292 }
293
294 /*
295 * Sanity check the length before doing anything.
296 */
297 if (vp->vp_length < EAP_HEADER_LEN) {
298 fr_strerror_const("EAP packet is too short");
299 return NULL;
300 }
301
302 /*
303 * Get the Actual length from the EAP packet
304 * First EAP-Message contains the EAP packet header
305 */
306 memcpy(&len, vp->vp_strvalue + 2, sizeof(len));
307 len = ntohs(len);
308
309 /*
310 * Take out even more weird things.
311 */
312 if (len < EAP_HEADER_LEN) {
313 fr_strerror_const("EAP packet has invalid length (less than 4 bytes)");
314 return NULL;
315 }
316
317
318 /*
319 * If the data is SMALLER than the requested length, die, too.
320 */
321 if (vp->vp_length < len) {
322 fr_strerror_printf("Malformed EAP packet. Length in packet header does not "
323 "match actual length");
324 return NULL;
325 }
326
327 /*
328 * Now that we know the lengths are OK, allocate memory.
329 */
330 eap_packet = (eap_packet_raw_t *) talloc_memdup(ctx, vp->vp_octets, len);
331 if (!eap_packet) return NULL;
332
333 /*
334 * Do more in-depth validity checks.
335 */
336 if (!eap_is_valid(ctx, &eap_packet)) {
337 talloc_free(eap_packet);
338 return NULL;
339 }
340
341 return eap_packet;
342}
343
344/*
345 * Add raw hex data to the reply.
346 */
347void eap_add_reply(request_t *request, fr_dict_attr_t const *da, uint8_t const *value, int len)
348{
349 fr_pair_t *vp;
350
351 MEM(pair_update_reply(&vp, da) >= 0);
352 fr_pair_value_memdup(vp, value, len, false);
353
354 RINDENT();
355 RDEBUG2("reply.%pP", vp);
356 REXDENT();
357}
358
359/** Handle the result of running a subrequest through a virtual server
360 *
361 * Storing the value of the State attribute in readiness for the next round.
362 */
364 request_t *request, void *uctx)
365{
366 eap_session_t *eap_session = talloc_get_type_abort(uctx, eap_session_t);
367
368 /*
369 * Grab the child's session state for re-use in the next round
370 */
372
374}
375
376/** Run a subrequest through a virtual server
377 *
378 * If eap_session_t has a child_state, inject that as an attribute in the request.
379 *
380 * @param[in] request the current (real) request.
381 * @param[in] eap_session representing the outer eap method.
382 * @param[in] virtual_server The virtual server to send the request to.
383 * @return
384 * - UNLANG_ACTION_PUSHED_CHILD on success
385 * - UNLANG_ACTION_FAIL on error
386 */
388{
389 fr_pair_t *vp;
390
391 fr_assert(request->parent);
392 fr_assert(virtual_server);
393
394 RDEBUG2("Running request through virtual server \"%s\"", cf_section_name2(virtual_server_cs(virtual_server)));
395
396 /*
397 * Re-present the previously stored child's session state if there is one
398 */
400
401 if (fr_pair_prepend_by_da(request->request_ctx, &vp, &request->request_pairs,
404
405 if (unlang_function_push_with_result(/* transparent */ unlang_interpret_result(request),
406 request,
407 NULL,
409 NULL, 0,
411 eap_session) < 0) return UNLANG_ACTION_FAIL;
412
413 if (unlang_call_push(NULL, request, virtual_server_cs(virtual_server), UNLANG_SUB_FRAME) < 0) return UNLANG_ACTION_FAIL;
414
416}
417
418/** Initialise the lib eap base library
419 *
420 */
422{
424 PERROR("%s", __FUNCTION__);
425 return -1;
426 }
427
428 /*
429 * But main_config.c does read the dictionaries before
430 * loading modules, so these have to exist.
431 */
433 PERROR("%s", __FUNCTION__);
435 return -1;
436 }
437
438 return 0;
439}
440
441/** De-init the lib eap base library
442 *
443 */
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
#define RCSID(id)
Definition build.h:506
#define UNUSED
Definition build.h:336
unlang_action_t unlang_call_push(unlang_result_t *p_result, request_t *request, CONF_SECTION *server_cs, bool top_frame)
Push a call frame onto the stack.
Definition call.c:147
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1184
#define MEM(x)
Definition debug.h:46
@ FR_RADIUS_CODE_ACCESS_REQUEST
RFC2865 - Access-Request.
Definition defs.h:33
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
#define fr_dict_autofree(_to_free)
Definition dict.h:915
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4395
#define fr_dict_autoload(_to_load)
Definition dict.h:912
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
Test enumeration values.
Definition dict_test.h:92
char const * eap_type2name(eap_type_t method)
Return an EAP-name for a particular type.
Definition types.c:54
uint8_t data[]
Definition types.h:125
@ FR_EAP_CODE_RESPONSE
Definition types.h:38
#define FR_EAP_EXPANDED_TYPE
Definition types.h:105
uint8_t code
Definition types.h:122
#define EAP_HEADER_LEN
Definition types.h:34
uint8_t length[2]
Definition types.h:124
@ FR_EAP_METHOD_NAK
Definition types.h:48
@ FR_EAP_METHOD_NOTIFICATION
Definition types.h:47
@ FR_EAP_METHOD_MAX
Definition types.h:102
Structure to represent packet format of eap on wire
Definition types.h:121
#define unlang_function_push_with_result(_result_p, _request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack that produces a result.
Definition function.h:144
talloc_free(hp)
unlang_result_t * unlang_interpret_result(request_t *request)
Get the last instruction result OR the last frame that was popped.
Definition interpret.c:1581
#define UNLANG_SUB_FRAME
Definition interpret.h:37
static fr_dict_t const * dict_freeradius
Definition base.c:37
fr_dict_attr_autoload_t eap_base_dict_attr[]
Definition base.c:107
fr_dict_attr_t const * attr_packet_type
Definition base.c:91
void eap_packet_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *list, eap_packet_raw_t const *eap)
Definition base.c:130
fr_dict_attr_t const * attr_eap_session_id
Definition base.c:88
fr_dict_attr_t const * attr_state
Definition base.c:101
fr_dict_attr_t const * attr_eap_identity
Definition base.c:89
fr_dict_attr_t const * attr_freeradius_proxied_to
Definition base.c:98
fr_dict_attr_t const * attr_chbind_response_code
Definition base.c:87
fr_dict_attr_t const * attr_eap_message
Definition base.c:94
fr_dict_attr_t const * attr_eap_type
Definition base.c:90
fr_dict_attr_t const * attr_eap_msk
Definition base.c:95
fr_dict_attr_t const * attr_eap_channel_binding_message
Definition base.c:93
static fr_dict_t const * dict_tls
Definition base.c:77
fr_dict_attr_t const * attr_tls_min_version
Definition base.c:103
fr_dict_t const * dict_radius
Definition base.c:76
int eap_base_init(void)
Initialise the lib eap base library.
Definition base.c:421
void eap_base_free(void)
De-init the lib eap base library.
Definition base.c:444
eap_packet_raw_t * eap_packet_from_vp(TALLOC_CTX *ctx, fr_pair_list_t *vps)
Definition base.c:279
fr_dict_attr_t const * attr_eap_emsk
Definition base.c:96
fr_dict_attr_t const * attr_ms_mppe_send_key
Definition base.c:99
fr_dict_attr_t const * attr_tls_max_version
Definition base.c:104
static unlang_action_t eap_virtual_server_resume(UNUSED unlang_result_t *p_result, request_t *request, void *uctx)
Handle the result of running a subrequest through a virtual server.
Definition base.c:363
fr_dict_attr_t const * attr_user_name
Definition base.c:102
static bool eap_is_valid(TALLOC_CTX *ctx, eap_packet_raw_t **eap_packet_p)
Basic EAP packet verifications & validations.
Definition base.c:167
fr_dict_attr_t const * attr_framed_mtu
Definition base.c:97
unlang_action_t eap_virtual_server(request_t *request, eap_session_t *eap_session, virtual_server_t *virtual_server)
Run a subrequest through a virtual server.
Definition base.c:387
fr_dict_attr_t const * attr_ms_mppe_recv_key
Definition base.c:100
fr_dict_autoload_t eap_base_dict[]
Definition base.c:80
void eap_add_reply(request_t *request, fr_dict_attr_t const *da, uint8_t const *value, int len)
Definition base.c:347
fr_dict_attr_t const * attr_message_authenticator
Definition base.c:92
char * identity
NAI (User-Name) from EAP-Identity.
Definition session.h:56
#define REQUEST_DATA_EAP_SESSION
Definition session.h:35
Tracks the progress of a single session of any EAP method.
Definition session.h:41
#define PERROR(_fmt,...)
Definition log.h:228
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:455
#define RINDENT()
Indent R* messages by one level.
Definition log.h:442
unsigned short uint16_t
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_OCTETS
Raw octets.
unsigned char uint8_t
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition pair.c:2962
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:707
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1352
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:290
int fr_pair_prepend_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and prepend)
Definition pair.c:1498
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:37
#define RDEBUG2(fmt,...)
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition pair.h:129
void fr_state_restore_from_parent(request_t *child, void const *unique_ptr, int unique_int)
Restore subrequest data from a parent request.
Definition state.c:958
void fr_state_store_in_parent(request_t *child, void const *unique_ptr, int unique_int)
Store subrequest's session-state list and persistable request data in its parent.
Definition state.c:912
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
Types of values contained within an fr_value_box_t.
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.