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