2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
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_provider.h"
19 #include <collections/hashtable.h>
20 #include <threading/mutex.h>
22 typedef struct private_eap_radius_provider_t private_eap_radius_provider_t
;
23 typedef struct private_listener_t private_listener_t
;
26 * Private data of registered listener
28 struct private_listener_t
{
31 * Implements listener_t interface
36 * Leases not acquired yet, identification_t => entry_t
38 hashtable_t
*unclaimed
;
41 * Leases acquired, identification_t => entry_t
46 * Mutex to lock leases
52 * Private data of an eap_radius_provider_t object.
54 struct private_eap_radius_provider_t
{
57 * Public eap_radius_provider_t interface.
59 eap_radius_provider_t
public;
62 * Additionally implements the listener_t interface
64 private_listener_t listener
;
68 * Singleton instance of provider
70 static eap_radius_provider_t
*singleton
= NULL
;
73 * Configuration attribute in an entry
76 /** type of attribute */
77 configuration_attribute_type_t type
;
85 static void destroy_attr(attr_t
*this)
92 * Hashtable entry with leases and attributes
95 /** identity we assigned the IP lease */
97 /** list of IP leases received from AAA, as host_t */
99 /** list of configuration attributes, as attr_t */
100 linked_list_t
*attrs
;
106 static void destroy_entry(entry_t
*this)
108 this->id
->destroy(this->id
);
109 this->addrs
->destroy_offset(this->addrs
, offsetof(host_t
, destroy
));
110 this->attrs
->destroy_function(this->attrs
, (void*)destroy_attr
);
115 * Get or create an entry from a locked hashtable
117 static entry_t
* get_or_create_entry(hashtable_t
*hashtable
, identification_t
*id
)
121 entry
= hashtable
->get(hashtable
, id
);
126 .addrs
= linked_list_create(),
127 .attrs
= linked_list_create(),
129 hashtable
->put(hashtable
, entry
->id
, entry
);
135 * Put an entry to hashtable, or destroy it ife empty
137 static void put_or_destroy_entry(hashtable_t
*hashtable
, entry_t
*entry
)
139 if (entry
->addrs
->get_count(entry
->addrs
) > 0 ||
140 entry
->attrs
->get_count(entry
->attrs
) > 0)
142 hashtable
->put(hashtable
, entry
->id
, entry
);
146 destroy_entry(entry
);
151 * Hashtable hash function
153 static u_int
hash(identification_t
*id
)
155 return chunk_hash_inc(id
->get_encoding(id
), id
->get_type(id
));
159 * Hashtable equals function
161 static bool equals(identification_t
*a
, identification_t
*b
)
163 return a
->equals(a
, b
);
167 * Insert an address entry to a locked claimed/unclaimed hashtable
169 static void add_addr(private_eap_radius_provider_t
*this,
170 hashtable_t
*hashtable
, identification_t
*id
, host_t
*host
)
174 entry
= get_or_create_entry(hashtable
, id
);
175 entry
->addrs
->insert_last(entry
->addrs
, host
);
179 * Remove the next address from the locked hashtable stored for given id
181 static host_t
* remove_addr(private_eap_radius_provider_t
*this,
182 hashtable_t
*hashtable
, identification_t
*id
)
187 entry
= hashtable
->remove(hashtable
, id
);
190 entry
->addrs
->remove_first(entry
->addrs
, (void**)&addr
);
191 put_or_destroy_entry(hashtable
, entry
);
197 * Insert an attribute entry to a locked claimed/unclaimed hashtable
199 static void add_attr(private_eap_radius_provider_t
*this,
200 hashtable_t
*hashtable
, identification_t
*id
, attr_t
*attr
)
204 entry
= get_or_create_entry(hashtable
, id
);
205 entry
->attrs
->insert_last(entry
->attrs
, attr
);
209 * Remove the next attribute from the locked hashtable stored for given id
211 static attr_t
* remove_attr(private_eap_radius_provider_t
*this,
212 hashtable_t
*hashtable
, identification_t
*id
)
217 entry
= hashtable
->remove(hashtable
, id
);
220 entry
->attrs
->remove_first(entry
->attrs
, (void**)&attr
);
221 put_or_destroy_entry(hashtable
, entry
);
227 * Clean up unclaimed leases assigned for an IKE_SA
229 static void release_unclaimed(private_listener_t
*this, ike_sa_t
*ike_sa
)
231 identification_t
*id
;
234 id
= ike_sa
->get_other_eap_id(ike_sa
);
235 this->mutex
->lock(this->mutex
);
236 entry
= this->unclaimed
->remove(this->unclaimed
, id
);
237 this->mutex
->unlock(this->mutex
);
240 destroy_entry(entry
);
244 METHOD(listener_t
, message_hook
, bool,
245 private_listener_t
*this, ike_sa_t
*ike_sa
,
246 message_t
*message
, bool incoming
, bool plain
)
248 if (plain
&& ike_sa
->get_state(ike_sa
) == IKE_ESTABLISHED
&&
249 !incoming
&& !message
->get_request(message
))
251 if ((ike_sa
->get_version(ike_sa
) == IKEV1
&&
252 message
->get_exchange_type(message
) == TRANSACTION
) ||
253 (ike_sa
->get_version(ike_sa
) == IKEV2
&&
254 message
->get_exchange_type(message
) == IKE_AUTH
))
256 /* if the addresses have not been claimed yet, they won't. Release
257 * these ressources. */
258 release_unclaimed(this, ike_sa
);
264 METHOD(listener_t
, ike_updown
, bool,
265 private_listener_t
*this, ike_sa_t
*ike_sa
, bool up
)
269 /* if the message hook does not apply because of a failed exchange
270 * or something, make sure we release any ressources now */
271 release_unclaimed(this, ike_sa
);
276 METHOD(attribute_provider_t
, acquire_address
, host_t
*,
277 private_eap_radius_provider_t
*this, linked_list_t
*pools
,
278 identification_t
*id
, host_t
*requested
)
280 enumerator_t
*enumerator
;
284 enumerator
= pools
->create_enumerator(pools
);
285 while (enumerator
->enumerate(enumerator
, &name
))
287 if (streq(name
, "radius"))
289 this->listener
.mutex
->lock(this->listener
.mutex
);
290 addr
= remove_addr(this, this->listener
.unclaimed
, id
);
293 add_addr(this, this->listener
.claimed
, id
, addr
->clone(addr
));
295 this->listener
.mutex
->unlock(this->listener
.mutex
);
299 enumerator
->destroy(enumerator
);
304 METHOD(attribute_provider_t
, release_address
, bool,
305 private_eap_radius_provider_t
*this, linked_list_t
*pools
, host_t
*address
,
306 identification_t
*id
)
308 enumerator_t
*enumerator
;
309 host_t
*found
= NULL
;
312 enumerator
= pools
->create_enumerator(pools
);
313 while (enumerator
->enumerate(enumerator
, &name
))
315 if (streq(name
, "radius"))
317 this->listener
.mutex
->lock(this->listener
.mutex
);
318 found
= remove_addr(this, this->listener
.claimed
, id
);
319 this->listener
.mutex
->unlock(this->listener
.mutex
);
323 enumerator
->destroy(enumerator
);
327 found
->destroy(found
);
334 * Enumerator implementation over attributes
337 /** implements enumerator_t */
339 /** list of attributes to enumerate */
341 /** currently enumerating attribute */
343 } attribute_enumerator_t
;
346 METHOD(enumerator_t
, attribute_enumerate
, bool,
347 attribute_enumerator_t
*this, configuration_attribute_type_t
*type
,
352 destroy_attr(this->current
);
353 this->current
= NULL
;
355 if (this->list
->remove_first(this->list
, (void**)&this->current
) == SUCCESS
)
357 *type
= this->current
->type
;
358 *data
= this->current
->data
;
364 METHOD(enumerator_t
, attribute_destroy
, void,
365 attribute_enumerator_t
*this)
369 destroy_attr(this->current
);
371 this->list
->destroy_function(this->list
, (void*)destroy_attr
);
375 METHOD(attribute_provider_t
, create_attribute_enumerator
, enumerator_t
*,
376 private_eap_radius_provider_t
*this, linked_list_t
*pools
,
377 identification_t
*id
, linked_list_t
*vips
)
379 attribute_enumerator_t
*enumerator
;
384 .enumerate
= (void*)_attribute_enumerate
,
385 .destroy
= _attribute_destroy
,
387 .list
= linked_list_create(),
390 /* we forward attributes regardless of pool configurations */
391 this->listener
.mutex
->lock(this->listener
.mutex
);
394 attr
= remove_attr(this, this->listener
.unclaimed
, id
);
399 enumerator
->list
->insert_last(enumerator
->list
, attr
);
401 this->listener
.mutex
->unlock(this->listener
.mutex
);
403 return &enumerator
->public;
406 METHOD(eap_radius_provider_t
, add_framed_ip
, void,
407 private_eap_radius_provider_t
*this, identification_t
*id
, host_t
*ip
)
409 this->listener
.mutex
->lock(this->listener
.mutex
);
410 add_addr(this, this->listener
.unclaimed
, id
, ip
);
411 this->listener
.mutex
->unlock(this->listener
.mutex
);
414 METHOD(eap_radius_provider_t
, add_attribute
, void,
415 private_eap_radius_provider_t
*this, identification_t
*id
,
416 configuration_attribute_type_t type
, chunk_t data
)
422 .data
= chunk_clone(data
),
424 this->listener
.mutex
->lock(this->listener
.mutex
);
425 add_attr(this, this->listener
.unclaimed
, id
, attr
);
426 this->listener
.mutex
->unlock(this->listener
.mutex
);
429 METHOD(eap_radius_provider_t
, destroy
, void,
430 private_eap_radius_provider_t
*this)
433 charon
->bus
->remove_listener(charon
->bus
, &this->listener
.public);
434 this->listener
.mutex
->destroy(this->listener
.mutex
);
435 this->listener
.claimed
->destroy(this->listener
.claimed
);
436 this->listener
.unclaimed
->destroy(this->listener
.unclaimed
);
443 eap_radius_provider_t
*eap_radius_provider_create()
447 private_eap_radius_provider_t
*this;
452 .acquire_address
= _acquire_address
,
453 .release_address
= _release_address
,
454 .create_attribute_enumerator
= _create_attribute_enumerator
,
456 .add_framed_ip
= _add_framed_ip
,
457 .add_attribute
= _add_attribute
,
462 .ike_updown
= _ike_updown
,
463 .message
= _message_hook
,
465 .claimed
= hashtable_create((hashtable_hash_t
)hash
,
466 (hashtable_equals_t
)equals
, 32),
467 .unclaimed
= hashtable_create((hashtable_hash_t
)hash
,
468 (hashtable_equals_t
)equals
, 32),
469 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
473 charon
->bus
->add_listener(charon
->bus
, &this->listener
.public);
475 singleton
= &this->public;
483 eap_radius_provider_t
*eap_radius_provider_get()