Log reasons for failure.
[freeradius.git] / src / modules / rlm_eap / rlm_eap.c
1 /*
2  * rlm_eap.c  contains handles that are called from modules.
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2000-2003,2006  The FreeRADIUS server project
21  * Copyright 2001  hereUare Communications, Inc. <raghud@hereuare.com>
22  * Copyright 2003  Alan DeKok <aland@freeradius.org>
23  */
24
25 #include <freeradius-devel/ident.h>
26 RCSID("$Id$")
27
28 #include <freeradius-devel/radiusd.h>
29 #include <freeradius-devel/modules.h>
30
31 #include "rlm_eap.h"
32
33 static const CONF_PARSER module_config[] = {
34         { "default_eap_type", PW_TYPE_STRING_PTR,
35           offsetof(rlm_eap_t, default_eap_type_name), NULL, "md5" },
36         { "timer_expire", PW_TYPE_INTEGER,
37           offsetof(rlm_eap_t, timer_limit), NULL, "60"},
38         { "ignore_unknown_eap_types", PW_TYPE_BOOLEAN,
39           offsetof(rlm_eap_t, ignore_unknown_eap_types), NULL, "no" },
40         { "cisco_accounting_username_bug", PW_TYPE_BOOLEAN,
41           offsetof(rlm_eap_t, cisco_accounting_username_bug), NULL, "no" },
42         { "max_sessions", PW_TYPE_INTEGER,
43           offsetof(rlm_eap_t, max_sessions), NULL, "2048"},
44
45         { NULL, -1, 0, NULL, NULL }           /* end the list */
46 };
47
48 /*
49  * delete all the allocated space by eap module
50  */
51 static int eap_detach(void *instance)
52 {
53         rlm_eap_t *inst;
54         int i;
55
56         inst = (rlm_eap_t *)instance;
57
58         rbtree_free(inst->session_tree);
59         inst->session_tree = NULL;
60         eaplist_free(inst);
61
62         for (i = 0; i < PW_EAP_MAX_TYPES; i++) {
63                 if (inst->types[i]) eaptype_free(inst->types[i]);
64                 inst->types[i] = NULL;
65         }
66
67         pthread_mutex_destroy(&(inst->session_mutex));
68
69         free(inst);
70
71         return 0;
72 }
73
74
75 /*
76  *      Compare two handlers.
77  */
78 static int eap_handler_cmp(const void *a, const void *b)
79 {
80         int rcode;
81         const EAP_HANDLER *one = a;
82         const EAP_HANDLER *two = b;
83
84         if (one->eap_id < two->eap_id) return -1;
85         if (one->eap_id > two->eap_id) return +1;
86
87         rcode = fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr);
88         if (rcode != 0) return rcode;
89
90         return memcmp(one->state, two->state, sizeof(one->state));
91 }
92
93
94 /*
95  * read the config section and load all the eap authentication types present.
96  */
97 static int eap_instantiate(CONF_SECTION *cs, void **instance)
98 {
99         int             i, eap_type;
100         int             num_types;
101         CONF_SECTION    *scs;
102         rlm_eap_t       *inst;
103
104         inst = (rlm_eap_t *) malloc(sizeof(*inst));
105         if (!inst) {
106                 return -1;
107         }
108         memset(inst, 0, sizeof(*inst));
109         if (cf_section_parse(cs, inst, module_config) < 0) {
110                 eap_detach(inst);
111                 return -1;
112         }
113
114         /*
115          *      Create our own random pool.
116          */
117         for (i = 0; i < 256; i++) {
118                 inst->rand_pool.randrsl[i] = fr_rand();
119         }
120         fr_randinit(&inst->rand_pool, 1);
121         inst->rand_pool.randcnt = 0;
122
123         inst->xlat_name = cf_section_name2(cs);
124         if (!inst->xlat_name) inst->xlat_name = "EAP";
125
126         /* Load all the configured EAP-Types */
127         num_types = 0;
128         for(scs=cf_subsection_find_next(cs, NULL, NULL);
129                 scs != NULL;
130                 scs=cf_subsection_find_next(cs, scs, NULL)) {
131
132                 const char      *auth_type;
133
134                 auth_type = cf_section_name1(scs);
135
136                 if (!auth_type)  continue;
137
138                 eap_type = eaptype_name2type(auth_type);
139                 if (eap_type < 0) {
140                         radlog(L_ERR, "rlm_eap: Unknown EAP type %s",
141                                auth_type);
142                         eap_detach(inst);
143                         return -1;
144                 }
145
146 #ifndef HAVE_OPENSSL_SSL_H
147                 /*
148                  *      This allows the default configuration to be
149                  *      shipped with EAP-TLS, etc. enabled.  If the
150                  *      system doesn't have OpenSSL, they will be
151                  *      ignored.
152                  *
153                  *      If the system does have OpenSSL, then this
154                  *      code will not be used.  The administrator will
155                  *      then have to delete the tls,
156                  *      etc. configurations from eap.conf in order to
157                  *      have EAP without the TLS types.
158                  */
159                 if ((eap_type == PW_EAP_TLS) ||
160                     (eap_type == PW_EAP_TTLS) ||
161                     (eap_type == PW_EAP_PEAP)) {
162                         DEBUG2("Ignoring EAP-Type/%s because we do not have OpenSSL support.", auth_type);
163                         continue;
164                 }
165 #endif
166
167                 /*
168                  *      If we're asked to load TTLS or PEAP, ensure
169                  *      that we've first loaded TLS.
170                  */
171                 if (((eap_type == PW_EAP_TTLS) ||
172                      (eap_type == PW_EAP_PEAP)) &&
173                     (inst->types[PW_EAP_TLS] == NULL)) {
174                         radlog(L_ERR, "rlm_eap: Unable to load EAP-Type/%s, as EAP-Type/TLS is required first.",
175                                auth_type);
176                         return -1;
177                 }
178
179                 /*
180                  *      Load the type.
181                  */
182                 if (eaptype_load(&inst->types[eap_type], eap_type, scs) < 0) {
183                         eap_detach(inst);
184                         return -1;
185                 }
186
187                 num_types++;    /* successfully loaded one more types */
188         }
189
190         if (num_types == 0) {
191                 radlog(L_ERR|L_CONS, "rlm_eap: No EAP type configured, module cannot do anything.");
192                 eap_detach(inst);
193                 return -1;
194         }
195
196         /*
197          *      Ensure that the default EAP type is loaded.
198          */
199         eap_type = eaptype_name2type(inst->default_eap_type_name);
200         if (eap_type < 0) {
201                 radlog(L_ERR|L_CONS, "rlm_eap: Unknown default EAP type %s",
202                        inst->default_eap_type_name);
203                 eap_detach(inst);
204                 return -1;
205         }
206
207         if (inst->types[eap_type] == NULL) {
208                 radlog(L_ERR|L_CONS, "rlm_eap: No such sub-type for default EAP type %s",
209                        inst->default_eap_type_name);
210                 eap_detach(inst);
211                 return -1;
212         }
213         inst->default_eap_type = eap_type; /* save the numerical type */
214
215         /*
216          *      List of sessions are set to NULL by the memset
217          *      of 'inst', above.
218          */
219
220         /*
221          *      Lookup sessions in the tree.  We don't free them in
222          *      the tree, as that's taken care of elsewhere...
223          */
224         inst->session_tree = rbtree_create(eap_handler_cmp, NULL, 0);
225         if (!inst->session_tree) {
226                 radlog(L_ERR|L_CONS, "rlm_eap: Cannot initialize tree");
227                 eap_detach(inst);
228                 return -1;
229         }
230
231         pthread_mutex_init(&(inst->session_mutex), NULL);
232
233         *instance = inst;
234         return 0;
235 }
236
237
238 /*
239  *      For backwards compatibility.
240  */
241 static int eap_authenticate(void *instance, REQUEST *request)
242 {
243         rlm_eap_t       *inst;
244         EAP_HANDLER     *handler;
245         eap_packet_t    *eap_packet;
246         int             rcode;
247
248         inst = (rlm_eap_t *) instance;
249
250         /*
251          *      Get the eap packet  to start with
252          */
253         eap_packet = eap_vp2packet(request->packet->vps);
254         if (eap_packet == NULL) {
255                 radlog_request(L_ERR, 0, request, "Malformed EAP Message");
256                 return RLM_MODULE_FAIL;
257         }
258
259         /*
260          *      Create the eap handler.  The eap_packet will end up being
261          *      "swallowed" into the handler, so we can't access it after
262          *      this call.
263          */
264         handler = eap_handler(inst, &eap_packet, request);
265         if (handler == NULL) {
266                 RDEBUG2("Failed in handler");
267                 return RLM_MODULE_INVALID;
268         }
269
270         /*
271          *      Select the appropriate eap_type or default to the
272          *      configured one
273          */
274         rcode = eaptype_select(inst, handler);
275
276         /*
277          *      If it failed, die.
278          */
279         if (rcode == EAP_INVALID) {
280                 eap_fail(handler);
281                 eap_handler_free(handler);
282                 RDEBUG2("Failed in EAP select");
283                 return RLM_MODULE_INVALID;
284         }
285
286         /*
287          *      If we're doing horrible tunneling work, remember it.
288          */
289         if ((request->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
290                 RDEBUG2("  Not-EAP proxy set.  Not composing EAP");
291                 /*
292                  *      Add the handle to the proxied list, so that we
293                  *      can retrieve it in the post-proxy stage, and
294                  *      send a response.
295                  */
296                 rcode = request_data_add(request,
297                                          inst, REQUEST_DATA_EAP_HANDLER,
298                                          handler,
299                                          (void *) eap_handler_free);
300                 rad_assert(rcode == 0);
301
302                 return RLM_MODULE_HANDLED;
303         }
304
305
306         /*
307          *      Maybe the request was marked to be proxied.  If so,
308          *      proxy it.
309          */
310         if (request->proxy != NULL) {
311                 VALUE_PAIR *vp = NULL;
312
313                 rad_assert(request->proxy_reply == NULL);
314
315                 /*
316                  *      Add the handle to the proxied list, so that we
317                  *      can retrieve it in the post-proxy stage, and
318                  *      send a response.
319                  */
320                 rcode = request_data_add(request,
321                                          inst, REQUEST_DATA_EAP_HANDLER,
322                                          handler,
323                                          (void *) eap_handler_free);
324                 rad_assert(rcode == 0);
325
326                 /*
327                  *      Some simple sanity checks.  These should really
328                  *      be handled by the radius library...
329                  */
330                 vp = pairfind(request->proxy->vps, PW_EAP_MESSAGE);
331                 if (vp) {
332                         vp = pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR);
333                         if (!vp) {
334                                 vp = pairmake("Message-Authenticator",
335                                               "0x00", T_OP_EQ);
336                                 rad_assert(vp != NULL);
337                                 pairadd(&(request->proxy->vps), vp);
338                         }
339                 }
340
341                 /*
342                  *      Delete the "proxied to" attribute, as it's
343                  *      set to 127.0.0.1 for tunneled requests, and
344                  *      we don't want to tell the world that...
345                  */
346                 pairdelete(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO);
347
348                 RDEBUG2("  Tunneled session will be proxied.  Not doing EAP.");
349                 return RLM_MODULE_HANDLED;
350         }
351
352         /*
353          *      We are done, wrap the EAP-request in RADIUS to send
354          *      with all other required radius attributes
355          */
356         rcode = eap_compose(handler);
357
358         /*
359          *      Add to the list only if it is EAP-Request, OR if
360          *      it's LEAP, and a response.
361          */
362         if (((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
363             (handler->eap_ds->request->type.type >= PW_EAP_MD5)) ||
364
365                 /*
366                  *      LEAP is a little different.  At Stage 4,
367                  *      it sends an EAP-Success message, but we still
368                  *      need to keep the State attribute & session
369                  *      data structure around for the AP Challenge.
370                  *
371                  *      At stage 6, LEAP sends an EAP-Response, which
372                  *      isn't put into the list.
373                  */
374             ((handler->eap_ds->response->code == PW_EAP_RESPONSE) &&
375              (handler->eap_ds->response->type.type == PW_EAP_LEAP) &&
376              (handler->eap_ds->request->code == PW_EAP_SUCCESS) &&
377              (handler->eap_ds->request->type.type == 0))) {
378
379                 /*
380                  *      Return FAIL if we can't remember the handler.
381                  *      This is actually disallowed by the
382                  *      specification, as unexpected FAILs could have
383                  *      been forged.  However, we want to signal to
384                  *      everyone else involved that we are
385                  *      intentionally failing the session, as opposed
386                  *      to accidentally failing it.
387                  */
388                 if (!eaplist_add(inst, handler)) {
389                         eap_fail(handler);
390                         eap_handler_free(handler);
391                         return RLM_MODULE_FAIL;
392                 }
393
394         } else {
395                 RDEBUG2("Freeing handler");
396                 /* handler is not required any more, free it now */
397                 eap_handler_free(handler);
398         }
399
400         /*
401          *      If it's an Access-Accept, RFC 2869, Section 2.3.1
402          *      says that we MUST include a User-Name attribute in the
403          *      Access-Accept.
404          */
405         if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
406             request->username) {
407                 VALUE_PAIR *vp;
408
409                 /*
410                  *      Doesn't exist, add it in.
411                  */
412                 vp = pairfind(request->reply->vps, PW_USER_NAME);
413                 if (!vp) {
414                         vp = pairmake("User-Name", "",
415                                       T_OP_EQ);
416                         strlcpy(vp->vp_strvalue, request->username->vp_strvalue,
417                                 sizeof(vp->vp_strvalue));
418                         vp->length = request->username->length;
419                         rad_assert(vp != NULL);
420                         pairadd(&(request->reply->vps), vp);
421                 }
422
423                 /*
424                  *      Cisco AP1230 has a bug and needs a zero
425                  *      terminated string in Access-Accept.
426                  */
427                 if ((inst->cisco_accounting_username_bug) &&
428                     (vp->length < (int) sizeof(vp->vp_strvalue))) {
429                         vp->vp_strvalue[vp->length] = '\0';
430                         vp->length++;
431                 }
432         }
433
434         return rcode;
435 }
436
437 /*
438  * EAP authorization DEPENDS on other rlm authorizations,
439  * to check for user existance & get their configured values.
440  * It Handles EAP-START Messages, User-Name initilization.
441  */
442 static int eap_authorize(void *instance, REQUEST *request)
443 {
444         rlm_eap_t       *inst;
445         int             status;
446         VALUE_PAIR      *vp;
447
448         inst = (rlm_eap_t *)instance;
449
450         /*
451          *      We don't do authorization again, once we've seen the
452          *      proxy reply (or the proxied packet)
453          */
454         if (request->proxy != NULL)
455                 return RLM_MODULE_NOOP;
456
457         /*
458          *      For EAP_START, send Access-Challenge with EAP Identity
459          *      request.  even when we have to proxy this request
460          *
461          *      RFC 2869, Section 2.3.1 notes that the "domain" of the
462          *      user, (i.e. where to proxy him) comes from the EAP-Identity,
463          *      so we CANNOT proxy the user, until we know his identity.
464          *
465          *      We therefore send an EAP Identity request.
466          */
467         status = eap_start(inst, request);
468         switch(status) {
469         case EAP_NOOP:
470                 return RLM_MODULE_NOOP;
471         case EAP_FAIL:
472                 return RLM_MODULE_FAIL;
473         case EAP_FOUND:
474                 return RLM_MODULE_HANDLED;
475         case EAP_OK:
476         case EAP_NOTFOUND:
477         default:
478                 break;
479         }
480
481         /*
482          *      RFC 2869, Section 2.3.1.  If a NAS sends an EAP-Identity,
483          *      it MUST copy the identity into the User-Name attribute.
484          *
485          *      But we don't worry about that too much.  We depend on
486          *      each EAP sub-module to look for handler->request->username,
487          *      and to get excited if it doesn't appear.
488          */
489
490         vp = pairfind(request->config_items, PW_AUTH_TYPE);
491         if ((!vp) ||
492             (vp->vp_integer != PW_AUTHTYPE_REJECT)) {
493                 vp = pairmake("Auth-Type", inst->xlat_name, T_OP_EQ);
494                 if (!vp) {
495                         RDEBUG2("Failed to create Auth-Type %s: %s\n",
496                                 inst->xlat_name, fr_strerror());
497                         return RLM_MODULE_FAIL;
498                 }
499                 pairadd(&request->config_items, vp);
500         }
501
502         if (status == EAP_OK) return RLM_MODULE_OK;
503
504         return RLM_MODULE_UPDATED;
505 }
506
507 /*
508  *      If we're proxying EAP, then there may be magic we need
509  *      to do.
510  */
511 static int eap_post_proxy(void *inst, REQUEST *request)
512 {
513         size_t          i;
514         size_t          len;
515         VALUE_PAIR      *vp;
516         EAP_HANDLER     *handler;
517
518         /*
519          *      Just in case the admin lists EAP in post-proxy-type Fail.
520          */
521         if (!request->proxy_reply) return RLM_MODULE_NOOP;
522
523         /*
524          *      If there was a handler associated with this request,
525          *      then it's a tunneled request which was proxied...
526          */
527         handler = request_data_get(request, inst, REQUEST_DATA_EAP_HANDLER);
528         if (handler != NULL) {
529                 int             rcode;
530                 eap_tunnel_data_t *data;
531
532                 /*
533                  *      Grab the tunnel callbacks from the request.
534                  */
535                 data = (eap_tunnel_data_t *) request_data_get(request,
536                                                               request->proxy,
537                                                               REQUEST_DATA_EAP_TUNNEL_CALLBACK);
538                 if (!data) {
539                         radlog_request(L_ERR, 0, request, "Failed to retrieve callback for tunneled session!");
540                         eap_handler_free(handler);
541                         return RLM_MODULE_FAIL;
542                 }
543
544                 /*
545                  *      Do the callback...
546                  */
547                 RDEBUG2("Doing post-proxy callback");
548                 rcode = data->callback(handler, data->tls_session);
549                 free(data);
550                 if (rcode == 0) {
551                         RDEBUG2("Failed in post-proxy callback");
552                         eap_fail(handler);
553                         eap_handler_free(handler);
554                         return RLM_MODULE_REJECT;
555                 }
556
557                 /*
558                  *      We are done, wrap the EAP-request in RADIUS to send
559                  *      with all other required radius attributes
560                  */
561                 eap_compose(handler);
562
563                 /*
564                  *      Add to the list only if it is EAP-Request, OR if
565                  *      it's LEAP, and a response.
566                  */
567                 if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
568                     (handler->eap_ds->request->type.type >= PW_EAP_MD5)) {
569                         if (!eaplist_add(inst, handler)) {
570                                 eap_fail(handler);
571                                 eap_handler_free(handler);
572                                 return RLM_MODULE_FAIL;
573                         }
574                         
575                 } else {        /* couldn't have been LEAP, there's no tunnel */
576                         RDEBUG2("Freeing handler");
577                         /* handler is not required any more, free it now */
578                         eap_handler_free(handler);
579                 }
580
581                 /*
582                  *      If it's an Access-Accept, RFC 2869, Section 2.3.1
583                  *      says that we MUST include a User-Name attribute in the
584                  *      Access-Accept.
585                  */
586                 if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
587                     request->username) {
588                         /*
589                          *      Doesn't exist, add it in.
590                          */
591                         vp = pairfind(request->reply->vps, PW_USER_NAME);
592                         if (!vp) {
593                                 vp = pairmake("User-Name", request->username->vp_strvalue,
594                                               T_OP_EQ);
595                                 rad_assert(vp != NULL);
596                                 pairadd(&(request->reply->vps), vp);
597                         }
598                 }
599
600                 return RLM_MODULE_OK;
601         } else {
602                 RDEBUG2("No pre-existing handler found");
603         }
604
605         /*
606          *      There may be more than one Cisco-AVPair.
607          *      Ensure we find the one with the LEAP attribute.
608          */
609         vp = request->proxy_reply->vps;
610         for (;;) {
611                 /*
612                  *      Hmm... there's got to be a better way to
613                  *      discover codes for vendor attributes.
614                  *
615                  *      This is vendor Cisco (9), Cisco-AVPair
616                  *      attribute (1)
617                  */
618                 vp = pairfind(vp, (9 << 16)  | 1);
619                 if (!vp) {
620                         return RLM_MODULE_NOOP;
621                 }
622
623                 /*
624                  *      If it's "leap:session-key", then stop.
625                  *
626                  *      The format is VERY specific!
627                  */
628                 if (strncasecmp(vp->vp_strvalue, "leap:session-key=", 17) == 0) {
629                         break;
630                 }
631
632                 /*
633                  *      Not this AV-pair.  Go to the next one.
634                  */
635                 vp = vp->next;
636         }
637
638         /*
639          *      The format is very specific.
640          */
641         if (vp->length != 17 + 34) {
642                 RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %d: Expected %d",
643                        vp->length, 17 + 34);
644                 return RLM_MODULE_NOOP;
645         }
646
647         /*
648          *      Decrypt the session key, using the proxy data.
649          */
650         i = 34;                 /* starts off with 34 octets */
651         len = rad_tunnel_pwdecode(vp->vp_octets + 17, &i,
652                                   request->home_server->secret,
653                                   request->proxy->vector);
654
655         /*
656          *      FIXME: Assert that i == 16.
657          */
658
659         /*
660          *      Encrypt the session key again, using the request data.
661          */
662         rad_tunnel_pwencode(vp->vp_strvalue + 17, &len,
663                             request->client->secret,
664                             request->packet->vector);
665
666         return RLM_MODULE_UPDATED;
667 }
668
669
670 /*
671  *      The module name should be the only globally exported symbol.
672  *      That is, everything else should be 'static'.
673  */
674 module_t rlm_eap = {
675         RLM_MODULE_INIT,
676         "eap",
677         RLM_TYPE_CHECK_CONFIG_SAFE,     /* type */
678         eap_instantiate,                /* instantiation */
679         eap_detach,                     /* detach */
680         {
681                 eap_authenticate,       /* authentication */
682                 eap_authorize,          /* authorization */
683                 NULL,                   /* preaccounting */
684                 NULL,                   /* accounting */
685                 NULL,                   /* checksimul */
686                 NULL,                   /* pre-proxy */
687                 eap_post_proxy,         /* post-proxy */
688                 NULL                    /* post-auth */
689         },
690 };