2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "eap_radius.h"
18 #include "radius_message.h"
19 #include "radius_client.h"
23 typedef struct private_eap_radius_t private_eap_radius_t
;
26 * Private data of an eap_radius_t object.
28 struct private_eap_radius_t
{
31 * Public authenticator_t interface.
38 identification_t
*server
;
43 identification_t
*peer
;
46 * EAP method type we are proxying
56 * EAP MSK, if method established one
61 * RADIUS client instance
63 radius_client_t
*client
;
66 * TRUE to use EAP-Start, FALSE to send EAP-Identity Response directly
71 * Prefix to prepend to EAP identity
77 * Add EAP-Identity to RADIUS message
79 static void add_eap_identity(private_eap_radius_t
*this,
80 radius_message_t
*request
)
83 /** EAP code (REQUEST/RESPONSE) */
85 /** unique message identifier */
87 /** length of whole message */
93 } __attribute__((__packed__
)) *hdr
;
97 id
= this->peer
->get_encoding(this->peer
);
98 prefix
= chunk_create(this->id_prefix
, strlen(this->id_prefix
));
99 len
= sizeof(*hdr
) + prefix
.len
+ id
.len
;
102 hdr
->code
= EAP_RESPONSE
;
104 hdr
->length
= htons(len
);
105 hdr
->type
= EAP_IDENTITY
;
106 memcpy(hdr
->data
, prefix
.ptr
, prefix
.len
);
107 memcpy(hdr
->data
+ prefix
.len
, id
.ptr
, id
.len
);
109 request
->add(request
, RAT_EAP_MESSAGE
, chunk_create((u_char
*)hdr
, len
));
113 * Copy EAP-Message attribute from RADIUS message to an new EAP payload
115 static bool radius2ike(private_eap_radius_t
*this,
116 radius_message_t
*msg
, eap_payload_t
**out
)
118 enumerator_t
*enumerator
;
119 eap_payload_t
*payload
;
120 chunk_t data
, message
= chunk_empty
;
123 enumerator
= msg
->create_enumerator(msg
);
124 while (enumerator
->enumerate(enumerator
, &type
, &data
))
126 if (type
== RAT_EAP_MESSAGE
&& data
.len
)
128 message
= chunk_cat("mc", message
, data
);
131 enumerator
->destroy(enumerator
);
134 *out
= payload
= eap_payload_create_data(message
);
136 /* apply EAP method selected by RADIUS server */
137 this->type
= payload
->get_type(payload
, &this->vendor
);
144 * Implementation of eap_method_t.initiate
146 static status_t
initiate(private_eap_radius_t
*this, eap_payload_t
**out
)
148 radius_message_t
*request
, *response
;
149 status_t status
= FAILED
;
152 request
= radius_message_create_request();
153 username
= chunk_create(this->id_prefix
, strlen(this->id_prefix
));
154 username
= chunk_cata("cc", username
, this->peer
->get_encoding(this->peer
));
155 request
->add(request
, RAT_USER_NAME
, username
);
159 request
->add(request
, RAT_EAP_MESSAGE
, chunk_empty
);
163 add_eap_identity(this, request
);
166 response
= this->client
->request(this->client
, request
);
169 if (radius2ike(this, response
, out
))
173 response
->destroy(response
);
175 request
->destroy(request
);
180 * Implementation of eap_method_t.process
182 static status_t
process(private_eap_radius_t
*this,
183 eap_payload_t
*in
, eap_payload_t
**out
)
185 radius_message_t
*request
, *response
;
186 status_t status
= FAILED
;
189 request
= radius_message_create_request();
190 request
->add(request
, RAT_USER_NAME
, this->peer
->get_encoding(this->peer
));
191 data
= in
->get_data(in
);
192 /* fragment data suitable for RADIUS (not more than 253 bytes) */
193 while (data
.len
> 253)
195 request
->add(request
, RAT_EAP_MESSAGE
, chunk_create(data
.ptr
, 253));
196 data
= chunk_skip(data
, 253);
198 request
->add(request
, RAT_EAP_MESSAGE
, data
);
200 response
= this->client
->request(this->client
, request
);
203 switch (response
->get_code(response
))
205 case RMC_ACCESS_CHALLENGE
:
206 if (radius2ike(this, response
, out
))
213 case RMC_ACCESS_ACCEPT
:
214 this->msk
= this->client
->decrypt_msk(this->client
,
218 case RMC_ACCESS_REJECT
:
220 DBG1(DBG_CFG
, "received %N from RADIUS server",
221 radius_message_code_names
, response
->get_code(response
));
225 response
->destroy(response
);
227 request
->destroy(request
);
232 * Implementation of eap_method_t.get_type.
234 static eap_type_t
get_type(private_eap_radius_t
*this, u_int32_t
*vendor
)
236 *vendor
= this->vendor
;
241 * Implementation of eap_method_t.get_msk.
243 static status_t
get_msk(private_eap_radius_t
*this, chunk_t
*msk
)
254 * Implementation of eap_method_t.is_mutual.
256 static bool is_mutual(private_eap_radius_t
*this)
269 * Implementation of eap_method_t.destroy.
271 static void destroy(private_eap_radius_t
*this)
273 this->peer
->destroy(this->peer
);
274 this->server
->destroy(this->server
);
275 this->client
->destroy(this->client
);
276 chunk_clear(&this->msk
);
281 * Generic constructor
283 eap_radius_t
*eap_radius_create(identification_t
*server
, identification_t
*peer
)
285 private_eap_radius_t
*this = malloc_thing(private_eap_radius_t
);
287 this->public.eap_method_interface
.initiate
= (status_t(*)(eap_method_t
*,eap_payload_t
**))initiate
;
288 this->public.eap_method_interface
.process
= (status_t(*)(eap_method_t
*,eap_payload_t
*,eap_payload_t
**))process
;
289 this->public.eap_method_interface
.get_type
= (eap_type_t(*)(eap_method_t
*,u_int32_t
*))get_type
;
290 this->public.eap_method_interface
.is_mutual
= (bool(*)(eap_method_t
*))is_mutual
;
291 this->public.eap_method_interface
.get_msk
= (status_t(*)(eap_method_t
*,chunk_t
*))get_msk
;
292 this->public.eap_method_interface
.destroy
= (void(*)(eap_method_t
*))destroy
;
294 this->client
= radius_client_create();
300 this->peer
= peer
->clone(peer
);
301 this->server
= server
->clone(server
);
302 /* initially EAP_RADIUS, but is set to the method selected by RADIUS */
303 this->type
= EAP_RADIUS
;
305 this->msk
= chunk_empty
;
306 this->eap_start
= lib
->settings
->get_bool(lib
->settings
,
307 "charon.plugins.eap-radius.eap_start", FALSE
);
308 this->id_prefix
= lib
->settings
->get_str(lib
->settings
,
309 "charon.plugins.eap-radius.id_prefix", "");
310 return &this->public;