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 * Hashtable entry with leases
76 /** identity we assigned the IP lease */
78 /** list of IP leases received from AAA, as host_t */
85 static void destroy_entry(entry_t
*this)
87 this->id
->destroy(this->id
);
88 this->addrs
->destroy_offset(this->addrs
, offsetof(host_t
, destroy
));
93 * Get or create an entry from a locked hashtable
95 static entry_t
* get_or_create_entry(hashtable_t
*hashtable
, identification_t
*id
)
99 entry
= hashtable
->get(hashtable
, id
);
104 .addrs
= linked_list_create(),
106 hashtable
->put(hashtable
, entry
->id
, entry
);
112 * Put an entry to hashtable, or destroy it ife empty
114 static void put_or_destroy_entry(hashtable_t
*hashtable
, entry_t
*entry
)
116 if (entry
->addrs
->get_count(entry
->addrs
) > 0)
118 hashtable
->put(hashtable
, entry
->id
, entry
);
122 destroy_entry(entry
);
127 * Hashtable hash function
129 static u_int
hash(identification_t
*id
)
131 return chunk_hash_inc(id
->get_encoding(id
), id
->get_type(id
));
135 * Hashtable equals function
137 static bool equals(identification_t
*a
, identification_t
*b
)
139 return a
->equals(a
, b
);
143 * Insert an address entry to a locked claimed/unclaimed hashtable
145 static void add_addr(private_eap_radius_provider_t
*this,
146 hashtable_t
*hashtable
, identification_t
*id
, host_t
*host
)
150 entry
= get_or_create_entry(hashtable
, id
);
151 entry
->addrs
->insert_last(entry
->addrs
, host
);
155 * Remove the next address from the locked hashtable stored for given id
157 static host_t
* remove_addr(private_eap_radius_provider_t
*this,
158 hashtable_t
*hashtable
, identification_t
*id
)
163 entry
= hashtable
->remove(hashtable
, id
);
166 entry
->addrs
->remove_first(entry
->addrs
, (void**)&addr
);
167 put_or_destroy_entry(hashtable
, entry
);
173 * Clean up unclaimed leases assigned for an IKE_SA
175 static void release_unclaimed(private_listener_t
*this, ike_sa_t
*ike_sa
)
177 identification_t
*id
;
180 id
= ike_sa
->get_other_eap_id(ike_sa
);
181 this->mutex
->lock(this->mutex
);
182 entry
= this->unclaimed
->remove(this->unclaimed
, id
);
183 this->mutex
->unlock(this->mutex
);
186 destroy_entry(entry
);
190 METHOD(listener_t
, message_hook
, bool,
191 private_listener_t
*this, ike_sa_t
*ike_sa
,
192 message_t
*message
, bool incoming
, bool plain
)
194 if (plain
&& ike_sa
->get_state(ike_sa
) == IKE_ESTABLISHED
&&
195 !incoming
&& !message
->get_request(message
))
197 if ((ike_sa
->get_version(ike_sa
) == IKEV1
&&
198 message
->get_exchange_type(message
) == TRANSACTION
) ||
199 (ike_sa
->get_version(ike_sa
) == IKEV2
&&
200 message
->get_exchange_type(message
) == IKE_AUTH
))
202 /* if the addresses have not been claimed yet, they won't. Release
203 * these ressources. */
204 release_unclaimed(this, ike_sa
);
210 METHOD(listener_t
, ike_updown
, bool,
211 private_listener_t
*this, ike_sa_t
*ike_sa
, bool up
)
215 /* if the message hook does not apply because of a failed exchange
216 * or something, make sure we release any ressources now */
217 release_unclaimed(this, ike_sa
);
222 METHOD(attribute_provider_t
, acquire_address
, host_t
*,
223 private_eap_radius_provider_t
*this, linked_list_t
*pools
,
224 identification_t
*id
, host_t
*requested
)
226 enumerator_t
*enumerator
;
230 enumerator
= pools
->create_enumerator(pools
);
231 while (enumerator
->enumerate(enumerator
, &name
))
233 if (streq(name
, "radius"))
235 this->listener
.mutex
->lock(this->listener
.mutex
);
236 addr
= remove_addr(this, this->listener
.unclaimed
, id
);
239 add_addr(this, this->listener
.claimed
, id
, addr
->clone(addr
));
241 this->listener
.mutex
->unlock(this->listener
.mutex
);
245 enumerator
->destroy(enumerator
);
250 METHOD(attribute_provider_t
, release_address
, bool,
251 private_eap_radius_provider_t
*this, linked_list_t
*pools
, host_t
*address
,
252 identification_t
*id
)
254 enumerator_t
*enumerator
;
255 host_t
*found
= NULL
;
258 enumerator
= pools
->create_enumerator(pools
);
259 while (enumerator
->enumerate(enumerator
, &name
))
261 if (streq(name
, "radius"))
263 this->listener
.mutex
->lock(this->listener
.mutex
);
264 found
= remove_addr(this, this->listener
.claimed
, id
);
265 this->listener
.mutex
->unlock(this->listener
.mutex
);
269 enumerator
->destroy(enumerator
);
273 found
->destroy(found
);
279 METHOD(attribute_provider_t
, create_attribute_enumerator
, enumerator_t
*,
280 private_eap_radius_provider_t
*this, linked_list_t
*pools
,
281 identification_t
*id
, linked_list_t
*vips
)
283 return enumerator_create_empty();
286 METHOD(eap_radius_provider_t
, add_framed_ip
, void,
287 private_eap_radius_provider_t
*this, identification_t
*id
, host_t
*ip
)
289 this->listener
.mutex
->lock(this->listener
.mutex
);
290 add_addr(this, this->listener
.unclaimed
, id
, ip
);
291 this->listener
.mutex
->unlock(this->listener
.mutex
);
294 METHOD(eap_radius_provider_t
, destroy
, void,
295 private_eap_radius_provider_t
*this)
298 charon
->bus
->remove_listener(charon
->bus
, &this->listener
.public);
299 this->listener
.mutex
->destroy(this->listener
.mutex
);
300 this->listener
.claimed
->destroy(this->listener
.claimed
);
301 this->listener
.unclaimed
->destroy(this->listener
.unclaimed
);
308 eap_radius_provider_t
*eap_radius_provider_create()
312 private_eap_radius_provider_t
*this;
317 .acquire_address
= _acquire_address
,
318 .release_address
= _release_address
,
319 .create_attribute_enumerator
= _create_attribute_enumerator
,
321 .add_framed_ip
= _add_framed_ip
,
326 .ike_updown
= _ike_updown
,
327 .message
= _message_hook
,
329 .claimed
= hashtable_create((hashtable_hash_t
)hash
,
330 (hashtable_equals_t
)equals
, 32),
331 .unclaimed
= hashtable_create((hashtable_hash_t
)hash
,
332 (hashtable_equals_t
)equals
, 32),
333 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
337 charon
->bus
->add_listener(charon
->bus
, &this->listener
.public);
339 singleton
= &this->public;
347 eap_radius_provider_t
*eap_radius_provider_get()