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