Annotation of embedaddon/strongswan/src/libimcv/imv/imv_agent.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2011-2015 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 "imcv.h"
17: #include "imv_agent.h"
18: #include "imv_session.h"
19:
20: #include "ietf/ietf_attr_assess_result.h"
21:
22: #include <tncif_names.h>
23: #include <tncif_identity.h>
24:
25: #include <utils/debug.h>
26: #include <collections/linked_list.h>
27: #include <bio/bio_reader.h>
28: #include <threading/rwlock.h>
29:
30: typedef struct private_imv_agent_t private_imv_agent_t;
31:
32: /**
33: * Private data of an imv_agent_t object.
34: */
35: struct private_imv_agent_t {
36:
37: /**
38: * Public members of imv_agent_t
39: */
40: imv_agent_t public;
41:
42: /**
43: * name of IMV
44: */
45: const char *name;
46:
47: /**
48: * message types registered by IMV
49: */
50: pen_type_t *supported_types;
51:
52: /**
53: * number of message types registered by IMV
54: */
55: uint32_t type_count;
56:
57: /**
58: * ID of IMV as assigned by TNCS
59: */
60: TNC_IMVID id;
61:
62: /**
63: * List of additional IMV IDs assigned by TNCS
64: */
65: linked_list_t *additional_ids;
66:
67: /**
68: * list of non-fatal unsupported PA-TNC attribute types
69: */
70: linked_list_t *non_fatal_attr_types;
71:
72: /**
73: * list of TNCS connection entries
74: */
75: linked_list_t *connections;
76:
77: /**
78: * rwlock to lock TNCS connection entries
79: */
80: rwlock_t *connection_lock;
81:
82: /**
83: * Inform a TNCS about the set of message types the IMV is able to receive
84: *
85: * @param imv_id IMV ID assigned by TNCS
86: * @param supported_types list of supported message types
87: * @param type_count number of list elements
88: * @return TNC result code
89: */
90: TNC_Result (*report_message_types)(TNC_IMVID imv_id,
91: TNC_MessageTypeList supported_types,
92: TNC_UInt32 type_count);
93:
94: /**
95: * Inform a TNCS about the set of message types the IMV is able to receive
96: *
97: * @param imv_id IMV ID assigned by TNCS
98: * @param supported_vids list of supported message vendor IDs
99: * @param supported_subtypes list of supported message subtypes
100: * @param type_count number of list elements
101: * @return TNC result code
102: */
103: TNC_Result (*report_message_types_long)(TNC_IMVID imv_id,
104: TNC_VendorIDList supported_vids,
105: TNC_MessageSubtypeList supported_subtypes,
106: TNC_UInt32 type_count);
107:
108: /**
109: * Deliver IMV Action Recommendation and IMV Evaluation Results to the TNCS
110: *
111: * @param imv_id IMV ID assigned by TNCS
112: # @param connection_id network connection ID assigned by TNCS
113: * @param rec IMV action recommendation
114: * @param eval IMV evaluation result
115: * @return TNC result code
116: */
117: TNC_Result (*provide_recommendation)(TNC_IMVID imv_id,
118: TNC_ConnectionID connection_id,
119: TNC_IMV_Action_Recommendation rec,
120: TNC_IMV_Evaluation_Result eval);
121:
122: /**
123: * Get the value of an attribute associated with a connection
124: * or with the TNCS as a whole.
125: *
126: * @param imv_id IMV ID assigned by TNCS
127: * @param connection_id network connection ID assigned by TNCS
128: * @param attribute_id attribute ID
129: * @param buffer_len length of buffer in bytes
130: * @param buffer buffer
131: * @param out_value_len size in bytes of attribute stored in buffer
132: * @return TNC result code
133: */
134: TNC_Result (*get_attribute)(TNC_IMVID imv_id,
135: TNC_ConnectionID connection_id,
136: TNC_AttributeID attribute_id,
137: TNC_UInt32 buffer_len,
138: TNC_BufferReference buffer,
139: TNC_UInt32 *out_value_len);
140:
141: /**
142: * Set the value of an attribute associated with a connection
143: * or with the TNCS as a whole.
144: *
145: * @param imv_id IMV ID assigned by TNCS
146: * @param connection_id network connection ID assigned by TNCS
147: * @param attribute_id attribute ID
148: * @param buffer_len length of buffer in bytes
149: * @param buffer buffer
150: * @return TNC result code
151: */
152: TNC_Result (*set_attribute)(TNC_IMVID imv_id,
153: TNC_ConnectionID connection_id,
154: TNC_AttributeID attribute_id,
155: TNC_UInt32 buffer_len,
156: TNC_BufferReference buffer);
157:
158: /**
159: * Reserve an additional IMV ID
160: *
161: * @param imv_id primary IMV ID assigned by TNCS
162: * @param out_imv_id additional IMV ID assigned by TNCS
163: * @return TNC result code
164: */
165: TNC_Result (*reserve_additional_id)(TNC_IMVID imv_id,
166: TNC_UInt32 *out_imv_id);
167:
168: };
169:
170: METHOD(imv_agent_t, bind_functions, TNC_Result,
171: private_imv_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
172: {
173: if (!bind_function)
174: {
175: DBG1(DBG_IMV, "TNC server failed to provide bind function");
176: return TNC_RESULT_INVALID_PARAMETER;
177: }
178: if (bind_function(this->id, "TNC_TNCS_ReportMessageTypes",
179: (void**)&this->report_message_types) != TNC_RESULT_SUCCESS)
180: {
181: this->report_message_types = NULL;
182: }
183: if (bind_function(this->id, "TNC_TNCS_ReportMessageTypesLong",
184: (void**)&this->report_message_types_long) != TNC_RESULT_SUCCESS)
185: {
186: this->report_message_types_long = NULL;
187: }
188: if (bind_function(this->id, "TNC_TNCS_RequestHandshakeRetry",
189: (void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS)
190: {
191: this->public.request_handshake_retry = NULL;
192: }
193: if (bind_function(this->id, "TNC_TNCS_SendMessage",
194: (void**)&this->public.send_message) != TNC_RESULT_SUCCESS)
195: {
196: this->public.send_message = NULL;
197: }
198: if (bind_function(this->id, "TNC_TNCS_SendMessageLong",
199: (void**)&this->public.send_message_long) != TNC_RESULT_SUCCESS)
200: {
201: this->public.send_message_long = NULL;
202: }
203: if (bind_function(this->id, "TNC_TNCS_ProvideRecommendation",
204: (void**)&this->provide_recommendation) != TNC_RESULT_SUCCESS)
205: {
206: this->provide_recommendation = NULL;
207: }
208: if (bind_function(this->id, "TNC_TNCS_GetAttribute",
209: (void**)&this->get_attribute) != TNC_RESULT_SUCCESS)
210: {
211: this->get_attribute = NULL;
212: }
213: if (bind_function(this->id, "TNC_TNCS_SetAttribute",
214: (void**)&this->set_attribute) != TNC_RESULT_SUCCESS)
215: {
216: this->set_attribute = NULL;
217: }
218: if (bind_function(this->id, "TNC_TNCC_ReserveAdditionalIMVID",
219: (void**)&this->reserve_additional_id) != TNC_RESULT_SUCCESS)
220: {
221: this->reserve_additional_id = NULL;
222: }
223:
224: if (this->report_message_types_long)
225: {
226: TNC_VendorIDList vendor_id_list;
227: TNC_MessageSubtypeList subtype_list;
228: int i;
229:
230: vendor_id_list = malloc(this->type_count * sizeof(TNC_UInt32));
231: subtype_list = malloc(this->type_count * sizeof(TNC_UInt32));
232:
233: for (i = 0; i < this->type_count; i++)
234: {
235: vendor_id_list[i] = this->supported_types[i].vendor_id;
236: subtype_list[i] = this->supported_types[i].type;
237: }
238: this->report_message_types_long(this->id, vendor_id_list, subtype_list,
239: this->type_count);
240: free(vendor_id_list);
241: free(subtype_list);
242: }
243: else if (this->report_message_types)
244: {
245: TNC_MessageTypeList type_list;
246: int i;
247:
248: type_list = malloc(this->type_count * sizeof(TNC_UInt32));
249:
250: for (i = 0; i < this->type_count; i++)
251: {
252: type_list[i] = (this->supported_types[i].vendor_id << 8) |
253: (this->supported_types[i].type & 0xff);
254: }
255: this->report_message_types(this->id, type_list, this->type_count);
256: free(type_list);
257: }
258: return TNC_RESULT_SUCCESS;
259: }
260:
261: /**
262: * finds a connection state based on its Connection ID
263: */
264: static imv_state_t* find_connection(private_imv_agent_t *this,
265: TNC_ConnectionID id)
266: {
267: enumerator_t *enumerator;
268: imv_state_t *state, *found = NULL;
269:
270: this->connection_lock->read_lock(this->connection_lock);
271: enumerator = this->connections->create_enumerator(this->connections);
272: while (enumerator->enumerate(enumerator, &state))
273: {
274: if (id == state->get_connection_id(state))
275: {
276: found = state;
277: break;
278: }
279: }
280: enumerator->destroy(enumerator);
281: this->connection_lock->unlock(this->connection_lock);
282:
283: return found;
284: }
285:
286: /**
287: * delete a connection state with a given Connection ID
288: */
289: static bool delete_connection(private_imv_agent_t *this, TNC_ConnectionID id)
290: {
291: enumerator_t *enumerator;
292: imv_state_t *state;
293: imv_session_t *session;
294: bool found = FALSE;
295:
296: this->connection_lock->write_lock(this->connection_lock);
297: enumerator = this->connections->create_enumerator(this->connections);
298: while (enumerator->enumerate(enumerator, &state))
299: {
300: if (id == state->get_connection_id(state))
301: {
302: found = TRUE;
303: session = state->get_session(state);
304: imcv_sessions->remove_session(imcv_sessions, session);
305: state->destroy(state);
306: this->connections->remove_at(this->connections, enumerator);
307: break;
308: }
309: }
310: enumerator->destroy(enumerator);
311: this->connection_lock->unlock(this->connection_lock);
312:
313: return found;
314: }
315:
316: /**
317: * Read a boolean attribute
318: */
319: static bool get_bool_attribute(private_imv_agent_t *this, TNC_ConnectionID id,
320: TNC_AttributeID attribute_id)
321: {
322: TNC_UInt32 len;
323: char buf[4];
324:
325: return this->get_attribute &&
326: this->get_attribute(this->id, id, attribute_id, 4, buf, &len) ==
327: TNC_RESULT_SUCCESS && len == 1 && *buf == 0x01;
328: }
329:
330: /**
331: * Read a string attribute
332: */
333: static char* get_str_attribute(private_imv_agent_t *this, TNC_ConnectionID id,
334: TNC_AttributeID attribute_id)
335: {
336: TNC_UInt32 len;
337: char buf[BUF_LEN];
338:
339: if (this->get_attribute &&
340: this->get_attribute(this->id, id, attribute_id, BUF_LEN, buf, &len) ==
341: TNC_RESULT_SUCCESS && len <= BUF_LEN)
342: {
343: return strdup(buf);
344: }
345: return NULL;
346: }
347:
348: /**
349: * Read an UInt32 attribute
350: */
351: static uint32_t get_uint_attribute(private_imv_agent_t *this, TNC_ConnectionID id,
352: TNC_AttributeID attribute_id)
353: {
354: TNC_UInt32 len;
355: char buf[4];
356:
357: if (this->get_attribute &&
358: this->get_attribute(this->id, id, attribute_id, 4, buf, &len) ==
359: TNC_RESULT_SUCCESS && len == 4)
360: {
361: return untoh32(buf);
362: }
363: return 0;
364: }
365:
366: /**
367: * Read a TNC identity attribute
368: */
369: static linked_list_t* get_identity_attribute(private_imv_agent_t *this,
370: TNC_ConnectionID id,
371: TNC_AttributeID attribute_id)
372: {
373: TNC_UInt32 len;
374: char buf[2048];
375: uint32_t count;
376: tncif_identity_t *tnc_id;
377: bio_reader_t *reader;
378: linked_list_t *list;
379:
380: list = linked_list_create();
381:
382: if (!this->get_attribute ||
383: this->get_attribute(this->id, id, attribute_id, sizeof(buf), buf, &len)
384: != TNC_RESULT_SUCCESS || len > sizeof(buf))
385: {
386: return list;
387: }
388:
389: reader = bio_reader_create(chunk_create(buf, len));
390: if (!reader->read_uint32(reader, &count))
391: {
392: goto end;
393: }
394: while (count--)
395: {
396: tnc_id = tncif_identity_create_empty();
397: if (!tnc_id->process(tnc_id, reader))
398: {
399: tnc_id->destroy(tnc_id);
400: goto end;
401: }
402: list->insert_last(list, tnc_id);
403: }
404:
405: end:
406: reader->destroy(reader);
407: return list;
408: }
409:
410: METHOD(imv_agent_t, create_state, TNC_Result,
411: private_imv_agent_t *this, imv_state_t *state)
412: {
413: TNC_ConnectionID conn_id;
414: char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL;
415: bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE;
416: linked_list_t *ar_identities;
417: imv_session_t *session;
418: uint32_t max_msg_len;
419:
420: conn_id = state->get_connection_id(state);
421: if (find_connection(this, conn_id))
422: {
423: DBG1(DBG_IMV, "IMV %u \"%s\" already created a state for Connection ID %u",
424: this->id, this->name, conn_id);
425: state->destroy(state);
426: return TNC_RESULT_OTHER;
427: }
428:
429: /* Get and display attributes from TNCS via IF-IMV */
430: has_long = get_bool_attribute(this, conn_id,
431: TNC_ATTRIBUTEID_HAS_LONG_TYPES);
432: has_excl = get_bool_attribute(this, conn_id,
433: TNC_ATTRIBUTEID_HAS_EXCLUSIVE);
434: has_soh = get_bool_attribute(this, conn_id,
435: TNC_ATTRIBUTEID_HAS_SOH);
436: tnccs_p = get_str_attribute(this, conn_id,
437: TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL);
438: tnccs_v = get_str_attribute(this, conn_id,
439: TNC_ATTRIBUTEID_IFTNCCS_VERSION);
440: t_p = get_str_attribute(this, conn_id,
441: TNC_ATTRIBUTEID_IFT_PROTOCOL);
442: t_v = get_str_attribute(this, conn_id,
443: TNC_ATTRIBUTEID_IFT_VERSION);
444: max_msg_len = get_uint_attribute(this, conn_id,
445: TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE);
446: ar_identities = get_identity_attribute(this, conn_id,
447: TNC_ATTRIBUTEID_AR_IDENTITIES);
448:
449: state->set_flags(state, has_long, has_excl);
450: state->set_max_msg_len(state, max_msg_len);
451:
452: DBG2(DBG_IMV, "IMV %u \"%s\" created a state for %s %s Connection ID %u: "
453: "%slong %sexcl %ssoh", this->id, this->name,
454: tnccs_p ? tnccs_p:"?", tnccs_v ? tnccs_v:"?", conn_id,
455: has_long ? "+":"-", has_excl ? "+":"-", has_soh ? "+":"-");
456: DBG2(DBG_IMV, " over %s %s with maximum PA-TNC message size of %u bytes",
457: t_p ? t_p:"?", t_v ? t_v :"?", max_msg_len);
458:
459: session = imcv_sessions->add_session(imcv_sessions, conn_id, ar_identities);
460: state->set_session(state, session);
461:
462: free(tnccs_p);
463: free(tnccs_v);
464: free(t_p);
465: free(t_v);
466:
467: /* insert state in connection list */
468: this->connection_lock->write_lock(this->connection_lock);
469: this->connections->insert_last(this->connections, state);
470: this->connection_lock->unlock(this->connection_lock);
471:
472: return TNC_RESULT_SUCCESS;
473: }
474:
475: METHOD(imv_agent_t, delete_state, TNC_Result,
476: private_imv_agent_t *this, TNC_ConnectionID connection_id)
477: {
478: if (!delete_connection(this, connection_id))
479: {
480: DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u",
481: this->id, this->name, connection_id);
482: return TNC_RESULT_FATAL;
483: }
484: DBG2(DBG_IMV, "IMV %u \"%s\" deleted the state of Connection ID %u",
485: this->id, this->name, connection_id);
486: return TNC_RESULT_SUCCESS;
487: }
488:
489: METHOD(imv_agent_t, change_state, TNC_Result,
490: private_imv_agent_t *this, TNC_ConnectionID connection_id,
491: TNC_ConnectionState new_state,
492: imv_state_t **state_p)
493: {
494: imv_state_t *state;
495: TNC_ConnectionState old_state;
496:
497: switch (new_state)
498: {
499: case TNC_CONNECTION_STATE_HANDSHAKE:
500: case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
501: case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
502: case TNC_CONNECTION_STATE_ACCESS_NONE:
503: state = find_connection(this, connection_id);
504: if (!state)
505: {
506: DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u",
507: this->id, this->name, connection_id);
508: return TNC_RESULT_FATAL;
509: }
510: old_state = state->change_state(state, new_state);
511: DBG2(DBG_IMV, "IMV %u \"%s\" changed state of Connection ID %u to '%N'",
512: this->id, this->name, connection_id,
513: TNC_Connection_State_names, new_state);
514: if (state_p)
515: {
516: *state_p = state;
517: }
518: if (new_state == TNC_CONNECTION_STATE_HANDSHAKE &&
519: old_state != TNC_CONNECTION_STATE_CREATE)
520: {
521: state->reset(state);
522: DBG2(DBG_IMV, "IMV %u \"%s\" reset state of Connection ID %u",
523: this->id, this->name, connection_id);
524: }
525: break;
526: case TNC_CONNECTION_STATE_CREATE:
527: DBG1(DBG_IMV, "state '%N' should be handled by create_state()",
528: TNC_Connection_State_names, new_state);
529: return TNC_RESULT_FATAL;
530: case TNC_CONNECTION_STATE_DELETE:
531: DBG1(DBG_IMV, "state '%N' should be handled by delete_state()",
532: TNC_Connection_State_names, new_state);
533: return TNC_RESULT_FATAL;
534: default:
535: DBG1(DBG_IMV, "IMV %u \"%s\" was notified of unknown state %u "
536: "for Connection ID %u",
537: this->id, this->name, new_state, connection_id);
538: return TNC_RESULT_INVALID_PARAMETER;
539: }
540: return TNC_RESULT_SUCCESS;
541: }
542:
543: METHOD(imv_agent_t, get_state, bool,
544: private_imv_agent_t *this, TNC_ConnectionID connection_id,
545: imv_state_t **state)
546: {
547: *state = find_connection(this, connection_id);
548: if (!*state)
549: {
550: DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u",
551: this->id, this->name, connection_id);
552: return FALSE;
553: }
554: return TRUE;
555: }
556:
557: METHOD(imv_agent_t, get_name, const char*,
558: private_imv_agent_t *this)
559: {
560: return this->name;
561: }
562:
563: METHOD(imv_agent_t, get_id, TNC_IMVID,
564: private_imv_agent_t *this)
565: {
566: return this->id;
567: }
568:
569: METHOD(imv_agent_t, reserve_additional_ids, TNC_Result,
570: private_imv_agent_t *this, int count)
571: {
572: TNC_Result result;
573: TNC_UInt32 id;
574: void *pointer;
575:
576: if (!this->reserve_additional_id)
577: {
578: DBG1(DBG_IMV, "IMV %u \"%s\" did not detect the capability to reserve "
579: "additional IMV IDs from the TNCS", this->id, this->name);
580: return TNC_RESULT_ILLEGAL_OPERATION;
581: }
582: while (count > 0)
583: {
584: result = this->reserve_additional_id(this->id, &id);
585: if (result != TNC_RESULT_SUCCESS)
586: {
587: DBG1(DBG_IMV, "IMV %u \"%s\" failed to reserve %d additional IMV IDs",
588: this->id, this->name, count);
589: return result;
590: }
591: count--;
592:
593: /* store the scalar value in the pointer */
594: pointer = (void*)(uintptr_t)id;
595: this->additional_ids->insert_last(this->additional_ids, pointer);
596: DBG2(DBG_IMV, "IMV %u \"%s\" reserved additional ID %u",
597: this->id, this->name, id);
598: }
599: return TNC_RESULT_SUCCESS;
600: }
601:
602: METHOD(imv_agent_t, count_additional_ids, int,
603: private_imv_agent_t *this)
604: {
605: return this->additional_ids->get_count(this->additional_ids);
606: }
607:
608: METHOD(imv_agent_t, create_id_enumerator, enumerator_t*,
609: private_imv_agent_t *this)
610: {
611: return this->additional_ids->create_enumerator(this->additional_ids);
612: }
613:
614: typedef struct {
615: /**
616: * implements enumerator_t
617: */
618: enumerator_t public;
619:
620: /**
621: * language length
622: */
623: TNC_UInt32 lang_len;
624:
625: /**
626: * language buffer
627: */
628: char lang_buf[BUF_LEN];
629:
630: /**
631: * position pointer into language buffer
632: */
633: char *lang_pos;
634:
635: } language_enumerator_t;
636:
637: METHOD(enumerator_t, language_enumerator_enumerate, bool,
638: language_enumerator_t *this, va_list args)
639: {
640: char *pos, *cur_lang, **lang;
641: TNC_UInt32 len;
642:
643: VA_ARGS_VGET(args, lang);
644:
645: if (!this->lang_len)
646: {
647: return FALSE;
648: }
649: cur_lang = this->lang_pos;
650: pos = strchr(this->lang_pos, ',');
651: if (pos)
652: {
653: len = pos - this->lang_pos;
654: this->lang_pos += len + 1;
655: this->lang_len -= len + 1;
656: }
657: else
658: {
659: len = this->lang_len;
660: pos = this->lang_pos + len;
661: this->lang_pos = NULL;
662: this->lang_len = 0;
663: }
664:
665: /* remove preceding whitespace */
666: while (*cur_lang == ' ' && len--)
667: {
668: cur_lang++;
669: }
670:
671: /* remove trailing whitespace */
672: while (len && *(--pos) == ' ')
673: {
674: len--;
675: }
676: cur_lang[len] = '\0';
677:
678: *lang = cur_lang;
679: return TRUE;
680: }
681:
682: METHOD(imv_agent_t, create_language_enumerator, enumerator_t*,
683: private_imv_agent_t *this, imv_state_t *state)
684: {
685: language_enumerator_t *e;
686:
687: INIT(e,
688: .public = {
689: .enumerate = enumerator_enumerate_default,
690: .venumerate = _language_enumerator_enumerate,
691: .destroy = (void*)free,
692: },
693: );
694:
695: if (!this->get_attribute ||
696: this->get_attribute(this->id, state->get_connection_id(state),
697: TNC_ATTRIBUTEID_PREFERRED_LANGUAGE, BUF_LEN,
698: e->lang_buf, &e->lang_len) != TNC_RESULT_SUCCESS ||
699: e->lang_len >= BUF_LEN)
700: {
701: e->lang_len = 0;
702: }
703: e->lang_buf[e->lang_len] = '\0';
704: e->lang_pos = e->lang_buf;
705:
706: return (enumerator_t*)e;
707: }
708:
709: METHOD(imv_agent_t, provide_recommendation, TNC_Result,
710: private_imv_agent_t *this, imv_state_t *state)
711: {
712: TNC_IMV_Action_Recommendation rec;
713: TNC_IMV_Evaluation_Result eval;
714: TNC_ConnectionID connection_id;
715: chunk_t reason_string;
716: char *reason_lang;
717: enumerator_t *e;
718:
719: state->get_recommendation(state, &rec, &eval);
720: connection_id = state->get_connection_id(state);
721:
722: /* send a reason string if action recommendation is not allow */
723: if (rec != TNC_IMV_ACTION_RECOMMENDATION_ALLOW)
724: {
725: /* find a reason string for the preferred language and set it */
726: if (this->set_attribute)
727: {
728: e = create_language_enumerator(this, state);
729: if (state->get_reason_string(state, e, &reason_string, &reason_lang))
730: {
731: this->set_attribute(this->id, connection_id,
732: TNC_ATTRIBUTEID_REASON_STRING,
733: reason_string.len, reason_string.ptr);
734: this->set_attribute(this->id, connection_id,
735: TNC_ATTRIBUTEID_REASON_LANGUAGE,
736: strlen(reason_lang), reason_lang);
737: }
738: e->destroy(e);
739: }
740: }
741: return this->provide_recommendation(this->id, connection_id, rec, eval);
742: }
743:
744: METHOD(imv_agent_t, add_non_fatal_attr_type, void,
745: private_imv_agent_t *this, pen_type_t type)
746: {
747: pen_type_t *type_p;
748:
749: type_p = malloc_thing(pen_type_t);
750: *type_p = type;
751: this->non_fatal_attr_types->insert_last(this->non_fatal_attr_types, type_p);
752: }
753:
754: METHOD(imv_agent_t, get_non_fatal_attr_types, linked_list_t*,
755: private_imv_agent_t *this)
756: {
757: return this->non_fatal_attr_types;
758: }
759:
760: METHOD(imv_agent_t, destroy, void,
761: private_imv_agent_t *this)
762: {
763: DBG1(DBG_IMV, "IMV %u \"%s\" terminated", this->id, this->name);
764: this->additional_ids->destroy(this->additional_ids);
765: this->non_fatal_attr_types->destroy_function(this->non_fatal_attr_types,
766: free);
767: this->connections->destroy_offset(this->connections,
768: offsetof(imv_state_t, destroy));
769: this->connection_lock->destroy(this->connection_lock);
770: free(this);
771:
772: /* decrease the reference count or terminate */
773: libimcv_deinit();
774: }
775:
776: /**
777: * Described in header.
778: */
779: imv_agent_t *imv_agent_create(const char *name,
780: pen_type_t *supported_types, uint32_t type_count,
781: TNC_IMVID id, TNC_Version *actual_version)
782: {
783: private_imv_agent_t *this;
784:
785: /* initialize or increase the reference count */
786: if (!libimcv_init(TRUE))
787: {
788: return NULL;
789: }
790:
791: INIT(this,
792: .public = {
793: .bind_functions = _bind_functions,
794: .create_state = _create_state,
795: .delete_state = _delete_state,
796: .change_state = _change_state,
797: .get_state = _get_state,
798: .get_name = _get_name,
799: .get_id = _get_id,
800: .reserve_additional_ids = _reserve_additional_ids,
801: .count_additional_ids = _count_additional_ids,
802: .create_id_enumerator = _create_id_enumerator,
803: .create_language_enumerator = _create_language_enumerator,
804: .provide_recommendation = _provide_recommendation,
805: .add_non_fatal_attr_type = _add_non_fatal_attr_type,
806: .get_non_fatal_attr_types = _get_non_fatal_attr_types,
807: .destroy = _destroy,
808: },
809: .name = name,
810: .supported_types = supported_types,
811: .type_count = type_count,
812: .id = id,
813: .additional_ids = linked_list_create(),
814: .non_fatal_attr_types = linked_list_create(),
815: .connections = linked_list_create(),
816: .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
817: );
818:
819: *actual_version = TNC_IFIMV_VERSION_1;
820: DBG1(DBG_IMV, "IMV %u \"%s\" initialized", this->id, this->name);
821:
822: return &this->public;
823: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>