Return to imc_os.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libimcv / plugins / imc_os |
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 "imc_os_state.h" 17: 18: #include <imc/imc_agent.h> 19: #include <imc/imc_msg.h> 20: #include <imc/imc_os_info.h> 21: #include <generic/generic_attr_bool.h> 22: #include <generic/generic_attr_string.h> 23: #include <ietf/ietf_attr.h> 24: #include <ietf/ietf_attr_attr_request.h> 25: #include "ietf/ietf_attr_fwd_enabled.h" 26: #include <ietf/ietf_attr_installed_packages.h> 27: #include <ietf/ietf_attr_numeric_version.h> 28: #include <ietf/ietf_attr_op_status.h> 29: #include <ietf/ietf_attr_product_info.h> 30: #include <ietf/ietf_attr_string_version.h> 31: #include <ita/ita_attr.h> 32: #include <ita/ita_attr_get_settings.h> 33: #include <ita/ita_attr_settings.h> 34: 35: #include <tncif_pa_subtypes.h> 36: 37: #include <pen/pen.h> 38: #include <utils/debug.h> 39: 40: /* IMC definitions */ 41: 42: static const char imc_name[] = "OS"; 43: 44: static pen_type_t msg_types[] = { 45: { PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM } 46: }; 47: 48: static imc_agent_t *imc_os; 49: static imc_os_info_t *os; 50: 51: /** 52: * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3 53: */ 54: TNC_Result TNC_IMC_API TNC_IMC_Initialize(TNC_IMCID imc_id, 55: TNC_Version min_version, 56: TNC_Version max_version, 57: TNC_Version *actual_version) 58: { 59: if (imc_os) 60: { 61: DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name); 62: return TNC_RESULT_ALREADY_INITIALIZED; 63: } 64: imc_os = imc_agent_create(imc_name, msg_types, countof(msg_types), 65: imc_id, actual_version); 66: if (!imc_os) 67: { 68: return TNC_RESULT_FATAL; 69: } 70: 71: os = imc_os_info_create(); 72: if (!os) 73: { 74: imc_os->destroy(imc_os); 75: imc_os = NULL; 76: 77: return TNC_RESULT_FATAL; 78: } 79: 80: if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1) 81: { 82: DBG1(DBG_IMC, "no common IF-IMC version"); 83: return TNC_RESULT_NO_COMMON_VERSION; 84: } 85: return TNC_RESULT_SUCCESS; 86: } 87: 88: /** 89: * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3 90: */ 91: TNC_Result TNC_IMC_API TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, 92: TNC_ConnectionID connection_id, TNC_ConnectionState new_state) 93: { 94: imc_state_t *state; 95: 96: if (!imc_os) 97: { 98: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); 99: return TNC_RESULT_NOT_INITIALIZED; 100: } 101: switch (new_state) 102: { 103: case TNC_CONNECTION_STATE_CREATE: 104: state = imc_os_state_create(connection_id); 105: return imc_os->create_state(imc_os, state); 106: case TNC_CONNECTION_STATE_DELETE: 107: return imc_os->delete_state(imc_os, connection_id); 108: default: 109: return imc_os->change_state(imc_os, connection_id, 110: new_state, NULL); 111: } 112: } 113: 114: /** 115: * Add IETF Product Information attribute to the send queue 116: */ 117: static void add_product_info(imc_msg_t *msg) 118: { 119: pa_tnc_attr_t *attr; 120: os_type_t os_type; 121: pen_t vendor_id = PEN_IETF; 122: int i; 123: 124: typedef struct vendor_pen_t { 125: os_type_t os_type; 126: pen_t pen; 127: } vendor_pen_t; 128: 129: vendor_pen_t vendor_pens[] = { 130: { OS_TYPE_DEBIAN, PEN_DEBIAN }, 131: { OS_TYPE_UBUNTU, PEN_CANONICAL }, 132: { OS_TYPE_FEDORA, PEN_FEDORA }, 133: { OS_TYPE_REDHAT, PEN_REDHAT }, 134: { OS_TYPE_ANDROID, PEN_GOOGLE } 135: }; 136: 137: os_type = os->get_type(os); 138: for (i = 0; i < countof(vendor_pens); i++) 139: { 140: if (os_type == vendor_pens[i].os_type) 141: { 142: vendor_id = vendor_pens[i].pen; 143: break; 144: } 145: } 146: attr = ietf_attr_product_info_create(vendor_id, 0, os->get_name(os)); 147: msg->add_attribute(msg, attr); 148: } 149: 150: /** 151: * Add IETF Numeric Version attribute to the send queue 152: */ 153: static void add_numeric_version(imc_msg_t *msg) 154: { 155: pa_tnc_attr_t *attr; 156: uint32_t major, minor; 157: 158: os->get_numeric_version(os, &major, &minor); 159: DBG1(DBG_IMC, "operating system numeric version is %d.%d", 160: major, minor); 161: 162: attr = ietf_attr_numeric_version_create(major, minor, 0, 0, 0); 163: msg->add_attribute(msg, attr); 164: } 165: 166: /** 167: * Add IETF String Version attribute to the send queue 168: */ 169: static void add_string_version(imc_msg_t *msg) 170: { 171: pa_tnc_attr_t *attr; 172: 173: attr = ietf_attr_string_version_create(os->get_version(os), 174: chunk_empty, chunk_empty); 175: msg->add_attribute(msg, attr); 176: } 177: 178: /** 179: * Add IETF Operational Status attribute to the send queue 180: */ 181: static void add_op_status(imc_msg_t *msg) 182: { 183: pa_tnc_attr_t *attr; 184: time_t uptime, last_boot; 185: 186: uptime = os->get_uptime(os); 187: last_boot = uptime ? time(NULL) - uptime : UNDEFINED_TIME; 188: if (last_boot != UNDEFINED_TIME) 189: { 190: DBG1(DBG_IMC, "last boot: %T, %u s ago", &last_boot, TRUE, uptime); 191: } 192: attr = ietf_attr_op_status_create(OP_STATUS_OPERATIONAL, 193: OP_RESULT_SUCCESSFUL, last_boot); 194: msg->add_attribute(msg, attr); 195: } 196: 197: /** 198: * Add IETF Forwarding Enabled attribute to the send queue 199: */ 200: static void add_fwd_enabled(imc_msg_t *msg) 201: { 202: pa_tnc_attr_t *attr; 203: os_fwd_status_t fwd_status; 204: 205: fwd_status = os->get_fwd_status(os); 206: DBG1(DBG_IMC, "IPv4 forwarding is %N", os_fwd_status_names, fwd_status); 207: attr = ietf_attr_fwd_enabled_create(fwd_status, 208: pen_type_create(PEN_IETF, IETF_ATTR_FORWARDING_ENABLED)); 209: msg->add_attribute(msg, attr); 210: } 211: 212: /** 213: * Add IETF Factory Default Password Enabled attribute to the send queue 214: */ 215: static void add_default_pwd_enabled(imc_msg_t *msg) 216: { 217: pa_tnc_attr_t *attr; 218: bool status; 219: 220: status = os->get_default_pwd_status(os); 221: DBG1(DBG_IMC, "factory default password is %sabled", status ? "en" : "dis"); 222: attr = generic_attr_bool_create(status, 223: pen_type_create(PEN_IETF, IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED)); 224: msg->add_attribute(msg, attr); 225: } 226: 227: /** 228: * Add ITA Device ID attribute to the send queue 229: */ 230: static void add_device_id(imc_msg_t *msg) 231: { 232: pa_tnc_attr_t *attr; 233: chunk_t chunk, value = chunk_empty, keyid; 234: char *name, *device_id, *device_handle, *cert_path; 235: certificate_t *cert = NULL; 236: private_key_t *privkey = NULL; 237: public_key_t *pubkey; 238: 239: /* Get the device ID as a character string */ 240: device_id = lib->settings->get_str(lib->settings, 241: "%s.plugins.imc-os.device_id", NULL, lib->ns); 242: if (device_id) 243: { 244: value = chunk_clone(chunk_from_str(device_id)); 245: } 246: 247: if (value.len == 0) 248: { 249: /* Derive the device ID from a private key bound to a smartcard or TPM */ 250: device_handle = lib->settings->get_str(lib->settings, 251: "%s.plugins.imc-os.device_handle", NULL, lib->ns); 252: if (device_handle) 253: { 254: chunk = chunk_from_hex( 255: chunk_create(device_handle, strlen(device_handle)), NULL); 256: privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY, 257: BUILD_PKCS11_KEYID, chunk, BUILD_END); 258: free(chunk.ptr); 259: 260: if (privkey) 261: { 262: if (privkey->get_fingerprint(privkey, KEYID_PUBKEY_INFO_SHA1, 263: &keyid)) 264: { 265: value = chunk_to_hex(keyid, NULL, FALSE); 266: } 267: privkey->destroy(privkey); 268: 269: } 270: } 271: } 272: 273: if (value.len == 0) 274: { 275: /* Derive the device ID from a raw public key */ 276: cert_path = lib->settings->get_str(lib->settings, 277: "%s.plugins.imc-os.device_pubkey", NULL, lib->ns); 278: if (cert_path) 279: { 280: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, 281: CERT_TRUSTED_PUBKEY, BUILD_FROM_FILE, 282: cert_path, BUILD_END); 283: if (cert) 284: { 285: DBG2(DBG_IMC, "loaded device public key from '%s'", cert_path); 286: } 287: else 288: { 289: DBG1(DBG_IMC, "loading device public key from '%s' failed", 290: cert_path); 291: } 292: } 293: 294: if (!cert) 295: { 296: /* Derive the device ID from the public key contained in a certificate */ 297: cert_path = lib->settings->get_str(lib->settings, 298: "%s.plugins.imc-os.device_cert", NULL, lib->ns); 299: if (cert_path) 300: { 301: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, 302: CERT_X509, BUILD_FROM_FILE, 303: cert_path, BUILD_END); 304: if (cert) 305: { 306: DBG2(DBG_IMC, "loaded device certificate from '%s'", cert_path); 307: } 308: else 309: { 310: DBG1(DBG_IMC, "loading device certificate from '%s' failed", 311: cert_path); 312: } 313: } 314: } 315: 316: /* Compute the SHA-1 keyid of the retrieved device public key */ 317: if (cert) 318: { 319: pubkey = cert->get_public_key(cert); 320: if (pubkey) 321: { 322: if (pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, 323: &keyid)) 324: { 325: value = chunk_to_hex(keyid, NULL, FALSE); 326: } 327: pubkey->destroy(pubkey); 328: } 329: cert->destroy(cert); 330: } 331: } 332: 333: if (value.len == 0) 334: { 335: /* Derive the device ID from some unique OS settings */ 336: name = os->get_type(os) == OS_TYPE_ANDROID ? 337: "android_id" : "/var/lib/dbus/machine-id"; 338: value = os->get_setting(os, name); 339: 340: /* Trim trailing newline character */ 341: if (value.len > 0 && value.ptr[value.len - 1] == '\n') 342: { 343: value.len--; 344: } 345: } 346: 347: if (value.len == 0) 348: { 349: DBG1(DBG_IMC, "no device ID available"); 350: return; 351: } 352: 353: DBG1(DBG_IMC, "device ID is %.*s", value.len, value.ptr); 354: attr = generic_attr_string_create(value, pen_type_create(PEN_ITA, 355: ITA_ATTR_DEVICE_ID)); 356: msg->add_attribute(msg, attr); 357: free(value.ptr); 358: } 359: 360: /** 361: * Add an IETF Installed Packages attribute to the send queue 362: */ 363: static void add_installed_packages(imc_state_t *state, imc_msg_t *msg) 364: { 365: pa_tnc_attr_t *attr; 366: ietf_attr_installed_packages_t *attr_cast; 367: enumerator_t *enumerator; 368: chunk_t name, version; 369: 370: enumerator = os->create_package_enumerator(os); 371: if (!enumerator) 372: { 373: return; 374: } 375: attr = ietf_attr_installed_packages_create(); 376: 377: while (enumerator->enumerate(enumerator, &name, &version)) 378: { 379: DBG2(DBG_IMC, "package '%.*s' (%.*s)", 380: name.len, name.ptr, version.len, version.ptr); 381: attr_cast = (ietf_attr_installed_packages_t*)attr; 382: attr_cast->add(attr_cast, name, version); 383: } 384: enumerator->destroy(enumerator); 385: 386: msg->add_attribute(msg, attr); 387: } 388: 389: /** 390: * Add ITA Settings attribute to the send queue 391: */ 392: static void add_settings(enumerator_t *enumerator, imc_msg_t *msg) 393: { 394: pa_tnc_attr_t *attr = NULL; 395: ita_attr_settings_t *attr_cast; 396: chunk_t value; 397: char *name; 398: bool first = TRUE; 399: 400: while (enumerator->enumerate(enumerator, &name)) 401: { 402: DBG1(DBG_IMC, "setting '%s'", name); 403: 404: value = os->get_setting(os, name); 405: if (!value.ptr) 406: { 407: continue; 408: } 409: if (first) 410: { 411: attr = ita_attr_settings_create(); 412: first = FALSE; 413: } 414: attr_cast = (ita_attr_settings_t*)attr; 415: attr_cast->add(attr_cast, name, value); 416: chunk_free(&value); 417: } 418: 419: if (attr) 420: { 421: msg->add_attribute(msg, attr); 422: } 423: } 424: 425: /** 426: * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3 427: */ 428: TNC_Result TNC_IMC_API TNC_IMC_BeginHandshake(TNC_IMCID imc_id, 429: TNC_ConnectionID connection_id) 430: { 431: imc_state_t *state; 432: imc_msg_t *out_msg; 433: TNC_Result result = TNC_RESULT_SUCCESS; 434: 435: if (!imc_os) 436: { 437: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); 438: return TNC_RESULT_NOT_INITIALIZED; 439: } 440: if (!imc_os->get_state(imc_os, connection_id, &state)) 441: { 442: return TNC_RESULT_FATAL; 443: } 444: if (lib->settings->get_bool(lib->settings, 445: "%s.plugins.imc-os.push_info", TRUE, lib->ns)) 446: { 447: out_msg = imc_msg_create(imc_os, state, connection_id, imc_id, 448: TNC_IMVID_ANY, msg_types[0]); 449: add_product_info(out_msg); 450: add_string_version(out_msg); 451: add_numeric_version(out_msg); 452: add_op_status(out_msg); 453: add_fwd_enabled(out_msg); 454: add_default_pwd_enabled(out_msg); 455: add_device_id(out_msg); 456: 457: /* send PA-TNC message with the excl flag not set */ 458: result = out_msg->send(out_msg, FALSE); 459: out_msg->destroy(out_msg); 460: } 461: 462: return result; 463: } 464: 465: static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) 466: { 467: imc_msg_t *out_msg; 468: enumerator_t *enumerator; 469: pa_tnc_attr_t *attr; 470: pen_type_t type; 471: TNC_Result result; 472: bool fatal_error = FALSE; 473: 474: /* generate an outgoing PA-TNC message - we might need it */ 475: out_msg = imc_msg_create_as_reply(in_msg); 476: 477: /* parse received PA-TNC message and handle local and remote errors */ 478: result = in_msg->receive(in_msg, out_msg, &fatal_error); 479: if (result != TNC_RESULT_SUCCESS) 480: { 481: out_msg->destroy(out_msg); 482: return result; 483: } 484: 485: /* analyze PA-TNC attributes */ 486: enumerator = in_msg->create_attribute_enumerator(in_msg); 487: while (enumerator->enumerate(enumerator, &attr)) 488: { 489: type = attr->get_type(attr); 490: 491: if (type.vendor_id == PEN_IETF) 492: { 493: if (type.type == IETF_ATTR_ATTRIBUTE_REQUEST) 494: { 495: ietf_attr_attr_request_t *attr_cast; 496: pen_type_t *entry; 497: enumerator_t *e; 498: 499: attr_cast = (ietf_attr_attr_request_t*)attr; 500: 501: e = attr_cast->create_enumerator(attr_cast); 502: while (e->enumerate(e, &entry)) 503: { 504: if (entry->vendor_id == PEN_IETF) 505: { 506: switch (entry->type) 507: { 508: case IETF_ATTR_PRODUCT_INFORMATION: 509: add_product_info(out_msg); 510: break; 511: case IETF_ATTR_STRING_VERSION: 512: add_string_version(out_msg); 513: break; 514: case IETF_ATTR_NUMERIC_VERSION: 515: add_numeric_version(out_msg); 516: break; 517: case IETF_ATTR_OPERATIONAL_STATUS: 518: add_op_status(out_msg); 519: break; 520: case IETF_ATTR_FORWARDING_ENABLED: 521: add_fwd_enabled(out_msg); 522: break; 523: case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED: 524: add_default_pwd_enabled(out_msg); 525: break; 526: case IETF_ATTR_INSTALLED_PACKAGES: 527: add_installed_packages(state, out_msg); 528: break; 529: default: 530: break; 531: } 532: } 533: else if (entry->vendor_id == PEN_ITA) 534: { 535: switch (entry->type) 536: { 537: case ITA_ATTR_DEVICE_ID: 538: add_device_id(out_msg); 539: break; 540: default: 541: break; 542: } 543: } 544: } 545: e->destroy(e); 546: } 547: } 548: else if (type.vendor_id == PEN_ITA && type.type == ITA_ATTR_GET_SETTINGS) 549: { 550: ita_attr_get_settings_t *attr_cast; 551: enumerator_t *e; 552: 553: attr_cast = (ita_attr_get_settings_t*)attr; 554: 555: e = attr_cast->create_enumerator(attr_cast); 556: add_settings(e, out_msg); 557: e->destroy(e); 558: } 559: } 560: enumerator->destroy(enumerator); 561: 562: if (fatal_error) 563: { 564: result = TNC_RESULT_FATAL; 565: } 566: else 567: { 568: /* send PA-TNC message with the EXCL flag set */ 569: result = out_msg->send(out_msg, TRUE); 570: } 571: out_msg->destroy(out_msg); 572: 573: return result; 574: } 575: 576: /** 577: * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3 578: 579: */ 580: TNC_Result TNC_IMC_API TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, 581: TNC_ConnectionID connection_id, 582: TNC_BufferReference msg, 583: TNC_UInt32 msg_len, 584: TNC_MessageType msg_type) 585: { 586: imc_state_t *state; 587: imc_msg_t *in_msg; 588: TNC_Result result; 589: 590: if (!imc_os) 591: { 592: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); 593: return TNC_RESULT_NOT_INITIALIZED; 594: } 595: if (!imc_os->get_state(imc_os, connection_id, &state)) 596: { 597: return TNC_RESULT_FATAL; 598: } 599: in_msg = imc_msg_create_from_data(imc_os, state, connection_id, msg_type, 600: chunk_create(msg, msg_len)); 601: result = receive_message(state, in_msg); 602: in_msg->destroy(in_msg); 603: 604: return result; 605: } 606: 607: /** 608: * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 609: */ 610: TNC_Result TNC_IMC_API TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id, 611: TNC_ConnectionID connection_id, 612: TNC_UInt32 msg_flags, 613: TNC_BufferReference msg, 614: TNC_UInt32 msg_len, 615: TNC_VendorID msg_vid, 616: TNC_MessageSubtype msg_subtype, 617: TNC_UInt32 src_imv_id, 618: TNC_UInt32 dst_imc_id) 619: { 620: imc_state_t *state; 621: imc_msg_t *in_msg; 622: TNC_Result result; 623: 624: if (!imc_os) 625: { 626: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); 627: return TNC_RESULT_NOT_INITIALIZED; 628: } 629: if (!imc_os->get_state(imc_os, connection_id, &state)) 630: { 631: return TNC_RESULT_FATAL; 632: } 633: in_msg = imc_msg_create_from_long_data(imc_os, state, connection_id, 634: src_imv_id, dst_imc_id,msg_vid, msg_subtype, 635: chunk_create(msg, msg_len)); 636: result =receive_message(state, in_msg); 637: in_msg->destroy(in_msg); 638: 639: return result; 640: } 641: 642: /** 643: * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3 644: */ 645: TNC_Result TNC_IMC_API TNC_IMC_BatchEnding(TNC_IMCID imc_id, 646: TNC_ConnectionID connection_id) 647: { 648: if (!imc_os) 649: { 650: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); 651: return TNC_RESULT_NOT_INITIALIZED; 652: } 653: return TNC_RESULT_SUCCESS; 654: } 655: 656: /** 657: * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3 658: */ 659: TNC_Result TNC_IMC_API TNC_IMC_Terminate(TNC_IMCID imc_id) 660: { 661: if (!imc_os) 662: { 663: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); 664: return TNC_RESULT_NOT_INITIALIZED; 665: } 666: imc_os->destroy(imc_os); 667: imc_os = NULL; 668: 669: os->destroy(os); 670: os = NULL; 671: 672: return TNC_RESULT_SUCCESS; 673: } 674: 675: /** 676: * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3 677: */ 678: TNC_Result TNC_IMC_API TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id, 679: TNC_TNCC_BindFunctionPointer bind_function) 680: { 681: if (!imc_os) 682: { 683: DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); 684: return TNC_RESULT_NOT_INITIALIZED; 685: } 686: return imc_os->bind_functions(imc_os, bind_function); 687: }