Add wrappers to IMC/IMV managers loading IMC/IMVs from function pointers
[strongswan.git] / src / libcharon / plugins / tnc_imv / tnc_imv_manager.c
1 /*
2 * Copyright (C) 2006 Mike McCauley
3 * Copyright (C) 2010-2011 Andreas Steffen
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "tnc_imv_manager.h"
18 #include "tnc_imv.h"
19 #include "tnc_imv_recommendations.h"
20
21 #include <tncifimv.h>
22 #include <tncif_names.h>
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/mman.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <fcntl.h>
30
31 #include <daemon.h>
32 #include <utils/lexparser.h>
33 #include <utils/debug.h>
34 #include <threading/mutex.h>
35
36 typedef struct private_tnc_imv_manager_t private_tnc_imv_manager_t;
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 imv->set_id(imv, this->next_imv_id);
70 if (imv->initialize(imv->get_id(imv), TNC_IFIMV_VERSION_1,
71 TNC_IFIMV_VERSION_1, &version) != TNC_RESULT_SUCCESS)
72 {
73 DBG1(DBG_TNC, "IMV \"%s\" failed to initialize", imv->get_name(imv));
74 return FALSE;
75 }
76 this->imvs->insert_last(this->imvs, imv);
77 this->next_imv_id++;
78
79 if (imv->provide_bind_function(imv->get_id(imv),
80 TNC_TNCS_BindFunction) != TNC_RESULT_SUCCESS)
81 {
82 if (imv->terminate)
83 {
84 imv->terminate(imv->get_id(imv));
85 }
86 DBG1(DBG_TNC, "IMV \"%s\" failed to obtain bind function",
87 imv->get_name(imv));
88 this->imvs->remove_last(this->imvs, (void**)&imv);
89 return FALSE;
90 }
91 return TRUE;
92 }
93
94 METHOD(imv_manager_t, remove_, imv_t*,
95 private_tnc_imv_manager_t *this, TNC_IMVID id)
96 {
97 enumerator_t *enumerator;
98 imv_t *imv, *removed_imv = NULL;
99
100 enumerator = this->imvs->create_enumerator(this->imvs);
101 while (enumerator->enumerate(enumerator, &imv))
102 {
103 if (id == imv->get_id(imv))
104 {
105 this->imvs->remove_at(this->imvs, enumerator);
106 removed_imv = imv;
107 break;
108 }
109 }
110 enumerator->destroy(enumerator);
111
112 return removed_imv;
113 }
114
115 METHOD(imv_manager_t, load, bool,
116 private_tnc_imv_manager_t *this, char *name, char *path)
117 {
118 imv_t *imv;
119
120 imv = tnc_imv_create(name, path);
121 if (!imv)
122 {
123 return FALSE;
124 }
125 if (!add(this, imv))
126 {
127 imv->destroy(imv);
128 return FALSE;
129 }
130 DBG1(DBG_TNC, "IMV %u \"%s\" loaded from '%s'", imv->get_id(imv), name, path);
131 return TRUE;
132 }
133
134 METHOD(imv_manager_t, load_from_functions, bool,
135 private_tnc_imv_manager_t *this, char *name,
136 TNC_IMV_InitializePointer initialize,
137 TNC_IMV_NotifyConnectionChangePointer notify_connection_change,
138 TNC_IMV_ReceiveMessagePointer receive_message,
139 TNC_IMV_ReceiveMessageLongPointer receive_message_long,
140 TNC_IMV_SolicitRecommendationPointer solicit_recommendation,
141 TNC_IMV_BatchEndingPointer batch_ending,
142 TNC_IMV_TerminatePointer terminate,
143 TNC_IMV_ProvideBindFunctionPointer provide_bind_function)
144 {
145 imv_t *imv;
146
147 imv = tnc_imv_create_from_functions(name,
148 initialize,notify_connection_change,
149 receive_message, receive_message_long,
150 solicit_recommendation, batch_ending,
151 terminate, provide_bind_function);
152 if (!imv)
153 {
154 return FALSE;
155 }
156 if (!add(this, imv))
157 {
158 imv->destroy(imv);
159 return FALSE;
160 }
161 DBG1(DBG_TNC, "IMV %u \"%s\" loaded", imv->get_id(imv), name);
162 return TRUE;
163 }
164
165 METHOD(imv_manager_t, is_registered, bool,
166 private_tnc_imv_manager_t *this, TNC_IMVID id)
167 {
168 enumerator_t *enumerator;
169 imv_t *imv;
170 bool found = FALSE;
171
172 enumerator = this->imvs->create_enumerator(this->imvs);
173 while (enumerator->enumerate(enumerator, &imv))
174 {
175 if (imv->has_id(imv, id))
176 {
177 found = TRUE;
178 break;
179 }
180 }
181 enumerator->destroy(enumerator);
182
183 return found;
184 }
185
186 METHOD(imv_manager_t, reserve_id, bool,
187 private_tnc_imv_manager_t *this, TNC_IMVID id, TNC_UInt32 *new_id)
188 {
189 enumerator_t *enumerator;
190 imv_t *imv;
191 bool found = FALSE;
192
193 enumerator = this->imvs->create_enumerator(this->imvs);
194 while (enumerator->enumerate(enumerator, &imv))
195 {
196 if (imv->get_id(imv))
197 {
198 found = TRUE;
199 *new_id = this->next_imv_id++;
200 imv->add_id(imv, *new_id);
201 DBG2(DBG_TNC, "additional ID %u reserved for IMV with primary ID %u",
202 *new_id, id);
203 break;
204 }
205 }
206 enumerator->destroy(enumerator);
207
208 return found;
209 }
210
211 METHOD(imv_manager_t, get_recommendation_policy, recommendation_policy_t,
212 private_tnc_imv_manager_t *this)
213 {
214 return this->policy;
215 }
216
217 METHOD(imv_manager_t, create_recommendations, recommendations_t*,
218 private_tnc_imv_manager_t *this)
219 {
220 return tnc_imv_recommendations_create(this->imvs);
221 }
222
223 METHOD(imv_manager_t, enforce_recommendation, bool,
224 private_tnc_imv_manager_t *this, TNC_IMV_Action_Recommendation rec,
225 TNC_IMV_Evaluation_Result eval)
226 {
227 char *group;
228 identification_t *id;
229 ike_sa_t *ike_sa;
230 auth_cfg_t *auth;
231 bool no_access = FALSE;
232
233 DBG1(DBG_TNC, "final recommendation is '%N' and evaluation is '%N'",
234 TNC_IMV_Action_Recommendation_names, rec,
235 TNC_IMV_Evaluation_Result_names, eval);
236
237 switch (rec)
238 {
239 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
240 group = "allow";
241 break;
242 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
243 group = "isolate";
244 break;
245 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
246 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
247 default:
248 group = "no access";
249 no_access = TRUE;
250 break;
251 }
252
253 ike_sa = charon->bus->get_sa(charon->bus);
254 if (!ike_sa)
255 {
256 DBG1(DBG_TNC, "policy enforcement point did not find IKE_SA");
257 return FALSE;
258 }
259
260 id = ike_sa->get_other_id(ike_sa);
261 DBG0(DBG_TNC, "policy enforced on peer '%Y' is '%s'", id, group);
262
263 if (no_access)
264 {
265 return FALSE;
266 }
267 else
268 {
269 auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
270 id = identification_create_from_string(group);
271 auth->add(auth, AUTH_RULE_GROUP, id);
272 DBG1(DBG_TNC, "policy enforcement point added group membership '%s'",
273 group);
274 }
275 return TRUE;
276 }
277
278
279 METHOD(imv_manager_t, notify_connection_change, void,
280 private_tnc_imv_manager_t *this, TNC_ConnectionID id,
281 TNC_ConnectionState state)
282 {
283 enumerator_t *enumerator;
284 imv_t *imv;
285
286 enumerator = this->imvs->create_enumerator(this->imvs);
287 while (enumerator->enumerate(enumerator, &imv))
288 {
289 if (imv->notify_connection_change)
290 {
291 imv->notify_connection_change(imv->get_id(imv), id, state);
292 }
293 }
294 enumerator->destroy(enumerator);
295 }
296
297 METHOD(imv_manager_t, set_message_types, TNC_Result,
298 private_tnc_imv_manager_t *this, TNC_IMVID id,
299 TNC_MessageTypeList supported_types,
300 TNC_UInt32 type_count)
301 {
302 enumerator_t *enumerator;
303 imv_t *imv;
304 TNC_Result result = TNC_RESULT_FATAL;
305
306 enumerator = this->imvs->create_enumerator(this->imvs);
307 while (enumerator->enumerate(enumerator, &imv))
308 {
309 if (id == imv->get_id(imv))
310 {
311 imv->set_message_types(imv, supported_types, type_count);
312 result = TNC_RESULT_SUCCESS;
313 break;
314 }
315 }
316 enumerator->destroy(enumerator);
317 return result;
318 }
319
320 METHOD(imv_manager_t, set_message_types_long, TNC_Result,
321 private_tnc_imv_manager_t *this, TNC_IMVID id,
322 TNC_VendorIDList supported_vids,
323 TNC_MessageSubtypeList supported_subtypes,
324 TNC_UInt32 type_count)
325 {
326 enumerator_t *enumerator;
327 imv_t *imv;
328 TNC_Result result = TNC_RESULT_FATAL;
329
330 enumerator = this->imvs->create_enumerator(this->imvs);
331 while (enumerator->enumerate(enumerator, &imv))
332 {
333 if (id == imv->get_id(imv))
334 {
335 imv->set_message_types_long(imv, supported_vids, supported_subtypes,
336 type_count);
337 result = TNC_RESULT_SUCCESS;
338 break;
339 }
340 }
341 enumerator->destroy(enumerator);
342 return result;
343 }
344
345 METHOD(imv_manager_t, solicit_recommendation, void,
346 private_tnc_imv_manager_t *this, TNC_ConnectionID id)
347 {
348 enumerator_t *enumerator;
349 imv_t *imv;
350
351 enumerator = this->imvs->create_enumerator(this->imvs);
352 while (enumerator->enumerate(enumerator, &imv))
353 {
354 imv->solicit_recommendation(imv->get_id(imv), id);
355 }
356 enumerator->destroy(enumerator);
357 }
358
359 METHOD(imv_manager_t, receive_message, void,
360 private_tnc_imv_manager_t *this, TNC_ConnectionID connection_id,
361 bool excl,
362 TNC_BufferReference msg,
363 TNC_UInt32 msg_len,
364 TNC_VendorID msg_vid,
365 TNC_MessageSubtype msg_subtype,
366 TNC_UInt32 src_imc_id,
367 TNC_UInt32 dst_imv_id)
368 {
369 bool type_supported = FALSE;
370 TNC_MessageType msg_type;
371 TNC_UInt32 msg_flags;
372 enumerator_t *enumerator;
373 imv_t *imv;
374
375 msg_type = (msg_vid << 8) | msg_subtype;
376
377 enumerator = this->imvs->create_enumerator(this->imvs);
378 while (enumerator->enumerate(enumerator, &imv))
379 {
380 if (imv->type_supported(imv, msg_vid, msg_subtype) &&
381 (!excl || (excl && imv->has_id(imv, dst_imv_id)) ))
382 {
383 if (imv->receive_message_long && src_imc_id)
384 {
385 type_supported = TRUE;
386 msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0;
387 imv->receive_message_long(imv->get_id(imv), connection_id,
388 msg_flags, msg, msg_len, msg_vid, msg_subtype,
389 src_imc_id, dst_imv_id);
390
391 }
392 else if (imv->receive_message && msg_vid <= TNC_VENDORID_ANY &&
393 msg_subtype <= TNC_SUBTYPE_ANY)
394 {
395 type_supported = TRUE;
396 msg_type = (msg_vid << 8) | msg_subtype;
397 imv->receive_message(imv->get_id(imv), connection_id,
398 msg, msg_len, msg_type);
399 }
400 }
401 }
402 enumerator->destroy(enumerator);
403 if (!type_supported)
404 {
405 DBG2(DBG_TNC, "message type 0x%06x/0x%08x not supported by any IMV",
406 msg_vid, msg_subtype);
407 }
408 }
409
410 METHOD(imv_manager_t, batch_ending, void,
411 private_tnc_imv_manager_t *this, TNC_ConnectionID id)
412 {
413 enumerator_t *enumerator;
414 imv_t *imv;
415
416 enumerator = this->imvs->create_enumerator(this->imvs);
417 while (enumerator->enumerate(enumerator, &imv))
418 {
419 if (imv->batch_ending)
420 {
421 imv->batch_ending(imv->get_id(imv), id);
422 }
423 }
424 enumerator->destroy(enumerator);
425 }
426
427
428 METHOD(imv_manager_t, destroy, void,
429 private_tnc_imv_manager_t *this)
430 {
431 imv_t *imv;
432
433 while (this->imvs->remove_last(this->imvs, (void**)&imv) == SUCCESS)
434 {
435 if (imv->terminate &&
436 imv->terminate(imv->get_id(imv)) != TNC_RESULT_SUCCESS)
437 {
438 DBG1(DBG_TNC, "IMV \"%s\" not terminated successfully",
439 imv->get_name(imv));
440 }
441 imv->destroy(imv);
442 }
443 this->imvs->destroy(this->imvs);
444 free(this);
445 }
446
447 /**
448 * Described in header.
449 */
450 imv_manager_t* tnc_imv_manager_create(void)
451 {
452 private_tnc_imv_manager_t *this;
453 recommendation_policy_t policy;
454
455 INIT(this,
456 .public = {
457 .add = _add,
458 .remove = _remove_, /* avoid name conflict with stdio.h */
459 .load = _load,
460 .load_from_functions = _load_from_functions,
461 .is_registered = _is_registered,
462 .reserve_id = _reserve_id,
463 .get_recommendation_policy = _get_recommendation_policy,
464 .create_recommendations = _create_recommendations,
465 .enforce_recommendation = _enforce_recommendation,
466 .notify_connection_change = _notify_connection_change,
467 .set_message_types = _set_message_types,
468 .set_message_types_long = _set_message_types_long,
469 .solicit_recommendation = _solicit_recommendation,
470 .receive_message = _receive_message,
471 .batch_ending = _batch_ending,
472 .destroy = _destroy,
473 },
474 .imvs = linked_list_create(),
475 .next_imv_id = 1,
476 );
477
478 policy = enum_from_name(recommendation_policy_names,
479 lib->settings->get_str(lib->settings,
480 "%s.plugins.tnc-imv.recommendation_policy", "default",
481 charon->name));
482 this->policy = (policy != -1) ? policy : RECOMMENDATION_POLICY_DEFAULT;
483 DBG1(DBG_TNC, "TNC recommendation policy is '%N'",
484 recommendation_policy_names, this->policy);
485
486 return &this->public;
487 }