The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_eap_fast.c
Go to the documentation of this file.
1 /*
2  * This program 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: 2b126812c0f442c6c6af6595d8ef55bc8b2d2350 $
19  * @file rlm_eap_fast.c
20  * @brief contains the interfaces that are called from eap
21  *
22  * @author Alexander Clouter (alex@digriz.org.uk)
23  *
24  * @copyright 2016 Alan DeKok (aland@freeradius.org)
25  * @copyright 2016 The FreeRADIUS server project
26  */
27 RCSID("$Id: 2b126812c0f442c6c6af6595d8ef55bc8b2d2350 $")
28 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
29 
30 #include <freeradius-devel/util/md5.h>
31 
32 #include "eap_fast.h"
33 #include "eap_fast_crypto.h"
34 
35 typedef struct {
36  SSL_CTX *ssl_ctx; //!< Thread local SSL_CTX.
38 
39 /*
40  * An instance of EAP-FAST
41  */
42 typedef struct {
43  char const *tls_conf_name; //!< Name of shared TLS config.
44  fr_tls_conf_t *tls_conf; //!< TLS config pointer.
45 
48 
49  char const *virtual_server; //!< Virtual server to use for processing
50  //!< inner EAP method.
52  char const *cipher_list; //!< cipher list specific to EAP-FAST
53  bool req_client_cert; //!< Whether we require a client cert
54  //!< in the outer tunnel.
55 
56  int stage; //!< Processing stage.
57 
58  fr_time_delta_t pac_lifetime; //!< seconds to add to current time to describe PAC lifetime
59  char const *authority_identity; //!< The identity we present in the EAP-TLS
60  uint8_t a_id[PAC_A_ID_LENGTH]; //!< The identity we present in the EAP-TLS
61  char const *pac_opaque_key; //!< The key used to encrypt PAC-Opaque
63 
64 
66  { FR_CONF_OFFSET("tls", rlm_eap_fast_t, tls_conf_name) },
67 
68  { FR_CONF_OFFSET("default_provisioning_eap_type", rlm_eap_fast_t, default_provisioning_method_name), .dflt = "mschapv2" },
69 
70  { FR_CONF_OFFSET_FLAGS("virtual_server", CONF_FLAG_REQUIRED | CONF_FLAG_NOT_EMPTY, rlm_eap_fast_t, virtual_server) },
71  { FR_CONF_OFFSET("cipher_list", rlm_eap_fast_t, cipher_list) },
72 
73  { FR_CONF_OFFSET("require_client_cert", rlm_eap_fast_t, req_client_cert), .dflt = "no" },
74 
75  { FR_CONF_OFFSET("pac_lifetime", rlm_eap_fast_t, pac_lifetime), .dflt = "604800" },
76  { FR_CONF_OFFSET_FLAGS("authority_identity", CONF_FLAG_REQUIRED, rlm_eap_fast_t, authority_identity) },
77  { FR_CONF_OFFSET_FLAGS("pac_opaque_key", CONF_FLAG_REQUIRED, rlm_eap_fast_t, pac_opaque_key) },
78 
80 };
81 
82 static fr_dict_t const *dict_freeradius;
83 static fr_dict_t const *dict_radius;
85 
88  { .out = &dict_freeradius, .proto = "freeradius" },
89  { .out = &dict_radius, .proto = "radius" },
90  { .out = &dict_eap_fast, .base_dir = "eap/fast", .proto = "eap-fast" },
91  { NULL }
92 };
93 
101 
108 
135 
138  { .out = &attr_eap_emsk, .name = "EAP-EMSK", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
139  { .out = &attr_eap_msk, .name = "EAP-MSK", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
140  { .out = &attr_eap_tls_require_client_cert, .name = "EAP-TLS-Require-Client-Cert", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
141  { .out = &attr_eap_type, .name = "EAP-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
142  { .out = &attr_ms_chap_challenge, .name = "Vendor-Specific.Microsoft.CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
143  { .out = &attr_ms_chap_peer_challenge, .name = "MS-CHAP-Peer-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_freeradius },
144  { .out = &attr_proxy_to_realm, .name = "Proxy-To-Realm", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
145 
146  { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
147  { .out = &attr_freeradius_proxied_to, .name = "Vendor-Specific.FreeRADIUS.Proxied-To", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
148  { .out = &attr_ms_mppe_send_key, .name = "Vendor-Specific.Microsoft.MPPE-Send-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
149  { .out = &attr_ms_mppe_recv_key, .name = "Vendor-Specific.Microsoft.MPPE-Recv-Key", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
150  { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
151  { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
152 
153  { .out = &attr_eap_fast_crypto_binding, .name = "Crypto-Binding", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
154  { .out = &attr_eap_fast_eap_payload, .name = "EAP-Payload", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
155  { .out = &attr_eap_fast_error, .name = "Error", .type = FR_TYPE_UINT32, .dict = &dict_eap_fast },
156  { .out = &attr_eap_fast_intermediate_result, .name = "Intermediate-Result", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
157  { .out = &attr_eap_fast_nak, .name = "NAK", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
158  { .out = &attr_eap_fast_pac_a_id, .name = "PAC.A-ID", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
159  { .out = &attr_eap_fast_pac_a_id_info, .name = "PAC.A-ID-Info", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
160  { .out = &attr_eap_fast_pac_acknowledge, .name = "PAC.Acknowledge", .type = FR_TYPE_UINT16, .dict = &dict_eap_fast },
161  { .out = &attr_eap_fast_pac_i_id, .name = "PAC.I-ID", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
162  { .out = &attr_eap_fast_pac_info_a_id, .name = "PAC.Info.A-ID", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
163  { .out = &attr_eap_fast_pac_info_a_id_info, .name = "PAC.Info.A-ID-Info", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
164  { .out = &attr_eap_fast_pac_info_i_id, .name = "PAC.Info.I-ID", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
165  { .out = &attr_eap_fast_pac_info_pac_lifetime, .name = "PAC.Info.PAC-Lifetime", .type = FR_TYPE_UINT32, .dict = &dict_eap_fast },
166  { .out = &attr_eap_fast_pac_info_pac_type, .name = "PAC.Info.PAC-Type", .type = FR_TYPE_UINT16, .dict = &dict_eap_fast },
167  { .out = &attr_eap_fast_pac_info_tlv, .name = "PAC.Info", .type = FR_TYPE_TLV, .dict = &dict_eap_fast },
168  { .out = &attr_eap_fast_pac_key, .name = "PAC.Key", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
169  { .out = &attr_eap_fast_pac_lifetime, .name = "PAC.Lifetime", .type = FR_TYPE_UINT32, .dict = &dict_eap_fast },
170  { .out = &attr_eap_fast_pac_opaque_i_id, .name = "PAC.Opaque.I-ID", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
171  { .out = &attr_eap_fast_pac_opaque_pac_key, .name = "PAC.Opaque.PAC-Key", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
172  { .out = &attr_eap_fast_pac_opaque_pac_lifetime, .name = "PAC.Opaque.PAC-Lifetime", .type = FR_TYPE_UINT32, .dict = &dict_eap_fast },
173  { .out = &attr_eap_fast_pac_opaque_pac_type, .name = "PAC.Opaque.PAC-Type", .type = FR_TYPE_UINT16, .dict = &dict_eap_fast },
174  { .out = &attr_eap_fast_pac_opaque_tlv, .name = "PAC.Opaque", .type = FR_TYPE_TLV, .dict = &dict_eap_fast },
175  { .out = &attr_eap_fast_pac_tlv, .name = "PAC", .type = FR_TYPE_TLV, .dict = &dict_eap_fast },
176  { .out = &attr_eap_fast_pac_type, .name = "PAC.Type", .type = FR_TYPE_UINT16, .dict = &dict_eap_fast },
177  { .out = &attr_eap_fast_result, .name = "Result", .type = FR_TYPE_UINT16, .dict = &dict_eap_fast },
178  { .out = &attr_eap_fast_vendor_specific, .name = "Vendor-Specific", .type = FR_TYPE_OCTETS, .dict = &dict_eap_fast },
179 
180  { NULL }
181 };
182 
183 /** Allocate the FAST per-session data
184  *
185  */
186 static eap_fast_tunnel_t *eap_fast_alloc(TALLOC_CTX *ctx, rlm_eap_fast_t const *inst)
187 {
188  eap_fast_tunnel_t *t = talloc_zero(ctx, eap_fast_tunnel_t);
189 
190  t->mode = EAP_FAST_UNKNOWN;
192 
193  t->default_provisioning_method = inst->default_provisioning_method;
194 
195  t->pac_lifetime = inst->pac_lifetime;
196  t->authority_identity = inst->authority_identity;
197  t->a_id = inst->a_id;
198  t->pac_opaque_key = (uint8_t const *)inst->pac_opaque_key;
199 
200  t->server_cs = inst->server_cs;
201 
202  return t;
203 }
204 
205 static void eap_fast_session_ticket(fr_tls_session_t *tls_session, const SSL *s,
206  uint8_t *secret, int *secret_len)
207 {
208  eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
209  uint8_t seed[2 * SSL3_RANDOM_SIZE];
210 
211  fr_assert(t->pac.key);
212 
213  SSL_get_server_random(s, seed, SSL3_RANDOM_SIZE);
214  SSL_get_client_random(s, &seed[SSL3_RANDOM_SIZE], SSL3_RANDOM_SIZE);
215 
216  T_PRF(t->pac.key, PAC_KEY_LENGTH, "PAC to master secret label hash",
217  seed, sizeof(seed), secret, SSL_MAX_MASTER_KEY_LENGTH);
218  *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
219 }
220 
221 static int _session_secret(SSL *s, void *secret, int *secret_len,
222  UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers,
223  UNUSED SSL_CIPHER const **cipher, void *arg)
224 {
225  // FIXME enforce non-anon cipher
226 
227  request_t *request = fr_tls_session_request(s);
228  fr_tls_session_t *tls_session = arg;
230 
231  if (!tls_session) return 0;
232 
233  t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
234 
235  if (!t->pac.key) return 0;
236 
237  RDEBUG2("processing PAC-Opaque");
238 
239  eap_fast_session_ticket(tls_session, s, secret, secret_len);
240 
241  memset(t->pac.key, 0, PAC_KEY_LENGTH);
242  talloc_free(t->pac.key);
243  t->pac.key = NULL;
244 
245  return 1;
246 }
247 
248 /*
249  * hints from hostap:src/crypto/tls_openssl.c:fr_tls_session_ticket_ext_cb()
250  *
251  * N.B. we actually always tell OpenSSL we have digested the ticket so that
252  * it does not cause a fail loop and enables us to update the PAC easily
253  *
254  */
255 static int _session_ticket(SSL *s, uint8_t const *data, int len, void *arg)
256 {
257  fr_tls_session_t *tls_session = talloc_get_type_abort(arg, fr_tls_session_t);
258  request_t *request = fr_tls_session_request(s);
260  fr_pair_list_t fast_vps;
261  fr_pair_t *vp;
262  char const *errmsg;
263  int dlen, plen;
264  uint16_t length;
266  eap_fast_attr_pac_opaque_t opaque_plaintext;
267 
268  if (!tls_session) return 0;
269 
270  fr_pair_list_init(&fast_vps);
271  t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);
272 
273  RDEBUG2("PAC provided via ClientHello SessionTicket extension");
274  RHEXDUMP3(data, len, "PAC-Opaque");
275 
276  if ((ntohs(opaque->hdr.type) & EAP_FAST_TLV_TYPE) != attr_eap_fast_pac_opaque_tlv->attr) {
277  errmsg = "PAC is not of type Opaque";
278 error:
279  RERROR("%s, sending alert to client", errmsg);
280  if (fr_tls_session_alert(request, tls_session, SSL3_AL_FATAL, SSL_AD_BAD_CERTIFICATE)) {
281  RERROR("too many alerts");
282  return 0;
283  }
284  if (t->pac.key) talloc_free(t->pac.key);
285 
286  memset(&t->pac, 0, sizeof(t->pac));
287  if (!fr_pair_list_empty(&fast_vps)) fr_pair_list_free(&fast_vps);
288  return 1;
289  }
290 
291  /*
292  * we would like to use the length of the SessionTicket
293  * but Cisco hates everyone and sends a zero padding payload
294  * so we have to use the length in the PAC-Opaque header
295  */
296  length = ntohs(opaque->hdr.length);
297  if (len - sizeof(opaque->hdr) < length) {
298  errmsg = "PAC has bad length in header";
299  goto error;
300  }
301 
302  if (length < PAC_A_ID_LENGTH + EVP_MAX_IV_LENGTH + EVP_GCM_TLS_TAG_LEN + 1) {
303  errmsg = "PAC file too short";
304  goto error;
305  }
306 
307  if (memcmp(opaque->aad, t->a_id, PAC_A_ID_LENGTH)) {
308  errmsg = "PAC has incorrect A_ID";
309  goto error;
310  }
311 
312  dlen = length - sizeof(opaque->aad) - sizeof(opaque->iv) - sizeof(opaque->tag);
313  plen = eap_fast_decrypt(opaque->data, dlen, opaque->aad, PAC_A_ID_LENGTH,
314  (uint8_t const *) opaque->tag, t->pac_opaque_key, opaque->iv,
315  (uint8_t *)&opaque_plaintext);
316  if (plen == -1) {
317  errmsg = "PAC failed to decrypt";
318  goto error;
319  }
320 
321  RHEXDUMP3((uint8_t const *)&opaque_plaintext, plen, "PAC-Opaque plaintext data section");
322 
323  if (eap_fast_decode_pair(tls_session, &fast_vps, attr_eap_fast_pac_opaque_tlv, (uint8_t *)&opaque_plaintext, plen, NULL) < 0) {
324  errmsg = fr_strerror();
325  goto error;
326  }
327 
328  for (vp = fr_pair_list_head(&fast_vps);
329  vp;
330  vp = fr_pair_list_next(&fast_vps, vp)) {
332  fr_assert(t->pac.type == 0);
333  t->pac.type = vp->vp_uint16;
334  } else if (vp->da == attr_eap_fast_pac_info_pac_lifetime) {
335  fr_assert(fr_time_eq(t->pac.expires, fr_time_wrap(0)));
336  t->pac.expires = fr_time_add(request->packet->timestamp, vp->vp_time_delta);
337  t->pac.expired = false;
338  /*
339  * Not sure if this is the correct attr
340  * The original enum didn't match a specific TLV nesting level
341  */
342  } else if (vp->da == attr_eap_fast_pac_key) {
343  fr_assert(t->pac.key == NULL);
344  fr_assert(vp->vp_length == PAC_KEY_LENGTH);
345  t->pac.key = talloc_array(t, uint8_t, PAC_KEY_LENGTH);
346  fr_assert(t->pac.key != NULL);
347  memcpy(t->pac.key, vp->vp_octets, PAC_KEY_LENGTH);
348  } else {
349  RERROR("unknown TLV: %pP", vp);
350  errmsg = "unknown TLV";
351  goto error;
352  }
353  }
354 
355  fr_pair_list_free(&fast_vps);
356 
357  if (!t->pac.type) {
358  errmsg = "PAC missing type TLV";
359  goto error;
360  }
361 
362  if (t->pac.type != PAC_TYPE_TUNNEL) {
363  errmsg = "PAC is of not of tunnel type";
364  goto error;
365  }
366 
367  if (fr_time_eq(t->pac.expires, fr_time_wrap(0))) {
368  errmsg = "PAC missing lifetime TLV";
369  goto error;
370  }
371 
372  if (!t->pac.key) {
373  errmsg = "PAC missing key TLV";
374  goto error;
375  }
376 
377  if (!SSL_set_session_secret_cb(tls_session->ssl, _session_secret, tls_session)) {
378  RERROR("Failed setting SSL session secret callback");
379  return 0;
380  }
381 
382  return 1;
383 }
384 
386 {
387  eap_session_t *eap_session = talloc_get_type_abort(mctx->rctx, eap_session_t);
388  eap_tls_session_t *eap_tls_session = talloc_get_type_abort(eap_session->opaque, eap_tls_session_t);
389  fr_tls_session_t *tls_session = eap_tls_session->tls_session;
390 
391  if ((eap_tls_session->state == EAP_TLS_INVALID) || (eap_tls_session->state == EAP_TLS_FAIL)) {
392  REDEBUG("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
393  } else {
394  RDEBUG2("[eap-tls process] = %s", fr_table_str_by_value(eap_tls_status_table, eap_tls_session->state, "<INVALID>"));
395  }
396 
397  switch (eap_tls_session->state) {
398  /*
399  * EAP-TLS handshake was successful, tell the
400  * client to keep talking.
401  *
402  * If this was EAP-TLS, we would just return
403  * an EAP-TLS-Success packet here.
404  */
405  case EAP_TLS_ESTABLISHED:
406  fr_tls_session_send(request, tls_session);
407  fr_assert(tls_session->opaque != NULL);
408  break;
409 
410  /*
411  * The TLS code is still working on the TLS
412  * exchange, and it's a valid TLS request.
413  * do nothing.
414  */
415  case EAP_TLS_HANDLED:
417 
418  /*
419  * Handshake is done, proceed with decoding tunneled
420  * data.
421  */
423  break;
424 
425  /*
426  * Anything else: fail.
427  */
428  default:
430  }
431 
432  /*
433  * Session is established, proceed with decoding
434  * tunneled data.
435  */
436  RDEBUG2("Session established. Proceeding to decode tunneled attributes");
437 
438  /*
439  * Process the FAST portion of the request.
440  */
441  switch (eap_fast_process(request, eap_session, tls_session)) {
443  eap_tls_fail(request, eap_session);
445 
446  /*
447  * Access-Challenge, continue tunneled conversation.
448  */
450  fr_tls_session_send(request, tls_session);
451  eap_tls_request(request, eap_session);
453 
454  /*
455  * Success.
456  */
458  if (eap_tls_success(request, eap_session, NULL) < 0) RETURN_MODULE_FAIL;
459 
460  /*
461  * @todo - generate MPPE keys, which have their own magical deriviation.
462  */
463 
464  /*
465  * Result is always OK, even if we fail to persist the
466  * session data.
467  */
468  *p_result = RLM_MODULE_OK;
469 
470  /*
471  * Write the session to the session cache
472  *
473  * We do this here (instead of relying on OpenSSL to call the
474  * session caching callback), because we only want to write
475  * session data to the cache if all phases were successful.
476  *
477  * If we wrote out the cache data earlier, and the server
478  * exited whilst the session was in progress, the supplicant
479  * could resume the session (and get access) even if phase2
480  * never completed.
481  */
482  return fr_tls_cache_pending_push(request, tls_session);
483 
484  /*
485  * No response packet, MUST be proxying it.
486  * The main EAP module will take care of discovering
487  * that the request now has a "proxy" packet, and
488  * will proxy it, rather than returning an EAP packet.
489  */
492 
493  default:
494  break;
495  }
496 
497  /*
498  * Something we don't understand: Reject it.
499  */
500  eap_tls_fail(request, eap_session);
502 }
503 
504 /*
505  * Do authentication, by letting EAP-TLS do most of the work.
506  */
508  request_t *request)
509 {
510  eap_session_t *eap_session = eap_session_get(request->parent);
511 
512  /*
513  * Setup the resumption frame to process the result
514  */
515  (void)unlang_module_yield(request, mod_handshake_resume, NULL, 0, eap_session);
516 
517  /*
518  * Process TLS layer until done.
519  */
520  return eap_tls_process(request, eap_session);
521 }
522 
523 /*
524  * Send an initial eap-tls request to the peer, using the libeap functions.
525  */
526 static unlang_action_t mod_session_init(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
527 {
529  rlm_eap_fast_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_eap_fast_thread_t);
530  eap_session_t *eap_session = eap_session_get(request->parent);
531  eap_tls_session_t *eap_tls_session;
532  fr_tls_session_t *tls_session;
533 
534  fr_pair_t *vp;
535  bool client_cert;
536 
537  eap_session->tls = true;
538 
539  /*
540  * EAP-TLS-Require-Client-Cert attribute will override
541  * the require_client_cert configuration option.
542  */
543  vp = fr_pair_find_by_da(&request->control_pairs, NULL, attr_eap_tls_require_client_cert);
544  if (vp) {
545  client_cert = vp->vp_uint32 ? true : false;
546  } else {
547  client_cert = inst->req_client_cert;
548  }
549 
550  eap_session->opaque = eap_tls_session = eap_tls_session_init(request, eap_session, thread->ssl_ctx, client_cert);
551  if (!eap_tls_session) RETURN_MODULE_FAIL;
552 
553  tls_session = eap_tls_session->tls_session;
554 
555  if (inst->cipher_list) {
556  RDEBUG2("Over-riding main cipher list with '%s'", inst->cipher_list);
557 
558  if (!SSL_set_cipher_list(tls_session->ssl, inst->cipher_list)) {
559  REDEBUG("Failed over-riding cipher list to '%s'. EAP-FAST will likely not work",
560  inst->cipher_list);
561  }
562  }
563 
564 #ifdef SSL_OP_NO_TLSv1_2
565  /*
566  * Forcibly disable TLSv1.2
567  */
568  SSL_set_options(tls_session->ssl, SSL_OP_NO_TLSv1_2);
569 #endif
570 
571  /*
572  * Push TLV of authority_identity into tls_record
573  * call eap_tls_compose() with args
574  *
575  * RFC 4851 section 4.1.1
576  * N.B. mandatory/reserved flags are not applicable here
577  */
579 
580  /*
581  * TLS session initialization is over. Now handle TLS
582  * related handshaking or application data.
583  */
584  if (eap_tls_compose(request, eap_session, EAP_TLS_START_SEND,
585  SET_START(eap_tls_session->base_flags) | EAP_FAST_VERSION,
586  &tls_session->clean_in, tls_session->clean_in.used,
587  tls_session->clean_in.used) < 0) {
588  talloc_free(tls_session);
590  }
591 
592  tls_session->record_init(&tls_session->clean_in);
593  tls_session->opaque = eap_fast_alloc(tls_session, inst);
594  eap_session->process = mod_handshake_process;
595 
596  if (!SSL_set_session_ticket_ext_cb(tls_session->ssl, _session_ticket, tls_session)) {
597  RERROR("Failed setting SSL session ticket callback");
599  }
600 
602 }
603 
605 {
606  rlm_eap_fast_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_fast_t);
607  rlm_eap_fast_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_fast_thread_t);
608 
609  t->ssl_ctx = fr_tls_ctx_alloc(inst->tls_conf, false);
610  if (!t->ssl_ctx) return -1;
611 
612  return 0;
613 }
614 
616 {
617  rlm_eap_fast_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_eap_fast_thread_t);
618 
619  if (likely(t->ssl_ctx != NULL)) SSL_CTX_free(t->ssl_ctx);
620  t->ssl_ctx = NULL;
621 
622  return 0;
623 }
624 
625 /*
626  * Attach the module.
627  */
628 static int mod_instantiate(module_inst_ctx_t const *mctx)
629 {
630  rlm_eap_fast_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_eap_fast_t);
631  CONF_SECTION *conf = mctx->mi->conf;
632  virtual_server_t const *virtual_server = virtual_server_find(inst->virtual_server);
633 
634  if (!virtual_server) {
635  cf_log_err_by_child(mctx->mi->conf, "virtual_server", "Unknown virtual server '%s'",
636  inst->virtual_server);
637  return -1;
638  }
639 
640  inst->server_cs = virtual_server_cs(virtual_server);
641  if (!inst->server_cs) {
642  cf_log_err_by_child(conf, "virtual_server", "Virtual server \"%s\" missing", inst->virtual_server);
643  return -1;
644  }
645 
646  inst->default_provisioning_method = eap_name2type(inst->default_provisioning_method_name);
647  if (!inst->default_provisioning_method) {
648  cf_log_err_by_child(conf, "default_provisioning_eap_type", "Unknown EAP type %s",
649  inst->default_provisioning_method_name);
650  return -1;
651  }
652 
653  /*
654  * Read tls configuration, either from group given by 'tls'
655  * option, or from the eap-tls configuration.
656  */
657  inst->tls_conf = eap_tls_conf_parse(conf, "tls");
658 
659  if (!inst->tls_conf) {
660  cf_log_err_by_child(conf, "tls", "Failed initializing SSL context");
661  return -1;
662  }
663 
664  if (talloc_array_length(inst->pac_opaque_key) - 1 != 32) {
665  cf_log_err_by_child(conf, "pac_opaque_key", "Must be 32 bytes long");
666  return -1;
667  }
668 
669  /*
670  * Allow anything for the TLS version, we try to forcibly
671  * disable TLSv1.2 later.
672  */
673  if (inst->tls_conf->tls_min_version > (float) 1.1) {
674  cf_log_err_by_child(conf, "tls_min_version", "require tls_min_version <= 1.1");
675  return -1;
676  }
677 
678  if (!fr_time_delta_ispos(inst->pac_lifetime)) {
679  cf_log_err_by_child(conf, "pac_lifetime", "must be non-zero");
680  return -1;
681  }
682 
684 
685  fr_md5_calc(inst->a_id, (uint8_t const *)inst->authority_identity,
686  talloc_array_length(inst->authority_identity) - 1);
687 
688  return 0;
689 }
690 
691 /*
692  * The module name should be the only globally exported symbol.
693  * That is, everything else should be 'static'.
694  */
697  .common = {
698  .magic = MODULE_MAGIC_INIT,
699  .name = "eap_fast",
700 
701  .inst_size = sizeof(rlm_eap_fast_t),
703  .instantiate = mod_instantiate, /* Create new submodule instance */
704 
705  .thread_inst_size = sizeof(rlm_eap_fast_thread_t),
706  .thread_instantiate = mod_thread_instantiate,
707  .thread_detach = mod_thread_detach,
708  },
709  .provides = { FR_EAP_METHOD_FAST },
710  .session_init = mod_session_init, /* Initialise a new EAP session */
711 };
#define true
Definition: abinary.c:57
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
#define USES_APPLE_DEPRECATED_API
Definition: build.h:468
#define RCSID(id)
Definition: build.h:481
#define UNUSED
Definition: build.h:313
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:256
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: cf_parse.h:405
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition: cf_parse.h:420
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
#define cf_log_err_by_child(_parent, _child, _fmt,...)
Log an error message against a specified child.
Definition: cf_util.h:316
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
Definition: defs.h:43
@ FR_RADIUS_CODE_STATUS_CLIENT
RFC2865/RFC5997 - Status Server (response)
Definition: defs.h:45
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
Definition: defs.h:34
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
Definition: defs.h:35
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:267
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:280
Specifies an attribute which must be present for the module to function.
Definition: dict.h:266
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:279
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
eap_type_t eap_name2type(char const *name)
Return an EAP-Type for a particular name.
Definition: types.c:38
@ FR_EAP_METHOD_FAST
Definition: types.h:89
ssize_t eap_fast_decode_pair(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
FIXME do something with mandatory.
Definition: eap_fast.c:428
void eap_fast_tlv_append(fr_tls_session_t *tls_session, fr_dict_attr_t const *tlv, bool mandatory, int length, void const *data)
Definition: eap_fast.c:108
fr_radius_packet_code_t eap_fast_process(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
Definition: eap_fast.c:898
Function declarations and packet structures.
uint8_t const * a_id
Definition: eap_fast.h:189
unsigned char aad[PAC_A_ID_LENGTH]
Definition: eap_fast.h:122
eap_fast_stage_t stage
Definition: eap_fast.h:172
#define PAC_A_ID_LENGTH
Definition: eap_fast.h:75
#define EAP_FAST_VERSION
Definition: eap_fast.h:34
fr_time_delta_t pac_lifetime
Definition: eap_fast.h:187
#define EAP_FAST_TLV_TYPE
Definition: eap_fast.h:43
int default_provisioning_method
Definition: eap_fast.h:185
unsigned char iv[EVP_MAX_IV_LENGTH]
Definition: eap_fast.h:123
eap_fast_pac_attr_hdr_t hdr
Definition: eap_fast.h:121
unsigned char tag[EVP_GCM_TLS_TAG_LEN]
Definition: eap_fast.h:124
char const * authority_identity
Definition: eap_fast.h:188
struct eap_fast_tunnel_t::@159 pac
uint8_t data[sizeof(eap_fast_attr_pac_opaque_plaintext_t) *2]
Definition: eap_fast.h:125
@ EAP_FAST_TLS_SESSION_HANDSHAKE
Definition: eap_fast.h:53
#define PAC_KEY_LENGTH
Definition: eap_fast.h:74
@ EAP_FAST_UNKNOWN
Definition: eap_fast.h:61
CONF_SECTION * server_cs
Definition: eap_fast.h:206
@ PAC_TYPE_TUNNEL
Definition: eap_fast.h:68
uint8_t const * pac_opaque_key
Definition: eap_fast.h:190
int eap_fast_decrypt(uint8_t const *ciphertext, size_t ciphertext_len, uint8_t const *aad, size_t aad_len, uint8_t const *tag, uint8_t const *key, uint8_t const *iv, uint8_t *plaintext)
USES_APPLE_DEPRECATED_API void T_PRF(unsigned char const *secret, unsigned int secret_len, char const *prf_label, unsigned char const *seed, unsigned int seed_len, unsigned char *out, unsigned int out_len)
Crypto function declarations.
void * opaque
Opaque data used by EAP methods.
Definition: session.h:62
bool tls
Whether EAP method uses TLS.
Definition: session.h:70
module_method_t process
Callback that should be used to process the next round.
Definition: session.h:64
static eap_session_t * eap_session_get(request_t *request)
Definition: session.h:82
Tracks the progress of a single session of any EAP method.
Definition: session.h:40
#define RERROR(fmt,...)
Definition: log.h:298
#define RHEXDUMP3(_data, _len, _fmt,...)
Definition: log.h:705
talloc_free(reap)
#define MD5_DIGEST_LENGTH
Definition: merged_model.c:248
unsigned short uint16_t
Definition: merged_model.c:31
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT16
16 Bit unsigned integer.
Definition: merged_model.c:98
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
void fr_md5_calc(uint8_t out[static MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Perform a single digest operation on a single input buffer.
Definition: merged_model.c:251
unsigned char uint8_t
Definition: merged_model.c:30
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:42
void * thread
Thread specific instance data.
Definition: module_ctx.h:43
void * rctx
Resume ctx that a module previously set.
Definition: module_ctx.h:45
void * thread
Thread instance data.
Definition: module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:64
module_instance_t * mi
Instance of the module being instantiated.
Definition: module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:50
Temporary structure to hold arguments for thread_instantiation calls.
Definition: module_ctx.h:63
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:693
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
static const conf_parser_t config[]
Definition: base.c:183
static char * secret
Definition: radclient-ng.c:69
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
static rs_t * conf
Definition: radsniff.c:53
#define RETURN_MODULE_HANDLED
Definition: rcode.h:58
#define RETURN_MODULE_OK
Definition: rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_OK
The module is OK, continue.
Definition: rcode.h:43
int stage
Processing stage.
Definition: rlm_eap_fast.c:56
fr_dict_attr_t const * attr_eap_fast_pac_a_id_info
Definition: rlm_eap_fast.c:115
fr_dict_attr_t const * attr_eap_fast_pac_lifetime
Definition: rlm_eap_fast.c:125
fr_dict_autoload_t rlm_eap_fast_dict[]
Definition: rlm_eap_fast.c:87
fr_dict_attr_t const * attr_eap_fast_pac_i_id
Definition: rlm_eap_fast.c:117
fr_dict_attr_t const * attr_user_password
Definition: rlm_eap_fast.c:107
fr_dict_attr_t const * attr_eap_fast_pac_type
Definition: rlm_eap_fast.c:132
static unlang_action_t mod_handshake_resume(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_eap_fast.c:385
fr_dict_attr_t const * attr_freeradius_proxied_to
Definition: rlm_eap_fast.c:103
fr_dict_attr_t const * attr_eap_fast_pac_opaque_tlv
Definition: rlm_eap_fast.c:130
char const * cipher_list
cipher list specific to EAP-FAST
Definition: rlm_eap_fast.c:52
fr_dict_attr_t const * attr_eap_fast_intermediate_result
Definition: rlm_eap_fast.c:112
fr_dict_attr_t const * attr_eap_message
Definition: rlm_eap_fast.c:102
fr_dict_attr_t const * attr_eap_type
Definition: rlm_eap_fast.c:97
fr_dict_attr_t const * attr_eap_msk
Definition: rlm_eap_fast.c:95
fr_dict_attr_t const * attr_eap_fast_pac_opaque_pac_key
Definition: rlm_eap_fast.c:127
static unlang_action_t mod_handshake_process(UNUSED rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
Definition: rlm_eap_fast.c:507
fr_dict_attr_t const * attr_eap_fast_pac_info_i_id
Definition: rlm_eap_fast.c:120
fr_dict_attr_t const * attr_eap_fast_pac_info_a_id_info
Definition: rlm_eap_fast.c:119
fr_dict_attr_t const * attr_eap_fast_pac_info_pac_lifetime
Definition: rlm_eap_fast.c:121
fr_dict_attr_autoload_t rlm_eap_fast_dict_attr[]
Definition: rlm_eap_fast.c:137
static fr_dict_t const * dict_freeradius
Definition: rlm_eap_fast.c:82
fr_dict_attr_t const * attr_eap_tls_require_client_cert
Definition: rlm_eap_fast.c:96
fr_dict_attr_t const * attr_eap_fast_pac_tlv
Definition: rlm_eap_fast.c:131
char const * tls_conf_name
Name of shared TLS config.
Definition: rlm_eap_fast.c:43
SSL_CTX * ssl_ctx
Thread local SSL_CTX.
Definition: rlm_eap_fast.c:36
fr_dict_attr_t const * attr_eap_fast_eap_payload
Definition: rlm_eap_fast.c:110
static fr_dict_t const * dict_radius
Definition: rlm_eap_fast.c:83
fr_dict_attr_t const * attr_ms_chap_challenge
Definition: rlm_eap_fast.c:98
fr_dict_attr_t const * attr_eap_fast_pac_key
Definition: rlm_eap_fast.c:124
fr_dict_attr_t const * attr_eap_fast_crypto_binding
Definition: rlm_eap_fast.c:109
rlm_eap_submodule_t rlm_eap_fast
Definition: rlm_eap_fast.c:696
static int _session_secret(SSL *s, void *secret, int *secret_len, UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers, UNUSED SSL_CIPHER const **cipher, void *arg)
Definition: rlm_eap_fast.c:221
fr_dict_attr_t const * attr_eap_fast_pac_acknowledge
Definition: rlm_eap_fast.c:116
fr_time_delta_t pac_lifetime
seconds to add to current time to describe PAC lifetime
Definition: rlm_eap_fast.c:58
static void eap_fast_session_ticket(fr_tls_session_t *tls_session, const SSL *s, uint8_t *secret, int *secret_len)
Definition: rlm_eap_fast.c:205
char const * pac_opaque_key
The key used to encrypt PAC-Opaque.
Definition: rlm_eap_fast.c:61
fr_dict_attr_t const * attr_eap_fast_pac_info_tlv
Definition: rlm_eap_fast.c:123
fr_dict_attr_t const * attr_eap_emsk
Definition: rlm_eap_fast.c:94
char const * default_provisioning_method_name
Definition: rlm_eap_fast.c:46
fr_dict_attr_t const * attr_ms_mppe_send_key
Definition: rlm_eap_fast.c:104
fr_dict_attr_t const * attr_eap_fast_pac_info_a_id
Definition: rlm_eap_fast.c:118
char const * virtual_server
Virtual server to use for processing inner EAP method.
Definition: rlm_eap_fast.c:49
char const * authority_identity
The identity we present in the EAP-TLS.
Definition: rlm_eap_fast.c:59
fr_dict_t const * dict_eap_fast
Definition: rlm_eap_fast.c:84
int default_provisioning_method
Definition: rlm_eap_fast.c:47
fr_dict_attr_t const * attr_eap_fast_pac_info_pac_type
Definition: rlm_eap_fast.c:122
fr_dict_attr_t const * attr_eap_fast_pac_a_id
Definition: rlm_eap_fast.c:114
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
Definition: rlm_eap_fast.c:604
fr_dict_attr_t const * attr_eap_fast_nak
Definition: rlm_eap_fast.c:113
fr_dict_attr_t const * attr_eap_fast_pac_opaque_pac_type
Definition: rlm_eap_fast.c:129
fr_dict_attr_t const * attr_eap_fast_error
Definition: rlm_eap_fast.c:111
fr_dict_attr_t const * attr_eap_fast_pac_opaque_pac_lifetime
Definition: rlm_eap_fast.c:128
fr_dict_attr_t const * attr_user_name
Definition: rlm_eap_fast.c:106
fr_dict_attr_t const * attr_proxy_to_realm
Definition: rlm_eap_fast.c:100
fr_dict_attr_t const * attr_ms_mppe_recv_key
Definition: rlm_eap_fast.c:105
static conf_parser_t submodule_config[]
Definition: rlm_eap_fast.c:65
fr_dict_attr_t const * attr_eap_fast_result
Definition: rlm_eap_fast.c:133
fr_tls_conf_t * tls_conf
TLS config pointer.
Definition: rlm_eap_fast.c:44
bool req_client_cert
Whether we require a client cert in the outer tunnel.
Definition: rlm_eap_fast.c:53
fr_dict_attr_t const * attr_eap_fast_pac_opaque_i_id
Definition: rlm_eap_fast.c:126
CONF_SECTION * server_cs
Definition: rlm_eap_fast.c:51
fr_dict_attr_t const * attr_ms_chap_peer_challenge
Definition: rlm_eap_fast.c:99
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
Definition: rlm_eap_fast.c:615
fr_dict_attr_t const * attr_eap_fast_vendor_specific
Definition: rlm_eap_fast.c:134
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_eap_fast.c:628
static eap_fast_tunnel_t * eap_fast_alloc(TALLOC_CTX *ctx, rlm_eap_fast_t const *inst)
Allocate the FAST per-session data.
Definition: rlm_eap_fast.c:186
static int _session_ticket(SSL *s, uint8_t const *data, int len, void *arg)
Definition: rlm_eap_fast.c:255
static unlang_action_t mod_session_init(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition: rlm_eap_fast.c:526
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1302
CONF_SECTION * conf
Module's instance configuration.
Definition: module.h:329
void * data
Module's instance data.
Definition: module.h:271
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition: module.c:419
RETURN_MODULE_FAIL
fr_assert(0)
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
module_t common
Common fields provided by all modules.
Definition: submodule.h:50
Interface exported by EAP submodules.
Definition: submodule.h:49
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:772
#define talloc_get_type_abort_const
Definition: talloc.h:282
#define fr_time_wrap(_time)
Definition: time.h:145
#define fr_time_delta_ispos(_a)
Definition: time.h:290
#define fr_time_eq(_a, _b)
Definition: time.h:241
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition: time.h:196
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
int eap_tls_success(request_t *request, eap_session_t *eap_session, eap_tls_prf_label_t *prf_label)
Send an EAP-TLS success.
Definition: tls.c:264
eap_tls_session_t * eap_tls_session_init(request_t *request, eap_session_t *eap_session, SSL_CTX *ssl_ctx, bool client_cert)
Create a new fr_tls_session_t associated with an eap_session_t.
Definition: tls.c:1131
int eap_tls_compose(request_t *request, eap_session_t *eap_session, eap_tls_status_t status, uint8_t flags, fr_tls_record_t *record, size_t record_len, size_t frag_len)
Convert the EAP-TLS reply packet into an EAP packet.
Definition: tls.c:114
int eap_tls_request(request_t *request, eap_session_t *eap_session)
Frames the OpenSSL data that needs to be sent to the client in an EAP-Request.
Definition: tls.c:372
int eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
Definition: tls.c:322
USES_APPLE_DEPRECATED_API fr_table_num_ordered_t const eap_tls_status_table[]
Definition: tls.c:80
fr_tls_conf_t * eap_tls_conf_parse(CONF_SECTION *cs, char const *attr)
Parse TLS configuration.
Definition: tls.c:1231
unlang_action_t eap_tls_process(request_t *request, eap_session_t *eap_session)
Process an EAP TLS request.
Definition: tls.c:963
int base_flags
Some protocols use the reserved bits of the EAP-TLS flags (such as PEAP).
Definition: tls.h:132
eap_tls_status_t state
The state of the EAP-TLS session.
Definition: tls.h:127
@ EAP_TLS_INVALID
Invalid, don't reply.
Definition: tls.h:91
@ EAP_TLS_HANDLED
TLS code has handled it.
Definition: tls.h:94
@ EAP_TLS_RECORD_RECV_COMPLETE
Received final fragment of a record.
Definition: tls.h:111
@ EAP_TLS_START_SEND
We're starting a new TLS session.
Definition: tls.h:100
@ EAP_TLS_FAIL
Fail, send fail.
Definition: tls.h:93
@ EAP_TLS_ESTABLISHED
Session established, send success (or start phase2).
Definition: tls.h:92
fr_tls_session_t * tls_session
TLS session used to authenticate peer or tunnel sensitive data.
Definition: tls.h:129
#define SET_START(x)
Definition: tls.h:86
Tracks the state of an EAP-TLS session.
Definition: tls.h:126
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition: pair_inline.c:43
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
Definition: pair_inline.c:125
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition: pair_inline.c:70
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
static fr_slen_t data
Definition: value.h:1265
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
virtual_server_t const * virtual_server_find(char const *name)
Return virtual server matching the specified name.