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