~ubuntu-branches/ubuntu/dapper/freeradius/dapper-updates

« back to all changes in this revision

Viewing changes to src/modules/rlm_eap/rlm_eap.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Hampson
  • Date: 2004-12-29 20:19:42 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20041229201942-uj2e95la965uthc7
Tags: 1.0.1-2
* freeradius-dialupadmin Suggests php4-mysql | php4-pgsql
   Closes: #279419
* Added a two-second pause to restart in init.d script
   Closes: #262635
* FreeRADIUS module packages now depend on the same source
  version of the main FreeRADIUS package.
   Closes: #284353
* FreeRADIUS-dialupadmin's default paths in admin.conf are
  now correct.
   Closes: #280942
* FreeRADIUS-dialupadmin's help.php3 can now find README.
   Closes: #280941
* Fixes stolen from 1.0.2 CVS:
  - Bug fix to make udpfromto code work
  - radrelay shouldn't dump core if it can't read a VP from the
    detail file.
  - Only initialize the random pool once.
  - In rlm_sql, don't escape characters twice.
  - In rlm_ldap, only claim Auth-Type if a plain text password is present.
  - Locking fixes in threading code
  - Fix building on gcc-4.0 by not trying to access static auth_port from
    other files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * rlm_eap.c  contains handles that are called from modules.
3
3
 *
4
 
 * Version:     $Id: rlm_eap.c,v 1.14 2003/07/07 19:15:42 aland Exp $
 
4
 * Version:     $Id: rlm_eap.c,v 1.26 2004/03/12 16:14:53 aland Exp $
5
5
 *
6
6
 *   This program is free software; you can redistribute it and/or modify
7
7
 *   it under the terms of the GNU General Public License as published by
17
17
 *   along with this program; if not, write to the Free Software
18
18
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
19
 *
20
 
 * Copyright 2000,2001  The FreeRADIUS server project
 
20
 * Copyright 2000-2003  The FreeRADIUS server project
21
21
 * Copyright 2001  hereUare Communications, Inc. <raghud@hereuare.com>
 
22
 * Copyright 2003  Alan DeKok <aland@freeradius.org>
22
23
 */
23
24
 
24
25
#include "autoconf.h"
25
26
#include "rlm_eap.h"
26
27
#include "modules.h"
27
28
 
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"},
 
29
static const char rcsid[] = "$Id: rlm_eap.c,v 1.26 2004/03/12 16:14:53 aland Exp $";
 
30
 
 
31
static const CONF_PARSER module_config[] = {
 
32
        { "default_eap_type", PW_TYPE_STRING_PTR,
 
33
          offsetof(rlm_eap_t, default_eap_type_name), NULL, "md5" },
 
34
        { "timer_expire", PW_TYPE_INTEGER,
 
35
          offsetof(rlm_eap_t, timer_limit), NULL, "60"},
 
36
        { "ignore_unknown_eap_types", PW_TYPE_BOOLEAN,
 
37
          offsetof(rlm_eap_t, ignore_unknown_eap_types), NULL, "no" },
 
38
        { "cisco_accounting_username_bug", PW_TYPE_BOOLEAN,
 
39
          offsetof(rlm_eap_t, cisco_accounting_username_bug), NULL, "no" },
31
40
 
32
41
        { NULL, -1, 0, NULL, NULL }           /* end the list */
33
42
};
39
48
 
40
49
 
41
50
/*
 
51
 * delete all the allocated space by eap module
 
52
 */
 
53
static int eap_detach(void *instance)
 
54
{
 
55
        rlm_eap_t *inst;
 
56
        int i;
 
57
 
 
58
        inst = (rlm_eap_t *)instance;
 
59
 
 
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
#ifdef HAVE_PTHREAD_H
 
68
        pthread_mutex_destroy(&(inst->session_mutex));
 
69
        pthread_mutex_destroy(&(inst->module_mutex));
 
70
#endif
 
71
 
 
72
        if (inst->default_eap_type_name) free(inst->default_eap_type_name);
 
73
        free(inst);
 
74
 
 
75
        return 0;
 
76
}
 
