return with TNC_RESULT_SUCCESS
[strongswan.git] / src / libcharon / plugins / tnc_imv / tnc_imv_manager.c
1 /*
2 * Copyright (C) 2006 Mike McCauley
3 * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
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 "tnc_imv_manager.h"
17 #include "tnc_imv.h"
18 #include "tnc_imv_recommendations.h"
19
20 #include <tncifimv.h>
21 #include <tncif_names.h>
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/mman.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <fcntl.h>
29
30 #include <daemon.h>
31 #include <utils/lexparser.h>
32 #include <debug.h>
33 #include <threading/mutex.h>
34
35 typedef struct private_tnc_imv_manager_t private_tnc_imv_manager_t;
36
37
38 /**
39 * Private data of an imv_manager_t object.
40 */
41 struct private_tnc_imv_manager_t {
42
43 /**
44 * Public members of imv_manager_t.
45 */
46 imv_manager_t public;
47
48 /**
49 * Linked list of IMVs
50 */
51 linked_list_t *imvs;
52
53 /**
54 * Next IMV ID to be assigned
55 */
56 TNC_IMVID next_imv_id;
57
58 /**
59 * Policy defining how to derive final recommendation from individual ones
60 */
61 recommendation_policy_t policy;
62 };
63
64 METHOD(imv_manager_t, add, bool,
65 private_tnc_imv_manager_t *this, imv_t *imv)
66 {
67 TNC_Version version;
68
69 /* Initialize the IMV module */
70 imv->set_id(imv, this->next_imv_id);
71 if (imv->initialize(imv->get_id(imv), TNC_IFIMV_VERSION_1,
72 TNC_IFIMV_VERSION_1, &version) != TNC_RESULT_SUCCESS)
73 {
74 DBG1(DBG_TNC, "IMV \"%s\" failed to initialize", imv->get_name(imv));
75 return FALSE;
76 }
77 this->imvs->insert_last(this->imvs, imv);
78 this->next_imv_id++;
79
80 if (imv->provide_bind_function(imv->get_id(imv), TNC_TNCS_BindFunction)
81 != TNC_RESULT_SUCCESS)
82 {
83 DBG1(DBG_TNC, "IMV \"%s\" could failed to obtain bind function",
84 imv->get_name(imv));
85 this->imvs->remove_last(this->imvs, (void**)&imv);
86 return FALSE;
87 }
88
89 return TRUE;
90 }
91
92 METHOD(imv_manager_t, remove_, imv_t*,
93 private_tnc_imv_manager_t *this, TNC_IMVID id)
94 {
95 enumerator_t *enumerator;
96 imv_t *imv, *removed_imv = NULL;
97
98 enumerator = this->imvs->create_enumerator(this->imvs);
99 while (enumerator->enumerate(enumerator, &imv))
100 {
101 if (id == imv->get_id(imv))
102 {
103 this->imvs->remove_at(this->imvs, enumerator);
104 removed_imv = imv;
105 break;
106 }
107 }
108 enumerator->destroy(enumerator);
109
110 return removed_imv;
111 }
112
113 METHOD(imv_manager_t, load, bool,
114 private_tnc_imv_manager_t *this, char *name, char *path)
115 {
116 imv_t *imv;
117
118 imv = tnc_imv_create(name, path);
119 if (!imv)
120 {
121 free(name);
122 free(path);
123 return FALSE;
124 }
125 if (!add(this, imv))
126 {
127 if (imv->terminate &&
128 imv->terminate(imv->get_id(imv)) != TNC_RESULT_SUCCESS)
129 {
130 DBG1(DBG_TNC, "IMV \"%s\" not terminated successfully",
131 imv->get_name(imv));
132 }
133 imv->destroy(imv);
134 return FALSE;
135 }
136 DBG1(DBG_TNC, "IMV %u \"%s\" loaded from '%s'", imv->get_id(imv), name, path);
137 return TRUE;
138 }
139
140 METHOD(imv_manager_t, is_registered, bool,
141 private_tnc_imv_manager_t *this, TNC_IMVID id)
142 {
143 enumerator_t *enumerator;
144 imv_t *imv;
145 bool found = FALSE;
146
147 enumerator = this->imvs->create_enumerator(this->imvs);
148 while (enumerator->enumerate(enumerator, &imv))
149 {
150 if (id == imv->get_id(imv))
151 {
152 found = TRUE;
153 break;
154 }
155 }
156 enumerator->destroy(enumerator);
157
158 return found;
159 }
160
161 METHOD(imv_manager_t, get_recommendation_policy, recommendation_policy_t,
162 private_tnc_imv_manager_t *this)
163 {
164 return this->policy;
165 }
166
167 METHOD(imv_manager_t, create_recommendations, recommendations_t*,
168 private_tnc_imv_manager_t *this)
169 {
170 return tnc_imv_recommendations_create(this->imvs);
171 }
172
173 METHOD(imv_manager_t, enforce_recommendation, bool,
174 private_tnc_imv_manager_t *this, TNC_IMV_Action_Recommendation rec,
175 TNC_IMV_Evaluation_Result eval)
176 {
177 char *group;
178 identification_t *id;
179 ike_sa_t *ike_sa;
180 auth_cfg_t *auth;
181 bool no_access = FALSE;
182
183 DBG1(DBG_TNC, "final recommendation is '%N' and evaluation is '%N'",
184 TNC_IMV_Action_Recommendation_names, rec,
185 TNC_IMV_Evaluation_Result_names, eval);
186
187 switch (rec)
188 {
189 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
190 group = "allow";
191 break;
192 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
193 group = "isolate";
194 break;
195 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
196 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
197 default:
198 group = "no access";
199 no_access = TRUE;
200 break;
201 }
202
203 ike_sa = charon->bus->get_sa(charon->bus);
204 if (!ike_sa)
205 {
206 DBG1(DBG_TNC, "policy enforcement point did not find IKE_SA");
207 return FALSE;
208 }
209
210 id = ike_sa->get_other_id(ike_sa);
211 DBG0(DBG_TNC, "policy enforced on peer '%Y' is '%s'", id, group);
212
213 if (no_access)
214 {
215 return FALSE;
216 }
217 else
218 {
219 auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
220 id = identification_create_from_string(group);
221 auth->add(auth, AUTH_RULE_GROUP, id);
222 DBG1(DBG_TNC, "policy enforcement point added group membership '%s'",
223 group);
224 }
225 return TRUE;
226 }
227
228
229 METHOD(imv_manager_t, notify_connection_change, void,
230 private_tnc_imv_manager_t *this, TNC_ConnectionID id,
231 TNC_ConnectionState state)
232 {
233 enumerator_t *enumerator;
234 imv_t *imv;
235
236 enumerator = this->imvs->create_enumerator(this->imvs);
237 while (enumerator->enumerate(enumerator, &imv))
238 {
239 if (imv->notify_connection_change)
240 {
241 imv->notify_connection_change(imv->get_id(imv), id, state);
242 }
243 }
244 enumerator->destroy(enumerator);
245 }
246
247 METHOD(imv_manager_t, set_message_types, TNC_Result,
248 private_tnc_imv_manager_t *this, TNC_IMVID id,
249 TNC_MessageTypeList supported_types,
250 TNC_UInt32 type_count)
251 {
252 enumerator_t *enumerator;
253 imv_t *imv;
254 TNC_Result result = TNC_RESULT_FATAL;
255
256 enumerator = this->imvs->create_enumerator(this->imvs);
257 while (enumerator->enumerate(enumerator, &imv))
258 {
259 if (id == imv->get_id(imv))
260 {
261 imv->set_message_types(imv, supported_types, type_count);
262 result = TNC_RESULT_SUCCESS;
263 break;
264 }
265 }
266 enumerator->destroy(enumerator);
267 return result;
268 }
269
270 METHOD(imv_manager_t, set_message_types_long, TNC_Result,
271 private_tnc_imv_manager_t *this, TNC_IMVID id,
272 TNC_VendorIDList supported_vids,
273 TNC_MessageSubtypeList supported_subtypes,
274 TNC_UInt32 type_count)
275 {
276 enumerator_t *enumerator;
277 imv_t *imv;
278 TNC_Result result = TNC_RESULT_FATAL;
279
280 enumerator = this->imvs->create_enumerator(this->imvs);
281 while (enumerator->enumerate(enumerator, &imv))
282 {
283 if (id == imv->get_id(imv))
284 {
285 imv->set_message_types_long(imv, supported_vids, supported_subtypes,
286 type_count);
287 result = TNC_RESULT_SUCCESS;
288 break;
289 }
290 }
291 enumerator->destroy(enumerator);
292 return result;
293 }
294
295 METHOD(imv_manager_t, solicit_recommendation, void,
296 private_tnc_imv_manager_t *this, TNC_ConnectionID id)
297 {
298 enumerator_t *enumerator;
299 imv_t *imv;
300
301 enumerator = this->imvs->create_enumerator(this->imvs);
302 while (enumerator->enumerate(enumerator, &imv))
303 {
304 imv->solicit_recommendation(imv->get_id(imv), id);
305 }
306 enumerator->destroy(enumerator);
307 }
308
309 METHOD(imv_manager_t, receive_message, void,
310 private_tnc_imv_manager_t *this, TNC_ConnectionID connection_id,
311 TNC_BufferReference message,
312 TNC_UInt32 message_len,
313 TNC_MessageType message_type)
314 {
315 bool type_supported = FALSE;
316 enumerator_t *enumerator;
317 imv_t *imv;
318
319 enumerator = this->imvs->create_enumerator(this->imvs);
320 while (enumerator->enumerate(enumerator, &imv))
321 {
322 if (imv->receive_message && imv->type_supported(imv, message_type))
323 {
324 type_supported = TRUE;
325 imv->receive_message(imv->get_id(imv), connection_id,
326 message, message_len, message_type);
327 }
328 }
329 enumerator->destroy(enumerator);
330 if (!type_supported)
331 {
332 DBG2(DBG_TNC, "message type 0x%08x not supported by any IMV", message_type);
333 }
334 }
335
336 METHOD(imv_manager_t, batch_ending, void,
337 private_tnc_imv_manager_t *this, TNC_ConnectionID id)
338 {
339 enumerator_t *enumerator;
340 imv_t *imv;
341
342 enumerator = this->imvs->create_enumerator(this->imvs);
343 while (enumerator->enumerate(enumerator, &imv))
344 {
345 if (imv->batch_ending)
346 {
347 imv->batch_ending(imv->get_id(imv), id);
348 }
349 }
350 enumerator->destroy(enumerator);
351 }
352
353
354 METHOD(imv_manager_t, destroy, void,
355 private_tnc_imv_manager_t *this)
356 {
357 imv_t *imv;
358
359 while (this->imvs->remove_last(this->imvs, (void**)&imv) == SUCCESS)
360 {
361 if (imv->terminate &&
362 imv->terminate(imv->get_id(imv)) != TNC_RESULT_SUCCESS)
363 {
364 DBG1(DBG_TNC, "IMV \"%s\" not terminated successfully",
365 imv->get_name(imv));
366 }
367 imv->destroy(imv);
368 }
369 this->imvs->destroy(this->imvs);
370 free(this);
371 }
372
373 /**
374 * Described in header.
375 */
376 imv_manager_t* tnc_imv_manager_create(void)
377 {
378 private_tnc_imv_manager_t *this;
379 recommendation_policy_t policy;
380
381 INIT(this,
382 .public = {
383 .add = _add,
384 .remove = _remove_, /* avoid name conflict with stdio.h */
385 .load = _load,
386 .is_registered = _is_registered,
387 .get_recommendation_policy = _get_recommendation_policy,
388 .create_recommendations = _create_recommendations,
389 .enforce_recommendation = _enforce_recommendation,
390 .notify_connection_change = _notify_connection_change,
391 .set_message_types = _set_message_types,
392 .set_message_types_long = _set_message_types_long,
393 .solicit_recommendation = _solicit_recommendation,
394 .receive_message = _receive_message,
395 .batch_ending = _batch_ending,
396 .destroy = _destroy,
397 },
398 .imvs = linked_list_create(),
399 .next_imv_id = 1,
400 );
401
402 policy = enum_from_name(recommendation_policy_names,
403 lib->settings->get_str(lib->settings,
404 "charon.plugins.tnc-imv.recommendation_policy", "default"));
405 this->policy = (policy != -1) ? policy : RECOMMENDATION_POLICY_DEFAULT;
406 DBG1(DBG_TNC, "TNC recommendation policy is '%N'",
407 recommendation_policy_names, this->policy);
408
409 return &this->public;
410 }