Patch from Masao Nishiku to implement PEAP version 0. It works
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_peap / rlm_eap_peap.c
1 /*
2  * rlm_eap_peap.c  contains the interfaces that are called from eap
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 2003 Alan DeKok <aland@freeradius.org>
21  */
22
23 #include "autoconf.h"
24 #include "eap_tls.h"
25 #include "eap_peap.h"
26
27 typedef struct rlm_eap_peap_t {
28         /*
29          *      Default tunneled EAP type
30          */
31         char    *default_eap_type_name;
32         int     default_eap_type;
33 } rlm_eap_peap_t;
34
35
36 static CONF_PARSER module_config[] = {
37         { "default_eap_type", PW_TYPE_STRING_PTR,
38           offsetof(rlm_eap_peap_t, default_eap_type_name), NULL, "mschapv2" },
39
40         { NULL, -1, 0, NULL, NULL }           /* end the list */
41 };
42
43 /*
44  *      Detach the module.
45  */
46 static int eappeap_detach(void *arg)
47 {
48         rlm_eap_peap_t *inst = (rlm_eap_peap_t *) arg;
49
50         if (inst->default_eap_type_name) free(inst->default_eap_type_name);
51
52         free(inst);
53
54         return 0;
55 }
56
57 /*
58  *      Attach the module.
59  */
60 static int eappeap_attach(CONF_SECTION *cs, void **instance)
61 {
62         rlm_eap_peap_t *inst;
63
64         inst = malloc(sizeof(*inst));
65         if (!inst) {
66                 radlog(L_ERR, "rlm_eap_peap: out of memory");
67                 return -1;
68         }
69         memset(inst, 0, sizeof(*inst));
70
71         /*
72          *      Parse the configuration attributes.
73          */
74         if (cf_section_parse(cs, inst, module_config) < 0) {
75                 eappeap_detach(inst);
76                 return -1;
77         }
78
79         /*
80          *      Convert the name to an integer, to make it easier to
81          *      handle.
82          */
83         inst->default_eap_type = eaptype_name2type(inst->default_eap_type_name);
84         if (inst->default_eap_type < 0) {
85                 radlog(L_ERR, "rlm_eap_peap: Unknown EAP type %s",
86                        inst->default_eap_type_name);
87                 eappeap_detach(inst);
88                 return -1;
89         }
90
91         *instance = inst;
92
93         return 0;
94 }
95
96 /*
97  *      Free the PEAP per-session data
98  */
99 static void peap_free(void *p)
100 {
101         peap_tunnel_t *t = (peap_tunnel_t *) p;
102
103         if (!t) return;
104
105         pairfree(&t->username);
106         pairfree(&t->state);
107
108         free(t);
109 }
110
111
112 /*
113  *      Free the PEAP per-session data
114  */
115 static peap_tunnel_t *peap_alloc(rlm_eap_peap_t *inst)
116 {
117         peap_tunnel_t *t;
118
119         t = rad_malloc(sizeof(*t));
120         memset(t, 0, sizeof(*t));
121
122         t->default_eap_type = inst->default_eap_type;
123
124         return t;
125 }
126
127 /*
128  *      Do authentication, by letting EAP-TLS do most of the work.
129  */
130 static int eappeap_authenticate(void *arg, EAP_HANDLER *handler)
131 {
132         int rcode;
133         eaptls_status_t status;
134         rlm_eap_peap_t *inst = (rlm_eap_peap_t *) arg;
135         tls_session_t *tls_session = (tls_session_t *) handler->opaque;
136
137         DEBUG2("  rlm_eap_peap: Authenticate");
138
139         status = eaptls_process(handler);
140         DEBUG2("  eaptls_process returned %d\n", status);
141         switch (status) {
142                 /*
143                  *      EAP-TLS handshake was successful, tell the
144                  *      client to keep talking.
145                  *
146                  *      If this was EAP-TLS, we would just return
147                  *      an EAP-TLS-Success packet here.
148                  */
149         case EAPTLS_SUCCESS:
150                 {
151                         eap_packet_t eap_packet;
152                         
153                         eap_packet.code = PW_EAP_REQUEST;
154                         eap_packet.id = handler->eap_ds->response->id + 1;
155                         eap_packet.length[0] = 0;
156                         eap_packet.length[1] = EAP_HEADER_LEN + 1;
157                         eap_packet.data[0] = PW_EAP_IDENTITY;
158
159                         record_plus(&tls_session->clean_in,
160                                     &eap_packet, sizeof(eap_packet));
161                         
162                         tls_handshake_send(tls_session);
163                         record_init(&tls_session->clean_in);
164                 }
165                 eaptls_request(handler->eap_ds, tls_session);
166                 DEBUG2("  rlm_eap_peap: EAPTLS_SUCCESS");
167                 return 1;
168
169                 /*
170                  *      The TLS code is still working on the TLS
171                  *      exchange, and it's a valid TLS request.
172                  *      do nothing.
173                  */
174         case EAPTLS_HANDLED:
175                 DEBUG2("  rlm_eap_peap: EAPTLS_HANDLED");
176                 return 1;
177
178                 /*
179                  *      Handshake is done, proceed with decoding tunneled
180                  *      data.
181                  */
182         case EAPTLS_OK:
183                 DEBUG2("  rlm_eap_peap: EAPTLS_OK");
184                 break;
185
186                 /*
187                  *      Anything else: fail.
188                  */
189         default:
190                 DEBUG2("  rlm_eap_peap: EAPTLS_OTHERS");
191                 return 0;
192         }
193
194         /*
195          *      Session is established, proceed with decoding
196          *      tunneled data.
197          */
198         DEBUG2("  rlm_eap_peap: Session established.  Proceeding to decode tunneled attributes.");
199
200         /*
201          *      We may need PEAP data associated with the session, so
202          *      allocate it here, if it wasn't already alloacted.
203          */
204         if (!tls_session->opaque) {
205                 tls_session->opaque = peap_alloc(inst);
206                 tls_session->free_opaque = peap_free;
207         }
208         
209         /*
210          *      Process the PEAP portion of the request.
211          */
212         rcode = eappeap_process(handler, tls_session);
213         switch (rcode) {
214         case RLM_MODULE_REJECT:
215                 eaptls_fail(handler->eap_ds, 0);
216                 return 0;
217           
218         case RLM_MODULE_HANDLED:
219                 eaptls_request(handler->eap_ds, tls_session);
220                 return 1;
221
222         case RLM_MODULE_OK:
223                 eaptls_success(handler->eap_ds, 0);
224                 eaptls_gen_mppe_keys(&handler->request->reply->vps, 
225                                      tls_session->ssl,
226                                      "client EAP encryption");
227                 return 1;
228
229         default:
230                 break;
231         }
232
233         eaptls_fail(handler->eap_ds, 0);
234         return 0;
235 }
236
237 /*
238  *      The module name should be the only globally exported symbol.
239  *      That is, everything else should be 'static'.
240  */
241 EAP_TYPE rlm_eap_peap = {
242         "eap_peap",
243         eappeap_attach,                 /* attach */
244         /*
245          *      Note! There is NO eappeap_initate() function, as the
246          *      main EAP module takes care of calling
247          *      eaptls_initiate().
248          *
249          *      This is because PEAP is a protocol on top of TLS, so
250          *      before we need to do PEAP, we've got to initiate a TLS
251          *      session.
252          */
253         NULL,                           /* Start the initial request */
254         NULL,                           /* authorization */
255         eappeap_authenticate,           /* authentication */
256         eappeap_detach                  /* detach */
257 };