9595b615682d1937b001d656c34d828fbdcee5ce
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000,2001  The FreeRADIUS server project
21  * Copyright 2001  hereUare Communications, Inc. <raghud@hereuare.com>
22  */
23
24 #include "autoconf.h"
25 #include "rlm_eap.h"
26 #include "modules.h"
27
28 static CONF_PARSER module_config[] = {
29         { "default_eap_type", PW_TYPE_STRING_PTR, offsetof(EAP_CONF, default_eap_type), NULL, "md5" },
30         { "timer_expire", PW_TYPE_INTEGER, offsetof(EAP_CONF, timer_limit), NULL, "60"},
31
32         { NULL, -1, 0, NULL, NULL }           /* end the list */
33 };
34
35 static int eap_init(void)
36 {
37         return 0;
38 }
39
40
41 /*
42  * read the config section and load all the eap authentication types present.
43  */
44 static int eap_instantiate(CONF_SECTION *cs, void **instance)
45 {
46         char            *auth_type;
47         CONF_SECTION    *scs;
48         EAP_TYPES       *types;
49         EAP_CONF        *conf;
50         rlm_eap_t       **eap_stuff;
51         
52         eap_stuff = (rlm_eap_t **)instance;
53         types    = NULL;
54         conf     = NULL;
55         auth_type = NULL;
56
57         conf = (EAP_CONF *)malloc(sizeof(EAP_CONF));
58         if (conf == NULL) {
59                 radlog(L_ERR, "rlm_eap: out of memory");
60                 return -1;
61         }
62         if (cf_section_parse(cs, conf, module_config) < 0) {
63                 free(conf);
64                 return -1;
65         }
66
67         /* Load all the configured EAP-Types */
68         for(scs=cf_subsection_find_next(cs, NULL, NULL);
69                 scs != NULL;
70                 scs=cf_subsection_find_next(cs, scs, NULL)) {
71
72                 auth_type = cf_section_name1(scs);
73
74                 if (!auth_type)  continue;
75
76                 if (eaptype_load(&types, auth_type, scs) < 0) {
77                         free(conf);
78                         return -1;
79                 }
80         }
81
82         if (!types) {
83                 free(conf->default_eap_type);
84                 conf->default_eap_type = NULL;
85                 free(conf);
86                 conf = NULL;
87                 return -1;
88         }
89
90         *eap_stuff = (rlm_eap_t *)malloc(sizeof(rlm_eap_t));
91         if (*eap_stuff) {
92                 (*eap_stuff)->typelist = types;
93                 (*eap_stuff)->echolist = NULL;
94                 (*eap_stuff)->conf = conf;
95         }  else {
96                 radlog(L_ERR, "rlm_eap: out of memory");
97                 eaptype_freelist(&types);
98                 free(conf->default_eap_type);
99                 conf->default_eap_type = NULL;
100                 free(conf);
101                 conf = NULL;
102                 return -1;
103         }
104
105         /* Generate a state key, specific to eap */
106         generate_key();
107         return 0;
108 }
109
110 /*
111  * delete all the allocated space by eap module
112  */
113 static int eap_detach(void *instance)
114 {
115         rlm_eap_t *t;
116         t = (rlm_eap_t *)instance;
117
118         eaplist_free(&(t->echolist));
119         eaptype_freelist(&(t->typelist));
120
121         free(t->conf->default_eap_type);
122         free(t->conf);
123
124         free(t);
125         t = NULL;
126
127         return 0;
128 }
129
130 /*
131  * Assumption: Any one of the Authorization module should
132  *      get the configured password for any valid user.
133  *      If not, Authentication fails to validate.
134  *
135  * All EAP types will be handled in their respective sub modules.
136  *
137  * To Handle EAP-response, we keep track of the EAP-request we send.
138  * When Success or Failure or when timed out, we delete them.
139  */
140 static int eap_authenticate(void *instance, REQUEST *request)
141 {
142         EAP_HANDLER     *handler;
143         rlm_eap_t       *eap_stuff;
144         eap_packet_t    *eap_packet;
145         int             status;
146
147         eap_stuff = (rlm_eap_t *)instance;
148
149         /* 
150          * Always, clean the list first as it is not timer based
151          * FIXME: Appropriate cleaning mechanism.
152          */
153         eaplist_clean(&(eap_stuff->echolist), (time_t)eap_stuff->conf->timer_limit);
154
155         /*
156          * Incase if EAP is not configured in autz block
157          * or eap_authorize is not invoked
158          */
159         status = eap_start(request);
160         switch(status) {
161         case EAP_NOOP:
162                 return RLM_MODULE_NOOP;
163         case EAP_FAIL:
164                 return RLM_MODULE_FAIL;
165         case EAP_FOUND:
166                 return RLM_MODULE_OK;
167         case EAP_NOTFOUND:
168         default:
169                 break;
170         }
171
172         /* get the eap packet  to start with */
173         eap_packet = eap_attribute(request->packet->vps);
174         if (eap_packet == NULL) {
175                 radlog(L_ERR, "rlm_eap: Malformed EAP Message");
176                 return RLM_MODULE_FAIL;
177         }
178
179         /*
180          * create the eap handler 
181          */
182         handler = eap_handler(&(eap_stuff->echolist), &eap_packet, request);
183         if (handler == NULL) {
184                 return RLM_MODULE_INVALID;
185         }
186
187         /*
188          * No User-Name, No authentication
189          */
190         if (handler->username == NULL) {
191                 radlog(L_ERR, "rlm_eap: Unknown User, authentication failed");
192                 eap_fail(request, handler->eap_ds->request);
193                 eap_handler_free(&handler);
194                 return RLM_MODULE_REJECT;
195         }
196
197         /*
198          * Select the appropriate eap_type or default to the configured one
199          */
200         if (eaptype_select(eap_stuff->typelist, handler,
201                 eap_stuff->conf->default_eap_type) == EAP_INVALID) {
202
203                 eap_fail(request, handler->eap_ds->request);
204                 eap_handler_free(&handler);
205                 return RLM_MODULE_INVALID;
206         }
207
208         /*
209          * We are done, wrap the EAP-request in RADIUS to send
210          * with all other required radius attributes
211          */
212         eap_compose(request, handler->eap_ds->request);
213
214         /*
215          * Add to the list only if it is EAP-Request
216          */
217         if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
218                 (handler->eap_ds->request->type.type >= PW_EAP_MD5)) {
219
220                 handler->id = eap_generateid(request, (u_char)handler->eap_ds->request->id);
221                 if (handler->id == NULL) {
222                         radlog(L_ERR, "rlm_eap: problem in generating ID, Present EAP is no more Valid");
223                         eap_handler_free(&handler);
224                 } else {
225                         eaplist_add(&(eap_stuff->echolist), handler);
226                 }
227         } else {
228                 /* handler is no more required, free it now */
229                 eap_handler_free(&handler);
230         }
231         return RLM_MODULE_OK;
232 }
233
234 /*
235  * EAP authorization DEPENDS on other rlm authorizations,
236  * to check for user existance & get their configured values.
237  * It Handles EAP-START Messages, User-Name initilization.
238  */
239 static int eap_authorize(void *instance, REQUEST *request)
240 {
241         VALUE_PAIR      *atype, *vp;
242         rlm_eap_t       *eap_stuff;
243         eap_packet_t    *eap_packet;
244         int             status;
245         unsigned char   *id;
246         
247         eap_stuff = (rlm_eap_t *)instance;
248
249         /* Authorization not valid for proxies */
250         if (request->proxy != NULL)
251                 return RLM_MODULE_NOOP;
252
253         /*
254          * For EAP_START, send Access-Challenge with EAP Identity request.
255          * even when we have to proxy this request
256          */
257         status = eap_start(request);
258         switch(status) {
259         case EAP_NOOP:
260                 return RLM_MODULE_NOOP;
261         case EAP_FAIL:
262                 return RLM_MODULE_FAIL;
263         case EAP_FOUND:
264                 return RLM_MODULE_HANDLED;
265         case EAP_NOTFOUND:
266         default:
267                 break;
268         }
269         
270         /*
271          * We should have User-Name to proceed further
272          */
273         if (request->username == NULL) {
274
275                 /* get the eap packet */
276                 eap_packet = eap_attribute(request->packet->vps);
277                 if (eap_packet == NULL) {
278                         radlog(L_ERR, "rlm_eap: Malformed EAP Message");
279                         return RLM_MODULE_FAIL;
280                 }
281
282                 id = eap_regenerateid(request, eap_packet->id);
283                 if (id == NULL) {
284                         radlog(L_ERR, "rlm_eap: User-Name cannot be obtained");
285                         free(eap_packet);
286                         return RLM_MODULE_FAIL;
287                 }
288
289                 request->username = eap_useridentity(eap_stuff->echolist, eap_packet, id);
290                 if (request->username == NULL) {
291                         radlog(L_ERR, "rlm_eap: Unknown User, authorization failed");
292                         free(eap_packet);
293                         free(id);
294                         return RLM_MODULE_FAIL;
295                 }
296                 free(eap_packet);
297                 free(id);
298         }
299
300         /*
301          * Enforce EAP authentication
302
303          * Auth-type(s) already set?  overide it with EAP
304          * If EAP-Message is present in RADIUS, then EAP authentication is MUST.
305
306          * TODO: When Multiple authentications are supported in RADIUS, 
307          *     then prioritize EAP by prepending it before all Auth-Types
308          */
309
310         atype = pairfind(request->config_items, PW_AUTHTYPE);
311         if ((atype == NULL) || 
312                 ((atype->lvalue != PW_AUTHTYPE_EAP) &&
313                 (atype->lvalue != PW_AUTHTYPE_ACCEPT) &&
314                 (atype->lvalue != PW_AUTHTYPE_REJECT))) {
315
316                 vp = pairmake("Auth-Type", "EAP", T_OP_EQ);
317                 if (vp == NULL) {
318                         return RLM_MODULE_FAIL;
319                 }
320                 /* to overide */
321                 pairdelete(&request->config_items, PW_AUTHTYPE);
322                 pairadd(&request->config_items, vp);
323
324                 /* To prioritize
325                 vp->next = request->config_items;
326                 request->config_items = vp;
327                 */
328         }
329
330         return RLM_MODULE_UPDATED;
331 }
332
333 /*
334  *      The module name should be the only globally exported symbol.
335  *      That is, everything else should be 'static'.
336  */
337 module_t rlm_eap = {
338         "eap",
339         RLM_TYPE_THREAD_UNSAFE,         /* type */
340         eap_init,                       /* initialization */
341         eap_instantiate,                /* instantiation */
342         {
343                 eap_authenticate,       /* authentication */
344                 eap_authorize,          /* authorization */
345                 NULL,                   /* preaccounting */
346                 NULL,                   /* accounting */
347                 NULL                    /* checksimul */
348         },
349         eap_detach,                     /* detach */
350         NULL,                           /* destroy */
351 };