77
 
 
78
 
 
79
/*
42
80
 * read the config section and load all the eap authentication types present.
43
81
 */
44
82
static int eap_instantiate(CONF_SECTION *cs, void **instance)
45
83
{
46
 
        char            *auth_type;
 
84
        int             eap_type;
 
85
        int             num_types;
47
86
        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;
 
87
        rlm_eap_t       *inst;
56
88
 
57
 
        conf = (EAP_CONF *)malloc(sizeof(*conf));
58
 
        if (conf == NULL) {
59
 
                radlog(L_ERR, "rlm_eap: out of memory");
 
89
        inst = (rlm_eap_t *) malloc(sizeof(*inst));
 
90
        if (!inst) {
60
91
                return -1;
61
92
        }
62
 
        memset(conf, 0, sizeof(*conf));
63
 
        if (cf_section_parse(cs, conf, module_config) < 0) {
64
 
                free(conf);
 
93
        memset(inst, 0, sizeof(*inst));
 
94
        if (cf_section_parse(cs, inst, module_config) < 0) {
 
95
                eap_detach(inst);
65
96
                return -1;
66
97
        }
67
98
 
68
99
        /* Load all the configured EAP-Types */
 
100
        num_types = 0;
69
101
        for(scs=cf_subsection_find_next(cs, NULL, NULL);
70
102
                scs != NULL;
71
103
                scs=cf_subsection_find_next(cs, scs, NULL)) {
72
104
 
 
105
                char    *auth_type;
 
106
 
73
107
                auth_type = cf_section_name1(scs);
74
108
 
75
109
                if (!auth_type)  continue;
76
110
 
77
 
                if (eaptype_load(&types, auth_type, scs) < 0) {
78
 
                        free(conf);
79
 
                        return -1;
80
 
                }
81
 
        }
82
 
 
83
 
        if (!types) {
84
 
                free(conf->default_eap_type);
85
 
                conf->default_eap_type = NULL;
86
 
                free(conf);
87
 
                conf = NULL;
88
 
                return -1;
89
 
        }
90
 
 
91
 
        *eap_stuff = (rlm_eap_t *)malloc(sizeof(rlm_eap_t));
92
 
        if (*eap_stuff) {
93
 
                (*eap_stuff)->typelist = types;
94
 
                (*eap_stuff)->echolist = NULL;
95
 
                (*eap_stuff)->conf = conf;
96
 
        }  else {
97
 
                radlog(L_ERR, "rlm_eap: out of memory");
98
 
                eaptype_freelist(&types);
99
 
                free(conf->default_eap_type);
100
 
                conf->default_eap_type = NULL;
101
 
                free(conf);
102
 
                conf = NULL;
103
 
                return -1;
104
 
        }
 
111
                eap_type = eaptype_name2type(auth_type);
 
112
                if (eap_type < 0) {
 
113
                        radlog(L_ERR|L_CONS, "rlm_eap: Unknown EAP type %s",
 
114
                               auth_type);
 
115
                        eap_detach(inst);
 
116
                        return -1;
 
117
                }
 
118
 
 
119
                /*
 
120
                 *      If we're asked to load TTLS or PEAP, ensure
 
121
                 *      that we've first loaded TLS.
 
122
                 */
 
123
                if (((eap_type == PW_EAP_TTLS) ||
 
124
                     (eap_type == PW_EAP_PEAP)) &&
 
125
                    (inst->types[PW_EAP_TLS] == NULL)) {
 
126
                        radlog(L_ERR, "rlm_eap: Unable to load EAP-Type/%s, as EAP-Type/TLS is required first.",
 
127
                               auth_type);
 
128
                        return -1;
 
129
                }
 
130
 
 
131
                /*
 
132
                 *      Load the type.
 
133
                 */
 
134
                if (eaptype_load(&inst->types[eap_type], eap_type, scs) < 0) {
 
135
                        eap_detach(inst);
 
136
                        return -1;
 
137
                }
 
138
 
 
139
                num_types++;    /* successfully loaded one more types */
 
140
        }
 
141
 
 
142
        if (num_types == 0) {
 
143
                radlog(L_ERR|L_CONS, "rlm_eap: No EAP type configured, module cannot do anything.");
 
144
                eap_detach(inst);
 
145
                return -1;
 
146
        }
 
147
 
 
148
        /*
 
149
         *      Ensure that the default EAP type is loaded.
 
150
         */
 
151
        eap_type = eaptype_name2type(inst->default_eap_type_name);
 
152
        if (eap_type < 0) {
 
153
                radlog(L_ERR|L_CONS, "rlm_eap: Unknown default EAP type %s",
 
154
                       inst->default_eap_type_name);
 
155
                eap_detach(inst);
 
156
                return -1;
 
157
        }
 
158
 
 
159
        if (inst->types[eap_type] == NULL) {
 
160
                radlog(L_ERR|L_CONS, "rlm_eap: No such sub-type for default EAP type %s",
 
161
                       inst->default_eap_type_name);
 
162
                eap_detach(inst);
 
163
                return -1;
 
164
        }
 
165
        inst->default_eap_type = eap_type; /* save the numerical type */
 
166
 
 
167
        /*
 
168
         *      List of sessions are set to NULL by the memset
 
169
         *      of 'inst', above.
 
170
         */
105
171
 
106
172
        /* Generate a state key, specific to eap */
107
173
        generate_key();
 
174
 
 
175
#ifdef HAVE_PTHREAD_H
 
176
        pthread_mutex_init(&(inst->session_mutex), NULL);
 
177
        pthread_mutex_init(&(inst->module_mutex), NULL);
 
178
#endif
 
179
 
 
180
        *instance = inst;
108
181
        return 0;
109
182
}
110
183
 
111
184
/*
112
 
 * delete all the allocated space by eap module
 
185
 *      Dumb wrapper.
 
186
 *      FIXME: this should be done more intelligently...
113
187
 */
114
 
static int eap_detach(void *instance)
 
188
static void my_handler_free(void *data)
115
189
{
116
 
        rlm_eap_t *t;
117
 
        t = (rlm_eap_t *)instance;
118
 
 
119
 
        eaplist_free(&(t->echolist));
120
 
        eaptype_freelist(&(t->typelist));
121
 
 
122
 
        free(t->conf->default_eap_type);
123
 
        free(t->conf);
124
 
 
125
 
        free(t);
126
 
        t = NULL;
127
 
 
128
 
        return 0;
 
190
  EAP_HANDLER *handler = (EAP_HANDLER *) data;
 
191
  eap_handler_free(&handler);
129
192
}
130
193
 
131
194
/*
132
 
 * Assumption: Any one of the Authorization module should
133
 
 *      get the configured password for any valid user.
134
 
 *      If not, Authentication fails to validate.
135
 
 *
136
 
 * All EAP types will be handled in their respective sub modules.
137
 
 *
138
 
 * To Handle EAP-response, we keep track of the EAP-request we send.
139
 
 * When Success or Failure or when timed out, we delete them.
 
195
 *      For backwards compatibility.
140
196
 */
141
197
static int eap_authenticate(void *instance, REQUEST *request)
142
198
{
 
199
        rlm_eap_t       *inst;
143
200
        EAP_HANDLER     *handler;
144
 
        rlm_eap_t       *eap_stuff;
145
201
        eap_packet_t    *eap_packet;
146
 
        int             status;
147
 
 
148
 
        eap_stuff = (rlm_eap_t *)instance;
149
 
 
150
 
        /* 
151
 
         * Always, clean the list first as it is not timer based
152
 
         * FIXME: Appropriate cleaning mechanism.
153
 
         */
154
 
        eaplist_clean(&(eap_stuff->echolist), (time_t)eap_stuff->conf->timer_limit);
 
202
        int             rcode;
 
203
#ifdef HAVE_PTHREAD_H
 
204
        int             locked = FALSE;
 
205
#endif
 
206
 
 
207
        inst = (rlm_eap_t *) instance;
155
208
 
156
209
        /*
157
 
         * Incase if EAP is not configured in autz block
158
 
         * or eap_authorize is not invoked
 
210
         *      Get the eap packet  to start with
159
211
         */
160
 
        status = eap_start(request);
161
 
        switch(status) {
162
 
        case EAP_NOOP:
163
 
                return RLM_MODULE_NOOP;
164
 
        case EAP_FAIL:
165
 
                return RLM_MODULE_FAIL;
166
 
        case EAP_FOUND:
167
 
                return RLM_MODULE_OK;
168
 
        case EAP_NOTFOUND:
169
 
        default:
170
 
                break;
171
 
        }
172
 
 
173
 
        /* get the eap packet  to start with */
174
212
        eap_packet = eap_attribute(request->packet->vps);
175
213
        if (eap_packet == NULL) {
176
214
                radlog(L_ERR, "rlm_eap: Malformed EAP Message");
178
216
        }
179
217
 
180
218
        /*
181
 
         * create the eap handler 
 
219
         *      Create the eap handler.  The eap_packet will end up being
 
220
         *      "swallowed" into the handler, so we can't access it after
 
221
         *      this call.
182
222
         */
183
 
        handler = eap_handler(&(eap_stuff->echolist), &eap_packet, request);
 
223
        handler = eap_handler(inst, &eap_packet, request);
184
224
        if (handler == NULL) {
185
 
                return RLM_MODULE_INVALID;
186
 
        }
187
 
 
188
 
        /*
189
 
         * No User-Name, No authentication
190
 
         */
191
 
        if (handler->username == NULL) {
192
 
                radlog(L_ERR, "rlm_eap: Unknown User, authentication failed");
193
 
                eap_fail(request, handler->eap_ds);
194
 
                eap_handler_free(&handler);
195
 
                return RLM_MODULE_REJECT;
196
 
        }
197
 
 
198
 
        /*
199
 
         * Select the appropriate eap_type or default to the configured one
200
 
         */
201
 
        if (eaptype_select(eap_stuff->typelist, handler,
202
 
                eap_stuff->conf->default_eap_type) == EAP_INVALID) {
203
 
 
204
 
                eap_fail(request, handler->eap_ds);
205
 
                eap_handler_free(&handler);
206
 
                return RLM_MODULE_INVALID;
207
 
        }
208
 
 
209
 
        /*
210
 
         * We are done, wrap the EAP-request in RADIUS to send
211
 
         * with all other required radius attributes
212
 
         */
213
 
        eap_compose(request, handler->eap_ds);
214
 
 
215
 
        /*
216
 
         * Add to the list only if it is EAP-Request,
217
 
         * OR if it's LEAP, and a response.
 
225
                DEBUG2("  rlm_eap: Failed in handler");
 
226
                return RLM_MODULE_INVALID;
 
227
        }
 
228
 
 
229
        /*
 
230
         *      If it's a recursive request, then disallow
 
231
         *      TLS, TTLS, and PEAP, inside of the TLS tunnel.
 
232
         */
 
233
        if ((request->options & RAD_REQUEST_OPTION_FAKE_REQUEST) != 0) {
 
234
                switch(handler->eap_ds->response->type.type) {
 
235
                case PW_EAP_TLS:
 
236
                case PW_EAP_TTLS:
 
237
                case PW_EAP_PEAP:
 
238
                        DEBUG2(" rlm_eap: Unable to tunnel TLS inside of TLS");
 
239
                        eap_fail(handler);
 
240
                        eap_handler_free(&handler);
 
241
                        return RLM_MODULE_INVALID;
 
242
                        break;
 
243
 
 
244
                default:        /* It may be OK, allow it to proceed */
 
245
                        break;
 
246
 
 
247
                }
 
248
        }
 
249
 
 
250
#ifdef HAVE_PTHREAD_H
 
251
        else {                  /* it's a normal request from a NAS */
 
252
                /*
 
253
                 *      The OpenSSL code isn't strictly thread-safe,
 
254
                 *      as we've got to provide callback functions.
 
255
                 *
 
256
                 *      Rather than doing that, we just ensure that the
 
257
                 *      sub-modules are locked via a mutex.
 
258
                 *
 
259
                 *      Don't lock it if we're calling ourselves recursively,
 
260
                 *      we've already got the lock.
 
261
                 */
 
262
                pthread_mutex_lock(&(inst->module_mutex));
 
263
                locked = TRUE;  /* for recursive calls to the module */
 
264
        }
 
265
#endif
 
266
 
 
267
        /*
 
268
         *      Select the appropriate eap_type or default to the
 
269
         *      configured one
 
270
         */
 
271
        rcode = eaptype_select(inst, handler);
 
272
 
 
273
#ifdef HAVE_PTHREAD_H
 
274
        if (locked) pthread_mutex_unlock(&(inst->module_mutex));
 
275
#endif
 
276
 
 
277
        /*
 
278
         *      If it failed, die.
 
279
         */
 
280
        if (rcode == EAP_INVALID) {
 
281
                eap_fail(handler);
 
282
                eap_handler_free(&handler);
 
283
                DEBUG2("  rlm_eap: Failed in EAP select");
 
284
                return RLM_MODULE_INVALID;
 
285
        }
 
286
 
 
287
        /*
 
288
         *      If we're doing horrible tunneling work, remember it.
 
289
         */
 
290
        if ((request->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
 
291
                DEBUG2("  Not-EAP proxy set.  Not composing EAP");
 
292
                /*
 
293
                 *      Add the handle to the proxied list, so that we
 
294
                 *      can retrieve it in the post-proxy stage, and
 
295
                 *      send a response.
 
296
                 */
 
297
                rcode = request_data_add(request,
 
298
                                         inst, REQUEST_DATA_EAP_HANDLER,
 
299
                                         handler, my_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, my_handler_free);
 
323
                rad_assert(rcode == 0);
 
324
 
 
325
                /*
 
326
                 *      Some simple sanity checks.  These should really
 
327
                 *      be handled by the radius library...
 
328
                 */
 
329
                vp = pairfind(request->proxy->vps, PW_EAP_MESSAGE);
 
330
                if (vp) {
 
331
                        vp = pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR);
 
332
                        if (!vp) {
 
333
                                vp = pairmake("Message-Authenticator",
 
334
                                              "0x00", T_OP_EQ);
 
335
                                rad_assert(vp != NULL);
 
336
                                pairadd(&(request->proxy->vps), vp);
 
337
                        }
 
338
                }
 
339
                        
 
340
                /*
 
341
                 *      Delete the "proxied to" attribute, as it's
 
342
                 *      set to 127.0.0.1 for tunneled requests, and
 
343
                 *      we don't want to tell the world that...
 
344
                 */
 
345
                pairdelete(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO);
 
346
 
 
347
                DEBUG2("  Tunneled session will be proxied.  Not doing EAP.");
 
348
                return RLM_MODULE_HANDLED;
 
349
        }
 
350
 
 
351
        /*
 
352
         *      We are done, wrap the EAP-request in RADIUS to send
 
353
         *      with all other required radius attributes
 
354
         */
 
355
        rcode = eap_compose(handler);
 
356
 
 
357
        /*
 
358
         *      Add to the list only if it is EAP-Request, OR if
 
359
         *      it's LEAP, and a response.
218
360
         */
219
361
        if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
220
362
            (handler->eap_ds->request->type.type >= PW_EAP_MD5)) {
221
 
                handler->id = eap_generateid(request, (u_char)handler->eap_ds->request->id);
222
 
                if (handler->id == NULL) {
223
 
                        radlog(L_ERR, "rlm_eap: problem in generating ID, Present EAP is not valid");
224
 
                        eap_handler_free(&handler);
225
 
                } else {
226
 
                        eaplist_add(&(eap_stuff->echolist), handler);
227
 
                }
 
363
                eaplist_add(inst, handler);
228
364
 
229
365
                /*
230
366
                 *      LEAP is a little different.  At Stage 4,
239
375
                   (handler->eap_ds->response->type.type == PW_EAP_LEAP) &&
240
376
                   (handler->eap_ds->request->code == PW_EAP_SUCCESS) &&
241
377
                   (handler->eap_ds->request->type.type == 0)) {
242
 
                VALUE_PAIR *state;
243
 
 
244
 
                DEBUG2("  rlm_eap: Saving LEAP state");
245
 
                handler->id = eap_regenerateid(request, (u_char)handler->eap_ds->request->id);
246
 
                if (handler->id == NULL) {
247
 
                        radlog(L_ERR, "rlm_eap: problem in generating ID, Present EAP is not valid");
248
 
                        eap_handler_free(&handler);
249
 
                } else {
250
 
                        eaplist_add(&(eap_stuff->echolist), handler);
251
 
                }
252
 
 
253
 
                /*
254
 
                 *  And copy the State attribute from the request
255
 
                 */
256
 
                state = paircopy2(request->packet->vps, PW_STATE);
257
 
 
258
 
                /*
259
 
                 *  FIXME: Assert there's only 1 state?
260
 
                 */
261
 
                pairadd(&request->reply->vps, state);
 
378
 
 
379
                eaplist_add(inst, handler);
262
380
 
263
381
        } else {
264
382
                DEBUG2("  rlm_eap: Freeing handler");
265
 
                /* handler is no more required, free it now */
 
383
                /* handler is not required any more, free it now */
266
384
                eap_handler_free(&handler);
267
385
        }
268
 
        return RLM_MODULE_OK;
 
386
 
 
387
        /*
 
388
         *      If it's an Access-Accept, RFC 2869, Section 2.3.1
 
389
         *      says that we MUST include a User-Name attribute in the
 
390
         *      Access-Accept.
 
391
         */
 
392
        if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
 
393
            request->username) {
 
394
                VALUE_PAIR *vp;
 
395
 
 
396
                /*
 
397
                 *      Doesn't exist, add it in.
 
398
                 */
 
399
                vp = pairfind(request->reply->vps, PW_USER_NAME);
 
400
                if (!vp) {
 
401
                        vp = pairmake("User-Name", request->username->strvalue,
 
402
                                      T_OP_EQ);
 
403
                        rad_assert(vp != NULL);
 
404
                        pairadd(&(request->reply->vps), vp);
 
405
                }
 
406
 
 
407
                /*
 
408
                 *      Cisco AP1230 has a bug and needs a zero
 
409
                 *      terminated string in Access-Accept.
 
410
                 */
 
411
                if ((inst->cisco_accounting_username_bug) &&
 
412
                    (vp->length < (int) sizeof(vp->strvalue))) {
 
413
                        vp->strvalue[vp->length] = '\0';
 
414
                        vp->length++;
 
415
                }
 
416
        }
 
