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