Added strongswan.conf and runtime option to enable/disable whitelist plugin
[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 %sabled", enable ? "en" : "dis");
165 this->enabled = enable;
166 }
167
168 METHOD(whitelist_listener_t, destroy, void,
169 private_whitelist_listener_t *this)
170 {
171 identification_t *key, *value;
172 enumerator_t *enumerator;
173
174 enumerator = this->ids->create_enumerator(this->ids);
175 while (enumerator->enumerate(enumerator, &key, &value))
176 {
177 value->destroy(value);
178 }
179 enumerator->destroy(enumerator);
180 this->ids->destroy(this->ids);
181 this->lock->destroy(this->lock);
182 free(this);
183 }
184
185 /**
186 * See header
187 */
188 whitelist_listener_t *whitelist_listener_create()
189 {
190 private_whitelist_listener_t *this;
191
192 INIT(this,
193 .public = {
194 .listener = {
195 .authorize = _authorize,
196 },
197 .add = _add,
198 .remove = _remove_,
199 .create_enumerator = _create_enumerator,
200 .flush = _flush,
201 .set_active = _set_active,
202 .destroy = _destroy,
203 },
204 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
205 .ids = hashtable_create((hashtable_hash_t)hash,
206 (hashtable_equals_t)equals, 32),
207 .enabled = lib->settings->get_bool(lib->settings,
208 "charon.plugins.whitelist.enabled", TRUE),
209 );
210
211 return &this->public;
212 }