/* * Authenticate a previously sent challenge. */ static int eap_sim_authenticate(void *arg, EAP_HANDLER *handler) { struct eap_sim_server_state *ess; VALUE_PAIR *vp, *vps; enum eapsim_subtype subtype; int success; arg = arg; /* shut up compiler */ ess = (struct eap_sim_server_state *)handler->opaque; /* vps is the data from the client */ vps = handler->request->packet->vps; success= unmap_eapsim_basictypes(handler->request->packet, handler->eap_ds->response->type.data, handler->eap_ds->response->type.length); if(!success) { return 0; } /* see what kind of message we have gotten */ if((vp = pairfind(vps, ATTRIBUTE_EAP_SIM_SUBTYPE, 0, TAG_ANY)) == NULL) { DEBUG2(" no subtype attribute was created, message dropped"); return 0; } subtype = vp->vp_integer; /* * Client error supersedes anything else. */ if (subtype == eapsim_client_error) { return 0; } switch(ess->state) { case eapsim_server_start: switch(subtype) { default: /* * pretty much anything else here is illegal, * so we will retransmit the request. */ eap_sim_stateenter(handler, ess, eapsim_server_start); return 1; case eapsim_start: /* * a response to our EAP-Sim/Request/Start! * */ return process_eap_sim_start(handler, vps); } break; case eapsim_server_challenge: switch(subtype) { default: /* * pretty much anything else here is illegal, * so we will retransmit the request. */ eap_sim_stateenter(handler, ess, eapsim_server_challenge); return 1; case eapsim_challenge: /* * a response to our EAP-Sim/Request/Challenge! * */ return process_eap_sim_challenge(handler, vps); } break; default: /* if we get into some other state, die, as this * is a coding error! */ DEBUG2(" illegal-unknown state reached in eap_sim_authenticate\n"); rad_assert(0 == 1); } return 0; }
/** Authenticate a previously sent challenge * */ static int mod_authenticate(UNUSED void *arg, eap_handler_t *handler) { REQUEST *request = handler->request; eap_sim_state_t *ess = handler->opaque; VALUE_PAIR *vp, *vps; enum eapsim_subtype subtype; int success; /* * VPS is the data from the client */ vps = handler->request->packet->vps; success = unmap_eapsim_basictypes(handler->request->packet, handler->eap_ds->response->type.data, handler->eap_ds->response->type.length); if (!success) return 0; /* * See what kind of message we have gotten */ vp = pairfind(vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY); if (!vp) { REDEBUG2("No subtype attribute was created, message dropped"); return 0; } subtype = vp->vp_integer; /* * Client error supersedes anything else. */ if (subtype == EAPSIM_CLIENT_ERROR) { return 0; } switch (ess->state) { case EAPSIM_SERVER_START: switch (subtype) { /* * Pretty much anything else here is illegal, so we will retransmit the request. */ default: eap_sim_stateenter(handler, ess, EAPSIM_SERVER_START); return 1; /* * A response to our EAP-Sim/Request/Start! */ case EAPSIM_START: return process_eap_sim_start(handler, vps); } break; case EAPSIM_SERVER_CHALLENGE: switch(subtype) { /* * Pretty much anything else here is illegal, so we will retransmit the request. */ default: eap_sim_stateenter(handler, ess, EAPSIM_SERVER_CHALLENGE); return 1; /* * A response to our EAP-Sim/Request/Challenge! */ case EAPSIM_CHALLENGE: return process_eap_sim_challenge(handler, vps); } break; default: rad_assert(0 == 1); } return 0; }
/** Authenticate a previously sent challenge * */ static rlm_rcode_t mod_process(UNUSED void *instance, eap_session_t *eap_session) { REQUEST *request = eap_session->request; eap_sim_session_t *eap_sim_session = talloc_get_type_abort(eap_session->opaque, eap_sim_session_t); fr_sim_decode_ctx_t ctx = { .keys = &eap_sim_session->keys, }; VALUE_PAIR *subtype_vp, *from_peer, *vp; fr_cursor_t cursor; eap_sim_subtype_t subtype; int ret; /* * VPS is the data from the client */ from_peer = eap_session->request->packet->vps; fr_cursor_init(&cursor, &request->packet->vps); fr_cursor_tail(&cursor); ret = fr_sim_decode(eap_session->request, &cursor, dict_eap_sim, eap_session->this_round->response->type.data, eap_session->this_round->response->type.length, &ctx); /* * RFC 4186 says we *MUST* notify, not just * send an EAP-Failure in this case where * we cannot decode an EAP-AKA packet. */ if (ret < 0) { RPEDEBUG2("Failed decoding EAP-SIM attributes"); eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION); return RLM_MODULE_HANDLED; /* We need to process more packets */ } vp = fr_cursor_current(&cursor); if (vp && RDEBUG_ENABLED2) { RDEBUG2("Decoded EAP-SIM attributes"); log_request_pair_list(L_DBG_LVL_2, request, vp, NULL); } subtype_vp = fr_pair_find_by_da(from_peer, attr_eap_sim_subtype, TAG_ANY); if (!subtype_vp) { REDEBUG("Missing EAP-SIM-Subtype"); eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION); return RLM_MODULE_HANDLED; /* We need to process more packets */ } subtype = subtype_vp->vp_uint16; switch (eap_sim_session->state) { /* * Response to our advertised versions and request for an ID * This is very similar to Identity negotiation in EAP-AKA['] */ case EAP_SIM_SERVER_START: switch (subtype) { case EAP_SIM_START: if (process_eap_sim_start(eap_session, from_peer) == 0) return RLM_MODULE_HANDLED; eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION); return RLM_MODULE_HANDLED; /* We need to process more packets */ /* * Case 1 where we're allowed to send an EAP-Failure * * This can happen in the case of a conservative * peer, where it refuses to provide the permanent * identity. */ case EAP_SIM_CLIENT_ERROR: { char buff[20]; vp = fr_pair_find_by_da(from_peer, attr_eap_sim_client_error_code, TAG_ANY); if (!vp) { REDEBUG("EAP-SIM Peer rejected SIM-Start (%s) with client-error message but " "has not supplied a client error code", fr_int2str(sim_id_request_table, eap_sim_session->id_req, "<INVALID>")); } else { REDEBUG("Client rejected SIM-Start (%s) with error: %s (%i)", fr_int2str(sim_id_request_table, eap_sim_session->id_req, "<INVALID>"), fr_pair_value_enum(vp, buff), vp->vp_uint16); } eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE); return RLM_MODULE_REJECT; } case EAP_SIM_NOTIFICATION: notification: { char buff[20]; vp = fr_pair_afrom_da(from_peer, attr_eap_sim_notification); if (!vp) { REDEBUG2("Received SIM-Notification with no notification code"); eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION); return RLM_MODULE_HANDLED; /* We need to process more packets */ } /* * Case 2 where we're allowed to send an EAP-Failure */ if (!(vp->vp_uint16 & 0x8000)) { REDEBUG2("SIM-Notification %s (%i) indicates failure", fr_pair_value_enum(vp, buff), vp->vp_uint16); eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE); return RLM_MODULE_REJECT; } /* * ...if it's not a failure, then re-enter the * current state. */ REDEBUG2("Got SIM-Notification %s (%i)", fr_pair_value_enum(vp, buff), vp->vp_uint16); eap_sim_state_enter(eap_session, eap_sim_session->state); return RLM_MODULE_HANDLED; default: unexpected_subtype: /* * RFC 4186 says we *MUST* notify, not just * send an EAP-Failure in this case. */ REDEBUG("Unexpected subtype %pV", &subtype_vp->data); eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION); return RLM_MODULE_HANDLED; /* We need to process more packets */ } } /* * Process the response to our previous challenge. */ case EAP_SIM_SERVER_CHALLENGE: switch (subtype) { /* * A response to our EAP-Sim/Request/Challenge! */ case EAP_SIM_CHALLENGE: switch (process_eap_sim_challenge(eap_session, from_peer)) { case 1: return RLM_MODULE_HANDLED; case 0: return RLM_MODULE_OK; case -1: eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION); return RLM_MODULE_HANDLED; /* We need to process more packets */ } case EAP_SIM_CLIENT_ERROR: { char buff[20]; vp = fr_pair_find_by_da(from_peer, attr_eap_sim_client_error_code, TAG_ANY); if (!vp) { REDEBUG("EAP-SIM Peer rejected SIM-Challenge with client-error message but " "has not supplied a client error code"); } else { REDEBUG("Client rejected SIM-Challenge with error: %s (%i)", fr_pair_value_enum(vp, buff), vp->vp_uint16); } eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE); return RLM_MODULE_REJECT; } case EAP_SIM_NOTIFICATION: goto notification; default: goto unexpected_subtype; } /* * Peer acked our failure */ case EAP_SIM_SERVER_FAILURE_NOTIFICATION: switch (subtype) { case EAP_SIM_NOTIFICATION: RDEBUG2("SIM-Notification ACKed, sending EAP-Failure"); eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE); return RLM_MODULE_REJECT; default: goto unexpected_subtype; } /* * Something bad happened... */ default: rad_assert(0); eap_sim_state_enter(eap_session, EAP_SIM_SERVER_FAILURE_NOTIFICATION); return RLM_MODULE_HANDLED; /* We need to process more packets */ } } /* * Initiate the EAP-SIM session by starting the state machine * and initiating the state. */ static rlm_rcode_t mod_session_init(void *instance, eap_session_t *eap_session) { REQUEST *request = eap_session->request; eap_sim_session_t *eap_sim_session; rlm_eap_sim_t *inst = instance; fr_sim_id_type_t type; fr_sim_method_hint_t method; MEM(eap_sim_session = talloc_zero(eap_session, eap_sim_session_t)); eap_session->opaque = eap_sim_session; /* * Set default configuration, we may allow these * to be toggled by attributes later. */ eap_sim_session->send_result_ind = inst->protected_success; eap_sim_session->id_req = SIM_ANY_ID_REQ; /* Set the default */ /* * This value doesn't have be strong, but it is * good if it is different now and then. */ eap_sim_session->sim_id = (fr_rand() & 0xff); /* * Save the keying material, because it could change on a subsequent retrieval. */ RDEBUG2("New EAP-SIM session"); /* * Process the identity that we received in the * EAP-Identity-Response and use it to determine * the initial request we send to the Supplicant. */ if (fr_sim_id_type(&type, &method, eap_session->identity, talloc_array_length(eap_session->identity) - 1) < 0) { RPWDEBUG2("Failed parsing identity, continuing anyway"); } switch (method) { default: RWDEBUG("EAP-Identity-Response hints that EAP-%s should be started, but we're attempting EAP-SIM", fr_int2str(sim_id_method_hint_table, method, "<INVALID>")); break; case SIM_METHOD_HINT_SIM: case SIM_METHOD_HINT_UNKNOWN: break; } eap_session->process = mod_process; /* * Figure out what type of identity we have * and use it to determine the initial * request we send. */ switch (type) { /* * These types need to be transformed into something * usable before we can do anything. */ case SIM_ID_TYPE_UNKNOWN: case SIM_ID_TYPE_PSEUDONYM: case SIM_ID_TYPE_FASTAUTH: /* * Permanent ID means we can just send the challenge */ case SIM_ID_TYPE_PERMANENT: eap_sim_session->keys.identity_len = talloc_array_length(eap_session->identity) - 1; MEM(eap_sim_session->keys.identity = talloc_memdup(eap_sim_session, eap_session->identity, eap_sim_session->keys.identity_len)); eap_sim_state_enter(eap_session, EAP_SIM_SERVER_START); return RLM_MODULE_HANDLED; } return RLM_MODULE_HANDLED; }