moved imv_manager to libtnccs
[strongswan.git] / src / libcharon / tnc / tnccs / tnccs_manager.c
1 /*
2 * Copyright (C) 2010 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 #define USE_TNC
17
18 #include "tnccs_manager.h"
19
20 #include <imc/imc_manager.h>
21 #include <imv/imv_manager.h>
22
23 #include <debug.h>
24 #include <daemon.h>
25 #include <utils/linked_list.h>
26 #include <threading/rwlock.h>
27
28 typedef struct private_tnccs_manager_t private_tnccs_manager_t;
29 typedef struct tnccs_entry_t tnccs_entry_t;
30 typedef struct tnccs_connection_entry_t tnccs_connection_entry_t;
31
32 /**
33 * TNCCS constructor entry
34 */
35 struct tnccs_entry_t {
36
37 /**
38 * TNCCS protocol type
39 */
40 tnccs_type_t type;
41
42 /**
43 * constructor function to create instance
44 */
45 tnccs_constructor_t constructor;
46 };
47
48 /**
49 * TNCCS connection entry
50 */
51 struct tnccs_connection_entry_t {
52
53 /**
54 * TNCCS connection ID
55 */
56 TNC_ConnectionID id;
57
58 /**
59 * TNCCS instance
60 */
61 tnccs_t *tnccs;
62
63 /**
64 * TNCCS send message function
65 */
66 tnccs_send_message_t send_message;
67
68 /**
69 * TNCCS request handshake retry flag
70 */
71 bool *request_handshake_retry;
72
73 /**
74 * collection of IMV recommendations
75 */
76 recommendations_t *recs;
77 };
78
79 /**
80 * private data of tnccs_manager
81 */
82 struct private_tnccs_manager_t {
83
84 /**
85 * public functions
86 */
87 tnccs_manager_t public;
88
89 /**
90 * list of TNCCS protocol entries
91 */
92 linked_list_t *protocols;
93
94 /**
95 * rwlock to lock the TNCCS protocol entries
96 */
97 rwlock_t *protocol_lock;
98
99 /**
100 * connection ID counter
101 */
102 TNC_ConnectionID connection_id;
103
104 /**
105 * list of TNCCS connection entries
106 */
107 linked_list_t *connections;
108
109 /**
110 * rwlock to lock TNCCS connection entries
111 */
112 rwlock_t *connection_lock;
113
114 /**
115 * TNC IMC manager controlling Integrity Measurement Collectors
116 */
117 imc_manager_t *imcs;
118
119 /**
120 * TNC IMV manager controlling Integrity Measurement Verifiers
121 */
122 imv_manager_t *imvs;
123
124 };
125
126 METHOD(tnccs_manager_t, add_method, void,
127 private_tnccs_manager_t *this, tnccs_type_t type,
128 tnccs_constructor_t constructor)
129 {
130 tnccs_entry_t *entry;
131
132 entry = malloc_thing(tnccs_entry_t);
133 entry->type = type;
134 entry->constructor = constructor;
135
136 this->protocol_lock->write_lock(this->protocol_lock);
137 this->protocols->insert_last(this->protocols, entry);
138 this->protocol_lock->unlock(this->protocol_lock);
139 }
140
141 METHOD(tnccs_manager_t, remove_method, void,
142 private_tnccs_manager_t *this, tnccs_constructor_t constructor)
143 {
144 enumerator_t *enumerator;
145 tnccs_entry_t *entry;
146
147 this->protocol_lock->write_lock(this->protocol_lock);
148 enumerator = this->protocols->create_enumerator(this->protocols);
149 while (enumerator->enumerate(enumerator, &entry))
150 {
151 if (constructor == entry->constructor)
152 {
153 this->protocols->remove_at(this->protocols, enumerator);
154 free(entry);
155 }
156 }
157 enumerator->destroy(enumerator);
158 this->protocol_lock->unlock(this->protocol_lock);
159 }
160
161 METHOD(tnccs_manager_t, create_instance, tnccs_t*,
162 private_tnccs_manager_t *this, tnccs_type_t type, bool is_server)
163 {
164 enumerator_t *enumerator;
165 tnccs_entry_t *entry;
166 tnccs_t *protocol = NULL;
167
168 this->protocol_lock->read_lock(this->protocol_lock);
169 enumerator = this->protocols->create_enumerator(this->protocols);
170 while (enumerator->enumerate(enumerator, &entry))
171 {
172 if (type == entry->type)
173 {
174 protocol = entry->constructor(is_server);
175 if (protocol)
176 {
177 break;
178 }
179 }
180 }
181 enumerator->destroy(enumerator);
182 this->protocol_lock->unlock(this->protocol_lock);
183
184 return protocol;
185 }
186
187 METHOD(tnccs_manager_t, create_connection, TNC_ConnectionID,
188 private_tnccs_manager_t *this, tnccs_t *tnccs,
189 tnccs_send_message_t send_message, bool* request_handshake_retry,
190 recommendations_t **recs)
191 {
192 tnccs_connection_entry_t *entry;
193
194 entry = malloc_thing(tnccs_connection_entry_t);
195 entry->tnccs = tnccs;
196 entry->send_message = send_message;
197 entry->request_handshake_retry = request_handshake_retry;
198 if (recs)
199 {
200 /* we assume a TNC Server needing recommendations from IMVs */
201 if (!this->imvs)
202 {
203 this->imvs = lib->get(lib, "imv-manager");
204 }
205 if (!this->imvs)
206 {
207 DBG1(DBG_TNC, "no IMV manager available!");
208 free(entry);
209 return 0;
210 }
211 entry->recs = this->imvs->create_recommendations(this->imvs);
212 *recs = entry->recs;
213 }
214 else
215 {
216 /* we assume a TNC Client */
217 if (!this->imcs)
218 {
219 this->imcs = lib->get(lib, "imc-manager");
220 }
221 if (!this->imcs)
222 {
223 DBG1(DBG_TNC, "no IMC manager available!");
224 free(entry);
225 return 0;
226 }
227 entry->recs = NULL;
228 }
229 this->connection_lock->write_lock(this->connection_lock);
230 entry->id = ++this->connection_id;
231 this->connections->insert_last(this->connections, entry);
232 this->connection_lock->unlock(this->connection_lock);
233
234 DBG1(DBG_TNC, "assigned TNCCS Connection ID %u", entry->id);
235 return entry->id;
236 }
237
238 METHOD(tnccs_manager_t, remove_connection, void,
239 private_tnccs_manager_t *this, TNC_ConnectionID id, bool is_server)
240 {
241 enumerator_t *enumerator;
242 tnccs_connection_entry_t *entry;
243
244 if (is_server)
245 {
246 if (this->imvs)
247 {
248 this->imvs->notify_connection_change(this->imvs, id,
249 TNC_CONNECTION_STATE_DELETE);
250 }
251 }
252 else
253 {
254 if (this->imcs)
255 {
256 this->imcs->notify_connection_change(this->imcs, id,
257 TNC_CONNECTION_STATE_DELETE);
258 }
259 }
260
261 this->connection_lock->write_lock(this->connection_lock);
262 enumerator = this->connections->create_enumerator(this->connections);
263 while (enumerator->enumerate(enumerator, &entry))
264 {
265 if (id == entry->id)
266 {
267 this->connections->remove_at(this->connections, enumerator);
268 if (entry->recs)
269 {
270 entry->recs->destroy(entry->recs);
271 }
272 free(entry);
273 DBG1(DBG_TNC, "removed TNCCS Connection ID %u", id);
274 }
275 }
276 enumerator->destroy(enumerator);
277 this->connection_lock->unlock(this->connection_lock);
278 }
279
280 METHOD(tnccs_manager_t, request_handshake_retry, TNC_Result,
281 private_tnccs_manager_t *this, bool is_imc, TNC_UInt32 imcv_id,
282 TNC_ConnectionID id,
283 TNC_RetryReason reason)
284 {
285 enumerator_t *enumerator;
286 tnccs_connection_entry_t *entry;
287
288 if (id == TNC_CONNECTIONID_ANY)
289 {
290 DBG2(DBG_TNC, "%s %u requests handshake retry for all connections "
291 "(reason: %u)", is_imc ? "IMC":"IMV", reason);
292 }
293 else
294 {
295 DBG2(DBG_TNC, "%s %u requests handshake retry for Connection ID %u "
296 "(reason: %u)", is_imc ? "IMC":"IMV", imcv_id, id, reason);
297 }
298 this->connection_lock->read_lock(this->connection_lock);
299 enumerator = this->connections->create_enumerator(this->connections);
300 while (enumerator->enumerate(enumerator, &entry))
301 {
302 if (id == TNC_CONNECTIONID_ANY || id == entry->id)
303 {
304 *entry->request_handshake_retry = TRUE;
305 break;
306 }
307 }
308 enumerator->destroy(enumerator);
309 this->connection_lock->unlock(this->connection_lock);
310
311 return TNC_RESULT_SUCCESS;
312 }
313
314 METHOD(tnccs_manager_t, send_message, TNC_Result,
315 private_tnccs_manager_t *this, TNC_IMCID imc_id, TNC_IMVID imv_id,
316 TNC_ConnectionID id,
317 TNC_BufferReference msg,
318 TNC_UInt32 msg_len,
319 TNC_MessageType msg_type)
320
321 {
322 enumerator_t *enumerator;
323 tnccs_connection_entry_t *entry;
324 tnccs_send_message_t send_message = NULL;
325 tnccs_t *tnccs = NULL;
326 TNC_VendorID msg_vid;
327 TNC_MessageSubtype msg_subtype;
328
329 msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY;
330 msg_subtype = msg_type & TNC_SUBTYPE_ANY;
331
332 if (msg_vid == TNC_VENDORID_ANY || msg_subtype == TNC_SUBTYPE_ANY)
333 {
334 DBG1(DBG_TNC, "not sending message of invalid type 0x%08x", msg_type);
335 return TNC_RESULT_INVALID_PARAMETER;
336 }
337
338 this->connection_lock->read_lock(this->connection_lock);
339 enumerator = this->connections->create_enumerator(this->connections);
340 while (enumerator->enumerate(enumerator, &entry))
341 {
342 if (id == entry->id)
343 {
344 tnccs = entry->tnccs;
345 send_message = entry->send_message;
346 break;
347 }
348 }
349 enumerator->destroy(enumerator);
350 this->connection_lock->unlock(this->connection_lock);
351
352 if (tnccs && send_message)
353 {
354 return send_message(tnccs, imc_id, imv_id, msg, msg_len, msg_type);
355 }
356 return TNC_RESULT_FATAL;
357 }
358
359 METHOD(tnccs_manager_t, provide_recommendation, TNC_Result,
360 private_tnccs_manager_t *this, TNC_IMVID imv_id,
361 TNC_ConnectionID id,
362 TNC_IMV_Action_Recommendation rec,
363 TNC_IMV_Evaluation_Result eval)
364 {
365 enumerator_t *enumerator;
366 tnccs_connection_entry_t *entry;
367 recommendations_t *recs = NULL;
368
369 this->connection_lock->read_lock(this->connection_lock);
370 enumerator = this->connections->create_enumerator(this->connections);
371 while (enumerator->enumerate(enumerator, &entry))
372 {
373 if (id == entry->id)
374 {
375 recs = entry->recs;
376 break;
377 }
378 }
379 enumerator->destroy(enumerator);
380 this->connection_lock->unlock(this->connection_lock);
381
382 if (recs)
383 {
384 recs->provide_recommendation(recs, imv_id, rec, eval);
385 return TNC_RESULT_SUCCESS;
386 }
387 return TNC_RESULT_FATAL;
388 }
389
390 METHOD(tnccs_manager_t, get_attribute, TNC_Result,
391 private_tnccs_manager_t *this, TNC_IMVID imv_id,
392 TNC_ConnectionID id,
393 TNC_AttributeID attribute_id,
394 TNC_UInt32 buffer_len,
395 TNC_BufferReference buffer,
396 TNC_UInt32 *out_value_len)
397 {
398 enumerator_t *enumerator;
399 tnccs_connection_entry_t *entry;
400 recommendations_t *recs = NULL;
401
402 if (id == TNC_CONNECTIONID_ANY ||
403 attribute_id != TNC_ATTRIBUTEID_PREFERRED_LANGUAGE)
404 {
405 return TNC_RESULT_INVALID_PARAMETER;
406 }
407
408 this->connection_lock->read_lock(this->connection_lock);
409 enumerator = this->connections->create_enumerator(this->connections);
410 while (enumerator->enumerate(enumerator, &entry))
411 {
412 if (id == entry->id)
413 {
414 recs = entry->recs;
415 break;
416 }
417 }
418 enumerator->destroy(enumerator);
419 this->connection_lock->unlock(this->connection_lock);
420
421 if (recs)
422 {
423 chunk_t pref_lang;
424
425 pref_lang = recs->get_preferred_language(recs);
426 if (pref_lang.len == 0)
427 {
428 return TNC_RESULT_INVALID_PARAMETER;
429 }
430 *out_value_len = pref_lang.len;
431 if (buffer && buffer_len >= pref_lang.len)
432 {
433 memcpy(buffer, pref_lang.ptr, pref_lang.len);
434 }
435 return TNC_RESULT_SUCCESS;
436 }
437 return TNC_RESULT_INVALID_PARAMETER;
438 }
439
440 METHOD(tnccs_manager_t, set_attribute, TNC_Result,
441 private_tnccs_manager_t *this, TNC_IMVID imv_id,
442 TNC_ConnectionID id,
443 TNC_AttributeID attribute_id,
444 TNC_UInt32 buffer_len,
445 TNC_BufferReference buffer)
446 {
447 enumerator_t *enumerator;
448 tnccs_connection_entry_t *entry;
449 recommendations_t *recs = NULL;
450
451 if (id == TNC_CONNECTIONID_ANY ||
452 (attribute_id != TNC_ATTRIBUTEID_REASON_STRING &&
453 attribute_id != TNC_ATTRIBUTEID_REASON_LANGUAGE))
454 {
455 return TNC_RESULT_INVALID_PARAMETER;
456 }
457
458 this->connection_lock->read_lock(this->connection_lock);
459 enumerator = this->connections->create_enumerator(this->connections);
460 while (enumerator->enumerate(enumerator, &entry))
461 {
462 if (id == entry->id)
463 {
464 recs = entry->recs;
465 break;
466 }
467 }
468 enumerator->destroy(enumerator);
469 this->connection_lock->unlock(this->connection_lock);
470
471 if (recs)
472 {
473 chunk_t attribute = { buffer, buffer_len };
474
475 if (attribute_id == TNC_ATTRIBUTEID_REASON_STRING)
476 {
477 return recs->set_reason_string(recs, imv_id, attribute);
478 }
479 else
480 {
481 return recs->set_reason_language(recs, imv_id, attribute);
482 }
483 }
484 return TNC_RESULT_INVALID_PARAMETER;
485 }
486
487 METHOD(tnccs_manager_t, destroy, void,
488 private_tnccs_manager_t *this)
489 {
490 this->protocols->destroy_function(this->protocols, free);
491 this->protocol_lock->destroy(this->protocol_lock);
492 this->connections->destroy_function(this->connections, free);
493 this->connection_lock->destroy(this->connection_lock);
494 free(this);
495 }
496
497 /*
498 * See header
499 */
500 tnccs_manager_t *tnccs_manager_create()
501 {
502 private_tnccs_manager_t *this;
503
504 INIT(this,
505 .public = {
506 .add_method = _add_method,
507 .remove_method = _remove_method,
508 .create_instance = _create_instance,
509 .create_connection = _create_connection,
510 .remove_connection = _remove_connection,
511 .request_handshake_retry = _request_handshake_retry,
512 .send_message = _send_message,
513 .provide_recommendation = _provide_recommendation,
514 .get_attribute = _get_attribute,
515 .set_attribute = _set_attribute,
516 .destroy = _destroy,
517 },
518 .protocols = linked_list_create(),
519 .connections = linked_list_create(),
520 .protocol_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
521 .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
522 .imcs = lib->get(lib, "imc-manager"),
523 .imvs = lib->get(lib, "imv-manager"),
524 );
525
526 return &this->public;
527 }
528