fixed whitelist enabling
[strongswan.git] / src / libcharon / plugins / whitelist / whitelist_listener.c
1 /*
2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "whitelist_listener.h"
17
18 #include <daemon.h>
19 #include <utils/hashtable.h>
20 #include <threading/rwlock.h>
21
22 typedef struct private_whitelist_listener_t private_whitelist_listener_t;
23
24 /**
25 * Private data of an whitelist_listener_t object.
26 */
27 struct private_whitelist_listener_t {
28
29 /**
30 * Public whitelist_listener_t interface.
31 */
32 whitelist_listener_t public;
33
34 /**
35 * Lock for hashtable
36 */
37 rwlock_t *lock;
38
39 /**
40 * Hashtable with whitelisted identities
41 */
42 hashtable_t *ids;
43
44 /**
45 * Whitelist checking enabled
46 */
47 bool enabled;
48 };
49
50 /**
51 * Hashtable hash function
52 */
53 static u_int hash(identification_t *key)
54 {
55 return chunk_hash(key->get_encoding(key));
56 }
57
58 /**
59 * Hashtable equals function
60 */
61 static bool equals(identification_t *a, identification_t *b)
62 {
63 return a->equals(a, b);
64 }
65
66 METHOD(listener_t, authorize, bool,
67 private_whitelist_listener_t *this, ike_sa_t *ike_sa,
68 bool final, bool *success)
69 {
70 /* check each authentication round */
71 if (this->enabled && !final)
72 {
73 bool whitelisted = FALSE;
74 identification_t *id;
75 auth_cfg_t *auth;
76
77 auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
78 /* for authenticated with EAP, check EAP identity */
79 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
80 if (!id)
81 {
82 id = auth->get(auth, AUTH_RULE_IDENTITY);
83 }
84 if (id)
85 {
86 this->lock->read_lock(this->lock);
87 whitelisted = this->ids->get(this->ids, id) != NULL;
88 this->lock->unlock(this->lock);
89 }
90 if (whitelisted)
91 {
92 DBG2(DBG_CFG, "peer identity '%Y' whitelisted", id);
93 }
94 else
95 {
96 DBG1(DBG_CFG, "peer identity '%Y' not whitelisted", id);
97 *success = FALSE;
98 }
99 }
100 return TRUE;
101 }
102
103 METHOD(whitelist_listener_t, add, void,
104 private_whitelist_listener_t *this, identification_t *id)
105 {
106 id = id->clone(id);
107 this->lock->write_lock(this->lock);
108 id = this->ids->put(this->ids, id, id);
109 this->lock->unlock(this->lock);
110 DESTROY_IF(id);
111 }
112
113 METHOD(whitelist_listener_t, remove_, void,
114 private_whitelist_listener_t *this, identification_t *id)
115 {
116 this->lock->write_lock(this->lock);
117 id = this->ids->remove(this->ids, id);
118 this->lock->unlock(this->lock);
119 DESTROY_IF(id);
120 }
121
122 /**
123 * Enumerator filter, from hashtable (key, value) to single identity
124 */
125 static bool whitelist_filter(rwlock_t *lock, identification_t **key,
126 identification_t **id, identification_t **value)
127 {
128 *id = *value;
129 return TRUE;
130 }
131
132 METHOD(whitelist_listener_t, create_enumerator, enumerator_t*,
133 private_whitelist_listener_t *this)
134 {
135 this->lock->read_lock(this->lock);
136 return enumerator_create_filter(this->ids->create_enumerator(this->ids),
137 (void*)whitelist_filter, this->lock,
138 (void*)this->lock->unlock);
139 }
140
141 METHOD(whitelist_listener_t, flush, void,
142 private_whitelist_listener_t *this, identification_t *id)
143 {
144 enumerator_t *enumerator;
145 identification_t *key, *value;
146
147 this->lock->write_lock(this->lock);
148 enumerator = this->ids->create_enumerator(this->ids);
149 while (enumerator->enumerate(enumerator, &key, &value))
150 {
151 if (value->matches(value, id))
152 {
153 this->ids->remove_at(this->ids, enumerator);
154 value->destroy(value);
155 }
156 }
157 enumerator->destroy(enumerator);
158 this->lock->unlock(this->lock);
159 }
160
161 METHOD(whitelist_listener_t, set_active, void,
162 private_whitelist_listener_t *this, bool enable)
163 {
164 DBG1(DBG_CFG, "whitelist functionality %s%sabled",
165 (this->enabled == enable) ? "was already " : "", enable ? "en" : "dis");
166 this->enabled = enable;
167 }
168
169 METHOD(whitelist_listener_t, destroy, void,
170 private_whitelist_listener_t *this)
171 {
172 identification_t *key, *value;
173 enumerator_t *enumerator;
174
175 enumerator = this->ids->create_enumerator(this->ids);
176 while (enumerator->enumerate(enumerator, &key, &value))
177 {
178 value->destroy(value);
179 }
180 enumerator->destroy(enumerator);
181 this->ids->destroy(this->ids);
182 this->lock->destroy(this->lock);
183 free(this);
184 }
185
186 /**
187 * See header
188 */
189 whitelist_listener_t *whitelist_listener_create()
190 {
191 private_whitelist_listener_t *this;
192
193 INIT(this,
194 .public = {
195 .listener = {
196 .authorize = _authorize,
197 },
198 .add = _add,
199 .remove = _remove_,
200 .create_enumerator = _create_enumerator,
201 .flush = _flush,
202 .set_active = _set_active,
203 .destroy = _destroy,
204 },
205 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
206 .ids = hashtable_create((hashtable_hash_t)hash,
207 (hashtable_equals_t)equals, 32),
208 .enabled = lib->settings->get_bool(lib->settings,
209 "charon.plugins.whitelist.enable", FALSE),
210 );
211
212 return &this->public;
213 }