26 RCSID(
"$Id: bad43ddfa90e68ffb181637404a768fd50ac2412 $")
28 #define LOG_PREFIX mctx->mi->name
30 #include <freeradius-devel/server/base.h>
31 #include <freeradius-devel/server/module_rlm.h>
32 #include <freeradius-devel/server/dl_module.h>
33 #include <freeradius-devel/server/dl_module.h>
34 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
35 #include <freeradius-devel/unlang/interpret.h>
36 #include <freeradius-devel/unlang/module.h>
77 cisco_accounting_username_bug), .dflt =
"no" },
135 char *our_name = NULL;
143 p = our_name = talloc_strdup(NULL,
name);
145 if (*p ==
'_') *p =
'-';
158 #if !defined(HAVE_OPENSSL_SSL_H) || !defined(HAVE_LIBSSL)
185 WARN(
"Ignoring EAP method %s because we don't have OpenSSL support",
name);
218 cf_log_err(ci,
"Unknown EAP type %s", default_method_name);
235 unsigned int i, s_i = 0;
249 REDEBUG(
"Peer sent empty (invalid) NAK. Can't select method to continue with");
258 for (i = 0; i < nak->
length; i++) {
263 if (nak->
data[i] == 0) {
264 REDEBUG(
"Peer NAK'd indicating it is not willing to continue");
280 !
inst->methods[nak->
data[i]].submodule) {
281 RDEBUG2(
"Peer NAK'd asking for unsupported EAP type %s (%d), skipping...",
294 if (last_type == nak->
data[i]) {
297 RDEBUG2(
"Peer NAK'd our request for %s (%d) with a request for %s (%d), skipping...",
298 type_str, nak->
data[i], type_str, nak->
data[i]);
300 RWARN(
"!!! We requested to use EAP type %s (%i)", type_str, nak->
data[i]);
301 RWARN(
"!!! The supplicant rejected that, and requested to use the same EAP type.");
302 RWARN(
"!!! i.e. the supplicant said 'I don't like %s, please use %s instead.",
304 RWARN(
"!!! The supplicant software is broken and does not work properly.");
305 RWARN(
"!!! Please upgrade it to software that works.");
310 sanitised[s_i++] = nak->
data[i];
314 REDEBUG(
"Peer presented no valid EAP types in its NAK response");
332 for (i = 0; i < s_i; i++) {
337 if (
vp->vp_uint32 != sanitised[i])
continue;
339 method = sanitised[i];
350 method = sanitised[0];
363 for (i = 0; i < s_i; i++) {
367 fr_sbuff_terminate(proposed);
374 fr_sbuff_terminate(allowed);
376 REDEBUG(
"No mutually acceptable EAP types found. Supplicant proposed: %s. We allow: %s",
393 RDEBUG2(
"Request cancelled - Destroying EAP-Session");
483 RDEBUG2(
"Cleaning up EAP session");
523 char const *p = identity;
524 char const *end = identity + (talloc_array_length(identity) - 1);
530 p = realm =
memrchr(identity,
'@', end - p);
533 return identity - end;
536 p = memchr(p,
'.', end - p);
539 return identity - end;
542 if ((realm - 1) == p) {
544 "Realm is missing label between realm separator '@' and label separator '.'");
545 return identity - realm;
547 if ((p + 1) == end) {
549 "Realm is missing label between label separator '.' and the end of the "
551 return identity - end;
554 return end - identity;
593 REDEBUG(
"Peer sent EAP type number %d, which is outside known range",
type->num);
610 eap_session->
request->parent->parent) {
611 RERROR(
"Multiple levels of TLS nesting are invalid");
628 switch (
inst->require_realm) {
641 talloc_array_length(eap_session->
identity) - 1,
663 if (!stripped_user_domain)
goto bad_id;
676 RDEBUG2(
"Using method from &control.EAP-Type");
684 }
else if (
inst->type_identity_submodule) {
687 for (i = 0; i <
inst->type_identity_submodule_len; i++) {
694 talloc_array_length(eap_session->
identity) - 1);
706 REDEBUG2(
"Peer tried to start unsupported EAP type %s (%d)",
721 TALLOC_FREE(eap_session->
opaque);
742 if (!
inst->methods[
type->num].submodule) {
755 if (eap_session->
rounds == 0) {
759 RDEBUG2(
"Using method from &control.EAP-Type");
773 method = &
inst->methods[eap_session->
type];
787 &eap_session->
subrequest->control_pairs, &request->control_pairs) < 0) {
789 RERROR(
"Failed copying parent's attribute list");
797 &request->request_pairs) < 0)
goto list_copy_fail;
850 type_vp->vp_uint32 = eap_session->
type;
864 REDEBUG(
"You set 'Auth-Type = EAP' for a request that does not contain an EAP-Message attribute!");
875 RPERROR(
"Malformed EAP Message");
926 if (!
inst->auth_type) {
927 WARN(
"No 'authenticate %s {...}' section or 'Auth-Type = %s' set. Cannot setup EAP authentication",
990 RDEBUG3(
"Request didn't contain an EAP-Message, not inserting EAP-Failure");
995 RDEBUG3(
"Reply already contained an EAP-Message, not inserting EAP-Failure");
1006 RDEBUG3(
"Failed to get eap_session, probably already removed, not inserting EAP-Failure");
1029 REDEBUG(
"Request rejected after last call to module \"%s\", transforming response into EAP-Failure",
1048 size_t j, loaded,
count = 0;
1050 loaded = talloc_array_length(
inst->type_submodules);
1058 if (!
inst->default_method_is_set) {
1062 for (i = 0; i < loaded; i++) {
1066 if (!submodule_inst)
continue;
1076 if (!submodule->
provides[j])
break;
1085 if (!
inst->default_method_is_set && (i == 0))
inst->default_method = method;
1090 if (
inst->methods[method].submodule) {
1094 "Duplicate EAP-Type %s. Conflicting entry %s[%u]",
1101 inst->methods[method].submodule_inst = submodule_inst;
1102 inst->methods[method].submodule = submodule;
1112 inst->type_identity_submodule[
inst->type_identity_submodule_len++] = submodule_inst;
1121 if (
inst->default_method_is_set && !
inst->methods[
inst->default_method].submodule) {
1128 cf_log_err(mctx->
mi->
conf,
"No EAP method(s) configured, module cannot do anything");
1136 if (!
inst->default_method_is_set) {
1137 if (
inst->type_identity_submodule_len > 0) {
1138 MEM(
inst->type_identity_submodule = talloc_realloc(
inst,
inst->type_identity_submodule,
1140 inst->type_identity_submodule_len));
1142 TALLOC_FREE(
inst->type_identity_submodule);
1147 if (!
inst->auth_type) {
1148 WARN(
"Failed to find 'authenticate %s {...}' section. EAP authentication will likely not work",
1155 for (i = 0; i < 256; i++)
inst->rand_pool.randrsl[i] =
fr_rand();
1157 inst->rand_pool.randcnt = 0;
1165 fr_perror(
"Failed initialising EAP base library");
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
#define L(_str)
Helper for initialising arrays of string literals.
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
#define CONF_PARSER_TERMINATOR
#define FR_CONF_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR is found
#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
#define FR_CONF_OFFSET_IS_SET(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct,...
@ CONF_FLAG_MULTI
CONF_PAIR can have multiple copies.
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Defines a CONF_PAIR to C data type mapping.
Common header for all CONF_* types.
A section grouping multiple CONF_PAIR.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_err_by_child(_parent, _child, _fmt,...)
Log an error message against a specified child.
#define cf_data_find(_cf, _type, _name)
rlm_rcode_t eap_fail(eap_session_t *eap_session)
rlm_rcode_t eap_start(request_t *request, rlm_eap_method_t const methods[], bool ignore_unknown_types)
rlm_rcode_t eap_compose(eap_session_t *eap_session)
eap_packet_t * response
Packet we received from the peer.
eap_packet_t * request
Packet we will send to the peer.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
fr_dict_enum_value_t * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
dl_module_common_t * exported
Symbol exported by the module, containing its public functions, name and behaviour control flags.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
eap_type_t eap_name2type(char const *name)
Return an EAP-Type for a particular name.
char const * eap_type2name(eap_type_t method)
Return an EAP-name for a particular type.
@ FR_EAP_METHOD_AKA_PRIME
Structure to represent packet format of eap on wire
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
void fr_isaac_init(fr_randctx *ctx, int flag)
int eap_base_init(void)
Initialise the lib eap base library.
void eap_base_free(void)
De-init the lib eap base library.
eap_packet_raw_t * eap_packet_from_vp(TALLOC_CTX *ctx, fr_pair_list_t *vps)
eap_session_t * eap_session_continue(void const *instance, eap_packet_raw_t **eap_packet_p, request_t *request)
Ingest an eap_packet into a thawed or newly allocated session.
void eap_session_freeze(eap_session_t **eap_session)
Freeze an eap_session_t so that it can continue later.
void eap_session_destroy(eap_session_t **eap_session)
'destroy' an EAP session and disassociate it from the current request
eap_session_t * eap_session_thaw(request_t *request)
Thaw an eap_session_t so it can be continued.
char * identity
NAI (User-Name) from EAP-Identity.
void * opaque
Opaque data used by EAP methods.
request_t * subrequest
Current subrequest being executed.
eap_type_t type
EAP method number.
module_method_t process
Callback that should be used to process the next round.
request_t * request
Current request.
rlm_rcode_t submodule_rcode
Result of last submodule call.
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
eap_round_t * prev_round
Previous response/request pair.
int rounds
How many roundtrips have occurred this session.
Tracks the progress of a single session of any EAP method.
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
#define REDEBUG2(fmt,...)
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_OCTETS
Raw octets.
void * memrchr(void const *s, int c, size_t n)
GNU libc extension on some platforms.
module_instance_t const * mi
Instance of the module being instantiated.
void * rctx
Resume ctx that a module previously set.
#define MODULE_INST_CTX(_mi)
Wrapper to create a module_inst_ctx_t as a compound literal.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
int module_rlm_submodule_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic conf_parser_t func for loading drivers.
bool module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv)
Set the next section type if it's not already set.
module_t common
Common fields presented by all modules.
#define RADIUS_AUTH_VECTOR_LENGTH
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.
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
fr_pair_t * fr_pair_find_by_da_idx(fr_pair_list_t const *list, fr_dict_attr_t const *da, unsigned int idx)
Find a pair with a matching da at a given index.
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
int fr_pair_value_mem_alloc(fr_pair_t *vp, uint8_t **out, size_t size, bool tainted)
Pre-allocate a memory buffer for a "octets" type value pair.
char * fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
Escape string that may contain binary data, and write it to a new buffer.
static const conf_parser_t config[]
uint32_t fr_rand(void)
Return a 32-bit random number.
#define RETURN_MODULE_REJECT
#define RETURN_MODULE_NOOP
#define RETURN_MODULE_RCODE(_rcode)
#define RETURN_MODULE_INVALID
#define RETURN_MODULE_UPDATED
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_INVALID
The module considers the request invalid.
@ RLM_MODULE_OK
The module is OK, continue.
@ RLM_MODULE_FAIL
Module failed, don't reply.
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
@ RLM_MODULE_REJECT
Immediately reject the request.
@ RLM_MODULE_UPDATED
OK (pairs modified).
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
fr_dict_autoload_t rlm_eap_dict[]
static int mod_load(void)
static unlang_action_t eap_method_select(rlm_rcode_t *p_result, module_ctx_t const *mctx, eap_session_t *eap_session)
Select the correct callback based on a response.
static fr_table_num_sorted_t const require_identity_realm_table[]
static ssize_t eap_identity_is_nai_with_realm(char const *identity)
Basic tests to determine if an identity is a valid NAI.
char const * caller
Original caller.
static fr_dict_attr_t const * attr_state
static fr_dict_attr_t const * attr_eap_identity
fr_dict_attr_autoload_t rlm_eap_dict_attr[]
static int submodule_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
static fr_dict_attr_t const * attr_eap_message
static fr_dict_attr_t const * attr_eap_type
static eap_type_t eap_process_nak(module_ctx_t const *mctx, request_t *request, eap_type_t last_type, eap_type_data_t *nak)
Process NAK data from EAP peer.
static void mod_authenticate_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
Cancel a call to a submodule.
static fr_dict_t const * dict_freeradius
eap_session_t * eap_session
The eap_session we're continuing.
rlm_eap_t * inst
Instance of the rlm_eap module.
static int eap_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
Convert EAP type strings to eap_type_t values.
static fr_dict_t const * dict_radius
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_attr_t const * attr_auth_type
rlm_rcode_t rcode
The result of the submodule.
static void mod_unload(void)
static fr_dict_attr_t const * attr_stripped_user_domain
static unlang_action_t mod_authenticate_result(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request, eap_session_t *eap_session, rlm_rcode_t result)
Process the result of calling a submodule.
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_attr_t const * attr_user_name
static size_t require_identity_realm_table_len
static const conf_parser_t module_config[]
static unlang_action_t mod_authenticate_result_async(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Call mod_authenticate_result asynchronously from the unlang interpreter.
static int mod_instantiate(module_inst_ctx_t const *mctx)
static fr_dict_attr_t const * attr_message_authenticator
static unlang_action_t mod_post_auth(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Resume context for calling a submodule.
Implements the EAP framework.
@ REQUIRE_REALM_NAI
Require the EAP-Identity contains an NAI domain.
@ REQUIRE_REALM_NO
Don't require that the identity is qualified.
@ REQUIRE_REALM_YES
Require the EAP-Identity string contain an NAI realm or that Stripped-User-Domain is present in the r...
Instance data for rlm_eap.
static int instantiate(module_inst_ctx_t const *mctx)
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
char const * name
Instance name e.g. user_database.
CONF_SECTION * conf
Module's instance configuration.
void * data
Module's instance data.
dl_module_t * module
Dynamic loader handle.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
void fr_state_discard_child(request_t *parent, void const *unique_ptr, int unique_int)
Remove state from a child.
int unlang_module_push(rlm_rcode_t *p_result, request_t *request, module_instance_t *mi, module_method_t method, bool top_frame)
Push a module or submodule onto the stack for evaluation.
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.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
fr_pair_value_bstrdup_buffer(vp, eap_session->identity, true)
fr_aka_sim_id_type_t type
Stores an attribute, a value and various bits of other data.
module_t common
Common fields provided by all modules.
module_instance_t * submodule_inst
Submodule's instance data.
#define MAX_PROVIDED_METHODS
rlm_eap_submodule_t const * submodule
Submodule's exported interface.
bool clone_parent_lists
< Namespace children should be allocated in.
eap_type_t provides[MAX_PROVIDED_METHODS]
Allow the module to register itself for more than one EAP-Method.
eap_type_identity_t type_identity
Do we recognise this identity?
Private structure to hold handles and interfaces for an EAP method.
Interface exported by EAP submodules.
request_t * unlang_subrequest_alloc(request_t *parent, fr_dict_t const *namespace)
Allocate a subrequest to run through a virtual server at some point in the future.
int unlang_subrequest_child_push(rlm_rcode_t *out, request_t *child, unlang_subrequest_session_t const *session, bool free_child, bool top_frame)
Push a pre-existing child back onto the stack as a subrequest.
An element in a lexicographically sorted array of name to num mappings.
#define talloc_get_type_abort_const
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
char const * fr_strerror(void)
Get the last library error.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
static size_t char ** out