added TNC_TNCS_ReserveAdditionalIMVID() function
[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 TNC_BufferReference message,
335 TNC_UInt32 message_len,
336 TNC_MessageType message_type)
337 {
338 bool type_supported = FALSE;
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->receive_message && imv->type_supported(imv, message_type))
346 {
347 type_supported = TRUE;
348 imv->receive_message(imv->get_id(imv), connection_id,
349 message, message_len, message_type);
350 }
351 }
352 enumerator->destroy(enumerator);
353 if (!type_supported)
354 {
355 DBG2(DBG_TNC, "message type 0x%08x not supported by any IMV", message_type);
356 }
357 }
358
359 METHOD(imv_manager_t, batch_ending, void,
360 private_tnc_imv_manager_t *this, TNC_ConnectionID id)
361 {
362 enumerator_t *enumerator;
363 imv_t *imv;
364
365 enumerator = this->imvs->create_enumerator(this->imvs);
366 while (enumerator->enumerate(enumerator, &imv))
367 {
368 if (imv->batch_ending)
369 {
370 imv->batch_ending(imv->get_id(imv), id);
371 }
372 }
373 enumerator->destroy(enumerator);
374 }
375
376
377 METHOD(imv_manager_t, destroy, void,
378 private_tnc_imv_manager_t *this)
379 {
380 imv_t *imv;
381
382 while (this->imvs->remove_last(this->imvs, (void**)&imv) == SUCCESS)
383 {
384 if (imv->terminate &&
385 imv->terminate(imv->get_id(imv)) != TNC_RESULT_SUCCESS)
386 {
387 DBG1(DBG_TNC, "IMV \"%s\" not terminated successfully",
388 imv->get_name(imv));
389 }
390 imv->destroy(imv);
391 }
392 this->imvs->destroy(this->imvs);
393 free(this);
394 }
395
396 /**
397 * Described in header.
398 */
399 imv_manager_t* tnc_imv_manager_create(void)
400 {
401 private_tnc_imv_manager_t *this;
402 recommendation_policy_t policy;
403
404 INIT(this,
405 .public = {
406 .add = _add,
407 .remove = _remove_, /* avoid name conflict with stdio.h */
408 .load = _load,
409 .is_registered = _is_registered,
410 .reserve_id = _reserve_id,
411 .get_recommendation_policy = _get_recommendation_policy,
412 .create_recommendations = _create_recommendations,
413 .enforce_recommendation = _enforce_recommendation,
414 .notify_connection_change = _notify_connection_change,
415 .set_message_types = _set_message_types,
416 .set_message_types_long = _set_message_types_long,
417 .solicit_recommendation = _solicit_recommendation,
418 .receive_message = _receive_message,
419 .batch_ending = _batch_ending,
420 .destroy = _destroy,
421 },
422 .imvs = linked_list_create(),
423 .next_imv_id = 1,
424 );
425
426 policy = enum_from_name(recommendation_policy_names,
427 lib->settings->get_str(lib->settings,
428 "charon.plugins.tnc-imv.recommendation_policy", "default"));
429 this->policy = (policy != -1) ? policy : RECOMMENDATION_POLICY_DEFAULT;
430 DBG1(DBG_TNC, "TNC recommendation policy is '%N'",
431 recommendation_policy_names, this->policy);
432
433 return &this->public;
434 }