type.data is malloc'd by everyone BUT radeapclient, which
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_ttls / rlm_eap_ttls.c
1 /*
2  * rlm_eap_ttls.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_ttls.h"
25
26
27 typedef struct rlm_eap_ttls_t {
28         /*
29          *      Default tunneled EAP type
30          */
31         char    *default_eap_type_name;
32         int     default_eap_type;
33
34         /*
35          *      Use the reply attributes from the tunneled session in
36          *      the non-tunneled reply to the client.
37          */
38         int     use_tunneled_reply;
39
40         /*
41          *      Use SOME of the request attributes from outside of the
42          *      tunneled session in the tunneled request
43          */
44         int     copy_request_to_tunnel;
45 } rlm_eap_ttls_t;
46
47
48 static CONF_PARSER module_config[] = {
49         { "default_eap_type", PW_TYPE_STRING_PTR,
50           offsetof(rlm_eap_ttls_t, default_eap_type_name), NULL, "md5" },
51
52         { "copy_request_to_tunnel", PW_TYPE_BOOLEAN,
53           offsetof(rlm_eap_ttls_t, copy_request_to_tunnel), NULL, "no" },
54
55         { "use_tunneled_reply", PW_TYPE_BOOLEAN,
56           offsetof(rlm_eap_ttls_t, use_tunneled_reply), NULL, "no" },
57
58         { NULL, -1, 0, NULL, NULL }           /* end the list */
59 };
60
61 /*
62  *      Detach the module.
63  */
64 static int eapttls_detach(void *arg)
65 {
66         rlm_eap_ttls_t *inst = (rlm_eap_ttls_t *) arg;
67
68         if (inst->default_eap_type_name) free(inst->default_eap_type_name);
69
70         free(inst);
71
72         return 0;
73 }
74
75 /*
76  *      Attach the module.
77  */
78 static int eapttls_attach(CONF_SECTION *cs, void **instance)
79 {
80         rlm_eap_ttls_t *inst;
81
82         inst = malloc(sizeof(*inst));
83         if (!inst) {
84                 radlog(L_ERR, "rlm_eap_ttls: out of memory");
85                 return -1;
86         }
87         memset(inst, 0, sizeof(*inst));
88
89         /*
90          *      Parse the configuration attributes.
91          */
92         if (cf_section_parse(cs, inst, module_config) < 0) {
93                 eapttls_detach(inst);
94                 return -1;
95         }
96
97         /*
98          *      Convert the name to an integer, to make it easier to
99          *      handle.
100          */
101         inst->default_eap_type = eaptype_name2type(inst->default_eap_type_name);
102         if (inst->default_eap_type < 0) {
103                 radlog(L_ERR, "rlm_eap_ttls: Unknown EAP type %s",
104                        inst->default_eap_type_name);
105                 eapttls_detach(inst);
106                 return -1;
107         }
108
109         /*
110          *      Can't tunnel TLS inside of TLS, we don't like it.
111          *
112          *      More realistically, we haven't tested it, so we don't
113          *      claim it works.
114          */
115         if ((inst->default_eap_type == PW_EAP_TLS) ||
116             (inst->default_eap_type == PW_EAP_TTLS) ||
117             (inst->default_eap_type == PW_EAP_PEAP)) {
118                 radlog(L_ERR, "rlm_eap_ttls: Cannot tunnel EAP-Type/%s inside of TTLS",
119                        inst->default_eap_type_name);
120                 eapttls_detach(inst);
121                 return -1;
122         }
123
124         *instance = inst;
125         return 0;
126 }
127
128
129 /*
130  *      Free the TTLS per-session data
131  */
132 static void ttls_free(void *p)
133 {
134         ttls_tunnel_t *t = (ttls_tunnel_t *) p;
135
136         if (!t) return;
137
138         if (t->username) {
139                 DEBUG2("  TTLS: Freeing handler for user %s",
140                        t->username->strvalue);
141         }
142
143         pairfree(&t->username);
144         pairfree(&t->state);
145         pairfree(&t->reply);
146         free(t);
147 }
148
149
150 /*
151  *      Allocate the TTLS per-session data
152  */
153 static ttls_tunnel_t *ttls_alloc(rlm_eap_ttls_t *inst)
154 {
155         ttls_tunnel_t *t;
156
157         t = rad_malloc(sizeof(*t));
158         memset(t, 0, sizeof(*t));
159
160         t->default_eap_type = inst->default_eap_type;
161         t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
162         t->use_tunneled_reply = inst->use_tunneled_reply;
163         return t;
164 }
165
166
167 /*
168  *      Do authentication, by letting EAP-TLS do most of the work.
169  */
170 static int eapttls_authenticate(void *arg, EAP_HANDLER *handler)
171 {
172         int rcode;
173         eaptls_status_t status;
174         rlm_eap_ttls_t *inst = (rlm_eap_ttls_t *) arg;
175         tls_session_t *tls_session = (tls_session_t *) handler->opaque;
176         ttls_tunnel_t *t = (ttls_tunnel_t *) tls_session->opaque;
177
178         DEBUG2("  rlm_eap_ttls: Authenticate");
179
180         /*
181          *      Process TLS layer until done.
182          */
183         status = eaptls_process(handler);
184         DEBUG2("  eaptls_process returned %d\n", status);
185         switch (status) {
186                 /*
187                  *      EAP-TLS handshake was successful, tell the
188                  *      client to keep talking.
189                  *
190                  *      If this was EAP-TLS, we would just return
191                  *      an EAP-TLS-Success packet here.
192                  */
193         case EAPTLS_SUCCESS:
194                 if (t->authenticated) {
195                         if (t->reply) {
196                                 pairadd(&handler->request->reply->vps, t->reply);
197                                 t->reply = NULL;
198                         }
199                         eaptls_success(handler->eap_ds, 0);
200                         eaptls_gen_mppe_keys(&handler->request->reply->vps,
201                                              tls_session->ssl,
202                                              "ttls keying material");
203                 } else {
204                         eaptls_request(handler->eap_ds, tls_session);
205                 }
206                 return 1;
207
208                 /*
209                  *      The TLS code is still working on the TLS
210                  *      exchange, and it's a valid TLS request.
211                  *      do nothing.
212                  */
213         case EAPTLS_HANDLED:
214                 return 1;
215
216                 /*
217                  *      Handshake is done, proceed with decoding tunneled
218                  *      data.
219                  */
220         case EAPTLS_OK:
221                 break;
222
223                 /*
224                  *      Anything else: fail.
225                  */
226         default:
227                 return 0;
228         }
229
230         /*
231          *      Session is established, proceed with decoding
232          *      tunneled data.
233          */
234         DEBUG2("  rlm_eap_ttls: Session established.  Proceeding to decode tunneled attributes.");
235
236         /*
237          *      We may need TTLS data associated with the session, so
238          *      allocate it here, if it wasn't already alloacted.
239          */
240         if (!tls_session->opaque) {
241                 tls_session->opaque = ttls_alloc(inst);
242                 tls_session->free_opaque = ttls_free;
243         }
244
245         /*
246          *      Process the TTLS portion of the request.
247          */
248         rcode = eapttls_process(handler, tls_session);
249         switch (rcode) {
250         case PW_AUTHENTICATION_REJECT:
251                 eaptls_fail(handler->eap_ds, 0);
252                 return 0;
253
254                 /*
255                  *      Access-Challenge, continue tunneled conversation.
256                  */
257         case PW_ACCESS_CHALLENGE:
258                 eaptls_request(handler->eap_ds, tls_session);
259                 return 1;
260
261                 /*
262                  *      Success: Return MPPE keys.
263                  */
264         case PW_AUTHENTICATION_ACK:
265                 eaptls_success(handler->eap_ds, 0);
266                 eaptls_gen_mppe_keys(&handler->request->reply->vps,
267                                      tls_session->ssl,
268                                      "ttls keying material");
269                 return 1;
270
271                 /*
272                  *      No response packet, MUST be proxying it.
273                  *      The main EAP module will take care of discovering
274                  *      that the request now has a "proxy" packet, and
275                  *      will proxy it, rather than returning an EAP packet.
276                  */
277         case PW_STATUS_CLIENT:
278                 rad_assert(handler->request->proxy != NULL);
279                 return 1;
280                 break;
281
282         default:
283                 break;
284         }
285
286         /*
287          *      Something we don't understand: Reject it.
288          */
289         eaptls_fail(handler->eap_ds, 0);
290         return 0;
291 }
292
293 /*
294  *      The module name should be the only globally exported symbol.
295  *      That is, everything else should be 'static'.
296  */
297 EAP_TYPE rlm_eap_ttls = {
298         "eap_ttls",
299         eapttls_attach,                 /* attach */
300         /*
301          *      Note! There is NO eapttls_initate() function, as the
302          *      main EAP module takes care of calling
303          *      eaptls_initiate().
304          *
305          *      This is because TTLS is a protocol on top of TLS, so
306          *      before we need to do TTLS, we've got to initiate a TLS
307          *      session.
308          */
309         NULL,                           /* Start the initial request */
310         NULL,                           /* authorization */
311         eapttls_authenticate,           /* authentication */
312         eapttls_detach                  /* detach */
313 };