36bab7068fe026bcd6e82bb54a654e07605ea181
[strongswan.git] / src / libcharon / plugins / tnc_tnccs / tnc_tnccs_manager.c
1 /*
2 * Copyright (C) 2010-2013 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 "tnc_tnccs_manager.h"
17
18 #include <tnc/tnc.h>
19 #include <tnc/imv/imv_manager.h>
20 #include <tnc/imc/imc_manager.h>
21 #include <tnc/imv/imv_manager.h>
22
23 #include <tncif_identity.h>
24
25 #include <tls.h>
26
27 #include <utils/debug.h>
28 #include <pen/pen.h>
29 #include <bio/bio_writer.h>
30 #include <collections/linked_list.h>
31 #include <threading/rwlock.h>
32
33 #include <stdio.h>
34
35 typedef struct private_tnc_tnccs_manager_t private_tnc_tnccs_manager_t;
36 typedef struct tnccs_entry_t tnccs_entry_t;
37 typedef struct tnccs_connection_entry_t tnccs_connection_entry_t;
38
39 /**
40 * TNCCS constructor entry
41 */
42 struct tnccs_entry_t {
43
44 /**
45 * TNCCS protocol type
46 */
47 tnccs_type_t type;
48
49 /**
50 * constructor function to create instance
51 */
52 tnccs_constructor_t constructor;
53 };
54
55 /**
56 * TNCCS connection entry
57 */
58 struct tnccs_connection_entry_t {
59
60 /**
61 * TNCCS connection ID
62 */
63 TNC_ConnectionID id;
64
65 /**
66 * TNCCS protocol type
67 */
68 tnccs_type_t type;
69
70 /**
71 * TNCCS instance
72 */
73 tnccs_t *tnccs;
74
75 /**
76 * TNCCS send message function
77 */
78 tnccs_send_message_t send_message;
79
80 /**
81 * TNCCS request handshake retry flag
82 */
83 bool *request_handshake_retry;
84
85 /**
86 * Maximum size of a PA-TNC message
87 */
88 u_int32_t max_msg_len;
89
90 /**
91 * collection of IMV recommendations
92 */
93 recommendations_t *recs;
94 };
95
96 /**
97 * private data of tnc_tnccs_manager
98 */
99 struct private_tnc_tnccs_manager_t {
100
101 /**
102 * public functions
103 */
104 tnccs_manager_t public;
105
106 /**
107 * list of TNCCS protocol entries
108 */
109 linked_list_t *protocols;
110
111 /**
112 * rwlock to lock the TNCCS protocol entries
113 */
114 rwlock_t *protocol_lock;
115
116 /**
117 * connection ID counter
118 */
119 TNC_ConnectionID connection_id;
120
121 /**
122 * list of TNCCS connection entries
123 */
124 linked_list_t *connections;
125
126 /**
127 * rwlock to lock TNCCS connection entries
128 */
129 rwlock_t *connection_lock;
130
131 };
132
133 METHOD(tnccs_manager_t, add_method, void,
134 private_tnc_tnccs_manager_t *this, tnccs_type_t type,
135 tnccs_constructor_t constructor)
136 {
137 tnccs_entry_t *entry;
138
139 entry = malloc_thing(tnccs_entry_t);
140 entry->type = type;
141 entry->constructor = constructor;
142
143 this->protocol_lock->write_lock(this->protocol_lock);
144 this->protocols->insert_last(this->protocols, entry);
145 this->protocol_lock->unlock(this->protocol_lock);
146 }
147
148 METHOD(tnccs_manager_t, remove_method, void,
149 private_tnc_tnccs_manager_t *this, tnccs_constructor_t constructor)
150 {
151 enumerator_t *enumerator;
152 tnccs_entry_t *entry;
153
154 this->protocol_lock->write_lock(this->protocol_lock);
155 enumerator = this->protocols->create_enumerator(this->protocols);
156 while (enumerator->enumerate(enumerator, &entry))
157 {
158 if (constructor == entry->constructor)
159 {
160 this->protocols->remove_at(this->protocols, enumerator);
161 free(entry);
162 }
163 }
164 enumerator->destroy(enumerator);
165 this->protocol_lock->unlock(this->protocol_lock);
166 }
167
168 METHOD(tnccs_manager_t, create_instance, tnccs_t*,
169 private_tnc_tnccs_manager_t *this, tnccs_type_t type, bool is_server,
170 identification_t *server, identification_t *peer,
171 tnc_ift_type_t transport)
172 {
173 enumerator_t *enumerator;
174 tnccs_entry_t *entry;
175 tnccs_t *protocol = NULL;
176
177 this->protocol_lock->read_lock(this->protocol_lock);
178 enumerator = this->protocols->create_enumerator(this->protocols);
179 while (enumerator->enumerate(enumerator, &entry))
180 {
181 if (type == entry->type)
182 {
183 protocol = entry->constructor(is_server, server, peer, transport);
184 if (protocol)
185 {
186 break;
187 }
188 }
189 }
190 enumerator->destroy(enumerator);
191 this->protocol_lock->unlock(this->protocol_lock);
192
193 return protocol;
194 }
195
196 METHOD(tnccs_manager_t, create_connection, TNC_ConnectionID,
197 private_tnc_tnccs_manager_t *this, tnccs_type_t type, tnccs_t *tnccs,
198 tnccs_send_message_t send_message, bool* request_handshake_retry,
199 u_int32_t max_msg_len, recommendations_t **recs)
200 {
201 tnccs_connection_entry_t *entry;
202
203 entry = malloc_thing(tnccs_connection_entry_t);
204 entry->type = type;
205 entry->tnccs = tnccs;
206 entry->send_message = send_message;
207 entry->request_handshake_retry = request_handshake_retry;
208 entry->max_msg_len = max_msg_len;
209 if (recs)
210 {
211 /* we assume a TNC Server needing recommendations from IMVs */
212 if (!tnc->imvs)
213 {
214 DBG1(DBG_TNC, "no IMV manager available!");
215 free(entry);
216 return 0;
217 }
218 entry->recs = tnc->imvs->create_recommendations(tnc->imvs);
219 *recs = entry->recs;
220 }
221 else
222 {
223 /* we assume a TNC Client */
224 if (!tnc->imcs)
225 {
226 DBG1(DBG_TNC, "no IMC manager available!");
227 free(entry);
228 return 0;
229 }
230 entry->recs = NULL;
231 }
232 this->connection_lock->write_lock(this->connection_lock);
233 entry->id = ++this->connection_id;
234 this->connections->insert_last(this->connections, entry);
235 this->connection_lock->unlock(this->connection_lock);
236
237 DBG1(DBG_TNC, "assigned TNCCS Connection ID %u", entry->id);
238 return entry->id;
239 }
240
241 METHOD(tnccs_manager_t, remove_connection, void,
242 private_tnc_tnccs_manager_t *this, TNC_ConnectionID id, bool is_server)
243 {
244 enumerator_t *enumerator;
245 tnccs_connection_entry_t *entry;
246
247 if (is_server)
248 {
249 if (tnc->imvs)
250 {
251 tnc->imvs->notify_connection_change(tnc->imvs, id,
252 TNC_CONNECTION_STATE_DELETE);
253 }
254 }
255 else
256 {
257 if (tnc->imcs)
258 {
259 tnc->imcs->notify_connection_change(tnc->imcs, id,
260 TNC_CONNECTION_STATE_DELETE);
261 }
262 }
263
264 this->connection_lock->write_lock(this->connection_lock);
265 enumerator = this->connections->create_enumerator(this->connections);
266 while (enumerator->enumerate(enumerator, &entry))
267 {
268 if (id == entry->id)
269 {
270 this->connections->remove_at(this->connections, enumerator);
271 if (entry->recs)
272 {
273 entry->recs->destroy(entry->recs);
274 }
275 free(entry);
276 DBG1(DBG_TNC, "removed TNCCS Connection ID %u", id);
277 }
278 }
279 enumerator->destroy(enumerator);
280 this->connection_lock->unlock(this->connection_lock);
281 }
282
283 METHOD(tnccs_manager_t, request_handshake_retry, TNC_Result,
284 private_tnc_tnccs_manager_t *this, bool is_imc, TNC_UInt32 imcv_id,
285 TNC_ConnectionID id,
286 TNC_RetryReason reason)
287 {
288 enumerator_t *enumerator;
289 tnccs_connection_entry_t *entry;
290
291 if (id == TNC_CONNECTIONID_ANY)
292 {
293 DBG2(DBG_TNC, "%s %u requests handshake retry for all connections "
294 "(reason: %u)", is_imc ? "IMC":"IMV", reason);
295 }
296 else
297 {
298 DBG2(DBG_TNC, "%s %u requests handshake retry for Connection ID %u "
299 "(reason: %u)", is_imc ? "IMC":"IMV", imcv_id, id, reason);
300 }
301 this->connection_lock->read_lock(this->connection_lock);
302 enumerator = this->connections->create_enumerator(this->connections);
303 while (enumerator->enumerate(enumerator, &entry))
304 {
305 if (id == TNC_CONNECTIONID_ANY || id == entry->id)
306 {
307 *entry->request_handshake_retry = TRUE;
308 break;
309 }
310 }
311 enumerator->destroy(enumerator);
312 this->connection_lock->unlock(this->connection_lock);
313
314 return TNC_RESULT_SUCCESS;
315 }
316
317 METHOD(tnccs_manager_t, send_message, TNC_Result,
318 private_tnc_tnccs_manager_t *this, TNC_IMCID imc_id, TNC_IMVID imv_id,
319 TNC_ConnectionID id,
320 TNC_UInt32 msg_flags,
321 TNC_BufferReference msg,
322 TNC_UInt32 msg_len,
323 TNC_VendorID msg_vid,
324 TNC_MessageSubtype msg_subtype)
325
326 {
327 enumerator_t *enumerator;
328 tnccs_connection_entry_t *entry;
329 tnccs_send_message_t send_message = NULL;
330 tnccs_t *tnccs = NULL;
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%02x/0x%08x",
335 msg_vid, msg_subtype);
336 return TNC_RESULT_INVALID_PARAMETER;
337 }
338
339 this->connection_lock->read_lock(this->connection_lock);
340 enumerator = this->connections->create_enumerator(this->connections);
341 while (enumerator->enumerate(enumerator, &entry))
342 {
343 if (id == entry->id)
344 {
345 tnccs = entry->tnccs;
346 send_message = entry->send_message;
347 break;
348 }
349 }
350 enumerator->destroy(enumerator);
351 this->connection_lock->unlock(this->connection_lock);
352
353 if (tnccs && send_message)
354 {
355 return send_message(tnccs, imc_id, imv_id, msg_flags, msg, msg_len,
356 msg_vid, msg_subtype);
357 }
358 return TNC_RESULT_FATAL;
359 }
360
361 METHOD(tnccs_manager_t, provide_recommendation, TNC_Result,
362 private_tnc_tnccs_manager_t *this, TNC_IMVID imv_id,
363 TNC_ConnectionID id,
364 TNC_IMV_Action_Recommendation rec,
365 TNC_IMV_Evaluation_Result eval)
366 {
367 enumerator_t *enumerator;
368 tnccs_connection_entry_t *entry;
369 recommendations_t *recs = NULL;
370
371 this->connection_lock->read_lock(this->connection_lock);
372 enumerator = this->connections->create_enumerator(this->connections);
373 while (enumerator->enumerate(enumerator, &entry))
374 {
375 if (id == entry->id)
376 {
377 recs = entry->recs;
378 break;
379 }
380 }
381 enumerator->destroy(enumerator);
382 this->connection_lock->unlock(this->connection_lock);
383
384 if (recs)
385 {
386 recs->provide_recommendation(recs, imv_id, rec, eval);
387 return TNC_RESULT_SUCCESS;
388 }
389 return TNC_RESULT_FATAL;
390 }
391
392 /**
393 * Write the value of a boolean attribute into the buffer
394 */
395 static TNC_Result bool_attribute(TNC_UInt32 buffer_len,
396 TNC_BufferReference buffer,
397 TNC_UInt32 *value_len,
398 bool value)
399 {
400 *value_len = 1;
401
402 if (buffer && buffer_len > 0)
403 {
404 *buffer = value ? 0x01 : 0x00;
405 return TNC_RESULT_SUCCESS;
406 }
407 else
408 {
409 return TNC_RESULT_INVALID_PARAMETER;
410 }
411 }
412
413 /**
414 * Write the value of an u_int32_t attribute into the buffer
415 */
416 static TNC_Result uint_attribute(TNC_UInt32 buffer_len,
417 TNC_BufferReference buffer,
418 TNC_UInt32 *value_len,
419 u_int32_t value)
420 {
421 *value_len = sizeof(u_int32_t);
422
423 if (buffer && buffer_len >= *value_len)
424 {
425 htoun32(buffer, value);
426 return TNC_RESULT_SUCCESS;
427 }
428 else
429 {
430 return TNC_RESULT_INVALID_PARAMETER;
431 }
432 }
433
434 /**
435 * Write the value of string attribute into the buffer
436 */
437 static TNC_Result str_attribute(TNC_UInt32 buffer_len,
438 TNC_BufferReference buffer,
439 TNC_UInt32 *value_len,
440 char *value)
441 {
442 *value_len = 1 + strlen(value);
443
444 if (buffer && buffer_len >= *value_len)
445 {
446 snprintf(buffer, buffer_len, "%s", value);
447 return TNC_RESULT_SUCCESS;
448 }
449 else
450 {
451 return TNC_RESULT_INVALID_PARAMETER;
452 }
453 }
454
455 /**
456 * Write the value of a TNC identity list into the buffer
457 */
458 static TNC_Result identity_attribute(TNC_UInt32 buffer_len,
459 TNC_BufferReference buffer,
460 TNC_UInt32 *value_len,
461 linked_list_t *list)
462 {
463 bio_writer_t *writer;
464 enumerator_t *enumerator;
465 u_int32_t count;
466 chunk_t value;
467 tncif_identity_t *tnc_id;
468 TNC_Result result = TNC_RESULT_INVALID_PARAMETER;
469
470 count = list->get_count(list);
471 writer = bio_writer_create(4 + TNCIF_IDENTITY_MIN_SIZE * count);
472 writer->write_uint32(writer, count);
473
474 enumerator = list->create_enumerator(list);
475 while (enumerator->enumerate(enumerator, &tnc_id))
476 {
477 tnc_id->build(tnc_id, writer);
478 }
479 enumerator->destroy(enumerator);
480
481 value = writer->get_buf(writer);
482 *value_len = value.len;
483 if (buffer && buffer_len >= value.len)
484 {
485 memcpy(buffer, value.ptr, value.len);
486 result = TNC_RESULT_SUCCESS;
487 }
488 writer->destroy(writer);
489
490 return result;
491 }
492
493 METHOD(tnccs_manager_t, get_attribute, TNC_Result,
494 private_tnc_tnccs_manager_t *this, bool is_imc,
495 TNC_UInt32 imcv_id,
496 TNC_ConnectionID id,
497 TNC_AttributeID attribute_id,
498 TNC_UInt32 buffer_len,
499 TNC_BufferReference buffer,
500 TNC_UInt32 *value_len)
501 {
502 enumerator_t *enumerator;
503 tnccs_connection_entry_t *entry;
504 bool attribute_match = FALSE, entry_found = FALSE;
505
506 if (is_imc)
507 {
508 switch (attribute_id)
509 {
510 /* these attributes are unsupported */
511 case TNC_ATTRIBUTEID_SOHR:
512 case TNC_ATTRIBUTEID_SSOHR:
513 return TNC_RESULT_INVALID_PARAMETER;
514
515 /* these attributes are supported */
516 case TNC_ATTRIBUTEID_PRIMARY_IMC_ID:
517 attribute_match = TRUE;
518 break;
519
520 /* these attributes are yet to be matched */
521 default:
522 break;
523 }
524 }
525 else
526 {
527 switch (attribute_id)
528 {
529 /* these attributes are unsupported or invalid */
530 case TNC_ATTRIBUTEID_REASON_STRING:
531 case TNC_ATTRIBUTEID_REASON_LANGUAGE:
532 case TNC_ATTRIBUTEID_SOH:
533 case TNC_ATTRIBUTEID_SSOH:
534 return TNC_RESULT_INVALID_PARAMETER;
535
536 /* these attributes are supported */
537 case TNC_ATTRIBUTEID_PRIMARY_IMV_ID:
538 case TNC_ATTRIBUTEID_AR_IDENTITIES:
539 attribute_match = TRUE;
540 break;
541
542 /* these attributes are yet to be matched */
543 default:
544 break;
545 }
546 }
547
548 if (!attribute_match)
549 {
550 switch (attribute_id)
551 {
552 /* these attributes are supported */
553 case TNC_ATTRIBUTEID_PREFERRED_LANGUAGE:
554 case TNC_ATTRIBUTEID_MAX_ROUND_TRIPS:
555 case TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE:
556 case TNC_ATTRIBUTEID_HAS_LONG_TYPES:
557 case TNC_ATTRIBUTEID_HAS_EXCLUSIVE:
558 case TNC_ATTRIBUTEID_HAS_SOH:
559 case TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL:
560 case TNC_ATTRIBUTEID_IFTNCCS_VERSION:
561 case TNC_ATTRIBUTEID_IFT_PROTOCOL:
562 case TNC_ATTRIBUTEID_IFT_VERSION:
563 break;
564
565 /* these attributes are unsupported or unknown */
566 case TNC_ATTRIBUTEID_DHPN:
567 case TNC_ATTRIBUTEID_TLS_UNIQUE:
568 default:
569 return TNC_RESULT_INVALID_PARAMETER;
570 }
571 }
572
573 /* attributes specific to the TNCC or TNCS are unsupported */
574 if (id == TNC_CONNECTIONID_ANY)
575 {
576 return TNC_RESULT_INVALID_PARAMETER;
577 }
578
579 this->connection_lock->read_lock(this->connection_lock);
580 enumerator = this->connections->create_enumerator(this->connections);
581 while (enumerator->enumerate(enumerator, &entry))
582 {
583 if (id == entry->id)
584 {
585 entry_found = TRUE;
586 break;
587 }
588 }
589 enumerator->destroy(enumerator);
590 this->connection_lock->unlock(this->connection_lock);
591
592 if (!entry_found)
593 {
594 return TNC_RESULT_INVALID_PARAMETER;
595 }
596
597 switch (attribute_id)
598 {
599 case TNC_ATTRIBUTEID_PREFERRED_LANGUAGE:
600 {
601 recommendations_t *recs;
602 chunk_t pref_lang;
603
604 recs = entry->recs;
605 if (!recs)
606 {
607 return TNC_RESULT_INVALID_PARAMETER;
608 }
609 pref_lang = recs->get_preferred_language(recs);
610 if (pref_lang.len == 0)
611 {
612 return TNC_RESULT_INVALID_PARAMETER;
613 }
614 *value_len = pref_lang.len;
615 if (buffer && buffer_len >= pref_lang.len)
616 {
617 memcpy(buffer, pref_lang.ptr, pref_lang.len);
618 }
619 return TNC_RESULT_SUCCESS;
620 }
621 case TNC_ATTRIBUTEID_MAX_ROUND_TRIPS:
622 return uint_attribute(buffer_len, buffer, value_len,
623 0xffffffff);
624 case TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE:
625 return uint_attribute(buffer_len, buffer, value_len,
626 entry->max_msg_len);
627 case TNC_ATTRIBUTEID_HAS_LONG_TYPES:
628 case TNC_ATTRIBUTEID_HAS_EXCLUSIVE:
629 return bool_attribute(buffer_len, buffer, value_len,
630 entry->type == TNCCS_2_0);
631 case TNC_ATTRIBUTEID_HAS_SOH:
632 return bool_attribute(buffer_len, buffer, value_len,
633 entry->type == TNCCS_SOH);
634 case TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL:
635 {
636 char *protocol;
637
638 switch (entry->type)
639 {
640 case TNCCS_1_1:
641 case TNCCS_2_0:
642 protocol = "IF-TNCCS";
643 break;
644 case TNCCS_SOH:
645 protocol = "IF-TNCCS-SOH";
646 break;
647 default:
648 return TNC_RESULT_INVALID_PARAMETER;
649 }
650 return str_attribute(buffer_len, buffer, value_len, protocol);
651 }
652 case TNC_ATTRIBUTEID_IFTNCCS_VERSION:
653 {
654 char *version;
655
656 switch (entry->type)
657 {
658 case TNCCS_1_1:
659 version = "1.1";
660 break;
661 case TNCCS_2_0:
662 version = "2.0";
663 break;
664 case TNCCS_SOH:
665 version = "1.0";
666 break;
667 default:
668 return TNC_RESULT_INVALID_PARAMETER;
669 }
670 return str_attribute(buffer_len, buffer, value_len, version);
671 }
672 case TNC_ATTRIBUTEID_IFT_PROTOCOL:
673 {
674 char *protocol;
675
676 switch (entry->tnccs->get_transport(entry->tnccs))
677 {
678 case TNC_IFT_EAP_1_0:
679 case TNC_IFT_EAP_1_1:
680 case TNC_IFT_EAP_2_0:
681 protocol = "IF-T for Tunneled EAP";
682 break;
683 case TNC_IFT_TLS_1_0:
684 case TNC_IFT_TLS_2_0:
685 protocol = "IF-T for TLS";
686 break;
687 default:
688 return TNC_RESULT_INVALID_PARAMETER;
689 }
690 return str_attribute(buffer_len, buffer, value_len, protocol);
691 }
692 case TNC_ATTRIBUTEID_IFT_VERSION:
693 {
694 char *version;
695
696 switch (entry->tnccs->get_transport(entry->tnccs))
697 {
698 case TNC_IFT_EAP_1_0:
699 case TNC_IFT_TLS_1_0:
700 version = "1.0";
701 break;
702 case TNC_IFT_EAP_1_1:
703 version = "1.1";
704 break;
705 case TNC_IFT_EAP_2_0:
706 case TNC_IFT_TLS_2_0:
707 version = "2.0";
708 break;
709 default:
710 return TNC_RESULT_INVALID_PARAMETER;
711 }
712 return str_attribute(buffer_len, buffer, value_len, version);
713 }
714 case TNC_ATTRIBUTEID_AR_IDENTITIES:
715 {
716 linked_list_t *list;
717 identification_t *peer;
718 tnccs_t *tnccs;
719 tncif_identity_t *tnc_id;
720 u_int32_t id_type, subject_type;
721 chunk_t id_value;
722 char *id_str;
723 TNC_Result result;
724
725 list = linked_list_create();
726 tnccs = entry->tnccs;
727 peer = tnccs->tls.get_peer_id(&tnccs->tls);
728 if (peer)
729 {
730 switch (peer->get_type(peer))
731 {
732 case ID_IPV4_ADDR:
733 id_type = TNC_ID_IPV4_ADDR;
734 subject_type = TNC_SUBJECT_MACHINE;
735 break;
736 case ID_IPV6_ADDR:
737 id_type = TNC_ID_IPV6_ADDR;
738 subject_type = TNC_SUBJECT_MACHINE;
739 break;
740 case ID_FQDN:
741 id_type = TNC_ID_USERNAME;
742 subject_type = TNC_SUBJECT_USER;
743 break;
744 case ID_RFC822_ADDR:
745 id_type = TNC_ID_RFC822_ADDR;
746 subject_type = TNC_SUBJECT_USER;
747 break;
748 case ID_DER_ASN1_DN:
749 id_type = TNC_ID_ASN1_DN;
750 subject_type = TNC_SUBJECT_USER;
751 break;
752 default:
753 id_type = TNC_ID_UNKNOWN;
754 subject_type = TNC_SUBJECT_UNKNOWN;
755 }
756 if (id_type != TNC_ID_UNKNOWN &&
757 asprintf(&id_str, "%Y", peer) >= 0)
758 {
759 id_value = chunk_from_str(id_str);
760 tnc_id = tncif_identity_create(
761 pen_type_create(PEN_TCG, id_type), id_value,
762 pen_type_create(PEN_TCG, subject_type),
763 pen_type_create(PEN_TCG,
764 tnccs->get_auth_type(tnccs)));
765 list->insert_last(list, tnc_id);
766 }
767 }
768 result = identity_attribute(buffer_len, buffer, value_len, list);
769 list->destroy_offset(list, offsetof(tncif_identity_t, destroy));
770 return result;
771 }
772 default:
773 return TNC_RESULT_INVALID_PARAMETER;
774 }
775 }
776
777 METHOD(tnccs_manager_t, set_attribute, TNC_Result,
778 private_tnc_tnccs_manager_t *this, bool is_imc,
779 TNC_UInt32 imcv_id,
780 TNC_ConnectionID id,
781 TNC_AttributeID attribute_id,
782 TNC_UInt32 buffer_len,
783 TNC_BufferReference buffer)
784 {
785 enumerator_t *enumerator;
786 tnccs_connection_entry_t *entry;
787 recommendations_t *recs = NULL;
788
789 if (is_imc || id == TNC_CONNECTIONID_ANY ||
790 (attribute_id != TNC_ATTRIBUTEID_REASON_STRING &&
791 attribute_id != TNC_ATTRIBUTEID_REASON_LANGUAGE))
792 {
793 return TNC_RESULT_INVALID_PARAMETER;
794 }
795
796 this->connection_lock->read_lock(this->connection_lock);
797 enumerator = this->connections->create_enumerator(this->connections);
798 while (enumerator->enumerate(enumerator, &entry))
799 {
800 if (id == entry->id)
801 {
802 recs = entry->recs;
803 break;
804 }
805 }
806 enumerator->destroy(enumerator);
807 this->connection_lock->unlock(this->connection_lock);
808
809 if (recs)
810 {
811 chunk_t attribute = { buffer, buffer_len };
812
813 if (attribute_id == TNC_ATTRIBUTEID_REASON_STRING)
814 {
815 return recs->set_reason_string(recs, imcv_id, attribute);
816 }
817 else
818 {
819 return recs->set_reason_language(recs, imcv_id, attribute);
820 }
821 }
822 return TNC_RESULT_INVALID_PARAMETER;
823 }
824
825 METHOD(tnccs_manager_t, destroy, void,
826 private_tnc_tnccs_manager_t *this)
827 {
828 this->protocols->destroy_function(this->protocols, free);
829 this->protocol_lock->destroy(this->protocol_lock);
830 this->connections->destroy_function(this->connections, free);
831 this->connection_lock->destroy(this->connection_lock);
832 free(this);
833 }
834
835 /*
836 * See header
837 */
838 tnccs_manager_t *tnc_tnccs_manager_create()
839 {
840 private_tnc_tnccs_manager_t *this;
841
842 INIT(this,
843 .public = {
844 .add_method = _add_method,
845 .remove_method = _remove_method,
846 .create_instance = _create_instance,
847 .create_connection = _create_connection,
848 .remove_connection = _remove_connection,
849 .request_handshake_retry = _request_handshake_retry,
850 .send_message = _send_message,
851 .provide_recommendation = _provide_recommendation,
852 .get_attribute = _get_attribute,
853 .set_attribute = _set_attribute,
854 .destroy = _destroy,
855 },
856 .protocols = linked_list_create(),
857 .connections = linked_list_create(),
858 .protocol_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
859 .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
860 );
861
862 return &this->public;
863 }
864