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