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