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: eac3644d7872b0fba5b9ac998198b819721522db $
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: eac3644d7872b0fba5b9ac998198b819721522db $")
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/virtual_servers.h>
69#include <freeradius-devel/server/pair.h>
70#include <freeradius-devel/server/auth.h>
71#include <freeradius-devel/unlang/call.h>
72#include <freeradius-devel/unlang/interpret.h>
73#include <freeradius-devel/unlang/function.h>
74#include "types.h"
75#include "attrs.h"
76
79static fr_dict_t const *dict_tls;
80
83 { .out = &dict_freeradius, .proto = "freeradius" },
84 { .out = &dict_radius, .proto = "radius" },
85 { .out = &dict_tls, .proto = "tls" },
87};
88
107
110 { .out = &attr_chbind_response_code, .name = "Chbind-Response-Code", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
111 { .out = &attr_eap_identity, .name = "EAP-Identity", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
112 { .out = &attr_eap_session_id, .name = "EAP-Session-Id", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
113 { .out = &attr_eap_type, .name = "EAP-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
114 { .out = &attr_state, .name = "State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
115 { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
116 { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
117 { .out = &attr_eap_channel_binding_message, .name = "Vendor-Specific.UKERNA.EAP-Channel-Binding-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
118 { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
119 { .out = &attr_eap_msk, .name = "EAP-MSK", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
120 { .out = &attr_eap_emsk, .name = "EAP-EMSK", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
121 { .out = &attr_framed_mtu, .name = "Framed-MTU", .type = FR_TYPE_UINT32, .dict = &dict_radius },
122 { .out = &attr_freeradius_proxied_to, .name = "Vendor-Specific.FreeRADIUS.Proxied-To", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
123 { .out = &attr_ms_mppe_send_key, .name = "Vendor-Specific.Microsoft.MPPE-Send-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
124 { .out = &attr_ms_mppe_recv_key, .name = "Vendor-Specific.Microsoft.MPPE-Recv-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
125 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
126 { .out = &attr_tls_min_version, .name = "Min-Version", .type = FR_TYPE_FLOAT32, .dict = &dict_tls },
127 { .out = &attr_tls_max_version, .name = "Max-Version", .type = FR_TYPE_FLOAT32, .dict = &dict_tls },
128
130};
131
132void eap_packet_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *list, eap_packet_raw_t const *eap)
133{
134 int total, size;
135 uint8_t const *ptr;
136 fr_pair_t *vp;
137
138 total = eap->length[0] * 256 + eap->length[1];
139
140 if (total == 0) {
141 DEBUG("Asked to encode empty EAP-Message!");
142 return;
143 }
144
145 ptr = (uint8_t const *) eap;
146
147 do {
148 size = total;
149 if (size > 253) size = 253;
150
152 fr_pair_value_memdup(vp, ptr, size, false);
153
154 fr_pair_append(list, vp);
155
156 ptr += size;
157 total -= size;
158 } while (total > 0);
159}
160
161/** Basic EAP packet verifications & validations
162 *
163 * @param[in] ctx talloc ctx for the eap packet.
164 * @param[in] eap_packet_p to validate.
165 * @return
166 * - true the packet is valid.
167 * - false the packet is invalid.
168 */
169static bool eap_is_valid(TALLOC_CTX *ctx, eap_packet_raw_t **eap_packet_p)
170{
171 uint16_t len;
172 size_t packet_len;
173 eap_packet_raw_t *eap_packet = *eap_packet_p;
174
175 /*
176 * These length checks are also done by eap_packet_from_vp(),
177 * but that's OK. The static analysis tools aren't smart
178 * enough to figure that out.
179 */
180 packet_len = talloc_array_length((uint8_t *) eap_packet);
181 if (packet_len <= EAP_HEADER_LEN) {
182 fr_strerror_printf("Invalid EAP data length %zu <= 4", packet_len);
183 return false;
184 }
185
186 memcpy(&len, eap_packet->length, sizeof(uint16_t));
187 len = ntohs(len);
188
189 if ((len <= EAP_HEADER_LEN) || (len > packet_len)) {
190 fr_strerror_printf("Invalid EAP length field. Expected value in range %d-%zu, was %u bytes",
191 EAP_HEADER_LEN, packet_len, len);
192 return false;
193 }
194
195 /*
196 * The supplicant only sends us a response.
197 */
198 if (eap_packet->code != FR_EAP_CODE_RESPONSE) {
199 fr_strerror_printf("Invalid EAP code %d: Ignoring the packet", eap_packet->code);
200 return false;
201 }
202
203 /* we don't expect notification, but we send it */
204 if (eap_packet->data[0] == FR_EAP_METHOD_NOTIFICATION) {
205 fr_strerror_const("Got NOTIFICATION, Ignoring the packet");
206 return false;
207 }
208
209 /*
210 * Handle expanded types by smashing them to
211 * normal types.
212 */
213 if (eap_packet->data[0] == FR_EAP_EXPANDED_TYPE) {
214 uint8_t *p, *q;
215
216 if (len <= (EAP_HEADER_LEN + 1 + 3 + 4)) {
217 fr_strerror_const("Expanded EAP type is too short: ignoring the packet");
218 return false;
219 }
220
221 if ((eap_packet->data[1] != 0) ||
222 (eap_packet->data[2] != 0) ||
223 (eap_packet->data[3] != 0)) {
224 fr_strerror_const("Expanded EAP type has unknown Vendor-ID: ignoring the packet");
225 return false;
226 }
227
228 if ((eap_packet->data[4] != 0) ||
229 (eap_packet->data[5] != 0) ||
230 (eap_packet->data[6] != 0)) {
231 fr_strerror_const("Expanded EAP type has unknown Vendor-Type: ignoring the packet");
232 return false;
233 }
234
235 if ((eap_packet->data[7] <= FR_EAP_METHOD_NAK) ||
236 (eap_packet->data[7] >= FR_EAP_METHOD_MAX)) {
237 fr_strerror_printf("Unsupported Expanded EAP type %s (%u): ignoring the packet",
238 eap_type2name(eap_packet->data[7]), eap_packet->data[7]);
239 return false;
240 }
241
242 /*
243 * Re-write the EAP packet to NOT have the expanded type.
244 */
245 q = (uint8_t *) eap_packet;
246 memmove(q + EAP_HEADER_LEN, q + EAP_HEADER_LEN + 7, len - 7 - EAP_HEADER_LEN);
247
248 p = talloc_realloc(ctx, eap_packet, uint8_t, len - 7);
249 if (!p) {
250 fr_strerror_printf("Unsupported EAP type %s (%u): ignoring the packet",
251 eap_type2name(eap_packet->data[0]), eap_packet->data[0]);
252 return false;
253 }
254
255 len -= 7;
256 p[2] = (len >> 8) & 0xff;
257 p[3] = len & 0xff;
258
259 *eap_packet_p = (eap_packet_raw_t *)p;
260
261 return true;
262 }
263
264 if ((eap_packet->data[0] == 0) ||
265 (eap_packet->data[0] >= FR_EAP_METHOD_MAX)) {
266 fr_strerror_printf("Unsupported EAP type %s (%u): ignoring the packet",
267 eap_type2name(eap_packet->data[0]), eap_packet->data[0]);
268 return false;
269 }
270
271 return true;
272}
273
274/*
275 * Handles multiple EAP-Message attrs
276 * ie concatenates all to get the complete EAP packet.
277 *
278 * NOTE: Sometimes Framed-MTU might contain the length of EAP-Message,
279 * refer fragmentation in rfc2869.
280 */
282{
283 fr_pair_t *vp;
284 eap_packet_raw_t *eap_packet;
285 uint16_t len;
286
287 /*
288 * Get only EAP-Message attribute list
289 */
291 if (!vp) {
292 fr_strerror_const("EAP-Message not found");
293 return NULL;
294 }
295
296 /*
297 * Sanity check the length before doing anything.
298 */
299 if (vp->vp_length < EAP_HEADER_LEN) {
300 fr_strerror_const("EAP packet is too short");
301 return NULL;
302 }
303
304 /*
305 * Get the Actual length from the EAP packet
306 * First EAP-Message contains the EAP packet header
307 */
308 memcpy(&len, vp->vp_strvalue + 2, sizeof(len));
309 len = ntohs(len);
310
311 /*
312 * Take out even more weird things.
313 */
314 if (len < EAP_HEADER_LEN) {
315 fr_strerror_const("EAP packet has invalid length (less than 4 bytes)");
316 return NULL;
317 }
318
319
320 /*
321 * If the data is SMALLER than the requested length, die, too.
322 */
323 if (vp->vp_length < len) {
324 fr_strerror_printf("Malformed EAP packet. Length in packet header does not "
325 "match actual length");
326 return NULL;
327 }
328
329 /*
330 * Now that we know the lengths are OK, allocate memory.
331 */
332 eap_packet = (eap_packet_raw_t *) talloc_memdup(ctx, vp->vp_octets, len);
333 if (!eap_packet) return NULL;
334
335 /*
336 * Do more in-depth validity checks.
337 */
338 if (!eap_is_valid(ctx, &eap_packet)) {
339 talloc_free(eap_packet);
340 return NULL;
341 }
342
343 return eap_packet;
344}
345
346/*
347 * Add raw hex data to the reply.
348 */
349void eap_add_reply(request_t *request, fr_dict_attr_t const *da, uint8_t const *value, int len)
350{
351 fr_pair_t *vp;
352
353 MEM(pair_update_reply(&vp, da) >= 0);
354 fr_pair_value_memdup(vp, value, len, false);
355
356 RINDENT();
357 RDEBUG2("reply.%pP", vp);
358 REXDENT();
359}
360
361/** Handle the result of running a subrequest through a virtual server
362 *
363 * Storing the value of the State attribute in readiness for the next round.
364 */
366 request_t *request, void *uctx)
367{
368 eap_session_t *eap_session = talloc_get_type_abort(uctx, eap_session_t);
369
370 /*
371 * Grab the child's session state for re-use in the next round
372 */
374
376}
377
378/** Run a subrequest through a virtual server
379 *
380 * If eap_session_t has a child_state, inject that as an attribute in the request.
381 *
382 * @param[in] request the current (real) request.
383 * @param[in] eap_session representing the outer eap method.
384 * @param[in] virtual_server The virtual server to send the request to.
385 * @return
386 * - UNLANG_ACTION_PUSHED_CHILD on success
387 * - UNLANG_ACTION_FAIL on error
388 */
390{
391 fr_pair_t *vp;
392
393 fr_assert(request->parent);
394 fr_assert(virtual_server);
395
396 RDEBUG2("Running request through virtual server \"%s\"", cf_section_name2(virtual_server_cs(virtual_server)));
397
398 /*
399 * Re-present the previously stored child's session state if there is one
400 */
402
403 if (fr_pair_prepend_by_da(request->request_ctx, &vp, &request->request_pairs,
406
407 if (unlang_function_push_with_result(/* transparent */ unlang_interpret_result(request),
408 request,
409 NULL,
411 NULL, 0,
413 eap_session) < 0) return UNLANG_ACTION_FAIL;
414
415 if (unlang_call_push(NULL, request, virtual_server_cs(virtual_server), UNLANG_SUB_FRAME) < 0) return UNLANG_ACTION_FAIL;
416
418}
419
420/** Initialise the lib eap base library
421 *
422 */
424{
426 PERROR("%s", __FUNCTION__);
427 return -1;
428 }
429
430 /*
431 * But main_config.c does read the dictionaries before
432 * loading modules, so these have to exist.
433 */
435 PERROR("%s", __FUNCTION__);
437 return -1;
438 }
439
440 return 0;
441}
442
443/** De-init the lib eap base library
444 *
445 */
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:487
#define UNUSED
Definition build.h:317
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:36
@ FR_RADIUS_CODE_ACCESS_REQUEST
RFC2865 - Access-Request.
Definition defs.h:33
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
#define fr_dict_autofree(_to_free)
Definition dict.h:917
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:294
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:307
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:4396
#define fr_dict_autoload(_to_load)
Definition dict.h:914
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:313
Specifies an attribute which must be present for the module to function.
Definition dict.h:293
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:306
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:1583
#define UNLANG_SUB_FRAME
Definition interpret.h:37
fr_dict_attr_autoload_t eap_base_dict_attr[]
Definition base.c:109
fr_dict_attr_t const * attr_packet_type
Definition base.c:93
void eap_packet_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *list, eap_packet_raw_t const *eap)
Definition base.c:132
fr_dict_attr_t const * attr_eap_session_id
Definition base.c:90
fr_dict_attr_t const * attr_state
Definition base.c:103
fr_dict_attr_t const * attr_eap_identity
Definition base.c:91
fr_dict_attr_t const * attr_freeradius_proxied_to
Definition base.c:100
fr_dict_attr_t const * attr_chbind_response_code
Definition base.c:89
fr_dict_attr_t const * attr_eap_message
Definition base.c:96
fr_dict_attr_t const * attr_eap_type
Definition base.c:92
fr_dict_attr_t const * attr_eap_msk
Definition base.c:97
fr_dict_attr_t const * attr_eap_channel_binding_message
Definition base.c:95
fr_dict_t const * dict_freeradius
Definition base.c:77
static fr_dict_t const * dict_tls
Definition base.c:79
fr_dict_attr_t const * attr_tls_min_version
Definition base.c:105
fr_dict_t const * dict_radius
Definition base.c:78
int eap_base_init(void)
Initialise the lib eap base library.
Definition base.c:423
void eap_base_free(void)
De-init the lib eap base library.
Definition base.c:446
eap_packet_raw_t * eap_packet_from_vp(TALLOC_CTX *ctx, fr_pair_list_t *vps)
Definition base.c:281
fr_dict_attr_t const * attr_eap_emsk
Definition base.c:98
fr_dict_attr_t const * attr_ms_mppe_send_key
Definition base.c:101
fr_dict_attr_t const * attr_tls_max_version
Definition base.c:106
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:365
fr_dict_attr_t const * attr_user_name
Definition base.c:104
static bool eap_is_valid(TALLOC_CTX *ctx, eap_packet_raw_t **eap_packet_p)
Basic EAP packet verifications & validations.
Definition base.c:169
fr_dict_attr_t const * attr_framed_mtu
Definition base.c:99
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:389
fr_dict_attr_t const * attr_ms_mppe_recv_key
Definition base.c:102
fr_dict_autoload_t eap_base_dict[]
Definition base.c:82
void eap_add_reply(request_t *request, fr_dict_attr_t const *da, uint8_t const *value, int len)
Definition base.c:349
fr_dict_attr_t const * attr_message_authenticator
Definition base.c:94
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:2966
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:38
#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.