Moved data structures to new collections subfolder
[strongswan.git] / src / libcharon / plugins / tnc_imv / tnc_imv_recommendations.c
1 /*
2 * Copyright (C) 2010-2012 Andreas Steffen
3 * 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 <tncifimv.h>
17 #include <tncif_names.h>
18
19 #include <tnc/tnc.h>
20 #include <tnc/imv/imv.h>
21 #include <tnc/imv/imv_manager.h>
22 #include <tnc/imv/imv_recommendations.h>
23
24 #include <debug.h>
25 #include <collections/linked_list.h>
26
27 typedef struct private_tnc_imv_recommendations_t private_tnc_imv_recommendations_t;
28 typedef struct recommendation_entry_t recommendation_entry_t;
29
30 /**
31 * Recommendation entry
32 */
33 struct recommendation_entry_t {
34
35 /**
36 * IMV ID
37 */
38 TNC_IMVID id;
39
40 /**
41 * Received a recommendation message from this IMV?
42 */
43 bool have_recommendation;
44
45 /**
46 * Action Recommendation provided by IMV instance
47 */
48 TNC_IMV_Action_Recommendation rec;
49
50 /**
51 * Evaluation Result provided by IMV instance
52 */
53 TNC_IMV_Evaluation_Result eval;
54
55 /**
56 * Reason string provided by IMV instance
57 */
58 chunk_t reason;
59
60 /**
61 * Reason language provided by IMV instance
62 */
63 chunk_t reason_language;
64 };
65
66 /**
67 * Private data of a recommendations_t object.
68 */
69 struct private_tnc_imv_recommendations_t {
70
71 /**
72 * Public members of recommendations_t.
73 */
74 recommendations_t public;
75
76 /**
77 * list of recommendations and evaluations provided by IMVs
78 */
79 linked_list_t *recs;
80
81 /**
82 * Preferred language for remediation messages
83 */
84 chunk_t preferred_language;
85 };
86
87 METHOD(recommendations_t, provide_recommendation, TNC_Result,
88 private_tnc_imv_recommendations_t* this, TNC_IMVID id,
89 TNC_IMV_Action_Recommendation rec,
90 TNC_IMV_Evaluation_Result eval)
91 {
92 enumerator_t *enumerator;
93 recommendation_entry_t *entry;
94 bool found = FALSE;
95
96 DBG2(DBG_TNC, "IMV %u provides recommendation '%N' and evaluation '%N'", id,
97 TNC_IMV_Action_Recommendation_names, rec,
98 TNC_IMV_Evaluation_Result_names, eval);
99
100 enumerator = this->recs->create_enumerator(this->recs);
101 while (enumerator->enumerate(enumerator, &entry))
102 {
103 if (entry->id == id)
104 {
105 found = TRUE;
106 entry->have_recommendation = TRUE;
107 entry->rec = rec;
108 entry->eval = eval;
109 break;
110 }
111 }
112 enumerator->destroy(enumerator);
113 return found ? TNC_RESULT_SUCCESS : TNC_RESULT_FATAL;
114 }
115
116 METHOD(recommendations_t, have_recommendation, bool,
117 private_tnc_imv_recommendations_t *this, TNC_IMV_Action_Recommendation *rec,
118 TNC_IMV_Evaluation_Result *eval)
119 {
120 enumerator_t *enumerator;
121 recommendation_entry_t *entry;
122 recommendation_policy_t policy;
123 TNC_IMV_Action_Recommendation final_rec;
124 TNC_IMV_Evaluation_Result final_eval;
125 bool first = TRUE, incomplete = FALSE;
126
127 final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
128 final_eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
129 if (rec && eval)
130 {
131 *rec = final_rec;
132 *eval = final_eval;
133 }
134
135 if (this->recs->get_count(this->recs) == 0)
136 {
137 DBG1(DBG_TNC, "there are no IMVs to make a recommendation");
138 return TRUE;
139 }
140 policy = tnc->imvs->get_recommendation_policy(tnc->imvs);
141
142 enumerator = this->recs->create_enumerator(this->recs);
143 while (enumerator->enumerate(enumerator, &entry))
144 {
145 if (!entry->have_recommendation)
146 {
147 incomplete = TRUE;
148 break;
149 }
150 if (first)
151 {
152 final_rec = entry->rec;
153 final_eval = entry->eval;
154 first = FALSE;
155 continue;
156 }
157 switch (policy)
158 {
159 case RECOMMENDATION_POLICY_DEFAULT:
160 switch (entry->rec)
161 {
162 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
163 final_rec = entry->rec;
164 break;
165 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
166 if (final_rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
167 {
168 final_rec = entry->rec;
169 };
170 break;
171 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
172 if (final_rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
173 {
174 final_rec = entry->rec;
175 };
176 break;
177 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
178 break;
179 }
180 switch (entry->eval)
181 {
182 case TNC_IMV_EVALUATION_RESULT_ERROR:
183 final_eval = entry->eval;
184 break;
185 case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR:
186 if (final_eval != TNC_IMV_EVALUATION_RESULT_ERROR)
187 {
188 final_eval = entry->eval;
189 }
190 break;
191 case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR:
192 if (final_eval != TNC_IMV_EVALUATION_RESULT_ERROR &&
193 final_eval != TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR)
194 {
195 final_eval = entry->eval;
196 }
197 break;
198 case TNC_IMV_EVALUATION_RESULT_COMPLIANT:
199 if (final_eval == TNC_IMV_EVALUATION_RESULT_DONT_KNOW)
200 {
201 final_eval = entry->eval;
202 }
203 break;
204 case TNC_IMV_EVALUATION_RESULT_DONT_KNOW:
205 break;
206 }
207 break;
208
209 case RECOMMENDATION_POLICY_ALL:
210 if (entry->rec != final_rec)
211 {
212 final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
213 }
214 if (entry->eval != final_eval)
215 {
216 final_eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
217 }
218 break;
219
220 case RECOMMENDATION_POLICY_ANY:
221 switch (entry->rec)
222 {
223 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
224 final_rec = entry->rec;
225 break;
226 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
227 if (final_rec != TNC_IMV_ACTION_RECOMMENDATION_ALLOW)
228 {
229 final_rec = entry->rec;
230 };
231 break;
232 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
233 if (final_rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
234 {
235 final_rec = entry->rec;
236 };
237 break;
238 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
239 break;
240 }
241 switch (entry->eval)
242 {
243 case TNC_IMV_EVALUATION_RESULT_COMPLIANT:
244 final_eval = entry->eval;
245 break;
246 case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR:
247 if (final_eval != TNC_IMV_EVALUATION_RESULT_COMPLIANT)
248 {
249 final_eval = entry->eval;
250 }
251 break;
252 case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR:
253 if (final_eval != TNC_IMV_EVALUATION_RESULT_COMPLIANT &&
254 final_eval != TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR)
255 {
256 final_eval = entry->eval;
257 }
258 break;
259 case TNC_IMV_EVALUATION_RESULT_ERROR:
260 if (final_eval == TNC_IMV_EVALUATION_RESULT_DONT_KNOW)
261 {
262 final_eval = entry->eval;
263 }
264 break;
265 case TNC_IMV_EVALUATION_RESULT_DONT_KNOW:
266 break;
267 }
268 }
269 }
270 enumerator->destroy(enumerator);
271
272 if (incomplete)
273 {
274 return FALSE;
275 }
276 if (rec && eval)
277 {
278 *rec = final_rec;
279 *eval = final_eval;
280 }
281 return TRUE;
282 }
283
284 METHOD(recommendations_t, clear_recommendation, void,
285 private_tnc_imv_recommendations_t *this)
286 {
287 enumerator_t *enumerator;
288 recommendation_entry_t *entry;
289
290 enumerator = this->recs->create_enumerator(this->recs);
291 while (enumerator->enumerate(enumerator, &entry))
292 {
293 entry->have_recommendation = FALSE;
294 entry->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
295 entry->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
296 chunk_clear(&entry->reason);
297 chunk_clear(&entry->reason_language);
298 }
299 enumerator->destroy(enumerator);
300 }
301
302 METHOD(recommendations_t, get_preferred_language, chunk_t,
303 private_tnc_imv_recommendations_t *this)
304 {
305 return this->preferred_language;
306 }
307
308 METHOD(recommendations_t, set_preferred_language, void,
309 private_tnc_imv_recommendations_t *this, chunk_t pref_lang)
310 {
311 free(this->preferred_language.ptr);
312 this->preferred_language = chunk_clone(pref_lang);
313 }
314
315 METHOD(recommendations_t, set_reason_string, TNC_Result,
316 private_tnc_imv_recommendations_t *this, TNC_IMVID id, chunk_t reason)
317 {
318 enumerator_t *enumerator;
319 recommendation_entry_t *entry;
320 bool found = FALSE;
321
322 DBG2(DBG_TNC, "IMV %u is setting reason string to '%.*s'",
323 id, (int)reason.len, reason.ptr);
324
325 enumerator = this->recs->create_enumerator(this->recs);
326 while (enumerator->enumerate(enumerator, &entry))
327 {
328 if (entry->id == id)
329 {
330 found = TRUE;
331 free(entry->reason.ptr);
332 entry->reason = chunk_clone(reason);
333 break;
334 }
335 }
336 enumerator->destroy(enumerator);
337 return found ? TNC_RESULT_SUCCESS : TNC_RESULT_INVALID_PARAMETER;
338 }
339
340 METHOD(recommendations_t, set_reason_language, TNC_Result,
341 private_tnc_imv_recommendations_t *this, TNC_IMVID id, chunk_t reason_lang)
342 {
343 enumerator_t *enumerator;
344 recommendation_entry_t *entry;
345 bool found = FALSE;
346
347 DBG2(DBG_TNC, "IMV %u is setting reason language to '%.*s'",
348 id, (int)reason_lang.len, reason_lang.ptr);
349
350 enumerator = this->recs->create_enumerator(this->recs);
351 while (enumerator->enumerate(enumerator, &entry))
352 {
353 if (entry->id == id)
354 {
355 found = TRUE;
356 free(entry->reason_language.ptr);
357 entry->reason_language = chunk_clone(reason_lang);
358 break;
359 }
360 }
361 enumerator->destroy(enumerator);
362 return found ? TNC_RESULT_SUCCESS : TNC_RESULT_INVALID_PARAMETER;
363 }
364
365 /**
366 * Enumerate reason and reason_language, not recommendation entries
367 */
368 static bool reason_filter(void *null, recommendation_entry_t **entry,
369 TNC_IMVID *id, void *i2, chunk_t *reason, void *i3,
370 chunk_t *reason_language)
371 {
372 if ((*entry)->reason.len)
373 {
374 *id = (*entry)->id;
375 *reason = (*entry)->reason;
376 *reason_language = (*entry)->reason_language;
377 return TRUE;
378 }
379 else
380 {
381 return FALSE;
382 }
383 }
384
385 METHOD(recommendations_t, create_reason_enumerator, enumerator_t*,
386 private_tnc_imv_recommendations_t *this)
387 {
388 return enumerator_create_filter(this->recs->create_enumerator(this->recs),
389 (void*)reason_filter, NULL, NULL);
390 }
391
392 METHOD(recommendations_t, destroy, void,
393 private_tnc_imv_recommendations_t *this)
394 {
395 recommendation_entry_t *entry;
396
397 while (this->recs->remove_last(this->recs, (void**)&entry) == SUCCESS)
398 {
399 free(entry->reason.ptr);
400 free(entry->reason_language.ptr);
401 free(entry);
402 }
403 this->recs->destroy(this->recs);
404 free(this->preferred_language.ptr);
405 free(this);
406 }
407
408 /**
409 * Described in header.
410 */
411 recommendations_t* tnc_imv_recommendations_create(linked_list_t *imv_list)
412 {
413 private_tnc_imv_recommendations_t *this;
414 recommendation_entry_t *entry;
415 enumerator_t *enumerator;
416 imv_t *imv;
417
418 INIT(this,
419 .public = {
420 .provide_recommendation = _provide_recommendation,
421 .have_recommendation = _have_recommendation,
422 .clear_recommendation = _clear_recommendation,
423 .get_preferred_language = _get_preferred_language,
424 .set_preferred_language = _set_preferred_language,
425 .set_reason_string = _set_reason_string,
426 .set_reason_language = _set_reason_language,
427 .create_reason_enumerator = _create_reason_enumerator,
428 .destroy = _destroy,
429 },
430 .recs = linked_list_create(),
431 );
432
433 enumerator = imv_list->create_enumerator(imv_list);
434 while (enumerator->enumerate(enumerator, &imv))
435 {
436 entry = malloc_thing(recommendation_entry_t);
437 entry->id = imv->get_id(imv);
438 entry->have_recommendation = FALSE;
439 entry->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
440 entry->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
441 entry->reason = chunk_empty;
442 entry->reason_language = chunk_empty;
443 this->recs->insert_last(this->recs, entry);
444 }
445 enumerator->destroy(enumerator);
446
447 return &this->public;
448 }