moved imc_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 <tnc/imv/imv_recommendations.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
121 METHOD(tnccs_manager_t, add_method, void,
122 private_tnccs_manager_t *this, tnccs_type_t type,
123 tnccs_constructor_t constructor)
124 {
125 tnccs_entry_t *entry;
126
127 entry = malloc_thing(tnccs_entry_t);
128 entry->type = type;
129 entry->constructor = constructor;
130
131 this->protocol_lock->write_lock(this->protocol_lock);
132 this->protocols->insert_last(this->protocols, entry);
133 this->protocol_lock->unlock(this->protocol_lock);
134 }
135
136 METHOD(tnccs_manager_t, remove_method, void,
137 private_tnccs_manager_t *this, tnccs_constructor_t constructor)
138 {
139 enumerator_t *enumerator;
140 tnccs_entry_t *entry;
141
142 this->protocol_lock->write_lock(this->protocol_lock);
143 enumerator = this->protocols->create_enumerator(this->protocols);
144 while (enumerator->enumerate(enumerator, &entry))
145 {
146 if (constructor == entry->constructor)
147 {
148 this->protocols->remove_at(this->protocols, enumerator);
149 free(entry);
150 }
151 }
152 enumerator->destroy(enumerator);
153 this->protocol_lock->unlock(this->protocol_lock);
154 }
155
156 METHOD(tnccs_manager_t, create_instance, tnccs_t*,
157 private_tnccs_manager_t *this, tnccs_type_t type, bool is_server)
158 {
159 enumerator_t *enumerator;
160 tnccs_entry_t *entry;
161 tnccs_t *protocol = NULL;
162
163 this->protocol_lock->read_lock(this->protocol_lock);
164 enumerator = this->protocols->create_enumerator(this->protocols);
165 while (enumerator->enumerate(enumerator, &entry))
166 {
167 if (type == entry->type)
168 {
169 protocol = entry->constructor(is_server);
170 if (protocol)
171 {
172 break;
173 }
174 }
175 }
176 enumerator->destroy(enumerator);
177 this->protocol_lock->unlock(this->protocol_lock);
178
179 return protocol;
180 }
181
182 METHOD(tnccs_manager_t, create_connection, TNC_ConnectionID,
183 private_tnccs_manager_t *this, tnccs_t *tnccs,
184 tnccs_send_message_t send_message, bool* request_handshake_retry,
185 recommendations_t **recs)
186 {
187 tnccs_connection_entry_t *entry;
188
189 entry = malloc_thing(tnccs_connection_entry_t);
190 entry->tnccs = tnccs;
191 entry->send_message = send_message;
192 entry->request_handshake_retry = request_handshake_retry;
193 if (recs)
194 {
195 /* we assume a TNC Server needing recommendations from IMVs */
196 if (!charon->imvs)
197 {
198 DBG1(DBG_TNC, "no IMV manager available!");
199 free(entry);
200 return 0;
201 }
202 entry->recs = charon->imvs->create_recommendations(charon->imvs);
203 *recs = entry->recs;
204 }
205 else
206 {
207 /* we assume a TNC Client */
208 if (!this->imcs)
209 {
210 this->imcs = lib->get(lib, "imc-manager");
211 }
212 if (!this->imcs)
213 {
214 DBG1(DBG_TNC, "no IMC manager available!");
215 free(entry);
216 return 0;
217 }
218 entry->recs = NULL;
219 }
220 this->connection_lock->write_lock(this->connection_lock);
221 entry->id = ++this->connection_id;
222 this->connections->insert_last(this->connections, entry);
223 this->connection_lock->unlock(this->connection_lock);
224
225 DBG1(DBG_TNC, "assigned TNCCS Connection ID %u", entry->id);
226 return entry->id;
227 }
228
229 METHOD(tnccs_manager_t, remove_connection, void,
230 private_tnccs_manager_t *this, TNC_ConnectionID id, bool is_server)
231 {
232 enumerator_t *enumerator;
233 tnccs_connection_entry_t *entry;
234
235 if (is_server)
236 {
237 if (charon->imvs)
238 {
239 charon->imvs->notify_connection_change(charon->imvs, id,
240 TNC_CONNECTION_STATE_DELETE);
241 }
242 }
243 else
244 {
245 if (this->imcs)
246 {
247 this->imcs->notify_connection_change(this->imcs, id,
248 TNC_CONNECTION_STATE_DELETE);
249 }
250 }
251
252 this->connection_lock->write_lock(this->connection_lock);
253 enumerator = this->connections->create_enumerator(this->connections);
254 while (enumerator->enumerate(enumerator, &entry))
255 {
256 if (id == entry->id)
257 {
258 this->connections->remove_at(this->connections, enumerator);
259 if (entry->recs)
260 {
261 entry->recs->destroy(entry->recs);
262 }
263 free(entry);
264 DBG1(DBG_TNC, "removed TNCCS Connection ID %u", id);
265 }
266 }
267 enumerator->destroy(enumerator);
268 this->connection_lock->unlock(this->connection_lock);
269 }
270
271 METHOD(tnccs_manager_t, request_handshake_retry, TNC_Result,
272 private_tnccs_manager_t *this, bool is_imc, TNC_UInt32 imcv_id,
273 TNC_ConnectionID id,
274 TNC_RetryReason reason)
275 {
276 enumerator_t *enumerator;
277 tnccs_connection_entry_t *entry;
278
279 if (id == TNC_CONNECTIONID_ANY)
280 {
281 DBG2(DBG_TNC, "%s %u requests handshake retry for all connections "
282 "(reason: %u)", is_imc ? "IMC":"IMV", reason);
283 }
284 else
285 {
286 DBG2(DBG_TNC, "%s %u requests handshake retry for Connection ID %u "
287 "(reason: %u)", is_imc ? "IMC":"IMV", imcv_id, id, reason);
288 }
289 this->connection_lock->read_lock(this->connection_lock);
290 enumerator = this->connections->create_enumerator(this->connections);
291 while (enumerator->enumerate(enumerator, &entry))
292 {
293 if (id == TNC_CONNECTIONID_ANY || id == entry->id)
294 {
295 *entry->request_handshake_retry = TRUE;
296 break;
297 }
298 }
299 enumerator->destroy(enumerator);
300 this->connection_lock->unlock(this->connection_lock);
301
302 return TNC_RESULT_SUCCESS;
303 }
304
305 METHOD(tnccs_manager_t, send_message, TNC_Result,
306 private_tnccs_manager_t *this, TNC_IMCID imc_id, TNC_IMVID imv_id,
307 TNC_ConnectionID id,
308 TNC_BufferReference msg,
309 TNC_UInt32 msg_len,
310 TNC_MessageType msg_type)
311
312 {
313 enumerator_t *enumerator;
314 tnccs_connection_entry_t *entry;
315 tnccs_send_message_t send_message = NULL;
316 tnccs_t *tnccs = NULL;
317 TNC_VendorID msg_vid;
318 TNC_MessageSubtype msg_subtype;
319
320 msg_vid = (msg_type >> 8) & TNC_VENDORID_ANY;
321 msg_subtype = msg_type & TNC_SUBTYPE_ANY;
322
323 if (msg_vid == TNC_VENDORID_ANY || msg_subtype == TNC_SUBTYPE_ANY)
324 {
325 DBG1(DBG_TNC, "not sending message of invalid type 0x%08x", msg_type);
326 return TNC_RESULT_INVALID_PARAMETER;
327 }
328
329 this->connection_lock->read_lock(this->connection_lock);
330 enumerator = this->connections->create_enumerator(this->connections);
331 while (enumerator->enumerate(enumerator, &entry))
332 {
333 if (id == entry->id)
334 {
335 tnccs = entry->tnccs;
336 send_message = entry->send_message;
337 break;
338 }
339 }
340 enumerator->destroy(enumerator);
341 this->connection_lock->unlock(this->connection_lock);
342
343 if (tnccs && send_message)
344 {
345 return send_message(tnccs, imc_id, imv_id, msg, msg_len, msg_type);
346 }
347 return TNC_RESULT_FATAL;
348 }
349
350 METHOD(tnccs_manager_t, provide_recommendation, TNC_Result,
351 private_tnccs_manager_t *this, TNC_IMVID imv_id,
352 TNC_ConnectionID id,
353 TNC_IMV_Action_Recommendation rec,
354 TNC_IMV_Evaluation_Result eval)
355 {
356 enumerator_t *enumerator;
357 tnccs_connection_entry_t *entry;
358 recommendations_t *recs = NULL;
359
360 this->connection_lock->read_lock(this->connection_lock);
361 enumerator = this->connections->create_enumerator(this->connections);
362 while (enumerator->enumerate(enumerator, &entry))
363 {
364 if (id == entry->id)
365 {
366 recs = entry->recs;
367 break;
368 }
369 }
370 enumerator->destroy(enumerator);
371 this->connection_lock->unlock(this->connection_lock);
372
373 if (recs)
374 {
375 recs->provide_recommendation(recs, imv_id, rec, eval);
376 return TNC_RESULT_SUCCESS;
377 }
378 return TNC_RESULT_FATAL;
379 }
380
381 METHOD(tnccs_manager_t, get_attribute, TNC_Result,
382 private_tnccs_manager_t *this, TNC_IMVID imv_id,
383 TNC_ConnectionID id,
384 TNC_AttributeID attribute_id,
385 TNC_UInt32 buffer_len,
386 TNC_BufferReference buffer,
387 TNC_UInt32 *out_value_len)
388 {
389 enumerator_t *enumerator;
390 tnccs_connection_entry_t *entry;
391 recommendations_t *recs = NULL;
392
393 if (id == TNC_CONNECTIONID_ANY ||
394 attribute_id != TNC_ATTRIBUTEID_PREFERRED_LANGUAGE)
395 {
396 return TNC_RESULT_INVALID_PARAMETER;
397 }
398
399 this->connection_lock->read_lock(this->connection_lock);
400 enumerator = this->connections->create_enumerator(this->connections);
401 while (enumerator->enumerate(enumerator, &entry))
402 {
403 if (id == entry->id)
404 {
405 recs = entry->recs;
406 break;
407 }
408 }
409 enumerator->destroy(enumerator);
410 this->connection_lock->unlock(this->connection_lock);
411
412 if (recs)
413 {
414 chunk_t pref_lang;
415
416 pref_lang = recs->get_preferred_language(recs);
417 if (pref_lang.len == 0)
418 {
419 return TNC_RESULT_INVALID_PARAMETER;
420 }
421 *out_value_len = pref_lang.len;
422 if (buffer && buffer_len >= pref_lang.len)
423 {
424 memcpy(buffer, pref_lang.ptr, pref_lang.len);
425 }
426 return TNC_RESULT_SUCCESS;
427 }
428 return TNC_RESULT_INVALID_PARAMETER;
429 }
430
431 METHOD(tnccs_manager_t, set_attribute, TNC_Result,
432 private_tnccs_manager_t *this, TNC_IMVID imv_id,
433 TNC_ConnectionID id,
434 TNC_AttributeID attribute_id,
435 TNC_UInt32 buffer_len,
436 TNC_BufferReference buffer)
437 {
438 enumerator_t *enumerator;
439 tnccs_connection_entry_t *entry;
440 recommendations_t *recs = NULL;
441
442 if (id == TNC_CONNECTIONID_ANY ||
443 (attribute_id != TNC_ATTRIBUTEID_REASON_STRING &&
444 attribute_id != TNC_ATTRIBUTEID_REASON_LANGUAGE))
445 {
446 return TNC_RESULT_INVALID_PARAMETER;
447 }
448
449 this->connection_lock->read_lock(this->connection_lock);
450 enumerator = this->connections->create_enumerator(this->connections);
451 while (enumerator->enumerate(enumerator, &entry))
452 {
453 if (id == entry->id)
454 {
455 recs = entry->recs;
456 break;
457 }
458 }
459 enumerator->destroy(enumerator);
460 this->connection_lock->unlock(this->connection_lock);
461
462 if (recs)
463 {
464 chunk_t attribute = { buffer, buffer_len };
465
466 if (attribute_id == TNC_ATTRIBUTEID_REASON_STRING)
467 {
468 return recs->set_reason_string(recs, imv_id, attribute);
469 }
470 else
471 {
472 return recs->set_reason_language(recs, imv_id, attribute);
473 }
474 }
475 return TNC_RESULT_INVALID_PARAMETER;
476 }
477
478 METHOD(tnccs_manager_t, destroy, void,
479 private_tnccs_manager_t *this)
480 {
481 this->protocols->destroy_function(this->protocols, free);
482 this->protocol_lock->destroy(this->protocol_lock);
483 this->connections->destroy_function(this->connections, free);
484 this->connection_lock->destroy(this->connection_lock);
485 free(this);
486 }
487
488 /*
489 * See header
490 */
491 tnccs_manager_t *tnccs_manager_create()
492 {
493 private_tnccs_manager_t *this;
494
495 INIT(this,
496 .public = {
497 .add_method = _add_method,
498 .remove_method = _remove_method,
499 .create_instance = _create_instance,
500 .create_connection = _create_connection,
501 .remove_connection = _remove_connection,
502 .request_handshake_retry = _request_handshake_retry,
503 .send_message = _send_message,
504 .provide_recommendation = _provide_recommendation,
505 .get_attribute = _get_attribute,
506 .set_attribute = _set_attribute,
507 .destroy = _destroy,
508 },
509 .protocols = linked_list_create(),
510 .connections = linked_list_create(),
511 .protocol_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
512 .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
513 .imcs = lib->get(lib, "imc-manager"),
514 );
515
516 return &this->public;
517 }
518