417
 
 
418
        return rcode;
269
419
}
270
420
 
271
421
/*
275
425
 */
276
426
static int eap_authorize(void *instance, REQUEST *request)
277
427
{
278
 
        VALUE_PAIR      *atype, *vp;
279
 
        rlm_eap_t       *eap_stuff;
280
 
        eap_packet_t    *eap_packet;
 
428
        rlm_eap_t       *inst;
281
429
        int             status;
282
 
        unsigned char   *id;
283
 
        
284
 
        eap_stuff = (rlm_eap_t *)instance;
285
 
 
286
 
        /* Authorization not valid for proxies */
 
430
        VALUE_PAIR      *vp;
 
431
 
 
432
        inst = (rlm_eap_t *)instance;
 
433
 
 
434
        /*
 
435
         *      We don't do authorization again, once we've seen the
 
436
         *      proxy reply (or the proxied packet)
 
437
         */
287
438
        if (request->proxy != NULL)
288
439
                return RLM_MODULE_NOOP;
289
440
 
290
441
        /*
291
 
         * For EAP_START, send Access-Challenge with EAP Identity request.
292
 
         * even when we have to proxy this request
 
442
         *      For EAP_START, send Access-Challenge with EAP Identity
 
443
         *      request.  even when we have to proxy this request
 
444
         *
 
445
         *      RFC 2869, Section 2.3.1 notes that the "domain" of the
 
446
         *      user, (i.e. where to proxy him) comes from the EAP-Identity,
 
447
         *      so we CANNOT proxy the user, until we know his identity.
 
448
         *
 
449
         *      We therefore send an EAP Identity request.
293
450
         */
294
 
        status = eap_start(request);
 
451
        status = eap_start(inst, request);
295
452
        switch(status) {
296
453
        case EAP_NOOP:
297
454
                return RLM_MODULE_NOOP;
303
460
        default:
304
461
                break;
305
462
        }
306
 
        
307
 
        /*
308
 
         * We should have User-Name to proceed further
309
 
         */
310
 
        if (request->username == NULL) {
311
 
 
312
 
                /* get the eap packet */
313
 
                eap_packet = eap_attribute(request->packet->vps);
314
 
                if (eap_packet == NULL) {
315
 
                        radlog(L_ERR, "rlm_eap: Malformed EAP Message");
316
 
                        return RLM_MODULE_FAIL;
317
 
                }
318
 
 
319
 
                id = eap_regenerateid(request, eap_packet->id);
320
 
                if (id == NULL) {
321
 
                        radlog(L_ERR, "rlm_eap: User-Name cannot be obtained");
322
 
                        free(eap_packet);
323
 
                        return RLM_MODULE_FAIL;
324
 
                }
325
 
 
326
 
                request->username = eap_useridentity(eap_stuff->echolist, eap_packet, id);
327
 
                if (request->username == NULL) {
328
 
                        radlog(L_ERR, "rlm_eap: Unknown User, authorization failed");
329
 
                        free(eap_packet);
330
 
                        free(id);
331
 
                        return RLM_MODULE_FAIL;
332
 
                }
333
 
                free(eap_packet);
334
 
                free(id);
335
 
        }
336
 
 
337
 
        /*
338
 
         * Enforce EAP authentication
339
 
 
340
 
         * Auth-type(s) already set?  overide it with EAP
341
 
         * If EAP-Message is present in RADIUS, then EAP authentication is MUST.
342
 
 
343
 
         * TODO: When Multiple authentications are supported in RADIUS, 
344
 
         *     then prioritize EAP by prepending it before all Auth-Types
345
 
         */
346
 
 
347
 
        atype = pairfind(request->config_items, PW_AUTHTYPE);
348
 
        if ((atype == NULL) || 
349
 
                ((atype->lvalue != PW_AUTHTYPE_EAP) &&
350
 
                (atype->lvalue != PW_AUTHTYPE_ACCEPT) &&
351
 
                (atype->lvalue != PW_AUTHTYPE_REJECT))) {
352
 
 
 
463
 
 
464
        /*
 
465
         *      RFC 2869, Section 2.3.1.  If a NAS sends an EAP-Identity,
 
466
         *      it MUST copy the identity into the User-Name attribute.
 
467
         *
 
468
         *      But we don't worry about that too much.  We depend on
 
469
         *      each EAP sub-module to look for handler->request->username,
 
470
         *      and to get excited if it doesn't appear.
 
471
         */
 
472
 
 
473
        vp = pairfind(request->config_items, PW_AUTH_TYPE);
 
474
        if ((!vp) ||
 
475
            (vp->lvalue != PW_AUTHTYPE_REJECT)) {
353
476
                vp = pairmake("Auth-Type", "EAP", T_OP_EQ);
354
 
                if (vp == NULL) {
 
477
                if (!vp) {
355
478
                        return RLM_MODULE_FAIL;
356
479
                }
357
 
                /* to overide */
358
 
                pairdelete(&request->config_items, PW_AUTHTYPE);
359
480
                pairadd(&request->config_items, vp);
360
 
 
361
 
                /* To prioritize
362
 
                vp->next = request->config_items;
363
 
                request->config_items = vp;
364
 
                */
365
481
        }
366
482
 
367
483
        return RLM_MODULE_UPDATED;
371
487
 *      If we're proxying EAP, then there may be magic we need
372
488
 *      to do.
373
489
 */
374
 
static int eap_post_proxy(void *instance, REQUEST *request)
 
490
static int eap_post_proxy(void *inst, REQUEST *request)
375
491
{
376
 
        int i, len;
377
 
        VALUE_PAIR *vp = request->proxy_reply->vps;
 
492
        int             i, len;
 
493
        VALUE_PAIR      *vp;
 
494
        EAP_HANDLER     *handler;
 
495
 
 
496
        /*
 
497
         *      If there was a handler associated with this request,
 
498
         *      then it's a tunneled request which was proxied...
 
499
         */
 
500
        handler = request_data_get(request, inst, REQUEST_DATA_EAP_HANDLER);
 
501
        if (handler != NULL) {
 
502
                int             rcode;
 
503
                eap_tunnel_data_t *data;
 
504
 
 
505
                /*
 
506
                 *      Grab the tunnel callbacks from the request.
 
507
                 */
 
508
                data = (eap_tunnel_data_t *) request_data_get(request,
 
509
                                                              request->proxy,
 
510
                                                              REQUEST_DATA_EAP_TUNNEL_CALLBACK);
 
511
                if (!data) {
 
512
                        radlog(L_ERR, "rlm_eap: Failed to retrieve callback for tunneled session!");
 
513
                        eap_handler_free(&handler);
 
514
                        return RLM_MODULE_FAIL;
 
515
                }
 
516
 
 
517
                /*
 
518
                 *      Do the callback...
 
519
                 */
 
520
                rcode = data->callback(handler, data->tls_session);
 
521
                free(data);
 
522
                if (rcode == 0) {
 
523
                        eap_handler_free(&handler);
 
524
                        return RLM_MODULE_REJECT;
 
525
                }
 
526
 
 
527
                /*
 
528
                 *      We are done, wrap the EAP-request in RADIUS to send
 
529
                 *      with all other required radius attributes
 
530
                 */
 
531
                rcode = eap_compose(handler);
 
532
 
 
533
                /*
 
534
                 *      Add to the list only if it is EAP-Request, OR if
 
535
                 *      it's LEAP, and a response.
 
536
                 */
 
537
                if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
 
538
                    (handler->eap_ds->request->type.type >= PW_EAP_MD5)) {
 
539
                        eaplist_add(inst, handler);
 
540
 
 
541
                } else {        /* couldn't have been LEAP, there's no tunnel */
 
542
                        DEBUG2("  rlm_eap: Freeing handler");
 
543
                        /* handler is not required any more, free it now */
 
544
                        eap_handler_free(&handler);
 
545
                }
 
546
 
 
547
                /*
 
548
                 *      If it's an Access-Accept, RFC 2869, Section 2.3.1
 
549
                 *      says that we MUST include a User-Name attribute in the
 
550
                 *      Access-Accept.
 
551
                 */
 
552
                if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
 
553
                    request->username) {
 
554
                        /*
 
555
                         *      Doesn't exist, add it in.
 
556
                         */
 
557
                        vp = pairfind(request->reply->vps, PW_USER_NAME);
 
558
                        if (!vp) {
 
559
                                vp = pairmake("User-Name", request->username->strvalue,
 
560
                                              T_OP_EQ);
 
561
                                rad_assert(vp != NULL);
 
562
                                pairadd(&(request->reply->vps), vp);
 
563
                        }
 
564
                }
 
565
 
 
566
                return RLM_MODULE_OK;
 
567
        }
 
568
 
378
569
 
379
570
        /*
380
571
         *      There may be more than one Cisco-AVPair.
381
572
         *      Ensure we find the one with the LEAP attribute.
382
573
         */
 
574
        vp = request->proxy_reply->vps;
383
575
        for (;;) {
384
576
                /*
385
577
                 *      Hmm... there's got to be a better way to
392
584
                if (!vp) {
393
585
                        return RLM_MODULE_NOOP;
394
586
                }
395
 
                
 
587
 
396
588
                /*
397
589
                 *      If it's "leap:session-key", then stop.
398
590
                 *
401
593
                if (strncasecmp(vp->strvalue, "leap:session-key=", 17) == 0) {
402
594
                        break;
403
595
                }
 
596
 
 
597
                /*
 
598
                 *      Not this AV-pair.  Go to the next one.
 
599
                 */
 
600
                vp = vp->next;
404
601
        }
405
602
 
406
603
        /*
441
638
 */
442
639
module_t rlm_eap = {
443
640
        "eap",
444
 
        RLM_TYPE_THREAD_UNSAFE,         /* type */
 
641
        RLM_TYPE_THREAD_SAFE,           /* type */
445
642
        eap_init,                       /* initialization */
446
643
        eap_instantiate,                /* instantiation */
447
644
        {