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