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
;
123 enumerator
= msg
->create_enumerator(msg
);
124 while (enumerator
->enumerate(enumerator
, &type
, &data
))
126 if (type
== RAT_EAP_MESSAGE
)
128 *out
= payload
= eap_payload_create_data(data
);
129 /* apply EAP method selected by RADIUS server */
130 this->type
= payload
->get_type(payload
, &this->vendor
);
131 enumerator
->destroy(enumerator
);
135 enumerator
->destroy(enumerator
);
140 * Implementation of eap_method_t.initiate
142 static status_t
initiate(private_eap_radius_t
*this, eap_payload_t
**out
)
144 radius_message_t
*request
, *response
;
145 status_t status
= FAILED
;
148 request
= radius_message_create_request();
149 username
= chunk_create(this->id_prefix
, strlen(this->id_prefix
));
150 username
= chunk_cata("cc", username
, this->peer
->get_encoding(this->peer
));
151 request
->add(request
, RAT_USER_NAME
, username
);
155 request
->add(request
, RAT_EAP_MESSAGE
, chunk_empty
);
159 add_eap_identity(this, request
);
162 response
= this->client
->request(this->client
, request
);
165 if (radius2ike(this, response
, out
))
169 response
->destroy(response
);
171 request
->destroy(request
);
176 * Implementation of eap_method_t.process
178 static status_t
process(private_eap_radius_t
*this,
179 eap_payload_t
*in
, eap_payload_t
**out
)
181 radius_message_t
*request
, *response
;
182 status_t status
= FAILED
;
184 request
= radius_message_create_request();
185 request
->add(request
, RAT_USER_NAME
, this->peer
->get_encoding(this->peer
));
186 request
->add(request
, RAT_EAP_MESSAGE
, in
->get_data(in
));
188 response
= this->client
->request(this->client
, request
);
191 switch (response
->get_code(response
))
193 case RMC_ACCESS_CHALLENGE
:
194 if (radius2ike(this, response
, out
))
201 case RMC_ACCESS_ACCEPT
:
202 this->msk
= this->client
->decrypt_msk(this->client
,
206 case RMC_ACCESS_REJECT
:
208 DBG1(DBG_CFG
, "received %N from RADIUS server",
209 radius_message_code_names
, response
->get_code(response
));
213 response
->destroy(response
);
215 request
->destroy(request
);
220 * Implementation of eap_method_t.get_type.
222 static eap_type_t
get_type(private_eap_radius_t
*this, u_int32_t
*vendor
)
224 *vendor
= this->vendor
;
229 * Implementation of eap_method_t.get_msk.
231 static status_t
get_msk(private_eap_radius_t
*this, chunk_t
*msk
)
242 * Implementation of eap_method_t.is_mutual.
244 static bool is_mutual(private_eap_radius_t
*this)
257 * Implementation of eap_method_t.destroy.
259 static void destroy(private_eap_radius_t
*this)
261 this->peer
->destroy(this->peer
);
262 this->server
->destroy(this->server
);
263 this->client
->destroy(this->client
);
264 chunk_clear(&this->msk
);
269 * Generic constructor
271 eap_radius_t
*eap_radius_create(identification_t
*server
, identification_t
*peer
)
273 private_eap_radius_t
*this = malloc_thing(private_eap_radius_t
);
275 this->public.eap_method_interface
.initiate
= (status_t(*)(eap_method_t
*,eap_payload_t
**))initiate
;
276 this->public.eap_method_interface
.process
= (status_t(*)(eap_method_t
*,eap_payload_t
*,eap_payload_t
**))process
;
277 this->public.eap_method_interface
.get_type
= (eap_type_t(*)(eap_method_t
*,u_int32_t
*))get_type
;
278 this->public.eap_method_interface
.is_mutual
= (bool(*)(eap_method_t
*))is_mutual
;
279 this->public.eap_method_interface
.get_msk
= (status_t(*)(eap_method_t
*,chunk_t
*))get_msk
;
280 this->public.eap_method_interface
.destroy
= (void(*)(eap_method_t
*))destroy
;
282 this->client
= radius_client_create();
288 this->peer
= peer
->clone(peer
);
289 this->server
= server
->clone(server
);
290 /* initially EAP_RADIUS, but is set to the method selected by RADIUS */
291 this->type
= EAP_RADIUS
;
293 this->msk
= chunk_empty
;
294 this->eap_start
= lib
->settings
->get_bool(lib
->settings
,
295 "charon.plugins.eap_radius.eap_start", FALSE
);
296 this->id_prefix
= lib
->settings
->get_str(lib
->settings
,
297 "charon.plugins.eap_radius.id_prefix", "");
298 return &this->public;