Annotation of embedaddon/strongswan/src/libimcv/imc/imc_agent.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2011-2014 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 "imc_agent.h"
18:
19: #include <tncif_names.h>
20:
21: #include <utils/debug.h>
22: #include <threading/rwlock.h>
23:
24: typedef struct private_imc_agent_t private_imc_agent_t;
25:
26: /**
27: * Private data of an imc_agent_t object.
28: */
29: struct private_imc_agent_t {
30:
31: /**
32: * Public members of imc_agent_t
33: */
34: imc_agent_t public;
35:
36: /**
37: * name of IMC
38: */
39: const char *name;
40:
41: /**
42: * message types registered by IMC
43: */
44: pen_type_t *supported_types;
45:
46: /**
47: * number of message types registered by IMC
48: */
49: uint32_t type_count;
50:
51: /**
52: * ID of IMC as assigned by TNCC
53: */
54: TNC_IMCID id;
55:
56: /**
57: * List of additional IMC IDs assigned by TNCC
58: */
59: linked_list_t *additional_ids;
60:
61: /**
62: * list of non-fatal unsupported PA-TNC attribute types
63: */
64: linked_list_t *non_fatal_attr_types;
65:
66: /**
67: * list of TNCC connection entries
68: */
69: linked_list_t *connections;
70:
71: /**
72: * rwlock to lock TNCC connection entries
73: */
74: rwlock_t *connection_lock;
75:
76: /**
77: * Is the transport protocol PT-TLS?
78: */
79: bool has_pt_tls;
80:
81: /**
82: * Inform a TNCC about the set of message types the IMC is able to receive
83: *
84: * @param imc_id IMC ID assigned by TNCC
85: * @param supported_types list of supported message types
86: * @param type_count number of list elements
87: * @return TNC result code
88: */
89: TNC_Result (*report_message_types)(TNC_IMCID imc_id,
90: TNC_MessageTypeList supported_types,
91: TNC_UInt32 type_count);
92:
93: /**
94: * Inform a TNCC about the set of message types the IMC is able to receive
95: *
96: * @param imc_id IMC ID assigned by TNCC
97: * @param supported_vids list of supported message vendor IDs
98: * @param supported_subtypes list of supported message subtypes
99: * @param type_count number of list elements
100: * @return TNC result code
101: */
102: TNC_Result (*report_message_types_long)(TNC_IMCID imc_id,
103: TNC_VendorIDList supported_vids,
104: TNC_MessageSubtypeList supported_subtypes,
105: TNC_UInt32 type_count);
106:
107: /**
108: * Get the value of an attribute associated with a connection
109: * or with the TNCC as a whole.
110: *
111: * @param imc_id IMC ID assigned by TNCC
112: * @param connection_id network connection ID assigned by TNCC
113: * @param attribute_id attribute ID
114: * @param buffer_len length of buffer in bytes
115: * @param buffer buffer
116: * @param out_value_len size in bytes of attribute stored in buffer
117: * @return TNC result code
118: */
119: TNC_Result (*get_attribute)(TNC_IMCID imc_id,
120: TNC_ConnectionID connection_id,
121: TNC_AttributeID attribute_id,
122: TNC_UInt32 buffer_len,
123: TNC_BufferReference buffer,
124: TNC_UInt32 *out_value_len);
125:
126: /**
127: * Set the value of an attribute associated with a connection
128: * or with the TNCC as a whole.
129: *
130: * @param imc_id IMV ID assigned by TNCC
131: * @param connection_id network connection ID assigned by TNCC
132: * @param attribute_id attribute ID
133: * @param buffer_len length of buffer in bytes
134: * @param buffer buffer
135: * @return TNC result code
136: */
137: TNC_Result (*set_attribute)(TNC_IMCID imc_id,
138: TNC_ConnectionID connection_id,
139: TNC_AttributeID attribute_id,
140: TNC_UInt32 buffer_len,
141: TNC_BufferReference buffer);
142:
143: /**
144: * Reserve an additional IMC ID
145: *
146: * @param imc_id primary IMC ID assigned by TNCC
147: * @param out_imc_id additional IMC ID assigned by TNCC
148: * @return TNC result code
149: */
150: TNC_Result (*reserve_additional_id)(TNC_IMCID imc_id,
151: TNC_UInt32 *out_imc_id);
152:
153: };
154:
155: METHOD(imc_agent_t, bind_functions, TNC_Result,
156: private_imc_agent_t *this, TNC_TNCC_BindFunctionPointer bind_function)
157: {
158: if (!bind_function)
159: {
160: DBG1(DBG_IMC, "TNC client failed to provide bind function");
161: return TNC_RESULT_INVALID_PARAMETER;
162: }
163: if (bind_function(this->id, "TNC_TNCC_ReportMessageTypes",
164: (void**)&this->report_message_types) != TNC_RESULT_SUCCESS)
165: {
166: this->report_message_types = NULL;
167: }
168: if (bind_function(this->id, "TNC_TNCC_ReportMessageTypesLong",
169: (void**)&this->report_message_types_long) != TNC_RESULT_SUCCESS)
170: {
171: this->report_message_types_long = NULL;
172: }
173: if (bind_function(this->id, "TNC_TNCC_RequestHandshakeRetry",
174: (void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS)
175: {
176: this->public.request_handshake_retry = NULL;
177: }
178: if (bind_function(this->id, "TNC_TNCC_SendMessage",
179: (void**)&this->public.send_message) != TNC_RESULT_SUCCESS)
180: {
181: this->public.send_message = NULL;
182: }
183: if (bind_function(this->id, "TNC_TNCC_SendMessageLong",
184: (void**)&this->public.send_message_long) != TNC_RESULT_SUCCESS)
185: {
186: this->public.send_message_long = NULL;
187: }
188: if (bind_function(this->id, "TNC_TNCC_GetAttribute",
189: (void**)&this->get_attribute) != TNC_RESULT_SUCCESS)
190: {
191: this->get_attribute = NULL;
192: }
193: if (bind_function(this->id, "TNC_TNCC_SetAttribute",
194: (void**)&this->set_attribute) != TNC_RESULT_SUCCESS)
195: {
196: this->set_attribute = NULL;
197: }
198: if (bind_function(this->id, "TNC_TNCC_ReserveAdditionalIMCID",
199: (void**)&this->reserve_additional_id) != TNC_RESULT_SUCCESS)
200: {
201: this->reserve_additional_id = NULL;
202: }
203:
204: if (this->report_message_types_long)
205: {
206: TNC_VendorIDList vendor_id_list;
207: TNC_MessageSubtypeList subtype_list;
208: int i;
209:
210: vendor_id_list = malloc(this->type_count * sizeof(TNC_UInt32));
211: subtype_list = malloc(this->type_count * sizeof(TNC_UInt32));
212:
213: for (i = 0; i < this->type_count; i++)
214: {
215: vendor_id_list[i] = this->supported_types[i].vendor_id;
216: subtype_list[i] = this->supported_types[i].type;
217: }
218: this->report_message_types_long(this->id, vendor_id_list, subtype_list,
219: this->type_count);
220: free(vendor_id_list);
221: free(subtype_list);
222: }
223: else if (this->report_message_types)
224: {
225: TNC_MessageTypeList type_list;
226: int i;
227:
228: type_list = malloc(this->type_count * sizeof(TNC_UInt32));
229:
230: for (i = 0; i < this->type_count; i++)
231: {
232: type_list[i] = (this->supported_types[i].vendor_id << 8) |
233: (this->supported_types[i].type & 0xff);
234: }
235: this->report_message_types(this->id, type_list, this->type_count);
236: free(type_list);
237: }
238: return TNC_RESULT_SUCCESS;
239: }
240:
241: /**
242: * finds a connection state based on its Connection ID
243: */
244: static imc_state_t* find_connection(private_imc_agent_t *this,
245: TNC_ConnectionID id)
246: {
247: enumerator_t *enumerator;
248: imc_state_t *state, *found = NULL;
249:
250: this->connection_lock->read_lock(this->connection_lock);
251: enumerator = this->connections->create_enumerator(this->connections);
252: while (enumerator->enumerate(enumerator, &state))
253: {
254: if (id == state->get_connection_id(state))
255: {
256: found = state;
257: break;
258: }
259: }
260: enumerator->destroy(enumerator);
261: this->connection_lock->unlock(this->connection_lock);
262:
263: return found;
264: }
265:
266: /**
267: * delete a connection state with a given Connection ID
268: */
269: static bool delete_connection(private_imc_agent_t *this, TNC_ConnectionID id)
270: {
271: enumerator_t *enumerator;
272: imc_state_t *state;
273: bool found = FALSE;
274:
275: this->connection_lock->write_lock(this->connection_lock);
276: enumerator = this->connections->create_enumerator(this->connections);
277: while (enumerator->enumerate(enumerator, &state))
278: {
279: if (id == state->get_connection_id(state))
280: {
281: found = TRUE;
282: state->destroy(state);
283: this->connections->remove_at(this->connections, enumerator);
284: break;
285: }
286: }
287: enumerator->destroy(enumerator);
288: this->connection_lock->unlock(this->connection_lock);
289:
290: return found;
291: }
292:
293: /**
294: * Read a boolean attribute
295: */
296: static bool get_bool_attribute(private_imc_agent_t *this, TNC_ConnectionID id,
297: TNC_AttributeID attribute_id)
298: {
299: TNC_UInt32 len;
300: char buf[4];
301:
302: return this->get_attribute &&
303: this->get_attribute(this->id, id, attribute_id, 4, buf, &len) ==
304: TNC_RESULT_SUCCESS && len == 1 && *buf == 0x01;
305: }
306:
307: /**
308: * Read a string attribute
309: */
310: static char* get_str_attribute(private_imc_agent_t *this, TNC_ConnectionID id,
311: TNC_AttributeID attribute_id)
312: {
313: TNC_UInt32 len;
314: char buf[BUF_LEN];
315:
316: if (this->get_attribute &&
317: this->get_attribute(this->id, id, attribute_id, BUF_LEN, buf, &len) ==
318: TNC_RESULT_SUCCESS && len <= BUF_LEN)
319: {
320: return strdup(buf);
321: }
322: return NULL;
323: }
324:
325: /**
326: * Read an UInt32 attribute
327: */
328: static uint32_t get_uint_attribute(private_imc_agent_t *this, TNC_ConnectionID id,
329: TNC_AttributeID attribute_id)
330: {
331: TNC_UInt32 len;
332: char buf[4];
333:
334: if (this->get_attribute &&
335: this->get_attribute(this->id, id, attribute_id, 4, buf, &len) ==
336: TNC_RESULT_SUCCESS && len == 4)
337: {
338: return untoh32(buf);
339: }
340: return 0;
341: }
342:
343: METHOD(imc_agent_t, create_state, TNC_Result,
344: private_imc_agent_t *this, imc_state_t *state)
345: {
346: TNC_ConnectionID conn_id;
347: char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL;
348: bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE;
349: uint32_t max_msg_len;
350:
351: conn_id = state->get_connection_id(state);
352: if (find_connection(this, conn_id))
353: {
354: DBG1(DBG_IMC, "IMC %u \"%s\" already created a state for Connection ID %u",
355: this->id, this->name, conn_id);
356: state->destroy(state);
357: return TNC_RESULT_OTHER;
358: }
359:
360: /* Get and display attributes from TNCC via IF-IMC */
361: has_long = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_LONG_TYPES);
362: has_excl = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_EXCLUSIVE);
363: has_soh = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_SOH);
364: tnccs_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL);
365: tnccs_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_VERSION);
366: t_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_PROTOCOL);
367: t_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_VERSION);
368: max_msg_len = get_uint_attribute(this, conn_id, TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE);
369:
370: state->set_flags(state, has_long, has_excl);
371: state->set_max_msg_len(state, max_msg_len);
372:
373: DBG2(DBG_IMC, "IMC %u \"%s\" created a state for %s %s Connection ID %u: "
374: "%slong %sexcl %ssoh", this->id, this->name,
375: tnccs_p ? tnccs_p:"?", tnccs_v ? tnccs_v:"?", conn_id,
376: has_long ? "+":"-", has_excl ? "+":"-", has_soh ? "+":"-");
377: DBG2(DBG_IMC, " over %s %s with maximum PA-TNC message size of %u bytes",
378: t_p ? t_p:"?", t_v ? t_v :"?", max_msg_len);
379:
380: this->has_pt_tls = streq(t_p, "IF-T for TLS");
381:
382: free(tnccs_p);
383: free(tnccs_v);
384: free(t_p);
385: free(t_v);
386:
387: this->connection_lock->write_lock(this->connection_lock);
388: this->connections->insert_last(this->connections, state);
389: this->connection_lock->unlock(this->connection_lock);
390: return TNC_RESULT_SUCCESS;
391: }
392:
393: METHOD(imc_agent_t, delete_state, TNC_Result,
394: private_imc_agent_t *this, TNC_ConnectionID connection_id)
395: {
396: if (!delete_connection(this, connection_id))
397: {
398: DBG1(DBG_IMC, "IMC %u \"%s\" has no state for Connection ID %u",
399: this->id, this->name, connection_id);
400: return TNC_RESULT_FATAL;
401: }
402: DBG2(DBG_IMC, "IMC %u \"%s\" deleted the state of Connection ID %u",
403: this->id, this->name, connection_id);
404: return TNC_RESULT_SUCCESS;
405: }
406:
407: METHOD(imc_agent_t, change_state, TNC_Result,
408: private_imc_agent_t *this, TNC_ConnectionID connection_id,
409: TNC_ConnectionState new_state,
410: imc_state_t **state_p)
411: {
412: imc_state_t *state;
413: TNC_ConnectionState old_state;
414:
415: switch (new_state)
416: {
417: case TNC_CONNECTION_STATE_HANDSHAKE:
418: case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
419: case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
420: case TNC_CONNECTION_STATE_ACCESS_NONE:
421: state = find_connection(this, connection_id);
422:
423: if (!state)
424: {
425: DBG1(DBG_IMC, "IMC %u \"%s\" has no state for Connection ID %u",
426: this->id, this->name, connection_id);
427: return TNC_RESULT_FATAL;
428: }
429: old_state = state->change_state(state, new_state);
430: DBG2(DBG_IMC, "IMC %u \"%s\" changed state of Connection ID %u to '%N'",
431: this->id, this->name, connection_id,
432: TNC_Connection_State_names, new_state);
433: if (state_p)
434: {
435: *state_p = state;
436: }
437: if (new_state == TNC_CONNECTION_STATE_HANDSHAKE &&
438: old_state != TNC_CONNECTION_STATE_CREATE)
439: {
440: state->reset(state);
441: DBG2(DBG_IMC, "IMC %u \"%s\" reset state of Connection ID %u",
442: this->id, this->name, connection_id);
443: }
444: break;
445: case TNC_CONNECTION_STATE_CREATE:
446: DBG1(DBG_IMC, "state '%N' should be handled by create_state()",
447: TNC_Connection_State_names, new_state);
448: return TNC_RESULT_FATAL;
449: case TNC_CONNECTION_STATE_DELETE:
450: DBG1(DBG_IMC, "state '%N' should be handled by delete_state()",
451: TNC_Connection_State_names, new_state);
452: return TNC_RESULT_FATAL;
453: default:
454: DBG1(DBG_IMC, "IMC %u \"%s\" was notified of unknown state %u "
455: "for Connection ID %u",
456: this->id, this->name, new_state, connection_id);
457: return TNC_RESULT_INVALID_PARAMETER;
458: }
459: return TNC_RESULT_SUCCESS;
460: }
461:
462: METHOD(imc_agent_t, get_state, bool,
463: private_imc_agent_t *this, TNC_ConnectionID connection_id,
464: imc_state_t **state)
465: {
466: *state = find_connection(this, connection_id);
467: if (!*state)
468: {
469: DBG1(DBG_IMC, "IMC %u \"%s\" has no state for Connection ID %u",
470: this->id, this->name, connection_id);
471: return FALSE;
472: }
473: return TRUE;
474: }
475:
476: METHOD(imc_agent_t, get_name, const char*,
477: private_imc_agent_t *this)
478: {
479: return this->name;
480: }
481:
482: METHOD(imc_agent_t, get_id, TNC_IMCID,
483: private_imc_agent_t *this)
484: {
485: return this->id;
486: }
487:
488: METHOD(imc_agent_t, reserve_additional_ids, TNC_Result,
489: private_imc_agent_t *this, int count)
490: {
491: TNC_Result result;
492: TNC_UInt32 id;
493: void *pointer;
494:
495: if (!this->reserve_additional_id)
496: {
497: DBG1(DBG_IMC, "IMC %u \"%s\" did not detect the capability to reserve "
498: "additional IMC IDs from the TNCC", this->id, this->name);
499: return TNC_RESULT_ILLEGAL_OPERATION;
500: }
501: while (count > 0)
502: {
503: result = this->reserve_additional_id(this->id, &id);
504: if (result != TNC_RESULT_SUCCESS)
505: {
506: DBG1(DBG_IMC, "IMC %u \"%s\" failed to reserve %d additional IMC IDs",
507: this->id, this->name, count);
508: return result;
509: }
510: count--;
511:
512: /* store the scalar value in the pointer */
513: pointer = (void*)(uintptr_t)id;
514: this->additional_ids->insert_last(this->additional_ids, pointer);
515: DBG2(DBG_IMC, "IMC %u \"%s\" reserved additional ID %u",
516: this->id, this->name, id);
517: }
518: return TNC_RESULT_SUCCESS;
519: }
520:
521: METHOD(imc_agent_t, count_additional_ids, int,
522: private_imc_agent_t *this)
523: {
524: return this->additional_ids->get_count(this->additional_ids);
525: }
526:
527: METHOD(imc_agent_t, create_id_enumerator, enumerator_t*,
528: private_imc_agent_t *this)
529: {
530: return this->additional_ids->create_enumerator(this->additional_ids);
531: }
532:
533: METHOD(imc_agent_t, add_non_fatal_attr_type, void,
534: private_imc_agent_t *this, pen_type_t type)
535: {
536: pen_type_t *type_p;
537:
538: type_p = malloc_thing(pen_type_t);
539: *type_p = type;
540: this->non_fatal_attr_types->insert_last(this->non_fatal_attr_types, type_p);
541: }
542:
543: METHOD(imc_agent_t, get_non_fatal_attr_types, linked_list_t*,
544: private_imc_agent_t *this)
545: {
546: return this->non_fatal_attr_types;
547: }
548:
549: METHOD(imc_agent_t, has_pt_tls, bool,
550: private_imc_agent_t *this)
551: {
552: return this->has_pt_tls;
553: }
554:
555: METHOD(imc_agent_t, destroy, void,
556: private_imc_agent_t *this)
557: {
558: DBG1(DBG_IMC, "IMC %u \"%s\" terminated", this->id, this->name);
559: this->additional_ids->destroy(this->additional_ids);
560: this->non_fatal_attr_types->destroy_function(this->non_fatal_attr_types,
561: free);
562: this->connections->destroy_function(this->connections, free);
563: this->connection_lock->destroy(this->connection_lock);
564: free(this);
565:
566: /* decrease the reference count or terminate */
567: libimcv_deinit();
568: }
569:
570: /**
571: * Described in header.
572: */
573: imc_agent_t *imc_agent_create(const char *name,
574: pen_type_t *supported_types, uint32_t type_count,
575: TNC_IMCID id, TNC_Version *actual_version)
576: {
577: private_imc_agent_t *this;
578:
579: /* initialize or increase the reference count */
580: if (!libimcv_init(FALSE))
581: {
582: return NULL;
583: }
584:
585: INIT(this,
586: .public = {
587: .bind_functions = _bind_functions,
588: .create_state = _create_state,
589: .delete_state = _delete_state,
590: .change_state = _change_state,
591: .get_state = _get_state,
592: .get_name = _get_name,
593: .get_id = _get_id,
594: .reserve_additional_ids = _reserve_additional_ids,
595: .count_additional_ids = _count_additional_ids,
596: .create_id_enumerator = _create_id_enumerator,
597: .add_non_fatal_attr_type = _add_non_fatal_attr_type,
598: .get_non_fatal_attr_types = _get_non_fatal_attr_types,
599: .has_pt_tls = _has_pt_tls,
600: .destroy = _destroy,
601: },
602: .name = name,
603: .supported_types = supported_types,
604: .type_count = type_count,
605: .id = id,
606: .additional_ids = linked_list_create(),
607: .non_fatal_attr_types = linked_list_create(),
608: .connections = linked_list_create(),
609: .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
610: );
611:
612: *actual_version = TNC_IFIMC_VERSION_1;
613: DBG1(DBG_IMC, "IMC %u \"%s\" initialized", this->id, this->name);
614:
615: return &this->public;
616: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>