initialize chunks and add debug output
[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_names.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'",
91 id, action_recommendation_names, rec, evaluation_result_names, eval);
92
93 enumerator = this->recs->create_enumerator(this->recs);
94 while (enumerator->enumerate(enumerator, &entry))
95 {
96 if (entry->id == id)
97 {
98 found = TRUE;
99 entry->have_recommendation = TRUE;
100 entry->rec = rec;
101 entry->eval = eval;
102 break;
103 }
104 }
105 enumerator->destroy(enumerator);
106 return found ? TNC_RESULT_SUCCESS : TNC_RESULT_FATAL;
107 }
108
109 METHOD(recommendations_t, have_recommendation, bool,
110 private_tnc_imv_recommendations_t *this, TNC_IMV_Action_Recommendation *rec,
111 TNC_IMV_Evaluation_Result *eval)
112 {
113 enumerator_t *enumerator;
114 recommendation_entry_t *entry;
115 recommendation_policy_t policy;
116 TNC_IMV_Action_Recommendation final_rec;
117 TNC_IMV_Evaluation_Result final_eval;
118 bool first = TRUE, incomplete = FALSE;
119
120 *rec = final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
121 *eval = final_eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
122
123 if (this->recs->get_count(this->recs) == 0)
124 {
125 DBG1(DBG_TNC, "there are no IMVs to make a recommendation");
126 return TRUE;
127 }
128 policy = charon->imvs->get_recommendation_policy(charon->imvs);
129
130 enumerator = this->recs->create_enumerator(this->recs);
131 while (enumerator->enumerate(enumerator, &entry))
132 {
133 if (!entry->have_recommendation)
134 {
135 incomplete = TRUE;
136 break;
137 }
138 if (first)
139 {
140 final_rec = entry->rec;
141 final_eval = entry->eval;
142 first = FALSE;
143 continue;
144 }
145 switch (policy)
146 {
147 case RECOMMENDATION_POLICY_DEFAULT:
148 switch (entry->rec)
149 {
150 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
151 final_rec = entry->rec;
152 break;
153 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
154 if (final_rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
155 {
156 final_rec = entry->rec;
157 };
158 break;
159 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
160 if (final_rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
161 {
162 final_rec = entry->rec;
163 };
164 break;
165 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
166 break;
167 }
168 switch (entry->eval)
169 {
170 case TNC_IMV_EVALUATION_RESULT_ERROR:
171 final_eval = entry->eval;
172 break;
173 case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR:
174 if (final_eval != TNC_IMV_EVALUATION_RESULT_ERROR)
175 {
176 final_eval = entry->eval;
177 }
178 break;
179 case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR:
180 if (final_eval != TNC_IMV_EVALUATION_RESULT_ERROR &&
181 final_eval != TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR)
182 {
183 final_eval = entry->eval;
184 }
185 break;
186 case TNC_IMV_EVALUATION_RESULT_COMPLIANT:
187 if (final_eval == TNC_IMV_EVALUATION_RESULT_DONT_KNOW)
188 {
189 final_eval = entry->eval;
190 }
191 break;
192 case TNC_IMV_EVALUATION_RESULT_DONT_KNOW:
193 break;
194 }
195 break;
196
197 case RECOMMENDATION_POLICY_ALL:
198 if (entry->rec != final_rec)
199 {
200 final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
201 }
202 if (entry->eval != final_eval)
203 {
204 final_eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
205 }
206 break;
207
208 case RECOMMENDATION_POLICY_ANY:
209 switch (entry->rec)
210 {
211 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
212 final_rec = entry->rec;
213 break;
214 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
215 if (final_rec != TNC_IMV_ACTION_RECOMMENDATION_ALLOW)
216 {
217 final_rec = entry->rec;
218 };
219 break;
220 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
221 if (final_rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
222 {
223 final_rec = entry->rec;
224 };
225 break;
226 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
227 break;
228 }
229 switch (entry->eval)
230 {
231 case TNC_IMV_EVALUATION_RESULT_COMPLIANT:
232 final_eval = entry->eval;
233 break;
234 case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR:
235 if (final_eval != TNC_IMV_EVALUATION_RESULT_COMPLIANT)
236 {
237 final_eval = entry->eval;
238 }
239 break;
240 case TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR:
241 if (final_eval != TNC_IMV_EVALUATION_RESULT_COMPLIANT &&
242 final_eval != TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR)
243 {
244 final_eval = entry->eval;
245 }
246 break;
247 case TNC_IMV_EVALUATION_RESULT_ERROR:
248 if (final_eval == TNC_IMV_EVALUATION_RESULT_DONT_KNOW)
249 {
250 final_eval = entry->eval;
251 }
252 break;
253 case TNC_IMV_EVALUATION_RESULT_DONT_KNOW:
254 break;
255 }
256 }
257 }
258 enumerator->destroy(enumerator);
259
260 if (incomplete)
261 {
262 return FALSE;
263 }
264 *rec = final_rec;
265 *eval = final_eval;
266 return TRUE;
267 }
268
269 METHOD(recommendations_t, get_preferred_language, chunk_t,
270 private_tnc_imv_recommendations_t *this)
271 {
272 return this->preferred_language;
273 }
274
275 METHOD(recommendations_t, set_preferred_language, void,
276 private_tnc_imv_recommendations_t *this, chunk_t pref_lang)
277 {
278 free(this->preferred_language.ptr);
279 this->preferred_language = chunk_clone(pref_lang);
280 }
281
282 METHOD(recommendations_t, set_reason_string, TNC_Result,
283 private_tnc_imv_recommendations_t *this, TNC_IMVID id, chunk_t reason)
284 {
285 enumerator_t *enumerator;
286 recommendation_entry_t *entry;
287 bool found = FALSE;
288
289 DBG2(DBG_TNC, "IMV %u is setting reason string to '%.*s'",
290 id, reason.len, reason.ptr);
291
292 enumerator = this->recs->create_enumerator(this->recs);
293 while (enumerator->enumerate(enumerator, &entry))
294 {
295 if (entry->id == id)
296 {
297 found = TRUE;
298 free(entry->reason.ptr);
299 entry->reason = chunk_clone(reason);
300 break;
301 }
302 }
303 enumerator->destroy(enumerator);
304 return found ? TNC_RESULT_SUCCESS : TNC_RESULT_INVALID_PARAMETER;
305 }
306
307 METHOD(recommendations_t, set_reason_language, TNC_Result,
308 private_tnc_imv_recommendations_t *this, TNC_IMVID id, chunk_t reason_lang)
309 {
310 enumerator_t *enumerator;
311 recommendation_entry_t *entry;
312 bool found = FALSE;
313
314 DBG2(DBG_TNC, "IMV %u is setting reason language to '%.*s'",
315 id, reason_lang.len, reason_lang.ptr);
316
317 enumerator = this->recs->create_enumerator(this->recs);
318 while (enumerator->enumerate(enumerator, &entry))
319 {
320 if (entry->id == id)
321 {
322 found = TRUE;
323 free(entry->reason_language.ptr);
324 entry->reason_language = chunk_clone(reason_lang);
325 break;
326 }
327 }
328 enumerator->destroy(enumerator);
329 return found ? TNC_RESULT_SUCCESS : TNC_RESULT_INVALID_PARAMETER;
330 }
331
332 METHOD(recommendations_t, destroy, void,
333 private_tnc_imv_recommendations_t *this)
334 {
335 recommendation_entry_t *entry;
336
337 while (this->recs->remove_last(this->recs, (void**)&entry) == SUCCESS)
338 {
339 free(entry->reason.ptr);
340 free(entry->reason_language.ptr);
341 free(entry);
342 }
343 this->recs->destroy(this->recs);
344 free(this->preferred_language.ptr);
345 free(this);
346 }
347
348 /**
349 * Described in header.
350 */
351 recommendations_t* tnc_imv_recommendations_create(linked_list_t *imv_list)
352 {
353 private_tnc_imv_recommendations_t *this;
354 recommendation_entry_t *entry;
355 enumerator_t *enumerator;
356 imv_t *imv;
357
358 INIT(this,
359 .public = {
360 .provide_recommendation = _provide_recommendation,
361 .have_recommendation = _have_recommendation,
362 .get_preferred_language = _get_preferred_language,
363 .set_preferred_language = _set_preferred_language,
364 .set_reason_string = _set_reason_string,
365 .set_reason_language = _set_reason_language,
366
367 .destroy = _destroy,
368 },
369 .recs = linked_list_create(),
370 );
371
372 enumerator = imv_list->create_enumerator(imv_list);
373 while (enumerator->enumerate(enumerator, &imv))
374 {
375 entry = malloc_thing(recommendation_entry_t);
376 entry->id = imv->get_id(imv);
377 entry->have_recommendation = FALSE;
378 entry->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
379 entry->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
380 entry->reason = chunk_empty;
381 entry->reason_language = chunk_empty;
382 this->recs->insert_last(this->recs, entry);
383 }
384 enumerator->destroy(enumerator);
385
386 return &this->public;
387 }