2 * rlm_eap.c contains handles that are called from modules.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * 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;
75 EapType methods[EAP_MAX_METHODS];
76 int vendors[EAP_MAX_METHODS];
79 pthread_mutex_t session_mutex;
87 static void eap_handler_free(EAP_HANDLER *handler)
89 eap_server_sm_deinit(handler->server_ctx.eap);
93 static void eaplist_free(rlm_eap_t *inst)
95 EAP_HANDLER *node, *next;
97 for (node = inst->session_head; node != NULL; node = next) {
99 eap_handler_free(node);
102 inst->session_head = inst->session_tail = NULL;
106 * Return a 32-bit random number.
108 static uint32_t eap_rand(fr_randctx *ctx)
112 num = ctx->randrsl[ctx->randcnt++];
113 if (ctx->randcnt == 256) {
122 * Add a handler to the set of active sessions.
124 * Since we're adding it to the list, we guess that this means
125 * the packet needs a State attribute. So add one.
127 static int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler)
133 rad_assert(handler != NULL);
134 rad_assert(handler->request != NULL);
137 * Generate State, since we've been asked to add it to
140 state = pairmake("State", "0x00", T_OP_EQ);
141 if (!state) return 0;
142 pairadd(&(handler->request->reply->vps), state);
143 state->length = EAP_STATE_LEN;
146 * The time at which this request was made was the time
147 * at which it was received by the RADIUS server.
149 handler->timestamp = handler->request->timestamp;
151 handler->src_ipaddr = handler->request->packet->src_ipaddr;
154 * We don't need this any more.
156 handler->request = NULL;
159 * Playing with a data structure shared among threads
160 * means that we need a lock, to avoid conflict.
162 pthread_mutex_lock(&(inst->session_mutex));
165 * Create a completely random state.
167 for (i = 0; i < 4; i++) {
168 lvalue = eap_rand(&inst->rand_pool);
169 memcpy(state->vp_octets + i * 4, &lvalue, sizeof(lvalue));
171 memcpy(handler->state, state->vp_strvalue, sizeof(handler->state));
176 status = rbtree_insert(inst->session_tree, handler);
181 prev = inst->session_tail;
183 prev->next = handler;
184 handler->prev = prev;
185 handler->next = NULL;
186 inst->session_tail = handler;
188 inst->session_head = inst->session_tail = handler;
189 handler->next = handler->prev = NULL;
194 * Now that we've finished mucking with the list,
197 pthread_mutex_unlock(&(inst->session_mutex));
200 radlog(L_ERR, "rlm_eap2: Failed to remember handler!");
201 eap_handler_free(handler);
209 * Find a a previous EAP-Request sent by us, which matches
210 * the current EAP-Response.
212 * Then, release the handle from the list, and return it to
215 * Also since we fill the eap_ds with the present EAP-Response we
216 * got to free the prev_eapds & move the eap_ds to prev_eapds
218 static EAP_HANDLER *eaplist_find(rlm_eap_t *inst, REQUEST *request)
223 EAP_HANDLER *handler, myHandler;
226 * We key the sessions off of the 'state' attribute, so it
229 state = pairfind(request->packet->vps, PW_STATE, 0);
231 (state->length != EAP_STATE_LEN)) {
235 myHandler.src_ipaddr = request->packet->src_ipaddr;
236 memcpy(myHandler.state, state->vp_strvalue, sizeof(myHandler.state));
239 * Playing with a data structure shared among threads
240 * means that we need a lock, to avoid conflict.
242 pthread_mutex_lock(&(inst->session_mutex));
245 * Check the first few handlers in the list, and delete
246 * them if they're too old. We don't need to check them
247 * all, as incoming requests will quickly cause older
248 * handlers to be deleted.
251 for (i = 0; i < 2; i++) {
252 handler = inst->session_head;
254 ((request->timestamp - handler->timestamp) > inst->timer_limit)) {
255 node = rbtree_find(inst->session_tree, handler);
256 rad_assert(node != NULL);
257 rbtree_delete(inst->session_tree, node);
260 * handler == inst->session_head
262 inst->session_head = handler->next;
264 handler->next->prev = NULL;
266 inst->session_head = NULL;
268 eap_handler_free(handler);
273 node = rbtree_find(inst->session_tree, &myHandler);
275 handler = rbtree_node2data(inst->session_tree, node);
278 * Delete old handler from the tree.
280 rbtree_delete(inst->session_tree, node);
283 * And unsplice it from the linked list.
286 handler->prev->next = handler->next;
288 inst->session_head = handler->next;
291 handler->next->prev = handler->prev;
293 inst->session_tail = handler->prev;
295 handler->prev = handler->next = NULL;
298 pthread_mutex_unlock(&(inst->session_mutex));
304 RDEBUG2("Request not found in the list");
309 * Found, but state verification failed.
312 radlog(L_ERR, "rlm_eap2: State verification failed.");
316 RDEBUG2("Request found, released from the list");
323 * delete all the allocated space by eap module
325 static int eap_detach(void *instance)
329 inst = (rlm_eap_t *)instance;
331 rbtree_free(inst->session_tree);
332 inst->session_tree = NULL;
334 eap_server_unregister_methods();
335 tls_deinit(inst->tls_ctx);
337 pthread_mutex_destroy(&(inst->session_mutex));
346 * Compare two handlers.
348 static int eap_handler_cmp(const void *a, const void *b)
351 const EAP_HANDLER *one = a;
352 const EAP_HANDLER *two = b;
354 rcode = fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr);
355 if (rcode != 0) return rcode;
357 return memcmp(one->state, two->state, sizeof(one->state));
361 static int server_get_eap_user(void *ctx, const u8 *identity,
362 size_t identity_len, int phase2,
363 struct eap_user *user)
367 EAP_HANDLER *handler = ctx;
368 REQUEST *request = handler->request;
370 os_memset(user, 0, sizeof(*user));
373 * FIXME: Run through "authorise" again to look up
374 * password for the given identity
376 identity = identity; /* -Wunused */
377 identity_len = identity_len; /* -Wunused */
380 * Do this always, just in case.
382 vp = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0);
384 user->password = (u8 *) os_strdup(vp->vp_strvalue);
385 user->password_len = vp->length;
387 if (!vp) vp = pairfind(request->config_items, PW_NT_PASSWORD, 0);
389 user->password = (u8 *) malloc(vp->length);
390 memcpy(user->password, vp->vp_octets, vp->length);
391 user->password_len = vp->length;
395 for (i = 0; i < handler->inst->num_types; i++) {
396 user->methods[i].vendor = handler->inst->vendors[i];
397 user->methods[i].method = handler->inst->methods[i];
403 * FIXME: run tunneled sessions through the tunneled portion...
407 * FIXME: Selectively control tunneled EAP types.
409 user->methods[0].vendor = EAP_VENDOR_IETF;
410 user->methods[0].method = EAP_TYPE_MD5;
411 user->methods[1].vendor = EAP_VENDOR_IETF;
412 user->methods[1].method = EAP_TYPE_MSCHAPV2;
415 * No password configured...
422 static const char * server_get_eap_req_id_text(void *ctx, size_t *len)
424 ctx = ctx; /* -Wunused */
430 static CONF_PARSER tls_config[] = {
434 { "ca_cert", PW_TYPE_STRING_PTR,
435 offsetof(rlm_eap_t, tparams.ca_cert),
436 NULL, "${confdir}/certs/ca.pem" },
437 { "server_cert", PW_TYPE_STRING_PTR,
438 offsetof(rlm_eap_t, tparams.client_cert),
439 NULL, "${confdir}/certs/server.pem" },
440 { "private_key_file", PW_TYPE_STRING_PTR,
441 offsetof(rlm_eap_t, tparams.private_key),
442 NULL, "${confdir}/certs/server.pem" },
443 { "private_key_password", PW_TYPE_STRING_PTR,
444 offsetof(rlm_eap_t, tparams.private_key_passwd),
447 { NULL, -1, 0, NULL, NULL } /* end the list */
450 static const CONF_PARSER module_config[] = {
451 { "timer_expire", PW_TYPE_INTEGER,
452 offsetof(rlm_eap_t, timer_limit), NULL, "60"},
453 { "cisco_accounting_username_bug", PW_TYPE_BOOLEAN,
454 offsetof(rlm_eap_t, cisco_accounting_username_bug), NULL, "no" },
456 { "tls", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tls_config },
458 { NULL, -1, 0, NULL, NULL } /* end the list */
462 static int eap_example_server_init_tls(rlm_eap_t *inst)
464 struct tls_config tconf;
466 os_memset(&tconf, 0, sizeof(tconf));
467 inst->tls_ctx = tls_init(&tconf);
468 if (inst->tls_ctx == NULL)
471 if (tls_global_set_params(inst->tls_ctx, &inst->tparams)) {
472 radlog(L_ERR, "rlm_eap2: Failed to set TLS parameters");
476 if (tls_global_set_verify(inst->tls_ctx, 0)) {
477 radlog(L_ERR, "rlm_eap2: Failed to set check_crl");
486 * read the config section and load all the eap authentication types present.
488 static int eap_instantiate(CONF_SECTION *cs, void **instance)
495 inst = (rlm_eap_t *) malloc(sizeof(*inst));
499 memset(inst, 0, sizeof(*inst));
500 if (cf_section_parse(cs, inst, module_config) < 0) {
506 * Create our own random pool.
508 for (i = 0; i < 256; i++) {
509 inst->rand_pool.randrsl[i] = fr_rand();
511 fr_randinit(&inst->rand_pool, 1);
514 * List of sessions are set to NULL by the memset
519 * Lookup sessions in the tree. We don't free them in
520 * the tree, as that's taken care of elsewhere...
522 inst->session_tree = rbtree_create(eap_handler_cmp, NULL, 0);
523 if (!inst->session_tree) {
524 radlog(L_ERR|L_CONS, "rlm_eap2: Cannot initialize tree");
530 * This registers ALL available methods.
532 * FIXME: we probably want to selectively register
535 if (eap_server_register_methods() < 0) {
540 /* Load all the configured EAP-Types */
542 has_tls = do_tls = 0;
543 for (scs=cf_subsection_find_next(cs, NULL, NULL);
545 scs=cf_subsection_find_next(cs, scs, NULL)) {
546 const char *auth_type;
549 auth_type = cf_section_name1(scs);
551 if (!auth_type) continue;
553 if (num_types >= EAP_MAX_METHODS) {
554 radlog(L_INFO, "WARNING: Ignoring EAP type %s: too many types defined", auth_type);
559 * Hostapd doesn't do case-insensitive comparisons.
560 * So we mash everything to uppercase for it.
562 strlcpy(buffer, auth_type, sizeof(buffer));
564 for (p = buffer; *p; p++) {
565 if (!islower((int)*p)) continue;
566 *p = toupper((int)*p);
569 inst->methods[num_types] = eap_server_get_type(buffer,
570 &inst->vendors[num_types]);
571 if (inst->methods[num_types] == EAP_TYPE_NONE) {
572 radlog(L_ERR|L_CONS, "rlm_eap2: Unknown EAP type %s",
578 switch (inst->methods[num_types]) {
593 num_types++; /* successfully loaded one more types */
595 inst->num_types = num_types;
597 if (do_tls && !has_tls) {
598 radlog(L_ERR|L_CONS, "rlm_eap2: TLS has not been configured. Cannot do methods that need TLS.");
607 if (eap_example_server_init_tls(inst) < 0) {
608 radlog(L_ERR|L_CONS, "rlm_eap2: Cannot initialize TLS");
614 pthread_mutex_init(&(inst->session_mutex), NULL);
621 static int eap_req2vp(EAP_HANDLER *handler)
623 int encoded, total, size;
625 VALUE_PAIR *head = NULL;
626 VALUE_PAIR **tail = &head;
629 ptr = wpabuf_head(handler->server_ctx.eap_if->eapReqData);
630 encoded = total = wpabuf_len(handler->server_ctx.eap_if->eapReqData);
634 if (size > 253) size = 253;
636 vp = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS);
641 memcpy(vp->vp_octets, ptr, size);
651 pairdelete(&handler->request->reply->vps, PW_EAP_MESSAGE);
652 pairadd(&handler->request->reply->vps, head);
657 static int eap_example_server_step(EAP_HANDLER *handler)
659 int res, process = 0;
660 REQUEST *request = handler->request;
662 res = eap_server_sm_step(handler->server_ctx.eap);
664 if (handler->server_ctx.eap_if->eapReq) {
665 DEBUG("==> Request");
667 handler->server_ctx.eap_if->eapReq = 0;
670 if (handler->server_ctx.eap_if->eapSuccess) {
671 DEBUG("==> Success");
675 if (handler->server_ctx.eap_if->eapKeyAvailable) {
676 int length = handler->server_ctx.eap_if->eapKeyDataLen;
684 * FIXME: Length is zero?
688 vp = radius_pairmake(request, &request->reply->vps,
689 "MS-MPPE-Recv-Key", "", T_OP_EQ);
691 memcpy(vp->vp_octets,
692 handler->server_ctx.eap_if->eapKeyData,
697 vp = radius_pairmake(request, &request->reply->vps,
698 "MS-MPPE-Send-Key", "", T_OP_EQ);
700 memcpy(vp->vp_octets,
701 handler->server_ctx.eap_if->eapKeyData + length,
708 if (handler->server_ctx.eap_if->eapFail) {
714 if (wpabuf_head(handler->server_ctx.eap_if->eapReqData)) {
715 if (!eap_req2vp(handler)) return -1;
726 * Handles multiple EAP-Message attrs
727 * ie concatenates all to get the complete EAP packet.
729 * NOTE: Sometimes Framed-MTU might contain the length of EAP-Message,
730 * refer fragmentation in rfc2869.
732 static int eap_vp2data(VALUE_PAIR *vps, void **data, int *data_len)
734 VALUE_PAIR *first, *vp;
740 * Get only EAP-Message attribute list
742 first = pairfind(vps, PW_EAP_MESSAGE, 0);
744 radlog(L_ERR, "rlm_eap2: EAP-Message not found");
749 * Sanity check the length before doing anything.
751 if (first->length < 4) {
752 radlog(L_ERR, "rlm_eap2: EAP packet is too short.");
757 * Get the Actual length from the EAP packet
758 * First EAP-Message contains the EAP packet header
760 memcpy(&len, first->vp_strvalue + 2, sizeof(len));
764 * Take out even more weird things.
767 radlog(L_ERR, "rlm_eap2: EAP packet has invalid length.");
772 * Sanity check the length, BEFORE malloc'ing memory.
775 for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE, 0)) {
776 total_len += vp->length;
778 if (total_len > len) {
779 radlog(L_ERR, "rlm_eap2: Malformed EAP packet. Length in packet header does not match actual length");
785 * If the length is SMALLER, die, too.
787 if (total_len < len) {
788 radlog(L_ERR, "rlm_eap2: Malformed EAP packet. Length in packet header does not match actual length");
793 * Now that we know the lengths are OK, allocate memory.
797 radlog(L_ERR, "rlm_eap2: out of memory");
803 * Copy the data from EAP-Message's over to our EAP packet.
807 /* RADIUS ensures order of attrs, so just concatenate all */
808 for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE, 0)) {
809 memcpy(ptr, vp->vp_strvalue, vp->length);
817 * FIXME: Add an "authorize" section which sets Auth-Type = EAP2
818 * FIXME: Also in "authorize", set User-Name if not already set.
825 static int eap_authenticate(void *instance, REQUEST *request)
828 EAP_HANDLER *handler;
834 inst = (rlm_eap_t *) instance;
836 vp = pairfind(request->packet->vps, PW_EAP_MESSAGE, 0);
838 RDEBUG("No EAP-Message. Not doing EAP.");
839 return RLM_MODULE_FAIL;
843 * Get the eap packet to start with
847 if (eap_vp2data(request->packet->vps, &data, &data_len) < 0) {
848 radlog(L_ERR, "rlm_eap2: Malformed EAP Message");
849 return RLM_MODULE_FAIL;
852 vp = pairfind(request->packet->vps, PW_STATE, 0);
854 handler = eaplist_find(inst, request);
856 RDEBUG("No handler found");
857 return RLM_MODULE_FAIL;
860 handler = malloc(sizeof(*handler));
861 if (!handler) return RLM_MODULE_FAIL;
863 memset(handler, 0, sizeof(*handler));
865 handler->inst = inst;
866 handler->eap_cb.get_eap_user = server_get_eap_user;
867 handler->eap_cb.get_eap_req_id_text = server_get_eap_req_id_text;
869 handler->eap_conf.eap_server = 1;
870 handler->eap_conf.ssl_ctx = inst->tls_ctx;
872 handler->server_ctx.eap = eap_server_sm_init(handler,
875 if (handler->server_ctx.eap == NULL) {
877 return RLM_MODULE_FAIL;
880 handler->server_ctx.eap_if = eap_get_interface(handler->server_ctx.eap);
882 /* Enable "port" and request EAP to start authentication. */
883 handler->server_ctx.eap_if->portEnabled = TRUE;
884 handler->server_ctx.eap_if->eapRestart = TRUE;
887 handler->request = request;
888 wpabuf_free(handler->server_ctx.eap_if->eapRespData);
889 handler->server_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
890 if (handler->server_ctx.eap_if->eapRespData) {
891 handler->server_ctx.eap_if->eapResp = TRUE;
894 if (eap_example_server_step(handler) < 0) {
895 RDEBUG("Failed in EAP library");
899 if (handler->server_ctx.eap_if->eapSuccess) {
900 request->reply->code = PW_AUTHENTICATION_ACK;
901 rcode = RLM_MODULE_OK;
903 } else if (handler->server_ctx.eap_if->eapFail) {
905 request->reply->code = PW_AUTHENTICATION_REJECT;
906 rcode = RLM_MODULE_REJECT;
909 request->reply->code = PW_ACCESS_CHALLENGE;
910 rcode = RLM_MODULE_HANDLED;
913 if (handler->server_ctx.eap_if->eapFail ||
914 handler->server_ctx.eap_if->eapSuccess) {
915 RDEBUG2("Freeing handler");
916 /* handler is not required any more, free it now */
917 eap_handler_free(handler);
920 eaplist_add(inst, handler);
924 * If it's an Access-Accept, RFC 2869, Section 2.3.1
925 * says that we MUST include a User-Name attribute in the
928 if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
931 * Doesn't exist, add it in.
933 vp = pairfind(request->reply->vps, PW_USER_NAME, 0);
935 vp = pairmake("User-Name", request->username->vp_strvalue,
937 rad_assert(vp != NULL);
938 pairadd(&(request->reply->vps), vp);
942 * Cisco AP1230 has a bug and needs a zero
943 * terminated string in Access-Accept.
945 if ((inst->cisco_accounting_username_bug) &&
946 (vp->length < (int) sizeof(vp->vp_strvalue))) {
947 vp->vp_strvalue[vp->length] = '\0';
952 vp = pairfind(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0);
954 vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
955 memset(vp->vp_strvalue, 0, AUTH_VECTOR_LEN);
956 vp->length = AUTH_VECTOR_LEN;
957 pairadd(&(request->reply->vps), vp);
964 * The module name should be the only globally exported symbol.
965 * That is, everything else should be 'static'.
967 module_t rlm_eap2 = {
970 RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
971 eap_instantiate, /* instantiation */
972 eap_detach, /* detach */
974 eap_authenticate, /* authentication */
975 NULL, /* authorization */
976 NULL, /* preaccounting */
977 NULL, /* accounting */
978 NULL, /* checksimul */
979 NULL, /* pre-proxy */
980 NULL, /* post-proxy */