Annotation of embedaddon/strongswan/src/libimcv/imv/imv_agent.c, revision 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>