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