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, version 2 if the
4 * License as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * @brief Uses hostapd library to support some methods not provided by rlm_eap.
21 * @copyright 2007 Alan DeKok <aland@deployingradius.com>
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/rad_assert.h>
33 #include <utils/includes.h>
35 #include <utils/common.h>
36 #include <eap_server/eap.h>
37 #include <crypto/tls.h>
40 struct eap_server_ctx {
41 struct eap_eapol_interface *eap_if;
46 #define EAP_STATE_LEN (AUTH_VECTOR_LEN)
47 typedef struct EAP_HANDLER {
48 struct EAP_HANDLER *prev, *next;
49 uint8_t state[EAP_STATE_LEN];
50 fr_ipaddr_t src_ipaddr;
55 struct rlm_eap_t *inst;
57 struct eapol_callbacks eap_cb;
58 struct eap_config eap_conf;
59 struct eap_server_ctx server_ctx;
62 typedef struct rlm_eap_t {
63 rbtree_t *session_tree;
64 EAP_HANDLER *session_head, *session_tail;
67 * Configuration items.
70 int cisco_accounting_username_bug;
72 struct tls_connection_params tparams;
77 char *pac_opaque_encr_key;
79 char *eap_fast_a_id_info;
82 int pac_key_refresh_time;
86 EapType methods[EAP_MAX_METHODS];
87 int vendors[EAP_MAX_METHODS];
90 pthread_mutex_t session_mutex;
98 static void eap_handler_free(EAP_HANDLER *handler)
100 eap_server_sm_deinit(handler->server_ctx.eap);
104 static void eaplist_free(rlm_eap_t *inst)
106 EAP_HANDLER *node, *next;
108 for (node = inst->session_head; node != NULL; node = next) {
110 eap_handler_free(node);
113 inst->session_head = inst->session_tail = NULL;
117 * Return a 32-bit random number.
119 static uint32_t eap_rand(fr_randctx *ctx)
123 num = ctx->randrsl[ctx->randcnt++];
124 if (ctx->randcnt == 256) {
133 * Add a handler to the set of active sessions.
135 * Since we're adding it to the list, we guess that this means
136 * the packet needs a State attribute. So add one.
138 static int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler)
144 rad_assert(handler != NULL);
145 rad_assert(handler->request != NULL);
148 * Generate State, since we've been asked to add it to
151 state = pairmake("State", "0x00", T_OP_EQ);
152 if (!state) return 0;
153 pairadd(&(handler->request->reply->vps), state);
154 state->length = EAP_STATE_LEN;
157 * The time at which this request was made was the time
158 * at which it was received by the RADIUS server.
160 handler->timestamp = handler->request->timestamp;
162 handler->src_ipaddr = handler->request->packet->src_ipaddr;
165 * We don't need this any more.
167 handler->request = NULL;
170 * Playing with a data structure shared among threads
171 * means that we need a lock, to avoid conflict.
173 pthread_mutex_lock(&(inst->session_mutex));
176 * Create a completely random state.
178 for (i = 0; i < 4; i++) {
179 lvalue = eap_rand(&inst->rand_pool);
180 memcpy(state->vp_octets + i * 4, &lvalue, sizeof(lvalue));
182 memcpy(handler->state, state->vp_strvalue, sizeof(handler->state));
187 status = rbtree_insert(inst->session_tree, handler);
192 prev = inst->session_tail;
194 prev->next = handler;
195 handler->prev = prev;
196 handler->next = NULL;
197 inst->session_tail = handler;
199 inst->session_head = inst->session_tail = handler;
200 handler->next = handler->prev = NULL;
205 * Now that we've finished mucking with the list,
208 pthread_mutex_unlock(&(inst->session_mutex));
211 radlog(L_ERR, "rlm_eap2: Failed to remember handler!");
212 eap_handler_free(handler);
220 * Find a a previous EAP-Request sent by us, which matches
221 * the current EAP-Response.
223 * Then, release the handle from the list, and return it to
226 * Also since we fill the eap_ds with the present EAP-Response we
227 * got to free the prev_eapds & move the eap_ds to prev_eapds
229 static EAP_HANDLER *eaplist_find(rlm_eap_t *inst, REQUEST *request)
234 EAP_HANDLER *handler, myHandler;
237 * We key the sessions off of the 'state' attribute, so it
240 state = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY);
242 (state->length != EAP_STATE_LEN)) {
246 myHandler.src_ipaddr = request->packet->src_ipaddr;
247 memcpy(myHandler.state, state->vp_strvalue, sizeof(myHandler.state));
250 * Playing with a data structure shared among threads
251 * means that we need a lock, to avoid conflict.
253 pthread_mutex_lock(&(inst->session_mutex));
256 * Check the first few handlers in the list, and delete
257 * them if they're too old. We don't need to check them
258 * all, as incoming requests will quickly cause older
259 * handlers to be deleted.
262 for (i = 0; i < 2; i++) {
263 handler = inst->session_head;
265 ((request->timestamp - handler->timestamp) > inst->timer_limit)) {
266 node = rbtree_find(inst->session_tree, handler);
267 rad_assert(node != NULL);
268 rbtree_delete(inst->session_tree, node);
271 * handler == inst->session_head
273 inst->session_head = handler->next;
275 handler->next->prev = NULL;
277 inst->session_head = NULL;
279 eap_handler_free(handler);
284 node = rbtree_find(inst->session_tree, &myHandler);
286 handler = rbtree_node2data(inst->session_tree, node);
289 * Delete old handler from the tree.
291 rbtree_delete(inst->session_tree, node);
294 * And unsplice it from the linked list.
297 handler->prev->next = handler->next;
299 inst->session_head = handler->next;
302 handler->next->prev = handler->prev;
304 inst->session_tail = handler->prev;
306 handler->prev = handler->next = NULL;
309 pthread_mutex_unlock(&(inst->session_mutex));
315 RDEBUG2("Request not found in the list");
320 * Found, but state verification failed.
323 radlog(L_ERR, "rlm_eap2: State verification failed.");
327 RDEBUG2("Request found, released from the list");
334 * delete all the allocated space by eap module
336 static int eap_detach(void *instance)
340 inst = (rlm_eap_t *)instance;
342 rbtree_free(inst->session_tree);
343 inst->session_tree = NULL;
345 eap_server_unregister_methods();
346 tls_deinit(inst->tls_ctx);
348 pthread_mutex_destroy(&(inst->session_mutex));
355 * Compare two handlers.
357 static int eap_handler_cmp(const void *a, const void *b)
360 const EAP_HANDLER *one = a;
361 const EAP_HANDLER *two = b;
363 rcode = fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr);
364 if (rcode != 0) return rcode;
366 return memcmp(one->state, two->state, sizeof(one->state));
370 static int server_get_eap_user(void *ctx, const u8 *identity,
371 size_t identity_len, int phase2,
372 struct eap_user *user)
376 EAP_HANDLER *handler = ctx;
377 REQUEST *request = handler->request;
379 os_memset(user, 0, sizeof(*user));
382 * FIXME: Run through "authorise" again to look up
383 * password for the given identity
385 identity = identity; /* -Wunused */
386 identity_len = identity_len; /* -Wunused */
389 * Do this always, just in case.
391 vp = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
393 user->password = (u8 *) os_strdup(vp->vp_strvalue);
394 user->password_len = vp->length;
396 if (!vp) vp = pairfind(request->config_items, PW_NT_PASSWORD, 0, TAG_ANY);
398 user->password = (u8 *) malloc(vp->length);
399 memcpy(user->password, vp->vp_octets, vp->length);
400 user->password_len = vp->length;
404 for (i = 0; i < handler->inst->num_types; i++) {
405 user->methods[i].vendor = handler->inst->vendors[i];
406 user->methods[i].method = handler->inst->methods[i];
412 * FIXME: run tunneled sessions through the tunneled portion...
416 * FIXME: Selectively control tunneled EAP types.
418 user->methods[0].vendor = EAP_VENDOR_IETF;
419 user->methods[0].method = EAP_TYPE_MD5;
420 user->methods[1].vendor = EAP_VENDOR_IETF;
421 user->methods[1].method = EAP_TYPE_MSCHAPV2;
424 * No password configured...
431 static const char * server_get_eap_req_id_text(void *ctx, size_t *len)
433 ctx = ctx; /* -Wunused */
439 static CONF_PARSER tls_config[] = {
443 { "ca_cert", PW_TYPE_STRING_PTR,
444 offsetof(rlm_eap_t, tparams.ca_cert),
445 NULL, "${confdir}/certs/ca.pem" },
446 { "server_cert", PW_TYPE_STRING_PTR,
447 offsetof(rlm_eap_t, tparams.client_cert),
448 NULL, "${confdir}/certs/server.pem" },
449 { "private_key_file", PW_TYPE_STRING_PTR,
450 offsetof(rlm_eap_t, tparams.private_key),
451 NULL, "${confdir}/certs/server.pem" },
452 { "private_key_password", PW_TYPE_STRING_PTR,
453 offsetof(rlm_eap_t, tparams.private_key_passwd),
456 { "dh_file", PW_TYPE_STRING_PTR,
457 offsetof(rlm_eap_t, tparams.dh_file), NULL, "whatever" },
459 { NULL, -1, 0, NULL, NULL } /* end the list */
462 static CONF_PARSER fast_config[] = {
463 { "pac_opaque_encr_key", PW_TYPE_STRING_PTR,
464 offsetof(rlm_eap_t, pac_opaque_encr_key), NULL, NULL },
465 { "eap_fast_a_id", PW_TYPE_STRING_PTR,
466 offsetof(rlm_eap_t, eap_fast_a_id), NULL, NULL },
467 { "eap_fast_a_id_info", PW_TYPE_STRING_PTR,
468 offsetof(rlm_eap_t, eap_fast_a_id_info), NULL, NULL },
469 { "eap_fast_prov", PW_TYPE_INTEGER,
470 offsetof(rlm_eap_t, eap_fast_prov), NULL, "3"},
471 { "pac_key_lifetime", PW_TYPE_INTEGER,
472 offsetof(rlm_eap_t, pac_key_lifetime), NULL, "604800"},
473 { "pac_key_refresh_time", PW_TYPE_INTEGER,
474 offsetof(rlm_eap_t, pac_key_refresh_time), NULL, "86400"},
475 { NULL, -1, 0, NULL, NULL } /* end the list */
478 static const CONF_PARSER module_config[] = {
479 { "timer_expire", PW_TYPE_INTEGER,
480 offsetof(rlm_eap_t, timer_limit), NULL, "60"},
481 { "cisco_accounting_username_bug", PW_TYPE_BOOLEAN,
482 offsetof(rlm_eap_t, cisco_accounting_username_bug), NULL, "no" },
484 { "backend_auth", PW_TYPE_BOOLEAN,
485 offsetof(rlm_eap_t, backend_auth), NULL, "yes" },
487 { "tls", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tls_config },
489 { "fast", PW_TYPE_SUBSECTION, 0, NULL, (const void *) fast_config },
491 { NULL, -1, 0, NULL, NULL } /* end the list */
495 static int eap_example_server_init_tls(rlm_eap_t *inst)
497 struct tls_config tconf;
499 os_memset(&tconf, 0, sizeof(tconf));
500 inst->tls_ctx = tls_init(&tconf);
501 if (inst->tls_ctx == NULL)
504 if (tls_global_set_params(inst->tls_ctx, &inst->tparams)) {
505 radlog(L_ERR, "rlm_eap2: Failed to set TLS parameters");
509 if (tls_global_set_verify(inst->tls_ctx, 0)) {
510 radlog(L_ERR, "rlm_eap2: Failed to set check_crl");
519 * read the config section and load all the eap authentication types present.
521 static int eap_instantiate(CONF_SECTION *cs, void **instance)
528 *instance = inst = talloc_zero(conf, rlm_eap_t);
529 if (!inst) return -1;
531 if (cf_section_parse(cs, inst, module_config) < 0) {
537 * Create our own random pool.
539 for (i = 0; i < 256; i++) {
540 inst->rand_pool.randrsl[i] = fr_rand();
542 fr_randinit(&inst->rand_pool, 1);
545 * List of sessions are set to NULL by the memset
550 * Lookup sessions in the tree. We don't free them in
551 * the tree, as that's taken care of elsewhere...
553 inst->session_tree = rbtree_create(eap_handler_cmp, NULL, 0);
554 if (!inst->session_tree) {
555 radlog(L_ERR, "rlm_eap2: Cannot initialize tree");
561 * This registers ALL available methods.
563 * FIXME: we probably want to selectively register
566 if (eap_server_register_methods() < 0) {
571 /* Load all the configured EAP-Types */
573 has_tls = do_tls = 0;
574 for (scs=cf_subsection_find_next(cs, NULL, NULL);
576 scs=cf_subsection_find_next(cs, scs, NULL)) {
577 const char *auth_type;
580 auth_type = cf_section_name1(scs);
582 if (!auth_type) continue;
584 if (num_types >= EAP_MAX_METHODS) {
585 radlog(L_INFO, "WARNING: Ignoring EAP type %s: too many types defined", auth_type);
590 * Hostapd doesn't do case-insensitive comparisons.
591 * So we mash everything to uppercase for it.
593 strlcpy(buffer, auth_type, sizeof(buffer));
595 for (p = buffer; *p; p++) {
596 if (!islower((int)*p)) continue;
597 *p = toupper((int)*p);
600 inst->methods[num_types] = eap_server_get_type(buffer,
601 &inst->vendors[num_types]);
602 if (inst->methods[num_types] == EAP_TYPE_NONE) {
603 radlog(L_ERR, "rlm_eap2: Unknown EAP type %s",
609 switch (inst->methods[num_types]) {
624 num_types++; /* successfully loaded one more types */
626 inst->num_types = num_types;
628 if (do_tls && !has_tls) {
629 radlog(L_ERR, "rlm_eap2: TLS has not been configured. Cannot do methods that need TLS.");
638 if (eap_example_server_init_tls(inst) < 0) {
639 radlog(L_ERR, "rlm_eap2: Cannot initialize TLS");
645 pthread_mutex_init(&(inst->session_mutex), NULL);
650 static int eap_req2vp(EAP_HANDLER *handler)
652 int encoded, total, size;
654 VALUE_PAIR *head = NULL;
655 VALUE_PAIR **tail = &head;
658 ptr = wpabuf_head(handler->server_ctx.eap_if->eapReqData);
659 encoded = total = wpabuf_len(handler->server_ctx.eap_if->eapReqData);
663 if (size > 253) size = 253;
665 vp = paircreate(PW_EAP_MESSAGE, 0);
670 memcpy(vp->vp_octets, ptr, size);
680 pairdelete(&handler->request->reply->vps, PW_EAP_MESSAGE, TAG_ANY);
681 pairadd(&handler->request->reply->vps, head);
686 static int eap_example_server_step(EAP_HANDLER *handler)
688 int res, process = 0;
689 REQUEST *request = handler->request;
691 res = eap_server_sm_step(handler->server_ctx.eap);
693 if (handler->server_ctx.eap_if->eapReq) {
694 DEBUG("==> Request");
696 handler->server_ctx.eap_if->eapReq = 0;
699 if (handler->server_ctx.eap_if->eapSuccess) {
700 DEBUG("==> Success");
704 if (handler->server_ctx.eap_if->eapKeyAvailable) {
705 int length = handler->server_ctx.eap_if->eapKeyDataLen;
713 * FIXME: Length is zero?
717 vp = radius_pairmake(request, &request->reply->vps,
718 "MS-MPPE-Recv-Key", "", T_OP_EQ);
720 memcpy(vp->vp_octets,
721 handler->server_ctx.eap_if->eapKeyData,
726 vp = radius_pairmake(request, &request->reply->vps,
727 "MS-MPPE-Send-Key", "", T_OP_EQ);
729 memcpy(vp->vp_octets,
730 handler->server_ctx.eap_if->eapKeyData + length,
737 if (handler->server_ctx.eap_if->eapFail) {
743 if (wpabuf_head(handler->server_ctx.eap_if->eapReqData)) {
744 if (!eap_req2vp(handler)) return -1;
755 * Handles multiple EAP-Message attrs
756 * ie concatenates all to get the complete EAP packet.
758 * NOTE: Sometimes Framed-MTU might contain the length of EAP-Message,
759 * refer fragmentation in rfc2869.
761 static int eap_vp2data(VALUE_PAIR *vps, void **data, int *data_len)
763 VALUE_PAIR *first, *vp;
769 * Get only EAP-Message attribute list
771 first = pairfind(vps, PW_EAP_MESSAGE, 0, TAG_ANY);
773 radlog(L_ERR, "rlm_eap2: EAP-Message not found");
778 * Sanity check the length before doing anything.
780 if (first->length < 4) {
781 radlog(L_ERR, "rlm_eap2: EAP packet is too short.");
786 * Get the Actual length from the EAP packet
787 * First EAP-Message contains the EAP packet header
789 memcpy(&len, first->vp_strvalue + 2, sizeof(len));
793 * Take out even more weird things.
796 radlog(L_ERR, "rlm_eap2: EAP packet has invalid length.");
801 * Sanity check the length, BEFORE malloc'ing memory.
804 for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE, 0, TAG_ANY)) {
805 total_len += vp->length;
807 if (total_len > len) {
808 radlog(L_ERR, "rlm_eap2: Malformed EAP packet. Length in packet header does not match actual length");
814 * If the length is SMALLER, die, too.
816 if (total_len < len) {
817 radlog(L_ERR, "rlm_eap2: Malformed EAP packet. Length in packet header does not match actual length");
822 * Now that we know the lengths are OK, allocate memory.
826 radlog(L_ERR, "rlm_eap2: out of memory");
832 * Copy the data from EAP-Message's over to our EAP packet.
836 /* RADIUS ensures order of attrs, so just concatenate all */
837 for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE, 0, TAG_ANY)) {
838 memcpy(ptr, vp->vp_strvalue, vp->length);
846 * FIXME: Add an "authorize" section which sets Auth-Type = EAP2
847 * FIXME: Also in "authorize", set User-Name if not already set.
854 static rlm_rcode_t eap_authenticate(void *instance, REQUEST *request)
857 EAP_HANDLER *handler;
863 inst = (rlm_eap_t *) instance;
865 vp = pairfind(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
867 RDEBUG("No EAP-Message. Not doing EAP.");
868 return RLM_MODULE_FAIL;
872 * Get the eap packet to start with
876 if (eap_vp2data(request->packet->vps, &data, &data_len) < 0) {
877 radlog(L_ERR, "rlm_eap2: Malformed EAP Message");
878 return RLM_MODULE_FAIL;
881 vp = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY);
883 handler = eaplist_find(inst, request);
885 RDEBUG("No handler found");
886 return RLM_MODULE_FAIL;
889 handler = malloc(sizeof(*handler));
890 if (!handler) return RLM_MODULE_FAIL;
892 memset(handler, 0, sizeof(*handler));
894 handler->inst = inst;
895 handler->eap_cb.get_eap_user = server_get_eap_user;
896 handler->eap_cb.get_eap_req_id_text = server_get_eap_req_id_text;
898 handler->eap_conf.eap_server = 1;
899 handler->eap_conf.ssl_ctx = inst->tls_ctx;
902 * Copy EAP-FAST parameters.
904 handler->eap_conf.pac_opaque_encr_key = inst->pac_opaque_encr_key;
905 handler->eap_conf.eap_fast_a_id = inst->eap_fast_a_id;
906 handler->eap_conf.eap_fast_a_id_len = strlen(inst->eap_fast_a_id);
907 handler->eap_conf.eap_fast_a_id_info = inst->eap_fast_a_id_info;
908 handler->eap_conf.eap_fast_prov = inst->eap_fast_prov;
909 handler->eap_conf.pac_key_lifetime = inst->pac_key_lifetime;
910 handler->eap_conf.pac_key_refresh_time = inst->pac_key_refresh_time;
911 handler->eap_conf.backend_auth = inst->backend_auth;
913 handler->server_ctx.eap = eap_server_sm_init(handler,
916 if (handler->server_ctx.eap == NULL) {
918 return RLM_MODULE_FAIL;
921 handler->server_ctx.eap_if = eap_get_interface(handler->server_ctx.eap);
923 /* Enable "port" and request EAP to start authentication. */
924 handler->server_ctx.eap_if->portEnabled = TRUE;
925 handler->server_ctx.eap_if->eapRestart = TRUE;
928 handler->request = request;
929 wpabuf_free(handler->server_ctx.eap_if->eapRespData);
930 handler->server_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
931 if (handler->server_ctx.eap_if->eapRespData) {
932 handler->server_ctx.eap_if->eapResp = TRUE;
935 if (eap_example_server_step(handler) < 0) {
936 RDEBUG("Failed in EAP library");
940 if (handler->server_ctx.eap_if->eapSuccess) {
941 request->reply->code = PW_AUTHENTICATION_ACK;
942 rcode = RLM_MODULE_OK;
944 } else if (handler->server_ctx.eap_if->eapFail) {
946 request->reply->code = PW_AUTHENTICATION_REJECT;
947 rcode = RLM_MODULE_REJECT;
950 request->reply->code = PW_ACCESS_CHALLENGE;
951 rcode = RLM_MODULE_HANDLED;
954 if (handler->server_ctx.eap_if->eapFail ||
955 handler->server_ctx.eap_if->eapSuccess) {
956 RDEBUG2("Freeing handler");
957 /* handler is not required any more, free it now */
958 eap_handler_free(handler);
961 eaplist_add(inst, handler);
965 * If it's an Access-Accept, RFC 2869, Section 2.3.1
966 * says that we MUST include a User-Name attribute in the
969 if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
972 * Doesn't exist, add it in.
974 vp = pairfind(request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
976 vp = pairmake("User-Name", request->username->vp_strvalue,
978 rad_assert(vp != NULL);
979 pairadd(&(request->reply->vps), vp);
983 * Cisco AP1230 has a bug and needs a zero
984 * terminated string in Access-Accept.
986 if ((inst->cisco_accounting_username_bug) &&
987 (vp->length < (int) sizeof(vp->vp_strvalue))) {
988 vp->vp_strvalue[vp->length] = '\0';
993 vp = pairfind(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
995 vp = paircreate(PW_MESSAGE_AUTHENTICATOR, 0);
996 memset(vp->vp_strvalue, 0, AUTH_VECTOR_LEN);
997 vp->length = AUTH_VECTOR_LEN;
998 pairadd(&(request->reply->vps), vp);
1005 * The module name should be the only globally exported symbol.
1006 * That is, everything else should be 'static'.
1008 module_t rlm_eap2 = {
1011 RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
1012 eap_instantiate, /* instantiation */
1013 eap_detach, /* detach */
1015 eap_authenticate, /* authentication */
1016 NULL, /* authorization */
1017 NULL, /* preaccounting */
1018 NULL, /* accounting */
1019 NULL, /* checksimul */
1020 NULL, /* pre-proxy */
1021 NULL, /* post-proxy */
1022 NULL /* post-auth */